/* ═══════════════════════════════════════════════════════════════════════════════════════
   READABLE — every piece of data legible, in every look (2026-09-30).

   The owner asked whether all data is readable across all skins and modes. It was measured
   (skins/readability.js: every text element, ink against the background actually painted behind
   it, 14 looks, 61 views) and it was not — in any look, Classic included. The misses were not the
   palette. They were a handful of habits layered on top of it:
     - text dimmed with `opacity` until it sat near 2:1 (weak betas, thin-coverage cells, the FY /
       expiry superscripts, provisional markers);
     - column-group tags painted in one fixed set of mid-tones tuned for the dark header and left
       at 2.3–2.6:1 on the light one;
     - secondary and caution text laid over heat-filled cells;
     - chart axis labels in a "dim" grey at 2.6–3:1;
     - links on Home with no colour rule at all, so the browser's default blue — 1.8:1 on dark.

   This file fixes those, for Classic and for every skin, and nothing else. It sets colour, fill
   and opacity only — never size, weight, spacing or layout, and never the heat fill. Every ink it
   uses is computed and checked by skins/build_skins.py against every surface it can land on
   (panel, wells, header band, hover wash, both heat fills); the floor is 4.5:1.

   De-emphasis is kept, just not as invisibility: a weak or thin value is still plainly secondary
   (about 4.5–5:1 against 15:1 for a normal number), it simply can be read now.

   Loaded after the app's stylesheets and before skins.css. One <link> to remove to undo it.
   GENERATED from skins/readable.base.css — edit the source, then `python3 skins/build_skins.py build`.
   ═══════════════════════════════════════════════════════════════════════════════════════ */

/* ───────────── Classic's inks (generated; every skin sets the same tokens in skins.css) ───────────── */
:root {
  --muted: #616c79;
  --bull: #167d35;
  --amber: #956407;
  --seg-mkt: #6b737e;
  --seg-ret: #257f74;
  --seg-val: #7d64b1;
  --seg-rate: #b15656;
  --seg-eco: #966654;
  --ink-2: #535e6a;
  --amber-ink: #7f5406;
  --accent-ink: #1d51ee;
  --bull-ink: #056f2b;
  --bear-ink: #b8131b;
  --dim-op: 0.73;
  --accent-fill: #2962ff;
}
:root[data-theme="dark"] {
  --ink-2: #929ba5;
  --amber-ink: #d29922;
  --accent-ink: #5c99fc;
  --bull-ink: #3fb950;
  --bear-ink: #fe6b61;
  --dim-op: 0.55;
  --accent-fill: #2b71e4;
  --muted: #8b949e;
  --bull: #3fb950;
  --amber: #d29922;
  --seg-mkt: #8b95a3;
  --seg-ret: #2f9c8f;
  --seg-val: #937bc9;
  --seg-rate: #c76c6c;
  --seg-eco: #ad7b69;
}

/* ───────────── 1. text that was dimmed with opacity → full opacity, in a checked ink ───────────── */
td .beta-weak { opacity: 1; color: var(--ink-2); }                     /* was .34 — a weak beta, ~2:1 */
td .beta-mid { opacity: 1; color: color-mix(in srgb, var(--text) 55%, var(--ink-2)); }   /* was .62; still between a strong beta and a weak one */
sup.muted[style*="opacity"] { opacity: 1 !important; color: var(--ink-2); }   /* FY / expiry tags; the opacity is inline */
.mac-sup { opacity: 1; }                                               /* provisional marker; keeps its parent's colour */
button.seg-barlab .seg-sum { opacity: 1; }
.bf-mx-c i { opacity: 1; }
.cmp-svg .cmp-tick, .cmp-svg .cmp-ql, .cmp-svg .cmp-ql.good, .cmp-svg .cmp-ql.bad { opacity: 1; }
.cmp-bl em, .cmp-bar .k small, .vm-howto .vmh-tail, .h6 .h6-sug-t small i { opacity: 1; }
.cmp-h2t th .gate-tag { opacity: 1; }

/* ───────────── 2. thin-data cells and dimmed rows ─────────────
   A thin-coverage cell was faded as a whole to 42–45% — the heat fill AND the number, which left the
   number near 2.2:1. The fade is the cue ("do not lean on this"), so it stays, but on the fill only:
   the cell is opaque again, a wash of the panel colour is laid over the fill (an inset shadow paints
   above the background and below the text), and the number takes the secondary ink. Same faded cell,
   readable number. */
table.rot-lead td.ctry-thin,
table.ctry-grid td.ctry-thin {
  opacity: 1; color: var(--ink-2);
  box-shadow: inset 0 0 0 9999px color-mix(in srgb, var(--panel) 56%, transparent);
}
/* rows the reader dimmed by picking others, and empty tier cells, are faded as a whole — as far as the floor allows */
.rot-country table.rot-lead tr.ctry-dim td,
table.ctry-grid tr.ctry-dim td,
.h6 .h6-mx-0 { opacity: var(--dim-op); }
.h6 .h6-mx-0 .h6-mx-tier { color: var(--text); }
/* the identity cells of a dimmed row keep the app's own rule (opacity 1, muted) — restated because the rule above is later */
.rot-country table.ctry-main tr.ctry-dim td:nth-child(-n+4),
table.ctry-grid tr.ctry-dim td:first-child { opacity: 1; }

/* ───────────── 3. column-group tags: the column-band ink of the same hue, per mode ───────────── */
.gate-bdaction, .gate-horizons, .gate-scan, .gate-strength, .gate-trend, .gate-vol, .gate-wcap { --gate-c: var(--seg-crv); }   /* was #4a7fd0 */
.gate-bdprice, .gate-gamma, .gate-implied, .gate-levels, .gate-position, .gate-price, .gate-skew, .gate-vmlens { --gate-c: var(--seg-val); }   /* was #8a6fc4 */
.gate-bdspread, .gate-credit, .gate-puts, .gate-risk, .gate-trade { --gate-c: var(--seg-rate); }   /* was #c25f5f */
.gate-bddebt, .gate-event, .gate-excursion, .gate-quality, .gate-real, .gate-setup, .gate-vmroute { --gate-c: var(--seg-qua); }   /* was #c2872f */
.gate-bdfund, .gate-calls, .gate-carry, .gate-edge, .gate-good, .gate-intensity, .gate-measured, .gate-odds, .gate-return { --gate-c: var(--seg-ret); }   /* was #2f9c8f */
.gate-flow, .gate-liquidity, .gate-options, .gate-prices, .gate-rules, .gate-vmcross { --gate-c: var(--seg-brd); }   /* was #6f8fa8 */
.gate-bdrating, .gate-bdsrc, .gate-context, .gate-score, .gate-trust { --gate-c: var(--seg-mkt); }   /* was #8b95a3 */
.scanner th .gate-tag { opacity: 1; }
/* A label that names a hue (a tag, a face button, a series) sits on a tint of that same hue, which
   eats its contrast. Mixing the hue toward the body ink keeps the colour's identity and works in
   both modes without a second palette: the body ink is dark on a light ground and light on a dark one. */
.h2-ev.m { color: color-mix(in srgb, var(--seg-ret) 68%, var(--text)); }
.h2-ev.d { color: color-mix(in srgb, var(--seg-crv) 68%, var(--text)); }
.beta-dis { opacity: 1; color: color-mix(in srgb, var(--gate-c, var(--ink-2)) 62%, var(--text)); }
.cmp-g { color: color-mix(in srgb, var(--gc) 58%, var(--text)); }
.cmp-svg .cmp-lab.pin, .cmp-svg .cmp-lab.me, .cmp-svg .cmp-end { fill: color-mix(in srgb, var(--c) 60%, var(--text)); }
/* every active toolbar button is printed in the accent (the app's own !important rule), over a tint of
   its own hue — teal, violet, wine, amber. --accent-ink is the accent checked on all of those tints. */
.active-btn { color: var(--accent-ink) !important; }

/* ───────────── 4. secondary and caution text on a heat-filled cell ───────────── */
td[style*="background"] .muted,
td[style*="background"].muted { color: var(--ink-2); }
td[style*="background"] .warn { color: var(--amber-ink); }
/* the briefing's own heat matrix and metric chips: signal-coloured numbers on a tint of the same colour */
.bf-mx-c.bear { color: color-mix(in srgb, var(--bear-ink) 72%, var(--text)); }
.bf-mx-c.bull { color: color-mix(in srgb, var(--bull-ink) 72%, var(--text)); }
.bf-m b.bull { color: var(--bull-ink); }
.bf-m b.bear { color: var(--bear-ink); }
.bf-m b.warn { color: var(--amber-ink); }
.cv-strip .m .k, .sec-band-in .muted, .cmp-h2t tr.gmed .nm, .cmp-h2t tr.med .nm, .cmp-h2t tr.gmed .co .rk,
.cmp-h2t tr.me .rk, .cmp-h2t tr.me .nm, .bf-m i, .ctlg-lab,
.h6 .h6-mx-tools, .h6 .h6-runid span { color: var(--ink-2); }   /* secondary text on a tinted band, strip, chip or card */

/* ───────────── 5. chart axis labels and legend notes ───────────── */
html:root, html:root[data-theme="dark"] { --cvc-dim: var(--ink-2); }

/* ───────────── 6. links with no colour rule of their own (browser blue on a dark panel) ───────────── */
:where(a:any-link) { color: var(--accent); }

/* ───────────── 7. accent text on the selected wash — the two places it is data ─────────────
   (A generic fix was tried and withdrawn: re-pointing --accent inside every accent-on-wash rule also
   changed the FILL of the chips that are accent-filled when active, and made their white text worse.) */
table.scanner tr.region-row td { color: var(--accent-ink); }
tr.cv-self .sym, tr.cv-self .cv-selftag { color: var(--accent-ink); }
/* a row the reader marked: its frozen block carries a slate wash, which the ticker and the secondary text sit on */
table.scanner tbody tr.row-marked > td .sym { color: color-mix(in srgb, var(--accent-ink) 60%, var(--text)); }
table.scanner tbody tr.row-marked > td .muted { color: color-mix(in srgb, var(--ink-2) 62%, var(--text)); }
/* identifiers printed as accent-on-wash chips: tickers, model ids */
.cv-tk, .h6 .h6-id, .h6 .h6-idp, .h6 .h6-new .h6-tk, .h6 .h6-chip.on, .mrm .mrmh-chip.on, .mi-act-n, .mi-live, .pb-use { color: var(--accent-ink); }

/* ───────────── 8. tinted chips: ink checked on a tint of its own colour ───────────── */
.cmp-call { --tc: var(--ink-2); }
.cmp-call.good { --tc: var(--bull-ink); }
.cmp-call.warn { --tc: var(--amber-ink); }
.cmp-call.bad { --tc: var(--bear-ink); }
.cmp-tier { --tc: var(--ink-2); }
.cmp-tier.good { --tc: var(--bull-ink); }
.cmp-tier.bad { --tc: var(--bear-ink); }
.cmp-pill { --tc: var(--ink-2); }
.cmp-pill.good { --tc: var(--bull-ink); }
.cmp-pill.warn { --tc: var(--amber-ink); }
.cmp-pill.bad { --tc: var(--bear-ink); }
.cmp-conf { --tc: var(--ink-2); }
.cmp-conf.h { --tc: var(--bull-ink); }
.cmp-conf.m { --tc: var(--accent-ink); }
.cmp-conf.l { --tc: var(--amber-ink); }
.cmp-mw { --tc: var(--ink-2); }
.cmp-mw.wide { --tc: var(--bull-ink); }
.cmp-mw.narrow { --tc: var(--amber-ink); }
.codbadge.wide, .gcap { color: var(--bear-ink); }
.codbadge.tight { color: var(--bull-ink); }
.codbadge.pend, .h6 .h6-tab b { color: var(--grey-chip); }
.chip.chip-dim, .chip .muted { color: var(--ink-2); }
/* counts printed on stacked-bar segments in the Model Hub */
.h6, :root[data-theme="dark"] .h6 { --h6-neutral: var(--ink-2); }
.h6 .h6-seg-notreliable { background: var(--bear-ink); opacity: .92; }   /* was a 58% wash: too light for the white count on it */

/* ───────────── 8b. the Company Financials tab (company_fin.css, built after this layer; 2026-10-02) ─────────────
   Found by the readability sweep once the tab existed: the value inside a chart bar was white at 95% on a 78%-opacity
   accent bar (3.2:1 on Classic, 1.8:1 on a dark skin whose accent is light); growth sub-rows, sub-headings and
   "implied" notes in muted at 9–11px; the projection heading in amber at 85%; the outflow figure in a fixed orange. */
.fin-svg .lab { fill: var(--ink-2); }
.fin-svg .lab.last { fill: var(--text); }
/* both label kinds print the text ink with a 3px halo in the panel colour (paint-order: stroke), so whatever the bar's
   colour the glyph sits on the panel */
.fin-svg .lab.in, .fin-svg .lab.pt { fill: var(--text); opacity: 1; paint-order: stroke; stroke: var(--panel); stroke-width: 3px; stroke-linejoin: round; }
.fin-svg .ax, .fin-svg .ax.x.sub { fill: var(--ink-2); }
.fin-svg .ax.x { opacity: 1; }
.fin-tbl td.dash, .fin-tbl th .sm, .fin-tbl td .chg, .fin-tbl td.proj .chg { color: var(--ink-2); }
/* growth sub-rows: 11px data in the secondary ink sat at 4.0–4.2 on the light side; a step toward the text ink, and
   the signal inks the layer checks on their own tints for the up / down cells */
.fin-tbl tr.g td { color: color-mix(in srgb, var(--ink-2) 70%, var(--text)); }
.fin-tbl tr.g td.pos { color: var(--bull-ink); }
.fin-tbl tr.g td.neg { color: var(--bear-ink); }
/* the app lays its own heat fill on these cells inline, up to 32% (stronger than the 22% the inks above are checked
   on): under it the data prints in the text ink, as on every other heat cell. The fill itself is not touched. */
.fin-tbl tr.g td[style*="background"] { color: var(--text); }
.fin-tbl th.proj, .fin-tbl th.proj .sm { color: var(--amber-ink); opacity: 1; }
.fin-kpi .spk-cap, .fin-kpi .spk-cap .n { color: var(--ink-2); opacity: 1; }
.fin-wf .out .v b, .fin-funnel .row.out .v b { color: var(--amber-ink); }

/* ───────────── 9. counts inside active pills, and the ticker chip inside the active nav pill ───────────── */
.cv-subnav button.on .n { color: #fff; }
.cv-chip.on .n { color: #fff; }
.h6 .h6-pill.on b { color: #fff; }
.h6 .h6-segctl button.on b { color: #fff; }
.qchips .qchip.active b { color: #fff; }
.nav-dd.active .nav-dd-num { color: #fff; }
.mrm-pill.active b { color: #fff; }
.mrm-segb.on b { color: #fff; }
.nav-item.cv-nav.cv-on .cv-nav-chip { background: rgba(0, 0, 0, .22); }   /* was a white wash, which thinned the white text on it */

/* ───────────── 10. Classic only: the fill under white pill text ───────────── */
:where(:root:not([data-skin])) .cv-subnav button.on { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .cv-chip.on { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .nav-item.cv-nav.cv-on { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .cmp-chip.on { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .cmp-seg button.on { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .cmp-us span { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .cmp-cchip button:hover { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .h6 .h6-pill.on { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .h6 .h6-btn-p { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .h6 .h6-segctl button.on { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .nav-item.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) #colmenu .cm-sort2-btn.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) #colmenu .cm-sort-btn.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .qchips .qchip.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .view-toggle .vt.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) button.ctry-mix.agg-chip.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .paper-add button { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .fxb-h.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) button.pb-use:hover { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .psb-mini .psb-mini-add:hover { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .nav-dd.active .nav-dd-btn { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .bf-sw.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .mrm-pill.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .mrm-btn { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .mrm-segb.on { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) button.mac-face.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) button.ctry-mix.fam-chip.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .mac-dsort.active { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .tutor-gc button { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .tutor-toast .tt-play { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .tu-steps .tu-step .tu-n { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .tu-end .tu-acts button.pri { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .tutor-chap .tch.on { background-color: var(--accent-fill); }
:where(:root:not([data-skin])) .tutor-start button { background-color: var(--accent-fill); }
:root:not([data-skin]) .dsw a.here { background-color: var(--accent-fill); }   /* its own rule is an inline <style> in the body */
