/* Design tokens of the web shell — light (:root) and dark ([data-theme="dark"]) — plus the one
   density override. Cut out of cockpit.css unchanged (Mobile Phase 1, commit 1): the mobile layout links
   THIS file and mobile.css, never cockpit.css, so both layouts read one token source and nothing of the
   desktop shell rules reaches the phone. Every page links fonts.css, tokens.css, then its layout sheet.
   Pixel-identical by construction: the rules are the same bytes in the same cascade order. */
:root {
    --bg:        #f4f6fb;
    --surface:   #ffffff;
    --surface-2: #f8fafd;
    --surface-3: #162038;
    --border:    #e3e8f0;
    --border-2:  #d4dbe6;
    --ink:       #0d1830;
    --ink-2:     #3a4660;
    --muted:     #6b7892;
    --brand:     #0d5ed8;
    --brand-2:   #06285f;
    --brand-deep:#010b23;
    /* --accent lived here and is gone (P-0e). It was a second spelling of --active: 15 consumers,
       all of them STATE (toggle, day-pill, stage-active, .tag-sl, .sc-active, .btn-row.update), not
       one brand surface - the brand is blue. .tag-sl proved the confusion by mixing both on one
       element: background rgba(56,189,248,.12) = --active, colour var(--accent). A green that means
       "selected" also sits next to --buy and --positive in a money app, where a trader reads green as
       "profit", not as "chosen". */
    --buy:       #117a3d;
    --buy-bg:    #e7f6ec;
    /* No consumer since P-0d; kept as the vacant half of a live pair. Reason: board, P-0b entry. */
    --buy-bg-2:  #d3eedc;   /* @token-keep: pair-half (P-0d 619f701) */
    --sell:      #b73535;
    --sell-bg:   #fbeaea;
    --sell-bg-2: #f5d6d6;
    --warn:      #b87410;
    --warn-bg:   #fbf1de;
    --shadow-sm: 0 1px 2px rgba(13, 24, 48, 0.04);
    /* Shell-Redesign Phase 1 (Bucket 2-4a): promoted roles + canonical tints + gradient stops.
       Values are UNCHANGED (pixel-identical substitution). Dark counterparts + scatter removal land
       in Bucket 2-4b; overflow alpha-variants + near-duplicate accidents live in the decaying
       allow-list in installer/check-css-tokens.ps1 (the B-MERGE worklist). */
    /* P-0b: LIGHT values corrected, dark counterparts added. Every one of these roles carried a
       SINGLE value across both themes, and the measurement was unambiguous: the light theme is the
       one that failed. The pattern is exact - every token WITH a dark counterpart (--buy --sell
       --warn --brand) clears both themes, every token with one value falls through in light.
       Contrast is measured against --surface (#ffffff light / #0e1a30 dark); the threshold is
       4.5:1 for a role that carries TEXT and 3:1 for one that only draws a ring or a dot
       (WCAG 1.4.11, non-text contrast). The tints follow their base: alpha unchanged, rgb tracks
       the base token per theme - which is why every dark tint below equals the previous single
       value, and the dark diff of this commit is empty. */
    --positive:       #17884b;                 /* was #1ca85c = 3.09:1 in light, and it carries text
                                                  (.pa-status[ok]) as well as dots. Now 4.51:1. */
    --positive-bg:    rgba(23, 136, 75, 0.15);
    --danger:         #eb1616;                 /* was #ef4444 = 3.76:1 in light; it is TEXT on
                                                  .pa-status[error] and .tag-take. Now 4.51:1. */
    --danger-bg:      rgba(235, 22, 22, 0.12);
    --active:         #089ee1;                 /* active/editing state (!= --info message, != --focus ring).
                                                  Was #38bdf8 = 2.14:1. Its only consumer is a 1px inset
                                                  ring on .btn-group__item.is-active - non-text, so the
                                                  bar is 3:1, not 4.5:1. Now 3.01:1. */
    --active-bg:      rgba(8, 158, 225, 0.16);
    --active-bg-2:    rgba(8, 158, 225, 0.08);
    /* The FILLED surface of a control - switch track when on, slider range. Not a tint: a tint sits
       behind content, this IS the content. It was rgba(56,189,248,.35) and .5 raw, i.e. the DARK cyan
       in both themes, which measured 1.07:1 against the off-state track in light - the colour signal
       of a switch was dead and only the 16px thumb travel still said anything. 3.00:1 against
       --border and 3.53:1 against --surface-2 now. */
    --control-on:     #078dc9;

    /* P-3: Domain-Hue der Rail-GRUPPE (nicht der Seite). Zwei Domains bekommen einen Ton, Configure
       KEINEN -- Trade Viewer (Live) und Trade History (Review) sind strukturelle Zwillinge, und das
       ist die einzige echte Verwechslungsgefahr der App.
       ZWEI Gates, nicht eines. Das erste ist der Kontrast gegen den TATSAECHLICHEN Partner
       --surface (die Rail hat background:var(--surface), nicht --surface-2) -- >= 4.5:1, weil das
       Ziel Text bei 10px ist.
       Das ZWEITE ist die Trennung der beiden Toene GEGENEINANDER. Das ist die eigentliche Aufgabe
       des Paares: die einzige Information, die es traegt, ist "diese Gruppe ist nicht jene". Jeder
       Ton gegen die Flaeche zu messen und nie gegeneinander beantwortet die Nebenfrage.
       Wer diese Werte aendert, prueft BEIDE Gates -- siehe HANDOVERs/P3_TRENNUNG.md, dort steht
       auch, warum eine Schwelle ohne ihre Metrik kein Gate ist.
       Ein --domain-configure gibt es NICHT: ein Token, das da ist, wird benutzt. */
    /* P-5a: Toast-FLAECHEN. Gleicher Wert in beiden Themes -- wie --ink-inverse, und aus demselben
       Grund: der Kontrast von Weiss gegen eine Volltonflaeche haengt nicht am Theme, also waere ein
       zweiter Wert eine Erfindung. Genau DAS war der Fehler, den P-5a behebt: der Toast benutzte
       --positive/--info als Flaeche, und die sind als TEXT auf dunklem Grund getuned. Im Dunkeln
       ergab das Weiss auf einem hellen Gruen -- 3.09:1. Drei von vier Schweregraden rissen dort.
       Alle vier hier gegen #fff gemessen; --toast-warning ist aus #b87410 nachgedunkelt (L 0.392
       -> 0.35, Farbton und Saettigung unveraendert), weil 3.79:1 auch im HELLEN schon zu wenig war. */
    --toast-success:  #17884b;                 /* 4.51:1 gegen --ink-inverse */
    --toast-error:    #b73535;                 /* 5.88:1 */
    --toast-warning:  #a4680e;                 /* 4.60:1  (war #b87410 = 3.79:1, in BEIDEN Themes) */
    --toast-info:     #2563eb;                 /* 5.17:1 */
    --domain-live:    #d81b7f;                 /* 4.79:1 auf --surface */
    --domain-review:  #7b3fd4;                 /* 5.99:1 auf --surface */
    --active-text:    #0369a1;                 /* label ON an --active-bg surface. The role that was
                                                  missing: --active is bright enough for a dot or a
                                                  ring and far too pale for text on its own tint. */
    --warn-strong:    #996f19;                 /* brighter warn solid for TV / stage / lock accents.
                                                  Was #d29922 = 2.52:1 in light and it carries text
                                                  (.tag-tv, .stage-final-label, .stage-final-lock).
                                                  Now 4.52:1; dark keeps #d29922 at 6.88:1. */
    /* --warn-strong-bg lived here. Its only consumer was .sides-pill, which is gone (P-0d).
       --shadow-md lived here too: only .tool-label used it, and that class never had markup.
       --buy-grad-from/-to and --sell-grad-from/-to lived here as well. The comment they carried
       ("a gradient is a role: from -> to") was right as a RULE and still legitimised four special
       colours: #15894a/#0e6a39 and #c93f3f/#a02929 are NOT derived from --buy #117a3d / --sell
       #b73535 â€” they were a fifth and sixth green and a fourth and fifth red, existing so that a
       button that was never built could have a gradient. Their only consumer was .submit. When the
       hand mode gets its order ticket, that button derives its gradient FROM --buy/--sell; that is
       one line in the hand-mode task, not four tokens in this file. */
    --shadow-lg:      0 4px 24px rgba(0, 0, 0, 0.18);
    --overlay:        rgba(13, 24, 48, 0.45);        /* sheet/scrim behind a mobile bottom sheet (Phase 3) */
    /* Bucket 2-4b: names the roles the dark-scatter rules were compensating for (a scatter rule can't
       be dissolved while it stands in for a token that never existed). Defined in BOTH blocks so
       step B is mechanical: point the light rules here + delete the scatter lines. Light value =
       majority of the affected selectors (--buy, today). --info = the message-severity blue. */
    --positive-text:  #117a3d;    /* "good" value/label text (.pos/.kpi/.pill.ok ...) */
    /* --info ist in P-5a gestorben. Sein einziger Leser war die Toast-Flaeche, und genau dort war es
       falsch: --info ist als TEXT getuned, und der dunkle Wert #497dee traegt weisse Schrift nur mit
       3.85:1. Die Rolle "informative Meldung" hat jetzt --toast-info und sonst niemanden.
       Nach der Regel aus P-0d: ein Token darf seinen letzten Verwender ueberleben, wenn es die
       leere Haelfte eines lebenden Paares ist -- --info hat kein Paar. Also weg. */
    --code-bg:        #f8fafd;    /* code block surface (darker dark than --surface-2) */
    /* Tinte AUF einer Farbflaeche - der Name stand seit Phase 1 als Merge-Ziel in der Allowlist
       ("new role: white text on colour") und wird mit S2 eingeloest. Gleicher Wert in beiden Themes,
       und das ist kein Versaeumnis: weisse Schrift auf --brand oder --sell bleibt weiss, egal welches
       Theme laeuft. Nicht --surface verwenden - das ist im Dunkeln #0e1a30. */
    --ink-inverse:    #fff;
    --r-sm: 6px;
    --r-md: 10px;
    --r-lg: 14px;
    --row-h: 36px;
    /* Shell-Redesign Phase 2 (2-2): the two shell measurements. Both were literals before â€” the head
       height twice (.topbar height + the account-strip's sticky offset, with nothing connecting them),
       the rail width not at all. Measurements are theme-free, so they live ONLY here and get no dark
       counterpart. --shell-rail-w is overridden once, in the icon-collapse query. */
    --shell-head-h: 56px;
    --shell-rail-w: 220px;
    /* Hoehe des Account-Streifens. Bisher ein Literal in .account-strip; sie gehoert hierher, weil
       "wo endet das obere Band" eine Shell-Frage ist und nicht nur die Hoehe eines Elements: alles,
       was unter Kopf UND Streifen anschliessen will, braucht die Summe der beiden. */
    --shell-strip-h: 30px;
    /* Kachel-Mindestbreiten fuer auto-fit-Leitern. Masse, also nur hier, kein Dark-Gegenstueck.
       --tile-min-kpi ist die schmalste Breite, bei der eine KPI-Kachel noch lesbar ist - AM INHALT
       gemessen, nicht aus einer Containerbreite zurueckgerechnet. Die breiteste Kachel der App ist
       "Win Rate" auf Statistics: laengste unumbrechbare Zeile 194px + 34px Polsterung/Rand = 228px;
       im Shell-Streifen sind es hoechstens 147px ("Total risk"). 240px deckt beides mit Reserve.
       WELCHE SPALTENZAHL HERAUSFAELLT, IST DAS ERGEBNIS UND NICHT DAS ZIEL. Der erste S3-Wurf hatte
       das umgedreht und zwei Extra-Tokens (210px / 168px) eingefuehrt, damit bei Referenzbreite
       wieder 4 bzw. 5 Spalten stehen - Werte, die exakt der Quotient (892-n*gap)/n waren, also eine
       hartkodierte Spaltenzahl im Kostuem eines Tokens. Dass Statistics dabei 214px-Kacheln bekam,
       waehrend die KPI-Kachel des Systems 284,5px breit ist, war der eigentliche Paritaetsbruch;
       auto-fits 3 Spalten a 289,3px sind die Paritaet.
       --tile-min-symbol behaelt bewusst die bisherigen 110px statt der vorgeschlagenen 96px
       (innerhalb der erlaubten +-16px): so bleibt die Live-States-Kachelreihe bei 1440
       pixelgleich, und der auto-fit-Wechsel wirkt genau dort, wo er soll - auf breiten Containern. */
    --tile-min-kpi: 240px;
    --tile-min-symbol: 110px;
    /* --tile-min-heat behaelt die bisherigen 480px, nur als Token und mit auto-FIT statt auto-fill. */
    --tile-min-heat:      480px;
    /* P-2e: die schmalste Breite, bei der eine Panel-Karte (Ueberschrift + Koerper) neben ihresgleichen
       noch lesbar ist. EIN Token fuer .chart-card und .sim-insight-card, weil sie dasselbe Bauteil in
       zwei Fuellungen sind - zwei Masse fuer einen Begriff waeren das zweite Vokabular, das diese
       Phase abbaut.
       Am Inhalt gemessen: die Textkarte braucht 347px ("Gate-Filter Impact": Kopfzeile 313 + 34
       Polsterung).

       ACHTUNG, DIE INHALTSMESSUNG HAT EINE DOMAENE - sie gilt fuer TEXT, nicht fuer CANVAS.
       Die Chart-Karte misst 179px, und DIESE ZAHL IST KEIN GUELTIGES MINIMUM. Ein <canvas> hat keine
       intrinsische Mindestbreite; gemessen wurde der Kartenkopf, nicht der Chart. Wer den Token
       spaeter auf 179 zieht, weil "die Methode das hergibt", beruft sich auf eine Methode, die hier
       gar nicht anwendbar ist.
       Das Minimum eines Charts ist eine ANDERE Messung: die schmalste Breite, bei der er noch etwas
       mitteilt - Achsenbeschriftungen kollidieren nicht, genug Stuetzstellen, y-Labels passen. Das
       ist messbar, nur nicht ueber eine DOM-Eigenschaft, und es ist bisher NICHT gemessen.
       Bis dahin regiert die Textkarte. Das ist eine ENTSCHEIDUNG, keine Messung, und sie geht in die
       sichere Richtung: 350 statt 179 kostet Platz, nicht Lesbarkeit. */
    --tile-min-panel:     350px;
    /* Jede auto-fit-Leiter auf dieser Seite steht als minmax(min(TOKEN, 100%), 1fr). Ohne das min()
       schrumpft eine Spur NICHT unter ihr Minimum: bei 520px Fenster ist die Statistics-Spalte 128px
       breit, die Karte blieb 350px und die Seite bekam 44px QUERSCROLL - gemessen, nicht vermutet.
       Dieselbe Latenz steckt in den Shell-Leitern (.kpi-row, .cond-tile-grid) aus C3; die habe ich
       hier NICHT angefasst, weil ich sie nicht verursacht habe - sie stehen als eigener Befund im
       Board. */
    /* How tall a card body may grow before it scrolls inside itself. Viewport-relative on purpose and
       deliberately WITHOUT calc() against --shell-head-h: a card sitting fourth in a grid should not
       grow to the fold, it should stop being taller than most of the screen. Measurement, so no dark
       counterpart.
       Correction to the handover premise: there were never "two numbers for one role". 540px was the
       COMPUTED value of 60vh at the 900px reference viewport, which my own Phase-0 report printed;
       the source carried 60vh three times, inline, in three .cshtml files. The unification is
       three copies -> one token, not two values -> one. */
    --card-scroll-max: 60vh;
    /* --tool-zone-profit-bg / -risk-bg / -secured-bg and --tool-stage-dimmed-opacity lived here,
       including dark counterparts. They were born in v0.5.x for the Long/Short tool and NEVER had a
       consumer: `git log -S "var(--tool-zone"` is empty over the entire history, and the tool draws
       on a canvas from chart settings instead. Same class as bridge-notify.* â€” created, never wired,
       and four token definitions that looked like coverage of a feature that does not read them. */
  }
  [data-theme="dark"] {
    --bg:        #07101f;
    --surface:   #0e1a30;
    --surface-2: #122340;
    --surface-3: #0a1525;
    --border:    #1d3358;
    --border-2:  #294776;
    --ink:       #e8eef9;
    --ink-2:     #b9c5dc;
    --muted:     #7a8aa8;
    --brand:     #2fa8ff;
    --brand-2:   #0d5ed8;
    --buy-bg:    #0d3624;
    --buy-bg-2:  #0a4a2c;
    --buy:       #6ad58c;
    --sell-bg:   #3a1717;
    --sell-bg-2: #4a1d1d;
    --sell:      #ef7878;
    --warn-bg:   #3a2a0e;
    --warn:      #f0b762;
    --active-text:   #7dd3fc;    /* the value .btn-group__item.is-active carried hard-coded â€” dark keeps its look */
    --positive-text: #6ad58c;    /* Bucket 2-4b: dark value the .pos/.kpi/.pill.ok scatter rules carried */
    --code-bg:       #08111e;
    --ink-inverse:   #fff;                     /* dito - Tinte auf Farbe wechselt nicht mit dem Theme */
    --shadow-sm: 0 1px 2px rgba(0,0,0,0.4);
    /* P-0b: the counterparts for the roles that carried a single value. Each equals the PREVIOUS
       single value, because in every case it was the light theme that failed the measurement - so
       this block restores what dark always rendered and the dark diff of this commit is empty.
       Two exceptions, both invisible in a screenshot: --info (light passed, dark was the weak side
       at 3.36:1) and --shadow-lg (a shadow on dark needs the opacity --shadow-sm already got). */
    --positive:      #1ca85c;
    --positive-bg:   rgba(28, 168, 92, 0.15);
    --danger:        #ef4444;
    --danger-bg:     rgba(239, 68, 68, 0.12);
    --active:        #38bdf8;
    --active-bg:     rgba(56, 189, 248, 0.16);
    --active-bg-2:   rgba(56, 189, 248, 0.08);
    --control-on:    #38bdf8;
    --toast-success: #17884b;                  /* P-5a: identisch zu hell -- siehe dort */
    --toast-error:   #b73535;
    --toast-warning: #a4680e;
    --toast-info:    #2563eb;
    --domain-live:   #ff7ba8;                  /* P-3: 7.15:1 auf --surface */
    --domain-review: #b98cff;                  /* P-3: 6.83:1 auf --surface */                  /* the raw value was already right here - 5.88:1 */
    --warn-strong:   #d29922;
    --shadow-lg:     0 4px 24px rgba(0,0,0,0.55);
    --overlay:       rgba(0,0,0,0.6);
    /* The three --tool-zone-* dark counterparts lived here â€” see the note in the base :root.
       --brand-deep deliberately gets NO counterpart: it is not a themed surface but the brand's own
       dark, and its two consumers are the logo tile (.brand-mark) and the login page, which is a
       fixed dark stage in BOTH themes. One value is the right answer there, not an omission. */
  }
  [data-density="compact"] { --row-h: 30px; }
