/* apps/app/src/tokens.css
 *
 * Every visual value used anywhere in apps/app lives here as a custom
 * property. No component may hardcode a hex color, a px shadow, or a font
 * name — reach for a token, and if the token you need doesn't exist, add it
 * here, not inline.
 *
 * Direction: "Studio" (docs/design/overhaul-2026-10-10-r5/), approved by Gabriel
 * 10 Oct 2026 after the Livery/Hairline hazard look read as blocky and gross
 * ("Washington Post had a baby with Spirit Airlines"). B3 jewel colors
 * (sapphire, ruby, emerald, graphite), Bricolage Grotesque headlines over
 * Instrument Sans, rounded 16/26px shapes, solid-color stat blocks, a white
 * app bar with an ink rule, and a navy dark mode. No yellow, no ink bars.
 * Replaces Hairline hazard (round 6 A) and Livery (round 5 C).
 */

@font-face {
  font-family: "Bricolage Grotesque";
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/bricolage.woff2") format("woff2");
}
@font-face {
  font-family: "Instrument Sans";
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/instrument.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Mono";
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/geist-mono.woff2") format("woff2");
}

:root {
  /* ---- radius ---- */
  --radius-xs: 6px;
  --radius-sm: 10px;
  --radius-control: 16px;
  --radius-card: 26px;
  --radius-lg: 30px;
  --radius-pill: 999px;

  /* ---- spacing (4px base) ---- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;
  --sp-10: 40px;
  --sp-12: 48px;

  /* Maximum readable width for public check-in pages. */
  --page-measure: 720px;

  /* ---- safe areas (notch, home indicator); 0 in a desktop browser ---- */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);

  /* ---- control heights ---- */
  --h-sm: 32px;
  --h-bar: 36px;
  --h-md: 44px;
  --h-lg: 48px;

  /* ---- type ----
   * Instrument Sans body, Bricolage Grotesque headlines and big numbers.
   */
  --font-fallback: -apple-system, "Segoe UI", system-ui, "Helvetica Neue", Arial, sans-serif;
  --font: "Instrument Sans", var(--font-fallback);
  --font-heading: "Bricolage Grotesque", var(--font);
  --font-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --fs-xs: 13px;
  --fs-sm: 14px;
  --fs-md: 15px;
  --fs-lg: 16px;
  --fs-xl: 24px;
  --fs-2xl: 32px;
  --fs-2xs: 12px;
  --fs-brand: 18px;
  --fs-stat: 40px;
  --fs-stat-text: 28px;
  /* Page headline: oversized, one per screen (comp A is 112px at 1440). */
  --fs-display: clamp(2.25rem, 1rem + 4.2vw, 4.5rem);
  /* Working-screen page title (28 to 40px) and the step between it and body. */
  --fs-title: clamp(1.75rem, 1.2rem + 1.4vw, 2.5rem);
  --fs-section: 1.25rem;

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;
  --fw-heavy: 800;
  --fw-black: 900;

  /* ---- lines: hairlines carry structure, not boxes ---- */
  --line-w: 1px;
  --rule-w: 1.5px;
  /* The one heavy line on a list page: under the table header. */
  --head-rule-w: 2px;
  /* Dense list metrics (round 7): one-row page head, filter row, table. */
  --page-head-h: 64px;
  --stat-block-h: 56px;
  --thead-h: 36px;
  --row-h: 44px;
  --progress-h: 2px;
  --tab-bar-h: 4px;
  --row-pad-y: 20px;
  --row-pad-y-compact: 8px;
  --tab-h: 44px;
  --mod-bar-h: 4px;
  --fade-w: 28px;

  /* z-index scale */
  --z-nav: 30;
  --z-menu: 50;
  --z-drawer: 60;
  --z-modal: 100;

  --ease: cubic-bezier(0.2, 0, 0.2, 1);
  --dur: 150ms;

  /* ---- nav shape (top tab row; a sidebar is ruled out) ---- */
  --shell-direction: column;
  --nav-direction: row;
  --nav-main-size: 56px;
  --nav-phone-size: 48px;
  --nav-modules-phone-size: var(--h-md);
  /* One spine: bar, strip and page share this container and gutter. */
  --shell-max: 1440px;
  --gutter: var(--sp-6);
  --shell-pad: max(var(--gutter), calc((100% - var(--shell-max)) / 2 + var(--gutter)));
  /* Height of the sticky chrome; AppShell keeps it measured. */
  --shell-top-h: calc(var(--nav-main-size) + var(--tab-h));
  --nav-border-bottom: 1px solid var(--border);
  --nav-border-right: none;

  /* ---- color: light ---- */
  --paper: #ffffff;
  --surface: #ffffff;
  --surface-raised: #ffffff;
  --surface-sunken: #f4f6fb;
  --surface-hover: #f4f6fb;
  --surface-zebra: #f9fafd;
  --ink: #0f1428;
  --ink-secondary: #555e78;
  --ink-muted: #6b7590;
  --border: #e6e9f2;
  --border-strong: #8089a3;
  --accent: #1d3fa8;
  --accent-strong: #14307f;
  --accent-soft: #e4eafb;
  --on-accent: #ffffff;
  --accent-shadow: none;
  --focus-ring: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent);

  --ok: #0e6b4f;
  --ok-soft: #dcf1e8;
  --ok-ink: #0a5640;
  --warn: #b3173a;
  --warn-soft: #fbe3e9;
  --warn-ink: #8c1230;
  --danger: #b3173a;
  --danger-soft: #fbe3e9;
  --danger-ink: #8c1230;
  --info: #1d3fa8;
  --info-soft: #e4eafb;
  --info-ink: #14307f;
  --attention: #b3173a;
  --on-attention: #ffffff;
  --neutral-soft: #eaeef7;
  --neutral-ink: #2a2f45;
  /* Solid fills for stat blocks and status chips; text on them is --on-solid. */
  --solid-neutral: #2a2f45;
  --on-solid: #ffffff;
  --on-fill: #ffffff;

  --mod-tc_hub: #1d3fa8;
  --mod-ems: #0e6b4f;
  --mod-cpr: #b3173a;
  --mod-testing: #4a5b78;
  --mod-clinicals: #0e6b8a;
  --mod-exams: #6b3fa0;
  --bar-mod-tc_hub: #1d3fa8;
  --bar-mod-ems: #0e6b4f;
  --bar-mod-cpr: #b3173a;
  --bar-mod-testing: #4a5b78;
  --bar-mod-clinicals: #0e6b8a;
  --bar-mod-exams: #6b3fa0;

  --shadow-xs: none;
  --shadow-sm: none;
  --shadow-md: 0 6px 18px rgba(15, 20, 40, 0.10), 0 1px 3px rgba(15, 20, 40, 0.06);
  --shadow-lg: 0 24px 60px rgba(15, 20, 40, 0.28);
  --scrim: rgba(15, 20, 40, 0.45);
  --edge: var(--border);
  --bar: #ffffff;
  --on-bar: #0f1428;
  /* Skeleton ink: visible on paper in both themes. */
  --skeleton: color-mix(in srgb, var(--ink) 10%, var(--paper));
}

/* ---- color: dark (system), navy ---- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #0a1226;
    --surface: #0e1730;
    --surface-raised: #111b36;
    --surface-sunken: #111b36;
    --surface-hover: #17234a;
    --surface-zebra: #0c142b;
    --ink: #eef2ff;
    --ink-secondary: #9eacd6;
    --ink-muted: #8593bd;
    --border: #1f2b4d;
    --border-strong: #6b7aa6;
    --accent: #5b80f0;
    --accent-strong: #9bb3ff;
    --accent-soft: #1b2a4d;
    --on-accent: #081030;
    --accent-shadow: none;
    --focus-ring: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent);

    --ok: #1fb384;
    --ok-soft: #123628;
    --ok-ink: #6fe0b4;
    --warn: #f0577a;
    --warn-soft: #3a1624;
    --warn-ink: #ff9fb3;
    --danger: #f0577a;
    --danger-soft: #3a1624;
    --danger-ink: #ff9fb3;
    --info: #5b80f0;
    --info-soft: #1b2a4d;
    --info-ink: #9bb3ff;
    --attention: #f0577a;
    --on-attention: #081030;
    --neutral-soft: #17234a;
    --neutral-ink: #b7c3e6;
    /* Solid fills for stat blocks and status chips; text on them is --on-solid. */
    --solid-neutral: #2b3760;
    --on-solid: #eef2ff;
    --on-fill: #081030;

    --mod-tc_hub: #7c9be0;
    --mod-ems: #4fd1a5;
    --mod-cpr: #f08aa0;
    --mod-testing: #9fb2d0;
    --mod-clinicals: #6ac4e0;
    --mod-exams: #b39ddb;
    --bar-mod-tc_hub: #7c9be0;
    --bar-mod-ems: #4fd1a5;
    --bar-mod-cpr: #f08aa0;
    --bar-mod-testing: #9fb2d0;
    --bar-mod-clinicals: #6ac4e0;
    --bar-mod-exams: #b39ddb;

    --shadow-xs: none;
    --shadow-sm: none;
    --shadow-md: 0 6px 18px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.3);
    --shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.55);
    --scrim: rgba(4, 8, 20, 0.6);
    --edge: var(--border);
    --bar: #0a1226;
    --on-bar: #eef2ff;
  }
}

:root[data-theme="dark"] {
  --paper: #0a1226;
  --surface: #0e1730;
  --surface-raised: #111b36;
  --surface-sunken: #111b36;
  --surface-hover: #17234a;
  --surface-zebra: #0c142b;
  --ink: #eef2ff;
  --ink-secondary: #9eacd6;
  --ink-muted: #8593bd;
  --border: #1f2b4d;
  --border-strong: #6b7aa6;
  --accent: #5b80f0;
  --accent-strong: #9bb3ff;
  --accent-soft: #1b2a4d;
  --on-accent: #081030;
  --accent-shadow: none;
  --focus-ring: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent);

  --ok: #1fb384;
  --ok-soft: #123628;
  --ok-ink: #6fe0b4;
  --warn: #f0577a;
  --warn-soft: #3a1624;
  --warn-ink: #ff9fb3;
  --danger: #f0577a;
  --danger-soft: #3a1624;
  --danger-ink: #ff9fb3;
  --info: #5b80f0;
  --info-soft: #1b2a4d;
  --info-ink: #9bb3ff;
  --attention: #f0577a;
  --on-attention: #081030;
  --neutral-soft: #17234a;
  --neutral-ink: #b7c3e6;
  /* Solid fills for stat blocks and status chips; text on them is --on-solid. */
  --solid-neutral: #2b3760;
  --on-solid: #eef2ff;
  --on-fill: #081030;

  --mod-tc_hub: #7c9be0;
  --mod-ems: #4fd1a5;
  --mod-cpr: #f08aa0;
  --mod-testing: #9fb2d0;
  --mod-clinicals: #6ac4e0;
  --mod-exams: #b39ddb;
  --bar-mod-tc_hub: #7c9be0;
  --bar-mod-ems: #4fd1a5;
  --bar-mod-cpr: #f08aa0;
  --bar-mod-testing: #9fb2d0;
  --bar-mod-clinicals: #6ac4e0;
  --bar-mod-exams: #b39ddb;

  --shadow-xs: none;
  --shadow-sm: none;
  --shadow-md: 0 6px 18px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.55);
  --scrim: rgba(4, 8, 20, 0.6);
  --edge: var(--border);
  --bar: #0a1226;
  --on-bar: #eef2ff;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  color-scheme: light dark;
  /* The bar never shifts or notches when a page starts to scroll. */
  scrollbar-gutter: stable;
}
:root[data-theme='light'] {
  color-scheme: light;
}
:root[data-theme='dark'] {
  color-scheme: dark;
}
html,
body {
  margin: 0;
}
body {
  font-family: var(--font);
  background: var(--paper);
  color: var(--ink);
  font-size: var(--fs-md);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}
html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}
h1,
h2,
h3 {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: var(--fw-heavy);
  letter-spacing: -0.02em;
}
h1 {
  font-size: var(--fs-display);
  font-weight: var(--fw-heavy);
  letter-spacing: -0.05em;
  line-height: 1.02;
  text-wrap: balance;
}
p {
  margin: 0;
}
a {
  color: inherit;
}
button {
  font-family: inherit;
}
:where(button) {
  color: inherit;
  background: transparent;
  border: 0;
}
:where(button.dashboard-list-row) {
  text-align: left;
  width: 100%;
}
::selection {
  background: var(--accent-soft);
  color: var(--accent-strong);
}
#root {
  min-height: 100vh;
  min-height: 100dvh;
}
:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-xs);
}
/* Box-shadow rings vanish in forced colors; fall back to a real outline. */
@media (forced-colors: active) {
  :focus-visible {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
}

/* ---- org accent (Settings > Branding) ----
 * applyOrgAccent() (lib/accent.js) sets --org-accent-light and --org-accent-dark
 * on :root when an org picked a color. With none set, --org-accent is invalid
 * and every `var(--org-accent, <default>)` below falls back to its default.
 * Used only on chrome rules: header top rule, active tab underline, page-header
 * tick, public page header rule. Buttons, links and focus rings keep --accent. */
:root {
  --org-accent: var(--org-accent-light);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --org-accent: var(--org-accent-dark);
  }
}
:root[data-theme="dark"] {
  --org-accent: var(--org-accent-dark);
}
