/* Self-hosted, latin subset only. Three reasons rather than one: the Content-Security-Policy
   then names no third-party origin at all; the page stops making a request to Google on every
   load, which is a tracking surface on a page that takes wallet signatures; and the fonts stop
   being a dependency that can fail while the site is up. Variable files cover their weight
   ranges, so this is five declarations over three files. */
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('/vendor/plex-mono-400.woff2') format('woff2');}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;
  src:url('/vendor/plex-mono-500.woff2') format('woff2');}
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:400 600;font-display:swap;
  src:url('/vendor/instrument-sans-400.woff2') format('woff2');}

/* ---------------------------------------------------------------------------------------------
   The design system, as tokens. Every colour, size, space and radius in this stylesheet comes
   from here, so the look can be changed in one place and a test can tell a token from a one-off.

   The direction is an instrument, not a trading terminal: the chrome is ink, paper and neutrals,
   and the only saturated colour on screen is a VERDICT -- whether the log says a thing beat its
   control, lost to it, or cannot be told apart. Colour therefore means something specific every
   time it appears, which is the opposite of an accent used for brand, links, active tabs and
   buttons at once (what --accent did here before).

   Strategies get an edge rule and a word rather than four more hues: eight colours competing on
   a row that also shows a red or green multiple is unreadable, and unreadable in a particular way
   for the 8% of men with a colour-vision deficiency.
   --------------------------------------------------------------------------------------------- */
:root{
  color-scheme:dark;
  /* surfaces and ink */
  --paper:#0E1620;          /* a blue-black with an actual hue: tinted greys (#0B0B0B, #111) are
                               the tell of a generated page */
  --surface:#151D26; --raised:#1B2430;
  --ink:#E8EBEF; --ink-2:#AEB7C2;
  /* 4.5:1 against the darkest surface this sits on (--field, which the view chips use).
     #7E8794 measured 4.31 there -- fine on the page background, short on a chip, which is
     exactly the case a stylesheet review misses and rendered text does not. */
  --muted:#949DAA;
  --line:#26303A; --line2:#33404D; --field:#1B2430;
  /* verdicts -- the only saturated colour, always paired with a word or a glyph */
  --beats:#4FB89C; --worse:#E0707E; --undecided:#8A93A0; --flag:#D8813F;
  /* data marks: a series is not a verdict */
  --series:#5A9BE8; --series-soft:rgba(90,155,232,.18);
  --tag:#1F2831; --tag-ink:#C9D2DB;
  /* network roles (the replay and the constellation ring): a role is not a verdict either, so it
     gets its own set rather than borrowing --beats/--worse -- most of these reuse an existing
     verdict/series hue by role (disperser=flag, farm=series, collector=worse, operator=beats,
     outside=ink-2, untraced=muted); --role-sniper is the one new hue per theme. All seven measure
     4.5:1+ against --paper in both themes (tightest: light --role-operator, 4.68:1); the full ratio
     table is in .superpowers/sdd/2026-09-28-networks/task-12-report.md and its fix-round reports. */
  --role-disperser:#D8813F; --role-farm:#5A9BE8; --role-collector:#E0707E; --role-sniper:#C77DDB;
  --role-operator:#4FB89C; --role-outside:#AEB7C2; --role-untraced:#949DAA;
  /* the deployer is its own hue (fix round 1: it shared the disperser's orange and the two stops could not be
     told apart); gold, 9.1:1 on --paper dark, olive 5.6:1 on --paper light */
  --role-deployer:#D9B43A;
  /* kept so existing rules resolve while the screens are restyled; both map to a verdict */
  --good:var(--beats); --bad:var(--worse); --warn:var(--flag);
  --bg:var(--paper); --accent:var(--ink); --accent-ink:var(--paper); --accent-soft:var(--raised);

  /* type: one workhorse and the mono kept for every numeral, which is what an instrument reads */
  --sans:'Instrument Sans',system-ui,-apple-system,sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,monospace;
  --t-micro:11px; --t-data:13px; --t-body:15px; --t-section:18px; --t-page:24px; --t-hero:34px;
  /* one addition to the scale, not two: a headline figure is the single thing on a report meant
     to be read from across a desk, and the band claim above it uses --t-hero. A step invented to
     sit between two existing ones is a grab bag, not a scale. */
  --t-display:46px;

  /* space on a 4px grid, and radius by hierarchy: a row is not a chip is not a panel */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
  --r-row:0; --r-chip:4px; --r-panel:8px; --r-drawer:12px;
  /* the only elevation in the system: a tooltip floats, nothing else does. Cards with soft grey
     shadows under each of them are the generated-page look this is deliberately not. */
  --lift:0 2px 8px var(--lift);
}
@media (prefers-color-scheme: light){
  :root:not([data-theme="dark"]){
    color-scheme:light;
    --paper:#FBFAF7; --surface:#FFFFFF; --raised:#F4F3EF;
    --ink:#0E1620; --ink-2:#3A434E; --muted:#656D78;
    --line:#D9DCE1; --line2:#C3C9D1; --field:#F2F1ED;
    --beats:#1E7F6B; --worse:#B23A48; --undecided:#737B85; --flag:#A8481C;
    --series:#2A78D6; --series-soft:rgba(42,120,214,.16);
    --tag:#EDEBE5; --tag-ink:#2E3A47;
    --role-disperser:#A8481C; --role-farm:#1F5FAE; --role-collector:#B23A48; --role-sniper:#7A3A92;
    --role-operator:#1E7F6B; --role-outside:#3A434E; --role-untraced:#656D78;
    --role-deployer:#7A6300;
  }
}
:root[data-theme="light"]{
  color-scheme:light;
  --paper:#FBFAF7; --surface:#FFFFFF; --raised:#F4F3EF;
  --ink:#0E1620; --ink-2:#3A434E; --muted:#656D78;
  --line:#D9DCE1; --line2:#C3C9D1; --field:#F2F1ED;
  --beats:#1E7F6B; --worse:#B23A48; --undecided:#737B85; --flag:#A8481C;
  --series:#2A78D6; --series-soft:rgba(42,120,214,.16);
  --tag:#EDEBE5; --tag-ink:#2E3A47;
  --role-disperser:#A8481C; --role-farm:#1F5FAE; --role-collector:#B23A48; --role-sniper:#7A3A92;
  --role-operator:#1E7F6B; --role-outside:#3A434E; --role-untraced:#656D78;
  --role-deployer:#7A6300;
}
/* The drawer is a summary; the report is the document. The link is first because that is the
   order a reader wants them in once they have decided this token is worth the time. */
.sub .report-link{color:var(--series);font-weight:500}
*{box-sizing:border-box}
html,body{margin:0;background:var(--bg);color:var(--ink)}
body{font:var(--t-data)/1.5 var(--sans);padding:var(--s3) var(--s3) 60px}
/* every numeral is tabular and mono: a column of figures that does not line up is a column
   nobody reads down */
.mono,td.n,th.n,.tag,.addr,.tile .v{font-family:var(--mono);font-variant-numeric:tabular-nums}
/* prose is measured, not full-width: past about 70 characters the eye loses the line */
.doc p,.note,.lead{max-width:68ch}
header{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 16px;margin-bottom:10px}
header h1{font-size:var(--t-section);font-weight:600;margin:0}
.status{font-size:var(--t-micro);color:var(--muted)}
.dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--good);margin-right:5px;vertical-align:middle}
.dot.off{background:var(--bad)}
nav{display:flex;gap:2px;border-bottom:1px solid var(--line);margin-bottom:12px;overflow-x:auto}
nav button{font:inherit;font-size:13px;font-weight:500;color:var(--muted);background:none;border:0;border-bottom:2px solid transparent;padding:8px 12px;cursor:pointer;white-space:nowrap}
nav button[aria-selected=true]{color:var(--ink);border-bottom-color:var(--accent)}
nav button .cnt{font-family:"IBM Plex Mono",monospace;font-size:var(--t-micro);color:var(--muted);margin-left:4px}
.filters{display:flex;flex-wrap:wrap;gap:6px 8px;align-items:center;padding:10px;background:var(--surface);border:1px solid var(--line);border-radius:6px;margin-bottom:12px}
.filters label{font-size:var(--t-micro);color:var(--muted);display:flex;align-items:center;gap:5px}
.filters select,.filters input[type=text],.filters input[type=number]{font:inherit;font-size:13px;color:var(--ink);background:var(--raised);border:1px solid var(--line2);border-radius:4px;padding:4px 7px;min-width:0}
.filters input[type=text]{width:130px}
.filters input.addr{width:360px}
.filters input[type=number]{width:80px}
.chip{font-size:var(--t-micro);padding:4px 9px;border:1px solid var(--line2);border-radius:14px;background:var(--raised);color:var(--muted);cursor:pointer;user-select:none}
.chip[aria-pressed=true]{background:var(--accent-soft);color:var(--accent);border-color:var(--accent)}
.chip:focus-visible,select:focus-visible,input:focus-visible,button:focus-visible,tr[tabindex]:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));gap:8px;margin-bottom:12px}
.tile.go{cursor:pointer}.tile.go:hover{border-color:var(--ink)}.tile.go:focus-visible{outline:2px solid var(--accent)}
.tile{background:var(--surface);border:1px solid var(--line);border-radius:6px;padding:8px 10px}
.tile .k{font-size:var(--t-micro);color:var(--muted);letter-spacing:.01em}
.tile .v{font-family:"IBM Plex Mono",monospace;font-size:var(--t-page);font-weight:500;margin-top:2px;font-variant-numeric:tabular-nums}
.tile .s{font-size:var(--t-micro);color:var(--muted)}
.grid{display:grid;grid-template-columns:1fr;gap:12px}
@media(min-width:1100px){.grid{grid-template-columns:minmax(0,1fr) 440px}}
@media(min-width:1500px){.grid{grid-template-columns:minmax(0,1fr) 560px}}
/* the detail pane is a fixed column: wide tables (wallet buys, caller posts, lineage launches, token snapshots)
   scroll inside it instead of being clipped by the panel's overflow:hidden */
.detail{min-width:0;overflow-x:auto}
.detail .snaps{font-size:var(--t-micro)}
.detail .snaps th,.detail .snaps td{padding:4px 5px}
.panel{background:var(--surface);border:1px solid var(--line);border-radius:6px;overflow:hidden}
.panel h2{font-size:var(--t-data);font-weight:600;letter-spacing:0;color:var(--muted);margin:0;padding:8px 10px;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:center;gap:8px}
.scroll{overflow-x:auto}
/* a followed wallet can trade all day; three of them filled the page and pushed positions, targets
   and P&L below the fold. The log keeps its own scroll instead of taking the page's. */
.scroll.cap{max-height:300px;overflow-y:auto}
.scroll.cap.open{max-height:none;overflow-y:visible}
.subhead{display:flex;align-items:center;gap:8px;padding:6px 10px 2px;font-size:var(--t-micro);
  letter-spacing:.01em;color:var(--muted);border-top:1px solid var(--line)}
.subhead .btn{text-transform:none;letter-spacing:0}
tfoot tr.totals td{border-top:2px solid var(--line2);font-weight:600;
  position:sticky;bottom:0;background:var(--surface)}
table{border-collapse:collapse;width:100%;font-size:var(--t-data)}
th,td{padding:5px 8px;border-bottom:1px solid var(--line);white-space:nowrap;text-align:left}
th{font-size:var(--t-micro);color:var(--muted);font-weight:500;letter-spacing:.03em;position:sticky;top:0;background:var(--surface);cursor:pointer;user-select:none}
th.sorted{color:var(--ink)}
th.n,td.n{text-align:right}
tbody tr{cursor:pointer}
tbody tr:hover{background:var(--raised)}
tbody tr.sel{background:var(--accent-soft)}
.tag{display:inline-block;font-size:var(--t-micro);padding:1px 5px;border-radius:3px;background:var(--tag);color:var(--tag-ink);margin-right:3px}
.tag.c{background:var(--accent);color:var(--accent-ink)}
.tag.bad{color:var(--bad);border:1px solid var(--bad);background:transparent}
.tag.good{color:var(--good);border:1px solid var(--good);background:transparent}
.helpwrap{position:fixed;inset:0;z-index:60;background:var(--bg);display:flex;flex-direction:column}
/* a class rule beats the UA stylesheet's [hidden]{display:none}, so display:flex above kept the
   overlay on screen whatever the hidden attribute said: it covered the page on every load and
   Close could not dismiss it. The attribute has to win here. */
.helpwrap[hidden]{display:none!important}
.helpnav a{color:var(--muted);text-decoration:none;border-bottom:1px dotted var(--line2)}
.helpnav a:hover{color:var(--accent)}
@media(max-width:900px){.helpnav{display:none}}
.sitefoot{max-width:1500px;margin:34px auto 0;padding:14px 16px 26px;border-top:1px solid var(--line2);
 color:var(--muted);font-size:var(--t-micro)}
.sitefoot a{color:var(--muted);text-decoration:none;border-bottom:1px dotted var(--line2)}
.sitefoot a:hover{color:var(--accent)}
.helpbar{display:flex;align-items:center;gap:10px;padding:10px 16px;border-bottom:1px solid var(--line);
  background:var(--surface);position:sticky;top:0}
.helpbody{overflow-y:auto;overflow-x:hidden;padding:18px;display:grid;gap:14px;align-content:start;
  grid-template-columns:repeat(auto-fit,minmax(440px,1fr));max-width:1700px;margin:0 auto;width:100%}
@media(max-width:900px){.helpbody{grid-template-columns:1fr;padding:12px}}
.doc.wide{grid-column:1/-1}
/* Two separate causes of clipped text, both fixed here.
   1. .panel sets overflow:hidden, so anything wider than the panel was cut off at its edge.
   2. a grid item defaults to min-width:auto, so .doc grew to its table's intrinsic width instead
      of shrinking to its column -- and table-layout:auto sized the table to its longest sentence.
   min-width:0 lets the column win, table-layout:fixed makes the cells wrap inside it. */
.doc{padding:16px 20px;overflow:visible;overflow-wrap:break-word;min-width:0;max-width:100%}
.doc *{min-width:0;max-width:100%}
.doc table{table-layout:fixed;width:100%}
.doc pre,.doc code{white-space:pre-wrap;overflow-wrap:anywhere}
.helpbody .doc{margin:0}
.doc h2{border-bottom:1px solid var(--line);margin-bottom:8px}
.doc h3{font-size:var(--t-micro);letter-spacing:.01em;color:var(--muted);margin:14px 0 6px}
.doc p{font-size:13px;line-height:1.65;margin:8px 0}
.doc ol,.doc ul{font-size:13px;line-height:1.8;padding-left:20px;margin:8px 0}
.doc code{background:var(--raised);border:1px solid var(--line2);border-radius:3px;padding:0 4px;font-size:var(--t-micro)}
.doc .note{border-left:2px solid var(--line2);padding-left:10px;color:var(--muted);font-size:var(--t-data)}
.doc-t{width:100%;max-width:100%;table-layout:fixed;border-collapse:collapse;font-size:var(--t-data);margin:6px 0}
.doc-t td{padding:5px 8px;border-top:1px solid var(--line);vertical-align:top}
/* the data tables set `th,td{white-space:nowrap}` globally, which is right for a column of numbers
   and fatal for a column of prose: the sentence could not wrap and was clipped at the panel edge */
.doc-t th,.doc-t td{white-space:normal;vertical-align:top}
.doc-t td:first-child{width:31%;color:var(--ink);font-weight:600}
.doc-t td{overflow-wrap:break-word;word-break:normal}
.welcome{padding:18px 20px;margin-bottom:12px;position:relative;border-left:4px solid var(--accent);background:var(--accent-soft)}
.welcome h2 span{font-size:var(--t-page);letter-spacing:0}
.welcome .wk{font-size:13px}
.welcome .wk.on{font-size:15px;font-weight:600}
.welcome .lead{margin:2px 0 6px;font-size:var(--t-data);line-height:1.5}
.btn.primary{background:var(--accent);color:var(--accent-ink);border-color:var(--accent);font-weight:600;padding:6px 14px;font-size:13px}
.plans{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;margin-top:10px}
.plan{border:1px solid var(--line);border-radius:8px;padding:14px 16px;background:var(--surface)}
.plan.on{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent) inset}
.plan .name{font-size:var(--t-micro);letter-spacing:.01em;color:var(--muted)}
.plan .price{font-size:var(--t-page);font-weight:600;margin:2px 0 8px}
.plan .price small{font-size:var(--t-micro);font-weight:400;color:var(--muted)}
.plan ul{margin:0;padding-left:18px;font-size:var(--t-data);line-height:1.75}
.plan li b{color:var(--ink)}
.cta{padding:16px 18px;border-left:4px solid var(--accent);background:var(--accent-soft);display:flex;gap:14px;align-items:center;flex-wrap:wrap;margin-bottom:12px}
.cta .big{font-size:15px;font-weight:600}
.cta[hidden]{display:none!important}
.showcase{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:12px;margin-bottom:12px}
.sc{background:var(--surface);border:1px solid var(--line);border-radius:8px;padding:10px 12px 8px;cursor:pointer;transition:border-color .15s,transform .15s}
.sc:hover,.sc:focus-visible{border-color:var(--accent);transform:translateY(-1px);outline:none}
.sc .t{font-size:var(--t-micro);letter-spacing:.01em;color:var(--muted);display:flex;justify-content:space-between;gap:8px}
.sc .t b{color:var(--ink);letter-spacing:0;text-transform:none;font-size:13px}
.sc svg{width:100%;height:auto;display:block;margin:6px 0 4px}
.sc .c{font-size:var(--t-micro);color:var(--muted);line-height:1.45}
.sc .c em{color:var(--ink);font-style:normal}
/* chart legends: each series named in its own colour, then one short line of what is counted */
.sc .c .k{font-weight:600;margin-right:10px;white-space:nowrap}
.sc .c .k-bar{color:var(--series)} .sc .c .k-acc{color:var(--accent)} .sc .c .k-good{color:var(--good)}
.sc .c .k-bad{color:var(--bad)} .sc .c .k-oth,.sc .c .k-und{color:var(--muted)}
.sc .c .kn{display:block;margin-top:3px}
.sc text{font-size:var(--t-micro);fill:var(--muted)}
.sc .bar{fill:var(--series)} .sc .bar.dim{fill:var(--series-soft)} .sc .good{fill:var(--good)} .sc .bad{fill:var(--bad)} .sc .acc{fill:var(--accent)}
.sc line.one{stroke:var(--muted);stroke-dasharray:2 3}
.sc .und{fill:var(--muted);opacity:.5} .sc .oth{fill:var(--muted);opacity:.45}
.sc line.ci{stroke:var(--ink);stroke-width:1.2}
.sc[hidden]{display:none!important}
/* research: a verdict you can read at a glance, then the detail, then the tally */
.rhead{display:grid;grid-template-columns:auto 1fr;gap:16px;align-items:start;padding:14px 16px 10px}
.rscore{text-align:center;min-width:92px}
.rscore .v{font-family:"IBM Plex Mono",monospace;font-size:var(--t-hero);font-weight:600;line-height:1}
.rscore .v.up{color:var(--good)} .rscore .v.dn{color:var(--bad)} .rscore .v.warn{color:var(--warn)}
.rscore .band{font-size:var(--t-micro);color:var(--muted);margin-top:3px;line-height:1.35}
.rflags{display:flex;flex-wrap:wrap;gap:6px;margin:7px 0 0}
.rsum{font-size:13px;line-height:1.55;margin:8px 0 0;max-width:70ch}
.rcols{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);gap:20px;padding:0 16px 14px}
@media (max-width:1150px){.rcols{grid-template-columns:1fr}}
.bd{display:grid;grid-template-columns:40px 84px 1fr;gap:9px;align-items:center;font-size:var(--t-data);padding:3px 0}
.bd .p{font-family:"IBM Plex Mono",monospace;text-align:right;font-variant-numeric:tabular-nums}
.bd .bar{background:var(--line);height:7px;border-radius:4px;overflow:hidden}
.bd .bar i{display:block;height:100%}
.bd .bar i.up{background:var(--good)} .bd .bar i.dn{background:var(--bad)}
.wlist{display:grid;grid-template-columns:auto 1fr auto;gap:2px 12px;align-items:baseline;font-size:var(--t-micro)}
.rposts{padding:0 16px 14px}
.rposts td{white-space:normal;word-break:break-word}
.rhead[hidden],.rcols[hidden],.rflags[hidden],.bd[hidden],.wlist[hidden],.rposts[hidden]{display:none!important}
.showcase.off{display:none}
.t[hidden],.sc .t[hidden]{display:none!important}
.welcome .wx{position:absolute;top:8px;right:8px;padding:1px 7px}
.welcome .wgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px;margin-top:8px}
.welcome .wk{font-size:var(--t-micro);letter-spacing:.01em;color:var(--muted);margin-bottom:4px}
.welcome .wk.on{color:var(--accent)}
.welcome ul{margin:0;padding-left:18px;font-size:var(--t-data);line-height:1.7}
.welcome .wfoot{margin-top:10px;display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.welcome .wfoot .muted{font-size:var(--t-micro)}
.tag.warn{color:var(--warn);border:1px solid var(--warn);background:transparent}
.px{font-family:"IBM Plex Mono",monospace}
.up{color:var(--good)}.dn{color:var(--bad)}
.sym{font-weight:600}
.addr{font-size:var(--t-micro);color:var(--muted)}
.detail{padding:10px 12px}
.detail h3{margin:0 0 2px;font-size:var(--t-body)}
.detail .sub{font-size:var(--t-micro);color:var(--muted);margin-bottom:10px;word-break:break-all}
.detail a{color:var(--series);text-decoration:none}
.kv{display:grid;grid-template-columns:auto 1fr;gap:5px 14px;font-size:var(--t-data);margin:6px 0 10px;line-height:1.45}
.facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));gap:8px;margin:10px 0 6px}
.facts .f{background:var(--surface);border:1px solid var(--line);border-radius:6px;padding:7px 9px}
.facts .f .k{font-size:var(--t-micro);letter-spacing:.01em;color:var(--muted)}
.facts .f .v{font-family:"IBM Plex Mono",monospace;font-size:15px;font-variant-numeric:tabular-nums;margin-top:2px}
.facts .f .s{font-size:var(--t-micro);color:var(--muted)}
#detail h4.grp{margin:12px 0 2px;font-size:var(--t-micro);letter-spacing:.01em;color:var(--accent);border-bottom:1px solid var(--line);padding-bottom:3px}
.caption{font-size:var(--t-micro);color:var(--muted);line-height:1.5;margin:2px 0 8px}
ul.redflags{margin:2px 0 6px;padding-left:18px;font-size:var(--t-data);line-height:1.6}
.caption i{display:inline-block;width:8px;height:8px;border-radius:50%;vertical-align:middle;margin-right:3px}
.kv .k{color:var(--muted)}
.kv .v{font-family:"IBM Plex Mono",monospace;font-variant-numeric:tabular-nums}
.snaps th,.snaps td{padding:4px 6px}
h4{font-size:var(--t-micro);letter-spacing:.01em;color:var(--muted);margin:14px 0 4px}
svg{display:block;width:100%;height:auto}
.chart{margin:8px 0 4px}
.chart text{font-family:"IBM Plex Mono",monospace;font-size:var(--t-micro);fill:var(--muted)}
.chart .grid line{stroke:var(--line);stroke-width:1}
.chart .ax{stroke:var(--line2)}
.chart .ln{fill:none;stroke:var(--series);stroke-width:2;stroke-linejoin:round}
.chart .ar{fill:var(--series-soft)}
.chart .ref{stroke:var(--accent);stroke-dasharray:3 3}
.chart .snap{fill:var(--accent)}
.chart .buy{fill:var(--good)}
.chart .sell{fill:var(--bad)}
.chart .hair{stroke:var(--line2)}
.bar{fill:var(--series)}
.bar.f{fill:var(--accent)}
.tip{position:fixed;pointer-events:none;background:var(--raised);border:1px solid var(--line2);border-radius:4px;padding:6px 8px;font-size:var(--t-micro);box-shadow:var(--lift);z-index:9;display:none}
.tip b{font-family:"IBM Plex Mono",monospace;font-weight:500}
.empty{padding:20px;color:var(--muted);font-size:13px;text-align:center}
.muted{color:var(--muted)}
.btn{font:inherit;font-size:var(--t-micro);color:var(--ink);background:var(--raised);border:1px solid var(--line2);border-radius:4px;padding:3px 8px;cursor:pointer}
.sig{padding:8px 10px;border-bottom:1px solid var(--line);display:grid;grid-template-columns:52px 1fr auto;gap:8px;align-items:start;cursor:pointer}
.sig:hover{background:var(--raised)}
.sig .t{color:var(--muted);font-family:"IBM Plex Mono",monospace;font-size:var(--t-micro);padding-top:2px}
.sig .h{font-weight:600}
.sig .b{font-size:var(--t-micro);color:var(--muted);margin-top:1px}
.sig .o{font-family:"IBM Plex Mono",monospace;font-size:var(--t-micro);text-align:right}
/* column headings over the alert list: a label and what the column means */
.sighead{display:grid;grid-template-columns:52px 1fr minmax(120px,26%);gap:8px;padding:8px 10px;border-bottom:1px solid var(--line2);font-size:var(--t-micro);font-weight:600;color:var(--muted)}
.sighead small{display:block;font-weight:400;margin-top:2px;line-height:1.35}
.sighead span:last-child{text-align:right}
.sig.buy .h{color:var(--good)} .sig.sell .h{color:var(--bad)} .sig.call .h{color:var(--accent)}
.hide{display:none}
@media (prefers-reduced-motion: no-preference){.panel,.tile{transition:opacity .15s}}

/* Two rows of navigation: where you are, and which view of it. The destination row is the product;
   the view row is the furniture inside it, so it is quieter and disappears when there is one view. */
#dests{display:flex;gap:var(--s1);border-bottom:1px solid var(--line);margin-bottom:var(--s2);overflow-x:auto}
#dests button{font:inherit;font-size:var(--t-body);font-weight:500;color:var(--muted);background:none;border:0;
  border-bottom:2px solid transparent;padding:var(--s2) var(--s3);cursor:pointer;white-space:nowrap}
#dests button[aria-selected=true]{color:var(--ink);border-bottom-color:var(--ink)}
#views{display:flex;gap:var(--s1);margin-bottom:var(--s3);overflow-x:auto}
#views[hidden]{display:none!important}
#views button{font:inherit;font-size:var(--t-data);color:var(--muted);background:var(--field);border:1px solid var(--line);
  border-radius:var(--r-chip);padding:var(--s1) var(--s3);cursor:pointer;white-space:nowrap}
#views button[aria-selected=true]{color:var(--ink);border-color:var(--line2);background:var(--surface)}
#legacy-tabs{display:none}

/* A withheld alert: the shape of a row, with nothing in it to read. Blurring real text would be a
   lie a reader can lift with devtools; there is nothing here to lift. */
.sig.held{opacity:.72}
.sig.held .h{color:var(--muted);font-weight:500}
.sig.held .b{color:var(--muted)}

/* The record of the kind, under the alert itself. Quieter than the alert -- it is context, not the
   event -- but present, because a reader deciding what to do with an alert should not have to go
   and look up whether that kind has ever been worth anything. */
.sig .rec{font-size:var(--t-micro);color:var(--muted);margin-top:2px}
/* the verdict, as colour, on every row: a list of twenty is scanned, not read */
.sig .rec.worse{color:var(--worse)}.sig .rec.beats{color:var(--beats)}.sig .rec.undecided{color:var(--undecided)}

/* The keyboard: a selected row, and the list of keys. Both are quiet -- the selection is a rule
   down the left edge rather than a fill, so it reads as "you are here" and not as a verdict. */
.kb{box-shadow:inset 2px 0 0 var(--ink)}
.keys{position:fixed;right:var(--s4);bottom:var(--s4);z-index:70;background:var(--surface);
  border:1px solid var(--line2);border-radius:var(--r-panel);padding:var(--s3);box-shadow:var(--lift)}
.keys[hidden]{display:none!important}
.keys td{padding:2px var(--s3) 2px 0;font-size:var(--t-data)}
.keys td.mono{color:var(--muted)}

/* Proof opens with the honest sentence, at the one size on the scale reserved for it. This is the
   page that decides whether a stranger believes the rest, so it gets the room. */
.proof-head{padding:var(--s5) var(--s3) var(--s4)}
.proof-head h1{font-size:var(--t-hero);font-weight:600;line-height:1.15;margin:0 0 var(--s4);max-width:22ch}
.proof-nums{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:var(--s4);margin-bottom:var(--s4)}
.proof-nums .v{font-family:var(--mono);font-size:var(--t-page);font-variant-numeric:tabular-nums}
.proof-nums .k{font-size:var(--t-body)}
.proof-nums .s{font-size:var(--t-micro);color:var(--muted);margin-top:2px}
/* the attribute wins: a class rule that sets display outranks the browser's [hidden], which is how
   an element "hidden" in script stays on screen (preflight refuses this pairing for that reason) */
.tiles[hidden]{display:none!important}

/* The interval mark. Colour is the verdict and nothing else: the dot sits where the value is, the
   whisker covers what the sample can support, and the line is what it is being judged against. */
.iv .wh{stroke:var(--line2);stroke-width:2}
.iv .ref{stroke:var(--muted);stroke-width:1;stroke-dasharray:2 2}
.iv .dot{fill:var(--undecided)}
.iv.beats .dot{fill:var(--beats)} .iv.beats .wh{stroke:var(--beats);opacity:.45}
.iv.worse .dot{fill:var(--worse)} .iv.worse .wh{stroke:var(--worse);opacity:.45}

/* The setup checklist (spec 4.5, task 8): a `.panel` (so it looks like every other panel) plus this
   marker, so its inner dk-ph/dk-pb/dk-check rules can be scoped without repeating them per tab --
   it renders inside both the Wallets tab and Overview's no-wallets state (SWDesk.renderSetup, the
   one definition), and only the outer spacing differs between those two places (scoped below,
   near each tab that uses it). */
.dk-setup .dk-ph{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s2);
  padding:var(--s3) var(--s4);border-bottom:1px solid var(--line)}
.dk-setup .dk-ph b{font-size:var(--t-body)}
.dk-setup .dk-pb{padding:var(--s3) var(--s4)}
.dk-setup .dk-check{display:flex;gap:var(--s2);align-items:baseline;padding:var(--s1) 0;font-size:var(--t-data)}
.dk-setup .dk-ok{color:var(--beats);font-family:var(--mono)}
.dk-setup .dk-todo{color:var(--muted);font-family:var(--mono)}

/* Research takes 30-90 seconds. The sources tick off while it works: done, in progress, waiting --
   by the clock, not by a progress bar that claims to know how far along the server is. */
.running{padding:var(--s3);font-size:var(--t-data)}
.running .done{color:var(--ink)}
.running .now{color:var(--ink);font-weight:500}
.running .todo{color:var(--muted)}

/* The help's page list: eleven places, one open at a time. A reader picks a page rather than
   scrolling past ten they did not want. */
.helppages{display:flex;flex-wrap:wrap;gap:var(--s1);padding:0 0 var(--s3);align-content:start}
.helppages button{font:inherit;font-size:var(--t-data);color:var(--muted);background:var(--field);
  border:1px solid var(--line);border-radius:var(--r-chip);padding:var(--s1) var(--s3);cursor:pointer}
.helppages button[aria-selected=true]{color:var(--ink);background:var(--surface);border-color:var(--line2)}
#help-q{font:inherit;font-size:var(--t-data);color:var(--ink);background:var(--field);
  border:1px solid var(--line2);border-radius:var(--r-chip);padding:var(--s1) var(--s2);min-width:200px}
@media(max-width:900px){.helppages{display:flex}}

/* ---- the landing page -------------------------------------------------------------------------
   One column, measured text, and the same tokens as the app: a reader who signs up should not feel
   they have arrived somewhere else. The only thing sized for a landing page is the headline. */
body.landing{max-width:980px;margin:0 auto;padding:0 var(--s4) var(--s6)}
.lheader{display:flex;align-items:center;gap:var(--s2);padding:var(--s4) 0;border-bottom:1px solid var(--line)}
.hero{padding:var(--s6) 0 var(--s5)}
.hero h1{font-size:var(--t-hero);font-weight:600;line-height:1.1;margin:0 0 var(--s4);max-width:18ch}
.hero .lead{font-size:var(--t-body);max-width:62ch;margin:0 0 var(--s4)}
.cta{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap}
.cta .muted{font-size:var(--t-micro)}
.strip{padding:var(--s5) 0;border-top:1px solid var(--line)}
.strip h2{font-size:var(--t-section);font-weight:600;margin:0 0 var(--s3)}
.strip p{max-width:68ch}
.ticker{border:1px solid var(--line);border-radius:var(--r-panel);overflow:hidden}
.trow{display:grid;grid-template-columns:5.5rem 9rem 6rem 4rem 1fr;gap:var(--s2);padding:6px var(--s3);
  font-size:var(--t-data);border-bottom:1px solid var(--line);align-items:baseline}
.trow:last-child{border-bottom:0}
.trow .t,.trow .p,.trow .r{font-family:var(--mono);font-variant-numeric:tabular-nums}
.trow .t,.trow .r{color:var(--muted)}
.trow .s{font-weight:500}
.trow .p.up{color:var(--beats)} .trow .p.dn{color:var(--worse)}
a.pn{display:block;color:inherit;text-decoration:none}
a.pn:hover .k{text-decoration:underline}
.steps{max-width:68ch;padding-left:var(--s4)}
.steps li{margin-bottom:var(--s2)}
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:var(--s4)}
.cards p{font-size:var(--t-data);color:var(--ink-2);margin:var(--s1) 0 0}
.faq p{margin-bottom:var(--s3)}
.lfooter{border-top:1px solid var(--line);padding:var(--s4) 0;font-size:var(--t-micro);color:var(--muted)}
@media(max-width:700px){.trow{grid-template-columns:4.5rem 1fr 3.5rem;}.trow .k,.trow .r{display:none}}

/* ---- the phone --------------------------------------------------------------------------------
   A grid or flex child's default min-width is its content, so a wide table makes its own column
   wider than the screen and the whole page scrolls sideways -- the table's own scroller never gets
   a chance. Letting those children shrink is what makes "the table scrolls, the page does not"
   true. Measured at 360px on every destination, not asserted here. */
.grid, .grid > *, section[id^=tab-], .panel, .filters, .filters > *{min-width:0}
.scroll{max-width:100%}
.filters input, .filters select{max-width:100%}
table{max-width:100%}
@media(max-width:700px){
  body{padding-left:var(--s2);padding-right:var(--s2)}
  .filters label, .filters input[type=text], .filters input[type=search]{width:100%}
  /* the detail panel is a sheet under the list at this width rather than a column beside it */
  .grid{grid-template-columns:minmax(0,1fr)}
}
/* A destination whose subject is the page itself, not a selected row, uses the whole width. */
@media(min-width:1100px){.grid.wide{grid-template-columns:minmax(0,1fr)}}
/* A table row that opens something says so before it is clicked. --raised is the token every
   other hoverable row already uses; a new colour here would be a second answer to one question. */
tr.click{cursor:pointer}
tr.click:hover{background:var(--raised)}
/* An identity is a link wherever it appears: the platform holds a page about it. */
a.ent{color:inherit;text-decoration:none;border-bottom:1px solid var(--line2)}
a.ent:hover{border-bottom-color:currentColor}
a.ent:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* the wallet panel's track button: its own row, above the record */
.trackbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:10px 0}
.trackbar input{font:inherit;font-size:var(--t-micro);width:150px;color:var(--ink);background:var(--raised);border:1px solid var(--line2);border-radius:4px;padding:3px 6px}
/* sortable headings: every table heading and the alert list's headings */
thead th{cursor:pointer;user-select:none}
thead th.sort-desc::after,.sighead .sort-desc::after{content:" \2193";color:var(--ink)}
thead th.sort-asc::after,.sighead .sort-asc::after{content:" \2191";color:var(--ink)}
.sighead [data-sk]{cursor:pointer}
/* a rule set behind a one-line summary: open it to read the thresholds */
details.how{margin:6px 0 10px;font-size:var(--t-micro);color:var(--muted)}
details.how summary{cursor:pointer;color:var(--ink)}
details.how ul{margin:6px 0 0;padding-left:18px;line-height:1.55}
details.how b{color:var(--ink);font-weight:600}
.mo-line{font-size:var(--t-data);margin:4px 0}
table.mo-res{margin:8px 0;font-size:var(--t-data)} table.mo-res th,table.mo-res td{padding:3px 12px 3px 0}

/* ---- the token pane and the research report (2026-09-24) -----------------------------------
   Both read as terminal output: every value was set in the mono, so a sentence like "has not sold,
   one transfer to a contract" looked like a log line and outweighed its label; section heads were
   11px and barely distinct from body text; each section sized its own label column, so values
   never lined up down the pane. Sentences go in the workhorse face (numerals stay tabular); the
   mono is kept for what an instrument reads -- the figure tiles, table columns and addresses. */
#detail .kv,#r-result .kv{grid-template-columns:10.5em minmax(0,1fr);gap:7px 16px;margin:2px 0 6px;line-height:1.5}
#detail .kv .k,#r-result .kv .k{color:var(--muted)}
#detail .kv .v,#r-result .kv .v{font-family:var(--sans);font-variant-numeric:tabular-nums;color:var(--ink);overflow-wrap:anywhere}
#detail .kv .v .mono,#r-result .kv .v .mono{font-family:var(--mono)}
#detail h4.grp,#r-result h4.grp{margin:24px 0 10px;padding-bottom:6px;font-size:var(--t-data);font-weight:600;
  color:var(--ink);letter-spacing:0;border-bottom:1px solid var(--line)}
#detail h4:not(.grp),#r-result h4:not(.grp){margin:22px 0 6px;font-size:var(--t-data);font-weight:600;color:var(--ink);letter-spacing:0}
/* a table's explanation is a caption under its title, not a parenthesis inside it */
#detail h4 .muted{display:block;margin-top:2px;font-size:var(--t-micro);font-weight:400;color:var(--muted)}
#detail .snaps,#r-result .snaps{width:100%;border-collapse:collapse}
#detail .snaps th,#r-result .snaps th{font-family:var(--sans);font-size:var(--t-micro);font-weight:500;color:var(--muted);
  text-align:left;padding:5px 6px;border-bottom:1px solid var(--line2);white-space:nowrap}
#detail .snaps th.n,#r-result .snaps th.n{text-align:right}
#detail .snaps td,#r-result .snaps td{padding:6px;border-bottom:1px solid var(--line)}
#detail .snaps tbody tr:last-child td,#r-result .snaps tbody tr:last-child td{border-bottom:0}

/* the header: the address on its own line, then the ways out as a row, not a dotted string */
#detail .sub,#r-result .rhead .sub{margin-bottom:4px}
.dlinks{display:flex;flex-wrap:wrap;align-items:center;gap:4px 16px;font-size:var(--t-micro);margin:0 0 12px}
.dlinks a{color:var(--series);text-decoration:none}
.dlinks a:hover{text-decoration:underline}
.dlinks .report-link{font-weight:600}

/* what the feed could and could not read: a status dot and a plain label, not a row of badges */
.covrow{display:flex;flex-wrap:wrap;gap:6px 16px;margin:0 0 14px;font-size:var(--t-micro);color:var(--ink-2)}
.cov{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.cov i{width:7px;height:7px;border-radius:50%;background:var(--line2);flex:none}
.cov.ok i{background:var(--beats)}
.cov.pending i{background:transparent;box-shadow:inset 0 0 0 1.5px var(--muted)}
.cov.failed i{background:var(--flag)}
.cov .when{color:var(--muted)}

/* the red-flag groups that are not red: a title and its signs as chips, not one run-on line */
.rf-group{margin:10px 0 0}
.rf-group .rf-k{font-size:var(--t-micro);color:var(--muted);margin-bottom:4px}
.rf-group .rf-v{display:flex;flex-wrap:wrap;gap:4px}
.rf-group .rf-v span{font-size:var(--t-micro);color:var(--ink-2);background:var(--tag);border-radius:var(--r-chip);padding:2px 7px}
ul.redflags{padding-left:16px}
ul.redflags li{margin:0 0 4px}

/* research: the loudest posts, account over its reach, the post beside it */
.rposts .who{font-weight:600;white-space:nowrap}
.rposts .who-s{font-size:var(--t-micro);color:var(--muted);white-space:nowrap}
.rposts td:first-child{width:170px;vertical-align:top}
/* the token pane is a 440-560px column: a narrower label keeps the values from wrapping early */
#detail .kv{grid-template-columns:8.5em minmax(0,1fr)}
/* the research verdict chips are words, not data */
#r-result .rflags .tag{font-family:var(--sans);font-size:var(--t-micro);padding:2px 8px}
/* the contract verdict (contract_safety): the tag says it, the list says why */
.safety{margin:0 0 6px}
.safety .tag{font-family:var(--sans);font-size:var(--t-micro);padding:2px 8px}
.safety ul.redflags{margin:8px 0 4px}

/* ---- custom alerts (2026-09-25): the builder, the picker it opens, the list and the inbox -----
   Layout B from the mockup review -- Watch / When these happen / Only if / Send to / Name, each
   its own labeled step -- rather than one run-on sentence: more vertical room, and each part has
   an obvious home on a phone.

   Fix round 1: a bare .step rule was reaching #setup's own .step rows on My desk (a divider
   nobody asked for on an unrelated checklist), because a generic class with no scope leaks the
   moment the site already has one by that name for something else. Every rule below that is not
   already namespaced alerts- or inbox- is scoped under #alerts-panel and/or .inbox-list, the only
   two places this markup renders. */
#alerts-panel{padding:var(--s3) var(--s4)}
.alerts-builder{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);gap:var(--s4)}
@media(max-width:1100px){.alerts-builder{grid-template-columns:1fr}}
.alerts-builder .panel{padding:var(--s4);overflow:visible}
.alerts-builder h4{margin:0 0 var(--s3);font-size:var(--t-body);font-weight:600}
.alerts-builder select,.alerts-builder input[type=text],.alerts-builder input:not([type]){font:inherit;
  font-size:var(--t-micro);color:var(--ink);background:var(--raised);border:1px solid var(--line2);
  border-radius:var(--r-chip);padding:4px 7px}
#alerts-panel .step{border-top:1px solid var(--line);padding:var(--s3) 0}
#alerts-panel .step:first-of-type{border-top:0;padding-top:0}
#alerts-panel .step .k{font-size:var(--t-micro);color:var(--muted);margin-bottom:var(--s2)}
/* a signal or condition already on the rule, with its own remove button */
.chip.sig{border-color:var(--series)}
.chip.cond{border-color:var(--beats)}
.chip .x{background:none;border:0;color:inherit;cursor:pointer;font-size:var(--t-micro);padding:0;margin-left:6px}
.chip.on{background:var(--accent-soft);color:var(--accent);border-color:var(--accent)}
#alerts-panel .add,#alerts-panel .link,.inbox-list .link{background:none;border:0;color:var(--series);
  cursor:pointer;font:inherit;font-size:var(--t-micro);padding:4px 2px}
.link.template{margin-right:var(--s2)}
/* a condition, or a "list" scope's token, being filled in before it is added: a label, a value, Add */
#alerts-panel .ask{display:inline-flex;flex-wrap:wrap;align-items:center;gap:6px;margin:var(--s1) var(--s2) var(--s1) 0}
/* Send to: a checkbox styled as a track-and-thumb switch, the shape used across the mockups */
#alerts-panel .tog{display:inline-flex;align-items:center;gap:6px;margin-right:var(--s4);font-size:var(--t-micro);cursor:pointer}
#alerts-panel .tog input{appearance:none;-webkit-appearance:none;width:26px;height:14px;margin:0;border-radius:7px;
  background:var(--line2);position:relative;cursor:pointer;flex:none}
#alerts-panel .tog input::after{content:"";position:absolute;left:2px;top:2px;width:10px;height:10px;border-radius:50%;background:var(--paper)}
#alerts-panel .tog input:checked{background:var(--beats)}
#alerts-panel .tog input:checked::after{left:auto;right:2px}
#alerts-panel .tog input:disabled{opacity:.6;cursor:not-allowed}
/* the preview panel: what the rule would have caught, not a forecast */
.preview .big{font-family:var(--mono);font-size:var(--t-page);font-weight:600;margin:2px 0}
.preview .too-few{color:var(--flag)}
#alerts-panel .small,.inbox-list .small{font-size:var(--t-micro)}

/* the picker a "+ Add signal"/"+ Add condition" button opens: search, groups, a greyed item with
   the reason it cannot fire on the chosen chain */
.alerts-picker{margin-top:var(--s2);padding:var(--s3);background:var(--raised);border:1px solid var(--line2);
  border-radius:var(--r-panel);max-width:380px}
.alerts-search{width:100%;font:inherit;font-size:var(--t-micro);color:var(--ink);background:var(--field);
  border:1px solid var(--line2);border-radius:var(--r-chip);padding:6px 9px;margin-bottom:var(--s2)}
.alerts-grp{font-size:var(--t-micro);font-weight:600;color:var(--muted);margin:var(--s2) 0 var(--s1)}
.alerts-item{display:flex;justify-content:space-between;align-items:center;gap:var(--s3);width:100%;
  text-align:left;background:none;border:0;border-radius:var(--r-chip);padding:6px var(--s2);
  color:var(--ink);cursor:pointer;font:inherit}
.alerts-item:hover:not(:disabled){background:var(--surface)}
.alerts-item .d{color:var(--muted);font-size:var(--t-micro);margin-top:1px}
.alerts-item.off{opacity:.5;cursor:not-allowed}
.alerts-item .tag{align-self:center;white-space:nowrap}

/* the alerts list, on My desk. Pause all / Resume all sits beside + New alert in the head, not
   buried in the template footer (fix round 1). */
.alerts-head{display:flex;justify-content:space-between;align-items:center;gap:var(--s3);margin-bottom:var(--s2)}
.head-btns{display:flex;align-items:center;gap:var(--s3)}
.alerts-err{color:var(--worse)}
/* flex, not a fixed grid: a rigid 20px/1fr/auto/auto grid at 360px left almost no room for the
   auto (fire count + actions) columns, and the 1fr text column collapsed to single-word-wide
   lines instead of wrapping like a paragraph (fix round 1). Flex-wrap lets the count and the
   actions drop to their own line first, keeping the name and summary readable. */
.alerts-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s1) var(--s3);
  padding:var(--s3) 0;border-top:1px solid var(--line)}
.alerts-row:first-of-type{border-top:0}
.alerts-row input[type=checkbox]{width:15px;height:15px;margin:0;flex:none}
.alerts-row .row-info{flex:1 1 220px;min-width:0}
/* the fire count */
.alerts-row .mono{flex:none}
/* three small text actions (Edit / Duplicate / Delete) rather than a native select that renders
   its own "···" and chevron (fix round 1) */
.row-actions{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;flex:none}

/* the header bell and the inbox it opens. #inbox-bell{display:inline-flex} has id specificity over
   the UA [hidden] rule, so [hidden] needs its own !important rule here -- the same trap documented
   near .helpwrap[hidden] and .tiles[hidden] above, and the reason a visitor was seeing the bell
   (fix round 1). The inbox itself stays the full-width strip under the header (flex:1 0 100% on
   the header's own flex row) rather than an absolutely-positioned dropdown: anchoring it precisely
   under the bell needs a positioned wrapper around the button, which is more coupling than a
   strip needs to earn -- it now just gets the same padding every other panel's content gets. */
#inbox-bell{display:inline-flex;align-items:center;gap:4px}
#inbox-bell[hidden]{display:none!important}
#inbox-bell .dot{display:inline-flex;align-items:center;justify-content:center;min-width:15px;height:15px;
  padding:0 4px;border-radius:8px;background:var(--worse);color:var(--paper);font-size:var(--t-micro);font-weight:600}
#inbox-bell .dot[hidden]{display:none!important}
.inbox-list{flex:1 0 100%;margin-top:var(--s2);max-height:420px;overflow-y:auto;padding:var(--s3) var(--s4)}
/* named .inbox-note, not .note: the site already has a .note class that caps prose at 68ch, and an
   unscoped reuse of that name here is what stopped the unread bar and dividers short of the
   dropdown's own width (fix round 1) */
.inbox-list .inbox-note{padding:var(--s3) 0;border-top:1px solid var(--line)}
.inbox-list .inbox-note:first-of-type{border-top:0}
.inbox-list .inbox-note.unread{border-left:2px solid var(--series);padding-left:var(--s2)}

/* ---- My Desk: Overview (task 4, 2026-09-26) ----------------------------------------------------
   Ported from the approved mockup's own dk- rules (docs/superpowers/specs/2026-09-26-desk-tabs-
   mockups/overview.html), scoped to this tab: the other four tabs get their own dk- classes under
   their own #tab-<view> from later tasks, so nothing here is shared furniture by default. */
/* the no-wallets state is the checklist alone (SWDesk.renderOverview): it needs its own top/bottom
   spacing here since nothing else in the tab supplies it, unlike the Wallets tab's copy, which sits
   in a grid column with its own gap (scoped near #tab-my-wallets below). */
#tab-overview .dk-setup{margin:0 0 var(--s4)}
#tab-overview .dk-hero{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,2fr);gap:var(--s5);
  align-items:end;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-panel);
  padding:var(--s5);margin-bottom:var(--s4)}
#tab-overview .dk-hero .dk-claim{font-size:var(--t-hero);font-weight:600;line-height:1.15;letter-spacing:-.01em}
#tab-overview .dk-hero .dk-sub{color:var(--muted);margin-top:var(--s2);font-size:var(--t-body)}
#tab-overview .dk-nums{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s3) var(--s5)}
/* a hero number is a <button>, not a plain div, so it is reachable and activatable by keyboard */
#tab-overview .dk-num{background:none;border:0;padding:0;margin:0;text-align:left;font:inherit;color:inherit;cursor:pointer}
#tab-overview .dk-num .k{font-size:var(--t-micro);color:var(--muted)}
#tab-overview .dk-num .v{font-family:var(--mono);font-size:var(--t-page);font-weight:500;font-variant-numeric:tabular-nums}
#tab-overview .dk-num .s{font-size:var(--t-micro);color:var(--muted)}
#tab-overview .dk-pos{color:var(--beats)} #tab-overview .dk-neg{color:var(--worse)}
#tab-overview .dk-grid2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s4);margin-top:var(--s4)}
#tab-overview .dk-ph{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s2);
  padding:var(--s3) var(--s4);border-bottom:1px solid var(--line)}
#tab-overview .dk-ph b{font-size:var(--t-body)}
#tab-overview .dk-ph a{color:var(--series);text-decoration:none;font-size:var(--t-micro)}
#tab-overview .dk-pb{padding:var(--s3) var(--s4)}
/* flex-wrap and .dk-what's flex-basis match #tab-activity's own .dk-item rule (final review fix):
   without them, dk-what's flex:1 shrank to fit dk-when+dk-kind+dk-amt on one line, word-wrapping a
   real alert's text across a dozen-plus lines at 360px instead of wrapping the row onto a new one. */
#tab-overview .dk-item{display:flex;flex-wrap:wrap;gap:var(--s1) var(--s3);align-items:baseline;padding:var(--s2) var(--s4);
  border-bottom:1px solid var(--line)}
#tab-overview .dk-item:last-child{border-bottom:0}
/* Needs attention rows open the token (the whole row); Latest activity rows do not -- only the
   .dk-sym link inside them does -- so the pointer cursor and hover fill are opt-in via .click. */
#tab-overview .dk-item.click{cursor:pointer}
#tab-overview .dk-item.click:hover{background:var(--raised)}
#tab-overview .dk-item.click:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
#tab-overview .dk-when{font-family:var(--mono);color:var(--muted);font-size:var(--t-micro);width:44px;flex:none}
#tab-overview .dk-kind{font-size:var(--t-micro);color:var(--muted);width:120px;flex:none}
#tab-overview .dk-what{flex:1 1 260px;min-width:0}
#tab-overview .dk-amt{font-family:var(--mono);font-variant-numeric:tabular-nums}
#tab-overview .dk-sym{font-weight:600;color:var(--ink);text-decoration:none;border-bottom:1px dotted var(--line2)}
#tab-overview .dk-chain{color:var(--muted);font-size:var(--t-micro)}
/* the chart: HTML axis labels beside/under the plot, not <text> inside the SVG's viewBox, so a
   phone does not scale them down along with the chart itself */
#tab-overview .dk-chart{display:flex;gap:var(--s2);height:190px;padding:var(--s2) var(--s4) var(--s3)}
#tab-overview .dk-axis{display:flex;flex-direction:column;justify-content:space-between;
  font-family:var(--mono);font-size:var(--t-micro);color:var(--muted);padding:0}
#tab-overview .dk-plot{flex:1;min-width:0}
/* The global `svg{width:100%;height:auto}` (below) makes the plot size itself from its own width
   via the viewBox's aspect ratio, not from .dk-chart's fixed 190px -- at 1500px wide the plot drew
   ~274px tall, at 360px ~60px, so the axis labels ($max/$0, top/bottom) never lined up with the
   drawn line. This selector is more specific and wins over the global rule: the svg fills its
   flex-stretched 190px parent instead, and preserveAspectRatio="none" (desk.js) stretches the
   already-normalised path to match, so $max sits at the plot's top and $0 at its bottom at every
   width (final review fix). */
#tab-overview .dk-plot svg{height:100%}
#tab-overview .dk-xaxis{display:flex;justify-content:space-between;font-family:var(--mono);
  font-size:var(--t-micro);color:var(--muted);padding:0 var(--s4) var(--s3) 70px}
@media(max-width:900px){
  #tab-overview .dk-hero{grid-template-columns:1fr;padding:var(--s4)}
  #tab-overview .dk-hero .dk-claim{font-size:var(--t-page)}
  #tab-overview .dk-nums{grid-template-columns:repeat(2,minmax(0,1fr))}
  #tab-overview .dk-grid2{grid-template-columns:1fr}
}

/* ---- My Desk: Positions (task 5, 2026-09-26) ---------------------------------------------------
   Ported from the approved mockup's dk- rules (docs/superpowers/specs/2026-09-26-desk-tabs-mockups/
   positions.html), scoped to this tab. The table and the phone cards are both drawn; the width
   decides which shows, and a wide table scrolls inside its own panel, never the page. */
#tab-positions .dk-bar{display:flex;flex-wrap:wrap;gap:var(--s3);align-items:center;margin-bottom:var(--s3)}
#tab-positions .dk-seg{display:inline-flex;border:1px solid var(--line2);border-radius:var(--r-chip);overflow:hidden}
#tab-positions .dk-seg button{font:inherit;font-size:var(--t-data);background:var(--field);color:var(--muted);border:0;
  border-right:1px solid var(--line2);padding:var(--s1) var(--s3);cursor:pointer}
#tab-positions .dk-seg button:last-child{border-right:0}
#tab-positions .dk-seg button[aria-pressed=true]{background:var(--surface);color:var(--ink)}
#tab-positions .dk-seg .dk-c{font-family:var(--mono);font-size:var(--t-micro);color:var(--muted);margin-left:var(--s1)}
#tab-positions .dk-bar input{font:inherit;background:var(--field);border:1px solid var(--line);border-radius:var(--r-chip);
  color:var(--ink);padding:5px 10px;min-width:260px}
#tab-positions .dk-strip{display:flex;flex-wrap:wrap;gap:var(--s5);font-size:var(--t-micro);color:var(--muted);margin-left:auto}
#tab-positions .dk-strip b{font-family:var(--mono);font-size:var(--t-data);color:var(--ink);font-weight:500;margin-left:var(--s1);
  font-variant-numeric:tabular-nums}
#tab-positions .dk-exits{font-size:var(--t-micro);margin:0 0 var(--s3)}
#tab-positions .dk-pos,#tab-positions .dk-strip b.dk-pos{color:var(--beats)}
#tab-positions .dk-neg,#tab-positions .dk-strip b.dk-neg{color:var(--worse)}
#tab-positions .dk-sym{font-weight:600;color:var(--ink);text-decoration:none;border-bottom:1px dotted var(--line2)}
#tab-positions .dk-chain{color:var(--muted);font-size:var(--t-micro)}
#tab-positions .dk-tok .dk-chain a{color:var(--muted)}
#tab-positions .dk-tags .tag{margin:1px 3px 1px 0}
#tab-positions .dk-tags{white-space:normal;max-width:300px}
#tab-positions th{cursor:default}
#tab-positions tr.dk-row{cursor:pointer}
#tab-positions tr.dk-row:hover td{background:var(--raised)}
#tab-positions .dk-card:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
#tab-positions tr.dk-open td{background:var(--raised)}
#tab-positions tr.dk-detail td{background:var(--raised);white-space:normal;padding:var(--s3) var(--s4) var(--s4)}
#tab-positions .dk-det{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);gap:var(--s5)}
#tab-positions .dk-det h5{margin:0 0 var(--s2);font-size:var(--t-micro);color:var(--muted);font-weight:500}
#tab-positions .dk-det h5:not(:first-child){margin-top:var(--s3)}
#tab-positions .dk-det table td,#tab-positions .dk-det table th{background:transparent;position:static}
#tab-positions .dk-warnrow{border-left:2px solid var(--worse);padding:var(--s1) var(--s3);margin-bottom:var(--s2)}
#tab-positions .dk-warnrow.dk-f{border-left-color:var(--flag)}
#tab-positions .dk-cf{display:flex;gap:var(--s3);align-items:baseline;padding:2px 0}
#tab-positions .dk-cf .muted{width:110px;flex:none;font-size:var(--t-micro)}
#tab-positions .dk-cf b{font-family:var(--mono);font-weight:500}
#tab-positions .dk-note{font-size:var(--t-micro);margin-top:var(--s2)}
#tab-positions .dk-acts{display:flex;flex-wrap:wrap;gap:var(--s2);margin-top:var(--s3)}
#tab-positions .dk-cards{display:none}
#tab-positions .dk-card{padding:var(--s3) var(--s4);border-bottom:1px solid var(--line);cursor:pointer}
#tab-positions .dk-card:last-child{border-bottom:0}
#tab-positions .dk-card.dk-open{background:var(--raised)}
#tab-positions .dk-card .dk-l1{display:flex;justify-content:space-between;align-items:baseline;gap:var(--s2)}
#tab-positions .dk-card .dk-l1 > span{min-width:0;overflow-wrap:anywhere}
#tab-positions .dk-card .dk-l2{display:flex;flex-wrap:wrap;gap:var(--s1) var(--s4);font-family:var(--mono);font-size:var(--t-micro);
  color:var(--muted);margin-top:var(--s1)}
#tab-positions .dk-card .dk-l2 b{color:var(--ink);font-weight:500}
#tab-positions .dk-card .dk-l2 b.dk-pos{color:var(--beats)}
#tab-positions .dk-card .dk-l2 b.dk-neg{color:var(--worse)}
#tab-positions .dk-card-det{padding:0 var(--s4) var(--s3);background:var(--raised);border-bottom:1px solid var(--line)}
#tab-positions .dk-tog{font:inherit;font-size:var(--t-micro);background:none;border:0;color:var(--muted);cursor:pointer;
  padding:0 var(--s1) 0 0;margin:0;width:16px;text-align:left}
#tab-positions .dk-tog:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
#tab-positions .dk-paused{font-size:var(--t-micro);margin:0 0 var(--s2)}
#tab-positions .dk-paused[hidden]{display:none}
@media(max-width:900px){
  #tab-positions .dk-tablewrap{display:none}
  #tab-positions .dk-cards{display:block}
  #tab-positions .dk-det{grid-template-columns:1fr}
  #tab-positions .dk-strip{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s1) var(--s4);width:100%;margin-left:0}
  #tab-positions .dk-bar input{min-width:0;flex:1}
}

/* ---- My Desk: Watching (task 6, 2026-09-26) -----------------------------------------------------
   Followed wallets, price targets and My alerts side by side; trades by followed wallets below.
   #alerts-panel is the third grid panel when signed in (it already has its own padding/head rules
   further up this file, from the alerts component itself) and its own full-width panel when signed
   out. Ported from the mockup's dk- rules (watching.html), scoped here as Overview and Positions
   scoped their own -- nothing here is shared furniture by default. */
#tab-watching .dk-grid3{display:grid;grid-template-columns:minmax(0,1.3fr) minmax(0,1fr) minmax(0,1fr);gap:var(--s4)}
#tab-watching .dk-ph{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s2);
  padding:var(--s3) var(--s4);border-bottom:1px solid var(--line)}
#tab-watching .dk-ph b{font-size:var(--t-body)}
#tab-watching .dk-phright{display:flex;gap:var(--s3);align-items:baseline;flex-wrap:wrap}
#tab-watching .dk-pb{padding:var(--s3) var(--s4)}
#tab-watching .dk-item{display:flex;flex-wrap:wrap;gap:var(--s1) var(--s3);align-items:baseline;
  padding:var(--s2) var(--s4);border-bottom:1px solid var(--line)}
#tab-watching .dk-item:last-child{border-bottom:0}
#tab-watching .dk-item.click{cursor:pointer}
#tab-watching .dk-item.click:hover{background:var(--raised)}
#tab-watching .dk-item.click:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
#tab-watching .dk-what{flex:1 1 220px;min-width:0}
#tab-watching .dk-sym{font-weight:600;color:var(--ink);text-decoration:none;border-bottom:1px dotted var(--line2)}
#tab-watching .dk-chain{color:var(--muted);font-size:var(--t-micro)}
/* the follow-wallet row (.dk-inline) and the revealed target form (.dk-form) share the same look;
   only .dk-form is a marker busy() reads, added/removed as the target form opens and closes, so it
   must never sit on the follow row too -- that would make Watching "busy" (and the 60s poll skip
   it) the whole time the tab is open, since the follow row is hidden only for a signed-out reader
   (fix round 1), not on every render. */
#tab-watching .dk-inline,#tab-watching .dk-form{display:flex;flex-wrap:wrap;gap:var(--s2);align-items:center}
#tab-watching .dk-form{margin-top:var(--s2);padding-top:var(--s2);border-top:1px solid var(--line)}
#tab-watching .dk-inline input,#tab-watching .dk-form input,#tab-watching .dk-form select{
  font:inherit;font-size:var(--t-micro);background:var(--field);border:1px solid var(--line2);
  border-radius:var(--r-chip);color:var(--ink);padding:5px 8px}
/* .dk-inline's own display:flex has the same specificity as the UA's [hidden]{display:none} and
   loads after it, so it would otherwise win and keep a hidden follow row on screen (the same trap
   documented near .helpwrap[hidden]/#inbox-bell[hidden] above; fix round 1, the first time this
   row is ever actually hidden). */
#tab-watching .dk-inline[hidden]{display:none!important}
#tab-watching .dk-note{font-size:var(--t-micro)}
/* a trade from before the follow started: history the account's own alert never judged */
#tab-watching .dk-dim{opacity:.55}
/* An open, non-demo alert builder needs its own two columns (the rule, its preview), not a third
   of the grid: the panel spans the row while one is open. :has() does this declaratively; .dk-wide
   is the same rule for a browser without it, kept in step by a MutationObserver (fix round 1). */
#tab-watching .dk-grid3 > .panel:has(.alerts-builder:not(.demo)),
#tab-watching .dk-grid3 > .panel.dk-wide{grid-column:1 / -1}
@media(max-width:900px){#tab-watching .dk-grid3{grid-template-columns:1fr}}

/* ---- My Desk: Activity (task 7, 2026-09-26) -----------------------------------------------------
   One timeline, newest first, grouped by day. The filter chips reuse .chip (the same component the
   Live filters already use, unscoped); everything with a dk- name here is new to this tab and
   scoped to it, as Overview/Positions/Watching scoped their own. */
#tab-activity .dk-bar{display:flex;flex-wrap:wrap;gap:var(--s2) var(--s3);align-items:center;margin-bottom:var(--s3)}
#tab-activity .dk-strip{margin-left:auto}
#tab-activity .dk-day{font-size:var(--t-micro);color:var(--muted);letter-spacing:.01em;
  padding:var(--s2) var(--s4);border-bottom:1px solid var(--line)}
#tab-activity .dk-day:first-child{border-top:0}
#tab-activity .dk-pb{padding:var(--s3) var(--s4)}
#tab-activity .dk-item{display:flex;flex-wrap:wrap;gap:var(--s1) var(--s3);align-items:baseline;
  padding:var(--s2) var(--s4);border-bottom:1px solid var(--line)}
#tab-activity .dk-item:last-child{border-bottom:0}
#tab-activity .dk-when{font-family:var(--mono);color:var(--muted);font-size:var(--t-micro);width:44px;flex:none}
#tab-activity .dk-kind{font-size:var(--t-micro);color:var(--muted);width:120px;flex:none}
#tab-activity .dk-what{flex:1 1 260px;min-width:0}
#tab-activity .dk-amt{font-family:var(--mono);font-variant-numeric:tabular-nums}
/* a sell's realized P&L is coloured the same way Overview colours it (renderItem applies plClass
   to both); this tab never defined the colour itself, so a real gain or loss read in plain ink. */
#tab-activity .dk-pos{color:var(--beats)} #tab-activity .dk-neg{color:var(--worse)}
#tab-activity .dk-sym{font-weight:600;color:var(--ink);text-decoration:none;border-bottom:1px dotted var(--line2)}
#tab-activity .dk-chain{color:var(--muted);font-size:var(--t-micro)}
#tab-activity .dk-what .tag.c{margin-left:var(--s2)}
/* Mark all read's own failure line (fix round 1): short, beside the button, and only ever a verdict
   -- var(--worse), the colour this stylesheet reserves for "lost to it", not a generic accent. */
#tab-activity .dk-mark-err{font-size:var(--t-micro);color:var(--worse)}
#tab-activity .dk-mark-err:empty{display:none}
#tab-activity .dk-more{display:block;margin:var(--s3) var(--s4)}
#tab-watching .dk-more{display:block;margin:var(--s3) var(--s4)}
@media(max-width:700px){#tab-activity .dk-strip{margin-left:0;width:100%}}

/* ---- My Desk: Wallets (task 8, 2026-09-26) -------------------------------------------------------
   Your wallets (add, remove), the signed-in line, Telegram and Setup. Setup (.dk-setup) is the
   shared component scoped above, not here -- only its placement in this tab's right-hand column is
   set here, via the same margin approach Overview's copy uses at the top of its own tab. */
#tab-my-wallets .dk-grid2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s4)}
#tab-my-wallets .dk-ph{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s2);
  padding:var(--s3) var(--s4);border-bottom:1px solid var(--line)}
#tab-my-wallets .dk-ph b{font-size:var(--t-body)}
#tab-my-wallets .dk-pb{padding:var(--s3) var(--s4)}
#tab-my-wallets .dk-item{display:flex;flex-wrap:wrap;gap:var(--s1) var(--s3);align-items:baseline;
  padding:var(--s2) var(--s4);border-bottom:1px solid var(--line)}
#tab-my-wallets .dk-item:last-child{border-bottom:0}
#tab-my-wallets .dk-what{flex:1 1 220px;min-width:0}
/* the add-wallet bar is always on screen (no open/closed state), so it is .dk-inline and not
   .dk-form -- .dk-form is the marker busy() reads to leave an *opened* form alone across the 60s
   poll (see #tab-watching above); a permanently-present .dk-form here would make this whole tab
   permanently "busy" and never refresh (deviation from the mockup's own class name, task 8). */
#tab-my-wallets .dk-inline{display:flex;flex-wrap:wrap;gap:var(--s2);align-items:center;
  border-bottom:1px solid var(--line)}
#tab-my-wallets .dk-inline input{font:inherit;font-size:var(--t-micro);background:var(--field);
  border:1px solid var(--line2);border-radius:var(--r-chip);color:var(--ink);padding:5px 8px}
#tab-my-wallets .dk-note{font-size:var(--t-micro)}
#tab-my-wallets .dk-setup{margin-top:var(--s4)}
@media(max-width:900px){#tab-my-wallets .dk-grid2{grid-template-columns:1fr}}

/* ---- Networks: the replay and the constellation ring (task 12, deploy/ui/replay.js,
   deploy/ui/constellation.js). Role fills read the tokens above; a stop or arc nothing was
   measured for is dashed and dimmed rather than drawn the same way as a counted one. -----------*/
.replay{display:flex;flex-direction:column;gap:var(--s2)}
.replay-svg{display:block;width:100%;height:auto;background:var(--field);border:1px solid var(--line);border-radius:var(--r-panel)}
/* fix round 1: one band per lane, its swatch and its word at the left edge; the playhead marks the moment */
.replay-band{fill:transparent}
.replay-lane.odd .replay-band{fill:var(--surface);opacity:.55}
.replay-lane-label{fill:var(--ink-2);font-family:var(--sans)}
.replay-playhead{stroke:var(--line2);stroke-width:1;stroke-dasharray:3 3}
.replay-tick{stroke:var(--line2);stroke-width:1}
.replay-tick-label{fill:var(--muted);font-family:var(--sans)}
/* fix round 2 (C1): a lane past its rows keeps every wallet at its true time; overlapping dots are
   translucent, so a burst reads darker where it is denser */
.replay-dots circle.dense{fill-opacity:.35;stroke:none}
.replay-dense-note,.replay-count-note{font-size:var(--t-micro);color:var(--muted)}
.replay-caption{font-size:var(--t-data);min-height:1.4em}
.replay-slider{width:100%}
.replay-steps{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px;font-size:var(--t-micro);color:var(--muted)}
.replay-steps li{padding:2px 0}
.replay-steps li.current{color:var(--ink);font-weight:500}
.wallet-dot circle,.replay-dots a circle{stroke:var(--paper);stroke-width:.5}
.replay-dots a{cursor:pointer}

.constellation{display:flex;flex-direction:column;gap:var(--s2)}
.constellation-svg{width:100%;height:auto}
.constellation-note{margin-top:var(--s1)}
.ring-arc{fill:none;stroke:var(--line2);stroke-width:1.5}
.ring-arc.not-traced{stroke:var(--role-untraced);opacity:.5}
.ring-stop circle{fill:var(--surface);stroke:var(--ink-2);stroke-width:1.5}
.ring-stop.not-traced circle{fill:none;stroke:var(--role-untraced);opacity:.6}
.ring-dots circle{stroke:none}
/* fix round 1: every stop carries its word outside the ring, so the ring reads without a legend */
.ring-label{fill:var(--ink-2);font-family:var(--sans)}
.ring-label .nt{fill:var(--muted);font-style:italic}
.ring-label .cnt{fill:var(--ink);font-family:var(--mono)}

.role-disperser{fill:var(--role-disperser)}
.role-deployer{fill:var(--role-deployer)}
.role-farm{fill:var(--role-farm)}
.role-collector{fill:var(--role-collector)}
.role-sniper{fill:var(--role-sniper)}
.role-operator_contract{fill:var(--role-operator)}
.role-payout{fill:var(--role-operator)}
.role-outside{fill:var(--role-outside)}
.role-untraced,.role-unchecked{fill:var(--role-untraced)}

/* Cabals, the top (task 13): the replay's steps read as a numbered list there, and one card per
   network. Cards stack to one column on a phone; min-width:0 keeps a long figure from widening the
   page past 360 px. */
#net-replay .replay-steps{list-style:decimal;padding-left:1.5em}
.netcards{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));gap:var(--s3);margin-top:var(--s3)}
.netcard{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-panel);padding:var(--s3);min-width:0}
.netcard h3{margin:0 0 var(--s2);font-size:var(--t-body)}
.netcard .net-ring{max-width:320px;margin:0 auto var(--s2)}
.netcard .tiles{grid-template-columns:repeat(2,minmax(0,1fr));margin-bottom:0}
.netcard .tile{min-width:0;overflow-wrap:anywhere}
.netcard .tile .v{font-size:var(--t-section)}
.netcard .cabnote{margin-top:var(--s2)}
/* who was on the other side (R37): one bar, five legs (Task 14); wallets never checked are their own segment,
   hatched so they never read as either side */
.netside{margin-top:var(--s3)}
.netside-h{font-size:var(--t-micro);color:var(--muted);margin-bottom:var(--s1)}
.netbar{display:flex;height:12px;border:1px solid var(--line);border-radius:3px;overflow:hidden;background:var(--field)}
.netbar span{display:block;height:100%}
.netside-legend{list-style:none;margin:var(--s1) 0 0;padding:0;display:flex;flex-wrap:wrap;gap:4px 14px;font-size:var(--t-micro);color:var(--ink-2)}
.netside-legend .sw{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:5px;vertical-align:-1px}
.os-net{background:var(--role-farm)}
.os-out{background:var(--role-outside)}
.os-unchecked{background:repeating-linear-gradient(45deg,var(--role-untraced) 0 3px,transparent 3px 6px)}
/* Task 14: the operator's own buys, and swaps no wallet could be read for (hatched the other way: unknown) */
.os-op{background:var(--role-operator)}
.os-unattr{background:repeating-linear-gradient(-45deg,var(--role-outside) 0 3px,transparent 3px 6px)}

/* Cabals, the explainer ("How a cabal works, and how we find one"): one section for every visitor,
   folded behind "How it works" once a real network is served. The fleet schematic is drawn twice, across
   for a wide screen and down for a phone (the wide one's text would scale to a few pixels there). */
details.cabx>summary{cursor:pointer;list-style:none}
details.cabx>summary::-webkit-details-marker{display:none}
details.cabx>summary h2{display:flex;align-items:baseline;gap:12px;margin:0;font-size:var(--t-section);font-weight:600;flex-wrap:wrap}
details.cabx>summary .cabx-toggle{font-family:var(--mono);font-size:var(--t-micro);font-weight:400;color:var(--series);margin-left:auto}
details.cabx>summary .cabx-toggle::before{content:'\25B8 '}
details.cabx[open]>summary .cabx-toggle::before{content:'\25BE '}
details.cabx[open]>summary{margin-bottom:var(--s2)}
.cabx-h{font-size:var(--t-body);font-weight:600;margin:var(--s5) 0 0}
.cabx-fig{margin:var(--s3) 0 0;min-width:0}
.cabx-cap{font-size:var(--t-micro);color:var(--muted);margin-top:var(--s1);font-style:italic}
.cabx-flow{display:block;color:var(--ink);max-width:100%}
.cabx-flow-narrow{display:none;max-width:360px;margin:0 auto}
@media(max-width:640px){.cabx-flow-wide{display:none}.cabx-flow-narrow{display:block}}
.cabx-ink{fill:var(--series);fill-opacity:.85}
.cabx-flag{fill:var(--flag);fill-opacity:.9}
.legend .sw.cabx-sw-ink{background:var(--series)}
.legend .sw.cabx-sw-flag{background:var(--flag)}
.legend .sw.cabx-sw-disperser{background:var(--role-disperser)}
.legend .sw.cabx-sw-deployer{background:var(--role-deployer)}
.legend .sw.cabx-sw-farm{background:var(--role-farm)}
.legend .sw.cabx-sw-collector{background:var(--role-collector)}
.legend .sw.cabx-sw-operator{background:var(--role-operator)}
#cabx-ring{max-width:420px;margin:0 auto}
#cabx-replay .replay-steps{list-style:decimal;padding-left:1.5em}
.cabx-steps{margin:var(--s3) 0 0;padding-left:1.5em;max-width:76ch;font-size:var(--t-body);line-height:1.62;color:var(--muted)}
.cabx-steps li{margin:0 0 var(--s2)}
.cabx-steps b{color:var(--ink);font-weight:600}
/* The Proof page's early edge study: prose above and below the finalists' table */
#early-panel{margin-top:12px}
#early-panel .ev-text{margin:0;padding:8px 10px 0;max-width:96ch;font-size:var(--t-data);line-height:1.55;color:var(--muted)}
#early-panel .ev-text p{margin:0 0 8px}
#early-panel #ev-summary{color:var(--ink);padding-bottom:4px}
#early-panel .ev-how{padding-top:0}
#early-panel .ev-how>summary{padding:2px 0 8px}
#early-panel .ev-how[hidden]{display:none}
#early-panel .ev-legend{display:grid;grid-template-columns:max-content 1fr;gap:4px 12px;padding:10px 10px 12px}
#early-panel .ev-legend dt{color:var(--ink);font-weight:600}
#early-panel .ev-legend dd{margin:0}
#early-panel td.ev-rule{white-space:normal;min-width:220px;max-width:360px;color:var(--ink)}
#early-panel td.ev-int{white-space:normal;min-width:150px}
#early-panel td.ev-st{white-space:normal;min-width:130px}
#early-panel #evtbl th{white-space:normal;vertical-align:bottom}
#early-panel tr.ev-main td{border-bottom:0;padding-top:10px}
#early-panel tr.ev-notes td{white-space:normal;color:var(--muted);font-size:var(--t-micro);line-height:1.5;padding:2px 10px 10px}
#early-panel tr.ev-notes div{max-width:110ch}
@media (max-width:480px){
  #early-panel .ev-legend{grid-template-columns:1fr;gap:0}
  #early-panel .ev-legend dd{margin-bottom:6px}
  #evtbl thead{display:none}
  #evtbl,#evtbl tbody,#evtbl tr,#evtbl td{display:block;width:auto;max-width:none;min-width:0}
  #evtbl tr.ev-main{border-top:1px solid var(--line)}
  #evtbl tr.ev-main td{display:flex;justify-content:space-between;gap:12px;white-space:normal;text-align:right;padding:2px 10px}
  #evtbl tr.ev-main td.ev-rule{display:block;text-align:left;padding-top:10px;padding-bottom:4px}
  #evtbl tr.ev-main td:not(.ev-rule)::before{content:attr(data-l);color:var(--muted);text-align:left}
}

/* "The read": checked answers per area (insights.js). Hidden until the API answers. */
.sw-read{border:1px solid var(--line);border-radius:6px;background:var(--surface);padding:10px 12px;margin-bottom:12px;max-width:100%;min-width:0}
.sw-read[hidden]{display:none}
.read-head{font-size:var(--t-body);font-weight:600;color:var(--ink);margin-bottom:6px;display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px}
.read-asof{font-size:var(--t-micro);font-weight:400;color:var(--muted)}
.read-q{margin:8px 0 2px;font-size:13px}
.read-claim{margin:4px 0;line-height:1.45}
.read-badge{display:inline-block;font-size:var(--t-micro);padding:1px 6px;border-radius:3px;background:var(--tag);color:var(--tag-ink)}
.read-none,.read-fine,.read-meta{font-size:var(--t-micro);color:var(--muted);margin:6px 0 0}
.read-sets{overflow-x:auto;max-width:100%}
.read-sets table{font-size:var(--t-micro);border-collapse:collapse}
.read-sets th,.read-sets td{padding:2px 8px;text-align:left;white-space:nowrap}
.read-private{margin-top:8px;border-top:1px dashed var(--line2);padding-top:6px;font-size:var(--t-micro);color:var(--muted)}
.read-private li{margin:2px 0;overflow-wrap:anywhere}
@media (max-width:640px){.sw-read .read-item~.read-item{display:none}}
