/* ============================================================== tokens ======
   Every colour, size, space, radius, shadow and duration in the interface is
   defined once, here. Nothing downstream carries a literal value.

   The rule that makes this work: components read tokens, never raw values, and
   tokens are only ever redefined as a complete set. A colour defined inside a
   single theme block is the classic bug, because the un-stamped state (a viewer
   on "system") never sees it and the page renders one theme's text on the
   other theme's ground.

   Three states, not two:
     :root                                       light, the ground state
     @media (prefers-color-scheme: dark)         the OS asked for dark
     :root[data-theme="dark" | "light"]          the person asked explicitly
   ========================================================================= */

/* ---------------------------------------------------------------- faces --
   Served from this machine, not a font CDN. The app promises that nothing
   leaves the machine except the documents you choose to have read, and a
   stylesheet request to a third party on every load would quietly break that.

   Three voices with three jobs. Fraunces is the editorial serif, for titles
   and the figures worth reading at a glance. Plex Sans carries everything
   read in sentences. Plex Mono is for labels, timestamps and anything that
   is data rather than prose. Fraunces is variable, so its optical size axis
   thins the strokes at display sizes without a second file. */

@font-face { font-family: "Fraunces"; src: url(/fonts/fraunces.woff2) format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Sans"; src: url(/fonts/plex-sans-400.woff2) format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Sans"; src: url(/fonts/plex-sans-500.woff2) format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Sans"; src: url(/fonts/plex-sans-600.woff2) format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url(/fonts/plex-mono-400.woff2) format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url(/fonts/plex-mono-500.woff2) format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url(/fonts/plex-mono-600.woff2) format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }

:root {
  color-scheme: light;

  /* --------------------------------------------------------------- type --
     Seven sizes, base 16px. The six-step scale runs at ratio 1.25; the
     seventh, eyebrow, exists only for uppercase mono labels, which read a
     full step larger than their pixel size because every letter is a capital.
     There is nowhere off-scale for a new screen to go. */

  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-sans: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --fs-display: 2.75rem;     /* 44 */
  --fs-heading: 1.875rem;    /* 30 */
  --fs-title: 1.3125rem;     /* 21 */
  --fs-body: 1rem;           /* 16 */
  --fs-small: 0.875rem;      /* 14 */
  --fs-label: 0.8125rem;     /* 13 */
  --fs-eyebrow: 0.6875rem;   /* 11 */

  --lh-display: 1.03;
  --lh-heading: 1.15;
  --lh-title: 1.3;
  --lh-body: 1.6;
  --lh-small: 1.5;
  --lh-label: 1.35;

  /* Large type needs negative tracking to stop it reading as loose; small
     uppercase needs positive tracking to stop it reading as a word. */
  --ls-display: -0.02em;
  --ls-heading: -0.015em;
  --ls-title: -0.01em;
  --ls-body: 0;
  --ls-label: 0.02em;
  --ls-eyebrow: 0.12em;

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;

  /* ------------------------------------------------------------- space --
     An 8px grid. Overlay it on any screen and the lines should land. */

  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;
  --sp-9: 96px;

  /* ------------------------------------------------------------ layout --
     The shell is wider than the measure on purpose. Cards and grids can use
     the full width; running prose is capped at a comfortable line length,
     because this is a product people read diagnoses and debriefs in. */

  --page-max: 960px;
  --measure: 68ch;
  --header-h: 56px;

  /* ------------------------------------------------------------ radius --
     Nearly square. Edges are drawn with hairlines, like a printed page, and
     a generous radius on a hairline box reads as a widget rather than a
     document. Full is for the record dot and nothing else. */

  --radius-sm: 2px;
  --radius-md: 3px;
  --radius-lg: 4px;
  --radius-full: 999px;

  /* ------------------------------------------------------------ motion --
     One curve. Things enter with a small rise and leave faster than they
     arrive, because an exit that lingers reads as lag. */

  --ease: cubic-bezier(.2, .8, .3, 1);
  --dur-fast: 150ms;
  --dur-base: 200ms;
  --dur-slow: 260ms;

  /* ------------------------------------------------------------ colour --
     Light is the ground state: a grey paper with a few degrees of green in
     it, one deep teal accent, and a warm red for risk. The neutrals carry
     the accent's hue so they read as chosen rather than defaulted. */

  --ground: #F1F3F2;
  --surface: #FAFBFA;
  --sunken: #E8ECEA;
  --raised: #FFFFFF;

  --line: #D3DAD7;
  --line-soft: #E0E5E3;
  --line-strong: #B9C3BF;

  --ink: #161A19;        /* 15.8:1 on ground */
  --ink-2: #48524E;      /*  7.3:1 */
  --ink-3: #5E6964;      /*  4.8:1 on the sunken surface, its worst case */

  --accent: #0B5D52;     /*  7.0:1 on ground, 7.5:1 carrying the surface */
  --accent-hover: #084B42;
  --accent-ink: #FAFBFA;
  --accent-soft: rgba(11, 93, 82, .08);
  --accent-line: rgba(11, 93, 82, .30);

  --ok: #3F6B34;
  --ok-soft: rgba(63, 107, 52, .09);
  --ok-line: rgba(63, 107, 52, .30);
  --warn: #7A5300;
  --warn-soft: rgba(122, 83, 0, .08);
  --warn-line: rgba(122, 83, 0, .30);
  --crit: #A83A2C;
  --crit-soft: rgba(168, 58, 44, .08);
  --crit-line: rgba(168, 58, 44, .30);

  /* --------------------------------------------------------- elevation --
     Depth comes from a hairline first and a shadow only when something
     genuinely floats. No gradients, no glass, no glow. */

  --elev-1: none;
  --elev-2: 0 1px 0 rgba(22, 26, 25, .04), 0 6px 18px rgba(22, 26, 25, .06);
  --elev-3: 0 2px 6px rgba(22, 26, 25, .08), 0 24px 56px rgba(22, 26, 25, .14);
  --scrim: rgba(22, 26, 25, .36);
  --skeleton: #E3E8E6;
  --skeleton-sheen: #F1F4F3;

  /* A ring with a gap, so it reads as designed rather than as a browser
     default fighting the border underneath it. */
  --focus-ring: 0 0 0 2px var(--ground), 0 0 0 4px var(--accent);
}

/* The OS asked for dark, and no explicit choice overrides it. Only tokens are
   redefined here, never component rules. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    /* Designed, not inverted: the surfaces sit closer together than their
       light counterparts, the accent lifts to a lighter teal so it does not
       sink into the ground, and the shadows are shorter and softer. */
    --ground: #0F1312;
    --surface: #171C1B;
    --sunken: #131817;
    --raised: #1D2322;

    --line: #2A3331;
    --line-soft: #202826;
    --line-strong: #3A4542;

    --ink: #E7EDEA;      /* 15.8:1 on ground */
    --ink-2: #B0BBB6;    /*  9.5:1 */
    --ink-3: #909D97;    /*  6.1:1 on the surface, its worst case */

    --accent: #5FBFAC;   /*  8.5:1 on ground */
    --accent-hover: #7BCDBC;
    --accent-ink: #0F1312;
    --accent-soft: rgba(95, 191, 172, .10);
    --accent-line: rgba(95, 191, 172, .32);

    --ok: #8FBF7F;
    --ok-soft: rgba(143, 191, 127, .10);
    --ok-line: rgba(143, 191, 127, .32);
    --warn: #D9AC5C;
    --warn-soft: rgba(217, 172, 92, .10);
    --warn-line: rgba(217, 172, 92, .32);
    --crit: #E08476;
    --crit-soft: rgba(224, 132, 118, .10);
    --crit-line: rgba(224, 132, 118, .32);

    --elev-1: none;
    --elev-2: 0 1px 0 rgba(0, 0, 0, .30), 0 6px 18px rgba(0, 0, 0, .28);
    --elev-3: 0 2px 6px rgba(0, 0, 0, .45), 0 24px 56px rgba(0, 0, 0, .40);
    --scrim: rgba(5, 7, 7, .64);
    --skeleton: #1E2524;
    --skeleton-sheen: #283130;
  }
}

/* An explicit choice wins in both directions: dark on a light OS, and light on
   a dark OS. The light branch needs no body because :root already holds it. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --ground: #0F1312;
  --surface: #171C1B;
  --sunken: #131817;
  --raised: #1D2322;

  --line: #2A3331;
  --line-soft: #202826;
  --line-strong: #3A4542;

  --ink: #E7EDEA;
  --ink-2: #B0BBB6;
  --ink-3: #909D97;

  --accent: #5FBFAC;
  --accent-hover: #7BCDBC;
  --accent-ink: #0F1312;
  --accent-soft: rgba(95, 191, 172, .10);
  --accent-line: rgba(95, 191, 172, .32);

  --ok: #8FBF7F;
  --ok-soft: rgba(143, 191, 127, .10);
  --ok-line: rgba(143, 191, 127, .32);
  --warn: #D9AC5C;
  --warn-soft: rgba(217, 172, 92, .10);
  --warn-line: rgba(217, 172, 92, .32);
  --crit: #E08476;
  --crit-soft: rgba(224, 132, 118, .10);
  --crit-line: rgba(224, 132, 118, .32);

  --elev-1: none;
  --elev-2: 0 1px 0 rgba(0, 0, 0, .30), 0 6px 18px rgba(0, 0, 0, .28);
  --elev-3: 0 2px 6px rgba(0, 0, 0, .45), 0 24px 56px rgba(0, 0, 0, .40);
  --scrim: rgba(5, 7, 7, .64);
  --skeleton: #1E2524;
  --skeleton-sheen: #283130;
}
