/* App styling for the tx workbench. Light theme only.

   css/brand.css loads first and owns the two sticky chrome strips and the palette. This file
   reads those tokens and never redeclares one, because brand.css styles itself with the same
   names: redefining --line or --ink here would repaint the shared chrome and this subdomain
   would stop matching the rest of the family. App-only aliases are declared under their own
   names below.

   Every rule assumes text wraps. There is no ellipsis, no line-clamp and no nowrap on any
   content class. The only nowrap in the file is on navigation chrome and on the status bar,
   both of which are labels rather than data. */

:root{
  /* App aliases over the brand palette. --panel is the card fill, the page sits on --bg2. */
  --panel:#ffffff;
  --dim:var(--ink2);
  /* --soft carries table headers, stat captions, card titles and hints, and every one of them
     is set below 18.66px, so it needs 4.5:1. #5a6779 is 5.75:1 on white and 5.54:1 on the
     #f8fafc header fill. The QA round that found the old #8a8a93 at 3.42:1 is not reopened
     here: this value is darker than the #6b6b74 that replaced it. */
  --soft:#5a6779;
  --acc:var(--accent-ink);
  --acc2:var(--accent);

  /* Severity stays semantic, and is the one place outside the brand palette. Each ink is
     checked against its own fill at the size it is used at (10px pills, 12.5px note bodies):
     critical 8.9:1, high 7.3:1, medium 8.6:1, low 6.5:1, ok 7.4:1. */
  --crit:#991b1b; --critbg:#fee2e2; --critline:#fca5a5;
  --high:#9a3412; --highbg:#ffedd5; --highline:#fdba74;
  --med:#1e40af;  --medbg:#dbeafe;  --medline:#bfdbfe;
  --low:#4d7c0f;  --lowbg:#ecfccb;  --lowline:#d9f99d;
  --ok:#166534;   --okbg:#dcfce7;   --okline:#bbf7d0;

  --gut:14px;
  /* The bar is sized from the subject control rather than the other way round: 38px of field
     plus 10px of clearance top and bottom, which is what the focus ring needs to be drawn
     whole inside the bar instead of overlapping the nav strip above it. */
  --subject-h:38px;
  --toolbar-h:58px;
  --status-h:28px;
  --rail-w:200px;
  --rail-w-icon:58px;
}

*{box-sizing:border-box}
html{overflow-x:clip;height:100%}

/* The shell fills the viewport and does not scroll. The two brand strips and the toolbar are
   flex items above a frame that takes the remaining height, so they stay on screen at every
   width without depending on sticky positioning surviving an ancestor's overflow. */
body{
  margin:0;height:100dvh;min-height:100vh;display:flex;flex-direction:column;overflow:hidden;
  background:var(--bg2);color:var(--ink);
  font-family:var(--font);
  -webkit-font-smoothing:antialiased;font-size:13px;line-height:1.5;
  overflow-wrap:anywhere;
}
body>.site-brand,body>.site-nav{flex:0 0 auto}
/* An absolutely positioned box with no positioned ancestor (a screen-reader caption on a chart)
   takes the initial containing block, which body's overflow:hidden does not clip. One such
   caption deep in the Monitor workspace made the document itself 1,900px tall at 360px, so a
   swipe on the toolbar scrolled the window and carried both pinned strips off screen. Positioning
   body and the workspace keeps every such box inside a clip that already exists. */
body{position:relative}

/* Shared-chrome parity with the other web3wagmi properties.

   css/brand.css is canonical and stays unedited, so the two values it leaves to the host page
   are supplied here. Atlas gives `.site-brand` the same 36px height as its inner element below
   640px, which puts the 1px bottom border inside the border box: without it the strip measures
   37px here, the chrome totals 74px against 73px everywhere else, and `.site-nav`, pinned at
   `top: var(--brand-h)`, sits one row above where the strip actually ends. Atlas also sets its
   body line-height to 1.55, which is what the nav link inherits there; app.css runs at 1.5, so
   the link box came out 0.6px shorter and carried the amber active underline up with it.
   Both declarations belong in brand.css whenever that shared file is next revised. */
.site-nav-link{line-height:1.55}
@media(max-width:640px){
  .site-brand{height:var(--brand-h)}
}
code,.mono,.code,kbd{font-family:var(--mono)}
a{color:var(--accent-ink)}
a:hover{color:#92400e}
h2,h3,h4{letter-spacing:-.01em;font-family:var(--display)}

.app{flex:1 1 auto;display:flex;flex-direction:column;min-height:0}

/* ---------- toolbar: subject, chain, primary action, live status ---------- */

.toolbar{
  flex:0 0 auto;height:var(--toolbar-h);
  display:flex;align-items:center;gap:8px;padding:0 var(--gut);
  background:var(--panel);border-bottom:1px solid var(--line);
  position:sticky;top:var(--chrome-h);z-index:30;
}
/* Property identity. The shared lockup above says web3wagmi and the nav says Tools, so the
   toolbar is where this particular tool names itself. Kept to one badge rather than a masthead,
   because a masthead is the brochure habit this layout exists to drop. */
.tb-app{display:flex;align-items:baseline;gap:8px;padding-right:12px;margin-right:2px;
  border-right:1px solid var(--line);flex:0 0 auto;min-width:0}
.tb-app-name{font-family:var(--display);font-size:16px;white-space:normal;font-weight:800;letter-spacing:-.3px;
  color:var(--ink);line-height:1}
.tb-app-name::before{content:"";display:inline-block;width:5px;height:5px;border-radius:50%;
  background:var(--accent);margin-right:6px;vertical-align:middle}
.tb-app-desc{font-size:11px;color:var(--ink3);white-space:normal;overflow-wrap:anywhere}
@media (max-width:1100px){.tb-app-desc{display:none}}
/* On a phone the toolbar wraps, and the badge shares its row with whatever wraps up beside it.
   It must be allowed to shrink, or it pushes that row past the viewport and the whole page
   scrolls sideways, which also drags the pinned brand strips out of view. */
@media (max-width:700px){
  .tb-app{padding-right:9px;min-width:0}
  .tb-app-name{overflow-wrap:anywhere}
}
.tb-field{display:flex;align-items:center;gap:7px;flex:1 1 360px;min-width:0}
.tb-field.tb-chain{flex:0 1 210px}
.tb-lbl{
  flex:0 0 auto;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.09em;
  color:var(--soft);white-space:nowrap;
}
.tb-in{
  font:inherit;width:100%;min-width:0;height:32px;padding:0 9px;
  border:1px solid var(--line);border-radius:6px;background:var(--panel);color:var(--ink);
}
.tb-in.mono{font-family:var(--mono);font-size:12.5px}
.tb-in::placeholder{color:var(--soft);opacity:1}
select.tb-in{height:34px;padding:0 6px}

/* ---------- the subject control ----------

   Every panel in the workspace is computed from whatever sits in this one field, so it is
   drawn as the heaviest control on the page: a 2px border against the 1px the chain select
   carries, a 13px mono value, and the primary action joined to it inside the same group.

   The three states are read off the value through :placeholder-shown, so nothing has to keep
   a class in sync with what was typed and a deep link that fills the field on boot lands in
   the filled state with no extra call.

   Every selector below carries two classes. The generic form rules further down this file
   reach this field through `input[type=text]` and `.tb-in.mono`, both of which outrank a
   single class and both of which are written later, so a one-class rule here lost its border
   width, its padding, its radius and its font size to them without saying so.

     empty    amber-tinted fill under a dark amber border, the one thing on the bar asking to
              be filled in
     filled   white fill under a near-black border, a control holding a value
     focus    the same dark amber border inside a 3px ring of the same ink, with the brand
              amber drawn as a hairline and an outer glow

   Contrast, measured against the colour each state actually paints beside:
     empty    border #b45309 on its own #fef6e7 fill 4.67:1, on the white bar 5.02:1
              placeholder #5a6779 on #fef6e7 5.35:1
     filled   border #0f172a on white 17.85:1 both sides, value #0f172a on white 17.85:1
     focus    ring #b45309 on the white bar 5.02:1 and on the white fill 5.02:1
     label    #b45309 on the white bar 5.02:1, and the keycap beside it the same
     Load     #ffffff on #b45309 5.02:1, and on the #92400e hover 7.09:1
   Brand amber #f59e0b reads 2.15:1 on white, so it never carries a boundary on its own. It is
   the hairline and the glow inside a ring that #b45309 draws, and removing it would leave
   every state still legible. */

.tb-subject{flex:1 1 440px;gap:9px}
.tb-lbl-subject{
  display:inline-flex;align-items:center;gap:5px;color:var(--acc);font-weight:800;
}
/* The shortcut, drawn as a keycap so it is never read as part of the field's value. The border
   is the same #b45309 as the glyph, 5.02:1 on the white bar, which makes the keycap outline a
   legible shape in its own right. The amber tint it started at measured 1.57:1. */
.tb-key{
  font-size:9.5px;line-height:13px;padding:0 4px;border-radius:3px;
  border:1px solid var(--acc);border-bottom-width:2px;background:var(--accent-tint);color:var(--acc);
}
.tb-in.tb-in-subject{
  flex:1 1 auto;min-width:0;
  height:var(--subject-h);
  /* 13px JetBrains Mono advances 0.6em, so 42 characters measure 327.6px and the field is
     sized from that figure at every breakpoint. The value is never shrunk to fit and is never
     clipped by a rule in this file: a text input that runs out of room scrolls its own value,
     which leaves the whole address present, selectable and copyable. */
  font-family:var(--mono);font-size:13px;font-weight:500;
  padding:0 11px;border-width:2px;border-radius:7px;
}
/* Empty. The amber wash is the invitation, and it is the only washed control on the bar. */
.tb-in.tb-in-subject:placeholder-shown{
  background:var(--accent-tint);border-color:var(--acc);
}
.tb-in.tb-in-subject::placeholder{color:var(--soft);font-weight:400}
/* Filled. White under near-black reads as a control that is holding something. */
.tb-in.tb-in-subject:not(:placeholder-shown){
  background:var(--panel);border-color:var(--ink);color:var(--ink);
}
/* Focus, in both states. The ring that carries the contrast is the 3px #b45309 outline: it
   clears 3:1 against the white bar outside it and against the white fill inside it, and
   forced-colors mode repaints an outline in a system colour, so the ring survives there. The
   two box-shadow bands are the brand amber, a hairline in the outline's offset gap and a soft
   glow outside it. Forced-colors drops a box-shadow, which costs the state nothing. */
.tb-in.tb-in-subject:focus,
.tb-in.tb-in-subject:focus-visible{
  background:var(--panel);border-color:var(--acc);
  outline:3px solid var(--acc);outline-offset:2px;
  box-shadow:0 0 0 2px var(--accent),0 0 0 8px rgba(245,158,11,.30);
}
/* The action the field hands off to, joined to it and sized to match. Two classes again,
   because .btn and .btn-primary are written later in this file. */
.btn.btn-load{
  flex:0 0 auto;height:var(--subject-h);padding:0 18px;
  font-size:13px;font-weight:800;letter-spacing:.01em;border-radius:7px;
}

/* The live status chip. Tone is set by app.js and never reads as a verdict on the subject:
   it describes what the workbench is doing. */
.chip{
  flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;min-width:0;
  font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.04em;
  text-transform:uppercase;padding:4px 8px;border-radius:5px;border:1px solid transparent;
  overflow-wrap:anywhere;
}
.chip-neutral{background:var(--line2);color:var(--dim);border-color:var(--line)}
.chip-busy{background:var(--accent-tint);color:var(--accent-ink);border-color:#fcd9a0}
.chip-ok{background:var(--okbg);color:var(--ok);border-color:var(--okline)}
/* A settled chip repeats the rail. It shows only while something is loading or has failed. */
.chip-ok,.chip-neutral{display:none}
.chip-warn{background:var(--highbg);color:var(--high);border-color:var(--highline)}
.chip-bad{background:var(--critbg);color:var(--crit);border-color:var(--critline)}

/* ---------- frame: rail plus workspace ---------- */

.frame{flex:1 1 auto;display:flex;min-height:0;min-width:0}

.rail{
  flex:0 0 var(--rail-w);display:flex;flex-direction:column;gap:2px;
  padding:8px 6px;background:var(--panel);border-right:1px solid var(--line);
  overflow-y:auto;overflow-x:hidden;
}
.rail-btn{
  font:inherit;cursor:pointer;text-align:left;width:100%;
  display:flex;align-items:center;gap:9px;
  background:none;border:1px solid transparent;border-radius:7px;padding:8px 9px;
  color:var(--dim);font-weight:600;font-size:13px;
}
.rail-btn:hover{background:var(--bg2);color:var(--ink)}
.rail-btn[aria-current="page"]{background:var(--accent-tint);color:var(--accent-ink);border-color:#fcd9a0}
.rail-ico{flex:0 0 18px;display:inline-flex;align-items:center;justify-content:center;position:relative}
.rail-ico svg{display:block;width:18px;height:18px}
.rail-lbl{flex:1 1 auto;min-width:0}
/* The count is data about the tab, so it is mono and it is never hidden. A tab with no count
   to report renders no badge at all, which reads differently from a badge showing zero. */
.rail-n{
  flex:0 0 auto;font-family:var(--mono);font-size:10.5px;font-weight:700;
  padding:1px 5px;border-radius:999px;background:var(--line2);color:var(--dim);
}
.rail-n.has{background:var(--critbg);color:var(--crit)}
.rail-btn[aria-current="page"] .rail-n{background:#fff;color:var(--accent-ink)}
/* Drawn as a keycap so the shortcut digit is never read as the tab's live count. */
.rail-key{
  flex:0 0 auto;font-family:var(--mono);font-size:10px;font-weight:700;color:var(--soft);
  border:1px solid var(--line);border-bottom-width:2px;border-radius:4px;
  padding:0 4px;line-height:14px;background:var(--bg2);
}

.workspace{flex:1 1 auto;min-width:0;min-height:0;overflow:auto;overscroll-behavior:contain;position:relative}
/* The subject identity and any screening-list failure stay on screen while the workspace
   scrolls under them, because both are statements about what was and was not screened. The
   cap keeps a long failure note from eating the workspace on a phone, and the note scrolls
   inside it rather than being cut short. */
.ws-head{position:sticky;top:0;z-index:5;background:var(--bg2);padding:10px var(--gut) 0;max-height:45vh;overflow:auto;display:flex;flex-direction:column;gap:8px}
.ws-head>div:empty{display:none}
.ws-body{padding:10px var(--gut) 28px;min-width:0}

/* ---------- status bar ---------- */

.statusbar{
  flex:0 0 var(--status-h);height:var(--status-h);
  display:flex;align-items:center;gap:7px;padding:0 var(--gut);
  background:var(--panel);border-top:1px solid var(--line);
  font-size:11px;color:var(--dim);
}
/* The three entries scroll inside their own region and the two actions sit outside it, so both
   buttons stay on screen at every width. Scrolling the whole bar pushed Copy link and Shortcuts
   past the right edge at 390px, and a phone has no keyboard to reach `c` or `?` instead, which
   left the shortcut sheet with no way in at all. The bar itself clips nothing, so the focus
   ring on either button is drawn whole rather than cut off by a 28px scroll container. */
.sb-line{
  flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:7px;
  overflow-x:auto;overflow-y:hidden;
}
/* Status-bar entries are one-line chrome labels. The figures they name are also written out
   in full inside the workspace, so nothing readable only here can be cut off here. */
.sb-item{white-space:nowrap;flex:0 0 auto}
.sb-sep{color:var(--soft);opacity:.5;flex:0 0 auto}
.sb-btn{
  font:inherit;font-size:11px;cursor:pointer;flex:0 0 auto;white-space:nowrap;
  background:none;border:1px solid var(--line);border-radius:5px;padding:2px 7px;color:var(--dim);
  display:inline-flex;align-items:center;gap:5px;
}
.sb-btn:hover{border-color:var(--accent);color:var(--ink)}
kbd{
  font-size:10px;line-height:14px;padding:0 4px;border-radius:3px;
  border:1px solid var(--line);background:var(--bg2);color:var(--soft);
}

/* ---------- shortcut sheet ---------- */

.sheet{
  border:1px solid var(--line);border-radius:12px;padding:16px 18px;
  max-width:min(460px,calc(100vw - 32px));background:var(--panel);color:var(--ink);
  box-shadow:var(--shadow);font-family:var(--font);
}
.sheet::backdrop{background:rgba(15,23,42,.32)}
.sheet-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
.sheet-head h2{margin:0;font-size:15px}
.sheet-keys{display:grid;grid-template-columns:auto 1fr;gap:7px 14px;margin:14px 0 0;font-size:12.5px}
.sheet-keys dt{margin:0}
.sheet-keys dd{margin:0;color:var(--dim)}
.sheet-foot{font-size:11.5px;color:var(--soft);margin:14px 0 0;line-height:1.5}

/* ---------- forms and buttons ---------- */

label.lbl,.lbl{display:block;font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:var(--soft);font-weight:700;margin-bottom:3px}
input.in,select.in,textarea.in,input[type=text],input[type=number],select,textarea{
  font:inherit;border:1px solid var(--line);border-radius:6px;padding:6px 9px;width:100%;
  background:var(--panel);color:var(--ink);min-width:0;
}
input.in.mono,input.addr{font-family:var(--mono);font-size:12.5px}
.in-short{max-width:140px}
/* #f59e0b reads 2.15:1 on white and cannot carry a focus ring on its own, so every field in
   the app rings in #b45309, which is 5.02:1 on white and 4.80:1 on the #f8fafc page fill. */
input:focus,select:focus,textarea:focus{outline:2px solid var(--acc);outline-offset:1px;border-color:var(--acc)}
textarea{min-height:110px;line-height:1.55;resize:vertical}

.btn{font:inherit;font-size:12.5px;cursor:pointer;border-radius:6px;border:1px solid var(--line);background:var(--panel);padding:6px 11px;color:var(--ink)}
.btn:hover{border-color:var(--accent)}
.btn[disabled]{opacity:.5;cursor:default;border-color:var(--line)}
/* White on #b45309 is 4.83:1, which clears AA at this size. #f59e0b behind white would be
   2.1:1, so the accent fill is the darker amber and the plain accent stays on borders. */
/* Primary actions are solid black with white text: the strongest contrast on the light surface,
   and it keeps amber for state (the active tab, focus, toggles) so the two never compete. */
.btn-primary{background:#0c0a09;color:#fff;border-color:#0c0a09;font-weight:700}
.btn-primary:hover{background:#292524;border-color:#292524}
.btn-primary:disabled{background:#a8a29e;border-color:#a8a29e;color:#fff}
.btn-quiet{background:var(--bg2);color:var(--dim)}
.btn.sm{padding:4px 8px;font-size:11.5px}
/* The ring sits outside the button so it does not depend on the button's own fill. */
.btn:focus-visible,button:focus-visible,.sb-btn:focus-visible,a:focus-visible{outline:2px solid var(--accent-ink);outline-offset:2px}
.rail-btn:focus-visible{outline:2px solid var(--accent-ink);outline-offset:-2px}
/* The bar is 28px and the button is 22.5px, so a ring offset outwards runs past the viewport
   edge at the bottom of the screen. Drawn just inside the button, the way the rail draws its
   own, the whole ring stays visible. */
.sb-btn:focus-visible{outline-offset:-1px}

/* ---------- tab body ---------- */

.tabroot{min-width:0}
.tab{display:flex;flex-direction:column;gap:12px;min-width:0}

.card{background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:11px 12px;min-width:0}
.card>h3{font-size:10.5px;text-transform:uppercase;letter-spacing:.08em;color:var(--soft);margin:0 0 8px;font-weight:700;font-family:var(--font)}
.card>h4{font-size:11.5px;margin:11px 0 6px;color:var(--dim);font-weight:700;font-family:var(--font)}
.card>h4:first-of-type{margin-top:2px}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:start}
@media(max-width:900px){.grid2{grid-template-columns:1fr}}
/* Monitor stacks its two columns under 900px. The subject, its alerts and the benchmark come
   first there, because the answer belongs above the controls that tune it. */
@media(max-width:900px){.mon-grid>.stack:last-child{order:-1}}
.row{display:flex;gap:8px;flex-wrap:wrap;align-items:center;min-width:0}
.row.form{align-items:flex-end}
.stack{display:flex;flex-direction:column;gap:10px;min-width:0}
.hint{font-size:11.5px;color:var(--soft);margin:3px 0 0}
.meta{font-size:11.5px;color:var(--dim);min-width:0}
.out{display:flex;flex-direction:column;gap:12px;min-width:0}

/* ---------- panel, the standard framed block ---------- */

.panel{background:var(--panel);border:1px solid var(--line);border-radius:9px;min-width:0}
.panel-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 12px;border-bottom:1px solid var(--line2);min-width:0}
.panel-title{font-size:10.5px;text-transform:uppercase;letter-spacing:.08em;color:var(--soft);font-weight:700;flex:1 1 auto;min-width:0}
.panel-actions{display:flex;gap:6px;flex-wrap:wrap;flex:0 0 auto}
.panel-body{padding:10px 12px;min-width:0}
.panel-critical{border-color:var(--critline)}
.panel-critical .panel-head{background:var(--critbg)}
.panel-critical .panel-title{color:var(--crit)}
.panel-high{border-color:var(--highline)}
.panel-high .panel-head{background:var(--highbg)}
.panel-high .panel-title{color:var(--high)}
.panel-medium{border-color:var(--medline)}
.panel-medium .panel-head{background:var(--medbg)}
.panel-medium .panel-title{color:var(--med)}
.panel-low{border-color:var(--lowline)}
.panel-low .panel-head{background:var(--lowbg)}
.panel-low .panel-title{color:var(--low)}
.panel-ok{border-color:var(--okline)}
.panel-ok .panel-head{background:var(--okbg)}
.panel-ok .panel-title{color:var(--ok)}
.panel-accent{border-color:#fcd9a0}
.panel-accent .panel-head{background:var(--accent-tint)}
.panel-accent .panel-title{color:var(--accent-ink)}

/* ---------- stat row: one compact line per figure ---------- */

/* A grid of equal cells, label above value. The old flex row pushed each label and its value to
   opposite edges, split long labels mid-word, and stretched a short last row across the gap. Grid
   tracks keep every cell the same width, and the hairlines are per-cell shadows so an unfilled
   last row shows as plain panel. */
.statrow{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));border:1px solid var(--line);border-radius:8px;background:var(--panel);overflow:hidden}
.stat{display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:4px;min-width:0;padding:10px 12px;
  box-shadow:1px 0 0 var(--line2),0 1px 0 var(--line2)}
.stat .k{font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:var(--soft);font-weight:700;line-height:1.3;word-break:keep-all;overflow-wrap:normal;hyphens:none}
.stat .v{font-family:var(--mono);font-size:17px;font-weight:700;letter-spacing:-.3px;line-height:1.2;color:var(--ink);overflow-wrap:anywhere}
.stat.t-critical .v{color:var(--crit)}
.stat.t-high .v{color:var(--high)}
.stat.t-medium .v{color:var(--med)}
.stat.t-low .v{color:var(--low)}
.stat.t-ok .v{color:var(--ok)}
/* A figure the run could not establish is drawn apart from a real zero. */
.stat.t-unknown .v{color:var(--soft);font-weight:600}
/* Two figures per line on a phone. One per line made an eleven-figure row taller than the screen. */
@media(max-width:560px){.statrow{grid-template-columns:repeat(2,minmax(0,1fr))}.stat .v{font-size:16px}}

/* ---------- disclosure ---------- */

.disc{border:1px solid var(--line);border-radius:8px;background:var(--panel);min-width:0}
.disc>summary{
  cursor:pointer;list-style:none;padding:7px 11px;font-size:11.5px;font-weight:700;color:var(--dim);
  display:flex;align-items:center;gap:7px;border-radius:8px;
}
.disc>summary::-webkit-details-marker{display:none}
.disc>summary::before{content:"+";font-family:var(--mono);color:var(--accent-ink);font-weight:700;flex:0 0 auto}
.disc[open]>summary::before{content:"\2212"}
.disc[open]>summary{border-bottom:1px solid var(--line2);border-radius:8px 8px 0 0}
.disc>summary:hover{color:var(--ink)}
.disc>summary:focus-visible{outline:2px solid var(--accent-ink);outline-offset:-2px}
.disc-body{padding:10px 11px;font-size:12.5px;color:var(--dim);min-width:0}
.disc-body>*+*{margin-top:8px}
.disc-critical{border-color:var(--critline)}
.disc-critical>summary{color:var(--crit);background:var(--critbg);}
.disc-high{border-color:var(--highline)}
.disc-high>summary{color:var(--high);background:var(--highbg)}

/* ---------- progress, named rather than a bare spinner ---------- */

.prog{border:1px solid var(--line);border-radius:8px;background:var(--panel);padding:9px 11px;min-width:0}
.prog-top{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;min-width:0}
.prog-label{flex:1 1 auto;min-width:0;font-size:12.5px;color:var(--ink)}
.prog-count{flex:0 0 auto;font-family:var(--mono);font-size:11.5px;font-weight:700;color:var(--dim)}
.prog-track{height:5px;border-radius:3px;background:var(--line2);margin-top:7px;overflow:hidden}
.prog-fill{height:100%;background:var(--accent);border-radius:3px;transition:width .2s ease;width:0}
.prog-fill.indet{width:35%;animation:slide 1.2s ease-in-out infinite}
@keyframes slide{0%{margin-left:-35%}100%{margin-left:100%}}
.prog-log{margin-top:7px;font-family:var(--mono);font-size:11px;color:var(--soft);line-height:1.6;max-height:150px;overflow:auto}
.prog-log div{overflow-wrap:anywhere}
.prog.done .prog-fill{background:var(--ok)}

/* ---------- designed states ---------- */

.state{border-radius:9px;padding:12px 14px;min-width:0;font-size:12.5px}
.state h3{margin:0 0 5px;font-size:13px;font-family:var(--font)}
.state .state-body{color:var(--dim)}
.state .state-body>*+*{margin-top:7px}
.state-actions{display:flex;gap:7px;flex-wrap:wrap;margin-top:10px}
.state-empty{border:1px dashed var(--line);background:var(--panel);color:var(--dim)}
.state-empty h3{color:var(--ink)}
/* A partial answer is drawn in the high tone so it can never be mistaken for a clean pass.
   The missing part is listed rather than summarised as a count. */
.state-partial{border:1px solid var(--highline);background:var(--highbg);color:#7c2d12}
.state-partial h3{color:var(--high)}
.state-partial .state-body{color:#7c2d12}
.state-error{border:1px solid var(--critline);background:var(--critbg);color:#7f1d1d}
.state-error h3{color:var(--crit)}
.state-error .state-body{color:#7f1d1d}
.state-error pre{white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;margin:8px 0 0;background:var(--panel);color:#7f1d1d;padding:9px;border-radius:6px;border:1px solid #fecaca;max-height:260px;overflow:auto}



/* ---------- pills and tags ---------- */

.sev{display:inline-block;font-family:var(--mono);font-size:10px;font-weight:700;padding:2px 6px;border-radius:4px;text-transform:uppercase;letter-spacing:.03em}
.sev.critical{background:var(--critbg);color:var(--crit)}
.sev.high{background:var(--highbg);color:var(--high)}
.sev.medium{background:var(--medbg);color:var(--med)}
.sev.low{background:var(--lowbg);color:var(--low)}
.sev.neutral{background:var(--line2);color:var(--dim)}
.sev.ok{background:var(--okbg);color:var(--ok)}
.tag{display:inline-block;font-family:var(--mono);font-size:10.5px;padding:2px 6px;border-radius:4px;background:var(--line2);color:var(--dim);margin:2px 3px 0 0}
.tag.addr{background:var(--accent-tint);color:var(--accent-ink)}
.tag.listed{background:var(--critbg);color:var(--crit)}
.tag.benign{background:var(--okbg);color:var(--ok)}

/* ---------- notes ---------- */

.note{font-size:12px;color:var(--dim);background:var(--bg2);border:1px solid var(--line2);border-radius:7px;padding:8px 10px}
.note b{color:var(--ink)}
.note-critical{background:var(--critbg);border-color:var(--critline);color:#7f1d1d}
.note-critical b{color:#7f1d1d}
.note-high{background:var(--highbg);border-color:var(--highline);color:#7c2d12}
.note-high b{color:#7c2d12}
.note-medium{background:var(--medbg);border-color:var(--medline);color:#1e3a8a}
.note-medium b{color:#1e3a8a}
.note-low{background:var(--lowbg);border-color:var(--lowline);color:#365314}
.note-low b{color:#365314}
.note-ok{background:var(--okbg);border-color:var(--okline);color:#14532d}
.note-ok b{color:#14532d}

/* ---------- tables ---------- */

table{width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed}
th{text-align:left;background:var(--bg2);color:var(--soft);font-size:10px;text-transform:uppercase;letter-spacing:.05em;font-weight:700;padding:6px 8px;vertical-align:bottom}
td{padding:6px 8px;vertical-align:top;border-top:1px solid var(--line2)}
td.empty{color:var(--soft);text-align:center;padding:14px}
.tblwrap{border:1px solid var(--line);border-radius:8px;overflow:auto;max-height:420px;background:var(--panel)}
.tblwrap thead th{position:sticky;top:0;z-index:2;background:var(--bg2);box-shadow:inset 0 -1px 0 0 var(--line)}
.tblwrap.dense table{font-size:11.5px}
.tblwrap.dense td,.tblwrap.dense th{padding:4px 7px}
/* On a phone the fixed layout split a six-column table into 50px columns, and a header such as
   TRANSFERS broke mid-word into three lines. Under 700px the table lays out automatically: a
   header word is never split, so the narrowest a column gets is its longest header word, and
   prose in a cell breaks between words. Addresses and hashes keep breaking anywhere through
   their own classes. A table whose headers need more than the frame scrolls inside .tblwrap,
   which is the one place a table may scroll sideways. */
@media(max-width:700px){
  .tblwrap table{table-layout:auto}
  .tblwrap th{overflow-wrap:normal;word-break:normal;hyphens:manual}
  .tblwrap td{overflow-wrap:break-word}
  .tblwrap td .mono,.tblwrap td.mono,.tblwrap td code,.tblwrap td .srclink{overflow-wrap:anywhere}
}
.tbl-cap{font-size:11px;color:var(--soft);margin:4px 0 0}
tr.hit td{background:#fff7f7}
tr.gap td{background:var(--highbg)}

/* ---------- findings and list rows, shared by the entity and screening tabs ---------- */

.finding{border:1px solid var(--line);border-radius:8px;padding:9px 11px;background:var(--panel)}
.finding+.finding{margin-top:7px}
.finding-head{display:flex;gap:8px;align-items:center;flex-wrap:wrap;min-width:0}
.finding-body{font-size:12px;color:var(--dim);margin-top:4px}
.finding-parties{font-size:11.5px;color:var(--soft);margin-top:4px}
.list-row{border:1px solid var(--line);border-radius:7px;padding:8px 10px;background:var(--panel);min-width:0}
.lists-state{font-size:11.5px;color:var(--dim)}

/* ---------- verdict banner ---------- */

.verdict{border-radius:9px;padding:11px 13px;border:1px solid var(--line);background:var(--panel)}
.verdict .lead{font-size:15px;font-weight:700;display:flex;gap:9px;align-items:center;flex-wrap:wrap;font-family:var(--display)}
.verdict .why{font-size:12.5px;color:var(--dim);margin-top:5px}
.verdict.v-critical{background:var(--critbg);border-color:var(--critline)}
.verdict.v-critical .why{color:#7f1d1d}
.verdict.v-high{background:var(--highbg);border-color:var(--highline)}
.verdict.v-high .why{color:#7c2d12}
.verdict.v-medium{background:var(--medbg);border-color:var(--medline)}
.verdict.v-medium .why{color:#1e3a8a}
.verdict.v-ok{background:var(--okbg);border-color:var(--okline)}
.verdict.v-ok .why{color:#14532d}
.verdict.v-neutral{background:var(--bg2)}

/* ---------- code and summary blocks ---------- */

pre.code{
  font-family:var(--mono);font-size:11px;line-height:1.6;
  background:var(--bg2);color:var(--ink);border:1px solid var(--line);padding:12px;border-radius:8px;overflow:auto;
  white-space:pre-wrap;overflow-wrap:anywhere;max-height:420px;margin:0;
}
.code{overflow-wrap:anywhere}

/* ---------- spinner, toast, error box ---------- */

.spin{display:inline-block;width:11px;height:11px;border:2px solid var(--line);border-top-color:var(--accent-ink);border-radius:50%;animation:spin .7s linear infinite;vertical-align:-1px}
@keyframes spin{to{transform:rotate(360deg)}}
.toast{
  position:fixed;left:50%;bottom:calc(var(--status-h) + 12px);transform:translateX(-50%) translateY(14px);
  background:#fffbeb;color:#1c1917;border:1px solid #f59e0b;box-shadow:0 4px 14px rgba(0,0,0,.14);
  padding:8px 13px;border-radius:7px;font-size:12.5px;
  max-width:min(560px,calc(100vw - 32px));opacity:0;pointer-events:none;transition:opacity .18s,transform .18s;z-index:60;
}
.toast.on{opacity:1;transform:translateX(-50%) translateY(0)}

.hidden{display:none}

/* ---------- tuning panel on the monitor tab ---------- */

.knob{border-top:1px solid var(--line2);padding:9px 0;min-width:0}
.knob:first-of-type{border-top:0}
.knob .lab{display:flex;justify-content:space-between;gap:9px;font-size:12px;font-weight:600;min-width:0}
.knob .lab b{font-family:var(--mono)}
.knob input[type=range]{width:100%;margin:6px 0 2px;accent-color:var(--accent-ink)}
.knob .row{margin-top:4px}
.knob .hint{margin-top:2px}
label.chk{display:flex;gap:8px;align-items:flex-start;cursor:pointer;font-size:12px;min-width:0}
label.chk input{width:auto;margin-top:2px;accent-color:var(--accent-ink)}
label.chk b{font-size:12px}
.tab-monitor .finding .finding-parties.mono{font-size:11px;color:var(--soft)}

/* ---------- responsive ---------- */

/* Under 1100px the rail keeps its icons and its counts and drops its labels. The label stays
   available as the button's accessible name and its tooltip, so nothing is lost. */
@media(max-width:1100px){
  .rail{flex-basis:var(--rail-w-icon);align-items:center;padding:8px 5px}
  .rail-btn{flex-direction:column;gap:3px;padding:7px 4px;justify-content:center;width:100%}
  .rail-lbl{display:none}
  .rail-key{display:none}
  .rail-n{font-size:9.5px;padding:0 4px}
}

/* A full 42 character address measures 327.6px at 13px mono, and the field needs 353.6px of
   border box to hold it. Below 980px the single-row bar can no longer promise that once the
   badge, the chain select and the status chip have taken their share, so the bar wraps here
   rather than at 700px and the subject takes a row of its own with the chain and the chip
   underneath it. The subject keeps the most room at every width because it is the only field
   whose value is data. */
@media(max-width:980px){
  .toolbar{height:auto;flex-wrap:wrap;padding:9px var(--gut);gap:8px}
  .tb-subject{flex:1 1 100%}
}

/* On a phone the rail becomes a horizontal strip above the workspace, and the toolbar wraps
   onto two rows. Both brand strips and the status bar stay where they are. */
@media(max-width:700px){
  :root{--gut:12px}
  .toolbar{padding:8px var(--gut);gap:7px}
  .tb-field{flex:1 1 100%}
  .tb-field.tb-chain{flex:1 1 130px}
  .chip{flex:1 1 90px;justify-content:center;min-width:0}
  .frame{flex-direction:column}
  .rail{
    flex:0 0 auto;flex-direction:row;align-items:stretch;gap:4px;
    border-right:0;border-bottom:1px solid var(--line);
    overflow-x:auto;overflow-y:hidden;padding:6px var(--gut);
  }
  .rail-btn{width:auto;flex:0 0 auto;flex-direction:row;gap:6px;padding:6px 9px}
  .rail-lbl{display:block;white-space:nowrap}
  .rail-ico{display:none}
  .statusbar{font-size:10.5px;gap:5px;padding:0 var(--gut)}
  .sb-btn kbd{display:none}
}

/* Measured: in the single-row layout the field ends up 184px narrower than the viewport, so a
   42 character address stops fitting on one line at about 538px. The subject therefore gets the
   whole row to itself from 560px down, with the label stacked above it and Load dropped below
   it, so neither takes width from the value. */
/* Below 560px the subject group dissolves into the bar (display:contents), so its three parts
   become rows of the bar itself: the label shares the first row with the tx badge, the field
   takes a full row, and Load sits beside the chain select. Stacking label, field, Load and chain
   one per row spent five rows on the bar and left a 400px workspace on a 740px phone. */
@media(max-width:560px){
  .tb-subject{display:contents}
  .tb-app{order:0;border-right:0}
  .tb-lbl-subject{order:1;flex:1 1 auto}
  .tb-in.tb-in-subject{order:2;flex:1 1 100%}
  .tb-field.tb-chain{order:3;flex:1 1 0}
  .btn.btn-load{order:4;flex:0 0 auto;padding:0 24px}
  .chip{order:5}
}
/* Under 430px the mono value steps down to the 12.5px the rest of the app already reads data
   at, which is the smallest step that keeps a 42 character address on one line on a 360px
   Android viewport. Nothing smaller is taken, and the value is never clipped either way. */
@media(max-width:430px){
  .tb-in.tb-in-subject{font-size:12.5px;padding:0 8px}
  /* Chrome lays its datalist arrow out as a real 17px flex item inside the input, and at phone
     widths that 17px is the difference between a whole address on one line and a scrolled one.
     The arrow goes here and the recent-subject list still opens on typing, which is the part
     that carries the value. Nothing else in the field is given up to make room.
     The `!important` is required: Chrome's UA sheet declares this pseudo-element's display
     with `!important`, and an author rule without it is measurably ignored (the field still
     reserved the 17px). This is the only `!important` in the file and it is here to match a
     UA declaration rather than to outrank anything written by hand. */
  .tb-in.tb-in-subject::-webkit-calendar-picker-indicator{display:none !important}
}
@media(max-width:400px){
  .tb-lbl{display:none}
  /* The chain label goes, the subject label stays. The subject is the control the page hangs
     on and it is the one field here whose placeholder alone would have to carry the name. */
  .tb-lbl-subject{display:inline-flex}
  .sb-item{font-size:10px}
}

/* ---------- charts (js/core/chart.js) ----------

   The chart layer owns the `cx-` prefix and nothing else in this file uses it, so a chart can
   never repaint a panel. Three rules hold across every block below.

   Text wraps. There is no ellipsis, no line-clamp and no nowrap on a label, a tick, a legend
   entry or a cell, at any width. A name that outgrows its column takes a second line and the
   row grows.

   Colour is the chart layer's only palette beyond severity. The series hues and the sequential
   ramp are set in chart.js as fills on the marks, because they belong to the data. Everything
   made of text here wears an ink token.

   The teaching collapses into the table toggle. The notes do not: `.cx-note` is always visible,
   which is where a failed source, an unread value or a coverage cap is stated in words. */

.cx-wrap{display:flex;flex-direction:column;gap:7px;min-width:0}
.cx{margin:0;min-width:0;display:flex;flex-direction:column;gap:7px}
.cx-head{display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;gap:2px;min-width:0}
.cx-title{font-size:12px;font-weight:700;color:var(--ink);font-family:var(--display)}
.cx-desc{font-size:11.5px;color:var(--soft);overflow-wrap:anywhere}
.cx-plot{min-width:0;display:flex;flex-direction:column;gap:6px}
.cx-empty{margin:0;font-size:12px;color:var(--soft);border:1px dashed var(--line);border-radius:8px;padding:12px;background:var(--panel)}

/* Notes stay on screen. A chart never hides the reason a value is missing behind a hover. */
.cx-notes{display:flex;flex-direction:column;gap:4px}
.cx-note{margin:0;font-size:11.5px;border-radius:6px;padding:6px 9px;overflow-wrap:anywhere}
.cx-note-high{background:var(--highbg);border:1px solid var(--highline);color:#7c2d12}
.cx-note-critical{background:var(--critbg);border:1px solid var(--critline);color:#7f1d1d}
.cx-note-neutral{background:var(--bg2);border:1px solid var(--line);color:var(--dim)}

/* ---------- horizontal bars ---------- */

.cx-bars{
  display:grid;
  grid-template-columns:minmax(92px,30%) minmax(80px,1fr) max-content;
  column-gap:10px;row-gap:4px;align-items:center;min-width:0;
}
.cx-bar-lab{font-size:11.5px;color:var(--ink);overflow-wrap:anywhere;min-width:0;padding:2px 0}
.cx-bar-track{min-width:0;border-radius:4px;padding:1px 0}
.cx-bar-track svg{display:block;width:100%;height:22px}
.cx-bar-val{
  font-family:var(--mono);font-size:11px;color:var(--ink);text-align:right;min-width:0;
  display:flex;flex-direction:column;align-items:flex-end;gap:1px;font-variant-numeric:tabular-nums;
}
.cx-bar-val b{font-weight:700}
.cx-bar-sev{font-size:9.5px;letter-spacing:.04em;text-transform:uppercase;color:var(--soft)}
.cx-bar-val.cx-unread b{color:var(--high);font-weight:600}
/* The second reading beside a bar: the denominator, or the state the length puts the row in.
   It wraps onto as many lines as it needs. */
.cx-bar-sub{display:block;font-size:10px;color:var(--soft);font-family:var(--sans);
  font-weight:400;letter-spacing:0;overflow-wrap:anywhere;margin-top:1px}
.cx-marker-cap{margin:0;display:flex;gap:6px;align-items:center;font-size:10.5px;color:var(--soft);overflow-wrap:anywhere}
.cx-marker-key{display:inline-block;width:2px;height:12px;background:var(--ink);opacity:.55;flex:0 0 auto}

/* Under 560px the label takes its own full-width line above its bar. The alternative, a
   narrower label column, is the start of truncation. */
@media(max-width:560px){
  .cx-bars{grid-template-columns:minmax(0,1fr) max-content;row-gap:2px}
  .cx-bar-lab{grid-column:1 / -1;padding-top:6px;font-weight:600}
}

/* ---------- stacked bar, sparkline, time series, graph, tree hosts ---------- */

.cx-stack-host,.cx-ts-host,.cx-tree-host{min-width:0;width:100%}
.cx-stack-host svg,.cx-ts-host svg,.cx-tree-host svg{display:block;max-width:100%}
/* The graph sizes its columns to fit wrapped labels. When the container is narrower than that,
   it scrolls sideways and keeps every character. */
.cx-seg,.cx-node,.cx-tree-n{cursor:default}
.cx-seg:hover path,.cx-node:hover circle,.cx-node:hover rect,.cx-node:hover polygon{filter:brightness(1.08)}
.cx-tree-n:hover rect{stroke:var(--accent-ink)}
.cx-ts{touch-action:pan-y}

.cx-events{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:3px}
.cx-events li{font-size:11px;color:var(--dim);display:flex;gap:6px;align-items:baseline;overflow-wrap:anywhere;min-width:0}
.cx-events b{font-family:var(--mono);font-size:10.5px;color:var(--ink);flex:0 0 auto}
.cx-ev-k{display:inline-block;width:8px;height:8px;border-radius:2px;flex:0 0 auto;align-self:center}

.cx-spark{display:inline-flex;align-items:center;gap:6px;vertical-align:middle}
.cx-spark svg{display:block}
.cx-spark-none{font-size:10.5px;color:var(--soft)}

/* ---------- dot matrix ---------- */

/* Over ten rows the grid scrolls inside a capped height and keeps its column headers pinned,
   the same contract .tblwrap already holds. Without the cap a 17 row matrix ran 932px at 390
   against a 584px workspace, the headers left the screen, and the columns stopped being
   identifiable. Nothing is shortened to fit: the grid scrolls. */
.cx-mx{display:grid;gap:2px;min-width:0;max-height:min(58vh,420px);overflow:auto;
  overscroll-behavior:contain;padding-right:2px}
.cx-mx-corner,.cx-mx-ch,.cx-mx-rh{
  font-size:10px;letter-spacing:.04em;text-transform:uppercase;color:var(--soft);
  font-weight:700;overflow-wrap:anywhere;min-width:0;padding:3px 2px;align-self:center;
}
.cx-mx-corner,.cx-mx-ch{position:sticky;top:0;z-index:2;background:var(--panel);
  align-self:stretch;display:flex;align-items:center;justify-content:center;
  box-shadow:inset 0 -1px 0 0 var(--line)}
.cx-mx-corner{justify-content:flex-start}
.cx-mx-ch{text-align:center}
.cx-mx-rh{text-transform:none;letter-spacing:0;font-size:11.5px;font-weight:400;color:var(--ink)}
.cx-mx-c{
  min-height:26px;border-radius:4px;display:flex;align-items:center;justify-content:center;
  padding:3px 4px;min-width:0;background:var(--line2);
}
.cx-mx-na{background:transparent;border:1px dashed var(--line)}
.cx-mx-v{font-family:var(--mono);font-size:10px;font-weight:700;color:var(--soft);overflow-wrap:anywhere;text-align:center}
.cx-scale{display:flex;align-items:center;gap:3px;flex-wrap:wrap;min-width:0}
.cx-scale-s{width:20px;height:10px;border-radius:2px;flex:0 0 auto}
.cx-scale-l{font-size:10px;color:var(--soft);font-family:var(--mono);overflow-wrap:anywhere}

/* ---------- legend ---------- */

.cx-legend{display:flex;flex-wrap:wrap;gap:4px 14px;min-width:0}
.cx-leg{display:flex;align-items:baseline;gap:6px;font-size:11px;color:var(--dim);min-width:0;overflow-wrap:anywhere}
.cx-sw{display:inline-block;width:10px;height:10px;border-radius:2px;border:1px solid transparent;flex:0 0 auto;align-self:center}
.cx-sw-line{height:3px;border-radius:2px;width:14px}
.cx-leg-shape{flex:0 0 auto;align-self:center}
.cx-leg-l{color:var(--dim)}
.cx-leg-v{font-family:var(--mono);font-size:10.5px;color:var(--ink);font-variant-numeric:tabular-nums}

/* ---------- the table view ---------- */

.cx-tbl{border:1px solid var(--line);border-radius:8px;background:var(--panel);min-width:0}
.cx-tbl>summary{
  cursor:pointer;list-style:none;padding:6px 10px;font-size:11px;font-weight:700;
  color:var(--acc);letter-spacing:.03em;text-transform:uppercase;
}
.cx-tbl>summary::-webkit-details-marker{display:none}
.cx-tbl>summary::before{content:"+ ";font-family:var(--mono)}
.cx-tbl[open]>summary::before{content:"- "}
.cx-tbl>summary:hover{background:var(--accent-tint)}
.cx-tbl>summary:focus-visible{outline:2px solid var(--acc);outline-offset:-2px;border-radius:7px}
.cx-tbl-b{padding:0 8px 8px}
.cx-tbl-b .tblwrap{border-radius:6px}

/* ---------- the hover layer ---------- */

.cx-hit{cursor:pointer}
.cx-hit:focus-visible{outline:2px solid var(--acc);outline-offset:1px;border-radius:4px}
.cx-tip{
  position:fixed;left:0;top:0;z-index:80;pointer-events:none;opacity:0;
  background:#fffbeb;color:#1c1917;border:1px solid #f59e0b;border-radius:7px;padding:7px 9px;
  max-width:min(320px,calc(100vw - 24px));box-shadow:var(--shadow);
  font-size:11.5px;line-height:1.45;overflow-wrap:anywhere;transition:opacity .12s;
}
.cx-tip.on{opacity:1}
.cx-tip-t{font-weight:700;margin-bottom:3px;overflow-wrap:anywhere}
.cx-tip-r{display:flex;gap:6px;align-items:baseline;min-width:0}
.cx-tip-k{display:inline-block;width:12px;height:3px;border-radius:2px;flex:0 0 auto;align-self:center}
.cx-tip-v{font-family:var(--mono);font-weight:700;font-variant-numeric:tabular-nums}
.cx-tip-l{color:var(--dim)}
.cx-tip-f{margin-top:4px;color:var(--dim);font-size:11px}

/* On paper the hover layer is gone, so the table view has to be reachable another way: the
   toggle stays printed and the table under an open one is kept with its chart. Every mark also
   carries its value beside it, which is what survives a black and white print. */
@media print{
  .cx-tbl,.cx{break-inside:avoid}
  .cx-tip{display:none}
}
@media (forced-colors:active){
  .cx-mx-c,.cx-tbl{border:1px solid CanvasText}
  .cx-mx-v{forced-color-adjust:none}
}

/* Forced colours repaint every fill and border from the system palette, so the empty and
   filled states of the subject stop differing by colour. The border weight still differs, and
   it is the weight that was carrying the "this is the control" reading in the first place. */
@media (forced-colors:active){
  .tb-in.tb-in-subject{border:2px solid CanvasText}
  .tb-in.tb-in-subject:not(:placeholder-shown){border-width:3px}
}

/* ---------- source links ----------

   Every link in this workbench goes to the record behind a claim, so it is styled to be found
   and followed rather than to sit quietly in the prose. The underline is drawn in currentColor,
   which keeps it visible on every tinted fill (a severity note, a hit row, the tooltip) as well
   as on a white card. Colour is never the only carrier: the underline and the
   external mark both say "this leaves the page" on their own. */

.srclink{
  color:var(--accent-ink);
  text-decoration:underline;
  text-decoration-color:currentColor;
  text-decoration-thickness:1px;
  text-underline-offset:2px;
  /* An address is read character by character and is never cut, so a link inside one wraps with
     the rest of the cell. */
  overflow-wrap:anywhere;
  border-radius:3px;
}
.srclink:hover{color:#92400e;text-decoration-thickness:2px}
.srclink:focus-visible{
  outline:2px solid var(--accent-ink);
  outline-offset:2px;
  background:var(--accent-tint);
}

/* The external mark is drawn, never typed. A glyph typed into the text would sit inside the
   monospace run of an address and change what the reader counts and copies. As an element it
   carries no character, and it trails every character of the address, so the address wraps
   exactly as the same address wraps without a link. */
.srclink-mk{
  display:inline-block;width:.72em;height:.72em;
  margin-left:.28em;vertical-align:-.04em;flex:0 0 auto;opacity:.9;
}

/* A link whose text is an address, a hash or a contract. The face and the character count match
   the unlinked text beside it. */
.srclink-mono{font-family:var(--mono);font-size:inherit}

/* What a builder that could not build a real URL renders as: the same text, no anchor, no
   pointer, nothing to click. A dead link would read as a receipt that opens on nothing. */
.srclink-off{color:inherit;overflow-wrap:anywhere}
.srclink-off.srclink-mono{font-family:var(--mono)}

.srclink-row{
  display:flex;flex-wrap:wrap;gap:4px 10px;align-items:baseline;
  min-width:0;margin-top:5px;font-size:11.5px;
}
/* A flex item will not shrink under its own min-content width unless it is told it may, and a
   77 character source URL is wider than a 390px phone. The item is allowed to shrink and the
   text inside it wraps, so a long URL wraps to the next line instead of widening the page. */
.srclink-row>*{min-width:0;max-width:100%}
.srclink-lead{color:var(--soft);font-size:11px}

/* A matched row is drawn on a pale red fill. The link keeps the accent ink there, which clears
   the contrast floor against that fill, and the underline carries the rest. */
tr.hit .srclink,tr.gap .srclink{color:var(--accent-ink)}

@media (forced-colors:active){
  .srclink{text-decoration:underline}
  .srclink-mk{forced-color-adjust:auto}
}

@media print{
  /* On paper a link is a claim with nowhere to go, so the URL is printed after the text it
     wrapped. The text itself is still printed in full. */
  .srclink::after{content:" (" attr(href) ")";font-size:9.5px;color:#334155;overflow-wrap:anywhere}
  .srclink-mk{display:none}
}

/* ---------------------------------------------------------------- tooltips */
.tip{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;margin:0 0 0 4px;
  border:1px solid var(--line,#d6d3d1);border-radius:50%;background:#fff;color:var(--dim,#57534e);
  font:700 10px/1 var(--mono);cursor:help;vertical-align:middle;position:relative}
.tip::after{content:"";position:absolute;inset:-14px}
.tip:hover,.tip:focus-visible{border-color:#f59e0b;color:#92400e;outline:none}
.has-tip{cursor:help}
.has-tip .k{text-decoration:underline dotted;text-underline-offset:3px;text-decoration-color:var(--soft)}
.tipbox{position:fixed;z-index:1000;display:none;max-width:min(320px,calc(100vw - 16px));padding:8px 10px;
  background:#fffbeb;color:#1c1917;border:1px solid #f59e0b;border-radius:6px;font-size:12px;line-height:1.45;
  box-shadow:0 4px 14px rgba(0,0,0,.18);pointer-events:none;overflow-wrap:anywhere;white-space:normal}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}

/* ---------------------------------------------------------------- touch targets

   On a coarse pointer every primary control is at least 44px in the direction a thumb has to
   hit it. The desktop density stays as it is, because a mouse does not need the room and the
   workbench is read more than it is tapped. */
@media (pointer:coarse){
  .tb-in.tb-in-subject,.btn.btn-load,select.tb-in{height:44px}
  .tb-key{display:none}
  .rail-btn{min-height:44px}
  .btn{min-height:44px;min-width:44px}
  input.in,select.in,select{min-height:44px}
  label.chk{min-height:44px;align-items:center}
  label.chk input{width:20px;height:20px;margin-top:0;flex:0 0 auto}
  .knob input[type=range]{height:44px;margin:0}
  .disc>summary,.cx-tbl>summary{min-height:44px;display:flex;align-items:center;gap:6px}
}

/* ---------------------------------------------------------------- chain picker */
.chainpick{position:relative;flex:1 1 auto;min-width:0}
.chainpick-native{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.chainpick-btn{display:flex;align-items:center;gap:8px;height:34px;cursor:pointer;text-align:left}
.chainpick-btn .chain-name{flex:1 1 auto;min-width:0;overflow-wrap:anywhere}
.chainpick-btn .chain-caret{flex:0 0 auto;color:var(--soft);font-size:12px}
.chain-logo{flex:0 0 auto;width:18px;height:18px;border-radius:50%;object-fit:cover}
.chainpick-list{position:absolute;z-index:70;top:calc(100% + 4px);left:0;right:0;min-width:190px;margin:0;padding:4px;
  list-style:none;background:#fff;border:1px solid var(--line);border-radius:8px;box-shadow:0 6px 18px rgba(0,0,0,.12)}
.chainpick-list li{display:flex;align-items:center;gap:9px;padding:8px 9px;border-radius:6px;cursor:pointer;font-size:14px;color:var(--ink)}
.chainpick-list li:hover,.chainpick-list li:focus{background:#fffbeb;outline:none}
.chainpick-list li[aria-selected=true]{background:#fef3c7;font-weight:600}
@media (hover:none),(max-width:560px){.chainpick-btn{height:44px}.chainpick-list li{min-height:44px}}

/* ---------------------------------------------------------------- sortable headers */
th.th-sort{cursor:pointer;user-select:none}
th.th-sort:hover{color:var(--ink)}
th.th-sort:focus-visible{outline:2px solid #f59e0b;outline-offset:-2px}
th.th-sort::after{content:"\2195";margin-left:4px;font-size:.9em;opacity:.35}
th[aria-sort=ascending]::after{content:"\25B2";opacity:.9;color:#b45309}
th[aria-sort=descending]::after{content:"\25BC";opacity:.9;color:#b45309}

/* ---------------------------------------------------------------- icon buttons */
button[data-icon]{min-width:34px;justify-content:center;gap:4px}
.btn-emoji{font-size:15px;line-height:1;font-family:"Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",sans-serif}
.btn-emoji-sfx{font-size:10.5px;font-weight:700;letter-spacing:.04em}

/* ================================================================ trace: bubble map

   The Trace tab is a working canvas: a summary strip, then one framed stage holding the map
   toolbar, the time range, the canvas with its wallet list beside it, and the legend. The
   canvas is the only surface that swallows touch gestures (touch-action:none), so pinch and
   drag reach the map while the rest of the page still scrolls around it. */

.tab-trace{gap:10px}
.tr-head{display:flex;flex-direction:column;gap:8px;min-width:0}
.tr-head:empty,.tr-busy:empty{display:none}
.tr-verdict{padding:9px 12px}
.tr-verdict .lead{font-size:14px}

/* The summary reads as an investigation: a funnel of what was read and expanded, then the
   risk found and the coverage behind it. Values sit next to their words so nothing is left
   floating at the far edge of a stretched cell. */
.tr-sum{background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:10px 12px;display:flex;flex-direction:column;gap:9px;min-width:0}
.tr-funnel{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;min-width:0}
.tr-step{display:inline-flex;align-items:baseline;gap:5px;flex-wrap:wrap;min-width:0}
.tr-n{font-family:var(--mono);font-size:17px;font-weight:700;color:var(--ink);letter-spacing:-.3px;line-height:1.2}
.tr-w{font-size:12.5px;color:var(--dim);font-weight:600}
.tr-sub{font-size:11px;color:var(--soft);background:var(--bg2);border:1px solid var(--line2);border-radius:999px;padding:0 7px}
.tr-step.t-medium .tr-n{color:var(--med)}
.tr-step.t-high .tr-n{color:var(--high)}
.tr-step.t-unknown .tr-n{color:var(--soft);font-size:14px}
.tr-arrow{color:#94a3b8;font-size:15px;line-height:1;margin-right:4px}
.tr-act{display:inline-flex;align-items:center;gap:6px;margin-left:auto;flex-wrap:nowrap}
.in.tr-sel{width:auto;max-width:none;flex:0 0 auto;padding:5px 8px}
.tr-groups{display:flex;flex-wrap:wrap;gap:8px 20px;padding-top:9px;border-top:1px solid var(--line2);min-width:0}
.tr-group{display:flex;flex-wrap:wrap;align-items:center;gap:6px;min-width:0}
.tr-gl{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:var(--soft);font-weight:700;margin-right:2px}
.tr-chip{display:inline-flex;align-items:center;gap:5px;padding:3px 9px 3px 4px;border-radius:999px;border:1px solid var(--line);background:var(--bg2);font-size:12px;color:var(--dim);min-width:0;flex-wrap:wrap;line-height:1.4}
.tr-ic{width:16px;height:16px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:10.5px;font-weight:800;color:#fff;background:#94a3b8;flex:0 0 auto;line-height:1}
.tr-cv{font-family:var(--mono);color:var(--ink);font-size:12px}
.tr-chip.t-critical{background:var(--critbg);border-color:var(--critline);color:#7f1d1d}
.tr-chip.t-critical .tr-ic{background:var(--crit)}
.tr-chip.t-critical .tr-cv{color:var(--crit)}
.tr-chip.t-high{background:var(--highbg);border-color:var(--highline);color:#7c2d12}
.tr-chip.t-high .tr-ic{background:var(--high)}
.tr-chip.t-high .tr-cv{color:var(--high)}
.tr-chip.t-ok{background:var(--okbg);border-color:var(--okline);color:#14532d}
.tr-chip.t-ok .tr-ic{background:var(--ok)}
.tr-chip.t-ok .tr-cv{color:var(--ok)}
/* An answer the run could not establish is dashed and carries a question mark. */
.tr-chip.t-unknown{border-style:dashed;background:var(--panel)}
.tr-chip.t-unknown .tr-ic{background:#94a3b8}
.tr-chip.t-unknown .tr-cv{color:var(--soft)}
.tr-chip.tr-muted{background:transparent;border-color:var(--line2);color:var(--soft);padding-left:9px}
.tr-meter{padding-left:9px}
.tr-bar{width:46px;height:6px;background:var(--line);border-radius:3px;overflow:hidden;display:inline-block;flex:0 0 auto}
.tr-bar-f{display:block;height:100%;background:var(--ok)}
.tr-meter.t-high .tr-bar-f{background:var(--high)}
.tr-meter.t-critical .tr-bar-f{background:var(--crit)}
.tr-pop{position:relative;display:inline-block;min-width:0}
.tr-pop>summary{list-style:none;cursor:pointer;padding-left:9px}
.tr-pop>summary::-webkit-details-marker{display:none}
.tr-pop>summary::after{content:"+";font-family:var(--mono);font-weight:700;margin-left:2px}
.tr-pop[open]>summary::after{content:"\2212"}
.tr-pop-body{position:absolute;z-index:40;top:calc(100% + 4px);left:0;width:min(440px,calc(100vw - 40px));background:#fff;border:1px solid var(--line);border-radius:8px;box-shadow:0 6px 18px rgba(15,23,42,.12);padding:9px 11px;font-size:12px;color:var(--dim)}
.tr-pop-why{margin:0 0 6px}
.tr-pop-row{font-family:var(--mono);font-size:11.5px;overflow-wrap:anywhere;padding:2px 0}
.tr-pop-err{font-family:var(--font);color:var(--soft)}

/* ---------- the stage ---------- */

.bm-stage{background:var(--panel);border:1px solid var(--line);border-radius:10px;min-width:0;display:flex;flex-direction:column}
.bm-bar{display:flex;flex-wrap:wrap;gap:6px 14px;align-items:center;padding:7px 9px;border-bottom:1px solid var(--line2);min-width:0}
.bm-grp{display:flex;gap:4px;align-items:center;flex-wrap:wrap;min-width:0}
.bm-grp-end{margin-left:auto}
.bm-ib{min-width:32px;font-weight:700;font-size:14px;line-height:1;padding:4px 8px}
.bm-tg[aria-pressed=true]{background:var(--accent-tint);border-color:var(--accent);color:var(--accent-ink);font-weight:700}
a.btn{text-decoration:none;display:inline-flex;align-items:center}

/* Two range inputs share one track. Each input ignores the pointer and only its thumb takes
   it, which is the standard way to get two draggable ends with native keyboard support. */
.bm-range{display:flex;align-items:center;gap:6px 10px;flex:1 1 380px;flex-wrap:wrap;min-width:0}
.bm-range-k{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:var(--soft);font-weight:700}
.bm-range-track{position:relative;flex:1 1 260px;min-width:170px;height:38px}
.bm-range-track::after{content:"";position:absolute;left:8px;right:8px;bottom:8px;height:2px;background:var(--line);border-radius:1px;pointer-events:none}
.bm-hist{position:absolute;left:8px;right:8px;top:1px;bottom:15px;display:flex;align-items:flex-end;gap:1px;pointer-events:none}
.bm-hb{flex:1 1 0;min-width:0;background:#e2e8f0;border-radius:1px 1px 0 0}
.bm-hb.on{background:#fbbf24}
.bm-thumb{position:absolute;left:0;right:0;bottom:0;width:100%;height:18px;margin:0;padding:0;background:transparent;pointer-events:none;-webkit-appearance:none;appearance:none;z-index:1}
.bm-thumb::-webkit-slider-runnable-track{background:transparent;height:18px;border:0}
.bm-thumb::-moz-range-track{background:transparent;height:18px;border:0}
.bm-thumb::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;pointer-events:auto;width:16px;height:16px;margin-top:1px;border-radius:50%;background:#fff;border:2px solid var(--accent-ink);cursor:ew-resize;box-shadow:0 1px 3px rgba(0,0,0,.18)}
.bm-thumb::-moz-range-thumb{pointer-events:auto;width:12px;height:12px;border-radius:50%;background:#fff;border:2px solid var(--accent-ink);cursor:ew-resize}
.bm-thumb:focus-visible{outline:none}
.bm-thumb:focus-visible::-webkit-slider-thumb{outline:2px solid var(--accent-ink);outline-offset:2px}
.bm-range-v{font-family:var(--mono);font-size:11.5px;color:var(--dim);overflow-wrap:anywhere}

.bm-body{display:grid;grid-template-columns:minmax(0,1fr) 330px;min-width:0}
.bm-body.bm-nolist{grid-template-columns:minmax(0,1fr)}
.bm-nolist .bm-list{display:none}
.bm-canvaswrap{position:relative;min-width:0}
.bm-canvas{position:relative;height:min(72vh,760px);min-height:380px;overflow:hidden;touch-action:none;user-select:none;-webkit-user-select:none;
  background-color:#fcfcfb;background-image:radial-gradient(#e7e5e4 1px,transparent 1px);background-size:22px 22px}
.bm-svg{display:block;width:100%;height:100%;cursor:grab}
.bm-node{transition:opacity .15s}
.bm-dim{opacity:.14}
.bm-link.bm-dim{opacity:.06}
.bm-link.bm-hot{stroke:#b45309;stroke-opacity:.85}
.bm-glyph{font-family:var(--font);font-weight:800;pointer-events:none}
.bm-label{font-family:var(--mono);fill:#1f2937;paint-order:stroke;stroke:#ffffff;stroke-linejoin:round;pointer-events:none}
.bm-hull path{fill-opacity:.1;stroke-opacity:.1}
.bm-hull-label{font-family:var(--font);font-weight:800;paint-order:stroke;stroke:#ffffff;stroke-linejoin:round;pointer-events:none}
.bm-selring{fill:none;stroke:#0f172a;pointer-events:none}
.bm-tip{position:absolute;display:none;pointer-events:none;z-index:6;max-width:300px;background:#fffbeb;border:1px solid #f59e0b;border-radius:6px;padding:7px 9px;font-size:12px;line-height:1.4;color:#1c1917;box-shadow:0 4px 14px rgba(0,0,0,.14);overflow-wrap:anywhere}
.bm-tip-a{font-size:11px}
.bm-tip-l{font-weight:700}
.bm-tip-s{display:flex;align-items:center;gap:5px;margin-top:3px;color:var(--dim)}
.bm-chip{flex:0 0 auto;display:block}

/* ---------- the wallet list ---------- */

.bm-list{border-left:1px solid var(--line2);display:flex;flex-direction:column;min-width:0;height:min(72vh,760px);min-height:380px}
.bm-list-head{padding:8px;border-bottom:1px solid var(--line2);display:flex;flex-direction:column;gap:5px}
.bm-q{width:100%}
.bm-list-meta{font-size:11px;color:var(--soft)}
.bm-rows{overflow:auto;flex:1 1 auto;min-height:0;overscroll-behavior:contain}
.bm-row{display:flex;align-items:stretch;border-bottom:1px solid var(--line2);min-width:0}
.bm-row.sel{background:#fffbeb;box-shadow:inset 3px 0 0 var(--accent)}
.bm-row.off .bm-row-main{opacity:.5}
.bm-row-main{flex:1 1 auto;min-width:0;display:flex;gap:8px;align-items:flex-start;text-align:left;background:none;border:0;padding:7px 4px 7px 9px;cursor:pointer;font:inherit;color:inherit}
.bm-row-main:hover{background:var(--bg2)}
.bm-row-main:focus-visible{outline:2px solid var(--accent-ink);outline-offset:-2px}
.bm-row-chip{flex:0 0 auto;padding-top:1px}
.bm-row-txt{display:flex;flex-direction:column;gap:3px;min-width:0}
.bm-row-a{font-size:11.5px;overflow-wrap:anywhere;color:var(--ink);line-height:1.35}
.bm-row-m{display:flex;flex-wrap:wrap;gap:4px 7px;align-items:center;font-size:11.5px;color:var(--dim)}
.bm-row-v{font-family:var(--mono)}
.bm-row-l{font-size:11px;color:var(--soft)}
.bm-eye{flex:0 0 auto;width:34px;background:none;border:0;color:var(--soft);cursor:pointer;display:flex;align-items:center;justify-content:center}
.bm-eye:hover{color:var(--ink)}
.bm-eye[aria-pressed=false]{color:var(--accent-ink)}
.bm-empty{padding:12px;font-size:12px;color:var(--soft)}
.bm-clusters{border-bottom:1px solid var(--line2)}
.bm-clusters>summary{cursor:pointer;padding:7px 10px;font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;font-weight:700;color:var(--soft)}
.bm-clusters>div{max-height:200px;overflow:auto}
.bm-clrow{display:flex;gap:7px;align-items:center;width:100%;text-align:left;background:none;border:0;border-top:1px solid var(--line2);padding:6px 10px;font:inherit;font-size:12px;color:var(--dim);cursor:pointer;flex-wrap:wrap}
.bm-clrow:hover{background:var(--bg2)}
.bm-clrow.on{background:#fffbeb}
.bm-clrow b{color:var(--ink);font-family:var(--mono)}
.bm-clsw{width:12px;height:12px;border-radius:4px;opacity:.6;flex:0 0 auto}

/* ---------- the wallet panel: over the canvas on a desk, a bottom sheet on a phone ---------- */

.bm-panel{position:absolute;top:10px;right:10px;width:min(370px,calc(100% - 20px));max-height:calc(100% - 20px);overflow:auto;overscroll-behavior:contain;background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:0 8px 24px rgba(15,23,42,.14);padding:10px 12px;z-index:5}
.bm-panel[hidden]{display:none}
.bm-p-head{display:flex;align-items:center;gap:8px;justify-content:space-between}
.bm-p-title{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0}
.bm-p-hop{font-size:11.5px;color:var(--dim);font-weight:600}
.bm-p-addr{margin:9px 0;font-family:var(--mono);font-size:12.5px;overflow-wrap:anywhere;display:flex;gap:8px;align-items:flex-start;justify-content:space-between;min-width:0}
.bm-p-addr>.srclink,.bm-p-addr>.srclink-off{min-width:0}
.bm-p-dl{display:grid;grid-template-columns:auto minmax(0,1fr);gap:5px 10px;margin:0;font-size:12px}
.bm-p-dl dt{color:var(--soft);font-size:10px;text-transform:uppercase;letter-spacing:.06em;font-weight:700;padding-top:2px}
.bm-p-dl dd{margin:0;min-width:0;overflow-wrap:anywhere;color:var(--ink)}
.bm-p-dl dd.bm-p-why{grid-column:2;color:var(--dim);font-size:11.5px;margin-top:-2px}
.bm-p-via{display:flex;flex-direction:column;gap:3px;min-width:0}
.bm-p-link{background:none;border:0;padding:0;color:var(--accent-ink);text-decoration:underline;cursor:pointer;text-align:left;font-size:11.5px;overflow-wrap:anywhere}
.bm-p-acts{display:flex;flex-wrap:wrap;gap:6px;margin-top:11px;align-items:center}

.bm-legend{display:flex;flex-wrap:wrap;gap:6px 14px;padding:7px 10px;border-top:1px solid var(--line2);font-size:11.5px;color:var(--dim);min-width:0}
.bm-lg{display:inline-flex;align-items:center;gap:5px}
.bm-tablebox[hidden]{display:none}
.bm-t-l{font-size:11px;color:var(--soft);margin-top:2px}

@media(max-width:1100px){.bm-body{grid-template-columns:minmax(0,1fr) 280px}}
@media(max-width:700px){
  .bm-body{grid-template-columns:minmax(0,1fr)}
  .bm-canvas{height:60vh;min-height:300px}
  .bm-list{border-left:0;border-top:1px solid var(--line2);height:auto;min-height:0;max-height:65vh}
  .bm-grp-end,.tr-act{margin-left:0}
  .bm-panel{position:fixed;left:0;right:0;bottom:0;top:auto;width:auto;max-height:72vh;border-radius:14px 14px 0 0;z-index:900;
    box-shadow:0 -8px 28px rgba(15,23,42,.22);padding:12px 16px calc(14px + env(safe-area-inset-bottom))}
  .tr-pop-body{position:static;width:auto;margin-top:6px}
  .tr-groups{gap:8px}
}
@media (pointer:coarse){
  .bm-row-main{min-height:44px}
  .bm-eye{width:44px;min-height:44px}
  .bm-clrow,.bm-clusters>summary{min-height:44px}
  .bm-p-link{padding:10px 0}
  .tr-pop>summary{min-height:44px}
  .bm-range-track{height:62px}
  .bm-range-track::after{bottom:21px}
  .bm-hist{bottom:40px}
  .bm-thumb{height:44px}
  .bm-thumb::-webkit-slider-runnable-track{height:44px}
  .bm-thumb::-webkit-slider-thumb{width:26px;height:26px;margin-top:9px}
  .bm-thumb::-moz-range-thumb{width:22px;height:22px}
}
@media (forced-colors:active){
  .bm-canvas,.bm-panel{border:1px solid CanvasText}
}

/* The toolbar chip repeated what each tab already shows in its own workspace (a spinner while
   loading, the error when a read fails), so it is kept only for screen readers, as the live
   region that announces progress. */
#statuschip{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0;white-space:normal}

/* The chain picker carries the same 2px ink outline as the filled subject box beside it, so the
   two controls the whole page is computed from read as one pair. Its label is for screen readers
   only: the logo and chain name already say what it is. */
.chainpick-btn{border:2px solid var(--ink);border-radius:7px;font-weight:600;height:var(--subject-h,36px)}
.chainpick-btn:focus-visible{outline:3px solid #b45309;outline-offset:1px}

/* Touch screens get the full 44px square on icon buttons; the 34px desktop minimum is for mice. */
@media (hover:none),(pointer:coarse){button[data-icon]{min-width:44px;min-height:44px}}

/* The status line (data source, list state, last fetch) is plumbing. Monitor's coverage table and
   the Lists tab carry the same facts where they are read, so the bar keeps only its two actions. */
.sb-line{display:none}
.statusbar{justify-content:flex-end}
