/*
 * Site styles. There is no CSS framework and no build step — this file is
 * served exactly as written, so everything the site needs is here or in the
 * site's own additions below.
 *
 * ---------------------------------------------------------------------------
 * FLUID TYPE & SPACE SCALE
 *
 * Every size below is derived from the six anchor numbers in --u-*. Change an
 * anchor and the whole scale moves with it, in proportion. That is the point:
 * retuning a site is editing six numbers, not auditing every value in the file.
 *
 * Each step is a clamp() between its value at the minimum viewport and its
 * value at the maximum, so text and spacing scale smoothly with the viewport
 * instead of jumping at breakpoints. No media queries are needed for sizing.
 *
 * TO RETUNE FOR THIS SITE (see refs/design/DESIGN.md):
 *   --u-min-ratio / --u-max-ratio   how dramatic the jump between sizes is.
 *                                   1.2 (minor third) reads calm and even;
 *                                   1.333 (perfect fourth) reads confident;
 *                                   above ~1.4 gets shouty for a practice site.
 *   --u-min-font / --u-max-font     base body size at each end, in px.
 *   --u-min-vw / --u-max-vw         the viewport range the scale spans.
 *
 * A larger max-ratio with the same min-ratio gives a site that is restrained on
 * a phone and expressive on a desktop, which usually suits a hero-led page.
 */
:root {
    /* --- Anchors: the dial for this site ------------------------------- */
    /* Anchored to the live page at 1440: body 16.5px, and the hero display
     * 74.25px. A 1.33 ratio puts --step-5 at ~69px and --step-6 within reach
     * of the display, without the mid-range steps overshooting the 20.6px h3
     * and 22px card headings the source actually uses. */
    --u-min-vw: 320;
    --u-max-vw: 1440;
    --u-min-font: 16;
    --u-max-font: 16.5;
    --u-min-ratio: 1.2;
    --u-max-ratio: 1.33;

    /* --- Derivation. Not usually edited by hand. ----------------------- */
    /* Slope and intercept of the line between the two anchor viewports,
     * expressed so each step can be written as clamp(min, calc(...), max). */
    --u-vw-range: calc(var(--u-max-vw) - var(--u-min-vw));

    /* Type steps, in rem at each anchor. Each step multiplies the previous
     * one by the ratio, so the relationship between sizes is fixed even as the
     * absolute values move. */
    --u-min-0: calc(var(--u-min-font) / 16);
    --u-max-0: calc(var(--u-max-font) / 16);

    --u-min--2: calc(var(--u-min-0) / var(--u-min-ratio) / var(--u-min-ratio));
    --u-max--2: calc(var(--u-max-0) / var(--u-max-ratio) / var(--u-max-ratio));
    --u-min--1: calc(var(--u-min-0) / var(--u-min-ratio));
    --u-max--1: calc(var(--u-max-0) / var(--u-max-ratio));
    --u-min-1: calc(var(--u-min-0) * var(--u-min-ratio));
    --u-max-1: calc(var(--u-max-0) * var(--u-max-ratio));
    --u-min-2: calc(var(--u-min-1) * var(--u-min-ratio));
    --u-max-2: calc(var(--u-max-1) * var(--u-max-ratio));
    --u-min-3: calc(var(--u-min-2) * var(--u-min-ratio));
    --u-max-3: calc(var(--u-max-2) * var(--u-max-ratio));
    --u-min-4: calc(var(--u-min-3) * var(--u-min-ratio));
    --u-max-4: calc(var(--u-max-3) * var(--u-max-ratio));
    --u-min-5: calc(var(--u-min-4) * var(--u-min-ratio));
    --u-max-5: calc(var(--u-max-4) * var(--u-max-ratio));

    /* --- Type scale ---------------------------------------------------- */
    /* step--2 fine print · step-0 body · step-2/3 section headings ·
     * step-4/5 hero display. Use these, not raw px. */
    --step--2: clamp(calc(var(--u-min--2) * 1rem), calc(var(--u-min--2) * 1rem + (var(--u-max--2) - var(--u-min--2)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max--2) * 1rem));
    --step--1: clamp(calc(var(--u-min--1) * 1rem), calc(var(--u-min--1) * 1rem + (var(--u-max--1) - var(--u-min--1)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max--1) * 1rem));
    --step-0: clamp(calc(var(--u-min-0) * 1rem), calc(var(--u-min-0) * 1rem + (var(--u-max-0) - var(--u-min-0)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max-0) * 1rem));
    --step-1: clamp(calc(var(--u-min-1) * 1rem), calc(var(--u-min-1) * 1rem + (var(--u-max-1) - var(--u-min-1)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max-1) * 1rem));
    --step-2: clamp(calc(var(--u-min-2) * 1rem), calc(var(--u-min-2) * 1rem + (var(--u-max-2) - var(--u-min-2)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max-2) * 1rem));
    --step-3: clamp(calc(var(--u-min-3) * 1rem), calc(var(--u-min-3) * 1rem + (var(--u-max-3) - var(--u-min-3)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max-3) * 1rem));
    --step-4: clamp(calc(var(--u-min-4) * 1rem), calc(var(--u-min-4) * 1rem + (var(--u-max-4) - var(--u-min-4)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max-4) * 1rem));
    --step-5: clamp(calc(var(--u-min-5) * 1rem), calc(var(--u-min-5) * 1rem + (var(--u-max-5) - var(--u-min-5)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max-5) * 1rem));

    /* --- Weight -------------------------------------------------------- */
    /* Named by the CSS value, not by a word. "bold" is a claim about how a
     * typeface renders; 700 is what you actually asked for, and two faces
     * disagree about which of their cuts reads as bold.
     *
     * THREE WEIGHTS, DELIBERATELY. Body, emphasis, headline — that is the
     * whole system, and it is expressed by which tokens exist rather than by
     * a rule asking politely. Adding --weight-800 needs a reason: the face
     * has a visibly distinct heavy cut AND 700 alone is not creating enough
     * contrast. If 700 and 800 render identically on screen, that is not one.
     * A flat hierarchy is almost always a spacing or size problem, not a
     * weight problem. */
    --weight-400: 400;  /* body */
    --weight-600: 600;  /* nav, card emphasis, eyebrows */
    --weight-700: 700;  /* headlines, CTAs */

    /* --- Leading ------------------------------------------------------- */
    /* A ladder rather than a derived scale, so it is t-shirt sized like
     * --space-* rather than numbered like --step-*. Tightest to loosest.
     *
     * The relationship worth holding: line-height falls as type size rises.
     * Display type at body leading looks unset; body copy at display leading
     * is unreadable. Pair --leading-xs with --step-4/5 and --leading-l with
     * --step-0. */
    --leading-xs: 1.05;   /* display, very large headlines */
    --leading-s: 1.18;     /* headings */
    --leading-m: 1.3;    /* subheadings, ledes, card copy */
    --leading-l: 1.5;     /* body copy */
    --leading-xl: 1.6;   /* long-form and small print, which need more air */

    /* --- Tracking ------------------------------------------------------ */
    /* Same shape: a ladder, tightest to loosest, in em so it scales with
     * whatever size it is applied to.
     *
     * The relationship: tracking tightens as size grows, and ALL-CAPS always
     * needs opening up — uppercase at 0 tracking reads cramped at any size.
     * Pair --tracking-xs with --step-4/5, --tracking-m with body, and
     * --tracking-l or --tracking-xl with any text-transform: uppercase. */
    --tracking-xs: -0.02em;  /* large display */
    --tracking-s: -0.01em;   /* headings */
    --tracking-m: 0;         /* body — the default, stated so it can be reset to */
    --tracking-l: 0.04em;    /* small caps-ish, buttons */
    --tracking-xl: 0.08em;   /* eyebrows and other all-caps runs */

    /* --- Space scale --------------------------------------------------- */
    /* Multiples of the base size rather than the type ratio, so spacing stays
     * predictable while type can be as dramatic as the site needs. */
    --space-3xs: clamp(0.25rem, calc(0.25rem + 0.1vw), 0.375rem);
    --space-2xs: clamp(0.5rem, calc(0.45rem + 0.2vw), 0.625rem);
    --space-xs: clamp(0.75rem, calc(0.68rem + 0.3vw), 0.9375rem);
    --space-s: clamp(1rem, calc(0.91rem + 0.43vw), 1.25rem);
    --space-m: clamp(1.5rem, calc(1.37rem + 0.65vw), 1.875rem);
    --space-l: clamp(2rem, calc(1.82rem + 0.87vw), 2.5rem);
    --space-xl: clamp(3rem, calc(2.73rem + 1.3vw), 3.75rem);
    --space-2xl: clamp(4rem, calc(3.64rem + 1.74vw), 5rem);
    --space-3xl: clamp(6rem, calc(5.46rem + 2.61vw), 7.5rem);

    /* --- Space pairs --------------------------------------------------- */
    /* A pair moves from the SMALLER step on a phone to the LARGER one on a
     * desktop, so the gap changes step rather than merely scaling. This is what
     * replaces per-breakpoint section padding: --space-l-2xl is roughly the old
     * "40-48px mobile, 80-96px desktop" rule, expressed once. */
    --space-2xs-xs: clamp(0.5rem, calc(0.35rem + 0.76vw), 0.9375rem);
    --space-xs-s: clamp(0.75rem, calc(0.57rem + 0.87vw), 1.25rem);
    --space-s-m: clamp(1rem, calc(0.7rem + 1.52vw), 1.875rem);
    --space-m-l: clamp(1.5rem, calc(1.13rem + 1.85vw), 2.5rem);
    --space-l-xl: clamp(2rem, calc(1.36rem + 3.15vw), 3.75rem);
    --space-xl-2xl: clamp(3rem, calc(2.27rem + 3.62vw), 5rem);
    --space-l-2xl: clamp(2rem, calc(0.91rem + 5.43vw), 5rem);
    --space-s-l: clamp(1.125rem, calc(0.72rem + 2.04vw), 2.5rem);  /* skip-a-step: grid gutter */
    --space-2xl-3xl: clamp(4rem, calc(2.55rem + 7.24vw), 7.5rem);

    /* --- Measure ------------------------------------------------------- */
    --measure: 65ch;        /* body copy */
    --measure-tight: 45ch;  /* card and caption copy */

    /* =====================================================================
     * COLOUR
     *
     * Three anchors drive the whole palette. Change them to match the
     * practice; everything else follows. See refs/design/DESIGN.md.
     *
     * That is the default path, and most sites never go past it. Underneath,
     * the palette is layered so a site can take more control WITHOUT hand-
     * writing hex values, which is what a migrated site needs:
     *
     *   1. Anchors        the three below. Tune these first.
     *   2. Per-role       --chroma-secondary, --l-tertiary and friends. A
     *                     brand's second colour is a designer's pick, not a
     *                     rotation of the first, so each role carries its own
     *                     hue, chroma and lightness, defaulting to the anchors.
     *   3. Neutrals       --hue-neutral, --chroma-ink, --chroma-ground. Greys
     *                     are their own decision -- see the block below.
     *   4. Polarity       --scheme. One number flips light/dark.
     *
     * Derive WITHIN a role, declare ACROSS roles. This is the same split
     * Bootstrap 5.3 makes (mix() generates each scale; the base of each theme
     * colour is declared) and the opposite of deriving everything from one
     * hue, which cannot express a real brand pair.
     *
     *   --palette-hue         the practice's brand hue, 0-360.
     *                         Roughly: 25 terracotta · 60 ochre · 145 green
     *                         · 195 teal · 240 blue · 275 violet · 340 rose
     *   --palette-chroma      how saturated the brand reads. OKLCH chroma is
     *                         NOT 0-1 — it runs about 0-0.37 in sRGB, and
     *                         above ~0.15 a surface colour starts to shout.
     *                         0.04 muted · 0.09 confident · 0.14 vivid
     *   --palette-secondary-shift
     *                         degrees from the primary to the secondary.
     *                         150-180 gives a complement; 30-60 an analogous
     *                         neighbour that reads calmer.
     * ===================================================================== */
    /* Hinchinbrook Health Care. Primary is the violet #9F7CF0 (oklch hue
     * 295.4); the kit's raw chroma of 0.168 is past the template's usable
     * range and reads as neon on a surface, so it is clamped to 0.15 and the
     * full-strength violet is reserved for accents.
     *
     * The kit's own "secondary" (#ECE5FF) sits 2.6 degrees from primary - a
     * tint, not a second hue. The real second colour on this site is the lime
     * #C6DE70 used on every button, at hue 119.6, which is +184 from primary.
     * That is what the shift encodes. */
    --palette-hue: 295.4;
    --palette-chroma: 0.15;
    --palette-secondary-shift: 184.2;

    --hue-primary: var(--palette-hue);
    --hue-secondary: calc(var(--palette-hue) + var(--palette-secondary-shift));

    /* Secondary and tertiary each carry their OWN chroma and lightness, not
     * the primary's. They default to it, so a site built from this template
     * still tunes with the three numbers above and renders identically.
     *
     * The override exists because a brand's second colour is often a designer's
     * choice rather than a systematic partner: on a migrated site the secondary
     * was measured at 3.6x the primary's chroma and 0.26 lighter in OKLCH
     * (deep forest green against warm terracotta). One shared chroma and one
     * shared lightness cannot express that pair, and forcing it produced a
     * washed-out grey-green beside a dusty mauve.
     *
     * This is the same concession the feedback colours below already make --
     * each of those carries its own chroma because "yellows need more to read
     * as yellow, reds less before they turn fluorescent". Brand colours want
     * the same latitude. */
    --chroma-secondary: var(--palette-chroma);
    --l-secondary: var(--l-solid);

    /* Tertiary: a third brand colour, typically doing button/CTA work, that is
     * neither a tint of the primary nor semantic. Practices routinely have one
     * ("Button Brown", "Morning Orange"). Defaults to an analogous neighbour of
     * the primary so it is harmless when unused. */
    --palette-tertiary-shift: 30;
    --hue-tertiary: calc(var(--palette-hue) + var(--palette-tertiary-shift));
    --chroma-tertiary: var(--palette-chroma);
    --l-tertiary: var(--l-solid);

    /* --- Neutrals: their own hue, not the brand's ---------------------
     *
     * --hue-neutral defaults to the brand hue, so a site that sets nothing
     * keeps the "greys feel of a piece with the accent" behaviour. But it is
     * a SEPARATE dial, because tying greys to the brand hue is not what any
     * mature system does and not what real practices choose:
     *
     *   - Tailwind ships five grey families (slate/gray/zinc/neutral/stone)
     *     precisely so the temperature of the greys is a decision.
     *   - Bootstrap keeps $gray independent of $theme-colors.
     *   - daisyUI declares base-100/200/300 per theme.
     *
     * And measured on our own migrated sites: both chose warm grounds at hue
     * 80-94 despite green brands at 145 and 166 -- roughly 80 degrees off the
     * brand. A green practice does not want green text, and at the default
     * hue 195 the old derivation gave --ink-strong an R-to-B spread of 17,
     * i.e. a visibly blue-black rather than a black.
     *
     * Set --hue-neutral to taste: the brand hue for a tinted-grey scheme, a
     * warm 70-90 for a settled off-black, or leave chroma at 0 for a true
     * neutral. --chroma-ink and --chroma-ground are separate because ink
     * carries tint better than a large ground does -- the same chroma that
     * reads as "warm grey" in a heading reads as "the wrong white" across a
     * full-bleed background. */
    /* +80 deg off the brand, which is what the previous code already did for
     * --ink-strong alone, and what both migrated practices independently
     * chose for their grounds (warm 80-94 against green brands at 145/166).
     * It defaults to the brand hue so that adding this dial changes nothing on
     * an existing site; the interesting values are elsewhere:
     *
     *   var(--palette-hue)              greys tinted toward the brand (default)
     *   calc(var(--palette-hue) + 80)   the offset real practices tend to pick
     *   70-90                           a warm, settled off-black
     *   with --chroma-ink: 0            a true neutral, no hue at all
     */
    --hue-neutral: var(--palette-hue);
    --chroma-ink: 0.012;    /* text. 0 = true grey; 0.03 = clearly tinted */
    --chroma-ground: calc(0.004 + 0.008 * (1 - var(--scheme)));  /* page background */
    --chroma-surface: calc(0.000 + 0.014 * (1 - var(--scheme))); /* raised surfaces */
    --chroma-border: calc(0.008 + 0.007 * (1 - var(--scheme)));  /* rules and outlines */
    /* Grounds carry MORE tint when dark and less when light: 0.014 across a
     * near-black reads as a warm dark, the same 0.014 across a near-white
     * reads as a colour cast. The old code expressed this by declaring the
     * light and dark neutrals separately; here it rides on --scheme. */

    /* Feedback hues are FIXED and do not follow the brand. A danger colour
     * that rotates with the practice's hue stops reading as danger — the
     * entire value of a semantic colour is that it means the same thing on
     * every site. Only the brand colours above derive from --palette-hue. */
    --hue-success: 145;
    --hue-warning: 75;
    --hue-danger: 27;
    --hue-info: 240;

    /* Lightness ramp. Dark mode overrides these below rather than declaring a
     * second palette — in OKLCH, dark mode is largely an inversion of these
     * four numbers. */
    --l-solid: 0.55;   /* solid fills: buttons, badges */
    --l-hover: 0.48;   /* one step darker for hover */
    --l-light: 0.66;   /* one step lighter: gradient partner for --primary */
    --l-muted: 0.92;   /* a touch stronger than pale, for wash gradients */
    --l-pale: 0.96;    /* tinted backgrounds */
    --l-on-solid: 0.99;/* text on a solid fill */

    /* --- Polarity -----------------------------------------------------
     *
     * --scheme is the one number that says which way round the site runs:
     * 1 = dark ink on a light ground (the norm), 0 = light ink on a dark
     * ground. Every neutral below is written as "light value, plus the
     * distance to its dark counterpart, times (1 - scheme)", so flipping the
     * one number inverts the whole set consistently.
     *
     * This is why the dark-mode block further down only sets --scheme and the
     * three brand-lightness values, instead of re-declaring eight neutrals
     * with a second set of hand-picked literals. Two hand-maintained sets
     * drift: the old block never declared --ink-strong at all, so headings
     * stayed at lightness 0.18 -- dark text on a dark ground.
     *
     * A site that should ALWAYS render dark sets --scheme: 0 here and deletes
     * the media query. A site that should never flip deletes the query alone. */
    --scheme: 1;

    /* Neutral lightness, light-mode value first, dark-mode value second.
     * Edit these to shift contrast; they are dials, not literals buried in
     * the colour definitions. */
    --l-ink-strong: calc(0.18 + 0.79 * (1 - var(--scheme)));
    --l-ink:        calc(0.25 + 0.70 * (1 - var(--scheme)));
    --l-ink-mid:    calc(0.45 + 0.35 * (1 - var(--scheme)));
    --l-ink-soft:   calc(0.54 + 0.12 * (1 - var(--scheme)));
    --l-bg:         calc(0.99 - 0.81 * (1 - var(--scheme)));
    --l-surface:    calc(1.00 - 0.78 * (1 - var(--scheme)));
    --l-border:     calc(0.90 - 0.58 * (1 - var(--scheme)));
    --l-border-strong: calc(0.82 - 0.40 * (1 - var(--scheme)));

    /* Brand */
    --primary: oklch(var(--l-solid) var(--palette-chroma) var(--hue-primary));
    --primary-hover: oklch(var(--l-hover) var(--palette-chroma) var(--hue-primary));
    --primary-light: oklch(var(--l-light) var(--palette-chroma) var(--hue-primary));
    --primary-muted: oklch(var(--l-muted) calc(var(--palette-chroma) * 0.35) var(--hue-primary));
    /* Chroma falls as lightness rises — a pale tint at full chroma reads
     * muddy rather than tinted. */
    --primary-pale: oklch(var(--l-pale) calc(var(--palette-chroma) * 0.25) var(--hue-primary));
    --on-primary: oklch(var(--l-on-solid) 0 0);

    --secondary: oklch(var(--l-secondary) var(--chroma-secondary) var(--hue-secondary));
    --secondary-hover: oklch(calc(var(--l-secondary) - 0.07) var(--chroma-secondary) var(--hue-secondary));
    --secondary-light: oklch(calc(var(--l-secondary) + 0.11) var(--chroma-secondary) var(--hue-secondary));
    --secondary-pale: oklch(var(--l-pale) calc(var(--chroma-secondary) * 0.25) var(--hue-secondary));
    --on-secondary: oklch(var(--l-on-solid) 0 0);

    /* Tertiary, same shape as the two above. */
    --tertiary: oklch(var(--l-tertiary) var(--chroma-tertiary) var(--hue-tertiary));
    --tertiary-hover: oklch(calc(var(--l-tertiary) - 0.07) var(--chroma-tertiary) var(--hue-tertiary));
    --tertiary-pale: oklch(var(--l-pale) calc(var(--chroma-tertiary) * 0.25) var(--hue-tertiary));
    --on-tertiary: oklch(var(--l-on-solid) 0 0);

    /* Aliases for the older names in DESIGN.md, so existing markup and any
     * site copied from an earlier template keep working. */
    --accent: var(--primary);
    --accent-dark: var(--primary-hover);
    --accent-pale: var(--primary-pale);

    /* Feedback. Chroma is per-hue: yellows need more to read as yellow, reds
     * less before they turn fluorescent. */
    --success: oklch(calc(var(--l-solid) - 0.03) 0.13 var(--hue-success));
    --success-pale: oklch(var(--l-pale) 0.03 var(--hue-success));
    --warning: oklch(0.75 0.14 var(--hue-warning));
    --warning-pale: oklch(var(--l-pale) 0.04 var(--hue-warning));
    --danger: oklch(var(--l-solid) 0.17 var(--hue-danger));
    --danger-pale: oklch(var(--l-pale) 0.03 var(--hue-danger));
    --info: oklch(var(--l-solid) 0.11 var(--hue-info));
    --info-pale: oklch(var(--l-pale) 0.03 var(--hue-info));

    /* Neutrals. DESIGN.md asked in prose for "a teal practice and a navy
     * practice want different --ink warmth"; --hue-neutral is that, made a
     * dial instead of a fixed derivation from the brand.
     *
     * Hue and chroma come from the --hue-neutral / --chroma-*
     * dials above, lightness from the --l-* dials, so all three are tunable
     * without editing any of these lines. Ink chroma tapers as text gets
     * lighter, and grounds use the lower --chroma-ground throughout. */
    --ink-strong: oklch(var(--l-ink-strong) calc(var(--chroma-ink) * 2.5) calc(var(--hue-neutral) + 80));  /* headings, dark surfaces */
    --ink: oklch(var(--l-ink) calc(var(--chroma-ink) * 1.25) var(--hue-neutral));
    --ink-mid: oklch(var(--l-ink-mid) var(--chroma-ink) var(--hue-neutral));
    --ink-soft: oklch(var(--l-ink-soft) calc(var(--chroma-ink) * 0.833) var(--hue-neutral));
    --bg: oklch(var(--l-bg) var(--chroma-ground) var(--hue-neutral));
    --surface: oklch(var(--l-surface) var(--chroma-surface) var(--hue-neutral));
    --border: oklch(var(--l-border) var(--chroma-border) var(--hue-neutral));
    --border-strong: oklch(var(--l-border-strong) calc(var(--chroma-border) * 1.25) var(--hue-neutral));

    /* Paired foreground for each ground, the way daisyUI's -content and
     * Bootstrap's -emphasis work. Use --on-bg rather than reaching for --ink
     * directly when the ground itself might be flipped. */
    --on-bg: var(--ink);
    --on-surface: var(--ink);

    /* --- Grid ---------------------------------------------------------- */
    /* Deliberately minimal: the container and gutter are fluid, placement is
     * left to each layout. Use .u-container and .u-grid below. */
    --grid-max-width: 77.5rem;
    --grid-gutter: var(--space-s-l);
    --grid-columns: 12;

    /* --- Radius -------------------------------------------------------- */
    /* Named by intent rather than by number, so a change of scale does not
     * mean auditing every --radius-3 in the stylesheet. */
    --radius-xs: 0.25rem;   /* tags, inline chips */
    --radius-s: 0.5rem;     /* buttons, inputs */
    --radius-m: 0.75rem;    /* cards */
    --radius-l: 1.25rem;    /* panels, modals, hero media */
    --radius-round: 50%;    /* avatars */
    --radius-pill: 999px;   /* pills, badges */

    /* --- Border widths ------------------------------------------------- */
    --border-thin: 1px;
    --border-medium: 2px;
    --border-thick: 4px;    /* accent rules, active states */

    /* --- Shadows ------------------------------------------------------- */
    /* Two knobs drive every shadow. --shadow-color takes the brand hue so a
     * raised card reads as part of this practice rather than as generic grey;
     * --shadow-strength is what dark mode adjusts, because a shadow on a dark
     * background needs MORE opacity to be seen, not less. */
    --shadow-color: var(--hue-primary, 220) 20% 15%;
    --shadow-strength: 1%;

    --shadow-s:
        0 1px 2px -1px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 9%));
    --shadow-m:
        0 3px 5px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 3%)),
        0 7px 14px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 5%));
    --shadow-l:
        0 -1px 3px 0 hsl(var(--shadow-color) / calc(var(--shadow-strength) + 2%)),
        0 6px 12px -3px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 3%)),
        0 15px 30px -6px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 5%));

    --shadow-inner-s: inset 0 1px 2px 0 hsl(var(--shadow-color) / calc(var(--shadow-strength) + 6%));
    --shadow-inner-m: inset 0 2px 6px 0 hsl(var(--shadow-color) / calc(var(--shadow-strength) + 9%));

    /* --- Layers -------------------------------------------------------- */
    /* Six values, so z-index is never invented at the call site. */
    --layer-behind: -1;    /* decorative washes sitting behind content */
    --layer-base: 1;
    --layer-raised: 2;      /* hover cards, sticky rows */
    --layer-nav: 3;         /* sticky header */
    --layer-overlay: 4;     /* dropdowns, popovers */
    --layer-modal: 5;       /* dialogs and their backdrop */
    --layer-top: 2147483647;/* skip links, live-region alerts */

    /* --- Motion -------------------------------------------------------- */
    --duration-fast: 120ms;   /* hover, focus */
    --duration-base: 220ms;   /* most transitions */
    --duration-slow: 400ms;   /* entrances */
    --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
    --reveal-distance: 1.5rem;

    /* Typefaces. Set these per site; everything else references them. */
    /* Open Sans body, Cabin display - both taken from the live page's
     * computed styles, not from the kit's declared scale, which names faces
     * the page does not actually render. */
    --font-body: 'Open Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-heading: 'Cabin', Georgia, serif;
}

/*
 * Dark mode is DELIBERATELY ABSENT, per the template's own note ("Delete
 * this block for a site that should only ever render light").
 *
 * Hinchinbrook renders light only, matching the live site, which has no
 * dark mode at all. The block was also actively wrong here rather than
 * merely unused: it flipped --l-on-solid to 0.18, so --on-primary became
 * near-black, and every element relying on it - the clinic cards, the top
 * bar, solid buttons - rendered dark ink for any visitor whose OS was set
 * to dark, while the page grounds stayed light because the site layer sets
 * them explicitly. Dark text on a dark violet card, and a broken half-state
 * generally.
 *
 * A headless browser defaults to light, so this is invisible to a default
 * screenshot: test with colorScheme:'dark' before reintroducing anything
 * scheme-dependent.
 */

/* ═══════════════════════════════════════════════════════════════════════
 * RESET
 *
 * Josh Comeau's Custom CSS Reset (joshwcomeau.com/css/custom-css-reset/),
 * lightly adapted. Normalises browser defaults so the base layer below is
 * building on the same ground in every browser. Leave this alone; make
 * design decisions in the base layer and the tokens above it.
 * ═══════════════════════════════════════════════════════════════════════ */

*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; }

html {
    -webkit-text-size-adjust: 100%;
    -moz-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

body {
    -webkit-font-smoothing: antialiased;
    line-height: 1.5;
}

/* Media is block-level and never overflows its container. */
img, picture, video, canvas, svg {
    display: block;
    max-width: 100%;
}

/* Form controls inherit typography rather than using browser chrome. */
input, button, textarea, select { font: inherit; }

/* Long words and URLs wrap instead of forcing a horizontal scrollbar. */
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }

/* A new stacking context on the root, so app-level layers cannot escape. */
#root, #__next { isolation: isolate; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ═══════════════════════════════════════════════════════════════════════
 * ELEMENT BASE LAYER
 *
 * Bare elements are styled here so a page is correct with no classes at
 * all. Without this, an unclassed <h2> falls back to the browser default
 * and whoever writes the page patches it with an inline style — which is
 * how a site ends up with a different heading treatment per page.
 *
 * Every heading has a matching .h1-.h6 class. Use the ELEMENT for document
 * structure (SEO, screen readers, outline) and the CLASS for appearance,
 * so an <h1> can look like an eyebrow without lying about the hierarchy:
 *
 *     <h1 class="h4">Still the page's real heading, just smaller</h1>
 *
 * Sites override these; they are a floor, not a straitjacket.
 * ═══════════════════════════════════════════════════════════════════════ */

body {
    font-family: var(--font-body);
    font-size: var(--step-0);
    font-weight: var(--weight-400);
    line-height: var(--leading-l);
    color: var(--ink);
    background: var(--bg);
}

/* Headings ─────────────────────────────────────────────────────────────
 * Margins are top-heavy on purpose: a heading belongs to what follows it,
 * so the space above is larger than the space below. */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    margin: var(--space-l) 0 var(--space-s);
    font-family: var(--font-heading);
    font-weight: var(--weight-700);
    line-height: var(--leading-s);
    letter-spacing: var(--tracking-xs);
    color: var(--ink-strong);
    text-wrap: balance;
}

:where(h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6) + * {
    margin-top: 0;
}

/* A heading opening its container needs no space above it. */
:where(h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6):first-child {
    margin-top: 0;
}

h1, .h1 { font-size: var(--step-5); }
h2, .h2 { font-size: var(--step-4); }
h3, .h3 { font-size: var(--step-3); }
h4, .h4 { font-size: var(--step-2); }
h5, .h5 { font-size: var(--step-1); line-height: var(--leading-m); }
h6, .h6 {
    font-size: var(--step-0);
    line-height: var(--leading-m);
    letter-spacing: var(--tracking-m);
    text-transform: uppercase;
}

/* A highlighted phrase inside a heading. One mechanism, not three. */
:where(h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6) em {
    font-style: italic;
    color: var(--primary);
}

/* Text ─────────────────────────────────────────────────────────────── */
p, ul, ol, dl, blockquote, figure, table, pre {
    margin: 0 0 var(--space-m);
}

/*
 * Line length is a container's job, not every paragraph's — capping each <p>
 * leaves text hugging the left of any column already sized for reading.
 * Use .measure (or set a width on the container) where prose needs it.
 */
.measure { max-width: var(--measure); }
.measure-tight { max-width: var(--measure-tight); }

/* Opening paragraph: larger and looser than body copy. */
.lede {
    font-size: var(--step-1);
    line-height: var(--leading-m);
    color: var(--ink-mid);
}

/* Small label above a heading. */
.eyebrow {
    display: block;
    margin-bottom: var(--space-2xs);
    font-size: var(--step--1);
    font-weight: var(--weight-600);
    letter-spacing: var(--tracking-l);
    text-transform: uppercase;
    color: var(--primary);
}

small, .text-small { font-size: var(--step--1); }

strong, b { font-weight: var(--weight-700); }

a {
    color: var(--primary);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
    transition: color var(--duration-fast) var(--ease-out);
}
a:hover { color: var(--primary-hover); }

/* A visible focus ring on every interactive element, always. */
:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
    border-radius: var(--radius-xs);
}

ul, ol { padding-left: var(--space-m); }

/*
 * List spacing applies to PROSE lists only. Navigation, button groups and
 * card grids are lists too, and flow margins on those knock flex/grid items
 * out of alignment (the site header) or balloon the spacing (the footer).
 *
 * Presence of a class is not the test — a footer nav is a nav whether or not
 * anyone put a class on it — so navigation context opts out explicitly.
 */
:where(ul, ol) > li { margin-bottom: var(--space-2xs); }
:where(ul, ol) > li:last-child { margin-bottom: 0; }

nav ul, nav ol,
header ul, header ol,
footer ul, footer ol,
menu {
    margin: 0;
    padding-left: 0;
    list-style: none;
}

nav li, header li, footer li, menu li {
    margin-bottom: 0;
}

/* A list explicitly used for layout carries no bullets, indent or margin. */
:where(ul, ol)[class] {
    margin: 0;
    padding-left: 0;
    list-style: none;
}

:where(ul, ol)[class] > li { margin-bottom: 0; }

blockquote {
    padding-left: var(--space-m);
    border-left: var(--border-thick) solid var(--primary-pale);
    color: var(--ink-mid);
    font-style: italic;
}

hr {
    height: 0;
    margin: var(--space-l) 0;
    border: 0;
    border-top: var(--border-thin) solid var(--border);
}

code, kbd, samp, pre {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.9em;
}

/* Media ────────────────────────────────────────────────────────────────
 * Images are rounded by default. The square-photo bug on Wellbrook was an
 * <img> with no radius sitting beside cards that had one. */
img, picture, video, canvas, svg {
    height: auto;
}

img {
    border-radius: var(--radius-m);
    background: var(--surface);
}

/*
 * Logos, icons and inline SVG are not photographs — a background plate and a
 * radius are wrong for them, and show up as a white box on a dark footer.
 */
img[class*="logo"], img[class*="icon"], .logo img, svg {
    border-radius: 0;
    background: none;
}

/* Opt out where a radius is wrong: full-bleed art, decorative crops. */
img.is-flush, .is-flush img { border-radius: 0; background: none; }

figure { margin-inline: 0; }

figcaption {
    margin-top: var(--space-2xs);
    font-size: var(--step--1);
    color: var(--ink-soft);
}

/* Tables ───────────────────────────────────────────────────────────── */
table {
    width: 100%;
    border-collapse: collapse;
    text-align: left;
}

th, td {
    padding: var(--space-2xs) var(--space-xs);
    border-bottom: var(--border-thin) solid var(--border);
    vertical-align: top;
}

th {
    font-weight: var(--weight-600);
    color: var(--ink-strong);
}

tbody tr:last-child :where(th, td) { border-bottom: 0; }

/* Forms ────────────────────────────────────────────────────────────── */
label {
    display: block;
    margin-bottom: var(--space-3xs);
    font-size: var(--step--1);
    font-weight: var(--weight-600);
    color: var(--ink-strong);
}

input, select, textarea {
    width: 100%;
    padding: var(--space-2xs) var(--space-xs);
    font-family: inherit;
    font-size: var(--step-0);
    color: var(--ink);
    background: var(--surface);
    border: var(--border-thin) solid var(--border-strong);
    border-radius: var(--radius-s);
    transition: border-color var(--duration-fast) var(--ease-out);
}

input:hover, select:hover, textarea:hover { border-color: var(--ink-soft); }
input:focus, select:focus, textarea:focus { border-color: var(--primary); }

textarea { min-height: 8rem; resize: vertical; }

input[type="checkbox"], input[type="radio"] {
    width: auto;
    accent-color: var(--primary);
}

/* Buttons size to their content, not to the form-control full width. */
input[type="submit"], input[type="button"] { width: auto; }

/*
 * A bare <button> is usually a UI affordance — a menu toggle, a dropdown
 * trigger — not a visual button, so it gets a reset rather than a look.
 * Add .btn when you want one that looks like a button.
 */
button {
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
}

::placeholder { color: var(--ink-soft); opacity: 1; }

fieldset { margin: 0 0 var(--space-m); padding: 0; border: 0; }

/* Buttons ──────────────────────────────────────────────────────────────
 * .btn is opt-in — put it on a <button> or an <a> that should look like a
 * button. Variants change colour, sizes change scale. A bare <button> is
 * reset above, not styled, because most of them are menu and dropdown
 * triggers rather than visual buttons. */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3xs);
    padding: var(--space-2xs) var(--space-s);
    font-family: inherit;
    font-size: var(--step--1);
    font-weight: var(--weight-600);
    line-height: var(--leading-s);
    text-align: center;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    border: var(--border-thin) solid transparent;
    border-radius: var(--radius-s);
    transition: background var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.btn--primary {
    background: var(--primary);
    color: var(--on-primary);
}
.btn--primary:hover { background: var(--primary-hover); color: var(--on-primary); }

.btn--secondary {
    background: transparent;
    border-color: var(--primary);
    color: var(--primary);
}
.btn--secondary:hover { background: var(--primary-pale); color: var(--primary-hover); }

.btn--ghost {
    background: transparent;
    color: var(--ink-mid);
}
.btn--ghost:hover { background: var(--primary-pale); color: var(--primary); }

/* Site ghost button: an outlined pill in the brand purple, matching
 * .btn--primary's shape so the two sit together as a pair. Declared after
 * .btn--primary so a `btn btn--primary btn--ghost` combination resolves to
 * the ghost treatment. */
.btn--ghost {
    background: transparent;
    color: var(--violet-deep);
    border: 2px solid var(--violet-deep);
    border-radius: 100px;
    padding: 13px 38px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.btn--ghost:hover {
    background: var(--violet-deep);
    color: var(--on-primary);
}

.btn--sm { padding: var(--space-3xs) var(--space-xs); font-size: var(--step--2); }
.btn--lg { padding: var(--space-xs) var(--space-m); font-size: var(--step-0); }

/*
 * ON A DARK GROUND
 *
 * Variants above assume a light background. On a dark or brand-coloured
 * section they invert: the solid button goes white, the outline picks up a
 * translucent white edge. Put .on-dark on the button or any ancestor.
 */
.on-dark .btn--primary,
.btn--primary.on-dark {
    background: var(--surface);
    color: var(--primary);
}

.on-dark .btn--primary:hover,
.btn--primary.on-dark:hover {
    background: var(--surface);
    color: var(--primary-hover);
}

.on-dark .btn--secondary,
.btn--secondary.on-dark {
    color: var(--on-primary);
    border-color: color-mix(in oklab, var(--on-primary) 40%, transparent);
}

.on-dark .btn--secondary:hover,
.btn--secondary.on-dark:hover {
    background: color-mix(in oklab, var(--on-primary) 12%, transparent);
    color: var(--on-primary);
}

.btn[disabled], .btn[aria-disabled="true"] {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Media frames ────────────────────────────────────────────────────────
 * A frame for an embed — map, video or photo — so the child fills a box of
 * known proportion instead of the element's natural size.
 *
 * The ratio, radius and any framing are DEFAULTS. Change them in this file
 * to suit the design; they are here so a frame is never unstyled, not to
 * fix how it should look. */
.media-frame {
    aspect-ratio: 4 / 3;
    overflow: hidden;
    border-radius: var(--radius-m);
    background: var(--surface);
}

.media-frame > :where(iframe, img, video) {
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
    object-fit: cover;
    border-radius: 0;
}

.media-frame--square { aspect-ratio: 1; }
.media-frame--wide { aspect-ratio: 16 / 9; }

/* Cards ────────────────────────────────────────────────────────────────
 * Deliberately minimal — a surface with a radius. Sites compose their own
 * card variants on top; modelling every one here would be guesswork. */
.card {
    padding: var(--space-m);
    background: var(--surface);
    border: var(--border-thin) solid var(--border);
    border-radius: var(--radius-m);
}

/* Utility ──────────────────────────────────────────────────────────── */
.visually-hidden, .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/*
 * Grid utilities. .u-container centres and pads; .u-grid lays out. Placement
 * within the grid is each layout's business — see refs/design/layouts.md.
 */
.u-container {
    max-width: var(--grid-max-width);
    margin-inline: auto;
    padding-inline: var(--grid-gutter);
}

.u-grid {
    display: grid;
    gap: var(--grid-gutter);
}

/*
 * Scroll entrance.
 *
 * Native scroll-driven animation — no library, no IntersectionObserver, no
 * JS. Add .reveal for a plain fade, or one of the directional modifiers.
 *
 * WHY THE WHOLE BLOCK IS INSIDE prefers-reduced-motion: a reveal implemented
 * as `opacity: 0` plus an animation leaves reduced-motion users staring at
 * invisible content when the animation never runs. Scoping the rule means
 * they simply get the content, with no trap to fall into.
 *
 * Safari and Firefox do not support animation-timeline yet, so content there
 * is simply visible. That is the correct failure for a practice site: no
 * entrance effect is always better than content that never arrives.
 */
@media (prefers-reduced-motion: no-preference) {
    .reveal {
        animation: reveal linear both;
        animation-timeline: view();
        animation-range: entry 0% cover 30%;
    }

    .reveal--up { --reveal-from: translateY(var(--reveal-distance)); }
    .reveal--down { --reveal-from: translateY(calc(var(--reveal-distance) * -1)); }
    .reveal--left { --reveal-from: translateX(var(--reveal-distance)); }
    .reveal--right { --reveal-from: translateX(calc(var(--reveal-distance) * -1)); }
}

@keyframes reveal {
    from {
        opacity: 0;
        transform: var(--reveal-from, none);
    }
}

/*
 * Doctor avatar fallback
 * Shows a gradient + person silhouette when no photo exists.
 * The <img> has onerror="this.style.display='none'" which hides
 * the broken image, revealing this CSS background underneath.
 *
 * Derived from the site's own --accent so a missing photo reads as part of
 * this practice rather than as a stray swatch. Define --accent in :root above.
 */
.doctor-avatar {
    position: relative;
    aspect-ratio: 4 / 5;
    overflow: hidden;
    border-radius: 0.5rem;
    background: linear-gradient(135deg,
        color-mix(in oklab, var(--primary) 85%, black),
        var(--primary));
    display: flex;
    align-items: center;
    justify-content: center;
}

.doctor-avatar::after {
    content: "";
    position: absolute;
    width: 40%;
    height: 40%;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='white' stroke-width='1.5'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
}

.doctor-avatar img {
    position: relative;
    z-index: var(--layer-base);
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/*
 * Mediflare footer logo — dark/light variants.
 * Default: inverted (white text) for dark footers.
 * Add .footer-light to <footer> for light backgrounds.
 */
.mf-logo-light { display: none; }
.mf-logo-dark { display: inline; }
.footer-light .mf-logo-light { display: inline; }
.footer-light .mf-logo-dark { display: none; }

/* Hours: prevent time strings from breaking between number and am/pm */
.hours-table td:last-child,
.footer__hours-row span {
    white-space: nowrap;
}

/* The markup uses .mb-0 on any element that must not carry the base
 * bottom margin - a last paragraph in a card, a paragraph wrapping a
 * button. It was in use 16 times on the homepage but never defined, so the
 * base p rule's 30px survived everywhere: it inflated the top bar, opened
 * the gap under the clinic photos, and left the CTA button optically high
 * because flex centring centres the box, margin included. */
.mb-0 { margin-bottom: 0 !important; }

/* ═══════════════════════════════════════════════════════════════════
 * HINCHINBROOK HEALTH CARE - site layer
 *
 * Everything below is transcribed from the live Elementor site's computed
 * styles at 1440. Values are measured, not chosen. Where a measured value
 * lands within a rounding of a scale step, the step is used so the page
 * still reflows; where it does not, the measured value stands.
 * ═══════════════════════════════════════════════════════════════════ */

:root {
    /* The three brand colours, as the kit names them. */
    --violet: oklch(0.6705 0.1681 295.4);      /* #9F7CF0 - eyebrows, links */
    --violet-deep: oklch(0.3520 0.0855 313.0); /* #4A2C5E - display headings */
    --lime: oklch(0.8597 0.1388 119.6);        /* #C6DE70 - every button */
    --violet-wash: oklch(0.9352 0.0356 298.0); /* #ECE5FF - alternating bands */
    /* Sampled from the hero photograph's own sky (#d9e6f0), so a wash in
     * this colour reads as more sky rather than as a veil over it. */
    --sky: oklch(0.9152 0.0208 240.0);
    --cream: oklch(0.9946 0.0046 106.4);       /* #FFFEFA - the "white" bands */
    --indigo: oklch(0.4780 0.1063 288.0);      /* #6059A6 - the kit's "Button" */

    /* The source container is 1400 wide with no padding of its own. */
    --grid-max-width: 87.5rem;
}

body { background: var(--cream); }

/* Display type: 74.25px Cabin 700 in Dark Violet on the live hero. */
.display {
    font-family: var(--font-heading);
    font-size: clamp(2.75rem, 1.6rem + 5.1vw, 4.64rem);
    font-weight: 700;
    line-height: 1.1;
    color: var(--violet-deep);
}

/* Eyebrow: 18.56px Open Sans 700 in the violet, uppercase in the copy
 * itself on the source rather than by text-transform. */
.eyebrow {
    font-family: var(--font-body);
    font-size: var(--step-1);
    font-weight: 700;
    color: var(--violet);
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

h2, h3 { font-family: var(--font-heading); color: var(--violet-deep); }
h2 { font-size: var(--step-3); font-weight: 700; line-height: 1.2; }
h3 { font-size: var(--step-1); font-weight: 700; line-height: 1.4; }

p { color: rgba(0, 0, 0, 0.68); font-weight: 500; }

/* Buttons: lime pill, dark-violet label, 15px/40px, fully rounded. */
.btn--primary {
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: var(--lime);
    color: var(--violet-deep);
    border-radius: 100px;
    padding: 15px 40px;
    font-weight: 700;
    border: 0;
}
.btn--primary:hover {
    background: color-mix(in oklab, var(--lime) 88%, black);
    color: var(--violet-deep);
}

/* Alternating band grounds, straight off the source. */
.section--band { background: var(--violet-wash); }
.section--cream { background: var(--cream); }

/* Scroll entrance animations ──────────────────────────────────────────
 * A fade with a small directional offset, matching the live site's
 * restraint: it is almost entirely a plain fade there, with two
 * slide-ups, so the travel here is deliberately short (18px, 26px for
 * the up/down pair) rather than the 40-100px a stock library uses.
 *
 * Elements are hidden by [data-reveal] and shown when the observer adds
 * [data-revealed]. The hiding rule is gated on .js so that a visitor
 * without JavaScript - or if the script fails - sees the page fully,
 * rather than a blank one. Same reason the observer falls back to
 * revealing everything if IntersectionObserver is missing.
 */
.js [data-reveal] {
    opacity: 0;
    transition:
        opacity 760ms cubic-bezier(0.22, 0.61, 0.36, 1),
        transform 760ms cubic-bezier(0.22, 0.61, 0.36, 1);
    transition-delay: var(--reveal-delay, 0ms);
    will-change: opacity, transform;
}

.js [data-reveal="up"]    { transform: translateY(26px); }
.js [data-reveal="down"]  { transform: translateY(-26px); }
.js [data-reveal="left"]  { transform: translateX(-18px); }
.js [data-reveal="right"] { transform: translateX(18px); }
.js [data-reveal="fade"]  { transform: none; }

.js [data-reveal][data-revealed] {
    opacity: 1;
    transform: none;
}

/* Once it has played, drop the compositor hint and the transform so the
 * element cannot interfere with position:fixed or sticky descendants. */
.js [data-reveal][data-reveal-done] {
    will-change: auto;
    transition: none;
}

/* Motion is decoration here - honour the OS setting exactly. */
@media (prefers-reduced-motion: reduce) {
    .js [data-reveal],
    .js [data-reveal="up"],
    .js [data-reveal="down"],
    .js [data-reveal="left"],
    .js [data-reveal="right"] {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

/* ── Hero ─────────────────────────────────────────────────────────────
 * A looping muted video behind a violet wash. The source hides the video
 * below its tablet breakpoint and lets the gradient carry the band; the
 * poster frame stands in wherever the video cannot play. */
.hero {
    position: relative;
    isolation: isolate;
    padding-block: var(--space-2xl) 0;
    /* NOT overflow:hidden - the clinic cards deliberately hang past this
     * band's lower edge, and clipping here cuts them in half. The media
     * wrapper below does its own clipping. */
}
.hero__media {
    position: absolute;
    inset: 0;
    overflow: hidden;
    z-index: -2;
}
.hero__video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
/* The wash. Strong at the top where the headline sits, clearing toward
 * the lower edge so the landscape reads. */
.hero::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(
        180deg,
        color-mix(in oklab, var(--cream) 88%, transparent) 0%,
        color-mix(in oklab, var(--cream) 62%, transparent) 42%,
        color-mix(in oklab, var(--violet-wash) 30%, transparent) 100%);
}
.hero__inner { padding-block: var(--space-3xl) var(--space-2xl); text-align: center; }
.hero__content { max-width: 52rem; margin-inline: auto; }
.hero__content .lede {
    max-width: 40rem;
    margin-inline: auto;
    /* The body ink is rgba(0,0,0,.68); over the pale hero wash that reads
     * washed out, so the lede takes the solid display violet instead. */
    color: var(--violet-deep);
}

@media (max-width: 48rem) {
    /* Matching the source, which marks the video hidden on mobile: the
     * poster still paints, so the band never falls back to bare colour. */
    .hero__video { display: none; }
    .hero__media {
        background: url("/assets/images/hinchinbrook-lookout-bg.webp") center / cover no-repeat;
    }
}

/* Three clinic cards straddling the hero's lower edge. */
/* The clinic cards sit in their own full-bleed row at the foot of the
 * hero. That row paints the transition itself: transparent across the top
 * half so the video reads through, resolving to the lavender of the band
 * below across the bottom half. The cards therefore appear to straddle the
 * boundary without any geometric overlap - no negative margins, no
 * clearance to keep in sync, and nothing that breaks when the hero's
 * content height changes. */
.hero__clinics-band {
    position: relative;
    z-index: 2;
    margin-top: var(--space-xl);
    padding-block: var(--space-xl);
    /* The stop sits at 62% rather than 50%: the cards are not centred in
     * this row (they have equal padding but their own height dominates),
     * so a true half-way stop crosses them high, around the photo. 62%
     * lands it just below the addresses, which reads as the band edge
     * passing behind the lower third of each card. */
    background: linear-gradient(
        180deg,
        transparent 0%,
        transparent 62%,
        var(--violet-wash) 62%,
        var(--violet-wash) 100%);
}
.hero__clinics {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--grid-gutter);
}
.clinic-card {
    /* Measured off the source: linear-gradient(#9F7CF0 0%, #4A2C5E 100%)
     * at 10px radius. */
    background: linear-gradient(180deg, var(--violet) 0%, var(--violet-deep) 100%);
    color: var(--on-primary);
    border-radius: 10px;
    padding: var(--space-s);
    text-align: center;
    box-shadow: 0 8px 26px rgb(74 44 94 / 0.22);
}
.clinic-card__media {
    aspect-ratio: 660 / 412;
    border-radius: var(--radius-m);
    overflow: hidden;
    margin-bottom: var(--space-s);
}
/* The photo must fill its frame at every width. Left as-is it stopped at
 * its intrinsic 660px inside a wider box and sat left-aligned, leaving
 * dead space to the right once the cards stack. */
.clinic-card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.clinic-card__name {
    font-family: var(--font-heading);
    font-size: var(--step-1);
    font-weight: 700;
    color: var(--on-primary);
    /* margin-top:0 is load-bearing: the base h2 rule sets a top margin
     * which stacked with the media's bottom margin and opened a 40px gap
     * between the photo and the clinic name. */
    margin-top: 0;
    margin-bottom: var(--space-2xs);
}
.clinic-card__address { color: var(--on-primary); margin-bottom: var(--space-2xs); }
.clinic-card__phone { font-family: var(--font-heading); font-weight: 700; }
.clinic-card__phone a {
    /* Lime on the source, which is what makes the number read as the
     * card's call to action rather than as more address text. */
    color: var(--lime);
    text-decoration: none;
    display: inline;
    min-height: 0;
    padding-block: 0;
}
.clinic-card__phone a:hover { text-decoration: underline; }

@media (max-width: 62rem) {
    .hero__clinics { grid-template-columns: 1fr; }
}

/* ── Accreditation strip ─────────────────────────────────────────────── */
/* The source sets this heading in Cabin 700 at 20.6px in Dark Violet - the
 * .h3 utility alone left it at the wrong size and the wrong colour. */
.accred__copy h2 {
    font-family: var(--font-heading);
    font-size: var(--step-0);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--violet-deep);
    margin-bottom: var(--space-2xs);
}

.accred {
    /* The marks wrap onto their own row below ~62rem, where the band's
     * bottom padding alone left the last logo hard against the edge. */
    padding-bottom: var(--space-xl);
}

.accred__row {
    display: grid;
    /* Copy column a little under half, so the three marks get the wider
     * track and sit clear of the text. */
    grid-template-columns: minmax(0, 42fr) minmax(0, 58fr);
    gap: var(--space-s);
    align-items: center;
}
.accred__marks {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    /* Kept below --space-l so the three marks hold one row for longer
     * before wrapping. */
    gap: var(--space-s);
    list-style: none;
    margin: 0;
    padding: 0;
}
.accred__marks img { max-height: 56px; width: auto; object-fit: contain; }
/* These marks ship with a baked-in white ground rather than transparency,
 * which reads as a box on the lavender band. Multiply drops the white out
 * and leaves the artwork.
 *
 * background:none is load-bearing: the element also carries an opaque white
 * background-color, and mix-blend-mode blends the IMAGE against what is
 * behind the element - an opaque element background paints over that, so
 * the box survived the blend until this was added. */
.accred__marks img,
.partners__marks img {
    background: none;
    mix-blend-mode: multiply;
}

@media (max-width: 62rem) {
    .accred__row { grid-template-columns: 1fr; gap: var(--space-l); }
    .accred__marks { justify-content: flex-start; }
}

/* ── Services ────────────────────────────────────────────────────────── */
/* This band follows the lavender accreditation strip, and its eyebrow was
 * sitting hard against that edge. */
.services { padding-block: var(--space-2xl) var(--space-2xl); }

/* An eyebrow reads as a label ON its heading, so the pair should sit
 * close. The base heading rule is deliberately top-heavy (space-l above),
 * which is right between a heading and the content before it, but wrong
 * directly under its own eyebrow. Scoped to the adjacency rather than to
 * named blocks, so it holds anywhere the pattern is used. */
.eyebrow + h1,
.eyebrow + h2,
.eyebrow + h3,
.eyebrow + .h1,
.eyebrow + .h2,
.eyebrow + .h3 { margin-top: var(--space-2xs); }
.services__head { text-align: center; max-width: 46rem; margin-inline: auto; }
.svc-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: var(--grid-gutter);
    row-gap: var(--space-xl);
    margin-top: var(--space-xl);
}
.svc__media {
    aspect-ratio: 780 / 488;
    border-radius: var(--radius-l);
    overflow: hidden;
    margin-bottom: var(--space-s);
}
.svc__title { margin-bottom: var(--space-2xs); }

/* Between 40rem and 62rem the grid is two columns, so a three-card row
 * leaves the third card alone on row two — hugging the left and looking
 * unbalanced (Vaccinations on the About page). Centring the tracks lets a
 * short final row sit in the middle of the band instead. The tracks are
 * given a width rather than 1fr, since a stretched 1fr track fills the row
 * and there is then nothing for justify-content to centre. */
/* Between 40rem and 62rem the grid is two columns, so a three-card row
 * leaves the third card alone on row two — hugging the left and looking
 * unbalanced (Vaccinations on the About page).
 *
 * justify-content alone does NOT fix this: the tracks stretch to fill the
 * row, so there is no free space for it to distribute. Instead the last
 * card, when it is also an odd-numbered one (i.e. it starts a new row on
 * its own), is spanned across both columns and centred within that span. */
@media (max-width: 62rem) {
    .svc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .svc-grid > :last-child:nth-child(odd) {
        grid-column: 1 / -1;
        max-width: calc(50% - (var(--grid-gutter) / 2));
        margin-inline: auto;
    }
}
@media (max-width: 40rem) { .svc-grid { grid-template-columns: 1fr; } }

/* ── CTA strip ─────────────────────────────────────────────────────────
 * The source runs the same indigo-to-violet gradient as the top bar, with
 * the copy left, a 1px lime rule as the divider, and the button right.
 * 80px of vertical padding. */
.cta-strip {
    background: linear-gradient(90deg, var(--indigo) 0%, var(--violet-deep) 100%);
    padding-block: var(--space-xl);
}
.cta-strip__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-l);
}
.cta-strip__copy {
    flex: 1 1 22rem;
    /* The divider is the copy column's own right border on the source,
     * not a separate element. */
    padding-right: var(--space-l);
    border-right: 1px solid var(--lime);
}
.cta-strip__text {
    font-family: var(--font-heading);
    font-size: var(--step-3);
    font-weight: 700;
    color: var(--on-primary);
    margin-bottom: var(--space-3xs);
}
.cta-strip__sub { color: var(--cream); font-size: var(--step-1); }
.cta-strip__sub a {
    color: var(--lime);
    text-decoration: none;
    display: inline;
    min-height: 0;
    padding-block: 0;
}
.cta-strip__sub a:hover { text-decoration: underline; }

/* The source's CTA button is larger than the inline ones: 20px/40px. */
.btn--lg { padding: 20px 40px; font-size: var(--step-0); }

@media (max-width: 62rem) {
    .cta-strip__inner { justify-content: center; text-align: center; }
    .cta-strip__copy {
        flex: 1 1 100%;
        padding-right: 0;
        padding-bottom: var(--space-m);
        border-right: 0;
        border-bottom: 1px solid var(--lime);
    }
}

/* ── About band ───────────────────────────────────────────────────────
 * ONE band, transcribed from the source: the team photo as the ground
 * under a lavender wash, carrying a cream copy card on the left and, on
 * the right, two photo cards above a Health Partners card. The partners
 * belong to this band; they are not a section of their own.
 *
 * Source geometry at 1440: band 965 tall; copy card 660x725 r15 at x=45;
 * photo cards 315x496 r15/r20 at x=735 and x=1080; partners card 660x198
 * r20 at x=735, y+527. */
.about {
    position: relative;
    isolation: isolate;
    padding-block: var(--space-2xl);
    background:
        linear-gradient(0deg,
            color-mix(in oklab, var(--violet-wash) 82%, transparent),
            color-mix(in oklab, var(--violet-wash) 82%, transparent)),
        url("/assets/images/practice-team-hinchinbrook.webp") center / cover no-repeat;
}
.about__grid {
    display: grid;
    /* 660 + 660 with the source's 30px gutter between the two tracks. */
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto auto;
    gap: var(--space-m);
    /* stretch, not start: each card fills the row track it sits in, so the
     * copy card runs the full height of the band and the partners card
     * meets the photo row above it. */
    align-items: stretch;
}
/* The copy card spans both rows on the left. */
.about__copy {
    grid-column: 1;
    grid-row: 1 / span 2;
    /* The card is now full height, so centre the copy in it rather than
     * leaving it top-aligned against a tall card. */
    display: flex;
    flex-direction: column;
    justify-content: center;
}
/* A flex container does not collapse its children's margins, so the
 * eyebrow's 10px bottom and the heading's 10px top stacked to 20px here
 * while the same pair reads 10px everywhere else on the page. */
.about__copy .eyebrow { margin-bottom: 0; }

/* Air between the tick list and the button that follows it in the about-copy
 * card - they were sitting flush, so the button read as part of the list. */
.about__copy .tick-list { margin-bottom: var(--space-m); }

/* A short lime rule above the eyebrow in the after-hours blocks, matching the
 * site's existing .rule language (2px lime) rather than inventing a second
 * divider treatment. Scoped to this block so other eyebrows are untouched. */
.afterhours__block .eyebrow::before {
    content: "";
    display: block;
    width: 3.5rem;
    margin-bottom: var(--space-xs);
    border-top: 2px solid var(--lime);
}

.panel {
    background: var(--cream);
    border-radius: var(--radius-l);
    padding: var(--space-xl);
}

.about__copy .rule {
    width: min(100%, 30rem);
    margin: var(--space-m) 0;
    border: 0;
    border-top: 2px solid var(--lime);
}

.about__photos {
    grid-column: 2;
    grid-row: 1;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-m);
}
.about__photo {
    aspect-ratio: 315 / 496;
    border-radius: var(--radius-l);
    overflow: hidden;
    background: var(--surface);
}
.about__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

.about__partners {
    grid-column: 2;
    grid-row: 2;
    padding: var(--space-m) var(--space-l);
}
.about__partners-title {
    font-family: var(--font-heading);
    font-size: var(--step-0);
    font-weight: 700;
    color: var(--violet-deep);
    margin-top: 0;
    margin-bottom: var(--space-s);
}

@media (max-width: 62rem) {
    .about__grid { grid-template-columns: 1fr; }
    .about__copy,
    .about__photos,
    .about__partners { grid-column: 1; grid-row: auto; }
}
@media (max-width: 30rem) {
    .about__photos { grid-template-columns: 1fr; }
}

/* ── Patient information ─────────────────────────────────────────────
 * Photo left (433x542 r15 on the source), copy and a row of three
 * gradient cards right. At the narrow breakpoint the copy and cards come
 * first and the photo drops below them full width, which is what the
 * source does rather than simply stacking in source order. */
/* The band had no padding of its own at all - it sat flush against the
 * About band above it and the footer below. Matching .services at
 * --space-2xl keeps the band rhythm even down the page. */
.patient-info { padding-block: var(--space-2xl); }

.patient-info__row {
    display: grid;
    grid-template-columns: minmax(0, 433fr) minmax(0, 890fr);
    gap: var(--space-xl);
    align-items: center;
}
.patient-info__media {
    aspect-ratio: 433 / 542;
    border-radius: var(--radius-l);
    overflow: hidden;
}
.patient-info__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

.pi-cards {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-m);
    margin-top: var(--space-m);
}
/* 65deg dark-violet-to-violet, measured off the source. */
.pi-card {
    display: flex;
    flex-direction: column;
    background: linear-gradient(65deg, var(--violet-deep) 23%, var(--violet) 100%);
    color: var(--on-primary);
    border-radius: var(--radius-l);
    padding: var(--space-m);
}
.pi-card__icon { display: block; margin-bottom: var(--space-m); }
/* Lime rather than the source's cream: it ties the card icons to the lime
 * check marks in the third card and to the buttons. */
.pi-card__icon svg { width: 35px; height: 35px; color: var(--lime); display: block; }
.pi-card__title {
    font-family: var(--font-heading);
    font-size: var(--step-0);
    font-weight: 700;
    color: var(--on-primary);
    margin-top: 0;
    margin-bottom: var(--space-2xs);
}
.pi-card__body,
.pi-card__note { color: var(--on-primary); font-size: var(--step--1); }
.pi-card__body a {
    color: var(--on-primary);
    text-decoration: none;
    display: inline;
    min-height: 0;
    padding-block: 0;
}
.pi-card__body a:hover { text-decoration: underline; }

/* Lime check marks, drawn as a background so the list needs no per-item
 * markup. */
.pi-card__list { list-style: none; margin: 0; padding: 0; }
.pi-card__list li {
    position: relative;
    padding-left: var(--space-m);
    margin-bottom: var(--space-2xs);
    color: var(--on-primary);
    font-size: var(--step--1);
}
.pi-card__list li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.35em;
    width: 15px;
    height: 15px;
    background: var(--lime);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z'/%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z'/%3E%3C/svg%3E") center / contain no-repeat;
}

@media (max-width: 68rem) {
    /* Copy and cards first, photo below at full width. */
    .patient-info__row { grid-template-columns: 1fr; gap: var(--space-xl); }
    .patient-info__body { order: 1; }
    .patient-info__media { order: 2; aspect-ratio: 16 / 10; }
}
@media (max-width: 48rem) {
    .pi-cards { grid-template-columns: 1fr; }
}

/* ── Partner marks ───────────────────────────────────────────────────── */
.partners__marks {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    /* space-around, not space-between: between pins the first and last
     * marks to the card's edges, which reads as though they are falling
     * out of it. */
    justify-content: space-around;
    gap: var(--space-m);
    list-style: none;
    margin: 0;
    padding: 0;
}
.partners__marks img { max-height: 52px; width: auto; object-fit: contain; }

/* The skip link is for keyboard users: off-screen until focused, rather
 * than hidden, so it stays reachable by tab. The template ships the markup
 * but no styling, so without this it renders as visible body text at the
 * very top of every page.
 *
 * (Re-added: an earlier slice-replacement of the patient-information block
 * took this rule with it, since it sat between the two section markers the
 * edit used as bounds. Slice edits need a marker they own.) */
.skip-link {
    position: absolute;
    left: var(--space-s);
    top: 0;
    z-index: var(--layer-overlay);
    padding: var(--space-2xs) var(--space-s);
    background: var(--violet-deep);
    color: var(--on-primary);
    border-radius: 0 0 var(--radius-m) var(--radius-m);
    text-decoration: none;
    transform: translateY(-110%);
    transition: transform 140ms ease;
}
.skip-link:focus { transform: translateY(0); color: var(--on-primary); }

/* ── Top bar + header ─────────────────────────────────────────────────
 * The source floats a white pill (1380x120, radius 1000px) over the hero
 * video, with a slim transparent strip of hours and phone above it. */
.topbar {
    position: relative;
    z-index: 3;
    background: linear-gradient(90deg, var(--indigo) 0%, var(--violet-deep) 100%);
    color: var(--on-primary);
}
.topbar__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-s);
    /* 38px on the source, with the text optically centred rather than
     * sitting on the padding box - hence the even padding and the flex
     * centring rather than a line-height. */
    min-height: 38px;
    padding-block: var(--space-3xs);
}
/* The base p rule sets margin-bottom:30px, which inflated this bar to 58px
 * and pushed the ink to the top: flex centring centres the box, and the box
 * included that margin. */
.topbar__hours,
.topbar__contact { margin: 0; line-height: 1; }
.topbar p { color: var(--on-primary); font-family: var(--font-heading); font-size: var(--step--1); }
.topbar__hours,
.topbar__contact { display: flex; align-items: center; gap: var(--space-s); }
.topbar svg { width: 17px; height: 17px; flex: none; vertical-align: -3px; }
.topbar a,
.topbar__fax {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3xs);
    color: var(--on-primary);
    text-decoration: none;
    min-height: 0;
    padding-block: 0;
}
.topbar a:hover { text-decoration: underline; }

/* The header sits over the hero rather than above it, so the pill floats
 * on the video exactly as the source does. */
/* The header is a floating cream pill that sits OVER the hero. Its padding
 * must therefore come out of the hero's own area, not out of the page above
 * it: .site-header has no background, so a padding-top here painted a white
 * band between the topbar and the top of the hero image (20px on every
 * page). Pulling the header up by its own padding puts that breathing room
 * over the hero instead, so the hero art now runs right up under the topbar
 * and more of it is visible - which is how the source sits. The negative
 * bottom margin grows to match, so the hero's own top padding still repays
 * exactly the overlap and per-page clearance is unchanged. */
/* The header is a floating cream pill that sits OVER the hero, and it has
 * no background of its own. A padding-top here therefore painted a white
 * band between the topbar and the top of the hero image (20px on every
 * page) rather than spacing the pill over the art.
 *
 * The space above the pill now comes out of the hero instead: the whole
 * header is pulled up over the hero by its full height, so the hero starts
 * flush under the topbar and more of the art is visible - which is how the
 * source sits. The pill keeps its padding-top, so it still floats clear of
 * the topbar rather than butting against it. */
/* The header is a floating cream pill sitting OVER the hero, and it has no
 * background of its own — so a padding-top on this wrapper painted a white
 * band between the topbar and the top of the hero image (20px on every
 * page) instead of spacing the pill over the art.
 *
 * The wrapper is now zero-height as far as the page flow is concerned: the
 * hero starts immediately under the topbar and the whole header floats on
 * top of it. The pill's clearance from the topbar comes from its own
 * margin-top, which costs the page nothing. More of the hero art is visible
 * as a result, which is how the source sits. */
.site-header {
    position: relative;
    z-index: 3;
    margin-bottom: -140px;
    padding-top: 0;
}
.site-header__bar { margin-top: var(--space-s); }
.site-header__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-m);
    min-height: 120px;
    padding-inline: var(--space-m);
    background: var(--cream);
    border-radius: 1000px;
    box-shadow: 0 2px 18px rgb(74 44 94 / 0.10);
}
/* The logo is a flex item next to the nav, so at tight widths flex-shrink
 * squeezed the LINK narrower while the image kept its 100px height - the
 * mark came out visibly squashed (measured 1.5 natural aspect rendering at
 * 0.96 around 1100px). Letting the box shrink is right; distorting the
 * artwork is not. object-fit: contain keeps the proportions whatever width
 * the flex line leaves, and max-height lets it scale down rather than
 * overflow. */
.site-logo { flex-shrink: 1; min-width: 0; }
.site-logo img {
    height: auto;
    width: auto;
    max-width: 100%;
    max-height: 100px;
    object-fit: contain;
    display: block;
}

.nav { display: flex; align-items: center; gap: var(--space-s); }
.nav__list {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    list-style: none;
    margin: 0;
    padding: 0;
}
.nav__list a,
.nav__toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3xs);
    padding: var(--space-3xs) var(--space-xs);
    font-family: var(--font-body);
    font-size: var(--step-0);
    font-weight: 600;
    /* --violet (#9F7CF0) on the cream ground is 3.14:1 — under the 4.5:1
     * WCAG AA minimum for body-size text, and axe flags it on every page.
     * --indigo is 5.97:1, is already the kit's own "Button" colour, and is
     * the same colour as the topbar gradient immediately above, so the
     * header reads as one family rather than two violets. */
    color: var(--indigo);
    text-decoration: none;
    background: none;
    border: 0;
    border-radius: var(--radius-s);
    cursor: pointer;
    white-space: nowrap;
}
.nav__list a:hover,
.nav__toggle:hover { color: var(--violet-deep); background: var(--violet-wash); }
/* Current page, styled the same as hover so the two read as one state. This
 * previously set only the colour, which was too quiet to notice - the nav
 * looked as though it never marked the current page at all. A dropdown child
 * marks its parent toggle too (see partials/scripts.html), so a gallery or
 * about sub-page highlights the menu item it lives under. */
.nav__list a.active,
.nav__toggle.active { color: var(--violet-deep); background: var(--violet-wash); }
.nav__toggle svg { width: 11px; height: 11px; }

.nav__item { position: relative; }
.nav__menu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: var(--layer-overlay);
    display: none;
    min-width: 13rem;
    padding: var(--space-3xs);
    list-style: none;
    margin: 0;
    background: var(--cream);
    border-radius: var(--radius-m);
    box-shadow: 0 6px 22px rgb(74 44 94 / 0.16);
}
.nav__item:where(:hover, :focus-within) .nav__menu,
.nav__menu[data-open] { display: block; }
.nav__menu a { width: 100%; }

.nav__burger {
    display: none;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    color: var(--violet-deep);
    background: none;
    border: 0;
    border-radius: var(--radius-s);
    cursor: pointer;
}
.nav__burger:hover { background: var(--violet-wash); }
.nav__burger svg { width: 24px; height: 24px; }

/* Must stay ABOVE the mobile query: same specificity, so whichever comes
 * last wins, and below it this hides the in-menu CTA at every width. */
.nav__cta-mobile { display: none; }

@media (max-width: 68rem) {
    .nav__burger { display: inline-flex; }
    .nav > .btn { display: none; }

    .site-header__bar { min-height: 88px; border-radius: var(--radius-l); }
    .site-logo img { height: 64px; }

    .nav__list {
        position: absolute;
        top: calc(100% + var(--space-2xs));
        /* left/right: 0 against .site-header__bar's own edges (see the rule
           just above). Anchoring to .site-header, the previous nearest
           positioned ancestor, made the drawer full-bleed and so wider than
           the cream bar it drops out of. */
        left: 0;
        right: 0;
        z-index: var(--layer-overlay);
        display: none;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        padding: var(--space-s);
        background: var(--cream);
        border-radius: var(--radius-l);
        box-shadow: 0 8px 26px rgb(74 44 94 / 0.18);
        max-height: calc(100dvh - 150px);
        overflow-y: auto;
    }
    /* The drawer's positioning context is the cream bar itself, so left/right:0
       lands exactly on its edges. NOT .u-container: its gutter is padding-inline,
       and an absolutely positioned child resolves against the PADDING box, so
       anchoring there is indistinguishable from anchoring to the full-bleed
       header. */
    .site-header__bar { position: relative; }
    .nav__list[data-open] { display: flex; }
    .nav__list > li > a,
    .nav__toggle { width: 100%; }

    .nav__menu {
        position: static;
        display: none;
        min-width: 0;
        padding: 0 0 var(--space-3xs) var(--space-s);
        background: none;
        box-shadow: none;
    }
    .nav__item:where(:hover, :focus-within) .nav__menu { display: none; }
    .nav__menu[data-open] { display: block; }

    .nav__cta-mobile {
        display: flex;
        margin-top: var(--space-s);
        padding-top: var(--space-s);
        border-top: var(--border-thin) solid var(--violet-wash);
    }
    .nav__cta-mobile .btn { width: 100%; justify-content: center; }
}

@media (max-width: 40rem) {
    .topbar__inner { justify-content: center; }
    .topbar__hours { width: 100%; justify-content: center; }
    .topbar__contact { justify-content: center; }
}

/* ── Footer ───────────────────────────────────────────────────────────
 * Transcribed from the source: a 94deg dark-violet-to-indigo gradient
 * carrying the logo and three link columns, then a lime bar with the
 * copyright and legal links. */
.site-footer {
    background: linear-gradient(94deg, var(--violet-deep) 0%, var(--indigo) 100%);
    color: var(--on-primary);
    padding-top: var(--space-2xl);
    /* No padding-bottom here: it would push the lime bar (a flow child) up off
     * the bottom and strand it mid-footer with the landscape below it. The
     * clearance belongs on the GRID alone - see .site-footer__grid. */
    /* The landscape below is pulled up under the footer content, so this needs
     * to be a positioning context and the content needs to sit above it. */
    position: relative;
}

/* ── The Hinchinbrook channel behind the footer ────────────────────────
 * STRATEGY (this is the second attempt; the first fought itself).
 *
 * The first version put the photo in the flow and pulled it up with a negative
 * margin sized from the VIEWPORT WIDTH (100vw / aspect). That cannot hold: the
 * footer content's height is driven by TEXT and jumps as the grid collapses
 * 4 -> 2 -> 1 columns (358px -> 645px -> 1151px in testing), while a
 * width-derived photo height SHRINKS over the same range (607px -> 177px).
 * The two move in opposite directions, so any single lift value is only ever
 * correct at one width - which is exactly the "layers fighting" symptom, one
 * riding over the other depending on screen size.
 *
 * So the photo is no longer in the flow at all. It is an absolutely positioned
 * layer PINNED TO THE BOTTOM of the footer, sized by its own aspect-ratio and
 * always at least as tall as it needs to be. The content sits above it and the
 * footer's height is set by the content alone. The two can no longer disagree,
 * because only one of them decides the height now.
 *
 * The image fades out at its top via a mask (not an overlay - an overlay cannot
 * remove a hard edge, it only tints it), so wherever its top lands it dissolves
 * into the purple with no line. */
.site-footer__landscape {
    position: absolute;
    /* Pinned to the bottom, full width. Not in the flow, so it cannot push the
     * content around or be pushed by it. */
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 0;
    pointer-events: none;
    line-height: 0;
    overflow: hidden;
    /* How tall the landscape is allowed to be. The photo keeps its aspect
     * ratio and is cropped from the TOP by the wrapper when the footer is
     * short, so the ridge, water and mangroves at its foot are always present
     * and always the same distance above the lime bar - which is the part that
     * has to look composed. Clamped so it stays a band, never the whole footer. */
    /* The floor matters more than it looks: on a narrow viewport the lime bar's
     * links wrap to three lines and eat most of a short band, leaving a thin
     * strip with no mountains in it. 20rem keeps the ridge and the water
     * visible all the way down to 390px. */
    height: clamp(20rem, calc(100vw / 2.373), 26rem);
    /* The photo fades in from fully transparent at the band's top edge to fully
     * opaque halfway down, so it emerges out of the purple gradient behind it
     * with no edge anywhere. Masking the WRAPPER (not the img) is what makes
     * this reliable: the wrapper is exactly the visible band, so the fade always
     * spans what is on screen no matter how the image is cropped inside it. */
    -webkit-mask-image: linear-gradient(
        180deg,
        transparent 0%,
        transparent 12%,
        rgba(0, 0, 0, 0.08) 22%,
        rgba(0, 0, 0, 0.24) 31%,
        rgba(0, 0, 0, 0.46) 40%,
        rgba(0, 0, 0, 0.70) 49%,
        rgba(0, 0, 0, 0.90) 56%,
        #000 64%);
    mask-image: linear-gradient(
        180deg,
        transparent 0%,
        transparent 12%,
        rgba(0, 0, 0, 0.08) 22%,
        rgba(0, 0, 0, 0.24) 31%,
        rgba(0, 0, 0, 0.46) 40%,
        rgba(0, 0, 0, 0.70) 49%,
        rgba(0, 0, 0, 0.90) 56%,
        #000 64%);
}
.site-footer__landscape img {
    /* Anchored to the BOTTOM of the wrapper: as the wrapper's height changes
     * the image is trimmed off the top (all sky, nothing anyone looks at)
     * rather than being scaled or having its foot cut off. */
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: auto;
    /* Never smaller than the wrapper, so there is no gap when the clamp is at
     * its upper bound on a narrow, tall viewport. */
    min-height: 100%;
    object-fit: cover;
    object-position: center bottom;
    display: block;
    border-radius: 0;
    /* No mask here - it goes on the WRAPPER. This img is taller than the
     * wrapper and the wrapper clips it, so a mask on the img had its entire
     * fade cropped away; what remained started part-opaque, which is precisely
     * the hard cut. See .site-footer__landscape. */
}
/* Tints what remains of the upper sky into the footer's colour so it does not
 * read as a separate blue. The mask does the dissolving; keep this light. */
.site-footer__landscape::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    /* Light touch only. The purple the eye reads through the upper band is the
     * footer's own gradient showing through the mask - not painted here - so
     * this just warms the remaining sky into the same family. */
    background: linear-gradient(
        180deg,
        color-mix(in oklab, var(--indigo) 22%, transparent) 0%,
        color-mix(in oklab, var(--indigo) 10%, transparent) 40%,
        transparent 62%);
}

/* Footer content rides above the landscape it overlaps. */
.site-footer__grid,
.site-footer__bar { position: relative; z-index: 1; }
.site-footer__grid {
    display: grid;
    /* Source tracks at 1440: brand 460, then three columns from x=581,
     * 859 and 1137 - so roughly 34/20/23/23. */
    grid-template-columns: minmax(0, 34fr) minmax(0, 20fr) minmax(0, 23fr) minmax(0, 23fr);
    gap: var(--space-l);
    /* Clears the landscape band pinned to the footer's bottom, so the content
     * stays off the ridge line at EVERY width - this is what stops the two
     * layers fighting as the grid collapses 4 -> 2 -> 1 columns. Mirrors the
     * band's own clamp, minus the lime bar's height. */
    /* The gap between the content and the landscape pinned below it - this is
     * the knob that moves the CONTENT down the photo (padding-top on
     * .site-footer only makes the whole footer taller, since the photo is
     * pinned to the bottom). Keep the divisor near 4.6: tighter than that and
     * the content drops past the ridge line, and the wide and narrow ends
     * start drifting apart again. */
    padding-bottom: clamp(10.5rem, calc(100vw / 4.6), 13.5rem);
}
.site-footer__logo img {
    height: 96px;
    width: auto;
    display: block;
    margin-bottom: var(--space-s);
    /* The logo is a white-ground export, not a transparent one, so on the
     * gradient it reads as a white tile. The source puts it on a rounded
     * white chip rather than knocking the ground out - matching that is
     * more honest than a blend, which would tint the artwork. */
    background: var(--cream);
    /* Pill, matching the live site, which sets border-radius:500px on the
     * logo image itself. A large fixed value rather than 50% so the shape
     * stays a pill on a wide logo instead of becoming an ellipse. */
    border-radius: 500px;
    padding: var(--space-2xs) var(--space-s);
}
.site-footer__blurb {
    color: var(--on-primary);
    font-size: var(--step--1);
    max-width: 30ch;
}
.site-footer__heading {
    font-family: var(--font-heading);
    font-size: var(--step-1);
    font-weight: 700;
    color: var(--on-primary);
    margin-top: 0;
    margin-bottom: var(--space-s);
}
.site-footer__col ul {
    list-style: none;
    margin: 0;
    padding: 0;
}
/* WCAG 2.2 target size (2.5.8) asks for 24x24 minimum. These links were 22px
 * tall - wide enough, but 2px short - so the line-height carries them over
 * rather than padding, which would change the visual rhythm of the column. */
.site-footer__col li { margin-bottom: var(--space-3xs); }
.site-footer__col li a,
.site-footer__legal a,
.site-footer__copy a,
.site-footer__value a { display: inline-block; min-height: 24px; line-height: 24px; }

/* Inline links inside a sentence are NOT padded to 24px. WCAG 2.2's target-size
 * criterion (2.5.8) exempts them for exactly this reason - a phone number or
 * address in running prose cannot grow without breaking the line rhythm, and
 * the surrounding text gives it a much larger effective hit area anyway. The
 * remaining sub-24px links on this site are all of that kind. */
.site-footer a {
    color: var(--on-primary);
    text-decoration: none;
    font-weight: 500;
}
.site-footer a:hover { color: var(--lime); text-decoration: underline; }

/* The icon is its own column, top-aligned against the label, with the
 * label and value stacked to its right. */
.site-footer__item {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2xs);
    margin-bottom: var(--space-s);
}
.site-footer__label {
    color: color-mix(in oklab, var(--on-primary) 78%, transparent);
    font-size: var(--step--1);
}
/* Lime, matching the source - the label text stays the muted white. The
 * top margin optically aligns the glyph with the label's cap height. */
.site-footer__icon {
    width: 22px;
    height: 22px;
    flex: none;
    margin-top: 0.15em;
    color: var(--lime);
}

/* The Facebook mark sits under the blurb in the source, in the pale
 * lavender rather than the lime used on the contact icons. */
.site-footer__social a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--violet-wash);
    min-height: 0;
    padding-block: 0;
}
.site-footer__social a:hover { color: var(--lime); }
.site-footer__social svg { width: 25px; height: 25px; display: block; }
.site-footer__value {
    color: var(--on-primary);
    font-weight: 700;
    margin-bottom: var(--space-s);
}
.site-footer__value a { font-weight: 700; }

/* The lime bar. Dark violet ink, since lime is a light ground. */
.site-footer__bar {
    /* Semi-transparent and pulled up ONTO the foot of the photo, so the
     * mangroves read through it and the bar blends into the vegetation rather
     * than slicing it off with a hard edge. */
    /* Semi-transparent so the mangroves at the foot of the photo read through
     * it and the bar blends into the vegetation rather than slicing it off.
     * No negative margin now: the landscape is pinned to the footer's bottom,
     * so the bar already sits over the foot of the image. */
    background: color-mix(in oklab, var(--lime) 80%, transparent);
    padding-block: var(--space-2xs);
}
.site-footer__bar-inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-s);
}
/* Once the bar wraps, space-between strands the items at the row edges - the
 * copyright hard left, the legal links hard right on a half-empty row. Centre
 * them as soon as that happens. The three items total ~695px plus gaps, so the
 * wrap falls between 790px and 780px (measured); 49rem/784px sits in that gap.
 * Centring used to start only at 40rem/640px, which left ~150px of
 * wrapped-but-not-centred widths - the tablet range this fixes. */
@media (max-width: 49rem) {
    .site-footer__bar-inner {
        justify-content: center;
        text-align: center;
    }
}
.site-footer__bar p { color: var(--violet-deep); font-size: var(--step--1); }
.site-footer__bar a { color: var(--violet-deep); font-weight: 500; }
.site-footer__bar a:hover { color: var(--violet-deep); text-decoration: underline; }
.site-footer__legal { display: flex; align-items: center; gap: var(--space-2xs); }

.powered-by {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    font-size: var(--step--2);
}
.powered-by img { height: 22px; width: auto; display: block; }
.powered-by a { min-height: 0; padding-block: 0; }
.mf-logo-dark { display: none; }

@media (max-width: 62rem) {
    .site-footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 40rem) {
    .site-footer__grid { grid-template-columns: 1fr; }
    /* Bar centring now lives with .site-footer__bar-inner - it starts at 71rem,
     * where the bar first wraps, not here. */
}

/* ── The Practice page ────────────────────────────────────────────────
 * Transcribed from /about/the-practice/. Reuses the homepage's .hero,
 * .accred, .svc-grid and .about band patterns; what follows is only the
 * treatments this page introduces. */

/* A plain hero over a photo ground - no video here, unlike the homepage. */
.page-hero .hero__media { background-position: center; background-size: cover; }

/* The four-feature panel straddling the hero's lower edge: one 1290x332
 * container at r20 with the violet-to-dark-violet gradient, divided into
 * four columns rather than four separate cards. */
.page-hero__features {
    position: relative;
    z-index: 2;
    padding-bottom: var(--space-2xl);
}
.feature-panel {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0;
    background: linear-gradient(160deg, var(--violet) 0%, var(--violet-deep) 100%);
    border-radius: var(--radius-l);
    padding: var(--space-l) var(--space-m);
    box-shadow: 0 8px 26px rgb(74 44 94 / 0.22);
}
.feature-panel__item {
    padding-inline: var(--space-m);
    border-right: var(--border-thin) solid color-mix(in oklab, var(--on-primary) 22%, transparent);
}
.feature-panel__item:last-child { border-right: 0; }
/* Inline SVG copied from the source's Font Awesome glyphs (microscope,
 * hospital, hands-helping, mobile-alt) — the paths only, so nothing loads
 * a webfont or an icon library. 35px and white, as measured on the source. */
.feature-panel__icon {
    display: block;
    width: 35px;
    height: 35px;
    margin-bottom: var(--space-xs);
    color: var(--on-primary);
}
.feature-panel__icon svg { width: 100%; height: 100%; display: block; }
.feature-panel__title {
    font-family: var(--font-heading);
    font-size: var(--step-1);
    font-weight: 700;
    color: var(--on-primary);
    margin-top: 0;
    margin-bottom: var(--space-2xs);
}
.feature-panel__body { color: var(--on-primary); font-size: var(--step--1); }

@media (max-width: 68rem) {
    .feature-panel { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--space-m); }
    .feature-panel__item:nth-child(2n) { border-right: 0; }
}
@media (max-width: 40rem) {
    .feature-panel { grid-template-columns: 1fr; }
    .feature-panel__item { border-right: 0; }
}

/* Mission runs straight into the accreditation strip - both are
 * section--band, so their lavender grounds merge and the two read as one
 * band with no breathing room. Caught by bandpad.mjs. */
.mission { padding-bottom: var(--space-2xl); }

/* Mission and commitment: mirrored splits, the second flipped. */
.mission__row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-2xl);
    align-items: center;
}
.mission__row + .mission__row { margin-top: var(--space-2xl); }
.mission__media {
    aspect-ratio: 650 / 447;
    border-radius: var(--radius-l);
    overflow: hidden;
}
.mission__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

@media (max-width: 62rem) {
    .mission__row { grid-template-columns: 1fr; gap: var(--space-l); }
    /* Keep the photo below the copy in both rows once stacked, so the
     * flipped row does not lead with an image on mobile. */
    .mission__row--flip > .mission__media { order: 2; }
}

/* Services detail: a two-column list pair, then the 3-up photo cards. */
/* Two rows: the eyebrow + title left-aligned on their own, then a three
 * column row carrying the lede/button beside the two service lists. */
.services-detail__head { text-align: left; max-width: 46rem; margin-inline: 0; }
.services-detail__lists {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-2xl);
    margin-top: var(--space-l);
    align-items: start;
}
.services-detail__intro .lede { margin-top: 0; }
.services-detail__cards { margin-top: var(--space-xl); }

@media (max-width: 62rem) {
    .services-detail__lists { grid-template-columns: 1fr; gap: var(--space-l); }
    .services-detail__head { max-width: none; }
}

/* A lime tick list, matching the check marks used in the patient-info
 * cards - drawn as a mask so the list needs no per-item markup. */
.tick-list { list-style: none; margin: 0; padding: 0; }
.tick-list li {
    position: relative;
    padding-left: var(--space-m);
    margin-bottom: var(--space-2xs);
}
.tick-list li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.4em;
    width: 15px;
    height: 15px;
    background: var(--lime);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z'/%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z'/%3E%3C/svg%3E") center / contain no-repeat;
}
/* On the dark About card the ticks still read, but the text must not
 * inherit the body ink. */
.about__copy .tick-list li { color: inherit; }

/* The service cards on this page carry a lavender caption panel under the
 * photo, rather than the homepage's bare title and body. */
.services-detail__cards .svc__panel {
    background: var(--violet-wash);
    border-radius: var(--radius-m);
    padding: var(--space-m);
    margin-top: calc(-1 * var(--space-l));
    margin-inline: var(--space-s);
    position: relative;
    z-index: 1;
}
.services-detail__cards .svc__title { margin-top: 0; margin-bottom: var(--space-2xs); }

/* ═══════════════════════════════════════════════════════════════════
 * DOCTORS & STAFF PAGE (doctors.html)
 *
 * Appended, never interleaved: every rule below is scoped to a class
 * this page owns, so nothing here can reach the homepage. Geometry is
 * transcribed from the live page's computed styles at 1440, same method
 * as the site layer above.
 * ═══════════════════════════════════════════════════════════════════ */

/* ── Doctors hero ─────────────────────────────────────────────────────
 * The source's band is a practice photograph as its ::before with a
 * cream wash over it. The homepage hero's .hero/.hero__media/.hero::after
 * scaffolding already does exactly this, so this page reuses it and only
 * swaps the video for a still and adjusts the type: on the source the H1
 * is the SMALL line (19px) and the display line beneath it is 58px, the
 * reverse of the homepage. */
/* The hero now sizes itself, since the locations card was moved out of it.
 * The source's hero art box is 1440x777 (aspect 1.853); matching that keeps
 * cover at the source's magnification with no side crop, and leaves real
 * building visible between the lede and the card that straddles the lower
 * edge. min-height rather than height so long copy can still grow it. */
/* One continuous expression, no breakpoint - so the hero never JUMPS as the
 * viewport narrows. It used to drop min-height to 0 at 62rem, which
 * collapsed the hero 543px -> 435px in a single step and shoved the copy
 * down onto the busy part of the photograph.
 *
 * The three terms, outermost first:
 *   max(..., 26rem)  a floor, so a phone still gets a real hero rather than
 *                    the 210px that 100vw/1.853 would give it
 *   min(..., 46rem)  a ceiling on very wide screens
 *   100vw / 1.853    the source's own hero aspect in between, which is what
 *                    keeps cover from over-magnifying and cropping the sides
 */
.doc-hero { min-height: max(min(calc(100vw / 1.853), 46rem), 26rem); }


/* The photograph meets the lavender band beneath it with a gradient rather
 * than a hard edge: fully opaque --violet-wash at the foot, clearing as it
 * rises. Only the lower part is tinted - there is deliberately NO veil over
 * the copy, because this photo is mostly bright sky up there and the text
 * reads cleanly against it unaided.
 *
 * Transparent is spelled as a zero-alpha --violet-wash rather than the
 * `transparent` keyword, which interpolates through transparent BLACK and
 * greys the middle of the ramp. */
/* The shared .hero::after wash (cream at the top, for heroes whose art is
 * busy behind the headline) is wrong for this photograph - it is bright sky
 * up there and the copy reads cleanly unaided, so the veil only greyed it.
 * Cancelled here; the lavender-from-the-bottom ramp below is all this hero
 * needs. */
.doc-hero::after { background: none; }

.doc-hero .hero__media::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    /* .hero__media is at z-index -2 (it sits behind the hero's own ground),
     * and a pseudo-element inherits that stacking - so without this the wash
     * paints UNDERNEATH the photograph and is completely invisible. This is
     * why several attempts at this gradient appeared to do nothing. */
    z-index: 1;
    /* Reads as the photograph continuing rather than a scrim on top of it:
     * the pale sky tone sampled from the image itself at the top, easing
     * through cream in the middle where the copy sits, and landing on the
     * band's own lavender at the foot. */
    background: linear-gradient(
        180deg,
        var(--sky) 0%,
        color-mix(in oklab, var(--sky) 88%, transparent) 22%,
        color-mix(in oklab, var(--cream) 70%, transparent) 44%,
        color-mix(in oklab, var(--cream) 30%, transparent) 62%,
        color-mix(in oklab, var(--violet-wash) 30%, transparent) 80%,
        var(--violet-wash) 100%);
}
/* Narrower viewports put the copy lower down the hero, over the building
 * rather than the sky, so the veil has to reach further and hold longer -
 * at 990 the lede sat directly on the dark verandah and was barely
 * readable. The stops move down and strengthen; the foot is unchanged. */
@media (max-width: 75rem) {
    .doc-hero .hero__media::after {
        background: linear-gradient(
            180deg,
            color-mix(in oklab, var(--sky) 78%, transparent) 0%,
            color-mix(in oklab, var(--cream) 72%, transparent) 34%,
            color-mix(in oklab, var(--cream) 60%, transparent) 58%,
            color-mix(in oklab, var(--violet-wash) 40%, transparent) 80%,
            var(--violet-wash) 100%);
    }
}
/* On a phone the copy wraps to many more lines and reaches further down the
 * hero than at any other width, so it needs the veil held almost the whole
 * way. The photograph still reads through it - it is a wash, not a cover. */
@media (max-width: 40rem) {
    .doc-hero .hero__media::after {
        background: linear-gradient(
            180deg,
            color-mix(in oklab, var(--sky) 80%, transparent) 0%,
            color-mix(in oklab, var(--cream) 80%, transparent) 30%,
            color-mix(in oklab, var(--cream) 74%, transparent) 62%,
            color-mix(in oklab, var(--violet-wash) 62%, transparent) 84%,
            var(--violet-wash) 100%);
    }
}



.doc-hero .hero__media {
    /* The source paints this same 1920x1080 photograph into a 1440x777 box,
     * where cover crops nothing horizontally - you see the whole building,
     * its left edge and the water behind. Our hero is 896px tall, so cover
     * has to scale up 1.15x and crop 153px (10%) off each side, which is why
     * the building read as a close-up of the roof rather than the whole
     * clinic. The height is capped below so cover has less to fill; the
     * focal point sits at 35% so the building stays in frame rather than
     * being pushed under the panel band. */
    background: url("/assets/images/doctors-hero-bg.webp") center bottom / cover no-repeat;
}
/* The media is inset:0 on the hero, so it inherits the hero's height and
 * cover then has to fill it - the taller the hero, the more it magnifies and
 * the more it crops off the sides. Capping the media at the source's own
 * aspect (1440x777 = 1.85) keeps the magnification at the source's, so the
 * whole building stays in frame; the hero's own ground shows below the cap
 * where the panel band sits anyway. */
/* Only cap the media on wide viewports. Above 62rem the hero is much taller
 * than the photograph's own aspect, so an uncapped cover magnifies 1.15x and
 * crops 10% off each side - losing the building's left edge and the water.
 * Capping to the source's 1.853 aspect there keeps the whole clinic in frame.
 *
 * Below that the hero is narrow and tall, so the cap would leave a big band
 * of empty ground under a short image; plain cover (inset:0, inherited) is
 * correct there and crops vertically, which this photograph tolerates. */
/* Half the card, so its midpoint lands on the hero's lower edge. CSS cannot
 * read an element's own height, so this is expressed as a percentage of the
 * card's width via translate instead - see .locations-panel below - and this
 * variable only carries the breakpoints where a fixed pull reads better than
 * a proportional one. 0 on phones: the card is tall there and any overlap
 * eats the hero entirely. */

/* The H1 carries .eyebrow for its look, but an eyebrow's bottom margin is
 * sized for a label sitting on a heading, and h1 brings its own top margin
 * from the base heading rule. Both are cleared so the pair reads as one
 * unit rather than as two blocks. */
.doc-hero__kicker {
    margin-top: 0;
    margin-bottom: var(--space-2xs);
    /* Measured on the source: rgb(159,124,240) = --violet, the light
     * lavender, NOT --violet-deep. The previous comment here asserted the
     * opposite and was simply wrong. */
    color: var(--violet);
}

/* 58px on the source, against the homepage hero's 74.25px. Capped a step
 * lower than .display so the two heroes stay visibly different. */
.doc-hero__display {
    font-size: clamp(2.25rem, 1.45rem + 3.55vw, 3.625rem);
    margin-bottom: var(--space-s);
}

/* The locations panel straddles the hero's lower edge. Same construction
 * as the homepage's clinic row and for the same reason: the row paints
 * the transition itself - transparent over the top portion so the
 * photograph reads through, resolving to the lavender of the band below -
 * so the overlap needs no negative margin and cannot drift out of sync
 * when the panel's copy reflows. The stop is at 50% here rather than the
 * homepage's 62% because this panel is a single low box, so a true
 * half-way stop does cross it at its middle. */
.doc-hero__panel-band {
    position: relative;
    /* z-index 1, not 2: this band only needs to sit above the hero, and at 2
     * it also painted above the section that follows it. */
    z-index: 1;
    background: var(--violet-wash);
    padding-top: 0;
    /* No bottom padding at all: the following section's own top padding is
     * the gap, and adding any here simply stacks a second one. */
    padding-bottom: 0;
}

/* The card straddles the hero's lower edge by exactly HALF ITS OWN HEIGHT,
 * computed rather than hardcoded: translate percentages resolve against the
 * element's own box, so -50% is always half the card no matter how the copy
 * reflows. The lift sits on this wrapper rather than the card because the
 * card carries data-reveal and the reveal system owns `transform` there.
 *
 * margin-bottom gives back the space the wrapper vacates, so the section
 * below keeps its own height instead of jumping up by the same amount. It
 * cannot be a percentage - vertical margin percentages resolve against the
 * parent's WIDTH, not its height - so the band's padding absorbs it instead. */
/* THE LIFT IS FLUID, NOT A BREAKPOINT.
 *
 * It used to switch on at 63rem, which put a cliff right where the layout is
 * most fragile: at 1008 the gap between the lede and the card was 96px, and
 * one pixel narrower it snapped to 221px. The narrow side looked better,
 * which is the giveaway - the lift was too aggressive for the space, not
 * wrong in principle.
 *
 * --lift-fraction ramps 0 -> 1 across the range instead of flipping:
 *   below ~48rem   0      the card sits in the band normally
 *   48rem..75rem   0..1   eased in as the hero gains height
 *   above 75rem    1      full half-card straddle
 *
 * clamp() does the ramp; the card's own height still supplies the 50%, so
 * the overlap remains exactly half a card wherever the fraction is 1. */
.locations-panel-lift {
    --lift-fraction: clamp(0, (100vw - 48rem) / 27rem, 1);
    transform: translateY(calc(-50% * var(--lift-fraction)));
    margin-bottom: calc(-1 * var(--panel-lift-give) * var(--lift-fraction));
}
/* The band's top padding fades out as the lift fades in - together they keep
 * the card the same distance below the hero copy at every width. */
.team-pillars.team-pillars {
    padding-top: calc(var(--space-l) * (1 - var(--lift-fraction, 0)));
}
/* Only used to reclaim the space the lift vacates, so an approximate value
 * shifts the FOLLOWING content slightly and never the card's own overlap,
 * which stays exactly half the card. */
/* Half a typical card. Only used to reclaim the space the lift vacates, so
 * an approximate value shifts what FOLLOWS slightly and never the card's own
 * overlap, which is always exactly half the card via translateY(-50%).
 * NB: this has to be declared on .team-pillars - the card lives inside that
 * section now, and while it was still pointing at the old (deleted)
 * .doc-hero__panel-band the variable never resolved, calc() was invalid, and
 * the compensation silently did nothing - which let the pillars ride 8px up
 * over the card and clip its bottom radius. */
.team-pillars { --panel-lift-give: 98px; }

/* THE LIFT ONLY APPLIES WHERE THE HERO CAN AFFORD IT.
 *
 * Below 63rem the hero collapses (553px -> 435px) while the card grows
 * taller, so a half-card lift drove the card 60px INTO the lede. The lift is
 * therefore scoped to wide viewports only; narrower, the card sits inside
 * the lavender band in normal flow with its own breathing room above. */
/* --lift-fraction has to be readable by .team-pillars too, since its padding
 * is the other half of the same ramp. */
.team-pillars {
    --lift-fraction: clamp(0, (100vw - 48rem) / 27rem, 1);
}

/* linear-gradient(#4A2C5E 0%, #9F7CF0 100%) at 10px radius on the source -
 * the deep violet at the top, the opposite direction to the homepage's
 * clinic cards. */
.locations-panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-l);
    background: linear-gradient(180deg, var(--violet-deep) 0%, var(--violet) 100%);
    border-radius: 10px;
    padding: var(--space-l) var(--space-xl);
    box-shadow: 0 8px 26px rgb(74 44 94 / 0.22);
}
.locations-panel__copy { flex: 1 1 32rem; }
.locations-panel__title {
    font-family: var(--font-heading);
    /* 41px on the source. */
    font-size: clamp(1.75rem, 1.28rem + 2.1vw, 2.5625rem);
    font-weight: 700;
    line-height: var(--leading-s);
    color: var(--on-primary);
    margin-top: 0;
    margin-bottom: var(--space-2xs);
}
/* The panel's ground is a saturated violet, so this copy takes the cream
 * rather than the base rgba(0,0,0,.68) body ink, which would vanish. */
.locations-panel__body {
    color: var(--cream);
    font-size: var(--step-0);
    line-height: var(--leading-m);
}

@media (max-width: 62rem) {
    .locations-panel {
        justify-content: center;
        text-align: center;
        padding: var(--space-l) var(--space-m);
    }
    .locations-panel__copy { flex: 1 1 100%; }
}

/* This section must sit ABOVE .doc-hero__panel-band in the stacking order.
 * The band is position:relative with a z-index and its box extends 98px past
 * its own content (the lifted card keeps its full height in flow), so
 * without this the band's opaque lavender paints over the top ~18px of every
 * icon in the first pillar row - which reads exactly like the icons being
 * clipped, and is why the identical icon rendered perfectly when cloned
 * anywhere else on the page. */
.team-pillars {
    position: relative;
}

/* ── Team pillars ─────────────────────────────────────────────────────
 * Four columns on the lavender wash, each a heading over a short
 * paragraph. No card ground on the source - the band's own colour is the
 * only surface, which is why these are bare grid cells rather than
 * .panel. */
/* Ported from the Eastgardens .detail-strip, which handles the 4 -> 2x2 -> 1
 * collapse cleanly. The key point is that there is NO gap: the cells sit
 * flush so their borders actually touch, and the padding inside each cell
 * provides the visual separation. A gap here is what stopped the horizontal
 * rule ever reaching the vertical one. */
.pillar-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 36rem) {
    .pillar-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 62rem) {
    .pillar-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* Inline SVG copied from the source's Font Awesome glyphs (briefcase-medical,
 * user-nurse, clinic-medical, hand-holding-medical) - the paths only, so no
 * webfont or icon library is loaded. 30px in --violet, as measured. */
.pillar__icon {
    display: block;
    margin-bottom: var(--space-s);
    color: var(--violet);
}
/* Size on the SVG itself, not on the span with height:100% inheriting down.
 * The percentage form rendered only the top 12px of a 30px glyph here, while
 * the identical .careers-pillar__icon rule - which sets width/height
 * directly on the svg - painted all 30. Measured side by side on the two
 * pages before changing it. Height only, so the non-square viewBoxes
 * (448x512, 576x512) keep their aspect instead of being squashed. */
/* Both axes explicitly, and the span shrink-wrapped to the icon.
 *
 * `width: auto` on an SVG in a WIDE block does not resolve from the aspect
 * ratio - it takes the container's width (270px in a 4-column track) and
 * then fits the viewBox into 270x30, letterboxing the glyph down to ~12px
 * of actual ink. That is why the icons looked sliced at 4 columns and were
 * fine at 2: the narrower track made the same bug much smaller. Measured
 * 12px of ink at 1440 vs 28px at 990 before fixing.
 *
 * preserveAspectRatio keeps each non-square viewBox (448x512, 576x512)
 * centred rather than stretched inside its 30px box. */
.pillar__icon {
    width: fit-content;
}
.pillar__icon svg {
    width: 30px;
    height: 30px;
    display: block;
}
/* The source separates the columns with a hairline in --violet-deep. The
 * rule goes on the left edge of every column except the first in each ROW,
 * so it survives the 4 -> 2 -> 1 column collapse without a stray leading
 * line: at 4-up only the 1st is exempt, at 2-up the 1st and 3rd. */
.pillar { padding: var(--space-m); }
/* Four across: a rule between each pair. */
.pillar + .pillar {
    border-left: var(--border-thin) solid
        color-mix(in oklab, var(--violet-deep) 45%, transparent);
}
/* In the 2x2 band the borders follow the GRID, not source order: one to the
 * left of the right-hand column, one above the second row. */
@media (min-width: 36rem) and (max-width: 61.999rem) {
    .pillar + .pillar { border-left: 0; border-top: 0; }
    .pillar:nth-child(2n) {
        border-left: var(--border-thin) solid
            color-mix(in oklab, var(--violet-deep) 45%, transparent);
    }
    .pillar:nth-child(n + 3) {
        border-top: var(--border-thin) solid
            color-mix(in oklab, var(--violet-deep) 45%, transparent);
    }
}
/* One column: a rule above every cell but the first. */
@media (max-width: 35.999rem) {
    .pillar + .pillar {
        border-left: 0;
        border-top: var(--border-thin) solid
            color-mix(in oklab, var(--violet-deep) 45%, transparent);
    }
}
.pillar__title {
    /* 25px on the source - a card heading, so a step below the section
     * headings and set from the h3 step rather than h2's. */
    font-size: var(--step-1);
    line-height: var(--leading-s);
    margin-top: 0;
    margin-bottom: var(--space-2xs);
}
/* 15px on the source: deliberately below body size, so four columns of it
 * still read as supporting copy rather than as four equal arguments. */
.pillar__body {
    font-size: var(--step--1);
    line-height: var(--leading-l);
}

/* ── Doctors grid ─────────────────────────────────────────────────────
 * Three to a row on the source, each a 150x150 portrait above the name.
 * The cards carry no ground of their own - they sit directly on the cream
 * band, separated by the gutter alone. */
.doctors__head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: end;
    gap: var(--space-l) var(--grid-gutter);
    margin-bottom: var(--space-xl);
}
/* 49px on the source, matching the closing CTA's heading. */
.doctors__title {
    font-size: clamp(2rem, 1.5rem + 2.2vw, 3.0625rem);
    margin: 0;
}
.doctors__intro { justify-self: end; text-align: right; }
.doctors__intro .lede { margin-bottom: var(--space-s); }

.doctor-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: var(--grid-gutter);
    row-gap: var(--space-xl);
}

/* 150x150 at 10px radius on the source. The avatars ship at exactly
 * 150x150, so the box is fixed rather than fluid - scaling a 150px source
 * up on a wide viewport would only soften it. aspect-ratio guards the
 * frame if a replacement image ever arrives non-square. */
.doctor-card__avatar {
    width: 150px;
    max-width: 100%;
    aspect-ratio: 1;
    border-radius: 10px;
    overflow: hidden;
    margin-bottom: var(--space-s);
    /* A ground behind the portrait, so a slow or missing image leaves the
     * card's shape intact rather than a collapsed gap. */
    background: var(--violet-wash);
}
.doctor-card__avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.doctor-card__name {
    /* 25px on the source. */
    font-size: var(--step-1);
    line-height: var(--leading-s);
    margin-top: 0;
    margin-bottom: var(--space-3xs);
}
/* The qualifications line is an h2 on the source at 19px in the violet.
 * It is a paragraph here - it is a subtitle on the name, not a section
 * heading, and marking it up as one would put a second-level heading
 * below a third-level one ten times over. */
.doctor-card__quals {
    font-family: var(--font-heading);
    font-size: var(--step-0);
    font-weight: 700;
    color: var(--violet);
    margin-bottom: var(--space-xs);
}
.doctor-card__bio { line-height: var(--leading-l); }

@media (max-width: 62rem) {
    .doctors__head { grid-template-columns: 1fr; }
    .doctors__intro { justify-self: start; text-align: left; }
    .doctor-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 40rem) {
    .doctor-grid { grid-template-columns: 1fr; }
}

/* ── Support team photographs ─────────────────────────────────────────
 * Three 430x287 photographs at 10px radius, each with a heading beneath.
 * The source gives these no bio copy at all, so the card is the photo and
 * its label and nothing else. */
.support-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--grid-gutter);
}
.support-card { margin: 0; }
.support-card__media {
    /* 430x287 on the source, and the photographs are 1280x853 - the same
     * 3:2, so nothing is cropped away by the frame. */
    aspect-ratio: 430 / 287;
    border-radius: 10px;
    overflow: hidden;
    margin-bottom: var(--space-s);
    background: var(--violet-wash);
}
.support-card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
/* A figcaption, so it needs the heading treatment applied by hand rather
 * than inheriting it - 25px, matching the doctor names. */
.support-card__name {
    font-family: var(--font-heading);
    font-size: var(--step-1);
    font-weight: 700;
    line-height: var(--leading-s);
    color: var(--violet-deep);
}

@media (max-width: 62rem) {
    .support-grid { grid-template-columns: 1fr; }
}

/* ── Closing team CTA ─────────────────────────────────────────────────
 * A photograph as the band's ground with a translucent lavender card over
 * it. The translucency is the whole treatment: rgba(236,229,255,.85) on
 * the source, so the photograph reads through the card rather than being
 * hidden by it. */
.team-cta {
    position: relative;
    isolation: isolate;
    padding-block: var(--space-2xl);
}
.team-cta__media {
    position: absolute;
    inset: 0;
    z-index: -1;
    background: url("/assets/images/team-based-care-bg.webp") center / cover no-repeat;
}
.team-cta__panel {
    /* 20px radius on the source, against the 10px used everywhere else on
     * this page - the one place it differs, so it is stated rather than
     * folded into a token. */
    background: rgb(236 229 255 / 0.85);
    border-radius: 20px;
    padding: var(--space-2xl) var(--space-xl);
    text-align: center;
}
/* 49px on the source. */
.team-cta__title {
    font-size: clamp(2rem, 1.5rem + 2.2vw, 3.0625rem);
    margin-top: 0;
    margin-bottom: var(--space-s);
}
.team-cta__body {
    max-width: 44rem;
    margin-inline: auto;
    margin-bottom: var(--space-l);
    font-size: var(--step-1);
    line-height: var(--leading-m);
    /* The panel is translucent over a photograph, so the body ink is
     * darkened from the base rgba(0,0,0,.68) to hold contrast wherever the
     * image behind it happens to be light. */
    color: var(--violet-deep);
}
/* Two buttons side by side on the source, wrapping rather than shrinking:
 * .btn sets white-space:nowrap, so a squeezed row would overflow instead
 * of breaking. */
.team-cta__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-s);
}

@media (max-width: 40rem) {
    .team-cta__panel { padding: var(--space-xl) var(--space-m); }
    /* Below this width the two pills stacked side by side leave each too
     * narrow to read, so they go full width one above the other. */
    .team-cta__actions .btn { width: 100%; }
}

/* ═══════════════════════════════════════════════════════════════════
 * PRACTICE POLICY · PRIVACY · TERMS - the three policy pages
 *
 * Transcribed from the live Elementor pages the same way the homepage
 * layer above was: band count, card count, radii and grounds come from
 * the measured container list, not from reading the copy.
 * ═══════════════════════════════════════════════════════════════════ */

/* A shared helper the homepage markup already asks for but nothing ever
 * defined - an image that fills its box at a fixed radius. Adding it here
 * makes the existing .media-fill wrappers behave rather than leaving the
 * class inert. */
.media-fill { overflow: hidden; background: var(--surface); }
.media-fill > img,
.media-fill > video { width: 100%; height: 100%; object-fit: cover; display: block; }

/* A generic lime rule. The homepage scopes its own to .about__copy; this
 * is the same treatment available anywhere. */
.rule {
    width: min(100%, 30rem);
    margin: var(--space-m) 0;
    border: 0;
    border-top: 2px solid var(--lime);
}

/* Readable measure for the long prose pages. The source panel is 1290
 * wide with 90px of inner padding, which at 16.5px body lands close to
 * 100 characters - too long to track comfortably, so the prose inside a
 * legal panel is capped nearer the template's own 65ch. */
.prose-measure { max-width: 72ch; }


/* ── PRACTICE POLICY · band 1: hero ────────────────────────────────────
 * Source: 1440x1041, a cream-to-lavender vertical gradient laid over a
 * consultation photograph. Copy left, one 397-wide new-patients card
 * right whose photo (r10 top) and lavender body (r10 bottom) are two
 * stacked containers. */
/* The hero photo sits directly on the New Patients card below it, so its
 * bottom corners are square - a radius there cuts a notch out of the join. */
.policy-hero__media img,
.policy-hero img {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}

.policy-hero {
    position: relative;
    isolation: isolate;
    /* Clears the site header's deliberate -120px overlap before adding any
     * padding of its own - otherwise the copy runs under the header bar,
     * which it did at 390 (measured -55px). */
    padding-block: calc(120px + var(--space-2xl)) var(--space-3xl);
    background:
        linear-gradient(180deg, var(--cream) 0%, var(--violet-wash) 100%);
}
/* ONE wash, not two. Dimming the photo to 0.16 AND laying a near-opaque
 * gradient over it stacked to about 0.02 effective - the landscape simply
 * vanished, where the source keeps it plainly legible behind the copy.
 * The photo carries full opacity and the gradient alone does the washing. */
.policy-hero::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: url("/assets/images/policy-hero-consultation.webp") center / cover no-repeat;
}
.policy-hero::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(180deg,
        color-mix(in oklab, var(--cream) 78%, transparent) 0%,
        color-mix(in oklab, var(--violet-wash) 86%, transparent) 100%);
}
.policy-hero > * { position: relative; z-index: 1; }

.policy-hero__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 397px;
    gap: var(--space-2xl);
    align-items: center;
}
.policy-hero__copy .display { margin-block: var(--space-2xs) var(--space-s); }
.policy-hero__copy .lede { color: var(--violet-deep); }

.new-patients {
    border-radius: 10px;
    overflow: hidden;
    background: var(--violet-wash);
    box-shadow: 0 18px 46px -28px rgba(74, 44, 94, 0.55);
}
.new-patients__media { aspect-ratio: 397 / 372; }
.new-patients__body { padding: var(--space-l); text-align: center; }
.new-patients__title {
    margin-top: 0;
    font-size: var(--step-2);
    color: var(--violet-deep);
}

@media (max-width: 62rem) {
    .policy-hero__grid { grid-template-columns: 1fr; gap: var(--space-xl); }
    .new-patients { max-width: 26rem; margin-inline: auto; }
}


/* ── PRACTICE POLICY · band 2: gradient help strip ─────────────────────
 * A 1290x173 r10 card on a violet-to-dark-violet gradient. The source
 * floats it over the seam between the hero and the lavender band, so it
 * is pulled up into the band above rather than given a band of its own. */
/* The section's own pull is the INVERSE of the lift fraction: full where the
 * fluid lift has ramped to nothing (or the card would sit below the hero
 * with a gap - measured -9% at 768), and zero where the lift is doing the
 * whole job (or it adds on top and overshoots - 78% instead of 50%). */
.policy-help {
    position: relative;
    z-index: 2;
    /* The card is lifted 50% up off the hero, so its lower half lands BELOW the
     * hero's gradient - on the page's white ground, which read as the lavender
     * divider sitting under the card instead of behind it. This carries the
     * hero's closing lavender down through the band so the card is overlaid on
     * it, which is what the spacing already implied. */
    background: var(--violet-wash);
    --lift-fraction: clamp(0, (100vw - 48rem) / 27rem, 1);
    margin-top: calc(-1 * var(--space-l) * (1 - var(--lift-fraction)));
}
.policy-help__card {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-l);
    padding: var(--space-l) var(--space-xl);
    border-radius: 10px;
    background: linear-gradient(180deg, var(--violet) 0%, var(--violet-deep) 100%);
    box-shadow: 0 22px 50px -30px rgba(74, 44, 94, 0.7);
}
.policy-help__hours {
    display: flex;
    align-items: center;
    gap: var(--space-s);
    font-family: var(--font-heading);
    font-size: var(--step-1);
    font-weight: 700;
    line-height: var(--leading-m);
    color: var(--cream);
}
/* The source sets the hours behind a white disc with the violet clock. */
.policy-help__icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 62px;
    height: 62px;
    border-radius: 50%;
    background: var(--cream);
    color: var(--violet-deep);
}
.policy-help__icon svg { width: 28px; height: 28px; display: block; }
.policy-help__text { color: var(--cream); font-weight: 500; }

@media (max-width: 62rem) {
    .policy-help__card { grid-template-columns: 1fr; text-align: center; justify-items: center; }
}


/* ── PRACTICE POLICY · band 3: appointment types ───────────────────────
 * Three equal columns across a 1290-wide row on the lavender wash. The
 * source gives these no card background - they read as columns of the
 * band itself, separated only by the gutter. */
.appt-band { padding-block: var(--space-2xl); }
/* Same structure as the doctors .pillar-grid and the careers pillars: NO gap,
 * so the cells touch and their borders can actually meet, with equal padding
 * per cell doing the separating. A gap here would leave the rules floating in
 * the middle of it, or make them impossible to join at all. */
.appt-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
}
.appt { padding-inline: var(--space-l); }
.appt:first-child { padding-left: 0; }
.appt:last-child { padding-right: 0; }
/* Vertical rules BETWEEN the columns - two of them for three columns. */
.appt + .appt {
    border-left: var(--border-thin) solid
        color-mix(in oklab, var(--violet) 40%, transparent);
}

/* The lighter purple, matching the eyebrows rather than the darker body
 * violet the service cards use. */
.appt__icon { display: block; margin-bottom: var(--space-s); }
.appt__icon svg { width: auto; height: 34px; color: var(--violet); display: block; }

.appt__title { margin-top: 0; font-size: var(--step-2); }

@media (max-width: 62rem) {
    .appt-grid { grid-template-columns: 1fr; gap: var(--space-l); }
    /* Stacked: the vertical rules make no sense, and the cells no longer need
     * the horizontal insets that created room for them. */
    .appt { padding-inline: 0; }
    .appt + .appt { border-left: 0; }
}


/* ── PRACTICE POLICY · band 4: emergency care / bulk billing ───────────
 * One cream band, two columns at the source's largest section heading. */
.emergency { background: var(--cream); padding-block: var(--space-2xl); }
.emergency__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-2xl);
    align-items: start;
}
.emergency h2 { margin-top: 0; font-size: var(--step-4); }
.emergency__sub {
    margin-top: var(--space-l);
    font-size: var(--step-1);
    color: rgba(0, 0, 0, 0.75);
}

/* `.tick-list` itself is defined once, further up (lime SVG mask). This block
 * previously redefined it as a violet border-chevron, which — landing later —
 * silently restyled the About page's lists too. Its comment already said "a
 * lime tick", so the two agents wanted the same thing; only the modifier and
 * the trailing margin were genuinely this page's, and they are kept here. */
.emergency .tick-list,
.policy-split .tick-list { margin-bottom: var(--space-m); }
.emergency .tick-list li,
.policy-split .tick-list li { font-weight: 500; }
.tick-list--muted li::before { background: color-mix(in oklab, var(--violet-deep) 55%, transparent); }

@media (max-width: 62rem) { .emergency__grid { grid-template-columns: 1fr; gap: var(--space-xl); } }


/* ── PRACTICE POLICY · band 5: the six policy cards ────────────────────
 * The source is ONE 1268-tall dark-violet-to-violet gradient band with
 * six 660-wide cream cards at r15 in two columns. The cards do not share
 * a row baseline - each column packs to its own height - so this is a
 * masonry column layout, not a two-column grid. */
.policy-cards {
    padding-block: var(--space-2xl);
    background: linear-gradient(180deg, var(--violet-deep) 0%, var(--violet) 100%);
}
.policy-cards__grid {
    columns: 2;
    column-gap: var(--space-l);
}
.policy-card {
    break-inside: avoid;
    margin-bottom: var(--space-l);
    padding: var(--space-l) var(--space-xl);
    background: var(--cream);
    border-radius: 15px;
}
.policy-card__title { margin-top: 0; font-size: var(--step-2); }
.policy-card__sub {
    margin-top: var(--space-m);
    font-size: var(--step-0);
    font-weight: 700;
    color: rgba(0, 0, 0, 0.75);
}

@media (max-width: 62rem) { .policy-cards__grid { columns: 1; } }


/* ── PRACTICE POLICY · bands 6 & 7: photo / copy splits ────────────────
 * Two cream bands with the same shape and the sides swapped: a 625-wide
 * r15 photo against the copy column. */
.policy-split { background: var(--cream); padding-block: var(--space-2xl); }
.policy-split__row {
    display: grid;
    grid-template-columns: 625fr 715fr;
    gap: var(--space-2xl);
    align-items: center;
}
.policy-split--reverse .policy-split__row { grid-template-columns: 715fr 625fr; }

/* aspect-ratio alone, never with align-self:stretch - a stretched grid
 * item has a definite height, so the ratio then resolves the WIDTH and the
 * item blows past its column. Let the column set the width. */
.policy-split__media {
    width: 100%;
    border-radius: 15px;
    aspect-ratio: 625 / 547;
}
.policy-split--reverse .policy-split__media { aspect-ratio: 625 / 586; }

.policy-split__copy h2 { margin-top: 0; font-size: var(--step-4); }
.policy-split__sub {
    margin-top: var(--space-l);
    font-size: var(--step-1);
    color: rgba(0, 0, 0, 0.75);
}

/* Office of the Health Ombudsman: three details across, under the copy. */
.ombudsman__name { margin-top: var(--space-l); font-size: var(--step-2); }
.ombudsman {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-m);
    margin-top: var(--space-s);
}
.ombudsman__label {
    font-family: var(--font-heading);
    font-weight: 700;
    color: var(--violet-deep);
    margin-bottom: var(--space-3xs);
}
.ombudsman__item p { font-size: var(--step--1); }
.ombudsman__item a { overflow-wrap: anywhere; }

@media (max-width: 62rem) {
    .policy-split__row,
    .policy-split--reverse .policy-split__row { grid-template-columns: 1fr; gap: var(--space-xl); }
    /* Keep the reading order copy-then-photo on both bands when they stack,
     * so the reversed band does not lead with an image on a phone. */
    .policy-split .policy-split__media { order: 2; }
    .policy-split__media,
    .policy-split--reverse .policy-split__media { aspect-ratio: 16 / 10; }
}
@media (max-width: 44rem) {
    .ombudsman { grid-template-columns: 1fr; gap: var(--space-s); }
}


/* ── PRACTICE POLICY · band 8: closing CTA panel ───────────────────────
 * A cream-to-lavender gradient over a photograph, carrying one wide
 * 1350x616 translucent-white panel at r20. */
.policy-cta {
    position: relative;
    isolation: isolate;
    padding-block: var(--space-2xl);
    background: linear-gradient(180deg, var(--cream) 0%, var(--violet-wash) 100%);
}
.policy-cta::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        linear-gradient(180deg,
            color-mix(in oklab, var(--cream) 72%, transparent) 0%,
            color-mix(in oklab, var(--violet-wash) 82%, transparent) 100%),
        url("/assets/images/policy-still-have-questions.webp") center / cover no-repeat;
}
.policy-cta__panel {
    padding: var(--space-2xl) var(--space-xl);
    text-align: center;
    background: rgba(255, 255, 255, 0.86);
    border-radius: 20px;
    backdrop-filter: blur(2px);
}
.policy-cta__panel > * { max-width: 46rem; margin-inline: auto; }
.policy-cta__title { margin-block: var(--space-2xs) var(--space-s); font-size: var(--step-4); }
.policy-cta__clinics {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-xs);
    list-style: none;
    margin: 0 auto var(--space-l);
    padding: 0;
}
.policy-cta__clinics li {
    margin: 0;
    padding: var(--space-3xs) var(--space-s);
    border-radius: 100px;
    background: var(--violet-wash);
    font-family: var(--font-heading);
    font-weight: 700;
    color: var(--violet-deep);
}


/* ── PRIVACY & TERMS · the legal panel ─────────────────────────────────
 * Both pages are the same two containers on the source: a 1440x1000
 * photograph behind the header, and ONE 1290-wide r20 panel that starts
 * inside the photo and runs the whole document down onto the lavender
 * band beneath. The panel is the page - there are no other bands. */
.legal {
    position: relative;
    isolation: isolate;
    /* The site header carries margin-bottom:-120px so a hero can sit under
     * it, so this band clears 120px BEFORE its own padding starts.
     *
     * The rest is the source's own geometry: the photograph runs at full
     * strength from the top of the page to y=880, where the panel begins.
     * The header floats over the photo rather than sitting above it. */
    padding-block: calc(120px + 640px) var(--space-2xl);
    background: var(--violet-wash);
}
.legal__media {
    position: absolute;
    inset: 0 0 auto 0;
    height: 1000px;
    z-index: -1;
    overflow: hidden;
}
.legal__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The source does NOT wash this photo - it runs at full strength and only
 * meets the lavender at its very bottom edge. Washing the whole image (as
 * this first did) loses the picture entirely. */
.legal__media::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        transparent 0%,
        transparent 82%,
        var(--violet-wash) 100%);
}

.legal__panel {
    padding: var(--space-2xl) clamp(var(--space-m), 6vw, 5.625rem);
    background: var(--cream);
    border-radius: 20px;
    box-shadow: 0 30px 70px -44px rgba(74, 44, 94, 0.6);
}

/* The source sets the page title in the full-strength violet, not the
 * dark violet the section headings use. */
.legal__title {
    margin-top: 0;
    font-size: var(--step-4);
    color: var(--violet);
}
.legal__title2 { font-size: var(--step-4); color: var(--violet); }
.legal__rule { width: 100%; margin-block: var(--space-xl); }

.legal__lede {
    max-width: 60ch;
    font-size: var(--step-1);
    line-height: var(--leading-m);
    color: rgba(0, 0, 0, 0.75);
    font-weight: 500;
}

/* Headings inside the panel: the source runs the numbered sections at 41px
 * and their subheads at 33px, both in near-black rather than the violet. */
.legal__panel h2 {
    margin-top: var(--space-xl);
    font-size: var(--step-3);
    color: rgba(0, 0, 0, 0.78);
}
.legal__panel h3 {
    margin-top: var(--space-l);
    font-size: var(--step-2);
    color: rgba(0, 0, 0, 0.78);
}

/* Long-form prose wants more air between lines than the site body default
 * and a measure short enough to track across. */
.legal__panel p,
.legal__panel li {
    max-width: 72ch;
    line-height: var(--leading-xl);
}
.legal__panel ul { max-width: 72ch; }
.legal__panel li { color: rgba(0, 0, 0, 0.68); font-weight: 500; }

@media (max-width: 48rem) {
    /* Still clears the header's -120px overlap; the photo band above the
     * panel shrinks to a third of its desktop height so a phone is not
     * scrolling past a full screen of picture before the document starts. */
    .legal { padding-block: calc(120px + 190px) var(--space-xl); }
    .legal__media { height: 460px; }
}


/* ═══════════════════════════════════════════════════════════════════
 * CONTACT & CAREERS
 *
 * Same method as the bands above: band count, column count, radii and
 * grounds are taken from the measured container list on the live page,
 * not from reading the copy.
 * ═══════════════════════════════════════════════════════════════════ */

/* ── CONTACT · band 1: hero ────────────────────────────────────────────
 * Source: 1440x1045, the 5.webp landscape as the ground under a lavender
 * wash, carrying ONE cream card (1350x945, r15) that holds the eyebrow,
 * display heading, lede, the entire enquiry form, and the violet-wash
 * "Please note" strip. The form is inside the card - the geometry shows
 * no container of its own around it, and the note strip (950x106) sits
 * within the card's bounds, not below it. */
.contact-hero {
    position: relative;
    isolation: isolate;
    /* The header overlaps the hero by design, so the top padding is spent
     * repaying that before it buys any clearance. */
    padding-block: calc(140px + var(--space-2xl)) var(--space-2xl);
}

/* The card drops past the hero's bottom edge onto the lavender band below it,
 * rather than stopping short. transform paints it down without reflowing; the
 * matching negative margin gives the vacated height back so the band does not
 * gain a gap above it. */
/* No overlap. The card simply sits within the hero with space above and below,
 * and is slightly translucent so the photograph behind reads through it. This
 * card holds the entire contact form and runs to ~1000px, so every
 * height-dependent overlap trick (transform down, translateY(-50%) up) either
 * underlaid it or dragged it off the top of the page. */
.contact-hero__lift { position: relative; }

.contact-hero__media {
    position: absolute;
    inset: 0;
    z-index: -2;
    overflow: hidden;
}
.contact-hero__media img {
    width: 100%; height: 100%;
    object-fit: cover; display: block;
    /* The global img rule rounds every image by 12px. On a full-bleed
     * background that shows as rounded corners with page ground behind them -
     * the same trap as the careers hero. A full-bleed background is square. */
    border-radius: 0;
}

/* The wash the source lays over the photograph: near-opaque lavender, so
 * the landscape reads as texture at the edges rather than as an image. */
.contact-hero::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    /* Was 86/72/88% - effectively opaque, so the photograph read as a flat
     * lavender block. The card sits on its own panel background and does not
     * need the photo knocked back to stay legible, so this is now a light
     * tint that ties the photo to the palette rather than hiding it. */
    background: linear-gradient(
        180deg,
        color-mix(in oklab, var(--violet-wash) 22%, transparent) 0%,
        color-mix(in oklab, var(--violet-wash) 10%, transparent) 55%,
        color-mix(in oklab, var(--violet-wash) 30%, transparent) 100%);
}

.contact-hero__card {
    /* Slightly narrower than the container it sits in, so the hero photograph
     * shows down both sides rather than the card running edge to edge. The
     * inline margin only bites once there is room for it. */
    max-width: 62rem;
    margin-inline: auto;
    border-radius: var(--radius-l);
    padding: var(--space-2xl) var(--space-xl);
    /* Slightly translucent so the hero photograph shows through. The blur keeps
     * the form legible over a busy photo without knocking the photo back. */
    background: color-mix(in oklab, var(--cream) 70%, transparent);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
}

.contact-hero__head {
    text-align: center;
    max-width: 46rem;
    margin-inline: auto;
    margin-bottom: var(--space-xl);
}
.contact-hero__head .lede { margin-bottom: var(--space-s); }
.contact-hero__sub { margin-bottom: 0; }

/* The form: two 465-wide fields per row on the source, then a full-width
 * message box, then a centred lime pill. Its inputs are underlines rather
 * than boxes - a bottom border only, transparent ground. */
.contact-form {
    max-width: 60rem;
    margin-inline: auto;
}
.contact-form__row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-m);
}
.contact-form__field { margin-bottom: var(--space-m); }

/* The label is present for assistive technology; the source shows the
 * field name as a placeholder inside the underline. */
.contact-form__field label {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.contact-form input,
.contact-form select,
.contact-form textarea {
    width: 100%;
    background: transparent;
    border: 0;
    /* Violet, not lime. The card is translucent over the hero photograph, and
     * lime on that ground does not hold enough contrast to read as a field
     * boundary. */
    border-bottom: 1px solid color-mix(in oklab, var(--violet-deep) 28%, transparent);
    border-radius: 0;
    padding: var(--space-s) 0;
    color: var(--ink);
}
.contact-form input:hover,
.contact-form select:hover,
.contact-form textarea:hover { border-bottom-color: color-mix(in oklab, var(--violet-deep) 45%, transparent); }
.contact-form input:focus,
.contact-form select:focus,
.contact-form textarea:focus {
    outline: 0;
    border-bottom-color: var(--violet);
}
.contact-form textarea { min-height: 9rem; resize: vertical; }
.contact-form ::placeholder { color: color-mix(in oklab, var(--ink) 58%, transparent); opacity: 1; }

.contact-form__submit { text-align: center; margin-top: var(--space-l); }

/* The "Please note" strip: violet wash, a lime bar down its leading edge,
 * square corners on the source. */
.contact-note {
    margin-top: var(--space-xl);
    background: var(--violet-wash);
    border-left: 4px solid var(--violet);
    padding: var(--space-s) var(--space-m);
}
.contact-note__title {
    font-family: var(--font-heading);
    font-weight: 700;
    color: var(--violet-deep);
    margin-bottom: var(--space-3xs);
}
.contact-note__body { font-size: var(--step--1); }

@media (max-width: 48rem) {
    .contact-form__row { grid-template-columns: 1fr; gap: 0; }
    .contact-hero__card { padding: var(--space-xl) var(--space-m); }
}

/* ── CONTACT · band 2: the three-up detail strip ───────────────────────
 * Source: 1440x517 on the violet wash, holding ONE 1290x217 row of three
 * equal columns. There is no per-column container in the geometry, so the
 * columns are separated by a hairline rule rather than given cards. */
.contact-detail { padding-block: var(--space-2xl); }

.contact-detail__row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-l);
}
.contact-detail__col {
    text-align: center;
    padding-inline: var(--space-m);
    border-left: 1px solid color-mix(in oklab, var(--violet-deep) 20%, transparent);
}
.contact-detail__col:first-child { border-left: 0; }

.contact-detail__icon { display: block; margin-bottom: var(--space-s); }
.contact-detail__icon svg {
    width: 30px;
    height: 30px;
    color: var(--violet);
    display: block;
    margin-inline: auto;
}
.contact-detail__title {
    font-family: var(--font-heading);
    font-size: var(--step-2);
    font-weight: 700;
    color: var(--violet-deep);
    margin-bottom: var(--space-s);
}
.contact-detail__body { font-size: var(--step--1); line-height: var(--leading-l); }
/* Was color:inherit / font-weight:inherit, which made the phone, fax and email
 * read as plain body text - the only links on the site that did not look like
 * links. They now take the same treatment as any other inline link. */
.contact-detail__body a,
.contact-detail__body .mf-email {
    color: var(--primary);
    font-weight: var(--weight-600);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
}
.contact-detail__body a:hover,
.contact-detail__body .mf-email:hover { color: var(--violet); }

@media (max-width: 62rem) {
    .contact-detail__row { grid-template-columns: 1fr; gap: var(--space-m); }
    .contact-detail__col {
        border-left: 0;
        border-top: 1px solid color-mix(in oklab, var(--violet-deep) 20%, transparent);
        padding-top: var(--space-m);
    }
    .contact-detail__col:first-child { border-top: 0; padding-top: 0; }
}

/* ── CONTACT · band 3: clinic locations ────────────────────────────────
 * Source: a cream band (1440x1013) with a centred head, then ONE row of
 * three 410x441 cards on the 106deg dark-violet-to-violet gradient, r15.
 * The 330x230 map (r10) sits INSIDE each card at its foot - it is not a
 * band of its own, which is what reading the copy alone would suggest. */
.clinic-locations { padding-block: var(--space-2xl); background: var(--cream); }

.clinic-locations__head {
    text-align: center;
    max-width: 48rem;
    margin-inline: auto;
    margin-bottom: var(--space-xl);
}
.clinic-locations__head .lede { margin-bottom: var(--space-2xs); }

.clinic-locations__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-m);
}

.loc-card {
    background: linear-gradient(106deg, var(--violet-deep) 0%, var(--violet) 100%);
    border-radius: var(--radius-l);
    padding: var(--space-l) var(--space-m);
    text-align: center;
    display: flex;
    flex-direction: column;
}
.loc-card__name {
    color: var(--on-primary);
    font-size: var(--step-2);
    font-weight: 700;
    margin-bottom: var(--space-2xs);
}
.loc-card__address {
    color: var(--on-primary);
    font-size: var(--step--1);
    margin-bottom: var(--space-2xs);
}
.loc-card__phone {
    font-family: var(--font-heading);
    font-weight: 700;
    margin-bottom: var(--space-m);
}
.loc-card__phone a { color: var(--lime); text-decoration: none; }
.loc-card__phone a:hover { text-decoration: underline; }

.loc-card__map {
    margin-top: auto;
    border-radius: var(--radius-m);
    overflow: hidden;
    aspect-ratio: 330 / 230;
    background: color-mix(in oklab, var(--violet-wash) 82%, white);
}
.loc-card__map iframe { width: 100%; height: 100%; border: 0; display: block; }

@media (max-width: 62rem) {
    .clinic-locations__grid { grid-template-columns: 1fr; }
    .loc-card__map { aspect-ratio: 16 / 9; }
}

/* ── CAREERS · band 1: hero ────────────────────────────────────────────
 * Source: 1440x1164, a white-to-lavender vertical gradient over the same
 * landscape photograph, carrying centred copy and a lime button. The
 * 1350x650 team photograph (r20) belongs to THIS band - it sits at its
 * foot and overlaps the violet band that follows, which is why the band
 * below starts 60px under the photo's lower edge on the source. */
/* .site-header carries margin-bottom: -120px so heroes sit under it, so a
 * hero's top padding is spent repaying that before it buys any clearance.
 * --space-3xl is ~120px, which repaid the overlap exactly and left the
 * eyebrow 20px under the header (17px on mobile) — visibly cramped, and
 * the reason this page read as having no top spacing. The sibling heroes
 * clear 80-100px, so add --space-xl on top to match them. */
.careers-hero {
    position: relative;
    /* NOT isolation:isolate. That made this hero a stacking context, which
     * TRAPPED .careers-hero__photo-wrap's z-index inside it - so the photo
     * could never paint above the purple band that follows, and its 60px of
     * overhang was painted over. The band read as clipping the photo flush.
     * A positive z-index here contains the hero's own negative-z media and
     * gradient just as well, while still letting the whole hero - photo
     * included - stack above the following band. */
    z-index: 1;
    padding-block: calc(var(--space-3xl) + var(--space-xl)) 0;
}

/* The hero's two background layers stop at the photo's top edge, NOT at the
 * hero's own bottom edge. The hero box extends to the photo's bottom, which
 * is 60px INSIDE the purple band below; an inset:0 background therefore
 * painted a pale wash across that whole 60px strip, hiding the purple beside
 * the photo. That is what made the photo read as stopping flush at the band
 * for so long - the overhang was always there, the band just wasn't visible
 * next to it. --careers-hero-bg-end is the distance from the hero's bottom
 * up to where the photo starts. */
.careers-hero { --careers-hero-overhang: var(--space-xl); }

/* The background gradient the photo sits ON. Live builds this hero as a solid
 * white -> lavender gradient with the photograph laid over it at 50% opacity,
 * so the photo is uniformly half-strength at EVERY width. Ours previously ran
 * the photo at full opacity with a wash painted over the top, which matched
 * at narrow widths (where the wash covered most of the photo) but read far
 * too saturated when wide. Same model as live now. */
.careers-hero__media {
    position: absolute;
    inset: 0 0 var(--careers-hero-overhang, 0px) 0;
    z-index: -2;
    overflow: hidden;
    background: linear-gradient(180deg, #ffffff 0%, #ece5ff 100%);
}
/* border-radius:0 is deliberate. The global img rule rounds every image by
 * 12px; harmless while this background ran the hero's full height, because
 * the rounded bottom corners fell outside the visible area. Clipping the
 * media short of the overhang brought them into view as rounded corners with
 * a sliver of page background beneath. A full-bleed background is square. */
.careers-hero__media img {
    width: 100%; height: 100%;
    object-fit: cover; display: block;
    /* border-radius:0 is deliberate - see below. */
    border-radius: 0;
    /* Matches live's ::before opacity. The gradient behind does the lightening
     * now, so this stays constant across widths. */
    opacity: 0.5;
    /* No scale hack needed: the source image had a single baked-in near-white
     * bottom row (visible on live too, same asset) which landed right on the
     * seam and read as a pale sliver above the purple. That row is cropped out
     * of careers-hero-bg.webp itself - 1920x1080 -> 1920x1079. */
}

.careers-hero::after {
    content: "";
    position: absolute;
    inset: 0 0 var(--careers-hero-overhang, 0px) 0;
    z-index: -1;
    /* The photo is half-opacity over a white->lavender gradient now (live's
     * model), so this layer no longer has to lighten anything. All it does is
     * carry the violet foot that blends the hero into the purple band. */
    background: linear-gradient(
        180deg,
        transparent 0%,
        transparent 55%,
        color-mix(in oklab, var(--violet-wash) 55%, transparent) 100%);
}

.careers-hero__inner { text-align: center; padding-bottom: var(--space-xl); }
.careers-hero__content { max-width: 46rem; margin-inline: auto; }
.careers-hero__content .lede { color: var(--ink); }

/* The photo hangs into the band below. Its wrapper keeps the container
 * gutter; the negative margin is on the band that follows, so nothing
 * here needs a z-index fight with the gradient. */
/* z-index 2 so the photograph paints OVER the purple band below it. */
.careers-hero__photo-wrap {
    position: relative;
    /* Above the purple band that follows it, so the photograph's lower edge
     * is drawn ON the purple rather than being covered by it. */
    z-index: 3;
}
.careers-hero__photo {
    border-radius: var(--radius-l);
    aspect-ratio: 1350 / 650;
    /* No negative margin here: the OVERHANG comes from the band below being
     * pulled up under this photo (see .careers-pillars). Measured on the
     * source, the photo's lower edge sits 50px into the purple, so its
     * rounded corners are drawn on the band. */
}

/* ── CAREERS · band 2: the four pillars ────────────────────────────────
 * Source: 1440x489, ONE violet-to-dark-violet vertical gradient band
 * holding a single row of FOUR centred icon columns separated by
 * hairline rules. The geometry lists no card container per column - four
 * cards would be the wrong transcription. */
.careers-pillars {
    background: linear-gradient(180deg, var(--violet) 0%, var(--violet-deep) 100%);
    padding-block: var(--space-2xl) var(--space-xl);
    /* The band is pulled up so the photograph's lower edge sits over it.
     *
     * position:relative + z-index:0 is load-bearing, not decoration: while
     * this band was STATIC its background painted in normal flow order -
     * i.e. after, and therefore ON TOP OF, the photo - so the photo's 60px
     * of overlap was completely hidden and the photo read as stopping flush
     * at the band's edge. The geometry was right the whole time; the paint
     * order was not. */
    /* NOT position:relative with a z-index of its own - that made this band
     * a stacking context that painted over the photograph hanging into it.
     * Left static, the band paints in flow order and the photo's wrapper
     * (z-index 3, position relative) sits cleanly above it. */
    margin-top: calc(var(--space-xl) * -1);
    padding-top: calc(var(--space-2xl) + var(--space-xl));
}

/* Same structure as the doctors .pillar-grid, which handles this collapse
 * properly: NO gap so the cells touch and their borders can meet, equal
 * padding per cell for the separation, mobile-first steps, and in the 2x2
 * band the rules follow the GRID rather than source order - one to the left
 * of the right-hand column, one above the second row. The previous version
 * had vertical rules only, so the fold had no horizontal divider at all. */
.careers-pillars__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 36rem) {
    .careers-pillars__row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 62rem) {
    .careers-pillars__row { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.careers-pillar {
    text-align: center;
    padding: var(--space-m) var(--space-s);
}
/* Four across: a rule between each pair. */
.careers-pillar + .careers-pillar {
    border-left: 1px solid color-mix(in oklab, white 26%, transparent);
}
@media (min-width: 36rem) and (max-width: 61.999rem) {
    .careers-pillar + .careers-pillar { border-left: 0; border-top: 0; }
    .careers-pillar:nth-child(2n) {
        border-left: 1px solid color-mix(in oklab, white 26%, transparent);
    }
    .careers-pillar:nth-child(n + 3) {
        border-top: 1px solid color-mix(in oklab, white 26%, transparent);
    }
}
@media (max-width: 35.999rem) {
    .careers-pillar + .careers-pillar {
        border-left: 0;
        border-top: 1px solid color-mix(in oklab, white 26%, transparent);
    }
}

.careers-pillar__icon { display: block; margin-bottom: var(--space-m); }
.careers-pillar__icon svg {
    width: 35px;
    height: 35px;
    /* Lime rather than the source's white - a deliberate deviation, matching
     * the lime the patient-information icons use elsewhere on the site. */
    color: var(--lime);
    display: block;
    margin-inline: auto;
}
.careers-pillar__title {
    font-family: var(--font-heading);
    font-size: var(--step-2);
    font-weight: 700;
    color: var(--on-primary);
    margin-bottom: var(--space-s);
}
.careers-pillar__body { color: var(--on-primary); font-size: var(--step--1); }


/* ── CAREERS · bands 3 & 4: The Practice / The Location ────────────────
 * Two cream bands built on the same three-column frame. Band 3 puts two
 * copy columns left-and-centre with a 417x885 portrait photo (r20) in
 * the right column; band 4 mirrors it, with a 543x679 photo (r20) in the
 * LEFT column and the heading plus both copy blocks to its right. The
 * measured photos are full-height column fills, not inline figures. */
.careers-split { padding-block: var(--space-2xl); background: var(--cream); }

.careers-split__heading { margin-bottom: var(--space-l); }
/* Zero, not --space-m: this heading sits inside .careers-split__body, which
 * is a grid with its own 40px row-gap - so a bottom margin here STACKS on
 * that gap. It measured 70px under The Location's title against 40px under
 * The Practice's, which is the extra space that read as a hole. */
.careers-split__heading--inline { margin-bottom: 0; }

.careers-split__eyebrow {
    font-size: var(--step-0);
    margin-bottom: var(--space-2xs);
}

.careers-split__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 0.95fr);
    gap: var(--space-l);
    /* stretch, not start: the media column should FILL the row's height
     * rather than dictate it - see the note on .careers-split__media. */
    align-items: stretch;
}
/* The Practice: the heading sits INSIDE the grid on its own row, and the
 * photograph spans both rows - so the image runs the full height of the
 * section alongside the title instead of starting below it. Same effect The
 * Location gets by putting its heading inside the copy column. */
.careers-split__row--headed {
    grid-template-rows: auto 1fr;
}
.careers-split__heading--span {
    grid-column: 1 / 3;
    grid-row: 1;
    margin-bottom: 0;
}
.careers-split__row--headed > .careers-split__col { grid-row: 2; }
.careers-split__row--headed > .careers-split__media {
    grid-column: 3;
    grid-row: 1 / 3;
}
@media (max-width: 62rem) {
    .careers-split__heading--span { grid-column: 1; }
    .careers-split__row--headed > .careers-split__col,
    .careers-split__row--headed > .careers-split__media {
        grid-column: auto;
        grid-row: auto;
    }
}

.careers-split__row--mirror {
    grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.55fr);
}

/* The photograph fills whatever height the copy establishes instead of
 * setting that height itself. It carried aspect-ratio 417/885 - very tall -
 * so it rendered 847px against a tallest copy column of 441px, forcing the
 * row nearly twice as tall as its content needed and pushing the heading
 * down. No aspect-ratio here; the image crops to the column via object-fit
 * (.media-fill already applies it), and a min-height keeps it from
 * collapsing when the copy is short. */
.careers-split__media {
    border-radius: var(--radius-l);
    width: 100%;
    min-height: 22rem;
    overflow: hidden;
    /* position:relative + an absolutely positioned img is what actually
     * takes the photograph OUT of the height calculation. height:100% alone
     * does not: the img is 800x1700, so at this column's width it wants to
     * be ~849px, it becomes the tallest grid item, and the row simply grows
     * to fit it - stretch then has nothing left to stretch against. Taking
     * it out of flow lets the COPY set the row height, which is the point. */
    position: relative;
}
.careers-split__media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Anchored high, but at 18% rather than 0 - the top ~15% of this
     * photograph is empty ceiling above the clinicians' heads, so a true
     * `top` would preserve exactly the part worth losing. 18% skips it and
     * still keeps the faces near the top of the frame. */
    object-position: center 18%;
    display: block;
}
/* The Location's photograph is a landscape and wants its own anchor, not
 * this one - it is framed with the town low and sky above. */
.careers-split__media--wide img { object-position: center center; }
.careers-split__media--wide { min-height: 26rem; }

.careers-split__body { display: grid; gap: var(--space-l); }
.careers-split__pair {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-l);
    align-items: start;
}

@media (max-width: 62rem) {
    .careers-split__row,
    .careers-split__row--mirror { grid-template-columns: 1fr; }
    /* Stacked: the media is no longer beside copy, so it needs a shape of
     * its own again rather than a column height to fill. */
    .careers-split__media,
    .careers-split__media--wide { aspect-ratio: 16 / 10; height: auto; min-height: 0; }
    .careers-split__pair { grid-template-columns: 1fr; }
}

/* The source's tick lists on this page use the same lime check as the rest
 * of the site, so they reuse the shared .tick-list defined above rather
 * than redeclaring it - a second ::before here would mask the first and
 * render the check as a bracket. Only the ink colour differs: this page's
 * lists sit on light grounds and take the body ink. */
/* The tick lists on these two pages use the shared .tick-list. They briefly
 * carried a scoped copy while two conflicting .tick-list definitions were
 * live at equal specificity - the second inherited the first's mask and
 * ground, clipping the marker to a bracket fragment. That was reconciled
 * upstream in this file, so the shared rule is correct again and the copy
 * is gone. Only the ink differs: these lists sit on light grounds. */
.careers-split .tick-list li,
.careers-advantage .tick-list li { color: rgba(0, 0, 0, 0.68); font-weight: 500; }


/* ── CAREERS · band 5: why GPs choose Hinchinbrook ─────────────────────
 * Source: a violet-wash band (1440x653) in three columns - copy and the
 * lime button on the left, two tick-lists to its right. */
.careers-advantage { padding-block: var(--space-2xl); }

.careers-advantage__row {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-l);
    align-items: start;
}
.careers-advantage__copy { max-width: 30rem; }
.careers-advantage__copy h2 { margin-bottom: var(--space-m); }
.careers-advantage__list h3 {
    font-size: var(--step-1);
    margin-bottom: var(--space-m);
}

/* Tablet: the copy takes a full-width row of its own, and the two benefit
 * lists stay SIDE BY SIDE beneath it - three columns is too tight here but
 * stacking all three wastes the width. Only below 40rem does everything
 * stack into one column. */
@media (max-width: 62rem) {
    .careers-advantage__row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .careers-advantage__copy {
        grid-column: 1 / -1;
        max-width: none;
    }
}
@media (max-width: 40rem) {
    .careers-advantage__row { grid-template-columns: 1fr; }
    .careers-advantage__copy { grid-column: auto; }
}

/* ── CAREERS · band 6: closing CTA ─────────────────────────────────────
 * Source: the Hinchinbrook lookout photograph runs full-bleed under a
 * 628-tall band; a 1350x650 inset crop (r15) sits within the container,
 * and a 1000x602 cream card (r20) overlaps its lower half and hangs past
 * its foot. The card is what carries the copy - the photo is behind it. */
.careers-discover {
    position: relative;
    isolation: isolate;
    padding-block: var(--space-2xl);
    background: var(--surface);
}
.careers-discover::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: url("/assets/images/careers-discover-bg.webp") no-repeat center / cover;
    opacity: 0.5;
}

.careers-discover__photo {
    border-radius: var(--radius-l);
    aspect-ratio: 1350 / 650;
}

.careers-discover__card {
    position: relative;
    /* The inset keeps the card narrower than the photograph it sits on at
     * every width - at 100% it ran edge to edge below ~1000px and the photo
     * disappeared behind it entirely. */
    width: min(100% - (2 * var(--space-l)), 62.5rem);
    margin-inline: auto;
    /* Overlap the photograph's lower half, as the source does. */
    margin-top: calc(var(--space-3xl) * -1);
    border-radius: var(--radius-l);
    padding: var(--space-2xl) var(--space-xl);
    text-align: center;
    box-shadow: 0 18px 48px rgba(74, 44, 94, 0.14);
}
.careers-discover__card h2 { margin-bottom: var(--space-m); }
.careers-discover__card .lede { margin-bottom: var(--space-s); }
.careers-discover__note { font-size: var(--step--1); margin-bottom: var(--space-l); }

/* Below the header's mobile breakpoint the topbar wraps to two lines and
 * the logo card grows, so the hero's --space-3xl top padding no longer
 * clears it and the eyebrow tucks underneath. Both heroes need the extra
 * room at the same width. */
@media (max-width: 62rem) {
    .contact-hero { padding-top: calc(var(--space-3xl) + var(--space-2xl)); }
    .careers-hero { padding-top: calc(var(--space-3xl) + var(--space-xl) + var(--space-l)); }
}

@media (max-width: 62rem) {
    .careers-discover__photo { aspect-ratio: 16 / 10; }
    .careers-discover__card {
        margin-top: calc(var(--space-2xl) * -1);
        padding: var(--space-xl) var(--space-m);
    }
}

/* ── Doctors page band rhythm ─────────────────────────────────────────
 * .section is a semantic hook on this site, not a layout rule: it carries
 * no padding of its own anywhere in this stylesheet, and the homepage's
 * bands each set their own. These three do the same, stated here rather
 * than by giving .section a global padding - that would change every band
 * on every page, which is not this page's call to make.
 *
 * The values come off the source: the lavender pillars band runs
 * 836-1448 around 96px of content, and the doctors band 1448-3744, both
 * of which land on the 80px-at-1440 step the rest of the site uses. */
.team-pillars,
.doctors,
.support-team { padding-block: var(--space-2xl); }

/* The pillars band sits directly beneath the locations panel, which
 * already supplies the air above it - the panel's own row paints the top
 * half of this band's colour. Padding here as well would double it. */
.team-pillars { padding-top: var(--space-l); }

/* The doctors band follows the pillars on a change of ground, so the
 * boundary itself does the separating and this side needs less. */
.doctors { padding-top: var(--space-xl); }

/* The support photographs continue on the same cream ground as the
 * doctors above them, with no colour change to mark the join - so this
 * one keeps the full step, and drops its own bottom padding because the
 * CTA band below brings 80px of its own. */
.support-team { padding-bottom: 0; }

/* ═══════════════════════════════════════════════════════════════════
 * SERVICES PAGE (/services)
 *
 * Transcribed from the live Elementor page's computed geometry at 1440.
 * Ten bands, in source order:
 *   1  svc-hero        hero, gradient + faded photo
 *   2  newpat          gradient new-patient strip straddling bands 1/3
 *   3  appt-features   three appointment features, lavender ground
 *   4  afterhours      after-hours + home visits, white, photo right
 *   5  services-grid   3x3 grid of nine cream cards, lavender ground
 *   6  clinical        three uncarded columns, cream ground
 *   7  telehealth      photo left + specialist list right, half wash
 *   8  svc-cta         CTA strip, no ground
 *   9  allied          copy left, partners card + photo right, cream
 *  10  billing         photo + accreditation left, one tall card right
 * ═══════════════════════════════════════════════════════════════════ */

/* ── Shared: lime tick lists ─────────────────────────────────────────
 * The source draws a Font Awesome check before every list item across
 * six of the ten bands. Drawn as a background so no per-item markup is
 * needed, matching how .pi-card__list already does it on the home page.
 * The source's ticks are dark; lime ties them to the rest of the kit. */
.svc-ticks { list-style: none; margin: 0 0 var(--space-s); padding: 0; }
.svc-ticks li {
    position: relative;
    padding-left: 1.9rem;
    margin-bottom: var(--space-2xs);
    color: rgba(0, 0, 0, 0.68);
    font-weight: 500;
    line-height: var(--leading-m);
}
.svc-ticks li:last-child { margin-bottom: 0; }
.svc-ticks li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.28em;
    width: 1.1rem;
    height: 1.1rem;
    background: currentColor;
    /* Lime, matching .tick-list elsewhere on the site - the affirmative accent.
     * Was --violet-deep, the dark body purple, which read as body text rather
     * than as a tick. */
    color: var(--lime);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7 425.4 105.4c12.5-12.5 32.8-12.5 45.3 0z'/%3E%3C/svg%3E") no-repeat center / contain;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7 425.4 105.4c12.5-12.5 32.8-12.5 45.3 0z'/%3E%3C/svg%3E") no-repeat center / contain;
}

/* A "Foo includes:" line introducing a tick list sits tight against it. */
.svc-lead { margin-bottom: var(--space-2xs); }

/* ── Band 1: services hero ────────────────────────────────────────────
 * White-to-lavender gradient with the clinic photograph behind it at
 * the source's 0.26. The band is 750 tall on a 1440 viewport, so the
 * padding is expressed in the space scale rather than pinned in px. */
.svc-hero {
    position: relative;
    isolation: isolate;
    background: linear-gradient(#fff 0%, var(--violet-wash) 100%);
    overflow: hidden;
}
.svc-hero::before {
    content: "";
    position: absolute;
    inset: 0;
    background: url("/assets/images/services-hero-bg.webp") center / cover no-repeat;
    opacity: 0.26;
    z-index: -1;
}
.svc-hero__inner {
    /* The header overlaps by 120px, so the first ~120px of this padding is
     * spent repaying it. --space-3xl + --space-l left only 40px of real
     * clearance, half what every sibling hero gives; --space-xl brings it
     * to the site's usual ~80px. */
    padding-block: calc(var(--space-3xl) + var(--space-xl)) var(--space-3xl);
    text-align: center;
}
.svc-hero__content { max-width: 52rem; margin-inline: auto; }
.svc-hero__content .lede { color: rgba(0, 0, 0, 0.72); }

/* ── Band 2: new-patient strip ────────────────────────────────────────
 * One gradient panel, not three cards. It straddles the hero's lower
 * edge on the source (top 722 against a hero ending at 808), so it is
 * pulled up out of the lavender band it belongs to. */
.newpat { padding-bottom: var(--space-xl); }
.newpat__panel {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: minmax(0, 20rem) minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-l);
    padding: var(--space-m) var(--space-l);
    border-radius: 10px;
    background: linear-gradient(var(--violet) 0%, var(--violet-deep) 100%);
}
.newpat__label { display: grid; grid-template-columns: auto 1fr; column-gap: var(--space-2xs); align-items: center; }
/* Spans both rows of the card and sits centred against them, rather than
 * pinned to the top of the first row. */
.newpat__icon {
    grid-row: 1 / span 2;
    align-self: center;
    display: flex;
    align-items: center;
}
.newpat__icon svg { width: auto; height: 38px; color: var(--lime); display: block; }
.newpat__label-text {
    font-family: var(--font-body);
    font-size: var(--step--1);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--lime);
}
.newpat__title {
    font-family: var(--font-heading);
    font-size: var(--step-1);
    font-weight: 700;
    line-height: var(--leading-m);
    color: #fff;
}
.newpat__body { color: rgba(255, 255, 255, 0.88); }
.newpat__body a { color: var(--lime); font-weight: 700; }
.newpat__body a:hover { color: var(--lime); text-decoration: underline; }

/* ── Band 3: appointment features ─────────────────────────────────────
 * Three equal columns on the lavender ground with NO card background —
 * icon, heading, paragraph, exactly as the source has it. */
.appt-features { padding-block: 0 var(--space-2xl); }
.appt-features__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-l);
}
.feature__icon svg { width: auto; height: 30px; color: var(--violet); display: block; }
.feature__title {
    font-family: var(--font-heading);
    font-size: var(--step-2);
    font-weight: 700;
    line-height: var(--leading-s);
    color: var(--violet-deep);
    margin-block: var(--space-xs) var(--space-2xs);
}

/* ── Band 4: after hours + home visits ────────────────────────────────
 * Copy fills the left column across both blocks; one tall photograph
 * (r15) sits in the right column. */
.afterhours { padding-block: var(--space-2xl); }
.afterhours__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
    gap: var(--space-2xl);
    align-items: start;
}
.afterhours__block { margin-top: var(--space-2xl); }
.afterhours__sub {
    font-size: var(--step-1);
    color: rgba(0, 0, 0, 0.75);
    margin-block: var(--space-m) var(--space-2xs);
}
.afterhours__list { list-style: none; margin: 0 0 var(--space-s); padding: 0; }
.afterhours__list li { margin-bottom: var(--space-2xs); color: rgba(0, 0, 0, 0.68); font-weight: 500; }
.afterhours__media {
    border-radius: 15px;
    overflow: hidden;
    aspect-ratio: 625 / 703;
}
.afterhours__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ── Band 5: the nine-card services grid ──────────────────────────────
 * 3x3 on the source at 1440: three rows of three 383-wide cream cards
 * at r16, each row taking its own height. Aligning the cards to stretch
 * keeps a row level, as the source's grid does. */
.services-grid { padding-block: var(--space-2xl); }
.services-grid__head { text-align: center; max-width: 46rem; margin-inline: auto; margin-bottom: var(--space-2xl); }
.svc-cards {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-l);
    align-items: stretch;
}
.svc-card {
    background: var(--cream);
    border-radius: 16px;
    padding: var(--space-l);
}
.svc-card__icon { display: block; margin-bottom: var(--space-s); }
.svc-card__icon svg { width: auto; height: 30px; color: var(--violet); display: block; }
.svc-card__title {
    font-family: var(--font-heading);
    font-size: var(--step-2);
    font-weight: 700;
    line-height: var(--leading-s);
    color: var(--violet-deep);
    margin-bottom: var(--space-xs);
}

/* ── Band 6: nursing / pathology / occupational ───────────────────────
 * Three columns on the cream ground, no card backgrounds. The source's
 * icons here are 35px rather than the grid's 30px. */
.clinical { padding-block: var(--space-2xl); }
.clinical__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-l);
    align-items: start;
}
.clinical__icon { display: block; margin-bottom: var(--space-s); }
.clinical__icon svg { width: auto; height: 35px; color: var(--violet); display: block; }
.clinical__title {
    font-family: var(--font-heading);
    font-size: var(--step-2);
    font-weight: 700;
    line-height: var(--leading-s);
    color: var(--violet-deep);
    margin-bottom: var(--space-xs);
}
.clinical__subtitle {
    font-size: var(--step-2);
    color: var(--violet-deep);
    margin-block: var(--space-m) var(--space-2xs);
}

/* ── Band 7: telehealth ───────────────────────────────────────────────
 * The source's ground is the lavender wash at 45% strength, which is a
 * distinctly paler band than .section--band — hence its own rule. */
.telehealth {
    background: color-mix(in srgb, var(--violet-wash) 45%, var(--cream));
    padding-block: var(--space-2xl);
}
.telehealth__head { text-align: center; max-width: 50rem; margin-inline: auto; margin-bottom: var(--space-xl); }
.telehealth__row {
    display: grid;
    grid-template-columns: minmax(0, 833fr) minmax(0, 417fr);
    gap: var(--space-l);
    align-items: start;
}
.telehealth__media {
    border-radius: 15px;
    overflow: hidden;
    aspect-ratio: 833 / 440;
}
.telehealth__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ── Band 8: CTA strip ────────────────────────────────────────────────
 * Unlike the home page's gradient strip, this one has no ground of its
 * own on the source — it sits on the page background. */
.svc-cta { padding-block: var(--space-2xl); }
.svc-cta__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-l);
}
.svc-cta__copy { flex: 1 1 26rem; }
.svc-cta__text {
    font-family: var(--font-heading);
    font-size: var(--step-3);
    font-weight: 700;
    line-height: var(--leading-s);
    color: var(--violet-deep);
}
.svc-cta__sub { font-size: var(--step-1); margin-top: var(--space-2xs); }
.svc-cta__sub a { font-weight: 700; }

/* ── Band 9: allied health ────────────────────────────────────────────
 * Narrow copy column left; the right column stacks a lime-outlined
 * partners card (r15) above a wide photograph (r15). */
.allied { padding-block: var(--space-2xl); }
.allied__row {
    display: grid;
    grid-template-columns: minmax(0, 427fr) minmax(0, 853fr);
    gap: var(--space-xl);
    align-items: start;
}
.allied__subtitle { font-size: var(--step-2); color: var(--violet-deep); margin-block: var(--space-m) var(--space-2xs); }
.allied__lead { margin-bottom: var(--space-2xs); }
.allied__stack { display: grid; gap: var(--space-m); }
.allied__partners {
    border: 1px solid var(--lime);
    border-radius: 15px;
    padding: var(--space-m) var(--space-l);
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: var(--space-l);
}
.allied__partners-title {
    font-size: var(--step-1);
    color: var(--violet-deep);
    margin: 0;
    white-space: nowrap;
}
.allied__media {
    border-radius: 15px;
    overflow: hidden;
    aspect-ratio: 853 / 332;
}
.allied__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ── Band 10: bulk billing + accreditation ────────────────────────────
 * Lavender ground with the landscape photograph behind it at the
 * source's 0.24. Left column: photo card (r15) over a white
 * accreditation card (r15). Right column: ONE tall cream card (r15)
 * carrying both the bulk-billing and the fees blocks — it is a single
 * container on the source, not two stacked cards. */
.billing {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    padding-block: var(--space-2xl);
}
.billing::before {
    content: "";
    position: absolute;
    inset: 0;
    background: url("/assets/images/services-billing-bg.webp") center / cover no-repeat;
    opacity: 0.24;
    z-index: -1;
}
.billing__row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-xl);
    align-items: start;
}
.billing__left { display: grid; gap: var(--space-m); }
.billing__media {
    border-radius: 15px;
    overflow: hidden;
    aspect-ratio: 660 / 592;
}
.billing__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.billing__accred {
    background: #fff;
    border-radius: 15px;
    padding: var(--space-m) var(--space-l);
}
.billing__accred-title { font-size: var(--step-1); margin-bottom: var(--space-2xs); }
.billing__card { border-radius: 15px; padding: var(--space-l); }
.billing__subtitle { font-size: var(--step-2); color: var(--violet-deep); margin-block: var(--space-m) var(--space-2xs); }

/* The accreditation marks reuse the home page's row, but this card is
 * narrower than that band, so they wrap and centre rather than spread. */
.billing__accred .accred__marks { justify-content: flex-start; flex-wrap: wrap; gap: var(--space-m); }

/* The partner marks in band 9 sit in a row beside their heading rather
 * than under it, so they need to shrink and wrap. */
.allied__partners .partners__marks { justify-content: flex-start; flex-wrap: wrap; gap: var(--space-m); margin: 0; }
.allied__partners .partners__marks img { max-height: 42px; }

/* ── Narrow viewports ─────────────────────────────────────────────────
 * Every multi-column band collapses to one column. The two-up bands go
 * first at 62rem; the three-up grids go two-wide there and one-wide at
 * 40rem, so a phone never gets a 3-across grid of unreadable cards. */
@media (max-width: 62rem) {
    .newpat__panel {
        grid-template-columns: minmax(0, 1fr);
        margin-top: calc(-1 * var(--space-xl));
        text-align: left;
    }
    .afterhours__row,
    .telehealth__row,
    .allied__row,
    .billing__row { grid-template-columns: minmax(0, 1fr); }
    .afterhours__media { aspect-ratio: 16 / 11; }
    .allied__partners { grid-template-columns: minmax(0, 1fr); gap: var(--space-s); }
    .allied__partners-title { white-space: normal; }
    .appt-features__grid,
    .svc-cards,
    .clinical__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 40rem) {
    .appt-features__grid,
    .svc-cards,
    .clinical__grid { grid-template-columns: minmax(0, 1fr); }
    .svc-cta__inner { flex-direction: column; align-items: flex-start; }
    .newpat__panel { padding: var(--space-m); }
    .svc-card { padding: var(--space-m); }
    .billing__card { padding: var(--space-m); }
}

/* ── Band defaults ────────────────────────────────────────────────────
 * .section is used 18 times across the site and was never defined, so
 * every band has been supplying its own vertical padding by hand - which
 * is exactly why "this section is lacking top and bottom padding" kept
 * reaching review. Defining it makes breathing room the default and a
 * flush band the deliberate exception.
 *
 * Deliberately LOW specificity (one class) so any band that already sets
 * its own padding-block continues to win on source order, and nothing
 * built before this changes. */
.section {
    padding-block: var(--space-2xl);
}
.section--tight {
    padding-block: var(--space-xl);
}
.section--flush {
    padding-block: 0;
}

/* The centred heading group at the top of a band. */
.section__head {
    max-width: 46rem;
    margin-inline: auto;
    text-align: center;
}
.section__head .lede { margin-inline: auto; }

/* ── Fluid half-card lift (shared) ────────────────────────────────────
 * A card that straddles a hero's lower edge sits exactly half above it,
 * computed from the CARD's own height rather than a fixed pixel margin.
 *
 * A fixed margin drifts badly, because the card grows as its text reflows
 * while the margin does not: the services panel measured 73% above the seam
 * at 1440 and 20% at 900, and practice-policy 56% down to 15%.
 *
 * --lift-fraction ramps the effect in rather than switching it at a
 * breakpoint, so there is no jump: none below 48rem, eased through the
 * middle, full half-card straddle above 75rem.
 *
 * The transform sits on a non-animated WRAPPER because these cards carry
 * data-reveal, and the reveal system owns `transform` on that element.
 * The negative margin-bottom gives back the space the transform does not
 * reflow, so the following content does not sit half a card too low. */
.newpat__lift,
.policy-help__lift {
    --lift-fraction: clamp(0, (100vw - 48rem) / 27rem, 1);
    transform: translateY(calc(-50% * var(--lift-fraction)));
    margin-bottom: calc(-1 * var(--lift-give) * var(--lift-fraction));
}
.newpat__lift { --lift-give: 55px; }
.policy-help__lift { --lift-give: 71px; }


/* Anchor targets clear the sticky header rather than landing underneath it.
 * Without this a /services#mental-health link scrolls the card's top edge to
 * y=0, where the header covers it. */
[id] { scroll-margin-top: calc(140px + var(--space-s)); }

/* ── CLINIC GALLERIES (/gallery/<clinic>) ─────────────────────────────
 * Source: an eyebrow + clinic name + intro, then an Address/Contact pair
 * split by a vertical rule, then a FLUSH four-across photo grid (measured
 * 320px square cells at 1280 with gap:0). */
.gallery-head { padding-block: calc(140px + var(--space-l)) var(--space-l); }
.gallery-head__inner { max-width: 46rem; margin-inline: auto; text-align: center; }
.gallery-head__inner .lede { color: var(--ink); }

/* The two facts sit side by side with a rule between them, the same
 * no-gap-so-the-border-can-meet arrangement as .appt-grid and the doctors
 * pillars: a gap would leave the rule floating in the middle of it. */
.gallery-facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-width: 46rem;
    margin: var(--space-l) auto 0;
    text-align: center;
}
.gallery-fact { padding-inline: var(--space-l); }
.gallery-fact + .gallery-fact {
    border-left: var(--border-thin) solid
        color-mix(in oklab, var(--violet) 40%, transparent);
}
.gallery-fact__icon { display: block; margin-bottom: var(--space-2xs); }
.gallery-fact__icon svg {
    width: auto; height: 26px; margin-inline: auto;
    color: var(--violet); display: block;
}
.gallery-fact__title { font-size: var(--step-1); margin: 0 0 var(--space-3xs); }
.gallery-fact__body { font-size: var(--step--1); }

/* Full-bleed, flush grid. NO gap - the source runs the photographs edge to
 * edge, and a gap here would read as a different design entirely. */
.gallery-band { padding-block: 0; }
.gallery-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 48rem) {
    .gallery-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 62rem) {
    .gallery-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.gallery-grid__item {
    display: block;
    position: relative;
    aspect-ratio: 1 / 1;
    overflow: hidden;
    /* Square corners: these tiles butt against each other, so a radius would
     * cut notches out of every join. Overrides the global img rounding too. */
    border-radius: 0;
}
.gallery-grid__item img {
    width: 100%; height: 100%;
    object-fit: cover; display: block;
    border-radius: 0;
    transition: transform var(--duration-slow) var(--ease-out);
}
.gallery-grid__item:hover img,
.gallery-grid__item:focus-visible img { transform: scale(1.04); }
.gallery-grid__item:focus-visible {
    outline: 3px solid var(--lime);
    outline-offset: -3px;
    z-index: 1;
}

@media (max-width: 36rem) {
    .gallery-facts { grid-template-columns: 1fr; gap: var(--space-m); }
    .gallery-fact { padding-inline: 0; }
    .gallery-fact + .gallery-fact {
        border-left: 0;
        border-top: var(--border-thin) solid
            color-mix(in oklab, var(--violet) 40%, transparent);
        padding-top: var(--space-m);
    }
}

/* ── Gallery lightbox ─────────────────────────────────────────────────
 * Built by the gallery script in partials/scripts.html and appended to the
 * body, so it is absent entirely until a tile is clicked. The tiles remain
 * real links to the full image, so this is an enhancement rather than the
 * only way to view a photograph. */
.lightbox {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: none;
    align-items: center;
    justify-content: center;
    gap: var(--space-s);
    padding: var(--space-l) var(--space-s) var(--space-2xl);
    background: color-mix(in oklab, var(--violet-deep) 92%, transparent);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
}
.lightbox[data-open] { display: flex; }

.lightbox__figure {
    margin: 0;
    max-width: min(100%, 68rem);
    max-height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}
.lightbox__img {
    max-width: 100%;
    /* Leaves room for the close button above and the counter below. */
    max-height: calc(100vh - 9rem);
    width: auto;
    height: auto;
    display: block;
    border-radius: var(--radius-l);
    box-shadow: 0 30px 70px -30px rgba(0, 0, 0, 0.75);
}

.lightbox__close,
.lightbox__nav {
    flex: none;
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    color: var(--violet-deep);
    background: color-mix(in oklab, var(--cream) 92%, transparent);
    transition: background var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}
.lightbox__close:hover,
.lightbox__nav:hover { background: var(--lime); transform: scale(1.06); }
.lightbox__close:focus-visible,
.lightbox__nav:focus-visible { outline: 3px solid var(--lime); outline-offset: 3px; }
.lightbox__close svg,
.lightbox__nav svg { width: 20px; height: 20px; }

.lightbox__close {
    position: absolute;
    top: var(--space-s);
    right: var(--space-s);
}

.lightbox__count {
    position: absolute;
    bottom: var(--space-m);
    left: 50%;
    transform: translateX(-50%);
    margin: 0;
    color: var(--on-primary);
    font-size: var(--step--1);
    letter-spacing: var(--tracking-l);
}

/* On a phone the arrows sit over the lower corners of the photo rather than
 * beside it - there is no room for three columns at that width. */
@media (max-width: 40rem) {
    .lightbox { padding-inline: var(--space-2xs); }
    .lightbox__nav { position: absolute; bottom: var(--space-2xl); }
    .lightbox__nav--prev { left: var(--space-m); }
    .lightbox__nav--next { right: var(--space-m); }
    .lightbox__img { max-height: calc(100vh - 12rem); }
}

@media (prefers-reduced-motion: reduce) {
    .lightbox__close, .lightbox__nav { transition: none; }
    .lightbox__close:hover, .lightbox__nav:hover { transform: none; }
}

/* ── 404 ──────────────────────────────────────────────────────────────
 * Served for any unmatched path, so it has to stand on its own: say what
 * happened, then offer the way back rather than leaving a dead end. */
.notfound { padding-block: calc(140px + var(--space-2xl)) var(--space-3xl); }
.notfound__inner { max-width: 46rem; margin-inline: auto; text-align: center; }

/* Decorative, and aria-hidden in the markup - the <h1> carries the meaning.
 * A screen reader announcing "404" adds nothing over "We couldn't find that
 * page". */
.notfound__code {
    font-family: var(--font-heading);
    font-size: clamp(4.5rem, 18vw, 9rem);
    font-weight: 700;
    line-height: 0.9;
    margin: 0 0 var(--space-2xs);
    /* 35% of --violet gave 1.42:1 against the cream - invisible to anyone with
     * low vision, and axe fails it even though the numerals are aria-hidden
     * and decorative. --violet-deep clears AA comfortably at this size. */
    color: color-mix(in oklab, var(--violet-deep) 70%, transparent);
}
.notfound h1 { margin-top: 0; }
.notfound .lede { color: var(--ink); }

.notfound__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-s);
    justify-content: center;
    margin-top: var(--space-l);
}

.notfound__links {
    margin-top: var(--space-2xl);
    padding-top: var(--space-l);
    border-top: var(--border-thin) solid
        color-mix(in oklab, var(--violet) 35%, transparent);
}
.notfound__links-title {
    font-size: var(--step-0);
    text-transform: uppercase;
    letter-spacing: var(--tracking-xl);
    color: var(--violet-deep);
    margin: 0 0 var(--space-s);
}
.notfound__links ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs) var(--space-m);
    justify-content: center;
}
.notfound__links a {
    display: inline-block;
    min-height: 24px;
    line-height: 24px;
    font-weight: 600;
}
