/* ===========================================================================
   components.css — shared UI: buttons, cards, header, footer, emergency bar,
   language switcher, booking modal, mobile action bar.
   Page-specific styling lives in assets/css/pages/*.css.
   =========================================================================== */

/* ══ Buttons ═══════════════════════════════════════════════════════════════ */
.btn {
  --btn-bg: var(--brand-600);
  --btn-fg: var(--c-text-invert);
  --btn-border: transparent;
  --btn-shadow: var(--sh-sm);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  /* 44px minimum touch target on every variant */
  min-block-size: 2.875rem;
  padding-block: var(--sp-3);
  padding-inline: var(--sp-6);
  border: 1px solid var(--btn-border);
  border-radius: var(--r-full);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-snug);
  line-height: 1.2;
  text-decoration: none;
  /* Deliberately NOT white-space: nowrap. That one line was behind a whole
     family of clipped layouts once the site stopped being English: a button
     that cannot wrap has a min-content width equal to its entire label, and
     because flex and grid items default to min-inline-size: auto they then
     refuse to shrink below it — so `flex: 1`, an auto grid column and a
     100%-wide .btn--block all quietly blew past their container instead of
     fitting inside it. Georgian and Russian labels run 40-60% longer than the
     English ones, which is where it surfaced. Wrapping costs a taller button;
     nowrap cost an unreachable one. `balance` stops a two-line label dropping
     a single word onto the second line. */
  text-wrap: balance;
  box-shadow: var(--btn-shadow);
  transition:
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}
.btn:hover { transform: translateY(-1px); box-shadow: var(--sh-md); color: var(--btn-fg); }
/* scale, not translateY(0): a tap on a phone never produces a hover, so
   this press state is the only acknowledgement the most-tapped control on
   the site gives between the tap and the next page painting. */
.btn:active { transform: scale(0.975); box-shadow: var(--sh-xs); }
.btn .icon { inline-size: 1.05em; block-size: 1.05em; }

.btn--primary { --btn-bg: var(--brand-600); --btn-shadow: var(--sh-glow); }
.btn--primary:hover { --btn-bg: var(--brand-700); }

.btn--accent { --btn-bg: var(--accent-500); --btn-fg: var(--ink-900); }
.btn--accent:hover { --btn-bg: var(--accent-400); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--brand-700);
  --btn-border: var(--c-border-strong);
  --btn-shadow: none;
}
.btn--ghost:hover { --btn-bg: var(--brand-50); --btn-border: var(--brand-300); }

.btn--on-dark {
  --btn-bg: rgb(255 255 255 / 0.1);
  --btn-fg: #fff;
  --btn-border: rgb(255 255 255 / 0.34);
  --btn-shadow: none;
  backdrop-filter: blur(8px);
}
.btn--on-dark:hover { --btn-bg: rgb(255 255 255 / 0.2); --btn-border: rgb(255 255 255 / 0.55); }

.btn--solid-light { --btn-bg: #fff; --btn-fg: var(--brand-800); }
.btn--solid-light:hover { --btn-bg: var(--brand-50); }

.btn--danger { --btn-bg: var(--danger-600); }
.btn--danger:hover { --btn-bg: var(--danger-700); }

.btn--lg { min-block-size: 3.375rem; padding-inline: var(--sp-7); font-size: var(--fs-base); }
.btn--sm { min-block-size: 2.5rem; padding-inline: var(--sp-4); font-size: var(--fs-xs); }
.btn--block { inline-size: 100%; }

/* Arrow nudge on hover — small, deliberate, direction-aware */
.btn__arrow { transition: transform var(--dur-base) var(--ease-out); }
.btn:hover .btn__arrow { transform: translateX(3px); }
[dir="rtl"] .btn:hover .btn__arrow { transform: translateX(-3px); }

/* Text link with a sliding underline */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-sm);
  text-decoration: none;
  color: var(--brand-700);
}
.link-arrow::after {
  content: "";
  position: absolute;
  inset: 0;
}
.link-arrow .icon { transition: transform var(--dur-base) var(--ease-out); }
.link-arrow:hover .icon { transform: translateX(4px); }
[dir="rtl"] .link-arrow:hover .icon { transform: translateX(-4px); }

/* ══ Badges & pills ════════════════════════════════════════════════════════ */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding-block: var(--sp-1);
  padding-inline: var(--sp-3);
  border-radius: var(--r-full);
  background: var(--brand-50);
  color: var(--brand-700);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-wide);
}
.badge--accent { background: var(--accent-100); color: var(--accent-700); }
.badge--glass {
  background: rgb(255 255 255 / 0.14);
  color: #fff;
  border: 1px solid rgb(255 255 255 / 0.26);
  backdrop-filter: blur(10px);
}

/* ══ Cards ═════════════════════════════════════════════════════════════════ */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface-raised);
  /* Cards are always a light, raised surface — reset text colour rather
     than inherit it, or a card dropped inside a dark section (.section--
     brand/.on-dark) silently inherits white-on-white and its text vanishes.
     Real bug: this is exactly what happened the first time a .card was
     used inside .section--brand on the home page. */
  color: var(--c-text);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  overflow: hidden;
  transition:
    transform var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}
.card:hover { transform: translateY(-3px); box-shadow: var(--sh-lg); border-color: var(--brand-200); }
.card:focus-within { border-color: var(--brand-400); box-shadow: var(--sh-lg); }

.card__body { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-3); flex: 1; }
/* .card__body is already a flex column with its own gap, so a .stack on top
   of it adds margins that stack *with* that gap rather than replacing it —
   8 templates do exactly this and were getting both. Opting into .stack means
   the stack owns the rhythm; the gap steps aside. */
.card__body.stack { gap: 0; }
.card__title { font-size: var(--fs-lg); font-family: var(--font-sans); font-weight: var(--fw-semibold); }
.card__text { font-size: var(--fs-sm); color: var(--c-text-muted); line-height: var(--lh-relaxed); }
.card__foot { margin-block-start: auto; padding-block-start: var(--sp-2); }

.card__icon {
  display: grid;
  place-items: center;
  inline-size: 3rem;
  block-size: 3rem;
  border-radius: var(--r-full);
  background: var(--brand-50);
  color: var(--brand-600);
  box-shadow: 0 0 0 1px rgb(var(--rgb-brand) / 0.08);
  transition:
    background-color var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out);
}
.card:hover .card__icon { background: var(--brand-600); color: #fff; box-shadow: var(--sh-glow); }
.card__icon .icon { inline-size: 1.5rem; block-size: 1.5rem; }

.card__media { aspect-ratio: 4 / 3; border-radius: 0; }
.card__media .media__img { transition: transform var(--dur-slower) var(--ease-out); }
.card:hover .card__media .media__img { transform: scale(1.04); }

/* ══ Feature list (checkmark bullets) ══════════════════════════════════════ */
.feature-list { display: flex; flex-direction: column; gap: var(--sp-3); list-style: none; padding: 0; }
.feature-list li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-3);
  align-items: start;
  font-size: var(--fs-sm);
  line-height: var(--lh-relaxed);
  color: var(--c-text-muted);
}
.feature-list .icon {
  inline-size: 1.35rem;
  block-size: 1.35rem;
  padding: 0.22rem;
  border-radius: var(--r-full);
  background: var(--brand-100);
  color: var(--brand-700);
  margin-block-start: 0.18em;
}
/* Sage variant — the secondary accent's main outlet: small, decorative,
   never a CTA or a large surface (see tokens.css's palette note). */
.feature-list--sage .icon { background: var(--sage-100); color: var(--sage-700); }
/* Any dark surface, not just .section--brand — the highlight bands on the
   home page use their own class but need the same inversion. */
.section--brand .feature-list li,
.on-dark .feature-list li { color: var(--brand-100); }
.section--brand .feature-list .icon,
.on-dark .feature-list .icon { background: rgb(255 255 255 / 0.16); color: #fff; }
.on-dark .eyebrow { color: var(--brand-200); }
.on-dark .lede { color: var(--brand-100); }
.on-dark h2, .on-dark h3 { color: #fff; }

/* ══ Stat blocks ═══════════════════════════════════════════════════════════ */
.stat { display: flex; flex-direction: column; gap: var(--sp-1); }
.stat__value {
  font-family: var(--font-display);
  font-size: var(--fs-2xl);
  font-weight: var(--fw-semibold);
  line-height: 1;
  letter-spacing: var(--tracking-tight);
  color: var(--brand-700);
}
.stat__label {
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--c-text-subtle);
}

/* ══ Emergency bar ═════════════════════════════════════════════════════════
   Visually distinct without shouting: a deep brand-adjacent bar with a single
   red pulse dot. It stays at the very top of the document flow.             */
.emergency-bar {
  position: relative;
  z-index: calc(var(--z-header) + 1);
  background: var(--ink-900);
  color: var(--brand-100);
  font-size: var(--fs-xs);
}
.emergency-bar__inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  min-block-size: var(--emergency-bar-h);
  padding-block: var(--sp-1);
  flex-wrap: wrap;
  text-align: center;
}
.emergency-bar__label { display: inline-flex; align-items: center; gap: var(--sp-2); font-weight: var(--fw-semibold); color: #fff; }
.emergency-bar__dot {
  inline-size: 0.5rem;
  block-size: 0.5rem;
  border-radius: var(--r-full);
  background: var(--danger-500);
  box-shadow: 0 0 0 0 rgb(var(--rgb-danger) / 0.65);
  animation: pulse-dot 2.4s var(--ease-out) infinite;
}
@keyframes pulse-dot {
  0%   { box-shadow: 0 0 0 0 rgb(var(--rgb-danger) / 0.6); }
  70%  { box-shadow: 0 0 0 8px rgb(var(--rgb-danger) / 0); }
  100% { box-shadow: 0 0 0 0 rgb(var(--rgb-danger) / 0); }
}
.emergency-bar__note { color: var(--brand-200); }
.emergency-bar__phone {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: #fff;
  font-weight: var(--fw-semibold);
  text-decoration: none;
  padding-block: var(--sp-1);
  padding-inline: var(--sp-3);
  border-radius: var(--r-full);
  border: 1px solid rgb(255 255 255 / 0.24);
  transition: background-color var(--dur-fast) var(--ease-out);
  /* Phone numbers stay LTR even inside an RTL page */
  direction: ltr;
  unicode-bidi: isolate;
}
.emergency-bar__phone:hover { background: rgb(255 255 255 / 0.12); color: #fff; }

/* The note is the first thing to go: below this width it wraps the bar onto a
   second line, and the label plus the number are what actually matter. */
@media (max-width: 60rem) {
  .emergency-bar__note { display: none; }
}

/* ══ Header ════════════════════════════════════════════════════════════════ */
.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-header);
  background: rgb(255 255 255 / 0.82);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-block-end: 1px solid transparent;
  transition: border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.site-header.is-stuck { border-block-end-color: var(--c-border); box-shadow: var(--sh-sm); }

@supports not (backdrop-filter: blur(1px)) {
  .site-header { background: #fff; }
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  min-block-size: var(--header-h);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  text-decoration: none;
  color: var(--ink-900);
  flex: none;
}
.brand__logo { block-size: 2.5rem; inline-size: 2.5rem; object-fit: contain; }
.brand__logo-fallback {
  display: grid;
  place-items: center;
  inline-size: 2.5rem;
  block-size: 2.5rem;
  border-radius: var(--r-md);
  background: var(--grad-brand);
  color: #fff;
}
.brand__name {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-snug);
  line-height: 1;
}
.brand__tag {
  display: block;
  font-family: var(--font-sans);
  font-size: 0.625rem;
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--c-text-subtle);
  margin-block-start: 0.25rem;
}

/* Desktop nav */
.site-nav { display: none; }
.site-nav__list { display: flex; align-items: center; gap: var(--sp-1); list-style: none; padding: 0; }
.site-nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-block-size: 2.75rem;
  padding-inline: var(--sp-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--ink-600);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);
}
.site-nav__link:hover { color: var(--brand-700); background: var(--brand-50); }
.site-nav__link[aria-current="page"] { color: var(--brand-700); font-weight: var(--fw-semibold); }
.site-nav__link[aria-current="page"]::after {
  content: "";
  position: absolute;
  inset-block-end: 0.55rem;
  inset-inline: var(--sp-3);
  block-size: 2px;
  border-radius: var(--r-full);
  background: var(--accent-500);
}

.site-header__actions { display: flex; align-items: center; gap: var(--sp-2); margin-inline-start: auto; }

/* Mobile nav toggle — base rule must precede the `min-width: 62rem` override
   below; two same-specificity `.nav-toggle` rules resolve by source order,
   so if this ever moves after that media query the hamburger button will
   render on desktop too (display: grid winning over display: none). */
.nav-toggle {
  display: grid;
  place-items: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  border-radius: var(--r-sm);
  color: var(--ink-700);
  border: 1px solid var(--c-border);
}
.nav-toggle:hover { background: var(--brand-50); color: var(--brand-700); }

/* Small screens: the header carries the brand and the two controls that must
   always be reachable. The tagline and the Book button are dropped — the hero
   CTA and the fixed mobile action bar both offer booking, so nothing is lost
   and the row stops overflowing at 360px. */
@media (max-width: 61.99rem) {
  /* 72px of header plus 40px of emergency bar was eating an eighth of a phone
     screen before the page even started. */
  :root { --header-h: 3.75rem; }
  .brand__tag { display: none; }
  .site-header__inner { gap: var(--sp-3); }
  .brand__logo { block-size: 2.25rem; inline-size: 2.25rem; }
}

@media (max-width: 29.99rem) {
  .site-header__actions > .btn { display: none; }
}

@media (min-width: 62rem) {
  .site-nav { display: block; margin-inline-start: var(--sp-4); }
  .nav-toggle { display: none; }
}

/* Mobile drawer */
.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  grid-template-rows: auto 1fr;
  background: var(--surface);
  padding-block-end: env(safe-area-inset-bottom);
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out), visibility var(--dur-base);
}
.mobile-nav[data-open="true"] { visibility: visible; opacity: 1; }
.mobile-nav__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-block-size: var(--header-h);
  border-block-end: 1px solid var(--c-border);
}
.mobile-nav__body { overflow-y: auto; padding-block: var(--sp-5) var(--sp-8); }
.mobile-nav__list { list-style: none; padding: 0; display: flex; flex-direction: column; }
.mobile-nav__link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-block-size: 3.5rem;
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  color: var(--ink-800);
  text-decoration: none;
  border-block-end: 1px solid var(--c-border);
}
.mobile-nav__link[aria-current="page"] { color: var(--brand-700); }
.mobile-nav__link .icon { color: var(--brand-400); }

@media (min-width: 62rem) { .mobile-nav { display: none; } }

/* ══ Language switcher ═════════════════════════════════════════════════════ */
.lang-switcher { position: relative; }
.lang-switcher__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-block-size: 2.75rem;
  padding-inline: var(--sp-3);
  border-radius: var(--r-full);
  border: 1px solid var(--c-border);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--ink-700);
  transition: background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.lang-switcher__toggle:hover { background: var(--brand-50); border-color: var(--brand-200); color: var(--brand-700); }
.lang-switcher__current { display: none; }
@media (min-width: 30rem) { .lang-switcher__current { display: inline; } }

.lang-switcher__menu {
  position: absolute;
  inset-block-start: calc(100% + var(--sp-2));
  inset-inline-end: 0;
  z-index: var(--z-dropdown);
  min-inline-size: 12rem;
  padding: var(--sp-2);
  list-style: none;
  background: var(--surface-raised);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  box-shadow: var(--sh-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition:
    opacity var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out),
    visibility var(--dur-fast);
}
.lang-switcher[data-open="true"] .lang-switcher__menu { opacity: 1; visibility: visible; transform: none; }

.lang-switcher__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  min-block-size: 2.75rem;
  padding-inline: var(--sp-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--ink-700);
  text-decoration: none;
}
.lang-switcher__item:hover { background: var(--brand-50); color: var(--brand-700); }
.lang-switcher__item[aria-current="true"] { background: var(--brand-50); color: var(--brand-700); font-weight: var(--fw-semibold); }
.lang-switcher__native { font-weight: var(--fw-medium); }
.lang-switcher__code {
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--c-text-subtle);
}

/* ══ Mobile action bar (emergency + booking FAB) ═══════════════════════════ */
.mobile-actions {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: var(--z-fab);
  display: flex;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--gutter);
  padding-block-end: calc(var(--sp-3) + env(safe-area-inset-bottom));
  background: rgb(255 255 255 / 0.88);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-block-start: 1px solid var(--c-border);
  transform: translateY(110%);
  transition: transform var(--dur-slow) var(--ease-out);
}
.mobile-actions.is-visible { transform: none; }
/* Three buttons (Emergency + My pet + Book) in one bar need tighter padding
   than .btn's own default — that default is sized for a button standing on
   its own, and at three-up on a 375px phone it overflowed the bar's width
   outright, clipping "Book an appointment" off the edge of the screen.

   Shortening the labels was only ever half a fix: it made the bar fit in
   English. Measured at 375px in Georgian — "გადაუდებელი" / "ჩემი ცხოველი" /
   "დაჯავშნა" — the row needed 428px against 335px of usable width, so "Book",
   the primary call to action, sat 53px past the right edge. Russian was the
   same story. And because .mobile-actions is position: fixed it doesn't
   extend the document's scroll width, so the button wasn't merely overflowing
   into a scrollable area: it was off-screen and untappable, with no scrollbar
   to hint that anything was missing.

   Three things all had to be true for that to happen, and none of them was
   about the labels:
     1. .btn sets white-space: nowrap, so a label can never wrap;
     2. a flex item's min-inline-size defaults to auto, meaning it refuses to
        shrink below min-content — which, under nowrap, is the whole label.
        `flex: 1` was therefore doing nothing whatsoever;
     3. .btn--emergency was flex: 0 0 auto, so the widest of the three gave up
        nothing at all.

   Fixed by making the row genuinely shrinkable and by dropping the emergency
   button to its icon (its label survives for screen readers, and the sheet it
   opens is headed "Before you call…"). That reclaims ~110px, which is what
   makes the bar fit in *any* language rather than in the ones we happened to
   measure. */
.mobile-actions .btn {
  flex: 1 1 0;
  min-inline-size: 0;
  padding-inline: var(--sp-4);
  /* The one place on the site where a button must not grow: a fixed three-up
     row on a phone, where a wrapped label would push the bar taller over the
     page. Here nowrap is right, and .btn__label gives the overrun somewhere
     to go. */
  white-space: nowrap;
}

/* text-overflow needs a block box with nowrap; .btn is a flex container, so
   the ellipsis has to live on an element inside it. Belt-and-braces — with
   the emergency button down to an icon there is ~54px of slack at 375px in
   Georgian — but it means a longer language still truncates inside the bar
   instead of escaping it. */
.mobile-actions .btn__label {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mobile-actions .btn--emergency {
  flex: 0 0 auto;
  /* Square, and the same 46px as .btn's min-block-size, so it stays a
     comfortable touch target with no label to give it width. */
  inline-size: 2.875rem;
  padding-inline: 0;
}

/* On the narrowest phones the icon-only emergency button isn't quite enough
   on its own: at 360px — the common Android width — Georgian's "ჩემი ცხოველი"
   still came up 5px short and hit the ellipsis. Tightening the bar's own
   gutter and the buttons' inline padding buys back ~12px of label room per
   button, which clears it at 360 and leaves the ellipsis for the genuinely
   extreme case (320px, an iPhone SE 1st-gen) rather than for an ordinary
   handset. Vertical padding and the 46px touch target are untouched. */
@media (max-width: 26rem) {
  .mobile-actions { padding-inline: var(--sp-4); }
  .mobile-actions .btn { padding-inline: var(--sp-3); }
}

@media (min-width: 62rem) { .mobile-actions { display: none; } }

/* Keep the last section clear of the fixed bar */
@media (max-width: 61.99rem) {
  body { padding-block-end: 4.75rem; }
}

/* ══ Footer ════════════════════════════════════════════════════════════════ */
.site-footer {
  background: var(--ink-900);
  color: var(--brand-100);
  /* Was a flat 96px top. On a phone that is a quarter of the screen spent
     before the first word of a footer — measured, the whole thing came to
     1268px, 1.56 full screens, for twelve links. Fluid instead: 40px on a
     phone, the original 96px once there is room for it. */
  padding-block: clamp(2.5rem, 6vw, 6rem) var(--sp-5);
  font-size: var(--fs-sm);
}
.site-footer a { color: var(--brand-100); text-decoration: none; }
.site-footer a:hover { color: #fff; text-decoration: underline; }

/* Two columns from the narrowest phone up, not one.
   Stacked single-file, the four blocks made the footer taller than the
   screen. "Explore" and "For clients" are short lists that sit happily side
   by side even at 320px; the brand and contact blocks span the full width
   because their content is prose and an address. Three rows instead of
   four, and the two link lists now cost the height of the taller one rather
   than the sum of both. */
.footer-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-6) var(--sp-5);
}
.footer-grid > :first-child,
.footer-grid > :last-child { grid-column: 1 / -1; }

@media (min-width: 44rem) { .footer-grid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-7); } }
@media (min-width: 68rem) {
  .footer-grid {
    grid-template-columns: 1.6fr 1fr 1fr 1.2fr;
    gap: var(--sp-6);
  }
  /* The spans above are a small-screen arrangement only. */
  .footer-grid > :first-child,
  .footer-grid > :last-child { grid-column: auto; }
}

/* Mark and wordmark on one row. The name's cap-height now lands within a
   few pixels of the .footer-col__title beside it, which is what makes the
   four columns read as one row rather than as a logo with three lists
   floating next to it. */
.footer-brand__name {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  color: #fff;
  margin-block-end: var(--sp-3);
}

.footer-brand__logo {
  inline-size: 2.25rem;
  block-size: auto;
  flex-shrink: 0;
}
.footer-brand__text { color: var(--brand-200); max-inline-size: 32ch; line-height: var(--lh-relaxed); }

.footer-col__title {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--brand-300);
  margin-block-end: var(--sp-4);
}
.footer-col__list { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
/* 2rem (32px) clears the WCAG 2.2 AA 24px floor with room to spare on a
   mouse, where the pointer is precise. A finger is not: the mobile rule
   below takes these to the full 44px Apple/Material both ask for. */
.footer-col__list a { display: inline-flex; align-items: center; min-block-size: 2rem; }
.footer-contact__row a { display: inline-flex; align-items: center; min-block-size: 2rem; }

@media (max-width: 40rem) {
  .footer-col__list a,
  .footer-contact__row a,
  .brand { min-block-size: 2.75rem; }
  .footer-col__list { gap: var(--sp-1); }
}

.footer-contact { display: flex; flex-direction: column; gap: var(--sp-3); }
.footer-contact__row { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-3); align-items: start; }
.footer-contact__row .icon { color: var(--brand-400); margin-block-start: 0.15em; }
.footer-contact__row a { direction: ltr; unicode-bidi: isolate; }

.footer-socials { display: flex; gap: var(--sp-2); margin-block-start: var(--sp-4); }
.footer-socials a {
  display: grid;
  place-items: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  border-radius: var(--r-full);
  border: 1px solid rgb(255 255 255 / 0.16);
  transition: background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.footer-socials a:hover { background: rgb(255 255 255 / 0.12); border-color: rgb(255 255 255 / 0.4); }

.footer-bottom {
  /* Fluid, for the same reason as the footer's own top padding: a flat 64px
     rule-to-copyright gap is proportionate on a wide screen and wasteful on
     a phone. */
  margin-block-start: clamp(2rem, 5vw, 4rem);
  padding-block-start: var(--sp-4);
  border-block-start: 1px solid rgb(255 255 255 / 0.12);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  justify-content: space-between;
  align-items: center;
  color: var(--brand-300);
  font-size: var(--fs-xs);
}

.footer-ethics {
  margin-block-start: var(--sp-6);
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--r-md);
  background: rgb(255 255 255 / 0.05);
  border: 1px solid rgb(255 255 255 / 0.1);
  color: var(--brand-200);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-3);
  align-items: start;
  line-height: var(--lh-relaxed);
}
.footer-ethics .icon { color: var(--brand-300); margin-block-start: 0.15em; }

/* ══ Booking modal ═════════════════════════════════════════════════════════ */
.booking-modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: end center;
  padding: 0;
  visibility: hidden;
  pointer-events: none;
}
.booking-modal[data-open="true"] { visibility: visible; pointer-events: auto; }

@media (min-width: 44rem) {
  .booking-modal { place-items: center; padding: var(--sp-5); }
}

.booking-modal__backdrop {
  position: absolute;
  inset: 0;
  background: var(--overlay);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out);
  backdrop-filter: blur(3px);
}
.booking-modal[data-open="true"] .booking-modal__backdrop { opacity: 1; }

.booking-modal__panel {
  position: relative;
  inline-size: 100%;
  max-inline-size: 34rem;
  max-block-size: 92svh;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface-raised);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: var(--sh-xl);
  transform: translateY(3%);
  opacity: 0;
  transition: transform var(--dur-slow) var(--ease-out), opacity var(--dur-base) var(--ease-out);
  padding-block-end: env(safe-area-inset-bottom);
}
.booking-modal[data-open="true"] .booking-modal__panel { transform: none; opacity: 1; }

@media (min-width: 44rem) {
  .booking-modal__panel { border-radius: var(--r-xl); transform: translateY(12px) scale(0.985); }
}

.booking-modal__head {
  position: sticky;
  inset-block-start: 0;
  z-index: 2;
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
  background: var(--surface-raised);
  border-block-end: 1px solid var(--c-border);
}
.booking-modal__title { font-size: var(--fs-xl); }
.booking-modal__sub { font-size: var(--fs-sm); color: var(--c-text-muted); margin-block-start: var(--sp-1); }
.booking-modal__close {
  margin-inline-start: auto;
  display: grid;
  place-items: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  border-radius: var(--r-full);
  color: var(--ink-500);
  flex: none;
}
.booking-modal__close:hover { background: var(--ink-50); color: var(--ink-800); }

.booking-form { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-5); }

.field { display: flex; flex-direction: column; gap: var(--sp-2); }
.field__label { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--ink-700); }
.field__hint { font-size: var(--fs-xs); color: var(--c-text-subtle); }
.field__error { font-size: var(--fs-xs); color: var(--danger-600); font-weight: var(--fw-medium); }
.field[data-invalid="true"] .input,
.field[data-invalid="true"] .select { border-color: var(--danger-500); }

.input, .select, .textarea {
  inline-size: 100%;
  /* block-size, not just min-block-size, on the select below: a native
     <select> sizes itself from its font metrics and ignores padding-block
     the way an <input> honours it, so an input and a select sitting one
     above the other came out 2px different in height. */
  min-block-size: 3rem;
  padding-block: var(--sp-3);
  padding-inline: var(--sp-4);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--c-text);
  font-size: var(--fs-base); /* 16px — prevents iOS zoom on focus */
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.input::placeholder { color: var(--ink-300); }

/* One explicit height for both, rather than leaving each to work it out.
   An <input> grows past min-block-size to fit its padding and line box (52px
   here); a <select> sizes from its own font metrics and largely ignores
   padding-block, so it settled at 48px — a 4px step visible any time the two
   sit one above the other, which on the booking form they always do.
   Textareas are excluded on purpose: they have to be free to grow. Checkboxes
   and radios too — a 52px-tall checkbox is not a checkbox. */
input.input:not([type="checkbox"]):not([type="radio"]),
.select,
select.input {
  block-size: 3.25rem;
}

.select,
select.input {
  appearance: none;
  padding-inline-end: var(--sp-8);
  /* Chevron drawn with a gradient so no background-image URL is needed and the
     position flips correctly for RTL. */
  background-image:
    linear-gradient(45deg, transparent 50%, var(--ink-400) 50%),
    linear-gradient(135deg, var(--ink-400) 50%, transparent 50%);
  background-position:
    right calc(var(--sp-5) + 4px) center,
    right var(--sp-5) center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}
[dir="rtl"] .select,
[dir="rtl"] select.input {
  background-position:
    left var(--sp-5) center,
    left calc(var(--sp-5) + 4px) center;
}

/* Segmented radio group — used for visit type and pet type */
.segmented { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.segmented__option { flex: 1 1 auto; min-inline-size: 7rem; }
.segmented__input { position: absolute; opacity: 0; pointer-events: none; }
.segmented__label {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-block-size: 3rem;
  padding-inline: var(--sp-4);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--ink-600);
  cursor: pointer;
  text-align: center;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}
.segmented__label:hover { border-color: var(--brand-300); background: var(--brand-50); }
.segmented__input:checked + .segmented__label {
  background: var(--brand-50);
  border-color: var(--brand-500);
  color: var(--brand-800);
  font-weight: var(--fw-semibold);
  box-shadow: inset 0 0 0 1px var(--brand-500);
}
.segmented__input:focus-visible + .segmented__label {
  outline: 2px solid var(--c-focus);
  outline-offset: 2px;
}

.field-row { display: grid; gap: var(--sp-4); grid-template-columns: 1fr; }
@media (min-width: 30rem) { .field-row { grid-template-columns: 1fr 1fr; } }

.booking-form__foot {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding-block-start: var(--sp-2);
}
.booking-form__note {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-3);
  align-items: start;
  padding: var(--sp-4);
  border-radius: var(--r-md);
  background: var(--brand-50);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
  color: var(--brand-800);
}
.booking-form__note .icon { color: var(--brand-500); margin-block-start: 0.1em; }

/* Live summary of the request — exactly what the admin will be told */
.booking-summary {
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px dashed var(--c-border-strong);
  background: var(--surface-sunken);
  font-size: var(--fs-sm);
  line-height: var(--lh-relaxed);
  color: var(--ink-600);
  white-space: pre-line;
}

/* Honeypot — off-screen and out of both the tab order and the accessibility
   tree, so it is invisible to real visitors (sighted or not) but still gets
   auto-filled by naive spam bots that populate every field on a page. */
.hp-field {
  position: absolute;
  inset-inline-start: -9999px;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
}

/* Submit button: idle / loading text swap, same element so layout never shifts */
.booking-submit__state {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
}
.icon--spin { animation: icon-spin 0.85s linear infinite; }
@keyframes icon-spin { to { transform: rotate(360deg); } }

/* ══ Booking result — success / error, replaces the form in place ══════════ */
.booking-result {
  padding: var(--sp-7) var(--sp-5) var(--sp-6);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sp-3);
}
.booking-result__icon {
  display: grid;
  place-items: center;
  inline-size: 3.5rem;
  block-size: 3.5rem;
  border-radius: var(--r-full);
  margin-block-end: var(--sp-2);
}
.booking-result__icon--success { background: var(--brand-100); color: var(--brand-700); }
.booking-result__icon--error { background: var(--danger-100); color: var(--danger-600); }
.booking-result__title { font-size: var(--fs-xl); }
.booking-result__text {
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  line-height: var(--lh-relaxed);
  max-inline-size: 26rem;
}
.booking-result .btn { margin-block-start: var(--sp-2); }
.booking-result__actions { justify-content: center; flex-wrap: wrap; }
.booking-result__actions a[href^="tel:"] { direction: ltr; unicode-bidi: isolate; }

body.is-locked { overflow: hidden; }


/* ── Phone field: dialling code + number on one row ──────────────────────────
   The code select is sized to its content so the number, which is the part
   being typed, keeps the remaining width. See apps/core/phone.py. */
.phone-field {
  display: flex;
  gap: var(--sp-2);
}
.phone-field select {
  flex: none;
  inline-size: auto;
  /* Enough for the widest code (+995) plus the flag and the chevron, without
     eating into the number, which is the field being typed. */
  min-inline-size: 7.5rem;
  max-inline-size: 40%;
}
.phone-field input { flex: 1; min-inline-size: 0; }
/* The shared select rule reserves --sp-8 (64px) at the end for the chevron,
   which is right for a full-width dropdown and far too much for this one: at
   7.5rem wide it left about 40px for the text and clipped "🇬🇪 +995" down to
   "🇬🇪 +9". Tighter inset here, and a little more minimum width. */
.phone-field select.input {
  min-inline-size: 8.25rem;
  padding-inline-end: var(--sp-6);
  background-position:
    right calc(var(--sp-3) + 4px) center,
    right var(--sp-3) center;
}
[dir="rtl"] .phone-field select.input {
  background-position:
    left var(--sp-3) center,
    left calc(var(--sp-3) + 4px) center;
}

/* ── Auth card heading ─────────────────────────────────────────────────────
   h1 elsewhere sizes for a full-width page section; inside the ~27rem auth
   card it wrapped a 3-word question ("What's your phone number?") onto three
   short lines. Sized down and given a matching lede so both scale together
   at the card's own width instead of the page's. */
.auth-card h1 { font-size: var(--fs-2xl); }
.auth-card .lede { font-size: var(--fs-md); }

/* ══ Two-door account page (/accounts/my-pet/) ═════════════════════════════
   Was six inline style="" attributes doing the work of a layout. */
.doors__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  text-align: center;
  margin-block-end: var(--sp-7);
}
.doors__head h1 { margin: 0; }
/* .lede is capped at 62ch and centred text needs the box centred too, or the
   measure sits left of the heading above it. */
.doors__head .lede { margin: 0 auto; }

.doors__grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
/* Both doors end on their button, whatever the copy above it does — without
   this the shorter card's button floats up and the pair looks misaligned. */
.door .card__body { gap: var(--sp-4); }
.door .card__text { flex: 1; }

.doors__aside {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  text-align: center;
  margin-block-start: var(--sp-7);
  padding: var(--sp-6) var(--sp-5);
  background: var(--surface-sunken);
  border: 1px solid var(--c-border);
  border-radius: var(--r-xl);
}
.doors__aside-title { font-weight: var(--fw-semibold); color: var(--c-heading); margin: 0; }
.doors__aside-text {
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  margin: 0;
  max-inline-size: 46ch;
}

/* ══ Booking / step wizard shell ═══════════════════════════════════════════
   The public booking flow's own layout. Previously five separate style=""
   attributes on the template — which is how the spacing drifted out of the
   token system in the first place. */
.wizard { padding-block: var(--sp-8) var(--sp-9); }
.wizard__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  text-align: center;
  margin-block-end: var(--sp-6);
}
.wizard__head h1 { font-size: var(--fs-2xl); margin: 0; }
.wizard__head .lede { margin: 0; }

/* Who the booking is for, shown as a chip rather than folded into the
   heading — see public_booking.html for why the name cannot live inside a
   translated sentence. The name gets dir="auto" so a Persian or Hebrew name
   sitting inside an English page (or the reverse) reads in its own
   direction instead of being reordered around the label. */
.wizard__subject {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  max-inline-size: 100%;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-full);
  background: var(--surface-sunken);
  border: 1px solid var(--c-border);
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
}
.wizard__subject svg { color: var(--brand-500); flex-shrink: 0; }
.wizard__subject-label { flex-shrink: 0; }
.wizard__subject-name {
  font-weight: var(--fw-semibold);
  color: var(--ink-800);
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  unicode-bidi: isolate;
}

.wizard__errors { margin-block-end: var(--sp-4); text-align: center; }

.wizard__card {
  background: var(--surface-raised);
  border: 1px solid var(--c-border);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-md);
  padding: var(--sp-6);
}
.wizard__fields { display: flex; flex-direction: column; gap: var(--sp-5); }
.wizard__actions { margin-block-start: var(--sp-6); }

@media (max-width: 40rem) {
  .wizard { padding-block: var(--sp-6) var(--sp-7); }
  .wizard__card { padding: var(--sp-5); }

  /* The submit rides the bottom of the screen while the card is in view, so
     "Continue" is always under the thumb instead of below the fold. The
     negative margins bleed it to the card's own edges; the top border and
     opaque background keep the fields from showing through underneath. */
  .wizard__actions {
    position: sticky;
    inset-block-end: 0;
    margin: var(--sp-5) calc(var(--sp-5) * -1) calc(var(--sp-5) * -1);
    padding: var(--sp-4) var(--sp-5);
    padding-block-end: calc(var(--sp-4) + env(safe-area-inset-bottom));
    background: var(--surface-raised);
    border-block-start: 1px solid var(--c-border);
    border-end-start-radius: var(--r-xl);
    border-end-end-radius: var(--r-xl);
  }
}

/* ── Home-visit fee notice ────────────────────────────────────────────────
   Quoted next to the visit-type choice in every booking flow. Reads as a
   quiet note while someone is still deciding, and firms up (accent ground,
   full-strength text) once they actually pick the home visit — the moment
   the number stops being background information and becomes a commitment. */
.fee-note {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin: var(--sp-3) 0 0;
  padding: var(--sp-3);
  border-radius: var(--r-md);
  border: 1px solid var(--c-border);
  background: var(--surface-sunken);
  color: var(--c-text-muted);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  transition:
    background-color var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out);
}
.fee-note__icon { flex: none; margin-block-start: 0.1em; color: var(--brand-600); }
.fee-note.is-active {
  background: var(--accent-100, #f7edc6);
  border-color: var(--accent-500, #d3b605);
  color: var(--ink-900);
  font-weight: var(--fw-medium);
}
.fee-note.is-active .fee-note__icon { color: var(--ink-900); }

/* ── Time-slot chips ──────────────────────────────────────────────────────
   auto-fill rather than a fixed column count: the number of open times
   changes with the day and the clinic's hours, so the grid has to work for
   three chips and for eighteen without either leaving a ragged half-row or
   squeezing below a thumb-sized target. */
.slots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(5rem, 1fr));
  gap: var(--sp-2);
}
.slot { position: relative; display: block; }
/* Visually hidden, not display:none — the radio has to stay focusable and
   reachable by keyboard and screen reader; the label beside it is the target
   people actually see. */
.slot__input {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  opacity: 0;
  pointer-events: none;
}
.slot__label {
  display: flex;
  align-items: center;
  justify-content: center;
  min-block-size: 2.875rem;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--c-text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}
.slot__label:hover { border-color: var(--brand-400); background: var(--brand-50); }
.slot__input:checked + .slot__label {
  background: var(--brand-600);
  border-color: var(--brand-600);
  color: var(--c-text-invert);
  font-weight: var(--fw-semibold);
}
.slot__input:focus-visible + .slot__label {
  outline: 2px solid var(--brand-500);
  outline-offset: 2px;
}
.slots__empty {
  padding: var(--sp-4);
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--r-md);
  text-align: center;
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  margin: 0;
}

/* ── Step-wizard footer ──────────────────────────────────────────────────────
   "← Back · Already have an account? Log in" was one run-on line of small
   text: on a phone it wrapped mid-sentence, and Back — the control people
   actually reach for — was the same weight as the prose around it. Back is a
   real target now, the sign-in prompt sits under it as a separate thought. */
.wizard-foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-4);
  margin-block-start: var(--sp-6);
  text-align: center;
}
.wizard-foot__back {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--r-full);
  border: 1px solid var(--c-border);
  background: var(--surface-raised);
  color: var(--c-text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  text-decoration: none;
  transition: border-color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);
}
.wizard-foot__back:hover { border-color: var(--c-border-strong); background: var(--surface-sunken); }
.wizard-foot__alt { font-size: var(--fs-sm); color: var(--c-text-muted); margin: 0; }

@media (min-width: 40rem) {
  .wizard-foot { flex-direction: row; justify-content: space-between; }
  /* Step 1 has no Back link — row + space-between with only one child pins
     it to the far side instead of the card's center. */
  .wizard-foot--centered { justify-content: center; }
}
@media (max-width: 40rem) {
  /* Full width, thumb-height, and above the prose — the one thing a lost
     visitor wants on a small screen is the way back. */
  .wizard-foot__back { inline-size: 100%; justify-content: center; }
}


/* ══ Compact footer ════════════════════════════════════════════════════════
   Used everywhere except the seven marketing pages. One row on a wide screen,
   one small stack on a phone — the point is that it ends the page without
   adding a screen of scrolling to it. */
.compact-footer {
  border-block-start: 1px solid var(--c-border);
  /* A step darker than the sunken surface — the card just above this (e.g.
     the "just want an appointment?" callout on /accounts/my-pet/) is often
     itself --surface-sunken, and the two were reading as one indistinct
     block instead of the footer grounding the page as its own closing
     element. */
  background: var(--ink-100);
  padding-block: var(--sp-6);
}
.compact-footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3) var(--sp-5);
}
.compact-footer__brand {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  color: var(--c-heading);
  text-decoration: none;
}
.compact-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  font-size: var(--fs-sm);
}
/* Same 32px-on-a-mouse / 44px-on-a-finger floor as .footer-col__list a in the
   full footer (see there for the WCAG/Apple/Material reasoning) — this row
   had never gotten the same treatment, so on a phone its three links sat at
   their bare line-height (~23px), well under the size a thumb can reliably
   hit, right beside a footer variant that already got this right. */
.compact-footer__links a { display: inline-flex; align-items: center; min-block-size: 2rem; color: var(--c-text-muted); text-decoration: none; }
.compact-footer__links a:hover { color: var(--c-text); text-decoration: underline; }
/* A phone number is nothing but digits, spaces and a leading "+" — none of
   them a strong-direction character, so with no anchor of their own they
   take the paragraph's base direction. In RTL (fa/he) that reordered
   "+995 599 99 64 87" into "87 64 99 599 995+": still a valid tel: link,
   but unreadable and impossible to copy down correctly. The full footer's
   phone link already isolates itself the same way (.footer-contact__row a);
   this one, reachable from every non-marketing page including the booking
   flow and the emergency pet-tag page, had been missed. */
.compact-footer__phone { direction: ltr; unicode-bidi: isolate; }
.compact-footer__legal { font-size: var(--fs-xs); color: var(--c-text-subtle); margin: 0; }

@media (max-width: 40rem) {
  /* Three centered rows at the desktop padding read as oversized on a phone
     for how little is actually in them — tighten both the outer padding and
     the gap between rows. */
  .compact-footer { padding-block: var(--sp-4); }
  .compact-footer__inner { flex-direction: column; text-align: center; gap: var(--sp-2); }
  .compact-footer__links { justify-content: center; }
  .compact-footer__links a { min-block-size: 2.75rem; }
}

/* ══ Scroll progress ═══════════════════════════════════════════════════════
   A hairline across the very top that fills as the page scrolls. On a page
   this long it answers "how much more is there?" without the visitor having
   to guess from a scrollbar they may not even have (mobile hides it, and the
   two horizontal strips on the homepage make the vertical one ambiguous).
   Driven natively by scroll-timeline where the browser has it, and by
   main.js's rAF fallback everywhere else. */
.scroll-progress {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: var(--z-modal);
  block-size: 3px;
  inline-size: 100%;
  transform: scaleX(var(--scroll-progress, 0));
  transform-origin: 0 50%;
  background: var(--grad-brand, var(--brand-600));
  pointer-events: none;
}
@supports (animation-timeline: scroll()) {
  /* Native version: no JS in the scroll path at all, so it can never lag
     behind the page the way a rAF-driven bar does under load. */
  .scroll-progress {
    animation: scroll-progress-grow linear;
    animation-timeline: scroll(root block);
  }
  @keyframes scroll-progress-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
}
@media (prefers-reduced-motion: reduce) { .scroll-progress { display: none; } }
