/*
 * Site styles. There is 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.
 *
 * COLOUR, TYPE AND SPACE ARE DIALS (#426). The first section is Dials
 * (github.com/joops/dials), copied verbatim between its begin and end
 * markers. It works out every colour, text size, space size and
 * corner from a few values called dials. This site sets its own dials in ONE
 * short block straight after the section, "This site's dials", and that block
 * is the only place in the file where a colour or a scale value is typed.
 *
 *   - Change the look by changing a dial: --brand for the brand colour,
 *     --size-min/--size-max and --ratio-min/--ratio-max for the type scale,
 *     --leading-body for line height, --space-min/--space-max and
 *     --space-density for spacing, --radius-base for corners,
 *     --font-body/--font-heading for faces.
 *   - Everything else reads a token: --surface*, --text*, --border*, --link,
 *     --focus, --solid/--on-solid/--soft/--on-soft/--line (and the named
 *     groups --brand-*, --secondary-*, --tertiary-*, --success-* ...), --size-*,
 *     --leading, --space-*, --radius-*, --border-width-*. Never a hex, rgb(),
 *     hsl() or named colour, never a px/rem length, and never a typed line
 *     height, anywhere else. Weights and letter spacing are the site's own:
 *     a weight is a unitless number, letter spacing is in em.
 *   - The rules are in refs/design/DESIGN.md ("Dials"). Every dial, token
 *     and class is listed in the reference for the version in the section's
 *     first line: github.com/joops/dials/blob/v0.4.0/docs/tokens.md. A
 *     gradient, a wash or a quiet coloured border is a pattern built from
 *     tokens (that reference, "Patterns"), never a token of its own.
 *     check-system.sh holds the section to _template's copy word for word,
 *     and fails a raw colour outside the dials block.
 */

/* ═══ Dials ═══ dials:begin ═════════════════════════════════════════════
 * Dials v0.4.0, VERBATIM. Never edit anything between this marker and the
 * end marker: check-system.sh fails the site if its copy differs from
 * _template's by a word. Each marker appears once; never write either in
 * prose. Set dials in "This site's dials" below; an upgrade
 * of Dials is a template change plus a migration of every site.
 * ═══════════════════════════════════════════════════════════════════════ */
/*! Dials v0.4.0 | MIT | https://github.com/joops/dials */
/* Dials: an AI-first CSS framework. This file is dials-colour.css, then
   dials-scale.css, then the fallback for older browsers; dials-base.css is optional.
   Its defaults are the Default theme: the device's own faces, nothing to load.
   The Dials house theme is themes/dials.css.
*/
/* ============================================================
   Dials: colour (dials-colour.css)
   Dials: seven colours and a few numbers, the only typed values.
   Derived: surfaces, text, lines and groups, worked out live with
   color-mix() and relative colour, in light and dark.
   Groups: .is-{group} points the ungrouped tokens at a group.
   Dials live on :root (and :host); the derived chain is declared on
   :root, [data-dials] and :host, so setting a dial on any
   [data-dials] element re-derives every token inside it.
   Needs color-mix(), light-dark() and relative colour. Don't
   register these with @property: they must resolve where they're
   used, which is what makes .is-dark bands work.
   ============================================================ */
:root, :host {
  /* ---- Colour dials: any CSS colour, preferably HSL ---- */
  --brand:     hsl(221 83% 53%);  /* the main colour: links, focus, primary buttons */
  --secondary: hsl(262 52% 55%);  /* a second colour: highlights and secondary actions (was --accent) */
  --success:   hsl(142 64% 38%);  /* status: done, saved, live */
  --warning:   hsl(38 92% 50%);  /* status: check this */
  --danger:    hsl(0 72% 51%);  /* status: errors and destructive actions */
  --info:      hsl(199 89% 42%);  /* status: neutral news */
  --grey:      hsl(220 9% 50%);  /* the hue and strength of the tint in paper and ink */

  /* ---- Number dials ---- */
  --balance: 0;              /* 1: every fill at --fill-lightness, so they carry equal weight. 0: exactly as set */
  --fill-lightness: 0.52;    /* the shared OKLCH lightness used when --balance is 1 */
  --dark-lift: 0.06;         /* how much lighter the fills are in dark */
  --tint-strength: 10%;      /* how much colour goes into a soft tint */
  --tint-vividness: 1;       /* 1-3: how saturated soft tints are, for crisper pastels */
  --text-contrast: 0;        /* 0-30: strengthens body, muted and quiet text and strong borders, for paper and ink that sit close together */
  --white-text-until: 0.179; /* fills below this luminance get white text, above it black. 0.179 gives each fill whichever contrasts more; held between 0.175 and 0.18333, where both still give 4.5:1: black needs (L + 0.05) / 0.05 >= 4.5, so L >= 0.175; white needs 1.05 / (L + 0.05) >= 4.5, so L <= 1.05 / 4.5 - 0.05 = 0.18333 */

  /* ---- Paper and ink: near-white and near-black, tinted by --grey at these OKLCH lightnesses.
     To use exact colours instead, set --paper-light, --paper-dark, --ink-light and/or
     --ink-dark (unset by default) to any colour. ---- */
  --paper-lightness: 0.985;       /* page background in light */
  --paper-dark-lightness: 0.17;   /* page background in dark */
  --ink-lightness: 0.2;           /* strongest text in light */
  --ink-dark-lightness: 0.95;     /* strongest text in dark */
}

/* Follow the visitor's light or dark setting. To force one, set
   :root { color-scheme: light; } (or dark) after dials.css. */
:root { color-scheme: light dark; }

:root, [data-dials], :host {
  /* ---- Internal: paper, ink and the six fills, worked out from the dials ---- */
  --dl-paper-light: var(--paper-light, oklch(from var(--grey) var(--paper-lightness) calc(c * 0.12) h));
  --dl-paper-dark:  var(--paper-dark,  oklch(from var(--grey) var(--paper-dark-lightness) calc(c * 0.15) h));
  --dl-ink-light:   var(--ink-light,   oklch(from var(--grey) var(--ink-lightness) calc(c * 0.25) h));
  --dl-ink-dark:    var(--ink-dark,    oklch(from var(--grey) var(--ink-dark-lightness) calc(c * 0.12) h));
  --dl-paper: light-dark(var(--dl-paper-light), var(--dl-paper-dark));
  --dl-ink:   light-dark(var(--dl-ink-light), var(--dl-ink-dark));
  --dl-paper-grey: oklch(from var(--dl-paper) l 0 h);  /* paper without its tint: soft tints mix into this, so they keep their own hue */

  --dl-secondary-dial: var(--accent, var(--secondary));  /* --accent is --secondary's old name: while a site still sets it, it wins */
  --dl-brand-base:     oklch(from var(--brand)              calc(l + (var(--fill-lightness) - l) * var(--balance)) c h);
  --dl-secondary-base: oklch(from var(--dl-secondary-dial)  calc(l + (var(--fill-lightness) - l) * var(--balance)) c h);
  --dl-success-base:   oklch(from var(--success)            calc(l + (var(--fill-lightness) - l) * var(--balance)) c h);
  --dl-warning-base:   oklch(from var(--warning)            calc(l + (var(--fill-lightness) - l) * var(--balance)) c h);
  --dl-danger-base:    oklch(from var(--danger)             calc(l + (var(--fill-lightness) - l) * var(--balance)) c h);
  --dl-info-base:      oklch(from var(--info)               calc(l + (var(--fill-lightness) - l) * var(--balance)) c h);
  --dl-brand:     light-dark(var(--dl-brand-base), oklch(from var(--dl-brand-base) calc(l + var(--dark-lift)) c h));
  --dl-secondary: light-dark(var(--dl-secondary-base), oklch(from var(--dl-secondary-base) calc(l + var(--dark-lift)) c h));
  --dl-success:   light-dark(var(--dl-success-base), oklch(from var(--dl-success-base) calc(l + var(--dark-lift)) c h));
  --dl-warning:   light-dark(var(--dl-warning-base), oklch(from var(--dl-warning-base) calc(l + var(--dark-lift)) c h));
  --dl-danger:    light-dark(var(--dl-danger-base), oklch(from var(--dl-danger-base) calc(l + var(--dark-lift)) c h));
  --dl-info:      light-dark(var(--dl-info-base), oklch(from var(--dl-info-base) calc(l + var(--dark-lift)) c h));

  /* ---- Surfaces ---- */
  --surface:         var(--dl-paper);                                            /* the page background */
  --surface-raised:  oklch(from var(--dl-paper) calc(l + 0.03) calc(c * 0.5) h);  /* cards, fields, popovers */
  --surface-lowered: color-mix(in oklab, var(--dl-ink) 4%, var(--dl-paper));     /* wells, table headers, quiet panels */
  --surface-sunken:  color-mix(in oklab, var(--dl-ink) 8%, var(--dl-paper));     /* code, inset areas, disabled fills */
  --surface-overlay: color-mix(in oklab, black 45%, transparent);                /* the scrim behind a dialog */

  /* ---- Text ---- */
  --text-strong:   var(--dl-ink);                                                                         /* headings, labels, emphasis */
  --text:          color-mix(in oklab, var(--dl-ink) calc(86% + var(--text-contrast) * 0.4%), var(--dl-paper));  /* body text */
  --text-muted:    color-mix(in oklab, var(--dl-ink) calc(70% + var(--text-contrast) * 1%), var(--dl-paper));    /* secondary text */
  --text-quiet:    color-mix(in oklab, var(--dl-ink) calc(64% + var(--text-contrast) * 1.2%), var(--dl-paper));  /* captions, dates, placeholders */
  --text-disabled: color-mix(in oklab, var(--dl-ink) 38%, var(--dl-paper));                                /* disabled controls: exempt from contrast rules */
  --link:          var(--brand-on-soft);                                                                  /* links: 4.5:1 on every surface */
  --link-hover:    light-dark(color(from var(--dl-brand-hover) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-brand-hover) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));  /* links on hover: a step stronger (the link 0.08 darker in OKLCH lightness in light, lighter in dark), and on to 7:1 if that's short */

  /* ---- Lines and effects ---- */
  --border-quiet:  color-mix(in oklab, var(--dl-ink) 7%, var(--dl-paper));   /* dividers that should barely show */
  --border:        color-mix(in oklab, var(--dl-ink) 13%, var(--dl-paper));  /* card and table borders: decorative */
  --border-strong: color-mix(in oklab, var(--dl-ink) calc(46% + var(--text-contrast) * 1%), var(--dl-paper));  /* field and control borders: 3:1 on surfaces */
  --focus:         var(--brand-on-soft);                                     /* the focus ring: opaque, 4.5:1 on surfaces */
  --selection:     color-mix(in oklab, var(--dl-brand) 22%, var(--dl-paper));  /* selected text background */
  --shadow-color:  light-dark(color-mix(in oklab, black 10%, transparent), color-mix(in oklab, black 45%, transparent));  /* the colour of shadows */
  --shadow-s: 0 1px 3px var(--shadow-color);    /* a slight lift: buttons, chips */
  --shadow-m: 0 4px 14px var(--shadow-color);   /* cards */
  --shadow-l: 0 12px 32px var(--shadow-color);  /* popovers, menus, dialogs */

  /* ---- Hover and pressed: the second half of a color-mix(), from Web Awesome.
     Use as color-mix(in oklch, var(--solid), var(--mix-hover)). ---- */
  --mix-hover:  oklch(from currentColor calc(1 - l) c h) 12%;  /* hover: away from the text colour */
  --mix-active: oklch(from currentColor calc(1 - l) c h) 22%;  /* pressed: further still */

  /* ---- Groups: brand, secondary, neutral, success, warning, danger, info. Five roles each:
     solid      a solid fill
     on-solid   text on it: white or black, whichever contrasts more (its sRGB luminance, as painted, vs --white-text-until)
     soft       a tinted background: the colour, held at L 0.7 or lighter in light (0.6 or darker in dark), mixed in OKLab
                into paper with its own tint taken out, so a blue soft stays blue on cream paper
     on-soft    text on soft, and coloured text on the page: the fill, moved only as far as 4.5:1 needs
     line       borders, icons and large text (24px, or 18.66px bold, and up): the dial, moved only as far as 3:1 needs

     Coloured text and lines follow one rule: keep the colour, and move it only as far as its
     contrast target needs, on the least contrasting background it sits on: its own soft tint,
     --surface-lowered or --surface-raised (--surface always lies between them). Only its
     linear-light RGB is scaled, which keeps the channels' ratios, so hue and saturation stay
     (in dark, until a channel reaches 1).
     --link-hover is the same rule at 7:1, starting from the link a step stronger.
       Y   the colour's luminance, 0.2126 r + 0.7152 g + 0.0722 b in linear sRGB (clipped to sRGB first)
       Yb  that background's luminance, as painted (clipped to sRGB)
       T   the target, plus 0.1 headroom so painting in 8 bits can't round it under the line
       light: Yt = (Yb + 0.05) / (T + 0.1) - 0.05; scale r, g and b by min(1, Yt / Y)
       dark:  Yt = (T + 0.1) * (Yb + 0.05) - 0.05; scale r, g and b by max(1, Yt / Y), each capped
              at 1; if a capped channel leaves it short, mix towards white only as far as Yt needs:
              by (Yt - Y1) / (1 - Y1), where Y1 is the luminance after scaling
     A colour that already passes keeps its exact value. CSS works out a relative colour from
     one colour's channels only, so the steps carry their numbers in colours:
       --dl-surfaces-y       the luminance of --surface-lowered in green, of --surface-raised in blue
       --dl-{group}-under    plus the soft tint's in red, mixed 50/50: Yb is min(2r, 4g, 4b) in light, max in dark
       --dl-{group}-text,    the colour, mixed 50/50 with a black whose alpha is s Yt, where s is 3 in
       --dl-{group}-line,    light (Yt is at most 0.29 there) and 1 in dark: scaling it up means Firefox
       --dl-brand-hover      rounding a mix's alpha to three decimals costs a third as much. Mixing
                             premultiplies, so the mix has alpha a = (1 + s Yt) / 2 and channels c / 2a:
                             the colour's channels are r * 2a, and Yt is (2a - 1) / s
       on-soft, line, hover  unpack both and scale, as above ---- */
  --dl-surfaces-y: color-mix(in srgb-linear, color(from var(--surface-lowered) srgb-linear 0 calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1)) 0), color(from var(--surface-raised) srgb-linear 0 0 calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))));

--dl-brand-under: color-mix(in srgb-linear, color(from var(--brand-soft) srgb-linear calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1)) 0 0), var(--dl-surfaces-y));
  --dl-brand-text:  color-mix(in srgb-linear, color(from var(--dl-brand-base) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-brand-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (4.5 + 0.1) - 0.05), 1))), color(from var(--dl-brand-under) srgb-linear 0 0 0 / calc(clamp(0, (4.5 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --dl-brand-line:  color-mix(in srgb-linear, color(from var(--brand) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-brand-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (3 + 0.1) - 0.05), 1))), color(from var(--dl-brand-under) srgb-linear 0 0 0 / calc(clamp(0, (3 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --brand-solid:    var(--dl-brand);
  --brand-on-solid: color(from var(--dl-brand) srgb-linear calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) / 1);
  --brand-soft:     oklch(from color-mix(in oklab, light-dark(oklch(from var(--dl-brand) max(l, 0.7) c h), oklch(from var(--dl-brand) min(l, 0.6) c h)) var(--tint-strength), var(--dl-paper-grey)) l calc(c * var(--tint-vividness)) h);
  --brand-on-soft:  light-dark(color(from var(--dl-brand-text) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-brand-text) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));
  --brand-line:     light-dark(color(from var(--dl-brand-line) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-brand-line) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));

  --dl-secondary-under: color-mix(in srgb-linear, color(from var(--secondary-soft) srgb-linear calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1)) 0 0), var(--dl-surfaces-y));
  --dl-secondary-text:  color-mix(in srgb-linear, color(from var(--dl-secondary-base) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-secondary-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (4.5 + 0.1) - 0.05), 1))), color(from var(--dl-secondary-under) srgb-linear 0 0 0 / calc(clamp(0, (4.5 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --dl-secondary-line:  color-mix(in srgb-linear, color(from var(--dl-secondary-dial) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-secondary-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (3 + 0.1) - 0.05), 1))), color(from var(--dl-secondary-under) srgb-linear 0 0 0 / calc(clamp(0, (3 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --secondary-solid:    var(--dl-secondary);
  --secondary-on-solid: color(from var(--dl-secondary) srgb-linear calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) / 1);
  --secondary-soft:     oklch(from color-mix(in oklab, light-dark(oklch(from var(--dl-secondary) max(l, 0.7) c h), oklch(from var(--dl-secondary) min(l, 0.6) c h)) var(--tint-strength), var(--dl-paper-grey)) l calc(c * var(--tint-vividness)) h);
  --secondary-on-soft:  light-dark(color(from var(--dl-secondary-text) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-secondary-text) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));
  --secondary-line:     light-dark(color(from var(--dl-secondary-line) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-secondary-line) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));

  --neutral-solid:    var(--dl-ink);
  --neutral-on-solid: var(--dl-paper);
  --neutral-soft:     var(--surface-lowered);
  --neutral-on-soft:  var(--text);
  --neutral-line:     var(--border);

  --dl-success-under: color-mix(in srgb-linear, color(from var(--success-soft) srgb-linear calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1)) 0 0), var(--dl-surfaces-y));
  --dl-success-text:  color-mix(in srgb-linear, color(from var(--dl-success-base) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-success-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (4.5 + 0.1) - 0.05), 1))), color(from var(--dl-success-under) srgb-linear 0 0 0 / calc(clamp(0, (4.5 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --dl-success-line:  color-mix(in srgb-linear, color(from var(--success) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-success-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (3 + 0.1) - 0.05), 1))), color(from var(--dl-success-under) srgb-linear 0 0 0 / calc(clamp(0, (3 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --success-solid:    var(--dl-success);
  --success-on-solid: color(from var(--dl-success) srgb-linear calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) / 1);
  --success-soft:     oklch(from color-mix(in oklab, light-dark(oklch(from var(--dl-success) max(l, 0.7) c h), oklch(from var(--dl-success) min(l, 0.6) c h)) var(--tint-strength), var(--dl-paper-grey)) l calc(c * var(--tint-vividness)) h);
  --success-on-soft:  light-dark(color(from var(--dl-success-text) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-success-text) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));
  --success-line:     light-dark(color(from var(--dl-success-line) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-success-line) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));

  --dl-warning-under: color-mix(in srgb-linear, color(from var(--warning-soft) srgb-linear calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1)) 0 0), var(--dl-surfaces-y));
  --dl-warning-text:  color-mix(in srgb-linear, color(from var(--dl-warning-base) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-warning-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (4.5 + 0.1) - 0.05), 1))), color(from var(--dl-warning-under) srgb-linear 0 0 0 / calc(clamp(0, (4.5 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --dl-warning-line:  color-mix(in srgb-linear, color(from var(--warning) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-warning-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (3 + 0.1) - 0.05), 1))), color(from var(--dl-warning-under) srgb-linear 0 0 0 / calc(clamp(0, (3 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --warning-solid:    var(--dl-warning);
  --warning-on-solid: color(from var(--dl-warning) srgb-linear calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) / 1);
  --warning-soft:     oklch(from color-mix(in oklab, light-dark(oklch(from var(--dl-warning) max(l, 0.7) c h), oklch(from var(--dl-warning) min(l, 0.6) c h)) var(--tint-strength), var(--dl-paper-grey)) l calc(c * var(--tint-vividness)) h);
  --warning-on-soft:  light-dark(color(from var(--dl-warning-text) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-warning-text) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));
  --warning-line:     light-dark(color(from var(--dl-warning-line) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-warning-line) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));

  --dl-danger-under: color-mix(in srgb-linear, color(from var(--danger-soft) srgb-linear calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1)) 0 0), var(--dl-surfaces-y));
  --dl-danger-text:  color-mix(in srgb-linear, color(from var(--dl-danger-base) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-danger-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (4.5 + 0.1) - 0.05), 1))), color(from var(--dl-danger-under) srgb-linear 0 0 0 / calc(clamp(0, (4.5 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --dl-danger-line:  color-mix(in srgb-linear, color(from var(--danger) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-danger-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (3 + 0.1) - 0.05), 1))), color(from var(--dl-danger-under) srgb-linear 0 0 0 / calc(clamp(0, (3 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --danger-solid:    var(--dl-danger);
  --danger-on-solid: color(from var(--dl-danger) srgb-linear calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) / 1);
  --danger-soft:     oklch(from color-mix(in oklab, light-dark(oklch(from var(--dl-danger) max(l, 0.7) c h), oklch(from var(--dl-danger) min(l, 0.6) c h)) var(--tint-strength), var(--dl-paper-grey)) l calc(c * var(--tint-vividness)) h);
  --danger-on-soft:  light-dark(color(from var(--dl-danger-text) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-danger-text) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));
  --danger-line:     light-dark(color(from var(--dl-danger-line) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-danger-line) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));

  --dl-info-under: color-mix(in srgb-linear, color(from var(--info-soft) srgb-linear calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1)) 0 0), var(--dl-surfaces-y));
  --dl-info-text:  color-mix(in srgb-linear, color(from var(--dl-info-base) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-info-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (4.5 + 0.1) - 0.05), 1))), color(from var(--dl-info-under) srgb-linear 0 0 0 / calc(clamp(0, (4.5 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --dl-info-line:  color-mix(in srgb-linear, color(from var(--info) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-info-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (3 + 0.1) - 0.05), 1))), color(from var(--dl-info-under) srgb-linear 0 0 0 / calc(clamp(0, (3 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
  --info-solid:    var(--dl-info);
  --info-on-solid: color(from var(--dl-info) srgb-linear calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) / 1);
  --info-soft:     oklch(from color-mix(in oklab, light-dark(oklch(from var(--dl-info) max(l, 0.7) c h), oklch(from var(--dl-info) min(l, 0.6) c h)) var(--tint-strength), var(--dl-paper-grey)) l calc(c * var(--tint-vividness)) h);
  --info-on-soft:  light-dark(color(from var(--dl-info-text) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-info-text) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));
  --info-line:     light-dark(color(from var(--dl-info-line) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--dl-info-line) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));
  --dl-brand-hover: color-mix(in srgb-linear, color(from light-dark(oklch(from var(--brand-on-soft) calc(l - 0.08) c h), oklch(from var(--brand-on-soft) calc(l + 0.08) c h)) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--dl-brand-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (7 + 0.1) - 0.05), 1))), color(from var(--dl-brand-under) srgb-linear 0 0 0 / calc(clamp(0, (7 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));

  /* ---- Ungrouped: components use these; .is-{group} points them at a group ---- */
  --solid:    var(--brand-solid);
  --on-solid: var(--brand-on-solid);
  --soft:     var(--brand-soft);
  --on-soft:  var(--brand-on-soft);
  --line:     var(--brand-line);

  /* ---- Deprecated: --accent's tokens, renamed --secondary-*. They still work; rename them ---- */
  --accent-solid:    var(--secondary-solid);     /* deprecated: use --secondary-solid */
  --accent-on-solid: var(--secondary-on-solid);  /* deprecated: use --secondary-on-solid */
  --accent-soft:     var(--secondary-soft);      /* deprecated: use --secondary-soft */
  --accent-on-soft:  var(--secondary-on-soft);   /* deprecated: use --secondary-on-soft */
  --accent-line:     var(--secondary-line);      /* deprecated: use --secondary-line */
}
.is-brand     { --solid: var(--brand-solid);     --on-solid: var(--brand-on-solid);     --soft: var(--brand-soft);     --on-soft: var(--brand-on-soft);     --line: var(--brand-line); }
.is-secondary { --solid: var(--secondary-solid); --on-solid: var(--secondary-on-solid); --soft: var(--secondary-soft); --on-soft: var(--secondary-on-soft); --line: var(--secondary-line); }
.is-neutral   { --solid: var(--neutral-solid);   --on-solid: var(--neutral-on-solid);   --soft: var(--neutral-soft);   --on-soft: var(--neutral-on-soft);   --line: var(--neutral-line); }
.is-success   { --solid: var(--success-solid);   --on-solid: var(--success-on-solid);   --soft: var(--success-soft);   --on-soft: var(--success-on-soft);   --line: var(--success-line); }
.is-warning   { --solid: var(--warning-solid);   --on-solid: var(--warning-on-solid);   --soft: var(--warning-soft);   --on-soft: var(--warning-on-soft);   --line: var(--warning-line); }
.is-danger    { --solid: var(--danger-solid);    --on-solid: var(--danger-on-solid);    --soft: var(--danger-soft);    --on-soft: var(--danger-on-soft);    --line: var(--danger-line); }
.is-info      { --solid: var(--info-solid);      --on-solid: var(--info-on-solid);      --soft: var(--info-soft);      --on-soft: var(--info-on-soft);      --line: var(--info-line); }
.is-accent    { --solid: var(--secondary-solid); --on-solid: var(--secondary-on-solid); --soft: var(--secondary-soft); --on-soft: var(--secondary-on-soft); --line: var(--secondary-line); }  /* deprecated: use .is-secondary */
/* A light or dark band: its own scheme, and its own background and text worked out in it */
.is-light { color-scheme: light; background-color: var(--surface); color: var(--text); }
.is-dark  { color-scheme: dark;  background-color: var(--surface); color: var(--text); }
/* ============================================================
   Dials: type and space (dials-scale.css)
   A few dials set every text size and every space size, the way
   Utopia (utopia.fyi) works them out, but the maths runs in the
   browser: change a dial and the whole scale follows. Leading is
   worked out the same way, for whatever size it's used at. This
   file sets no type on any element: only
   dials-base.css does that. Dials live on
   :root (and :host); the derived scale is declared on :root,
   [data-dials] and :host, so a dial set on a [data-dials] element
   re-derives the sizes inside it.
   ============================================================ */
:root, :host {
  /* ---- Dials ---- */
  --screen-min: 360;       /* the screen widths the scale runs between, in px */
  --screen-max: 1240;
  --size-min: 16;          /* body text at the narrowest and widest screens, in px */
  --size-max: 18;
  --ratio-min: 1.2;        /* each step is this much bigger than the last: 1.2 minor third, */
  --ratio-max: 1.25;       /* 1.25 major third, 1.333 perfect fourth, 1.5 fifth, 1.618 golden */
  --space-min: var(--size-min);  /* --space-s at each end, in px: follows body text */
  --space-max: var(--size-max);  /* size unless you set a number */
  --space-density: 1;      /* scales every space size: 0.8 compact, 1.25 roomy */
  --radius-base: 10;       /* corner radius of cards and fields, in px (a number, not a length) */

  /* Faces: set per site, and load them yourself (each theme file names its Google Fonts link) */
  --font-body: ui-sans-serif, system-ui, sans-serif;  /* body text and controls */
  --font-heading: ui-sans-serif, system-ui, sans-serif;  /* headings */
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;  /* code, kbd, samp, pre */

  /* Border widths: every border and outline uses one of these */
  --border-width-s: 1px;   /* hairlines: cards, fields, tables */
  --border-width-m: 2px;   /* emphasis; outline offsets */
  --border-width-l: 3px;   /* focus rings, quote bars, active tabs */

  /* ---- Leading: one dial for the rhythm of the type ---- */
  /* --leading-body: 1.5;      line height at body size (--size-0), unitless. Every larger size keeps the same gap between lines, so it gets proportionally tighter; the space after paragraphs is one body line */
  /* --font-accent: var(--font-body);  a third face, for ledes, pull quotes or buttons; read it as var(--font-accent, var(--font-body)) */
}

:root, [data-dials], :host {
  /* ---- Internal: worked out from the dials, never edited by hand ---- */
  --dl-screen-range: calc(var(--screen-max) - var(--screen-min));
  --dl-fluid: calc((100vw - var(--screen-min) * 1px) / var(--dl-screen-range) * 16);  /* 0 at the narrowest, 16px at the widest */
  --dl-min-0: calc(var(--size-min) / 16);
  --dl-max-0: calc(var(--size-max) / 16);
  --dl-min--1: calc(var(--dl-min-0) / var(--ratio-min));
  --dl-max--1: calc(var(--dl-max-0) / var(--ratio-max));
  --dl-min--2: calc(var(--dl-min--1) / var(--ratio-min));
  --dl-max--2: calc(var(--dl-max--1) / var(--ratio-max));
  --dl-min-1: calc(var(--dl-min-0) * var(--ratio-min));
  --dl-max-1: calc(var(--dl-max-0) * var(--ratio-max));
  --dl-min-2: calc(var(--dl-min-1) * var(--ratio-min));
  --dl-max-2: calc(var(--dl-max-1) * var(--ratio-max));
  --dl-min-3: calc(var(--dl-min-2) * var(--ratio-min));
  --dl-max-3: calc(var(--dl-max-2) * var(--ratio-max));
  --dl-min-4: calc(var(--dl-min-3) * var(--ratio-min));
  --dl-max-4: calc(var(--dl-max-3) * var(--ratio-max));
  --dl-min-5: calc(var(--dl-min-4) * var(--ratio-min));
  --dl-max-5: calc(var(--dl-max-4) * var(--ratio-max));
  --dl-min-6: calc(var(--dl-min-5) * var(--ratio-min));
  --dl-max-6: calc(var(--dl-max-5) * var(--ratio-max));
  --dl-min-7: calc(var(--dl-min-6) * var(--ratio-min));
  --dl-max-7: calc(var(--dl-max-6) * var(--ratio-max));
  --dl-min-8: calc(var(--dl-min-7) * var(--ratio-min));
  --dl-max-8: calc(var(--dl-max-7) * var(--ratio-max));

  /* ---- Font sizes: --size-0 is body text; each number up or down is one step of the ratio,
     running in a straight line between its two ends ---- */
  --size--2: clamp(min(var(--dl-min--2), var(--dl-max--2)) * 1rem, var(--dl-min--2) * 1rem + (var(--dl-max--2) - var(--dl-min--2)) * var(--dl-fluid), max(var(--dl-min--2), var(--dl-max--2)) * 1rem);
  --size--1: clamp(min(var(--dl-min--1), var(--dl-max--1)) * 1rem, var(--dl-min--1) * 1rem + (var(--dl-max--1) - var(--dl-min--1)) * var(--dl-fluid), max(var(--dl-min--1), var(--dl-max--1)) * 1rem);
  --size-0: clamp(min(var(--dl-min-0), var(--dl-max-0)) * 1rem, var(--dl-min-0) * 1rem + (var(--dl-max-0) - var(--dl-min-0)) * var(--dl-fluid), max(var(--dl-min-0), var(--dl-max-0)) * 1rem);
  --size-1: clamp(min(var(--dl-min-1), var(--dl-max-1)) * 1rem, var(--dl-min-1) * 1rem + (var(--dl-max-1) - var(--dl-min-1)) * var(--dl-fluid), max(var(--dl-min-1), var(--dl-max-1)) * 1rem);
  --size-2: clamp(min(var(--dl-min-2), var(--dl-max-2)) * 1rem, var(--dl-min-2) * 1rem + (var(--dl-max-2) - var(--dl-min-2)) * var(--dl-fluid), max(var(--dl-min-2), var(--dl-max-2)) * 1rem);
  --size-3: clamp(min(var(--dl-min-3), var(--dl-max-3)) * 1rem, var(--dl-min-3) * 1rem + (var(--dl-max-3) - var(--dl-min-3)) * var(--dl-fluid), max(var(--dl-min-3), var(--dl-max-3)) * 1rem);
  --size-4: clamp(min(var(--dl-min-4), var(--dl-max-4)) * 1rem, var(--dl-min-4) * 1rem + (var(--dl-max-4) - var(--dl-min-4)) * var(--dl-fluid), max(var(--dl-min-4), var(--dl-max-4)) * 1rem);
  --size-5: clamp(min(var(--dl-min-5), var(--dl-max-5)) * 1rem, var(--dl-min-5) * 1rem + (var(--dl-max-5) - var(--dl-min-5)) * var(--dl-fluid), max(var(--dl-min-5), var(--dl-max-5)) * 1rem);
  --size-6: clamp(min(var(--dl-min-6), var(--dl-max-6)) * 1rem, var(--dl-min-6) * 1rem + (var(--dl-max-6) - var(--dl-min-6)) * var(--dl-fluid), max(var(--dl-min-6), var(--dl-max-6)) * 1rem);
  --size-7: clamp(min(var(--dl-min-7), var(--dl-max-7)) * 1rem, var(--dl-min-7) * 1rem + (var(--dl-max-7) - var(--dl-min-7)) * var(--dl-fluid), max(var(--dl-min-7), var(--dl-max-7)) * 1rem);  /* display type */
  --size-8: clamp(min(var(--dl-min-8), var(--dl-max-8)) * 1rem, var(--dl-min-8) * 1rem + (var(--dl-max-8) - var(--dl-min-8)) * var(--dl-fluid), max(var(--dl-min-8), var(--dl-max-8)) * 1rem);  /* display type: the top of the scale */

  /* ---- Leading: worked out for the size of the element it's used on ---- */
  /* --leading is a length: apply it on each element that sets a font size (dials-base.css applies it to every
     element), never on a wrapper for its children to inherit, where it would pass on one fixed length. */
  --dl-leading-body: var(--leading-body, 1.5);
  /* the body's gap between lines at every larger size (1em + the body gap), so bigger text gets proportionally
     tighter lines; smaller text keeps the body ratio; no size goes below 1.05 */
  --leading: max(1.05em, min(var(--dl-leading-body) * 1em, 1em + (var(--dl-leading-body) - 1) * var(--size-0)));  /* line height for the size it's on: the same gap between lines as body text at every larger size */
  --space-paragraph: calc(var(--dl-leading-body) * var(--size-0));  /* one body line: the space after paragraphs and other blocks; headings take two above and half below */

  /* ---- Space: multiples of the space base (Utopia's t-shirt sizes), times the density ---- */
  --dl-space-min: calc(var(--space-min) / 16 * var(--space-density));
  --dl-space-max: calc(var(--space-max) / 16 * var(--space-density));
  --space-3xs: clamp(calc(var(--dl-space-min) * 0.25rem), calc(var(--dl-space-min) * 0.25rem + (var(--dl-space-max) * 0.25 - var(--dl-space-min) * 0.25) * var(--dl-fluid)), calc(var(--dl-space-max) * 0.25rem));
  --space-2xs: clamp(calc(var(--dl-space-min) * 0.5rem), calc(var(--dl-space-min) * 0.5rem + (var(--dl-space-max) * 0.5 - var(--dl-space-min) * 0.5) * var(--dl-fluid)), calc(var(--dl-space-max) * 0.5rem));
  --space-xs: clamp(calc(var(--dl-space-min) * 0.75rem), calc(var(--dl-space-min) * 0.75rem + (var(--dl-space-max) * 0.75 - var(--dl-space-min) * 0.75) * var(--dl-fluid)), calc(var(--dl-space-max) * 0.75rem));
  --space-s: clamp(calc(var(--dl-space-min) * 1rem), calc(var(--dl-space-min) * 1rem + (var(--dl-space-max) * 1 - var(--dl-space-min) * 1) * var(--dl-fluid)), calc(var(--dl-space-max) * 1rem));
  --space-m: clamp(calc(var(--dl-space-min) * 1.5rem), calc(var(--dl-space-min) * 1.5rem + (var(--dl-space-max) * 1.5 - var(--dl-space-min) * 1.5) * var(--dl-fluid)), calc(var(--dl-space-max) * 1.5rem));
  --space-l: clamp(calc(var(--dl-space-min) * 2rem), calc(var(--dl-space-min) * 2rem + (var(--dl-space-max) * 2 - var(--dl-space-min) * 2) * var(--dl-fluid)), calc(var(--dl-space-max) * 2rem));
  --space-xl: clamp(calc(var(--dl-space-min) * 3rem), calc(var(--dl-space-min) * 3rem + (var(--dl-space-max) * 3 - var(--dl-space-min) * 3) * var(--dl-fluid)), calc(var(--dl-space-max) * 3rem));
  --space-2xl: clamp(calc(var(--dl-space-min) * 4rem), calc(var(--dl-space-min) * 4rem + (var(--dl-space-max) * 4 - var(--dl-space-min) * 4) * var(--dl-fluid)), calc(var(--dl-space-max) * 4rem));
  --space-3xl: clamp(calc(var(--dl-space-min) * 6rem), calc(var(--dl-space-min) * 6rem + (var(--dl-space-max) * 6 - var(--dl-space-min) * 6) * var(--dl-fluid)), calc(var(--dl-space-max) * 6rem));
  --space-4xl: clamp(calc(var(--dl-space-min) * 8rem), calc(var(--dl-space-min) * 8rem + (var(--dl-space-max) * 8 - var(--dl-space-min) * 8) * var(--dl-fluid)), calc(var(--dl-space-max) * 8rem));
  /* One-up pairs: small on phones, the next size up on desktops */
  --space-3xs-2xs: clamp(calc(var(--dl-space-min) * 0.25rem), calc(var(--dl-space-min) * 0.25rem + (var(--dl-space-max) * 0.5 - var(--dl-space-min) * 0.25) * var(--dl-fluid)), calc(var(--dl-space-max) * 0.5rem));
  --space-2xs-xs: clamp(calc(var(--dl-space-min) * 0.5rem), calc(var(--dl-space-min) * 0.5rem + (var(--dl-space-max) * 0.75 - var(--dl-space-min) * 0.5) * var(--dl-fluid)), calc(var(--dl-space-max) * 0.75rem));
  --space-xs-s: clamp(calc(var(--dl-space-min) * 0.75rem), calc(var(--dl-space-min) * 0.75rem + (var(--dl-space-max) * 1 - var(--dl-space-min) * 0.75) * var(--dl-fluid)), calc(var(--dl-space-max) * 1rem));
  --space-s-m: clamp(calc(var(--dl-space-min) * 1rem), calc(var(--dl-space-min) * 1rem + (var(--dl-space-max) * 1.5 - var(--dl-space-min) * 1) * var(--dl-fluid)), calc(var(--dl-space-max) * 1.5rem));
  --space-m-l: clamp(calc(var(--dl-space-min) * 1.5rem), calc(var(--dl-space-min) * 1.5rem + (var(--dl-space-max) * 2 - var(--dl-space-min) * 1.5) * var(--dl-fluid)), calc(var(--dl-space-max) * 2rem));
  --space-l-xl: clamp(calc(var(--dl-space-min) * 2rem), calc(var(--dl-space-min) * 2rem + (var(--dl-space-max) * 3 - var(--dl-space-min) * 2) * var(--dl-fluid)), calc(var(--dl-space-max) * 3rem));
  --space-xl-2xl: clamp(calc(var(--dl-space-min) * 3rem), calc(var(--dl-space-min) * 3rem + (var(--dl-space-max) * 4 - var(--dl-space-min) * 3) * var(--dl-fluid)), calc(var(--dl-space-max) * 4rem));
  --space-2xl-3xl: clamp(calc(var(--dl-space-min) * 4rem), calc(var(--dl-space-min) * 4rem + (var(--dl-space-max) * 6 - var(--dl-space-min) * 4) * var(--dl-fluid)), calc(var(--dl-space-max) * 6rem));
  --space-3xl-4xl: clamp(calc(var(--dl-space-min) * 6rem), calc(var(--dl-space-min) * 6rem + (var(--dl-space-max) * 8 - var(--dl-space-min) * 6) * var(--dl-fluid)), calc(var(--dl-space-max) * 8rem));
  /* Skip pairs, for gutters and section padding that need a bigger swing */
  --space-s-l: clamp(calc(var(--dl-space-min) * 1rem), calc(var(--dl-space-min) * 1rem + (var(--dl-space-max) * 2 - var(--dl-space-min) * 1) * var(--dl-fluid)), calc(var(--dl-space-max) * 2rem));
  --space-m-xl: clamp(calc(var(--dl-space-min) * 1.5rem), calc(var(--dl-space-min) * 1.5rem + (var(--dl-space-max) * 3 - var(--dl-space-min) * 1.5) * var(--dl-fluid)), calc(var(--dl-space-max) * 3rem));
  --space-l-2xl: clamp(calc(var(--dl-space-min) * 2rem), calc(var(--dl-space-min) * 2rem + (var(--dl-space-max) * 4 - var(--dl-space-min) * 2) * var(--dl-fluid)), calc(var(--dl-space-max) * 4rem));

  /* ---- Corners ---- */
  --radius-s: calc(var(--radius-base) * 0.5px);
  --radius-m: calc(var(--radius-base) * 1px);
  --radius-l: calc(var(--radius-base) * 1.6px);
  --radius-pill: 999px;
}
/* ============================================================
   Dials: the fallback (src/fallback.css, built into the end of dials.css)
   For browsers with color-mix() but without relative colour or
   light-dark(): Chrome and Edge 111-122, Safari 16.2-17, Firefox
   113-127. They can't work out the derived chain above, so this
   block works every public colour token out again from the same
   dials, with color-mix() alone. It comes after the chain and uses
   the same selectors, so it wins there; a site's own file, loaded
   after dials.css, still wins over it. It never sets a dial.
   Approximations, held to the same contrast as the chain (the
   contrast check's --fallback mode):
   - The page is light. .is-dark bands are dark, .is-light bands light.
   - Paper and ink come from --grey at fixed mixes, so the four
     lightness dials, --balance, --dark-lift, --tint-vividness and
     --text-contrast have no effect. --paper-light and friends do.
   - on-solid text can't follow the fill's luminance: each group has a
     fixed choice, and its fill is pulled a fixed amount towards the
     other end so the text keeps 4.5:1 in every Dials theme. White on
     brand, secondary, danger and info, whose fills are darkened; black
     on success, whose fill is lightened, and warning, as set.
   - Coloured text and lines can't move only as far as their target
     needs: on-soft is the dial mixed a fixed amount into ink (so --link
     and --focus too), line a smaller amount, and --link-hover further
     still. The amounts hold 4.5:1 and 3:1 on every surface and soft
     tint, for every theme and for extreme dials, so they over-shoot for
     most colours. Ink is near-black on a light page and near-white in an
     .is-dark band, so the same mix works in both.
   - No calc() and no percentages computed inside color-mix(): only
     literal percentages and dials that are one (--tint-strength).
   ============================================================ */
@supports not ((color: oklch(from red l c h)) and (color: light-dark(red, red))) {
  /* ---- Internal: the scheme switches, literal percentages a band can flip ---- */
  :root, :host, .is-light {
    color-scheme: light;
    --dl-fb-dark: 0%;     /* how much of the dark paper and ink to use */
    --dl-fb-raise: 38%;   /* how much white lifts --surface-raised */
    --dl-fb-shadow: 10%;  /* the strength of shadows */
  }
  .is-dark {
    color-scheme: dark;
    --dl-fb-dark: 100%;
    --dl-fb-raise: 4%;
    --dl-fb-shadow: 45%;
  }

  /* Bands are declared here too, so every token is worked out again in a band's own scheme */
  :root, [data-dials], :host, .is-light, .is-dark {
    /* ---- Internal: paper, ink and the six fills ---- */
    --dl-paper-light: var(--paper-light, color-mix(in oklab, var(--grey) 20%, white));
    --dl-paper-dark:  var(--paper-dark,  color-mix(in oklab, var(--grey) 30%, black));
    --dl-ink-light:   var(--ink-light,   color-mix(in oklab, var(--grey) 34%, black));
    --dl-ink-dark:    var(--ink-dark,    color-mix(in oklab, var(--grey) 17%, white));
    --dl-paper: color-mix(in oklab, var(--dl-paper-dark) var(--dl-fb-dark), var(--dl-paper-light));
    --dl-ink:   color-mix(in oklab, var(--dl-ink-dark) var(--dl-fb-dark), var(--dl-ink-light));
    --dl-brand:   color-mix(in oklab, var(--brand) 72%, black);
    --dl-secondary: color-mix(in oklab, var(--accent, var(--secondary)) 67%, black);
    --dl-success: color-mix(in oklab, var(--success) 85%, white);
    --dl-warning: var(--warning);
    --dl-danger:  color-mix(in oklab, var(--danger) 78%, black);
    --dl-info:    color-mix(in oklab, var(--info) 61%, black);

    /* ---- Surfaces ---- */
    --surface:         var(--dl-paper);
    --surface-raised:  color-mix(in oklab, white var(--dl-fb-raise), var(--dl-paper));
    --surface-lowered: color-mix(in oklab, var(--dl-ink) 4%, var(--dl-paper));
    --surface-sunken:  color-mix(in oklab, var(--dl-ink) 8%, var(--dl-paper));
    --surface-overlay: color-mix(in oklab, black 45%, transparent);

    /* ---- Text: a step stronger than the chain's defaults, to cover --text-contrast ---- */
    --text-strong:   var(--dl-ink);
    --text:          color-mix(in oklab, var(--dl-ink) 94%, var(--dl-paper));
    --text-muted:    color-mix(in oklab, var(--dl-ink) 89%, var(--dl-paper));
    --text-quiet:    color-mix(in oklab, var(--dl-ink) 86%, var(--dl-paper));
    --text-disabled: color-mix(in oklab, var(--dl-ink) 38%, var(--dl-paper));
    --link:          var(--brand-on-soft);
    --link-hover:    color-mix(in oklab, var(--brand) 20%, var(--dl-ink));

    /* ---- Lines and effects ---- */
    --border-quiet:  color-mix(in oklab, var(--dl-ink) 7%, var(--dl-paper));
    --border:        color-mix(in oklab, var(--dl-ink) 13%, var(--dl-paper));
    --border-strong: color-mix(in oklab, var(--dl-ink) 64%, var(--dl-paper));
    --focus:         var(--brand-on-soft);
    --selection:     color-mix(in oklab, var(--brand) 22%, var(--dl-paper));
    --shadow-color:  color-mix(in oklab, black var(--dl-fb-shadow), transparent);
    --shadow-s: 0 1px 3px var(--shadow-color);
    --shadow-m: 0 4px 14px var(--shadow-color);
    --shadow-l: 0 12px 32px var(--shadow-color);
    --mix-hover:  black 12%;
    --mix-active: black 22%;

    /* ---- Groups: soft mixed into paper, on-soft and line mixed towards ink ---- */
    --brand-solid:    var(--dl-brand);
    --brand-on-solid: white;
    --brand-soft:     color-mix(in oklab, var(--brand) var(--tint-strength), var(--dl-paper));
    --brand-on-soft:  color-mix(in oklab, var(--brand) 26%, var(--dl-ink));
    --brand-line:     color-mix(in oklab, var(--brand) 40%, var(--dl-ink));

    --secondary-solid:    var(--dl-secondary);
    --secondary-on-solid: white;
    --secondary-soft:     color-mix(in oklab, var(--accent, var(--secondary)) var(--tint-strength), var(--dl-paper));
    --secondary-on-soft:  color-mix(in oklab, var(--accent, var(--secondary)) 26%, var(--dl-ink));
    --secondary-line:     color-mix(in oklab, var(--accent, var(--secondary)) 40%, var(--dl-ink));

    --neutral-solid:    var(--dl-ink);
    --neutral-on-solid: var(--dl-paper);
    --neutral-soft:     var(--surface-lowered);
    --neutral-on-soft:  var(--text);
    --neutral-line:     var(--border);

    --success-solid:    var(--dl-success);
    --success-on-solid: black;
    --success-soft:     color-mix(in oklab, var(--success) var(--tint-strength), var(--dl-paper));
    --success-on-soft:  color-mix(in oklab, var(--success) 26%, var(--dl-ink));
    --success-line:     color-mix(in oklab, var(--success) 40%, var(--dl-ink));

    --warning-solid:    var(--dl-warning);
    --warning-on-solid: black;
    --warning-soft:     color-mix(in oklab, var(--warning) var(--tint-strength), var(--dl-paper));
    --warning-on-soft:  color-mix(in oklab, var(--warning) 26%, var(--dl-ink));
    --warning-line:     color-mix(in oklab, var(--warning) 40%, var(--dl-ink));

    --danger-solid:    var(--dl-danger);
    --danger-on-solid: white;
    --danger-soft:     color-mix(in oklab, var(--danger) var(--tint-strength), var(--dl-paper));
    --danger-on-soft:  color-mix(in oklab, var(--danger) 26%, var(--dl-ink));
    --danger-line:     color-mix(in oklab, var(--danger) 40%, var(--dl-ink));

    --info-solid:    var(--dl-info);
    --info-on-solid: white;
    --info-soft:     color-mix(in oklab, var(--info) var(--tint-strength), var(--dl-paper));
    --info-on-soft:  color-mix(in oklab, var(--info) 26%, var(--dl-ink));
    --info-line:     color-mix(in oklab, var(--info) 40%, var(--dl-ink));

    /* ---- Ungrouped ---- */
    --solid:    var(--brand-solid);
    --on-solid: var(--brand-on-solid);
    --soft:     var(--brand-soft);
    --on-soft:  var(--brand-on-soft);
    --line:     var(--brand-line);

    /* ---- Deprecated: the old names for the secondary group ---- */
    --accent-solid:    var(--secondary-solid);
    --accent-on-solid: var(--secondary-on-solid);
    --accent-soft:     var(--secondary-soft);
    --accent-on-soft:  var(--secondary-on-soft);
    --accent-line:     var(--secondary-line);
  }
  /* the group classes again, so they still win on a [data-dials] element or a band */
  .is-brand     { --solid: var(--brand-solid);     --on-solid: var(--brand-on-solid);     --soft: var(--brand-soft);     --on-soft: var(--brand-on-soft);     --line: var(--brand-line); }
  .is-secondary { --solid: var(--secondary-solid); --on-solid: var(--secondary-on-solid); --soft: var(--secondary-soft); --on-soft: var(--secondary-on-soft); --line: var(--secondary-line); }
  .is-neutral   { --solid: var(--neutral-solid);   --on-solid: var(--neutral-on-solid);   --soft: var(--neutral-soft);   --on-soft: var(--neutral-on-soft);   --line: var(--neutral-line); }
  .is-success   { --solid: var(--success-solid);   --on-solid: var(--success-on-solid);   --soft: var(--success-soft);   --on-soft: var(--success-on-soft);   --line: var(--success-line); }
  .is-warning   { --solid: var(--warning-solid);   --on-solid: var(--warning-on-solid);   --soft: var(--warning-soft);   --on-soft: var(--warning-on-soft);   --line: var(--warning-line); }
  .is-danger    { --solid: var(--danger-solid);    --on-solid: var(--danger-on-solid);    --soft: var(--danger-soft);    --on-soft: var(--danger-on-soft);    --line: var(--danger-line); }
  .is-info      { --solid: var(--info-solid);      --on-solid: var(--info-on-solid);      --soft: var(--info-soft);      --on-soft: var(--info-on-soft);      --line: var(--info-line); }
  .is-accent    { --solid: var(--secondary-solid); --on-solid: var(--secondary-on-solid); --soft: var(--secondary-soft); --on-soft: var(--secondary-on-soft); --line: var(--secondary-line); }
}
/* Generated by tools/fallback.mjs from dials.css (src/colour.css 8cab4e67a684f482): the defaults in
   the light scheme. Don't edit. The last resort, for browsers without color-mix() (Chrome and Edge
   before 111, Safari before 16.2, Firefox before 113, all 2022 or older): they can't work anything
   out, so every colour token is flat and they get the house colours, light only. Colour dials have no
   effect there; type and space work as normal. */
@supports not (color: color-mix(in srgb, red, blue)) {
  :root, [data-dials], :host, .is-light, .is-dark {
    color-scheme: light;
    --surface: #f9fafc;
    --surface-raised: #feffff;
    --surface-lowered: #eef0f2;
    --surface-sunken: #e4e5e7;
    --surface-overlay: rgb(0 0 0 / 45%);
    --text-strong: #151619;
    --text: #2f3033;
    --text-muted: #505154;
    --text-quiet: #5d5e61;
    --text-disabled: #999a9d;
    --link: #2362e9;
    --link-hover: #0743c2;
    --border-quiet: #e7e8ea;
    --border: #d7d8db;
    --border-strong: #86878a;
    --focus: #2362e9;
    --selection: #c9dbfc;
    --shadow-color: rgb(0 0 0 / 10%);
    --shadow-s: 0 1px 3px rgb(0 0 0 / 10%);
    --shadow-m: 0 4px 14px rgb(0 0 0 / 10%);
    --shadow-l: 0 12px 32px rgb(0 0 0 / 10%);
    --mix-hover: black 12%;
    --mix-active: black 22%;
    --brand-solid: #2463eb;
    --brand-on-solid: #ffffff;
    --brand-soft: #e9f1ff;
    --brand-on-soft: #2362e9;
    --brand-line: #2463eb;
    --secondary-solid: #7c51c8;
    --secondary-on-solid: #ffffff;
    --secondary-soft: #f1eefc;
    --secondary-on-soft: #7c51c8;
    --secondary-line: #7c51c8;
    --neutral-solid: #151619;
    --neutral-on-solid: #f9fafc;
    --neutral-soft: #eef0f2;
    --neutral-on-soft: #2f3033;
    --neutral-line: #d7d8db;
    --success-solid: #239f50;
    --success-on-solid: #000000;
    --success-soft: #eaf4eb;
    --success-on-soft: #197c3d;
    --success-line: #229c4f;
    --warning-solid: #f59f0a;
    --warning-on-solid: #000000;
    --warning-soft: #faf1e7;
    --warning-on-soft: #976003;
    --warning-line: #bd7906;
    --danger-solid: #dc2828;
    --danger-on-solid: #ffffff;
    --danger-soft: #ffece9;
    --danger-on-soft: #d02525;
    --danger-line: #dc2828;
    --info-solid: #0c8eca;
    --info-on-solid: #000000;
    --info-soft: #e9f2f9;
    --info-on-soft: #0773a4;
    --info-line: #0c8eca;
    --accent-solid: #7c51c8;
    --accent-on-solid: #ffffff;
    --accent-soft: #f1eefc;
    --accent-on-soft: #7c51c8;
    --accent-line: #7c51c8;
  }
}
/* ═══ dials:end (Dials) ═════════════════════════════════════════════════ */

/* ═══ This site's dials ═════════════════════════════════════════════════
 * The ONLY place a colour or a scale value is typed. The values reproduce
 * the site's look before Dials: the practice kit's violet, lime and dark
 * violet, its cream page, and its type and space knobs, so it looks the
 * same. Light only, as live: the practice has no dark palette.
 * ═══════════════════════════════════════════════════════════════════════ */
:root {
    color-scheme: light;   /* light only, as live */

    /* Colour dials: the brand kit's own hex, written as HSL to one decimal
     * place, which paints the same hex (in each comment). Each is a group
     * with five roles: --brand-solid, --brand-on-solid, --brand-soft,
     * --brand-on-soft and --brand-line. The site layer below names them as
     * the kit does (--violet, --violet-deep, --lime), declared once from
     * these. The lime is the template's third colour, the one for buttons
     * and calls to action, rather than Dials' second: in older browsers
     * Dials darkens its second colour for white text, and no white holds
     * 4.5:1 on a darkened lime; the third colour's fallback can keep the
     * lime with black on it (below). */
    --brand: hsl(258.1 79.5% 71.4%);     /* #9F7CF0, violet: eyebrows, icons, the light end of the violet gradients */
    --secondary: hsl(276 36.2% 27.1%);   /* #4A2C5E, dark violet: headings, the violet grounds, the focus ring */
    --tertiary: hsl(73.1 62.5% 65.5%);   /* #C6DE70, lime, the call-to-action colour: every button, ticks, icons on violet */
    --success: hsl(126 46% 33%);         /* the status colours: the template's */
    --warning: hsl(37 74% 54%);
    --danger: hsl(3 56% 48%);
    --info: hsl(202 64% 41%);            /* also the hue of the doctors hero's sky wash (--sky, site layer) */
    --grey: hsl(255 12% 50%);            /* the ink's violet-grey; paper and ink are both exact below, so in light it tints nothing */

    /* Paper and ink, exact. The cream page, and a violet-black ink: --text
     * (lists and plain text, #302F34; #222028 before) and --text-muted (the
     * ledes, #525154; #56545B before) follow from it. Paragraphs keep live's
     * translucent black (--ink-body, site layer). */
    --paper-light: hsl(48 100% 99%);     /* #FFFEFA, cream */
    --ink-light: hsl(255 12% 9%);        /* #16141A */

    /* Colour defaults Dials v0.4 moved, held at v0.3's so every colour stays
     * as it was. The site is light only, but check-contrast scores the dark
     * scheme too, and these keep that identical. */
    --dark-lift: 0.04;
    --tint-strength: 8%;
    --paper-dark-lightness: 0.186;
    --ink-dark-lightness: 0.934;

    /* Type and space, fitted to live at 1440 (the fleet's 390-1440 range):
     * body 16px on a phone to 16.5px, and a 1.2 (phone) to 1.33 (desktop)
     * ratio that lands --size-1 at 21.9 (live's 20.6px h3 and 22-25px card
     * heads), --size-3 at 38.8 (live's 41px section heads) and --size-5 at
     * 68.7 (live's 74.25px hero display, -7.5%). Space: live's
     * 10/15/20/30/40/60/80/120 rhythm is --space-2xs..3xl at 1440 exactly
     * (--space-s 20px); phones run 20% tighter (16px). */
    --screen-min: 390;
    --screen-max: 1440;
    --size-min: 16;
    --size-max: 16.5;
    --ratio-min: 1.2;
    --ratio-max: 1.33;
    --space-min: 16;
    --space-max: 20;
    --space-density: 1;

    /* Type (Dials v0.4): Dials' one type dial is line height, --leading-body:
     * body text 1.5. Live sets line height by role, not by size, so the
     * site's rules read numbers rather than Dials' size curve (--leading):
     * the own tokens below, each holding at every size. Weights and letter
     * spacing are plain values on the rules that use them: body 400;
     * headings, bold runs and buttons 700; the nav, labels and links in
     * small print 600; the buttons' capitals 0.03em. Nothing is tracked by
     * size. Running text is capped at 65ch where a container asks for it
     * (.measure, the template's --measure). */
    --leading-body: 1.5;
    /* Hinchinbrook's own type tokens: values measured off live, role by
     * role, that the dial does not hold. Dials' size curve keeps body text's
     * gap between lines at every larger size, so it lands none of these
     * leadings; live tracks every heading flat and gives four kinds of
     * capitals their own spacing; and live's paragraphs are a fourth
     * weight, 500. */
    --leading-headline: 1.2;  /* headings, titles, names and buttons at a flat line height */
    --leading-hero: 1.1;      /* the hero display titles (.display) */
    --leading-snug: 1.3;      /* ledes, card copy, search results, the policy help text */
    --leading-subhead: 1.4;   /* h3: card and band subheads */
    --leading-loose: 1.6;     /* the legal pages' running text */
    --tracking-heading: -0.02em;   /* every heading, at every size */
    --tracking-eyebrow: 0.02em;    /* the eyebrows' capitals: tighter than the buttons' */
    --tracking-wide: 0.04em;       /* the accreditation strip's capitals, the gallery's photo count */
    --tracking-label: 0.06em;      /* the new-patient label's small capitals */
    --tracking-wider: 0.08em;      /* the 404 page's "Popular pages" capitals */
    --weight-copy: 500;            /* live's paragraph weight: Open Sans 500, every body line on the site */

    /* Corners: --radius-l 20px (photo frames, panels, the clinic cards),
     * --radius-m 12.5px, --radius-s 6.25px; the cards' 10px, the panels'
     * 15px and the pills' 8px follow --radius-base in the site layer. */
    --radius-base: 12.5;
    /* Accent rules and active states are 4px, not Dials' 3px */
    --border-width-l: 4px;

    /* Faces: Open Sans body, Cabin display, both taken from the live page's
     * computed styles; both are linked in each page's <head>. */
    --font-body: 'Open Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-heading: 'Cabin', Georgia, serif;
    --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ── The tertiary group ───────────────────────────────────────────────────
 * A third brand colour, typically doing button and CTA work, that is neither
 * a tint of the brand nor a status colour (practices routinely have one:
 * "Button Brown", "Morning Orange"). Dials has no third brand group, so the
 * template adds one with the same five roles, worked out the way Dials v0.2.0
 * works out its own groups (each formula is Dials' brand formula with the
 * tertiary colour in it), from public tokens only. Set --tertiary above;
 * never set these. class="is-tertiary" points --solid and friends at it,
 * like .is-secondary. Declared on bands too, so a band's group follows the
 * band's own scheme.
 *
 *   --tertiary-on-soft  the fill, moved only as far as 4.5:1 needs on the
 *                       least contrasting of its soft tint, --surface-lowered
 *                       and --surface-raised; a colour that passes is kept
 *   --tertiary-line     the dial, moved only as far as 3:1 needs, the same way
 *
 * Dials carries the numbers those two need in its internal --dl-* plumbing,
 * which nothing outside Dials may read, so the template works the same
 * numbers out again from public tokens in its own --tpl-* properties: the
 * luminance of --surface-lowered and --surface-raised (Dials' --dl-surfaces-y)
 * and of the soft tint, and the colour carrying its target. They are the
 * template's plumbing: never use or set a --tpl-* property anywhere else. */
:root, [data-dials], .is-light, .is-dark {
    --tpl-tertiary-base:  oklch(from var(--tertiary) calc(l + (var(--fill-lightness) - l) * var(--balance)) c h);
    --tertiary-solid:     light-dark(var(--tpl-tertiary-base), oklch(from var(--tpl-tertiary-base) calc(l + var(--dark-lift)) c h));
    --tertiary-on-solid:  color(from var(--tertiary-solid) srgb-linear calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) calc(clamp(0, (clamp(0.175, var(--white-text-until), 0.18333) - (0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))) * 1000000, 1)) / 1);
    --tertiary-soft:      oklch(from color-mix(in oklab, light-dark(oklch(from var(--tertiary-solid) max(l, 0.7) c h), oklch(from var(--tertiary-solid) min(l, 0.6) c h)) var(--tint-strength), oklch(from var(--surface) l 0 h)) l calc(c * var(--tint-vividness)) h);
    --tpl-surfaces-y:     color-mix(in srgb-linear, color(from var(--surface-lowered) srgb-linear 0 calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1)) 0), color(from var(--surface-raised) srgb-linear 0 0 calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1))));
    --tpl-tertiary-under: color-mix(in srgb-linear, color(from var(--tertiary-soft) srgb-linear calc(0.2126 * clamp(0, r, 1) + 0.7152 * clamp(0, g, 1) + 0.0722 * clamp(0, b, 1)) 0 0), var(--tpl-surfaces-y));
    --tpl-tertiary-text:  color-mix(in srgb-linear, color(from var(--tpl-tertiary-base) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--tpl-tertiary-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (4.5 + 0.1) - 0.05), 1))), color(from var(--tpl-tertiary-under) srgb-linear 0 0 0 / calc(clamp(0, (4.5 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
    --tpl-tertiary-line:  color-mix(in srgb-linear, color(from var(--tertiary) srgb-linear clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1) / 1), light-dark(color(from var(--tpl-tertiary-under) srgb-linear 0 0 0 / calc(clamp(0, 3 * ((min(2 * r, 4 * g, 4 * b) + 0.05) / (3 + 0.1) - 0.05), 1))), color(from var(--tpl-tertiary-under) srgb-linear 0 0 0 / calc(clamp(0, (3 + 0.1) * (max(2 * r, 4 * g, 4 * b) + 0.05) - 0.05, 1)))));
    --tertiary-on-soft:   light-dark(color(from var(--tpl-tertiary-text) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--tpl-tertiary-text) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));
    --tertiary-line:      light-dark(color(from var(--tpl-tertiary-line) srgb-linear calc(r * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(g * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) calc(b * 2 * alpha * min(1, (2 * alpha - 1) / 3 / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / 1), color(from color(from var(--tpl-tertiary-line) srgb-linear min(1, r * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, g * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) min(1, b * 2 * alpha * max(1, (2 * alpha - 1) / max(0.000001, 2 * alpha * (0.2126 * r + 0.7152 * g + 0.0722 * b)))) / alpha) srgb-linear calc(r + (1 - r) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(g + (1 - g) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) calc(b + (1 - b) * clamp(0, (2 * alpha - 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) / max(0.000001, 1 - (0.2126 * r + 0.7152 * g + 0.0722 * b)), 1)) / 1));
}
.is-tertiary { --solid: var(--tertiary-solid); --on-solid: var(--tertiary-on-solid); --soft: var(--tertiary-soft); --on-soft: var(--tertiary-on-soft); --line: var(--tertiary-line); }
/* The tertiary group in older browsers: without relative colour or
 * light-dark() (iOS 16 and 17, Safari before 18, Chrome and Edge before 123,
 * Firefox before 128) the derivation above cannot be worked out, and Dials'
 * own fallback covers only Dials' groups. So, the way Dials' fallback does
 * its groups, under the same condition and with the same selectors as the
 * derivation: the five roles again with color-mix(in oklab, ...) alone, from
 * --tertiary and the paper (--surface) and ink (--text-strong) Dials'
 * fallback has already worked out. As in Dials v0.2.0's fallback, on-soft is
 * the colour mixed 26% into ink and the line 40% into ink; neither can move
 * only as far as it needs there, so both over-shoot for most colours. Text
 * on the fill is a fixed white, with the fill pulled towards black as Dials
 * pulls --brand (72%), so it keeps 4.5:1. A site with a very light
 * --tertiary checks it: check-contrast.mjs --fallback. */
@supports not ((color: oklch(from red l c h)) and (color: light-dark(red, red))) {
    :root, [data-dials], .is-light, .is-dark {
        --tertiary-solid:    color-mix(in oklab, var(--tertiary) 72%, black);
        --tertiary-on-solid: white;
        --tertiary-soft:     color-mix(in oklab, var(--tertiary) var(--tint-strength), var(--surface));
        --tertiary-on-soft:  color-mix(in oklab, var(--tertiary) 26%, var(--text-strong));
        --tertiary-line:     color-mix(in oklab, var(--tertiary) 40%, var(--text-strong));
    }
}

/* The lime in older browsers. The template's tertiary fallback pulls the
 * fill 72% towards black and puts white on it, which suits a dark third
 * colour; on this light lime it gives an olive that fails white text
 * (mf-websites#438). Here the fill stays the lime with black on it, as the
 * modern browsers paint it (Dials' own fallback rule: a fixed white or
 * black on-solid). */
@supports not ((color: oklch(from red l c h)) and (color: light-dark(red, red))) {
    :root, [data-dials], .is-light, .is-dark {
        --tertiary-solid: var(--tertiary);
        --tertiary-on-solid: black;
    }
}

/* ── The template's own tokens ────────────────────────────────────────────
 * What Dials does not cover: the measure, the grid, the shared control
 * corner, the tap target, layers and motion. None of them is a colour, a text
 * size or a space size. Line height is Dials' --leading; weights and letter
 * spacing are written on the elements that use them, as plain numbers and em
 * (the template's old --leading-*, --tracking-* and --weight-* are in "Old
 * names" below). */
:root {
    /* --- Weight -------------------------------------------------------- */
    /* THREE WEIGHTS, DELIBERATELY: 400 body, 600 emphasis (nav, labels,
     * buttons, eyebrows, strong) and 700 headline. A fourth needs a reason:
     * the face has a visibly distinct cut AND the three are not creating
     * enough contrast. A flat hierarchy is almost always a spacing or size
     * problem, not a weight problem. */

    /* --- Measure ------------------------------------------------------- */
    --measure: 65ch;                 /* body copy, where a container asks for it (.measure) */
    --measure-tight: 45ch;           /* card and caption copy */

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

    /* --- Corners beyond Dials' three ----------------------------------- */
    --radius-xs: calc(var(--radius-base) * 0.333px);  /* tags, inline chips, the focus ring: a third of --radius-m, so it follows --radius-base */
    --radius-round: 50%;                   /* avatars */
    --control-radius: var(--radius-s);     /* buttons AND fields: a site sets this once, both follow */

    /* --- Touch targets ------------------------------------------------- */
    /* The smallest box a finger hits reliably: 44px (WCAG 2.5.5, Apple's
     * HIG). A fixed dimension rather than spacing, so it does not scale. */
    --target-min: 2.75rem;

    /* --- Inset shadows, from Dials' --shadow-color ------------------------ */
    --shadow-inner-s: inset 0 1px 2px 0 var(--shadow-color);
    --shadow-inner-m: inset 0 2px 6px 0 var(--shadow-color);

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

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

/* ═══ Old names ═══ aliases:begin ═══════════════════════════════════════
 * The template's token names before Dials (#426), each pointing at the Dials
 * token that replaces it, so markup, the Form controls section and any site
 * layer written against them keep working until #427 migrates the live
 * sites. NEVER use one in new work: use the name on the right. Delete this
 * whole block (down to aliases:end) once nothing reads any of them.
 *
 * Declared on [data-dials] and the .is-light/.is-dark bands as well as
 * :root, so a re-themed scope's or a band's aliases follow its own dials and
 * scheme, as Dials' own tokens do (its fallback works them out again there). Names Dials took over with a new meaning are NOT
 * here: --surface is now the PAGE (the old raised --surface is
 * --surface-raised), --secondary is the second brand colour's dial (it used
 * to be its fill: that is --secondary-solid), --accent is that dial's old
 * Dials name (deprecated in Dials v0.2.0: never set it), --success/--warning/
 * --danger/--info/--tertiary are dials (the fill is --success-solid ...), and --border, --border-strong, --space-*,
 * --radius-s/m/l, --shadow-* and --font-* are Dials' own. The --u-*,
 * --palette-*, --hue-*, --chroma-*, --l-* and --scheme dials are gone: set
 * the Dials dials instead. */
:root, [data-dials], .is-light, .is-dark {
    --primary: var(--brand-solid);
    --primary-hover: light-dark(oklch(from var(--brand-solid) calc(l - 0.07) c h), oklch(from var(--brand-solid) calc(l + 0.07) c h));
    --primary-light: oklch(from var(--brand-solid) calc(l + 0.11) c h);
    --primary-muted: color-mix(in oklab, var(--brand-solid) 15%, var(--surface));
    --primary-pale: var(--brand-soft);
    --on-primary: var(--brand-on-solid);
    --secondary-hover: light-dark(oklch(from var(--secondary-solid) calc(l - 0.07) c h), oklch(from var(--secondary-solid) calc(l + 0.07) c h));
    --secondary-light: oklch(from var(--secondary-solid) calc(l + 0.11) c h);
    --secondary-pale: var(--secondary-soft);
    --on-secondary: var(--secondary-on-solid);
    --tertiary-hover: light-dark(oklch(from var(--tertiary-solid) calc(l - 0.07) c h), oklch(from var(--tertiary-solid) calc(l + 0.07) c h));
    --tertiary-pale: var(--tertiary-soft);
    --on-tertiary: var(--tertiary-on-solid);
    --accent-dark: var(--primary-hover);
    --accent-pale: var(--brand-soft);
    --success-pale: var(--success-soft);
    --warning-pale: var(--warning-soft);
    --danger-pale: var(--danger-soft);
    --info-pale: var(--info-soft);
    --ink-strong: var(--text-strong);
    --ink: var(--text);
    --ink-mid: var(--text-muted);
    --ink-soft: var(--text-quiet);
    --bg: var(--surface);
    --on-bg: var(--text);
    --on-surface: var(--text);
    --step--2: var(--size--2);
    --step--1: var(--size--1);
    --step-0: var(--size-0);
    --step-1: var(--size-1);
    --step-2: var(--size-2);
    --step-3: var(--size-3);
    --step-4: var(--size-4);
    --step-5: var(--size-5);
    --step-6: var(--size-6);
    --step-7: var(--size-7);
    --step-8: var(--size-8);
    --border-thin: var(--border-width-s);
    --border-medium: var(--border-width-m);
    --border-thick: var(--border-width-l);

    /* The template's type ladder before Dials v0.3 (#436), FROZEN at its old
     * values, so a site layer written against it renders exactly as it did.
     * They do not follow Dials, and the template reads none of them: line
     * height is var(--leading), and weights and letter spacing are plain
     * values on each element. check-system.sh accepts these values only
     * exactly as written here. */
    --weight-400: 400;
    --weight-600: 600;
    --weight-700: 700;
    --leading-xs: 1.05;
    --leading-s: 1.18;
    --leading-m: 1.3;
    --leading-l: 1.5;
    --leading-xl: 1.6;
    --tracking-xs: -0.02em;
    --tracking-s: -0.01em;
    --tracking-m: 0;
    --tracking-l: 0.04em;
    --tracking-xl: 0.08em;
}
/* ═══ aliases:end (Old names) ═══════════════════════════════════════════ */


/* ═══════════════════════════════════════════════════════════════════════
 * 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: the base layer's body rule, from --leading-body */
}

/* 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(--size-0);
    font-weight: 400;
    line-height: var(--leading-body);   /* a number, so it inherits as one; --leading is a length */
    color: var(--text);
    background: var(--surface);
}

/* 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: 700;
    line-height: var(--leading);        /* for each heading's own size: on the heading, never inherited */
    color: var(--text-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(--size-5); }
h2, .h2 { font-size: var(--size-4); }
h3, .h3 { font-size: var(--size-3); }
h4, .h4 { font-size: var(--size-2); }
h5, .h5 { font-size: var(--size-1); }
h6, .h6 {
    font-size: var(--size-0);
    letter-spacing: 0.03em;   /* capitals */
    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(--on-soft);   /* coloured text on the page */
}

/* 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(--size-1);
    line-height: var(--leading);
    color: var(--text-muted);
}

/* Small label above a heading. */
.eyebrow {
    display: block;
    margin-bottom: var(--space-2xs);
    font-size: var(--size--1);
    font-weight: 600;
    line-height: var(--leading);
    letter-spacing: 0.03em;   /* capitals */
    text-transform: uppercase;
    color: var(--on-soft);
}

small, .text-small { font-size: var(--size--1); line-height: var(--leading); }

strong, b { font-weight: 600; }

a {
    color: var(--link);
    text-decoration-thickness: var(--border-width-s);
    text-underline-offset: 0.15em;
    transition: color var(--duration-fast) var(--ease-out);
}
a:hover { color: var(--link-hover); }

/* The focus ring lives in "Form controls & focus" below. */

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 {
    /* The quote bar is a quiet border in the group's colour: Dials' subtle
     * border pattern (tokens.md, "A subtle border in a group's colour"),
     * declared here rather than at :root so it follows an .is-* class on the
     * quote. --line itself is a strong 3:1 line since Dials v0.2.0; 30% of
     * it keeps the bar about as light as it was before (the pattern's
     * example is 40%: a step darker). Decoration: no contrast promised. */
    --quote-bar: color-mix(in oklab, var(--line) 30%, var(--border));
    padding-left: var(--space-m);
    border-left: var(--border-width-l) solid var(--quote-bar);
    color: var(--text-muted);
    font-style: italic;
}

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

code, kbd, samp, pre {
    font-family: var(--font-mono);
    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-raised) }`
 * 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(--size--1);
    line-height: var(--leading);
    color: var(--text-quiet);
}

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

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

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

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

/* ═══ 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 0px 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-width-s) solid <colour> and
 *   --field-radius: 0px (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 0px.
 * - Colours follow the band. The colour tokens are declared on the page
 *   AND on every .is-light/.is-dark band and [data-dials] scope, as Dials
 *   declares its own: a browser on Dials' fallback (no relative colour)
 *   works a token out once per scope, so declared on :root alone a field
 *   in a dark band kept the light page's border and ring. A site that
 *   changes a field COLOUR sets it on the same four selectors, after this
 *   section (:root, [data-dials], .is-light, .is-dark { --field-...: ... }),
 *   or a band keeps the default. Sizes are set on :root only.
 * - A panel on a ground that is not a Dials surface (a brand fill) re-sets
 *   the leaf colour tokens on the container, never the rules:
 *     .brand-panel {
 *         --focus-ring: var(--brand-on-solid);
 *         --field-border: var(--brand-on-solid);
 *     }
 *   --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(--size-0), 1rem);  /* never below 16px, or iOS zooms the page on focus */
    --field-leading: var(--leading);              /* Dials' leading, worked out at the field's own size */
    --field-weight: 400;                          /* one weight wherever the field sits */
    --field-label-weight: 600;                    /* the label's weight: the site's emphasis weight */
    --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-border-w: var(--border-width-s);
    /* 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-w: var(--border-width-m);        /* >= --field-border-w, so the ring covers the border */
}

/* The colours, on the bands too (see above). */
:root, [data-dials], .is-light, .is-dark {
    --field-bg: var(--surface-raised);            /* fields sit on the raised surface, as cards do */
    --field-ink: var(--text);
    --field-border: var(--border-strong);         /* Dials' control border: 3:1 on every surface */
    --field-border-hover: var(--text-quiet);
    --field-placeholder: var(--text-quiet);
    --focus-ring: var(--focus);                   /* Dials' focus ring: >= 3:1 on every surface, light and dark */
}

/* 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(--size--1);
    font-weight: var(--field-label-weight);
    line-height: var(--leading);
    color: var(--text-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(--brand-solid); }

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; every one is at least
 * --target-min (44px) tall, the tap target. A bare <button> is
 * reset above, not styled, because most of them are menu and dropdown
 * triggers rather than visual buttons. */
.btn,
.mf-search__submit,
.mf-search-overlay__close {
    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(--size-0);   /* one step above the template's --size--1, the owner's choice (4 Nov 2026) */
    font-weight: 600;
    line-height: var(--leading);        /* at each button size's own font size (.btn--sm, .btn--lg) */
    letter-spacing: 0;
    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-width-s) 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(--solid);
    color: var(--on-solid);
}
/* Hover and pressed mix the fill away from its text colour (Dials' --mix-*),
 * so they work on every group: <a class="btn btn--primary is-tertiary">. */
.btn--primary:hover { background: color-mix(in oklch, var(--solid), var(--mix-hover)); color: var(--on-solid); }
.btn--primary:active { background: color-mix(in oklch, var(--solid), var(--mix-active)); color: var(--on-solid); }

.btn--secondary {
    background: transparent;
    border-color: var(--solid);
    color: var(--on-soft);
}
.btn--secondary:hover { background: var(--soft); color: var(--on-soft); }

.btn--ghost {
    background: transparent;
    color: var(--text-muted);
}
.btn--ghost:hover { background: var(--soft); color: var(--on-soft); }

/* Site ghost button: an outlined pill in the dark violet, matching
 * .btn--primary's shape so the two sit together as a pair. Declared after
 * .btn--primary so a `btn btn--primary btn--ghost` combination resolves to
 * the ghost treatment. */
.btn--ghost,
.mf-search-overlay__close {
    background: transparent;
    color: var(--violet-deep);
    border: var(--border-width-m) solid var(--violet-deep);
    /* The 2px border comes out of the padding, so the box matches .btn--primary. */
    padding: calc(var(--space-xs) - var(--border-width-m)) calc(var(--space-l) - var(--border-width-m));
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.btn--ghost:hover,
.mf-search-overlay__close:hover {
    background: var(--violet-deep);
    color: var(--secondary-on-solid);
}

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

/*
 * ON A BRAND-COLOURED GROUND
 *
 * A dark band is class="is-dark" on the section: Dials works every token out
 * again in the dark scheme, so the buttons above need nothing more. On a band
 * painted with a brand fill (background: var(--solid)) they invert instead:
 * the solid button goes to the raised surface, the outline picks up a
 * translucent edge in the fill's text colour. Put .on-dark on the button or
 * any ancestor.
 */
.on-dark .btn--primary,
.btn--primary.on-dark {
    background: var(--surface-raised);
    color: var(--on-soft);
}

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

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

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

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

.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-raised);
    border: var(--border-width-s) 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 gradient
 * is Dials' band pattern (tokens.md, "Gradients are patterns"): from one
 * fill to another, decoration only, so no text is ever set on it.
 * The <img> has onerror="this.style.display='none'" which hides
 * the broken image, revealing this CSS background underneath.
 *
 * Derived from the site's own brand fill so a missing photo reads as part of
 * this practice rather than as a stray swatch.
 */
:root, [data-dials], .is-light, .is-dark {
    --avatar-shade: color-mix(in oklab, var(--brand-solid) 85%, black);   /* the avatar gradient's darker end: the brand fill, a step darker. color-mix() rather than relative colour, so Dials' fallback browsers draw it too */
}

.doctor-avatar {
    position: relative;
    aspect-ratio: 4 / 5;
    overflow: hidden;
    border-radius: var(--radius-s);
    background: linear-gradient(135deg, var(--avatar-shade), var(--brand-solid));
    display: flex;
    align-items: center;
    justify-content: center;
}

/* The silhouette is an icon on the brand fill, so it is drawn in the fill's
 * own text colour, --brand-on-solid, through a mask (the shape only), and
 * keeps 3:1 in light and dark. A white silhouette fell to 2.8:1 on a dark
 * page, where the fill is lifted (mf-websites#431). */
.doctor-avatar::after {
    content: "";
    position: absolute;
    width: 40%;
    height: 40%;
    background-color: var(--brand-on-solid);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='black' 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") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='black' 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") center / contain no-repeat;
}

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

/*
 * Mediflare footer logo: the footer is a dark violet gradient, so it is the
 * white (inverted) logo; the dark one stays hidden.
 */
.mf-logo-light { display: none; }
.mf-logo-dark { display: inline; }
.footer-light .mf-logo-light { display: inline; }
.footer-light .mf-logo-dark { display: none; }

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

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

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

:root {
    /* ── The kit's colours, named as the kit names them ───────────────
     * Each is declared once here, from the dials, so the rules below read
     * as before:
     *   --violet       #9F7CF0  the brand fill: eyebrows, icons, the light
     *                           end of the violet gradients
     *   --violet-deep  #4A2C5E  the secondary fill: headings, the violet
     *                           grounds, the focus ring
     *   --lime         #C6DE70  the tertiary fill: every button, ticks
     *   --indigo       #6059A6  the kit's "Button": inline links, the nav,
     *                           the dark end of the top bar and footer.
     *                           The violet, darker, greyer and a touch
     *                           bluer, worked out from the brand fill, so
     *                           it moves with --brand.
     *   --violet-wash  #ECE5FF  the alternating bands: the violet at 19% on
     *                           the raised surface (#ECE7FD)
     *   --sky          #D9E6F0  the doctors hero's wash, sampled from the
     *                           photograph's own sky: the info blue at 18%
     *                           on the raised surface (#DAE7EF)
     * Older browsers get the same colours from the dials themselves (the
     * block after this one). */
    --violet: var(--brand-solid);
    --violet-deep: var(--secondary-solid);
    --lime: var(--tertiary-solid);
    --indigo: oklch(from var(--brand-solid) calc(l - 0.1631) calc(c - 0.0487) calc(h - 9.966));
    --violet-wash: color-mix(in oklab, var(--violet) 19%, var(--surface-raised));
    --sky: color-mix(in oklab, var(--info-solid) 18%, var(--surface-raised));
    /* Two opaque tints of the wash: live's telehealth band (the wash at 45%
     * over cream) and the ground behind the clinic maps while they load. */
    --violet-wash-pale: color-mix(in srgb, var(--violet-wash) 45%, var(--surface));
    --map-ground: color-mix(in oklab, var(--violet-wash) 82%, var(--surface-raised));

    /* Live's body inks are translucent black rather than a grey, so the
     * paragraph colour takes whatever ground it sits on. Four measured
     * strengths, each named for where live uses it. */
    --ink-body: color-mix(in srgb, black 68%, transparent);   /* p, lists */
    --ink-lede: color-mix(in srgb, black 72%, transparent);   /* services lede */
    --ink-sub: color-mix(in srgb, black 75%, transparent);    /* subheads */
    --ink-legal: color-mix(in srgb, black 78%, transparent);  /* legal headings */

    /* Form controls & focus (the template section's tokens). The contact
     * form's fields are live's underlines on the translucent card, flush
     * left; the underline turns violet on focus under the one ring.
     * Underline mode: --field-radius is 0px (an underline has no corners);
     * the buttons keep --control-radius, the pill. */
    --field-h: calc(1lh + var(--space-s) * 2 + var(--border-width-s));   /* live's padded line: 15/16px of air above and below */
    --field-textarea-h: 9rem;
    --field-leading: var(--leading-body);
    --field-pad-block: var(--space-s);
    --field-pad-inline: 0px;           /* a length, not 0: the select chevron's calc() needs one */
    --control-radius: var(--radius-pill);   /* the lime pill buttons */
    --field-radius: 0px;
    --field-border-w: 0;
    --field-border-bottom: var(--border-width-s) solid var(--field-border);
    --field-focus-outline: none;                                                      /* focus is the underline, not a ring (owner, 2026-10-06) */
    --field-focus-border-bottom: var(--focus-ring-w) solid var(--focus-ring);         /* thickens to 2px in the ring colour: cream on the violet panels */

    /* Live's own corners, from --radius-base (12.5): 10px on cards and
     * avatars, 15px on photo frames and panels (and 16px on the services
     * cards, folded in here), 8px on the nav and search pills. 20px is
     * Dials' --radius-l already. */
    --radius-card: calc(var(--radius-base) * 0.8px);
    --radius-panel: calc(var(--radius-base) * 1.2px);
    --radius-chip: calc(var(--radius-base) * 0.64px);

    /* Two more layers: the hero media sits one below its own wash (-2), and
     * the footer landscape sits at 0 so the content can ride above it. */
    --layer-sunken: -2;
    --layer-flat: 0;

    /* Fixed geometry, not rhythm: the floating header pill is 120px tall and
     * sits 20px under the top bar, and the whole header overlaps the band
     * below it by that 140px. Every hero repays it. */
    --header-bar: 120px;
    --header-overlap: 140px;

    /* The half-card lift ramp, shared by every straddling card: 0 below
     * 48rem, easing in to 1 by 75rem. Defined once here rather than in four
     * rules - see "Fluid half-card lift" below. */
    --lift-fraction: clamp(0, (100vw - 48rem) / 27rem, 1);

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

/* The field colours, on the page and on any band, as the Form controls
 * section declares its own. A field is an underline: the dark violet at
 * 70% into the cream (5:1 on the page, 3.3:1 at worst on the contact card
 * over its photograph; it was a translucent 28%, 1.6:1 there, too faint to
 * find a field by), 85% on hover; the placeholder is Dials' quiet text (it
 * was the ink at 58%, 3.5:1 on the card); the ring is the dark violet. The site is light only, but a dark page or band would keep
 * Dials' own underline and ring (light-dark()), so nothing here is ever
 * drawn dark on dark. */
:root, [data-dials], .is-light, .is-dark {
    --field-bg: var(--surface);
    --field-border: light-dark(color-mix(in oklab, var(--violet-deep) 70%, var(--surface)), var(--border-strong));
    --field-border-hover: light-dark(color-mix(in oklab, var(--violet-deep) 85%, var(--surface)), var(--text-quiet));
    --focus-ring: light-dark(var(--violet-deep), var(--focus));
}
/* The same in older browsers, which have no light-dark(): the site's on
 * the page, Dials' own in a dark band. */
@supports not ((color: oklch(from red l c h)) and (color: light-dark(red, red))) {
    :root, [data-dials], .is-light {
        --field-border: color-mix(in oklab, var(--violet-deep) 70%, var(--surface));
        --field-border-hover: color-mix(in oklab, var(--violet-deep) 85%, var(--surface));
        --focus-ring: var(--violet-deep);
    }
    .is-dark {
        --field-border: var(--border-strong);
        --field-border-hover: var(--text-quiet);
        --focus-ring: var(--focus);
    }
}
/* The contact form sits on a translucent card over the hero photograph,
 * and its fields stay see-through, as live draws them: only the underline
 * shows. Measured on the card as it renders, where the photograph darkens
 * the ground: the underline 3.3:1 at worst, the focus underline 7.7:1, and
 * the placeholder, Dials' muted text here (the quiet text is 4.3:1 on the
 * darkest patch), 5.2:1. */
.contact-hero__card {
    --field-bg: transparent;
    --field-placeholder: var(--text-muted);
}

/* The kit's colours in older browsers (no relative colour: iOS 16 and 17,
 * Safari before 18, Chrome and Edge before 123, Firefox before 128), under
 * Dials' own fallback condition. Dials' fallback pulls every fill towards
 * black so it can carry white text, which would darken both violets; the
 * site sets its own text on each, so here each is the dial as set, and the
 * indigo and the sky are mixed from the dials. (The wash follows --violet.) */
@supports not ((color: oklch(from red l c h)) and (color: light-dark(red, red))) {
    :root {
        --violet: var(--brand);
        --violet-deep: var(--secondary);
        --indigo: color-mix(in oklab, var(--brand) 75%, black);
        --sky: color-mix(in oklab, var(--info) 18%, var(--surface-raised));
    }
}

/* Images: live's photos carry a 12px corner and sit on a white plate while
 * they load; logos, icons and inline drawings carry neither. (The template
 * dropped both defaults; this site keeps them.) */
img {
    border-radius: var(--radius-m);
    background: var(--surface-raised);
}
img[class*="logo"], img[class*="icon"], .logo img, svg {
    border-radius: 0;
    background: none;
}
/* Opt out where a radius is wrong: full-bleed art, decorative crops. */
img.is-flush, .is-flush img { border-radius: 0; background: none; }

/* --- Type, as measured on live --------------------------------------
 * Headings: Cabin 700 on a 1.2 line and -0.02em at every size, as live
 * sets them (Dials' size curve would loosen the smaller ones); bold runs
 * at 700, the heading weight, not the nav's 600; ledes on a 1.3 line;
 * buttons on a 1.2 line. */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    line-height: var(--leading-headline);
    letter-spacing: var(--tracking-heading);
}
h5, .h5, h6, .h6 { line-height: var(--leading-snug); }
h6, .h6 { letter-spacing: 0; }
strong, b { font-weight: 700; }
.lede { line-height: var(--leading-snug); }



/* Inline links. The template paints them --primary, which is now the kit's
 * own violet #9F7CF0 - 3.1:1 on the cream, under the 4.5:1 AA floor for body
 * text. They take --indigo instead (5.97:1), the same a11y call the nav
 * already makes. The published links were #7A5BBE, a colour the template
 * derived from the old clamped primary and never one the kit names. */
a { color: var(--indigo); }
a:hover { color: var(--violet-deep); }

/* Display type: 74.25px Cabin 700 in Dark Violet on the live hero. */
.display {
    font-family: var(--font-heading);
    font-size: var(--size-5);
    font-weight: 700;
    line-height: var(--leading-hero);
    color: var(--violet-deep);
}

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

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

p { color: var(--ink-body); font-weight: var(--weight-copy); }

/* Buttons: lime pill (--control-radius), dark-violet label, 15px/40px at 1440. */
.btn--primary,
.mf-search__submit {
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: var(--lime);
    color: var(--violet-deep);
    padding: var(--space-xs) var(--space-l);
    font-weight: 700;
    border: 0;
}
.btn--primary:hover,
.btn--primary:active,
.mf-search__submit:hover {
    background: color-mix(in oklab, var(--lime) 88%, black);
    color: var(--violet-deep);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* ── Top bar + header ─────────────────────────────────────────────────
 * The source floats a white pill (1380x120, radius 1000px) over the hero
 * video, with a slim transparent strip of hours and phone above it. */
.topbar {
    position: relative;
    z-index: var(--layer-nav);
    background: linear-gradient(90deg, var(--indigo) 0%, var(--violet-deep) 100%);
    color: var(--secondary-on-solid);
}
.topbar__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-s);
    /* 38px on the source, with the text optically centred rather than
     * sitting on the padding box - hence the even padding and the flex
     * centring rather than a line-height. */
    min-height: 38px;
    padding-block: var(--space-3xs);
}
/* The base p rule sets margin-bottom:30px, which inflated this bar to 58px
 * and pushed the ink to the top: flex centring centres the box, and the box
 * included that margin. */
.topbar__hours,
.topbar__contact { margin: 0; line-height: 1; }
/* The hours arrive as Rails' <table class="hours-table">, set here as one
 * line of "Mon–Fri 8:00am–5:00pm | Sat ..." to match the bar. */
.topbar__hours { color: var(--secondary-on-solid); font-family: var(--font-heading); font-size: var(--size--1); }
.topbar__hours :is(table, tbody, tr, td) { display: inline; width: auto; margin: 0; padding: 0; border: 0; }
.topbar__hours td + td::before { content: " "; }
/* A group never breaks inside itself ("Mon–" / "Fri"); the line wraps between groups. */
.topbar__hours tr { display: inline-block; white-space: nowrap; }
.topbar__hours tr + tr::before { content: "|"; margin-inline: var(--space-2xs); }
.topbar p { color: var(--secondary-on-solid); font-family: var(--font-heading); font-size: var(--size--1); }
.topbar__hours,
.topbar__contact { display: flex; align-items: center; gap: var(--space-s); }
.topbar svg { width: 17px; height: 17px; flex: none; vertical-align: -3px; }
.topbar a,
.topbar__fax {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3xs);
    color: var(--secondary-on-solid);
    text-decoration: none;
    min-height: 0;
    padding-block: 0;
}
.topbar a:hover { text-decoration: underline; }

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

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

.nav__item { position: relative; }
.nav__menu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: var(--layer-overlay);
    display: none;
    min-width: 13rem;
    padding: var(--space-3xs);
    list-style: none;
    margin: 0;
    background: var(--surface);
    border-radius: var(--radius-m);
    box-shadow: 0 6px 22px color-mix(in srgb, var(--violet-deep) 16%, transparent);
}
.nav__item:where(:hover, :focus-within) .nav__menu,
.nav__menu[data-open] { display: block; }
.nav__menu a { width: 100%; }

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

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

/* The bar's tablet size, at the source's own 68rem. */
@media (max-width: 68rem) {
    .site-header__bar { min-height: 88px; border-radius: var(--radius-l); }
    .site-logo img { height: 64px; }
}

/* The menu folds behind the button up to 1349px, not 68rem: from 68rem to
 * about 1290px the open menu, Book Appointment and the logo never fitted in
 * the pill together, and the logo was squeezed to nothing (3px wide at
 * 1089px); with the search trigger beside them they fit from 1350px. The
 * bar keeps its desktop size above 68rem, so its height does not change.
 * partials/scripts.html closes an open menu past this width (84.375rem). */
@media (max-width: 84.3125rem) {
    .nav__burger { display: inline-flex; }
    .nav > .btn { display: none; }

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

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

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

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

/* ── Site search ──────────────────────────────────────────────────────
 * mediflare.js writes the box unstyled; every rule here is this site's, on
 * its tokens. One placement at every width: one button
 * (.site-search__trigger, data-mf-search-open) opens the one overlay
 * mediflare.js builds (.mf-search-overlay). From 768px up the trigger is
 * drawn as a search field (the --field-* tokens: this site's fields are an
 * underline) and the overlay is a centred card over a dimmed page; on
 * phones (767px and under) the trigger is a bare magnifier beside the menu
 * button and the overlay fills the screen. Never inside the menu: search
 * behind the hamburger is search most patients never find. The overlay and
 * the results list are styled ONLY through :not([hidden]): a display of
 * their own would override [hidden] and they would never close. Search
 * joins the lime .btn--primary, Close the outlined .btn--ghost. */

/* The trigger, drawn as a field so it matches the box it opens: the same
 * underline, the same clear ground, the same type. In the pill's nav,
 * between the menu and Book Appointment; where the menu folds away it sits
 * beside the menu button. */
.site-search__trigger {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs);
    min-block-size: var(--field-h);
    padding-block: 0;
    padding-inline: var(--field-pad-inline) var(--space-l);
    font-size: var(--field-font-size);
    font-weight: var(--field-weight);
    line-height: var(--field-leading);
    white-space: nowrap;
    color: var(--field-placeholder);
    background: 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);
    transition: color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);
}
.site-search__trigger svg { flex: none; }
/* 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(--violet-deep); border-color: var(--field-border-hover); }

/* With the menu open in the pill (1350px up) the bar is tight even at its
 * widest: the trigger is the magnifier alone, a 44px square, and the menu's
 * links close up a step, so the logo keeps its full size (measured from
 * 1350 to 1920, every 20px and +-1 at the edge: 17 to 60px to spare). */
@media (min-width: 84.375rem) {
    /* The magnifier alone is an icon button, not a field, so it drops the
     * field's underline and takes the phone magnifier's look. */
    .site-search__trigger {
        justify-content: center;
        inline-size: var(--target-min);
        block-size: var(--target-min);
        min-block-size: 0;
        padding: 0;
        color: var(--violet-deep);
        border: 0;
        border-radius: var(--radius-chip);
    }
    .site-search__trigger:hover,
    .site-search__trigger[aria-expanded="true"] { color: var(--violet-deep); background: var(--violet-wash); }
    .site-search__text { display: none; }   /* the name is the aria-label */
    .nav__list { gap: var(--space-3xs); }
}

/* The box: the field and Search on one row, the status and results below. */
.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; }
/* Read out, not shown: the placeholder says what the field is. */
.mf-search__label {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.mf-search__status {
    margin: 0;
    font-size: var(--size--1);
    line-height: var(--leading-snug);
    color: var(--ink-body);
}
.mf-search__status:empty { display: none; }

/* Results: titles in the headings' dark violet, excerpts in the body ink,
 * matches marked in the band violet. */
.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);
    border-radius: var(--radius-chip);
    color: var(--ink-body);
    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(--ink-body); background: var(--violet-wash); }
.mf-search__link:hover .mf-search__title { text-decoration: underline; }
/* Inside a scrolling list an outset ring is clipped, so it sits inset. */
.mf-search__link:focus-visible { outline-offset: calc(-1 * var(--focus-ring-w)); }
.mf-search__title {
    display: block;
    font-family: var(--font-heading);
    font-weight: 700;
    line-height: var(--leading-headline);
    color: var(--violet-deep);
}
.mf-search__excerpt {
    display: block;
    margin-top: var(--space-3xs);
    font-size: var(--size--1);
    line-height: var(--leading-body);
    color: var(--ink-body);
}
.mf-search__excerpt mark {
    color: var(--violet-deep);
    background: var(--violet-wash);
    border-radius: var(--radius-xs);
}

/* Phones: full screen, cream, under the topbar's indigo. 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, so the
 * results run the full width. */
.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-s);
    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(--surface);
    border-block-start: var(--border-width-l) solid var(--indigo);
}
.mf-search-overlay__header { display: contents; }
.mf-search-overlay__close {
    grid-column: 1;
    grid-row: 1;
    align-self: center;
    position: relative;
    z-index: var(--layer-base);   /* above the box, which spans this cell too */
}
.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: center;   /* the underline field is taller than the two pills */
}
.mf-search--overlay .mf-search__input { grid-column: 2; grid-row: 1; }
.mf-search--overlay .mf-search__submit { grid-column: 3; grid-row: 1; }
.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));
}

/* From 768px the overlay is a centred card under a dimmed, lightly blurred
 * page (body::after, in the dark violet), growing with its results up to
 * the viewport, past which they scroll inside it. It refines the
 * full-screen rules above at equal specificity, so it must stay after them.
 * The card sits one layer above its backdrop: body::after comes after the
 * overlay in the tree, so at an equal z-index it would paint over it. Both
 * sit above the topbar and header (--layer-nav) and the menus
 * (--layer-overlay). */
@media (min-width: 48rem) {
    .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-m));
        max-inline-size: var(--measure);
        max-block-size: calc(100dvh - 2 * var(--space-3xl));
        margin-inline: auto;
        padding: var(--space-s) var(--space-m);
        border-radius: var(--radius-l);
        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(--violet-deep) 50%, transparent);
        backdrop-filter: blur(var(--space-3xs));
    }
}

/* Phones: the trigger is a bare 44px magnifier beside the menu button, in
 * its violet, with its hover. */
@media (max-width: 47.999rem) {
    .site-search__trigger {
        justify-content: center;
        inline-size: var(--target-min);
        block-size: var(--target-min);
        min-block-size: 0;
        padding: 0;
        color: var(--violet-deep);
        border: 0;
        border-radius: var(--radius-chip);
    }
    .site-search__trigger:hover,
    .site-search__trigger[aria-expanded="true"] { color: var(--violet-deep); background: var(--violet-wash); }
    .site-search__text { display: none; }   /* the name is the aria-label */
}

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

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

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

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

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

/* The Facebook mark sits under the blurb in the source, in the pale
 * lavender rather than the lime used on the contact icons. */
.site-footer__social a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--violet-wash);
    min-height: 0;
    padding-block: 0;
}
.site-footer__social a:hover { color: var(--lime); }
.site-footer__social svg { width: 25px; height: 25px; display: block; }
.site-footer__value {
    color: var(--secondary-on-solid);
    font-weight: 700;
    margin-bottom: var(--space-s);
}
.site-footer__value a { font-weight: 700; }
/* Rails' hours table: day left, time right, no rules. */
.site-footer__hours table { width: auto; margin: 0; }
.site-footer__hours td { padding: 0 var(--space-2xs) 0 0; border: 0; color: var(--secondary-on-solid); }
.site-footer__hours td:last-child { padding-right: 0; }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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



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

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

/* 58px on the source, against the homepage hero's 74.25px: a step below
 * .display (--step-4, 51.6 at 1440) so the two heroes stay visibly different. */
.doc-hero__display {
    font-size: var(--size-4);
    margin-bottom: var(--space-s);
}

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

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

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

/* linear-gradient(#4A2C5E 0%, #9F7CF0 100%) at 10px radius on the source -
 * the deep violet at the top, the opposite direction to the homepage's
 * clinic cards. */
.locations-panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-l);
    background: linear-gradient(180deg, var(--violet-deep) 0%, var(--violet) 100%);
    border-radius: var(--radius-card);
    padding: var(--space-l) var(--space-xl);
    box-shadow: 0 8px 26px color-mix(in srgb, var(--violet-deep) 22%, transparent);
}
.locations-panel__copy { flex: 1 1 32rem; }
.locations-panel__title {
    font-family: var(--font-heading);
    /* 41px on the source; --step-3 is 38.8 at 1440. */
    font-size: var(--size-3);
    font-weight: 700;
    line-height: var(--leading-headline);
    color: var(--secondary-on-solid);
    margin-top: 0;
    margin-bottom: var(--space-2xs);
}
/* The panel's ground is a saturated violet, so this copy takes the cream
 * rather than the base rgba(0,0,0,.68) body ink, which would vanish. */
.locations-panel__body {
    color: var(--surface);
    font-size: var(--size-0);
    line-height: var(--leading-snug);
}

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

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

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

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

.doctor-grid {
    display: grid;
    /* Three-up on a doubled track, so a short last row can be centred: a
     * lone card starts two tracks in, a lone pair one track in. The count is
     * whatever Rails holds, so this holds for any number of doctors. */
    grid-template-columns: repeat(6, minmax(0, 1fr));
    column-gap: var(--grid-gutter);
    row-gap: var(--space-xl);
}
.doctor-grid > * { grid-column: span 2; }
.doctor-grid > :last-child:nth-child(3n + 1) { grid-column: 3 / span 2; }
.doctor-grid > :nth-last-child(2):nth-child(3n + 1) { grid-column: 2 / span 2; }

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

@media (max-width: 62rem) {
    .doctors__head { grid-template-columns: 1fr; }
    .doctors__intro { justify-self: start; text-align: left; }
    .doctor-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .doctor-grid > :last-child:nth-child(3n + 1),
    .doctor-grid > :nth-last-child(2):nth-child(3n + 1) { grid-column: span 2; }
    .doctor-grid > :last-child:nth-child(2n + 1) { grid-column: 2 / span 2; }
}
@media (max-width: 40rem) {
    .doctor-grid { grid-template-columns: minmax(0, 1fr); }
    .doctor-grid > *,
    .doctor-grid > :last-child:nth-child(n),
    .doctor-grid > :nth-last-child(2):nth-child(n) { grid-column: auto; }
}

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

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

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

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

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

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

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


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

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

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

.new-patients {
    border-radius: var(--radius-card);
    overflow: hidden;
    background: var(--violet-wash);
    box-shadow: 0 18px 46px -28px color-mix(in srgb, var(--violet-deep) 55%, transparent);
}
.new-patients__media { aspect-ratio: 397 / 372; }
.new-patients__body { padding: var(--space-l); text-align: center; }
.new-patients__title {
    margin-top: 0;
    font-size: var(--size-2);
    color: var(--violet-deep);
}

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


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

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


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

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

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

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


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

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

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


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

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


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

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

.policy-split__copy h2 { margin-top: 0; font-size: var(--size-4); }
.policy-split__sub {
    margin-top: var(--space-l);
    font-size: var(--size-1);
    color: var(--ink-sub);
}

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

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


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


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

.legal__panel {
    /* Was clamp(space-m, 6vw, 90px): 24px on a phone, 86px at 1440. The
     * l-2xl pair is the scale's nearest ramp (32px to 80px). */
    padding: var(--space-2xl) var(--space-l-2xl);
    background: var(--surface);
    border-radius: var(--radius-l);
    box-shadow: 0 30px 70px -44px color-mix(in srgb, var(--violet-deep) 60%, transparent);
}

/* The source sets the page title in the full-strength violet, not the
 * dark violet the section headings use. */
.legal__title {
    margin-top: 0;
    font-size: var(--size-4);
    color: var(--violet);
}

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

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

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


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

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

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

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

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

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

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

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

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


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

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

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

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

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

.contact-detail__icon { display: block; margin-bottom: var(--space-s); }
.contact-detail__icon svg {
    width: 30px;
    height: 30px;
    color: var(--violet);
    display: block;
    margin-inline: auto;
}
.contact-detail__title {
    font-family: var(--font-heading);
    font-size: var(--size-2);
    font-weight: 700;
    color: var(--violet-deep);
    margin-bottom: var(--space-s);
}
.contact-detail__body { font-size: var(--size--1); line-height: var(--leading-body); }
/* Rails' hours table, centred in the column like the copy around it. */
.contact-detail__hours table { width: auto; margin: 0 auto; }
.contact-detail__hours td { padding: 0 var(--space-2xs); border: 0; color: var(--ink-body); font-weight: var(--weight-copy); }
.contact-detail__hours + .contact-detail__body { margin-top: var(--space-2xs); }
/* Was color:inherit / font-weight:inherit, which made the phone, fax and email
 * read as plain body text - the only links on the site that did not look like
 * links. They now take the same treatment as any other inline link. */
.contact-detail__body a,
.contact-detail__body .mf-email {
    color: var(--indigo);
    font-weight: 600;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
}
.contact-detail__body a:hover,
.contact-detail__body .mf-email:hover { color: var(--violet); }

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

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

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

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

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

.loc-card__map {
    margin-top: auto;
    border-radius: var(--radius-m);
    overflow: hidden;
    aspect-ratio: 330 / 230;
    background: var(--map-ground);
}
.loc-card__map iframe { width: 100%; height: 100%; border: 0; display: block; }

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* ── Narrow viewports ─────────────────────────────────────────────────
 * Every multi-column band collapses to one column. The two-up bands go
 * first at 62rem; the three-up grids go two-wide there and one-wide at
 * 40rem, so a phone never gets a 3-across grid of unreadable cards. */
@media (max-width: 62rem) {
    .newpat__panel {
        grid-template-columns: minmax(0, 1fr);
        /* The inverse of the lift ramp, as .policy-help: a full pull where the
         * lift is nothing, none where it is whole. A fixed pull stacked on the
         * partial lift and rode onto the hero's button at 989-992px. */
        margin-top: calc(-1 * var(--space-xl) * (1 - var(--lift-fraction)));
        text-align: left;
    }
    .afterhours__row,
    .telehealth__row,
    .allied__row,
    .billing__row { grid-template-columns: minmax(0, 1fr); }
    .afterhours__media { aspect-ratio: 16 / 11; }
    .allied__partners { grid-template-columns: minmax(0, 1fr); gap: var(--space-s); }
    .allied__partners-title { white-space: normal; }
    /* Two-up on a doubled track, so a lone last card centres. */
    .appt-features__grid,
    .svc-cards,
    .clinical__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    :is(.appt-features__grid, .svc-cards, .clinical__grid) > * { grid-column: span 2; }
    :is(.appt-features__grid, .svc-cards, .clinical__grid) > :last-child:nth-child(2n + 1) { grid-column: 2 / span 2; }
}

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

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

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

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


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

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

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

/* Full-bleed, flush grid. NO gap - the source runs the photographs edge to
 * edge, and a gap here would read as a different design entirely. */
.gallery-band { padding-block: 0; }
.gallery-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}
/* Three- and four-up on doubled tracks, so a short last row of tiles is
 * centred rather than left hanging off the left edge (Forrest Beach has six
 * photos, Halifax and Ingham eight). The tiles stay flush with each other. */
@media (min-width: 48rem) {
    .gallery-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
    .gallery-grid > * { grid-column: span 2; }
    .gallery-grid > :last-child:nth-child(3n + 1) { grid-column: 3 / span 2; }
    .gallery-grid > :nth-last-child(2):nth-child(3n + 1) { grid-column: 2 / span 2; }
}
@media (min-width: 62rem) {
    .gallery-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); }
    .gallery-grid > :last-child:nth-child(3n + 1),
    .gallery-grid > :nth-last-child(2):nth-child(3n + 1) { grid-column: span 2; }
    .gallery-grid > :last-child:nth-child(4n + 1) { grid-column: 4 / span 2; }
    .gallery-grid > :nth-last-child(2):nth-child(4n + 1) { grid-column: 3 / span 2; }
    .gallery-grid > :nth-last-child(3):nth-child(4n + 1) { grid-column: 2 / span 2; }
}
.gallery-grid__item {
    display: block;
    position: relative;
    aspect-ratio: 1 / 1;
    overflow: hidden;
    /* Square corners: these tiles butt against each other, so a radius would
     * cut notches out of every join. Overrides the global img rounding too. */
    border-radius: 0;
}
.gallery-grid__item img {
    width: 100%; height: 100%;
    object-fit: cover; display: block;
    border-radius: 0;
    transition: transform var(--duration-slow) var(--ease-out);
}
.gallery-grid__item:hover img,
.gallery-grid__item:focus-visible img { transform: scale(1.04); }
.gallery-grid__item:focus-visible {
    outline-offset: calc(var(--focus-ring-w) * -1);   /* inside the tile: the grid clips an outside ring */
    z-index: var(--layer-base);
}

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

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

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

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

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

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

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

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

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

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

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

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

/* The violet grounds (the topbar and footer, the gradient cards and bands):
 * the one ring goes cream there, >= 3:1 from the violet end to the deep end.
 * The footer's lime bar sets it back. */
.topbar, .site-footer, .hero__clinics-band, .clinic-card, .loc-card, .pi-card, .newpat__panel, .cta-strip, .policy-help__card, .skip-link, .lightbox { --focus-ring: var(--surface); }
.site-footer__bar { --focus-ring: var(--violet-deep); }
/* The skip link hangs from the top edge over the topbar: its ring sits inside
 * its own violet-deep tab, where nothing else can land under it. */
.skip-link:focus-visible { outline-offset: calc(var(--focus-ring-w) * -2); }
/* The fallback's gradient is for a doctor with no photo: under a photo it shows as
 * a hairline ring at the anti-aliased edge, so a box holding a photo has none. */
.doctor-avatar:has(img) { background: none; }
/* The card's own photo background is a pale placeholder; with no photo the box shows
 * the fallback's primary gradient, which the white person icon needs. */
.doctor-card__avatar.doctor-avatar:not(:has(img)) { background: linear-gradient(135deg, color-mix(in oklab, var(--violet) 85%, black), var(--violet)); }

/* Buttons on live's 1.2 line (the template's is Dials' --leading, 1.5 at
 * button size), so a button keeps its height. */
.btn,
.mf-search__submit,
.mf-search-overlay__close { line-height: var(--leading-headline); }
/* The person icon of a doctor with no photo stays white on the violet
 * gradient (the template draws it in --brand-on-solid, black on this
 * violet): 3.2:1 at the gradient's light end. */
.doctor-avatar::after { background-color: var(--secondary-on-solid); }
/* An h1 set as an eyebrow (the doctors hero's kicker) keeps the heading's
 * line, as it did before the eyebrow rule set one. */
.doc-hero__kicker { line-height: var(--leading-headline); }
/* The legal pages' "Last updated" line keeps the prose's line. */
.legal__panel small { line-height: var(--leading-loose); }
/* Violet text that falls short of contrast takes Dials' violet for text,
 * --brand-on-soft (#795EB9), and nowhere else: the eyebrows on the lilac
 * bands (2.6:1 in the violet, under the 3:1 large text needs; 4.2:1 now)
 * and the violet in body-size bold (the doctors' qualifications, the careers
 * columns' eyebrows: 3.1:1, under 4.5:1). The eyebrows on the cream keep
 * the violet: at their size it passes 3:1. */
:is(.section--band, .telehealth) .eyebrow,
.doctor-card__quals,
.careers-split__eyebrow { color: var(--brand-on-soft); }
