/*
 * 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 ------------------------------- */
    --u-min-vw: 320;
    --u-max-vw: 1240;
    --u-min-font: 16;
    --u-max-font: 18;
    --u-min-ratio: 1.2;
    --u-max-ratio: 1.25;
    /* Space unit (rem) at each end. Every --space-* step and pair is a fixed
     * multiple of it, so these two knobs move the whole spacing rhythm at once. */
    --u-space-min: 1;
    --u-space-max: 1.25;

    /* --- 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));
    /* Display extensions, still the same geometric chain: a site never needs
     * to invent a bigger heading step. */
    --u-min-6: calc(var(--u-min-5) * var(--u-min-ratio));
    --u-max-6: calc(var(--u-max-5) * var(--u-max-ratio));
    --u-min-7: calc(var(--u-min-6) * var(--u-min-ratio));
    --u-max-7: calc(var(--u-max-6) * var(--u-max-ratio));
    --u-min-8: calc(var(--u-min-7) * var(--u-min-ratio));
    --u-max-8: calc(var(--u-max-7) * 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));
    --step-6: clamp(calc(var(--u-min-6) * 1rem), calc(var(--u-min-6) * 1rem + (var(--u-max-6) - var(--u-min-6)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max-6) * 1rem));
    --step-7: clamp(calc(var(--u-min-7) * 1rem), calc(var(--u-min-7) * 1rem + (var(--u-max-7) - var(--u-min-7)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max-7) * 1rem));
    --step-8: clamp(calc(var(--u-min-8) * 1rem), calc(var(--u-min-8) * 1rem + (var(--u-max-8) - var(--u-min-8)) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-max-8) * 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 space unit (--u-space-min / --u-space-max) rather than
     * the type ratio, so spacing stays predictable while type can be as
     * dramatic as the site needs. DO NOT redeclare these per site: tune the
     * --u-* knobs above and every step and pair follows. */
    --space-3xs: clamp(calc(var(--u-space-min) * 0.25rem), calc(var(--u-space-min) * 0.25rem + (var(--u-space-max) * 0.3 - var(--u-space-min) * 0.25) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 0.3rem));
    --space-2xs: clamp(calc(var(--u-space-min) * 0.5rem), calc(var(--u-space-min) * 0.5rem + (var(--u-space-max) * 0.5 - var(--u-space-min) * 0.5) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 0.5rem));
    --space-xs: clamp(calc(var(--u-space-min) * 0.75rem), calc(var(--u-space-min) * 0.75rem + (var(--u-space-max) * 0.75 - var(--u-space-min) * 0.75) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 0.75rem));
    --space-s: clamp(calc(var(--u-space-min) * 1rem), calc(var(--u-space-min) * 1rem + (var(--u-space-max) * 1 - var(--u-space-min) * 1) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 1rem));
    --space-m: clamp(calc(var(--u-space-min) * 1.5rem), calc(var(--u-space-min) * 1.5rem + (var(--u-space-max) * 1.5 - var(--u-space-min) * 1.5) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 1.5rem));
    --space-l: clamp(calc(var(--u-space-min) * 2rem), calc(var(--u-space-min) * 2rem + (var(--u-space-max) * 2 - var(--u-space-min) * 2) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 2rem));
    --space-xl: clamp(calc(var(--u-space-min) * 3rem), calc(var(--u-space-min) * 3rem + (var(--u-space-max) * 3 - var(--u-space-min) * 3) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 3rem));
    --space-2xl: clamp(calc(var(--u-space-min) * 4rem), calc(var(--u-space-min) * 4rem + (var(--u-space-max) * 4 - var(--u-space-min) * 4) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 4rem));
    --space-3xl: clamp(calc(var(--u-space-min) * 6rem), calc(var(--u-space-min) * 6rem + (var(--u-space-max) * 6 - var(--u-space-min) * 6) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 6rem));
    --space-4xl: clamp(calc(var(--u-space-min) * 8rem), calc(var(--u-space-min) * 8rem + (var(--u-space-max) * 8 - var(--u-space-min) * 8) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 8rem));

    /* --- 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(calc(var(--u-space-min) * 0.5rem), calc(var(--u-space-min) * 0.5rem + (var(--u-space-max) * 0.75 - var(--u-space-min) * 0.5) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 0.75rem));
    --space-xs-s: clamp(calc(var(--u-space-min) * 0.75rem), calc(var(--u-space-min) * 0.75rem + (var(--u-space-max) * 1 - var(--u-space-min) * 0.75) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 1rem));
    --space-s-m: clamp(calc(var(--u-space-min) * 1rem), calc(var(--u-space-min) * 1rem + (var(--u-space-max) * 1.5 - var(--u-space-min) * 1) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 1.5rem));
    --space-m-l: clamp(calc(var(--u-space-min) * 1.5rem), calc(var(--u-space-min) * 1.5rem + (var(--u-space-max) * 2 - var(--u-space-min) * 1.5) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 2rem));
    --space-l-xl: clamp(calc(var(--u-space-min) * 2rem), calc(var(--u-space-min) * 2rem + (var(--u-space-max) * 3 - var(--u-space-min) * 2) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 3rem));
    --space-xl-2xl: clamp(calc(var(--u-space-min) * 3rem), calc(var(--u-space-min) * 3rem + (var(--u-space-max) * 4 - var(--u-space-min) * 3) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 4rem));
    --space-l-2xl: clamp(calc(var(--u-space-min) * 2rem), calc(var(--u-space-min) * 2rem + (var(--u-space-max) * 4 - var(--u-space-min) * 2) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 4rem));
    --space-s-l: clamp(calc(var(--u-space-min) * 1.125rem), calc(var(--u-space-min) * 1.125rem + (var(--u-space-max) * 2 - var(--u-space-min) * 1.125) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 2rem));  /* skip-a-step: grid gutter */
    --space-2xl-3xl: clamp(calc(var(--u-space-min) * 4rem), calc(var(--u-space-min) * 4rem + (var(--u-space-max) * 6 - var(--u-space-min) * 4) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 6rem));
    --space-3xl-4xl: clamp(calc(var(--u-space-min) * 6rem), calc(var(--u-space-min) * 6rem + (var(--u-space-max) * 8 - var(--u-space-min) * 6) * (100vw - var(--u-min-vw) * 1px) / var(--u-vw-range) * 16), calc(var(--u-space-max) * 8rem));

    /* --- 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.
     * ===================================================================== */
    --palette-hue: 195;
    --palette-chroma: 0.09;
    --palette-secondary-shift: 150;

    --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;
    color-scheme: light;

    /* 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-primary, 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-from: 0;
    --reveal-distance: 1.5rem;

    /* Typefaces. Set these per site; everything else references them. */
    --font-body: system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-heading: var(--font-body);   /* override for a display face */
}

/* Matraville renders light only, as live does: the template's dark-scheme
 * block that lived here is deleted (its own instruction for a light-only
 * site) and color-scheme is pinned beside --scheme, so UA widgets match.
 * Once the colours run through the roles, that block would flip them. */

/* ═══════════════════════════════════════════════════════════════════════
 * 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. */
:where(input, button, textarea, select) { font: inherit; }   /* zero specificity: "Form controls" below must win */

/* 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); }

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 carry NO radius and NO background plate by default.
 *
 * They used to. `img { border-radius: var(--radius-m); background: var(--surface) }`
 * was added to fix one square photo on Wellbrook, and it cost far more than it
 * saved: every migration since has had to undo it, because a faithful clone of a
 * customer's live site decides its own corners, and the background plate fills
 * the transparent areas of every PNG and SVG — a logo on a dark footer renders
 * as a solid block. Ten of the thirteen sites on this box carried an override
 * for it before it was removed.
 *
 * A radius is a design decision belonging to the site's own stylesheet, next to
 * the cards it should match. Use .is-rounded (below) or a site-layer rule; do
 * not put it back here. */
img, picture, video, canvas, svg {
    height: auto;
}

/* Opt in where a photo should match the radius of the cards around it. */
img.is-rounded, .is-rounded img { border-radius: var(--radius-m); }

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 ────────────────────────────────────────────────────────────── */
/* ═══ Form controls & focus ═══ form-controls:begin ══════════════════════
 * A text field's look, and every focus ring on the site, are set ONCE,
 * here: by the --field-* and --focus-ring* tokens and a few base rules.
 * Every text-like control on the site (contact, search, careers, booking,
 * anything mediflare.js or Connect writes) inherits it, so they match by
 * construction.
 *
 * - This section is copied VERBATIM from _template and never edited in a
 *   site: check-system.sh fails the site if its copy differs by a character.
 *   A site differs only in TOKEN VALUES, set in the site layer's own :root,
 *   below this section (a later :root wins over the defaults here).
 * - Never restyle a control inside a component. A component rule may place
 *   a field (grid, margin, width) but never sets its border, radius,
 *   background or height -- check-system.sh fails the site if one does.
 * - Fields and buttons share ONE corner, --control-radius: set it in the
 *   site layer's :root and both follow. Never set --field-radius
 *   (check-system.sh fails it), except to 0 in underline mode below;
 *   pill buttons mean pill fields.
 * - The base rules are at zero specificity (:where), so any token change
 *   reaches every field and nothing here outranks a deliberate override.
 * - ONE focus ring per site, on links, buttons and fields alike: an outline
 *   in --focus-ring at --focus-ring-w. No other rule sets a focus outline,
 *   colour or box-shadow (check-system.sh fails one); outline-offset may be
 *   adjusted where a ring would be clipped.
 * - Underline-only fields: set --field-border-w: 0,
 *   --field-border-bottom: var(--border-thin) solid <colour> and
 *   --field-radius: 0 (an underline has no corners to share; a rounded one
 *   curves at its ends, and buttons keep --control-radius); optionally
 *   --field-focus-border-bottom: var(--focus-ring-w) solid var(--focus-ring)
 *   so the underline thickens with the ring. No extra rules. Underline
 *   mode is the only time a site sets --field-radius, and check-system.sh
 *   then requires the 0.
 * - Dark panels and bands: the container re-sets the tokens for its
 *   descendants, never the rules. Tokens defined here are resolved on :root,
 *   so re-set the leaf values, not the ones they derive from:
 *     .band--dark {
 *         --focus-ring: var(--surface);
 *         --field-bg: transparent;
 *         --field-ink: var(--on-primary);
 *         --field-border: var(--on-primary);
 *         --field-placeholder: color-mix(in oklab, var(--on-primary) 70%, transparent);
 *     }
 *   --focus-ring must reach >= 3:1 against every ground it is drawn on.
 * The guard finds this section by the begin/end markers; keep both.
 * ═══════════════════════════════════════════════════════════════════════ */

:root {
    --field-h: var(--target-min);                 /* the single-line height: exact, never below the 44px target */
    --field-textarea-h: calc(var(--field-h) * 3); /* the textarea's minimum height */
    --field-pad-block: var(--space-2xs);          /* textarea only; a one-line field centres its text in --field-h */
    --field-pad-inline: var(--space-xs);
    --field-font-size: max(var(--step-0), 1rem);  /* never below 16px, or iOS zooms the page on focus */
    --field-leading: var(--leading-m);
    --field-weight: var(--weight-400);            /* one weight wherever the field sits */
    --field-radius: var(--control-radius);        /* = the .btn radius, by construction; never set it */
    --field-textarea-radius: min(var(--field-radius), var(--radius-l));   /* a pill textarea is a capsule; cap it */
    --field-bg: var(--surface);
    --field-ink: var(--ink);
    --field-border-w: var(--border-thin);
    --field-border: var(--border-strong);
    --field-border-hover: var(--ink-soft);
    --field-placeholder: var(--ink-soft);
    /* Unset by default, so they follow --field-border-w/--field-border:
     * --field-border-bottom          the resting bottom edge (underline mode)
     * --field-focus-border-bottom    the bottom edge while focused
     * --field-focus-outline          the field's ring; leave it to the default */
    --focus-ring: var(--primary);                 /* >= 3:1 against --bg, --field-bg and every ground it lands on */
    --focus-ring-w: var(--border-medium);         /* >= --field-border-w, so the ring covers the border */
}

/* THE focus ring: every interactive element, always. Fields refine the
 * offset and radius below; nothing else sets a focus outline. */
:focus-visible {
    outline: var(--focus-ring-w) solid var(--focus-ring);
    outline-offset: 2px;
    border-radius: var(--radius-xs);
}

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

/* THE base rule. Every text-like control: text, email, tel, search, number,
 * date, url, password, select and textarea -- not checkboxes, radios,
 * ranges, files or button-type inputs. */
:where(input:not([type=checkbox],[type=radio],[type=range],[type=file],[type=color],[type=submit],[type=button],[type=reset],[type=image],[type=hidden]), select, textarea) {
    --_field-radius: var(--field-radius);
    appearance: none;
    box-sizing: border-box;
    width: 100%;
    height: var(--field-h);
    min-height: var(--field-h);
    padding: 0 var(--field-pad-inline);
    font: inherit;
    font-size: var(--field-font-size);
    font-weight: var(--field-weight);
    line-height: var(--field-leading);
    color: var(--field-ink);
    background-color: var(--field-bg);
    border: var(--field-border-w) solid var(--field-border);
    border-bottom: var(--field-border-bottom, var(--field-border-w) solid var(--field-border));
    border-radius: var(--_field-radius);
    box-shadow: none;
    transition: border-color var(--duration-fast) var(--ease-out);
}

:where(input:not([type=checkbox],[type=radio],[type=range],[type=file],[type=color],[type=submit],[type=button],[type=reset],[type=image],[type=hidden]), select, textarea):hover {
    border-color: var(--field-border-hover);
}

/* One edge on focus. The offset pulls the ring in by the border's width, so
 * it is drawn ON the border (covering it) rather than outside it; the border
 * and shadow are held at rest so nothing draws a second edge. Specificity
 * 0,1,0 and later than the global :focus-visible, so it wins over that one
 * (whose offset and radius suit links, not fields). In underline mode the
 * bottom edge may take --field-focus-border-bottom as well. */
:where(input:not([type=checkbox],[type=radio],[type=range],[type=file],[type=color],[type=submit],[type=button],[type=reset],[type=image],[type=hidden]), select, textarea):focus {
    border-color: var(--field-border);
    border-bottom: var(--field-border-bottom, var(--field-border-w) solid var(--field-border));
    box-shadow: none;
    outline: none;
}
:where(input:not([type=checkbox],[type=radio],[type=range],[type=file],[type=color],[type=submit],[type=button],[type=reset],[type=image],[type=hidden]), select, textarea):focus-visible {
    outline: var(--field-focus-outline, var(--focus-ring-w) solid var(--focus-ring));
    outline-offset: calc(var(--field-border-w) * -1);
    border-bottom: var(--field-focus-border-bottom, var(--field-border-bottom, var(--field-border-w) solid var(--field-border)));
    border-radius: var(--_field-radius);
}

:where(textarea) {
    --_field-radius: var(--field-textarea-radius);
    height: auto;
    min-height: var(--field-textarea-h);
    padding-block: var(--field-pad-block);
    resize: vertical;
}

/* The chevron is one conic-gradient wedge in --field-ink: tokens only, no
 * image, so it recolours with the palette and the scheme. (Two half-square
 * linear gradients leave a seam where they meet.) */
:where(select) {
    padding-inline-end: calc(var(--field-pad-inline) * 2 + var(--space-xs));
    background-image: conic-gradient(from -45deg at 50% 100%, var(--field-ink) 90deg, transparent 0);
    background-position: calc(100% - var(--field-pad-inline)) 50%;
    background-size: calc(var(--space-3xs) * 2.5) calc(var(--space-3xs) * 1.25);
    background-repeat: no-repeat;
    cursor: pointer;
}
:where(select[multiple], select[size]) { height: auto; padding-block: var(--field-pad-block); padding-inline-end: var(--field-pad-inline); background-image: none; }

:where(input, textarea)::placeholder { color: var(--field-placeholder); opacity: 1; }

/* The browser's own clear (x) in a search box, redrawn as a mask so it takes
 * --field-ink instead of the browser's grey. */
:where(input[type=search])::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
    inline-size: 1em;
    block-size: 1em;
    cursor: pointer;
    background-color: var(--field-ink);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 4l8 8M12 4l-8 8' stroke='black' stroke-width='2' stroke-linecap='round'/%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 16 16'%3E%3Cpath d='M4 4l8 8M12 4l-8 8' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

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

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

/* ═══ form-controls:end (Form controls & focus) ═════════════════════════ */

/*
 * 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;
}

/* 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;
    min-block-size: var(--target-min);   /* 44px tap target, every size and variant */
    cursor: pointer;
    border: var(--border-thin) solid transparent;
    border-radius: var(--control-radius);   /* shared with every field; set --control-radius, not this */
    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); }

.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);
}

/*
 * Section rhythm. EVERY band on a page should be a .section — this is what
 * gives a page its vertical breathing room, and it is the single most
 * repeated review comment when it is missed ("this section is lacking top
 * and bottom padding", raised three separate times on one site).
 *
 * It is a class rather than a bare `section` selector because bands are not
 * always <section> elements, and because a band that deliberately runs flush
 * to its neighbour needs to say so out loud via --flush.
 *
 * Do not hand-roll the padding. --space-l-2xl is the site-wide "40px phone /
 * 80px desktop" step, already a clamp; a bespoke value breaks the rhythm.
 *
 * Verify with bandpad.mjs, which measures the real rendered ink gap between
 * adjacent bands and fails under 40px.
 */
.section { padding-block: var(--space-l-2xl); }
.section--tight { padding-block: var(--space-l); }
.section--flush { padding-block: 0; }

/* A centred intro (eyebrow + heading + standfirst) above a band's content. */
.section__head {
    max-width: 46rem;
    margin-inline: auto;
    text-align: center;
}

/*
 * 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;
}
/* ── 404 ──────────────────────────────────────────────────────────────
 * Served for any unmatched path, so it stands alone: say what happened, then
 * offer the way back rather than leaving a dead end.
 *
 * Deliberately written against fallbacks rather than this site's own token
 * names - every site in the fleet has a different vocabulary, and a 404 that
 * silently loses its layout because one variable is spelt differently is
 * worse than one that is slightly plainer. */
.notfound {
    padding-block: var(--space-3xl) var(--space-2xl);
    text-align: center;
}
.notfound__inner { max-width: 46rem; margin-inline: auto; }
.notfound__code {
    font-size: var(--step-8);   /* the site's display step, as its section titles */
    font-weight: var(--weight-700);
    line-height: var(--leading-xs);
    margin: 0 0 var(--space-2xs);
    opacity: 0.55;
}
.notfound h1 { margin-top: 0; }
.notfound__lede { font-size: var(--step-1); line-height: var(--leading-l); margin-inline: auto; max-width: 40rem; }
.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-xl);
    padding-top: var(--space-l);
    border-top: var(--border-thin) solid currentColor;
    border-color: color-mix(in oklab, currentColor 22%, transparent);
}
.notfound__links-title {
    font-size: var(--step-0);
    text-transform: uppercase;
    letter-spacing: var(--tracking-xl);
    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-l);
    justify-content: center;
}
.notfound__links a {
    display: inline-block;
    min-height: 24px;   /* WCAG 2.5.8 target size */
    line-height: var(--leading-l);
    font-weight: var(--weight-600);
}

/* ==========================================================================
   MATRAVILLE MEDICAL CENTRE — site layer
   Transcribed from https://www.matravillemedicalcentre.com.au (Elementor 4.2.4)
   at 1440px. Every value here was MEASURED off live, not chosen.
   Sources: pagemap-*.txt (band tops/heights/padding), geo-*.txt (nested
   layout tree), copy-*.txt (type sizes/weights/colours), hf.txt (header+footer).
   ========================================================================== */

:root {
    /* --- Palette: live's Elementor kit, ON THE TEMPLATE'S DIALS --------
     * Every value below is an exact OKLCH conversion of live's measured
     * sRGB, verified by painting each role to a canvas. The kit's four
     * globals ARE the template's roles, so every template component (focus
     * rings, pale/hover variants) paints in the brand rather than the
     * template's default teal:
     *   primary   = rgb(194, 9, 25)    #C20919  kit primary: headings, nav, rules
     *   secondary = rgb(217, 217, 217) #D9D9D9  kit secondary: header CTA text
     *   tertiary  = rgb(254, 242, 242) #FEF2F2  kit accent: pale red wash
     *   ink       = rgb(23, 20, 21)    kit text, used at live's own 76% alpha
     *   ink-strong = black, bg = #F5F5F5, surface = white, border = #D5D5D5,
     *   all on the neutral dials. */
    --palette-hue: 26.58;
    --palette-chroma: 0.2060;
    --l-primary: 0.5147;
    --chroma-secondary: 0;              /* achromatic: hue is irrelevant */
    --l-secondary: 0.8853;
    --palette-tertiary-shift: -9.2;     /* 17.38 */
    --chroma-tertiary: 0.0129;
    --l-tertiary: 0.9705;
    --hue-neutral: 355.35;              /* the kit text's faint warm cast */
    --chroma-ink: 0.0042;               /* --ink = 1.25x = 0.0052 */
    --l-ink: 0.1952;                    /* rgb(23, 20, 21) */
    --l-ink-strong: 0;                  /* black: L 0 is black at any hue/chroma */
    --l-bg: 0.9702;                     /* rgb(245, 245, 245) */
    --chroma-ground: 0;
    --l-border: 0.8730;                 /* rgb(213, 213, 213) */
    --chroma-border: 0;
    --l-on-solid: 1;                    /* live's text on fills is #fff */

    /* Live's body ink is the kit text colour at live's own 76% alpha
       (rgba(23, 20, 21, 0.76)); color-mix paints identically to that rgba. */
    --mx-ink: color-mix(in srgb, var(--ink) 76%, transparent);
    /* Extension colours: measured on live, derivable from no role. The three
       --ink* roles share one hue and chroma, so a second, neutral dark grey
       cannot be one of them while --ink carries the kit text's warm cast. */
    --mx-ink-solid: oklch(0.3211 0 0);           /* rgb(51, 51, 51) #333, live's body default */
    --mx-black-hover: oklch(0.2264 0 0);         /* rgb(28, 28, 28) #1C1C1C, button hover */
    --mx-warning-ink: oklch(0.5521 0.0769 79.72); /* rgb(138, 109, 59) #8A6D3B, alert dismiss */

    /* --- Scale: the template's eight knobs, fitted to live ---------------
     * Every --step-* and --space-* is generated from these eight numbers;
     * no step is redeclared here. Live sets all its type in rem on a fluid
     * root (calc(0.75rem + 0.3125vw): 13.22px at 390, 16.5 at 1440), so its
     * whole ramp scales by one factor (0.8012) between the two widths. The
     * fit therefore uses ONE ratio at both ends and a min font that is the
     * max x 0.8012.
     *
     * Type, fitted by least squares (log error, weighted by how often each
     * size occurs on live: 20.6 x148, 16.5 x96, 18.56 x83, 33 x63, 41.25 x27,
     * 24.75 x15, 66 x9 ...). At 1440 the steps land at
     *   -1 15.57 (live 16.5, -5.6%)    0 18.16 (18.56, -2.2%)
     *    1 21.17 (20.62, +2.7%)        2 24.69 (24.75, -0.2%)
     *    4 33.57 (33, +1.7%)           5 39.14 (41.25 -5.1%; 37.1 lede +5.4%)
     *    7 53.21 (49.5, +7.5%)         8 62.04 (66, -6.0%)
     * RMS error 3.8%, worst 7.7%; the same percentages hold at 390.
     *
     * Space: live's spacing is Elementor px, a 10/20/30/40/60/80/120 rhythm
     * at 1440. --u-space-max 1.25 (a 20px unit) generates it exactly: 2xs 10,
     * xs 15, s 20, m 30, l 40, xl 60, 2xl 80, 3xl 120, 4xl 160. Live does not
     * scale its spacing (its mobile overrides are the same px, 20/30/40/50/60);
     * this site does, by owner decision: --u-space-min is 0.8 of the max, the
     * template's 1 : 1.25, so at 390 the unit is 16px and every step and every
     * mobile override is 20% tighter than live's (60 -> 48, 20 -> 16). */
    --u-min-vw: 390;
    --u-max-vw: 1440;
    --u-min-font: 14.55;
    --u-max-font: 18.16;
    --u-min-ratio: 1.166;
    --u-max-ratio: 1.166;
    --u-space-min: 1;
    --u-space-max: 1.25;

    /* Leading: live's own values. xs and s are retuned for this site (the
       template's 1.05 / 1.18 become live's 1.1 / 1.2); 2xs, m-loose, 2xl and
       3xl are extensions for live's 1.0 buttons, 1.4 CTAs, 1.875 tick lists
       and 1.9 alert copy. */
    --leading-2xs: 1;
    --leading-xs: 1.1;
    --leading-s: 1.2;
    --leading-m-loose: 1.4;
    --leading-2xl: 1.875;
    --leading-3xl: 1.9;

    /* Weights: live uses Manrope 500, 800 and 900 as well as the template's
       three -- measured on the contact intro, the header CTA / footer headings
       and the hero display respectively. */
    --weight-500: 500;
    --weight-800: 800;
    --weight-900: 900;

    /* The alert's left bar is 5px on live; this site has no other thick rule. */
    --border-thick: 5px;

    /* Live's container: the modal width across all pages is 1290 at 1440.
       Bands set their own inline padding, so the shell is the inner width. */
    --mx-shell: 80.625rem;        /* 1290px */
    /* Live's outer frame: the header, home hero and quick strip sit in a
       centred 1920px inner on wide screens. */
    --mx-frame: 120rem;           /* 1920px */
}

/* The fluid root live uses is NOT reproduced here, at any width. The Utopia steps
   are already fluid, so a fluid root underneath them scales every size twice --
   measured, that compounded into 41% of elements changing line count at 390. The
   same fluidity, measured off live, lives once in the scale's knobs instead. */
html { font-size: 100%; }
/* Fixed dimensions in this layer are live's px divided by 16. They were first
   written against live's 16.5px fluid root (450px as 27.2727rem); when the root
   became 100% they all rendered 3% short -- the 450px caduceus at 436, the 999px
   map at 969, the 250px contacts offset at 242. Re-based 2026-09-21. */

body {
    font-family: Poppins, system-ui, -apple-system, "Segoe UI", sans-serif;
    font-size: var(--step--1);         /* live body 16.5 */
    font-weight: var(--weight-400);
    line-height: var(--leading-l);
    color: var(--mx-ink-solid);
    background: var(--surface);
}

/* ---- Template resets -----------------------------------------------------
   The template's h1-h6 rules (letter-spacing, text-wrap: balance,
   overflow-wrap) change line counts against live. Live sets none of them,
   so headings must wrap exactly as live wraps them. */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: Manrope, system-ui, sans-serif;
    letter-spacing: normal;
    text-wrap: wrap;
    margin: 0;
    line-height: var(--leading-xs);
    color: var(--primary);
}
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: normal; }

/* ---- Narrow-desktop repairs (an improvement on live) ---------------------
   Between roughly 1210 and 1330 the services cards' three columns get narrow
   enough that a single long word no longer fits: "Communications" needs 250px
   in a 175px column and paints across the next card, and "BOOK YOUR
   APPOINTMENT" needs 198px in a 173px content box and spills out of its own
   button. Live has both faults at the same widths (measured: the heading
   overflows by 74px at 1260) — this is one of the few places we deliberately
   improve on the source rather than reproduce it, because the text is
   unreadable, not merely different.

   Deliberately narrow in scope: only below 1400, only these two components,
   so every line break at 1440 and at the tablet/mobile breakpoints stays
   byte-identical to live. */
/* ---- Services cards: fit the type to the column ------------------------
   Live sets these card headings at a fixed 2rem and the CTA at a fixed
   1.375rem, which do not fit the column they sit in: at live's own 1440
   design width "Communications" overflows by 22px and paints across the next
   card, and by 1260 the button's text spills out of its own box. Both faults
   are present on live at every width.

   Breaking the words apart fixes the overlap but hyphenates mid-syllable
   ("Vaccinatio-ns"), so instead the type scales down with the column and the
   button gives up its 40px sides only when they no longer fit. At 1440 this
   renders identically to live; below that the words stay whole. */
.mx-svc__col .mx-btn {
    max-width: 100%;
    padding-inline: var(--space-xs);
    /* The label stays on one line: it takes --step-1 where the column has
       room, and is otherwise sized to the column (the column is a container),
       as the headings above are. "BOOK YOUR APPOINTMENT" measures 13.04em in
       Manrope 700; 13.3 leaves sub-pixel slack. Below 1025 and from ~1500 up
       the step wins, so only the three-column desktop range changes. */
    font-size: min(var(--step-1), calc((100cqi - 2 * var(--space-xs)) / 13.3));
}
p { margin: 0 0 var(--space-xs); }
p:last-child { margin-bottom: 0; }

img { max-width: 100%; height: auto; }

a { color: var(--primary); }

/* ==========================================================================
   Layout primitives
   ========================================================================== */

/* Live's bands are full-bleed with their own inline padding; the inner
   content is capped at the shell. Padding values per band come from
   pagemap; these are the two recurring pairs. */
.mx-band { padding-inline: 0; }
.mx-in {
    max-width: var(--mx-shell);
    margin-inline: auto;
    width: 100%;
}

/* Measured band paddings, one class per distinct live value */
:root {
    /* Live's 100 / 150 / 200px band insets and wide gaps, as sums of the
       scale's pairs so they move with the knobs. Each is exactly live's value
       from 1440 up (live holds 100/150/200 at 1440, 1920 and 2223 alike) and
       gives way as the viewport narrows: s 88 / m 129 / l 176 at 1200. Below
       1200 every band sets its own padding (see the responsive blocks), so the
       narrow end of each never shows. */
    --mx-inset-s: calc(var(--space-2xl-3xl) - var(--space-s));                                       /* 100 at 1440 */
    --mx-inset-m: calc(var(--space-2xl-3xl) + var(--space-l-2xl) - var(--space-l) - var(--space-2xs)); /* 150 at 1440 */
    --mx-inset-l: calc(var(--space-3xl-4xl) + var(--space-2xl-3xl) - var(--space-2xl));                /* 200 at 1440 */
    /* Fixed dimensions used in more than one rule */
    --mx-mark-w: 28.125rem;       /* 450px: the caduceus at its natural width */
    --mx-dochero-w: 90.625rem;    /* 1450px: live's doctors-hero cap */
    --mx-hub-w: 71.25rem;         /* 1140px: live's patient-hub cap */
    --mx-tick: 0.85rem;           /* tick-list icon */
    /* Header mark: follows live above ~1500 (244@1600, 312@1920). Below that the
       owner's floor of 350px takes over -- live shrinks the mark to 139-211px
       through the 1024-1440 band, where it reads too small beside a full nav.
       21.875rem = 350px. */
    --mx-logo-w: 21.875rem;
    /* Held at the owner's 350px rather than growing to 440 at 1920: live's own
       mark is 312px at 1920 and 347px from 2223 up, so 350 meets live on a wide
       screen and the bar lands on live's 120px there (100px mark + 10px each side). */
}

.mx-p-120-150 { padding: var(--space-3xl) var(--mx-inset-m); }   /* 120px 150px */
/* Live pads these bands a fixed 200px a side and holds it until its 1024
   breakpoint, so between 1200 and 1440 the content is squeezed into whatever is
   left. The inline half is a fluid pair instead: same generous gutter on a wide
   screen, and the content keeps its width as the viewport narrows. */
.mx-p-120-200 { padding: var(--space-3xl) var(--mx-inset-l); }  /* live: 120px 200px */
.mx-p-180-150 { padding: calc(var(--space-3xl) + var(--space-xl)) var(--mx-inset-m); }   /* 180px 150px */
.mx-p-40-100  { padding: var(--space-l) var(--mx-inset-s); }   /* 40px 100px */
.mx-p-150-100 { padding: var(--mx-inset-m) var(--mx-inset-s) var(--space-3xl); } /* 150px 100px 120px */

/* ==========================================================================
   Header — measured 1440x177, white, inline padding 57.59px.
   Nav LEFT (x=58, wraps to two rows at 464px wide), logo CENTRED (x=571,
   211x60), CTA RIGHT (black pill, Manrope 15/800, padding 19px 40px 20px).
   ========================================================================== */
.site-header {
    background: var(--surface);
    /* live pads the bar 4% a side: 57.6px at 1440, 88.9px at 2223 */
    padding-inline: max(var(--space-xl), 4vw);
    position: relative;
    z-index: var(--layer-nav);
    /* live: 1px solid rgba(23,20,21,.76) under the whole header */
    border-bottom: var(--border-thin) solid var(--mx-ink);
}
.mx-hdr {
    display: grid;
    /* The nav track gets what the menu needs before the CTA track takes more than
       its content: with a 350px brand in the middle, equal outer tracks folded the
       menu to three ragged rows at 1040-1200 while the CTA sat on unused width. */
    grid-template-columns: minmax(0,1fr) auto minmax(0,auto);
    align-items: center;
    /* No min-height. Live's 177px bar at 1440 is its menu folded onto two 87px
       rows; wherever the menu is on one line (live from 1919 up, here from ~1360)
       the bar is the mark plus 10px above and below -- 120px, as live measures. */
    gap: var(--space-s);
    /* live caps the bar's inner at 1920 and centres it */
    max-width: var(--mx-frame);
    margin-inline: auto;
}
/* Once the menu, mark and CTA all fit on one line, the outer tracks share the
   spare width equally and the mark sits on the page's centre line, as on live
   (measured: mark centred at 1440, 1920 and 2223). max-content floors keep the
   menu whole: while the row is tight the nav track simply takes what it needs
   and the mark slides off-centre instead of the menu folding. */
@media (min-width: 1270px) {
    /* max-content, not auto, for the mark: an auto track is allowed to shrink, and
       the mark's max-width:100% then shrank with it (265px at 1280, under the
       owner's 350px floor). */
    .mx-hdr { grid-template-columns: minmax(max-content, 1fr) max-content minmax(max-content, 1fr); }
}
/* 1270-1359: the row is 50px short of fitting, which folded the menu onto two
   lines and made the bar 175px -- a quarter of a 720px-high laptop screen. The
   links give up 9px a side and the row gap halves instead, and the bar stays at
   120px with the mark at its full 350px. */
@media (min-width: 1270px) and (max-width: 1359px) {
    .mx-hdr { gap: var(--space-2xs); }
    .mx-hdr .mx-nav__list a { padding-inline: var(--space-3xs); }   /* .mx-hdr prefix: the base link rule sits further down the file */
}

.mx-hdr__nav { justify-self: start; }
.mx-hdr__brand { justify-self: center; padding-block: var(--space-2xs); }   /* live: 10px above and below the mark */
.mx-hdr__cta { justify-self: end; }

.mx-logo img {
    /* Live scales the mark with the viewport: 177px @1280, 211 @1440, 244 @1600,
       312 @1920. Transcribing the 1440 value alone froze it small on wide screens. */
    /* Above 1280 this follows live exactly (177@1280, 211@1440, 244@1600,
       312@1920). The 11.0625rem floor holds live's 1280 size through the
       1024-1280 band, where live shrinks the mark to 139px and it reads small
       while the full nav is still on screen. */
    width: var(--mx-logo-w);
    height: auto;
    display: block;
}

/* Nav: Poppins 18.5616/400, padding 30px 17px, red when current,
   ink otherwise. Live draws a 1px rule between items. */
.mx-nav__list {
    display: flex;
    flex-wrap: wrap;
    /* Centre the items on whichever rows they fold onto -- left-aligned wrapped
       rows read as broken rather than as a deliberate two-line menu. */
    justify-content: center;
    list-style: none;
    margin: 0;
    padding: 0;
    /* No cap: live wraps only when the row is actually too narrow, and sits on a
       single line at 1920. Capping at live's 1440 width folded it at every width. */
    max-width: min(100%, 38.625rem);   /* 618px — live's single-line width at 1920 */
}
.mx-nav__list > li {
    margin: 0;
    display: flex;
    align-items: center;
}
/* Live draws the separator as li::after — a 1px x 43px rule in brand red,
   on EVERY item (including the last of each wrapped row), not a border
   between items. */
.mx-nav__list > li::after {
    content: "";
    width: 1px;
    height: 2.6875rem;                 /* 43px */
    background: var(--primary);
    flex: none;
}
.mx-nav__list a {
    display: block;
    font-family: Poppins, system-ui, sans-serif;
    font-size: var(--step-0);               /* 18.5616 */
    font-weight: var(--weight-400);
    line-height: var(--leading-l);
    color: var(--mx-ink);
    text-decoration: none;
    padding: var(--space-m) var(--space-xs);      /* 30px 17px */
}
.mx-nav__list a:hover,
.mx-nav__list a:focus-visible { color: var(--primary); }
.mx-nav__list a[aria-current="page"] { color: var(--primary); }

/* Header CTA: black block, Manrope 15/800 in live's #D9D9D9 — measured
   14.9:1 on black, so live's colour is kept (an earlier 3.1:1 reading was
   wrong). Body CTAs are white on live and stay white. */
/* The search box's Search and the overlay's Close are buttons the platform
   component writes (it takes no classes), so they join these rules rather
   than copying them. */
.mx-btn,
.mf-search__submit,
.mf-search-overlay__close {
    display: inline-flex;                                 /* centres the label in the 44px floor */
    align-items: center;
    justify-content: center;
    min-block-size: var(--target-min);                    /* 44px tap target */
    font-family: Manrope, system-ui, sans-serif;
    font-weight: var(--weight-700);
    line-height: var(--leading-m-loose);                  /* live: 32.3385 on 23.0989 */
    text-decoration: none;
    text-align: center;
    background: var(--ink-strong);
    color: var(--on-primary);
    border: var(--border-thin) solid var(--ink-strong);
    border-radius: var(--control-radius);
    cursor: pointer;
}
.mx-btn:hover, .mx-btn:focus-visible,
.mf-search__submit:hover, .mf-search__submit:focus-visible,
.mf-search-overlay__close:hover, .mf-search-overlay__close:focus-visible { background: var(--mx-black-hover); color: var(--on-primary); }

.mx-btn--hdr,
.mf-search__submit,
.mf-search-overlay__close {
    font-size: var(--step--1);              /* live 15px */
    font-weight: var(--weight-800);
    line-height: var(--leading-2xs);                    /* live: 15px on 15px */
    padding: var(--space-s) var(--space-l);   /* live's 19px 40px 20px; 20 on the scale */
    color: var(--secondary);             /* live: #D9D9D9 on black, 14.9:1 */
}
/* Body CTA: Manrope 23.0989/700, measured padding 20px 40px */
.mx-btn--lg {
    font-size: var(--step-2);                 /* live 23.0989 */
    padding: var(--space-s) var(--space-l);           /* live's 20px 40px */
}
.mx-btn--form {
    font-size: var(--step-1);                /* 20.624 */
    padding: var(--space-s) var(--space-l);
}

/* Mobile nav toggle — live uses an Elementor hamburger; the markup is ours.
   The search square (.site-search__open) is built from these same rules. */
.mx-nav-toggle,
.site-search__open {
    display: none;
    background: none;
    border: 0;
    padding: var(--space-2xs);
    color: var(--primary);
    cursor: pointer;
    line-height: 0;
}
.mx-nav-toggle svg { width: 1.7rem; height: 1.7rem; fill: currentColor; }
.site-search__open svg { width: 1.7rem; height: 1.7rem; }   /* a stroked glyph: no fill */

/* ==========================================================================
   Footer — measured 628px total: a 580px white band (4-col grid
   252/252/383/252, padding 120px 150px) then a red legal row (83px,
   padding 30px 150px) and a black Powered-by strip (48px).
   ========================================================================== */
.site-footer { background: var(--surface); }

.mx-foot__top {
    display: grid;
    grid-template-columns: minmax(0,252fr) minmax(0,252fr) minmax(0,383fr) minmax(0,252fr);
    padding: var(--space-3xl) var(--mx-inset-m);      /* 120px 150px */
    gap: 0;
    align-items: start;
    border-top: var(--border-thin) solid var(--mx-ink-solid);   /* live: 1px solid #333 on the 580px band */
}
/* Live renders the logo at 294x84 inside a 252px track: its widget-container
   is 302px wide and starts 50px LEFT of the track (x=100 against 150). It
   overhangs into the page margin, not over anything, so it is reproduced. */
.mx-foot__logo { margin-left: calc(-1 * (var(--space-l) + var(--space-2xs))); }   /* -50px */
.mx-foot__logo img { width: 18.375rem; max-width: none; height: auto; display: block; }   /* 294px */

.mx-foot__col { display: flex; flex-direction: column; gap: var(--space-m); }  /* 30px */
/* Contact Us / Address: 215px widgets sitting at the END of a 252px column,
   text left-aligned inside them (live: align-items flex-end, widget 215). */
.mx-foot__col--right { align-items: flex-end; text-align: left; }
.mx-foot__col--right > * { width: 13.4375rem; }             /* 215px */
.mx-foot__col--hours { padding-left: calc(var(--space-4xl) + var(--space-xs)); justify-content: center; }  /* 175px */
/* The hours text fills its track (383fr less the 175px indent = 208px at 1440,
   472px at 2223). It was capped at the 1440 figure, which wrapped "25 December -
   4 January (Annually)" on wide screens and made the footer 84px taller than live. */

.mx-foot h2 {
    font-family: Manrope, system-ui, sans-serif;
    font-size: var(--step-1);              /* 22px */
    font-weight: var(--weight-800);
    letter-spacing: var(--tracking-xs);   /* live -0.4px at 22px */
    line-height: var(--leading-xs);
    color: var(--primary);
    margin: 0;
}
.mx-foot p, .mx-foot a {
    font-family: Poppins, system-ui, sans-serif;
    font-size: var(--step-0);               /* 18.5616 */
    font-weight: var(--weight-400);
    line-height: var(--leading-l);
    color: var(--mx-ink);
    margin: 0;
}
.mx-foot a { text-decoration: none; }
.mx-foot a:hover, .mx-foot a:focus-visible { text-decoration: underline; }
.mx-foot strong { font-weight: var(--weight-700); }
.mx-foot em { font-style: italic; }
.mx-foot__contact { display: flex; flex-direction: column; gap: var(--space-xs); }   /* live: two <p> at 14.85px margin */
/* Hours come from Rails: {{opening_hours_html}} is a two-column table (day
   group, times) and {{hours_notes}} a sentence under it. Set in the footer's
   own type, the day group bold as live's "Monday to Friday :" was. */
.mx-foot .mx-hours { font-family: Poppins, system-ui, sans-serif; font-size: var(--step-0); line-height: var(--leading-l); color: var(--mx-ink); }
.mx-foot .mx-hours__note { margin-top: var(--space-2xs); }

.mx-foot__legal {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-s-l);
    align-items: center;
    padding: var(--space-m) var(--mx-inset-m);      /* 30px 150px */
    background: var(--primary);
    line-height: var(--leading-m-loose);                  /* live's row is 83px on 30px padding */
}
.mx-foot__legal p {
    font-size: var(--step--1);                   /* live 16.4992 */
    color: var(--on-primary);            /* live #D9D9D9 on red measures 4.45:1 — below AA (4.5) */
    margin: 0;
}
.mx-foot__legal ul {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs) var(--space-m);
    justify-self: end;
    list-style: none;
    margin: 0;
    padding: 0;
}
.mx-foot__legal a {
    font-size: var(--step--1);               /* 14.4368 */
    color: var(--on-primary);            /* live: the anchor is red but its text span is white — this IS live */
    text-decoration: none;
}
.mx-foot__legal a:hover, .mx-foot__legal a:focus-visible { text-decoration: underline; }

.mx-foot__powered {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2xs);
    background: var(--ink-strong);
    padding: var(--space-2xs);                /* 10px */
    min-height: 3rem;              /* 48px */
    line-height: var(--leading-2xs);                    /* live: 48px total around a 26px logo */
}
.mx-foot__powered a { display: block; line-height: 0; }
.mx-foot__powered p {
    font-size: var(--step--2);                /* live 12.3744 */
    color: color-mix(in srgb, var(--surface) 61%, transparent);  /* live: rgba(255,255,255,.61); blends to #9C9C9C on black = 7.6:1, passes AA */
    margin: 0;
}
.mx-foot__powered img { width: 4.5rem; height: auto; }   /* 72px */
.mx-foot__powered .mf-logo-light { display: none; }

/* ==========================================================================
   Type -- every size is a --step-* generated by the knobs in :root; the
   px figures in the comments are live's measured values at 1440, kept as
   the record of what the fit is aiming at.
   ========================================================================== */
/* Display sizes sit above the scale's top step (live: 148.5 / 132 / 120px at
   1440, i.e. 9 / 8 / 7.3rem). Live sets them at a fixed ratio to its 4rem
   section title, which is --step-8 here, so they are written as that same
   ratio of --step-8: they move with the knobs, and land 6% under live exactly
   as the section titles do (139.6 / 124.1 / 113.2 at 1440). */
.mx-h-hero {                           /* 148.493 / 900 */
    /* The scale's ceiling is 1440 (--u-max-vw), so the hero stops growing
       there with every other size. Live keeps scaling it to 162px at 1920 and
       drops to a flat 144 from 1921; the hand-fitted line that followed it was
       removed with the move onto the knobs, so above 1440 the hero holds at
       its 1440 size (within 3% of live's 144 on the 2223 reference). */
    /* --fs is the WIDTH-based size. Contexts below re-set --fs only; the one
       font-size declaration for desktop (further down) then holds it against the
       viewport HEIGHT as well. */
    --fs: calc(var(--step-8) * 2.25);   /* live 9rem = 2.25 x its 4rem section title */
    --vcap: 13vh;
    font-size: var(--fs);
    font-weight: var(--weight-900);
    line-height: var(--leading-xs);
    color: var(--primary);
}
/* Above 1920 live's root falls back from 18px to 16px, so its hero drops from
   162px to a flat 144px and holds there (measured 144 at 1921, 2223 and 2560).
   Letting the fitted line run on gave 170px at 2223 and 180px at 2560. */
.mx-h-hero--sm { --fs: calc(var(--step-8) * 2); --vcap: 11.5vh; }   /* live 8rem = 2 x 4rem */
/* Screen HEIGHT. Every display size above is a function of width alone, so a
   1366x768 laptop got the same 146px three-line title as a tall monitor: the
   title filled the screen and the Book button sat 300px below the fold. On
   desktop the title is also held to a share of the viewport height -- 13vh for
   the 148px heroes, and the same proportion for the 132px and 120px ones. At
   the reference 2223x1218 none of the caps binds (13vh = 158 against 144), so
   that view is unchanged; at 1366x768 the home title becomes 100px on two lines
   and the button and phone number are on screen. 4rem is a floor for very short
   windows. Desktop only -- tablet and mobile set their own sizes below. */
@media (min-width: 1025px) {
    .mx-h-hero { font-size: min(var(--fs), max(var(--step-8), var(--vcap))); }
}
/* Live breaks the about title "MATRAVILLE'S FIRST / MEDICAL CENTRE" because its
   fallback face is wide. Manrope is narrower, so on a wide screen a third word
   fits on line one and strands "CENTRE". Balancing keeps live's two even lines
   without changing the line count. Desktop only: tablet and mobile already match. */
@media (min-width: 1025px) {
    .mx-h-hero--sm { text-wrap: balance; }
}
.mx-h-xl  { font-size: var(--step-8); font-weight: var(--weight-700); }  /* live 66 at 1440 */
.mx-h-lg  { font-size: var(--step-7); font-weight: var(--weight-700); }      /* 49.4977 */
.mx-h-md  { font-size: var(--step-5); font-weight: var(--weight-700); }    /* 41.248 */
.mx-h-sm  { font-size: var(--step-4); font-weight: var(--weight-700); }      /* 32.9984 */
.mx-h-xs  { font-size: var(--step-2); font-weight: var(--weight-700); }    /* 24.7488 */

.mx-lede   { font-size: var(--step-5); color: var(--mx-ink); line-height: var(--leading-l); }  /* 37.1232 */
.mx-lede--sm { font-size: var(--step-4); }                                          /* 32.9984 */
/* Elementor trims each widget's line-height overhang with negative margins on
   its container, measured on every hero: -13/-11 on the hero H1 (home,
   services, doctors, contact, about), -10/-6 on a 37px lede, -7/-7 on the
   33px lede. Reproduced literally; without them each hero runs 24-57px tall. */
.mx-h-hero { margin: calc(-1 * var(--space-xs)) 0 calc(-1 * var(--space-2xs)); }   /* live -13 / -11 */
/* Uppercase headings run wider than the mixed-case sizes the scale was fitted
   against, so give them somewhere to break rather than overrun their column. */
.mx-band h2, .mx-band h3 { text-wrap: balance; overflow-wrap: break-word; }
/* Display headings are set as live sets them at 1440. At that ratio they
   are wider than a phone viewport once the band padding is counted, so they are
   additionally capped against the viewport itself — the cap only ever binds
   below ~700px and leaves the desktop sizes untouched. */
.mx-h-hero, .mx-h-hero--sm, .mx-h-hero--svc {
    overflow-wrap: break-word;
    max-width: 100%;
}
@media (max-width: 700px) {
    .mx-h-hero { font-size: min(calc(var(--step-8) * 2.25), 13vw); }
    .mx-h-hero--sm { font-size: min(calc(var(--step-8) * 2), 12vw); }
    .mx-h-hero--svc { font-size: min(calc(var(--step-8) * 1.825), 11vw); }
}
/* Tablet: a display heading must never be wider than its longest word allows,
   or overflow-wrap (the last-resort guard above) cuts the word in two. Measured in
   Manrope 900: "MATRAVILLE" is 5.99em and "MATRAVILLE'S" 6.88em. At 768 the home
   and doctors heroes set "MATRAVILLE" 707px wide in a 688px column and broke it
   "MATRAVILL / E"; the about hero, held to live's 673px tablet inner, broke
   "MATRAVILLE / 'S" at every width from 768 to 1024. Each size is capped at
   column / word-width, with a little air. Live never hits this only because its
   webfonts 404 and its fallback face is narrower at weight 900. */
@media (min-width: 701px) and (max-width: 1024px) {
    .mx-h-hero { font-size: min(calc(var(--step-8) * 2.25), calc((100vw - 2 * var(--space-l)) / 6.1)); }
    .mx-h-hero--sm { font-size: min(calc(var(--step-8) * 2), calc(min(100vw - 2 * var(--space-l), 673px) / 7)); }
    .mx-h-hero--svc { font-size: min(calc(var(--step-8) * 1.825), calc((100vw - 2 * var(--space-l)) / 6.6)); }   /* HEALTHCARE 6.45em */
}
p.mx-lede { margin: calc(-1 * var(--space-2xs)) 0 calc(-1 * var(--space-3xs)); }   /* live -10 / -6 */
p.mx-lede--sm { margin: calc(-1 * var(--space-3xs)) 0; }   /* live -7 */
.mx-body   { font-size: var(--step-1); color: var(--mx-ink); line-height: var(--leading-l); } /* 20.624 */
.mx-body-s { font-size: var(--step-0); color: var(--mx-ink); line-height: var(--leading-l); }/* 18.5616 */
.mx-body-xs{ font-size: var(--step-0); color: var(--mx-ink-solid); line-height: var(--leading-l); }

/* ==========================================================================
   Homepage
   ========================================================================== */

/* Band 0 — hero. Live: 1440x1117, padding 0 100px; inner 1240 with
   120px block padding; a 546px block then a 2-col 575/575 grid. */
.mx-hero { padding: 0 var(--mx-inset-s); background: var(--surface); }
.mx-hero__in {
    /* live grows with the viewport up to a 1920 inner, then centres it */
    max-width: var(--mx-frame);
    margin-inline: auto;
    padding-block: var(--space-3xl);          /* 120px */
    display: flex;
    flex-direction: column;
    gap: var(--mx-inset-s);                       /* 100px row gap */
}
.mx-hero__head { padding: var(--space-l); }
.mx-hero__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-2xs);
    padding: var(--space-l);
    align-items: start;
}
.mx-hero__actions {
    display: flex;
    align-items: center;
    gap: var(--space-s);                    /* 25px */
    /* Live keeps this nowrap and lets the phone number break its own text -- at
       1060-1104 it splits "02 9311 2525" across THREE lines. Holding the number
       together instead (white-space: nowrap below) means the row must be allowed
       to wrap, or the phone runs into the lede beside it. A deliberate departure
       from live: see the site CLAUDE.md. */
    flex-wrap: wrap;
    row-gap: var(--space-2xs);
}
.mx-hero__phone {
    /* A phone number is one token: breaking "02 9311 2525" across two lines reads
       as two numbers. It only had room to wrap between 1100 and 1440, which is
       exactly where the hero actions column is narrowest. */
    white-space: nowrap;
    font-family: Manrope, system-ui, sans-serif;
    font-size: var(--step-4);                   /* 32.9984 */
    font-weight: var(--weight-700);
    color: var(--ink-strong);
    text-decoration: none;
    line-height: var(--leading-m-loose);                  /* live: 46.1978 */
}
.mx-hero__phone:hover, .mx-hero__phone:focus-visible { text-decoration: underline; }
.mx-arrow { width: 2rem; height: 2rem; fill: var(--ink-strong); flex: none; }
.mx-hero__lede { text-align: right; }

/* Band 1 — the quick strip. Live: 4 equal 360px columns, gap 0, each with
   50px padding and a 35px internal gap, separated by 1px rules. */
.mx-strip {
    display: grid;
    /* minmax(0,…) not 1fr: live's tracks are equal (measured 360px x4), and
       a bare 1fr sizes to content and overhangs at 1200 */
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0;
    background: var(--surface);
    border-block: var(--border-thin) solid var(--border);
    /* live: the rules run edge to edge, the four cells sit in a centred 1920 */
    padding-inline: max(0px, calc((100% - var(--mx-frame)) / 2));
}
@media (min-width: 1921px) {
    /* live rules both outer edges; below 1921 they are the viewport edge */
    .mx-strip__cell:first-child { border-left: var(--border-thin) solid var(--mx-ink-solid); }
    .mx-strip__cell:last-child { border-right: var(--border-thin) solid var(--mx-ink-solid); }
}
.mx-strip__cell {
    display: flex;
    flex-direction: column;
    gap: var(--space-m);                    /* 35px */
    padding: var(--space-s-l);                /* 50px */
}
.mx-strip__cell + .mx-strip__cell { border-left: var(--border-thin) solid var(--mx-ink-solid); }   /* live: 1px solid #333 */
.mx-strip__cell h2 { font-size: var(--step-4); font-weight: var(--weight-700); color: var(--primary); }

/* Band 2 — emergencies. Live: 1440x1000, padding 40px 100px; inner grid
   476/714 gap 50; left is the caduceus, right is a heading plus a 332/332
   grid whose right column carries a red left rule. */
.mx-emerg { background: var(--surface); }
.mx-emerg__grid {
    display: grid;
    grid-template-columns: minmax(0,476fr) minmax(0,714fr);
    gap: var(--space-s-l);                    /* 50px */
    margin-inline: auto;
}
.mx-emerg__art { display: flex; align-items: flex-start; justify-content: center; padding: var(--space-2xs); }   /* live centres the 450px mark in its 40% column */
.mx-emerg__art img { width: 100%; max-width: var(--mx-mark-w); height: auto; }  /* 450px */
.mx-emerg__body { display: flex; flex-direction: column; }
.mx-emerg__body > h2 { padding-bottom: var(--space-xl); }   /* live: 136px widget on a 73px heading */
.mx-emerg__cols {
    display: grid;
    grid-template-columns: minmax(0,332fr) minmax(0,332fr);
    gap: var(--space-s-l);
    padding-top: var(--space-s-l);            /* 50px */
}
/* Live: the contacts column carries a 250px TOP padding (its heading sits at
   y=+250), a 20px gap, and no rule of its own; the red divider is the
   border-right of the 315px text widget, which stretches to the row. */
.mx-emerg__contacts {
    padding-top: calc(var(--space-4xl) + var(--space-2xl) + var(--space-2xs));   /* 250px */
    display: flex;
    flex-direction: column;
    gap: var(--space-s);                    /* 20px */
}
.mx-emerg__contacts h3 {
    font-size: var(--step-4);                   /* 32.9984 */
    line-height: var(--leading-m);                  /* 42.898 */
    font-weight: var(--weight-700);
    color: var(--mx-ink-solid);
    margin: 0;
    /* Live keeps this on one line only by letting it spill ~8px past its 332px
       track into the band's margin. On the scale the step is a shade wider, so
       it wraps instead of clipping — the same words, inside their column. */
    text-wrap: balance;
}
.mx-emerg__contacts h4 {
    font-size: var(--step-2);                 /* 24.7488 */
    line-height: var(--leading-l);                  /* 37.1232 */
    font-weight: var(--weight-700);
    color: var(--primary);
    margin: var(--space-2xs) 0 var(--space-xs);        /* live: 8.24961 0 16 */
}
.mx-emerg__contacts a { color: inherit; text-decoration: none; }
.mx-emerg__contacts a:hover, .mx-emerg__contacts a:focus-visible { text-decoration: underline; }
.mx-emerg__text {
    display: flex;
    flex-direction: column;
    gap: var(--space-s);
    /* Live sizes this widget as a share of the row -- 315px in a 332px track at
       1440, 539px in 567px at 2223, 95% both times. As a fixed 315px it squeezed
       the text into a 255px column on a wide screen, 14 lines deep. */
    max-width: 95%;
    padding-right: var(--space-xl);          /* 60px */
    border-right: var(--border-thin) solid var(--primary);
}

/* Band 3 — doctors summary. Live: padding 150px 150px 150px 100px; a
   595/595 grid; left column padded 0 50 0 100 carries the heading, lede
   and button; right column is four rows each with a top rule. */
.mx-docs { background: var(--surface); padding: var(--mx-inset-m) var(--mx-inset-m) var(--mx-inset-m) var(--mx-inset-s); overflow-x: clip; }
.mx-docs__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0; }
.mx-docs__left {
    container-type: inline-size;       /* the heading below is sized to it */
    display: flex;
    flex-direction: column;
    gap: var(--space-m);                    /* 35px */
    padding: 0 var(--space-s-l) 0 var(--mx-inset-s);  /* 0 50 0 100 */
}
.mx-docs__left > h2 { padding-bottom: var(--space-xl); }   /* live: 80px pad on a -9/-8 margin = 63 net */
/* The heading is set so "EXPERIENCED" fills its 445px box at 66px; the third
   line, "PROFESSIONALS", is 533px at that size and on live paints over the
   first doctor's blurb in the next column. It must stay under ~61px to clear
   the column edge (495px incl. the 50px gutter), so it takes the step below the
   section titles: --step-7, 53.2px at 1440 (PROFESSIONALS 431px). */
.mx-h-xl--fit { font-size: min(var(--step-7), calc(100cqi / 8.2)); }   /* PROFESSIONALS 8.1em */
.mx-docs__lede { display: flex; flex-direction: column; gap: var(--space-s); max-width: 72%; }  /* live: 72% of the column -- 320px at 1440, 602px at 2223 */
.mx-docs__btn { padding-top: calc(var(--space-4xl) + var(--space-4xl) + var(--space-3xl) + var(--space-2xs)); }          /* live: the button widget pads 450px on top */
.mx-docs__list { display: flex; flex-direction: column; }
.mx-docs__row {
    display: flex;
    min-width: 0;                      /* the row sits in a grid track; without this it holds 720px and overflows by 2px */
    flex-direction: column;
    gap: var(--space-s);                    /* 25px */
    padding: var(--space-l) 0;              /* 40px */
    border-top: var(--border-thin) solid var(--mx-ink);
}
.mx-docs__row:first-child { flex-grow: 1; }   /* live: the stretched surplus sits in row one */
.mx-docs__row:last-child { border-bottom: var(--border-thin) solid var(--mx-ink); }
.mx-docs__row h3 { font-size: var(--step-4); line-height: var(--leading-m); font-weight: var(--weight-700); color: var(--primary); }
.mx-docs__role {
    font-family: Manrope, system-ui, sans-serif;
    font-size: var(--step-2);                 /* 24.7488 */
    font-weight: var(--weight-400);
    color: var(--mx-ink-solid);
    margin: 0;
}
.mx-docs__row p:last-child { font-size: var(--step-1); color: var(--mx-ink); margin: 0 0 var(--space-xs); }   /* live: 14.85px below */

/* Bands 4 (home) and 3 (services) — the services grid. Live: band padding
   120px 200px, an inner card padded 120px, heading, then a 3-col grid of
   226px columns with a 60px gap and a 30px internal column gap. */
.mx-svc { background: var(--surface); }
.mx-svc--grey { background: var(--bg); }
.mx-svc__card {
    /* No cap. Live's "1040" at 1440 is just the viewport less the band's 200px a
       side; measured at 2223 the card is 1823px and its title sits on one line.
       Capped at the 1290 shell it stopped growing at ~1700 and folded the title. */
    margin-inline: auto;
    /* Live spends a fixed 120px per side here. At 1440 that leaves the three
       columns 226px each and everything fits; by 1260 it has eaten 232px of
       an 874px card and the columns are down to 175px, which is what makes
       the headings collide and the button spill. The vertical padding keeps
       live's value; the horizontal gives way as the viewport narrows. */
    padding: var(--space-3xl) var(--space-l-2xl);
    display: flex;
    flex-direction: column;
    gap: var(--space-m);                    /* 35px */
    border: var(--border-thin) solid var(--mx-ink);   /* live: 1px solid rgba(23,20,21,.76) */
}
.mx-svc--grey .mx-svc__card { border-color: transparent; }
.mx-svc__title { text-align: center; padding-bottom: var(--space-xl); }   /* live: 208px widget on a 145px heading */
.mx-svc__grid {
    display: grid;
    /* live: 226.656px 226.672px 226.672px inside an 800px track — equal
       columns, so minmax(0,1fr) rather than 1fr (which sizes to content) */
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-xl);                   /* live: 60px at 1440 */
}
/* Live's grid rows are equal-height (measured 475.109px / 526.812px, each
   sized by its tallest cell) with every cell starting at the top, so the
   columns must stretch to the row rather than shrink to content. */
.mx-svc__col {
    container-type: inline-size;       /* its heading is sized to the column */
    display: flex;
    flex-direction: column;
    gap: var(--space-m);                    /* 30px */
    justify-content: flex-start;
    height: 100%;
}
.mx-svc__col .mx-svc__cta { margin-top: auto; }
.mx-svc__col h3 {
    /* Live fixes this at 2rem (32.9984), which does not fit its own column —
       see the repair note above. It takes live's step (--step-4) wherever the
       column has room for it, and is otherwise capped at column width over the
       longest word, "Communication" (7.81em in Manrope 700): 32px in the 253px
       column at 1440, the full step from ~1500 and on phones. */
    font-size: min(var(--step-4), calc(100cqi / 7.9));   /* Communication 7.81em */
    /* "Communications" is 14 characters in one word and outruns any column
       width this grid can give it, at live's size or a smaller one. Allowing
       a break is the last resort, and it only ever fires on that one word:
       every other heading here fits whole at every width. */
    overflow-wrap: break-word;
    font-weight: var(--weight-700);
    color: var(--mx-ink);
}
.mx-svc__cta { display: flex; flex-direction: column; gap: var(--space-xs); align-items: flex-start; }   /* live: the button is its own width (386px in a 487px column at 2223); it only fills the column when the column is narrower than it */
.mx-svc__note {
    font-size: var(--step-0);               /* 18.5616 */
    font-style: italic;
    color: var(--primary);
    margin: 0;
}

/* Check list — live's Elementor icon list, measured on /services:
   items are Poppins 20.624/lh 30.936 (NOT the 16.4992 a naive text dump
   reports, which reads a nested span), each with padding-bottom 5.5px and
   margin-top 5.5px, and an 18px-wide icon slot carrying a red FA check. */
.mx-ticks { list-style: none; margin: 0; padding: 0; }
.mx-ticks li {
    display: grid;
    grid-template-columns: 1.125rem 1fr;   /* 18px icon slot */
    align-items: start;
    font-size: var(--step-1);                     /* 20.624 */
    line-height: var(--leading-2xl);                     /* 30.936 */
    color: var(--mx-ink-solid);
    margin: 0;
    padding-bottom: var(--space-3xs);              /* 5.5px */
}
.mx-ticks li + li { margin-top: var(--space-3xs); }   /* 5.5px */
.mx-ticks li:last-child { padding-bottom: 0; }
.mx-ticks svg { width: var(--mx-tick); height: var(--mx-tick); fill: var(--primary); margin-top: calc((1lh - var(--mx-tick)) / 2); }   /* centred on the first line */
.mx-ticks i { font-style: italic; }

/* Band 5 — contact CTA. Live: padding 120px 150px, grid 520/520 gap 100,
   left column padded 0 100 0 0 with a divider and a 3-col detail row. */
.mx-cta { background: var(--surface); }
.mx-cta__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--mx-inset-s);                       /* 100px */
    margin-inline: auto;
}
.mx-cta__left {
    display: flex;
    flex-direction: column;
    justify-content: center;                  /* live centres the text against the 999px map */
    gap: var(--space-s-l);                    /* 50px */
    padding-right: var(--mx-inset-s);             /* 100px */
}
.mx-cta__head { display: flex; flex-direction: column; gap: var(--space-m); }
/* live: the intro is 71% of the column (298px of 420 at 1440, 576 of 812 at 2223) */
.mx-cta__head p { max-width: 71%; }
.mx-cta__rule { border: 0; border-top: var(--border-thin) solid var(--border); margin: 0; }
.mx-cta__details {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-s-l);
}
.mx-cta__details h3 { font-size: var(--step-4); font-weight: var(--weight-700); color: var(--primary); margin-bottom: var(--space-2xs); }
.mx-cta__details a { color: inherit; text-decoration: none; }
.mx-cta__details a:hover, .mx-cta__details a:focus-visible { text-decoration: underline; }
.mx-cta__actions { display: flex; flex-direction: column; gap: var(--space-s); align-items: flex-start; }
/* Live's left column is an Elementor google_maps widget: iframe 520x999 at
   1440 (370 tablet, 330 mobile) with brightness(85%) contrast(146%)
   saturate(0%) — a greyscale map. It does not paint in headless captures. */
.mx-cta__map { display: flex; }
.mx-cta__map iframe {
    width: 100%;
    height: 100%;
    min-height: 62.4375rem;            /* 999px */
    border: 0;
    filter: brightness(85%) contrast(146%) saturate(0%);
}

/* ==========================================================================
   About
   ========================================================================== */
.mx-about-hero { background: var(--surface); }
.mx-about-hero__in {
    /* no cap: live grows with the viewport; band padding sets the inset */
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-m);                    /* 35px */
}
.mx-about-hero h2 {
    font-size: var(--step-5);                 /* 41.248 */
    font-weight: var(--weight-700);
    color: var(--mx-ink-solid);
}
.mx-about-hero__cols {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--mx-inset-m);                       /* 150px */
}

/* About band 2 — a 3-col grid (340/340/340, gap 60) with the caduceus in
   the middle column and stacks of icon-boxes either side. */
.mx-split3 { background: var(--surface); }
.mx-split3__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-xl);                    /* 60px */
    /* no cap: live grows with the viewport; band padding sets the inset */
    margin-inline: auto;
    /* Live stretches both text columns to the row and spreads the three items
       over it. At 1440 the text is taller than the 604px mark so nothing moves;
       at 2223 the mark is 800px and the items sit top / middle / bottom. */
    align-items: stretch;
}
.mx-split3__col { display: flex; flex-direction: column; justify-content: space-between; gap: var(--space-s-l); }  /* 50px minimum */
.mx-split3__art { display: flex; align-items: center; justify-content: center; height: 100%; }
.mx-split3__art img { width: 100%; max-width: var(--mx-mark-w); height: auto; }  /* fills the column to its natural 450px: 340 at 1440, 450 from ~1800 */
/* The markup's headings are h2 (one level under the page h1). This rule was
   written for h3 and matched nothing, so the six items ran at the template's
   default h2 size with no gap beneath them. */
.mx-ibox h2, .mx-ibox h3 { font-size: var(--step-4); line-height: var(--leading-m); font-weight: var(--weight-700); color: var(--primary); margin-bottom: var(--space-xs); }

/* ==========================================================================
   Doctors
   ========================================================================== */
.mx-dochero { background: var(--surface); padding-inline: var(--space-l); }
.mx-dochero__in {
    max-width: var(--mx-dochero-w);             /* live caps this inner at 1450; it measures 1360 at 1440 only because the viewport is narrower than the cap */
    margin-inline: auto;
    padding-block: var(--space-3xl);          /* 120px */
    display: flex;
    flex-direction: column;
    gap: var(--space-m);
    align-items: flex-start;
}
/* Live centres the doctors hero and its lede across the full 1360 inner. */
.mx-dochero__in--centre { align-items: center; text-align: center; }
.mx-dochero .mx-lede--sm { max-width: var(--mx-dochero-w); }
.mx-dochero__in > div:last-child { margin-top: var(--space-s); }   /* live: button widget margin-top 25 */

.mx-bios { background: var(--surface); padding: var(--space-l) var(--mx-inset-m) var(--mx-inset-m); }   /* live: 40px 150px 150px */
.mx-bios__list {
    /* no cap: live grows with the viewport; band padding sets the inset */
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: var(--mx-inset-m);                       /* 150px */
}
/* Live's row: gap 35px, padding-top 40px, and four widgets measuring
   82 / 0 / 1 / <prose>. The second is the qualifications line, which on live
   is an "&nbsp;" paragraph collapsing to ZERO height — so the quals text is
   folded into the title block here rather than shipped as its own widget. */
.mx-bio { display: flex; flex-direction: column; gap: var(--space-m); padding-top: var(--space-l); }
.mx-bio__head { min-height: 5.125rem; }   /* live's 82px title widget */
.mx-bio h2 {
    font-size: var(--step-4);                   /* 32.9984 */
    line-height: var(--leading-m);                  /* 42.898 */
    font-weight: var(--weight-700);
    color: var(--primary);
    margin: var(--space-2xs) 0 var(--space-2xs);        /* live: 8.24961 0 12 */
}
.mx-bio__role {
    font-size: var(--step-1);                /* 20.624 */
    line-height: var(--leading-l);                  /* 30.936 */
    font-weight: var(--weight-700);
    color: var(--mx-ink);
    margin: 0;
}
.mx-bio__quals { font-size: var(--step-0); color: var(--mx-ink); margin: var(--space-2xs) 0 0; }
.mx-bio__rule { border: 0; border-top: var(--border-thin) solid var(--ink-strong); margin: 0; }   /* live: 1px solid #000 */
.mx-bio__text { display: block; }
.mx-bio__text p {
    font-size: var(--step-0);               /* 18.5616 */
    line-height: var(--leading-l);                  /* 27.8424 */
    color: var(--mx-ink);
    margin: 0 0 var(--space-xs);                /* live: 14.8493 */
}
.mx-bio__text p:last-child { margin-bottom: 0; }
/* The cards come from Rails: names and role lines are stored in normal case
   (they also print on the Your Health practice-info page) and set in capitals
   here, as live types them. `bio` is plain text with blank lines between
   paragraphs, so the breaks are kept rather than collapsed. */
.mx-bio h2, .mx-bio__role { text-transform: uppercase; }
.mx-bio__bio { white-space: pre-line; }

/* Doctors band 2 — a CTA row then a 3-col value grid (363px, gap 75). */
.mx-values { background: var(--surface); border-top: var(--border-thin) solid var(--ink-strong); }
/* no cap: live grows with the viewport; band padding sets the inset */
.mx-values__cta {
    display: flex;
    gap: var(--space-s-l);
    align-items: flex-start;
    justify-content: space-between;
    padding-bottom: var(--space-xl);         /* 70px */
    flex-wrap: wrap;
}
.mx-values__cta > div:first-child { flex: 1 1 40rem; display: flex; flex-direction: column; gap: var(--space-m); }
/* live: the intro is 47% of its column (408px of 868 at 1440, 666 of 1416 at 2223) */
.mx-values__cta p { max-width: 47%; }
.mx-values__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-2xl);                    /* 75px */
}
/* Live's cells: 1px solid black box, padding 50, flex column centred, gap 35,
   heading 41.248/49.5 centred with 8.25/16 margins, text 20.624/33 centred. */
.mx-values__cell {
    padding: var(--space-s-l);                /* 50px */
    border: var(--border-thin) solid var(--ink-strong);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-m);                    /* 35px */
    text-align: center;
}
.mx-values__cell h3 {
    font-size: var(--step-5);                 /* 41.248 */
    line-height: var(--leading-s);                  /* 49.4977 */
    font-weight: var(--weight-700);
    color: var(--primary);
    margin: var(--space-2xs) 0 var(--space-xs);        /* live: 8.24961 0 16 */
}
.mx-values__cell p {
    font-size: var(--step-1);                /* 20.624 */
    line-height: var(--leading-xl);                  /* 32.9984 */
    color: var(--mx-ink);
    margin: 0;
}

/* ==========================================================================
   Services
   ========================================================================== */
.mx-svchero { background: var(--surface); }
.mx-svchero__in {
    /* no cap: live grows with the viewport; band padding sets the inset */
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-l);                    /* 40px */
    align-items: flex-start;
}
/* Live centres this hero and sets it at 120.444px, not the 148.493 used
   on the home/doctors/contact heroes. Its lede is 807px wide, centred. */
.mx-svchero__in--centre { align-items: center; text-align: center; }
.mx-h-hero--svc { --fs: calc(var(--step-8) * 1.825); --vcap: 10.5vh; }  /* live 7.3rem = 1.825 x 4rem */
.mx-svchero .mx-lede { max-width: 50.4375rem; }     /* 807px */

/* Services band 2 — a 470/470 grid, gap 100 */
.mx-fees { background: var(--surface); }
.mx-fees__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--mx-inset-s);                       /* 100px */
    /* no cap: live grows with the viewport; band padding sets the inset */
    margin-inline: auto;
}
.mx-fees__col { display: flex; flex-direction: column; gap: var(--space-m); align-items: flex-start; }
.mx-fees__col > * { width: 100%; }
.mx-fees__col .mx-btn { width: auto; }
/* {{communication_policy}} arrives as <p> blocks; one blank line between them, as live's <br><br>. */
.mx-prose p { margin: 0; }
.mx-prose p + p { margin-top: 1lh; }
.mx-fees h3 { font-size: var(--step-4); font-weight: var(--weight-700); color: var(--primary); margin-bottom: var(--space-xs); }
.mx-fees__rule { border: 0; border-top: var(--border-thin) solid var(--primary); margin: 0; }

/* Services band 4 — allied health: a 352/587 grid, gap 100 */
.mx-allied { background: transparent; }
.mx-allied__grid {
    display: grid;
    grid-template-columns: minmax(0,352fr) minmax(0,588fr);
    gap: var(--mx-inset-s);                       /* 100px */
    /* no cap: live grows with the viewport; band padding sets the inset */
    margin-inline: auto;
    align-items: center;                      /* live centres the text against the mark */
}
.mx-allied__art { display: flex; justify-content: center; }
.mx-allied__art img { width: 100%; max-width: 31.25rem; height: auto; }  /* fills the column to its natural 500px: 353 at 1440, 500 from ~1900 */
.mx-allied__body { display: flex; flex-direction: column; gap: var(--space-m); align-items: flex-start; }
.mx-allied__body > *:not(.mx-btn) { width: 100%; }
.mx-allied__sub { font-size: var(--step-4); font-weight: var(--weight-700); color: var(--mx-ink); }
.mx-allied__cols {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-2xl);                    /* 75px */
}
.mx-allied__cols h4 { font-size: var(--step-2); font-weight: var(--weight-600); color: var(--mx-ink); margin-bottom: var(--space-xs); }
.mx-allied__prose { display: flex; flex-direction: column; gap: var(--space-xs); }
.mx-allied__prose p { font-size: var(--step-0); color: var(--mx-ink); margin: 0; }

/* ==========================================================================
   Contact
   ========================================================================== */
.mx-contact { background: var(--surface); }
.mx-contact__grid {
    display: grid;
    grid-template-columns: minmax(0,609fr) minmax(0,406fr);
    gap: var(--space-3xl);                    /* 125px */
    /* no cap: live grows with the viewport; band padding sets the inset */
    margin-inline: auto;
    align-items: start;
}
.mx-contact__main { display: flex; flex-direction: column; gap: var(--space-m); }

/* Live's form: underline-only fields, transparent grounds, Poppins 20.624,
   placeholders visible and each field's <label> screen-reader-only (live's
   elementor-screen-only) — reproduced as is. Fields 59px, textarea 201px. */
.mx-form { display: flex; flex-direction: column; gap: var(--space-s); }
.mx-form__row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-s); }
/* The fields' look -- underline-only, transparent, Poppins --step-1, 59px,
 * textarea 201px, and the focus underline that thickens to 2px red -- is the
 * --field-* tokens in :root: see Form controls. */
.mx-form .mx-btn { align-self: flex-start; }

/* Live's alert: pale red wash with a red left bar */
.mx-alert {
    position: relative;
    background: var(--tertiary);
    border-left: var(--border-thick) solid var(--primary);
    padding: var(--space-xs) var(--space-s);      /* 15px 20px */
}
.mx-alert h2 { font-size: var(--step-0); line-height: var(--leading-l); font-weight: var(--weight-700); color: var(--primary); margin-bottom: var(--space-2xs); }
.mx-alert p { font-size: var(--step--2); line-height: var(--leading-3xl); color: var(--mx-ink); margin: 0; padding-right: var(--space-s); }  /* 13px / 24.7488 */
.mx-alert__dismiss {
    position: absolute;
    top: 0.625rem;                    /* 10px */
    right: 0.625rem;
    background: none;
    border: 0;
    padding: 0 var(--space-3xs);
    font-size: var(--step-1);              /* 20px */
    line-height: var(--leading-m);
    color: var(--mx-warning-ink);                    /* live's Elementor dismiss colour */
    cursor: pointer;
    /* A 44px target around the same glyph: the box grows about its centre,
     * so the x stays where live drew it. */
    display: inline-flex; align-items: center; justify-content: center;
    min-inline-size: var(--target-min); min-block-size: var(--target-min);
    top: calc(0.625rem + (1lh - var(--target-min)) / 2);
    right: calc(0.625rem + (1lh - var(--target-min)) / 2);
}
.mx-alert__dismiss:hover, .mx-alert__dismiss:focus-visible { color: var(--primary); }

/* Sidebar card — live: rgba(217,217,217,0.2) (the kit secondary at 20%), padding 50px */
.mx-reach {
    background: color-mix(in srgb, var(--secondary) 20%, transparent);
    padding: var(--space-s-l);                /* 50px */
    display: flex;
    flex-direction: column;
    gap: var(--space-m);
}
.mx-reach h2 { font-size: var(--step-7); font-weight: var(--weight-700); color: var(--primary); }  /* 49.4977 */
.mx-reach__intro {
    font-family: Manrope, system-ui, sans-serif;
    font-size: var(--step-0);                /* 17 */
    font-weight: var(--weight-500);
    color: var(--mx-ink);
    margin: 0;
}
.mx-reach__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-m) var(--space-xs);
    padding-top: var(--space-s-l);            /* 50px */
}
.mx-reach__grid h3 { font-size: var(--step-4); font-weight: var(--weight-700); color: var(--primary); margin-bottom: var(--space-2xs); }
.mx-reach__grid a { color: inherit; text-decoration: none; }
.mx-reach__grid a:hover, .mx-reach__grid a:focus-visible { text-decoration: underline; }
/* Rails' hours table ({{opening_hours_html}}), shared by the contact card and
   the footer. Stacked, day group over times, as live typed "Monday to Friday"
   over "8:30 am - 5:30pm": both columns are too narrow for the pair side by side. */
.mx-hours .hours-table { width: auto; margin: 0; font: inherit; color: inherit; }
.mx-hours .hours-table :where(tr, td) { display: block; }
.mx-hours .hours-table td { padding: 0; border: 0; text-align: inherit; white-space: nowrap; }
.mx-hours .hours-table td:first-child { font-weight: var(--weight-700); }
.mx-map { width: 100%; height: 21.5625rem; border: 0; }   /* live: 306x345 at 1440, 345 tall at every width */

/* ==========================================================================
   Patient hub pages
   ========================================================================== */
.mx-hub-hero { background: var(--surface); }
.mx-hub-hero__in {
    /* no cap: live grows with the viewport; band padding sets the inset */
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-m);
}
.mx-hub { background: transparent; padding: 0 0 var(--space-xl); }
/* A .u-container (in the markup): live caps the hub at 1140 with a 20px gutter. */
.mx-hub__in { --grid-max-width: var(--mx-hub-w); --grid-gutter: var(--space-s); }
.mx-hub__intro { display: flex; flex-direction: column; gap: var(--space-s); padding-block: var(--space-s-l); }
/* Live centres both hub headings across the 1140 shell. */
.mx-hub__intro--centre { text-align: center; align-items: center; }
.mx-hub__intro--centre p { max-width: var(--mx-hub-w); }
.mx-hub__h1 { color: var(--mx-ink-solid); }
.mx-hub--lead { padding-top: var(--space-xl); }
.mx-hub__intro p { font-size: var(--step-1); color: var(--mx-ink-solid); margin: 0; }
.mx-hub__rule { border: 0; border-top: var(--border-thin) solid var(--border); margin: var(--space-s) 0 var(--space-l); }
#mediflare-yourhealth-hub { min-height: 20rem; }

/* ==========================================================================
   Legal pages
   Live builds both as a 100vh hero band carrying a background image, then a
   WHITE CARD (1290 wide, 100px padding) that rides UP into the hero on a
   negative top margin. The card is an in-flow sibling of the hero, never an
   absolutely-positioned child — measured on live: hero 1000x1440 at
   min-height 100vh, card w=1290 x=75 pad=100px, margin-top −500px on BOTH
   pages (an earlier −700 reading was taken at a 1400px viewport, where the
   100vh hero is correspondingly taller — measure these at vh=1000).

   Privacy: pale-pink watermark caduceus, background-size CONTAIN at top-left
            on a #FEF2F2-ish ground, card radius 20px, page ground #F5F5F5.
   Terms:   deep-red textured photo, background-size COVER centred on black,
            card square, band ground #D9D9D9 below the hero.
   ========================================================================== */
.mx-legal { background: var(--bg); }

.mx-legal__hero {
    min-height: 100vh;
    background-repeat: no-repeat;
}
.mx-legal--privacy .mx-legal__hero {
    background-color: var(--tertiary);
    background-image: url("/assets/images/legal-privacy-hero.1971585ede.webp");
    background-size: contain;
    background-position: 0% 0%;
}
.mx-legal--terms .mx-legal__hero {
    background-color: var(--ink-strong);
    background-image: url("/assets/images/legal-terms-hero.bcd12e5314.webp");
    background-size: cover;
    background-position: 50% 50%;
}

/* The card. Depth is live's own measured overlap, applied to a sibling in
   normal flow so the content below it is never painted over. */
.mx-legal__card {
    position: relative;
    z-index: var(--layer-raised);
    max-width: var(--mx-shell);       /* 1290px */
    margin: calc(-1 * (var(--space-4xl) + var(--space-4xl) + var(--space-4xl) + var(--space-s))) auto 0;   /* −500px */
    background: var(--surface);
    border-radius: var(--radius-l);  /* 20px */
    padding: var(--mx-inset-s);                   /* 100px */
}
.mx-legal--terms .mx-legal__card {
    border-radius: 0;                  /* live: square on terms, 20px on privacy */
}
/* live's ground below the terms hero is #D9D9D9, not the #F5F5F5 of privacy */
.mx-legal--terms { background: var(--secondary); }

/* Live's text widget measures 1090px inside the 1290 card — the measure, not
   the shell, is what sets the line count, and a 1281px measure ran the pages
   ~13% short. */
.mx-legal__in { max-width: 68.125rem; }   /* 1090px */
.mx-legal h1 {
    font-size: var(--step-7);                 /* 57.7473 privacy / 49.4977 terms */
    line-height: var(--leading-s);                  /* 69.2967 */
    font-weight: var(--weight-700);
    color: var(--primary);
    margin-bottom: var(--space-s);
}
.mx-legal--terms h1 { font-size: var(--step-7); }
.mx-legal h2 {
    font-size: var(--step-5);                 /* 41.248 — live's h3 */
    line-height: var(--leading-s);                  /* 49.4977 */
    font-weight: var(--weight-700);
    color: var(--mx-ink);
    margin: var(--space-2xs) 0 var(--space-xs);             /* live: 8.24961 0 16.4992 */
}
.mx-legal h3 {
    font-size: var(--step-4);                   /* 32.9984 — live's h4 */
    line-height: var(--leading-m);                  /* 42.898 */
    font-weight: var(--weight-700);
    color: var(--mx-ink);
    margin: var(--space-2xs) 0 var(--space-xs);
}
.mx-legal h4 { font-size: var(--step-2); line-height: var(--leading-m); font-weight: var(--weight-700); color: var(--mx-ink); margin: var(--space-2xs) 0 var(--space-xs); }
.mx-legal p, .mx-legal li {
    font-family: Poppins, system-ui, sans-serif;
    font-size: var(--step--1);                   /* live 16.4992 */
    color: var(--mx-ink);
    line-height: var(--leading-l);
}
/* The policies print the site's full URL inline. It is one unbreakable token,
   67px wider than a 290px phone measure, and with the site-wide overflow-wrap:
   normal it pushed both legal pages 17px past the viewport at 390. */
.mx-legal p, .mx-legal li { overflow-wrap: break-word; }
.mx-legal p { margin: 0 0 var(--space-xs); }
.mx-legal ul, .mx-legal ol { padding-left: var(--space-m); margin: 0 0 var(--space-xs); }
.mx-legal li { margin-bottom: 0; }   /* live: margin 0 */
.mx-legal strong { font-weight: var(--weight-700); }
.mx-legal a { color: var(--primary); }
.mx-legal__lede { margin-bottom: var(--space-m); }

/* ==========================================================================
   404
   ========================================================================== */
.mx-404 { background: var(--surface); text-align: center; }
.mx-404__in {
    max-width: 52rem;
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-m);
    align-items: center;
}
.mx-404__links { display: flex; flex-wrap: wrap; gap: var(--space-xs) var(--space-m); justify-content: center; list-style: none; margin: 0; padding: 0; }
.mx-404__links a { font-size: var(--step-0); }

/* ==========================================================================
   Whole words — headings sized against their own column
   At laptop widths (1100-1366) six headings were wider than the column they
   sit in, and the last-resort overflow-wrap cut them mid-word: "APPOINTMENT /
   S", "COMPREHENSIV / E" and "PHYSIOTHERAP / Y" in the four-up strip, "Addres /
   s" in the home CTA, "CONTINUIT / Y" on /doctors, "CONTAC / T" on /contact
   (from 1100 right up to 1440) and "APPOINTMEN / T" on /services. Live shares
   several of these; none of them reads as deliberate.

   Each column is a size container and its heading is capped at column width /
   longest word, the word measured in Manrope at the weight used (em figures
   beside each rule). The cap only binds where the word would not otherwise fit,
   so every size at 1440 and up is unchanged except the contact hero, which was
   already breaking there. Browsers without container units keep the plain size
   declared earlier in this file -- the declarations below are then dropped.
   ========================================================================== */
/* Desktop only: below 1025 the strip is two-up, the grids stack, and the tablet
   and mobile blocks further down set their own sizes. */
@media (min-width: 1025px) {
    .mx-strip__cell,
    .mx-cta__details > div,
    .mx-values__cell,
    .mx-contact__main,
    .mx-fees__col { container-type: inline-size; }

    .mx-strip__cell h2   { font-size: min(var(--step-4), calc(100cqi / 8.6)); }    /* COMPREHENSIVE 8.44em */
    .mx-cta__details h3  { font-size: min(var(--step-4), calc(100cqi / 4.1)); }    /* Address 3.98em */
    .mx-values__cell h3  { font-size: min(var(--step-5), calc(100cqi / 6.8)); }    /* ESTABLISHED 6.61em */
    .mx-fees__col > .mx-h-xl { font-size: min(var(--step-8), calc(100cqi / 7.25)); }   /* APPOINTMENT 7.09em */
}
/* CONTACT is 4.85em at weight 900. */
@media (min-width: 1025px) {
    .mx-contact__main > .mx-h-hero {
        --fs: min(calc(var(--step-8) * 2.25), calc(100cqi / 4.95));
    }
    /* MATRAVILLE is 5.99em: 12px too wide for the home hero between 1025 and ~1040 */
    .mx-hero__head { container-type: inline-size; }
    .mx-hero__head > .mx-h-hero {
        --fs: min(calc(var(--step-8) * 2.25), calc(100cqi / 6.1));
    }
}

/* ==========================================================================
   Screen dimensions -- height on laptops
   ========================================================================== */
/* 1. Short screens. The hero bands spend a fixed 120-180px above and below their
   content whatever the screen height, so on a 768px-high laptop the padding
   alone was a third of the screen. Each is held to a share of the viewport
   height instead. The shares are set so nothing changes at the reference
   2223x1218 (10vh = 122 against 120, 15vh = 183 against 180); they only bind
   on screens shorter than about 1200px. */
@media (min-width: 1025px) {
    .mx-hero__in { padding-block: min(var(--space-3xl), 10vh); gap: min(var(--mx-inset-s), 8.3vh); }
    .mx-about-hero.mx-p-120-150,
    .mx-contact.mx-p-120-150 { padding-block: min(var(--space-3xl), 10vh); }
    .mx-dochero__in { padding-block: min(var(--space-3xl), 10vh); }
    .mx-svchero.mx-p-180-150 { padding-block: min(calc(var(--space-3xl) + var(--space-xl)), 15vh); }
}

/* 2. Very large screens. The site no longer grows its root font past 2240px:
   the design-system standard keeps the root at 100% and the scale's steps stop
   at --u-max-vw (1440), so a 3840 screen shows the 1440 sizes, not a scaled-up
   2223 composition. */

/* ==========================================================================
   Skip link
   ========================================================================== */
/* Clipped rather than positioned off-screen: a left:-9999px element is
   itself a horizontal overflow and fails the overflow gate. */
.mx-skip {
    position: absolute;
    top: 0;
    left: 0;
    background: var(--primary);
    color: var(--on-primary);
    padding: var(--space-xs) var(--space-s);
    z-index: var(--layer-top);
    clip-path: inset(50%);
    white-space: nowrap;
}
.mx-skip:focus { clip-path: none; }

/* ==========================================================================
   Reveals — one-way IntersectionObserver entrance, never scroll-linked.
   26px vertical / 18px horizontal travel over 760ms.
   ========================================================================== */
[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);
    will-change: opacity, transform;
}
[data-reveal="up"]    { transform: translateY(26px); }
[data-reveal="down"]  { transform: translateY(-26px); }
[data-reveal="left"]  { transform: translateX(-18px); }
[data-reveal="right"] { transform: translateX(18px); }
[data-reveal="fade"]  { transform: none; }
[data-reveal][data-revealed] { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* ==========================================================================
   Responsive — live is desktop down to 1025px, then Elementor's tablet
   breakpoint (<=1024) and mobile (<=767). Both were MEASURED on live, band
   by band, at 1024/768/390: live keeps its desktop rem scale for section
   titles (4rem), column heads (2rem) and ledes (2.25rem) on tablet, drops
   to 3rem / 2rem / 2rem on mobile, gives hero H1s an explicit 6.5rem (about
   6.3rem) then 4rem / 3.4rem / 3.6rem, and switches paddings to FIXED px
   (bands 80/40 then 60/20, buttons 20/40, inputs 59px, cards 40 then 20).
   ========================================================================== */

/* 1025-1200: live has no breakpoint here and its desktop layout overruns
   (the doctors heading paints over the list, as it does at 1440). Kept as a
   thin overflow guard only. */
@media (max-width: 1200px) {
    .mx-p-120-150, .mx-p-120-200 { padding: var(--space-3xl) var(--space-2xl); }
    .mx-p-180-150 { padding: calc(var(--space-3xl) + var(--space-xl)) var(--space-2xl); }
    .mx-p-150-100 { padding: var(--space-3xl) var(--space-2xl) var(--space-3xl); }
    .mx-hero { padding-inline: var(--space-2xl); }
    .mx-docs { padding: var(--space-3xl) var(--space-2xl) var(--space-3xl) var(--space-s-l); }
    .mx-docs__left { padding: 0 var(--space-m) 0 var(--space-s-l); }
    .mx-bios { padding: var(--space-l) var(--space-2xl) var(--space-3xl); }
    .mx-foot__top { padding: var(--space-3xl) var(--space-2xl); }
    .mx-foot__legal { padding: var(--space-m) var(--space-2xl); }
    .mx-foot__col--hours { padding-left: var(--space-xl); }
    .mx-cta__grid { gap: var(--space-s-l); }
    .mx-cta__left { padding-right: var(--space-m); }
    .mx-contact__grid { gap: var(--space-s-l); }
    .mx-allied__grid, .mx-fees__grid { gap: var(--space-s-l); }
    .mx-about-hero__cols { gap: var(--space-xl); }
}

/* ---- Tablet: Elementor's breakpoint, <=1024 ---------------------------- */
@media (max-width: 1024px) {
    /* bands: live pads 80px 40px */
    .mx-p-120-150, .mx-p-120-200, .mx-p-180-150, .mx-p-40-100 { padding: var(--space-2xl) var(--space-l); }
    .mx-p-150-100 { padding: var(--space-2xl) var(--space-l); }
    .mx-hero { padding-inline: var(--space-l); }
    .mx-hero__in { padding-block: var(--space-2xl) var(--space-2xl); gap: var(--space-xl); }
    .mx-hero__head, .mx-hero__row { padding: 0; }
    .mx-docs { padding: var(--space-2xl) var(--space-l); }
    .mx-bios { padding: var(--space-l) var(--space-l) var(--space-2xl); }
    .mx-bios__list { gap: var(--space-2xl); }
    .mx-dochero { padding-inline: var(--space-l); }
    .mx-dochero__in { padding-block: var(--space-xl) var(--space-2xl); }

    /* header — live: logo 45% wide (455px at 1024) driving a 131px bar, a
       44px filled-red hamburger centred, the CTA at its desktop size */
    .site-header { padding-inline: 0 var(--space-l); }
    .mx-hdr {
        grid-template-columns: 45% minmax(0, 1fr) auto;
        min-height: 0;
        gap: 0;
        align-items: center;
    }
    .mx-hdr__nav { grid-column: 2; justify-self: center; order: 2; }
    .mx-hdr__brand { grid-column: 1; justify-self: start; order: 1; width: 100%; padding-block: 0; }
    .mx-hdr__cta { grid-column: 3; order: 3; }
    .mx-logo img { width: 100%; }
    .mx-nav-toggle,
    .site-search__open {
        display: inline-flex;
        width: 44px;
        height: 44px;
        padding: 0;                     /* the 29px icon is centred in the fixed 44px box */
        background: var(--primary);
        color: var(--on-primary);
        align-items: center;
        justify-content: center;
    }
    .mx-nav-toggle svg,
    .site-search__open svg { width: 29px; height: 29px; }
    /* The open menu (owner, 2026-09-21): a light grey panel rather than white, so
       it reads as a layer over the page, and each row fills red with white text on
       hover, focus and press -- a whole-row target, not just a colour change on the
       word. Rows run edge to edge and carry the page gutter as their own padding, so
       the fill reaches both sides and the labels still line up with the content.
       Contrast: ink on #F5F5F5 9.6:1, red (current page) on #F5F5F5 5.9:1, white on
       red 6.5:1. */
    .mx-nav {
        position: absolute;
        inset-inline: 0;
        top: 100%;
        background: var(--bg);
        border-top: var(--border-thin) solid var(--border);
        border-bottom: var(--border-thin) solid var(--border);
        display: none;
        padding: 0;
    }
    .mx-nav.is-open { display: block; }
    .mx-nav__list { flex-direction: column; max-width: none; }
    .mx-nav__list > li::after { display: none; }
    .mx-nav__list > li + li { border-top: var(--border-thin) solid var(--border); }
    .mx-nav__list > li { display: block; }
    .mx-nav__list a { padding: var(--space-xs) var(--space-l); transition: background-color var(--duration-fast) ease, color var(--duration-fast) ease; }
    .mx-nav__list a:hover,
    .mx-nav__list a:focus-visible,
    .mx-nav__list a:active,
    .mx-nav__list a[aria-current="page"]:hover,
    .mx-nav__list a[aria-current="page"]:focus-visible { background: var(--primary); color: var(--on-primary); }
    .mx-nav__list a { --focus-ring: var(--on-primary); }   /* a focused row is solid red: the ring goes white */
    .mx-nav__list a:focus-visible { outline-offset: -4px; }

    /* type: live keeps section titles at 4rem, column heads at 2rem */
    /* type override removed: the scale is fluid and carries this */
    /* type override removed: the scale is fluid and carries this */
    /* type override removed: the scale is fluid and carries this */
    /* type override removed: the scale is fluid and carries this */
    .mx-lede { font-size: var(--step-5); }
    .mx-lede--sm { font-size: var(--step-4); }

    /* home hero — live centres it and puts the lede ABOVE the CTA row */
    .mx-hero__head { text-align: center; }
    .mx-hero__row { grid-template-columns: 1fr; gap: var(--space-xl); justify-items: center; }
    .mx-hero__lede { order: -1; text-align: center; max-width: 807px; }
    .mx-hero__actions { justify-content: center; flex-wrap: wrap; }
    .mx-hero__actions .mx-btn { flex: none; }

    /* about hero — live: a 673px inner at the band's left, centred within */
    .mx-about-hero__in { max-width: 673px; margin-inline: 0; text-align: center; align-items: center; }
    .mx-about-hero__cols { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-xl); text-align: left; }

    /* doctors hero — live is LEFT-aligned on tablet */
    .mx-dochero__in--centre { align-items: flex-start; text-align: left; }

    /* contact hero — live centres the title; single column */
    .mx-contact__grid { grid-template-columns: 1fr; gap: var(--space-l); }
    .mx-contact__main > h1 { text-align: center; }

    /* quick strip — live: 2 columns, each cell padded 150px 50px 50px with
       a #333 bottom rule, heading 2rem */
    /* The top rule stays: every cell closes with a rule beneath it, and without one
       above the first cell "NEW PATIENTS" ran straight out of the hero. Live rules it too. */
    .mx-strip { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); border-block: 0; border-top: var(--border-thin) solid var(--mx-ink-solid); }
    .mx-strip__cell { padding: calc(var(--space-3xl) + var(--space-m)) calc(var(--space-l) + var(--space-2xs)) calc(var(--space-l) + var(--space-2xs)); border-left: 0; border-bottom: var(--border-thin) solid var(--mx-ink-solid); }
    .mx-strip__cell:nth-child(even) { border-left: var(--border-thin) solid var(--mx-ink-solid); }   /* live keeps the divider between the two columns */
    .mx-strip__cell h2 { font-size: var(--step-4); }

    /* emergencies — live hides the caduceus, runs a 672px body, stacks the
       text (indented 75px, red bottom rule) over the contacts */
    .mx-emerg__grid { grid-template-columns: 1fr; gap: 0; }
    .mx-emerg__art { display: none; }
    .mx-emerg__body { max-width: 672px; }
    .mx-emerg__cols { grid-template-columns: 1fr; gap: var(--space-m); padding-top: calc(var(--space-l) + var(--space-2xs)); }
    .mx-emerg__text { max-width: none; margin-left: calc(var(--space-xl) + var(--space-xs)); padding: 0 var(--space-xl) var(--space-m) 0; border-right: 0; border-bottom: var(--border-thin) solid var(--primary); }
    .mx-emerg__contacts { padding-top: 0; }
    .mx-emerg__contacts h3 { white-space: normal; }

    /* doctors band — one column; heading 4rem; lede a 522px widget */
    .mx-docs__grid { grid-template-columns: 1fr; gap: calc(var(--space-l) + var(--space-2xs)); }
    .mx-docs__left { padding: 0; }
    .mx-docs__left > h2 { padding-bottom: var(--space-s); }
    .mx-docs__lede { max-width: 522px; }
    .mx-docs__btn { padding-top: 0; margin-top: 0; }
    .mx-docs__row { padding: var(--space-l) 0; }
    .mx-docs__row:first-child { flex-grow: 0; }

    /* services card — live: 40px padding, 2 columns at 50px */
    .mx-svc__card { padding: var(--space-l); gap: calc(var(--space-s) + var(--space-xs)); }
    .mx-svc__title { padding-bottom: 0; }
    .mx-svc__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: calc(var(--space-l) + var(--space-2xs)); }

    /* CTA — map 370px on top, text below, button auto width */
    .mx-cta__grid { grid-template-columns: 1fr; gap: var(--space-l); }
    .mx-cta__left { padding-right: 0; }
    .mx-cta__map iframe { min-height: 370px; height: 370px; }
    .mx-cta__head p, .mx-values__cta p { max-width: none; }   /* live: width resets at tablet */

    /* about band 3 — one column in DOM order, the caduceus at 450px */
    .mx-split3__grid { grid-template-columns: 1fr; gap: calc(var(--space-l) + var(--space-2xs)); }
    .mx-split3__art { height: auto; }
    .mx-split3__art img { max-width: var(--mx-mark-w); }

    /* doctors values — one column, cells padded 50 */
    .mx-values__grid { grid-template-columns: 1fr; gap: calc(var(--space-l) + var(--space-2xs)); }
    .mx-values__cell { padding: calc(var(--space-l) + var(--space-2xs)); container-type: inline-size; }
    .mx-values__cell h3 { font-size: min(var(--step-5), calc(100cqi / 8.6)); }   /* COMPREHENSIVE 8.44em */
    .mx-values__cta { padding-bottom: calc(var(--space-l) + var(--space-2xs)); }

    .mx-fees__grid, .mx-allied__grid { grid-template-columns: 1fr; gap: var(--space-l); }
    .mx-allied__art { display: flex; justify-content: center; }
    .mx-allied__art img { max-width: 16rem; }

    /* contact sidebar — live: 50px padding, 3rem title, 345px map */
    .mx-reach { padding: calc(var(--space-l) + var(--space-2xs)); }
    .mx-reach h2 { font-size: var(--step-7); }

    /* footer — live: 2 columns, 80px 40px, 50px gap; the logo keeps its
       294px and its 50px overhang; blocks run full width, left-aligned */
    .mx-foot__top { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: calc(var(--space-l) + var(--space-2xs)); padding: var(--space-2xl) var(--space-l); }
    .mx-foot__col--hours { padding-left: 0; }
    .mx-foot__col--right { align-items: flex-start; }
    .mx-foot__col--right > *, .mx-foot__col--hours > * { width: auto; max-width: none; }
    .mx-foot__legal { padding: var(--space-m) var(--space-l); }

    /* legal — live: privacy runs a 300px spacer (250 on mobile) above the
       card, terms a 500px (450) hero; the card rides up 100px, pads 70px,
       sits 40px in; the titles keep their desktop rem at every width */
    .mx-legal--privacy .mx-legal__hero { min-height: 300px; }
    .mx-legal--terms .mx-legal__hero { min-height: 500px; }
    .mx-legal__card { margin: calc(-1 * (var(--space-2xl) + var(--space-s))) var(--space-l) 0; padding: calc(var(--space-xl) + var(--space-2xs)); max-width: none; }
}

/* ---- Mobile: Elementor's breakpoint, <=767 ------------------------------ */
@media (max-width: 767px) {
    .mx-p-120-150, .mx-p-120-200, .mx-p-180-150, .mx-p-40-100, .mx-p-150-100 { padding: var(--space-xl) var(--space-s); }
    .mx-hero { padding-inline: var(--space-s); }
    .mx-hero__in { padding-block: calc(var(--space-l) + var(--space-2xs)) var(--space-xl); gap: calc(var(--space-l) + var(--space-2xs)); }
    .mx-docs, .mx-bios { padding: var(--space-xl) var(--space-s); }
    .mx-dochero { padding-inline: var(--space-s); }
    .mx-dochero__in { padding-block: calc(var(--space-l) + var(--space-2xs)) var(--space-xl); }
    .mx-bios__list { gap: var(--space-xl); }

    /* header — live: the logo full-width on its own row (110px), then a
       row with the 38px hamburger and the desktop-size CTA */
    .site-header { padding-inline: 0; }
    /* The menu button and the CTA are a centred pair under the centred logo (owner,
       2026-09-21). Live centres them too, but 57px apart, which read as two loose
       objects; 20px keeps them together as one group on the logo's centre line. */
    /* Flex, not grid: the logo spans both grid columns, and a spanning item's width
       is shared out between the tracks it crosses -- each cell came out wider than
       its button by a different amount, so a "centred" grid sat the pair 7px right
       of the logo with a 60px hole between them. A wrapping flex row centres the
       two by their own sizes. Order comes from the tablet block (logo, menu, CTA). */
    .mx-hdr {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        align-items: center;
        gap: 0 var(--space-s);
        padding: 0 var(--space-s) var(--space-s);
    }
    .mx-hdr__brand { flex: 0 0 100%; width: 100%; }
    .mx-logo img { width: 100%; max-width: 386px; margin-inline: auto; }
    .mx-hdr__nav, .mx-hdr__cta { flex: none; }
    .mx-hdr__nav { line-height: 0; }   /* the button is the only thing in flow here; no stray line box under it */
    /* 44px, not live's 38: the minimum touch target */
    .mx-nav-toggle, .site-search__open { width: 44px; height: 44px; padding: 0; }   /* the 28px icon centred in the box */
    .mx-nav-toggle svg, .site-search__open svg { width: 28px; height: 28px; }
    .mx-nav__list a { padding-inline: var(--space-s); }

    /* type — live: hero 4rem (about 3.4, services/contact 3.6), section
       titles 3rem, ledes 2rem, column heads stay 2rem */
    /* type override removed: the scale is fluid and carries this */
    .mx-h-hero--sm { font-size: var(--step-7); }   /* live 3.4rem */
    .mx-h-hero--svc { font-size: min(var(--step-8), calc((100vw - 2 * var(--space-s)) / 6.5)); }   /* live 3.6rem; HEALTHCARE 6.45em */
    .mx-contact__main > h1 { font-size: var(--step-8); text-align: left; }   /* live 3.6rem */
    .mx-h-xl, .mx-h-xl--fit { font-size: var(--step-6); }   /* live 3rem; PROFESSIONALS 8.1em fits a 320px column */
    .mx-lede { font-size: var(--step-4); }   /* live 2rem on mobile */
    .mx-lede--sm { font-size: var(--step-1); }
    .mx-btn--lg { font-size: var(--step-1); }
    .mx-hero__phone { font-size: var(--step-2); }

    /* heroes go left-aligned and stacked on mobile */
    .mx-hero__head { text-align: left; }
    .mx-hero__row { justify-items: start; gap: var(--space-l); }
    .mx-hero__lede { text-align: left; }
    .mx-hero__actions { justify-content: flex-start; }
    .mx-about-hero__in { max-width: none; text-align: left; align-items: flex-start; }
    .mx-about-hero__cols { grid-template-columns: 1fr; gap: var(--space-s); }
    .mx-svchero__in--centre { align-items: center; }

    .mx-strip { grid-template-columns: 1fr; }
    .mx-strip__cell { padding: calc(var(--space-l) + var(--space-2xs)); }
    .mx-strip__cell:nth-child(even) { border-left: 0; }

    .mx-emerg__body { max-width: none; }
    .mx-emerg__cols { gap: var(--space-m); padding-top: var(--space-l); }
    .mx-emerg__text { margin-left: 0; }

    .mx-svc__card { padding: var(--space-s); }
    .mx-svc__title { text-align: left; }   /* live: left-aligned on mobile, centred from tablet up */
    .mx-svc__grid { grid-template-columns: 1fr; gap: calc(var(--space-l) + var(--space-2xs)); }

    /* CTA — live puts the map BELOW the text on mobile, at 330px */
    .mx-cta__map { order: 2; }
    .mx-cta__map iframe { min-height: 330px; height: 330px; }
    .mx-cta__details { grid-template-columns: 1fr; gap: var(--space-s); }

    .mx-split3__grid { gap: calc(var(--space-l) + var(--space-2xs)); }
    .mx-split3__art img { max-width: 350px; }
    .mx-values__cta { flex-direction: column; gap: var(--space-s); }
    .mx-values__cell { padding: var(--space-l); }
    .mx-allied__cols { grid-template-columns: 1fr; gap: var(--space-m); }

    /* contact — live: sidebar 50px 30px 30px, 2.5rem title, alert 10px */
    .mx-reach { padding: calc(var(--space-l) + var(--space-2xs)) var(--space-m) var(--space-m); }
    .mx-reach h2 { font-size: var(--step-5); }
    .mx-reach__grid { grid-template-columns: 1fr; gap: var(--space-s); padding-top: var(--space-m); }
    .mx-form__row { grid-template-columns: 1fr; }
    .mx-alert { padding: var(--space-2xs) var(--space-xs); }

    /* footer — live: one column, 50px 20px, the logo centred, the legal
       row centred */
    /* centred throughout (owner, 2026-09-21): the logo and the legal row already
       were, which left the three text blocks hanging off the left edge between them */
    .mx-foot__top { grid-template-columns: 1fr; padding: calc(var(--space-l) + var(--space-2xs)) var(--space-s); gap: calc(var(--space-l) + var(--space-2xs)); text-align: center; }
    .mx-foot__col, .mx-foot__col--right { align-items: center; text-align: center; }
    .mx-foot__logo { margin-left: 0; display: flex; justify-content: center; }
    .mx-foot .mx-hours .hours-table { margin-inline: auto; text-align: center; }   /* the Rails hours table centres with the rest */
    .mx-foot__logo img { max-width: 100%; }
    .mx-foot__legal { grid-template-columns: 1fr; gap: var(--space-xs); padding: var(--space-m) var(--space-s); text-align: center; }
    .mx-foot__legal ul { justify-self: center; justify-content: center; }

    .mx-legal--privacy .mx-legal__hero { min-height: 250px; }
    .mx-legal--terms .mx-legal__hero { min-height: 450px; }
    .mx-legal__card { margin: calc(-1 * (var(--space-2xl) + var(--space-s))) var(--space-s) 0; padding: calc(var(--space-l) + var(--space-2xs)) var(--space-m); }
    .mx-hub__in { --grid-gutter: var(--space-xs); }
}

/* ==========================================================================
   Site search — the platform component (mediflare.js), which writes the box
   unstyled; every rule here is this site's, on its tokens. ONE search window
   (the overlay mediflare.js builds) at every width: from 768 up a centred card
   over a dimmed page, below 768 full screen. Two buttons open it, one shown
   per width, each where its header has room:
     1025+     .site-search__trigger, before Book Appointment, drawn as the
               site's search field (live's underline, the --field-* tokens)
     <=1024    .site-search__open, the Menu square's twin beside it (phones
               included; see the header's phone block)
   The desktop trigger shortens where the CTA track is tight, so the header
   never wraps or changes height (measured 768-1920 every 20px, +-1 at each
   edge): the magnifier alone in its underline, 44px, up to 1499; magnifier
   and "Search" (no ellipsis) at 1500-1549; magnifier and "Search…" from 1550
   (each band keeps 20px+ in hand for a classic 15-17px scrollbar).
   Below ~1440 the CTA track is exactly its content, so any extra width would
   come out of the menu's track and fold the menu.
   The overlay and the results list are styled ONLY through :not([hidden]),
   or they never close. Search and Close join the .mx-btn and .mx-btn--hdr
   rules (square, black, live's grey caps) rather than copying them.
   ========================================================================== */
:root {
    --target-min: 2.75rem;   /* 44px: icon-only controls */

    /* Form fields: every text control -- contact form and search -- is live's
     * contact field: underline-only on a transparent ground, square, Poppins
     * at --step-1 (20.624 at 1440), 59px, the textarea 201px, no side padding.
     * Focus is ONE edge, the underline itself: it thickens to 2px and turns
     * the site's red (6.3:1 on white); no outline. Tokens only; see Form
     * controls, whose base rule takes the underline opt-ins below.
     * Buttons keep live's square corner through --control-radius (.mx-btn,
     * the Book button); the underline has no corners, so --field-radius
     * is 0px (underline mode). */
    --control-radius: 0;
    --field-h: 3.6875rem;                  /* live: 59px */
    --field-textarea-h: 12.5625rem;        /* live: 201px */
    --field-leading: var(--leading-l);
    --field-font-size: var(--step-1);
    --field-pad-block: var(--space-3xs);   /* live 7px */
    --field-pad-inline: 0;
    --field-radius: 0px;
    --field-bg: transparent;
    --field-ink: var(--mx-ink-solid);
    --field-placeholder: color-mix(in oklab, var(--mx-ink-solid) 60%, transparent);
    --field-border-w: 0;
    --field-border: var(--border);
    --field-border-hover: var(--border);
    --field-border-bottom: var(--border-thin) solid var(--border);
    --focus-ring: var(--primary);
    --field-focus-outline: none;
    --field-focus-border-bottom: var(--focus-ring-w) solid var(--focus-ring);
}

/* ONE focus ring (owner, 2026-10-06): the red, on links, buttons and fields
 * (the fields' ring IS the underline: --field-focus-outline stays none, the
 * owner rejected double edges). 6.27:1 on white, 5.76 on the grey bands,
 * 3.35 on the black Powered-by strip. On a solid red ground -- the legal
 * row, and a focused row of the phone menu -- the token goes white (5.9:1).
 * Tokens only; no focus rules. */
.mx-foot__legal { --focus-ring: var(--on-primary); }

.mx-hdr__cta { display: flex; align-items: center; gap: var(--space-xs); }

/* The desktop trigger, drawn as the field it opens: live's underline on a
 * transparent ground (--field-border-bottom), Poppins in the placeholder's
 * grey. The glyph is the menu's ink, red on hover as the menu links are. It
 * is a button, so its focus is the site's one ring. The phone/tablet search
 * square is the Menu button's twin and is built from the .mx-nav-toggle
 * rules (header section). */
.site-search__trigger {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    gap: var(--space-2xs);
    inline-size: var(--target-min);
    block-size: var(--target-min);
    padding: 0;
    font: inherit;
    font-size: var(--field-font-size);
    font-weight: var(--field-weight);
    line-height: var(--field-leading);
    white-space: nowrap;
    color: var(--mx-ink-solid);
    background: var(--field-bg);
    border: 0;
    border-bottom: var(--field-border-bottom);
    border-radius: var(--field-radius);
    cursor: pointer;
    transition: color var(--duration-fast) var(--ease-out);
}
.site-search__trigger svg { flex: none; }
.site-search__text { display: none; color: var(--field-placeholder); }   /* the name is the aria-label */
/* The ellipsis is drawn, not spoken: the name stays "Search this site". */
.site-search__text::after { content: "\2026" / ""; }
.site-search__trigger:hover,
.site-search__trigger[aria-expanded="true"] { color: var(--primary); }

/* Where the CTA track has room, the word shows and the trigger takes the
 * field's own height. */
@media (min-width: 1500px) {
    .site-search__trigger {
        justify-content: flex-start;
        inline-size: auto;
        block-size: var(--field-h);
        padding-inline: var(--field-pad-inline) var(--space-l);
    }
    .site-search__text { display: inline; }
}
@media (min-width: 1500px) and (max-width: 1549px) {
    .site-search__trigger { padding-inline-end: var(--space-2xs); }
    .site-search__text::after { content: none; }
}

/* The box: field and Search on one row, status and results beneath. */
.mf-search__form {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-2xs);
    align-items: stretch;
}
.mf-search__label,
.mf-search__status,
.mf-search__results { grid-column: 1 / -1; }
.mf-search__label {   /* read out, not shown: the magnifier and placeholder say it */
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* The search field IS a contact-form field (live's underline): its look is
 * the --field-* tokens (Form controls), never a rule here. */

/* Search and Close are .mx-btn + .mx-btn--hdr, the header's Book Appointment
 * (see those rules). Here only what a 44px control beside a field needs: the
 * target height, a tighter side padding, and capitals, as every button on the
 * site is typed. */
.mf-search__submit,
.mf-search-overlay__close {
    min-block-size: var(--target-min);
    padding-block: 0;
    padding-inline: var(--space-m);
    text-transform: uppercase;
}

.mf-search__status {
    margin: 0;
    padding-inline: var(--space-xs);
    font-size: var(--step--1);
    line-height: var(--leading-m);
    color: var(--mx-ink-solid);
}
.mf-search__status:empty { display: none; }

/* Results: the title as a heading (Manrope, the headings' red), the excerpt
 * in body copy, matches in a red tint. */
.mf-search__results { margin: 0; padding: 0; list-style: none; }
.mf-search__results:not([hidden]) { display: flex; flex-direction: column; gap: var(--space-3xs); }
.mf-search__link {
    display: block;
    padding: var(--space-2xs) var(--space-xs);
    color: var(--mx-ink-solid);
    text-decoration: none;
    overflow-wrap: anywhere;
    transition: background var(--duration-fast) var(--ease-out);
}
.mf-search__link:hover,
.mf-search__link:focus-visible { color: var(--mx-ink-solid); background: var(--bg); }
.mf-search__link:hover .mf-search__title { text-decoration: underline; }
.mf-search__link:focus-visible { outline-offset: calc(-1 * var(--border-medium)); border-radius: 0; }   /* inset: a scrolling list clips an outset ring */
.mf-search__title {
    display: block;
    font-family: Manrope, system-ui, sans-serif;
    font-size: var(--step-0);
    font-weight: var(--weight-700);
    line-height: var(--leading-s);
    color: var(--primary);
}
.mf-search__excerpt {
    display: block;
    margin-top: var(--space-3xs);
    font-size: var(--step--1);
    line-height: var(--leading-l);
    color: var(--mx-ink-solid);
}
.mf-search__excerpt mark {
    color: var(--ink-strong);
    background: color-mix(in srgb, var(--primary) 16%, transparent);
}

/* Full screen: the open menu's light grey, under a red rule. One row holds
 * Close, the field and Search (Close first, matching the focus order); the
 * results scroll below it, inside the overlay. mediflare.js locks the page
 * behind. Subgrid puts the box's own children on the overlay's grid. */
.mf-search-overlay:not([hidden]) {
    position: fixed;
    inset: 0;
    z-index: var(--layer-modal);
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-rows: auto auto minmax(0, 1fr);
    gap: var(--space-xs) var(--space-2xs);
    padding-block-start: max(var(--space-s), env(safe-area-inset-top));
    padding-inline: max(var(--space-s), env(safe-area-inset-left)) max(var(--space-s), env(safe-area-inset-right));
    background: var(--bg);
    border-block-start: var(--border-thick) solid var(--primary);
}
.mf-search-overlay__header { display: contents; }
.mf-search-overlay__close {
    grid-column: 1;
    grid-row: 1;
    position: relative;
    z-index: var(--layer-base);   /* above the box, which spans this cell too */
    padding-inline: var(--space-s);
}
.mf-search--overlay,
.mf-search--overlay .mf-search__form {
    grid-column: 1 / -1;
    grid-row: 1 / -1;
    display: grid;
    grid-template-columns: subgrid;
    grid-template-rows: subgrid;
    align-items: stretch;   /* Close, the field and Search share one height */
}
.mf-search--overlay .mf-search__input { grid-column: 2; grid-row: 1; }
.mf-search--overlay .mf-search__submit { grid-column: 3; grid-row: 1; padding-inline: var(--space-s); }
.mf-search--overlay .mf-search__status { grid-column: 1 / -1; grid-row: 2; }
.mf-search--overlay .mf-search__results {
    grid-column: 1 / -1;
    grid-row: 3;
    align-self: stretch;
    min-block-size: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-block-end: max(var(--space-s), env(safe-area-inset-bottom));
}
.mf-search--overlay .mf-search__link:hover,
.mf-search--overlay .mf-search__link:focus-visible { background: var(--surface); }   /* the ground is already grey */

/* From 768 up the same overlay is a centred card (the DocSearch pattern),
 * square like everything on the site, offset from the top rather than
 * vertically centred, so it grows downward with its results up to the
 * viewport, past which they scroll inside it. A press on the dimmed page,
 * Close or Esc closes it (mediflare.js, #249). It refines the full-screen
 * rules above at equal specificity, so it must stay after them. Stacking:
 * the backdrop is body::after at --layer-modal; the card sits one above it,
 * since body::after follows the overlay in tree order and would paint over
 * it at an equal z-index. */
@media (min-width: 768px) {
    .mf-search-overlay:not([hidden]) {
        inset: var(--space-3xl) 0 auto;
        z-index: calc(var(--layer-modal) + 1);
        inline-size: calc(100% - 2 * var(--space-s));
        max-inline-size: calc(var(--measure-tight) + var(--space-3xl));
        max-block-size: calc(100dvh - 2 * var(--space-3xl));
        margin-inline: auto;
        padding: var(--space-s);
        box-shadow: var(--shadow-l);
    }
    .mf-search--overlay .mf-search__results { padding-block-end: 0; }
    html[data-mf-search-overlay="open"] body::after {
        content: "";
        position: fixed;
        inset: 0;
        z-index: var(--layer-modal);
        background: color-mix(in oklab, var(--ink-strong) 50%, transparent);
        -webkit-backdrop-filter: blur(var(--space-3xs));
        backdrop-filter: blur(var(--space-3xs));
    }
}

/* 1025-1099: the icon takes 54px from the menu's column, which folded the
 * menu onto a third row and grew the bar by 80px. The row gaps halve and the
 * links give up some side padding, as they already do at 1270-1359, and the
 * menu stays on two rows. */
@media (min-width: 1025px) and (max-width: 1099px) {
    .mx-hdr, .mx-hdr__cta { gap: var(--space-2xs); }
    .mx-hdr .mx-nav__list a { padding-inline: var(--space-2xs); }
}

/* Which button shows where. 1025+: the field-drawn trigger. 1024 and under: the search
 * square beside the Menu square (the tablet and phone header blocks make both
 * squares visible), phones included. Under 337px, Menu, search and the full
 * Book Appointment no longer fit on one row, so the button reads "Book"; its
 * aria-label keeps the full name (owner, 2026-10-06). */
@media (max-width: 1024px) {
    .site-search__trigger { display: none; }
    .mx-hdr__nav { display: flex; align-items: center; gap: var(--space-2xs); }
}
@media (max-width: 336px) {
    .mx-btn__more { display: none; }
}

