/* ==========================================================================
   Park Square Pharmacy — stylesheet
   Design system: see /design-system/MASTER.md

   Editorial layout, availability-led. Shares the Pharmacy at SPAR palette and
   the Lexend + Source Sans 3 pairing with the group's other stores, and
   nothing else: the grid, the components and the section rhythm are this
   store's own. Hairlines and whitespace do the work that cards and shadows
   do elsewhere.
   ========================================================================== */

/* ---------- 1. Tokens ---------------------------------------------------- */
:root {
  /* palette — red + charcoal, taken from the shop logo and cleaned into
     accessible steps. See design-system/MASTER.md before changing these. */
  --red-800:#8E0D16; --red-700:#A80F1C; --red-600:#C1121F; --red-500:#DC2230;
  --red-400:#F73E4C;   /* red that still clears 4.5:1 on charcoal — the lighter
                          tints above 70% lightness read as pink, not brand */
  --red-300:#FF5A66;   /* its hover step */
  --red-100:#FBDDE0; --red-50:#FDF3F4;
  --ink-900:#191616; --ink-800:#241F1F; --ink-700:#332C2C; --ink-600:#5A5050;
  --ink-300:#C9BFBF; --ink-200:#E7E0E0; --ink-100:#F2EDED; --ink-50:#FAF7F7;
  --white:#FFFFFF;
  --teal-800:#115E56; --teal-700:#0F766E; --teal-50:#EFFAF8;
  --ok-700:#15803D;  --ok-100:#DCFCE7;   /* semantic only: "open now" */
  --alert-700:#B3261E; --alert-50:#FDF3F3;

  /* semantic — light */
  --bg:var(--white);
  --bg-alt:var(--ink-50);
  --surface:var(--white);
  --surface-2:var(--ink-100);
  --text:var(--ink-700);
  --text-muted:var(--ink-600);
  --heading:var(--ink-800);
  --brand:var(--red-600);
  --brand-hover:var(--red-700);
  --brand-strong:var(--red-800);
  --brand-soft:var(--red-50);
  --on-brand:var(--white);
  --link:var(--red-700);
  --link-hover:var(--red-800);
  --cta:var(--teal-700);
  --cta-hover:var(--teal-800);
  --on-cta:var(--white);
  --accent:var(--ink-800);
  --accent-soft:var(--ink-100);
  --band:var(--ink-900);
  --on-band:#F0EBEB;
  --border:var(--ink-200);
  --border-brand:var(--red-100);
  --focus:#1A56DB;
  --danger:var(--alert-700);
  --danger-soft:var(--alert-50);
  --scrim:rgba(25,22,22,.55);
  --ok:var(--ok-700);
  --ok-soft:var(--ok-100);

  /* hairline — the editorial layout's main structural device */
  --rule:var(--ink-200);
  --rule-strong:var(--ink-300);

  /* scale */
  --r-sm:6px; --r-md:10px; --r-lg:16px; --r-full:999px;
  --shadow-sm:0 1px 2px rgba(15,23,42,.06);
  --shadow-md:0 6px 20px -6px rgba(15,23,42,.16);
  --shadow-lg:0 18px 44px -14px rgba(15,23,42,.22);
  --tap:48px;
  --container:1220px;
  --measure:64ch;
  --gutter:clamp(1.25rem, 4vw, 3rem);
  /* Section rhythm. 8rem top and bottom put 256px between some sections, which
     read as the page having run out of content. 3.5rem gives 112px between two
     full-rhythm sections — still generous, no longer a void. */
  --section-y:clamp(2.25rem, 4vw, 3.5rem);
  --t-fast:150ms ease;
  --t-base:220ms ease;

  /* Charcoal blocks — the week ribbon's days and the home page's tiles. In light
     mode the block is its own contrast (16.9:1 on white) and the edge matches it;
     in dark mode the block is only 1.25:1 against the page, so the edge has to do
     the separating and is set to 3.6:1. */
  /* Form control edges. --border (#E7E0E0) is 1.3:1 on white, so every field,
     the upload zone and the choice buttons had boundaries below the 3:1 that
     WCAG 1.4.11 asks of a UI component. This clears it on white (3.7:1) and on
     the --bg-alt fills (3.5:1). Used only by controls, so cards and hairlines
     elsewhere keep their lighter rule. */
  --field-edge:#8F8181;

  --block-bg:#1F1C1B;
  --block-edge:#1F1C1B;

  /* z-scale */
  --z-float:20; --z-nav:40; --z-skip:60;

  color-scheme: light dark;
}

/* dark palette — declared twice so the toggle wins in both directions */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:#141010;
    --field-edge:#7E7170;
    --block-bg:#2B2524;
    --block-edge:rgba(255,255,255,.38);
    --bg-alt:#1A1515;
    --surface:#1F1919;
    --surface-2:#1A1515;
    --text:#EDE7E6;
    --text-muted:#B7A9A8;
    --heading:#F6F0EF;
    --brand:var(--red-400);
    --brand-hover:var(--red-300);
    --brand-strong:#FFC2C6;
    --brand-soft:#3A1417;
    --on-brand:#2B0206;
    --link:var(--red-400);
    --link-hover:var(--red-300);
    --cta:#5EDDCC;
    --cta-hover:#93EDE1;
    --on-cta:#04231F;
    --accent:#EDE7E6;
    --accent-soft:#2A2222;
    --band:#0D0A0A;
    --on-band:#E8E1E0;
    --border:#3A302F;
    --border-brand:#5A2429;
    --rule:#332B2A;
    --rule-strong:#4A3E3D;
    --focus:#93B4FF;
    --danger:#FF9B95;
    --danger-soft:#3B1615;
    --scrim:rgba(0,0,0,.66);
    --ok:#5CD98B;
    --ok-soft:#10301D;
    --shadow-sm:0 1px 2px rgba(0,0,0,.4);
    --shadow-md:0 6px 20px -6px rgba(0,0,0,.6);
    --shadow-lg:0 18px 44px -14px rgba(0,0,0,.7);
  }
}

:root[data-theme="dark"] {
  --bg:#141010;
  --field-edge:#7E7170;
  --block-bg:#2B2524;
  --block-edge:rgba(255,255,255,.38);
  --bg-alt:#1A1515;
  --surface:#1F1919;
  --surface-2:#1A1515;
  --text:#EDE7E6;
  --text-muted:#B7A9A8;
  --heading:#F6F0EF;
  --brand:var(--red-400);
  --brand-hover:var(--red-300);
  --brand-strong:#FFC2C6;
  --brand-soft:#3A1417;
  --on-brand:#2B0206;
  --link:var(--red-400);
  --link-hover:var(--red-300);
  --cta:#5EDDCC;
  --cta-hover:#93EDE1;
  --on-cta:#04231F;
  --accent:#EDE7E6;
  --accent-soft:#2A2222;
  --band:#0D0A0A;
  --on-band:#E8E1E0;
  --border:#3A302F;
  --border-brand:#5A2429;
  --rule:#332B2A;
  --rule-strong:#4A3E3D;
  --focus:#93B4FF;
  --danger:#FF9B95;
  --danger-soft:#3B1615;
  --scrim:rgba(0,0,0,.66);
  --ok:#5CD98B;
  --ok-soft:#10301D;
  --shadow-sm:0 1px 2px rgba(0,0,0,.4);
  --shadow-md:0 6px 20px -6px rgba(0,0,0,.6);
  --shadow-lg:0 18px 44px -14px rgba(0,0,0,.7);
}

/* ---------- 2. Reset + base --------------------------------------------- */
*,*::before,*::after { box-sizing:border-box; }
* { margin:0; }

html { -webkit-text-size-adjust:100%; scroll-behavior:smooth; scroll-padding-top:104px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior:auto; } }

body {
  background:var(--bg);
  color:var(--text);
  font-family:"Source Sans 3","Segoe UI",system-ui,-apple-system,sans-serif;
  font-size:17px;
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

h1,h2,h3,h4 {
  font-family:Lexend,"Segoe UI",system-ui,sans-serif;
  color:var(--heading);
  line-height:1.1;
  font-weight:600;
  letter-spacing:-.022em;
  text-wrap:balance;
}
/* Editorial scale: display sizes run larger and tighter than the group's
   other stores, and headings carry the hierarchy without coloured plates. */
h1 { font-size:clamp(2.4rem,1.5rem + 4.2vw,4.4rem); font-weight:700; letter-spacing:-.032em; }
h2 { font-size:clamp(1.8rem,1.25rem + 2.5vw,2.9rem); letter-spacing:-.026em; }
h3 { font-size:clamp(1.15rem,1.05rem + .5vw,1.4rem); letter-spacing:-.012em; }
h4 { font-size:1.05rem; }

p { text-wrap:pretty; }
img,svg { display:block; max-width:100%; }
img { height:auto; }
[hidden] { display:none !important; }
a { color:var(--link); text-underline-offset:3px; }
a:hover { color:var(--link-hover); }
ul,ol { padding-left:1.25rem; }
strong { font-weight:600; color:var(--heading); }
abbr[title] { text-decoration-style:dotted; cursor:help; }

:focus-visible { outline:3px solid var(--focus); outline-offset:2px; border-radius:var(--r-sm); }
::selection { background:var(--brand-soft); color:var(--brand-strong); }

/* ---------- 3. Layout helpers ------------------------------------------- */
.container { width:100%; max-width:var(--container); margin-inline:auto; padding-inline:var(--gutter); }
.section { padding-block:var(--section-y); }
.section--tint { background:var(--bg-alt); }
.section--edge { border-top:1px solid var(--rule); }
.measure { max-width:var(--measure); }
.center { text-align:center; }
.stack > * + * { margin-top:1.1rem; }
.sr-only {
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

.grid > *, .split > *, .footer__grid > * { min-width:0; }
a[href^="mailto:"], .footer__list a { overflow-wrap:anywhere; }

.grid { display:grid; gap:clamp(1rem,2.2vw,1.5rem); }
.grid--2 { grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr)); }
.grid--3 { grid-template-columns:repeat(auto-fit,minmax(min(100%,288px),1fr)); }
.grid--4 { grid-template-columns:repeat(auto-fit,minmax(min(100%,224px),1fr)); }

/* Editorial section opener: a hairline, a label, then the heading. */
.opener { border-top:2px solid var(--heading); padding-top:1.1rem; margin-bottom:clamp(2rem,4.5vw,3.25rem); }
.opener__label {
  font-family:Lexend,system-ui,sans-serif; font-size:.76rem; font-weight:600;
  letter-spacing:.14em; text-transform:uppercase; color:var(--brand);
  display:flex; align-items:center; gap:.55rem; margin-bottom:.9rem;
}
.opener__label svg { width:15px; height:15px; flex:none; }
.opener p { color:var(--text-muted); font-size:1.1rem; margin-top:.9rem; max-width:58ch; }
/* Lifts the 58ch measure where the intro is meant to sit on a single line.
   It still wraps on narrow screens — nothing is forced with nowrap. */
.opener--wide p { max-width:none; }

/* Oversized editorial intro paragraph. */
.lede {
  font-size:clamp(1.15rem,1.02rem + .6vw,1.42rem);
  line-height:1.5; color:var(--heading); font-weight:400;
  max-width:54ch; letter-spacing:-.006em;
}

/* Small caps-ish label used throughout instead of pill eyebrows. */
.label {
  font-family:Lexend,system-ui,sans-serif; font-size:.74rem; font-weight:600;
  letter-spacing:.14em; text-transform:uppercase; color:var(--text-muted);
}

.rule { border:0; border-top:1px solid var(--rule); margin-block:clamp(2rem,5vw,3.5rem); }

/* ---------- 4. Skip link ------------------------------------------------ */
.skip-link {
  position:absolute; left:1rem; top:-120px; z-index:var(--z-skip);
  background:var(--brand); color:var(--on-brand);
  padding:.85rem 1.25rem; border-radius:var(--r-md); font-weight:600;
  text-decoration:none; transition:top var(--t-fast);
}
.skip-link:focus { top:1rem; color:var(--on-brand); }

/* ---------- 5. Buttons -------------------------------------------------- */
.btn {
  display:inline-flex; align-items:center; justify-content:center; gap:.55rem;
  min-height:var(--tap); padding:.75rem 1.5rem;
  font-family:Lexend,system-ui,sans-serif; font-size:1rem; font-weight:600;
  border:2px solid transparent; border-radius:var(--r-sm);
  text-decoration:none; cursor:pointer; text-align:center;
  letter-spacing:-.005em;
  transition:background-color var(--t-fast), border-color var(--t-fast), color var(--t-fast), box-shadow var(--t-fast);
}
.btn svg { width:20px; height:20px; flex:none; }
.btn--primary { background:var(--brand); color:var(--on-brand); }
.btn--primary:hover { background:var(--brand-hover); color:var(--on-brand); }
.btn--cta { background:var(--cta); color:var(--on-cta); }
.btn--cta:hover { background:var(--cta-hover); color:var(--on-cta); }
.btn--outline { background:transparent; color:var(--heading); border-color:var(--rule-strong); }
.btn--outline:hover { border-color:var(--brand); color:var(--brand); }
.btn--onbrand { background:var(--white); color:var(--ink-900); }
.btn--onbrand:hover { background:var(--ink-50); color:var(--ink-900); }
.btn--onbrand-outline { background:rgba(255,255,255,.08); color:var(--white); border-color:rgba(255,255,255,.55); }
.btn--onbrand-outline:hover { background:rgba(255,255,255,.18); color:var(--white); border-color:var(--white); }
.btn--wide { width:100%; }
.btn--sm { min-height:44px; padding:.55rem 1.05rem; font-size:.95rem; }
.btn[disabled],.btn[aria-disabled="true"] { opacity:.6; cursor:not-allowed; }
.btn-row { display:flex; flex-wrap:wrap; gap:.85rem; }
.btn-row--center { justify-content:center; }

/* ---------- 6. Masthead --------------------------------------------------
   One sticky row, publication-style: logo, then rules and navigation, then a
   live availability readout. There is no separate utility bar — the phone
   number lives in the readout and in the cover, where it is bigger.
   ------------------------------------------------------------------------ */
.masthead {
  position:sticky; top:0; z-index:var(--z-nav);
  background:color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter:saturate(1.6) blur(12px);
  -webkit-backdrop-filter:saturate(1.6) blur(12px);
  border-bottom:1px solid var(--rule);
}
@supports not (backdrop-filter: blur(4px)) { .masthead { background:var(--bg); } }

.masthead__inner {
  display:flex; align-items:center; gap:clamp(1rem,3vw,2.5rem);
  min-height:76px; padding-block:.7rem;
}
.brand { display:inline-flex; align-items:center; text-decoration:none; flex:none; }
.brand__logo { display:block; height:50px; width:auto; border-radius:var(--r-sm); }
@media (max-width:480px) { .brand__logo { height:42px; } }

.masthead__nav { display:flex; align-items:center; gap:.35rem; margin-left:auto; }
.nav__link {
  font-family:Lexend,system-ui,sans-serif; font-size:.97rem; font-weight:500;
  color:var(--text); text-decoration:none; padding:.6rem .85rem;
  border-radius:var(--r-sm); position:relative;
  transition:color var(--t-fast);
}
.nav__link:hover { color:var(--brand); }
.nav__link[aria-current="page"] { color:var(--heading); font-weight:600; }
.nav__link[aria-current="page"]::after {
  content:''; position:absolute; left:.85rem; right:.85rem; bottom:.3rem;
  height:2px; background:var(--brand);
}

.masthead__end { display:flex; align-items:center; gap:.5rem; flex:none; }

/* The live readout: a dot, a state, and today's closing time. */
.readout {
  display:inline-flex; align-items:center; gap:.55rem;
  font-family:Lexend,system-ui,sans-serif; font-size:.88rem; font-weight:600;
  color:var(--heading); padding:.5rem .85rem;
  border:1px solid var(--rule); border-radius:var(--r-full);
  white-space:nowrap;
}
.readout__dot { width:9px; height:9px; border-radius:50%; background:var(--text-muted); flex:none; }
.readout[data-open="true"] .readout__dot { background:var(--ok); box-shadow:0 0 0 3px color-mix(in srgb, var(--ok) 22%, transparent); }
.readout[data-open="false"] .readout__dot { background:var(--ink-300); }
@media (max-width:1080px) { .readout { display:none; } }

.icon-btn {
  display:inline-flex; align-items:center; justify-content:center;
  width:var(--tap); height:var(--tap); flex:none;
  border:1px solid var(--rule); border-radius:var(--r-sm);
  background:transparent; color:var(--heading); cursor:pointer;
  transition:border-color var(--t-fast), color var(--t-fast);
}
.icon-btn:hover { border-color:var(--brand); color:var(--brand); }
.icon-btn svg { width:21px; height:21px; }

@media (max-width:960px) { .masthead__nav { display:none; } }

/* Theme toggle: show the icon for the mode you would switch TO. */
.theme-toggle .icon-moon { display:none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display:block; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display:none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display:block; }
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display:none; }
}


/* ---------- 7. Cover -----------------------------------------------------
   Full-bleed photograph with the headline set over it. The image is the
   panoramic shopfront, so the band keeps a wide aspect and crops rather than
   letterboxes. A gradient scrim carries the text contrast; it is opaque
   enough at the bottom-left that the type clears AA over any frame.
   ------------------------------------------------------------------------ */
.cover { position:relative; background:var(--ink-900); isolation:isolate; }
.cover__media { position:absolute; inset:0; z-index:-2; overflow:hidden; }
/* Anchored to the top, not a percentage. The shopfront signage begins 3.6% down
   the source image and its white lettering 6% down, so ANY proportional top-crop
   clips the name on a short viewport — where the image scales by width and
   overflows vertically. "top" is the only value safe at every height; the floor
   at the bottom of the frame is what gets given up instead. */
.cover__media img { width:100%; height:100%; object-fit:cover; object-position:center top; }
.cover::after {
  content:''; position:absolute; inset:0; z-index:-1;
  background:
    linear-gradient(to top, rgba(12,9,9,.94) 0%, rgba(12,9,9,.78) 34%, rgba(12,9,9,.38) 62%, rgba(12,9,9,.22) 100%),
    linear-gradient(to right, rgba(12,9,9,.72) 0%, rgba(12,9,9,.18) 58%, transparent 100%);
}
.cover__inner {
  display:flex; flex-direction:column; justify-content:flex-end;
  min-height:clamp(480px, 72vh, 720px);
  padding-block:clamp(3rem,7vw,5rem);
}
/* Narrow viewports crop into the middle of the shopfront, where the signage
   sits directly behind the headline. Darken the scrim and drop the left-in
   gradient, which does nothing once the column is full width. (There is no
   object-position override here: at phone widths the image scales by height and
   crops horizontally, so a vertical value would do nothing.) */
@media (max-width:700px) {
  .cover::after {
    background:linear-gradient(to top, rgba(12,9,9,.95) 0%, rgba(12,9,9,.88) 42%, rgba(12,9,9,.66) 74%, rgba(12,9,9,.5) 100%);
  }
  /* At phone widths the image scales by height, so there is no vertical overflow
     to crop with: the shopfront signage always occupies the top 24.5% of the
     cover (measured off the source, not estimated) and the eyebrow was sitting
     across it. The text is pushed clear instead. Because the sign's foot scales
     with the cover height, the padding has to beat 0.245 x the final height —
     which lands around 13rem at phone widths. */
  .cover__inner { padding-top:clamp(15.5rem, 62vw, 17rem); padding-bottom:2rem; }
  /* Tightening the stack lowers the cover height, which in turn lowers the
     sign's foot — the two compound, so this buys clearance twice over. */
  .cover__lede { margin-top:1rem; }
  .cover__actions { margin-top:1.35rem; }
  .cover__foot { margin-top:1.5rem; padding-top:1rem; gap:.5rem 1.25rem; }
}
.cover__eyebrow {
  display:inline-flex; align-items:center; gap:.6rem; align-self:flex-start;
  font-family:Lexend,system-ui,sans-serif; font-size:.78rem; font-weight:600;
  letter-spacing:.15em; text-transform:uppercase; color:#FFFFFF;
  background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.28);
  padding:.45rem .9rem; border-radius:var(--r-full); margin-bottom:1.5rem;
}
.cover__eyebrow svg { width:15px; height:15px; }
.cover h1 { color:#FFFFFF; max-width:15ch; }
/* 70px display type only needs 3:1, so this takes a deeper red than the small
   text on charcoal does — close to the brand --red-600 rather than a tint. */
.cover h1 em { font-style:normal; color:var(--red-500); }
.cover__lede {
  color:rgba(255,255,255,.88); font-size:clamp(1.05rem,.98rem + .5vw,1.28rem);
  line-height:1.55; max-width:46ch; margin-top:1.4rem;
}
.cover__actions { display:flex; flex-wrap:wrap; gap:.85rem; margin-top:2rem; }
.cover__foot {
  display:flex; flex-wrap:wrap; align-items:center; gap:.7rem 1.6rem;
  margin-top:2.4rem; padding-top:1.4rem;
  border-top:1px solid rgba(255,255,255,.22);
}
.cover__fact {
  display:inline-flex; align-items:center; gap:.55rem;
  color:rgba(255,255,255,.9); font-size:.97rem;
}
.cover__fact svg { width:18px; height:18px; flex:none; color:rgba(255,255,255,.7); }
.cover__fact a { color:#FFFFFF; text-decoration:none; font-weight:600; }
.cover__fact a:hover { color:#FFFFFF; text-decoration:underline; }

/* ---------- 8. Week ribbon -----------------------------------------------
   The signature component. Seven cells, one per day, today marked in brand
   red — the whole point of the store is that none of them says "closed".
   A progress line under today shows how far through the trading day it is.
   Colour is never the only signal: today's cell also carries the word TODAY
   and aria-current, and the status is written out in the readout above.
   ------------------------------------------------------------------------ */
/* The band itself stays on the page background; only the day blocks are
   charcoal. The tokens below are read by .day, which re-points --heading and
   --text-muted inside itself so the existing cell rules need no rewriting. */
.week { background:var(--bg); }

.week__inner { padding-block:clamp(1.5rem,3vw,2.25rem); }
.week__head {
  display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between;
  gap:.75rem 1.5rem; margin-bottom:1.35rem;
}
.week__title { font-family:Lexend,system-ui,sans-serif; font-weight:600; color:var(--heading); font-size:1.05rem; }
.week__note { color:var(--text-muted); font-size:.95rem; }

.week__days {
  display:grid; grid-template-columns:repeat(7,1fr); gap:.5rem;
  list-style:none; padding:0; margin:0;
}
.day {
  border:1px solid var(--block-edge); border-radius:var(--r-md);
  background:var(--block-bg); padding:.85rem .6rem .7rem; text-align:center;
  /* Charcoal block, so the text inside runs light. NOTE: --brand is deliberately
     not re-pointed here — .day[data-today] uses it as a FILL, and the deep red is
     what carries the white label at 6.2:1. */
  --heading:#F7F2F1;
  --text-muted:#B3A6A5;
  display:flex; flex-direction:column; gap:.3rem; min-height:104px;
  justify-content:center;
}
.day__name {
  font-family:Lexend,system-ui,sans-serif; font-size:.78rem; font-weight:600;
  letter-spacing:.1em; text-transform:uppercase; color:var(--text-muted);
}
.day__time { font-family:Lexend,system-ui,sans-serif; font-weight:600; color:var(--heading); font-size:.98rem; letter-spacing:-.01em; }
.day__tag { font-size:.72rem; font-weight:600; letter-spacing:.09em; text-transform:uppercase; color:transparent; }

.day[data-today="true"] { background:var(--brand); border-color:var(--brand); }
.day[data-today="true"] .day__name { color:rgba(255,255,255,.82); }
.day[data-today="true"] .day__time { color:#FFFFFF; }
.day[data-today="true"] .day__tag { color:#FFFFFF; }
:root[data-theme="dark"] .day[data-today="true"] .day__time,
:root[data-theme="dark"] .day[data-today="true"] .day__tag { color:var(--on-brand); }
:root[data-theme="dark"] .day[data-today="true"] .day__name { color:color-mix(in srgb, var(--on-brand) 78%, transparent); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .day[data-today="true"] .day__time,
  :root:not([data-theme="light"]) .day[data-today="true"] .day__tag { color:var(--on-brand); }
  :root:not([data-theme="light"]) .day[data-today="true"] .day__name { color:color-mix(in srgb, var(--on-brand) 78%, transparent); }
}

.week__progress { margin-top:1.1rem; }
.week__track { height:6px; border-radius:var(--r-full); background:var(--surface-2); overflow:hidden; border:1px solid var(--rule); }
.week__bar { height:100%; width:0%; background:var(--brand); border-radius:var(--r-full); transition:width 600ms ease; }

.week__scale { display:flex; justify-content:space-between; margin-top:.5rem; font-size:.86rem; color:var(--text-muted); }

@media (max-width:860px) {
  .week__days { grid-template-columns:repeat(4,1fr); }
}
@media (max-width:520px) {
  .week__days { grid-template-columns:repeat(2,1fr); }
  .day { min-height:88px; }
}

/* ---------- 9. Chapters --------------------------------------------------
   Numbered editorial sections. The aside sticks while the body scrolls on
   desktop; below 900px it collapses to a single column and stops sticking.
   ------------------------------------------------------------------------ */
.chapter { padding-block:clamp(2.25rem,4vw,3.5rem); border-top:1px solid var(--rule); }
.chapter--tint { background:var(--bg-alt); }
.chapter__grid { display:grid; grid-template-columns:minmax(0,5fr) minmax(0,7fr); gap:clamp(2rem,5vw,4.5rem); }
.chapter__aside { position:sticky; top:104px; align-self:start; }
.chapter__num {
  font-family:Lexend,system-ui,sans-serif; font-size:clamp(2.6rem,2rem + 2.4vw,3.9rem);
  font-weight:700; line-height:1; letter-spacing:-.04em;
  color:var(--brand); opacity:.9; margin-bottom:.6rem;
  font-variant-numeric:tabular-nums;
}
.chapter__kicker { color:var(--text-muted); margin-top:1rem; max-width:34ch; }
.chapter__body > * + * { margin-top:1.75rem; }

@media (max-width:900px) {
  .chapter__grid { grid-template-columns:1fr; gap:1.75rem; }
  .chapter__aside { position:static; }
}

/* ---------- 9a. Charcoal blocks -----------------------------------------
   Four components share this surface: the home page tiles, the send-a-script
   tool, the FAQ list and the About page's story. Defining it once means the
   treatment changes in one place. Each component keeps only its own padding
   and layout below.

   --brand IS re-pointed here, unlike in .day, because nothing inside these
   blocks uses it as a fill — only as a text or mark colour, which needs the
   lighter --red-400 to clear contrast on charcoal.
   ------------------------------------------------------------------------ */
.tile, .script-block, .faq, .story-block {
  background:var(--block-bg);
  border:1px solid var(--block-edge);
  border-radius:var(--r-lg);

  --heading:#F7F2F1;
  --text:#DFD6D5;
  --text-muted:#B3A6A5;
  --rule:rgba(255,255,255,.16);
  --brand:var(--red-400);
  --link:var(--red-400);
  --link-hover:var(--red-300);
  --cta:#5EDDCC;
  color:var(--text);
}

/* The About page's story, in the same surface. No numeral: it is the only one
   left on that page, so a "01" with nothing after it read as a stray. */
.story-block { padding:clamp(1.75rem,4vw,3.25rem); }
.story-block__grid {
  display:grid; grid-template-columns:minmax(0,5fr) minmax(0,7fr);
  gap:clamp(1.5rem,4vw,3.5rem);
}
.story-block__aside { align-self:start; }
/* 36ch, not 34: the longest line is "Park Square Pharmacy at SPAR, 2018." at
   35 characters, and at 34ch it wrapped and defeated the point of the spans. */
.story-block__kicker { color:var(--text-muted); margin-top:1rem; max-width:36ch; }
.story-block__kicker span { display:block; }
.story-block__mark {
  display:block;
  width:clamp(160px,60%,230px); height:auto;
  margin:clamp(2rem,4vw,3.25rem) auto 0;
  opacity:.9;
}
/* Stacked, the logo lands between the kicker and the body text, where it reads
   as the rule between the two — so it is sized down and the margins even out. */
@media (max-width:900px) {
  .story-block__mark { width:clamp(150px,44%,190px); margin-top:1.75rem; }
}
.story-block__body > * + * { margin-top:1.25rem; }
@media (max-width:900px) { .story-block__grid { grid-template-columns:minmax(0,1fr); gap:1.5rem; } }

/* Narrow phones: hold the kicker to one line per sentence. Buying width back
   from the block's own padding first means the type only has to drop to 14px
   instead of about 12px. Below roughly 340px the longest sentence wraps anyway
   and that is accepted — at that width there is nothing left to give. */
@media (max-width:420px) {
  .story-block { padding-left:1.35rem; padding-right:1.35rem; }
  .story-block__kicker { font-size:.875rem; }
}

/* ---------- 9b. Tiles ----------------------------------------------------
   The home page's four subjects, as a 2x2 grid instead of four full-width
   chapters — the same editorial numerals and hairlines, a quarter of the
   scrolling. The chapters themselves still run on the inner pages, where the
   detail lives.
   ------------------------------------------------------------------------ */
.tiles {
  display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(1.25rem,2.6vw,2rem);
  list-style:none; padding:0; margin:0;
}
.tile {
  padding:clamp(1.5rem,2.6vw,2.15rem);
  display:flex; flex-direction:column;
  transition:border-color var(--t-base);
}
/* A translucent hover edge would composite against the white page and vanish,
   so the hover state is the brand instead. */
.tile:hover { border-color:var(--brand); }
.tile__num {
  font-family:Lexend,system-ui,sans-serif; font-size:2.1rem; font-weight:700;
  line-height:1; letter-spacing:-.04em; color:var(--brand);
  font-variant-numeric:tabular-nums; margin-bottom:.5rem;
}
.tile h3 { font-size:clamp(1.25rem,1.1rem + .6vw,1.55rem); }
.tile__kicker { color:var(--text-muted); margin-top:.7rem; }
.tile__points {
  list-style:none; padding:0; margin:1.35rem 0 0;
  display:grid; gap:.6rem; border-top:1px solid var(--rule); padding-top:1.35rem;
}
.tile__points li { display:flex; gap:.6rem; align-items:flex-start; font-size:.98rem; }
.tile__points svg { width:18px; height:18px; flex:none; margin-top:.28rem; color:var(--cta); }
/* An odd number of tiles leaves the last one alone in its row with a hole
   beside it. Let it span instead, and run its points in two columns so the
   extra width is used rather than just stretched. This is automatic, so the
   tiles can be reordered or added to without anyone having to remember. */
.tiles .tile:last-child:nth-child(odd) { grid-column:1 / -1; }
.tiles .tile:last-child:nth-child(odd) .tile__points {
  grid-template-columns:repeat(2,minmax(0,1fr)); gap:.6rem 2rem;
}
@media (max-width:700px) {
  .tiles .tile:last-child:nth-child(odd) .tile__points { grid-template-columns:minmax(0,1fr); }
}

/* Kept for any tile that opts into spanning explicitly. Only ever the LAST
   tile — placed mid-grid it would leave a hole in the row above. */
.tile--wide { grid-column:1 / -1; }
/* Heading left, kicker right. Left to stack, a 62ch kicker under a heading
   leaves the right half of a full-width tile empty. */
.tile--wide .tile__head {
  display:grid; grid-template-columns:minmax(0,5fr) minmax(0,7fr);
  gap:clamp(1.5rem,4vw,3.5rem); align-items:start;
}
.tile--wide .tile__kicker { max-width:62ch; margin-top:0; }
@media (max-width:900px) {
  .tile--wide .tile__head { grid-template-columns:minmax(0,1fr); gap:0; }
  .tile--wide .tile__kicker { margin-top:.7rem; }
}
.tile__points--two { grid-template-columns:repeat(2,minmax(0,1fr)); gap:.6rem 2rem; }
@media (max-width:700px) { .tile__points--two { grid-template-columns:minmax(0,1fr); } }

/* The doctor's consulting hours. Visually quieter than the pharmacy's own hours
   in the week ribbon, on purpose: two different sets of hours on one page is a
   real chance to mislead someone into a wasted trip. */
.tile__hours {
  display:flex; gap:.6rem; align-items:flex-start;
  margin:1.35rem 0 0; padding-top:1.35rem;
  border-top:1px solid var(--rule);
  font-size:.94rem; color:var(--text-muted);
}
.tile__hours svg { width:18px; height:18px; flex:none; margin-top:.2rem; color:var(--brand); }
.tile__hours b { color:var(--heading); font-weight:600; }

.tile__actions {
  display:flex; flex-wrap:wrap; gap:.65rem;
  margin-top:auto; padding-top:1.5rem;
}

/* Filled buttons inside a tile.
   The tile re-points --brand to --red-400, the lighter red that stays legible
   AS TEXT on charcoal. As a BACKGROUND it is wrong: white on #F73E4C is only
   3.65:1 and fails AA. So a filled button here goes back to the real SPAR red,
   which is 6.22:1 — and it reads as the same button as the one on the cover,
   which is the point. */
.tile .btn--primary { background:var(--red-600); color:var(--white); }
.tile .btn--primary:hover { background:var(--red-700); color:var(--white); }

/* The one secondary action (tile 03's "See clinic fees") stays outlined so the
   pair keeps a hierarchy. --rule-strong is not re-pointed by the tile, so it
   would otherwise use the light-theme border on a dark surface. */
.tile .btn--outline { border-color:rgba(255,255,255,.38); color:var(--heading); }
.tile .btn--outline:hover { border-color:var(--red-400); color:var(--red-400); }

/* Below ~420px two full-width-ish buttons side by side leave ugly stubs;
   let them stack and fill instead. */
@media (max-width:420px) {
  .tile__actions { flex-direction:column; align-items:stretch; }
  .tile__actions .btn { width:100%; }
}
.tile__link {
  display:inline-flex; align-items:center; gap:.45rem;
  min-height:44px;
  font-family:Lexend,system-ui,sans-serif; font-weight:600; font-size:.98rem;
  color:var(--link); text-decoration:none; cursor:pointer;
  background:none; border:0; padding:0;
}
.tile__link:hover { color:var(--link-hover); text-decoration:underline; }
.tile__link svg { width:18px; height:18px; flex:none; transition:transform var(--t-fast); }
.tile__link:hover svg { transform:translateX(3px); }
.tile__link--plain { color:var(--text-muted); }
.tile__link--plain:hover { color:var(--brand); }

@media (max-width:820px) { .tiles { grid-template-columns:1fr; } }

/* ---------- 10. Ledger ---------------------------------------------------
   Hairline-ruled definition list. Replaces the card grid used elsewhere in
   the group: same information, no boxes.
   ------------------------------------------------------------------------ */
.ledger { margin:0; }
.ledger__row {
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.45fr);
  gap:.4rem 1.75rem; padding-block:1.05rem;
  border-top:1px solid var(--rule);
}
.ledger__row:last-child { border-bottom:1px solid var(--rule); }
.ledger dt {
  font-family:Lexend,system-ui,sans-serif; font-weight:600;
  color:var(--heading); font-size:1.02rem; letter-spacing:-.01em;
}
.ledger dd { margin:0; color:var(--text-muted); }
@media (max-width:640px) { .ledger__row { grid-template-columns:1fr; } }

/* Compact marker list used inside chapters. */
.marks { list-style:none; padding:0; margin:0; display:grid; gap:1.15rem; }
.marks li { display:flex; gap:.7rem; align-items:flex-start; }
.marks svg { width:20px; height:20px; flex:none; margin-top:.22rem; color:var(--cta); }
.marks b { display:block; font-family:Lexend,system-ui,sans-serif; font-weight:600; color:var(--heading); }
.marks span.desc { color:var(--text-muted); }

/* Pull-quote, used once or twice for emphasis. */
.pull {
  border-left:3px solid var(--brand); padding:.2rem 0 .2rem 1.35rem;
  font-family:Lexend,system-ui,sans-serif; font-size:clamp(1.1rem,1rem + .55vw,1.35rem);
  line-height:1.45; color:var(--heading); font-weight:500; letter-spacing:-.012em;
  max-width:44ch;
}

/* Key-number row. */
.figures { display:flex; flex-wrap:wrap; gap:.75rem 2.75rem; }
.figures__item { min-width:0; }
.figures__num {
  font-family:Lexend,system-ui,sans-serif; font-weight:700; color:var(--heading);
  font-size:clamp(1.6rem,1.3rem + 1.2vw,2.15rem); line-height:1.05; letter-spacing:-.03em;
}
.figures__label { color:var(--text-muted); font-size:.93rem; margin-top:.2rem; }

/* The tiles, the tool and the owners are one run, so they sit closer together
   than the site's default section rhythm. The tool is a block rather than a
   band, so the space above and below it is kept even — the default rhythm left
   it visibly off-centre, 256px above against 100px below. */
#what-we-do { padding-bottom:clamp(1.75rem,3vw,2.5rem); }
#upload-script { padding-block:clamp(1.75rem,3vw,2.5rem); }
#pharmacists { padding-top:clamp(1.75rem,3vw,2.5rem); }

/* ---------- 11. People ---------------------------------------------------
   Portraits in a row, names beneath. No cards, no hover lifts. The track count
   is auto-fit rather than fixed, so adding or removing a person (a clinic
   sister, say) needs no CSS change.
   ------------------------------------------------------------------------ */
/* Tracks are capped, not 1fr: with only two people a fr-based grid would blow
   each portrait up to half the container. justify-content keeps them left. */
.people {
  display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,268px));
  justify-content:start;
  gap:clamp(1.25rem,2.6vw,2.25rem);
  list-style:none; padding:0; margin:0;
}
.person__photo { border-radius:var(--r-lg); overflow:hidden; }
.person h3 { margin-top:1rem; font-size:1.12rem; }
.person__role { color:var(--brand); font-size:.88rem; font-weight:600; font-family:Lexend,system-ui,sans-serif; letter-spacing:.02em; margin-top:.15rem; }
.person p:not(.person__role):not(.person__reg) { color:var(--text-muted); margin-top:.6rem; font-size:.98rem; }
.person__reg { color:var(--text-muted); font-size:.86rem; margin-top:.7rem; padding-top:.7rem; border-top:1px solid var(--rule); }
@media (max-width:460px) { .people { grid-template-columns:1fr; } }

/* Wide variant: the two owners side by side, together filling the container.
   Portrait on top, detail beneath. One column below 640px. Used on the home
   page, where each has a bio popup; the About page keeps the capped grid. */
.people--wide {
  grid-template-columns:repeat(2,minmax(0,1fr));
  justify-content:stretch;
  gap:clamp(1.5rem,3.2vw,2.75rem);
  max-width:none;
}
.people--wide .person__line { color:var(--text-muted); margin-top:.7rem; max-width:52ch; }
.people--wide .person__more { margin-top:1.1rem; }
@media (max-width:640px) { .people--wide { grid-template-columns:minmax(0,1fr); } }

/* The team block: portraits on the left, the four values beside them. The
   values were their own numbered chapter; moving them here puts the promise
   next to the faces making it. */
.team-grid {
  display:grid;
  grid-template-columns:minmax(0,auto) minmax(0,1fr);
  gap:clamp(1.75rem,4vw,3.5rem);
  align-items:start;
}
.team-grid .people { grid-template-columns:repeat(2,minmax(160px,248px)); }
@media (max-width:900px) {
  .team-grid { grid-template-columns:minmax(0,1fr); gap:2rem; }
}

/* Branded, but flat: a coloured rule and a coloured mark, alternating the two
   hues the site actually has. No raised plates — see the anti-patterns. */
.values { list-style:none; padding:0; margin:0; display:grid; gap:1.1rem; }
.values__item {
  display:grid; grid-template-columns:auto minmax(0,1fr); gap:.9rem;
  padding:.9rem 0 .9rem 1.1rem;
  border-left:3px solid var(--value-accent);
}
.values__item:nth-child(odd)  { --value-accent:var(--brand); }
.values__item:nth-child(even) { --value-accent:var(--cta); }
.values__icon { color:var(--value-accent); display:flex; }
.values__icon svg { width:22px; height:22px; }
.values h3 { font-size:1.05rem; }
.values p { color:var(--text-muted); margin-top:.3rem; font-size:.97rem; }
@media (max-width:460px) {
  .values__item { grid-template-columns:minmax(0,1fr); gap:.5rem; }
}

/* ---------- 12. Figure ---------------------------------------------------
   Editorial photograph with a caption rule beneath it.
   ------------------------------------------------------------------------ */
.figure { margin:0; }
.figure figcaption, .figure__cap {
  margin-top:.8rem; padding-top:.8rem; border-top:1px solid var(--rule);
  color:var(--text-muted); font-size:.92rem;
}
.bleed { width:100vw; margin-left:calc(50% - 50vw); }
.bleed img { width:100%; height:clamp(300px,42vw,520px); object-fit:cover; }

/* ---------- 13. FAQ ------------------------------------------------------ */
/* The question list sits in a charcoal block, like the tiles and the tool, and
   re-points its tokens the same way. Each row highlights on hover and while
   open — summary is the control, so the whole row is the hit area, and the
   padding is on the summary rather than the wrapper so the highlight spans the
   full width of the block. */
.faq { padding:clamp(.5rem,1.2vw,1rem) clamp(1rem,2.4vw,1.75rem); }
.faq details { border-bottom:1px solid var(--rule); }
.faq details:last-child { border-bottom:0; }
.faq summary {
  display:flex; align-items:flex-start; justify-content:space-between; gap:1.25rem;
  padding:1.35rem clamp(.65rem,1.4vw,1rem); cursor:pointer; list-style:none;
  margin-inline:calc(clamp(.65rem,1.4vw,1rem) * -1);
  border-radius:var(--r-md);
  font-family:Lexend,system-ui,sans-serif; font-weight:600; color:var(--heading);
  font-size:clamp(1.02rem,.98rem + .3vw,1.16rem); letter-spacing:-.012em;
  min-height:var(--tap);
  transition:color var(--t-fast), background-color var(--t-fast);
}
.faq summary::-webkit-details-marker { display:none; }
.faq summary:hover { background:rgba(255,255,255,.07); color:#FFFFFF; }
.faq details[open] > summary { color:var(--brand); }
.faq summary:focus-visible { outline:3px solid var(--focus); outline-offset:-2px; }
.faq .chev { width:22px; height:22px; flex:none; margin-top:.15rem; color:var(--brand); transition:transform var(--t-base); }
.faq details[open] .chev { transform:rotate(180deg); }
/* The answer is a light panel inside the charcoal block, so it has to put back
   the tokens .faq re-points — and they are theme-dependent, the same trap as the
   form panel inside .script-block. */
.faq__body {
  background:var(--bg);
  border-radius:var(--r-md);
  padding:1.2rem clamp(1rem,2vw,1.35rem) 1.3rem;
  margin:0 0 1.1rem;
  max-width:none;

  --heading:var(--ink-800);
  --text:var(--ink-700);
  --text-muted:var(--ink-600);
  --rule:var(--ink-200);
  --brand:var(--red-600);
  --link:var(--red-700);
  --link-hover:var(--red-800);
  color:var(--text);
}
.faq__body > * + * { margin-top:.85rem; }
.faq__body p { color:var(--text); max-width:70ch; }
:root[data-theme="dark"] .faq__body {
  background:var(--surface);
  --heading:#F6F0EF;
  --text:#EDE7E6;
  --text-muted:#B7A9A8;
  --rule:#3A302F;
  --brand:var(--red-400);
  --link:var(--red-400);
  --link-hover:var(--red-300);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .faq__body {
    background:var(--surface);
    --heading:#F6F0EF;
    --text:#EDE7E6;
    --text-muted:#B7A9A8;
    --rule:#3A302F;
    --brand:var(--red-400);
    --link:var(--red-400);
    --link-hover:var(--red-300);
  }
}

/* ---------- 14. Find us ---------------------------------------------------
   The Find us section was folded into the footer (see `.footer__locate`), so
   every page carries the address and the map and the nav links are in-page.
   ------------------------------------------------------------------------ */

/* ---------- 15. Closing band ----------------------------------------------
   Removed: every page ended on one and the owner took them all out. The footer
   carries the address, hours and contact on every page, so the band was saying
   the same thing twice.
   ------------------------------------------------------------------------ */

/* ---------- 16. Footer colophon ------------------------------------------ */
/* The footer is a charcoal band. Rather than restating every rule in a dark
   variant, it re-points the tokens its components already read — so links,
   hairlines, buttons, the map frame and the compliance strip all adapt without
   being rewritten. Anything added to the footer later inherits this for free. */
.site-footer {
  background:var(--band);
  padding-block:clamp(3rem,6vw,4.5rem) 2rem;

  --heading:#F7F2F1;
  --text:#DFD6D5;
  --text-muted:#AEA09F;
  --rule:rgba(255,255,255,.13);
  --rule-strong:rgba(255,255,255,.30);
  --surface:rgba(255,255,255,.05);
  --surface-2:rgba(255,255,255,.06);
  --link:var(--red-400);
  --link-hover:var(--red-300);
  --brand:var(--red-400);
  --danger:#FF9B95;

  color:var(--text);
}

/* The wordmark is white, so the footer uses the transparent-background crop
   (assets/img/logo-banner-light.png) instead of the plated one in the header.
   See README §1e — never use it on a light surface, where it disappears.

   On charcoal the bare artwork sits flat, so it gets a plate to lift it off the
   band. The outline is white rather than red: the wordmark is already white and
   a red rule around a notice-shaped box reads as an alert. To switch it to red,
   change the border-color below to var(--brand) — nothing else needs touching. */
.footer__brand .brand {
  display:inline-flex;
  padding:.9rem 1.15rem;
  border-radius:var(--r-md);
  background:rgba(255,255,255,.06);
  border:1px solid rgba(255,255,255,.28);
  box-shadow:0 8px 22px -12px rgba(0,0,0,.7);
  transition:border-color var(--t-fast), background-color var(--t-fast);
}
.footer__brand .brand:hover { border-color:rgba(255,255,255,.5); background:rgba(255,255,255,.09); }
.footer__brand .brand__logo { background:none; height:52px; }

/* The Google embed is light and stays light: recolouring it would recolour
   Google's own logo and attribution with it. Framed so it reads as a deliberate
   panel rather than a hole in the band. */
.footer__map { box-shadow:0 10px 30px -12px rgba(0,0,0,.55); }
/* Column widths are set by the email address: it needs ~252px beside its icon,
   and a narrower Contact column breaks it mid-word. Pages is the one with slack
   — its longest item is "Services & fees" — so the width comes from there. */
.footer__grid { display:grid; grid-template-columns:minmax(0,1.8fr) minmax(0,.65fr) minmax(0,1.62fr) minmax(0,1.35fr); gap:clamp(1.75rem,3.5vw,3rem); }
@media (max-width:900px) { .footer__grid { grid-template-columns:repeat(2,minmax(0,1fr)); } }
@media (max-width:520px) { .footer__grid { grid-template-columns:1fr; } }

/* Find us, in the footer. Text left, map right; the map keeps a hairline and
   the same 16px radius as every other framed thing on the site. */
.footer__locate {
  display:grid; grid-template-columns:minmax(0,4fr) minmax(0,6fr);
  gap:clamp(1.5rem,3.5vw,3rem); align-items:center;
  padding-bottom:clamp(2.25rem,4.5vw,3rem);
  margin-bottom:clamp(2.25rem,4.5vw,3rem);
  border-bottom:1px solid var(--rule);
}
.footer__locate-text address { font-style:normal; color:var(--heading); font-size:1.08rem; font-weight:600; margin-top:.9rem; line-height:1.45; }
.footer__locate-text p { color:var(--text-muted); margin-top:.7rem; max-width:38ch; font-size:.98rem; }
.footer__locate-text .btn-row { margin-top:1.25rem; }
.footer__map { border:1px solid var(--rule); border-radius:var(--r-lg); overflow:hidden; background:var(--surface-2); }
.footer__map iframe { display:block; width:100%; height:clamp(240px,26vw,320px); border:0; }
@media (max-width:820px) {
  .footer__locate { grid-template-columns:1fr; }
  .footer__map iframe { height:260px; }
}

.footer__brand p { color:var(--text-muted); margin-top:1.1rem; max-width:40ch; font-size:.98rem; }
.footer__brand .brand__logo { height:56px; }
.site-footer h4 { font-size:.78rem; letter-spacing:.13em; text-transform:uppercase; color:var(--text-muted); font-weight:600; margin-bottom:1rem; }
.footer__list { list-style:none; padding:0; margin:0; display:grid; gap:.6rem; }
.footer__list a { color:var(--text); text-decoration:none; }
.footer__list a:hover { color:var(--brand); text-decoration:underline; }
/* Contact rows lead with their icon. align-items:flex-start, not center: the
   email address wraps to two lines on a narrow column and a centred icon would
   drift to the middle of the block. */
.footer__list--contact a { display:inline-flex; align-items:flex-start; gap:.6rem; }
.footer__list--contact svg { width:18px; height:18px; flex:none; margin-top:.28rem; color:var(--brand); }
.footer__list--contact span { min-width:0; overflow-wrap:anywhere; }
.footer__hours li { display:flex; justify-content:space-between; gap:1rem; color:var(--text-muted); font-size:.95rem; }
.footer__hours .time { color:var(--heading); font-weight:600; white-space:nowrap; }
.footer__hours li[data-today="true"] .time,
.footer__hours li[data-today="true"] span:first-child { color:var(--brand); }

.social-row { display:flex; gap:.5rem; margin-top:1.4rem; }
.social-row a {
  display:inline-flex; align-items:center; justify-content:center;
  width:var(--tap); height:var(--tap);
  border:1px solid var(--rule); border-radius:var(--r-sm); color:var(--heading);
  transition:border-color var(--t-fast), color var(--t-fast);
}
.social-row a:hover { border-color:var(--brand); color:var(--brand); }
.social-row svg { width:20px; height:20px; }

/* Registration strip. */
.compliance { margin-top:clamp(2.5rem,5vw,3.5rem); padding-top:2rem; border-top:1px solid var(--rule); }
.compliance__facts { list-style:none; padding:0; margin:0; display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,270px),1fr)); gap:1.5rem; }
.compliance__fact { display:flex; gap:.85rem; }
.compliance__icon { color:var(--brand); flex:none; }
.compliance__icon svg { width:22px; height:22px; }
.compliance__text { display:grid; gap:.15rem; min-width:0; }
.compliance__label { font-size:.76rem; letter-spacing:.12em; text-transform:uppercase; color:var(--text-muted); font-weight:600; font-family:Lexend,system-ui,sans-serif; }
.compliance__value { font-family:Lexend,system-ui,sans-serif; font-weight:600; color:var(--heading); }
.compliance__meta { font-size:.9rem; color:var(--text-muted); }
.tbc { color:var(--danger); font-weight:600; }
/* One line on desktop: no measure cap, and it wraps naturally on narrow screens. */
.compliance__note { display:flex; gap:.7rem; margin-top:1.75rem; padding-top:1.5rem; border-top:1px solid var(--rule); color:var(--text-muted); font-size:.93rem; }
/* No nowrap: forcing it would push the page into a horizontal scroll at the
   widths where it does not quite fit. The line is short enough to sit on one
   line unaided above ~1150px, and wraps cleanly below that. */
.compliance__note svg { width:19px; height:19px; flex:none; margin-top:.2rem; color:var(--cta); }

.footer__legal { margin-top:2.5rem; padding-top:1.5rem; border-top:1px solid var(--rule); display:flex; flex-wrap:wrap; gap:.6rem 1.5rem; align-items:center; justify-content:space-between; color:var(--text-muted); font-size:.9rem; }
.footer__legal nav { display:flex; gap:1.25rem; }
.footer__legal a { color:var(--text-muted); }
.footer__credit a { color:var(--text-muted); }

/* ---------- 17. Page head (inner pages) ---------------------------------- */
.page-head { padding-block:clamp(2rem,4vw,3rem) clamp(1.75rem,3.2vw,2.5rem); border-bottom:1px solid var(--rule); }
/* Page head with the actions alongside, rather than under, the intro — the
   right half was empty. Buttons stack and fill their column; bottom-aligned so
   they finish level with the last line of the intro. */
.page-head__grid {
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,clamp(15rem,24vw,18rem));
  gap:clamp(1.5rem,4vw,3.5rem);
  align-items:end;
}
.page-head__actions { display:grid; gap:.75rem; }
.page-head__actions .btn { width:100%; justify-content:flex-start; gap:.7rem; }
.page-head__grid p { margin-bottom:0; }
@media (max-width:780px) {
  .page-head__grid { grid-template-columns:minmax(0,1fr); gap:1.5rem; align-items:stretch; }
  .page-head__actions { grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr)); }
  .page-head__actions .btn { justify-content:center; }
}

.breadcrumbs { display:flex; flex-wrap:wrap; gap:.5rem; list-style:none; padding:0; margin:0 0 1.5rem; font-size:.9rem; color:var(--text-muted); }
.breadcrumbs a { color:var(--text-muted); }
.breadcrumbs li + li::before { content:'/'; margin-right:.5rem; color:var(--rule-strong); }
.page-head p { color:var(--text-muted); font-size:1.12rem; margin-top:1.1rem; max-width:58ch; }
/* Same as .opener--wide: lifts the measure where the intro should sit on one
   line. It still wraps on narrow screens; nothing is forced with nowrap. */
.page-head--wide p { max-width:none; }

/* ---------- 18. Status pill (used on photos and in the cover) ------------ */
.status {
  display:inline-flex; align-items:center; gap:.5rem;
  font-family:Lexend,system-ui,sans-serif; font-size:.9rem; font-weight:600;
  padding:.45rem .85rem; border-radius:var(--r-full);
  background:var(--surface); border:1px solid var(--rule); color:var(--heading);
}
.status svg { width:16px; height:16px; }
/* The modifiers are scoped to .status on purpose. main.js puts them on every
   [data-status] element, including the plain text readouts in the masthead and
   over the cover, which must not pick up a pill background. */
.status.status--open { background:var(--ok-soft); border-color:color-mix(in srgb, var(--ok) 40%, transparent); color:var(--ok); }
.status.status--closed { background:var(--surface-2); color:var(--text-muted); }

/* ---------- 19. Panels + steps -------------------------------------------
   The one place the editorial layout allows a box: the send-a-script tool is
   an instrument, not an article, so it gets a surface to sit on.
   ------------------------------------------------------------------------ */
.panel {
  background:var(--surface); border:1px solid var(--rule);
  border-radius:var(--r-lg); padding:clamp(1.5rem,3.2vw,2.4rem);
}
.panel--tint { background:var(--bg-alt); }

.steps { list-style:none; padding:0; margin:0; counter-reset:step; display:grid; gap:1.4rem; }
.steps li { position:relative; counter-increment:step; padding-left:3.25rem; padding-bottom:1.4rem; }
.steps li::before {
  content:counter(step,decimal-leading-zero);
  position:absolute; left:0; top:0;
  font-family:Lexend,system-ui,sans-serif; font-weight:700; font-size:1.08rem;
  color:var(--brand); letter-spacing:.02em; font-variant-numeric:tabular-nums;
}
.steps li::after {
  content:''; position:absolute; left:.6rem; top:1.9rem; bottom:.1rem; width:2px;
  background:var(--rule);
}
.steps li:last-child { padding-bottom:0; }
.steps li:last-child::after { display:none; }
.steps h3 { font-size:1.06rem; }
.steps p { color:var(--text-muted); margin-top:.35rem; }
/* ---------- 10b. Medical-aid logo marquee -------------------------------
   Two identical groups scroll as one track; translating by half the track
   width (plus half the gap between the groups) lands exactly on the seam,
   so the loop is invisible. Logo files live in assets/img/schemes/.        */
.logo-marquee {
  --marquee-gap:1rem;
  --marquee-speed:46s;
  position:relative;
  overflow:hidden;
  padding-block:.25rem;
  /* fade the strip out at both edges instead of cutting logos off hard */
  -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
          mask-image:linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
}
.logo-marquee__track {
  display:flex;
  gap:var(--marquee-gap);
  width:max-content;
  animation:marquee-scroll var(--marquee-speed) linear infinite;
}
.logo-marquee__group {
  display:flex;
  gap:var(--marquee-gap);
  list-style:none;
  margin:0;
  padding:0;
}
.logo-marquee__item {
  flex:none;
  display:grid;
  place-items:center;
  width:186px;
  height:92px;
  padding:1rem 1.25rem;
  /* the plate stays light in both themes: scheme logos are drawn for white */
  background:#FFFFFF;
  border:1px solid var(--border);
  border-radius:var(--r-md);
  box-shadow:var(--shadow-sm);
}
.logo-marquee__item img {
  max-width:100%;
  max-height:46px;
  width:auto;
  object-fit:contain;
}

@keyframes marquee-scroll {
  from { transform:translateX(0); }
  to   { transform:translateX(calc(-50% - (var(--marquee-gap) / 2))); }
}

/* Let people stop it to read a logo, by pointer or by keyboard. */
.logo-marquee:hover .logo-marquee__track,
.logo-marquee:focus-within .logo-marquee__track { animation-play-state:paused; }

/* No motion: drop the duplicate group and hand over a normal scrollable strip. */
@media (prefers-reduced-motion: reduce) {
  .logo-marquee {
    overflow-x:auto;
    -webkit-mask-image:none;
            mask-image:none;
    scrollbar-width:thin;
  }
  .logo-marquee__track { animation:none; width:auto; }
  .logo-marquee__group[aria-hidden="true"] { display:none; }
}

/* ---------- 10b-2. Medical-aid logos band ----------------------------------
   A solid brand-red band so the white logo cards stand out, rather than white
   tiles on an almost-white background. Cards are larger, logos bigger, and a
   hovered card lifts with a white glow ring (the strip pauses on hover, so the
   card stays under the pointer). Extra vertical padding stops the lift and the
   shadows being clipped by the strip. */
.logos-band { background:var(--red-600); color:#FFFFFF; }
:root[data-theme="dark"] .logos-band { background:#7A0B14; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .logos-band { background:#7A0B14; }
}
.logos-band .opener { border-top-color:rgba(255,255,255,.55); }
.logos-band .opener h2 { color:#FFFFFF; }
.logos-band .opener p { color:rgba(255,255,255,.92); }
.logos-band .opener__label { color:#FFFFFF; }
.logos-band__note { color:rgba(255,255,255,.92); }
.logos-band__note a { color:#FFFFFF; font-weight:600; }
.logos-band__note a:hover { color:#FFFFFF; text-decoration-thickness:2px; }
.logos-band :focus-visible { outline-color:#FFFFFF; }

/* The band is a strip, not a section: it carries one heading and the scroller,
   so it uses its own tighter rhythm rather than the full --section-y. */
.logos-band { padding-block:clamp(2.25rem,4.2vw,3.25rem); }
.logos-band .opener { margin-bottom:1.5rem; padding-top:.9rem; }
.logos-band .opener p { margin-top:.6rem; }
.logos-band__note { margin-top:1.35rem; }
.logos-band .logo-marquee { --marquee-gap:1.25rem; padding-block:.6rem; }
.logos-band .logo-marquee__item {
  width:224px; height:124px; padding:1.25rem 1.5rem;
  border:0; border-radius:var(--r-lg);
  box-shadow:0 14px 30px -14px rgba(40,0,6,.55);
  transition:transform var(--t-base), box-shadow var(--t-base);
}
.logos-band .logo-marquee__item img { max-height:64px; }
.logos-band .logo-marquee__item:hover {
  transform:translateY(-4px);
  box-shadow:0 0 0 4px rgba(255,255,255,.35), 0 20px 36px -14px rgba(40,0,6,.65);
}

/* ---------- 10c. Photography --------------------------------------------
   Every photo sits in a frame with a fixed aspect-ratio, so the layout is
   already the right shape before the real pictures arrive and nothing shifts
   when they land (no CLS). If a file is missing, main.js flags the frame and
   the labelled "pending" state below shows through instead of a broken image.
   Shot list: PHOTOSHOOT.md                                                  */
.photo {
  position:relative;
  overflow:hidden;
  border-radius:var(--r-lg);
  background:var(--surface-2);
  border:1px solid var(--border);
}
.photo img {
  display:block;
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:center;
}
.photo--3x2  { aspect-ratio:3 / 2; }
.photo--4x3  { aspect-ratio:4 / 3; }
.photo--1x1  { aspect-ratio:1 / 1; }
.photo--16x9 { aspect-ratio:16 / 9; }

/* pending state — visible only while the photo file is absent */
.photo__pending {
  position:absolute; inset:0;
  display:flex;
  flex-direction:column; align-items:center; justify-content:center;
  gap:.6rem; padding:1.25rem; text-align:center;
  background:
    repeating-linear-gradient(45deg,
      var(--surface-2) 0 12px, var(--bg-alt) 12px 24px);
  color:var(--text-muted);
}
.photo[data-loaded="true"] .photo__pending { display:none; }
/* A real photo needs no frame: the outline and tint are only for the pending state. */
.photo[data-loaded="true"] { border:0; background:none; box-shadow:none; }

.photo__pending svg { width:30px; height:30px; opacity:.5; }
.photo__pending b {
  font-family:Lexend,system-ui,sans-serif; font-size:.95rem;
  font-weight:600; color:var(--heading); display:block;
}
.photo__pending span { font-size:.85rem; max-width:30ch; }
.photo__pending code {
  font-size:.78rem; letter-spacing:.02em;
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-sm); padding:.15rem .45rem; color:var(--text-muted);
}

/* caption under a framed photo */
.photo-figure { margin:0; }
.photo-figure figcaption {
  margin-top:.7rem; font-size:.9rem; color:var(--text-muted); text-align:left;
}

/* status pill floated over the hero photo */
.photo__overlay {
  position:absolute; left:1rem; bottom:1rem; right:1rem;
  display:flex; flex-wrap:wrap; gap:.5rem;
}
.photo__overlay .status {
  background:var(--surface);
  box-shadow:var(--shadow-md);
  border-color:var(--border);
}
.photo__overlay .status--open { background:var(--ok-soft); border-color:var(--ok); }

/* premises gallery — one feature shot plus five supporting ones */
.gallery { display:grid; gap:clamp(.75rem,1.6vw,1rem); grid-template-columns:1fr; }
/* Four frames: the feature runs the full width at 16:9, the other three sit in
   a row beneath. The old rule spanned the feature 2x2 for a six-photo set; with
   four that left two holes in the last row. */
@media (min-width: 720px) {
  .gallery { grid-template-columns:repeat(3, 1fr); }
  .gallery > .photo { aspect-ratio:4 / 3; }
  .gallery > .photo:first-child { grid-column:1 / -1; aspect-ratio:16 / 9; }
}

/* Team portraits. Editorial: a full-width 4:5 plate, not a small circle, so
   the owners read as a row of portraits rather than avatars. */
.person__photo.photo {
  width:100%; aspect-ratio:4 / 5; border-radius:var(--r-lg);
  margin:0; padding:0; overflow:hidden; display:block;
}
.person__photo.photo .photo__pending { gap:.35rem; padding:.75rem; }
.person__photo.photo .photo__pending svg { display:none; }
.person__photo.photo .photo__pending b {
  font-size:clamp(1.8rem,1.4rem + 1.2vw,2.4rem); letter-spacing:-.03em; color:var(--brand);
}
.person__photo.photo .photo__pending span { font-size:.8rem; }
.person__photo.photo .photo__pending code { display:none; }

/* ---------- 14. Tables --------------------------------------------------- */
.table-wrap { overflow-x:auto; border:1px solid var(--border); border-radius:var(--r-lg); background:var(--surface); }
table { border-collapse:collapse; width:100%; min-width:520px; font-size:.98rem; }
caption { text-align:left; padding:1rem 1.15rem; color:var(--text-muted); font-size:.92rem; }
th,td { padding:.9rem 1.15rem; text-align:left; border-bottom:1px solid var(--border); }
thead th {
  font-family:Lexend,system-ui,sans-serif; font-size:.85rem; font-weight:600;
  text-transform:uppercase; letter-spacing:.06em;
  color:var(--text-muted); background:var(--bg-alt);
}
tbody tr:last-child td { border-bottom:0; }
td.price { font-variant-numeric:tabular-nums; font-weight:600; color:var(--heading); white-space:nowrap; }

/* ---------- 15. Forms ---------------------------------------------------- */
.form { display:grid; gap:1.15rem; }
.field { display:grid; gap:.4rem; }
.field label { font-family:Lexend,system-ui,sans-serif; font-weight:600; font-size:.94rem; color:var(--heading); }
.field .hint { font-size:.87rem; color:var(--text-muted); }
.field .req { color:var(--danger); }
.input, .field select, .field textarea {
  width:100%; min-height:var(--tap); padding:.7rem .9rem;
  font-family:inherit; font-size:1rem; color:var(--text);
  background:var(--surface); border:1px solid var(--field-edge); border-radius:var(--r-md);
  transition:border-color var(--t-fast), box-shadow var(--t-fast);
}
.field textarea { min-height:9rem; resize:vertical; line-height:1.6; }
.input:hover, .field select:hover, .field textarea:hover { border-color:var(--heading); }
.input:focus-visible, .field select:focus-visible, .field textarea:focus-visible { border-color:var(--focus); }
.input[aria-invalid="true"], .field textarea[aria-invalid="true"], .field select[aria-invalid="true"] {
  border-color:var(--danger); background:var(--danger-soft);
}
.field .error { display:none; align-items:center; gap:.4rem; color:var(--danger); font-size:.9rem; font-weight:600; }
.field .error svg { width:16px; height:16px; flex:none; }
.field .error[data-visible="true"] { display:flex; }

.checkbox { display:flex; gap:.75rem; align-items:flex-start; }
.checkbox input { width:22px; height:22px; margin-top:.28rem; flex:none; accent-color:var(--brand); cursor:pointer; }
.checkbox label { font-family:inherit; font-weight:400; font-size:.95rem; color:var(--text-muted); line-height:1.55; cursor:pointer; }

.form-note {
  display:flex; gap:.65rem; align-items:flex-start;
  padding:.9rem 1rem; border-radius:var(--r-md);
  background:var(--bg-alt); border:1px solid var(--field-edge);
  font-size:.92rem; color:var(--text-muted);
}
.form-note svg { width:20px; height:20px; flex:none; color:var(--cta); margin-top:.1rem; }

.form-status { display:none; padding:1rem 1.15rem; border-radius:var(--r-md); font-weight:600; }
.form-status[data-state="success"] { display:block; background:var(--ok-soft); color:var(--ok); border:1px solid var(--ok); }
.form-status[data-state="error"] { display:block; background:var(--danger-soft); color:var(--danger); border:1px solid var(--danger); }

/* ---------- 15b. Send a script -----------------------------------------
   The real file input covers the whole drop zone, so tapping anywhere opens
   the camera or picker and keyboard focus lands on a genuine control.       */
fieldset.field { border:0; margin:0; padding:0; min-width:0; }
.field legend {
  font-family:Lexend,system-ui,sans-serif; font-weight:600; font-size:.94rem;
  color:var(--heading); padding:0; margin-bottom:.4rem;
}

.field .upload-zone {
  position:relative;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:.55rem; min-height:188px; padding:1.5rem 1.25rem;
  border:2px dashed var(--field-edge); border-radius:var(--r-lg);
  background:var(--bg-alt); text-align:center; cursor:pointer;
  font-family:inherit; font-weight:400; color:var(--text-muted);
  transition:border-color var(--t-fast), background-color var(--t-fast);
}
.upload-zone:hover { border-color:var(--brand); }
.upload-zone:focus-within { border-color:var(--focus); outline:3px solid var(--focus); outline-offset:2px; }
.upload-zone[data-has-file="true"] { border-style:solid; border-color:var(--ok); background:var(--surface); }
.upload-zone:has(input[aria-invalid="true"]) { border-color:var(--danger); background:var(--danger-soft); }
.upload-zone input[type="file"] {
  position:absolute; inset:0; width:100%; height:100%;
  opacity:0; cursor:pointer;
}
.upload-zone__icon {
  display:grid; place-items:center; width:60px; height:60px;
  border-radius:var(--r-full); background:var(--surface); color:var(--brand);
  box-shadow:var(--shadow-sm);
}
.upload-zone__icon svg { width:28px; height:28px; }
.upload-zone__title { font-family:Lexend,system-ui,sans-serif; font-weight:600; font-size:1.02rem; color:var(--heading); }
.upload-zone__hint { font-size:.9rem; }

.upload-preview {
  display:flex; align-items:center; gap:.9rem; padding:.75rem;
  border:1px solid var(--field-edge); border-radius:var(--r-md); background:var(--surface);
}
.upload-preview img {
  width:64px; height:84px; flex:none; object-fit:cover;
  border:1px solid var(--border); border-radius:var(--r-sm);
}
.upload-preview__meta {
  flex:1; min-width:0; display:grid; gap:.1rem;
  font-size:.9rem; color:var(--text-muted); overflow-wrap:anywhere;
}
.upload-preview__meta strong { color:var(--ok); }

.choice-row { display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%, 150px), 1fr)); gap:.6rem; }
.field .choice {
  display:flex; align-items:center; gap:.6rem;
  min-height:var(--tap); padding:.7rem 1rem;
  border:1px solid var(--field-edge); border-radius:var(--r-md); background:var(--surface);
  font-family:inherit; font-weight:600; font-size:.98rem; color:var(--text);
  cursor:pointer; transition:border-color var(--t-fast), background-color var(--t-fast);
}
.choice input { width:20px; height:20px; margin:0; flex:none; accent-color:var(--brand); cursor:pointer; }
.choice:has(input:checked) { border-color:var(--brand); background:var(--brand-soft); color:var(--brand-strong); }
.choice:focus-within { outline:3px solid var(--focus); outline-offset:2px; }

/* Send a script, stacked: intro and steps on top, form centred below. On wider
   screens the steps run across in a row so the section does not grow too tall. */
/* The send-a-script tool sits in a charcoal block, like the day cells and the
   tiles. Text inside runs light; the form itself keeps a light surface, because
   inputs need to read as inputs rather than as part of the block. */
.script-block { padding:clamp(1.75rem,4vw,3.25rem); }
/* The note above the form is an aside on the block, not a panel on the page. */
.script-block .upload-stack__note {
  background:rgba(255,255,255,.06);
  border-color:rgba(255,255,255,.16);
}
/* The form panel returns to page colours so the fields look like fields. The
   .script-block above re-points eight text tokens for charcoal; the panel has to
   put all eight back, and they are theme-dependent — writing the light inks here
   unconditionally rendered the labels dark-on-dark in dark mode. */
.script-block .panel {
  --heading:var(--ink-800);
  --text:var(--ink-700);
  --text-muted:var(--ink-600);
  --rule:var(--ink-200);
  --brand:var(--red-600);
  --link:var(--red-700);
  --link-hover:var(--red-800);
  --cta:var(--teal-700);
  color:var(--text);
  background:var(--bg);
  border-color:var(--border);
}
:root[data-theme="dark"] .script-block .panel {
  --heading:#F6F0EF;
  --text:#EDE7E6;
  --text-muted:#B7A9A8;
  --rule:#3A302F;
  --brand:var(--red-400);
  --link:var(--red-400);
  --link-hover:var(--red-300);
  --cta:#5EDDCC;
  background:var(--surface);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .script-block .panel {
    --heading:#F6F0EF;
    --text:#EDE7E6;
    --text-muted:#B7A9A8;
    --rule:#3A302F;
    --brand:var(--red-400);
    --link:var(--red-400);
    --link-hover:var(--red-300);
    --cta:#5EDDCC;
    background:var(--surface);
  }
}

.upload-stack { display:grid; gap:clamp(1.75rem,3.5vw,2.5rem); }
.upload-stack .opener { margin-bottom:clamp(1.5rem,3vw,2.25rem); }
.upload-stack__intro { width:100%; max-width:980px; margin-inline:auto; }
.upload-stack__form { width:100%; max-width:760px; margin-inline:auto; }
.upload-stack__note { margin-bottom:1rem; }

@media (min-width: 720px) {
  .steps--row { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:1.5rem; margin-top:0; }
  .steps--row li { padding-left:0; padding-top:3.25rem; padding-bottom:0; }
  /* the connector runs sideways to the next number instead of downwards */
  .steps--row li::after { top:1.12rem; bottom:auto; left:2.85rem; right:-1.25rem; width:auto; height:2px; }
}

@media (min-width: 640px) {
  #script-form { grid-template-columns:repeat(2, minmax(0, 1fr)); column-gap:1rem; }
  #script-form > * { grid-column:1 / -1; }
  #script-form > .field:has(#script-name),
  #script-form > .field:has(#script-phone) { grid-column:auto; }
}

/* Wide screens: the form spreads across the page in three columns to cut its
   height. Photo on the left running down beside the fields; name and phone,
   then collect/deliver, then notes on the right; consent across the full width,
   then the privacy note with the send button beside it. "dense" lets the button
   slot in beside the privacy note even though it comes last in the markup, and
   the optional delivery-address row simply adds one more row on the right. */
@media (min-width: 1000px) {
  .upload-stack__form { max-width:none; }
  #script-form {
    grid-template-columns:repeat(3, minmax(0, 1fr));
    column-gap:1.25rem;
    grid-auto-flow:row dense;
  }
  #script-form > * { grid-column:2 / -1; }
  #script-form > .field:has(#script-photo) {
    grid-column:1; grid-row:1 / span 3;
    display:flex; flex-direction:column; gap:.5rem;
  }
  #script-form > .field:has(#script-photo) .upload-zone { flex:1; min-height:0; }
  #script-form > .field:has(#script-name) { grid-column:2; }
  #script-form > .field:has(#script-phone) { grid-column:3; }
  /* consent runs the full width on one line; privacy note and button share the row below */
  #script-form > .field:has(#script-consent) { grid-column:1 / -1; }
  #script-form > .form-note { grid-column:1 / span 2; }
  #script-form > button[type="submit"] { grid-column:3; align-self:center; }
  #script-form textarea { min-height:5.5rem; }
}

/* ---------- 19. Floating buttons ---------------------------------------- */
:root { --float-inset:1.1rem; --float-size:56px; --tabbar-h:64px; --tabbar-space:0px; }

.wa-float {
  position:fixed; right:var(--float-inset); bottom:calc(var(--float-inset) + var(--tabbar-space)); z-index:var(--z-float);
  display:inline-flex; align-items:center; gap:.6rem;
  min-height:56px; padding:.75rem 1.25rem;
  /* Brand red rather than WhatsApp green; the icon still says WhatsApp.
     White on #C1121F is 5.9:1. A soft ring pulses out to draw the eye. */
  background:#C1121F; color:#FFFFFF;
  border-radius:var(--r-full); box-shadow:var(--shadow-lg);
  font-family:Lexend,system-ui,sans-serif; font-weight:600; font-size:.97rem;
  text-decoration:none; cursor:pointer;
  transition:background-color var(--t-fast);
  animation:wa-pulse 2s ease-out infinite;
}
.wa-float:hover { background:#9B0E19; color:#FFFFFF; }
/* Stop pulsing once someone is pointing at it or has tabbed to it. */
.wa-float:hover, .wa-float:focus-visible { animation:none; }
@keyframes wa-pulse {
  0%   { box-shadow:0 0 0 0 rgba(193,18,31,.55), var(--shadow-lg); }
  70%  { box-shadow:0 0 0 16px rgba(193,18,31,0), var(--shadow-lg); }
  100% { box-shadow:0 0 0 0 rgba(193,18,31,0), var(--shadow-lg); }
}
@media (prefers-reduced-motion: reduce) { .wa-float { animation:none; } }
.wa-float svg { width:26px; height:26px; flex:none; }
@media (max-width:520px) { .wa-float__label { display:none; } .wa-float { padding:.85rem; } }

/* Back to top — injected by main.js, since it cannot work without JS.
   Sits directly above the WhatsApp button so the two never overlap. */
.to-top {
  position:fixed; z-index:var(--z-float);
  right:var(--float-inset);
  bottom:calc(var(--float-inset) + var(--float-size) + .65rem + var(--tabbar-space));
  display:inline-flex; align-items:center; justify-content:center;
  width:48px; height:48px;
  background:var(--surface); color:var(--heading);
  border:1px solid var(--border); border-radius:var(--r-full);
  box-shadow:var(--shadow-md);
  cursor:pointer;
  /* hidden by default: not visible, and not reachable by Tab */
  opacity:0; visibility:hidden; transform:translateY(8px);
  transition:opacity var(--t-base), transform var(--t-base),
             visibility var(--t-base), background-color var(--t-fast),
             border-color var(--t-fast), color var(--t-fast);
}
.to-top[data-visible="true"] { opacity:1; visibility:visible; transform:none; }
.to-top:hover { background:var(--brand-soft); border-color:var(--border-brand); color:var(--brand-strong); }
.to-top svg { width:24px; height:24px; }
@media (prefers-reduced-motion: reduce) { .to-top { transition:none; } }

/* ---------- 19a. Branded popup (services & fees) --------------------------
   Native <dialog>: the browser provides the focus trap, Esc to close and
   focus return. Full screen on phones.                                      */
.modal {
  --modal-band:#C1121F;
  width:min(56rem, calc(100% - 2rem)); max-width:none;
  max-height:min(88vh, 60rem);
  margin:auto; /* the global reset zeroes margins, which would pin the dialog top-left */
  padding:0; border:0; border-radius:var(--r-lg);
  background:var(--surface); color:var(--text);
  box-shadow:var(--shadow-lg); overflow:hidden;
}
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .modal { --modal-band:#7A0B14; } }
:root[data-theme="dark"] .modal { --modal-band:#7A0B14; }
.modal[open] { display:flex; flex-direction:column; animation:modal-in .22s ease-out; }
.modal::backdrop { background:rgba(20,12,12,.62); backdrop-filter:blur(3px); }
@keyframes modal-in { from { opacity:0; transform:translateY(12px) scale(.98); } to { opacity:1; transform:none; } }
html.modal-open { overflow:hidden; }

.modal__band {
  position:relative; flex:none;
  display:flex; align-items:center; gap:1rem;
  padding:1.1rem 4.25rem 1.1rem 1.25rem;
  background:var(--modal-band);
  background-image:radial-gradient(circle at 100% 0, rgba(255,255,255,.16), transparent 55%);
  color:#fff;
}
.modal__logo { flex:none; width:auto; height:52px; border-radius:var(--r-md); box-shadow:0 0 0 2px rgba(255,255,255,.85); }
.modal__eyebrow {
  display:block; font-family:Lexend,system-ui,sans-serif; font-size:.78rem; font-weight:600;
  letter-spacing:.08em; text-transform:uppercase; color:#FFE3E5;
}
.modal__band h2 { margin:0; color:#fff; font-size:clamp(1.3rem, 2.6vw, 1.7rem); line-height:1.2; }
.modal__close {
  position:absolute; top:50%; right:.9rem; transform:translateY(-50%);
  display:inline-flex; align-items:center; justify-content:center;
  width:44px; height:44px; cursor:pointer;
  background:rgba(255,255,255,.12); color:#fff;
  border:1px solid rgba(255,255,255,.5); border-radius:var(--r-full);
  transition:background-color var(--t-fast), color var(--t-fast);
}
.modal__close:hover { background:#fff; color:var(--modal-band); }
.modal__close:focus-visible { outline:3px solid #fff; outline-offset:2px; }
.modal__close svg { width:22px; height:22px; }

.modal__body {
  flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior:contain;
  display:grid; gap:1.15rem; padding:1.25rem;
}
.modal__label { margin:0 0 .5rem; font-family:Lexend,system-ui,sans-serif; font-weight:600; font-size:.95rem; color:var(--heading); }
.modal__intro { margin:0; color:var(--text-muted); }
.modal__chips { list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:.5rem; }
.modal__chips li {
  display:inline-flex; align-items:center; gap:.4rem;
  padding:.4rem .8rem; border-radius:var(--r-full);
  background:var(--brand-soft); color:var(--brand-strong); border:1px solid var(--border-brand);
  font-weight:600; font-size:.92rem;
}
.modal__chips svg { width:16px; height:16px; }
.modal th, .modal td { padding:.7rem 1rem; }

/* Long-form variant (privacy notice): narrower, for comfortable reading. */
.modal--doc { width:min(46rem, calc(100% - 2rem)); }
.modal__doc { display:block; line-height:1.65; }
.modal__doc section + section { margin-top:1.5rem; padding-top:1.5rem; border-top:1px solid var(--border); }
.modal__doc h3 { margin:0 0 .5rem; font-size:1.08rem; color:var(--heading); }
.modal__doc p { margin:0; color:var(--text); }
.modal__doc p + p, .modal__doc ul + p, .modal__doc p + ul, .modal__doc p + address, .modal__doc address + p { margin-top:.75rem; }
.modal__doc ul { margin:0; padding-left:1.2rem; display:grid; gap:.5rem; }
.modal__doc li::marker { color:var(--brand); }
.modal__meta { font-size:.9rem; color:var(--text-muted) !important; margin-bottom:1.25rem !important; }
.modal__address {
  font-style:normal; padding:.9rem 1.1rem; border-radius:var(--r-md);
  background:var(--bg-alt); border:1px solid var(--border);
}
/* Without JS the footer link targets #privacy-notice, so show it as a page.
   Scoped to no-JS: with JS the popup opens properly, and :target can stay
   stuck after the hash is cleared, which would leave a closed popup showing. */
html:not(.modal-js) .modal:target:not([open]) {
  display:flex; flex-direction:column; position:fixed; inset:0; z-index:100;
  margin:auto; max-height:calc(100% - 2rem);
}

.modal__foot {
  flex:none; display:flex; flex-wrap:wrap; justify-content:flex-end; gap:.75rem;
  padding:1rem 1.25rem calc(1rem + env(safe-area-inset-bottom));
  border-top:1px solid var(--border); background:var(--bg-alt);
}
@media (max-width:560px) {
  .modal { width:100%; height:100%; max-height:none; margin:0; inset:0; border-radius:0; }
  .modal__logo { height:40px; }
  .modal__foot .btn { flex:1 1 100%; }
  /* Fee table becomes a list: service and fee on one line, notes underneath. */
  .modal table { min-width:0; }
  .modal thead { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
  .modal tbody tr {
    display:grid; grid-template-columns:1fr auto; column-gap:1rem;
    padding:.75rem 1rem; border-bottom:1px solid var(--border);
  }
  .modal tbody tr:last-child { border-bottom:0; }
  .modal tbody th, .modal tbody td { padding:0; border:0; }
  .modal tbody td:last-child { grid-column:1 / -1; margin-top:.2rem; color:var(--text-muted); font-size:.9rem; }
}
@media (prefers-reduced-motion: reduce) { .modal[open] { animation:none; } .modal__close { transition:none; } }

/* Service detail popups: plain prose and ledgers, no portrait column. */
.modal--detail .modal__body > * + * { margin-top:1.25rem; }
.modal--detail .modal__intro { font-size:1.08rem; color:var(--heading); }

/* Bio popups: portrait beside the detail, inside the same branded shell as the
   services popup. One column below 640px so the portrait never squeezes. */
.modal--bio .bio__grid {
  display:grid; grid-template-columns:minmax(0,210px) minmax(0,1fr);
  gap:clamp(1.25rem,3vw,2.25rem); align-items:start;
}
/* The aside sticks while a long biography scrolls past it, so the portrait and
   the registration details stay in view rather than scrolling away at the top. */
.modal--bio .bio__aside { position:sticky; top:0; }
.modal--bio .bio__photo { width:100%; aspect-ratio:4/5; border-radius:var(--r-lg); overflow:hidden; }
.modal--bio .bio__photo img { width:100%; height:100%; object-fit:cover; }
.modal--bio .bio__facts { margin:1.25rem 0 0; }
.modal--bio .bio__facts > div { padding-block:.6rem; border-top:1px solid var(--rule); }
.modal--bio .bio__facts > div:last-child { border-bottom:1px solid var(--rule); }
.modal--bio .bio__facts dt {
  font-family:Lexend,system-ui,sans-serif; font-size:.7rem; font-weight:600;
  letter-spacing:.11em; text-transform:uppercase; color:var(--text-muted);
}
.modal--bio .bio__facts dd { margin:.15rem 0 0; color:var(--heading); font-weight:600; font-size:.95rem; line-height:1.4; }
.modal--bio .bio__body > * + * { margin-top:1rem; }
.modal--bio .bio__body p { color:var(--text-muted); max-width:62ch; }
.modal--bio .modal__intro { font-size:1.1rem; color:var(--heading); }
.modal--bio .bio__close {
  margin-top:1.4rem; padding-top:1.2rem; border-top:1px solid var(--rule);
  font-family:Lexend,system-ui,sans-serif; font-size:1.02rem;
  color:var(--heading); font-weight:500; letter-spacing:-.01em;
}
@media (max-width:640px) {
  .modal--bio .bio__grid { grid-template-columns:minmax(0,1fr); }
  .modal--bio .bio__aside { position:static; }
  .modal--bio .bio__photo { max-width:190px; }
}

/* ---------- 19b. Mobile tab bar -----------------------------------------
   Replaces the header links at 960px and below. Page content and the floating
   buttons are lifted by --tabbar-space so nothing ever sits underneath it.  */
.tabbar { display:none; }

@media (max-width: 960px) {
  :root { --tabbar-space:calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px)); }
  body { padding-bottom:var(--tabbar-space); }

  .tabbar {
    display:block;
    position:fixed; left:0; right:0; bottom:0; z-index:var(--z-nav);
    background:var(--surface);
    border-top:1px solid var(--border);
    box-shadow:0 -6px 18px -10px rgba(25,22,22,.18);
    padding-bottom:env(safe-area-inset-bottom, 0px);
  }
  .tabbar__list {
    display:grid; grid-template-columns:repeat(4, minmax(0, 1fr));
    max-width:640px; margin:0 auto; padding:0; list-style:none;
  }
  .tabbar__link {
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    gap:.2rem; min-height:var(--tabbar-h); padding:.35rem .15rem;
    font-family:Lexend,system-ui,sans-serif; font-size:.8125rem; font-weight:500;
    line-height:1.1; text-align:center;
    color:var(--text-muted); text-decoration:none;
    transition:color var(--t-fast);
  }
  .tabbar__link svg { width:24px; height:24px; flex:none; }
  .tabbar__link:hover { color:var(--heading); }
  .tabbar__link[aria-current="page"] { color:var(--brand); font-weight:600; }
  .tabbar__link--primary { color:var(--heading); font-weight:600; }
  .tabbar__icon {
    display:grid; place-items:center;
    width:48px; height:30px; border-radius:var(--r-full);
    background:var(--brand); color:var(--on-brand);
  }
  .tabbar__icon svg { width:20px; height:20px; }
}

/* ---------- 20b. Portrait entrance and tilt ------------------------------
   The same recipe used on the two doctor sites, dialled back for this one: the
   frame clips open from the bottom while the photograph settles back from a
   slight push-in, then the portrait follows the pointer a few degrees with a
   sheen tracking the cursor. Two rates rather than one is what makes the
   entrance read as a camera settling instead of a wipe.

   No spinning ring or floating chips here — those belong to the sites that use
   them. This page is hairlines and whitespace, so the motion is the whole
   effect. All of it is off under prefers-reduced-motion (section 21).
   ------------------------------------------------------------------------ */
.person__photo { will-change:transform; transform-style:preserve-3d; }

/* The card's own fade-up stands down; the clip and settle carry the entrance,
   and running both would have the portrait drifting while it unveils. */
.person.reveal { opacity:1; transform:none; transition:none; }

.person.reveal .person__photo {
  /* Overshooting the insets means the clip finishes outside the frame, so the
     rounded corners are never shaved mid-animation. */
  clip-path:inset(calc(100% + 40px) -40px -40px -40px);
  transition:clip-path 900ms cubic-bezier(0.77, 0, 0.175, 1) var(--pd, 0ms);
}
.person.reveal .person__photo img {
  transform:scale(1.10);
  transform-origin:50% 28%;   /* pulls back from the face, not the frame centre */
  transition:transform 1300ms cubic-bezier(0.23, 1, 0.32, 1) var(--pd, 0ms);
}
.person.reveal[data-shown="true"] .person__photo { clip-path:inset(-40px); }
.person.reveal[data-shown="true"] .person__photo img { transform:none; }

/* The name and role arrive just behind their portrait. */
.person.reveal h3, .person.reveal .person__role,
.person.reveal p:not(.person__role), .person.reveal .person__reg {
  opacity:0; transform:translateY(8px);
  transition:opacity 420ms ease calc(var(--pd, 0ms) + 420ms),
             transform 420ms cubic-bezier(0.23, 1, 0.32, 1) calc(var(--pd, 0ms) + 420ms);
}
.person.reveal[data-shown="true"] h3,
.person.reveal[data-shown="true"] .person__role,
.person.reveal[data-shown="true"] p:not(.person__role),
.person.reveal[data-shown="true"] .person__reg { opacity:1; transform:none; }

/* Staggered so the row reads left to right rather than landing as a block. */
.people .person:nth-child(2) { --pd:140ms; }
.people .person:nth-child(3) { --pd:280ms; }
.people .person:nth-child(4) { --pd:420ms; }

/* A sheen that follows the cursor, faded in only while tilting so the portrait
   is clean at rest. */
.person__photo .glare {
  position:absolute; inset:0; z-index:3; pointer-events:none;
  background:radial-gradient(circle at var(--gx,50%) var(--gy,30%),
    rgba(255,255,255,.26), transparent 52%);
  opacity:0; transition:opacity 300ms ease;
}
.person__photo.is-tilting .glare { opacity:1; }

@media (prefers-reduced-motion: reduce) {
  .person.reveal .person__photo,
  .person.reveal[data-shown="true"] .person__photo { clip-path:none; transition:none; }
  .person.reveal .person__photo img { transform:none; transition:none; }
  .person.reveal h3, .person.reveal .person__role,
  .person.reveal p:not(.person__role), .person.reveal .person__reg {
    opacity:1; transform:none; transition:none;
  }
  .person__photo .glare { display:none; }
}

/* ---------- 21. Motion --------------------------------------------------- */
.reveal { opacity:0; transform:translateY(14px); transition:opacity 420ms ease, transform 420ms ease; }
.reveal[data-shown="true"] { opacity:1; transform:none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity:1 !important; transform:none !important; transition:none !important; }
  *,*::before,*::after { animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important; }
}

/* ---------- 22. Print ---------------------------------------------------- */
@media print {
  .site-header, .utility-bar, .wa-float, .to-top, .tabbar, .cta-band { display:none !important; }
  body { font-size:12pt; color:#000; background:#fff; padding-bottom:0; }
  a[href^="http"]::after { content:" (" attr(href) ")"; font-size:9pt; }
}
