/* TradingBot console — Frontend V3.

   The visual and informational source of truth is the Figma page
   "05 — Full Product v3" (file lIZzdeyVbqjSraY6KkG0Pr, canvas 24:6). Every
   token below is the value Figma publishes as a variable; every measurement is
   the one the frame declares. Where this file departs from Figma it says so at
   the point of departure, and there are exactly two such places — both are
   contrast corrections, both are recorded in
   docs/design/v3-figma-fidelity.md.

   Stack constraints inherited from the rest of the console: no build step, no
   framework, no outbound request. Inter is used when the machine has it and
   the stack falls back otherwise, exactly as static/app.css does — a webfont
   would be a network call on a console whose system page claims the dataset is
   verified entirely offline. */

:root {
  /* ---- Figma variables, verbatim (get_variable_defs on 24:7) ---------- */
  --tb-bg-app: #0d1420;
  --tb-bg-surface: #1f2937;
  --tb-bg-subtle: #1f2937;
  --tb-border-default: #526072;

  --tb-text-primary: #ffffff;
  --tb-text-secondary: #d9dee7;
  --tb-text-muted: #8a94a6;

  --tb-success: #24a865;
  --tb-success-subtle: #167544;
  --tb-warning: #e99a19;
  --tb-warning-subtle: #a66508;
  --tb-accent: #3478f6;
  --tb-accent-subtle: #1e5cc8;

  /* ---- Departure 1: status chips ------------------------------------- *
     Figma fills a status chip with `*-subtle` and writes the label in the
     matching full-strength hue: #24a865 on #167544 is 1.87:1, #e99a19 on
     #a66508 is 2.03:1. Chip labels are 10-11px semibold — small text, so AA
     asks for 4.5:1 and these miss it by a factor of two. The design intent is
     "quiet tinted chip, label in the status hue", and that intent survives if
     the fill becomes a tint of the hue over the surface rather than an opaque
     darker sibling. That is also what static/app.css already does for the same
     job (--success-bg and friends), so V3 does not invent a second convention.

     Measured on --tb-bg-surface, which is the darker of the two backgrounds a
     chip ever sits on: success 4.94, warning 5.47, accent 4.63, danger 4.73.
     tests/test_v3_frontend.py parses these declarations and re-derives the
     ratios; the numbers in this comment are not the authority, that test is. */
  --tb-success-chip-fg: #37c67d;
  --tb-warning-chip-fg: #f0ad3c;
  --tb-accent-chip-fg: #7aa9fa;
  --tb-danger-chip-fg: #f58b8e;
  --tb-success-chip-bg: rgba(55, 198, 125, 0.16);
  --tb-warning-chip-bg: rgba(240, 173, 60, 0.16);
  --tb-accent-chip-bg: rgba(122, 169, 250, 0.16);
  --tb-danger-chip-bg: rgba(245, 139, 142, 0.16);

  /* Neutral chip — the state Figma never had to draw because its mock always
     had data. Most of this console's chips are neutral today. */
  --tb-neutral-chip-fg: #b9c2d0;
  --tb-neutral-chip-bg: rgba(185, 194, 208, 0.13);

  /* danger has no Figma variable: the mock contains no failing state. Chosen
     in the same family as the rest and held to the same ratio. */
  --tb-danger: #e5484d;

  /* ---- Departure 2: focus ring --------------------------------------- *
     Figma draws no focus state at all. A keyboard-operable console needs one,
     and --tb-accent at 3.61:1 on the surface is under the 3:1 that WCAG 1.4.11
     asks of a focus indicator only by luck of rounding. The lighter accent is
     used for the ring so the indicator clears the bar on every surface. */
  --tb-focus: #7aa9fa;

  /* ---- Geometry, from the frames ------------------------------------- */
  --tb-sidebar-w: 240px;
  --tb-main-w: 1200px;
  --tb-radius-card: 12px;
  --tb-radius-block: 10px;
  --tb-radius-pill: 999px;

  --tb-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --tb-mono: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Mono", Menlo, Consolas, monospace;

  /* ---- Motion ---------------------------------------------------------- *
     Four durations and two curves for the whole surface. A microinteraction
     that has to be noticed is 120ms; a state change 200ms; something that
     travels across the page 380ms; the ambient layer is measured in seconds
     because it must never read as activity. Everything below is switched off
     wholesale in the reduced-motion block at the end of this file. */
  --tb-dur-fast: 120ms;
  --tb-dur: 200ms;
  --tb-dur-slow: 380ms;
  --tb-dur-ambient: 24s;
  --tb-ease: cubic-bezier(0.2, 0, 0, 1);
  --tb-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--tb-bg-app);
  color: var(--tb-text-primary);
  font-family: var(--tb-sans);
  font-size: 13px;
  line-height: 1.45;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

/* Figma sets every heading explicitly; the browser's own h1..h4 scale is
   never what a frame declares, so it is neutralised here rather than
   overridden at each of the fourteen screens. */
h1, h2, h3, h4 { margin: 0; font-weight: 600; line-height: 1.2; font-size: inherit; }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }

a { color: var(--tb-accent-chip-fg); text-decoration: none; }
a:hover { text-decoration: underline; }

/* One ring, everywhere, and never removed without a replacement. */
:focus-visible {
  outline: 2px solid var(--tb-focus);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 10px 14px;
  background: var(--tb-accent-subtle);
  color: var(--tb-text-primary);
  font-size: 12px;
  font-weight: 600;
  border-radius: 0 0 var(--tb-radius-block) 0;
}
.skip-link:focus { left: 0; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ====================================================================== *
   Shell — Sidebar 240 + Main 1200 = the 1440 the frames are drawn at.
   ====================================================================== */

.app {
  display: flex;
  align-items: stretch;
  min-height: 100vh;
  position: relative;
}

/* Ambient layer. A pair of very wide, very low-opacity radial washes that
   drift against each other. It exists to keep a mostly-flat dark surface from
   looking dead; at 0.05 alpha over 24s it is below the threshold at which a
   reader would call it movement, which is the point — an operations console
   must not appear to be doing something when it is not. */
.app::before {
  content: "";
  position: fixed;
  inset: -20%;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(46% 38% at 22% 12%, rgba(52, 120, 246, 0.05), transparent 68%),
    radial-gradient(40% 34% at 84% 78%, rgba(36, 168, 101, 0.04), transparent 70%);
  animation: ambient-drift var(--tb-dur-ambient) ease-in-out infinite alternate;
}

@keyframes ambient-drift {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(1.6%, -1.2%, 0) scale(1.05); }
}

.sidebar {
  position: relative;
  z-index: 1;
  flex: 0 0 var(--tb-sidebar-w);
  width: var(--tb-sidebar-w);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 24px 18px 20px;
  background: var(--tb-bg-surface);
  border-right: 1px solid var(--tb-border-default);
}

.brand { display: flex; flex-direction: column; gap: 2px; color: inherit; }
.brand:hover { text-decoration: none; }
.brand-name { font-size: 20px; font-weight: 700; color: var(--tb-text-primary); }
.brand-sub { font-size: 11px; color: var(--tb-text-muted); }

.sidebar-spacer { flex: 1 0 0; min-height: 0; }

.mode-card {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 12px;
  background: var(--tb-bg-subtle);
  border: 1px solid var(--tb-border-default);
  border-radius: var(--tb-radius-block);
}
.mode-card dt { font-size: 9px; font-weight: 600; color: var(--tb-text-muted); letter-spacing: 0.04em; }
.mode-card dd { margin: 0; font-size: 12px; font-weight: 600; color: var(--tb-text-primary); }
.mode-card .mode-note { font-size: 10px; font-weight: 400; color: var(--tb-text-muted); }

.main {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  max-width: var(--tb-main-w);
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 30px 32px;
  background: transparent;
}

.page-head { display: flex; flex-direction: column; gap: 6px; }
.page-head h1 { font-size: 28px; font-weight: 700; color: var(--tb-text-primary); }
.page-head p { font-size: 13px; color: var(--tb-text-secondary); }

/* ====================================================================== *
   Navigation
   ====================================================================== */

.nav { display: flex; flex-direction: column; gap: 4px; }

.nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-radius: var(--tb-radius-block);
  font-size: 13px;
  font-weight: 500;
  color: var(--tb-text-secondary);
  transition: color var(--tb-dur) var(--tb-ease);
}
.nav a:hover { text-decoration: none; color: var(--tb-text-primary); }

/* The active pill is a separate painted layer rather than a background on the
   link, so it can carry a view-transition-name and morph from one nav entry to
   the next as the document changes. The link keeps its own text colour. */
.nav a::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: transparent;
  transition: background var(--tb-dur) var(--tb-ease);
}
.nav a:hover::before { background: rgba(255, 255, 255, 0.04); }

.nav a[aria-current="page"] {
  color: var(--tb-text-primary);
  font-weight: 600;
}
.nav a[aria-current="page"]::before {
  background: var(--tb-accent-subtle);
  view-transition-name: nav-active;
}

.nav .dot { position: relative; z-index: 1; }
.nav span { position: relative; z-index: 1; }

/* ====================================================================== *
   Dots — Figma exports these as 7px and 6px single-fill circles (V3 / Dot
   001..009). A circle whose only variable is its fill is a token, not a glyph,
   so it is drawn here and coloured by the status token; the exported
   dimensions are reproduced exactly.
   ====================================================================== */

.dot {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}
.dot-sm { width: 6px; height: 6px; }

.dot-success { color: var(--tb-success); }
.dot-warning { color: var(--tb-warning); }
.dot-accent  { color: var(--tb-accent); }
.dot-muted   { color: var(--tb-text-muted); }
.dot-danger  { color: var(--tb-danger); }

/* Lifecycle motion: only a genuinely running process breathes. Everything
   else is a static dot, because a console that animates an idle state is
   lying about it. */
.dot-live { animation: dot-breathe 2.6s var(--tb-ease) infinite; }

@keyframes dot-breathe {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.55; transform: scale(0.82); }
}

/* ====================================================================== *
   Chips
   ====================================================================== */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  border-radius: var(--tb-radius-pill);
  font-size: 10px;
  font-weight: 600;
  white-space: nowrap;
  background: var(--tb-neutral-chip-bg);
  color: var(--tb-neutral-chip-fg);
}
.chip-lg { gap: 8px; padding: 8px 10px; font-size: 11px; }

.chip-success { background: var(--tb-success-chip-bg); color: var(--tb-success-chip-fg); }
.chip-warning { background: var(--tb-warning-chip-bg); color: var(--tb-warning-chip-fg); }
.chip-accent  { background: var(--tb-accent-chip-bg);  color: var(--tb-accent-chip-fg); }
.chip-danger  { background: var(--tb-danger-chip-bg);  color: var(--tb-danger-chip-fg); }

/* Inside a chip the dot inherits the chip's corrected foreground, so the two
   never disagree about which status they are showing. */
.chip .dot { color: currentColor; }

/* ====================================================================== *
   Cards and panels
   ====================================================================== */

.card {
  background: var(--tb-bg-surface);
  border: 1px solid var(--tb-border-default);
  border-radius: var(--tb-radius-card);
  padding: 14px 16px;
}

/* Figma's panels are all vertical stacks with a declared gap; the gap is the
   panel's own property rather than a margin on its children, so a panel that
   needs a different rhythm overrides one value instead of unsetting margins. */
.panel {
  display: flex;
  flex-direction: column;
  gap: 11px;
  background: var(--tb-bg-surface);
  border: 1px solid var(--tb-border-default);
  border-radius: var(--tb-radius-card);
  padding: 15px 17px;
}

/* Microinteraction. Two properties only — a 1px rise and a brighter edge — on
   the cards that actually lead somewhere. `will-change` is deliberately absent:
   a dozen promoted layers cost more than this animation is worth. */
.card-link {
  display: block;
  color: inherit;
  transition:
    transform var(--tb-dur-fast) var(--tb-ease-out),
    border-color var(--tb-dur) var(--tb-ease),
    background-color var(--tb-dur) var(--tb-ease);
}
.card-link:hover {
  text-decoration: none;
  transform: translateY(-1px);
  border-color: var(--tb-accent);
  background: color-mix(in srgb, var(--tb-bg-surface) 92%, var(--tb-accent));
}
.card-link:active { transform: translateY(0); }

.section-head {
  display: flex;
  align-items: center;
  gap: 12px;
}
.section-head h2 { font-size: 17px; font-weight: 600; color: var(--tb-text-primary); }
.section-head .rule { flex: 1 0 0; min-width: 0; }
.section-head a { font-size: 10px; font-weight: 600; }

.divider {
  height: 1px;
  background: var(--tb-border-default);
  border: 0;
  margin: 0;
}

.empty-state {
  padding: 22px 16px;
  border: 1px dashed var(--tb-border-default);
  border-radius: var(--tb-radius-card);
  color: var(--tb-text-muted);
  font-size: 12px;
}

/* ====================================================================== *
   Overview (Figma 24:7)
   ====================================================================== */

/* Figma draws the banner at a fixed 1136×48, which is exactly the main
   column's content width; it is written as a stretch here so the same rule
   holds at 1280 and 1024. */
.status-banner {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 48px;
  padding: 10px 14px;
  border-radius: var(--tb-radius-card);
  border: 1px solid transparent;
}
.status-banner .rule { flex: 1 0 0; min-width: 0; }
.status-banner-text { font-size: 11px; font-weight: 500; color: var(--tb-text-secondary); }
.status-banner-trailing { font-size: 10px; font-weight: 600; color: var(--tb-text-secondary); }

.status-banner-success { background: var(--tb-success-chip-bg); border-color: var(--tb-success); }
.status-banner-warning { background: var(--tb-warning-chip-bg); border-color: var(--tb-warning); }
.status-banner-danger  { background: var(--tb-danger-chip-bg);  border-color: var(--tb-danger); }

/* Figma lays four 266px tiles with a 16px gap, which stops 24px short of the
   banner above them. Equal columns across the full width instead: the mock's
   short row reads as an unstretched frame rather than an intent, and four
   fractional columns keep the row flush at every viewport. */
.metric-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}
.metric {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 102px;
}
.metric-label { font-size: 9px; font-weight: 600; color: var(--tb-text-muted); letter-spacing: 0.04em; }
.metric-value { font-size: 23px; font-weight: 600; color: var(--tb-text-primary); }
.metric-note { font-size: 10px; color: var(--tb-text-muted); }

/* 724 + 18 + 394 = 1136, the content width. Held as a ratio so the split
   survives the narrower viewports. */
.focus-row {
  display: grid;
  grid-template-columns: minmax(0, 724fr) minmax(0, 394fr);
  gap: 18px;
  align-items: start;
}

.focus-strategies { display: flex; flex-direction: column; gap: 10px; }
.focus-list { display: flex; flex-direction: column; gap: 10px; }

.focus-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 13px 16px;
}
.focus-card-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.focus-card-name { font-size: 14px; font-weight: 600; color: var(--tb-text-primary); }
.focus-card-desc { font-size: 10px; color: var(--tb-text-muted); }
.focus-card-meta {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  font-size: 10px;
  font-weight: 500;
  color: var(--tb-text-secondary);
}

/* The overview's panel is drawn one step roomier than the detail panels
   (Figma 26:62: px 18 / py 16 / gap 13 against the shared 17 / 15 / 11). */
.research-pulse { gap: 13px; padding: 16px 18px; }
.research-pulse h2 { font-size: 17px; font-weight: 600; color: var(--tb-text-primary); }
.panel-sub { font-size: 10px; color: var(--tb-text-muted); }

.pulse-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px 22px;
  margin: 0;
}
.pulse-stats > div { display: flex; align-items: baseline; gap: 8px; }
.pulse-stats dt { font-size: 10px; color: var(--tb-text-muted); }
.pulse-stats dd { margin: 0; font-size: 12px; font-weight: 600; color: var(--tb-text-primary); }

.pulse-kicker { font-size: 9px; font-weight: 600; color: var(--tb-text-muted); letter-spacing: 0.04em; }
.pulse-headline { font-size: 13px; font-weight: 600; color: var(--tb-text-primary); }
.pulse-meta,
.pulse-empty { font-size: 10px; color: var(--tb-text-muted); }
.research-pulse a { font-size: 10px; font-weight: 600; }

.next-block {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-top: auto;
  padding: 10px 12px;
  background: var(--tb-bg-subtle);
  border: 1px solid var(--tb-border-default);
  border-radius: var(--tb-radius-block);
}
.next-title { font-size: 10px; font-weight: 600; color: var(--tb-text-primary); }
.next-item { font-size: 10px; color: var(--tb-text-secondary); }

/* ====================================================================== *
   Strategien (Figma 24:46)
   ====================================================================== */

.toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
}
.toolbar .rule { flex: 1 0 0; min-width: 0; }

.filter-group { display: flex; gap: 4px; }
.filter {
  padding: 8px 12px;
  border-radius: 9px;
  font-size: 10px;
  font-weight: 500;
  color: var(--tb-text-secondary);
  transition: background var(--tb-dur) var(--tb-ease), color var(--tb-dur) var(--tb-ease);
}
.filter:hover { text-decoration: none; background: rgba(255, 255, 255, 0.05); color: var(--tb-text-primary); }
.filter.is-active {
  background: var(--tb-accent-subtle);
  color: var(--tb-text-primary);
  font-weight: 600;
}

.search {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px;
  background: var(--tb-bg-surface);
  border: 1px solid var(--tb-border-default);
  border-radius: 9px;
}
.search:focus-within { border-color: var(--tb-focus); }
.search-glyph { font-size: 11px; color: var(--tb-text-muted); line-height: 1; }
.search input {
  width: 150px;
  border: 0;
  background: none;
  color: var(--tb-text-primary);
  font: inherit;
  font-size: 10px;
}
.search input::placeholder { color: var(--tb-text-muted); }
.search input:focus { outline: none; }

.note-bar {
  display: flex;
  align-items: center;
  min-height: 48px;
  padding: 10px 14px;
  border-radius: 11px;
  background: var(--tb-bg-subtle);
  border: 1px solid var(--tb-border-default);
  font-size: 10px;
  font-weight: 500;
  color: var(--tb-text-secondary);
}
/* The closing note is a footnote, not a statement of the same weight as the
   one above the list. */
.note-bar-quiet {
  min-height: 0;
  padding: 12px 14px;
  border-radius: var(--tb-radius-block);
  background: var(--tb-bg-surface);
  font-weight: 400;
  color: var(--tb-text-muted);
}

/* Figma places three fixed 360px cards with a 16px gap. Written as a
   fill-based grid so a fourth strategy wraps instead of overflowing, and so
   the row stays flush at 1280 and 1024. */
.strategy-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 16px;
}

.strategy-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  height: 100%;
  min-height: 280px;
  padding: 16px 17px;
  border-radius: 13px;
}
.strategy-card-head { display: flex; align-items: center; gap: 9px; }
.strategy-card-head .rule { flex: 1 0 0; min-width: 0; }
.strategy-card-name { font-size: 16px; font-weight: 600; color: var(--tb-text-primary); }
.strategy-card-desc { font-size: 11px; color: var(--tb-text-secondary); }

.strategy-card .divider { display: block; width: 100%; }

.strategy-facts { display: flex; gap: 28px; flex-wrap: wrap; }
.fact { display: flex; flex-direction: column; gap: 2px; }
.fact-label { font-size: 8px; font-weight: 600; color: var(--tb-text-muted); letter-spacing: 0.04em; }
.fact-value { font-size: 11px; font-weight: 600; color: var(--tb-text-primary); }

.lifecycle-block { display: flex; flex-direction: column; gap: 5px; }
.lifecycle-label { font-size: 8px; font-weight: 600; color: var(--tb-text-muted); letter-spacing: 0.04em; }

/* 5 × 8px dots on a 13px pitch = 60px, exactly the exported asset's box.
   `align-self` keeps that box at 60px instead of letting the column stretch
   it — the dots would look the same either way, but the track is a figure
   with a declared size, not a full-width rule. */
.lifecycle { display: flex; gap: 5px; align-self: flex-start; }
.lifecycle-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--tb-border-default);
  transition: background var(--tb-dur) var(--tb-ease);
}
.lifecycle-dot.is-reached { background: var(--tb-accent); }

.strategy-next { display: flex; align-items: baseline; gap: 8px; margin-top: auto; }
.strategy-next-label { font-size: 9px; color: var(--tb-text-muted); }
.strategy-next-value { font-size: 10px; font-weight: 600; color: var(--tb-accent-chip-fg); }

/* ====================================================================== *
   Strategie (Figma 24:85)
   ====================================================================== */

.status-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 48px;
  padding: 10px 14px;
  border-radius: 11px;
  background: var(--tb-bg-subtle);
  border: 1px solid var(--tb-border-default);
}
.status-bar p { font-size: 10px; font-weight: 500; color: var(--tb-text-secondary); }

.panel-title { font-size: 14px; font-weight: 600; color: var(--tb-text-primary); }
.panel-note { font-size: 10px; color: var(--tb-text-muted); }

/* The wide lifecycle track. Figma fixes each connector at 112px for its six
   stages; here they flex, so the same component stays flush whatever number of
   stages the governance ladder has and at every viewport. */
.track { display: flex; align-items: flex-start; }
.track-step { display: flex; flex-direction: column; gap: 5px; flex: 0 0 auto; }
.track-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--tb-border-default);
}
.track-dot.is-reached { background: var(--tb-accent); }
.track-label { font-size: 9px; font-weight: 500; color: var(--tb-text-muted); }
.track-label.is-current { font-weight: 600; color: var(--tb-text-primary); }
.track-link {
  flex: 1 1 auto;
  min-width: 24px;
  height: 2px;
  margin-top: 5px;
  background: var(--tb-border-default);
}
.track-link.is-reached { background: var(--tb-accent); }

/* 748 + 18 + 370 = 1136. */
.detail-row {
  display: grid;
  grid-template-columns: minmax(0, 748fr) minmax(0, 370fr);
  gap: 18px;
  align-items: start;
}
.detail-main { display: flex; flex-direction: column; gap: 12px; }
.detail-side { display: flex; flex-direction: column; gap: 12px; }

.hypothesis-text { font-size: 12px; color: var(--tb-text-secondary); }
.chip-row { display: flex; gap: 8px; flex-wrap: wrap; }

.section-head-tight { align-items: baseline; gap: 8px; }
.section-head-tight h2 { font-size: 15px; }
.count { font-size: 10px; color: var(--tb-text-muted); }

.pair-list { display: flex; flex-direction: column; gap: 12px; }
.pair-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 91px;
  padding: 12px 14px;
  border-radius: 11px;
}
.pair-card-head { display: flex; align-items: center; gap: 9px; }
.pair-card-name { font-size: 13px; font-weight: 600; color: var(--tb-text-primary); }
.pair-facts { display: flex; gap: 22px; flex-wrap: wrap; }
.pair-facts .fact { gap: 3px; }

.gate-name { font-size: 13px; font-weight: 600; color: var(--tb-text-primary); }
.gate-when { font-size: 21px; font-weight: 600; color: var(--tb-text-primary); }
.detail-side .fact { gap: 3px; }
.detail-side a { font-size: 10px; font-weight: 600; }
.limit-item { font-size: 10px; color: var(--tb-text-secondary); }

/* ====================================================================== *
   Pair (Figma 24:124, 24:163, 29:2, 29:238)
   ====================================================================== */

.kpi-row {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 16px;
}
.kpi {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-height: 94px;
  padding: 12px 14px;
  border-radius: 11px;
}
.kpi-label { font-size: 8px; font-weight: 600; color: var(--tb-text-muted); letter-spacing: 0.04em; }
.kpi-value { font-size: 21px; font-weight: 600; color: var(--tb-text-primary); }
.kpi-note { font-size: 9px; color: var(--tb-text-muted); }

/* 758 + 18 + 360 = 1136. */
.pair-row {
  display: grid;
  grid-template-columns: minmax(0, 758fr) minmax(0, 360fr);
  gap: 18px;
  align-items: start;
}
.panel-body { font-size: 11px; color: var(--tb-text-secondary); }
.chip-verdict { align-self: flex-start; padding: 7px 10px; }

.kv { display: flex; flex-direction: column; gap: 8px; margin: 0; }
.kv > div { display: flex; align-items: baseline; gap: 8px; }
.kv dt { font-size: 10px; color: var(--tb-text-muted); flex: 0 1 auto; }
.kv dd {
  margin: 0 0 0 auto;
  font-size: 10px;
  font-weight: 600;
  color: var(--tb-text-primary);
  text-align: right;
}

/* The equity figure. Bars are sized by a custom property so the height is
   data, not a class, and they grow from the baseline on reveal. */
/* Figma fixes the chart panel at 425px because its mock always has a curve.
   Here the panel is only as tall as what it has to show — reserving 425px for
   a sentence explaining that there is no curve would make the absence look
   like a rendering failure. */
.bars { display: flex; align-items: flex-end; gap: 7px; height: 240px; }
.bar {
  flex: 1 1 0;
  min-width: 8px;
  height: var(--bar-height, 0%);
  background: var(--tb-accent);
  border-radius: 4px;
  transform-origin: bottom;
}
.js .reveal .bar { transform: scaleY(0); }
.js .reveal.is-revealed .bar {
  transform: scaleY(1);
  transition: transform var(--tb-dur-slow) var(--tb-ease-out);
}

.data-table { width: 100%; border-collapse: collapse; font-size: 10px; }
.data-table th {
  text-align: left;
  font-size: 8px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--tb-text-muted);
  padding: 0 8px 8px 0;
}
.data-table td {
  padding: 8px 8px 8px 0;
  border-top: 1px solid var(--tb-border-default);
  color: var(--tb-text-secondary);
}

@media (prefers-reduced-motion: reduce) {
  .js .reveal .bar,
  .js .reveal.is-revealed .bar { transform: none; }
}

/* ====================================================================== *
   System (Figma 24:319) and Technische Details (24:358)
   ====================================================================== */

/* 736 + 18 + 382 = 1136. */
.system-row {
  display: grid;
  grid-template-columns: minmax(0, 736fr) minmax(0, 382fr);
  gap: 18px;
  align-items: start;
}
.system-side { display: flex; flex-direction: column; gap: 12px; }

.health-list { display: flex; flex-direction: column; gap: 10px; }
.health-row { display: flex; align-items: center; gap: 10px; }
.health-row .dot { width: 8px; height: 8px; }
.health-row .rule { flex: 1 0 0; min-width: 0; }
.health-text { display: flex; flex-direction: column; gap: 2px; }
.health-name { font-size: 11px; font-weight: 600; color: var(--tb-text-primary); }
.health-note { font-size: 9px; color: var(--tb-text-muted); }

.kpi-success { color: var(--tb-success-chip-fg); }
.kpi-warning { color: var(--tb-warning-chip-fg); }
.kpi-danger { color: var(--tb-danger-chip-fg); }

/* The technical level prints identifiers in full; they wrap rather than
   overflow, and the value column gets the room instead of the label. */
.kv-wide > div { align-items: start; }
.kv-wide dd { max-width: 62%; word-break: break-all; text-align: right; }
.mono { font-family: var(--tb-mono); font-size: 9px; }

/* ====================================================================== *
   Reveal — cards, tiles and charts enter once, staggered by their position,
   and only when they first come into view. The initial state lives behind
   `.js` so a document without JavaScript is never left with an invisible
   page.
   ====================================================================== */

/* The hidden starting state lives behind *two* gates, and both matter.

   `.js` keeps a document that never ran the script from being left at opacity
   0. The motion query keeps a reader who asked for no motion from depending on
   the script at all: without it their content is hidden from first paint until
   `v3.js` executes and only then appears — which is a flash of invisible
   content shown to exactly the audience least willing to tolerate one. Inside
   the query, reduced motion never hides anything in the first place. */
@media (prefers-reduced-motion: no-preference) {
  .js .reveal {
    opacity: 0;
    transform: translateY(8px);
  }
  .js .reveal.is-revealed {
    opacity: 1;
    transform: none;
    transition:
      opacity var(--tb-dur-slow) var(--tb-ease-out),
      transform var(--tb-dur-slow) var(--tb-ease-out);
    transition-delay: var(--reveal-delay, 0ms);
  }
}

/* ====================================================================== *
   Page transitions. Cross-document view transitions where the browser has
   them; a short entry animation everywhere else. Both are suppressed under
   reduced motion.
   ====================================================================== */

@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--tb-dur-slow);
  animation-timing-function: var(--tb-ease-out);
}

/* The sidebar is the same object across a navigation, so it must not
   cross-fade with the page body. */
.sidebar { view-transition-name: sidebar; }
.main { view-transition-name: main; }

@media (prefers-reduced-motion: no-preference) {
  @supports not (view-transition-name: none) {
    .main { animation: page-enter var(--tb-dur-slow) var(--tb-ease-out) both; }
  }
}

@keyframes page-enter {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* ====================================================================== *
   Reduced motion. Not a softening — a removal. Anything that moves on its
   own, transitions, or transforms is switched off, including the view
   transition and the ambient layer.
   ====================================================================== */

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }

  .app::before { animation: none; }
  .dot-live { animation: none; }

  /* The reveal needs no override here: its hidden state is scoped to
     `no-preference`, so under this query it was never applied. */

  .card-link:hover { transform: none; }
}

/* ====================================================================== *
   Error state. Not in Figma — the page was never drawn — so it is derived
   from the design system instead of invented: the shared shell, one panel,
   the existing spacing and type scale, and the same chip and filter
   components the rest of the console uses.
   ====================================================================== */

.error-panel { max-width: 640px; gap: 13px; }
.error-panel .chip { align-self: flex-start; }
.error-actions { display: flex; gap: 4px; flex-wrap: wrap; }

/* A tile holding a span rather than a figure. Same box, same label, value at
   reading size so a real date range does not burst the row at 1024. */
.kpi-value-compact { font-size: 13px; line-height: 1.35; font-weight: 600; }
