/* ============================================================================
   Molecular AI — marketing site design tokens
   Adopts the product's "Control Room" system (MOL-202) so the site and the app
   read as one thing. Aaron's call, 2026-08-11.

   SOURCE OF TRUTH: molecular_app/static/tokens.css
   Every colour below is copied from it verbatim. If that file changes, this
   one is downstream — do not "improve" a value here. Several hexes in it were
   deliberately darkened from the design mocks to clear WCAG AA against all
   three grounds (canvas / surface / raised); correcting them back toward the
   prettier value would silently break contrast.

   TWO DELIBERATE DIVERGENCES FROM THE APP, both documented at their token:
     1. The type scale. The app's base is 12.5px — instrument density for a
        tool you operate. A page you read needs larger type, so the scale below
        is a marketing scale built on the same families. The app's own sizes
        are kept as --app-fs-* for anything that sits beside a screenshot.
     2. prefers-color-scheme. The app deliberately ignores it, because its
        thirteen page bodies still carry hardcoded light colours and honouring
        the OS would repaint the shell dark around white pages. This site has
        no such constraint, so it honours the OS preference when the visitor
        has expressed no explicit choice. An explicit choice still wins, and
        the mechanism and storage key match the app exactly.
   ========================================================================== */

/* ---- Fonts: self-hosted, no CDN, no Google Fonts link --------------------- */
/* IBM Plex Sans + IBM Plex Mono, SIL OFL 1.1 — see design/fonts/OFL.txt.
   These four files are byte-identical to molecular_app/static/fonts/. */

@font-face {
  font-family: 'IBM Plex Sans';
  src: url('fonts/ibm-plex-sans-latin-400-700.woff2') format('woff2-variations');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('fonts/ibm-plex-mono-latin-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('fonts/ibm-plex-mono-latin-500.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('fonts/ibm-plex-mono-latin-600.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* NOTE: there is no IBM Plex Mono 700 file, in the app or here. Do not ask for
   weight 700 in mono — it will synthesise. The app has this bug in
   .wb-node__tag and .lk-eyebrow; don't reproduce it. Cap mono at 600. */

/* ============================ LIGHT (default) ============================= */
:root {
  /* ---- Brand. The accent IS the brand. -------------------------------- */
  /* The old --teal #2097A5 is RETIRED per the app's tokens.css. And note the
     logo PNG's cyan (#02DCF3) is NOT the brand either — it is a legacy asset
     colour. Neither value appears anywhere below. */
  --color-brand:          #0a97b0;
  --color-brand-contrast: #ffffff;
  --color-brand-text:     #0a7d92;   /* the accessible-on-white variant */
  --color-brand-tint:     rgba(10, 151, 176, 0.08);

  /* ---- Surfaces. The page is NOT white — getting this backwards is the
     single easiest way to look mismatched against the product. ---------- */
  --color-canvas:         #f5f4f2;   /* the page itself — warmed a step */
  --color-canvas-alt:     #fbfaf8;   /* alternating band; derived, same warm axis */
  --color-surface:        #f8f7f4;   /* wells, table headers, input chrome */
  --color-surface-raised: #ffffff;   /* cards, nav, panels */
  --color-border:         #e4e6ea;
  --color-border-subtle:  #eef0f2;   /* hairline row dividers */
  --color-border-strong:  #dfe2e7;   /* inputs, controls */
  --color-border-dashed:  #d5d9de;

  /* ---- Text ----------------------------------------------------------- */
  --color-text:           #1d232c;
  --color-text-secondary: #454b54;
  --color-text-muted:     #66707c;
  --color-text-subtle:    #6b7178;
  --color-text-placeholder: #9aa4b0;

  /* ---- Health / status. Never used for brand emphasis. ---------------- */
  --color-ok:        #189968;  --color-ok-text:     #147a53;
  --color-ok-tint:   rgba(24, 153, 104, 0.12);  --color-ok-contrast: #ffffff;
  --color-warn:      #e0a52c;  --color-warn-text:   #96690f;
  --color-warn-strong: #b8821b;
  --color-warn-tint: rgba(184, 130, 27, 0.12);  --color-warn-contrast: #3d2c05;
  --color-danger:    #d6484d;  --color-danger-text: #b3312f;
  --color-danger-tint: rgba(214, 72, 77, 0.1);
  --color-danger-contrast: #ffffff;
  --state-stale-text: #ba5b1d;

  /* ---- Medallion layer hues. Used by the diagrams and the layer chips. - */
  --layer-bronze:    #a5713a;
  --layer-silver:    #6f7a87;
  --layer-gold:      #a8862b;
  --layer-reporting: #7a4fd0;

  /* ---- AA-safe variants — MARKETING ONLY. Do not push these back upstream
     without a product decision; the values above are the product's and are
     correct for their use (dots, chips, 1px rules), where WCAG's 4.5:1 text
     rule does not apply.

     They fail as TEXT on the light grounds, and this site sets layer names and
     links as text. Measured against --color-canvas #f5f4f2:
       brand-text  #0a7d92 = 4.41   bronze #a5713a = 3.83
       warn-strong #b8821b = 3.08   silver #6f7a87 = 4.00
       stale-text  #ba5b1d = 4.18   gold   #a8862b = 3.15
     Each variant below is the smallest darkening that clears 4.5:1. -------- */
  --color-brand-text-aa:  #0A7A8F;  /* 4.59 on canvas */
  --color-warn-strong-aa: #936816;  /* 4.55 */
  --state-stale-text-aa:  #B1561C;  /* 4.56 */
  --layer-bronze-text:    #946634;  /* 4.57 */
  --layer-silver-text:    #67717E;  /* 4.54 */
  --layer-gold-text:      #886D23;  /* 4.52 */
  --layer-reporting-text: #7a4fd0;  /* 4.99 — already passes in light */

  /* Primary button fill. White-on-brand is 3.46:1, which fails AA for any
     label short of 18.66px bold. The product has this too — see MOL-250.
     This site darkens the FILL rather than lightening the label, so the
     button still reads as brand. */
  --color-brand-fill-aa:  #098297;  /* white label = 4.51 */

  /* ---- Navigation. A dark slab in BOTH themes — it never inverts. Its
     accent #4cc9e0 is deliberately DECOUPLED from --color-brand, so on a
     light page brand cyan appears at two values at once. That is the
     product's behaviour; reproduce it rather than harmonising it. ------- */
  --color-nav-bg:          #0b0d11;
  --color-nav-text:        #8b94a1;
  --color-nav-text-active: #eaf7fa;
  --color-nav-text-hover:  #dfe3e8;
  --color-nav-faint:       #767f8a;
  --color-nav-hover-bg:    rgba(255, 255, 255, 0.04);
  --color-nav-active-bg:   rgba(76, 201, 224, 0.09);
  --color-nav-accent:      #4cc9e0;
  --color-nav-rule:        #1d222a;

  /* ---- Type families -------------------------------------------------- */
  --font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont,
                 'Segoe UI', system-ui, sans-serif;
  --font-family-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo,
                      monospace;

  /* ---- Marketing type scale — DIVERGENCE 1 ---------------------------- */
  /* The app's scale tops out at 22px because it is an instrument panel. A
     landing page is read at arm's length, so this scale is built for prose
     and display while keeping the app's families and its label treatment. */
  --fs-2xs:  0.6875rem; /* 11px — mono eyebrows and labels */
  --fs-xs:   0.8125rem; /* 13px — captions, meta */
  --fs-sm:   0.9375rem; /* 15px — secondary body */
  --fs-base: 1.0625rem; /* 17px — body. Larger than the app's 12.5px, on purpose */
  --fs-lg:   1.25rem;   /* 20px — lede */
  --fs-xl:   1.5rem;    /* 24px — h3 */
  --fs-2xl:  clamp(1.5rem, 1.25rem + 1.2vw, 1.875rem);   /* 24→30 h2 */
  --fs-3xl:  clamp(1.875rem, 1.4rem + 2.3vw, 2.5rem);    /* 30→40 */
  --fs-4xl:  clamp(2.25rem, 1.5rem + 3.6vw, 3.25rem);    /* 36→52 h1 */

  /* The app's own sizes, for any element that sits beside a screenshot and
     should match it exactly (stat tiles, table chrome). */
  --app-fs-xs:    10px;
  --app-fs-sm:    11px;
  --app-fs-md:    12px;
  --app-fs-base:  12.5px;
  --app-fs-title: 13.5px;
  --app-fs-stat:  22px;

  --lh-tight: 1.14;
  --lh-snug:  1.3;
  --lh-body:  1.62;

  --tracking-display: -0.018em;
  --letter-spacing-label: 0.16em;  /* the product's signature label tracking */

  --weight-regular: 400; --weight-medium: 500;
  --weight-semibold: 600; --weight-bold: 700;

  --measure: 66ch;

  /* ---- Spacing. The app's 8-step scale, extended upward for page rhythm.
     Steps 1–8 are the app's exact values; 9–11 are marketing-only. ------ */
  --space-1: 4px;  --space-2: 6px;  --space-3: 8px;  --space-4: 12px;
  --space-5: 16px; --space-6: 20px; --space-7: 24px; --space-8: 32px;
  --space-9: 48px; --space-10: 64px; --space-11: 96px;

  --section-y: clamp(3.5rem, 2.5rem + 5vw, 6.5rem);
  --gutter:    clamp(1.25rem, 0.9rem + 1.6vw, 2rem);
  --container: 72rem;
  --container-narrow: 46rem;

  /* ---- Radii. The app's four tokens — plus the literal 10px it actually
     uses for cards, tables, stats and modals. Buttons and inputs at 6px is
     the one rule that holds consistently over there. ------------------- */
  --radius-sm:   4px;
  --radius-md:   6px;   /* buttons, inputs, controls */
  --radius-lg:   8px;
  --radius-card: 10px;  /* cards, tables, stat tiles — the real convention */
  --radius-pill: 999px;

  /* ---- Elevation. Blue-black ink, never pure black. ------------------- */
  --shadow-node:    0 1px 3px rgba(16, 24, 40, 0.06);
  --shadow-pill:    0 1px 2px rgba(16, 24, 40, 0.05);
  --shadow-overlay: 0 10px 32px rgba(16, 24, 40, 0.14);

  /* ---- Motion. The app uses the literal `ease` keyword, not a custom
     cubic-bezier. Matching it. ---------------------------------------- */
  --duration-fast: 0.15s;
  --duration-base: 0.2s;
  --ease: ease;

  --nav-height: 56px;
}

/* ============================== DARK ===================================== */
/* Mechanism matches the app exactly: data-theme="dark" on <html>, localStorage
   key `mol_theme`. Light is the ABSENCE of the attribute, not "light".       */

:root[data-theme="dark"] {
  --color-brand:          #4cc9e0;
  --color-brand-contrast: #08131a;
  --color-brand-text:     #4cc9e0;
  --color-brand-tint:     rgba(76, 201, 224, 0.08);

  --color-canvas:         #101216;   /* warmed a step */
  --color-canvas-alt:     #15171a;   /* alternating band; derived, same warm axis */
  --color-surface:        #171a1e;
  --color-surface-raised: #14161a;
  --color-border:         #232933;
  --color-border-subtle:  #1b2028;
  --color-border-strong:  #262c35;
  --color-border-dashed:  #5c6572;

  --color-text:           #e6e9ed;
  --color-text-secondary: #aeb6c0;
  --color-text-muted:     #8b94a1;
  --color-text-subtle:    #828b97;
  --color-text-placeholder: #5c6572;

  /* In dark the text-on-tint variants collapse to the status colour itself. */
  --color-ok:        #3dd68c;  --color-ok-text:     #3dd68c;
  --color-ok-tint:   rgba(61, 214, 140, 0.1);   --color-ok-contrast: #08131a;
  --color-warn:      #d9a13b;  --color-warn-text:   #d9a13b;
  --color-warn-strong: #d9a13b;
  --color-warn-tint: rgba(217, 161, 59, 0.1);   --color-warn-contrast: #12151a;
  --color-danger:    #f2555a;  --color-danger-text: #f2555a;
  --color-danger-tint: rgba(242, 85, 90, 0.1);
  --color-danger-contrast: #08131a;
  --state-stale-text: #e8833a;

  --layer-bronze: #c08d52;
  --layer-silver: #96a0ac;
  --layer-gold:   #d3b04c;
  /* --layer-reporting carries over unchanged in the app — and that is the one
     place the carry-over hurts: #7a4fd0 measures 3.17–3.42 on the dark
     grounds, below AA. Marketing-only lighter variant for text use. */
  --layer-bronze-text:    #c08d52;  /* 5.90 on surface — fine as-is */
  --layer-silver-text:    #96a0ac;  /* 6.52 */
  --layer-gold-text:      #d3b04c;  /* 8.30 */
  --layer-reporting-text: #926FD8;  /* 4.52 on surface, vs 3.17 for #7a4fd0 */

  /* In dark the brand is light enough that neither AA variant is needed:
     brand-text #4cc9e0 measures 8.84–9.52, and the button's near-black label
     on cyan is 9.60. Both point back at the base tokens. */
  --color-brand-text-aa:  #4cc9e0;
  --color-warn-strong-aa: #d9a13b;
  --state-stale-text-aa:  #e8833a;
  --color-brand-fill-aa:  #4cc9e0;

  /* Borders carry separation in dark — the app drops the node shadow. */
  --shadow-node:    none;
  --shadow-pill:    0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-overlay: 0 10px 32px rgba(0, 0, 0, 0.5);

  /* The --color-nav-* group is NOT redefined. The nav is a dark slab in both
     themes, exactly as in the product. */
}

/* ---- DIVERGENCE 2: honour the OS preference, but only as a default ------- */
/* Guarded so an explicit light choice always wins over a dark OS. The app
   omits this on purpose (its page bodies are hardcoded light); this site has
   no such constraint and ignoring the preference would be worse UX. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) {
    --color-brand:          #4cc9e0;
    --color-brand-contrast: #08131a;
    --color-brand-text:     #4cc9e0;
    --color-brand-tint:     rgba(76, 201, 224, 0.08);

    --color-canvas:         #101216;   /* warmed a step */
  --color-canvas-alt:     #15171a;   /* alternating band; derived, same warm axis */
    --color-surface:        #171a1e;
    --color-surface-raised: #14161a;
    --color-border:         #232933;
    --color-border-subtle:  #1b2028;
    --color-border-strong:  #262c35;
    --color-border-dashed:  #5c6572;

    --color-text:           #e6e9ed;
    --color-text-secondary: #aeb6c0;
    --color-text-muted:     #8b94a1;
    --color-text-subtle:    #828b97;
    --color-text-placeholder: #5c6572;

    --color-ok:        #3dd68c;  --color-ok-text:     #3dd68c;
    --color-ok-tint:   rgba(61, 214, 140, 0.1);   --color-ok-contrast: #08131a;
    --color-warn:      #d9a13b;  --color-warn-text:   #d9a13b;
    --color-warn-strong: #d9a13b;
    --color-warn-tint: rgba(217, 161, 59, 0.1);   --color-warn-contrast: #12151a;
    --color-danger:    #f2555a;  --color-danger-text: #f2555a;
    --color-danger-tint: rgba(242, 85, 90, 0.1);
    --color-danger-contrast: #08131a;
    --state-stale-text: #e8833a;

    --layer-bronze: #c08d52;
    --layer-silver: #96a0ac;
    --layer-gold:   #d3b04c;
    --layer-bronze-text:    #c08d52;
    --layer-silver-text:    #96a0ac;
    --layer-gold-text:      #d3b04c;
    --layer-reporting-text: #926FD8;
    --color-brand-text-aa:  #4cc9e0;
    --color-warn-strong-aa: #d9a13b;
    --state-stale-text-aa:  #e8833a;
    --color-brand-fill-aa:  #4cc9e0;

    --shadow-node:    none;
    --shadow-pill:    0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-overlay: 0 10px 32px rgba(0, 0, 0, 0.5);
  }
}
