@import 'tailwindcss';

/* ─────────────────────────────────────────────────────────────────────────────
   NABDH design tokens

   A dark control-room palette: near-black backgrounds so illuminated data carries
   the hierarchy, one accent for the brand, and clearly separated state colours.
   State is never communicated by colour alone — every badge, marker and row also
   carries a text label, which keeps the interface readable for colour-blind operators
   and on the washed-out projectors these demos tend to run on.

   Three token families sit alongside the state colours because the platform routinely
   shows three *kinds* of number on one screen and confusing them would be dangerous:
   `ai` for a model's output, `simulation` for something that was computed rather than
   measured, and `twin` for the digital twin's own reading of the world.
   ───────────────────────────────────────────────────────────────────────────── */

@theme {
  --color-base: #05080f;
  --color-surface: #0b1220;
  --color-surface-2: #101a2c;
  --color-surface-3: #16233a;
  --color-elevated: #16233a;
  --color-border: #1e2d47;
  --color-border-strong: #2b3f60;

  --color-text: #e8eefb;
  --color-text-muted: #93a5c4;
  --color-text-faint: #64789a;

  --color-brand: #24d07f;
  --color-brand-dim: #17864f;
  --color-brand-glow: #24d07f26;
  /* The only colour that is legible on a brand-filled surface. It is a token rather
     than a literal because the brand itself moves between themes, and a foreground
     that does not move with it is the classic way a button goes unreadable in light
     mode. */
  --color-on-brand: #052012;

  --color-info: #38bdf8;
  --color-accent: #a78bfa;

  --color-normal: #10b981;
  --color-watch: #fbbf24;
  --color-warning: #f97316;
  --color-critical: #ef4444;
  --color-emergency: #ff3d71;
  --color-muted: #7d90b0;

  /* Provenance families (§81, §82). */
  --color-ai: #a78bfa;
  --color-simulation: #22d3ee;
  --color-twin: #7dd3fc;
  /* The 3D scene's ground. Deliberately fixed rather than themed: WebGL clears the canvas
     to this exact colour, and a themed surface behind it would show as a seam. */
  --color-scene: #060a11;

  --font-sans:
    ui-sans-serif, system-ui, 'Segoe UI', 'Noto Sans Arabic', 'Dubai', 'Tahoma', 'Helvetica Neue',
    Arial, sans-serif;
  --font-mono: ui-monospace, 'Cascadia Code', 'Consolas', 'SF Mono', 'Roboto Mono', monospace;

  --radius-panel: 0.875rem;
}

:root {
  color-scheme: dark;
  --nabdh-grid-line: #ffffff08;
  /* Glass is a deliberate, sparing effect: one blurred surface reads as depth, ten
     read as fog. These variables exist so the treatment stays consistent where it is
     used and easy to find where it is not. */
  --nabdh-glass-bg: #0b122099;
  --nabdh-glass-border: #2b3f6099;
  --nabdh-glow: 0 0 0 1px #24d07f22, 0 18px 48px -24px #24d07f55;
}

/* ── Light mode ───────────────────────────────────────────────────────────────
   A control room runs dark, but the same screens get opened on a laptop in daylight
   and printed into a report. Only the surface and text tokens move; the state hues
   are darkened just enough to hold contrast on white without becoming different
   colours, so a red row is the same red everywhere.
   ───────────────────────────────────────────────────────────────────────────── */

:root[data-theme='light'] {
  color-scheme: light;
  --color-base: #f4f7fc;
  --color-surface: #ffffff;
  --color-surface-2: #eef2f9;
  --color-surface-3: #e2e8f2;
  --color-elevated: #ffffff;
  --color-border: #d5dde9;
  --color-border-strong: #b7c4d6;

  --color-text: #0d1626;
  --color-text-muted: #46587a;
  --color-text-faint: #6b7d9c;

  --color-brand: #0a7a44;
  --color-brand-dim: #06552f;
  --color-brand-glow: #0a7a4420;
  /* White on the light-mode brand is only 3.5:1 — fine for a border, not for the label
     on a primary button. The dark green clears 4.5:1 on both brands. */
  --color-on-brand: #ffffff;

  --color-info: #03608f;
  --color-accent: #6d28d9;

  --color-normal: #047857;
  --color-watch: #775200;
  --color-warning: #a13207;
  --color-critical: #c11414;
  --color-emergency: #a8123a;
  --color-muted: #55677f;

  --color-ai: #6d28d9;
  --color-simulation: #0b6a86;
  --color-twin: #03608f;

  --nabdh-grid-line: #0d162610;
  --nabdh-glass-bg: #ffffffcc;
  --nabdh-glass-border: #b7c4d6aa;
  --nabdh-glow: 0 0 0 1px #0a7a4422, 0 18px 40px -26px #0a7a4466;
}

/* ── High contrast ───────────────────────────────────────────────────────────
   Not a theme so much as an accessibility mode: borders become visible rather than
   suggested, muted text stops being muted, and the ambient washes are switched off
   so nothing sits on a gradient.
   ───────────────────────────────────────────────────────────────────────────── */

:root[data-contrast='high'] {
  --color-base: #000000;
  --color-surface: #06080d;
  --color-surface-2: #0d1119;
  --color-surface-3: #141a26;
  --color-border: #6d7f9c;
  --color-border-strong: #9db0cc;
  --color-text: #ffffff;
  --color-text-muted: #d5deed;
  --color-text-faint: #b5c2d6;
  --color-normal: #34d399;
  --color-watch: #fcd34d;
  --color-warning: #fb923c;
  --color-critical: #ff8a8a;
  --color-emergency: #ffa3ba;
  --color-muted: #a9bad4;
  --color-on-brand: #000000;
  --nabdh-grid-line: transparent;
  --nabdh-glass-bg: #06080d;
  --nabdh-glass-border: #9db0cc;
}

:root[data-contrast='high'] .nabdh-radial,
:root[data-contrast='high'] .nabdh-grid-bg {
  background-image: none;
}

:root[data-theme='light'][data-contrast='high'] {
  --color-base: #ffffff;
  --color-surface: #ffffff;
  --color-surface-2: #f1f4fa;
  --color-surface-3: #e4e9f2;
  --color-border: #4a5a75;
  --color-border-strong: #24344d;
  --color-text: #000000;
  --color-text-muted: #23324a;
  --color-text-faint: #33456280;

  /* Without these, light + high contrast inherits the *dark* high-contrast state hues
     — #fcd34d on white is 1.4:1, which is the least readable combination in the whole
     product, in the one mode chosen specifically for readability. Every value below
     clears 7:1 on both white and the raised surface. */
  --color-brand: #046b39;
  --color-brand-dim: #024527;
  --color-on-brand: #ffffff;
  --color-normal: #02563a;
  --color-watch: #664700;
  --color-warning: #8a3208;
  --color-critical: #a30d0d;
  --color-emergency: #8f0b30;
  --color-muted: #33455f;
  --color-info: #03567f;
  --color-accent: #5b21b6;
  --color-ai: #5b21b6;
  --color-simulation: #04607a;
  --color-twin: #03567f;

  /* The high-contrast block above sets the glass surface for a dark ground. Without
     these two lines the command bar stays near-black while the page turns white, and
     the bar's own text — now dark navy — is set on it. Black on black, in the mode
     chosen for legibility. */
  --nabdh-glass-bg: #ffffff;
  --nabdh-glass-border: #24344d;
}

* {
  border-color: var(--color-border);
}

html,
body {
  height: 100%;
}

body {
  background-color: var(--color-base);
  color: var(--color-text);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ── Typography scale ─────────────────────────────────────────────────────────
   Named steps rather than ad-hoc sizes, so a heading in the war room is the same
   heading in the twin. The data steps are separate from the prose steps because a
   readout and a paragraph want different things: prose wants comfortable leading,
   a readout wants tight tabular digits that do not reflow as they change.
   ───────────────────────────────────────────────────────────────────────────── */

.type-display {
  font-size: clamp(2rem, 1.2rem + 2.6vw, 3.25rem);
  line-height: 1.05;
  font-weight: 600;
  letter-spacing: -0.03em;
}

.type-h1 {
  font-size: clamp(1.35rem, 1.1rem + 0.9vw, 1.75rem);
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.type-h2 {
  font-size: 1.125rem;
  line-height: 1.3;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.type-h3 {
  font-size: 0.8125rem;
  line-height: 1.35;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.type-body {
  font-size: 0.875rem;
  line-height: 1.6;
}

.type-caption {
  font-size: 0.6875rem;
  line-height: 1.45;
}

/** A headline figure: large, tabular, and never italic or condensed. */
.type-data {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.25rem);
  line-height: 1;
  font-weight: 600;
  letter-spacing: -0.02em;
}

/** Raw telemetry, where alignment matters more than beauty. */
.type-telemetry {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.8125rem;
  letter-spacing: -0.01em;
}

/* Arabic sets a little larger than Latin at the same nominal size, and its numerals
   are rendered Latin throughout the product for cross-language comparability. */
[dir='rtl'] .type-body,
[dir='rtl'] .type-caption {
  line-height: 1.75;
}

/* Ambient grid — a faint reference lattice that reads as an instrument background
   without competing with the data drawn on top of it. */
.nabdh-grid-bg {
  background-image:
    linear-gradient(to right, var(--nabdh-grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--nabdh-grid-line) 1px, transparent 1px);
  background-size: 44px 44px;
}

.nabdh-radial {
  background:
    radial-gradient(1100px 620px at 78% -8%, #24d07f14, transparent 62%),
    radial-gradient(900px 520px at 8% 4%, #38bdf814, transparent 58%);
}

/** One blurred surface, used for the command bar and floating panels only. */
.nabdh-glass {
  background-color: var(--nabdh-glass-bg);
  border-color: var(--nabdh-glass-border);
  backdrop-filter: blur(14px) saturate(1.2);
}

/** Reserved for the single most important panel on a screen. */
.nabdh-glow {
  box-shadow: var(--nabdh-glow);
}

/* Numeric readouts line up column-to-column and never reflow as digits change. */
.tnum {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

/* ── Focus ────────────────────────────────────────────────────────────────── */

:focus-visible {
  outline: 2px solid var(--color-brand);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ── Scrollbars ───────────────────────────────────────────────────────────── */

* {
  scrollbar-width: thin;
  scrollbar-color: var(--color-border-strong) transparent;
}

*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

*::-webkit-scrollbar-track {
  background: transparent;
}

*::-webkit-scrollbar-thumb {
  background-color: var(--color-border-strong);
  border-radius: 999px;
  border: 3px solid transparent;
  background-clip: content-box;
}

/* ── Motion ───────────────────────────────────────────────────────────────── */

@keyframes nabdh-pulse {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.45;
    transform: scale(1.35);
  }
}

.nabdh-pulse {
  animation: nabdh-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

@keyframes nabdh-sweep {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(400%);
  }
}

.nabdh-sweep::after {
  content: '';
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 25%;
  background: linear-gradient(90deg, transparent, #24d07f30, transparent);
  animation: nabdh-sweep 2.2s ease-in-out infinite;
}

@keyframes nabdh-fade-up {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.nabdh-enter {
  animation: nabdh-fade-up 0.35s ease-out both;
}

@keyframes nabdh-dash {
  to {
    stroke-dashoffset: -24;
  }
}

/** Energy flowing along a line. Direction of travel is the direction of power. */
.nabdh-flow {
  stroke-dasharray: 4 8;
  animation: nabdh-dash 1.6s linear infinite;
}

.nabdh-flow-reverse {
  stroke-dasharray: 4 8;
  animation: nabdh-dash 1.6s linear infinite reverse;
}

.nabdh-flow-fast {
  animation-duration: 0.7s;
}

.nabdh-flow-slow {
  animation-duration: 3s;
}

/** A risk propagating outward from a node, drawn as a ring rather than a blast. */
@keyframes nabdh-wave {
  from {
    r: 4;
    opacity: 0.55;
  }
  to {
    r: 34;
    opacity: 0;
  }
}

.nabdh-wave {
  animation: nabdh-wave 1.8s ease-out infinite;
}

/** A scan line for panels that are actively computing. */
@keyframes nabdh-scan {
  from {
    transform: translateY(-100%);
  }
  to {
    transform: translateY(1200%);
  }
}

.nabdh-scan::before {
  content: '';
  position: absolute;
  inset-inline: 0;
  height: 12%;
  background: linear-gradient(180deg, transparent, #38bdf826, transparent);
  animation: nabdh-scan 2.6s linear infinite;
  pointer-events: none;
}

/* Anyone who has asked their system to reduce motion gets a still interface. On a
   wall display that runs for hours, this matters more than it does on a landing page.
   The same switch is exposed in the product as a preference, because a projector in a
   judging room is not the same environment as the operator's own machine. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

:root[data-motion='reduced'] *,
:root[data-motion='reduced'] *::before,
:root[data-motion='reduced'] *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}

/* ── Print ────────────────────────────────────────────────────────────────── */

@media print {
  body {
    background: #fff;
    color: #000;
  }
  .no-print {
    display: none !important;
  }
}

/*
 * Labels floating beside an asset in the Live 3D Grid (4.2).
 *
 * Rendered as DOM over the WebGL canvas rather than as in-scene text, so they inherit the
 * console's type and colour tokens and a screen reader can reach them. The plate behind
 * each one is what makes a label legible over a scene whose background is whatever
 * happens to be behind it — white text on a bright transformer is not a label.
 *
 * `pointer-events: none` throughout: the label must never swallow a click meant for the
 * asset it is describing.
 */
.nabdh-scene-label {
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
  padding: 0.2rem 0.45rem;
  border-radius: 5px;
  border: 1px solid color-mix(in srgb, var(--color-border-strong) 70%, transparent);
  background: color-mix(in srgb, #05080f 82%, transparent);
  backdrop-filter: blur(2px);
  font-family: var(--font-mono);
  line-height: 1.25;
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
}

.nabdh-scene-label .code {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--color-text);
}

.nabdh-scene-label .reading {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}

/* The status word: the non-colour channel that carries state on its own (§24). */
.nabdh-scene-label .status {
  font-size: 9px;
  letter-spacing: 0.08em;
  color: var(--color-normal);
}

.nabdh-scene-label[data-state='watch'] .status { color: var(--color-watch); }
.nabdh-scene-label[data-state='warning'] .status { color: var(--color-warning); }
.nabdh-scene-label[data-state='critical'] .status,
.nabdh-scene-label[data-state='emergency'] .status { color: var(--color-critical); }

.nabdh-scene-label[data-state='warning'] { border-color: color-mix(in srgb, var(--color-warning) 55%, transparent); }
.nabdh-scene-label[data-state='critical'],
.nabdh-scene-label[data-state='emergency'] { border-color: color-mix(in srgb, var(--color-critical) 65%, transparent); }
