/* ==========================================================================
   Design System v2.1 — BASE
   Webfont, reset, element defaults.
   --------------------------------------------------------------------------
   Loads after tokens.css / scales.css / semantic.css, before components.css.
   Everything here consumes ROLE tokens (semantic.css) — never a --colour-*.

   Scope: this file styles bare elements only. No classes, no components. It is
   the layer that makes unstyled HTML already look right, so components don't
   have to re-state colour and type on every wrapper — which is how the old
   CSS grew to 10,385 !important.
   ========================================================================== */

/* ── Roboto, self-hosted ─────────────────────────────────────────────────
   Guidelines §5: "Roboto throughout".

   WHY SELF-HOSTED rather than a Google Fonts <link>:
   1. First paint is already gated on CDN stylesheets (header.php:1016-1023
      hides page content until they report, with a 3s timeout). Adding a
      third-party font host would extend that critical path, not just sit
      alongside it.
   2. portal/.htaccess sets font-src 'self' … — a gstatic.com link would need
      the CSP widened. Self-hosting needs no security change at all.
   3. No third-party request means no per-visitor call to Google from a
      clinical system, and no dependency on their availability.

   VARIABLE FONTS: these are Roboto's variable faces (weight axis 400–700), so
   the four weights the spec uses — 400/500/600/700 — come from ONE file per
   subset instead of four static files. 43KB covers all of them.

   Only the subsets we need: latin and latin-ext. latin-ext exists for accented
   patient and clinic names; the browser fetches it only if such a character is
   actually rendered, and likewise fetches italic only if italic is used. So the
   typical page downloads 43KB and nothing else.

   Filenames carry the upstream version (v51) so the cache headers in
   .htaccess can be immutable — a future Roboto update lands as a new filename
   rather than a stale cache.

   Licence: SIL Open Font License 1.1 (NOT Apache-2.0, despite what most
   references still say — google/fonts now ships Roboto under ofl/). OFL
   requires the notice to travel with the files: fonts/OFL.txt. It also
   reserves the family name, so don't rename 'Roboto' below.
   See fonts/README.md for provenance and byte sizes. */

@font-face {
    font-family: 'Roboto';
    font-style: normal;
    font-weight: 400 700;          /* variable range, not four faces */
    font-display: swap;            /* show fallback immediately, swap when ready */
    src: url('fonts/roboto-v51-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                   U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                   U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                   U+FFFD;
}

@font-face {
    font-family: 'Roboto';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('fonts/roboto-v51-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;
}

/* Real italics rather than a synthesised slant. Costs nothing when unused —
   the browser never requests a face it doesn't need to render. */
@font-face {
    font-family: 'Roboto';
    font-style: italic;
    font-weight: 400 700;
    font-display: swap;
    src: url('fonts/roboto-v51-latin-italic.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                   U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                   U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                   U+FFFD;
}

@font-face {
    font-family: 'Roboto';
    font-style: italic;
    font-weight: 400 700;
    font-display: swap;
    src: url('fonts/roboto-v51-latin-ext-italic.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;
}


/* ── Reset ───────────────────────────────────────────────────────────────
   Deliberately small. A heavy reset is what a decade of !important is built
   on top of; this only neutralises the browser defaults that actually fight
   a token system. */

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

/* Margins are a layout decision, so they belong to the component that owns
   the spacing — not to the element. Reinstated per-element below only where
   flowing prose needs it. */
body, h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ol, ul {
    margin: 0;
}

ul[role="list"], ol[role="list"] {
    padding: 0;
    list-style: none;
}

/* [hidden] MUST WIN, and it doesn't on its own.
   -----------------------------------------------------------------------------
   The attribute hides an element through the UA stylesheet's `display: none`, which
   ANY author-level display beats — so `.v2-button { display: inline-flex }` makes every
   button in the system unhideable by its own hidden attribute. Daniel hit this three
   times running on Load more: the JS set `hidden = true` correctly each time and
   nothing happened, and my first fix scoped :not([hidden]) onto the one component,
   which the .v2-button rule then beat anyway.

   !important is the right tool here and one of the few places it is. `hidden` is a
   promise the platform makes about the element, not a style suggestion — nothing should
   be able to override it by accident, and every author display rule in this codebase
   would otherwise have to remember to opt out one at a time.

   The `:where()` keeps specificity at zero so it never fights anything else. */
:where([hidden]) { display: none !important; }

/* ── Document ────────────────────────────────────────────────────────────
   NOTE: no `zoom` here, and there must never be one. The classic portal wraps
   every page in .page-zoom-wrapper at zoom 0.75/0.875, which costs 72 touch
   points across 15 files — modal widths divided by a zoom-factor variable, JS
   that re-parents modals out of the stacking context, and a Safari
   double-paint workaround. v2 sizes in real px and scales by breakpoint
   instead. See Portal Utilities/redesign/AUDIT.md §4. */

html {
    /* The AA control in the status-bar panel sets --ui-font-scale; every type
       token is rem, so this one line scales all of it. 100% (rather than 16px)
       multiplies the user's own browser base-font setting instead of
       overriding it — overriding it is the classic way a "font size" feature
       ends up fighting the accessibility setting it was meant to serve. */
    font-size: calc(100% * var(--ui-font-scale, 1));

    -webkit-text-size-adjust: 100%;   /* stop iOS inflating text on rotate */
    text-size-adjust: 100%;
}

body {
    margin: 0;
    min-height: 100vh;
    font-family: var(--font-family-base);
    font-size: var(--type-body-size);
    font-weight: var(--type-body-weight);
    line-height: var(--type-body-leading);
    color: var(--text-body);
    background-color: var(--surface-page);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* ── Headings ────────────────────────────────────────────────────────────
   Sizes come from the spec's roles, not from the tag's nesting depth. §3's
   section accent applies to headings, and it's set by a section wrapper
   repointing --heading-colour — so a heading inside My Patients turns Golden
   Hour without any component knowing which section it's in.

   Only h1/h2 have specified sizes. h3–h6 map to "Heading copy" (16px Medium)
   because the spec defines no further steps; if a design needs a third size,
   that's a question for the file, not a local override. */
:where(h1, h2, h3, h4, h5, h6) {
    color: var(--heading-colour, var(--text-strong));
    text-wrap: balance;    /* avoids a single orphaned word on wrapped headings */
}

h1 {
    font-size: var(--type-h1-size);
    font-weight: var(--type-h1-weight);
    line-height: var(--type-h1-leading);
}

h2 {
    font-size: var(--type-h2-size);
    font-weight: var(--type-h2-weight);
    line-height: var(--type-h2-leading);
}

h3, h4, h5, h6 {
    font-size: var(--type-heading-size);
    font-weight: var(--type-heading-weight);
    line-height: var(--type-heading-leading);
}

/* ── Prose ───────────────────────────────────────────────────────────────  */

p {
    text-wrap: pretty;
}

small, figcaption {
    font-size: var(--type-caption-size);
    font-weight: var(--type-caption-weight);
    line-height: var(--type-caption-leading);
    color: var(--text-muted);
}

strong, b {
    font-weight: 700;
}

hr {
    height: 1px;
    border: 0;
    background-color: var(--border-subtle);
}

/* ── Links ───────────────────────────────────────────────────────────────
   Underlined by default. Colour alone is not a sufficient affordance — it
   fails WCAG 1.4.1 (Use of Colour) for anyone who can't distinguish the hue
   from body copy. Components that genuinely aren't prose links (nav items,
   buttons-as-links) opt out explicitly. */
a {
    color: var(--text-link);
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
}

a:hover {
    text-decoration-thickness: 2px;
}

/* ── Focus ───────────────────────────────────────────────────────────────
   :focus-visible only, so a mouse click doesn't leave a ring but keyboard and
   assistive tech always do. The old CSS removed outlines outright in several
   places — that is a WCAG 2.4.7 failure and must not come back.

   outline-offset keeps the ring clear of the control's own border, and
   `outline` (not box-shadow) means it survives overflow:hidden ancestors and
   is visible in forced-colours mode. */
:focus-visible {
    outline: 2px solid var(--border-focus);
    outline-offset: 2px;
}

/* ── Forms ───────────────────────────────────────────────────────────────  */

input, button, textarea, select {
    font: inherit;          /* browsers otherwise fall back to system UI font */
    color: inherit;
}

button {
    cursor: pointer;
}

/* Native control chrome — dropdown arrows, date pickers, scrollbars, spin
   buttons — is painted by the OS, and gets it wrong unless told the mode.
   The classic portal had to patch dark-mode <select> popups by hand for this
   exact reason; declaring color-scheme fixes the whole class of it. */
:root {
    color-scheme: light;
}

[data-theme="dark"] {
    color-scheme: dark;
}

/* ── Media ───────────────────────────────────────────────────────────────  */

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

svg {
    fill: currentColor;    /* icons inherit the text colour by default */
}

/* ── Motion ──────────────────────────────────────────────────────────────
   Honour the OS-level reduced-motion preference globally, so no individual
   component has to remember. Not disabled entirely — 0.01ms keeps
   transitionend/animationend handlers firing, which is what breaks when
   people set `animation: none`. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        /* DELAYS TOO, not just durations. The typed salutation is built out of
           staggered animation-delays — the delay IS the motion there, so
           collapsing only the duration would leave the whole effect running at
           full length. Everything lands at once instead, which is what someone
           who asked for less movement is asking for. Safe globally: nothing in
           v2 uses a delay for correctness. */
        animation-delay: 0s !important;
        transition-delay: 0s !important;
        scroll-behavior: auto !important;
    }
}
