/* Design tokens — the palette, in one file, so a colour changes once rather
   than across seven byte-identical copies.

   Loaded as a <link>, first, before each page's own <style> — load-bearing: a
   page may legitimately override a token and the later rule must win, and it
   is render-blocking, which is what keeps the theme from flashing.

   The light block matches BOTH `:root.theme-light` and `body.theme-light`:
   the boot script writes to <html> before <body> exists; the app's toggle
   writes to <body>. index.html and login.html deliberately do not load this.

   A colour used as a fill is not the same colour used as text — that is the
   idea behind most of the splits below. Ratios in the comments are measured
   against --panel-2, the worst surface in both themes. Do not adjust a colour
   without re-measuring; see sys_design-system.md §1 and §18. */
  :root{
    /* ---------- TYPE: THE APPLICATION FONT ----------

       The reader chooses the face, and this is the only place the stacks
       live. Every surface reads --app-font/--app-font-display; ten choices
       are `:root[data-app-font="<id>"]` blocks at the foot of this file.

       The values here are option one, "STRIDE Default" (JS/core/app-font.js)
       — no block of its own, so an unknown or absent attribute falls back to
       it silently rather than to a browser default. Stamped on <html> by the
       inline boot script before paint, from the `pma_font` localStorage
       mirror, the theme's own mechanism — profiles.settings has not arrived
       in the parse yet.

       --app-brand-font is not a preference: the wordmark stays Space Grotesk
       under every choice, a third token rather than --app-font-display.

       Deliberately not routed through these: monospace (fixed advance width
       for alignment), the Notes rich-text vocabulary (persisted content
       shared with other readers), print/export documents (neutral for a
       recipient), and login.html/index.html (load no session yet).

       Every stack ends in a face a phone actually has — mobile.html fetches
       no webfont, so each chain names the iOS face, then the Android face,
       before a generic as the true last resort. */
    --app-font:'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --app-font-display:'Space Grotesk', system-ui, sans-serif;
    --app-brand-font:'Space Grotesk', system-ui, sans-serif;

    /* ---------- STACKING ----------

       One scale, and the newest layer wins. Every fixed layer takes its
       z-index from a token here; a layer opened from another one is raised
       above it at runtime by JS/core/layers.js — the one rule that cannot be
       expressed in CSS, since a dialog cannot know at authoring time what it
       opens on top of. Do not add a z-index to a new fixed layer without a
       token: the 99999 spiral starts with one component that "just needs to
       be above that other thing". */
    --z-sticky:20;         /* pinned headers, sticky toolbars — inside the page */
    --z-float:60;          /* popovers and pickers anchored to a control */
    --z-panel:190;         /* side panels and their backdrop */
    --z-dialog:300;        /* modal dialogs: the ordinary case */
    --z-alert:400;         /* dialogs that must outrank an ordinary one on their own */
    --z-boot:9999;         /* the session-boot curtain, above everything by definition */
    /* Raised layers are assigned --z-dialog + N*--z-step by layers.js. The gap to
       --z-alert is deliberately wide enough for the nesting anyone will actually do. */
    --z-step:10;

    /* ---------- MOTION ----------

       Five durations and three curves. Every animated control draws from
       these; a literal duration in a component is drift, and the suite says so.

       The signature curve is --ease-out: a fast start that settles rather
       than arrives. Enter decelerates; exit accelerates and is quicker,
       since the reader has already decided and is waiting on the next thing.

       --dur-micro is the deliberate exception to "long enough to see": hover,
       a chevron, a badge changing state are response, not animation, and
       past ~150ms a hover reads as lag rather than feedback — the rule here
       is "fast enough not to be felt," the opposite direction from the rest.

       --dur-quick is long enough that a disclosure reads as a movement you
       can follow, not a jump with a blur. --dur-surface shows a detail
       surface coming from somewhere; --dur-exit stays shorter than the
       surface it reverses, since the reader has already decided. --dur-
       progress is a bar you can watch travel.

       --stagger-max * --stagger-step caps a list reveal at 520ms whatever
       the length, so Expand-all over forty rows costs one --dur-quick plus
       that cap — raising the CAP rather than the step is how a sequence
       becomes a bounded queue instead of forty bars moving at once.

       JavaScript reads these rather than restating them: the per-item delay
       and "has the group finished" arithmetic live in JS/core/motion.js. */
    --dur-micro:140ms;      /* hover, chevron, badge, selected state — response, not motion */
    --dur-quick:460ms;      /* disclosure, panel reveal, flyout */
    --dur-surface:530ms;    /* a detail surface arriving */
    --dur-exit:430ms;       /* the same surface leaving — shorter than the arrival */
    --dur-progress:800ms;   /* a value filling to where it actually is */
    --ease-out:cubic-bezier(.22,.7,.28,1);   /* enter, and anything that settles */
    --ease-in:cubic-bezier(.4,.0,1,1);       /* exit — leaves faster than it came */
    --ease-move:cubic-bezier(.3,.7,.4,1);    /* small transforms already in flight */
    /* The stagger step for a group revealing in order, and the cap that stops a long list
       becoming a cascade the reader waits out. Read by JS/core/motion.js, never copied. */
    --stagger-step:65ms;
    --stagger-max:8;

    /* ---------- THE PHONE IS SLOWER ON PURPOSE ----------

       A thumb on a 6-inch screen is not a cursor on a 27-inch one. The whole
       board is one column taken in at a glance, so the reveal IS the page
       arriving — longer travel, a wider gap between rows, a curve that
       decelerates for longer.

       mobile.html aliases its own --stagger-step to the phone step on :root,
       since motionStaggerMs() reads that token off the root, keeping this
       file the index of every number. It does NOT alias --dur-quick: a
       :root override reaches every consumer on the page, which once put a
       disclosure clock on the page-arrival clock's number — a vocabulary
       token is aliased for a whole page only when every control on it really
       does want the new number. */
    --dur-phone-reveal:900ms;    /* the shell and the cards arriving */
    --stagger-step-phone:110ms;  /* the gap between one card and the next */
    /* A longer tail than --ease-out: it leaves the start quickly and spends most of the time
       settling, which is the part that reads as smooth. */
    --ease-phone:cubic-bezier(.16,.84,.24,1);

    /* ---------- ATTENTION AND MECHANISM CLOCKS ----------

       The five above are the vocabulary: every ordinary control uses one of
       them. These are the rest, here for one reason — so that every duration
       in this application is in this file, findable rather than scattered as
       literals.

       THEY ARE NOT PART OF THE VOCABULARY, and that distinction is the point
       of the split: a new control must not reach for one of these. They
       belong to a specific piece of machinery that already exists.

       The curves stay with the thing — only the duration is a shared
       decision; a clock style's overshoot or the dots' ease is declared beside it. */

    /* The working indicator's three dots: one pulse cycle, and the gap between them that
       makes it read as motion travelling rather than a throb. */
    --dur-dots:1.15s;
    --dur-dots-step:.16s;
    /* The boot overlay's joke fading in, once. */
    --dur-quip:.45s;
    /* A field or a row flashing to say "this just changed" — long enough to catch the eye
       after it has moved on, which is the whole job. */
    --dur-flash:1.1s;
    /* The note-refresh spinner's rotation, and a Momentum message landing. */
    --dur-spin:.8s;
    --dur-land:.7s;
    /* The funky clock's twelve marker drifting. Slow on purpose: it is decoration on a
       decoration. */
    --dur-drift:4s;
    /* ANALOGUE CLOCK HANDS. The hour and minute hands share one movement across every style;
       the SECOND hand is where the five styles differ, because that is the hand you watch —
       a quality movement does not overshoot, a funky one does, and the curve beside each
       style says how. These are only how long it takes. */
    --dur-hand-hour:.3s;
    --dur-hand-min:.25s;
    --dur-hand-sec:.2s;
    --dur-hand-sec-traditional:.12s;
    --dur-hand-sec-modern:.18s;
    --dur-hand-sec-retro:.22s;
    --dur-hand-sec-funky:.2s;

    /* HCA Tech Solutions dark palette — deep navy instead of the old
       neutral near-black, matching the marketing site's identity. */
    --bg:#0a1628;
    --panel:#101f36;
    --panel-2:#16283f;
    /* Three border tiers, picked by what the edge DOES. --border-strong is the WCAG
       1.4.11 tier at 3:1, and only for edges identifying a CONTROL. --border separates
       rows and cards; --border-soft is a quiet divider inside a card. All three were
       1.07-1.19:1 before — invisible, which made the board read as one block. Do NOT
       raise --border to 3:1 "for consistency": a control-grade edge on every card is a
       wireframe. */
    --border-strong:#4e71a5;              /* 3.00 */
    --border:#395379;                     /* 1.91 — was #24344c at 1.19 */
    --border-soft:#294263;                /* 1.46 — was #1c2d44 at 1.07 */
    --text:#f4f6fb;                       /* 13.78 */
    --text-dim:#a9b6cc;                   /*  7.27 */
    --text-faint:#8390a5;                 /*  4.61 — was #6b7a94 at 3.43 */
    /* Three accent roles. --accent for edges/rings/dots, --accent-fill under white
       text (white on #3b82f6 is 3.68 — every primary button failed), --accent-text
       for accent-coloured TEXT on a surface or on its own soft wash. */
    --accent:#3b82f6;
    --accent-fill:#1e6ff5;                /* white on it: 4.52 */
    --accent-text:#70a4f8;                /* 5.93 on panel-2, 4.54 on its own wash */
    --accent-soft:rgba(59,130,246,.20);
    /* In-scope washes for a filter-driven surface (the OKR area/quarter
       matrix). Two strengths, since "everything is included" and "you
       narrowed to this" are different statements one alpha cannot make both
       of. Cell text keeps --text throughout both: 12.55:1 / 9.98:1. */
    --scope-soft:rgba(59,130,246,.15);
    --scope-strong:rgba(59,130,246,.30);
    --focus-ring:#3b82f6;                 /* >=4.05 on every surface — see §18 */
    --red:#d13438;
    --red-text:#e07577;                   /* 4.95 — was --red at 3.02 */
    --red-soft:rgba(209,52,56,.16);
    --green:#107c41;
    --green-text:#17b35e;                 /* 5.43 — was --green at 2.82, the worst in the app */
    --green-soft:rgba(16,124,65,.20);
    --yellow:#ffb900;
    --yellow-soft:rgba(255,185,0,.16);
    /* Warning TEXT on a --yellow-soft wash. Separate from --yellow because the two themes
       need opposite ends of the ramp: bright here, deep amber in light mode. */
    --warn-text:#ffcf4d;
    --orange:#ca5010;
    --orange-text:#ef7636;                /* 5.19 — was --orange at 3.31 */
    --orange-soft:rgba(202,80,16,.18);
    /* Was a literal #8764b8 in .pill.st-monitor here while classic_team_board.html had a token.
       Tokenised so the two stop drifting. */
    --purple:#8764b8;
    --purple-text:#aa92cd;                /* 5.46 — was #8764b8 at 3.22 */
    --purple-soft:rgba(135,100,184,.18);
    --gray-soft:rgba(200,198,196,.14);
    --radius:10px;
    --radius-sm:7px;
    /* THE WIDTH OF A RESIZE GRIP, AND THEREFORE THE GUTTER A PANE OWES IT.
       A grip is `position:absolute` over the edge of the pane it resizes, so
       whatever it covers is content the reader cannot see cleanly — one
       token, so a wider grip widens its own gutter. */
    --rail-grip-w:9px;
    /* The padding a rail gives its content, naming it once so every rail
       looks like the same object. Must be >= --rail-grip-w, since the grip
       lives inside this padding — asserted in
       _docs/tests/focused-fixes-2026-08-31.test.js. */
    --rail-pad:14px;

    /* OKR health, as ALIASES of the palette rather than six new colours — they
       follow --red/--green/… into the light block automatically.

       That holds only because the light class lands on :root. An alias
       computes on the element it is DECLARED on, so if `.theme-light` were
       ever applied to <body> alone, these would keep their dark values and
       every OKR status colour would silently freeze — applyTheme() sets the
       class on <html> AND <body> for this reason; do not "simplify" it to one.

       The mapping: red is losing time, orange is slipping, green is on
       track, blue is ahead, purple is finished, grey has not begun. Purple
       for completed keeps "done" visually distinct from "going well". */
    /* `behind` is the one family that is NOT an alias: on this navy ground
       the offender is CHROMA, not luminance, and --red itself could not move
       — it is the danger colour everywhere else in the application, so
       softening it would change what "this will destroy something" looks
       like to answer a complaint about one board. All the softening comes
       out of saturation (63% -> 32%/34%), none out of lightness, since --red
       already sits one hundredth above the 3:1 floor. Pinned by
       _docs/tests/okr-behind-red.test.js, which also asserts --red is
       untouched. The light block re-declares all three: they are declared
       once on :root and light mode inherits them, so a real value here is a
       dark value light mode would silently get too. */
    --okr-behind:#ac5d63;                 /* 3.19 on --panel-2 — was --red #d13438 at 3.02 */
    --okr-behind-text:#c68b8f;            /* 5.31, and 4.80 on its own wash — was --red-text #e07577 at 4.95 / 4.51 */
    --okr-behind-soft:rgba(172,93,99,.12);/* was --red-soft rgba(209,52,56,.16) */
    --okr-slightly:var(--orange);
    --okr-slightly-text:var(--orange-text);
    --okr-slightly-soft:var(--orange-soft);
    --okr-ontrack:var(--green);
    --okr-ontrack-text:var(--green-text);
    --okr-ontrack-soft:var(--green-soft);
    --okr-ahead:var(--accent);
    --okr-ahead-text:var(--accent-text);
    --okr-ahead-soft:var(--accent-soft);
    --okr-done:var(--purple);
    --okr-done-text:var(--purple-text);
    --okr-done-soft:var(--purple-soft);
    --okr-idle:var(--border-strong);
    --okr-idle-text:var(--text-faint);
    --okr-idle-soft:var(--gray-soft);
    /* The quiet states on a key result: a measure on track, ahead, finished
       or not yet started needs no colour of its own under an objective that
       already carries the verdict. Aliased onto the neutral text ramp.
       `strong` is completed — worth telling apart from idle, without
       spending a colour on it. */
    --okr-quiet:var(--text-faint);
    --okr-quiet-strong:var(--text-dim);
  }

  :root.theme-light, body.theme-light{
    /* This block is also the contract for the team's custom theme: a team
       may publish a single colour, from which JS/core/theme-custom.js
       derives a whole palette as INLINE custom properties on <html>, a LAYER
       over one of these two bases rather than a fourth palette.

       The list this block redeclares IS the list that module derives —
       THEME_CUSTOM_TOKENS, thirty-two names, pinned by
       _docs/tests/theme-custom-contrast.test.js. A token added here and not
       there is stranded on a custom theme. Add it to both, or to neither.

       Same component styles, different values — a cool muted blue-gray
       rather than stark white/black, so it reads as the same brand. Surfaces
       sit ~5% below where they started, since panels cover most of the
       screen and arrived as a wall of glare at pure white. */
    --bg:#e7ebf2;
    --panel:#f1f4f9;
    --panel-2:#dee4ee;
    --border-strong:#6b84a6;              /* 3.00 */
    --border:#96a7c0;                     /* 1.91 — was #c8d1de at 1.21 */
    --border-soft:#b2bfd5;                /* 1.45 — was #d7dee9 at 1.06 */
    --text:#26303f;                       /* 10.42 */
    /* The light text ramp was two tiers pretending to be three — 0.47 apart,
       indistinguishable on screen. Dim goes darker to open the gap; faint
       comes up over the AA floor. */
    --text-dim:#3d4a5c;                   /*  7.05 — was #556780 at 4.52 */
    --text-faint:#596578;                 /*  4.62 — was #616e82 at 4.05 */
    --accent:#2560c8;
    --accent-fill:#2560c8;                /* white on it: 5.86 — already fine in light */
    --accent-text:#2257b6;                /* 5.29 */
    /* Was rgba(59,130,246,.12) — the DARK blue, in the light block. A copy-paste that
       made every selected background in light mode the wrong hue. */
    --accent-soft:rgba(37,96,200,.12);
    /* The light-mode pair. Slightly lower alphas: the same wash over a light panel reads
       stronger, and the point is a tint that leaves the grid's structure and its status rings
       intact. Measured 9.94:1 for cell text on the quiet wash and 8.33:1 on the strong one. */
    --scope-soft:rgba(37,96,200,.14);
    --scope-strong:rgba(37,96,200,.26);
    --focus-ring:#2560c8;                 /* >=4.58 on every surface */
    --red:#c62828;
    --red-text:#ad2323;                   /* 5.40 */
    --red-soft:rgba(198,40,40,.12);
    --green:#157a3d;
    --green-text:#126935;                 /* 5.31 */
    --green-soft:rgba(21,122,61,.12);
    --yellow:#836008;                     /* 4.51 — was #a6790a at 3.07 */
    --yellow-soft:rgba(166,121,10,.16);
    --warn-text:#6d4e00;   /* 5.8:1 on the wash; #e0b04a was 1.7:1 */
    --orange:#a8480f;
    --orange-text:#95400d;                /* 5.45 */
    --orange-soft:rgba(168,72,15,.14);
    --purple:#6b4894;
    --purple-text:#6b4894;                /* 5.52 — light purple already passes */
    --purple-soft:rgba(107,72,148,.14);
    --gray-soft:rgba(70,66,62,.08);

    /* The OKR `behind` family, put back to the palette: the other five are
       aliases on :root reaching this block by inheritance, but this one is a
       real dark value there, so without these three lines light mode would
       paint a dark red on a pale panel. Aliases, not values, deliberately —
       they point at --red, which IS derived, so a custom light theme still
       moves them with nothing extra to keep in contrast. */
    --okr-behind:var(--red);
    --okr-behind-text:var(--red-text);
    --okr-behind-soft:var(--red-soft);
  }

/* ================= THE TEN APPLICATION FONTS =================

   One block per option, and option one is not here — "STRIDE Default" is the
   bare :root declaration above, so a second block would be the same stack
   written twice. The ids match APP_FONTS in JS/core/app-font.js exactly;
   `_docs/tests/application-font.test.js` pins the two lists to each other.

   Only option one pairs a different display face with its body face — every
   other choice is one face, headings included, so a reader who asks for a
   serif application is not handed grotesque headings.

   What a phone actually gets is written against each one: Android has roughly
   four text faces, so what survives ten options there is the CATEGORY — sans
   stays sans, serif stays serif, never a browser default. */

/* Clean. The device's own interface face, whatever that is. */
:root[data-app-font="system"]{
  --app-font:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
  --app-font-display:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
}
/* Clean. Helvetica Neue on Apple, Roboto on Android — Android aliases the Arial/Helvetica
   family names onto Roboto, and Roboto is named explicitly so it does not depend on that. */
:root[data-app-font="neo"]{
  --app-font:'Helvetica Neue', Helvetica, Arial, 'Liberation Sans', Roboto, 'Noto Sans', sans-serif;
  --app-font-display:'Helvetica Neue', Helvetica, Arial, 'Liberation Sans', Roboto, 'Noto Sans', sans-serif;
}
/* Modern. Segoe UI on Windows, Trebuchet MS on Apple, Noto Sans on Android — three humanist
   faces, which is what keeps this option recognisably itself on all three. */
:root[data-app-font="humanist"]{
  --app-font:'Segoe UI', Candara, Corbel, 'Trebuchet MS', 'Lucida Grande', 'Noto Sans', Roboto, sans-serif;
  --app-font-display:'Segoe UI', Candara, Corbel, 'Trebuchet MS', 'Lucida Grande', 'Noto Sans', Roboto, sans-serif;
}
/* Traditional, and the WIDEST of the ten — the one to check a dense row against. Verdana is on
   Apple and Windows; Android has no wide face and aliases it onto Roboto. */
:root[data-app-font="wide"]{
  --app-font:Verdana, Tahoma, 'DejaVu Sans', Geneva, 'Noto Sans', Roboto, sans-serif;
  --app-font-display:Verdana, Tahoma, 'DejaVu Sans', Geneva, 'Noto Sans', Roboto, sans-serif;
}
/* Modern, geometric, and the LOWEST x-height of the ten. Avenir Next on Apple, Century Gothic
   or Futura where they exist, then system-ui — which is Roboto on Android. The names after
   system-ui are not dead: an engine too old to understand system-ui skips it. */
:root[data-app-font="geometric"]{
  --app-font:'Avenir Next', Avenir, 'Century Gothic', Futura, 'URW Gothic', system-ui, Roboto, 'Noto Sans', sans-serif;
  --app-font-display:'Avenir Next', Avenir, 'Century Gothic', Futura, 'URW Gothic', system-ui, Roboto, 'Noto Sans', sans-serif;
}
/* Expressive. Space Grotesk is a WEBFONT and mobile.html deliberately fetches no fonts, so this
   is the one option whose lead face a phone cannot have. Futura carries it on iOS and macOS —
   geometric, wide, high-waisted, the closest system face to Space Grotesk's character — and
   Noto Sans carries it on Android, which at least keeps it distinct from the four options that
   land on Roboto there. Named before Roboto for exactly that reason. */
:root[data-app-font="grotesk"]{
  --app-font:'Space Grotesk', Futura, 'Trebuchet MS', 'Noto Sans', Roboto, sans-serif;
  --app-font-display:'Space Grotesk', Futura, 'Trebuchet MS', 'Noto Sans', Roboto, sans-serif;
}
/* Elegant. Optima on Apple, Candara or Gill Sans on Windows, Noto Sans on Android. */
:root[data-app-font="elegant"]{
  --app-font:Optima, Candara, 'Gill Sans', 'Gill Sans MT', 'Trebuchet MS', 'Noto Sans', Roboto, sans-serif;
  --app-font-display:Optima, Candara, 'Gill Sans', 'Gill Sans MT', 'Trebuchet MS', 'Noto Sans', Roboto, sans-serif;
}
/* Elegant, and a SERIF — the option to check a table against. Iowan Old Style on Apple,
   Palatino Linotype on Windows, Noto Serif on Android. Georgia is kept as the broad middle. */
:root[data-app-font="book"]{
  --app-font:'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia, 'Noto Serif', 'Times New Roman', serif;
  --app-font-display:'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia, 'Noto Serif', 'Times New Roman', serif;
}
/* Traditional, and the serif built for screens rather than for paper — larger x-height, sturdier
   strokes. Georgia everywhere Apple and Windows, Noto Serif on Android. */
:root[data-app-font="screen"]{
  --app-font:Georgia, Charter, 'Bitstream Charter', 'Sitka Text', Cambria, 'Liberation Serif', 'Noto Serif', serif;
  --app-font-display:Georgia, Charter, 'Bitstream Charter', 'Sitka Text', Cambria, 'Liberation Serif', 'Noto Serif', serif;
}
