/* 01-foundation.css - tokens, reset, typography, colour, spacing scale

   NUMBERED CASCADE. File order IS cascade order. These files are linked from
   App.razor in numeric order and nothing else, so a rule in a later file wins
   over the same-specificity rule in an earlier one.

   APPEND a new file in sequence. Never insert one alphabetically or renumber
   an existing one: both silently change which rule wins on every page.

   07-admin.css is the exception and is linked from AdminLayout only, so a
   member of the public downloads zero bytes of back-office CSS. That is why
   this sequence stops at 04.

   ---------------------------------------------------------------------------
   CONTRAST ANNOTATIONS ARE MACHINE READ.

   Every colour token below carries its MEASURED WCAG 2.x contrast ratio
   against each ground it is actually used on, in the form

       12.34:1 on --other-token [AA 4.5]

   ColourContrastTests parses this file, recomputes the ratio from the two hex
   values and fails the build when the real number is below either the stated
   number or the bracketed WCAG floor. The numbers are therefore not a comment
   in the decorative sense: they are the assertion. If you change a hex value
   you must re-measure, not re-guess.

   Floors: 4.5 for body text, 3.0 for text at or above 24px (19px bold) and for
   non-text UI boundaries such as the focus ring.

   Several numbers here are LOWER than the approximations printed in
   docs/DESIGN.md section 2, which were eyeballed rather than measured. The
   measured values are what ships and what the tests pin. In particular
   --sage and --teal do not reach 4.5 on any ground on this site, so both are
   large-text and UI only, exactly as DESIGN.md's own prose (not its table)
   already required.
   --------------------------------------------------------------------------- */

/* Fraunces, variable, opsz 9 to 144 and wght 100 to 900. Self hosted.
   Self hosting is a product rule, not a preference: a request to the Google
   Fonts CDN from a page about a named condition is a third-party disclosure
   that HHS tracking-technology guidance treats as a real exposure for a
   healthcare provider, and the site CSP has no external hosts at all, so such
   a request would simply be blocked. The two subsets below are the latin and
   latin-ext cuts, downloaded once and committed under the SIL Open Font
   License (see OFL-Fraunces.txt and OFL-Inter.txt beside the binaries).
   SelfHostedFontTests fails the build if a CDN host name reappears in this
   file at all, comments included. */
/* SUBSET, AND THE RANGE BELOW IS WHAT THE FILE ACTUALLY CONTAINS.

   Fraunces sets headings and nothing else on this site, so its latin cut is
   printable ASCII plus the typographic characters a page can plausibly carry.
   No em dash and no en dash: scripts/check-copy-style.sh fails the build on
   either, so the glyphs would be unreachable weight.

   67KB to 24KB, and about 20KB of that came from PINNING THE OPTICAL SIZE
   AXIS rather than from dropping glyphs. Fraunces here runs from about 20px
   to about 80px, one band, and one optical size chosen for it is a difference
   almost nobody can see beside a difference every visitor on rural cellular
   can feel. There is no longer an opsz axis in the file, which is why nothing
   in this cascade asks for font-optical-sizing any more.

   The range is DECLARED HONESTLY. Nothing outside it is in the file, so a
   character outside it falls to the next family in the stack instead of
   rendering as a blank box. FontCoverageTests fails the build if a character
   this file cannot draw ever appears in the site copy, so the narrow range is
   a ratchet rather than a hope. scripts/subset-fonts.py is how the cut is
   made. */
@font-face {
    font-family: "Fraunces";
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url("../fonts/fraunces-variable-latin.woff2") format("woff2");
    unicode-range: U+0020-007E, U+00A0, U+00A9, U+00AE, U+00B0, U+2018-2019, U+201C-201D, U+2026, U+2122, U+FEFF, U+FFFD;
}

@font-face {
    font-family: "Fraunces";
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url("../fonts/fraunces-variable-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Inter, variable, wght 100 to 900. Self hosted, same reasons. */
/* SUBSET, and a WIDER cut than Fraunces on purpose.

   Inter keeps the whole Latin-1 supplement, because it is the body and UI
   face and it is what renders a visitor's own name in the admin inbox. That
   is the one string on this site whose spelling nobody here chooses, and a
   name that drops to the system sans halfway through is a small insult to the
   person who typed it. 48KB to 32KB.

   The weight axis stays whole. Inter is set at 400, 500 and 600 across the
   site and clamping the axis to that band measured LARGER, not smaller,
   because limiting a range rebases every delta rather than dropping it. */
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url("../fonts/inter-variable-latin.woff2") format("woff2");
    unicode-range: U+0020-007E, U+00A0-00FF, U+2018-2019, U+201C-201D, U+2026, U+2122, U+FEFF, U+FFFD;
}

@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url("../fonts/inter-variable-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ===========================================================================
   TOKENS. docs/DESIGN.md section 2, 3 and 4. The only colours, sizes and
   spaces that may appear anywhere in this cascade.
   =========================================================================== */

:root {
    /* --- Ground ------------------------------------------------------------
       Grounds carry no ratio of their own; the ink tokens below state the
       pair. --bg-deep is the one exception worth naming here because it is
       also a large block of colour beside --bg. */
    --bg: #FBFAF8; /* warm off-white, the default page */
    --bg-raised: #FFFFFF; /* cards and panels. 12.86:1 on --bg-deep [AA 3.0] */
    --bg-sage: #EFF3EE; /* the calm band: insurers, process, quiet sections */
    --bg-deep: #073649; /* footer and the occasional full-bleed statement */

    /* --- Ink ---------------------------------------------------------------
       Body copy sits on one of the three light grounds, so each ink token
       states all three. */
    --ink: #16303C; /* body text. 13.23:1 on --bg [AA 4.5], 13.80:1 on --bg-raised [AA 4.5], 12.30:1 on --bg-sage [AA 4.5] */
    --ink-strong: #00486C; /* headings, the wordmark teal. 9.39:1 on --bg [AA 4.5], 9.80:1 on --bg-raised [AA 4.5], 8.74:1 on --bg-sage [AA 4.5] */
    --ink-muted: #4A6270; /* captions, meta, eyebrows. 6.15:1 on --bg [AA 4.5], 6.42:1 on --bg-raised [AA 4.5], 5.72:1 on --bg-sage [AA 4.5] */
    --ink-on-deep: #EAF2F4; /* text on the footer. 11.33:1 on --bg-deep [AA 4.5] */

    /* --- Brand -------------------------------------------------------------
       --teal is the logo teal and is the one brand colour that CANNOT carry
       body text on any ground here. It is used for rules, icon strokes and
       the focus ring, never for a paragraph. */
    --teal: #0C90A8; /* LARGE TEXT AND UI ONLY. 3.61:1 on --bg [AA 3.0], 3.77:1 on --bg-raised [AA 3.0], 3.36:1 on --bg-sage [AA 3.0] */
    --teal-text: #056077; /* the text-safe teal, used for links. 6.83:1 on --bg [AA 4.5], 7.13:1 on --bg-raised [AA 4.5], 6.36:1 on --bg-sage [AA 4.5] */
    --teal-deep: #00486C; /* the primary button ground. 9.80:1 with --bg-raised [AA 4.5], 9.39:1 on --bg [AA 4.5] */
    --violet: #8460B4; /* accent, sparingly. 4.67:1 on --bg [AA 4.5], 4.87:1 on --bg-raised [AA 4.5], 4.34:1 on --bg-sage [AA 3.0] */
    --violet-soft: #B490D8; /* DECORATIVE ONLY, never text */
    --sage: #609084; /* LARGE TEXT AND UI ONLY. 3.46:1 on --bg [AA 3.0], 3.61:1 on --bg-raised [AA 3.0] */
    --sage-soft: #A8C4AC; /* DECORATIVE ONLY, never text. The petal divider. */
    --sage-text: #386B5E; /* the text-safe sage, for the strapline and nothing else. 5.86:1 on --bg [AA 4.5], 6.11:1 on --bg-raised [AA 4.5], 5.45:1 on --bg-sage [AA 4.5] */

    /* --- State -------------------------------------------------------------
       --focus is a non-text boundary, so its floor is 3.0, and it has to
       clear it on the footer ground as well as the light ones. */
    --focus: #0C90A8; /* focus ring. 3.61:1 on --bg [AA 3.0], 3.77:1 on --bg-raised [AA 3.0], 3.36:1 on --bg-sage [AA 3.0], 3.41:1 on --bg-deep [AA 3.0] */
    --error: #A32B2B; /* field errors. 6.85:1 on --bg [AA 4.5], 7.15:1 on --bg-raised [AA 4.5] */
    --success: #2F6B4F; /* confirmations. 6.03:1 on --bg [AA 4.5], 6.29:1 on --bg-raised [AA 4.5] */

    /* --- Line --------------------------------------------------------------
       Hairlines are decoration, not meaning: nothing on this site is
       communicated by a rule alone, so no floor applies to them. */
    --rule: #E2E0DA;
    --rule-strong: #C9CFC7;

    /* --- Type --------------------------------------------------------------
       docs/DESIGN.md section 3. Fraunces for display, Inter for everything
       else. Both self hosted above. */
    --font-display: "Fraunces", "Iowan Old Style", Georgia, serif;
    --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;

    --fs-display: clamp(2.75rem, 1.6rem + 4.6vw, 5rem);
    --fs-h1: clamp(2.15rem, 1.5rem + 2.6vw, 3.25rem);
    --fs-h2: clamp(1.65rem, 1.3rem + 1.5vw, 2.35rem);
    --fs-h3: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
    --fs-lead: clamp(1.125rem, 1.05rem + 0.4vw, 1.375rem);
    --fs-body: 1.0625rem; /* 17px. NEVER below 16px. */
    --fs-small: 0.9375rem; /* 15px */

    --lh-display: 1.15;
    --lh-heading: 1.3;
    --lh-body: 1.65;

    /* Measure. A full-width paragraph is a bug (DESIGN.md section 3).

       62ch, NOT 66ch. The ch unit is the advance width of the digit zero, and
       in Inter zero is wider than the average lowercase letter, so a 66ch
       column measured out at about 85 characters per line against a
       comfortable 45 to 75. The number in DESIGN.md was the thing that was
       wrong, and it has been corrected there as well: 62ch sets about 78
       characters, and the lead sits a step narrower again so a standfirst is
       still visibly a standfirst.

       Anything that clips rather than wraps must cap itself with
       min(var(--measure), 100%). A ch value doubles with the text, so at 200%
       it stops being a cap at all. See .table-wrap in 04-public.css. */
    --measure: 62ch;
    --measure-lead: 54ch;

    /* --- Space -------------------------------------------------------------
       An 8px base. docs/DESIGN.md section 4. */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 32px;
    --space-6: 48px;
    --space-7: 64px;
    --space-8: 80px;
    --space-9: 96px;
    --space-10: 128px;

    /* --- Frame ------------------------------------------------------------- */
    --container: min(100% - 2.5rem, 1200px);
    --container-narrow: min(100% - 2.5rem, 760px);
    --gutter: var(--space-5);
    --radius: 8px;
    --radius-card: 12px;

    /* The mobile call bar is fixed, so the page has to reserve its height or
       it sits on top of the last paragraph. 02-layout.css sets this to a real
       number under 860px and back to zero above it; every long-form page
       reads it rather than hardcoding a magic bottom padding. */
    --call-bar-height: 0px;

    /* The single motion duration on the site. DESIGN.md law 4: nothing moves
       unless the user asked it to. This exists for hover and focus feedback
       and for nothing else, and the reduced-motion block at the foot of this
       file zeroes it. */
    --motion: 150ms;

    /* Dark mode is not shipped (DESIGN.md section 2). Declare the scheme so
       the browser does not invent one and repaint form controls in colours
       that were never contrast checked. */
    color-scheme: light;
}

/* ===========================================================================
   RESET. Small on purpose. Anything that is not fixing a real browser default
   belongs in 02 or 03, not here.
   =========================================================================== */

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

html {
    -webkit-text-size-adjust: 100%;
    /* Anchored headings must not land under the sticky nothing: there is no
       sticky header on this site, but in-page FAQ links still read better
       with a little air above the target. */
    scroll-padding-top: var(--space-5);
}

body {
    margin: 0;
    background-color: var(--bg);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    font-synthesis-weight: none;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    /* THE LAST RESORT THAT MAKES 200% TEXT REFLOW.

       A single long word, Relationships or Confidentiality, is 257px at 200%
       text. In a grid cell narrower than that it does not wrap, it hangs out
       of its block, and the whole document scrolls sideways: no element box
       overflows, so nothing in the layout looks wrong, and the page is still
       a WCAG 1.4.10 failure.

       break-word only acts when a word genuinely cannot fit the line it is
       on, so at every normal text size this changes nothing at all. It is the
       difference between reflowing and breaking, and reflowing is the one the
       success criterion asks for. */
    overflow-wrap: break-word;
    /* The fixed call bar under 860px. Reserving its height here, once, is
       what keeps it off the last paragraph of every page. */
    padding-bottom: var(--call-bar-height);
}

h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd,
ul,
ol {
    margin: 0;
}

ul,
ol {
    padding: 0;
}

img,
picture,
svg,
video {
    display: block;
    max-width: 100%;
}

img {
    height: auto;
}

/* ===========================================================================
   BASE TYPOGRAPHY
   =========================================================================== */

h1,
h2,
h3,
h4 {
    font-family: var(--font-display);
    color: var(--ink-strong);
    line-height: var(--lh-heading);
    font-weight: 500;
    text-wrap: balance;
    /* Fraunces used to carry a live optical size axis here. It does not any
       more: the axis was about 20KB of the 67KB the file cost on every page,
       for a band of heading sizes narrow enough that one optical size covers
       it, and scripts/subset-fonts.py now pins it at 30. Nothing asks for
       font-optical-sizing anywhere in this cascade, because there is nothing
       left to ask. See the @font-face block at the top of this file. */
}

h1 {
    font-size: var(--fs-h1);
    line-height: var(--lh-display);
}

h2 {
    font-size: var(--fs-h2);
}

h3 {
    font-size: var(--fs-h3);
}

h4 {
    font-size: var(--fs-body);
    font-weight: 600;
}

p,
li,
dd,
dt {
    max-width: var(--measure);
}

p + p {
    margin-top: var(--space-4);
}

a {
    color: var(--teal-text);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
}

a:hover {
    color: var(--ink-strong);
}

strong,
b {
    font-weight: 600;
}

small {
    font-size: var(--fs-small);
}

hr {
    border: 0;
    border-top: 1px solid var(--rule);
    margin: var(--space-6) 0;
}

/* The one letterspaced style on the site. DESIGN.md section 3: never
   letterspace lowercase body text; the logo's letterspaced caps are for this
   eyebrow label and nothing else. */
.eyebrow {
    font-family: var(--font-body);
    font-size: var(--fs-small);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-muted);
    font-weight: 600;
    margin: 0 0 var(--space-3);
}

.lead {
    font-size: var(--fs-lead);
    line-height: 1.55;
    max-width: var(--measure-lead);
    color: var(--ink);
}

/* ===========================================================================
   FOCUS. DESIGN.md section 7: focus is never suppressed, and the ring is part
   of the component rather than an override somebody can delete later.
   =========================================================================== */

:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
    border-radius: 2px;
}

/* THE STRAY BOX AROUND THE HEADLINE ON A COLD LOAD.

   Blazor's FocusOnNavigate puts focus on the h1 after every navigation, which
   is right: it is what lets a keyboard or screen-reader user carry on from
   the new page's title instead of from the top of the chrome. But it also
   runs on the FIRST render, and before any interaction has happened Chrome's
   :focus-visible heuristic still says "the last input was a keyboard", so it
   drew a teal ring around the h1 of every page arrived at from a search
   result. It reads as a rendering fault, on first impression, on every page.

   <html> ships with .no-interaction and the script at the foot of App.razor
   removes it the first time a pointer or a key is used. So the ring is
   suppressed on the initial render and present for every navigation after it,
   which is exactly the behaviour that was wanted. Focus itself is never
   moved, removed or delayed: this hides a ring on a programmatic target that
   no Tab can reach, and nothing else. */
.no-interaction h1:focus-visible {
    outline: none;
}

/* Only for elements that opt out of the default ring by drawing their own.
   Nothing in this cascade removes a ring without drawing a replacement. */
:focus:not(:focus-visible) {
    outline: none;
}

/* ===========================================================================
   FORM BASE. Component styling is in 03-components.css; this is only the part
   that has to be true of every control on the site.
   =========================================================================== */

input,
select,
textarea,
button {
    font: inherit;
    color: inherit;
}

input,
select,
textarea {
    background-color: var(--bg-raised);
}

button {
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
}

label {
    display: block;
    font-weight: 600;
    font-size: var(--fs-small);
    color: var(--ink);
    margin-bottom: var(--space-2);
}

fieldset {
    border: 0;
    padding: 0;
    margin: 0;
    min-width: 0;
}

legend {
    padding: 0;
}

table {
    border-collapse: collapse;
}

/* ===========================================================================
   ACCESSIBILITY UTILITIES
   =========================================================================== */

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ===========================================================================
   REDUCED MOTION. DESIGN.md section 7: reduce removes EVERY transition,
   including the 150ms card fade. This audience includes people for whom
   motion is a symptom trigger, so the rule is a blanket, not a curation.
   =========================================================================== */

@media (prefers-reduced-motion: reduce) {
    :root {
        --motion: 0ms;
    }

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}
