/* ═══════════════════════════════════════════════════════════════════════════
   DRIIF DESIGN SYSTEM — TOKENS v1.0
   Single source of truth. This block is byte-identical in every Driif file.
   Rule: if a value is not a token below, it does not belong in a component.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── BREAKPOINTS ──────────────────────────────────────────────────────────
   Three, and only three. Custom properties can't be used inside @media, so
   these are documented here and written as literals everywhere else.
     sm   640px   below this: everything is one column
     md  1024px   two-column grids appear, edge padding goes to 48
     lg  1600px   full asymmetric layout, edge padding goes to 64
   Above lg the layout is UNCAPPED — it keeps growing on ultrawide. Only
   text blocks stop growing, via the measure tokens.
   ───────────────────────────────────────────────────────────────────────── */

:root{
  /* ── COLOR: two poles, everything else is a pole at an opacity ───────── */
  --black: #0C0E0E;
  --white: #F3F3EE;
  --rgb-black: 12,14,14;
  --rgb-white: 243,243,238;

  --color-accent:      #E7FF25;
  --color-accent-ink:  var(--black);
  --color-accent-dim:  rgba(231,255,37,.24);  /* background tint — a fill, never legible as text */

  /* ── SCENE PALETTE ───────────────────────────────────────────────────────
     A third hue, declared ONLY for the tactical scenes in How Mission OS
     Operates. It is not a UI colour: never text, never a border, never a
     button. It exists because the scenes need to separate two things the
     two-pole system cannot — what the operator DESIGNATED from what the
     force IS — and opacity alone cannot carry that distinction on a
     near-black ground.

     Matched to the committed Plan render, where the objective marker
     already ships in this hue. The rest of the scene palette needs no new
     tokens and must not invent any:
       own assets (UAV/UGV/USV)      --color-accent
       terrain, constraints, chrome  --white at opacity
       degraded / link-lost state    same hues, dashed + reduced opacity
       hostile or unknown contact    --color-designate, SHAPE carries the
                                     difference (diamond + exclusion ring,
                                     versus the objective's bracket + dot)

     That last rule is the reason there is no fourth colour: attention hue
     stays one hue, and identity is carried by symbology, which is how real
     tactical displays do it. If a scene ever seems to need a new colour,
     the answer is almost certainly a new glyph. */
  --color-designate: #D93B2B;

  --scrim-45: rgba(var(--rgb-black),.45);
  --scrim-82: rgba(var(--rgb-black),.82);

  /* ── TYPE FAMILIES: two ──────────────────────────────────────────────────
     Space Grotesk carries all structure — display, headings, eyebrows,
     pills, buttons, nav. IBM Plex Sans carries reading text only.
     NOTE: dropping IBM Plex Mono removed the system's only true monospace,
     so numeric readouts now rely on font-variant-numeric: tabular-nums
     (see --num). If counters ever need to look like instrumentation again,
     that's the decision to revisit.
     ─────────────────────────────────────────────────────────────────────── */
  --font-display: 'Space Grotesk', ui-sans-serif, system-ui, sans-serif;
  --font-body:    'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;

  /* ── TYPE SCALE ──────────────────────────────────────────────────────────
     Two ramps, because UI text and display text want different logic.

     UI ramp — FIXED px. Never scales; a 12px button is 12px everywhere.
     Display ramp — FLUID. Each clamp interpolates linearly from its 640px
     value to its 1920px value, then holds. Named by USE, not by number, so
     the usage rule survives being handed to someone else.
     ─────────────────────────────────────────────────────────────────────── */

  /* UI ramp (fixed) */
  --ui-xs: 12px;   /* nav, buttons, pills, micro labels */
  --ui-sm: 14px;   /* secondary labels, footer links, counters */
  --ui-md: 16px;   /* dense body, form text — also the mobile input floor */

  /* Display ramp (fluid: 640px → 1920px, then flat)

     Sized for a VIDEO-BACKED hero. The top of this ramp is deliberately
     restrained: display type over moving footage has to stay legible without
     covering the frame. The reading end barely moves — 16px is the reading
     floor and the iOS input floor, so body cannot come down. That makes this
     a compression of the top, not a uniform shrink.
     Ceiling at 1920: display 80 / h1 44 / h2 34 / h3 26 / lead 21 / body 18. */
  --text-eyebrow: clamp(13px, calc(0.39vw + 10.5px), 18px); /* section eyebrow */
  --text-body:    clamp(16px, calc(0.16vw + 15px),   18px); /* reading text */
  --text-lead:    clamp(17px, calc(0.31vw + 15px),   21px); /* lead paragraph */
  --text-h3:      clamp(19px, calc(0.55vw + 15.5px), 26px); /* card titles */
  --text-h2:      clamp(22px, calc(0.94vw + 16px),   34px); /* sub-sections */
  --text-h1:      clamp(26px, calc(1.41vw + 17px),   44px); /* section headings */
  --text-display: clamp(36px, calc(3.44vw + 14px),   80px); /* hero, once per page */

  /* ── LINE HEIGHT: locked per role ────────────────────────────────────────
     Unitless so it tracks font-size. Every text role picks exactly one of
     these — that is what stops a page ending up with fourteen of them.
     ─────────────────────────────────────────────────────────────────────── */
  --lh-display: 1.02;  /* hero only; bumps to 1.12 under 640 where it wraps */
  --lh-tight:   1.10;  /* h1, h2 */
  --lh-snug:    1.20;  /* h3, card titles */
  --lh-body:    1.55;  /* all reading text — meets the 1.5–1.6 rule */
  --lh-flat:    1;     /* single-line labels: pills, buttons, nav, counters */

  /* ── TRACKING: four values, no more ──────────────────────────────────── */
  --track-display: -0.02em;  /* display sizes */
  --track-tight:   -0.01em;  /* h1, h2, h3 */
  --track-label:    0.08em;  /* 12–14px uppercase UI */
  --track-eyebrow:  0.16em;  /* the eyebrow tier — deliberately wide */
  /* --caps-track is the knob the .caps utility reads. Uppercase needs positive
     tracking to breathe and how much depends on size, so .caps ships three
     tiers and any element can override this locally. */
  --caps-track:     0.08em;
  /* reading text takes no tracking at all */

  /* ── MEASURE: how wide a text block may get ──────────────────────────────
     The layout is uncapped; text is not. These are the only thing standing
     between a full-bleed grid and a 150-character line.
     ─────────────────────────────────────────────────────────────────────── */
  --measure-body: 68ch;  /* long-form reading */
  --measure-lead: 52ch;  /* the right-hand column of a split */
  --measure-card: 42ch;  /* copy inside a card */
  --measure-display: 24ch; /* keeps the hero to two or three strong lines */

  /* ── SPACING: 8pt ramp ───────────────────────────────────────────────── */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;
  --space-10: 128px;

  /* ── LAYOUT ──────────────────────────────────────────────────────────────
     --edge is the ONLY thing between content and the viewport edge.
     24 on mobile, 48 at md, 64 at lg. There is no max-width anywhere.
     ─────────────────────────────────────────────────────────────────────── */
  --edge: 24px;
  --gutter:    clamp(24px, 2.5vw, 48px);    /* the one grid gutter */
  --gutter-lg: clamp(32px, 6vw, 160px);     /* the gap inside a split */
  --section-y:    clamp(64px, 7vw, 160px);  /* major section rhythm */
  --section-y-sm: clamp(48px, 4.5vw, 96px); /* minor section rhythm */

  /* ── SHAPE ───────────────────────────────────────────────────────────── */
  --radius: 0;        /* the system is sharp everywhere */
  --chamfer: 16px;    /* button cut corner */
  --notch: 28px;      /* capability card cut corner */
  --hex: 60px;        /* corner arrow badge */
  --hair: 1px;        /* every drawn line */

  /* ── MOTION ──────────────────────────────────────────────────────────────
     Built-in CSS easings are too weak to read as intentional. These are the
     canonical strong curves — never hand-roll a bezier.
     ─────────────────────────────────────────────────────────────────────── */
  --ease-out:    cubic-bezier(0.23, 1, 0.32, 1);      /* entering / exiting — the default */
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);     /* moving on screen */
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);      /* iOS-like, long travel */
  /* NEVER ease-in on UI: it delays the moment the user is watching. */

  --dur-press:  140ms;  /* button press feedback */
  --dur-fast:   180ms;  /* hover, nav return, small state changes */
  --dur-ui:     240ms;  /* dropdowns, nav hide */
  --dur-enter:  900ms;  /* scroll reveals — marketing pace, not UI pace. Bumped
                            from 600ms per direct comparison against a reference
                            site's scroll-in effect: the visible difference wasn't
                            missing motion, it was pace — theirs runs close to 1s. */
  --dur-scene: 1000ms;  /* Operate Stage's scene-to-scene wipe — slower again than
                            --dur-enter per direct feedback: even 600ms still read
                            as a fast, unclear flick across a full-width scene. */
  --dur-drawer: 420ms;  /* paired with --ease-drawer — an accordion panel's own
                            expand/collapse (Decision Layer), longer than --dur-ui
                            since it's travelling its own variable content height,
                            not just a small dropdown-sized box. */
  --stagger:     60ms;  /* between siblings entering together */

  --ease: var(--ease-out);   /* legacy alias */
  --dur:  var(--dur-ui);     /* legacy alias */
}

/* ── SURFACES ──────────────────────────────────────────────────────────────
   A surface declares which pole it sits on. --pole is the ink color for that
   ground and every neutral derives from it, so one variable flips a whole
   section and every component inside follows with no overrides.

   Alternate by REGISTER, not position:
     dark  = mission register — the threat, the products, the ask
     light = capability register — what the system is and where it runs
   Position-based alternation breaks the moment a section is inserted.
   ───────────────────────────────────────────────────────────────────────── */
.surface-dark{
  --pole: var(--rgb-white);
  --color-bg: var(--black);
  --color-text: var(--white);
  --color-eyebrow: var(--color-text-muted);
}
.surface-light{
  --pole: var(--rgb-black);
  --color-bg: var(--white);
  --color-text: var(--black);
  --color-eyebrow: var(--color-text-muted);
}
/* Derived neutrals are re-declared in every scope on purpose: a custom
   property's computed value is substituted where it is DECLARED, so a
   :root-only definition would never see a local --pole and the flip would
   silently do nothing. */
:root, .surface-dark, .surface-light{
  --color-surface:       rgba(var(--pole),.04);
  --color-border-subtle: rgba(var(--pole),.12);
  --color-border:        rgba(var(--pole),.24);
  --color-border-strong: rgba(var(--pole),.32);
  --color-text-muted:    rgba(var(--pole),.60);
  --color-pill-border:   rgba(var(--pole),.72);
}
:root{
  --pole: var(--rgb-white);
  --color-bg: var(--black);
  --color-text: var(--white);
  --color-eyebrow: var(--color-text-muted);
}
/* The flip classes set tokens and ink ONLY. They must not paint a
   background, or a clipped component (the notch card) gets its own
   unclipped box filled in and loses the cut. Grounds paint themselves. */
.surface-dark, .surface-light{ color: var(--color-text); }

/* ── RESPONSIVE: the three breakpoints ──────────────────────────────────── */
@media (min-width:1024px){ :root{ --edge:48px; } }
@media (min-width:1600px){ :root{ --edge:64px; } }
@media (max-width:639px){  :root{ --lh-display:1.12; } }
