/* ==========================================================================
   RX-OS — Colors & Type
   Cognitive security for critical infrastructure.
   ==========================================================================

   Loading this file:
     <link rel="stylesheet" href="colors_and_type.css">

   The defaults are DARK (terminal / console / OT operator at 3am).
   Add <html class="theme-light"> to flip to the paper variant used on
   the longform pages (/about, /technology).
   ========================================================================== */

/* Fonts — hosted locally in /fonts, sourced from Google Fonts
   (See README.md → VISUAL FOUNDATIONS → Type for substitution notes) */
@font-face {
  font-family: "RX Display";
  src: url("fonts/InstrumentSerif-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "RX Display";
  src: url("fonts/InstrumentSerif-Italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "RX Sans";
  /* Was HankenGrotesk-Variable.woff2 — that file is an ITALIC face declared as
     font-style: normal, which put the entire dashboard in italics. Measured
     skew on a 140px "H": Hanken 14px, Inter Tight 0px, RX Mono 0px.
     Inter Tight was already deployed in this directory and unused. */
  src: url("fonts/InterTight-Variable.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "RX Mono";
  src: url("fonts/JetBrainsMono-Variable.woff2") format("woff2-variations");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

/* =========================
   1.  PRIMITIVES
   ========================= */
:root {
  /* -- Neutrals (dark base) -----------------------------------------------
     Near-black, with a whisper of cool hue. NOT pure #000 for large areas,
     NOT pure #fff for text. We want kernel-panel depth, not OLED void. */
  --rx-ink-0:   #07090B;   /* hero backgrounds, below-fold blocks */
  --rx-ink-1:   #0B0E12;   /* app chrome, default surface */
  --rx-ink-2:   #121620;   /* raised surface, cards, inputs */
  --rx-ink-3:   #1A2030;   /* hovered rows, nested panels */
  --rx-ink-4:   #242C3E;   /* borders on dark, subtle dividers */

  --rx-fog-4:   #3A4458;   /* disabled text / tertiary on dark */
  --rx-fog-3:   #727C90;   /* muted text on dark — was #6B7487, which measured
                             4.12:1 on the raised surface. Same hue, +7% light. */
  --rx-fog-2:   #A0A8BC;   /* secondary text on dark */
  --rx-fog-1:   #D4D9E4;   /* primary text on dark */
  --rx-bone:    #ECEAE2;   /* warm off-white (paper mode, body on dark) */
  --rx-paper:   #F6F3EB;   /* warm paper, used on /about + /technology */
  --rx-chalk:   #FFFFFF;   /* reserved for pure-white accents */

  /* -- Signal colors -----------------------------------------------------
     Terminal-derived. Green is the default live/healthy. Amber = anomaly
     detected. Red = guard engaged. Cyan = discovery (passive). */
  --rx-signal-500: #7DD87A;   /* healthy, live, online, evidence ok */
  --rx-signal-600: #4FB85A;
  --rx-signal-300: #B7ECB4;
  --rx-signal-900: #0E2612;

  --rx-anomaly-500: #F3B64A;  /* warning, behavioural drift */
  --rx-anomaly-300: #F9D88A;
  --rx-anomaly-900: #2A1D07;

  --rx-guard-500: #E25D4A;    /* alert, threat, blocked */
  --rx-guard-300: #F0958A;
  --rx-guard-900: #2C0E08;

  --rx-sense-500: #7AB6D8;    /* discovery / passive / scanning */
  --rx-sense-300: #B3D5EA;
  --rx-sense-900: #0B1E2A;

  /* -- Deep brand ---------------------------------------------------------
     Dark petrol/teal; quiet, sovereign, Belgian-engineering. */
  --rx-deep-900: #04120F;
  --rx-deep-800: #0B1F1C;
  --rx-deep-500: #16504A;
  --rx-deep-300: #3D8F85;

  /* -- Functional radii & elevation -------------------------------------- */
  --rx-radius-0: 0;
  --rx-radius-1: 2px;
  --rx-radius-2: 4px;
  --rx-radius-3: 6px;
  --rx-radius-4: 10px;     /* cards, panels */
  --rx-radius-pill: 999px;

  --rx-border-thin: 1px solid var(--rx-ink-4);
  --rx-border-hairline: 1px solid rgba(212, 217, 228, 0.08);

  /* We use inset shadows for depth, not drop shadows.
     Drop shadows = marketing slop; inset = instrument panel. */
  --rx-inset-hair:  inset 0 0 0 1px rgba(255,255,255,0.04);
  --rx-inset-soft:  inset 0 1px 0 0 rgba(255,255,255,0.06), inset 0 0 0 1px rgba(255,255,255,0.04);
  --rx-glow-signal: 0 0 0 1px var(--rx-signal-500), 0 0 24px -4px rgba(125, 216, 122, 0.45);
  --rx-glow-guard:  0 0 0 1px var(--rx-guard-500),  0 0 24px -4px rgba(226, 93, 74, 0.45);
  --rx-drop-sm:     0 1px 0 rgba(0,0,0,0.4), 0 2px 6px rgba(0,0,0,0.3);
  --rx-drop-lg:     0 4px 1px rgba(0,0,0,0.5), 0 12px 32px rgba(0,0,0,0.5);

  /* -- Spacing scale (4px base) ------------------------------------------ */
  --rx-s-0:  0px;
  --rx-s-1:  4px;
  --rx-s-2:  8px;
  --rx-s-3:  12px;
  --rx-s-4:  16px;
  --rx-s-5:  24px;
  --rx-s-6:  32px;
  --rx-s-7:  48px;
  --rx-s-8:  64px;
  --rx-s-9:  96px;
  --rx-s-10: 128px;

  /* -- Motion -------------------------------------------------------------
     Everything is fast and firm. This is an instrument, not a storefront.
     No bouncing, no spring overshoot. */
  --rx-ease:       cubic-bezier(0.2, 0.6, 0.2, 1);
  --rx-ease-out:   cubic-bezier(0.16, 1, 0.3, 1);
  --rx-dur-fast:   80ms;
  --rx-dur-med:    160ms;
  --rx-dur-slow:   320ms;

  /* -- Font stacks -------------------------------------------------------- */
  --rx-ff-display: "RX Display", "Instrument Serif", Georgia, "Times New Roman", serif;
  --rx-ff-sans:    "RX Sans", "Hanken Grotesk", ui-sans-serif, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --rx-ff-mono:    "RX Mono", "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}

/* =========================
   2.  SEMANTIC TOKENS (dark default)
   ========================= */
:root {
  --bg:        var(--rx-ink-0);
  --bg-raised: var(--rx-ink-1);
  --bg-sunk:   #04060A;
  --surface:   var(--rx-ink-2);
  --surface-2: var(--rx-ink-3);

  --fg:        var(--rx-bone);
  --fg-1:      var(--rx-fog-1);     /* secondary */
  --fg-2:      var(--rx-fog-2);     /* tertiary / captions */
  --fg-3:      var(--rx-fog-3);     /* disabled, muted */
  --fg-on-accent: var(--rx-ink-0);

  --line:      rgba(212, 217, 228, 0.08);
  --line-strong: rgba(212, 217, 228, 0.16);

  --accent:    var(--rx-signal-500);
  --accent-fg: var(--rx-ink-0);
  --warn:      var(--rx-anomaly-500);
  --danger:    var(--rx-guard-500);
  --info:      var(--rx-sense-500);

  --focus-ring: 0 0 0 2px var(--rx-ink-0), 0 0 0 4px var(--rx-signal-500);
}

/* =========================================================================
   LIGHT MODE — "European desk"
   =========================================================================
   This used to be a warm editorial paper (#F6F3EB) borrowed from the longform
   marketing pages. Those pages do not exist in this deployment, and a cream
   sheet is not what a fleet operator in Brussels expects: the reference is the
   crisp, low-chrome look of European public-sector tooling — white surfaces, a
   cool grey rule, and one restrained institutional accent.

   The accent is NOT invented. --rx-deep-500 is already in the brand, described
   in the primitives above as "dark petrol/teal; quiet, sovereign, Belgian-
   engineering". It is exactly the right colour for this and it means the light
   theme reinforces the identity instead of diluting it.

   Why some PRIMITIVES are redefined here, which is normally wrong:
   the signal/anomaly/guard hues were chosen for a near-black background and
   are far too pale on white (#7DD87A on white is ~1.9:1 — invisible). About
   275 colour references across the app point at these primitives directly.
   Retuning them here fixes every one of those at once; the alternative was
   editing each call site and living with a half-converted app in between.
   Each is kept at the same hue, darkened only as far as legibility needs.
   ========================================================================= */
html.theme-light,
.theme-light {
  --bg:        #F5F7F9;   /* app background — cool, not cream */
  --bg-raised: #FFFFFF;   /* header, cards, table surface */
  --bg-sunk:   #EBEEF2;   /* inputs, wells, inset areas */
  --surface:   #FFFFFF;
  --surface-2: #F0F3F6;

  --fg:        #0F1419;   /* near-black with a cool cast, never pure #000 */
  --fg-1:      #2A313A;
  --fg-2:      #55606E;
  --fg-3:      #646C7A;   /* muted — solved against --bg-sunk (#EBEEF2), the DARKEST
                             light surface it ever sits on. Against white it is 5.29:1.
                             Two earlier passes solved against a lighter ground and
                             kept failing on the alarm queue rows. */
  --fg-on-accent: #FFFFFF;

  --line:         rgba(15, 20, 25, 0.10);
  --line-strong:  rgba(15, 20, 25, 0.20);

  --accent:    var(--rx-deep-500);
  --accent-fg: #FFFFFF;

  /* Status hues, re-tuned for a white ground.
     These stay light enough that var(--rx-ink-0) text on top of them still
     reads — that pairing is used throughout for "on" chips and tabs. */
  --rx-signal-500: #2E7D3E;   /* 4.9:1 on white */
  --rx-signal-600: #1F5C2C;
  --rx-signal-300: #DCF0DF;
  --rx-signal-900: #E8F5EA;

  --rx-anomaly-500: #8A5A00;  /* 5.1:1 on white */
  --rx-anomaly-300: #FAEBCC;
  --rx-anomaly-900: #FDF6E7;

  --rx-guard-500: #B3352B;    /* 5.0:1 on white */
  --rx-guard-300: #F7DCD8;
  --rx-guard-900: #FCEEEC;

  --rx-sense-500: #1F6088;    /* 5.2:1 on white */
  --rx-sense-300: #DAEAF3;
  --rx-sense-900: #EDF5FA;

  /* ...and darker siblings for the places where a status colour is TEXT on
     white rather than a fill. Small text needs ~4.5:1 and the fills above do
     not reach it. */
  --ok-text:     #1F6B32;
  --warn-text:   #8A5A00;
  --danger-text: #B3352B;
  --info-text:   #1F6088;

  --warn:      var(--rx-anomaly-500);
  --danger:    var(--rx-guard-500);
  --info:      var(--rx-sense-500);

  /* Depth: the dark theme leans on white insets and heavy black drops, both
     of which disappear or bruise on white. Light mode uses a hairline and a
     soft, short shadow instead. */
  --rx-inset-hair:  inset 0 0 0 1px rgba(15, 20, 25, 0.06);
  --rx-inset-soft:  inset 0 0 0 1px rgba(15, 20, 25, 0.08);
  --rx-drop-sm:     0 1px 2px rgba(15, 20, 25, 0.08);
  --rx-drop-lg:     0 2px 4px rgba(15, 20, 25, 0.06), 0 12px 28px rgba(15, 20, 25, 0.10);
  --rx-glow-signal: 0 0 0 1px var(--rx-signal-500);
  --rx-glow-guard:  0 0 0 1px var(--rx-guard-500);

  --rx-border-thin:     1px solid rgba(15, 20, 25, 0.14);
  --rx-border-hairline: 1px solid rgba(15, 20, 25, 0.08);

  /* Used as "text on a dark accent fill" across the app — white, not cream. */
  --rx-paper: #FFFFFF;

  /* Text that sits ON a status fill. Dark theme pairs near-black with a pale
     green; light theme pairs white with a dark green. Same rule, both ways. */
  --on-status: #FFFFFF;

  --focus-ring: 0 0 0 2px #FFFFFF, 0 0 0 4px var(--rx-deep-500);
}

/* Dark mode keeps the on-white text tokens pointing at its own hues so the
   same rule works in both themes. */
:root {
  --on-status:   var(--rx-ink-0);
  --ok-text:     var(--rx-signal-500);
  --warn-text:   var(--rx-anomaly-500);
  --danger-text: var(--rx-guard-500);
  --info-text:   var(--rx-sense-500);
}

/* =========================
   3.  BASE TYPE
   ========================= */
html {
  font-family: var(--rx-ff-sans);
  font-size: 16px;
  line-height: 1.5;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* "tnum" 0 disabled tabular figures here, and font-feature-settings
     beats font-variant-numeric, so the tables asking for tabular-nums
     were silently overridden and numeric columns never aligned. */
  font-feature-settings: "ss01", "cv11";
  font-variant-numeric: tabular-nums;
}

body { margin: 0; }

/* Display — editorial serif, tight tracking. Used for hero headlines only.
   Italic is the brand flex — appears on /home ("Infrastructure that *thinks*") */
.rx-display,
h1 {
  font-family: var(--rx-ff-display);
  font-weight: 400;
  font-size: clamp(42px, 6.4vw, 96px);
  line-height: 0.96;
  letter-spacing: -0.02em;
  color: var(--fg);
  margin: 0 0 var(--rx-s-5);
  text-wrap: pretty;
}
.rx-display em, h1 em { font-style: italic; }

/* H2 — section header, sans, smaller, colder */
.rx-h2,
h2 {
  font-family: var(--rx-ff-display);
  font-weight: 400;
  font-size: clamp(28px, 3.4vw, 48px);
  line-height: 1.05;
  letter-spacing: -0.015em;
  color: var(--fg);
  margin: 0 0 var(--rx-s-4);
  text-wrap: balance;
}

/* H3 — subsection, sans, all-caps-adjacent */
.rx-h3,
h3 {
  font-family: var(--rx-ff-sans);
  font-weight: 600;
  font-size: 20px;
  line-height: 1.2;
  letter-spacing: -0.005em;
  margin: 0 0 var(--rx-s-3);
}

/* H4 — in-card title */
.rx-h4,
h4 {
  font-family: var(--rx-ff-sans);
  font-weight: 600;
  font-size: 15px;
  line-height: 1.3;
  letter-spacing: 0;
  margin: 0 0 var(--rx-s-2);
}

/* Eyebrow — tiny kicker above headings ("Architecture", "Compliance", etc.) */
.rx-eyebrow {
  font-family: var(--rx-ff-sans);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-2);
  margin: 0 0 var(--rx-s-3);
  display: inline-flex;
  align-items: center;
  gap: var(--rx-s-2);
}
.rx-eyebrow::before {
  content: "";
  display: inline-block;
  width: 18px; height: 1px;
  background: currentColor;
  opacity: 0.7;
}

/* Body — default paragraph */
.rx-body,
p {
  font-family: var(--rx-ff-sans);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.55;
  color: var(--fg-1);
  margin: 0 0 var(--rx-s-4);
  text-wrap: pretty;
}
.rx-body--lg { font-size: 19px; line-height: 1.5; color: var(--fg); }
.rx-body--sm { font-size: 14px; line-height: 1.5; }

/* Caption — small dim label */
.rx-caption {
  font-family: var(--rx-ff-sans);
  font-size: 13px;
  line-height: 1.4;
  color: var(--fg-2);
}

/* Code / value — inline or block, tabular */
.rx-code, code, kbd, samp {
  font-family: var(--rx-ff-sans);
  font-size: 0.92em;
  font-feature-settings: "tnum", "zero";
  font-weight: 450;
}
pre.rx-code, .rx-code--block {
  display: block;
  padding: var(--rx-s-4);
  background: var(--bg-sunk);
  border: 1px solid var(--line);
  border-radius: var(--rx-radius-3);
  color: var(--fg);
  font-size: 13px;
  line-height: 1.55;
  overflow-x: auto;
  white-space: pre;
}

/* Metric — large tabular number. Dashboards. */
.rx-metric {
  font-family: var(--rx-ff-sans);
  font-weight: 500;
  font-size: clamp(36px, 5vw, 72px);
  line-height: 1;
  letter-spacing: -0.03em;
  font-feature-settings: "tnum";
  color: var(--fg);
}
.rx-metric__unit {
  font-size: 0.35em;
  letter-spacing: 0;
  color: var(--fg-2);
  margin-left: 0.25em;
  font-weight: 400;
}

/* Path — rx-os's signature "rx-os.local/dashboard" / "rx-os :: passive discovery" lockup */
.rx-path {
  font-family: var(--rx-ff-sans);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--fg-2);
  display: inline-flex;
  gap: 0.5ch;
  align-items: baseline;
}
.rx-path strong { color: var(--fg); font-weight: 500; }

/* Marker — the "//", "#", "{}", "<>", "~", "\*" principle markers
   used in /about → Principles. Decorative, monospace, large. */
.rx-marker {
  font-family: var(--rx-ff-sans);
  font-weight: 400;
  font-size: 40px;
  line-height: 1;
  color: var(--rx-signal-500);
  opacity: 0.8;
}

/* Links */
a { color: inherit; text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { text-decoration-color: var(--accent); }

/* Selection */
::selection { background: var(--rx-signal-500); color: var(--rx-ink-0); }

/* =========================
   DATA TYPOGRAPHY (2026-07-27)
   The UI chrome is set in the sans; monospace is reserved strictly for
   machine values — identifiers, hashes, coordinates, timestamps, keys.
   Numerals stay column-aligned everywhere via tabular figures.
   ========================= */
body { font-variant-numeric: tabular-nums; }

code, pre, kbd,
.kbd, .mono, .badge-mono,
[data-mono],
.evidence .block, .evidence .chain,
.search-bar .kbd,
.tape-t, .age-val, .rail-item .right-meta {
  font-family: var(--rx-ff-mono);
}

/* =========================================================================
   PERMANENTLY DARK SURFACES
   =========================================================================
   A video letterbox stays near-black in both themes — you do not put footage
   on a white plate. That makes it an island of dark inside the light theme,
   and the light text tokens (#646C7A muted, #2E7D3E ok) are dark-on-dark
   there: the "sin video para CH1" message measured 2.8:1 and the REC badge
   3.5:1 once light became the default.

   Rather than special-case each label, these surfaces re-declare the text
   tokens to their dark-theme values. Everything inside inherits and the same
   markup reads correctly whichever theme is active.
   ========================================================================= */
.video-stage,
.al-video,
.snap-card,
.on-dark {
  --fg:        var(--rx-bone);
  --fg-1:      var(--rx-fog-1);
  --fg-2:      var(--rx-fog-2);
  --fg-3:      var(--rx-fog-3);
  --on-status: var(--rx-ink-0);
  --ok-text:     #7DD87A;
  --warn-text:   #F3B64A;
  --danger-text: #F0958A;
  /* Badges here (REC, the timeline marker) reach for the PRIMITIVE rather
     than the semantic token, so the primitive has to come back too or they
     stay at the light theme's dark green on a black plate. */
  --rx-signal-500:  #7DD87A;
  --rx-anomaly-500: #F3B64A;
  --rx-guard-500:   #F0958A;
  --rx-sense-500:   #7AB6D8;
  --line:        rgba(212, 217, 228, 0.14);
  --line-strong: rgba(212, 217, 228, 0.24);
  color: var(--fg);
}
