/* ============================================================
   The Ledger — BROADSHEET (2026-09-07)

   Replaces the gruvbox card system. The class vocabulary is unchanged
   — `ln-card`, `ln-stat`, `ln-table`, `ln-badge` and the rest are all
   still here and still named the same, because ~900 call sites across
   templates/index.html and static/js/*.js emit them. What changed is
   what they MEAN:

     · Nothing is a box. `ln-card` has no border, no fill and no radius;
       a section is a heading, a rule, and the content under it. The old
       page was twelve identically-bordered cards stacked, which gave the
       reader no hierarchy at all — total equity and win rate had the
       same 1.25rem.
     · Three faces, one job each. Newsreader sets the FIGURES (the actual
       product), IBM Plex Sans the structure, IBM Plex Mono every clock,
       count and symbol. All self-hosted — `font-src 'self'`, and the
       CSP admits no font CDN (main.py `_csp`).
     · Colour is spent once. An ordinary block is ink; the emerald is the
       app's mark and appears about three times per view — the active nav
       rule, the one primary action, the equity line. Gain and loss keep
       their hues but NEVER carry the sign alone: every signed value is
       written with + or −, and the words Bought / Sold / Vetoed sit
       beside the colour. The old file's own note about green-vs-red
       failing deuteranopia at ΔE 4.1 is why, and it still applies.

   Six themes, as before. Each one re-cuts the same ROLE tokens rather
   than a separate palette, so a component styled once is styled in all
   six. The `--ch-*` chart series tokens below are UNTOUCHED from the
   gruvbox era: they were validated with the dataviz validator against
   real card surfaces, and a re-skin is not the place to relitigate them.
   ============================================================ */

/* ── Faces (self-hosted; Plex Sans and Newsreader are variable) ───── */
@font-face {
  font-family: 'Newsreader'; font-style: normal; font-weight: 200 700;
  font-display: swap; src: url('../fonts/Newsreader.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans'; font-style: normal; font-weight: 100 700;
  font-display: swap; src: url('../fonts/IBMPlexSans.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 400;
  font-display: swap; src: url('../fonts/IBMPlexMono-400.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 500;
  font-display: swap; src: url('../fonts/IBMPlexMono-500.woff2') format('woff2');
}

:root {
  /* structure — a warm ground, three rule weights, no card fill */
  --bg-page:    #16130f;   /* the ground */
  --bg-card:    #1c1813;   /* the few things that genuinely lift: modal, toast, tip */
  --bg-card2:   #241f19;   /* the quietest raise: input wells, zebra */
  --border:     #302a22;   /* hairline — between figures and rows */
  --border-2:   #5c5348;   /* section rule — above a table head */
  --text:       #eae3d6;   /* body */
  --bright:     #fbf6ec;   /* the lede figure, and nothing else */
  --muted:      #8e8578;   /* labels, secondary */
  --faint:      #6f6759;   /* specs, disabled */
  --accent:     #10b981;   /* one primary action per view */
  --accent-dim: #0d9268;
  --gold:       #c9a95a;   /* your own book, and provenance */
  --green:      #96c060;   /* with a + sign — stepped toward yellow so it survives deuteranopia beside --red */
  --amber:      #d98c3a;   /* warn, unresolved, paper-trading */
  --red:        #c26b5c;   /* with a − sign */
  --purple:     #b57b96;
  --blue:       #7aa7c7;
  --masthead:   #eae3d6;   /* the rule under the masthead is INK, not a border */

  --f-fig:  'Newsreader', Georgia, 'Times New Roman', serif;
  --f-ui:   'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --f-data: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ── Chart tokens ───────────────────────────────────────────
   UNCHANGED from the gruvbox era, deliberately. Series identity does not
   follow the theme: the six themes are chosen for mood, their accents were
   never stepped to be told apart, and a run of the CVD gates over them fails
   on three checks at once. Chart CHROME is themed (surface, grid, ink from
   the roles above); the categorical slots are fixed and validated.

   RE-VALIDATED 2026-09-07 against the Broadsheet grounds themselves
   (`dataviz/scripts/validate_palette.js`), not the old card surfaces:
     dark   #16130f — ALL PASS. worst adjacent CVD ΔE 8.4 (protan),
                      normal-vision 19.3, every slot over 3:1.
     light  #faf6ec — worst adjacent CVD ΔE 9.1 (protan), normal-vision 19.6,
                      and a CONTRAST WARN: #eb6834 2.97, #1baf7a 2.61,
                      #eda100 2.01, #e87ba4 2.49 sit under 3:1.
   That warn is not dismissable — it obligates relief, and the relief is
   already standing: every chart ships a legend, selective direct labels, and
   a "View data" table twin (`.ln-chart-data`). Do not remove one from a light
   chart without re-reading this.
   The diverging pair passes outright in both modes (ΔE 19.2 dark, 21.6 light).

   --ch-up / --ch-down are STATUS, not series: they mean gain/loss and follow
   the theme so a green bar and a green table cell say the same thing. Nothing
   in this app encodes a sign with them alone — the sign is always carried by
   which side of the zero baseline a mark sits on, plus a signed value in the
   label, the tooltip, and the table. */
:root {
  --ch-1: #3987e5;   /* blue    */
  --ch-2: #d95926;   /* orange  */
  --ch-3: #199e70;   /* aqua    */
  --ch-4: #c98500;   /* yellow  */
  --ch-5: #d55181;   /* magenta */
  --ch-up:   var(--green);
  --ch-down: var(--red);
  /* The diverging pair, for polarity that is NOT good/bad — a crowded net-long
     futures position is not a "gain". Blue ↔ red survives deuteranopia
     (ΔE 19.2 dark, 21.6 light) where green/red does not. */
  --ch-div-neg: #e66767;
  --ch-grid: var(--border);
  --ch-ink:  var(--muted);
}

[data-theme="light"] {
  --ch-1: #2a78d6; --ch-2: #eb6834; --ch-3: #1baf7a; --ch-4: #eda100; --ch-5: #e87ba4;
  --ch-div-neg: #e34948;
  /* ⚠ The ONE place --ch-down leaves --red, and the reason is measured, not
     taste: on this cream ground the two demands pull opposite ways. Deuteran
     separation from the gain needs the loss LIGHT (--red at #b04437 gives
     ΔE 3.1, unusable); body text needs it DARK (#d0604a is 3.57:1, under the
     4.5 floor). No single value does both. So the TEXT keeps --red and the
     MARK takes a lighter step of the same hue — ΔE 11.0 against the gain,
     3.57:1 against the surface, which is a mark, not a paragraph. Dark mode
     needs no such split: #96c060 vs #c26b5c is ΔE 13.3 with both text-grade. */
  --ch-down: #d0604a;
  --bg-page: #faf6ec; --bg-card: #fffdf6; --bg-card2: #efe9d9;
  --border: #ddd5c2; --border-2: #a89f8c; --text: #241f19; --bright: #100d0a;
  --muted: #6b6258; --faint: #8a8073; --masthead: #241f19;
  --accent: #047857; --accent-dim: #065f46; --gold: #9a7b2e; --green: #1e5c2e;
  --amber: #b3691a; --red: #b04437; --purple: #8a5570; --blue: #35617f;
}
[data-theme="nord"] {
  --bg-page: #2e3440; --bg-card: #343b48; --bg-card2: #3b4252;
  --border: #3f4757; --border-2: #5a657a; --text: #e5e9f0; --bright: #eceff4;
  --muted: #8f9cb3; --faint: #6b7789; --masthead: #e5e9f0;
  --accent: #8fbcbb; --accent-dim: #7aa9a8; --gold: #ebcb8b; --green: #a3be8c;
  --amber: #d08770; --red: #bf616a; --purple: #b48ead; --blue: #88c0d0;
}
[data-theme="dracula"] {
  --bg-page: #282a36; --bg-card: #2f313d; --bg-card2: #383a4a;
  --border: #3c3f4f; --border-2: #6272a4; --text: #f0f0ea; --bright: #f8f8f2;
  --muted: #8b93b8; --faint: #6272a4; --masthead: #f0f0ea;
  --accent: #50fa7b; --accent-dim: #3fd968; --gold: #f1fa8c; --green: #50fa7b;
  --amber: #ffb86c; --red: #ff5555; --purple: #bd93f9; --blue: #8be9fd;
}
[data-theme="solarized"] {
  --bg-page: #002b36; --bg-card: #05303c; --bg-card2: #073642;
  --border: #0a4552; --border-2: #48626a; --text: #93a1a1; --bright: #eee8d5;
  --muted: #7d9294; --faint: #5b7076; --masthead: #93a1a1;
  --accent: #2aa198; --accent-dim: #1f8079; --gold: #b58900; --green: #859900;
  --amber: #cb4b16; --red: #dc322f; --purple: #6c71c4; --blue: #268bd2;
}
[data-theme="hyrule"] {
  --bg-page: #10140d; --bg-card: #171c12; --bg-card2: #1e2418;
  --border: #2c3324; --border-2: #4c5940; --text: #e8e7db; --bright: #f4f3ea;
  --muted: #8a9380; --faint: #6a7362; --masthead: #e8e7db;
  --accent: #5aa36b; --accent-dim: #47854f; --gold: #ddb04a; --green: #5aa36b;
  --amber: #e0a33a; --red: #cc5b4a; --purple: #9a86c0; --blue: #57b0a6;
}

html, body { transition: background-color .2s, color .2s; }
*, *::before, *::after { box-sizing: border-box; }

body {
  background: var(--bg-page);
  color: var(--text);
  font-family: var(--f-ui);
  font-size: .9rem;
  min-height: 100vh;
}
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-dim); }

::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: var(--bg-page); }
::-webkit-scrollbar-thumb { background: var(--border-2); border-radius: 3px; }

/* One ramp for every number in the app: tabular, mono, and never re-flowing
   as a value ticks. `.num` is Bootstrap-adjacent and `.ln-num` is ours; both
   land here so a table cell only needs one of them. */
.ln-num, .num, .ln-mono, .ln-table .num { font-family: var(--f-data); font-variant-numeric: tabular-nums; }

/* ── Masthead ───────────────────────────────────────────────
   Two rules under it — one at full ink, one at a fifth — which is the
   newspaper device that says "the page starts here" without a fill. */
.ln-navbar {
  /* NOT transparent, despite the flat look: the element is `sticky-top` in
     index.html, so a transparent masthead lets the page scroll through it.
     It takes the ground's own colour instead, which reads the same and is
     opaque. */
  background: var(--bg-page) !important;
  border-bottom: none;
  padding: 1.1rem 0 .1rem;
  /* ⚠ Set NO `position` here. index.html puts `.sticky-top` on this element,
     and ledger.css loads after Bootstrap — a `position: relative` at equal
     specificity silently wins and the masthead stops sticking. Sticky is
     itself a containing block, so the ::after rule below still anchors. */
}
.ln-navbar::after {
  content: ''; position: absolute; left: 1.5rem; right: 1.5rem; bottom: 0;
  height: 3px;
  background: linear-gradient(var(--masthead) 0 1px, transparent 1px 2px, var(--masthead) 2px 3px);
  opacity: .55;
}
.ln-brand {
  color: var(--text) !important;
  font-family: var(--f-fig); font-weight: 400; font-size: 1.75rem;
  letter-spacing: .01em; line-height: 1;
}
.ln-sub-brand {
  color: var(--muted) !important;
  font-size: .62rem; font-weight: 500; letter-spacing: .14em; text-transform: uppercase;
  transition: color .15s; padding-left: .1rem; margin-top: .3rem;
}
.ln-sub-brand:hover { color: var(--text) !important; }
/* `.ln-mark` (the ◆ the Broadsheet hid as chrome) is gone entirely as of
   2026-09-08 — every template that carried it now calls `ledger_mark()` from
   `_mark.html`, so there is no element left for the rule to hide. */
.ln-brand-app { display: inline-flex; align-items: center; gap: .5rem; }
.ln-logo { display: inline-flex; width: 1.15rem; height: 1.15rem; }
.ln-logo svg { width: 100%; height: 100%; display: block; }
/* The hub masthead's sub-brand is 0.62rem micro-caps, so the mark rides at
   the cap height of the type beside it rather than the 1.15rem the public
   wordmark can carry. */
.ln-sub-brand-marked { display: inline-flex; align-items: center; gap: .34rem; }
.ln-logo-sm { width: .8rem; height: .8rem; }
.ln-home-link {
  color: var(--muted) !important; text-decoration: none;
  font-size: .62rem; font-weight: 500; letter-spacing: .14em; text-transform: uppercase;
  transition: color .15s; padding-left: .1rem; margin-top: .3rem;
}
.ln-home-link:hover { color: var(--text) !important; }
.ln-home-link .bi { font-size: .7em; }
.ln-demo-badge {
  font-family: var(--f-ui);
  font-size: .58rem; font-weight: 500; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); border: 1px solid var(--border); border-radius: 2px;
  padding: .2rem .55rem; white-space: nowrap;
}

/* The sections are micro-caps with an underline on the live one — no pill,
   no fill. Bootstrap's .nav-link padding is overridden so the rule sits on
   the word rather than around a button. */
.navbar-nav .nav-link {
  color: var(--muted) !important;
  padding: .2rem 0 .28rem !important;
  margin: 0 .7rem;
  border-radius: 0;
  border-bottom: 1px solid transparent;
  font-size: .66rem; font-weight: 500; letter-spacing: .13em; text-transform: uppercase;
  transition: color .15s, border-color .15s;
}
.navbar-nav .nav-link:hover { color: var(--text) !important; background: none; }
.navbar-nav .nav-link.active {
  color: var(--text) !important; background: none;
  border-bottom-color: var(--accent);
}
.navbar-nav .nav-link .bi { display: none; }   /* the section is its name, not an icon */
.navbar-toggler { border-color: var(--border); }

/* ── Sections ───────────────────────────────────────────────
   The page's own heading: a serif name, an italic standfirst beside it,
   and a rule under the pair. */
.ln-section { padding-top: .25rem; }
.ln-section-header {
  display: flex; align-items: baseline; gap: .9rem;
  margin-bottom: 1.35rem; padding-bottom: .6rem;
  border-bottom: 1px solid var(--border-2);
  flex-wrap: wrap;
}
.ln-section-header h2 {
  font-family: var(--f-fig); font-size: 1.6rem; font-weight: 400; color: var(--text);
  margin: 0; letter-spacing: 0; line-height: 1.1;
}
.ln-section-header h2 .bi { display: none; }
.ln-section-header > .ln-muted { font-family: var(--f-fig); font-style: italic; font-size: .95rem; }

/* ── "Cards" — which are sections, not boxes ────────────────
   No fill, no border, no radius. The header is a serif name over a rule;
   the body is the content under it. Bootstrap's .h-100 and the row gutters
   still do the column work. */
.ln-card { background: none; border: none; border-radius: 0; overflow: visible; }
.ln-card-header {
  background: none;
  border-bottom: 1px solid var(--border-2);
  padding: 0 0 .5rem;
  font-family: var(--f-fig); font-weight: 400; font-size: 1.12rem; color: var(--text);
  display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  letter-spacing: 0;
}
.ln-card-header .bi { display: none; }
/* the caption the app hangs off most headers, in the standfirst's dress */
.ln-card-header .ln-muted { font-family: var(--f-fig); font-style: italic; font-size: .84rem; }
.ln-card-header.ln-collapsible { cursor: pointer; user-select: none; }
.ln-card-header.ln-collapsible.collapsed { border-bottom-color: var(--border); }
.ln-collapse-caret { margin-left: auto; transition: transform .2s; color: var(--muted); font-size: .8rem; }
.ln-card-header.ln-collapsible.collapsed .ln-collapse-caret { transform: rotate(-90deg); }
.ln-card-body { padding: .85rem 0 0; }

/* ── Figures ────────────────────────────────────────────────
   The page's one repeating unit: micro-caps label, serif figure, quiet sub.
   The left rule comes from the neighbouring column, so a row of tiles reads
   as one ruled band rather than six separate objects. `.ln-stat` sits inside
   a Bootstrap column, so the rule goes on the tile and the first-in-row case
   is handled by the row's own left edge. */
.ln-stat {
  display: block; background: none; border: none; border-radius: 0;
  border-left: 1px solid var(--border);
  padding: .8rem 0 .8rem 1.05rem;
  height: 100%;
}
.ln-stat-label {
  color: var(--muted); font-size: .62rem; text-transform: uppercase;
  letter-spacing: .14em; margin-bottom: .18rem; font-weight: 500;
}
.ln-stat-value {
  font-family: var(--f-fig); font-weight: 300; font-size: 1.7rem; line-height: 1.12;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em; color: var(--text);
}
.ln-stat-sub { font-size: .7rem; color: var(--muted); margin-top: .15rem; line-height: 1.35; }

/* THE LEDE. One figure per screen is the reason you opened it — the book's
   value — and it gets the size that says so. Marked by the renderer
   (`statTile(..., {lead: true})`) rather than by position, so re-ordering a
   tile row cannot silently move it. */
.ln-stat-lead { border-left: none; padding-left: 0; }
.ln-stat-lead .ln-stat-value { font-size: 3.4rem; line-height: 1.02; color: var(--bright); }
.ln-stat-lead .ln-stat-sub { font-size: .74rem; }
@media (max-width: 991px) { .ln-stat-lead .ln-stat-value { font-size: 2.4rem; } }

/* ── The desk (agent strip) ─────────────────────────────────
   Contributors under a masthead, not five cards: a name, a state, a line
   about the job, separated by rules. */
.ln-agent-card {
  background: none; border: none; border-radius: 0;
  border-left: 1px solid var(--border);
  padding: .1rem 0 .1rem 1.05rem;
  height: 100%;
  display: flex; flex-direction: column; gap: .3rem;
}
.ln-agent-card:hover { border-color: var(--border); }
.ln-agent-card.is-running { border-left-color: var(--accent); }
.ln-agent-card.is-error   { border-left-color: var(--red); }
.ln-agent-card.is-disabled { opacity: .5; }

.ln-agent-top { display: flex; align-items: center; gap: .45rem; }
.ln-agent-name {
  font-weight: 600; font-size: .82rem; letter-spacing: .01em; text-transform: capitalize;
}
.ln-agent-actions { margin-left: auto; display: flex; gap: .25rem; }

.ln-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--faint); flex: 0 0 auto; }
.ln-dot.idle     { background: var(--faint); }
.ln-dot.running  { background: var(--accent); animation: ln-pulse 1.1s ease-in-out infinite; }
.ln-dot.error    { background: var(--red); }
.ln-dot.disabled { background: var(--border); }
@keyframes ln-pulse { 0%,100% { opacity:1 } 50% { opacity:.25 } }

.ln-agent-line { font-family: var(--f-data); font-size: .66rem; color: var(--muted); }
.ln-agent-outcome { font-size: .72rem; color: var(--muted); line-height: 1.4; }

/* ── Controls ───────────────────────────────────────────────
   The emerald is spent on ONE primary action per view; everything else is
   an outline or a word. */
.ln-btn {
  background: var(--accent); color: #06231a; border: 1px solid var(--accent);
  border-radius: 3px; padding: .32rem .8rem;
  font-family: var(--f-ui); font-size: .75rem; font-weight: 600; cursor: pointer;
  transition: background .15s, border-color .15s;
}
.ln-btn:hover:not(:disabled) { background: var(--accent-dim); border-color: var(--accent-dim); }
.ln-btn:disabled { background: none; border-color: var(--border); color: var(--faint); cursor: default; }

.ln-btn-sec {
  background: none; color: var(--text);
  border: 1px solid var(--border-2); border-radius: 3px;
  padding: .32rem .8rem; font-family: var(--f-ui); font-size: .75rem; cursor: pointer;
  transition: color .15s, border-color .15s;
}
.ln-btn-sec:hover { color: var(--bright); border-color: var(--muted); }

.ln-btn-danger {
  background: none; color: var(--red);
  border: 1px solid color-mix(in srgb, var(--red) 40%, transparent); border-radius: 3px;
  padding: .32rem .8rem; font-family: var(--f-ui); font-size: .75rem; cursor: pointer;
}
.ln-btn-danger:hover { border-color: var(--red); }

.ln-btn-icon {
  background: none; border: 1px solid var(--border);
  color: var(--muted); border-radius: 3px;
  padding: .12rem .42rem; font-family: var(--f-data); font-size: .7rem; cursor: pointer;
  line-height: 1.35; transition: color .15s, border-color .15s;
}
.ln-btn-icon:hover { color: var(--text); border-color: var(--muted); }
.ln-btn-icon.active { color: var(--text); border-color: var(--accent); background: none; }

/* ── Forms ──────────────────────────────────────────────────
   A well, not a box: the field is the quietest raise on the page with a
   rule under it, and the label is micro-caps above. */
.ln-input, .ln-select {
  background: var(--bg-card2); color: var(--text);
  border: 1px solid var(--border); border-radius: 3px;
  padding: .34rem .6rem; font-family: var(--f-ui); font-size: .8rem; width: 100%;
}
.ln-input:focus, .ln-select:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 18%, transparent);
}
.ln-input::placeholder { color: var(--faint); }
.ln-label {
  display: block; color: var(--muted); font-size: .62rem;
  text-transform: uppercase; letter-spacing: .14em; margin-bottom: .22rem; font-weight: 500;
}

/* ── Tables ─────────────────────────────────────────────────
   Ruled, never boxed. The head is micro-caps over the section rule; rows
   are separated by the hairline and nothing else. */
.ln-table { width: 100%; color: var(--text); font-size: .8rem; border-collapse: collapse; }
.ln-table thead th {
  background: var(--bg-page); color: var(--muted);
  font-family: var(--f-ui);
  font-size: .62rem; text-transform: uppercase; letter-spacing: .14em;
  font-weight: 500; padding: .5rem .7rem .45rem 0;
  border-bottom: 1px solid var(--border); text-align: left;
  position: sticky; top: 0; z-index: 1;
}
.ln-table tbody td {
  padding: .5rem .7rem .5rem 0;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.ln-table tbody tr:last-child td { border-bottom: none; }
.ln-table tbody tr:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }
.ln-table .num, .ln-table th.num { text-align: right; padding-right: 0; }
.ln-table strong { font-weight: 600; }
.ln-scroll { max-height: 420px; overflow-y: auto; overflow-x: auto; }

/* ── Tags ───────────────────────────────────────────────────
   Outline and micro-caps, never a filled pill. Provenance and state read
   as words first; the hue is the second signal. */
.ln-badge {
  display: inline-block; padding: .1rem .42rem;
  border-radius: 2px; font-family: var(--f-ui);
  font-size: .58rem; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase;
  border: 1px solid var(--border); background: none; color: var(--muted);
}
.ln-badge-agent { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
.ln-badge-user  { color: var(--gold);   border-color: color-mix(in srgb, var(--gold) 42%, transparent); }
.ln-badge-scout { color: var(--blue);   border-color: color-mix(in srgb, var(--blue) 42%, transparent); }
.ln-badge-buy   { color: var(--green);  border-color: color-mix(in srgb, var(--green) 42%, transparent); }
.ln-badge-sell  { color: var(--red);    border-color: color-mix(in srgb, var(--red) 42%, transparent); }
.ln-badge-ok    { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
.ln-badge-warn  { color: var(--amber);  border-color: color-mix(in srgb, var(--amber) 42%, transparent); }
.ln-badge-muted { color: var(--muted);  border-color: var(--border); }
.ln-badge-veto  { color: var(--red);    border-color: color-mix(in srgb, var(--red) 42%, transparent); }

/* The three target provenances must read differently at a glance. */
.ln-row-agent td:first-child { box-shadow: inset 2px 0 0 var(--accent); padding-left: .6rem; }
.ln-row-user  td:first-child { box-shadow: inset 2px 0 0 var(--gold);   padding-left: .6rem; }
.ln-row-scout td:first-child { box-shadow: inset 2px 0 0 var(--blue);   padding-left: .6rem; }

/* ── Scout signals — the digest ─────────────────────────────
   These are literally editorial: a headline, a rationale, sources. So they
   are set as a digest — a rule between entries and one coloured left edge
   carrying the state — rather than as accordions inside a bordered card. */
.ln-signal-scroll { max-height: 19rem; overflow-y: auto; padding-right: .25rem; }
.ln-items-scroll  { max-height: 19rem; overflow-y: auto; }

.ln-signal {
  border: none; border-left: 2px solid var(--blue);
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  padding: .6rem 0 .6rem .85rem;
  margin-bottom: 0;
  background: none;
}
details.ln-signal > summary { list-style: none; cursor: pointer; }
details.ln-signal > summary::-webkit-details-marker { display: none; }
details.ln-signal > summary .ln-signal-caret { color: var(--muted); transition: transform .15s; font-size: .68rem; }
details.ln-signal[open] > summary .ln-signal-caret { transform: rotate(90deg); }
details.ln-signal[open] { border-left-color: var(--accent); background: color-mix(in srgb, var(--text) 2%, transparent); }
.ln-signal.is-unresolved { border-left-color: var(--amber); opacity: .8; }
.ln-signal-head { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.ln-signal-sym { font-family: var(--f-ui); font-weight: 600; font-size: .9rem; }
.ln-signal-headline { font-family: var(--f-fig); font-size: 1.02rem; line-height: 1.3; margin-top: .1rem; }
.ln-signal-rationale {
  font-size: .76rem; color: var(--muted); margin-top: .3rem;
  white-space: pre-wrap; line-height: 1.5;
}
.ln-signal-evidence { margin-top: .35rem; font-family: var(--f-data); font-size: .68rem; }
.ln-signal-evidence a { display: inline-block; margin-right: .6rem; }
.ln-theme-pill {
  font-family: var(--f-ui);
  font-size: .56rem; padding: .1rem .42rem; border-radius: 2px;
  letter-spacing: .12em; text-transform: uppercase;
  background: none; color: var(--blue);
  border: 1px solid color-mix(in srgb, var(--blue) 38%, transparent);
}

/* ── Settings: repeatable rows ──────────────────────────────*/
.ln-repeat-row {
  border: none; border-bottom: 1px solid var(--border); border-radius: 0;
  padding: .55rem 0; margin-bottom: 0; background: none;
}
.ln-repeat-head { display: flex; align-items: center; gap: .45rem; }
.ln-chip-input { font-size: .76rem; }
.ln-source-badge {
  font-family: var(--f-ui);
  font-size: .56rem; text-transform: uppercase; letter-spacing: .12em;
  padding: .08rem .38rem; border-radius: 2px;
  background: none; color: var(--muted); border: 1px solid var(--border);
}

/* ── Charts ─────────────────────────────────────────────────*/
.ln-chart-box { position: relative; height: 280px; }
.ln-chart-tall { height: 340px; }
.ln-chart-short { height: 200px; }
.ln-chart-data summary {
  cursor: pointer; color: var(--muted); font-size: .68rem; padding: .35rem 0;
  font-family: var(--f-ui); letter-spacing: .12em; text-transform: uppercase;
}
.ln-chart-data[open] summary { margin-bottom: .4rem; }

/* A chart with nothing to draw says why, in a frame that still reads as a
   chart slot so the section does not collapse — but a shorter one, because
   a first run has every panel empty at once and four 280px voids is a wall.
   In this system the empty state is the one a reader sees most, so it is a
   sentence on a quiet page rather than a box around the word "No". */
.ln-chart-note {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; height: 100%; padding: 1rem; gap: .3rem;
  color: var(--muted); font-family: var(--f-fig); font-style: italic;
  font-size: .95rem; line-height: 1.5;
}
.ln-chart-box:has(> .ln-chart-note) { height: 140px; }
.ln-chart-box.is-loading { opacity: .45; transition: opacity .15s; }

/* ── Sparklines ─────────────────────────────────────────────*/
.ln-spark { display: block; width: 100%; height: 24px; margin-top: .4rem; }
.ln-spark path { fill: none; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.ln-spark .ln-spark-line { stroke: var(--muted); opacity: .5; }
.ln-spark .ln-spark-head { fill: var(--accent); }

/* ── Meter (52-week position bullet) ────────────────────────*/
.ln-meter {
  position: relative; height: 5px; border-radius: 3px;
  background: color-mix(in srgb, var(--text) 9%, transparent);
  min-width: 54px;
}
.ln-meter-fill {
  position: absolute; inset: 0 auto 0 0; border-radius: 3px;
  background: color-mix(in srgb, var(--text) 22%, transparent);
}
.ln-meter-mark {
  position: absolute; top: -2px; width: 2px; height: 9px; border-radius: 1px;
  background: var(--text); transform: translateX(-1px);
}

/* ── Chart filter row ───────────────────────────────────────
   One row above the charts it scopes. The chips are micro-caps with a rule
   under the live one — the same gesture as the nav, so "which one is on" is
   one idea across the app. */
.ln-filter-row {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  margin-bottom: .9rem;
}
.ln-chip {
  border: none; border-bottom: 1px solid transparent; background: none;
  color: var(--muted); border-radius: 0; padding: .14rem 0;
  font-family: var(--f-ui); font-size: .64rem; letter-spacing: .13em; text-transform: uppercase;
  cursor: pointer; transition: color .15s, border-color .15s;
  display: inline-flex; align-items: center; gap: .35rem;
}
.ln-chip:hover { color: var(--text); }
.ln-chip.active { color: var(--text); border-bottom-color: var(--accent); background: none; }
/* the chip's own swatch is the legend key — identity never rides on the text
   colour, which stays an ink token */
.ln-chip-key { width: 9px; height: 9px; border-radius: 2px; flex: 0 0 auto; }
.ln-chip:not(.active) .ln-chip-key { opacity: .3; }
/* a selected chip says how to unselect it */
#perf-chips .ln-chip.active::after,
#pf-perf-chips .ln-chip.active::after,
#macro-chips .ln-chip.active::after { content: '×'; color: var(--muted); margin-left: .1rem; font-size: .8rem; line-height: 1; }
#perf-chips .ln-chip.active:hover::after,
#pf-perf-chips .ln-chip.active:hover::after,
#macro-chips .ln-chip.active:hover::after { color: var(--red); }
.ln-chip.ln-chip-clear { border-bottom-style: dashed; border-bottom-color: var(--border-2); }

/* ── Price hover ────────────────────────────────────────────
   One floating tip for the whole page. This is one of the few things that
   genuinely lifts off the page, so it keeps a surface and a shadow. */
.ln-price-tip {
  position: fixed; z-index: 3000; pointer-events: none;
  background: var(--bg-card); color: var(--text);
  border: 1px solid var(--border-2); border-left: 2px solid var(--accent);
  border-radius: 3px; padding: .45rem .65rem; font-family: var(--f-data); font-size: .74rem;
  box-shadow: 0 8px 28px rgba(0,0,0,.45); max-width: 260px;
  display: none;
}
.ln-price-tip.is-on { display: block; }
.ln-price-tip .ln-price-tip-sym { font-weight: 500; margin-right: .35rem; }
.ln-price-tip .ln-price-tip-name { font-family: var(--f-ui); color: var(--muted); font-size: .7rem; }
.ln-price-tip .ln-price-tip-when { color: var(--muted); font-size: .66rem; margin-top: .15rem; }

/* ── Modal ──────────────────────────────────────────────────*/
.ln-modal .modal-content {
  background: var(--bg-card); color: var(--text);
  border: 1px solid var(--border-2); border-radius: 4px;
}
.ln-modal .modal-header, .ln-modal .modal-footer {
  border-color: var(--border); background: none;
}
.ln-modal .modal-title {
  font-family: var(--f-fig); color: var(--text); font-size: 1.25rem; font-weight: 400;
}
.ln-modal .btn-close { filter: invert(1) grayscale(1) opacity(.5); }
[data-theme="light"] .ln-modal .btn-close { filter: none; opacity: .5; }

/* ── Decisions / audit log ──────────────────────────────────*/
.ln-chain {
  border: none; border-bottom: 1px solid var(--border); border-radius: 0;
  margin-bottom: 0; overflow: visible;
}
.ln-chain-head {
  background: none; padding: .55rem 0;
  display: flex; align-items: baseline; gap: .5rem;
  cursor: pointer; font-size: .78rem; flex-wrap: wrap;
}
.ln-chain-head:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }
/* the headline: what the run WAS. The raw id is a join key, not a name. */
.ln-chain-name { font-family: var(--f-fig); font-size: 1rem; color: var(--text); }
.ln-chain-syms { font-family: var(--f-data); font-size: .7rem; color: var(--accent); }
.ln-chain-id { font-family: var(--f-data); color: var(--faint); font-size: .68rem; }
.ln-decision {
  padding: .45rem 0 .45rem .85rem; border-top: 1px solid var(--border);
  font-size: .78rem; display: flex; gap: .5rem; align-items: flex-start;
}
.ln-decision-rationale {
  color: var(--muted); font-size: .74rem; margin-top: .15rem;
  white-space: pre-wrap; word-break: break-word; line-height: 1.5;
}

/* ── Utility ────────────────────────────────────────────────*/
.ln-muted  { color: var(--muted); }
.ln-accent { color: var(--accent); }
.ln-gold   { color: var(--gold); }
.ln-pos    { color: var(--green); }
.ln-neg    { color: var(--red); }
/* The empty state is the one this app shows most — an unfunded lab has every
   panel empty at once — so it is written as a sentence, not a shrug. */
.ln-empty {
  color: var(--muted); text-align: center; padding: 2.2rem 1rem;
  font-family: var(--f-fig); font-style: italic; font-size: 1rem;
}

.ln-banner {
  border: none; border-left: 2px solid var(--border-2); border-radius: 0;
  padding: .55rem .9rem; font-size: .8rem; line-height: 1.5;
  margin-bottom: .9rem; background: none;
}
.ln-banner-warn { border-left-color: var(--amber);  color: var(--amber);  background: color-mix(in srgb, var(--amber) 7%, transparent); }
.ln-banner-err  { border-left-color: var(--red);    color: var(--red);    background: color-mix(in srgb, var(--red) 7%, transparent); }
.ln-banner-info { border-left-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, transparent); }

/* Paper-trading disclosure — deliberately always visible in the Lab. */
.ln-paper-tag {
  display: inline-block; font-family: var(--f-ui);
  font-size: .56rem; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--amber); border: 1px solid color-mix(in srgb, var(--amber) 45%, transparent);
  background: none;
  border-radius: 2px; padding: .12rem .42rem; vertical-align: middle;
}

/* ── Toast ──────────────────────────────────────────────────*/
#ln-toast {
  position: fixed; bottom: 1.2rem; right: 1.2rem; z-index: 2000;
  display: flex; flex-direction: column; gap: .4rem;
}
.ln-toast-item {
  background: var(--bg-card); border: 1px solid var(--border-2);
  border-left: 2px solid var(--accent);
  border-radius: 3px; padding: .55rem .85rem; font-size: .8rem;
  max-width: 380px; box-shadow: 0 8px 28px rgba(0,0,0,.45);
}
.ln-toast-item.err { border-left-color: var(--red); }

/* ── Sub-tabs (Intelligence) ────────────────────────────────*/
.ln-tabs { display: flex; gap: 1.4rem; border-bottom: 1px solid var(--border); margin-bottom: 1.1rem; }
.ln-tab {
  background: none; border: none; border-bottom: 1px solid transparent;
  color: var(--muted); padding: .35rem 0 .45rem; cursor: pointer;
  font-family: var(--f-ui); font-size: .66rem; letter-spacing: .13em; text-transform: uppercase;
  margin-bottom: -1px; transition: color .15s, border-color .15s;
}
.ln-tab:hover { color: var(--text); }
.ln-tab.active { color: var(--text); border-bottom-color: var(--accent); }

/* ── Settings ───────────────────────────────────────────────*/
.ln-provider-row {
  display: flex; align-items: center; gap: .5rem;
  padding: .55rem 0; border: none; border-bottom: 1px solid var(--border);
  border-radius: 0; margin-bottom: 0; background: none;
}
.ln-provider-row.expanded { border-bottom-color: var(--accent); }
.ln-provider-fields { padding: .6rem 0 .2rem; }
.ln-routing-table td { padding: .3rem .4rem .3rem 0; }

@media (max-width: 768px) {
  .ln-chart-box { height: 220px; }
  .ln-chart-short { height: 180px; }
  .ln-stat-value { font-size: 1.4rem; }
  .ln-stat, .ln-agent-card { border-left: none; padding-left: 0; }
  .navbar-nav .nav-link { margin: 0; padding: .35rem 0 !important; }
}
