/* ===========================================================================
   ADRI OS Design Standard — v1.1.0
   The one stylesheet every ADRI OS product is built from.

   v1.1.0 (2026-10-19, Mak Banjac: apply Apple's Human Interface Guidelines).
   The floors now match Apple's: no text under 11px, a 44px touch target on a
   touch screen, type in rem so a person's own text size setting reaches it,
   and a defined answer to Increase Contrast, Windows High Contrast, Reduce
   Transparency and the phone's safe areas. Desktop density is unchanged.
   Rules: plugins/system/knowledge/KNW_2026-10-19_OS_MB_ADRI-Interface-Guidelines.md
   Behavior (Escape, Back, confirm, status): design/adrios-ui.js

   Canon: the LC Brief (apps/lc-brief-web). This file is that design language
   given names, made portable, and made platform-independent. It is NOT a
   reinterpretation — every value here traces to a line in the Brief's source.

   Binding: .claude/rules/design-standard.md
   Spec:    plugins/system/knowledge/KNW_2026-08-03_OS_MB_Design-Standard.md
   Guide:   design/README.md

   THREE TIERS
     1. Foundations (tokens, type, severity)  — mandatory, no exceptions
     2. Principles (see the spec)             — mandatory
     3. Components (below the fold here)      — use when the pattern applies

   A product is not required to look like the LC Brief. It is required to be
   built from the same material. If it renders a table, it renders THIS table.

   Deviation requires a written approval marker from Mak or Miron. See the rule.
   ======================================================================== */


/* ── Type ────────────────────────────────────────────────────────────────
   Self-hosted, latin-subset, ~180 KB once and cached forever.

   WHY SELF-HOSTED: until 2026-08-03 the Brief declared 'Inter' and never
   shipped it, so every role fell through to a system font and the two
   platforms rendered three different typefaces each:
       UI      declared Inter  → Mac: SF Pro     Windows: Segoe UI
       Serif   declared New York → Mac: New York  Windows: Georgia
       Mono    declared SF Mono → Mac: SF Mono    Windows: Consolas
   ADRI is a Windows-first shop. The design language had therefore never
   actually shipped to the people who use it. Never reintroduce a system-font
   stack: it silently forks the product by platform.

   All three families are SIL Open Font License 1.1. See fonts/LICENSES.md. */

@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400 800;
  font-display: swap; src: url('fonts/inter-var-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'Literata'; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url('fonts/literata-var-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 400;
  font-display: swap; src: url('fonts/plexmono-400-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 600;
  font-display: swap; src: url('fonts/plexmono-600-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 700;
  font-display: swap; src: url('fonts/plexmono-700-latin.woff2') format('woff2');
}


/* ── Tokens ─────────────────────────────────────────────────────────────
   Every value a product may use. Hardcoding a hex in a component is a
   standard violation — the hook blocks it. If a value you need is missing,
   that is a gap in the standard: raise it, do not invent locally. */

:root {
  /* Families. Three, each with one job. Never mix the jobs. */
  --ui:    'Inter', system-ui, sans-serif;              /* interface       */
  --serif: 'Literata', Georgia, serif;                  /* titles + prose  */
  --mono:  'IBM Plex Mono', Consolas, monospace;        /* numbers + IDs   */

  /* Ground and paper. The warm room (Brief, 2026-07-03: "the warm room is
     the whole app — paper, ink, deep green"). Surfaces are never pure white. */
  --ground:      #f3efe7;
  --ground-glow: #faf6ed;   /* radial highlight, see .adri-ground */
  --surface:     #fffdf8;   /* cards, tables, panels                   */
  --surface-2:   #fbf8f1;   /* panel heads, insets, hover              */
  --surface-3:   #faf7ef;   /* table head                              */
  --surface-4:   #f2ece0;   /* pressed, deep inset                     */

  /* Lines, lightest to heaviest. */
  --divider: #f0e9db;   /* inside a card, between sections */
  --rule:    #ece5d7;   /* table row rules                 */
  --border:  #e7e1d5;   /* card and panel edges            */
  --border-2:#ded5c4;   /* control edges                   */
  --border-3:#c9bca4;   /* control hover, emphasis         */
  --border-4:#b3a78c;   /* a hovered chip edge, a scrollbar thumb under the pointer */

  /* Ink, darkest to faintest.

     THE QUIET RAMP HAS ONE RUNG, NOT THREE (2026-08-11). --muted, --faint and
     --label were three steps of quietness below --ink-3. Measured against this
     file's own paper they scored 3.29, 2.00 and 2.25 — all under the 4.5 WCAG AA
     floor, and all used at the SMALLEST sizes in the system (--t-xs 11.5px,
     --t-label 10.5px, --t-micro 9.5px), where the large-text exemption cannot
     apply because nothing here reaches 24px.

     The minimum AA-passing value for each lands on #746a5e, #716a5d and
     #716a5b — one colour with three names. The floor simply does not permit a
     three-rung quiet ramp on warm paper. So there is now ONE quiet text value,
     and the roles that used to be separated by ever-lighter grey are separated
     by type instead — which is what "type has three jobs" already asked for.
     A 10.5px uppercase label with tracking is unmistakable without also being
     too pale to read. */
  --ink:    #241f18;   /* primary text                         */
  --ink-2:  #45403a;   /* body prose                           */
  --ink-3:  #6b6153;   /* secondary, captions                  */
  --muted:  #746a5e;   /* labels, metadata, hints, placeholders */
  --label:  var(--muted);  /* uppercase micro-labels — same ink, told apart by type */
  /* Text and icons on a solid fill: the primary button, a pressed filter chip,
     a count badge, the toast, the help button. Surfaces are never pure white,
     so white appears only here. */
  --on-solid: #ffffff;

  /* NEVER TEXT. Disabled controls only, which WCAG 1.4.3 exempts from the
     contrast floor, plus purely decorative marks that carry no meaning. At 2.31
     on paper this clears neither the 4.5 text floor nor the 3.0 non-text floor,
     so any informational use is a defect — including an icon that tells the
     user something is available. Both of this file's own uses were exactly that
     and have been moved to --muted. */
  --faint:  #b3a894;

  /* Accent. Deep green. Identity is not the same value as action. */
  --accent:     #166b45;   /* identity: links, job numbers, brand mark */
  /* Darkened 2026-08-11 from #1f8a43. That value carried a white label at 4.40
     and read as text on the pressed surface at 3.74 — the ONE primary control
     in the system, below the floor in both directions. Its own hover state
     (--action-h) already passed at 5.77, so the button only became readable
     once you moused over it: an oversight rather than an intent. */
  --action:     #1c7b3c;   /* the ONE primary control on a surface     */
  --action-h:   #17753a;   /* its hover                                */
  --action-p:   #11592b;   /* its pressed state: the press is felt     */
  --accent-sub: #eaf4ec;   /* accent-tinted fill                       */
  --accent-line:#c5e0cf;   /* accent-tinted border                     */
  --accent-h:   #12583a;   /* an accent fill under the pointer (help button) */
  --accent-wash:#f3f8f1;   /* the lightest accent tint: directive, combobox row */
  --accent-wash-line:#dcead6; /* its border                             */
  --accent-ink: #123c22;   /* text on the accent wash (the directive move) */

  /* Armed. A destructive or irreversible confirm, never a resting state. */
  --armed:   #b3460e;
  --armed-h: #9c3c0a;

  /* Severity. SIX tiers, in urgency order. This vocabulary is closed: a
     product may not add a seventh tier or re-map an existing one. Compute the
     tier once in the data layer, then let the UI render it. */
  --off:  #86181d; --off-bg:  #86181d; --off-tx:  #ffffff;  /* turned off   */
  --crit: #86181d; --crit-bg: #fff1f0; --crit-tx: #86181d;  /* critical     */
  --need: #a9740f; --need-bg: #fff8eb; --need-tx: #7a4d00;  /* needs action */
  --mon:  #35688f; --mon-bg:  #eef4fb; --mon-tx:  #0a4a8f;  /* monitor      */
  --ok:   #1f6b34; --ok-bg:   #e8f5ec; --ok-tx:   #1f6b34;  /* on track     */
  --wait: #8b8071; --wait-bg: #f5f5f7; --wait-tx: #6e6e73;  /* waiting      */

  /* Two more values for the same tiers, not new tiers. --need-solid is the
     needs-action tier as a solid fill under an --on-solid label (a pressed
     filter chip, a count badge). White on --need measures 4.04, under the
     4.5 floor, and the same is true of dark ink, so the fill must be darker.
     --need stays the mark: the dot and the row spine. The -line values are
     the edge of a tier-tinted box (a banner). */
  --need-solid: #946509;
  --crit-line: #f5c2c0; --need-line: #f0e0a8; --mon-line: #cde3fb; --ok-line: #b9e3c6;

  /* Materials. A material is what a thing is MADE OF, never what state it is
     in — which is why these sit outside the closed severity vocabulary above
     and may never be used to mean anything. The test: if removing the colour
     would lose information, it is a severity and belongs in that block; if it
     would only lose the object's identity, it is a material and belongs here.

     Sticky-note paper (AI-1052, Valerie Card, 2026-08-18: "is there a way for
     it to look like a yellow sticky note so can see it as soon as open the
     file"). A pinned note that a person chose to put on a record, rendered as
     the paper it is named after. More saturated than --need-bg on purpose so it
     never reads as "needs action": #fff3bd vs #fff8eb. Its edge is the only
     value the high-contrast mode moves — the yellow is the point. */
  --sticky-paper:  #fff3bd;   /* the note                            */
  --sticky-gum:    #ffe994;   /* the gummed strip along its top edge */
  --sticky-line:   #ecd681;   /* its edge                            */
  --sticky-ink:    #4a3d12;   /* body ink on paper — 9.6:1           */
  --sticky-by:     #6d5d24;   /* byline and controls — 5.6:1         */
  --sticky-shadow: rgba(120,96,20,.16);
  --sticky-lift:   #fff8dc;   /* the remove control under the pointer */

  /* The tag on a note item: a small label that names where a note came from. */
  --note-tag:     #e3d6b8;
  --note-tag-ink: #5c5343;   /* 5.3:1 on --note-tag */

  /* System accents. For naming an external system, never for status.
     Used as a 7px dot on a secondary control, never as a filled slab. */
  --sys-dash:      #33456b;
  --sys-symbility: #1a8a96;
  --sys-xactimate: #3a5a86;
  --sys-alacrity:  #6d5bd0;
  --sys-comms:     #1e6fd9;
  --sys-cc:        #b5622a;

  /* Division accents (2026-09-15, Mike Ferrante). For naming a job's division
     on a multi-division loss, never for status — the six severity tiers above
     stay the only status vocabulary. Border colour is the saturated value;
     the -bg tint is the chip's fill, paired with black --ink lettering per
     Mike's direct request. Every -bg tint measures 13:1+ against --ink,
     the solid values do not (2.4-3.5:1 measured) — hence the two-value pair,
     the same shape the severity tiers above already use. */
  /* REC was --accent green (2026-09-15); Mike asked to keep WTR's blue and
     make REC a light red instead. Distinct hue from the severity reds
     (--crit #86181d, --alert #bb3325) so a REC chip is never read as a
     Critical flag. */
  --div-rec: #b23b3b;
  --div-rec-bg: #f3e1e1;
  --div-wtr: #1a7ab8;
  --div-wtr-bg: #dcebf4;
  --div-mld: #5c7a3a;
  --div-mld-bg: #e6ebe1;
  --div-asb: #8a6d1f;
  --div-asb-bg: #ede9dd;
  --div-fire:#9c5a2e;
  --div-fire-bg:#f0e6df;
  --div-con: #6b4f8a;
  --div-con-bg: #e8e4ed;

  /* Radius. Five steps. Nothing between them. */
  --r-xs: 6px;    /* chips, micro-controls        */
  --r-sm: 8px;    /* inputs, buttons, small cards */
  --r-md: 11px;   /* cards, panels                */
  --r-lg: 16px;   /* hero cards, popovers         */
  --r-pill: 999px;

  /* Elevation. Two resting, one lifted. Shadows are warm, never neutral grey. */
  --shadow:    0 1px 2px rgba(60,45,25,.04), 0 8px 24px rgba(60,45,25,.05);
  --shadow-md: 0 8px 28px rgba(40,30,15,.14);
  --shadow-lg: 0 18px 60px rgba(40,30,15,.28);

  /* Type scale. Fixed. Density changes spacing, never type size — that is
     what keeps a dense board and a light form recognisably one system.

     THE FLOOR IS 11px (2026-10-19). Apple's smallest legible size is 11pt on
     iPhone and 10pt on a Mac. The old --t-micro (9.5px) and --t-label (10.5px)
     sat under both, on the quietest ink, in uppercase. They now share the
     floor and stay told apart by weight and tracking.

     IN REM, NOT PX. At the browser's default 16px root each value below is
     the same pixel size as before (13px = .8125rem). A person who sets larger
     text in the browser now gets larger text, which is the web form of
     Apple's Dynamic Type. Never set a font-size on html: it would rescale
     every product at once. */
  --t-micro: .6875rem;   /* 11px    stat labels                 */
  --t-label: .6875rem;   /* 11px    uppercase labels, chips     */
  --t-xs:    .71875rem;  /* 11.5px  metadata, claim numbers     */
  --t-sm:    .78125rem;  /* 12.5px  table body, captions        */
  --t-base:  .8125rem;   /* 13px    interface default           */
  --t-md:    .9375rem;   /* 15px    stat values, emphasis       */
  --t-prose: .96875rem;  /* 15.5px  serif narrative             */
  --t-lg:    1.0625rem;  /* 17px    section heads               */
  --t-xl:    1.375rem;   /* 22px    page titles                 */
  --t-2xl:   1.5rem;     /* 24px    record name (the hero)      */

  /* Touch target. Apple: a control a person taps is at least 44 by 44
     points. On a touch screen every control in this file reaches it (see
     "Touch" below). A mouse is precise, so desktop keeps its density. */
  --hit: 44px;

  /* Density. The two knobs a product may turn. Default is compact: these are
     working tools and more rows on screen beats airy cards (Brief, 2026-07-03,
     Mak: "so much blank space"). Use .adri-comfortable only on low-frequency
     surfaces — intake forms, portals, onboarding. */
  --cell-y: 6px;  --cell-x: 12px;
  --gap:    8px;
  --pad:    16px;

  /* Motion. .12s is the house transition. Celebration is the only exception
     and lives in its own component. */
  --fast: .12s;
  --base: .18s;
  --ease: cubic-bezier(.4, 0, .2, 1);
}

.adri-comfortable { --cell-y: 10px; --cell-x: 16px; --gap: 12px; --pad: 22px; }

/* One appearance, declared. Without this a browser's automatic dark mode
   (Chrome on Android, some Samsung browsers) inverts the paper on its own and
   breaks every severity colour. */
:root { color-scheme: light; }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ── The person's own settings ───────────────────────────────────────────
   Apple answers each accessibility setting with a defined change, never
   with nothing. These are the web forms of the same settings. Each one
   changes values only. The layout never moves.

   Increase Contrast (prefers-contrast: more). The quiet inks reach 7:1 on
   every surface and every control edge reaches 3:1, measured against
   --surface, --surface-2, --surface-4 and --ground. */
@media (prefers-contrast: more) {
  :root {
    --muted:    #544b40;   /* 7.3-8.4:1 */
    --ink-3:    #4a4237;   /* 8.4-9.7:1 */
    --ink-2:    var(--ink);
    --wait-tx:  #4a4a4f;   /* 7.3-8.5:1 */
    --accent:   #0f5234;   /* 7.8-9.1:1 */
    --border:   #9c917c;
    --border-2: #8f8470;   /* 3.1-3.6:1 */
    --border-3: #7a6f5c;
    --rule:     #c2b69f;
    --divider:  #c2b69f;
  }
  a { text-decoration: underline; }
}

/* Windows High Contrast and other forced palettes. The browser replaces
   every colour, so a chip, a pill or a spine that is drawn only by its fill
   disappears. Give each one an edge in the system text colour. */
@media (forced-colors: active) {
  .chip, .pill, .count-badge, .fchip, .btn, .navlink, .banner, .toast, .ai-mark { border: 1px solid CanvasText; }
  .btn.primary, .fchip[aria-pressed="true"], .navlink[aria-current="page"], .navlink.active { border-width: 2px; }
  .board tbody tr[class*="t-"] td.spine { border-left: 3px solid CanvasText; }
  :focus-visible { outline-color: Highlight; }
}

/* Reduce Transparency. The topbar is the one translucent material. */
@media (prefers-reduced-transparency: reduce) {
  .adri-topbar { background: var(--surface); backdrop-filter: none; }
}


/* ── Base ──────────────────────────────────────────────────────────────── */

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

body {
  font-family: var(--ui);
  font-size: var(--t-base);
  color: var(--ink);
  min-height: 100vh;
  background: radial-gradient(1100px 600px at 85% -10%, var(--ground-glow) 0%, transparent 55%), var(--ground);
  /* NOTE: no -webkit-font-smoothing. It thins text on macOS only and does
     nothing on Windows, which widens the gap between the two platforms.
     Omitting it makes both converge. Do not add it back. */
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* A link inside a sentence is underlined. Its green against the body ink is
   2.5:1, so colour alone does not mark it (Apple: never colour alone). A
   link that stands on its own (a job number in a table, a nav pill, a
   button) keeps its own shape and needs no line. */
:where(p, li, dd, .prose, .note .body, .banner, .empty, .directive .why, .modal-msg) a:not([class]) {
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px;
}
button, input, select, textarea { font-family: inherit; font-size: inherit; }
button { cursor: pointer; }

/* Focus is always visible and always the accent. Never remove it. */
:focus-visible { outline: 2px solid var(--action); outline-offset: 2px; border-radius: var(--r-xs); }

/* Type helpers */
.mono   { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.num    { font-variant-numeric: tabular-nums; }
.title  { font-family: var(--serif); font-weight: 600; letter-spacing: -.02em; color: var(--ink); }
.prose  { font-family: var(--serif); font-size: var(--t-prose); line-height: 1.55; color: var(--ink-2); max-width: 58ch; }
.label  { font-size: var(--t-micro); font-weight: 800; letter-spacing: .08em;
          text-transform: uppercase; color: var(--label); }
.clamp2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }


/* ═══════════════════════════════════════════════════════════════════════
   TIER 3 — COMPONENTS
   Use when the pattern applies. A product with no table owes nobody a table.
   But a product that renders a table renders this one.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Shell ─────────────────────────────────────────────────────────────── */

.adri-topbar {
  display: flex; align-items: center; gap: 12px;
  padding: 0 20px; height: 52px;
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 100;
}
/* Ink base is explicit so the mark reads the same whether it is a <div> or an
   <a> linking home — as an anchor it would otherwise inherit the global accent
   link colour and the whole mark, em included, would come out one flat colour. */
.adri-topbar .brand { font-weight: 700; font-size: var(--t-md); letter-spacing: -.3px; color: var(--ink); white-space: nowrap; flex: 0 0 auto; }
.adri-topbar .brand:hover { text-decoration: none; }
/* The mark is the way home when it is a link, so it is a control: 28px at a
   desk, 44px on a touch screen. */
.adri-topbar a.brand { display: inline-block; line-height: 28px; }   /* inline-block, never flex: flex drops the space before <em> */
.adri-topbar .brand em { font-style: normal; color: var(--accent); }
.adri-spring { flex: 1 1 auto; }
.adri-app { max-width: 1440px; margin: 0 auto; padding: var(--pad) 20px 60px; }
.adri-app.reading { max-width: 1100px; }

/* Ecosystem nav. The apps behind brief.advanceddri.com are one product, so the
   link set in the topbar is the same component everywhere: quiet pills, the
   current page filled with the identity accent. Nothing else belongs in the
   topbar — a page's own action buttons go in .page-toolbar, below it, or the nav
   stops being recognisable from one page to the next. */
.navlink {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 11px; border-radius: var(--r-sm);
  border: 1px solid var(--border-2); background: var(--surface);
  color: var(--ink-3); font-size: var(--t-sm); font-weight: 600;
  text-decoration: none; white-space: nowrap;
}
.navlink:hover { border-color: var(--border-3); color: var(--ink); text-decoration: none; }
.navlink:active { background: var(--surface-4); }
.navlink.active,
.navlink[aria-current="page"] { background: var(--accent); border-color: var(--accent); color: var(--surface); }
.navlink.active:hover,
.navlink[aria-current="page"]:hover { background: var(--action-h); border-color: var(--action-h); color: var(--surface); }

/* Mobile nav. Below the breakpoint the topbar can no longer fit brand + count +
   four navlinks + whoami on one line, so the ecosystem nav (everything after
   the toggle button) collapses into a dropdown behind a hamburger.

   .adri-navmenu is display:contents above the breakpoint — it disappears from
   the box model entirely, so its children (count/navlink/whoami) lay out
   exactly as if they were direct children of .adri-topbar. Desktop is
   pixel-identical to before this pattern existed; nothing below this comment
   runs until 760px. A page adopts the pattern by wrapping its navlinks (and
   whoami) in <nav class="adri-navmenu" id="adriNavMenu"> and adding the
   toggle button before it — see design/README.md.

   Open/closed is a .open class, never the hidden attribute — every page here
   already carries its own `[hidden] { display: none !important; }` for toast
   and gate elements, and that !important would have beaten display:contents
   at EVERY width, not just the collapsed one, making the whole nav vanish on
   desktop the moment the menu started closed.

   The icon is two inline SVGs (a standard hamburger/close pair, not hand-
   positioned divs) with every class prefixed adri-navtoggle- rather than a
   bare name like .bar or .icon. .bar collided for real: job.html and
   dashboard.html each define their own page-scoped .bar for progress meters,
   and a hand-built hamburger sharing that name inherited a stray margin-top
   from job.html's rule on every load — visible there, present but subtler on
   dashboard.html too. A component meant to live in every page's topbar cannot
   risk a name a future page might reuse for something unrelated. */
.adri-navtoggle {
  display: none; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0; flex: 0 0 auto;
  border: 1px solid var(--border-2); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink-2); cursor: pointer;
}
.adri-navtoggle:hover { border-color: var(--border-3); background: var(--surface-2); }
.adri-navtoggle svg { width: 20px; height: 20px; display: block; }
.adri-navtoggle .adri-navtoggle-close { display: none; }
.adri-navtoggle[aria-expanded="true"] .adri-navtoggle-open { display: none; }
.adri-navtoggle[aria-expanded="true"] .adri-navtoggle-close { display: block; }
.adri-navmenu { display: contents; }
@media (max-width: 760px) {
  .count { display: none; }   /* redundant with the page body; just overflows here */
  .adri-navtoggle { display: flex; }
  .adri-navmenu {
    display: none; flex-direction: column; align-items: stretch; gap: 8px;
    position: absolute; top: 100%; left: 0; right: 0;
    padding: 12px 16px 16px; background: var(--surface);
    border-bottom: 1px solid var(--border); box-shadow: var(--shadow-lg);
  }
  .adri-navmenu.open { display: flex; }
  .adri-navmenu .navlink { justify-content: flex-start; width: 100%; padding: 10px 12px; }
  .adri-navmenu .whoami {
    text-align: left; padding: 8px 12px 0; margin-top: 4px; border-top: 1px solid var(--divider);
  }
}

/* Page toolbar. A page's own actions live here, never in the topbar. */
.page-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 16px; }
.page-toolbar .adri-spring { flex: 1 1 auto; }
@media (max-width: 760px) {
  /* An empty flex spring only holds a line open when the row has room to stay
     on one line. Once .page-toolbar's buttons wrap, the spring collapses to
     nothing and they read as left-aligned by accident — never the intent. */
  .page-toolbar { justify-content: center; }
  .page-toolbar .adri-spring { display: none; }
}

/* The two other things a topbar carries: a count of what is on screen, and who
   you are signed in as. Both belong to the shell, not to a page. */
.count  { color: var(--muted); font-size: var(--t-sm); font-variant-numeric: tabular-nums; }
.whoami { font-size: var(--t-sm); color: var(--muted); text-align: right; line-height: 1.3; }
.whoami b { display: block; color: var(--ink); font-weight: 600; }


/* ── Severity chip. The six-tier vocabulary, rendered. ─────────────────── */

.chip {
  display: inline-block; padding: 2px 8px; border-radius: 5px;
  font-size: var(--t-label); font-weight: 700; letter-spacing: .2px; white-space: nowrap;
}
.chip.off  { background: var(--off-bg);  color: var(--off-tx);  }
.chip.crit { background: var(--crit-bg); color: var(--crit-tx); }
.chip.need { background: var(--need-bg); color: var(--need-tx); }
.chip.mon  { background: var(--mon-bg);  color: var(--mon-tx);  }
.chip.ok   { background: var(--ok-bg);   color: var(--ok-tx);   }
.chip.wait { background: var(--wait-bg); color: var(--wait-tx); }

/* Tier text colour. The same six tiers for a severity word set in running prose
   rather than in a chip ("This job's risk is CRITICAL"). Takes the same tier
   class, so a sentence and a chip cannot disagree. */
.tx-off  { color: var(--off-tx); }
.tx-crit { color: var(--crit-tx); }
.tx-need { color: var(--need-tx); }
.tx-mon  { color: var(--mon-tx); }
.tx-ok   { color: var(--ok-tx); }
.tx-wait { color: var(--wait-tx); }

.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--r-pill);
  background: var(--surface-4); color: var(--muted);
  font-size: var(--t-xs); font-weight: 800; letter-spacing: .3px;
}
.pill.need { background: var(--need-bg); color: var(--need-tx); }
.pill.crit { background: var(--crit-bg); color: var(--crit-tx); }


/* ── Board. The dense data table. ──────────────────────────────────────── */

.board {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; box-shadow: var(--shadow); overflow: hidden;
}
/* Wide content scrolls inside its own box. The page body NEVER scrolls
   sideways — that is a hard layout invariant, not a preference. */
.board .scroll {
  overflow: auto; max-height: calc(100vh - 210px);
  /* dvh tracks the mobile browser's ACTUAL visible viewport, so this stops
     recalculating (and visibly jumping) every time the address bar hides or
     shows mid-scroll — vh alone is fixed to the largest-possible viewport and
     never sees that change. Browsers without dvh support just keep the vh
     value above; this is a second declaration, not a replacement. */
  max-height: calc(100dvh - 210px);
}
.board table { border-collapse: collapse; width: 100%; }
.board thead th {
  text-align: left; padding: 7px var(--cell-x);
  font-size: var(--t-label); font-weight: 700; letter-spacing: .5px;
  text-transform: uppercase; color: var(--label); background: var(--surface-3);
  border-bottom: 1px solid var(--border-2); white-space: nowrap;
  position: sticky; top: 0; z-index: 2;
}
.board tbody td {
  padding: var(--cell-y) var(--cell-x); border-bottom: 1px solid var(--rule);
  vertical-align: middle; font-size: var(--t-sm); line-height: 1.35;
}
.board tbody tr:last-child td { border-bottom: none; }
.board tbody tr[data-row] { cursor: pointer; }
.board tbody tr[data-row]:hover td { background: rgba(22,107,69,.045); }
/* While a wheel scroll is in flight the pointer sits still and the ROWS move
   under it, so :hover repaints every row in turn and reads as the colors
   changing on their own. Add .scrolling for ~140ms during scroll. */
.board .scroll.scrolling tbody tr[data-row]:hover td { background: none; }

.board .cell-id   { font-family: var(--mono); color: var(--accent); font-weight: 700; }
.board .cell-name { font-weight: 600; color: var(--ink); white-space: nowrap; }
.board .cell-num  { font-variant-numeric: tabular-nums; color: var(--ink-2); }
.board .cell-meta { font-family: var(--mono); color: var(--muted); font-size: var(--t-xs); }

/* Severity spine. A 3px inset marker plus a wash on the first cell, so a row's
   tier is readable while scanning a long board without hunting for its chip.
   Put .spine on the FIRST cell and a t-<tier> class on the row; the tier is the
   same closed six-tier vocabulary as .chip, so a row and its chip can never
   disagree. Compute the tier in the data layer, never per page.

   This is a genuine addition to the standard rather than a local invention: the
   risk board's whole job is triage by severity, and the system had no row-level
   severity treatment. Any product with a severity-ranked table should use it. */
.board tbody tr.t-off  td.spine { box-shadow: inset 3px 0 0 var(--off);  background: var(--off-bg);  }
.board tbody tr.t-crit td.spine { box-shadow: inset 3px 0 0 var(--crit); background: var(--crit-bg); }
.board tbody tr.t-need td.spine { box-shadow: inset 3px 0 0 var(--need); background: var(--need-bg); }
.board tbody tr.t-mon  td.spine { box-shadow: inset 3px 0 0 var(--mon);  background: var(--mon-bg);  }
.board tbody tr.t-ok   td.spine { box-shadow: inset 3px 0 0 var(--ok);   background: var(--ok-bg);   }
.board tbody tr.t-wait td.spine { box-shadow: inset 3px 0 0 var(--wait); background: var(--wait-bg); }
/* The off tier is a solid dark fill, so its spine text needs the light ink. */
.board tbody tr.t-off td.spine { color: var(--off-tx); }

/* Chunky always-visible scrollbars. Overlay scrollbars hide until you scroll,
   which made the horizontal bar impossible to find on a wide board. */
.board .scroll::-webkit-scrollbar { height: 14px; width: 14px; -webkit-appearance: none; }
.board .scroll::-webkit-scrollbar-track { background: var(--surface-4); }
.board .scroll::-webkit-scrollbar-thumb { background: var(--border-3); border-radius: 7px; border: 3px solid var(--surface-4); }
.board .scroll::-webkit-scrollbar-thumb:hover { background: var(--border-4); }


/* ── Stat strip. One segmented unit, not loose tiles of ragged widths. ─── */

.stats {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(96px, max-content);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); overflow: hidden; width: max-content;
}
.stat { padding: 9px 16px; border-left: 1px solid var(--divider); min-width: 0; }
.stat:first-child { border-left: none; }
.stat .k { font-size: var(--t-micro); font-weight: 800; letter-spacing: .08em;
           text-transform: uppercase; color: var(--label); }
.stat .v { margin-top: 2px; font-family: var(--mono); font-size: var(--t-md);
           font-weight: 600; letter-spacing: -.2px; color: var(--ink);
           font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 760px) {
  .stats { grid-auto-flow: row; width: 100%; }
  .stat { border-left: none; border-top: 1px solid var(--divider); }
  .stat:first-child { border-top: none; }
}


/* ── Filter chips. The counts ARE the filters. ─────────────────────────── */

.fchips { display: flex; gap: 6px; flex-wrap: wrap; }
.fchip {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 6px 12px; border-radius: var(--r-pill);
  border: 1px solid var(--border-2); background: var(--surface);
  font-size: 12px; font-weight: 600; color: var(--ink-2);
  cursor: pointer; transition: all var(--fast);
}
.fchip b { font-size: var(--t-base); font-weight: 700; }
.fchip:hover { border-color: var(--border-4); }
.fchip:active { background: var(--surface-4); }
.fchip.crit { color: var(--crit-tx); }
.fchip.need { color: var(--need-tx); }
.fchip.mon  { color: var(--mon-tx);  }
.fchip[aria-pressed="true"].crit { background: var(--crit); border-color: var(--crit); color: var(--on-solid); }
.fchip[aria-pressed="true"].need { background: var(--need-solid); border-color: var(--need-solid); color: var(--on-solid); }
.fchip[aria-pressed="true"].mon  { background: var(--mon);  border-color: var(--mon);  color: var(--on-solid); }
.fchip[aria-pressed="true"]      { background: var(--ink);  border-color: var(--ink);  color: var(--surface); }


/* ── Buttons. ONE primary per surface. ─────────────────────────────────────
   Everything else is a calm paper button. A secondary that names an external
   system carries a 7px color DOT, never a filled slab — six competing tints
   made the rail read as noise (Brief, 2026-07-27).

   A control must do what it says. If a move has no instrument behind it, it
   renders as a directive line, not a button. A button that does not do what
   it says is a broken promise. */

.btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 16px; border-radius: var(--r-sm);
  border: 1px solid var(--border-2); background: var(--surface);
  color: var(--ink); font-size: var(--t-base); font-weight: 600;
  transition: background var(--fast), border-color var(--fast);
}
.btn:hover { background: var(--surface-2); border-color: var(--border-3); }
.btn.primary { background: var(--action); border-color: var(--action); color: var(--on-solid); font-weight: 700; }
.btn.primary:hover { background: var(--action-h); border-color: var(--action-h); }
/* Armed = one tap from irreversible. Never a resting state. */
.btn.primary.armed { background: var(--armed); border-color: var(--armed); }
.btn.primary.armed:hover { background: var(--armed-h); border-color: var(--armed-h); }
.btn.quiet { border-color: transparent; background: none; color: var(--muted); }
.btn.quiet:hover { background: var(--surface-2); color: var(--ink); }
/* Pressed. Apple gives every control a highlighted state, so the press is
   felt before the result arrives. On a touch screen there is no hover, so
   this is the only feedback the finger gets. */
.btn:active { background: var(--surface-4); border-color: var(--border-3); }
.btn.primary:active { background: var(--action-p); border-color: var(--action-p); }
.btn.primary.armed:active { background: var(--armed-h); border-color: var(--armed-h); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .55; cursor: default; }
/* Working. The label stays, so the person still reads what they pressed;
   adrios-ui.js swaps the words to the state ("Sending…"). */
.btn[aria-busy="true"] { cursor: progress; opacity: .8; }
.btn .kbd { font-size: var(--t-xs); opacity: .55; font-weight: 500; }

.btn.dot { position: relative; padding-left: 26px; }
.btn.dot::before {
  content: ''; position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  width: 7px; height: 7px; border-radius: 50%; background: var(--border-3);
}
.btn.dot.dash::before      { background: var(--sys-dash); }
.btn.dot.symbility::before { background: var(--sys-symbility); }
.btn.dot.xactimate::before { background: var(--sys-xactimate); }
.btn.dot.alacrity::before  { background: var(--sys-alacrity); }
.btn.dot.comms::before     { background: var(--sys-comms); }

/* The directive line: the move stated, when there is no in-app instrument. */
.directive {
  background: var(--accent-wash); border: 1px solid var(--accent-wash-line); border-left: 3px solid var(--action);
  border-radius: var(--r-md); padding: 13px 16px;
}
.directive .move { font-size: var(--t-md); font-weight: 650; color: var(--accent-ink); line-height: 1.4; }
.directive .why  { margin-top: 7px; font-size: 12px; color: var(--muted); line-height: 1.45; }


/* ── Form controls ─────────────────────────────────────────────────────── */

.field, .input, .select, .textarea {
  width: 100%; padding: 8px 11px; border-radius: var(--r-sm);
  border: 1px solid var(--border-2); background: var(--surface);
  color: var(--ink); font-size: var(--t-base); line-height: 1.4;
}
.textarea { min-height: 64px; resize: vertical; }
/* Focus stays visible on a field. The border change alone is a 1px shift
   that a user cannot find, so the ring from the base :focus-visible rule
   stays on, drawn tighter to the field. */
.field:focus, .input:focus, .select:focus, .textarea:focus {
  outline: 2px solid var(--action); outline-offset: 1px; border-color: var(--action);
}
.input.bad, .textarea.bad { border-color: var(--crit); background: var(--crit-bg); }
.search { border-radius: var(--r-pill); background: var(--surface-4); padding: 0 15px; height: 34px; }
.search:focus { background: var(--surface); box-shadow: 0 0 0 3px rgba(22,107,69,.10); }
/* iOS Safari zooms the whole page when a focused field has text under 16px,
   and it does not zoom back out. On a phone every field gets 16px. This is the
   one place the type scale bends: the scale is fixed, the zoom is not ours. */
@media (max-width: 760px) {
  input, select, textarea, .field, .input, .select, .textarea, .search { font-size: 16px; }
}


/* ── Slide-in record panel ─────────────────────────────────────────────── */

.adri-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,.28);
  opacity: 0; pointer-events: none; transition: opacity var(--base); z-index: 200;
}
.adri-overlay.open { opacity: 1; pointer-events: auto; }

.panel {
  position: fixed; top: 0; right: 0; height: 100vh; height: 100dvh;
  width: 940px; max-width: 96vw; background: var(--surface);
  box-shadow: -8px 0 30px rgba(40,30,15,.14); z-index: 201;
  transform: translateX(100%); transition: transform .2s ease;
  display: flex; flex-direction: column;
}
.panel.open { transform: translateX(0); }
/* Head is wayfinding chrome in ONE fixed row. It never scrolls away, and the
   body below opens with the RECORD — serial position: the record opens the
   surface, navigation is chrome. */
.panel-head {
  display: flex; align-items: center; gap: var(--gap);
  padding: 11px 16px; border-bottom: 1px solid var(--border); background: var(--surface-2);
  flex: 0 0 auto;
}
.panel-body { overflow-y: auto; padding: var(--pad) 20px 28px; flex: 1 1 auto; }
.panel-cols { display: grid; grid-template-columns: 1.08fr .92fr; gap: 0 26px; align-items: start; }
.panel-cols > .ref { border-left: 1px solid var(--divider); padding-left: 24px; }
@media (max-width: 1000px) {
  .panel-cols { grid-template-columns: 1fr; }
  .panel-cols > .ref { border-left: none; padding-left: 0; }
}


/* ── Record masthead. Name is the hero, state sits beside it. ──────────── */

.mast-id { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.mast-name { font-size: var(--t-2xl); font-weight: 650; letter-spacing: -.5px; color: var(--ink); }
.mast-sub {
  margin-top: 7px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: var(--t-sm); color: var(--muted);
}
.mast-sub .mono { color: var(--accent); font-weight: 700; }


/* ── Collapsible section ───────────────────────────────────────────────── */

.section { margin-top: 18px; border-top: 1px solid var(--divider); padding-top: 13px; }
.section > .head {
  display: flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--label);
}
.section > .head .chev { font-size: 11px; transition: transform .15s; }
.section.open > .head .chev { transform: rotate(90deg); }
.section > .body { display: none; margin-top: 10px; }
.section.open > .body { display: block; }

/* Key/value ledger. Anything retyped elsewhere is click-to-copy —
   interaction cost is a bug. */
.kv { display: grid; grid-template-columns: 108px 1fr; gap: 5px 12px; font-size: var(--t-base); }
.kv .k { color: var(--muted); }
.kv .v { color: var(--ink); }
.copyable { cursor: copy; }
.copyable:hover { color: var(--accent); }
/* --muted, not --faint: this glyph is the affordance telling the user the value
   can be copied, so it is informational and owes the 3:1 non-text floor at
   minimum. --faint cleared neither floor. */
.copyable:hover::after { content: '⧉'; margin-left: 5px; color: var(--muted); font-size: 11px; }


/* ── Timeline / note item ──────────────────────────────────────────────── */

.note {
  padding: 10px 12px; background: var(--surface-2); border-left: 2px solid var(--border-2);
  border-radius: var(--r-xs); margin-bottom: var(--gap);
}
.note .meta { font-size: 12px; color: var(--muted); margin-bottom: 3px; }
.note .meta strong { color: var(--ink); }
.note .body { font-size: var(--t-base); line-height: 1.45; color: var(--ink-2); }
/* Borrowed context. Visibly indented and tagged so it can never be mistaken
   for the record you opened. */
.note.foreign { border-left-color: var(--border-3); background: var(--ground); margin-left: 14px; }
.note .tag {
  font-size: 11px; font-weight: 700; letter-spacing: .03em; padding: 1px 6px;
  border-radius: 4px; background: var(--note-tag); color: var(--note-tag-ink); margin-left: 6px;
}


/* ── Sticky note ───────────────────────────────────────────────────────────
   A short fact a PERSON chose to pin to a record so the next person does not
   have to read its whole history. Distinct from .note above, which is a system
   record of something that happened: a sticky is disposable, authored, and
   removable, and it looks like paper because that is what it is standing in
   for. Never a status, never a task, never a system message.

   Three cues, so the object survives a colourblind eye and a bad monitor: the
   paper, the gummed strip across the top, and the lift. Hue alone is never the
   signal. Near-square corners on purpose — paper is cut, not rounded. */

.sticky {
  display: flex; align-items: flex-start; gap: 8px; border-radius: 3px;
  background: linear-gradient(var(--sticky-gum) 0 7px, var(--sticky-paper) 7px);
  border: 1px solid var(--sticky-line); padding: 12px 10px 9px 11px;
  box-shadow: 0 1px 2px var(--sticky-shadow);
}
.sticky .body {
  flex: 1; min-width: 0; font-size: var(--t-base); line-height: 1.45;
  color: var(--sticky-ink); overflow-wrap: anywhere; white-space: pre-wrap;
}
/* Attribution is quiet by default: the note is the point, the byline is the
   audit. */
.sticky .by { display: block; font-size: var(--t-label); color: var(--sticky-by); margin-top: 3px; }
/* Remove. Reads against the PAPER, never against the surface behind it. */
.sticky .x {
  flex: 0 0 auto; border: 1px solid transparent; background: none; padding: 0 5px;
  border-radius: var(--r-xs); font-size: 12px; line-height: 1.5; font-family: var(--ui);
  color: var(--sticky-by); cursor: pointer;
  transition: background var(--fast), color var(--fast), border-color var(--fast);
}
.sticky .x:hover { background: var(--sticky-lift); color: var(--armed); border-color: var(--sticky-line); }
/* The mark stays small on the paper. Its hit area reaches 24px at a desk and
   44px on a touch screen (see "Touch"). */
.sticky .x { position: relative; }
.sticky .x::after { content: ''; position: absolute; inset: -4px; }


/* ── Modal ─────────────────────────────────────────────────────────────── */

.modal-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,.35);
  display: none; align-items: center; justify-content: center; z-index: 300;
}
.modal-overlay.open { display: flex; }
.modal {
  background: var(--surface); width: 460px; max-width: 92vw; max-height: 88vh;
  overflow-y: auto; border-radius: 12px; padding: 20px; box-shadow: var(--shadow-lg);
}
.modal.wide { width: min(820px, 95vw); }
.modal .modal-title { font-family: var(--serif); font-size: var(--t-lg); font-weight: 600; margin-bottom: 12px; }
/* The message under a confirm's title: what happens, to which record, and
   whether it can be taken back. */
.modal .modal-msg { color: var(--ink-2); line-height: 1.45; }
.modal .modal-msg + .modal-msg { margin-top: 8px; }
.modal label { display: block; font-size: 12px; font-weight: 600; color: var(--ink-3); margin: 12px 0 6px; }
.modal-actions { display: flex; justify-content: flex-end; gap: var(--gap); margin-top: 18px; }
/* On a phone the choices stack full width, the act on top and Cancel under
   it, where a thumb reaches both (Apple's action sheet). Markup order stays
   Cancel first, act last, so a keyboard reaches Cancel first. */
@media (max-width: 760px) {
  .modal-actions { flex-direction: column-reverse; align-items: stretch; }
  .modal-actions .btn { justify-content: center; }
}


/* ── Toast ─────────────────────────────────────────────────────────────── */

.toast {
  position: fixed; bottom: calc(24px + env(safe-area-inset-bottom, 0px)); left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--ink); color: var(--on-solid); padding: 11px 18px; border-radius: 10px;
  font-size: var(--t-base); font-weight: 500; opacity: 0; pointer-events: none;
  transition: opacity .2s, transform .2s; z-index: 400; box-shadow: 0 6px 24px rgba(0,0,0,.25);
}
.toast.open { opacity: 1; transform: translateX(-50%) translateY(0); }


/* ── Banners and states ────────────────────────────────────────────────────
   Empty is an ANSWER, not a spinner. A known-empty state says so and says
   when it was checked. A spinner that can never resolve is a defect. */

.banner { border-radius: var(--r-sm); padding: 9px 13px; font-size: 12px; margin-bottom: 12px; }
.banner.info { background: var(--mon-bg);  border: 1px solid var(--mon-line);  color: var(--mon-tx); }
.banner.warn { background: var(--need-bg); border: 1px solid var(--need-line); color: var(--need-tx); }
.banner.err  { background: var(--crit-bg); border: 1px solid var(--crit-line); color: var(--crit-tx); }
.banner.ok   { background: var(--ok-bg);   border: 1px solid var(--ok-line);   color: var(--ok-tx); }

.empty { text-align: center; padding: 40px 24px; color: var(--muted); font-size: var(--t-base); }
.empty .h { font-family: var(--serif); font-size: var(--t-lg); font-weight: 600; color: var(--ink); margin-bottom: 5px; }
/* --muted, not --faint: "an empty state says WHEN it was checked" is the whole
   point of this line — it is the evidence, not decoration. */
.empty .checked { display: block; margin-top: 9px; font-size: var(--t-xs); color: var(--muted); }

.spinner {
  display: inline-block; width: 18px; height: 18px;
  border: 2px solid var(--border-2); border-top-color: var(--action);
  border-radius: 50%; animation: adri-spin .7s linear infinite;
  vertical-align: middle; margin-right: var(--gap);
}
@keyframes adri-spin { to { transform: rotate(360deg); } }


/* ── Combobox. Use over a <select> once a list passes ~15 items. ───────── */

.combo { position: relative; }
.combo-list {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 50;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-md);
  max-height: 280px; overflow-y: auto; display: none;
}
.combo-list.open { display: block; }
.combo-row { padding: 9px 12px; cursor: pointer; border-bottom: 1px solid var(--rule); }
.combo-row:last-child { border-bottom: none; }
.combo-row:hover, .combo-row.on { background: var(--accent-wash); }
.combo-row .c { float: right; color: var(--muted); font-size: var(--t-xs); }


/* ── Help affordance. Every product carries the route to the AI team. ──── */

.help-fab {
  position: fixed; z-index: 200;
  right: calc(22px + env(safe-area-inset-right, 0px));
  bottom: calc(22px + env(safe-area-inset-bottom, 0px));
  box-sizing: border-box; height: 50px; max-width: 50px; overflow: hidden;
  display: inline-flex; align-items: center; gap: 9px; padding: 0 16px;
  border: none; border-radius: var(--r-pill);
  background: var(--accent); color: var(--on-solid); font-size: 14px; font-weight: 600;
  text-decoration: none; white-space: nowrap; cursor: pointer;
  box-shadow: 0 4px 14px rgba(0,0,0,.20);
  transition: max-width .34s var(--ease), box-shadow var(--base), background var(--base);
}
.help-fab:hover { max-width: 190px; background: var(--accent-h); text-decoration: none; box-shadow: 0 6px 20px rgba(0,0,0,.26); }
.help-fab .fab-ico { flex: 0 0 auto; width: 18px; text-align: center; font-size: 20px; line-height: 1; font-weight: 700; }
.help-fab .fab-label { opacity: 0; transition: opacity .2s ease .04s; }
.help-fab:hover .fab-label { opacity: 1; }
/* Reduced motion removes the width animation, which is the movement. The colour
   and shadow changes stay: they are feedback that the control is live, and
   removing them leaves a button that looks inert under the cursor. */
@media (prefers-reduced-motion: reduce) { .help-fab { transition: box-shadow var(--base), background var(--base); } }


/* ── Count badge. A small numeric bubble that attaches to a nav link or a
   button, showing how many things need attention right now (unread notes,
   promises due, files past SLA). It is not the same thing as .btn.dot: the
   dot names an external system on a secondary control, this badge counts
   items needing action on whatever it is pinned to.

   Only two severity states exist, because a count badge answers one
   question, "does this need attention today or is it already late," and
   that maps directly onto two rungs of the closed six-tier vocabulary: NEEDS
   ACTION (--need, due today, a warning) and CRITICAL (--crit, overdue, the
   most urgent state the system has). No third tier is introduced, and the
   tokens are the same ones every chip and spine already use, so a badge and
   a chip for the same job can never disagree.

   ZERO STATE: when the count is 0, do not render a badge showing "0". Remove
   the element from the DOM entirely. An empty state is an answer, per the
   standard, and a bubble reading "0" is noise sitting on a control that has
   nothing to report.

   ONE-SHOT ATTENTION, NEVER A PULSE: a badge that animates forever asks for
   an exemption the standard does not grant, since .12s is the house
   transition and celebration is the only named exception to it. Instead the
   badge plays a single settle-and-pop once, the moment it first appears, via
   the .pop class the consuming app adds on first render (and may remove once
   the animation ends, since a finished one-shot needs no class to hold it
   steady). The keyframes run with the default iteration count of one and
   never repeat, so this rule must never gain an unbounded repeat count. */

.count-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 17px; height: 17px; padding: 0 5px; box-sizing: border-box;
  border-radius: var(--r-pill);
  font-family: var(--mono); font-size: var(--t-label); font-weight: 700;
  line-height: 1; letter-spacing: 0; white-space: nowrap;
  font-variant-numeric: tabular-nums; /* numerals stay mono and tabular, never proportional */
}
.count-badge.need { background: var(--need-solid); color: var(--on-solid); }
.count-badge.crit { background: var(--crit); color: var(--on-solid); }

/* Overflow. The app caps the label at "99+" (or similar) before handing it to
   the badge; this component never truncates or does the math itself. The
   rule below keeps 1, 2, or 3 characters legible and keeps the badge from
   stretching the control it sits on: it stays a circle at one digit and
   grows into a short pill at two or three, never wider than it needs to be. */
.count-badge { max-width: 34px; overflow: hidden; text-overflow: clip; }

/* Attachment. Give the host (a .navlink, a .btn, any inline control) its own
   `position: relative`, then add `.corner` to lift the badge out of the flow
   and pin it to the host's top-right corner. The 2px border, in the colour
   of whatever surface the host sits on, reads as a notch cut into the host
   rather than a shape floating beside it. */
.count-badge.corner {
  position: absolute; top: -7px; right: -7px;
  border: 2px solid var(--surface);
}

/* The one-shot settle: a quick overshoot-and-rest, not a loop. */
@keyframes adri-badge-pop {
  0%   { transform: scale(.4); opacity: 0; }
  55%  { transform: scale(1.18); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
.count-badge.pop { animation: adri-badge-pop .32s var(--ease); }
@media (prefers-reduced-motion: reduce) {
  .count-badge.pop { animation: none; }
}


/* ── AI mark. Text the system drafted, said once and the same way. ────────
   Apple: say clearly where AI made something, and never let a person take
   it for a person's words. One mark, one wording, everywhere: "AI draft",
   with what the person does next ("check it before you send"). It is a
   material label, not a severity, so it uses no tier colour. A draft that
   leaves ADRI still waits for a person (the user stays the decider). */
.ai-mark {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 2px 9px; border-radius: var(--r-pill);
  background: var(--surface-4); color: var(--ink-3);
  font-size: var(--t-xs); font-weight: 700; letter-spacing: .2px; white-space: nowrap;
}
.ai-mark::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--ink-3); }


/* ── Touch. The 44px target, on a touch screen only. ──────────────────────
   Apple's floor for a tapped control is 44 by 44 points. A finger is not a
   pointer: a field PM in a van, a rep in a car, a 70-year-old customer. So on
   a touch screen (pointer: coarse) every control in this file is at least
   --hit tall, and an icon control is --hit wide. A mouse stays dense: none of
   this runs at a desk.

   A small control that must keep its look (the sticky note's remove mark)
   keeps it and gets an invisible hit area that reaches 44px instead. This
   block sits last in the file so it wins over each component's own size. */
@media (pointer: coarse) {
  .btn, .navlink, .field, .input, .select, .combo-row { min-height: var(--hit); }
  .fchip { min-height: var(--hit); align-items: center; }
  .search { height: var(--hit); }
  .adri-navtoggle { width: var(--hit); height: var(--hit); }
  .section > .head { min-height: var(--hit); }
  .adri-topbar a.brand { line-height: var(--hit); }
  .adri-navmenu .navlink { min-height: var(--hit); }
  input[type="checkbox"], input[type="radio"] { width: 22px; height: 22px; }
  .sticky .x::after { inset: -12px; }
}
