/* ═══════════════════════════════════════════════════════════════════════════
   STEP 1 — DESIGN TOKENS
   Scoped to .landing, never :root. portal.php loads this same stylesheet, so
   a :root override would drag the tooth chart and the billing tables with it.
   ═══════════════════════════════════════════════════════════════════════════ */
.landing {
    /* ── Canvases: three warm grounds, used as a rhythm, not an alternation ── */
    /* The page ground: marble as a COLOUR, warm and close to white. The real
       marble texture is used too, but only on #services, where the rows sit on
       a glass panel that keeps text legible over the veining. Everywhere else
       the stone is this flat tone — body copy laid straight on a photographed
       texture stops being comfortable to read, and the section that needs the
       material most is the one that gets it. */
    --canvas:       #FAF7F1;   /* the marble, as a colour */
    --canvas-deep:  #F2ECE1;   /* recessed bands — cards float above this */
    --canvas-lift:  #FFFFFF;   /* cards and panels */

    /* ── The storefront ─────────────────────────────────────────────────────
       The hero photograph, and the whole reason the page opens the way it
       does. The path is relative to THIS FILE, so it climbs out of css/ first.
       Sized by tools/make-hero-image.php (2.3 MB source down to ~312 KB).
       Without this token .hero paints white text onto bare cream and the
       headline all but disappears — if the hero ever looks blank, check here
       before anything else. */
    --hero-photo:   url("../images/clinic-hero.jpg");

    /* ── Ink ── */
    /* The clinic's charcoal #434746, deepened for body copy and lifted for
       secondary. Replaces the navy that was here — the navy came from
       nowhere in particular, this comes off her own shopfront. */
    --ink:          #2F3331;   /* 11.98:1 on marble */
    --ink-2:        #5C6360;   /* 5.76:1 — secondary copy, still AA */
    --ink-3:        #8B918E;   /* non-text only: rules, disabled marks */

    /* Dark surfaces: the top bar, the walk-in card, the closing band. Their
       charcoal proper, with a deeper step for the footer. */
    --band:         #333736;
    --band-deep:    #282B2A;

    /* ── Accents, taken from the clinic itself ──────────────────────────────
       The whole palette below is sampled from her shopfront: the amber of the
       signage, the sand of the marble, the brown of the slatted wall, the gold
       of her tooth mark, and the charcoal of the frames. Nothing here was
       chosen because it looked nice in the abstract.

       ONE action colour. Every button, link and interactive affordance on the
       page is brown and nothing else is — that single rule, not the hue, is
       the mechanism behind "the buttons are easy to find".

       The clinic's brown deepened: #A6754B as supplied puts a white label at
       3.99:1, under AA. The fill drops to #8A5F3A, which reads 5.56:1
       white-on-fill and 5.20:1 as an object. Same hue, same wood, legible. */
    --brand:        #8A5F3A;
    --brand-deep:   #6F4B2D;   /* hover */
    --brand-wash:   #F3EBE1;   /* tinted fills */

    /* Amber and gold are her signage and her tooth mark, and on marble they
       measure 1.89:1 and 1.49:1 — they cannot be text and cannot be a button.
       They are a 1px rule, a dot, an underline, and nothing else on a light
       ground. On the charcoal band gold reads 5.92:1, and there it is a real
       colour. This is the same discipline the old palette used for gold. */
    --gold:         #FAC632;   /* hairlines on marble; type only on the band */
    /* The Services cards' gold (clinic request, 2026-09-14: "a golden,
       premium look"). --gold above measures 1.49:1 on white and cannot be
       text, so the cards use the antique gold of the marble's own veins:
       --gold-ink is that vein darkened until it reads 6.3:1 on white (text),
       --gold-vein is the vein itself (1px rules and borders only). */
    --gold-ink:     #7A5A1E;
    --gold-vein:    #C9A961;
    --gold-line:    rgba(201, 169, 97, 0.55);
    --amber:        #F2A74B;
    --sand:         #D9B384;   /* plates, chips, borders */
    --line:         #E7DDCC;
    --line-soft:    #F0E8DB;

    /* -- Glass ---------------------------------------------------------------
       The marble behind the services bottoms out at luminance 181 in its
       darkest veins. Body copy on bare stone there measures 2.74:1 -- nowhere
       near AA. On this glass the same copy measures 5.49:1. The panels are not
       decoration; they are what makes text on marble legible.

       --glass-strong must stay in step with GLASS_ALPHA in
       tools/make-marble.php, which re-verifies that number every time the
       stone is rebuilt. */
    --glass:        rgba(255, 255, 255, 0.72);
    --glass-strong: rgba(255, 255, 255, 0.82);
    --glass-hover:  rgba(255, 255, 255, 0.90);
    --glass-edge:   rgba(255, 255, 255, 0.62);
    --glass-blur:   blur(20px) saturate(1.18);
    --hairline:     rgba(217, 179, 132, 0.35);

    /* ── Depth: one ambient shadow, and a lifted variant for hover ──────────
       Long, soft, low-opacity, and tinted with the ink rather than pure black,
       so a raised card looks like it is sitting in the same warm light as the
       page instead of being cut out of it. */
    --shadow:       0 20px 40px -15px rgba(47, 51, 49, 0.07);
    --shadow-lift:  0 28px 56px -18px rgba(47, 51, 49, 0.13);
    --shadow-plate: inset 0 1px 0 rgba(255, 255, 255, 0.7);

    /* ── Radii ── */
    --r-s: 8px;  --r-m: 16px;  --r-l: 24px;  --r-pill: 999px;

    /* ── Type ───────────────────────────────────────────────────────────────
       The pairing measured off zen.dentist: Cormorant Garamond at 400 for
       display, Hanken Grotesk for everything else. The part that actually
       makes it read premium is not the serif — it is the SIZE GAP between a
       large, light, tightly-tracked serif and a very small sans label tracked
       out to +0.14em. Both halves are required.                               */
    --font-display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
    --font-body:    "Hanken Grotesk", "Segoe UI", system-ui, sans-serif;

    --step--1: 13px;   --step-0: 16px;   --step-1: 19px;
    --step-2: 26px;    --step-3: 36px;   --step-4: 52px;   --step-5: 68px;

    --max: 1200px;
    --gap: 96px;       /* vertical rhythm between sections */
    --pad: 40px;       /* the single left/right edge for the whole page */

    background-color: var(--canvas);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: var(--step-0);
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
}

/* ═══════════════════════════════════════════════════════════════════════════
   STEP 2 — COMPONENTS
   Not one class name is invented, renamed or removed below. Every selector
   already exists in templates/landing.php.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Typography ──────────────────────────────────────────────────────────────
   :where() is doing real work here, not decoration. Written the obvious way as
   `.landing h1, .landing h2, .landing h3`, this rule has specificity (0,1,1) —
   a class PLUS an element — which outranks every single-class component rule
   at (0,1,0). Its `margin: 0` then silently beat the margin-bottom on
   .hero__title, .closing__title and .hmo__name, and beat `margin-inline: auto`
   on .pay__truth, knocking that block 73px out of alignment with the page.

   :where() contributes zero specificity, so these rules land at (0,1,0) and
   lose to any component rule that comes after them — which is what a reset is
   supposed to do. Do not "simplify" this back to a plain selector list.       */
.landing :where(h1, h2, h3) {
    margin: 0;
    /* base.css sets h1-h3 to #1C1C1C. That is only (0,0,1), so this wins — but
       it only wins because the colour is stated here. Without it the headings
       sat outside the palette entirely, a near-black that belongs to the
       dashboards rather than to her shopfront. */
    color: var(--ink);
    font-family: var(--font-display);
    font-weight: 400;                 /* Cormorant carries at 400; bold muddies it */
    letter-spacing: -0.018em;
    line-height: 1.1;
    text-wrap: balance;
}
.landing :where(p) { margin: 0; }

/* Every inline SVG needs a size floor. Without one an <svg> with no width
   attribute falls back to its 300x150 default — the mobile menu button did
   exactly that and pushed the page 100px wider than the screen. This sits
   before the per-context icon sizes below so each of them still wins.

   :where() again, and for the same reason: written as `.landing .icon` this
   is (0,2,0) and outranks the single-class `.pick__icon` at (0,1,0), which
   shrank the card icons from 32px to 18px. Wrapped, it lands at (0,1,0) and
   every per-context size below overrides it as intended. */
.landing :where(.icon) { width: 18px; height: 18px; flex: none; }

/* The utility label. This is the workhorse of the whole system: small, heavy
   for its size, and tracked wide. It appears as an eyebrow, a tag, a day of
   the week, a field label and a button — and it is what holds the page
   together underneath the serif. */
/* NOTE: .wayfind__step is deliberately NOT in this list. It is the <figure>,
   not a label — it wraps the photo AND the caption sentence, so putting it
   here set the whole caption in 11.5px tracked uppercase. The label treatment
   is applied to the numeral inside it instead, further down. */
.landing .eyebrow,
.landing .tag,
.landing .hours__day,
.landing .contact-list__label,
.landing .topbar__item,
.landing .btn,
.landing .navbar__link {
    font-family: var(--font-body);
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    line-height: 1.4;
}

.landing .eyebrow {
    display: flex; align-items: center; gap: 10px;
    margin: 0 0 18px; color: var(--brand);
}
/* Gold appears here as a 26px rule and nowhere else in this block. It is the
   only decorative use of the colour on a cream ground, and at 1px it is a
   texture rather than a contrast surface. */
.landing .eyebrow::before {
    content: ""; width: 26px; height: 1px;
    background-color: var(--gold); flex: none;
}

/* ── Layout: ONE container rule, ONE left edge ───────────────────────────── */
.landing .section { padding: var(--gap) var(--pad); background-color: var(--canvas); }
.landing .section > * { max-width: var(--max); margin-inline: auto; }

/* The canvas rhythm. White for the two content-dense sections, deep warm for
   the two where cards need something to float above. */
.landing .section--white { background-color: var(--canvas-lift); }
.landing .section:not(.section--white) { background-color: var(--canvas-deep); }

/* ── The services section is laid on her marble ──────────────────────────────
   The wall behind the gold tooth mark, prepared by tools/make-marble.php from
   the clinic's own close-up: cropped clear of the mark and the lettering,
   white-balanced out of the warm clinic lighting, and flattened until the
   veining is something you notice only when you look for it.

   A flat colour sits UNDER the photograph rather than relying on it. The image
   is one crop of a real wall, so at very wide viewports it stretches; the
   colour beneath means the section still reads correctly if it stretches, and
   still reads correctly before it loads or if it 404s. `fixed` lets the stone
   stay put while the cards travel over it, which is what makes it read as a
   wall rather than as a printed backdrop.

   If the surface ever looks orange, the white balance in the tool has drifted
   — the raw stone photographs at about #D9B580 under those lights. */
/* "Where to find us" is laid on the slatted wall from her own clinic — the
   brown panel the tooth mark is fixed to. It is a dark ground, so every piece
   of type in this section is re-stated light below; nothing inherits the
   charcoal it uses everywhere else. The cards stay pale and keep their own
   contrast, which is what lets them read as objects ON a wall.

   VERTICAL SLATS, DRAWN IN CSS -- the client's own specification.
   This replaced a generated horizontal JPEG. Pure CSS is the better answer
   here for three reasons: the slats stay razor sharp at any zoom or pixel
   density, there is no image request at all, and the pitch is a number in
   this file rather than baked into a bitmap. A repeating-linear-gradient at
   90deg gives the vertical run; the stops model one slat in section --
   groove, lit left bevel, front face, shading away, right bevel, groove.

   The radial is layered ABOVE the slats (first background-image layer paints
   on top) rather than being an ::after overlay. An absolutely-positioned
   overlay would sit above this section's cards and swallow their clicks; as a
   background layer it cannot touch them, and no z-index juggling is needed. */
.landing #visit-us {
    background-color: #3D261A;
    background-image:
        radial-gradient(circle at 50% 18%,
            rgba(255, 255, 255, 0.10) 0%,
            rgba(0, 0, 0, 0.46) 100%),
        repeating-linear-gradient(
            90deg,
            #170D08 0px,     /* deep groove, left edge   */
            #170D08 3px,     /* groove width             */
            #6E4733 4px,     /* lit bevel                */
            #482D1F 7px,     /* front face of the slat   */
            #3B2418 23px,    /* face shading away        */
            #21130B 26px,    /* right bevel in shadow    */
            #170D08 28px     /* into the next groove     */
        );
}
/* Visit Us sits on the dark wood slats, so its heading is inverted. These
   MUST track the header component's class names: when the section headers were
   unified, a title still keyed to the old .section__title would have rendered
   near-black on a near-black background and simply vanished, with no error and
   nothing in the markup to suggest why. */
.landing #visit-us .sec-head__title { color: #ffffff; }
.landing #visit-us .eyebrow { color: var(--gold); }
.landing #visit-us .eyebrow::before,
.landing #visit-us .eyebrow::after { background-color: var(--gold); }
.landing #visit-us .sec-head__lead {
    color: rgba(255, 255, 255, 0.86);
}

.landing #services {
    background-color: var(--canvas);
    background-image: url("../images/marble-panel.jpg");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    background-attachment: fixed;
}

/* A phone cannot afford a fixed background — it forces a repaint of the whole
   layer on every scroll frame, which is exactly the stutter this page is built
   to avoid. Scroll it with the content there. */
@media (max-width: 1000px), (hover: none) {
    .landing #services { background-attachment: scroll; }
}

/* The head BLOCK spans the container so its left edge matches the content
   under it; the TEXT inside is capped to a readable measure. Putting the cap
   on the block is what previously knocked the headings out of line. */
/* Head: the title leads, and its sentence is INDENTED beneath it rather than
   set in a second column. Two columns made the lead read as a separate note
   off to one side; indented under the title it reads as the title's own
   subtitle, which is what it is.
   The rule down its left, and the indent it justified, were removed on
   2026-09-14 with every other coloured left bar in the app. The lead now sits
   flush under the title, set apart by space and a lighter ink. */
/* Superseded 2026-09-18 by .sec-head at the end of this file, which every
   section header now uses. Kept only because .section__lead is still applied
   by a handful of inner blocks that are not section headers. */
.landing .section__lead {
    max-width: 54ch;
    margin-top: 16px;
    color: var(--ink-2);
    font-size: var(--step-0);
}

/* ── Buttons: sage, and only sage ────────────────────────────────────────── */
.landing .btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 9px;
    min-height: 46px; padding: 0 24px;
    border: 1px solid transparent; border-radius: var(--r-pill);
    background-color: transparent; color: inherit;
    cursor: pointer; text-decoration: none; white-space: nowrap;
    transition: background-color .22s ease, color .22s ease,
                border-color .22s ease, transform .22s ease, box-shadow .22s ease;
}
.landing .btn:hover { transform: translateY(-1px); }
.landing .btn:active { transform: translateY(0); }
.landing .btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

.landing .btn--gold {                              /* the primary action, now sage */
    background-color: var(--brand); color: #ffffff;
    box-shadow: var(--shadow);
}
.landing .btn--gold:hover { background-color: var(--brand-deep); box-shadow: var(--shadow-lift); }

.landing .btn--outline { border-color: var(--brand); color: var(--brand); }
.landing .btn--outline:hover { background-color: var(--brand-wash); }

.landing .btn--glass {
    border-color: rgba(255,255,255,.5); color: #ffffff;
    background-color: rgba(255,255,255,.1);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.landing .btn--glass:hover { background-color: rgba(255,255,255,.2); border-color: rgba(255,255,255,.85); }

.landing .btn--lg { min-height: 56px; padding: 0 32px; font-size: 12.5px; }
.landing .btn--block { width: 100%; }
.landing .btn .icon { width: 17px; height: 17px; }

/* ── Stage: topbar + transparent nav over the storefront ─────────────────── */
.landing .stage { position: relative; }

.landing .topbar {
    position: relative; z-index: 3;
    display: flex; flex-wrap: wrap; align-items: center;
    justify-content: space-between; gap: 12px 28px;
    padding: 11px var(--pad);
    background-color: var(--band); color: rgba(255,255,255,.82);
}
.landing .topbar__group { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 26px; }
.landing .topbar__item { display: inline-flex; align-items: center; gap: 8px; }
.landing .topbar .icon { width: 14px; height: 14px; opacity: .65; }

.landing .status {
    display: inline-flex; align-items: center; gap: 8px;
    font-family: var(--font-body); font-size: 11.5px; font-weight: 600;
    letter-spacing: .14em; text-transform: uppercase;
}
.landing .status__dot {
    width: 7px; height: 7px; border-radius: 50%; background-color: var(--gold);
    box-shadow: 0 0 0 3px rgba(250,198,50,.26);
}

/* ── The navigation bar, and what it does on scroll ─────────────────────────
   Two states.

   AT REST it is transparent and sits on the storefront photograph, carrying
   only a soft top gradient — enough to hold white text off the bright glass,
   not so much that it becomes a band across the picture.

   ONCE PAST THE TOP BAR it becomes a real surface: warm translucent white
   over a blur, a hairline, a soft shadow, ink-coloured text, and 32px shorter.
   That change is not decoration. White-on-photo stops being readable the
   moment the page scrolls onto the cream ground, so the bar has to change or
   the links disappear.

   WHY FIXED FROM THE START, rather than switching position on scroll:
   swapping position:static to position:fixed takes the bar out of flow and
   everything below it jumps up by its own height. Fixed from the first paint
   means the only thing that ever animates is appearance. --topbar-h is
   measured and set by script, so the bar sits exactly under the top bar at
   rest and slides up to 0 when that bar scrolls away.

   Zen's own nav never changes state — their hero is light enough for dark
   text throughout, so they never needed this. Their declared 700ms ease-out
   is therefore an untested number on that page; 500ms is used here because
   the bar must finish changing while the user is still scrolling, not
   half a second behind them. The curve is theirs. */
.landing .navbar {
    position: fixed; top: var(--topbar-h, 44px); right: 0; left: 0; z-index: 50;
    display: flex; align-items: center; gap: 28px;
    height: 104px; padding: 0 var(--pad);
    border-bottom: 1px solid transparent;
    /* The storefront is brightest exactly where the nav sits — the lit
       doorway and the marble wall — so white links land on near-white glass.
       The scrim has to still be carrying weight at the BOTTOM of the bar,
       where the links actually are, not just at the very top. */
    background-image: linear-gradient(180deg,
        rgba(24,26,25,.72) 0%, rgba(24,26,25,.42) 58%, rgba(24,26,25,0) 100%);
    transition: top .5s cubic-bezier(0, 0, .2, 1),
                height .5s cubic-bezier(0, 0, .2, 1),
                background-color .5s cubic-bezier(0, 0, .2, 1),
                border-color .5s cubic-bezier(0, 0, .2, 1),
                box-shadow .5s cubic-bezier(0, 0, .2, 1);
}

.is-stuck .landing .navbar {
    top: 0;
    height: 72px;
    background-color: rgba(250, 247, 241, 0.90);
    background-image: none;
    -webkit-backdrop-filter: blur(16px) saturate(1.4);
    backdrop-filter: blur(16px) saturate(1.4);
    border-bottom-color: var(--line);
    box-shadow: 0 10px 30px -20px rgba(47, 51, 49, 0.55);
}
.is-stuck .landing .brand__name { color: var(--ink); text-shadow: none; }
.is-stuck .landing .navbar__link { text-shadow: none; }
.is-stuck .landing .brand__tagline { color: var(--ink-2); }
.is-stuck .landing .brand__badge { background-color: transparent; box-shadow: none; }
.is-stuck .landing .navbar__link { color: var(--ink-2); }
.is-stuck .landing .navbar__link:hover,
.is-stuck .landing .navbar__link.is-active { color: var(--ink); }
/* The glass button has no photograph to sit on any more, so it becomes the
   ordinary outline button the rest of the page uses. */
.is-stuck .landing .btn--glass {
    border-color: var(--brand); color: var(--brand);
    background-color: transparent;
    -webkit-backdrop-filter: none; backdrop-filter: none;
}
.is-stuck .landing .btn--glass:hover { background-color: var(--brand-wash); }
.is-stuck .landing .navbar__toggle { border-color: var(--line); color: var(--ink); background-color: transparent; }

/* Colour and height are the only things that move, so everything inside the
   bar can cross-fade on the same clock without any of it being laid out. */
.landing .brand__name,
.landing .brand__tagline,
.landing .navbar__link,
.landing .btn--glass {
    transition: color .5s cubic-bezier(0, 0, .2, 1),
                border-color .5s cubic-bezier(0, 0, .2, 1),
                background-color .5s cubic-bezier(0, 0, .2, 1);
}
.landing .brand { display: flex; align-items: center; gap: 13px; text-decoration: none; }
.landing .brand__badge {
    display: grid; place-items: center; width: 46px; height: 46px; flex: none;
    border-radius: 13px; background-color: rgba(255,255,255,.95);
    box-shadow: var(--shadow);
}
.landing .brand__logo { width: 32px; height: 32px; object-fit: contain; }
.landing .brand__text { display: flex; flex-direction: column; line-height: 1.2; }
.landing .brand__name {
    color: #fff; font-family: var(--font-display); font-size: 23px; letter-spacing: -.01em;
    text-shadow: 0 1px 10px rgba(22,24,23,.6);
}
.landing .brand__tagline {
    color: rgba(255,255,255,.72); font-size: 10.5px; font-weight: 600;
    letter-spacing: .14em; text-transform: uppercase;
}

.landing .navbar__menu { display: flex; align-items: center; gap: 34px; margin: 0 0 0 auto; padding: 0; list-style: none; }
.landing .navbar__link {
    position: relative; display: inline-block; padding-bottom: 4px;
    text-shadow: 0 1px 10px rgba(22,24,23,.65);
    color: rgba(255,255,255,.88); text-decoration: none; transition: color .2s ease;
}
.landing .navbar__link::after {
    content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 1px;
    background-color: var(--gold); transform: scaleX(0); transform-origin: left;
    transition: transform .28s cubic-bezier(.4,0,.2,1);
}
.landing .navbar__link:hover,
.landing .navbar__link.is-active { color: #fff; }
.landing .navbar__link:hover::after,
.landing .navbar__link.is-active::after { transform: scaleX(1); }
.landing .navbar__actions { display: flex; align-items: center; gap: 12px; }
.landing .navbar__toggle { display: none; }
/* Login and Book inside the phone menu; the desktop bar shows its own. */
.landing .navbar__menu-actions { display: none; }

/* ── Hero ────────────────────────────────────────────────────────────────── */
.landing .hero {
    position: relative; display: flex; align-items: flex-end;
    /* No negative margin any more: the bar is fixed, so it is already out of
       flow and the photograph simply starts under the top bar and runs behind
       it. The old -104px existed only to pull the hero up under an in-flow
       bar, and leaving it in would drag the picture under the top bar too. */
    /* Full screen. The storefront is the whole argument of this page, so it
       gets the whole viewport rather than a fixed 780px slab. Minus the top
       bar so the photograph plus that bar is exactly one screen and nothing
       is cut off. svh (not vh) because on a phone vh counts the space behind
       the browser's own toolbars, which pushes the buttons off-screen; the
       vh line above is the fallback for browsers without svh.
       620px floor: on a short laptop in landscape, a pure viewport height
       leaves no room for the headline and buttons at all. */
    min-height: max(620px, calc(100vh - var(--topbar-h, 41px)));
    min-height: max(620px, calc(100svh - var(--topbar-h, 41px)));
    margin-top: 0; padding: 200px var(--pad) 88px;
    background-image:
        linear-gradient(180deg,
            rgba(22,24,23,.60) 0%, rgba(22,24,23,.10) 24%,
            rgba(22,24,23,.08) 46%, rgba(30,33,32,.84) 74%, rgba(34,37,36,.96) 100%),
        var(--hero-photo);
    background-size: cover; background-position: center 38%;
}
.landing .hero__inner { width: 100%; max-width: var(--max); margin-inline: auto; }
.landing .hero__kick {
    display: inline-flex; align-items: center; gap: 10px; margin-bottom: 20px;
    padding: 7px 16px; border-radius: var(--r-pill);
    border: 1px solid rgba(255,255,255,.28); background-color: rgba(255,255,255,.1);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    color: #fff; font-size: 11px; font-weight: 600;
    letter-spacing: .14em; text-transform: uppercase;
}
/* THE HEADLINE MUST NOT COVER HER NAME.
   "REINA G. GAPIT, D.M.D." is painted on the glass and sits around 38% down
   the photograph. At 15ch the headline wraps to three lines, and a three-line
   block bottom-anchored in a 780px hero starts at roughly 304px — directly on
   top of her signage. This has been reported once before.
   26ch wraps it to two lines instead, which drops the block to about 400px
   and leaves her name clear. If you change the size or the measure here,
   re-check that overlap: the constraint is the photograph, not the type. */
/* 2026-09-24: the approved tagline "Compassionate Care, Confident Smiles." is
   much shorter than the sentence it replaced, and at a fixed 46-54px light
   weight it read as small on a laptop while wrapping to three lines on a
   phone. The size is now fluid with the screen width, a step heavier, and
   the measure is in em so it always breaks as "Compassionate Care, /
   Confident Smiles." — two lines, which keeps the block clear of her name. */
.landing .hero__title {
    max-width: 12em; margin-bottom: 18px; color: #fff;
    font-size: clamp(40px, 4.4vw + 14px, 84px); font-weight: 400; line-height: 1.04; letter-spacing: -.02em;
    text-shadow: 0 2px 24px rgba(22,24,23,.55);
}
.landing .hero__text {
    max-width: 46ch; margin-bottom: 34px; color: rgba(255,255,255,.94);
    font-size: clamp(18px, .6vw + 14px, 23px); font-weight: 500; line-height: 1.5; letter-spacing: .01em;
    text-shadow: 0 1px 14px rgba(22,24,23,.6);
}
.landing .hero__actions { display: flex; flex-wrap: wrap; gap: 13px; }

/* ── Services: four rows, four columns, one grid ─────────────────────────── */
/* -- Services: editorial rows on glass, over her marble ----------------------
   Two columns per service. LEFT is metadata: the numeral and the category
   tags. RIGHT is the headline and its sentence. Book sits at the far right,
   spanning both rows.

   HOW THE LEFT COLUMN IS POSSIBLE WITHOUT TOUCHING THE HTML
   The markup nests .svc-row__tl and .tags inside .svc-row__meta, which would
   normally lock them together in one cell. That wrapper is set to
   `display: contents`, so its own box disappears and its two children become
   grid items of .svc-row directly -- letting the tags sit in the LEFT column
   beside the numeral while the sentence stays on the RIGHT. No class renamed,
   no element added, no JavaScript hook disturbed.

   WHY THE ROWS SIT ON GLASS: see the --glass note in the token block. Text on
   bare marble fails AA; on glass it passes comfortably. */
/* 2026-09-14: one rounded card per service (clinic request), in place of one
   glass panel with hairlines and a gold bar sliding in on the live row. Each
   card still sits on glass, so the text keeps its AA contrast over the marble.
   Shape: 16px radius (--r-m), the page's card radius. Depth: one soft shadow
   tier, only on the card that is live or hovered. */
.landing .svc-rows {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* THE WHITE BOX AROUND EACH SERVICE WAS NOT FROM HERE.
   css/services.css -- the STAFF DASHBOARD stylesheet -- defines an unanchored
   `.svc-row` at (0,1,0) setting background-color:#ffffff, a full border and a
   radius. Both stylesheets load on every page. This rule wins on specificity
   only for the properties it actually DECLARES, so any it omits fall straight
   through. background-color, border, border-radius and flex-wrap are declared
   here for that reason alone -- they look redundant and are not. */
.landing .svc-row {
    display: grid;
    /* One content column and one control column. Everything that describes
       the service stacks on the left in reading order — headline, sentence,
       then the tags that qualify it — and Book sits alone at the far right,
       vertically centred against the whole block.

       The tags come LAST rather than sitting beside the headline: they are
       the detail you check after deciding the service is relevant, not the
       label you read on the way in. */
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto auto;
    gap: 12px 48px;
    align-items: start;
    background-color: var(--glass-strong);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    border: 1px solid var(--gold-line);
    border-radius: var(--r-m);
    flex-wrap: nowrap;
    padding: 30px 36px;
    /* Named properties rather than `all`: `all` would also animate the grid
       tracks and the border collapse, which is where hover jitter comes from. */
    transition: background-color .35s cubic-bezier(.16, 1, .3, 1),
                border-color .35s cubic-bezier(.16, 1, .3, 1),
                transform .35s cubic-bezier(.16, 1, .3, 1),
                box-shadow .35s cubic-bezier(.16, 1, .3, 1);
}
/* The one elevation tier, tinted warm gold rather than grey, and the gold
   hairline firms up to the full vein colour. */
.landing .svc-row:hover {
    background-color: var(--glass-hover);
    border-color: var(--gold-vein);
    transform: translateY(-3px);
    box-shadow: 0 2px 6px rgba(122, 90, 30, 0.06),
                0 14px 28px -10px rgba(122, 90, 30, 0.22);
}

/* SCROLL FOCUS.
   One service at a time is the live one: it lifts, brightens and holds its
   full weight, while the others recede. The dimming is applied only while
   .is-focusing is present — a class the script adds — so with no JavaScript
   every service stays at full strength and nothing is hidden from anyone.

   opacity and transform only, so this costs nothing on a weak phone. */
/* `:not(.is-focus)` is not just tidier than dimming everything and undoing it
   on the active row — it is load-bearing. Every .svc-row also carries .reveal,
   and `.reveal-armed .landing .reveal.is-in { opacity: 1 }` is (0,4,0). Written
   as `.is-focusing .svc-row` this rule ties at (0,4,0) and loses on order, so
   nothing dimmed at all. With the :not() it reads (0,5,0) and wins. */
.landing .svc-rows.is-focusing .svc-row:not(.is-focus) {
    opacity: .46;
}
/* Armed a frame late, exactly as the wayfinding transitions are. Adding
   .is-focusing IS a change from full strength to dimmed, so declaring the
   transition on it would make every page load open with all four services
   visibly fading down together. .is-focus-ready arrives on the next frame,
   after the resting state has painted. */
.landing .svc-rows.is-focusing.is-focus-ready .svc-row {
    transition: opacity .45s cubic-bezier(.16, 1, .3, 1),
                transform .45s cubic-bezier(.16, 1, .3, 1),
                background-color .35s cubic-bezier(.16, 1, .3, 1),
                border-color .35s cubic-bezier(.16, 1, .3, 1),
                box-shadow .35s cubic-bezier(.16, 1, .3, 1);
}
.landing .svc-rows.is-focusing .svc-row.is-focus {
    opacity: 1;
    transform: translateY(-3px);
    background-color: var(--glass-hover);
    border-color: var(--gold-vein);
    box-shadow: 0 2px 6px rgba(122, 90, 30, 0.06),
                0 14px 28px -10px rgba(122, 90, 30, 0.22);
}
/* The live one carries a slightly larger headline. Kept small — 2px, not a
   jump — so the list does not visibly reflow as you scroll past it. */
.landing .svc-rows.is-focusing .svc-row.is-focus .svc-row__title { font-size: 36px; }
.landing .svc-rows.is-focusing.is-focus-ready .svc-row__title {
    transition: font-size .45s cubic-bezier(.16, 1, .3, 1);
}

/* -- Left column: metadata -- */
.landing .svc-row__meta { display: contents; }
.landing .tags {
    grid-column: 1; grid-row: 3;
    display: flex; flex-wrap: wrap; align-content: start; gap: 7px;
    margin: 4px 0 0; padding: 0; list-style: none;
}
.landing .tag {
    padding: 5px 11px; border-radius: var(--r-pill);
    border: 1px solid var(--line-soft);
    background-color: rgba(255, 255, 255, 0.66);
    color: var(--ink-2); font-size: 10px;
}
.landing .svc-row .tag {
    border-color: var(--gold-line);
    background-color: rgba(201, 169, 97, 0.08);
    color: var(--gold-ink);
}

/* -- Right column: the headline and its sentence -- */
.landing .svc-row__title {
    grid-column: 1; grid-row: 1;
    font-size: 34px; line-height: 1.14; letter-spacing: -.02em;
    /* Cormorant at 500, not 400: gold is lighter than ink, and the hairline
       strokes of the 400 cut thin out in it. */
    color: var(--gold-ink);
    font-weight: 500;
}
/* A short gold rule under each service name, like the rule under a menu
   heading. Drawn with a pseudo-element so no markup changes. */
.landing .svc-row__title::after {
    content: "";
    display: block;
    width: 40px;
    height: 1px;
    margin-top: 14px;
    background-color: var(--gold-vein);
    /* Grown with a transform rather than by animating width. Both look
       identical — 40px scaled by 1.8 is 72px — but width is a layout property,
       so the browser reflows the row on every frame of the transition, while a
       transform is handled on the compositor and touches no layout at all.
       transform-origin pins it to the left so it extends rightward rather than
       spreading from its centre. */
    transform-origin: left center;
    transition: transform .45s cubic-bezier(.16, 1, .3, 1);
}
.landing .svc-row:hover .svc-row__title::after,
.landing .svc-rows.is-focusing .svc-row.is-focus .svc-row__title::after {
    transform: scaleX(1.8);
}
@media (prefers-reduced-motion: reduce) {
    .landing .svc-row__title::after { transition: none; }
}

.landing .svc-row__tl {
    grid-column: 1; grid-row: 2;
    max-width: 62ch;
    color: var(--ink-2); font-size: 15.5px; line-height: 1.72;
}

.landing .svc-row__go {
    grid-column: 2; grid-row: 1 / span 3;
    justify-self: end; align-self: center;
    min-height: 44px; padding: 0 22px;                 /* 44px: a real touch target */
    border: 1px solid var(--brand); border-radius: var(--r-pill);
    background-color: transparent; color: var(--brand);
    font-family: var(--font-body); font-size: 11.5px; font-weight: 600;
    letter-spacing: .14em; text-transform: uppercase; cursor: pointer;
    transition: background-color .22s ease, color .22s ease;
}
.landing .svc-row__go:hover { background-color: var(--brand); color: #fff; }
.landing .svc-row__go:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

/* ── Getting seen: two cards ─────────────────────────────────────────────── */
.landing .pick { display: grid; grid-template-columns: repeat(2, 1fr); gap: 22px; }
.landing .pick__card {
    display: flex; flex-direction: column; gap: 15px;
    padding: 44px 42px; border-radius: var(--r-l);
    background-color: var(--canvas-lift); border: 1px solid var(--line-soft);
    box-shadow: var(--shadow);
    transition: transform .3s cubic-bezier(.4,0,.2,1), box-shadow .3s ease;
}
.landing .pick__card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); }
.landing .pick__icon { width: 32px; height: 32px; color: var(--brand); stroke-width: 1.3; }
.landing .pick__title { font-size: var(--step-3); }
.landing .pick__text { color: var(--ink-2); font-size: 15.5px; line-height: 1.75; }
.landing .pick__act { margin-top: auto; padding-top: 10px; }
/* The walk-in card is the one a patient standing at the counter needs, so it
   is the one that is filled rather than outlined. */
.landing .pick__card--now { background-color: var(--band); border-color: var(--band); }
.landing .pick__card--now .pick__icon { color: var(--gold); }
.landing .pick__card--now .pick__title { color: #fff; }
.landing .pick__card--now .pick__text { color: #CFD4D1; }
.landing .pick__card--now .btn--gold { background-color: var(--gold); color: #2A2205; }
.landing .pick__card--now .btn--gold:hover { background-color: #FFD65A; }

/* ── Visit us ────────────────────────────────────────────────────────────── */
.landing .visit { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: 26px; align-items: start; }
.landing .visit__info {
    display: flex; flex-direction: column; gap: 26px;
    padding: 40px; border-radius: var(--r-l);
    background-color: var(--canvas-lift); border: 1px solid var(--line-soft);
    box-shadow: var(--shadow);
}
/* THE SIGNATURE. Every unit in Ramaida Centrum is a near-identical glass front
   with a number on it, and that number is genuinely how a patient finds her.
   So the stall number is set as a physical plate — sand, tracked, slightly
   raised — and the same plate shape returns on the wayfinding numerals.
   One object, two appearances, both of them true. (It was three until the
   service numerals came out: four services are a menu, not a sequence.) */
.landing .plate {
    display: inline-flex; align-items: center; gap: 9px; align-self: flex-start;
    padding: 8px 15px; border-radius: var(--r-s);
    border: 1px solid var(--sand); background-color: var(--canvas-deep);
    box-shadow: var(--shadow-plate);
    color: var(--ink); font-size: 11px; font-weight: 600;
    letter-spacing: .16em; text-transform: uppercase;
}
.landing .address { color: var(--ink-2); font-size: 15.5px; line-height: 1.75; font-style: normal; }
.landing .hours { display: flex; flex-direction: column; }
.landing .hours__row {
    display: flex; align-items: baseline; justify-content: space-between; gap: 20px;
    padding: 11px 0; border-bottom: 1px solid var(--line-soft);
}
.landing .hours__row:last-child { border-bottom: 0; }
.landing .hours__day { color: var(--ink-2); }
.landing .hours__time { color: var(--ink); font-size: 15px; font-variant-numeric: tabular-nums; }
.landing .hours__time--note { color: var(--ink-2); font-size: 13.5px; font-style: italic; }
.landing .contact-list { display: flex; flex-direction: column; gap: 14px; margin: 0; padding: 0; list-style: none; }
/* Markup here is: <a><svg/><span><span class="label">Phone</span>0923…</span></a>
   As a column flex the icon took its own line and the label stayed glued to
   the number — "PHONE0923-618-3285". The ITEM is the row (icon beside text)
   and the inner span is the column (label above number). */
.landing .contact-list__item {
    display: flex; flex-direction: row; align-items: center;
    gap: 13px; font-size: 16px;
}
.landing .contact-list__item > span {
    display: flex; flex-direction: column; gap: 2px; min-width: 0;
}
.landing .contact-list__item .icon { color: var(--brand); }
.landing .contact-list__label { display: block; color: var(--ink-2); }
.landing .contact-list a { color: var(--brand); text-decoration: none; }
.landing .contact-list a:hover { text-decoration: underline; }
/* .visit__map IS the <iframe>, not a box around one. Styling it as a
   container and sizing "the iframe inside it" matched nothing, so the frame
   fell back to the HTML default width of 300px and sat in a 616px grid cell
   with a dead gap beside it. An iframe has no intrinsic width — it must be
   told. Do not reintroduce a descendant selector here. */
.landing .visit__map {
    display: block;
    width: 100%;
    height: 100%;
    min-height: 520px;
    border: 0;
    border-radius: var(--r-l);
    background-color: var(--canvas-deep);
    box-shadow: var(--shadow);
}

/* -- Wayfinding: one step at a time, on glass -------------------------------
   Four thumbnails in a row asked the patient to compare pictures. The walk is
   a SEQUENCE, so the section shows one large frame and steps through it.

   PROGRESSIVE ENHANCEMENT, and it matters here more than anywhere else on the
   page. Every rule that hides a step is behind `.wayfind--live`, a class only
   the script adds. With JavaScript off, blocked, or still parsing, all four
   steps simply stack and the patient can still read the whole route. A person
   standing in a mall corridor looking for a door must never be shown one
   picture and no way to reach the next. */
/* No panel around the pictures. The frame, the border and the glass card were
   all box around box; the photograph carries itself and simply floats, held
   down by a shadow beneath it. */
.landing .wayfind {
    display: grid;
    gap: 22px;
    margin-top: 30px;
}

/* Without the script this is a plain stack; with it, the positioning context
   the steps are absolutely placed inside. */
.landing .wayfind__stage { display: grid; gap: 16px; }

.landing .wayfind--live .wayfind__stage {
    position: relative;
    display: block;
    aspect-ratio: 16 / 9;
    border-radius: var(--r-l);
    /* The shadow lives on the STAGE, not on each step, so it does not fade in
       and out with the frames — the picture appears to sit on one shelf while
       the images change behind it. */
    box-shadow: 0 34px 60px -30px rgba(20, 14, 9, 0.75);
}

.landing .wayfind__step { display: flex; flex-direction: column; gap: 13px; margin: 0; }

.landing .wayfind--live .wayfind__step {
    position: absolute;
    inset: 0;
    display: block;
    opacity: 0;
    visibility: hidden;
    transform: translateX(24px);
}

/* TRANSITIONS ARE ARMED ONE FRAME LATE, ON PURPOSE.
   Adding .wayfind--live flips all four steps from visible to hidden. If the
   transition were declared on .wayfind--live itself, every page load would
   begin with four stacked frames visibly fading out over half a second before
   the first one came back. The starting state has to be applied instantly and
   the transitions turned on afterwards, which is what .wayfind--ready does.

   It is added from a double requestAnimationFrame, so it also never arrives in
   a tab whose rendering is frozen — and there the carousel simply switches
   instantly instead of freezing mid-fade with all four frames showing at once.
   Degrading to no animation is correct; degrading to four overlapping photos
   is not.

   visibility is delayed out so the leaving frame is not clickable while it
   fades, and snapped in so the arriving one is reachable immediately. */
.landing .wayfind--ready .wayfind__step {
    transition: opacity .5s cubic-bezier(.16, 1, .3, 1),
                transform .5s cubic-bezier(.16, 1, .3, 1),
                visibility 0s linear .5s;
}
.landing .wayfind--live .wayfind__step.is-current {
    opacity: 1;
    visibility: visible;
    transform: none;
}
.landing .wayfind--ready .wayfind__step.is-current { transition-delay: 0s, 0s, 0s; }

.landing .wayfind__frame {
    display: block; overflow: hidden; border-radius: var(--r-m);
    border: 1px solid var(--line-soft); background-color: var(--canvas-lift);
    box-shadow: var(--shadow);
}
.landing .wayfind__frame img {
    display: block; width: 100%; height: 178px; object-fit: cover;
}
.landing .wayfind--live .wayfind__frame {
    height: 100%;
    border: 0;
    border-radius: var(--r-l);
    overflow: hidden;
    background: none;
    box-shadow: none;
}
.landing .wayfind--live .wayfind__frame img { height: 100%; }

.landing .wayfind__step figcaption { display: flex; align-items: flex-start; gap: 11px; }
.landing .wayfind__step figcaption b {
    display: grid; place-items: center; flex: none;
    width: 38px; height: 27px; margin-top: 1px;
    border: 1px solid var(--sand); border-radius: var(--r-s);
    background-color: rgba(255, 255, 255, 0.72); color: var(--ink-2);
    font-family: var(--font-body); font-size: 10.5px; font-weight: 600;
    letter-spacing: .1em; font-variant-numeric: tabular-nums;
}
.landing .wayfind__step figcaption span { color: var(--ink-2); font-size: 14.5px; line-height: 1.65; }

/* The caption floats over the photograph as its own surface rather than being
   set on the image: these four frames differ wildly in brightness at the
   bottom edge, and text laid on them is a contrast promise you cannot keep. */
.landing .wayfind--live .wayfind__step figcaption {
    position: absolute;
    right: 16px; bottom: 16px; left: 16px;
    align-items: center;
    padding: 14px 18px;
    border-radius: var(--r-m);
    background-color: var(--glass-hover);
    -webkit-backdrop-filter: blur(14px) saturate(1.2);
    backdrop-filter: blur(14px) saturate(1.2);
    box-shadow: 0 10px 28px -12px rgba(47, 51, 49, 0.45);
}
.landing .wayfind--live .wayfind__step figcaption span {
    color: var(--ink); font-size: 15px;
}

/* -- Controls -- */
.landing .wayfind__nav {
    display: none;                       /* only meaningful once live */
    align-items: center; justify-content: center; gap: 18px;
}
.landing .wayfind--live .wayfind__nav { display: flex; }

.landing .wayfind__arrow {
    display: grid; place-items: center;
    width: 46px; height: 46px;           /* a real touch target */
    border: 1px solid var(--sand); border-radius: 50%;
    background-color: rgba(255, 255, 255, 0.72); color: var(--ink);
    cursor: pointer;
    transition: background-color .28s cubic-bezier(.16, 1, .3, 1),
                border-color .28s cubic-bezier(.16, 1, .3, 1),
                color .28s cubic-bezier(.16, 1, .3, 1);
}
.landing .wayfind__arrow:hover:not(:disabled) {
    background-color: var(--brand); border-color: var(--brand); color: #ffffff;
}
.landing .wayfind__arrow:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }
/* Clamped rather than wrapped: this is a route with a start and an end, and a
   disabled arrow says "this is the door" better than looping back to the street. */
.landing .wayfind__arrow:disabled { opacity: .38; cursor: default; }

.landing .wayfind__count {
    min-width: 108px; text-align: center;
    color: var(--ink-2); font-size: 11.5px; font-weight: 600;
    letter-spacing: .14em; text-transform: uppercase;
    font-variant-numeric: tabular-nums;
}

/* ── HMO ─────────────────────────────────────────────────────────────────── */
/* Card above, name and sentence centred beneath it. Side by side, the
   sentence read as a caption hanging off the artwork; stacked and centred, the
   card is the evidence and the words underneath are the statement. */
.landing .hmo {
    display: flex; flex-direction: column; align-items: center;
    gap: 26px; text-align: center;
    padding: 44px; border-radius: var(--r-l);
    background-color: var(--canvas-lift); border: 1px solid var(--line-soft);
    box-shadow: var(--shadow);
}
/* The card sits in a holder again. Dropping the frame was a deliberate call
   earlier — the artwork is already a card, and framing a picture of a card
   looked like an advertisement — but with nothing behind it the image just
   floated on white with no edge of its own. A warm mat with a hairline reads
   as a card in a wallet, which is what it is. */
.landing .hmo__logo {
    flex: none; width: 268px; padding: 14px;
    border: 1px solid var(--line); border-radius: var(--r-m);
    background-color: var(--canvas); box-shadow: var(--shadow);
}
.landing .hmo__logo img {
    display: block; width: 100%; height: auto;
    border-radius: 7px; box-shadow: 0 4px 14px rgba(47, 51, 49, 0.16);
}
.landing .hmo__body { flex: 0 1 auto; }
.landing .hmo__name { margin-bottom: 8px; font-size: var(--step-3); }
.landing .hmo__text { max-width: 52ch; margin-inline: auto; color: var(--ink-2); font-size: 15.5px; line-height: 1.75; }

/* ── Ways to pay: THE DESK LIGHT ─────────────────────────────────────────────
   In her clinic the gold tooth mark glows on the marble wall under a warm
   spotlight, directly above the desk where patients pay. This band recreates
   that moment: her marble, a warm light swaying slowly across it, and the
   gold veining showing clearest wherever the light falls. "Settled at the
   front desk" is shown, not just said.

   HOW THE LIGHT MOVES WITHOUT REPAINTING
   .pay-stage__light carries a radial MASK and slides sideways. Inside it,
   .pay-stage__stone (the marble at full strength) slides the other way by the
   same distance, so the stone stands still and only the pool of light
   travels. Both moves are transforms, which the compositor handles alone.
   The distances are paired: the light is 100% of the band wide and moves
   17%; the stone is 160% wide, so it moves 17/160 = 10.625% of itself. Change
   one inset and you must change the other keyframe, or the marble will drift.

   Borrowed from seasats.com, adapted: the heading lines rise out of their own
   masks, and each card's name rolls letter by letter into a fresh copy.     */

.landing .pay-stage {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    padding: clamp(84px, 11vw, 150px) var(--pad) clamp(72px, 9vw, 120px);
    background-color: var(--canvas);
    /* Warmth pooled at the top, where her spotlight is. Static. */
    background-image:
        radial-gradient(60% 55% at 50% 0%, rgba(250, 198, 50, 0.10), transparent 70%),
        radial-gradient(80% 60% at 50% 100%, rgba(217, 179, 132, 0.16), transparent 70%);
}

/* Her marble, faintly, everywhere: the veins are always there... */
.landing .pay-stage::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -3;
    background: url("../images/marble-panel.jpg") center / cover no-repeat;
    opacity: 0.2;
}

/* ...and fully visible only where the light is. */
.landing .pay-stage__light {
    position: absolute;
    inset: 0;
    z-index: -2;
    pointer-events: none;
    -webkit-mask-image: radial-gradient(closest-side, #000 0%, rgba(0, 0, 0, 0.7) 38%, transparent 100%);
            mask-image: radial-gradient(closest-side, #000 0%, rgba(0, 0, 0, 0.7) 38%, transparent 100%);
    -webkit-mask-size: 62% 118%;
            mask-size: 62% 118%;
    -webkit-mask-position: 50% 38%;
            mask-position: 50% 38%;
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    animation: payStageSway 13s ease-in-out infinite alternate;
}
.landing .pay-stage__stone {
    position: absolute;
    inset: 0 -30%;
    background: url("../images/marble-panel.jpg") center / cover no-repeat;
    opacity: 0.72;
    animation: payStageCounter 13s ease-in-out infinite alternate;
}
/* The light itself, breathing on a different clock from the sway (7.5s
   against 13s) so the two never settle into a loop you can see repeating. */
.landing .pay-stage__light::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 38%;
    width: 56%;
    aspect-ratio: 1;
    translate: -50% -50%;
    border-radius: 50%;
    background: radial-gradient(closest-side,
        rgba(250, 198, 50, 0.34) 0%,
        rgba(242, 167, 75, 0.14) 46%,
        transparent 74%);
    mix-blend-mode: multiply;
    animation: payStageBreathe 7.5s ease-in-out infinite alternate;
}
/* Film grain, so the soft gradients never band on a cheap phone screen. */
.landing .pay-stage::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    opacity: 0.06;
    mix-blend-mode: multiply;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.18 0 0 0 0 0.16 0 0 0 0 0.12 0 0 0 1 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

@keyframes payStageSway    { from { transform: translateX(-17%); }     to { transform: translateX(17%); } }
@keyframes payStageCounter { from { transform: translateX(10.625%); }  to { transform: translateX(-10.625%); } }
@keyframes payStageBreathe { from { scale: 0.9; opacity: 0.8; }         to { scale: 1.07; opacity: 1; } }

/* Scrolled away, the light stops: nothing to see, nothing to spend. The class
   is set by armPayStage() in js/landing.js. */
.landing .pay-stage.is-offscreen .pay-stage__light,
.landing .pay-stage.is-offscreen .pay-stage__stone,
.landing .pay-stage.is-offscreen .pay-stage__light::after { animation-play-state: paused; }

.landing .pay-stage__inner { position: relative; max-width: var(--max); margin-inline: auto; }

/* ── Head ──
   Layout, alignment and type now come from .sec-head at the end of this file,
   which this element also carries. What stays here is only the marble pool
   below, which exists because of THIS section's background and nothing else. */
.landing .pay-stage__head {
    position: relative;
    margin-bottom: clamp(52px, 7vw, 84px);
}
/* A calm pool of marble behind the words, so small type never lands on a dark
   vein as the light passes over it. */
.landing .pay-stage__head::before {
    content: "";
    position: absolute;
    z-index: -1;
    inset: -14% -8%;
    background: radial-gradient(closest-side, rgba(250, 247, 241, 0.86), rgba(250, 247, 241, 0.5) 60%, transparent 100%);
}
/* The centred eyebrow and its second gold rule went with the centring. Left
   against a hard edge, one leading rule is enough; the trailing one existed
   only to stop a centred label looking lopsided. */
/* The title, mask, line and lead rules that used to sit here are gone. They
   were this section's private copy of a heading, and .sec-head at the end of
   this file is now the only one. Leaving them would have meant two sets of
   class names for the same thing, which is how the page ended up with two
   different headings in the first place. */

/* ── The three ways ── */
.landing .pay {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(14px, 2vw, 24px);
    margin: 0 auto;
    padding: 0;
    list-style: none;
}
.landing .pay__item {
    position: relative;
    display: block;
    overflow: hidden;
    aspect-ratio: 4 / 5;
    max-width: 100%;
    border-radius: var(--r-l);
    border: 1px solid rgba(217, 179, 132, 0.55);
    background-color: var(--canvas-deep);
    box-shadow: 0 20px 40px -18px rgba(47, 51, 49, 0.18);
    transition: translate 0.55s cubic-bezier(.16, 1, .3, 1),
                box-shadow 0.55s cubic-bezier(.16, 1, .3, 1);
}
/* THE REVEAL TRAP, FOURTH TIME. Every .pay__item also carries .reveal, and
   `.reveal-armed .landing .reveal.is-in` (0,4,0) sets both `transform: none`
   and its own `transition` list. A hover written with `transform` loses that
   fight outright, and any `transition` here is replaced by the reveal's.
   So the lift uses the separate `translate` property, which composes with
   transform instead of competing with it, and this rule re-states the
   reveal's transitions WITH the hover ones added, at (0,5,0). */
.reveal-armed .landing .pay .pay__item.is-in {
    transition: opacity 1.2s var(--ease-out) var(--d, 0ms),
                transform 1.2s var(--ease-out) var(--d, 0ms),
                translate 0.55s cubic-bezier(.16, 1, .3, 1),
                box-shadow 0.55s cubic-bezier(.16, 1, .3, 1);
}

.landing .pay__media { position: absolute; inset: 0; display: block; padding: 0; border: 0; }
.landing .pay__media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.9s cubic-bezier(.16, 1, .3, 1);
}
/* Kept because the class is still in the markup; every tile fills now. */
.landing .pay__media--photo img { object-fit: cover; }

/* The floating label: a solid surface, because the three pictures differ too
   much at the bottom edge for text laid on a photo to stay readable. */
.landing .pay__body {
    position: absolute;
    right: 14px;
    bottom: 14px;
    left: 14px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    overflow: hidden;
    padding: 16px 18px;
    border-radius: var(--r-m);
    background-color: rgba(255, 255, 255, 0.94);
    -webkit-backdrop-filter: blur(14px) saturate(1.3);
            backdrop-filter: blur(14px) saturate(1.3);
    box-shadow: 0 10px 28px -12px rgba(47, 51, 49, 0.45);
    transition: transform 0.5s cubic-bezier(.16, 1, .3, 1);
}
/* Gold leaf catching the light as the card is picked up. */
.landing .pay__body::after {
    content: "";
    position: absolute;
    top: -40%;
    bottom: -40%;
    left: -60%;
    width: 40%;
    pointer-events: none;
    background: linear-gradient(100deg, transparent, rgba(250, 198, 50, 0.28), rgba(255, 244, 214, 0.7), rgba(250, 198, 50, 0.22), transparent);
    transform: translateX(0) skewX(-18deg);
}
.landing .pay__name {
    display: block;
    color: var(--gold-ink);            /* antique gold, 6.3:1 on the plate */
    font-family: var(--font-display);
    font-size: 25px;
    font-weight: 500;
    line-height: 1.12;
    letter-spacing: -0.012em;
}
.landing .pay__note { color: var(--ink-2); font-size: 14px; line-height: 1.5; }

/* The letter roll. armPaymentNames() splits each name into words, and each
   word holds its letters twice. Every WORD is its own clip, not the whole
   name: a name that wraps onto two lines would otherwise show letters from
   the first line sliding through the second. */
.landing .pay__word {
    position: relative;
    display: inline-block;
    overflow: hidden;
    vertical-align: top;
    padding-block: 0.04em 0.14em;
    margin-block: -0.04em -0.14em;
}
.landing .pay__letters { display: block; white-space: nowrap; }
.landing .pay__letters--copy { position: absolute; inset: 0.04em 0 auto; }
.landing .pay__char {
    display: inline-block;
    transition: transform 0.5s cubic-bezier(.16, 1, .3, 1);
    transition-delay: calc(var(--i, 0) * 16ms);
}
.landing .pay__letters--copy .pay__char { transform: translateY(130%); }

/* Hover only where hover is real. On a phone a tap would otherwise leave the
   card stuck lifted with its name half-rolled. */
@media (hover: hover) {
    .landing .pay__item:hover {
        translate: 0 -6px;
        box-shadow: 0 34px 60px -24px rgba(122, 90, 30, 0.42);
    }
    .landing .pay__item:hover .pay__media img { transform: scale(1.05); }
    .landing .pay__item:hover .pay__body { transform: translateY(-4px); }
    .landing .pay__item:hover .pay__body::after {
        transform: translateX(520%) skewX(-18deg);
        transition: transform 1.1s var(--ease-out);
    }
    .landing .pay__item:hover .pay__letters--first .pay__char { transform: translateY(-130%); }
    .landing .pay__item:hover .pay__letters--copy .pay__char { transform: translateY(0); }
}

/* ── The truth, kept, on its own glass ── */
.landing .pay__truth {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    max-width: 760px;
    margin: clamp(32px, 4vw, 46px) auto 0;
    padding: 16px 22px;
    border: 1px solid rgba(217, 179, 132, 0.55);
    border-radius: 18px;
    background-color: rgba(255, 255, 255, 0.88);
    -webkit-backdrop-filter: blur(12px);
            backdrop-filter: blur(12px);
    color: var(--ink-2);
    font-size: 14px;
    line-height: 1.65;
}
.landing .pay__truth .icon { flex: none; width: 20px; height: 20px; margin-top: 2px; color: var(--gold-ink); }
.landing .pay__truth strong { color: var(--ink); font-weight: 600; }

/* Reduced motion: the same band, perfectly still. `animation: none` rather
   than the page-wide 0.01ms duration, which on an infinite alternating
   animation would flicker between its two ends every frame. */
@media (prefers-reduced-motion: reduce) {
    .landing .pay-stage__light,
    .landing .pay-stage__stone,
    .landing .pay-stage__light::after { animation: none !important; }
    .landing .pay__char,
    .landing .pay__body::after { transition: none !important; }
}

/* ── Closing band — the one loud moment on the page ──────────────────────────
   Everything above is warm and quiet. The page ends on deep navy because the
   closing band has exactly one job, and gold finally gets to behave like a
   colour here: 5.98:1 on this ground, where on cream it was 2.28:1.          */
.landing .closing {
    padding: 110px var(--pad); background-color: var(--band); color: #fff;
    background-image: radial-gradient(120% 100% at 50% 0%, rgba(250,198,50,.14), transparent 62%);
}
.landing .closing__inner { max-width: 680px; margin-inline: auto; text-align: center; }
.landing .closing__title { margin-bottom: 16px; color: #fff; font-size: var(--step-4); font-weight: 300; }
.landing .closing__text { margin-bottom: 34px; color: #CFD4D1; font-size: 16.5px; line-height: 1.7; }
.landing .closing__actions { display: flex; flex-wrap: wrap; gap: 13px; justify-content: center; }
.landing .closing .btn--gold { background-color: var(--gold); color: #2A2205; }
.landing .closing .btn--gold:hover { background-color: #FFD65A; }
.landing .closing .btn--outline { border-color: rgba(255,255,255,.4); color: #fff; }
.landing .closing .btn--outline:hover { background-color: rgba(255,255,255,.1); border-color: #fff; }

/* ── Footer ──────────────────────────────────────────────────────────────── */
.landing .footer { padding: 66px var(--pad) 30px; background-color: var(--band-deep); color: rgba(255,255,255,.66); font-size: 14px; }
.landing .footer__grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 44px; max-width: var(--max); margin-inline: auto; }
.landing .footer__head { margin-bottom: 13px; color: #fff; font-family: var(--font-display); font-size: 21px; }
.landing .footer__text { max-width: 40ch; font-size: 15px; line-height: 1.75; }
.landing .footer__links,
.landing .footer__contact { display: flex; flex-direction: column; gap: 10px; margin: 0; padding: 0; list-style: none; }
.landing .footer__links a,
.landing .footer__contact a { color: rgba(255,255,255,.78); text-decoration: none; }
.landing .footer__links a:hover,
.landing .footer__contact a:hover { color: var(--gold); }
.landing .footer__bottom {
    max-width: var(--max); margin: 44px auto 0; padding-top: 22px;
    border-top: 1px solid rgba(255,255,255,.12);
    color: rgba(255,255,255,.5); font-size: 12.5px;
}

/* ── Motion ──────────────────────────────────────────────────────────────────
   THE CURVE. cubic-bezier(0.22, 0.61, 0.36, 1) is a pure decelerate — it
   leaves at full speed and eases to a stop, with no acceleration phase at all.
   Everything that reveals on this page uses it and nothing uses anything else.

   THE NUMBERS, and why they look wrong. 1.2 seconds over 10 pixels is more
   than twice as slow as the 0.55s/14px this page had, over a shorter distance.
   That is the whole trick: a long, small, decelerating move reads as something
   SETTLING INTO PLACE, while a short fast one reads as something SLIDING IN —
   and sliding in is what makes a page feel templated. Measured off the
   reference sites, and it is the single change that does the most work.

   Only opacity and transform animate. Both are composited, neither triggers
   layout, so a reveal costs nothing measurable on the phone a patient walked
   in with. */
.landing { --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1); }

.reveal-armed .landing .reveal { opacity: 0; transform: translateY(10px); }
.reveal-armed .landing .reveal.is-in {
    opacity: 1;
    transform: none;
    /* --d is the stagger, set per element by script. */
    transition: opacity 1.2s var(--ease-out) var(--d, 0ms),
                transform 1.2s var(--ease-out) var(--d, 0ms);
}

/* THE HERO ENTRANCE. Four lines arriving in sequence rather than together —
   eyebrow, headline, sentence, buttons — so the first thing a visitor sees is
   the storefront resolving into a page rather than a page appearing at once.

   Guarded behind .reveal-armed, which only script adds. With JavaScript off,
   blocked, or still parsing, none of this applies and the hero is simply
   there. A patient looking for a phone number must never meet a blank screen
   because an animation did not run. */
@keyframes heroRise { to { opacity: 1; transform: none; } }

.reveal-armed .landing .hero__kick,
.reveal-armed .landing .hero__title,
.reveal-armed .landing .hero__text,
.reveal-armed .landing .hero__actions {
    opacity: 0;
    transform: translateY(14px);
    animation: heroRise .95s var(--ease-out) forwards;
}
.reveal-armed .landing .hero__kick { animation-delay: .15s; }
.reveal-armed .landing .hero__title { animation-delay: .28s; }
.reveal-armed .landing .hero__text { animation-delay: .44s; }
.reveal-armed .landing .hero__actions { animation-delay: .58s; }

@media (prefers-reduced-motion: reduce) {
    .landing *,
.landing *::before,
.landing *::after {
        animation-duration: .01ms !important;
        animation-delay: 0ms !important;
        transition-duration: .01ms !important;
        transition-delay: 0ms !important;
    }
    .reveal-armed .landing .reveal { opacity: 1 !important; transform: none !important; }
    .reveal-armed .landing .hero__kick,
.reveal-armed .landing .hero__title,
.reveal-armed .landing .hero__text,
.reveal-armed .landing .hero__actions { opacity: 1 !important; transform: none !important; }
}

/* ── Responsive ──────────────────────────────────────────────────────────── */
/* Four wayfinding photos and three tall payment cards need a middle step —
   dropping straight from 4-up to 1-up leaves a tablet showing one enormous
   photo per screen. */
/* SHORT SCREENS. The hero copy is anchored to the bottom, so the shorter the
   viewport the higher that block sits — and at around 720px tall it climbs
   into "REINA G. GAPIT, D.M.D." on the glass. Two moves: lift the crop so her
   signage rides higher in the frame (a LOWER percentage lifts it), and take
   a few points off the headline so the block is shorter to begin with.
   This overlap has been reported twice; check it whenever the hero changes. */
@media (max-height: 820px) {
    .landing .hero { background-position: center 30%; }
    .landing .hero__title { font-size: clamp(40px, 3.6vw + 14px, 66px); }
    .landing .hero__text { margin-bottom: 26px; }
    /* The eyebrow pill is the last ~50px pushing the block into her signage,
       and it is the one line here that is pure repetition — the top bar already
       reads "Stall 104B, Ground Floor, Ramaida Centrum" two inches above it.
       Dropping it on short screens costs the visitor nothing and buys back
       exactly the room the headline needs. */
    .landing .hero__kick { display: none; }
}

/* PHONES AND TABLETS (2026-09-24). Up to 1000px the hero is about 560-600px
   tall and its text starts near the top, so the 4:3 storefront scaled to
   "cover" put "REINA G. GAPIT, D.M.D." (40-46% down the photo) right where the
   headline begins. Measured on ten screens from 360x640 to 1000x800: the
   clear band between the navbar and the text is only ~66px, and enlarging the
   photo to 135% of the hero's height, anchored to its bottom edge, places her
   name inside that band on every one of them. Only the ceiling is cropped.
   If the navbar, top bar or hero padding changes, re-measure this. */
@media (max-width: 1000px) {
    .landing .hero { background-size: auto 135%; background-position: 40% 100%; }
    /* Half the bytes (146 KB, not 312 KB) and still sharp at this crop on a
       3x phone screen. Preloaded in templates/partials/page-head.php. */
    .landing { --hero-photo: url("../images/clinic-hero-1280.jpg"); }
}

/* Phones: the headline scales with the screen width so "Compassionate Care,"
   always fits on its first line (about 37px at 360px, 44px at 430px) and the
   tagline reads as two balanced lines, never with "Care," left alone. */
@media (max-width: 600px) {
    .landing .hero__title { font-size: clamp(34px, 10.2vw, 46px); }
}

@media (max-width: 1100px) {
    /* This wrapper now contains one carousel stage plus its controls, not four
       thumbnail cards. The old two-column tablet rule squeezed the photo into
       half the available width and made the caption cover the landmark. */
    .landing .wayfind { grid-template-columns: minmax(0, 1fr); }
}

@media (min-width: 621px) and (max-width: 1100px) {
    .landing .wayfind--live .wayfind__stage {
        aspect-ratio: auto;
        box-shadow: none;
    }
    .landing .wayfind--live .wayfind__step.is-current { position: relative; }
    .landing .wayfind--live .wayfind__frame {
        height: auto;
        aspect-ratio: 16 / 9;
        box-shadow: 0 24px 44px -28px rgba(20, 14, 9, 0.65);
    }
    .landing .wayfind--live .wayfind__step figcaption {
        position: static;
        margin-top: 13px;
        background-color: var(--canvas-lift);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        box-shadow: none;
    }
}

@media (max-width: 1000px) {
    .landing { --gap: 68px; --pad: 24px; --step-4: 38px; --step-5: 44px; --step-3: 28px; }
    /* Section-head spacing at this width is handled by .sec-head's own narrow
       rule. .section__lead stays: a few inner blocks still use it. */
    .landing .section__lead { margin-top: 12px; }
    /* One column: numeral, headline, sentence, tags, Book -- which is the DOM
       order once .svc-row__meta is display:contents, so the metadata still
       leads and the headline still follows it. */
    .landing .svc-row {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: none;
        gap: 12px;
        padding: 24px 20px;
    }
    .landing .svc-row__title,
    .landing .svc-row__tl,
    .landing .tags,
    .landing .svc-row__go { grid-column: 1; grid-row: auto; }
    .landing .svc-row__title { font-size: 27px; }
    .landing .svc-row__go { justify-self: start; align-self: start; margin-top: 4px; }
    .landing .pick,
.landing .visit,
.landing .footer__grid { grid-template-columns: minmax(0,1fr); }
    /* A 4:5 card at full phone width is taller than the screen and buries the
       next method below the fold. Wide banner instead — the picture still
       fills, it just stops being a portrait. */
    .landing .hero { min-height: 560px; padding-top: 170px; }
    .landing .navbar__menu,
    .landing .navbar__actions { display: none; }

    /* THE MOBILE DRAWER. Without this the hamburger does nothing at all.
       toggleMobileNav() in js/landing.js toggles `.is-open` on #navbar-menu and
       nothing else — there is no second class and no wrapper — so this rule and
       this rule alone is what makes the button work. It was lost when this file
       was rewritten with .landing scoping, and the menu stayed display:none on
       every phone and tablet.

       Login and Book stay hidden here, as they were before: the hero carries
       "Book a Visit" and "I'm here now" at full width a few hundred pixels
       below, so the actions in the bar are a duplicate on a small screen.

       The panel is opaque marble rather than glass. It drops over the
       storefront photograph, and a translucent drawer over a busy picture is
       where menu text stops being readable. */
    .landing .navbar__menu.is-open {
        display: flex;
        position: absolute;
        top: 100%;
        right: 0;
        left: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 2px;
        margin: 0;
        padding: 10px var(--pad) 18px;
        background-color: var(--canvas);
        border-bottom: 1px solid var(--line);
        box-shadow: 0 20px 44px -24px rgba(47, 51, 49, 0.55);
    }
    /* Inside the drawer the links sit on marble, not on the photograph, so the
       white and its shadow both have to go. 46px keeps them a real touch
       target for an older patient. */
    .landing .navbar__menu.is-open .navbar__link {
        display: flex;
        align-items: center;
        min-height: 46px;
        color: var(--ink-2);
        text-shadow: none;
        padding-bottom: 0;
    }
    .landing .navbar__menu.is-open .navbar__link.is-active,
    .landing .navbar__menu.is-open .navbar__link:hover { color: var(--ink); }
    /* The underline animates from the left edge of a full-width row, which
       reads as a stray rule rather than an underline. */
    .landing .navbar__menu.is-open .navbar__link::after { display: none; }

    /* Book and Login, full width at the bottom of the menu (2026-09-16).
       This replaces the old reasoning that the hero's "Book a Visit" made the
       bar's buttons a duplicate: the hero never offered Login, so a returning
       patient on a phone had no way in. 48px tall, a real thumb target. */
    .landing .navbar__menu.is-open .navbar__menu-actions {
        display: flex;
        flex-direction: column;
        gap: 10px;
        margin-top: 12px;
        padding-top: 14px;
        border-top: 1px solid var(--line);
    }
    .landing .navbar__menu-actions .btn {
        justify-content: center;
        width: 100%;
        min-height: 48px;
    }
    .landing .navbar__menu-actions .btn--outline-brand {
        border: 1px solid var(--brand);
        background-color: transparent;
        color: var(--brand);
    }
    .landing .navbar__menu-actions .btn--outline-brand:hover { background-color: var(--brand-wash); }
    /* A long menu on a short phone in landscape must scroll, not run off. */
    .landing .navbar__menu.is-open {
        max-height: calc(100dvh - 80px);
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    .landing .navbar__toggle {
        display: grid; place-items: center; margin-left: auto;
        width: 44px; height: 44px; border-radius: var(--r-s);
        border: 1px solid rgba(255,255,255,.4);
        background-color: rgba(255,255,255,.1); color: #fff;
    }
}


/* WAYS TO PAY ON TABLETS AND PHONES: a swipeable row, not a stack.
   The client asked for full pictures, not thumbnails. Stacked full-width, the
   three 4:5 cards run to about 1,300px of scrolling; squashed to 16:9 banners,
   the name plate covers half of each photograph. So they stay 4:5 and sit in a
   row the patient swipes through, with the next card peeking in from the
   right so it is obvious there is more. The row bleeds to the screen edges;
   the band's own overflow keeps the page from ever scrolling sideways. */
@media (max-width: 900px) {
    .landing .pay-stage__light {
        -webkit-mask-size: 110% 120%;
                mask-size: 110% 120%;
    }
    .landing .pay-stage__light::after { width: 96%; }
    /* gap and lead size now come from .sec-head's own narrow-screen rules. */

    .landing .pay {
        display: flex;
        gap: 14px;
        margin-inline: calc(var(--pad) * -1);
        padding: 6px var(--pad) 22px;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scroll-snap-type: x mandatory;
        scroll-padding-inline: var(--pad);
        scrollbar-width: none;
    }
    .landing .pay::-webkit-scrollbar { display: none; }
    .landing .pay__item {
        flex: 0 0 min(78%, 340px);
        scroll-snap-align: start;
    }
    .landing .pay__truth { margin-top: 18px; padding: 14px 16px; font-size: 13.5px; }
}

@media (max-width: 620px) {
    .landing .wayfind { grid-template-columns: minmax(0,1fr); }
    .landing .wayfind__frame img { height: 210px; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   THE SECTION HEADER — one implementation, every section
   ═══════════════════════════════════════════════════════════════════════════

   This page used to introduce its sections two different ways. Services,
   Getting seen, Where to find us and HMO each used a plain left-aligned block
   with the title at --step-4. Ways to pay had its own treatment: centred, a
   display line rising out of a mask, an eyebrow with a gold rule.

   So the page changed its mind about where a heading belongs halfway down —
   left, left, left, left, then suddenly centre — and only one section had any
   motion. That reads as a draft somebody stopped editing, not a decision.

   One component now, applied to all five. `.sec-head` carries the layout and
   the rise; the section-specific classes keep only what is genuinely specific
   to their own background (the marble pool behind Ways to pay, for instance).

   The rise is tied to the page's existing reveal system rather than a new
   observer: `.reveal` already gets `.is-in` from armScrollReveal(), and the
   hidden state only exists behind `.reveal-armed`, which that function adds
   and which it never adds when the visitor has asked for reduced motion or
   the browser has no IntersectionObserver. A heading can therefore never be
   left invisible — the worst outcome is that it simply appears.
   ------------------------------------------------------------------------ */

.landing .sec-head {
    position: relative;
    display: grid;
    justify-items: start;
    gap: 20px;
    margin: 0 auto clamp(44px, 6vw, 72px);
    text-align: left;
}

/* Left-aligned, with the single gold rule leading the label. That rule only
   reads as deliberate against a hard left edge — centred it needs a matching
   one on the other side just to look balanced, which is decoration added to
   fix a problem the centring created. */
.landing .sec-head .eyebrow { margin: 0; }

/* One size for every heading on the page. Ways to pay set the scale and the
   rest were two steps smaller, so the page had a climax in the wrong place:
   the section about payment methods shouted while "Four areas of care", which
   is what the clinic actually does, murmured. Same weight for all of them now,
   and the page keeps its rhythm through spacing and background instead. */
.landing .sec-head__title {
    margin: 0;
    font-weight: 300;
    font-size: clamp(38px, 8vw, 104px);
    line-height: 0.94;
    letter-spacing: -0.024em;
}

/* Each line rises out of its own mask. The padding gives Cormorant's
   ascenders and descenders room inside the clip; the negative margin gives
   that room back, so line spacing is unchanged by the mask existing. */
.landing .sec-head__mask {
    display: block;
    overflow: hidden;
    padding-block: 0.06em 0.12em;
    margin-block: -0.06em -0.12em;
}

.landing .sec-head__line { display: block; }

.landing .sec-head__lead {
    max-width: 48ch;
    margin: 0;
    color: var(--ink-2);
    font-size: var(--step-0);
    line-height: 1.65;
}

/* The rise itself. 108% rather than 100% so a descender clears the mask edge
   completely before the transition starts. */
.reveal-armed .landing .sec-head__line { transform: translateY(108%); }

.reveal-armed .landing .sec-head.is-in .sec-head__line {
    transform: none;
    transition: transform 1.15s var(--ease-out) 130ms;
}

/* The second line follows the first rather than arriving with it. */
.reveal-armed .landing .sec-head.is-in .sec-head__mask + .sec-head__mask .sec-head__line {
    transition-delay: 260ms;
}

/* Ways to pay no longer overrides the size — it is the same heading as the
   rest now, which is the point. */

@media (max-width: 640px) {
    .landing .sec-head { gap: 16px; }
    .landing .sec-head__lead { max-width: 38ch; }
}
