:root{
  /* ONE TOKEN SCOPE (redesign spec §5.1). The app palette that used to live on .avb-app is
     the site's palette; the sibling palette that used to live here is gone, so no two pages
     can disagree about what --up or --bg means. --surface/--text/--amber stay as aliases for
     the few legacy rules that still read them. */
  --gutter:clamp(16px,3.5vw,72px);
  --bg:#04060C; --panel:#0A0D14; --panel-2:#101119; --raise:#151824;
  --surface:#0A0D14; --surface-2:#101119;
  --line:#1C2029; --line-soft:#141821; --line-2:#242A35;
  --field-bg:#121821; --field-line:#5A6779; --field-line-hover:#7C8A9C;
  --ink:#EAEEF4; --ink-2:#C7D0DB; --text:#EAEEF4; --dim:#8A94A2; --faint:#78828F;
  --btc:#F7931A; --btc-bd:rgba(247,147,26,.38); --btc-glow:rgba(247,147,26,.22); --btc-tint:rgba(247,147,26,.12);
  --amber:#F3AE1F; --amber-dim:#B27E2B;
  --up:#2BDF5F; --up-tint:rgba(43,223,95,.13); --up-bd:rgba(43,223,95,.35); --up-dim:#1A5C46;
  --base:#F3AE1F; --base-tint:rgba(243,174,31,.13); --base-bd:rgba(243,174,31,.35);
  --down:#F13334; --down-tint:rgba(241,51,52,.13); --down-bd:rgba(241,51,52,.35); --down-dim:#6B2530;
  --cand:#98A2AF; --upx:#33E1C4; --upx-dim:#1C5E54;
  --unclear:#8A94A6; --unclear-tint:rgba(138,148,166,.13); --unclear-bd:rgba(138,148,166,.35);
  --mono:var(--font-mono),'IBM Plex Mono',ui-monospace,'SF Mono',Menlo,monospace;
  --sans:var(--font-sans),'IBM Plex Sans',system-ui,-apple-system,sans-serif;
  --serif:var(--font-serif),'IBM Plex Serif',Georgia,serif;
  --display:var(--sans);
  /* SURFACES THAT WERE LITERALS (Kevin, 2026-09-08: the theme switch). Every translucent dark
     that used to be typed inline is a token now, so light mode is a second block of values and
     not a second stylesheet. well = the ground behind a control · glass = a popover · veil = a
     chip or backdrop over the board · scrim = a modal backdrop · hi-N = a highlight on a surface
     (white on dark, black on light) · found = the "found it" ring · hm-gap = the board's ground.
     ☢️ --hm-gap is DUPLICATED in lib/heatmap.ts (HM_GAP_DARK/LIGHT) — the dimmed fills blend
     toward it in JS. Change both. */
  --well:rgba(8,10,14,.7); --well-2:rgba(8,11,18,.8);
  --glass:rgba(10,13,20,.97); --veil:rgba(3,5,10,.72); --veil-2:rgba(3,5,10,.82);
  --scrim:rgba(2,4,8,.7); --vignette:rgba(2,4,8,.5); --shadow:rgba(0,0,0,.55);
  --hi-1:rgba(255,255,255,.03); --hi-2:rgba(255,255,255,.045); --hi-3:rgba(255,255,255,.08); --hi-4:rgba(255,255,255,.13);
  --ink-a1:rgba(233,239,246,.03); --ink-a2:rgba(233,239,246,.09); --ink-a3:rgba(233,239,246,.12);
  --found:#fff; --found-rgb:255,255,255; --dim-ink:#4a525e; --hi-5:rgba(255,255,255,.16); --scrim-soft:rgba(2,4,8,.62);
  --hm-gap:#03050a; --zone-up:#eafff2; --zone-down:#ffeaea; --placeholder:#A8B2BF; --down-ink:#FF7B7B;
  --hdr:52px; --wrap:1600px; --r:5px;
  color-scheme:dark;
  /* the six breakpoints, by name, for reading the file: xs 430 · sm 640 · md 900 · lg 1180 · xl 1440 */
}
/* LIGHT MODE — the same tokens, the other way round. Dark is the site's default and the card
   people share; light is a visitor's choice, kept in localStorage (lib/theme.ts) and stamped on
   <html> before paint (app/layout.tsx). The cell fills of the heat ramp do not change — they
   read on a light gap the way a finviz map does — so only what is drawn AGAINST the page moves:
   grounds, lines, inks, and the accents, which go a step deeper to hold contrast on white. */
:root[data-theme="light"]{
  --bg:#F3F5F8; --panel:#FFFFFF; --panel-2:#F7F9FB; --raise:#E8ECF1;
  --surface:#FFFFFF; --surface-2:#F7F9FB;
  --line:#D8DEE6; --line-soft:#E6EAF0; --line-2:#C6CED9;
  --field-bg:#FFFFFF; --field-line:#AEB8C6; --field-line-hover:#7C8A9C;
  --ink:#0E1420; --ink-2:#2A3341; --text:#0E1420; --dim:#5E6875; --faint:#66707D;
  /* the accents go a step deeper than their dark values: they are TEXT on white as often as
     they are fills, and 9.5–11px mono labels need 4.5:1 (--btc 4.1 on the page, 4.5 on a panel). */
  --btc:#B85F00; --btc-bd:rgba(184,95,0,.45); --btc-glow:rgba(184,95,0,.18); --btc-tint:rgba(184,95,0,.09);
  --amber:#9C6A08; --amber-dim:#8A6A25;
  --up:#0E7A36; --up-tint:rgba(14,122,54,.12); --up-bd:rgba(14,122,54,.4); --up-dim:#BFE6CD;
  --base:#9C6A08; --base-tint:rgba(156,106,8,.12); --base-bd:rgba(156,106,8,.4);
  --down:#D42728; --down-tint:rgba(212,39,40,.1); --down-bd:rgba(212,39,40,.4); --down-dim:#F2C6C8;
  --cand:#6B7684; --upx:#0A776A; --upx-dim:#BDE8E1;
  --unclear:#6F7A8A; --unclear-tint:rgba(111,122,138,.12); --unclear-bd:rgba(111,122,138,.4);
  --well:rgba(255,255,255,.7); --well-2:rgba(255,255,255,.85);
  --glass:rgba(255,255,255,.97); --veil:rgba(243,245,248,.78); --veil-2:rgba(243,245,248,.9);
  --scrim:rgba(24,30,42,.42); --vignette:rgba(24,30,42,.08); --shadow:rgba(24,30,42,.18);
  --hi-1:rgba(14,20,32,.03); --hi-2:rgba(14,20,32,.05); --hi-3:rgba(14,20,32,.08); --hi-4:rgba(14,20,32,.12);
  --ink-a1:rgba(14,20,32,.03); --ink-a2:rgba(14,20,32,.09); --ink-a3:rgba(14,20,32,.14);
  --found:#0E1420; --found-rgb:14,20,32; --dim-ink:#AEB6C2; --hi-5:rgba(14,20,32,.16); --scrim-soft:rgba(24,30,42,.36);
  --hm-gap:#E4E8EE; --zone-up:#0F6B33; --zone-down:#9E1F20; --placeholder:#5E6875; --down-ink:#B71C1C;
  color-scheme:light;
}
:root[data-theme="light"] .avb-app{--mc-hi:#8A6A1E;--mc-lo:#6D4FD6}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--text);font-family:var(--sans);font-size:15px;line-height:1.5;
  -webkit-font-smoothing:antialiased;font-feature-settings:"tnum" 1;overflow-x:hidden}
a{color:inherit;text-decoration:none}
svg{max-width:100%}
.wrap{max-width:var(--wrap);margin-inline:auto;padding-inline:clamp(.9rem,2.5vw,1.6rem)}
:focus-visible{outline:1.5px solid var(--amber);outline-offset:2px}
.mono{font-family:var(--mono)}
.num{font-family:var(--mono);font-variant-numeric:tabular-nums}
.up{color:var(--up)} .down{color:var(--down)} .cand{color:var(--cand)} .amber{color:var(--amber)}
.dim{color:var(--dim)} .faint{color:var(--faint)}

/* concept strip */
.strip{background:var(--surface);border-bottom:1px solid var(--line)}
.strip .wrap{display:flex;justify-content:space-between;gap:1rem;padding-block:.35rem;
  font-family:var(--mono);font-size:.76rem;letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}
.strip b{color:var(--amber);font-weight:600}
@media(max-width:640px){.strip .r{display:none}}

/* top bar */
.topbar{position:sticky;top:0;z-index:30;background:color-mix(in srgb,var(--bg) 86%,transparent);
  backdrop-filter:blur(8px);border-bottom:1px solid var(--line)}
.topbar .wrap{display:flex;align-items:center;gap:1.2rem;height:52px}
.logo{display:flex;align-items:center;gap:.55rem;font-family:var(--mono);font-weight:600;letter-spacing:.02em}
.logo .tk{font-size:.95rem}
.logo .tk b{color:var(--amber)}
.logo .slash{color:var(--faint)}
.logo .dn{font-size:.7rem;color:var(--faint);border:1px solid var(--line);border-radius:3px;padding:.05rem .3rem;letter-spacing:.1em;text-transform:uppercase}
.topnav{display:flex;gap:1.1rem;margin-left:auto;align-items:center}
.topnav a{font-family:var(--mono);font-size:.82rem;letter-spacing:.04em;color:var(--dim);transition:color .15s}
.topnav a:hover,.topnav a.active{color:var(--text)}
.tag{font-family:var(--mono);font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;color:var(--faint);border:1px solid var(--line);border-radius:100px;padding:.2rem .55rem}
@media(max-width:720px){.topnav a.hideable{display:none}}

/* denominator toggle — the signature */
.denomtoggle{display:inline-flex;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;font-family:var(--mono)}
.denomtoggle button{background:transparent;color:var(--dim);border:0;cursor:pointer;font-family:inherit;
  font-size:.84rem;font-weight:600;padding:.3rem .7rem;letter-spacing:.03em;transition:background .15s,color .15s}
.denomtoggle button.on{background:var(--amber);color:#1a1206}
.denomtoggle button:not(.on):hover{color:var(--text);background:var(--surface-2)}

/* hero line */
.hero{border-bottom:1px solid var(--line);background:linear-gradient(180deg,var(--surface) 0%,var(--bg) 100%)}
.hero .wrap{padding-block:clamp(1rem,2.2vw,1.6rem);display:flex;justify-content:space-between;align-items:flex-end;gap:1.5rem;flex-wrap:wrap}
.hero h1{font-family:var(--sans);font-weight:700;font-size:clamp(2rem,4vw,3rem);letter-spacing:-.025em;margin:0;line-height:1.12}
.hero h1 .b{color:var(--amber)}
.hero .herolens{margin:.85rem 0 0;font-size:.82rem;letter-spacing:.06em;text-transform:uppercase;color:var(--faint)}
.hero .herolens::before{content:"◧ ";color:var(--amber)}
.hero p{margin:.55rem 0 0;color:var(--dim);max-width:64ch;font-size:1.05rem;line-height:1.55}
.hero .live{font-family:var(--mono);font-size:.76rem;letter-spacing:.1em;text-transform:uppercase;color:var(--faint);display:flex;align-items:center;gap:.45rem}
.hero .live i{width:6px;height:6px;border-radius:50%;background:var(--up);box-shadow:0 0 6px var(--up);animation:pulse 2.4s ease-in-out infinite;font-style:normal}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}

/* stat ribbon */
.ribbon{border-bottom:1px solid var(--line);background:var(--surface)}
.ribbon .wrap{display:grid;grid-template-columns:repeat(6,1fr);gap:0}
.stat{padding:1rem clamp(.7rem,1.4vw,1.4rem);border-left:1px solid var(--line-soft)}
.stat:first-child{border-left:0}
.stat .k{font-family:var(--mono);font-size:.76rem;letter-spacing:.08em;text-transform:uppercase;color:var(--dim);white-space:nowrap;display:flex;align-items:center;gap:.3rem}
.stat .v{font-family:var(--mono);font-size:1.65rem;font-weight:600;margin-top:.3rem;letter-spacing:-.02em}
@media(max-width:900px){.ribbon .wrap{grid-template-columns:repeat(3,1fr)}.stat:nth-child(4){border-left:0}}
@media(max-width:560px){.ribbon .wrap{grid-template-columns:repeat(2,1fr)}.stat:nth-child(3){border-left:0}}

/* toolbar: the lens (timeframe) + view/denomination controls */
.toolbar{position:sticky;top:52px;z-index:20;background:color-mix(in srgb,var(--bg) 92%,transparent);backdrop-filter:blur(6px);
  border-bottom:1px solid var(--line)}
.toolbar .wrap{display:flex;align-items:center;gap:.7rem;padding-block:.6rem;flex-wrap:wrap}
.lens-lead{font-size:.72rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint)}
.tools{margin-left:auto;display:inline-flex;align-items:center;gap:.5rem;flex-wrap:wrap}

/* the lens control — the signature interaction. Each option teaches its own return window. */
.lens{display:inline-flex;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--surface)}
.lens button{position:relative;background:transparent;border:0;border-right:1px solid var(--line-soft);cursor:pointer;
  font-family:var(--mono);color:var(--dim);padding:.34rem 1rem .38rem;display:flex;flex-direction:column;align-items:center;gap:.08rem;
  transition:background .15s,color .15s}
.lens button:last-child{border-right:0}
.lens .lb{font-size:.88rem;font-weight:600;letter-spacing:.01em}
.lens .lr{font-size:.66rem;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.lens button:not(.on):hover{background:var(--surface-2);color:var(--text)}
.lens button.on{background:var(--raise);color:var(--text)}
.lens button.on .lr{color:var(--amber)}
.lens button.on::after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;background:var(--amber)}
.tabs{display:inline-flex;gap:.15rem;background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:.15rem}
.tabs button{background:transparent;border:0;color:var(--dim);font-family:var(--mono);font-size:.82rem;font-weight:600;
  padding:.3rem .6rem;border-radius:3px;cursor:pointer;letter-spacing:.02em;white-space:nowrap}
.tabs button.on{background:var(--raise);color:var(--text)}
.tabs button:not(.on):hover{color:var(--text)}
.chip{background:var(--surface);border:1px solid var(--line);color:var(--dim);font-family:var(--mono);font-size:.8rem;
  padding:.3rem .55rem;border-radius:100px;cursor:pointer;display:inline-flex;align-items:center;gap:.35rem}
.chip .dot{width:6px;height:6px;border-radius:50%}
.chip.on{border-color:var(--amber);color:var(--text)}
.search{margin-left:auto;background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  color:var(--text);font-family:var(--mono);font-size:.84rem;padding:.35rem .6rem;min-width:130px}
.search::placeholder{color:var(--faint)}

/* the table */
.tablewrap{overflow-x:auto}
table.basket{width:100%;border-collapse:separate;border-spacing:0;font-family:var(--mono);font-size:.92rem}
.basket thead th{background:var(--bg);
  text-align:right;padding:.7rem 1.05rem;border-bottom:1px solid var(--line);
  font-size:.78rem;letter-spacing:.05em;text-transform:uppercase;color:var(--dim);font-weight:600;white-space:nowrap;cursor:pointer;user-select:none}
.basket thead th.l{text-align:left}
.basket thead th:hover{color:var(--text)}
.basket thead th .ar{color:var(--amber);margin-left:.2rem}
.basket tbody td{text-align:right;padding:.9rem 1.05rem;border-bottom:1px solid var(--line-soft);white-space:nowrap}
.basket tbody td.l{text-align:left}
.basket tbody td.num{font-size:.98rem}
.basket tbody tr{cursor:pointer;transition:background .1s}
.basket tbody tr:hover{background:var(--surface)}
.basket tbody tr.open{background:var(--surface)}
.coincell{display:flex;align-items:center;gap:.6rem}
.coincell .sym{font-weight:700;font-size:1.05rem;color:var(--text)}
.coincell .nm{color:var(--dim);font-size:.9rem}
.coinlogo{border-radius:50%;flex:0 0 auto;vertical-align:middle;background:var(--surface-2)}
img.coinlogo{object-fit:cover;display:block}
.coinlogo--mono{display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);color:var(--dim);font-family:var(--mono);font-weight:600;text-transform:uppercase;letter-spacing:-.03em}
.cardname{display:inline-flex;align-items:center;gap:.5rem;flex-wrap:wrap}
.coincell .rank{color:var(--faint);width:1.6rem;text-align:right;font-size:.78rem}
.deemph{opacity:.85}
.locked .lockcell{filter:blur(4px);opacity:.6;user-select:none}
.lockrow td{color:var(--faint)}
.lockpill{font-family:var(--mono);font-size:.72rem;color:var(--amber);border:1px solid var(--amber-dim);border-radius:100px;padding:.1rem .5rem}

/* low-conviction inline tag (list rows) */
.lowconv{font-family:var(--mono);font-size:.66rem;color:var(--faint);border:1px solid var(--line);border-radius:3px;
  padding:.05rem .3rem;text-transform:uppercase;letter-spacing:.05em;margin-left:.4rem;white-space:nowrap}

/* the tri-dot lens spine — one shape per timeframe, tinted to that timeframe's state.
   Rendered only when a coin disagrees with itself across timeframes (the product's edge). */
.tfspine{display:inline-flex;align-items:center;gap:.34rem;margin-left:.5rem;vertical-align:middle}
.tfd{display:inline-flex;align-items:center;gap:.1rem;line-height:1;padding-bottom:1px;border-bottom:1px solid transparent}
.tfd.cur{border-bottom-color:currentColor}
.tfd i{font-style:normal;font-size:.7rem;line-height:1}
.tfd em{font-style:normal;font-family:var(--mono);font-size:.64rem;color:var(--faint);text-transform:uppercase}
.tfd.cur em{color:var(--dim)}

/* detail panel (expanded row) */
.detail td{padding:0!important;border-bottom:1px solid var(--line)!important;background:var(--surface)}
.detailin{display:grid;grid-template-columns:1.4fr 1fr;gap:1.2rem;padding:1.1rem 1.1rem 1.3rem}
@media(max-width:820px){.detailin{grid-template-columns:1fr}}
.detailin .disc{grid-column:1/-1;font-family:var(--mono);font-size:.76rem;color:var(--amber);
  border-left:2px solid var(--amber-dim);padding-left:.6rem;margin-bottom:.2rem}
.dchart{background:var(--bg);border:1px solid var(--line);border-radius:var(--r);padding:.8rem}
.dhead{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:.5rem;font-family:var(--mono);font-size:.74rem;letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}
.profilegrid{display:grid;grid-template-columns:repeat(2,1fr);gap:.5rem .9rem;margin-bottom:.9rem}
.profilegrid .k{font-family:var(--mono);font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}
.profilegrid .v{font-family:var(--mono);font-size:.95rem;font-weight:600;margin-top:.1rem}
.reads{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}
.reads li{font-size:.88rem;line-height:1.4;padding-left:.9rem;position:relative;color:var(--text)}
.reads li::before{content:"›";position:absolute;left:0;color:var(--up)}
.reads b{font-family:var(--mono);color:var(--amber);font-weight:600}
.invalidbox{margin-top:.8rem;border:1px dashed var(--down-dim);border-radius:var(--r);padding:.6rem .7rem;background:color-mix(in srgb,var(--down) 6%,transparent)}
.invalidbox .k{font-family:var(--mono);font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;color:var(--down);margin-bottom:.25rem}
.invalidbox p{margin:0;font-size:.88rem;line-height:1.4;color:var(--text)}
.invalidbox b{font-family:var(--mono);color:var(--down);font-weight:600}
.detaillink{font-family:var(--mono);font-size:.8rem;color:var(--amber);margin-top:.7rem;display:inline-block}

/* generic section + buttons for secondary pages */
.section{padding-block:clamp(1.6rem,3vw,2.4rem)}
.section h2{font-family:var(--sans);font-weight:600;font-size:1.5rem;letter-spacing:-.01em;margin:0 0 .3rem}
.section .eyebrow{font-family:var(--mono);font-size:.74rem;letter-spacing:.12em;text-transform:uppercase;color:var(--amber);margin:0 0 .5rem}
.section .lede{color:var(--dim);max-width:64ch;margin:0 0 1.4rem}
.btn{font-family:var(--mono);font-size:.82rem;letter-spacing:.04em;padding:.5rem .9rem;border-radius:var(--r);
  border:1px solid var(--line);background:var(--surface);color:var(--text);cursor:pointer;display:inline-flex;gap:.4rem;align-items:center}
.btn:hover{border-color:var(--dim)}
.btn--amber{background:var(--amber);color:#1a1206;border-color:var(--amber)}
/* A button-shaped statement, not a control: what the member tier says before it exists. */
.btn--soon{color:var(--dim);border-style:dashed;cursor:default;pointer-events:none}

/* ledger + pricing panels (dark) */
.panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.ltable{width:100%;border-collapse:collapse;font-family:var(--mono);font-size:.88rem}
.ltable th,.ltable td{text-align:right;padding:.6rem .9rem;border-bottom:1px solid var(--line-soft)}
.ltable th{font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);font-weight:600}
.ltable th.l,.ltable td.l{text-align:left}
.ltable tbody tr:hover{background:var(--surface-2)}
.ltable .stamp2::before{content:"✓ ";color:var(--up)}
.ledger-stats{display:flex;flex-wrap:wrap;gap:1.4rem;padding:.9rem 1rem;border-bottom:1px solid var(--line);background:var(--surface-2)}
.pricegrid{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
@media(max-width:720px){.pricegrid{grid-template-columns:1fr}}
.plan{border:1px solid var(--line);border-radius:var(--r);padding:1.3rem;background:var(--surface)}
.plan.member{border-color:var(--amber-dim)}
.plan .pname{font-family:var(--mono);font-size:.74rem;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.plan.member .pname{color:var(--amber)}
.plan .price{font-family:var(--mono);font-size:2rem;font-weight:600;margin:.4rem 0}
.plan .price small{font-size:.82rem;color:var(--dim);font-weight:500}
.plan ul{list-style:none;margin:.8rem 0 0;padding:0;display:flex;flex-direction:column;gap:.5rem}
.plan li{font-size:.9rem;padding-left:1.3rem;position:relative;color:var(--text)}
.plan li::before{content:"+";position:absolute;left:0;color:var(--up);font-family:var(--mono)}
.plan li.no{color:var(--faint)} .plan li.no::before{content:"–";color:var(--faint)}

/* report detail page grid */
.reportgrid{display:grid;grid-template-columns:1.5fr 1fr;gap:0}
@media(max-width:760px){.reportgrid{grid-template-columns:1fr}.reportgrid>div:first-child{border-right:0!important;border-bottom:1px solid var(--line)}}

/* report: per-timeframe state strip — the cross-lens read at a glance */
.tfstrip{display:grid;grid-template-columns:repeat(3,1fr);gap:0;border-bottom:1px solid var(--line)}
.tfchip{display:flex;flex-direction:column;gap:.25rem;padding:.75rem 1.1rem;border-left:3px solid var(--line);border-right:1px solid var(--line-soft)}
.tfchip:first-child{border-left-width:3px}
.tfchip:last-child{border-right:0}
.tfchip .tk{font-size:.68rem;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.tfchip .ts{font-family:var(--mono);font-size:.9rem;font-weight:600;letter-spacing:.01em}
.tfchip .tv{font-size:.76rem}
@media(max-width:560px){.tfstrip{grid-template-columns:1fr}.tfchip{border-right:0;border-bottom:1px solid var(--line-soft)}}

/* footer */
footer.foot{border-top:1px solid var(--line);background:var(--surface);margin-top:2rem}
footer.foot .wrap{padding-block:1.6rem;display:flex;justify-content:space-between;gap:1.4rem;flex-wrap:wrap;align-items:flex-start}
.foot-line{font-family:var(--sans);font-size:1.05rem;max-width:30ch;color:var(--text)}
.foot-line b{color:var(--amber);font-weight:600}
.foot-disc{font-family:var(--mono);font-size:.72rem;line-height:1.7;color:var(--faint);max-width:52ch}
.foot-disc b{color:var(--down)}

/* ===== stage-sectioned board (BasketDashboard) ===== */
.board{padding-block:.4rem 3rem}
.board-note{font-size:.74rem;color:var(--faint);margin-top:1.4rem;line-height:1.7}
/* each section is a self-contained panel with a stage-colored top edge */
.sec{margin-top:2.2rem;border:1px solid var(--line);border-top:3px solid var(--sec-color,var(--line));border-radius:var(--r);background:var(--surface);overflow:hidden}
.sec:first-child{margin-top:.7rem}

/* ===== side-by-side board (view="board"): the three states as columns, meat above the fold ===== */
.board .wrap.cols{display:grid;grid-template-columns:repeat(3,1fr);gap:.9rem;align-items:start}
.board .wrap.cols .sec{margin-top:0}
.board .wrap.cols .board-note{grid-column:1/-1;margin-top:.5rem}
.board .wrap.cols .sechead{padding:.8rem .9rem .7rem}
.board .wrap.cols .sechead h2{font-size:1.15rem}
.board .wrap.cols .secstat{flex-basis:100%}
.board .wrap.cols .subtitle{padding:.55rem .9rem;font-size:.88rem}
@media(max-width:1040px){.board .wrap.cols{grid-template-columns:1fr}.board .wrap.cols .sec{margin-top:1.4rem}.board .wrap.cols .sec:first-child{margin-top:.7rem}}

/* compact column list — one lean row per coin */
.collist{padding:.3rem .5rem .6rem}
.crc{border-bottom:1px solid var(--line-soft)}
.crc:last-child{border-bottom:0}
.crc.soft{opacity:.72}
.crc-row{display:grid;grid-template-columns:22px minmax(0,1fr) auto auto auto;align-items:center;gap:.5rem;padding:.42rem .35rem;border-radius:4px}
.crc-row.clickable{cursor:pointer}
.crc-row.clickable:hover{background:var(--surface-2)}
.crc.open .crc-row{background:var(--surface-2)}
.crc-id{display:flex;align-items:baseline;gap:.4rem;min-width:0}
.crc-id .sym{font-family:var(--mono);font-weight:700;font-size:.92rem}
.crc-id .nm{font-family:var(--mono);font-size:.76rem;color:var(--dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.crc-pct{font-family:var(--mono);font-weight:700;font-size:1.02rem;min-width:3.5rem;text-align:right}
.crc-detail{padding:.15rem .1rem .5rem;border-top:1px dashed var(--line-soft)}
.sechead{display:flex;align-items:baseline;gap:.85rem;flex-wrap:wrap;padding:1rem 1.15rem .85rem;border-bottom:1px solid var(--line);background:color-mix(in srgb,var(--sec-color,var(--surface)) 8%,var(--surface))}
.sechead .icon{font-size:1.3rem}
.sechead h2{font-size:1.5rem;font-weight:700;letter-spacing:-.02em;margin:0;display:flex;align-items:center;gap:.55rem}
.sechead .count{font-family:var(--mono);font-size:.84rem;letter-spacing:.05em;text-transform:uppercase;color:var(--dim)}
.sechead .count b{color:var(--text);font-weight:600}
.sechead .count .locked{color:var(--amber)}
.sechead .unlock{margin-left:auto;font-family:var(--mono);font-size:.78rem;color:var(--amber);border:1px solid var(--amber-dim);border-radius:100px;padding:.22rem .7rem;cursor:pointer;white-space:nowrap}
.sechead .unlock:hover{background:color-mix(in srgb,var(--amber) 12%,transparent)}
.sechead h2{color:var(--sec-color)}
.sechead .secstat{margin-left:auto;font-family:var(--mono);font-size:.8rem;letter-spacing:.03em;color:var(--dim);white-space:nowrap}
.subtitle{color:var(--dim);font-size:.95rem;line-height:1.55;margin:0;padding:.85rem 1.15rem;max-width:88ch}
.subtitle.faint{color:var(--faint);padding-top:0}
.secempty{margin:0 1.15rem 1.15rem;border:1px dashed var(--line);border-radius:var(--r);background:var(--surface-2);
  padding:1rem 1.1rem;color:var(--faint);font-size:.88rem;letter-spacing:.02em}

/* temporary "reveal all" dev toggle */
.revealbtn{font-family:var(--mono);font-size:.8rem;letter-spacing:.02em;padding:.32rem .7rem;border-radius:var(--r);border:1px solid var(--line);background:var(--surface);color:var(--dim);cursor:pointer;white-space:nowrap}
.revealbtn:hover{color:var(--text);border-color:var(--dim)}
.revealbtn.on{background:var(--amber);color:#1a1206;border-color:var(--amber)}

/* inner content sits inside the panel */
.sec .fallback,.sec .summary{margin:0 1.15rem 1.15rem}
.sec .grid{padding:.1rem 1.15rem 1.15rem}
.basket--sec tbody tr:last-child td{border-bottom:0}
.basket--sec thead th:first-child,.basket--sec tbody td:first-child{padding-left:1rem}
.basket--sec thead th:last-child,.basket--sec tbody td:last-child{padding-right:1rem}

/* section list table reuses .basket; strip the sort affordances */
.basket--sec thead th{cursor:default;background:var(--surface-2)}
.basket tbody tr.lockrow{cursor:default}
.basket tbody tr.clickable{cursor:pointer}
.miniwatch{font-family:var(--mono);font-size:.66rem;color:var(--amber);border:1px solid var(--amber-dim);border-radius:3px;padding:.05rem .3rem;text-transform:uppercase;letter-spacing:.05em;margin-left:.4rem}

/* quiet-week fallback + candidate summary */
.fallback{border:1px dashed var(--line);border-radius:var(--r);background:var(--surface-2);padding:.9rem 1rem;margin-bottom:.9rem}
.fallback .k{font-family:var(--mono);font-size:.74rem;letter-spacing:.06em;text-transform:uppercase;color:var(--dim)}
.fallback .k b{color:var(--amber)}
.fallback p{margin:.35rem 0 0;color:var(--faint);font-size:.88rem}
.summary{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap;background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:.7rem .9rem;margin-bottom:.8rem}
.summary .n{font-family:var(--mono);font-size:1.3rem;font-weight:600}
.summary .t{color:var(--dim);font-size:.88rem}
.summary .lockpill{margin-left:auto}

/* card view */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));gap:.85rem}
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:.9rem 1rem;position:relative;transition:border-color .12s}
.card.clickable{cursor:pointer}
.card.clickable:hover{border-color:var(--dim)}
.card .crow{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
.card .sym{font-family:var(--mono);font-weight:700;font-size:1.08rem}
.card .nm{color:var(--dim);font-size:.88rem;font-family:var(--mono)}
.card .cardspark{margin:.6rem 0 .6rem;height:44px}
.card .cardspark svg{width:100%;height:44px;display:block}
.card .metrics{display:flex;align-items:center;justify-content:space-between;gap:.5rem;font-family:var(--mono)}
.card .big{font-size:1.55rem;font-weight:700;letter-spacing:-.01em}
.card .biglabel{font-size:.72rem;letter-spacing:.07em;text-transform:uppercase;color:var(--dim)}
.card .meta{font-family:var(--mono);font-size:.84rem;color:var(--dim);margin-top:.6rem;border-top:1px solid var(--line-soft);padding-top:.55rem}
.card.locked{border-style:dashed}
.card.locked .lockable{filter:blur(5px);opacity:.55;user-select:none;pointer-events:none}
.card.analysis-locked .lockable{filter:blur(4px);opacity:.5;user-select:none}
.card .lockoverlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.25rem;background:color-mix(in srgb,var(--bg) 30%,transparent);border-radius:var(--r)}
.card .lockoverlay .pill{font-family:var(--mono);font-size:.72rem;color:var(--amber);border:1px solid var(--amber-dim);border-radius:100px;padding:.12rem .55rem;background:var(--surface)}
.card .lockoverlay .sub{font-family:var(--mono);font-size:.67rem;color:var(--faint)}
.card .analysistag{font-family:var(--mono);font-size:.68rem;color:var(--amber);border:1px solid var(--amber-dim);border-radius:100px;padding:.08rem .45rem;position:absolute;top:.6rem;right:.6rem}
.card .exphint{position:absolute;bottom:.62rem;right:.7rem;font-family:var(--mono);font-size:.7rem;color:var(--faint);opacity:0;transition:opacity .12s}
.card.clickable:hover .exphint{opacity:1}

/* expanded card — spans the full grid width */
.card.cardopen{grid-column:1/-1;border-color:var(--dim)}
.card.cardopen .detailin{padding:.9rem 0 .2rem}
.closebtn{background:transparent;border:1px solid var(--line);color:var(--dim);border-radius:3px;cursor:pointer;font-family:var(--mono);font-size:.82rem;line-height:1;padding:.16rem .42rem}
.closebtn:hover{color:var(--text);border-color:var(--dim)}

/* invalidation lives in a compact ⓘ popover now (was a full-width red box) */
.detailfoot{display:flex;align-items:center;justify-content:space-between;gap:.6rem;margin-top:.7rem}
.detailfoot .detaillink{margin-top:0}
.infobtn{background:transparent;border:0;color:var(--dim);font-size:.95rem;line-height:1;cursor:pointer;padding:.1rem .15rem;display:inline-flex;align-items:center;border-radius:50%}
.infobtn:hover,.infobtn[aria-expanded="true"]{color:var(--amber)}
.infopop{margin-top:.55rem;background:var(--surface-2);border:1px solid var(--line);border-left:2px solid var(--down-dim);border-radius:var(--r);padding:.6rem .75rem}
.infopop .lead{margin:0 0 .5rem;font-family:var(--sans);font-size:.84rem;line-height:1.45;color:var(--dim)}
.infopop .k{font-family:var(--mono);font-size:.67rem;letter-spacing:.08em;text-transform:uppercase;color:var(--down);margin-bottom:.2rem}
.infopop p:last-child{margin:0;font-size:.88rem;line-height:1.45;color:var(--text)}
.infopop b{font-family:var(--mono);color:var(--down);font-weight:600}

@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}

/* ============================================================================
   AltVsBTC Dashboard — the "denominator" identity (see /BRAND.md), scoped under
   .avb-app so its palette + component CSS never leak into the secondary pages
   (reports / ledger / pricing keep the :root tokens above). Type = IBM Plex
   (Sans for display/body, Mono for the whole readout layer) loaded in layout.tsx.
   Bitcoin-orange is the reserved anchor — it only ever means "the reference".
   ========================================================================== */
.avb-app{
  display:flex;flex-direction:column;min-height:100vh;
  background:var(--bg);color:var(--ink);font-family:var(--display);font-size:15px;line-height:1.45;
  -webkit-font-smoothing:antialiased;font-variant-numeric:tabular-nums;letter-spacing:.005em}
.avb-app .up{color:var(--up)} .avb-app .down{color:var(--down)}
.avb-app .base{color:var(--base)} .avb-app .btc{color:var(--btc)}
.avb-app .unclear{color:var(--unclear)}
/* the readout layer — every number, label, tick, pill and state name is mono.
   ☢️ This list used to run straight into the .denomtag rule below: a comment sat between the
   last selector and its declaration block, so CSS read the whole thing as ONE selector list
   and gave the orange "/BTC" chip — display:inline-flex, a border, a radius and padding — to
   every `thead th`, `td.n`, `td.rank`, `svg text`, `.big`, `.cap` and `.sym` in the app.
   inline-flex on a `td` drops it out of table layout, which is why the macro table's cells
   stacked on top of each other. The list now terminates in its own block. */
.avb-app .cap,.avb-app .big,.avb-app .s2,
.avb-app thead th,.avb-app td.n,.avb-app td.rank,.avb-app .sym,
.avb-app .btcw .lbl,.avb-app .btcw .px,.avb-app .tf button,
.avb-app svg text,.avb-app .baselbl{font-family:var(--mono);font-variant-numeric:tabular-nums}

/* the denominator tag — the signature motif, an orange "/BTC" chip */
.avb-app .denomtag{display:inline-flex;align-items:center;gap:4px;font-size:11.5px;font-weight:600;
  color:var(--btc);border:1px solid var(--btc-bd);border-radius:6px;padding:2px 7px;letter-spacing:.05em;
  white-space:nowrap;line-height:1.4;text-shadow:none}
.avb-app .denomtag .s{opacity:.6}

/* header — see .sh-* below; the rail is gone */
.avb-app a:focus-visible,.avb-app button:focus-visible{outline:2px solid var(--btc);outline-offset:2px;border-radius:6px}

/* top bar */
.avb-app .main{min-width:0;flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
.avb-app .pagebar{display:flex;align-items:center;gap:22px;padding:9px var(--gutter);border-bottom:1px solid var(--line)}
.avb-app .topbar .sub{color:var(--dim);font-weight:600;font-size:15px}
.avb-app .btcw{margin-left:auto;display:flex;align-items:center;gap:12px}
.avb-app .btcw .lbl{font-size:12.5px;color:var(--faint);font-weight:600}
.avb-app .btcw .px{font-size:16px;font-weight:700}
.avb-app .btcw .px .pc{font-size:15px;font-weight:700;margin-left:5px}
.avb-app .tf{display:inline-flex;background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:3px}
.avb-app .tf button{background:transparent;border:0;color:var(--dim);font-weight:700;font-size:14px;padding:6px 11px;border-radius:6px;cursor:pointer}
.avb-app .tf button.on{background:var(--raise);color:var(--ink);box-shadow:inset 0 0 0 1px var(--line)}

/* content */
.avb-app .content{padding:11px 32px 14px;display:flex;flex-direction:column;gap:13px;max-width:1920px;width:100%;margin:0 auto}
.avb-app .shell-content{font-size:15px;line-height:1.5}
.avb-app h1.title{margin:0 0 3px;font-size:23px;font-weight:700;letter-spacing:-.02em}
.avb-app .lead{color:var(--dim);font-size:14.5px;margin:0}
.avb-app .lead .asof{color:var(--faint)}

/* top section — Altcoin Dominance fills the tall left column; the other six modules sit in an
   equal 3×2 grid to its right (row 1: Distribution · Altseason · Regime, row 2: signal modules). */
.avb-app .topgrid{display:grid;grid-template-columns:1.25fr 1fr 1fr 1fr;grid-auto-rows:auto;gap:12px;align-items:stretch}
/* One row now that Distribution, Recent Changes and the Opportunity Scanner are gone —
   a two-row span left an empty half-grid beside the dominance card. */
.avb-app .topgrid > .domcard{grid-column:1;grid-row:1}
.avb-app .topgrid > .card{padding:12px 14px;min-width:0}

/* row-2 signal modules (BTC pressure · recent changes · opportunity scanner) */
.avb-app .modcard{gap:2px;container-type:inline-size}
.avb-app .modcard .rr-hd h3{font-size:14px}
.avb-app .modnote{font-size:12px;color:var(--dim);margin:8px 0 0;line-height:1.4}
.avb-app .modnote b{color:var(--ink);font-weight:700}
/* BTC dominance pressure */
.avb-app .press{display:flex;align-items:center;gap:13px;margin-top:11px}
.avb-app .pbar{flex:1;height:13px;border-radius:7px;background:var(--panel-2);overflow:hidden;border:1px solid var(--line)}
.avb-app .pfill{height:100%;border-radius:7px;transition:width .25s ease}
.avb-app .pread{flex:none;text-align:right}
.avb-app .pword{font-family:var(--mono);font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}
.avb-app .pscore{font-family:var(--mono);font-size:21px;font-weight:700;line-height:1.05}
.avb-app .pscore i{font-style:normal;font-size:12px;color:var(--dim);font-weight:600}
/* recent state changes — two columns (improving / weakening); the transition is two tinted
   state chips (Down/Base/Up, coloured red/amber/green) so from→to reads at a glance */
.avb-app .chcols{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:10px}
.avb-app .chcol{min-width:0}
.avb-app .chcol-hd{font-family:var(--mono);font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px}
.avb-app .chcol-hd.u{color:var(--up)} .avb-app .chcol-hd.d{color:var(--down)}
.avb-app .chrow{display:flex;align-items:center;justify-content:space-between;gap:6px;row-gap:2px;margin-bottom:7px;flex-wrap:wrap}
/* card too narrow for two 140px columns → stack Improving over Weakening instead of bleeding */
@container (max-width:300px){.avb-app .chcols{grid-template-columns:1fr;gap:10px}}
.avb-app .chrow .chsym{font-family:var(--mono);font-weight:700;font-size:12.5px}
.avb-app .chg{display:inline-flex;align-items:center;gap:4px}
.avb-app .chg em{font-style:normal;color:var(--faint);font-size:11px}
.avb-app .sp{font-family:var(--mono);font-style:normal;font-weight:700;font-size:10px;padding:2px 6px;border-radius:5px;letter-spacing:.02em;line-height:1.35}
.avb-app .sp.u{color:var(--up);background:var(--up-tint)}
.avb-app .sp.b{color:var(--base);background:var(--base-tint)}
.avb-app .sp.d{color:var(--down);background:var(--down-tint)}
.avb-app .sp.x{color:var(--unclear);background:var(--unclear-tint)}
.avb-app .chempty{color:var(--faint);font-family:var(--mono);font-size:12px}
/* module coin rows are links to the coin's report — give them the affordance the tape chips have */
.avb-app a.chrow,.avb-app a.opp{cursor:pointer;border-radius:6px;margin-inline:-4px;padding:2px 4px;transition:background .12s}
.avb-app a.chrow:hover,.avb-app a.opp:hover{background:var(--raise)}
.avb-app a.chrow:hover .chsym,.avb-app a.opp:hover .osym{color:var(--btc)}
/* opportunity scanner */
.avb-app .opps{display:flex;flex-direction:column;gap:9px;margin-top:11px}
.avb-app .opp{display:flex;align-items:center;gap:9px;min-width:0}
.avb-app .opp .odot{width:8px;height:8px;border-radius:50%;background:var(--up);flex:none;box-shadow:0 0 7px var(--up)}
.avb-app .opp .osym{font-family:var(--mono);font-weight:700;font-size:13px;min-width:56px;flex:none}
.avb-app .opp .olbl{font-family:var(--mono);color:var(--dim);font-size:11.5px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.avb-app .donut{display:flex;gap:13px;align-items:center;margin-top:4px}
.avb-app .donut .leg{font-size:12.5px;color:var(--ink-2);display:flex;flex-direction:column;gap:7px;min-width:0;flex:1}
.avb-app .donut .leg span{display:flex;align-items:center;gap:7px;min-width:0;overflow:hidden}
/* the LABEL is the shrinkable element — the % value stays whole at any card width */
.avb-app .donut .leg span .t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.avb-app .donut .leg b{flex:none}
.avb-app .donut .leg i{width:9px;height:9px;border-radius:50%;flex:none}
.avb-app .donut .leg b{margin-left:auto;font-weight:700;color:var(--ink)}

/* cards + the full-width table */
.avb-app .card{border:1px solid var(--line);border-radius:13px;background:var(--panel);display:flex;flex-direction:column}
.avb-app .table-card{width:100%}
.avb-app .card > .hd{display:flex;align-items:center;gap:12px;padding:16px 18px}
.avb-app .card > .hd h3{margin:0;font-size:16px;font-weight:700}
/* table header: the timeframe lens + search sit clustered on the right */
.avb-app .table-card .hd .tf{margin-left:auto}
.avb-app .table-card .hd .search{margin-left:0}
.avb-app .search{margin-left:auto;display:flex;align-items:center;gap:8px;background:var(--panel-2);border:1px solid var(--line);border-radius:9px;padding:8px 12px;min-width:210px;color:var(--faint)}
.avb-app .search svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.8}
.avb-app .search input{background:transparent;border:0;outline:0;color:var(--ink);font:inherit;font-size:14px;width:100%;padding:0}
.avb-app .search input::placeholder{color:var(--faint)}
/* three state columns of the "Altcoins vs Bitcoin" board */
/* ── the structure tape ──────────────────────────────────────────────────────
   Replaces the equal-width state columns. Populations differ by up to 14×, so equal
   columns meant huge dead regions beside runaway ones. A band sizes to its own content
   and the page's vertical weight becomes the market's actual shape. */
.avb-app .tape{display:flex;flex-direction:column;gap:10px;padding:2px 14px 14px;min-width:0}

/* one-line proportion bar — the whole distribution before any scrolling */
.avb-app .tapebar{display:flex;height:32px;border:1px solid var(--line);border-radius:9px;overflow:hidden}
.avb-app .tseg{display:flex;align-items:center;justify-content:center;gap:7px;min-width:0;padding:0 8px;
  font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  white-space:nowrap;overflow:hidden;border-right:1px solid var(--bg)}
.avb-app .tseg:last-child{border-right:0}
.avb-app .tseg-t{overflow:hidden;text-overflow:ellipsis}
.avb-app .tseg b{font-size:13px}
.avb-app .tseg.u{background:var(--up-tint);color:var(--up)}
.avb-app .tseg.b{background:var(--base-tint);color:var(--base)}
.avb-app .tseg.d{background:var(--down-tint);color:var(--down)}
.avb-app .tseg.x{background:var(--unclear-tint);color:var(--unclear)}

/* one band per state: fixed rail + a grid that reflows to the content */
.avb-app .band{display:grid;grid-template-columns:126px minmax(0,1fr);border:1px solid var(--line-soft);
  border-radius:11px;background:var(--panel);overflow:hidden}
.avb-app .band.u{border-left:3px solid var(--up)}
.avb-app .band.b{border-left:3px solid var(--base)}
.avb-app .band.d{border-left:3px solid var(--down)}
.avb-app .band.x{border-left:3px solid var(--unclear)}
.avb-app .band-rail{border-right:1px solid var(--line-soft);padding:12px 13px;min-width:0}
.avb-app .band.u .band-rail{background:color-mix(in srgb,var(--up) 7%,transparent)}
.avb-app .band.b .band-rail{background:color-mix(in srgb,var(--base) 7%,transparent)}
.avb-app .band.d .band-rail{background:color-mix(in srgb,var(--down) 7%,transparent)}
.avb-app .band.x .band-rail{background:color-mix(in srgb,var(--unclear) 7%,transparent)}
/* the rail label rides along a tall band instead of scrolling out of view */
.avb-app .band-rail > *{display:block}
.avb-app .band-rail{position:sticky;top:var(--hdr);align-self:start}
.avb-app .band-ico{font-size:15px;line-height:1;font-weight:700}
.avb-app .band-name{font-family:var(--mono);font-size:11.5px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;margin-top:5px}
.avb-app .band-n{font-family:var(--mono);font-size:25px;font-weight:700;line-height:1.05;color:var(--ink)}
.avb-app .band-share{font-family:var(--mono);font-size:11px;color:var(--dim)}
.avb-app .band.u .band-ico,.avb-app .band.u .band-name{color:var(--up)}
.avb-app .band.b .band-ico,.avb-app .band.b .band-name{color:var(--base)}
.avb-app .band.d .band-ico,.avb-app .band.d .band-name{color:var(--down)}
.avb-app .band.x .band-ico,.avb-app .band.x .band-name{color:var(--unclear)}
.avb-app .band-body{min-width:0}
.avb-app .band-empty{margin:0;padding:16px 14px;color:var(--faint);font-size:13px}

/* the coins themselves — a dense grid that tiles at any count */
.avb-app .chips{display:grid;grid-template-columns:repeat(auto-fill,minmax(212px,244px));gap:7px;padding:10px}
.avb-app .chip{display:flex;align-items:center;gap:9px;min-width:0;padding:7px 9px;cursor:pointer;
  border:1px solid var(--line-soft);border-radius:9px;background:var(--panel-2);transition:background .12s,border-color .12s}
.avb-app .chip:hover,.avb-app .chip:focus-visible{background:var(--raise);border-color:var(--line-2);outline:none}
.avb-app .chip .ico{width:26px;height:26px;font-size:10px;flex:none}
.avb-app .chip-id{display:flex;flex-direction:column;min-width:0;flex:1;line-height:1.2}
.avb-app .chip-sym{font-family:var(--mono);font-size:12.5px;font-weight:700;color:var(--ink)}
.avb-app .chip-nm{font-size:10.5px;color:var(--dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.avb-app .chip-n{font-family:var(--mono);font-size:13px;font-weight:700;flex:none}
.avb-app .chip .star{font-size:14px;flex:none;opacity:.35}
.avb-app .chip:hover .star,.avb-app .chip .star.on{opacity:1}
.avb-app .chip.starred{border-color:var(--btc-bd)}
@media(max-width:760px){
  .avb-app .band{grid-template-columns:1fr}
  .avb-app .band-rail{display:flex;align-items:baseline;gap:8px;border-right:0;border-bottom:1px solid var(--line-soft)}
  .avb-app .band-rail > *{position:static;margin:0}
  .avb-app .band-n{font-size:16px}
  .avb-app .chips{grid-template-columns:1fr}
}

.avb-app .tablewrap{overflow-x:auto}
.avb-app .table-card table{width:100%;border-collapse:separate;border-spacing:0;font-size:15px}
.avb-app .table-card thead th{font-size:12.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--faint);font-weight:600;padding:10px 18px;text-align:right}
.avb-app .table-card thead th:first-child{text-align:center;width:44px}
.avb-app .table-card thead th:nth-child(2),.avb-app .table-card thead th:nth-child(3){text-align:left}
.avb-app .table-card tbody td{padding:11px 18px;border-top:1px solid var(--line-soft);text-align:right;vertical-align:middle}
.avb-app .table-card tbody tr{cursor:pointer}
.avb-app .table-card tbody tr:hover{background:var(--panel-2)}
.avb-app .table-card tbody tr:focus-visible{outline:2px solid var(--btc);outline-offset:-2px;background:var(--panel-2)}
.avb-app td.rank{color:var(--faint);text-align:center}
.avb-app td.coin{text-align:left}
.avb-app .cc{display:flex;align-items:center;gap:11px}
.avb-app .ico{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;font-weight:700;font-size:11.5px;flex:none;overflow:hidden;background:var(--panel-2)}
.avb-app img.ico{display:block;object-fit:cover}
.avb-app .ico--mono{color:var(--ink);text-transform:uppercase}
.avb-app .nm{font-weight:700;font-size:15px}
.avb-app .sym{color:var(--dim);font-size:14px;margin-left:6px;font-weight:600}
.avb-app td.n{font-weight:700;font-size:15px;font-variant-numeric:tabular-nums}
.avb-app .star{color:var(--faint);cursor:pointer;font-size:15px;background:transparent;border:0;padding:0;line-height:1}
.avb-app .star.on{color:var(--btc)}

/* signal-module internals (Altseason / Altcoin Dominance / Regime) */
.avb-app .rr-hd{display:flex;align-items:center;gap:8px;margin-bottom:4px}
.avb-app .rr-hd h3{margin:0;font-size:15px;font-weight:700}
.avb-app .rr-hd .i2{margin-left:auto;color:var(--faint);font-size:15px}
.avb-app .gaugewrap{display:flex;flex-direction:column;align-items:center;margin-top:2px}
.avb-app .gaugewrap svg{max-width:100%;height:auto}
.avb-app .gcap{font-size:12px;color:var(--dim);text-align:center;margin-top:3px;max-width:34ch;line-height:1.4}
/* $OTHERS.D dominance module (replaces Timeframe Divergence) */
.avb-app .domcard{display:flex;flex-direction:column}
.avb-app .domtag{display:inline-flex;align-items:center;font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.03em;color:var(--upx);border:1px solid color-mix(in srgb,#33E1C4 34%,transparent);background:color-mix(in srgb,#33E1C4 12%,transparent);border-radius:5px;padding:2px 7px}
.avb-app .domhead{display:flex;align-items:baseline;gap:9px;margin:0 0 5px}
.avb-app .domval{font-family:var(--mono);font-size:25px;font-weight:700;letter-spacing:-.02em;line-height:1}
.avb-app .domchg{font-family:var(--mono);font-size:12px;font-weight:700}
.avb-app .domchg.pos{color:var(--up)}
.avb-app .domchg.neg{color:var(--down)}
.avb-app .domchart{position:relative;flex:1;min-height:72px;margin-bottom:2px}
.avb-app .domchart svg{width:100%;height:100%;display:block}
.avb-app .domrange{position:absolute;right:2px;bottom:3px;font-family:var(--mono);font-size:10.5px;color:var(--faint);letter-spacing:.02em}
/* ⓘ explainer tooltip (hover / focus) — carries a module's plain-language note */
.avb-app .info{position:relative;cursor:help;outline:none}
.avb-app .info .tip{position:absolute;top:calc(100% + 8px);right:0;width:236px;background:var(--panel-2);border:1px solid var(--line);border-radius:9px;padding:10px 12px;font-size:12px;font-weight:400;line-height:1.5;letter-spacing:normal;text-transform:none;color:var(--dim);text-align:left;box-shadow:0 10px 28px var(--shadow);opacity:0;visibility:hidden;transform:translateY(-4px);transition:opacity .14s ease,transform .14s ease,visibility .14s;z-index:30;pointer-events:none}
.avb-app .info:hover .tip,.avb-app .info:focus-visible .tip{opacity:1;visibility:visible;transform:translateY(0)}
.avb-app .rsub{font-size:12.5px;color:var(--dim);margin:0 0 8px}
.avb-app .regbox{border:1px solid var(--up-bd);background:var(--up-tint);border-radius:11px;padding:9px 12px;display:flex;align-items:center;gap:11px}
.avb-app .regbox .rk{font-weight:700;font-size:15px;color:var(--up);letter-spacing:.01em}
.avb-app .regbox .rs{font-size:12.5px;color:var(--dim);margin-top:2px}
.avb-app .regbox .bmk{width:30px;height:30px;border-radius:50%;background:var(--btc);color:#231301;display:grid;place-items:center;font-weight:700;flex:none;font-size:15px;margin-left:auto}
.avb-app .regime p{font-size:12.5px;color:var(--dim);margin:8px 0 0;line-height:1.45;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

/* honesty line — added for the live product (mockup omitted it) */
.avb-app .honesty{margin-top:4px;padding:12px 4px 4px;border-top:1px solid var(--line-soft);display:flex;gap:16px;justify-content:space-between;flex-wrap:wrap;color:var(--faint);font-size:13px;line-height:1.5}
.avb-app .honesty .rnfa{white-space:nowrap;font-weight:700}

@media(max-width:1200px){
  .avb-app .topgrid{grid-template-columns:1fr 1fr 1fr}
  .avb-app .topgrid > .domcard{grid-column:1 / -1;grid-row:auto;min-height:200px}
}
@media(max-width:820px){
  .avb-app{grid-template-columns:1fr}
  /* the rail collapses to a horizontal top strip — nav stays reachable on mobile */
  .avb-app .rail{position:static;height:auto;flex-direction:row;align-items:center;gap:12px;padding:10px 16px;
    border-right:0;border-bottom:1px solid var(--line);overflow-x:auto}
        .avb-app .nav{display:flex;flex-direction:row;gap:4px;flex:none}
        .avb-app .topgrid{grid-template-columns:1fr}
  .avb-app .topbar{padding:9px 16px;flex-wrap:wrap;gap:12px}
  .avb-app .table-card .hd{flex-wrap:wrap;row-gap:10px}
  .avb-app .table-card .hd .tf{margin-left:0}
  .avb-app .content{padding:11px 16px 14px}
}

/* ============================================================================
   Coin report (/reports/[symbol]) — the compact "standing report vs BTC".
   Rendered by <CoinReport> inside <AppShell identity> so it inherits the .avb-app
   identity tokens (no :root reset). Class names are cr-* prefixed and unique.
   ========================================================================== */
/* vs-BTC window cells below the chart — the clean heatmap-popup style, on the single view */

/* ============================================================================
   Heatmap (/heatmap) — the Gridz diagonal strength grid, ported into the shell.
   Fills the main column (below the top bar, beside the rail); hm-* namespaced.
   ============================================================================ */
.avb-app .avb-heatmap{position:relative;flex:1 1 auto;min-height:340px;overflow:hidden;background:var(--hm-gap);display:flex;flex-direction:column;padding-inline:var(--gutter)}
/* The scroller whose height animates between ten rows and the whole basket. overflow
   is hidden so the rows below the cut are clipped rather than scrolled — the expand
   control is the only way down, which is the point. */
.avb-app .hm-gridwrap{position:relative;flex:0 0 auto;overflow:hidden;background:var(--hm-gap);
  transition:max-height .42s cubic-bezier(.22,.61,.36,1)}
@media (prefers-reduced-motion:reduce){.avb-app .hm-gridwrap{transition:none}}
.avb-app .hm-grid{position:relative;display:grid;gap:2px;background:var(--hm-gap)}
/* ── THE BUBBLE FIELD ─────────────────────────────────────────────────────────
   One canvas, sized by its host. `touch-action:none` because the whole surface is a drag
   target — without it the browser claims the gesture for scrolling and the pointermove stream
   stops halfway through a sling. `display:block` kills the inline-baseline gap that would
   otherwise leave a few px of panel under the canvas. */
.avb-app .hm-bubblewrap{position:relative;width:100%;min-width:0;overflow:hidden;
  border-radius:var(--r);background:var(--panel)}
/* ☢️ pan-y, NOT none — `none` made the whole canvas a SCROLL DEAD ZONE on a phone. The field
   fills the panel, so a thumb landing anywhere on it could not scroll the page at all: the
   page simply refused to move under the finger. Same call as .hm-radial-svg, and the sling is
   protected in Bubbles.tsx instead — a touch press selects but never tows. */
.avb-app .hm-bubbles{display:block;touch-action:pan-y;cursor:grab}
.avb-app .hm-bubbles:active{cursor:grabbing}

/* ☢️ padding:0 IS LOAD-BEARING, AND IT IS NOT COSMETIC. A <button> that never states its
   padding gets the USER AGENT's, which in Chrome is 1px 6px — so every tile was 12px
   narrower inside than out, while gridType() budgets its type against the CELL width
   (0.86 of it, a PROPORTIONAL 7% reserve each side). Below ~86px of cell the fixed 6px is
   the larger of the two, and the budget then promises room the cell does not have: measured
   at 412px, 106 of 1000 tickers overflowed their tile by 3px and were shaved by
   overflow:hidden. It was never mobile-only — desktop clipped the same 106 by 2px.
   The UA value also differs between browsers, so the board was laying out to whatever
   Chrome happened to default to. Stating it makes 0.86 mean what it says. */
.avb-app .hm-px{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;
  overflow:hidden;line-height:1;border:0;padding:0;text-align:center;
  transition:filter .12s ease, box-shadow .12s ease}
/* The grid's logo. object-fit:contain so a non-square icon is letterboxed rather than
   stretched, and the same 24% rounding the bullseye clips its marks with. */
.avb-app .hm-px .hm-ico{display:block;flex:0 0 auto;object-fit:contain;border-radius:24%;pointer-events:none}
.avb-app .hm-px .hm-t{font-family:var(--mono);font-weight:700;font-size:clamp(11px,1.2vw,16px);letter-spacing:.01em}
.avb-app .hm-px .hm-v{font-family:var(--mono);font-weight:600;font-size:clamp(8px,.85vw,12px);opacity:.82;margin-top:.15em}
.avb-app button.hm-px:hover,.avb-app button.hm-px:focus-visible{filter:brightness(1.12);z-index:20;
  box-shadow:inset 0 0 0 2px rgba(var(--found-rgb),.55), 0 8px 26px var(--shadow);outline:none}

/* overlay chrome */
.avb-app .hm-vignette{position:absolute;inset:0 0 34px 0;pointer-events:none;z-index:2;
  background:radial-gradient(125% 125% at 50% 50%, transparent 60%, var(--vignette) 100%)}
.avb-app .hm-zone{position:absolute;z-index:4;font-family:var(--mono);text-transform:uppercase;letter-spacing:.2em;
  pointer-events:none;white-space:nowrap;font-weight:700;font-size:12.5px}
.avb-app .hm-zone.hm-tr{top:14px;right:16px;color:var(--zone-up)}
.avb-app .hm-zone.hm-bl{bottom:44px;left:16px;color:var(--zone-down)}
/* pill backdrop so the zone labels read as overlays, never colliding with tile text */
.avb-app .hm-zone{background:var(--veil);border-radius:100px;padding:4px 11px;backdrop-filter:blur(2px)}
.avb-app .hm-legend{position:absolute;bottom:13px;right:16px;z-index:5;display:flex;gap:13px;align-items:center;
  font-family:var(--mono);font-size:11px;letter-spacing:.05em;color:var(--dim);
  background:var(--veil);border:1px solid var(--ink-a2);border-radius:9px;padding:7px 11px}
.avb-app .hm-legend .hm-sw{display:inline-flex;align-items:center;gap:6px}
.avb-app .hm-legend i{width:11px;height:11px;border-radius:2px;display:inline-block}
.avb-app .hm-stamp{position:absolute;bottom:13px;left:16px;z-index:5;font-family:var(--mono);font-size:11px;
  letter-spacing:.05em;color:var(--faint);background:var(--veil);border-radius:7px;padding:5px 9px}

/* coin-info popup */
.avb-app .hm-backdrop{position:fixed;inset:0;z-index:50;background:var(--scrim-soft);backdrop-filter:blur(3px);
  display:grid;place-items:center;padding:20px;animation:hm-fade .14s ease}
.avb-app .hm-sheet{width:min(420px,94vw);background:var(--panel);border:1px solid var(--ink-a3);border-radius:16px;
  box-shadow:0 24px 70px var(--shadow);overflow:hidden;animation:hm-pop .16s cubic-bezier(.2,.8,.2,1)}
@keyframes hm-fade{from{opacity:0}to{opacity:1}}
@keyframes hm-pop{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:none}}
.avb-app .hm-sheet .hm-top{position:relative;padding:18px 18px 14px;border-bottom:1px solid var(--ink-a2)}
.avb-app .hm-sheet .hm-cx{position:absolute;top:12px;right:12px;width:30px;height:30px;border-radius:8px;border:1px solid var(--ink-a3);
  background:transparent;color:var(--dim);font-size:15px;display:grid;place-items:center}
.avb-app .hm-sheet .hm-cx:hover{background:var(--ink-a2);color:var(--ink)}
.avb-app .hm-sheet .hm-nm{font-size:20px;font-weight:700;letter-spacing:-.01em}
.avb-app .hm-sheet .hm-nm .hm-tk{font-family:var(--mono);color:var(--dim);font-weight:700;font-size:14px;margin-left:8px}
.avb-app .hm-sheet .hm-badge{display:inline-flex;align-items:center;gap:6px;margin-top:9px;font-family:var(--mono);font-size:12px;font-weight:700;
  letter-spacing:.03em;padding:4px 10px;border-radius:999px;border:1px solid var(--hc);color:var(--hc);
  background:color-mix(in srgb, var(--hc) 12%, transparent)}
.avb-app .hm-sheet .hm-big{font-family:var(--mono);font-weight:700;font-size:34px;letter-spacing:-.02em;margin-top:12px}
.avb-app .hm-sheet .hm-biglbl{font-family:var(--mono);font-size:12px;color:var(--dim);margin-left:8px;font-weight:600}
/* SNAPSHOT — the camera and its menu. Present on every surface worth sharing, and quiet
   until asked: a control that exists to export should not compete with the data. */
.avb-app .snap{position:relative;display:inline-flex;align-items:center;gap:8px}
.avb-app .snap-btn{
  display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--panel-2);color:var(--dim);cursor:pointer;
  transition:color .12s ease,border-color .12s ease}
.avb-app .snap-btn:hover,.avb-app .snap-btn.on{color:var(--ink);border-color:var(--btc-bd)}
.avb-app .snap-menu{
  position:absolute;top:calc(100% + 6px);right:0;z-index:60;min-width:196px;
  background:var(--panel);border:1px solid var(--line-2);border-radius:7px;
  box-shadow:0 14px 34px var(--shadow);padding:6px;display:flex;flex-direction:column;gap:2px}
.avb-app .snap-hd{
  font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.11em;
  text-transform:uppercase;color:var(--faint);padding:6px 9px 5px}
.avb-app .snap-item{
  font-family:var(--mono);font-size:12.5px;font-weight:600;letter-spacing:.02em;text-align:left;
  padding:8px 9px;border:0;border-radius:5px;background:transparent;color:var(--ink-2);cursor:pointer}
.avb-app .snap-item:hover:not(:disabled){background:var(--raise);color:var(--ink)}
.avb-app .snap-item:disabled{color:var(--faint);cursor:default}
.avb-app .snap-said{
  font-family:var(--mono);font-size:11.5px;font-weight:600;letter-spacing:.03em;
  color:var(--dim);white-space:nowrap}
/* On the board the camera floats over the mosaic, so it needs its own ground to sit on. */
/* ☢️ Z-INDEX 30, NOT 20. A hovered cell is raised to 20, and among equal z-index the later DOM
   node wins — there are a thousand cells after these, so at 20 every one of them painted over
   the controls. Below the hover card (40) and the camera's own menu (60), above the board. */
.avb-app .fs--board{position:absolute;top:12px;right:14px;z-index:30;
  background:var(--veil);backdrop-filter:blur(2px)}
/* The camera sits UNDER the full-screen button: 12 + its 30px + an 8px gap. */
.avb-app .snap--board{position:absolute;top:50px;right:14px;z-index:30}
/* ☢️ ON A PHONE THE GRID GETS A BAND FOR THE TWO BUTTONS. On the bullseye they float over the
   rim, where the outermost cells are half off-screen anyway; on the grid every pixel is a
   coin and the corner stack covered the two right-most cells of rows one and two (2026-09-06
   audit). .hm-fitrows is the grid's own class (Heatmap.tsx): reserve 40px above it and lay the
   buttons side by side in that band instead of stacked over the cells. */
@media (max-width:640px){
  .avb-app .avb-heatmap.hm-fitrows{padding-top:40px}
  .avb-app .hm-fitrows .fs--board{top:6px;right:14px}
  .avb-app .hm-fitrows .snap--board{top:6px;right:52px}
}
.avb-app .snap--board .snap-btn{background:var(--veil);backdrop-filter:blur(2px)}
.avb-app .snap--board .snap-said{background:var(--veil-2);padding:4px 9px;border-radius:100px}
/* ── Full screen ──────────────────────────────────────────────────────────────────────────
   Matched to .snap-btn exactly, because the two sit side by side and any difference in size
   or weight reads as one of them being broken. */
.avb-app .fsbtn{
  display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--panel-2);color:var(--dim);cursor:pointer;
  transition:color .12s ease,border-color .12s ease}
.avb-app .fsbtn:hover,.avb-app .fsbtn[aria-pressed="true"]{color:var(--ink);border-color:var(--btc-bd)}
.avb-app .fsbtn:focus-visible{outline:2px solid var(--btc);outline-offset:2px}

/* In the list heading and the popup the camera rides the line it sits on — as does the
   fullscreen button beside it. ☢️ .snap--list was briefly deleted here when this block
   was written: RankList still carried the class, so the camera lost its margin and its
   baseline and sat jammed against the heading. */
.avb-app .snap--list,.avb-app .fs--list{margin-left:12px;vertical-align:middle}
/* The UA paints a fullscreen element on BLACK and gives it no padding of its own, so both
   have to be restated or the board arrives edge-to-edge on a colour that is not the site's. */
.avb-app .avb-heatmap:fullscreen,.avb-app .rk:fullscreen{background:var(--bg);width:100vw}
/* ⚠️ Specificity: `.avb-app .fp .avb-heatmap` (0,3,0) already sets a height, so the fullscreen
   rule has to out-rank it rather than merely follow it. The height itself still comes from
   --hm-panel-h — Heatmap feeds it the viewport height while full screen — this only releases
   the flex:0 0 auto basis so the panel can actually take it. */
.avb-app .fp .avb-heatmap:fullscreen{height:100vh;max-height:100vh;flex:1 1 auto}
/* The board ROW fullscreens (the board, the list on its right, and the card between them):
   the row is the UA's black canvas, so it restates the ground; the panel fills the height;
   the list drops its gutter and runs the full height beside it. */
.avb-app .hm-row:fullscreen{background:var(--bg);width:100vw;height:100vh}
.avb-app .hm-row:fullscreen .hm-side-main .avb-heatmap{height:100vh;max-height:100vh;flex:1 1 auto}
.avb-app .hm-row:fullscreen .hm-side{margin-right:0}
.avb-app .rk:fullscreen{overflow-y:auto;height:100vh}
.avb-app .snap--sheet{position:absolute;top:14px;right:52px}
/* The coin page's camera rides the action row; the macro pair's sits with its chart controls. */
.avb-app .snap--coin .snap-btn{width:34px;height:34px}
.avb-app .snap--macro{align-self:center}
.avb-app .snap--macro .snap-btn{width:30px;height:30px}

/* BTC.D chart picker — only Bitcoin's card has two things worth plotting, so this sits
   between the headline and the chart rather than in the sheet's chrome. */
.avb-app .hm-sheet .hm-chartsel{display:flex;gap:2px;padding:14px 18px 0}
.avb-app .hm-sheet .hm-chartbtn{
  font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:.06em;
  padding:6px 13px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--panel-2);color:var(--dim);cursor:pointer;transition:color .12s ease,border-color .12s ease}
.avb-app .hm-sheet .hm-chartbtn:hover{color:var(--ink-2)}
.avb-app .hm-sheet .hm-chartbtn.on{background:var(--raise);color:var(--ink);border-color:var(--btc-bd)}
.avb-app .hm-sheet .hm-spark{padding:10px 18px 4px}
.avb-app .hm-sheet .hm-spark svg{width:100%;height:56px;display:block}
/* Seven windows, matching the hover card. */
/* ☢️ minmax(0,1fr), NOT 1fr. A bare 1fr is minmax(AUTO,1fr) — it floors at min-content, so one
   wide value widens its column and the seven-column grid grows past the card it sits in. On a
   390px phone the row measured 393px inside a 388px container and the 1Y chip's right edge
   landed at 394 against a card ending at 390. Zero as the floor lets the columns share what
   there is, which is the behaviour the equal split was always meant to describe. */
.avb-app .hm-sheet .hm-rows{padding:6px 18px 16px;display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:2px}
.avb-app .hm-sh-px{display:flex;justify-content:space-between;gap:12px;margin:0 18px 4px;padding-top:10px;
  border-top:1px solid var(--line-soft);font-family:var(--mono);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--faint)}
.avb-app .hm-sh-px b{font-weight:700;color:var(--ink);letter-spacing:.02em}
.avb-app .hm-sheet .hm-cell{padding:9px 4px;text-align:center;border-radius:8px;background:var(--ink-a1)}
.avb-app .hm-sheet .hm-cell .hm-w{font-family:var(--mono);font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}
.avb-app .hm-sheet .hm-cell .hm-p{font-family:var(--mono);font-weight:700;font-size:13px;margin-top:4px}
/* ⚠️ AND A FOUR-DIGIT RETURN STILL SPILLS ITS OWN CELL once the grid stops overflowing the
   card. ZEC at +2695% needs 47px in a 41px box on a 390px phone — the number no longer pushes
   the card apart, it just overlaps its neighbours, which is the same unreadability wearing a
   different shape. Smaller type here rather than a compacted "+2.7k%": the digits are the
   thing the reader came for, and 41px of them is still legible.
   ☢️ After the base rule. A media query adds no specificity, so placed earlier in the file it
   would lose every declaration to the 13px above — twice already in this stylesheet. */
@media (max-width:430px){
  .avb-app .hm-sheet .hm-cell{padding-left:2px;padding-right:2px}
  .avb-app .hm-sheet .hm-cell .hm-p{font-size:11px}
}
.avb-app .hm-sheet .hm-foot{padding:0 18px 16px;color:var(--faint);font-size:11px;font-family:var(--mono);letter-spacing:.03em}
.avb-app .hm-pos{color:var(--up)} .avb-app .hm-neg{color:var(--down)} .avb-app .hm-zero{color:var(--dim)}
@media(max-width:560px){
  .avb-app .hm-backdrop{align-items:end;padding:0}
  .avb-app .hm-sheet{width:100vw;border-radius:16px 16px 0 0}
  .avb-app .hm-stamp,.avb-app .hm-legend{display:none}
}

/* per-page top-bar header (the slot where "Bitcoin-Denominated Altcoin Monitor" sits) */
.avb-app .topbar--rich{align-items:flex-start;padding-top:11px;padding-bottom:11px}
/* ============================================================================
   Macro Dashboard (/macro) — stacked auto-scaled pair lanes (line or candle)
   sharing one time axis + crosshair. Panel language matches the site cards;
   chart chrome is deliberately recessive, ink reserved for data + readouts.
   ========================================================================== */
.avb-app .macro{padding:11px 32px 26px;max-width:1920px;width:100%;margin:0 auto;display:flex;flex-direction:column;gap:12px}
.avb-app .mc-controls{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;flex-wrap:wrap}
.avb-app .mc-chips{display:flex;flex-wrap:wrap;gap:7px;align-items:center;min-width:0}
.avb-app .mc-chip{display:inline-flex;align-items:center;gap:7px;font-family:var(--mono);font-size:11.5px;font-weight:700;
  letter-spacing:.02em;color:var(--dim);background:var(--panel);border:1px solid var(--line);border-radius:100px;
  padding:5px 12px;cursor:pointer;transition:border-color .12s,color .12s}
.avb-app .mc-chip:hover{border-color:var(--line-2);color:var(--ink-2)}
.avb-app .mc-chip i{width:9px;height:9px;border-radius:50%;flex:none}
.avb-app .mc-chip.on{background:var(--panel-2)}
.avb-app .mc-chipops{display:inline-flex;gap:2px;margin-left:4px}
.avb-app .mc-chipops button{background:transparent;border:0;color:var(--faint);font-family:var(--mono);font-size:11px;
  font-weight:700;padding:5px 7px;cursor:pointer;border-radius:6px}
.avb-app .mc-chipops button:hover{color:var(--ink-2);background:var(--panel-2)}
/* ☢️ WRAPS, BECAUSE flex-end + nowrap SPILLS OFF THE LEFT. This row packs to the right, so
   once its children exceed the row on a narrow screen the excess goes out the LEFT edge —
   where body{overflow-x:hidden} clips it silently. Measured at 390px: the LIST/CARDS toggle
   sat at -190..-74, entirely outside the window and unreachable, so the macro page could not
   be switched between its two views on a phone at all. Nothing overflowed visibly and nothing
   errored; the control was simply gone.
   ⚠️ Wrapping rather than scrolling: a wrapped row shows every control at rest, where a
   horizontal scroller hides half of them behind a gesture nobody is told about. */
.avb-app .mc-asof{font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--dim);
  white-space:nowrap;margin-right:4px}
.avb-app .mc-viewops{display:flex;align-items:center;justify-content:flex-end;gap:8px;
  flex-wrap:wrap;min-width:0}
.avb-app .mc-seg{display:inline-flex;background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:3px}
.avb-app .mc-seg button{background:transparent;border:0;color:var(--dim);font-family:var(--mono);font-weight:700;
  font-size:12px;padding:5px 11px;border-radius:6px;cursor:pointer}
.avb-app .mc-seg button.on{background:var(--raise);color:var(--ink);box-shadow:inset 0 0 0 1px var(--line)}
/* BTC.D's Market cap / Equal weight switch (components/macro/EwSwitch): under the description on its
   page, and small at the right of the BTC.D card's foot. */
.avb-app .ew-sw{margin-top:10px}
.avb-app .ew-sw-c{margin:0;padding:2px;flex:none}
.avb-app .ew-sw-c button{font-size:10px;padding:2px 7px}
.avb-app .mc-chartwrap{position:relative;border:1px solid var(--line);border-radius:13px;background:var(--panel);
  padding:6px 4px 2px;min-width:0;overflow:hidden}
.avb-app .mc-chartwrap svg{display:block;cursor:crosshair;touch-action:pan-y}
.avb-app .mc-empty{display:grid;place-items:center;height:220px;color:var(--faint);font-family:var(--mono);font-size:13px}
.avb-app .mc-yearline{stroke:var(--line-soft);stroke-width:1}
.avb-app .mc-lanesep{stroke:var(--line);stroke-width:1}
.avb-app .mc-xtick{fill:var(--faint);font-family:var(--mono);font-size:10.5px}
.avb-app .mc-line{fill:none;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}
.avb-app .mc-cross{stroke:var(--dim);stroke-width:1;stroke-dasharray:3 3}
/* ⚠️ Quieter than the vertical one. The time line is a shared reading across twelve charts and
   has to carry; this one only says where the pointer is inside one card, and at full strength
   two crossing dashed lines fight for the same attention the data wants. */
.avb-app .mc-cross-h{opacity:.55}
.avb-app .mc-dot{stroke:var(--panel);stroke-width:2}
.avb-app .mc-lanelabel{fill:var(--ink);font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:.03em}
.avb-app .mc-laneread{font-family:var(--mono);font-size:11.5px}
.avb-app .mc-laneval{fill:var(--ink);font-weight:700}
.avb-app .mc-lanechg{font-weight:700}
.avb-app .mc-lanechg.pos{fill:var(--up)} .avb-app .mc-lanechg.neg{fill:var(--down)}
/* ── Trend legs ──────────────────────────────────────────────────────────────
   The line cut at its own extremes: green where a leg ends at or above where it started,
   red where it does not. Same two tokens the candles use, so a rising leg and a rising
   candle are the same green rather than two greens the eye has to reconcile. */
.avb-app .mc-leg.up{stroke:var(--up)}
.avb-app .mc-leg.down{stroke:var(--down)}
/* The extreme markers are deliberately NOT green/red: they mark where the series turned,
   which is a different kind of fact from which way a leg ran. Gold for the high, lilac for
   the low. The panel-coloured ring lifts the dot off whichever leg passes under it. */
/* ONE DEFINITION FOR BOTH VIEWS. The tape paints its markers as SVG and the cards paint
   theirs as HTML, so the colour has to be reachable from both — a token is the only thing
   that is. Two hexes for one colour drift apart without anything failing. */
.avb-app{--mc-hi:#eedcae;--mc-lo:#a78bfa}
.avb-app .mc-xdot{stroke:var(--panel);stroke-width:1.5}
.avb-app .mc-xdot.hi,.avb-app .mc-xlbl.hi{fill:var(--mc-hi)}
.avb-app .mc-xdot.lo,.avb-app .mc-xlbl.lo{fill:var(--mc-lo)}
.avb-app .mc-xlbl{font-family:var(--mono);font-size:9.5px;font-weight:700;letter-spacing:.02em}
/* The card grid's own dots, in HTML because that plot is a stretched viewBox — see the note
   at `dots` in MacroDashboard. translate(-50%,-50%) centres them on the point itself. */
.avb-app .mc-cardplotwrap{position:relative}
.avb-app .mc-xdot2{position:absolute;width:7px;height:7px;border-radius:50%;
  transform:translate(-50%,-50%);box-shadow:0 0 0 1.5px var(--panel);pointer-events:none}
.avb-app .mc-xdot2.hi{background:var(--mc-hi)}
.avb-app .mc-xdot2.lo{background:var(--mc-lo)}
.avb-app .mc-cu{fill:var(--up);stroke:var(--up)}
.avb-app .mc-cd{fill:var(--down);stroke:var(--down)}
.avb-app .mc-datebg{fill:var(--panel)}
.avb-app .mc-pmi50{stroke:var(--line-2);stroke-width:1;stroke-dasharray:2 4}
.avb-app .mc-pmi50lbl{fill:var(--faint);font-family:var(--mono);font-size:9.5px}
.avb-app .mc-hoverdate{fill:var(--ink-2);font-family:var(--mono);font-size:10.5px;font-weight:700}
/* card view — the tape re-flowed into a scannable grid; same semantics per card */
/* ☢️ FOUR ACROSS, CAPPED. auto-fill takes as many columns as will fit, so a wide monitor drew
   FIVE and left the last row ragged — twelve pairs divide evenly by four and not by five, so
   the fifth column buys nothing and costs a hole. Below the cap auto-fill still handles the
   narrowing; above it the count is fixed, and the grid stays three clean rows of four. */
.avb-app .mc-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}
@media (min-width:1280px){.avb-app .mc-cards{grid-template-columns:repeat(4,1fr)}}
.avb-app .mc-card{border:1px solid var(--line);border-radius:13px;background:var(--panel);padding:11px 13px 9px;
  display:flex;flex-direction:column;gap:8px;min-width:0;transition:border-color .12s}
.avb-app .mc-card:hover{border-color:var(--line-2)}
.avb-app .mc-cardhead{display:flex;align-items:center;justify-content:space-between;gap:8px;min-width:0}
.avb-app .mc-cardhead .mc-pairnm{font-size:12.5px;font-family:var(--mono);min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.avb-app .mc-cardread{font-family:var(--mono);font-size:12px;flex:none;display:inline-flex;align-items:baseline;gap:8px}
.avb-app .mc-cardread b{color:var(--ink);font-weight:700}
.avb-app .mc-cardread em{font-style:normal;font-weight:700;font-size:11px}
.avb-app .mc-cardread em.pos{color:var(--up)} .avb-app .mc-cardread em.neg{color:var(--down)}
/* ☢️ touch-action:pan-y, OR THE CROSSHAIR NEVER APPEARS ON A PHONE. Without it the browser
   claims the gesture for scrolling the moment a finger moves and cancels the pointer stream —
   so dragging across a card on mobile did nothing at all, and a crosshair that flickered in
   before the cancel read as "the line drops out and doesn't sustain". Measured with real touch
   events: five samples across a card, the readout never left its idle value once.
   ⚠️ pan-y and NOT none — the same choice .cp-chartwrap documents. `none` would win the
   gesture and cost the reader the ability to scroll a grid of twelve cards with their thumb.
   Vertical still scrolls the page; horizontal reads the chart. */
.avb-app .mc-cardplot{width:100%;height:118px;display:block;cursor:crosshair;touch-action:pan-y}
/* The ticks under a card plot — three years, or five months on an enlarged card.
   space-between puts the first hard left and the last hard right, which is where those two
   months actually sit in the plot above; the inner ones land within a month of theirs. */
.avb-app .mc-cardaxis{display:flex;justify-content:space-between;padding:3px 2px 0;
  font-family:var(--mono);font-size:9px;letter-spacing:.06em;color:var(--faint);
  font-variant-numeric:tabular-nums}
/* The footer is the positioning context for the date that rides the crosshair. */
.avb-app .mc-cardwhen{transition:left .06s linear}
/* ⚠️ ABSOLUTE WHILE HOVERING — WHICH COLLAPSES THE FOOTER UNLESS IT IS HELD OPEN. I wrote the
   warning and then caused it anyway: with the date out of flow, a footer whose only child is
   that date has no in-flow content left and measured ZERO, dropping the card's contents 15px
   the instant the pointer arrived. Caught by measuring rather than by looking — the label
   itself looked perfect. min-height holds the row at the height the text would have had. */
.avb-app .mc-cardwhen.on{position:absolute;transform:translateX(-50%);white-space:nowrap;
  color:var(--ink);pointer-events:none}
.avb-app .mc-cardfoot{position:relative;min-height:15px;display:flex;align-items:center;justify-content:space-between;gap:8px;
  font-family:var(--mono);font-size:10.5px;color:var(--faint)}
/* ── The way out ── each card head carries a link to the pair's own page (/macro/<slug>).
   ⚠️ The negative margins are what keep the card head at its 18px: the button is taller than
   the text beside it, and without them all thirteen cards grow to make room for it. */
.avb-app .mc-cardhead .mc-pairnm{margin-right:auto}
.avb-app .mc-grow{flex:none;width:22px;height:22px;margin:-2px 0;position:relative;z-index:1;text-decoration:none}
/* The 40px thumb floor applies (.fsbtn, pointer:coarse) — same trick, bigger numbers. The
   target then hangs below the head over the plot wrap, which is positioned and would win the
   hit-test for those pixels — hence the z-index above. */
@media (pointer: coarse){.avb-app .mc-grow{margin:-11px -6px -11px -4px}}
.avb-app .mc-tablewrap{border:1px solid var(--line);border-radius:13px;background:var(--panel);
  overflow:hidden auto;max-height:none}
.avb-app .mc-tablescroll{overflow-x:auto}
/* The LIST view's pair name is the same way out. */
.avb-app .mc-pairlink{text-decoration:none;color:inherit}
.avb-app .mc-pairlink:hover{color:var(--base)}
.avb-app .mc-table{width:100%;min-width:620px;table-layout:auto;border-collapse:separate;border-spacing:0;font-size:13px}

/* COLUMN WIDTHS: exactly ONE column carries a percentage. Auto table layout distributes
   slack across whatever asks for it, so putting width:1% on the four content columns (an
   earlier attempt at "shrink to fit") made five columns bid for 104% and the browser
   collapsed them into each other. Letting only Reading ask for 100% makes it absorb the
   slack and leaves the rest at their natural width, which is what the layout wanted. */
.avb-app .mc-table th.d,.avb-app .mc-table td.d{width:100%}

.avb-app .mc-table th{font-family:var(--mono);font-size:10px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--faint);font-weight:600;text-align:right;padding:11px 18px;white-space:nowrap;
  background:var(--panel);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:1}
.avb-app .mc-table td{padding:11px 18px;border-top:1px solid var(--line-soft);text-align:right;
  font-family:var(--mono);font-variant-numeric:tabular-nums;white-space:nowrap}
.avb-app .mc-table tbody tr:first-child td{border-top:0}

/* The pair is the row's LABEL, so it reads left like its header. Everything numeric reads
   right so the decimal points line up down the column. */
.avb-app .mc-table th:first-child,.avb-app .mc-table td:first-child{text-align:left;padding-left:20px}
.avb-app .mc-table th.d,.avb-app .mc-table td.d{text-align:left}

/* A rule between the measured block and the prose, so the eye knows where numbers stop. */
.avb-app .mc-table th.d,.avb-app .mc-table td.d{border-left:1px solid var(--line-soft);padding-left:22px}
.avb-app .mc-table td.d{color:var(--dim);font-family:var(--display);font-size:12.5px;white-space:normal;
  line-height:1.45;min-width:240px}

.avb-app .mc-table tbody tr:hover td{background:var(--hi-1)}
.avb-app .mc-table td.dim{color:var(--faint)}
.avb-app .mc-table td.pos{color:var(--up)} .avb-app .mc-table td.neg{color:var(--down)}

@media (max-width:760px){
  /* The prose column is what makes this table wide; on a phone the numbers are the point. */
  .avb-app .mc-table th.d,.avb-app .mc-table td.d{display:none}
  .avb-app .mc-table{min-width:0}
  .avb-app .mc-table th,.avb-app .mc-table td{padding:10px 12px}
}
.avb-app .mc-pairnm{display:inline-flex;align-items:center;gap:8px;font-weight:700;color:var(--ink)}
.avb-app .mc-pairnm i{width:9px;height:9px;border-radius:50%;flex:none}
.avb-app .mc-pmitag{font-style:normal;font-size:9.5px;font-weight:700;letter-spacing:.06em;border-radius:4px;
  padding:1.5px 5px;margin-left:7px;vertical-align:1px}
.avb-app .mc-pmitag.u{color:var(--up);background:var(--up-tint)}
.avb-app .mc-pmitag.d{color:var(--down);background:var(--down-tint)}
.avb-app .mc-missing{margin:0;font-family:var(--mono);font-size:11.5px;color:var(--base)}
.avb-app .mc-meta{margin:0;font-size:12px;color:var(--faint);line-height:1.5}
@media(max-width:820px){.avb-app .macro{padding:11px 16px 20px}.avb-app .mc-viewops{width:100%;justify-content:flex-end}}

.avb-app .pagehead{min-width:0}
.avb-app .pagehead-kicker{font-family:var(--mono);font-size:11px;letter-spacing:.24em;text-transform:uppercase;color:var(--faint)}
.avb-app .pagehead-title{font-size:clamp(15px,1.5vw,19px);font-weight:700;letter-spacing:-.01em;margin-top:3px;margin-bottom:0;line-height:1.14;color:var(--ink)}
.avb-app .pagehead-title .b{color:var(--base)}
/* ONE LINE, STRUCTURALLY — this sits directly above the board and a second line is a second
   line the disc does not get. The copy in HeatmapControls is sized to fit, but the lens prefix
   is DATA (lensLabel grows with whatever is ticked), so wording alone cannot hold the rule and
   the clamp does. The full string is on the element's title for whatever the ellipsis eats.
   ⚠️ All three declarations are load-bearing: text-overflow does nothing without overflow
   hidden, and neither does anything without a width to overflow — which max-width supplies. */
.avb-app .pagehead-desc{margin-top:4px;color:var(--dim);font-size:12px;line-height:1.42;max-width:110ch;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media(max-width:820px){.avb-app .pagehead-desc{display:none}}
/* ☢️ THE MACRO PAGE OPTS OUT OF THE ONE-LINE RULE. That rule exists for the BOARD, where the
   description sits on top of a height-bound disc and every extra line comes off the coins.
   /macro has no disc — its lanes scroll — and its sentence is 1,407px against a 792px box, so
   the clamp ate the second half: the only line telling a visitor the data was "pulled
   2026-07-27" was behind an ellipsis on every desktop (2026-09-06 audit). Wrapping costs the
   macro page one line and gives the reader the date back. */
.avb-app .pagehead-desc--wrap{white-space:normal;overflow:visible;text-overflow:clip;max-width:96ch}

/* ============================================================
   AUTH + ALERTS — /login and /alerts. Same terminal palette as
   the dashboard, using the :root tokens at the top of this file.
   ============================================================ */
.auth-wrap{min-height:100vh;display:grid;place-items:center;background:var(--bg);padding:32px 20px}
.auth-card{width:100%;max-width:420px;background:var(--surface);border:1px solid var(--line);border-radius:calc(var(--r) * 2);padding:32px}
.auth-brand{display:inline-block;font-family:var(--mono);font-size:12px;letter-spacing:.18em;color:var(--dim);text-decoration:none;margin-bottom:20px}
.auth-brand span{color:var(--amber)}
.auth-card h1{font-family:var(--sans);font-size:22px;font-weight:600;color:var(--text);margin:0 0 8px}
.auth-sub{font-size:13px;line-height:1.6;color:var(--dim);margin:0 0 24px}
.auth-form{display:flex;flex-direction:column;gap:8px}
.auth-form label{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.auth-form input{background:var(--bg);border:1px solid var(--line);border-radius:var(--r);color:var(--text);font-family:var(--sans);font-size:14px;padding:11px 12px}
.auth-form input:focus{outline:none;border-color:var(--amber-dim)}
.auth-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;width:100%;border-radius:var(--r);border:1px solid var(--line);background:var(--raise);color:var(--text);font-family:var(--sans);font-size:14px;font-weight:600;padding:11px 14px;cursor:pointer;margin-top:6px}
.auth-btn:hover{border-color:var(--line);background:var(--surface-2)}
/* The primary action is --up, the site's own green, not the Bitcoin amber. Amber is the
   DENOMINATOR everywhere else on this site — it means "this is measured against Bitcoin" —
   and a sign-in button is not that. --up already exists as a token; the mock's teal is it. */
.auth-btn--primary{background:var(--up);border-color:var(--up);color:#08120E;margin-top:10px}
.auth-btn--primary:hover{filter:brightness(1.07)}
.auth-btn--primary:disabled{opacity:.45;cursor:not-allowed}
.auth-btn--google{background:var(--surface-2)}
.auth-or{display:flex;align-items:center;gap:12px;margin:20px 0 4px;color:var(--faint);font-size:10.5px;font-family:var(--mono);text-transform:uppercase;letter-spacing:.14em}
.auth-or::before,.auth-or::after{content:"";flex:1;height:1px;background:var(--line-soft)}
.auth-note{font-size:12.5px;line-height:1.6;color:var(--dim);background:var(--bg);border:1px solid var(--line-soft);border-left:2px solid var(--faint);border-radius:var(--r);padding:10px 12px;margin:0 0 18px}
.auth-note code{font-family:var(--mono);font-size:11.5px;color:var(--text)}

/* ── Sign in, as a popup ───────────────────────────────────────────────────────────────────
   A login is an interruption, so it sits on top of the board rather than replacing it. */
/* The sign-out control is a FORM (it posts a server action), so the wrapper must not
   introduce a block box into the header's flex row. */
.avb-app .sh-out{display:contents}
/* THE ACCOUNT CLUSTER SITS AT THE FAR RIGHT, AWAY FROM THE REST. Alerts, Pricing and Contact
   are places on this site; your account is not, and standing it in that run made it read as a
   fourth destination. The auto margin takes every pixel between them.
   ☢️ IT IS ON THE GROUP, NOT ON THE BUTTON. It used to sit on .sh-signin, which worked only
   while that button was alone out there — adding Profile beside it stranded Profile back on
   the left. A wrapper also survives .sh-out being display:contents, which is why the signed-in
   form could never have carried the margin itself. */
.avb-app .sh-acct{display:flex;align-items:stretch;gap:2px;margin-left:auto}
.avb-app .sh-signin{border:0;background:none;font:inherit;letter-spacing:inherit;
  text-transform:inherit;cursor:pointer;color:var(--btc)}
.avb-app .sh-profile{color:var(--dim)}
.avb-app .sh-profile:hover,.avb-app .sh-profile.on{color:var(--text)}
.avb-app .sh-signin:hover{color:var(--text)}
.si-scrim{position:fixed;inset:0;z-index:60;display:grid;place-items:center;padding:24px;
  background:var(--veil);backdrop-filter:blur(3px);animation:hm-fade .14s ease;
  overflow-y:auto}
.si-card{position:relative;max-width:400px;width:100%;animation:hm-pop .16s cubic-bezier(.2,.8,.2,1)}
.si-x{position:absolute;top:10px;right:12px;width:28px;height:28px;display:flex;
  align-items:center;justify-content:center;border:0;background:none;color:var(--faint);
  font-size:20px;line-height:1;cursor:pointer;border-radius:var(--r)}
.si-x:hover{color:var(--text);background:var(--raise)}
/* The tabs are BUTTONS in the dialog and links nowhere else, so the shared rule has to cover
   both — a button brings its own font, border and background and would otherwise ignore it. */
.auth-tab{border:0;background:none;font-family:var(--sans);cursor:pointer}
@media (max-width:620px){.si-scrim{padding:12px;place-items:start center}}

/* ── Sign in / Create account ─────────────────────────────────────────────────────────────
   One card, two modes, switched by ?mode= in the URL rather than by client state — so the tab
   is a LINK, and it survives a refresh. */
.avb-app .auth-tabs,.auth-tabs{display:flex;gap:20px;border-bottom:1px solid var(--line-soft);margin:14px 0 20px}
.auth-tab{position:relative;padding:0 0 9px;font-family:var(--sans);font-size:14px;font-weight:600;
  color:var(--faint);text-decoration:none;transition:color .12s ease}
.auth-tab:hover{color:var(--dim)}
.auth-tab.on{color:var(--text)}
/* The underline sits ON the container's border, not under it, so the two never double up. */
.auth-tab.on::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--up)}
.auth-hint{font-size:11.5px;line-height:1.5;color:var(--faint);margin:2px 0 0}
.auth-btn--wallet{background:var(--surface-2)}
.wl-list{display:flex;flex-direction:column;gap:8px}
/* Each wallet is a button of the same weight as the one it replaced — a picker should not
   look like a downgrade from the thing you clicked. */
.wl-opt{justify-content:flex-start;gap:10px;padding-left:14px;margin-top:0}
.wl-ico{width:18px;height:18px;border-radius:4px;flex:0 0 auto}
/* A plain-text action under a solid button: it is the third-choice door and should not compete
   with the two above it for weight. */
.auth-link{display:block;width:100%;margin-top:12px;padding:0;border:0;background:none;
  font-family:var(--sans);font-size:12.5px;color:var(--faint);cursor:pointer;text-align:center;
  transition:color .12s ease}
.auth-link:hover{color:var(--dim);text-decoration:underline}
.auth-note--tight{margin:16px 0 0;font-size:11.5px}
.auth-note--ok{border-left-color:var(--up)}
.auth-note--bad{border-left-color:var(--down)}
.auth-card .auth-btn+.auth-btn,.auth-card form+form{margin-top:10px}

.auth-note--ok{border-left-color:var(--up)}
.auth-note--bad{border-left-color:var(--down)}
.auth-foot{font-size:11.5px;color:var(--faint);margin:24px 0 0;text-align:center}
.auth-foot a{color:var(--dim)}
/* Heatmap · Bullseye view — strongest at the centre, weakest on the rim.
   Shares the grid view's colour scale; only the placement differs. */
.hm-radial{position:relative;flex:1 1 auto;min-height:0;overflow:hidden;
  /* On the container as well as the svg: a drag starting on the panel rather than on a wedge
     would otherwise begin a selection that runs straight through the labels. */
  user-select:none;-webkit-user-select:none}
/* the svg is square by construction; pin it so its 1:1 aspect cannot drive the
   container height, and let preserveAspectRatio fit it to the shorter side. */
/* The ellipse fills the panel, so the svg simply fills its box and nothing scrolls. */
.hm-radial svg{position:absolute;inset:0;width:100%;height:100%;display:block}
/* The board is a pan/zoom surface: the basket is drawn at a FIXED cell size, so with a
   wide basket the outer rings legitimately fall outside the panel and are reached by
   dragging or zooming out, rather than by shrinking every cell to fit. */
.hm-radial-svg{cursor:grab;touch-action:pan-y;
  /* The board is a module you manipulate, not a document you select. Without this a drag
     paints every label blue and the browser's own text-selection fights the pan. */
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
.hm-radial-svg text{user-select:none;-webkit-user-select:none}
/* Icons are decoration inside a cell that is already the hit target — taking pointer events
   would make the glyph swallow clicks meant for the wedge. */
/* Round every icon box. Most token art is already a circle on transparency and is
   unaffected; the square ones (exchange-style tiles) were the only hard corners on a board
   made entirely of soft marks, so they read as damage rather than as brand. */
.hm-sicon{pointer-events:none;clip-path:inset(0 round 24%)}
.hm-sicon--tiny{opacity:.92}
.hm-radial-svg:active{cursor:grabbing}
.hm-sect{cursor:pointer;outline:none}
/* stroke matches the grid's 2px gap and its gap colour, so a cell reads as the same
   box in either layout. */
.hm-sect path,.hm-fills path{stroke:var(--hm-gap);stroke-width:2;transition:opacity .12s ease}
.hm-sect:hover path{opacity:.82}
/* The wedge colour is painted once, in .hm-fills; that layer takes no pointer events so it
   can never sit between a cursor and the sector that owns it. .hm-hit is the live surface
   laid over each wedge — no fill of its own until hover, when it lifts the sector under the
   cursor. Without it only the glyphs were clickable and the coin sheet looked broken here. */
.hm-fills{pointer-events:none}
.hm-sect .hm-hit{fill:transparent;stroke:none;pointer-events:all;transition:fill .12s ease}
/* The same affordance the grid gives a cell — brighten, and lay a white rule on the
   boundary. The grid uses box-shadow:inset, which SVG has no equivalent for; a CENTRED
   stroke gets there anyway, because neighbouring wedges paint over its outer half while
   their own fills stop at the shared edge — what survives is the inner half, an inset
   outline. vector-effect holds it at one weight instead of thickening as you zoom in. */
.hm-sect:hover .hm-hit{
  fill:var(--hi-4);
  /* SOLID white, not 62%. A translucent stroke composites with the tile beneath it, so on
     an orange or green wedge it came out grey — the grid's outline reads white because a
     box-shadow:inset sits above the fill rather than mixing into it. Nothing overdraws this
     stroke: sibling wedges paint only a transparent fill, and all the coloured fills are in
     the hm-fills layer underneath. */
  stroke:var(--found);stroke-width:3;vector-effect:non-scaling-stroke;
}
.hm-sect:hover .hm-slabel,.hm-sect:hover .hm-svalue{opacity:1}
/* The clicked cell keeps the outline while its sheet is open, so it stays obvious WHICH
   wedge the panel belongs to. Brighter and heavier than hover — hover is "you could",
   selected is "you did". The board goes inert behind the sheet, so hover cannot fire here
   and the two states never compete. */
.hm-sect.is-sel .hm-hit{
  fill:var(--hi-5);
  stroke:var(--found);stroke-width:4;vector-effect:non-scaling-stroke;
}
.hm-sect:focus-visible path{stroke:var(--text);stroke-width:2.4}

/* THE BENCHMARK MEDALLION answers to the same states as any wedge, but every rule above is
   written against the <path> a sector is drawn with and this one is a <circle> — so hover,
   focus and selection have to be spelled out again or the centre of the board would be the
   only cell that looks dead to the pointer. */
.hm-btc circle{transition:stroke .12s ease,opacity .12s ease}
.hm-btc:hover circle{opacity:.85}
.hm-btc:focus-visible circle,.hm-btc.is-sel circle{
  stroke:var(--found);stroke-width:4;vector-effect:non-scaling-stroke;
}
.hm-slabel,.hm-svalue{font-family:var(--mono);text-anchor:middle;dominant-baseline:middle;pointer-events:none;letter-spacing:.01em}
.hm-slabel{font-weight:700}
/* ☢️ SPLIT BULLSEYE (local experiment, 2026-09-04) — BITCOIN'S OWN LEVEL.
   The one mark on that board that is not a coin: everything above it beat Bitcoin over the
   selected window, everything below it lost to it. Bitcoin orange, because the medallion it
   runs through is that colour and the line is the same fact spread sideways.
   ⚠️ PLACED AFTER .hm-slabel DELIBERATELY. Source order settles ties at equal specificity, so
   a rule for this board written above the bullseye's own would lose to it silently — the trap
   this file has sprung three times. Anything overriding a .hm-* base belongs below it.
   ⚠️ The stroke is non-scaling (set as an attribute on the element), so a pinch to 12x does
   not draw a 24px orange bar across the board. */
.hm-btcline{stroke:#f7931a;stroke-width:1.5;opacity:.55;pointer-events:none;stroke-dasharray:6 5}
/* SPLIT BULLSEYE — the medallion's three lines.
   ☢️ FACE, WEIGHT AND TRACKING ARE SET INLINE IN THE COMPONENT, DELIBERATELY — see BRAND_FACE
   there. `.avb-app svg text{font-family:var(--mono)}` is (0,1,1) and beats any bare class
   written here, so a font-family in this block would be dead code that looks alive. What is
   left here is only what nothing else is competing for. */
.hm-cline{text-anchor:middle;dominant-baseline:middle;pointer-events:none}
.hm-svalue{font-weight:600;opacity:.82}
/* Zoom controls sit in the panel's own corner rather than the page header: they act on
   this chart only, and the header controls already carry the basket-wide filters. */
.hm-zoom{position:absolute;right:10px;bottom:10px;display:flex;gap:4px;z-index:6}
.hm-zbtn{min-width:26px;height:26px;padding:0 6px;display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:12px;font-weight:600;line-height:1;color:var(--text);
  background:var(--well-2);border:1px solid var(--line);border-radius:4px;cursor:pointer;
  backdrop-filter:blur(3px);transition:background .12s ease,border-color .12s ease}
.hm-zbtn:hover{background:var(--raise);border-color:var(--text)}
.hm-zbtn:focus-visible{outline:2px solid var(--text);outline-offset:1px}
.hm-zwide{min-width:34px}

/* Heatmap header controls — layout + strength window, in the page header so no tile is
   ever covered. Wraps under the copy on narrow screens. */
.hm-head{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;flex-wrap:wrap}
.hm-head-copy{min-width:0;flex:1 1 420px}
/* ☢️ ONE WRAPPING RUN AT EVERY WIDTH. This was a two-column grid above ~1650px and a packed
   run below it, and the seam was visible: the search box sat under the layout tabs on a wide
   window and mid-row on a narrow one, moving as the window moved. Two layouts for one bar is
   two things to get right and one more thing to be inconsistent about. */
.hm-controls{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;padding-top:0}
.hm-band{display:flex;gap:8px 18px;align-items:center;flex-wrap:wrap;min-width:0}
/* ☢️ THE FILTER GROUP IS A WRAPPER, NOT A COLUMN. Left as a flex BLOCK it claims a whole row
   of its own and the controls inside it can never share a line with Layout or Timeframe —
   which is the reserved emptiness this bar had, wearing a different shape. display:contents
   makes its children peers of everything else so the whole bar packs as one run.
   ⚠️ Above 760px only: below that it is the panel behind the More button and must keep its
   box, or display:none has nothing to hide. Scoped past `.avb-app .hm-more{display:flex}`,
   which is (0,2,0) and sits later in this file. */
/* (The desktop display:contents rule that flattened this group into the bar is gone: the
   group is the Filters panel now, at every width.) */
/* ⚠️ THE RIGHT ZONE CARRIES SIX GROUPS IN HALF THE BAR, so it is the one that decides how many
   rows the whole bar costs. A tighter column gap here is worth more than anywhere else on the
   run: measured at 1440px it is the difference between two rows and three. */
.hm-band-r{gap:8px 12px}
/* The search and its report button travel together — they are one control with an exit. */
/* Sized to its content: at 100% it claims a whole row and everything after it drops a line. */
.hm-searchrow{display:flex;gap:8px;align-items:center;flex-wrap:wrap;flex:0 1 auto}
/* ⚠️ THE FIELD SHRINKS SO THE BUTTON HAS SOMEWHERE TO GO. It was 340px wide holding a
   placeholder of twelve characters, and once a coin is picked it holds a name — neither needs
   that much. `flex:1 1 200px` lets it take the row when it is alone and give way the moment
   the report button appears beside it, instead of pushing that button onto a line of its own. */
.hm-searchrow .hm-search{flex:1 1 200px;min-width:150px;max-width:260px}

/* The right zone packs toward the edge, and its rows stay right-aligned when it wraps. */
.hm-band-r{justify-content:flex-end}
.hm-ctl{display:flex;flex-direction:row;align-items:center;gap:8px}
/* ── A CONTROL THAT THIS LAYOUT DOES NOT USE ─────────────────────────────────────────────
   Dimmed and inert, NEVER removed. Cells used to vanish on the list and Order by on the
   bubbles, which meant the run re-flowed every time the layout changed: 213px and 341px of
   controls appearing and disappearing slid everything after them sideways, so the reader had
   to re-find Min market cap on each switch. A fixed set of slots costs the width of two
   greyed groups and buys a bar you can learn once.

   ⚠️ THE `disabled` ATTRIBUTE IS WHAT MAKES IT INERT, not this rule. Opacity only says so, and
   pointer-events:none would still leave the buttons in the tab order — reachable by keyboard,
   invisible to the mouse, which is the worst of both. This dims; the attribute disables. */
.avb-app .hm-ctl.is-off{opacity:.34}

/* ── THE WATCH STAR ──────────────────────────────────────────────────────────────────────
   Quiet until it is on, then it carries the same amber the lens uses for "you have chosen
   something here". It sits in the coin sheet and on the coin's own page; deliberately NOT in
   the hover preview, which moves out from under the pointer. */
.avb-app .wstar{display:inline-flex;align-items:center;gap:6px;padding:5px 9px;
  background:var(--well);border:1px solid var(--line);border-radius:var(--r);
  color:var(--dim);cursor:pointer;
  font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;transition:color .12s ease,border-color .12s ease}
.avb-app .wstar:hover{color:var(--text);border-color:var(--line-soft)}
.avb-app .wstar.on{color:var(--btc);border-color:var(--btc);background:rgba(247,147,26,.08)}
.avb-app .wstar svg{flex:0 0 auto}
/* The word is the affordance on a page with room; the glyph carries it where there is not. */
@media (max-width:620px){.avb-app .wstar-txt{display:none}}
@media (pointer:coarse){.avb-app .wstar{min-height:36px}}

/* ── THE PROFILE PAGE ────────────────────────────────────────────────────────────────────
   Two cards on the same terminal ground the rest of the site uses. No new palette. */
.avb-app .pf{max-width:920px;margin:0 auto;padding:22px var(--gutter) 60px}
.avb-app .pf-head{margin-bottom:18px}
.avb-app .pf-h1{font-size:clamp(19px,2.2vw,26px);font-weight:700;letter-spacing:-.01em;color:var(--ink)}
.avb-app .pf-sub{margin-top:5px;color:var(--dim);font-size:12.5px;line-height:1.45;max-width:70ch}
.avb-app .pf-card{margin-top:16px;padding:16px 18px;border:1px solid var(--line);border-radius:8px;
  background:var(--well)}
.avb-app .pf-h2{display:flex;align-items:baseline;gap:10px;
  font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--faint)}
.avb-app .pf-count{margin-left:auto;color:var(--dim);font-variant-numeric:tabular-nums}
.avb-app .pf-dl{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  gap:14px;margin:14px 0 16px}
.avb-app .pf-dl dt{font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--faint);margin-bottom:3px}
.avb-app .pf-dl dd{color:var(--text);font-size:13px;word-break:break-word}
.avb-app .pf-out{padding:7px 12px;border:1px solid var(--line);border-radius:5px;background:none;
  color:var(--dim);cursor:pointer;font-family:var(--mono);font-size:10.5px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase}
.avb-app .pf-out:hover{color:var(--text);border-color:var(--line-soft)}
.avb-app .pf-empty{margin-top:12px;color:var(--dim);font-size:12.5px;line-height:1.5}
.avb-app .pf-empty a{color:var(--btc)}
.avb-app .pf-list{list-style:none;margin:12px 0 0;padding:0}
.avb-app .pf-row{display:flex;align-items:center;gap:12px;padding:8px 0;
  border-top:1px solid var(--line-soft)}
.avb-app .pf-coin{display:flex;align-items:center;gap:9px;min-width:0;flex:1 1 auto;
  text-decoration:none;color:inherit}
.avb-app .pf-tk{font-family:var(--mono);font-weight:700;font-size:12px;letter-spacing:.06em;color:var(--text)}
.avb-app .pf-nm{color:var(--dim);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.avb-app .pf-rets{display:flex;gap:14px;flex:0 0 auto}
/* Fixed-width columns so the numbers form a column rather than a ragged edge. */
.avb-app .pf-r{display:flex;flex-direction:column;align-items:flex-end;min-width:52px;
  font-family:var(--mono);font-size:12px;font-variant-numeric:tabular-nums;color:var(--dim)}
.avb-app .pf-r i{font-style:normal;font-size:8.5px;letter-spacing:.13em;color:var(--faint)}
.avb-app .pf-r.up{color:var(--up,#43d17a)}
.avb-app .pf-r.down{color:var(--down,#e35d6a)}
.avb-app .pf-asof{margin-top:12px;color:var(--faint);font-size:11px}
@media (max-width:620px){
  .avb-app .pf-nm{display:none}
  .avb-app .pf-rets{gap:10px}
  .avb-app .pf-r{min-width:44px}
}


/* ONE SLOT, TWO NAMES. The list asks for "Rows" and every board for "Coins" — the same
   position holding a different question. Their labels differ by 7px, which was enough to slide
   Order by, Min market cap and Min volume sideways on every switch into and out of the list.
   The label reserves the wider of the two words so the slot's width is a constant. */
.avb-app .hm-ctl--count .hm-ctl-lbl{min-width:40px}
.avb-app .hm-ctl.is-off .hm-segbtn{cursor:not-allowed}
/* Disabled buttons still take :hover in several browsers, and a control that lights up under
   the pointer reads as clickable however faint it is. */
.avb-app .hm-ctl.is-off .hm-segbtn:hover{color:var(--dim)}
.avb-app .hm-ctl.is-off .hm-segbtn.on:hover{color:var(--text)}
.hm-ctl-lbl{font-family:var(--mono);font-weight:700;font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--dim);white-space:nowrap}
.hm-seg{display:flex;gap:2px;background:var(--well);border:1px solid var(--line);border-radius:var(--r);padding:2px}
/* The options carry weight — they are the controls, not captions. Their LABELS (.hm-ctl-lbl)
   were kept light so the row read as "label: choices"; Kevin (2026-09-29) found them too faint
   to find, so they are bold now, a step dimmer than the options rather than a step fainter.
 */
.hm-segbtn{background:none;border:0;border-radius:3px;color:var(--dim);font-family:var(--mono);font-weight:700;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;padding:5px 10px;cursor:pointer;white-space:nowrap}
.hm-segbtn:hover{color:var(--text)}
.hm-segbtn.on{background:var(--raise);color:var(--text);box-shadow:inset 0 0 0 1px var(--line-soft)}
@media (max-width:900px){.hm-controls{width:100%}}
/* ☢️ BELOW THE THREE-COLUMN WIDTH, FALL BACK TO WRAPPING — NOT TO ONE COLUMN PER ZONE.
   Stacking the zones was the obvious move and it cost 178px: measured at 1100px and 900px the
   bar went from 136px to 314px, because the right zone's six groups each took a row of their
   own instead of flowing two or three to a line. Flex-wrap keeps the grouping (a reader still
   meets steer, then horizon, then filters) and gives back the old packing. */
@media (max-width:760px){
  .hm-controls{display:flex;flex-wrap:wrap;align-items:center}
  .hm-band-r{justify-content:flex-start}
}

/* Heatmap hover preview — the read without the click. Pointer-driven, so it must never
   intercept the pointer itself or it would fight the tile underneath. */
.hm-hover{position:fixed;z-index:40;pointer-events:none;background:var(--glass);border:1px solid var(--line-2,var(--line));border-radius:8px;padding:12px 13px 10px;box-shadow:0 18px 40px var(--shadow);backdrop-filter:blur(8px);animation:hmHoverIn .1s ease-out}
@keyframes hmHoverIn{from{opacity:0;transform:translateY(3px)}to{opacity:1;transform:none}}
.hm-hv-top{display:flex;align-items:baseline;gap:7px;margin-bottom:6px}
.hm-hv-sym{font-family:var(--mono);font-size:13px;font-weight:700;color:var(--ink,var(--text));letter-spacing:.04em}
.hm-hv-name{font-family:var(--display,var(--sans));font-size:11.5px;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hm-hv-big{font-family:var(--mono);font-size:23px;font-weight:600;line-height:1.1;display:flex;align-items:baseline;gap:8px}
.hm-hv-win{font-size:10px;font-weight:500;color:var(--faint);letter-spacing:.06em;text-transform:uppercase}
.hm-hv-state{display:inline-flex;align-items:center;gap:6px;margin:8px 0 2px;padding:3px 8px;border-radius:4px;border:1px solid var(--hc);color:var(--hc);background:color-mix(in srgb,var(--hc) 12%,transparent);font-family:var(--mono);font-size:10.5px;letter-spacing:.05em}
.hm-hv-state i{font-style:normal;color:var(--faint);border-left:1px solid currentColor;padding-left:6px;margin-left:2px;opacity:.7}
.hm-hv-spark{height:38px;margin:8px 0 6px;opacity:.95}
.hm-hv-spark svg{width:100%;height:100%;display:block}
/* Seven windows now (6M and YTD joined the five), so the card widened to 320px to keep each
   column able to hold "+2695%" without wrapping. */
.hm-hv-rows{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;border-top:1px solid var(--line-soft);padding-top:7px}
.hm-hv-rows>div{display:flex;flex-direction:column;gap:2px;align-items:center}
.hm-hv-w{font-family:var(--mono);font-size:8.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--faint)}
.hm-hv-p{font-family:var(--mono);font-size:10.5px;font-weight:600;color:var(--dim)}
.hm-hv-p.hm-pos{color:var(--up)}
.hm-hv-p.hm-neg{color:var(--down)}
/* The price line: what the coin costs, in the two denominations the site cares about. */
.hm-hv-px{display:flex;justify-content:space-between;gap:10px;margin-top:8px;padding-top:7px;
  border-top:1px solid var(--line-soft);font-family:var(--mono);font-size:9.5px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--faint)}
.hm-hv-px b{font-weight:700;color:var(--ink);letter-spacing:.02em}
.hm-hv-foot{margin-top:8px;font-family:var(--mono);font-size:8.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint);opacity:.75}

/* Table view inside the unified Overview — the board is no longer a page, so it scrolls
   inside the shell's main column rather than owning the viewport. */
.avb-board{padding:0 18px 28px;overflow-y:auto;max-height:100%}
.avb-board .table-card{margin-top:0}
.watchbtn{background:var(--raise);border:1px solid var(--line);border-radius:var(--r);color:var(--dim);font-family:var(--mono);font-size:11px;letter-spacing:.06em;padding:6px 11px;cursor:pointer;margin-left:auto}
.watchbtn:hover{color:var(--text);border-color:var(--faint)}
.watchbtn.on{background:var(--amber);border-color:var(--amber);color:#0A0C0F}

/* The state tape and its horizon label share one row — the bands are grouped on the
   flagship horizon and do NOT follow the return column's timeframe. */
.avb-app .taperow{display:flex;align-items:center;gap:14px}
.avb-app .taperow .tapebar{flex:1;min-width:0}
.avb-app .tape-macro{display:inline-flex;align-items:center;gap:7px;flex:0 0 auto;font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);white-space:nowrap}
.avb-app .tape-macro i{font-style:normal;color:var(--ink-2,var(--text));background:var(--raise);border:1px solid var(--line);border-radius:4px;padding:2px 7px;letter-spacing:.04em}
@media (max-width:900px){.avb-app .tape-macro{display:none}}

/* ============================================================================
   SITE HEADER — one ruled ledger line.
   The mark is typeset notation, not a picture: ALT set over BTC, split by a
   Bitcoin-orange hairline. That same hairline is the only underline in the row,
   reappearing under the active tab — so the mark's divider, the product's
   denominator and "where you are" are one recurring rule.
   Orange appears exactly twice: the fraction rule, and the active tab.
   ============================================================================ */
.avb-app .sh{
  position:sticky;top:0;z-index:40;
  height:var(--hdr);box-sizing:border-box;
  display:flex;align-items:stretch;gap:26px;
  padding:0 var(--gutter);
  background:var(--bg);border-bottom:1px solid var(--line);
}

/* The mark. Two decks inside 52px means ~10px type, so the rule between them does the
   work the glyph size cannot. `padding-bottom` on the numerator is the optical nudge:
   the fraction's optical centre sits above its box centre, so centring the box lands
   the mark low. */
.avb-app .sh-mark{
  display:flex;flex-direction:row;justify-content:center;align-items:center;gap:9px;
  flex:0 0 auto;text-decoration:none;padding:0 2px;
  align-self:center;
}
/* The wordmark beside the mark, the way CoinGecko and CoinMarketCap set theirs: the glyph
   carries the identity, the name carries the address. Optical size is matched to the nav
   rather than the mark, so it reads as part of the header rather than as a second logo. */
.avb-app .sh-word{
  font-family:var(--display);font-size:15px;font-weight:600;letter-spacing:-.015em;
  color:var(--ink);line-height:1;white-space:nowrap;
}
/* The TLD half-steps back so the eye lands on the name first and still reads one unit. */
.avb-app .sh-word-tld{color:var(--dim);font-weight:500}
/* Below this the nav needs the room more than the address does; the mark still identifies. */
@media (max-width:620px){.avb-app .sh-word{display:none}}

/* HOVER: the mark's slash runs across the name.
   The band is painted into the text itself with background-clip, so the orange travels
   THROUGH the glyphs rather than passing over them as an overlay — a stripe drawn on top
   would cross the gaps between letters too and read as a scanline, not as the slash.
   The gradient is 260% of the box so the band can start and finish fully off the word. */
.avb-app .sh-word{
  background-image:linear-gradient(100deg,
    var(--ink) 0 40%,
    #FF5B2E 46%, var(--btc) 50%, #FF5B2E 54%,
    var(--ink) 60% 100%);
  background-size:260% 100%;
  background-position:135% 0;
  -webkit-background-clip:text;background-clip:text;
}
/* Only on hover does the fill become the gradient. At rest the colours are plain, so the
   .com keeps stepping back and nothing depends on background-clip being supported. */
.avb-app .sh-mark:hover .sh-word,
.avb-app .sh-mark:focus-visible .sh-word{
  color:transparent;
  animation:avb-slash 1.5s cubic-bezier(.5,0,.5,1) infinite;
}
/* The TLD is a CHILD element, and background-clip:text only paints inside the glyphs of the
   element that owns the background — a child paints its own text. Making it transparent to
   "let the band through" would simply erase it. So it keeps a real colour and warms in time
   with the sweep instead, catching the slash as it passes. */
.avb-app .sh-mark:hover .sh-word-tld,
.avb-app .sh-mark:focus-visible .sh-word-tld{
  animation:avb-slash-tld 1.5s cubic-bezier(.5,0,.5,1) infinite;
}
@keyframes avb-slash-tld{
  0%,100%{color:var(--dim)}
  /* peaks just after the band clears the name, so the warmth reads as travel */
  55%{color:var(--btc)}
}

@keyframes avb-slash{
  0%{background-position:135% 0}
  60%{background-position:-35% 0}
  100%{background-position:-35% 0}
}

/* The slash is baked into logo-mark.png, so it cannot be selected — but it is the only warm
   thing in the mark, so an orange glow pulsing in time with the sweep reads as that stroke
   lighting up and hands the two halves the same heartbeat. */
.avb-app .sh-mark:hover .sh-logo,
.avb-app .sh-mark:focus-visible .sh-logo{animation:avb-slash-glow 1.5s ease-in-out infinite}
@keyframes avb-slash-glow{
  0%,100%{filter:drop-shadow(0 0 0 transparent)}
  45%{filter:drop-shadow(0 0 6px var(--btc-glow)) drop-shadow(0 0 2px rgba(255,91,46,.55))}
}

@media (prefers-reduced-motion:reduce){
  .avb-app .sh-mark:hover .sh-word,
  .avb-app .sh-mark:focus-visible .sh-word,
  .avb-app .sh-mark:hover .sh-logo,
  .avb-app .sh-mark:focus-visible .sh-logo{animation:none}
  /* Still acknowledge the hover, just without motion. */
  .avb-app .sh-mark:hover .sh-word{color:var(--btc)}
  .avb-app .sh-mark:hover .sh-word-tld{color:var(--btc);animation:none}
}
/* The monogram in the 52px row. Height is the only axis set so the intrinsic 1.19 aspect
   holds; `display:block` drops the inline baseline gap that would push it off centre. */
.avb-app .sh-logo{display:block;height:30px;width:auto}

/* Tabs: text only. A board has labels, not pictograms. */
.avb-app .sh-nav{display:flex;align-items:stretch;gap:2px;flex:0 0 auto}
.avb-app .sh-tab{
  display:flex;align-items:center;padding:0 11px;
  font-family:var(--mono);font-size:11.5px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;
  color:var(--dim);text-decoration:none;
  border-bottom:1px solid transparent;margin-bottom:-1px;
}
.avb-app .sh-tab:hover{color:var(--ink)}
.avb-app .sh-tab.on{color:var(--ink);border-bottom-color:var(--btc)}

/* The census — the state of the instrument, in this product's own units. Text, not a
   colour-coded rule: it must read without colour and must not re-proportion on lens
   change. Counts sum to the printed total by construction. */
.avb-app .sh-census{
  display:flex;align-items:center;gap:15px;margin-left:auto;flex:0 1 auto;min-width:0;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--dim);white-space:nowrap;overflow:hidden;
}
.avb-app .sh-c,.avb-app .sh-close{display:inline-flex;align-items:baseline;gap:5px}
.avb-app .sh-c b,.avb-app .sh-close b{font-weight:600;font-size:12px;letter-spacing:.02em;color:var(--ink-2)}
.avb-app .sh-total b{color:var(--ink)}
.avb-app .sh-close{padding-left:15px;border-left:1px solid var(--line)}
.avb-app .sh-census--min{display:none}

/* Account business, not instruments — demoted right of the census. */
/* ☢️ IT GROWS, SO THE SIGN-IN HAS SOMEWHERE TO GO. Every child of .sh was flex:0 0 auto, so
   the whole header packed against the left and the util run ended at x=754 on a 1406px bar —
   "Sign in" sat in the MIDDLE of the chrome while the right half stood empty. margin-left:auto
   below cannot move anything inside a group that is only as wide as its contents; the group
   has to span the bar first. */
.avb-app .sh-util{display:flex;align-items:stretch;gap:2px;flex:1 1 auto}
.avb-app .sh-ut{
  display:flex;align-items:center;padding:0 9px;
  font-family:var(--mono);font-size:11px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--dim);text-decoration:none;
  border-bottom:1px solid transparent;margin-bottom:-1px;
}
.avb-app .sh-ut:hover{color:var(--ink-2)}
.avb-app .sh-ut.on{color:var(--ink);border-bottom-color:var(--btc)}
.avb-app .sh-tab:focus-visible,.avb-app .sh-ut:focus-visible,.avb-app .sh-mark:focus-visible{
  outline:2px solid var(--btc);outline-offset:-3px;border-radius:2px;
}

/* Narrow: the tab run scrolls rather than collapsing to a menu, and the census keeps the
   two facts a stranger gets wrong — basket size, and that it is a settled close. */
@media (max-width:1180px){
  .avb-app .sh-census{display:none}
  .avb-app .sh-census--min{display:flex;margin-left:auto}
}
@media (max-width:860px){
  .avb-app .sh{gap:12px;padding:0 12px}
  .avb-app .sh-nav{overflow-x:auto;scrollbar-width:none}
  .avb-app .sh-nav::-webkit-scrollbar{display:none}
  .avb-app .sh-tab{padding:0 8px}
  .avb-app .sh-census--min{display:none}
  .avb-app .sh-search-txt,.avb-app .sh-kbd{display:none}
  .avb-app .sh-search{padding:0 10px}
}
/* Below the small breakpoint the tab bar carries the sections; the header keeps the brand,
   the search and the account (redesign spec §6.2). */
@media (max-width:640px){
  .avb-app .sh-nav{display:none}
  .avb-app .sh-util{justify-content:flex-end}
  .avb-app{padding-bottom:58px}
  .avb-app .tb{display:grid}
}

/* The full wordmark, where it has room — footer sign-off. Same notation, readable size. */
/* The wordmark is the A/B monogram image (components/Brand.tsx). Height is the only axis set
   — width follows the intrinsic 1.19 aspect, so the mark can never be stretched by a parent. */
.avb-app .wm{display:inline-block;width:auto;object-fit:contain}
.avb-app .wm--md{height:34px}
.avb-app .wm--sm{height:24px}
/* Inside the page bar the description is the last thing in the box, so its own margins are
   dead space stacked on the bar's padding — 16px charged to every route's first data pixel. */
.avb-app .pagebar .pagehead-desc{margin:0}
.avb-app .pagebar .pagehead-title{margin-bottom:2px}
/* The control row sets the page bar's height on Overview, and the Bullseye is height-bound —
   every pixel here comes straight off the disc. Labels sit inline with their segments. */
/* Pinned under the header: a full-width disc scrolls the page, and the controls must
   not scroll away with it. */
.avb-app .pagebar{padding:6px var(--gutter);position:sticky;top:var(--hdr);z-index:35;background:var(--bg)}

/* Map footer — the key, the colour scale and the provenance line, on their own rule
   BELOW the field. Previously these were four absolutely-positioned overlays printing on
   top of live tiles (and on top of each other at the bottom-left corner). */
.avb-app .hm-foot-rule{
  flex:0 0 auto;display:flex;align-items:center;gap:20px;
  height:34px;padding:0 16px;border-top:1px solid var(--line);background:var(--bg);
  font-family:var(--mono);font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--dim);
}
.avb-app .hm-key{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.avb-app .hm-scale{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;color:var(--dim)}
.avb-app .hm-scale i{width:9px;height:9px;border-radius:2px;display:inline-block;margin-left:8px}
.avb-app .hm-scale i:first-child{margin-left:0}
.avb-app .hm-src{margin-left:auto;white-space:nowrap;color:var(--faint)}
/* The panel's lower edge. Sits under the mosaic rather than over it, so it neither hides a
   coin nor sits under the vignette's darkened corner. */
.avb-app .hm-edgebar{flex:0 0 auto;position:relative;z-index:6;display:flex;justify-content:center;
  align-items:center;gap:10px;padding:6px 0;background:var(--bg);border-top:1px solid var(--line)}
/* THE RESIZE GRIP — the panel's lower edge, made draggable. It sits beside Expand rather than
   spanning the bar: a full-width drag strip would swallow the click target of the button in
   the middle of it, and the pair reads as one control cluster on the edge they both move. */
.avb-app .hm-grip{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:48px;height:18px;padding:0;border:1px solid var(--line);border-radius:4px;
  background:transparent;color:var(--dim);cursor:ns-resize;
  /* ☢️ Without this the browser claims the gesture for scrolling and the pointermove stream
     stops dead partway through the drag — the panel follows for 20px and then freezes. */
  touch-action:none;
  transition:color .12s ease,border-color .12s ease}
.avb-app .hm-grip:hover{color:var(--text);border-color:var(--text)}
.avb-app .hm-grip:focus-visible{outline:2px solid var(--text);outline-offset:1px}
.avb-app .hm-grip-lines{display:block;width:20px;height:5px;
  background:repeating-linear-gradient(to bottom,currentColor 0 1px,transparent 1px 3px)}
/* NOTHING TO SHOW IS NOTHING TO DRAW. The bar rides under BOTH boards now, so it can end up
   holding no control at all — the bullseye has no Expand, and a basket short enough to need no
   expanding has none either. Left alone it still paints its rule, its background and 6px of
   padding: an empty ruled strip under the board where previously there was nothing.
   ⚠️ `:empty` cannot do this. The grip is hidden with display:none on touch and is still a
   child node, so the bar is never empty — the test has to be for the CONTROLS. */
.avb-app .hm-edgebar:not(:has(.hm-grip)){display:none}
/* DESKTOP ONLY, as asked. A drag handle wants a pointer that can hover and a window worth
   resizing; on a phone the panel is already sized to the viewport, and an 18px target sitting
   under the board is one more thing to catch while panning it. */
@media (max-width:760px),(pointer:coarse){
  .avb-app .hm-grip{display:none}
  /* …which the rule above cannot see: the grip is present but display:none, so the bar would
     survive on a child that draws nothing. The grip is now the bar's ONLY control, so on touch
     the bar never has anything to show. */
  .avb-app .hm-edgebar{display:none}
}
@media (max-width:760px){.avb-app .hm-key{display:none}}

/* ── Front page: chart over ranked list ─────────────────────────────────────────────────
   The chart used to own the whole viewport (flex:1 on .avb-heatmap). It now takes a fixed
   slice so the ranked list beneath it is always reachable, and the pair scrolls as one
   column. Height is viewport-relative with a ceiling: on a tall monitor a 90vh bullseye
   would push the list entirely below the fold, which is the one thing this layout exists
   to prevent. */
.avb-app .fp{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column}
/* ☢️ The height is NOT written here any more. It was `min(76vh,760px)` on this rule while the
   grid sized itself to ten rows in Heatmap.tsx — two numbers for one panel, which is why the
   two views opened at visibly different heights. Heatmap owns it now (PANEL_VH / PANEL_MAX)
   and hands it down as --hm-panel-h on this element, because the grid's height has to be a
   ROW COUNT and a CSS length cannot be divided into rows. Do not reintroduce a fallback
   length here: the inline value is always present, including in the server's HTML. */
/* ⚠️ min-height:0 alongside it. The base .avb-heatmap carries min-height:340px, which the grid
   already overrides via .hm-fitrows — leaving the BULLSEYE with a 340px CSS floor under a JS
   floor of PANEL_MIN (240). Dragging into that gap moved nothing on screen while the stored
   number, the grip's own "currently N pixels tall" label and avb-hm-h all kept counting down.
   Two floors for one edge; the JS one is the one the drag is bounded by, so it wins. */
.avb-app .fp .avb-heatmap{flex:0 0 auto;height:var(--hm-panel-h);min-height:0}
/* Grid view is sized by its CONTENT — ten rows on load, all rows when expanded — so
   the panel height follows the animation instead of clipping it. The bullseye keeps
   the fixed-height panel above, because it is a pan/zoom viewport, not a list. */
/* min-height:0 as well as height:auto — the base .avb-heatmap carries min-height:340px,
   which held the panel open under a single row of cells (Min turnover $10M leaves ~22
   coins) and left ~260px of dead black between the grid and the list below it. */
.avb-app .fp .avb-heatmap.hm-fitrows{height:auto;min-height:0}

/* ── The ranked list ──────────────────────────────────────────────────────────────────── */
.avb-app .rk{border-top:1px solid var(--line);background:var(--bg);padding-inline:var(--gutter)}
.avb-app .rk-head{padding:16px 0 10px}
.avb-app .rk-title{font-family:var(--mono);font-size:13.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--ink);margin:0}
.avb-app .rk-win{color:var(--btc)}
.avb-app .rk-sub{margin:4px 0 0;font-size:13px;color:var(--dim)}
.avb-app .rk-warn{color:var(--base)}

/* NO sticky header here on purpose: this wrapper's overflow makes it the containing block
   for a sticky <th>, which would pin the header to the top of the TABLE rather than the
   viewport and leave it stranded mid-list. The list is read top-down anyway. */
.avb-app .rk-scroll{overflow-x:auto}
.avb-app .rk-table{width:100%;border-collapse:collapse;font-family:var(--mono);font-size:13.8px}
/* `display` and `border` are re-asserted, not decoration: the mono-readout group up at
   .avb-app thead th hands every table header in this scope the orange .denomtag chip
   treatment — inline-flex, a full border, a pill radius — which collapses a real header row
   into a stack of floating chips. That group is load-bearing for the chip itself, so this
   table opts out here instead of editing it. */
.avb-app .rk-table th{
  display:table-cell;border:0;border-radius:0;
  background:var(--panel);color:var(--faint);font-weight:600;font-size:11px;letter-spacing:.15em;
  text-transform:uppercase;text-align:right;padding:9px 12px;border-bottom:1px solid var(--line);
  white-space:nowrap;line-height:1.4;
}
.avb-app .rk-table td{padding:7px 12px;text-align:right;border-bottom:1px solid var(--line-soft);white-space:nowrap}
.avb-app .rk-row{cursor:pointer;outline:none}
.avb-app .rk-row:hover td{background:var(--panel-2)}
.avb-app .rk-row:focus-visible td{background:var(--raise);box-shadow:inset 0 0 0 1px var(--btc-bd)}

.avb-app .rk-table th.rk-num,.avb-app .rk-table td.rk-num{width:1%;text-align:right;color:var(--faint);font-variant-numeric:tabular-nums}
/* Content-sized, with a FLOOR. width:1% alone collapsed this to 24px and the name span to
   zero — its inner .rk-coin-in is a flex row whose name span carries overflow:hidden, so it
   "fits" by vanishing. The min-width is what makes shrink-to-content safe here.
   ☢️ The CELL is not the flex box and must never become one — see RankList.tsx. Coin and Trend then read as one block
   on the left and the slack falls between them and the numbers, which is where a reader's eye
   wants a break anyway. */
.avb-app .rk-table th.rk-coin,.avb-app .rk-table td.rk-coin{width:1%;min-width:250px;text-align:left;white-space:nowrap}
.avb-app .rk-coin-in{display:flex;align-items:center;gap:9px}
.avb-app .rk-coin-in .ico{width:22px;height:22px;flex:0 0 auto}
.avb-app .rk-sym{font-weight:700;color:var(--ink);letter-spacing:.04em}
/* Wider than it was: on a broad screen the slack lands here, and a name that can spell itself
   out is a better use of it than empty table. Still capped, still ellipsised. */
.avb-app .rk-name{color:var(--faint);font-size:12px;overflow:hidden;text-overflow:ellipsis;max-width:320px}

/* Every window is shown; the one the ranking is on is lifted out of the row.
   The band starts HERE, at the heading, so the column reads as one object from the top of the
   table to the bottom rather than as a tint that begins under the header. */
.avb-app .rk-table th.rk-w.on{color:var(--btc);border-bottom-color:var(--btc-bd);
  background-image:linear-gradient(rgba(247,147,26,.09),rgba(247,147,26,.09))}
/* The heading IS the timeframe control. The button inherits every type property from the th so
   the column reads as a heading, not as a row of buttons — the affordance is the pointer and
   the hover, which is as much as a table heading should ever claim.
   ⚠️ `color:inherit` is what carries the .on state (var(--btc)) through to the label; a button
   defaults to its own colour and would have left the selected column looking unselected. */
.avb-app .rk-table th.rk-w .rk-wbtn{
  all:unset;display:block;width:100%;box-sizing:border-box;
  font:inherit;letter-spacing:inherit;text-transform:inherit;color:inherit;text-align:inherit;
  cursor:pointer;transition:color .12s ease}
.avb-app .rk-table th.rk-w:not(.on) .rk-wbtn:hover{color:var(--text)}
.avb-app .rk-table th.rk-w .rk-wbtn:focus-visible{outline:2px solid var(--btc);outline-offset:2px;border-radius:3px}
.avb-app .rk-table td.rk-w{font-variant-numeric:tabular-nums;color:var(--ink-2)}
/* THE SELECTED COLUMN CARRIES A WASH THE WHOLE HEIGHT OF THE TABLE (Kevin, 2026-08-31).
   ☢️ A FILL LIVED HERE BEFORE AND WAS PULLED FOR READING AS "A GREY WASH DOWN THE MIDDLE".
   That verdict was about the COLOUR, not about the idea: it was a neutral panel fill sitting
   behind cells whose text is an inline per-row heat colour, so it muddied every number it was
   meant to lift. This one is keyed to --btc at very low alpha — the same orange the heading
   and its underline already use — so the band reads as the SAME MARK continued downward
   rather than as a second, greyer one competing with the heat.
   ⚠️ NOT A NEUTRAL TINT, AND THIS IS THE WHOLE POINT. On a near-black table a white overlay
   IS a grey — rendered side by side, rgba(255,255,255,.035) is exactly the "strange grey
   highlight" this replaced, because low-alpha white over #0A0C0F resolves to slate. Only a
   HUED wash stays clean at this weight.
   ⚠️ THE SAME ALPHA IN THE HEADING AND THE CELLS. Different values read as a band that changes
   shade at the header rule — the column has to be one even object from the top of the table to
   the bottom, which is the entire ask.
   ⚠️ background-IMAGE, NOT background. Two other rules paint these cells and both must still
   work: the row hover sets `background:var(--panel-2)` (a SHORTHAND, which resets
   background-image) and this selector is the more specific of the two, so a plain `background`
   here would win outright and a hovered row would go dead flat across its selected cell. As an
   image the tint layers OVER whatever colour the row supplies, so hover, focus and .is-found
   all still change the ground underneath it.
   ⚠️ And NOT box-shadow, however tempting inset edges are: the standout pulse animates
   box-shadow on these same cells (avb-standout-cell) and a more specific shadow here would
   silently stop that animation on the selected column. */
.avb-app .rk-table td.rk-w.on{font-weight:700;font-size:15px;
  background-image:linear-gradient(rgba(247,147,26,.09),rgba(247,147,26,.09))}
.avb-app .rk-pos{color:var(--up)}
.avb-app .rk-neg{color:var(--down)}
.avb-app .rk-zero{color:var(--faint)}
/* .on carries its own per-row tint inline, so the sign colours must not fight it. */
/* The inline heat-scale colour is authoritative on EVERY return cell now, not only the
   ranked one, so the flat green/red must stand down across the whole row. */
.avb-app .rk-table td.rk-w.rk-pos,.avb-app .rk-table td.rk-w.rk-neg{color:inherit}

/* The window a row was actually ranked on, when the selected one has no history for it. */
.avb-app .rk-sub-tag{
  margin-left:6px;padding:1px 4px;border:1px solid var(--line-2);border-radius:3px;
  font-size:10px;font-weight:700;letter-spacing:.08em;color:var(--base);vertical-align:middle;
}

/* ☢️ TREND IS SIZED TO THE CHART, NOT TO THE SLACK. It briefly took width:100% — "give me
   what is left" — which handed a 94px sparkline a 940px column and left it adrift in the
   middle of the table. A column should be as wide as the thing in it.
   The slack goes back to `coin`, the one column whose content is genuinely variable: a longer
   name simply uses it (see .rk-name's max-width) instead of it becoming a void.
   ⚠️ Do NOT instead pin `coin` to width:1% — .rk-coin-in is a flex row whose name span carries
   overflow:hidden, so 1% collapses the column to 24px and the NAME to zero width while still
   "fitting". Starving it is not the same as not feeding it. */
.avb-app .rk-table th.rk-trend,.avb-app .rk-table td.rk-trend{width:186px;text-align:center}
/* The chart now uses most of its column rather than floating in the middle of one. */
.avb-app .rk-trend svg{width:150px;height:24px;display:block;margin:0 auto}
.avb-app .rk-table td.rk-vol{color:var(--faint)}
@media (max-width:900px){
  .avb-app .rk-name,.avb-app .rk-table th.rk-trend,.avb-app .rk-table td.rk-trend{display:none}
}

/* ☢️ ON A PHONE THE COIN COLUMN WAS EATING THE WHOLE TABLE. min-width:250px is sized for a
   cell holding an icon, a ticker AND a full name — but the name is hidden from 900px down, so
   from there the column was reserving 250px to draw about 90px of content. Against a 382px
   board that left room for exactly ONE return column, and a ranked list showing one number is
   a ranked list with nothing to compare.
   Freeing the reservation (the content still sets the floor) and tightening the cell padding
   fits four windows in the first screen; the rest scroll, as they do on CoinGecko. */
@media (max-width:760px){
  .avb-app .rk-table{font-size:12px}
  .avb-app .rk-table th,.avb-app .rk-table td{padding:7px 6px}
  .avb-app .rk-table th.rk-coin,.avb-app .rk-table td.rk-coin{min-width:0}
  .avb-app .rk-coin-in{gap:6px}
  .avb-app .rk-coin-in .ico{width:18px;height:18px}
  .avb-app .rk-table td.rk-w.on{font-size:13px}
}

/* ☢️ THE LIST'S TIMEFRAME SWITCHER WAS 29x15px ON A PHONE. It is the control that decides
   what the whole ranked list is sorted by, and it was the smallest target on the site —
   under even WCAG 2.5.8's absolute 24px floor, let alone Apple's 44. It reads as a table
   heading (deliberately: see .rk-wbtn), and that is exactly why it was never sized like the
   button it is. The <th>'s own vertical padding is dropped in the same breath so the header
   row lands AT 44px rather than at 44 + 14 of padding.
   Keyed on pointer, not width: a desktop window dragged narrow keeps its heading-sized
   heading. Flex-end preserves the right alignment the block layout inherited from the th. */
@media (pointer:coarse){
  .avb-app .rk-table th.rk-w{padding-top:0;padding-bottom:0}
  .avb-app .rk-table th.rk-w .rk-wbtn{min-height:44px;display:flex;align-items:center;justify-content:flex-end}
}

/* A real control, not a run of underlined words in a sentence: it leaves the site, so it
   gets a button's affordance and a button's hit area. */
.avb-app .hm-sheet .hm-foot{display:flex;flex-direction:column;align-items:flex-start;gap:11px}
.avb-app .hm-foot-note{color:var(--faint)}
.avb-app .hm-cg{display:inline-flex;align-items:center;gap:7px;align-self:stretch;justify-content:center;
  min-height:38px;padding:0 16px;border:1px solid var(--line);border-radius:7px;
  background:var(--hi-1);color:var(--text);text-decoration:none;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.08em;text-transform:uppercase;font-weight:600;
  transition:background .13s ease,border-color .13s ease,color .13s ease}
.avb-app .hm-cg:hover{background:rgba(243,174,31,.10);border-color:var(--base);color:var(--base)}
.avb-app .hm-cg:active{background:rgba(243,174,31,.16)}
.avb-app .hm-cg:focus-visible{outline:2px solid var(--base);outline-offset:2px}

/* ── THE SEARCH RESULT ────────────────────────────────────────────────────────
   ONE MARK, FOUR SURFACES: a white glow that breathes until it is dismissed.
   Every layout reads the same .is-found (the bubbles field draws its own, on canvas — see
   Bubbles.tsx — because it has no elements to style).

   ☢️ IT BREATHES UNTIL DISMISSED, WHICH IT COULD NOT DO BEFORE. The grid's ring blinked
   exactly twice and stopped, because until now there was no way to CLEAR a search: a mark
   that never ended would have pulsed at the reader forever. The search field holds the coin
   and offers an ×, so the mark can now stay until it is answered — and a search you made ten
   seconds ago is still findable on a board of a thousand cells.

   ☢️ WHITE, AND A RING RATHER THAN A FILL. A cell's COLOUR IS ITS RETURN; washing it would
   overwrite the datum, which is the same constraint the standouts are built around. White is
   the one value on this board that means "the thing you asked for" rather than a direction —
   green and red are already spoken for.
   ⚠️ It must not be mistaken for a STANDOUT, which also pulses white. That one washes the
   whole cell from the inside; this one is an edge. Different shape, same vocabulary.

   ⚠️ THE GLOW RIDES A PSEUDO-ELEMENT ON THE GRID, NOT THE CELL. The standout animation owns
   box-shadow on .hm-px itself, and a second animation on the same property would silently win
   or lose depending on declaration order — a coin that is BOTH searched and a standout would
   lose one of its two marks. ::after has its own box, so the two compose. */
.avb-app .hm-px.is-found{z-index:3}
.avb-app .hm-px.is-found::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:2px solid var(--found);animation:avb-found 1.5s ease-in-out infinite}
@keyframes avb-found{
  0%,100%{border-color:rgba(var(--found-rgb),.34);box-shadow:0 0 0 0 rgba(var(--found-rgb),0)}
  50%    {border-color:var(--found);box-shadow:0 0 11px 1px rgba(var(--found-rgb),.5)}
}
/* The wedge is a path: no pseudo-element, so the stroke itself carries the pulse. */
.hm-sect.is-found path{stroke:var(--found);animation:avb-found-wedge 1.5s ease-in-out infinite}
@keyframes avb-found-wedge{
  0%,100%{stroke-width:2;stroke-opacity:.55}
  50%    {stroke-width:4;stroke-opacity:1}
}
/* The row glows from its own edge inward. ⚠️ On the TR — the standout pulse animates the TDs,
   so the two never contend for the same property on the same element. */
.avb-app .rk-row.is-found{animation:avb-found-row 1.5s ease-in-out infinite}
@keyframes avb-found-row{
  0%,100%{background:var(--hi-2);box-shadow:inset 3px 0 0 rgba(var(--found-rgb),.45)}
  50%    {background:var(--hi-4); box-shadow:inset 3px 0 0 var(--found), 0 0 12px rgba(var(--found-rgb),.22)}
}
/* Reduced motion keeps the MARK and drops only the movement — the answer to a search must
   still be visible, it just stops breathing. */
@media (prefers-reduced-motion:reduce){
  .avb-app .hm-px.is-found::after{animation:none;border-color:var(--found)}
  .hm-sect.is-found path{animation:none;stroke-width:3}
  .avb-app .rk-row.is-found{animation:none;background:var(--hi-3);box-shadow:inset 3px 0 0 var(--found)}
}

/* ── STANDOUTS ────────────────────────────────────────────────────────────────
   The two coins in each band that moved the most places since yesterday. The WHOLE CELL
   breathes — an edge ring alone was too easy to miss on a board of a thousand.

   ☢️ THE WASH NEVER REACHES FULL, and that is the constraint the whole effect is built
   around. A cell's colour IS its return; a solid mark would overwrite the datum. It runs
   between a light floor and a heavy peak — never 0, so a glance at any instant finds all
   eight, and never opaque, so the heat colour reads through the whole cycle. It rides as an
   INSET box-shadow, which paints above the background and BELOW the text, so the ticker and
   the percentage stay legible through it.

   ☢️ DIRECTION IS A COLOUR, AND IT IS NOT THE UP/DOWN GREEN AND RED. Those already mean
   "gained or lost against Bitcoin" everywhere on this board, and a coin can climb 300 places
   while still down on the window — a green wash on a red cell would read as a contradiction.
   The top gainer of a band pulses WHITE, the top loser GREY: brightness carries the direction,
   so it reads without a legend and without borrowing a hue that already means something.

   ☢️ A WHITE WASH FORCES THE INK DARK, AND ONLY ON THE SURFACES WHOSE GROUND IS LIGHT. A tile
   carries its ink inline from textOnP(), chosen for the UNWASHED heat colour — so lightening
   the ground under white text collapses the label. Measured before this rule existed: LAB fell
   to 1.99:1 and ICP to 1.95:1, against a 3:1 floor for large text. The grid and the bullseye
   flip to near-black; the LIST does not, because its ground is the near-black panel rather
   than a heat colour, and white-on-washed-panel is the readable pairing there. Grey needs no
   flip on any surface — it darkens the ground rather than lightening it.

   ⚠️ GREY IS ALSO WHAT A DIMMED CELL LOOKS LIKE. The category lens desaturates everything
   outside the chosen theme, so a grey-washed standout sitting in a dimmed board is the one
   ambiguity in this design. The ring is what separates them: a dimmed cell has no ring, and
   the standout's is at full opacity and 4px.

   ⚠️ IT WILL NOT SURVIVE A SNAPSHOT. lib/snapshotDom.ts transcribes computed colour and
   geometry, not animation or box-shadow, so the PNG export shows the board without the marks.
   That is the right trade — an export is a still of the numbers, and this is an interaction
   affordance, not a datum. */
.avb-app .is-standout{position:relative;z-index:4}
/* The top gainer: white. */
.avb-app .hm-px.so-up,.avb-app .hm-sect.so-up{--so:255,255,255;--so-peak:.5}
.avb-app .rk-row.so-up{--so:var(--found-rgb);--so-peak:.5}
/* !important because the tile sets `color` INLINE from textOnP(), and inline wins otherwise. */
.avb-app .hm-px.so-up{color:#080B12 !important}
/* No !important needed here: an SVG `fill` PRESENTATION ATTRIBUTE has specificity zero, so any
   stylesheet selector beats it. (Same rule that once hijacked a chart legend's font-family.) */
.avb-app .hm-sect.so-up text{fill:#080B12}
/* The top loser: the board's own dim grey (--dim, #8A94A2). */
.avb-app .hm-px.so-down,.avb-app .rk-row.so-down,.avb-app .hm-sect.so-down{--so:138,148,162;--so-peak:.62}

/* The grid tile: ring first in the list so it paints ABOVE the wash. */
.avb-app .hm-px.is-standout{animation:avb-standout 1.6s ease-in-out infinite}
@keyframes avb-standout{
  0%,100%{box-shadow:inset 0 0 0 2px rgba(var(--so),.85),
                     inset 0 0 0 9999px rgba(var(--so),.22),
                     0 0 3px 0 rgba(var(--so),.3)}
  50%    {box-shadow:inset 0 0 0 4px rgba(var(--so),1),
                     inset 0 0 0 9999px rgba(var(--so),var(--so-peak,.62)),
                     0 0 10px 1px rgba(var(--so),.7)}
  /* ⚠️ THE OUTER GLOW IS DELIBERATELY SMALL. Grid cells are ~46px and sit 2px apart, so a
     wide halo spills across the whole of both neighbours and they read as marked too — the
     mark stops saying WHICH coin moved. The inset wash does the work; the glow only lifts the
     cell off the mosaic. */
}

/* ⚠️ A <tr> CANNOT CARRY THE WASH — a box-shadow on a table row is painted per CELL and
   browsers disagree about it, so the animation goes on the cells and the row only holds the
   colour. Every td washes; the outer two add the vertical ends of the ring. */
.avb-app tr.rk-row.is-standout td{animation:avb-standout-cell 1.6s ease-in-out infinite}
@keyframes avb-standout-cell{
  0%,100%{box-shadow:inset 0 2px 0 rgba(var(--so),.8), inset 0 -2px 0 rgba(var(--so),.8),
                     inset 0 0 0 9999px rgba(var(--so),.18)}
  50%    {box-shadow:inset 0 3px 0 rgba(var(--so),1),   inset 0 -3px 0 rgba(var(--so),1),
                     inset 0 0 0 9999px rgba(var(--so),calc(var(--so-peak,.62) * .8))}
}

/* ☢️ THE BULLSEYE WASH GOES ON .hm-hit's FILL, WHICH IS THE ONLY PATH IN THE GROUP. The
   coloured wedge is painted in the inert .hm-fills layer, NOT inside .hm-sect — a selector
   reaching for "the wedge path" here matches nothing and the mark silently never appears.
   .hm-hit carries the same geometry and sits directly over the wedge, so filling it washes
   exactly the right shape. A transparent fill still hit-tests, so the cell stays clickable at
   every point in the cycle. */
.avb-app .hm-sect.is-standout .hm-hit{animation:avb-standout-wedge 1.6s ease-in-out infinite}
@keyframes avb-standout-wedge{
  0%,100%{fill:rgba(var(--so),.22); stroke:rgba(var(--so),.85); stroke-width:2}
  50%    {fill:rgba(var(--so),var(--so-peak,.62)); stroke:rgba(var(--so),1); stroke-width:4}
}

/* ☢️ A PULSE IS EXACTLY WHAT VESTIBULAR TRIGGERS ASK TO BE SPARED. Eight cells breathing at
   once is a lot of motion; reduced-motion keeps a STATIC wash and ring, so the mark is just
   as findable and nothing moves. */
@media (prefers-reduced-motion:reduce){
  .avb-app .hm-px.is-standout,.avb-app tr.rk-row.is-standout td,
  .avb-app .hm-sect.is-standout .hm-hit{animation:none}
  .avb-app .hm-px.is-standout{box-shadow:inset 0 0 0 4px rgba(var(--so),1),
                                         inset 0 0 0 9999px rgba(var(--so),.45)}
  .avb-app tr.rk-row.is-standout td{box-shadow:inset 0 3px 0 rgba(var(--so),1),
                                    inset 0 -3px 0 rgba(var(--so),1),
                                    inset 0 0 0 9999px rgba(var(--so),.4)}
  .avb-app .hm-sect.is-standout .hm-hit{fill:rgba(var(--so),.45);stroke:rgba(var(--so),1);stroke-width:3}
}

/* Coin search — sits at the head of the control run, before Layout. */
.avb-app .hm-search{position:relative;flex:0 0 auto;min-width:150px}
.avb-app .hm-search-in{width:100%;padding:5px 9px;background:var(--field-bg);border:1px solid var(--field-line);
  border-radius:4px;color:var(--text);font-family:var(--mono);font-size:11px;letter-spacing:.04em}
.avb-app .hm-search-in:hover{border-color:var(--field-line-hover)}
/* ☢️ THE PROMPT IS THE ONLY THING THAT SAYS WHAT THE BOX IS FOR, so it does not get the
   small-label colour. --faint measured 5.08:1 here, which PASSES AA for body text — the
   letters were legible and still went unread, because 11px mono at normal weight in a muted
   grey reads as a caption sitting on the page rather than as an invitation to type. Brighter
   AND heavier: contrast was only half of what made it disappear. */
.avb-app .hm-search-in::placeholder{color:var(--placeholder);font-weight:600;opacity:1}
.avb-app .hm-search-in:focus{outline:none;border-color:var(--btc);
  box-shadow:0 0 0 3px var(--btc-glow)}
/* ⚠️ :focus above kills the UA outline, so keyboard users need one put back explicitly —
   the same ring .hm-search-x already uses, rather than a second invention. */
.avb-app .hm-search-in:focus-visible{outline:2px solid var(--btc);outline-offset:1px}
/* Room for the ×, so a long coin name runs UNDER the button rather than into it. */
.avb-app .hm-search.has-value .hm-search-in{padding-right:26px}
/* ⚠️ A search input paints its OWN clear affordance in WebKit; ours is the one that also
   clears the board, so the native one has to go or there are two crosses in the field. */
.avb-app .hm-search-in::-webkit-search-cancel-button{display:none}
.avb-app .hm-search-x{
  position:absolute;top:50%;right:5px;transform:translateY(-50%);
  display:flex;align-items:center;justify-content:center;width:18px;height:18px;
  padding:0;border:0;border-radius:3px;background:transparent;color:var(--faint);
  font-size:13px;line-height:1;cursor:pointer;transition:color .12s ease,background .12s ease}
.avb-app .hm-search-x:hover{color:var(--ink);background:var(--hi-3)}
.avb-app .hm-search-x:focus-visible{outline:2px solid var(--btc);outline-offset:1px}
.avb-app .hm-search-hits{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:40;margin:0;padding:4px;
  list-style:none;background:var(--panel);border:1px solid var(--line);border-radius:5px;max-height:260px;overflow:auto;
  box-shadow:0 12px 30px var(--shadow)}
.avb-app .hm-search-hit{display:flex;gap:8px;align-items:baseline;width:100%;padding:5px 8px;border:0;border-radius:3px;
  background:transparent;color:var(--text);cursor:pointer;text-align:left;font-family:var(--mono);font-size:11px}
.avb-app .hm-search-hit.on{background:rgba(243,174,31,.14)}
.avb-app .hm-search-sym{font-weight:700}
.avb-app .hm-search-nm{color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}


/* ============================================================================
   MOBILE PASS
   The desktop layout assumes a wide control run, a hover pointer and a sticky
   chrome that costs nothing. None of those hold on a phone, so each is undone
   here rather than being approximated by shrinking the desktop one.
   ============================================================================ */

/* THE FILTERS PANEL (redesign spec §6.1). Four controls on the bar; everything else lives in
   this panel, closed by default at every width: a dropdown under the bar on a desktop, a
   bottom sheet on a phone. */
.avb-app .hm-more-btn,.avb-app .hm-moved{
  display:inline-flex;align-items:center;gap:7px;padding:0 12px;min-height:32px;align-self:center;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;cursor:pointer;
  color:var(--dim);background:var(--panel);border:1px solid var(--line-2);border-radius:6px}
.avb-app .hm-more-btn:hover,.avb-app .hm-moved:hover{color:var(--ink);border-color:var(--field-line)}
.avb-app .hm-more-btn.on,.avb-app .hm-more-btn.has{color:var(--ink);border-color:var(--field-line)}
.avb-app .hm-moved.on{color:var(--base);border-color:var(--base-bd);background:var(--base-tint)}
.avb-app .hm-badge{display:inline-block;min-width:16px;padding:1px 5px;border-radius:3px;background:var(--btc);color:#1a0d00;font-size:10px;font-weight:700;text-align:center;letter-spacing:0}
.avb-app .hm-moved.on .hm-badge{background:var(--base)}
.avb-app .hm-summary{margin-left:auto;align-self:center;font-family:var(--mono);font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);white-space:nowrap}
.avb-app .hm-head{position:relative}
.avb-app .hm-more{display:none;position:absolute;left:var(--gutter);top:100%;z-index:60;width:min(640px,calc(100vw - 2*var(--gutter)));
  background:var(--panel);border:1px solid var(--line-2);border-radius:10px;box-shadow:0 24px 60px var(--shadow);
  padding:14px 16px 16px;flex-wrap:wrap;gap:14px 22px;align-items:flex-start;justify-content:flex-start}
.avb-app .hm-more.open{display:flex}
.avb-app .hm-more-head{width:100%;display:flex;align-items:center;justify-content:space-between;padding-bottom:10px;border-bottom:1px solid var(--line)}
.avb-app .hm-more-title{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink)}
.avb-app .hm-more-x{background:none;border:0;color:var(--dim);font-size:20px;line-height:1;cursor:pointer;padding:0 4px}
.avb-app .hm-more-x:hover{color:var(--ink)}

@media (max-width:760px){
  /* Chrome scrolls away. On a short viewport a sticky header plus a sticky page bar ate
     roughly a third of the screen, and the board is the product. */
  .avb-app .sh{position:static}
  .avb-app .pagebar{position:static}
  .avb-app .band-rail{position:static}

  /* On a phone the panel is a bottom sheet. */
  .avb-app .hm-more-btn,.avb-app .hm-moved{min-height:36px}
  .avb-app .hm-more{position:fixed;left:0;right:0;bottom:0;top:auto;width:auto;max-height:78vh;overflow:auto;border-radius:16px 16px 0 0;
    flex-direction:column;align-items:stretch;gap:12px;padding:12px 16px calc(16px + env(safe-area-inset-bottom))}
  .avb-app .hm-more.open{display:flex}
  .avb-app .hm-summary{display:none}
  .avb-app .hm-more .hm-ctl{flex-direction:column;align-items:flex-start;gap:5px}
  .avb-app .hm-more .hm-seg{width:100%}
  .avb-app .hm-search{width:100%}

  .avb-app .hm-segbtn{padding-left:12px;padding-right:12px}
  /* ☢️ AND ONCE A RUN OF OPTIONS IS TOO LONG FOR THE PHONE, IT WRAPS — IT DOES NOT PUSH THE
     PAGE SIDEWAYS. Adding YTD made Timeframe eight buttons wide: 286px became 333px, and with
     the caption inline the group ran to 420px inside a 375px viewport, so the whole document
     gained 45px of horizontal scroll. Measured before and after at 390x844.
     Wrapping and not scrolling, because an option scrolled off the right edge is an option
     nobody finds; and this is the same answer .hm-controls already gives one level up when its
     zones stop fitting. A no-op for every run that DOES fit — flex-wrap only acts on overflow —
     so it costs the other segmented controls nothing while making this class of break
     impossible for all of them. */
  .avb-app .hm-seg{flex-wrap:wrap}

  /* ☢️ AND THE SPACE COMES BACK FROM THE CHROME, NOT THE CONTROLS. Eight stacked groups on a
     390px screen each carried a 14px caption row and its own gaps, and the board did not start
     until 384px down — 45% of the phone gone before a single coin. The captions stay (they are
     what tells LENS from ROWS) but they stop costing a line of their own, and the runs sit
     closer together. */
  .avb-app .hm-controls{gap:6px 12px}
  .avb-app .hm-more .hm-ctl{gap:2px}
  .avb-app .hm-ctl-lbl{line-height:1.1}
  
  /* The controls run wraps to its own lines instead of squeezing. */
  /* Switching this run to a column re-aims the flex main axis, so .hm-head-copy's
     `flex:1 1 420px` basis stops meaning "420px wide" and starts meaning "420px TALL" —
     which is the ~420px of dead black between the title and the controls on a phone.
     space-between then pushed the two apart to fill it. Both are undone here. */
  .avb-app .hm-head{flex-direction:column;gap:12px;justify-content:flex-start;flex-wrap:nowrap}
  .avb-app .hm-head-copy{flex:0 0 auto;width:100%}
  .avb-app .hm-controls{width:100%;gap:6px 12px}
  .avb-app .pagehead-title{font-size:17px;line-height:1.25}

  /* The detail sheet becomes a bottom sheet — reachable by thumb, and clearly modal. */
  .avb-app .hm-sheet{width:100%;max-width:none;border-radius:12px 12px 0 0;margin-top:auto}
  .avb-app .hm-backdrop{align-items:flex-end}
  .avb-app .hm-cx{min-width:40px;min-height:40px}

  /* The hover card is a pointer affordance with no touch equivalent; on a phone it can only
     appear stuck to the last tap, so it is removed rather than left to linger. */
  .hm-hover{display:none}
}

/* ☢️ pan-y AND NOT none — A THUMB SCROLL MUST SCROLL THE PAGE, NOT TOW THE BOARD.
   `none` handed every one-finger swipe to the pan handler, so scrolling past the board on a
   phone dragged the disc out of its panel and left a black void where it had been (Kevin,
   2026-09-08). This is the same call .mc-cardplot and .cp-chartwrap already document:
   vertical belongs to the page, the module reads whatever is left.
   Pinch is still withheld from the browser — pinch-zoom is absent from the value — so a
   two-finger gesture reaches the SVG instead of zooming the page.
   In FULL SCREEN the row IS the viewport and there is no page beneath it to scroll, so the
   board takes the whole gesture back and one-finger panning returns.
   ⚠️ AND THAT HATCH DOES NOT EXIST ON AN iPHONE. iOS Safari ships no ELEMENT Fullscreen API,
   so FullscreenButton never renders there and :fullscreen never matches: on iPhone one-finger
   board panning is simply gone, permanently. That is the accepted trade — the +/-/Fit cluster
   is enlarged for touch and pinch is centre-anchored, so every ring is still reachable. */
.hm-radial-svg{touch-action:pan-y}
:fullscreen .hm-radial-svg{touch-action:none}

/* "Coming soon" nav items. Blurred rather than hidden so the roadmap is visible without
   offering a door that goes nowhere; pointer-events:none keeps a stray tap inert. */
.avb-app .sh-soon{display:inline-flex;align-items:center;gap:6px;cursor:default;pointer-events:none;opacity:.5}
.avb-app .sh-soon-txt{filter:blur(2.2px);user-select:none}
.avb-app .sh-soon-tag{font-family:var(--mono);font-size:8.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--faint);border:1px solid var(--line);border-radius:3px;padding:1px 4px;filter:none}

/* Live-feed indicator. Dim and still until the feed answers, then green with a slow pulse —
   the pulse is the only moving thing in the chrome, so it reads as "this is updating". */
.avb-app .hm-live{display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--faint)}
.avb-app .hm-live i{width:6px;height:6px;border-radius:50%;background:var(--faint);flex:none}
.avb-app .hm-live.on{color:var(--up)}
.avb-app .hm-live.on i{background:var(--up);animation:avb-pulse 2.4s ease-in-out infinite}
@keyframes avb-pulse{0%,100%{opacity:1}50%{opacity:.28}}
@media (prefers-reduced-motion:reduce){.avb-app .hm-live.on i{animation:none}}

/* Show more — the list's own control, sitting where the list ends. */
.avb-app .rk-more{display:flex;justify-content:center;padding:18px 0 26px}
.avb-app .rk-more-btn{
  min-height:40px;padding:0 26px;border:1px solid var(--line);border-radius:8px;
  background:var(--hi-1);color:var(--text);cursor:pointer;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.09em;text-transform:uppercase;font-weight:600;
  transition:background .13s ease,border-color .13s ease,color .13s ease}
.avb-app .rk-more-btn:hover{background:rgba(243,174,31,.10);border-color:var(--base);color:var(--base)}
.avb-app .rk-more-btn:focus-visible{outline:2px solid var(--base);outline-offset:2px}

/* Coin art in the popups. The hover card and the sheet both lead with identity now — a
   ticker alone made you translate a string into a coin before reading the number. */
.avb-app .hm-hv-top{display:flex;align-items:center;gap:8px}
.avb-app .hm-hv-top .ico{width:20px;height:20px;flex:none}
.avb-app .hm-sheet .hm-nm{display:flex;align-items:center;gap:10px}
.avb-app .hm-sheet .hm-nm .ico{width:26px;height:26px;flex:none}

/* ============================================================================
   VIEW TRANSITION — the board rebuilding its order
   Grid cells are HTML buttons and bullseye cells are SVG paths, so there is no
   shared element to morph between them. What CAN be shared is the ORDER: every
   cell arrives on a delay taken from its rank, so the strongest lands first and
   the board assembles outward from the centre of the ranking. That reads as the
   same set of blocks reconstructing rather than as two screens crossfading, and
   it costs nothing per frame — transform and opacity only, no JS in the loop.
   ============================================================================ */
.avb-app .avb-arrive{
  animation:avb-arrive .34s cubic-bezier(.2,.72,.3,1) backwards;
  /* Capped so a thousand cells still finish inside ~0.6s: past ~600 the delay
     stops growing and the tail lands together. */
  animation-delay:calc(min(var(--i, 0) * 0.9ms, 320ms));
}
@keyframes avb-arrive{
  from{opacity:0;transform:scale(.86)}
  to{opacity:1;transform:scale(1)}
}
/* SVG needs its own origin, or every wedge scales about the viewBox corner and
   the board explodes outward instead of settling. */
.avb-app .hm-sect.avb-arrive,.avb-app .hm-fills .avb-arrive{transform-box:fill-box;transform-origin:center}

/* Rows come in as a list does — from where they are, not scaled up. */
.avb-app .rk-row.avb-arrive{animation-name:avb-arrive-row}
@keyframes avb-arrive-row{
  from{opacity:0;transform:translateY(4px)}
  to{opacity:1;transform:none}
}

/* The list carries the board's palette, far enough back to stay a list. */
/* The tint belongs to the ROW, not to each cell. Painting it per <td> put a seam at every
   column boundary, and any cell with a background of its own — the ranked column — cut a
   hard vertical edge straight through the wash. One background on the <tr> is continuous by
   construction, so there is nothing to align. */
/* THE TINT IS A LEFT EDGE, NOT A WASH. Carried across the full row it competed with the
   numbers it sits behind — six columns of percentages, each already coloured, reading through
   a coloured ground. It now holds the identity end of the row, where the rank and the ticker
   are, and is now an EDGE rather than a wash -- it lives entirely to the left of the rank,
   never under it.
   ☢️ THE LIMIT IS IN PIXELS, NOT PERCENT, AND IT IS 12. The rank column is right-aligned and
   auto-sized, so the digit's left edge MOVES with how many digits it has: measured at 28.7px
   for "1", 20.4px for "12", and 12.0px for "100" -- flush against the cell's own padding-left.
   Any percentage-based stop that looks clear on the first row runs underneath row 100, and
   would run under a four-digit rank at 1000 rows too. Finishing by 10px sits inside that
   padding, where no digit of any length can reach. */
.avb-app .rk-row{
  background:linear-gradient(90deg,
    var(--rowbar,transparent) 0,
    var(--rowbar,transparent) 4px,
    var(--rowtint0,transparent) 10px);
  transition:filter .13s ease}
.avb-app .rk-row:hover{filter:brightness(1.5)}
.avb-app .rk-row.is-found{background:linear-gradient(90deg,rgba(243,174,31,.16),rgba(243,174,31,.05) 60%,transparent)}

@media (prefers-reduced-motion:reduce){
  .avb-app .avb-arrive{animation:none}
}

/* ── The theme lens ──────────────────────────────────────────────────────────
   Picking a category LIGHTS its coins and DIMS the rest; it never removes one. The dimmed
   colours themselves are computed in lib/heatmap (dimForP / DIM_INK) rather than laid on as
   opacity — lib/snapshotDom.ts transcribes the grid and the list by reading computed
   background-color and color and does NOT apply opacity, so an opacity dim would export a
   fully-lit board. Rules here may therefore change COLOUR freely, but must never reach for
   opacity or filter on a cell that has to survive a snapshot. */

/* The picker. A menu rather than a run of pills: thirteen themes plus All is ~1,100px of
   segmented control, and this header already wraps to two rows. */
/* ── The [+] custom window ────────────────────────────────────────────────────
   Sits at the end of the timeframe run and borrows .hm-segbtn so it reads as one more
   member of that control rather than as a separate feature bolted to the end. The × is a
   SEPARATE button, not a corner of the pill: a destructive action inside a selection
   control is how people clear a window they meant to select. */
.avb-app .hm-cw{position:relative;display:inline-flex;align-items:center}
.avb-app .hm-cw-btn{font-weight:700}
.avb-app .hm-cw-clear{margin-left:2px;padding:2px 6px;background:none;border:0;cursor:pointer;
  color:var(--faint);font-family:var(--mono);font-size:13px;line-height:1;border-radius:3px}
.avb-app .hm-cw-clear:hover{color:var(--down);background:rgba(241,51,52,.10)}
.avb-app .hm-cw-clear:focus-visible{outline:2px solid var(--base);outline-offset:1px}
.avb-app .hm-cw-pop{position:absolute;top:calc(100% + 6px);right:0;z-index:45;width:238px;padding:11px;
  background:var(--glass);border:1px solid var(--line);border-radius:7px;
  box-shadow:0 18px 40px var(--shadow);backdrop-filter:blur(8px)}
/* ☢️ ON A PHONE THE POPOVER HANGS FROM THE GROUP, NOT FROM THE "+" PILL. The box is 238px
   wide and anchored right:0 to its pill. On a desktop the pill is the last thing on the row, so
   the box opens leftward over the other pills and fits. The phone wrap (see .hm-seg{flex-wrap})
   moved the pill to the SECOND row's left edge, at x≈130 — and a 238px box hung from that edge
   starts at −77px: "NDOW", "WEEKS MONTHS YEARS" with Days gone, "PPLY". Found by the 2026-09-06
   audit, one day after the wrap shipped. Making the pill static and the group the positioning
   context puts the box at the group's right edge — 358px wide here, so a 238px box has 120px to
   spare — and drops it below the whole group instead of over row one.
   ⚠️ THIS BLOCK MUST FOLLOW .hm-cw{position:relative} ABOVE: same specificity, so order decides. */
@media (max-width:640px){
  .avb-app .hm-seg{position:relative}
  .avb-app .hm-cw{position:static}
}
.avb-app .hm-cw-h{margin:0 0 9px;font-family:var(--mono);font-size:10.5px;font-weight:700;
  letter-spacing:.11em;text-transform:uppercase;color:var(--base)}
.avb-app .hm-cw-units{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:3px;margin-bottom:9px}
.avb-app .hm-cw-unit{padding:6px 2px;background:var(--well);border:1px solid var(--line);
  border-radius:4px;cursor:pointer;color:var(--dim);
  font-family:var(--mono);font-size:9.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase}
.avb-app .hm-cw-unit:hover{color:var(--text);border-color:var(--line-soft)}
.avb-app .hm-cw-unit.on{color:var(--base);border-color:var(--base);background:rgba(243,174,31,.10)}
.avb-app .hm-cw-row{display:flex;align-items:center;gap:9px;margin-bottom:8px}
.avb-app .hm-cw-lbl{flex:1 1 auto;font-family:var(--mono);font-size:10.5px;letter-spacing:.05em;color:var(--dim)}
.avb-app .hm-cw-in{width:74px;padding:6px 8px;background:var(--well-2);border:1px solid var(--line);
  border-radius:4px;color:var(--text);font-family:var(--mono);font-size:12.5px;text-align:right}
.avb-app .hm-cw-in:focus{outline:none;border-color:var(--base)}
/* The note is always present — it explains the ceiling BEFORE a rejection, so the reader
   learns the bound from the control rather than from being refused by it. */
.avb-app .hm-cw-note{margin:0 0 10px;font-size:11px;line-height:1.35;color:var(--faint)}
.avb-app .hm-cw-note.bad{color:var(--base)}
.avb-app .hm-cw-act{display:flex;gap:6px}
.avb-app .hm-cw-go{flex:1 1 auto;padding:7px 10px;border:1px solid var(--base);border-radius:4px;
  background:rgba(243,174,31,.14);color:var(--base);cursor:pointer;
  font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
.avb-app .hm-cw-go:hover:not(:disabled){background:rgba(243,174,31,.24)}
.avb-app .hm-cw-go:disabled{opacity:.4;cursor:not-allowed}
.avb-app .hm-cw-cancel{padding:7px 10px;border:1px solid var(--line);border-radius:4px;
  background:none;color:var(--dim);cursor:pointer;
  font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
.avb-app .hm-cw-cancel:hover{color:var(--text);border-color:var(--line-soft)}
.avb-app .hm-cw-err{margin:6px 0 0;font-size:11.5px;color:var(--base)}
@media (pointer:coarse){
  .avb-app .hm-cw-unit{min-height:40px}
  .avb-app .hm-cw-in{min-height:44px}
  .avb-app .hm-cw-go,.avb-app .hm-cw-cancel{min-height:44px}
  .avb-app .hm-cw-clear{min-width:34px;min-height:34px}
}

.avb-app .hm-cat{position:relative}
.avb-app .hm-cat-btn{display:flex;align-items:center;gap:8px;min-width:124px;padding:5px 9px;
  background:var(--well);border:1px solid var(--line);border-radius:var(--r);cursor:pointer;
  font-family:var(--mono);font-weight:700;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--dim)}
.avb-app .hm-cat-btn:hover{color:var(--text);border-color:var(--line-soft)}
.avb-app .hm-cat-btn.on{color:var(--text);border-color:var(--amber);background:rgba(240,172,69,.08)}
.avb-app .hm-cat-cur{flex:1 1 auto;text-align:left;white-space:nowrap}
.avb-app .hm-cat-car{color:var(--faint);font-size:9px}
.avb-app .hm-cat-btn.on .hm-cat-car{color:var(--amber)}
/* The menu is now a PANEL, not a list: the scroll belongs to the options so the Clear/Done
   footer stays reachable with thirteen themes ticked and the list scrolled to the bottom.
   Putting overflow on the menu itself would have scrolled the footer out of the panel. */
.avb-app .hm-cat-menu{position:absolute;top:calc(100% + 4px);left:0;z-index:40;margin:0;padding:4px;
  min-width:max(100%,208px);background:var(--glass);border:1px solid var(--line);
  border-radius:6px;box-shadow:0 18px 40px var(--shadow);backdrop-filter:blur(8px);
  display:flex;flex-direction:column;max-height:min(70vh,360px)}
.avb-app .hm-cat-list{margin:0;padding:0;list-style:none;overflow-y:auto;min-height:0;flex:1 1 auto}

/* The "+" row under a ladder: a floor no rung offers. Sits INSIDE the menu, under a divider,
   so it reads as the last option rather than as a separate control. */
.avb-app .hm-cat-custom{border-top:1px solid var(--line);margin-top:4px;padding:8px 10px 4px}
.avb-app .hm-cat-customlbl{display:block;font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--faint);margin-bottom:5px}
.avb-app .hm-cat-customrow{display:flex;gap:6px;align-items:center}
.avb-app .hm-cat-customin{flex:1 1 auto;min-width:0;padding:5px 8px;background:var(--field-bg);
  border:1px solid var(--field-line);border-radius:4px;color:var(--text);font-family:var(--mono);
  font-size:11px;letter-spacing:.04em}
.avb-app .hm-cat-customin::placeholder{color:var(--placeholder)}
.avb-app .hm-cat-customin:focus{outline:none;border-color:var(--btc);box-shadow:0 0 0 3px var(--btc-glow)}
.avb-app .hm-cat-customin:focus-visible{outline:2px solid var(--btc);outline-offset:1px}
/* A rejected entry has to SAY so — it keeps the current floor, and a silent no-op reads as a
   broken button rather than as "I could not read that". */
.avb-app .hm-cat-customin.bad{border-color:var(--down)}
.avb-app .hm-cat-customgo{flex:0 0 auto;width:28px;height:28px;border-radius:4px;
  border:1px solid var(--field-line);background:transparent;color:var(--text);
  font-family:var(--mono);font-size:15px;line-height:1;cursor:pointer}
.avb-app .hm-cat-customgo:hover{background:var(--hi-3);border-color:var(--field-line-hover)}
.avb-app .hm-cat-customgo:focus-visible{outline:2px solid var(--btc);outline-offset:1px}
.avb-app .hm-cat-customerr{margin:6px 0 2px;font-size:10px;color:var(--down);letter-spacing:.02em}
@media (pointer: coarse){
  .avb-app .hm-cat-customin{min-height:40px}
  .avb-app .hm-cat-customgo{width:40px;height:40px}
}/* A fixed-width gutter, so every label starts on the same x whether or not it is ticked —
   a check that shifts the text it belongs to reads as the row jumping under the finger. */
.avb-app .hm-tick{flex:0 0 auto;width:13px;color:var(--base);font-size:11px;line-height:1;text-align:center}
.avb-app .hm-band-hint{display:block;margin-top:2px;font-size:9.5px;letter-spacing:.02em;color:var(--faint)}
.avb-app .hm-cat-opt{align-items:flex-start}
/* The line under the ranked list that says what # counts and which venues price the board.
   Quieter than the sentence it follows — it answers a question rather than making a claim. */
.avb-app .rk-basis{color:var(--faint);white-space:nowrap}
@media (max-width:760px){.avb-app .rk-basis{display:block;white-space:normal;margin-top:2px}}
.avb-app .hm-cat-foot{display:flex;gap:6px;flex:0 0 auto;margin-top:4px;padding-top:6px;border-top:1px solid var(--line-soft)}
/* The hide switch sits in the footer beside Clear and Done. It is a CHECKBOX among two actions,
   so it keeps its tick and its on-state fill rather than borrowing either button's look — a
   reader has to be able to see that it is currently ON without opening the board behind it. */
.avb-app .hm-cat-foot-tgl{display:flex;align-items:center;justify-content:center;gap:5px;
  flex:1 1 auto;min-width:0;padding:7px 8px;border:1px solid var(--line);border-radius:5px;
  background:none;color:var(--dim);font-family:var(--mono);font-size:10.5px;letter-spacing:.08em;
  text-transform:uppercase;cursor:pointer;white-space:nowrap}
.avb-app .hm-cat-foot-tgl:hover:not(:disabled){color:var(--ink);border-color:var(--line-strong,var(--line))}
.avb-app .hm-cat-foot-tgl.on{color:var(--amber);border-color:var(--amber);background:rgba(240,165,0,.10)}
/* ⚠️ A DISABLED CONTROL SHOULD LOOK UNAVAILABLE, NOT ABSENT. At .4 and .35 these measured
   1.95:1 and 1.76:1 — WCAG exempts inactive controls, so they broke no rule, but a reader
   cannot tell a button that is off from a smudge. .6 still sits far below the enabled state
   (which is 6.3:1) so the affordance survives; it just stays readable while it waits. */
.avb-app .hm-cat-foot-tgl:disabled{opacity:.6;cursor:not-allowed}
.avb-app .hm-cat-clear{flex:1 1 auto;padding:6px 8px;border:1px solid var(--line);border-radius:4px;
  background:none;color:var(--dim);cursor:pointer;
  font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
.avb-app .hm-cat-clear:hover:not(:disabled){color:var(--text);border-color:var(--line-soft)}
.avb-app .hm-cat-clear:disabled{opacity:.6;cursor:not-allowed}
.avb-app .hm-cat-done{flex:1 1 auto;padding:6px 8px;border:1px solid var(--base);border-radius:4px;
  background:rgba(243,174,31,.14);color:var(--base);cursor:pointer;
  font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
.avb-app .hm-cat-done:hover{background:rgba(243,174,31,.24)}
@media (pointer:coarse){
  .avb-app .hm-cat-opt{min-height:44px;align-items:center}
  .avb-app .hm-cat-clear,.avb-app .hm-cat-done{min-height:44px}
}
.avb-app .hm-cat-rule{height:1px;margin:4px 2px;background:var(--line-soft)}
/* The lens-wide switch under the three columns. Full width because it acts on all of them. */
/* ⚠️ NO width:100% ANY MORE. It was a full-width row of its own; it is a flex item in the
   footer now, and a 100% width there fights the flex basis of the two buttons beside it. */
.avb-app .hm-onlylit:disabled{opacity:.6;cursor:not-allowed}
.avb-app .hm-onlylit:disabled:hover{background:none;color:var(--dim)}
.avb-app .hm-cat-opt{display:flex;align-items:baseline;gap:12px;width:100%;padding:6px 9px;border:0;
  border-radius:3px;background:none;cursor:pointer;text-align:left;
  font-family:var(--mono);font-size:11px;letter-spacing:.05em;color:var(--dim)}
.avb-app .hm-cat-opt:hover{background:var(--raise);color:var(--text)}
.avb-app .hm-cat-opt.on{background:rgba(240,172,69,.14);color:var(--text)}
.avb-app .hm-cat-nm{flex:1 1 auto;white-space:nowrap}
/* Ticker-style rows (the Breadth presets): a section header, then symbol + its name. */
.avb-app .hm-cat-grp{padding:9px 9px 4px;font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--faint)}
/* Top Performers is the one section coloured so it stands apart from the other groups.
   The list is the presets with the highest share of coins beating Bitcoin, so this colour does not flip. */
.avb-app .hm-cat-grp.up{color:var(--up);background:var(--up-tint);border-radius:3px;margin:6px 6px 2px;padding:6px 8px 4px}
.avb-app .hm-cat-opt.trend-up{background:var(--up-tint)}
.avb-app .hm-cat-opt.trend-up .hm-cat-nm,
.avb-app .hm-cat-opt.trend-up .hm-cat-det{color:var(--up)}
.avb-app .hm-cat-opt.trend-up.on{background:rgba(240,172,69,.14)}
.avb-app .hm-cat-list li:first-child .hm-cat-grp{padding-top:4px}
.avb-app .hm-cat-det{min-width:0;overflow:hidden;text-overflow:ellipsis;font-size:10.5px;letter-spacing:.02em;
  color:var(--faint);white-space:nowrap}
.avb-app .hm-cat-opt:has(.hm-cat-det) .hm-cat-nm{flex:0 0 108px;font-weight:600;color:var(--text)}
.avb-app .hm-cat-opt:disabled{opacity:.4;cursor:default}
.avb-app .hm-cat-opt:disabled:hover{background:none;color:var(--dim)}
.avb-app .hm-ctl--preset .hm-cat-menu{max-height:min(82vh,680px);min-width:min(460px,calc(100vw - 16px));max-width:calc(100vw - 16px)}
/* Default, Performance, Category. Stays put while the rows scroll. */
.avb-app .hm-preset-modes{display:flex;gap:2px;flex:0 0 auto;padding:2px 2px 6px;margin:0 2px 2px;border-bottom:1px solid var(--line-soft)}
.avb-app .hm-preset-modes .hm-segbtn{flex:1 1 0;min-width:0;padding-left:4px;padding-right:4px}
/* A phone tab bar covers the bottom of a long dropdown, and a one-line detail gets cut off.
   The preset menu becomes a sheet above that bar, and the reading wraps. */
@media (max-width:640px){
  .avb-app .hm-ctl--preset .hm-cat-menu{
    position:fixed;left:8px;right:8px;top:64px;bottom:calc(66px + env(safe-area-inset-bottom));
    width:auto;min-width:0;max-width:none;max-height:none;z-index:55}
  .avb-app .hm-cat-det{white-space:normal;overflow:visible;text-overflow:clip;line-height:1.3}
}
/* The size of the lens before you pick it: a nine-coin theme is about to black out the board. */
.avb-app .hm-cat-n{font-size:10px;color:var(--faint);font-variant-numeric:tabular-nums}

/* ── THE LENS PANEL — three axes side by side ────────────────────────────────────────────
   Theme, chain and band used to be three triggers on the bar. As one control they have to be
   three COLUMNS rather than one long list, because the ticks inside a column are ORed and the
   columns are ANDed: showing them stacked would imply the wrong operator between them, and a
   single merged list could not express the intersection at all.

   ☢️ THE SCROLL BELONGS TO EACH COLUMN, NOT THE PANEL. Sixteen chains against four bands means
   the columns have very different heights; scrolling the panel would carry the Clear/Done
   footer off the bottom, which is the same bug the single menu already fixed once. */
.avb-app .hm-lens-menu{min-width:min(560px,calc(100vw - 32px))}
.avb-app .hm-lens-cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:4px;
  min-height:0;flex:1 1 auto}
.avb-app .hm-lens-col{display:flex;flex-direction:column;min-height:0;min-width:0}
.avb-app .hm-lens-col + .hm-lens-col{border-left:1px solid var(--line-soft);padding-left:4px}
.avb-app .hm-lens-hd{flex:0 0 auto;padding:2px 9px 6px;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.13em;text-transform:uppercase;color:var(--faint);white-space:nowrap}
/* The name may be longer than a third of the panel (Performance's bands, the longer chains);
   it wraps rather than being clipped, since the count is what must never be pushed out. */
.avb-app .hm-lens-col .hm-cat-nm{white-space:normal}

/* Set-once ladders read as one word — a floor, a count — so the trigger is sized to the words
   rather than to the lens's 124px, which was chosen for "3 themes". */
.avb-app .hm-choice-btn{min-width:96px}

@media (max-width:760px){
  /* ☢️ TWO COLUMNS, NOT THREE AND NOT ONE. Three 90px columns on a phone is unreadable, so this
     stacked all three — and stacking is what made the panel useless. The height is shared out
     between the lists, so three lists plus three headers inside a 360px cap left THEME showing
     1.2 of its 13 rows, BLOCKCHAIN 1.2 of 16, and PERFORMANCE collapsed to ONE PIXEL — its four
     bands were unreachable on a phone entirely. Measured, not guessed.
     Theme and chain sit side by side now: they are the two long lists and they read as a pair
     (a theme AND a chain), so they share the tall row. Performance is four short bands and
     takes the full width beneath them, where it cannot be squeezed to nothing. */
  .avb-app .hm-lens-menu{min-width:100%}
  .avb-app .hm-lens-cols{grid-template-columns:repeat(2,minmax(0,1fr));
    grid-template-rows:minmax(0,1fr) auto;gap:0 6px}
  .avb-app .hm-lens-col + .hm-lens-col{border-left:1px solid var(--line-soft);padding-left:6px;
    border-top:0;margin-top:0;padding-top:0}
  /* The third axis drops to its own full-width row, so it takes a rule above it rather than
     a rule beside it. */
  .avb-app .hm-lens-col:nth-child(3){grid-column:1 / -1;border-left:0;padding-left:0;
    border-top:1px solid var(--line-soft);margin-top:4px;padding-top:4px}
  /* Capped so four bands cannot crowd out the two lists that have 29 rows between them. */
  .avb-app .hm-lens-col:nth-child(3) .hm-cat-list{max-height:120px}
  /* ⚠️ THE CAP, NOT 70vh, WAS BINDING. min(70vh,360px) on a 915px phone resolves to 360px —
     the vh half never applied. The panel is inside the Filters drawer with the board below it,
     so it can afford far more; lib/useMenuFit.ts still clamps it to the real room when the
     trigger sits low enough that this would run off-screen. */
  .avb-app .hm-lens-menu{max-height:min(78vh,600px)}
  .avb-app .hm-choice-btn{min-width:0;width:100%}
}

/* A list must never be squeezed to nothing — below three rows it is a scrollbar, not a list.
   ☢️ BUT THE FLOOR ONLY APPLIES WHERE THERE IS HEIGHT TO SPEND. A min-height is a floor the
   panel CANNOT shrink past, so on a short screen it stops lib/useMenuFit.ts from capping the
   panel to the room that actually exists — the clamp asks for 380px, the floors insist on
   more, and the difference goes off the screen where nothing can reach it. Gated on the
   viewport being tall enough to afford them, so a short one gets a panel that scrolls
   instead of a panel that overflows. */
@media (max-width:760px) and (min-height:720px){
  .avb-app .hm-lens-col .hm-cat-list{min-height:132px}
  .avb-app .hm-lens-col:nth-child(3) .hm-cat-list{min-height:88px}
}

/* A dimmed tile is still a coin: hovering one has to bring it back far enough to read, or the
   lens would make four fifths of the board unusable rather than quiet. brightness() is safe
   here precisely because a hover state can never be captured in a snapshot. */
.avb-app button.hm-px.is-dim:hover,.avb-app button.hm-px.is-dim:focus-visible{filter:brightness(2.4)}
/* A dimmed wedge keeps its hit target and its hover; only its paint recedes — and it recedes
   by INK COLOUR (DIM_INK, set as a fill attribute), not by an opacity rule here. A rule here
   would have to be hand-copied into BULLSEYE_CSS in lib/snapshotViews.ts to survive an export,
   and the one that was not copied is the one that silently stops matching the screen. */
/* The list's coin column is plain text, so COLOUR is the dim — never opacity, or the export
   would print it at full strength. ☢️ var(--dim-ink) is DIM_INK in lib/heatmap.ts; the two are the
   same ink on the same row (the percentages are coloured inline, from TS) and drift between
   them shows up as one dimmed row wearing two greys. */
.avb-app .rk-row.is-dim .rk-sym,.avb-app .rk-row.is-dim .rk-name,.avb-app .rk-row.is-dim .rk-vol,
.avb-app .rk-row.is-dim .rk-num{color:var(--dim-ink)}
.avb-app .rk-row.is-dim:hover .rk-sym,.avb-app .rk-row.is-dim:hover .rk-name{color:var(--dim)}
/* The logo of an out-of-lens row. A real background-color and color, not an opacity, so
   snapshotDom transcribes it as the rect + text it looks like. */
.avb-app .ico--dim{background:var(--raise);color:var(--dim-ink)}
.avb-app .rk-lens{color:var(--amber)}
.avb-app .pagehead-lens{color:var(--amber)}
.avb-app .hm-lens-note{color:var(--dim)}
.avb-app .hm-lens-warn{color:var(--faint)}

/* Reset — beside the Preset on the top row: the way back to ALTS.7D. */
.avb-app .hm-reset{padding:5px 11px;font-weight:700;background:var(--well);border:1px solid var(--line);
  border-radius:var(--r);cursor:pointer;white-space:nowrap;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--dim)}
.avb-app .hm-reset:hover:not(:disabled){color:var(--text);border-color:var(--down)}
/* Disabled rather than hidden: a control that vanishes when it has nothing to do makes the
   header jump every time the board returns to its defaults. */
.avb-app .hm-reset:disabled{opacity:.4;cursor:default}
.avb-app .hm-resetctl{display:flex;align-items:center;gap:6px}
.avb-app .hm-save.on{color:var(--btc);border-color:var(--btc)}

@media (max-width:760px){
  .avb-app .hm-more .hm-cat,.avb-app .hm-more .hm-cat-btn{width:100%}
  .avb-app .hm-cat-btn,.avb-app .hm-reset{min-height:34px}
}

/* ═══════════════════════════════════════════════════════════════════════════════════════
   THE COIN PAGE (/reports/[symbol]) — one asset, denominated in Bitcoin.
   Rendered inside <AppShell identity>, so it inherits the .avb-app tokens and adds no reset.
   Everything here is server-rendered HTML; only the chart's two toggles are interactive.
   ═══════════════════════════════════════════════════════════════════════════════════════ */
.avb-app .cp{max-width:1180px;margin:0 auto;padding:0 var(--gutter) 72px}
.avb-app .cp-crumbs{display:flex;align-items:center;gap:8px;padding:18px 0 0;
  font-family:var(--mono);font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:var(--faint)}
.avb-app .cp-crumbs a{color:var(--dim);text-decoration:none}
.avb-app .cp-crumbs a:hover{color:var(--base)}

/* ── Identity + price ─────────────────────────────────────────────────────────────────── */
.avb-app .cp-head{display:flex;flex-wrap:wrap;gap:26px;justify-content:space-between;
  align-items:flex-end;padding:18px 0 22px;border-bottom:1px solid var(--line)}
.avb-app .cp-h1{margin:0;font-family:var(--mono);font-size:clamp(30px,5vw,52px);font-weight:700;
  letter-spacing:-.01em;line-height:1;color:var(--ink)}
.avb-app .cp-slash{color:var(--base);margin:0 .06em}
.avb-app .cp-quote{color:var(--dim)}
.avb-app .cp-name{margin:9px 0 0;font-size:15px;color:var(--dim);display:flex;align-items:center;gap:11px;flex-wrap:wrap}
.avb-app .cp-rank{font-family:var(--mono);font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--faint);border:1px solid var(--line);border-radius:999px;padding:2px 9px}
.avb-app .cp-tags{list-style:none;display:flex;flex-wrap:wrap;gap:6px;margin:11px 0 0;padding:0}
.avb-app .cp-tags a{display:inline-block;font-family:var(--mono);font-size:10.5px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--dim);text-decoration:none;
  background:var(--hi-2);border:1px solid var(--line);border-radius:5px;padding:3px 9px}
.avb-app .cp-tags a:hover{color:var(--base);border-color:var(--base)}

/* The right column of the report header: the jump-to-another-report search above, the price
   row below. Right-aligned so both edges line up with the page gutter. */
.avb-app .cp-headright{display:flex;flex-direction:column;align-items:flex-end;gap:16px}
.avb-app .cp-search{flex:0 0 auto;width:min(300px,100%)}
/* ⚠️ The dropdown is anchored to the field, and the field is inside a flex column whose
   siblings paint after it. Without a stacking context of its own the hit list slid UNDER the
   price row — visible, unreadable, and clickable only on its top few pixels. */
.avb-app .cp-search{position:relative;z-index:50}
.avb-app .cp-search .hm-search-hits{text-align:left}
.avb-app .cp-search-none{color:var(--faint);cursor:default}
.avb-app .cp-price{display:grid;grid-template-columns:repeat(4,auto);gap:10px 30px;margin:0;text-align:right}
/* ☢️ AFTER THE BASE RULES, NOT BESIDE THE OTHER MEDIA BLOCKS. A media query adds no
   specificity, so this sat 1,300 lines earlier than the .cp-headright rule it overrides and
   lost every declaration to it — align-items computed to flex-end and the field stayed 300px,
   indented, on a 390px screen. Position in the file is the only thing deciding this. */
@media (max-width:760px){
  /* The header is already stacked here, so the search takes the width like every other field. */
  .avb-app .cp-headright{width:100%;align-items:stretch}
  .avb-app .cp-search{width:100%}
  .avb-app .cp-price{justify-content:start;text-align:left}
}
.avb-app .cp-price>div{display:flex;flex-direction:column;gap:3px}
.avb-app .cp-price dt{font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.avb-app .cp-price dd{margin:0}
.avb-app .cp-px{font-family:var(--mono);font-size:22px;font-weight:700;color:var(--ink);white-space:nowrap}
.avb-app .cp-px--btc{color:var(--base)}
.avb-app .cp-chg{font-family:var(--mono);font-size:18px;font-weight:700}
/* THE CLOCK THE HEADER RUNS ON, beside the numbers it governs. A fifth grid cell spanning the
   row: the four readouts above it are what it describes, and the footer 5,000px down is not
   where a reader looks for it (2026-09-06 audit: live board, nightly report, no stamp near
   either). Same face and pulse as the board's own badge, so one rule reads as one rule. */
.avb-app .cp-price .cp-clock{grid-column:1 / -1;text-align:inherit}
.avb-app .cp-price .cp-clock .sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.avb-app .cp-live{display:inline-flex;align-items:center;gap:6px;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.13em;text-transform:uppercase;color:var(--faint)}
.avb-app .cp-live::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--faint);flex:none}
.avb-app .cp-live.on{color:var(--up)}
.avb-app .cp-live.on::before{background:var(--up);animation:avb-pulse 2.4s ease-in-out infinite}

.avb-app .cp .pos,.avb-app .cp .cp-chg.pos,.avb-app .cp td.pos,.avb-app .cp dd.pos{color:var(--up)}
.avb-app .cp .neg,.avb-app .cp .cp-chg.neg,.avb-app .cp td.neg,.avb-app .cp dd.neg{color:var(--down)}
.avb-app .cp .flat,.avb-app .cp td.flat,.avb-app .cp dd.flat{color:var(--faint)}

/* ── The verdict ──────────────────────────────────────────────────────────────────────── */
.avb-app .cp-verdict{display:flex;flex-wrap:wrap;gap:22px;justify-content:space-between;
  align-items:center;padding:22px 0}
.avb-app .cp-vmain{flex:1 1 420px;min-width:0}
.avb-app .cp-vline{margin:0 0 12px;font-size:clamp(17px,2.4vw,23px);font-weight:600;color:var(--ink);line-height:1.35}
.avb-app .cp-pips{list-style:none;display:flex;flex-wrap:wrap;gap:6px;margin:0;padding:0}
.avb-app .cp-pips li{display:flex;flex-direction:column;gap:2px;align-items:center;
  min-width:62px;padding:6px 9px;border-radius:6px;border:1px solid var(--line);
  font-family:var(--mono);background:var(--hi-1)}
.avb-app .cp-pips .pl{font-size:9.5px;letter-spacing:.1em;color:var(--faint)}
.avb-app .cp-pips .pv{font-size:13px;font-weight:700}
.avb-app .cp-pips li.won{border-color:rgba(43,223,95,.4);background:rgba(43,223,95,.09)}
.avb-app .cp-pips li.won .pv{color:var(--up)}
.avb-app .cp-pips li.lost{border-color:rgba(241,51,52,.28);background:rgba(241,51,52,.06)}
.avb-app .cp-pips li.lost .pv{color:var(--down)}


/* ── Chart ────────────────────────────────────────────────────────────────────────────── */
.avb-app .cp-chart{border:1px solid var(--line);border-radius:10px;background:var(--panel);overflow:hidden}
.avb-app .cp-charthd{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:12px 14px;
  border-bottom:1px solid var(--line)}
.avb-app .cp-seg{display:inline-flex;border:1px solid var(--line);border-radius:7px;overflow:hidden}
.avb-app .cp-seg button{appearance:none;background:transparent;border:0;cursor:pointer;
  padding:6px 13px;font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--dim)}
.avb-app .cp-seg button+button{border-left:1px solid var(--line)}
.avb-app .cp-seg button:hover:not(.on){color:var(--text)}
.avb-app .cp-seg button.on{background:rgba(243,174,31,.14);color:var(--base)}
.avb-app .cp-seg button:focus-visible{outline:2px solid var(--base);outline-offset:-2px}
.avb-app .cp-cap{margin-left:auto;font-family:var(--mono);font-size:10.5px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--faint)}
/* The crosshair readout. It keeps its height with or without a pointer on the chart, so the
   chart below does not jump the moment someone touches it. */
/* The coin page's [+] — same idea as the board's, and the only place Minutes and Hours are
   offered, because one coin can be asked of a live venue and a thousand cannot. */
.avb-app .cp-plus{font-weight:700}
/* ☢️ flex:0 0 100% — the panel lives INSIDE .cp-charthd (so an outside-click dismissal can
   treat the whole header as "inside"), and .cp-charthd is a flex ROW. Left to itself the
   panel became a 197px column squeezed between the segmented controls. Claiming a full basis
   drops it onto its own line under them, which is where a popover belongs. */
.avb-app .cp-pick{flex:0 0 100%;margin:8px 0 0;padding:11px;background:var(--glass);
  border:1px solid var(--line);border-radius:7px;max-width:340px}
.avb-app .cp-pick-units{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:4px;margin-bottom:9px}
.avb-app .cp-pick-units button{padding:7px 2px;background:var(--well);border:1px solid var(--line);
  border-radius:4px;cursor:pointer;color:var(--dim);
  font-family:var(--mono);font-size:9.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase}
.avb-app .cp-pick-units button:hover{color:var(--text);border-color:var(--line-soft)}
.avb-app .cp-pick-units button.on{color:var(--base);border-color:var(--base);background:rgba(243,174,31,.10)}
.avb-app .cp-pick-row{display:flex;align-items:center;gap:9px;margin-bottom:8px}
.avb-app .cp-pick-row label{flex:1 1 auto;font-family:var(--mono);font-size:10.5px;letter-spacing:.05em;color:var(--dim)}
.avb-app .cp-pick-row input{width:82px;padding:6px 8px;background:var(--well-2);border:1px solid var(--line);
  border-radius:4px;color:var(--text);font-family:var(--mono);font-size:12.5px;text-align:right}
.avb-app .cp-pick-row input:focus{outline:none;border-color:var(--base)}
.avb-app .cp-pick-note{margin:0 0 10px;font-size:11px;line-height:1.35;color:var(--faint)}
.avb-app .cp-pick-note.bad{color:var(--base)}
.avb-app .cp-pick-act{display:flex;gap:6px}
.avb-app .cp-pick-go{flex:1 1 auto;padding:7px 10px;border:1px solid var(--base);border-radius:4px;
  background:rgba(243,174,31,.14);color:var(--base);cursor:pointer;
  font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
.avb-app .cp-pick-go:hover:not(:disabled){background:rgba(243,174,31,.24)}
.avb-app .cp-pick-go:disabled{opacity:.4;cursor:not-allowed}
.avb-app .cp-pick-x{padding:7px 10px;border:1px solid var(--line);border-radius:4px;background:none;
  color:var(--dim);cursor:pointer;
  font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
@media (pointer:coarse){
  .avb-app .cp-pick-units button{min-height:40px}
  .avb-app .cp-pick-row input,.avb-app .cp-pick-go,.avb-app .cp-pick-x{min-height:44px}
}
.avb-app .cp-inds{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:8px 0 2px}
.avb-app .cp-indlbl{font-family:var(--mono);font-size:9.5px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--faint);margin-right:2px}
.avb-app .cp-ind{padding:5px 9px;border:1px solid var(--line);border-radius:4px;background:var(--well);
  color:var(--dim);cursor:pointer;font-family:var(--mono);font-size:10px;font-weight:700;
  letter-spacing:.05em;text-transform:uppercase;transition:color .12s ease,border-color .12s ease}
.avb-app .cp-ind:hover{color:var(--text);border-color:var(--line-soft)}
.avb-app .cp-ind.on{color:var(--base);border-color:var(--base);background:rgba(243,174,31,.10)}
.avb-app .cp-ind:focus-visible{outline:2px solid var(--base);outline-offset:2px}
.avb-app .cp-charthint{margin:7px 0 0;font-size:11px;color:var(--faint)}
@media (pointer:coarse){
  .avb-app .cp-ind{min-height:40px;padding:0 12px;display:inline-flex;align-items:center}
}
/* ☢️ THE TOUCH FLOOR IS SCOPED TO THE POINTER, NOT THE WIDTH — a thumb is a thumb at any
   screen size. It lived inside @media (max-width:760px), so a 768px touch tablet missed it by
   eight pixels and every control on it stayed 34px: the measurement pass counted 26–32 targets
   under 40px there, on every route, and the width-scoped fix did not move that number at all.
   (pointer:coarse) is the question actually being asked.
   ⚠️ AND THE CONTROLS GET BIGGER HERE, NOT SMALLER. The ask that prompted this pass was to
   shrink the control bar; taken literally on a touch device it would push a thumb target
   further below the floor it was already under. The height comes back out of the chrome around
   the controls instead — captions, gaps, and the prose stack below. */
@media (pointer: coarse) {
  .avb-app .hm-segbtn{min-height:40px}
  /* The last six, found by counting rather than by eye: the two icon buttons that sit over
     the board, the coin search field, and the wordmark in the header. */
  .avb-app .fsbtn,.avb-app .snap-btn{min-width:40px;min-height:40px}
  .avb-app .hm-search-in{min-height:40px}
  .sh-mark{min-height:40px;display:inline-flex;align-items:center}
  .avb-app .hm-zbtn{min-width:40px;height:40px}
  .avb-app .hm-cat-btn,.avb-app .hm-choice-btn,.avb-app .hm-cat-opt{min-height:40px}
  .avb-app .hm-reset{min-height:40px}
  /* The macro page has its own control vocabulary — pair chips, view/range/scale/style segs,
     the All·None·Reset run — none of which share a class with the board's. Counted, not
     assumed: 26 targets under the floor on /macro alone after the board routes were clean. */
  .avb-app .mc-seg button,.avb-app .mc-chip,.avb-app .mc-chipops button{min-height:40px}
  /* The last five, named by reading the DOM rather than guessing at class names — which is
     how the macro sweep above went from a partial fix to a complete one.
     ⚠️ Scoped to the two containers that hold LINKS SHAPED LIKE BUTTONS. A blanket rule on <a>
     would give every inline link in a paragraph a 40px line box and wreck the prose. */
  .avb-app .cp-cats a{min-height:40px;display:inline-flex;align-items:center}
  .avb-app .wstar{min-height:40px}
  .avb-app .btn{min-height:40px;display:inline-flex;align-items:center;justify-content:center}
}

/* ⚠️ THE PROSE ABOVE THE BOARD IS TIGHTENED ON A PHONE, NOT REMOVED. At 390px the headline
   wrapped to 43px, the board title to 60 and its subtitle to 59 — 162px of type, against 22,
   30 and 19 on a desktop where the same words fit on one line each. They still say everything
   they said; they just stop being three double-height paragraphs stacked on top of the thing
   the reader came for. */
@media (max-width:520px){
  .avb-app .pagehead-title{font-size:16px;line-height:1.2}
  .avb-app .rk-title{font-size:13px;line-height:1.25}
  .avb-app .rk-sub{font-size:11px;line-height:1.35}
}

@media (max-width:640px){
  .avb-app .cp-indlbl{width:100%;margin-bottom:2px}
}
/* ☢️ contain:inline-size — WITHOUT IT, HOVERING THE CHART RESIZES THE PAGE. `.cp` is
   `margin:0 auto` inside a column flex, which makes the article FIT-CONTENT: its width is
   the widest max-content among its children. The crosshair swaps this line from a short
   summary to a full O/H/L/C/VOL readout whose max-content is ~140px wider, so moving the
   pointer onto the chart widened the whole article and re-wrapped every section under it.
   Containing the inline size takes this line out of that calculation; flex-wrap then wraps
   the readout inside the width the page already had. */
/* ☢️ TWO ROWS, NEITHER OF WHICH MAY WRAP. This was one wrapping flex line, and hovering the
   chart swapped its contents from two children to four — below ~900px the extra ones no longer
   fitted, the line wrapped, and the block grew 48px to 70px. The chart under it jumped 22px
   down when the crosshair arrived and back up when it left. Measured at four widths: steady at
   1400 and 1100, moving at 900 and 700, which is exactly what made it feel like a glitch
   rather than a layout fault.
   Fixed height by construction now — one line per row whatever either holds. */
.avb-app .cp-read{display:flex;flex-direction:column;gap:2px;contain:inline-size;
  padding:12px 14px 4px}
.avb-app .cp-read-main{display:flex;align-items:baseline;gap:6px 12px;min-width:0;flex-wrap:nowrap}
/* ⚠️ min-width:0 is what lets a flex child shrink below its content and therefore ellipsis at
   all; without it the span keeps its intrinsic width and pushes the row wide instead. */
.avb-app .cp-readdet{min-width:0;flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The readout's optional words (bar count, "over this window") — see PairChart. Hidden where
   the row cannot hold them rather than letting the ellipsis pick which half survives. */
@media (max-width:480px){.avb-app .cp-read-opt{display:none}}
/* ⚠️ nowrap + ellipsis because this row now carries the 0%-vs-BTC key beside the date, and
   the panel being EXACTLY two lines tall is load-bearing — see the note in PairChart. Without
   a truncation rule a narrow window would wrap this row and shove the chart down. */
.avb-app .cp-read-sub{min-height:16px;line-height:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.avb-app .cp-readpx{font-family:var(--mono);font-size:22px;font-weight:700;color:var(--ink);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.avb-app .cp-readlbl{font-family:var(--mono);font-size:11px;letter-spacing:.05em;color:var(--faint)}
.avb-app .cp-readlbl b{font-weight:700}
/* The key for the 0%-vs-BTC level, which no longer carries a badge on the chart itself.
   ⚠️ IT HAS TO LOOK LIKE THE LINE IT NAMES — same hue, same dimming, same dash — or it is a
   second thing to learn rather than a translation of the first.
   ☢️ WHICH IS WHY IT IS A GRADIENT AND NOT `border:1px dashed`. A CSS dashed border draws the
   USER AGENT's pattern (Chrome ≈2px on 2px at this width) and no property tunes it, so the
   swatch would only look dashed rather than look like THIS dash. lightweight-charts draws
   LineStyle.Dashed as [2 * lineWidth, 2 * lineWidth] — 2px on 2px at 1px wide — and the
   gradient reproduces exactly that. */
.avb-app .cp-zerokey{display:inline-block;width:14px;height:1px;vertical-align:middle;
  background:repeating-linear-gradient(to right,rgba(247,147,26,.5) 0 2px,transparent 2px 4px);
  margin-right:.4em;position:relative;top:-1px}

/* ⚠️ pan-y, not none. The chart tracks a finger horizontally, but taking the whole gesture
   would trap the page: on a phone the chart is most of the viewport, and a reader who swipes
   up to scroll would find the page frozen under their thumb. */
/* ☢️ THE HEIGHT IS A REAL CSS LENGTH AND IT MUST STAY ONE. lightweight-charts sizes its
   canvas imperatively from what it measures here; a percentage height against an auto-height
   parent measures ZERO, and the chart then renders nothing while reporting no error at all.
   touch-action:pan-y leaves vertical page scrolling to the browser and horizontal drag to the
   chart, so panning the chart on a phone does not fight scrolling the page.

   ☢️ contain:inline-size IS WHAT STOPS A FEEDBACK LOOP, and it is not an optimisation.
   `.cp` is `margin:0 auto` inside a column flex, which makes it FIT-CONTENT — its width is
   whatever its widest child needs. A <canvas> carries an intrinsic pixel width (the old SVG,
   sized by viewBox, did not), so the chart's own width fed back into the width of the box it
   is measured against: one wheel-zoom reflowed the whole article from 808px to 948px and
   moved every section on the page. Containing the inline size takes the canvas out of that
   calculation, so the chart fits the page instead of the page fitting the chart. */
/* THE SWITCH ABOVE THE CHART SLOT, and the TradingView frame that takes the slot when chosen.
   Taller than our own chart on purpose: a drawing surface needs room for the toolbar and the
   hand. Height is fixed rather than viewport-relative so the iframe never re-lays out mid-draw. */
.avb-app .cp-chartswitch{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px;margin:0 0 10px}
.avb-app .cp-chart--tv{padding:0}
.avb-app .cp-tvwrap{width:100%;height:560px;background:var(--panel)}
@media (max-width:640px){.avb-app .cp-tvwrap{height:440px}}
.avb-app .cp-chartwrap{position:relative;width:100%;min-width:0;height:clamp(220px,32vw,320px);
  touch-action:pan-y;contain:inline-size;overflow:hidden}

/* Axis labels are HTML over the chart, never SVG text — the chart is stretched by
   preserveAspectRatio:none and text inside it would be drawn at the wrong aspect. */
.avb-app .cp-yaxis{position:absolute;inset:0;pointer-events:none}
.avb-app .cp-yaxis span{position:absolute;left:8px;transform:translateY(-50%);
  font-family:var(--mono);font-size:9.5px;letter-spacing:.04em;color:var(--faint);
  background:color-mix(in srgb,var(--panel) 82%,transparent);padding:1px 4px;border-radius:3px}
.avb-app .cp-xaxis{display:flex;justify-content:space-between;padding:2px 14px 0;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--faint)}
.avb-app .cp-nochart{margin:0;padding:60px 20px;text-align:center;color:var(--faint);font-size:13px}
.avb-app .cp-chartnote{margin:0;padding:11px 14px;border-top:1px solid var(--line);
  font-size:12.5px;color:var(--dim)}

/* ── Sections ─────────────────────────────────────────────────────────────────────────── */
.avb-app .cp-sec{padding:34px 0 0}
.avb-app .cp-sec h2{margin:0 0 7px;font-size:clamp(19px,2.6vw,25px);font-weight:700;color:var(--ink);letter-spacing:-.01em}
.avb-app .cp-h3{margin:26px 0 10px;font-family:var(--mono);font-size:11px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--faint)}
.avb-app .cp-lede{margin:0 0 16px;font-size:14.5px;line-height:1.6;color:var(--dim);max-width:76ch}
.avb-app .cp-note{margin:12px 0 0;font-size:12.5px;line-height:1.6;color:var(--faint);max-width:80ch}

/* ── Tables ───────────────────────────────────────────────────────────────────────────── */
.avb-app .cp-tablewrap{overflow-x:auto;border:1px solid var(--line);border-radius:9px;background:var(--panel)}
.avb-app .cp-table{width:100%;border-collapse:collapse;font-family:var(--mono);font-size:13.5px}
.avb-app .cp-table th{display:table-cell;border:0;border-radius:0;background:transparent;
  font-weight:600;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);
  text-align:right;padding:11px 14px;border-bottom:1px solid var(--line);white-space:nowrap;line-height:1.4}
.avb-app .cp-table thead th:first-child,.avb-app .cp-table tbody th{text-align:left}
.avb-app .cp-table td{padding:10px 14px;text-align:left;border-bottom:1px solid var(--line-soft);white-space:nowrap}
.avb-app .cp-table td.num{text-align:right;font-variant-numeric:tabular-nums}
.avb-app .cp-table td.lead{font-weight:700;font-size:15px}
.avb-app .cp-table tbody th{font-size:11px;color:var(--dim);border-bottom:1px solid var(--line-soft);
  padding:10px 14px;white-space:nowrap}
.avb-app .cp-table tbody tr:last-child td,.avb-app .cp-table tbody tr:last-child th{border-bottom:0}
.avb-app .cp-table tbody tr:hover td,.avb-app .cp-table tbody tr:hover th{background:var(--panel-2)}
.avb-app .cp-cls{font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}

/* ── Stat rows ────────────────────────────────────────────────────────────────────────── */
.avb-app .cp-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  gap:1px;margin:0 0 16px;background:var(--line);border:1px solid var(--line);border-radius:9px;overflow:hidden}
.avb-app .cp-stats>div{display:flex;flex-direction:column;gap:5px;padding:15px 17px;background:var(--panel)}
.avb-app .cp-stats dt{font-family:var(--mono);font-size:10px;letter-spacing:.11em;text-transform:uppercase;color:var(--faint)}
.avb-app .cp-stats dd{margin:0;font-family:var(--mono);font-size:19px;font-weight:700;color:var(--ink)}

.avb-app .cp-vols{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(112px,1fr));
  gap:1px;margin:0;padding:0;background:var(--line);border:1px solid var(--line);border-radius:9px;overflow:hidden}
.avb-app .cp-vols li{display:flex;flex-direction:column;gap:4px;padding:13px 15px;background:var(--panel)}
.avb-app .cp-vols .vl{font-family:var(--mono);font-size:10px;letter-spacing:.11em;text-transform:uppercase;color:var(--faint)}
.avb-app .cp-vols .vv{font-family:var(--mono);font-size:15px;font-weight:700;color:var(--ink)}

/* ── Horizon cards ────────────────────────────────────────────────────────────────────── */
.avb-app .cp-hz{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:14px}
/* ⚠️ The 3px top edge was the STATE's colour (up/base/down/unclear) and those modifier
   classes went with the trend-state system. A plain border keeps the card's shape without
   colouring it by a reading the page no longer makes. */
.avb-app .cp-hzcard{border:1px solid var(--line);border-radius:9px;
  background:var(--panel);padding:16px 18px}
.avb-app .cp-hzcard .hzk{margin:0 0 13px;font-family:var(--mono);font-size:10px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--faint)}
.avb-app .cp-hzcard dl{display:grid;grid-template-columns:1fr auto;gap:7px 12px;margin:0;
  padding-top:12px;border-top:1px solid var(--line-soft)}
.avb-app .cp-hzcard dl>div{display:contents}
.avb-app .cp-hzcard dt{font-size:12px;color:var(--faint)}
.avb-app .cp-hzcard dd{margin:0;font-family:var(--mono);font-size:12.5px;font-weight:700;color:var(--ink);text-align:right}

/* ── Peers ────────────────────────────────────────────────────────────────────────────── */
.avb-app .cp-peers{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
  gap:9px;margin:0;padding:0}
.avb-app .cp-peers a{display:flex;align-items:center;gap:10px;padding:12px 15px;text-decoration:none;
  border:1px solid var(--line);border-radius:8px;background:var(--panel)}
.avb-app .cp-peers a:hover{border-color:var(--base);background:var(--panel-2)}
.avb-app .cp-peers .psym{font-family:var(--mono);font-size:13.5px;font-weight:700;color:var(--ink)}
.avb-app .cp-peers .pnm{flex:1;min-width:0;font-size:12px;color:var(--faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.avb-app .cp-peers .pv{font-family:var(--mono);font-size:13px;font-weight:700}

/* ── Footer ───────────────────────────────────────────────────────────────────────────── */
.avb-app .cp-foot{margin-top:44px;padding-top:20px;border-top:1px solid var(--line)}
.avb-app .cp-foot p{margin:0 0 10px;font-size:12.5px;line-height:1.65;color:var(--faint);max-width:88ch}
.avb-app .cp-backlink a{color:var(--base);text-decoration:none;font-weight:600}
.avb-app .cp-backlink a:hover{text-decoration:underline}
.avb-app .cp--missing{padding-top:60px}

/* The sheet's own link to all of the above. A primary action, so it does not read as the
   twin of the outbound CoinGecko button sitting beside it. */
.avb-app .hm-report{display:inline-flex;align-items:center;justify-content:center;gap:7px;
  align-self:stretch;min-height:38px;padding:0 16px;border-radius:7px;text-decoration:none;
  background:rgba(243,174,31,.14);border:1px solid var(--base);color:var(--base);
  font-family:var(--mono);font-size:11.5px;letter-spacing:.08em;text-transform:uppercase;font-weight:700;
  transition:background .13s ease}
.avb-app .hm-report:hover{background:rgba(243,174,31,.24)}
.avb-app .hm-report:focus-visible{outline:2px solid var(--base);outline-offset:2px}

@media (max-width:860px){
  .avb-app .cp-price{grid-template-columns:repeat(2,1fr);text-align:left;gap:14px 22px;width:100%}
  .avb-app .cp-head{align-items:flex-start}
}
@media (max-width:640px){
  .avb-app .cp-table{font-size:12px}
  .avb-app .cp-table th,.avb-app .cp-table td{padding:9px 8px}
  .avb-app .cp-px{font-size:19px}
}

/* ── Coin page: contract, supply, range, candle readout ──────────────────────────────────── */
.avb-app .cp-contracts{list-style:none;margin:0;padding:0;display:grid;gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:9px;overflow:hidden}
.avb-app .cp-contracts li{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;
  padding:13px 16px;background:var(--panel)}
.avb-app .cc-chain{font-family:var(--mono);font-size:10px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--base);border:1px solid var(--btc-bd);border-radius:5px;padding:3px 9px;flex:0 0 auto}
/* The address must wrap rather than push the row wide — 44 characters on a 380px phone. */
.avb-app .cc-addr{font-family:var(--mono);font-size:12px;color:var(--ink);flex:1 1 240px;
  min-width:0;overflow-wrap:anywhere;line-height:1.5}
.avb-app .cc-acts{display:flex;align-items:center;gap:8px;flex:0 0 auto}
.avb-app .cp-copy{appearance:none;cursor:pointer;padding:5px 12px;border-radius:6px;
  border:1px solid var(--line);background:var(--hi-2);color:var(--dim);
  font-family:var(--mono);font-size:10px;letter-spacing:.09em;text-transform:uppercase;font-weight:700}
.avb-app .cp-copy:hover{color:var(--text);border-color:var(--dim)}
.avb-app .cp-copy.done{color:var(--up);border-color:var(--up)}
.avb-app .cp-copy:focus-visible{outline:2px solid var(--base);outline-offset:2px}
.avb-app .cc-exp{font-family:var(--mono);font-size:10px;letter-spacing:.09em;text-transform:uppercase;
  font-weight:700;color:var(--dim);text-decoration:none;white-space:nowrap}
.avb-app .cc-exp:hover{color:var(--base)}

/* 24h range: where the last price sits between the day's low and high. */
.avb-app .cp-range{display:flex;align-items:center;gap:12px;font-family:var(--mono);font-size:12px;color:var(--dim)}
.avb-app .cp-range .rt{position:relative;flex:1 1 auto;height:6px;border-radius:3px;
  background:linear-gradient(90deg,var(--down),var(--unclear) 50%,var(--up))}
.avb-app .cp-range .rt i{position:absolute;top:50%;width:3px;height:16px;border-radius:2px;
  background:var(--ink);transform:translate(-50%,-50%);box-shadow:0 0 0 2px var(--panel)}
.avb-app .cp-range .rl{color:var(--down)}
.avb-app .cp-range .rh{color:var(--up)}

/* OHLC readout — its own line so the price stays the biggest thing on the row. */
.avb-app .cp-readohlc{font-family:var(--mono);font-size:11.5px;color:var(--dim);
  font-variant-numeric:tabular-nums;letter-spacing:.02em}
.avb-app .cp-readohlc b{color:var(--faint);font-weight:700;font-size:10px;letter-spacing:.08em}

@media (max-width:640px){
  .avb-app .cp-contracts li{gap:8px 10px}
  .avb-app .cc-addr{flex-basis:100%;font-size:11px}
  .avb-app .cp-readohlc{font-size:10.5px}
}

/* ═══════════════════════════════════════════════════════════════════════════════════════
   COIN PAGE — MOBILE PASS
   Every number below is measured, not guessed: character counts against IBM Plex Mono's
   0.61em advance (it is duplexed, so a count IS a width), at a 390px viewport = 358px of
   content after the 16px gutters.
   ═══════════════════════════════════════════════════════════════════════════════════════ */

/* ── TAP TARGETS ─────────────────────────────────────────────────────────────────────────
   Measured from the shipped rules: chart toggles 26.6px, Copy 24.0px, category chips
   20.6px, the explorer link 12.0px. Apple asks for 44, Material for 48, and WCAG 2.5.8 for
   24 as an absolute floor — the last two were under even that. Keyed on POINTER, not on
   width: a coarse pointer is the reason the target has to be bigger, and a desktop window
   dragged narrow should not get finger-sized controls. */
@media (pointer:coarse){
  .avb-app .cp-seg button{min-height:44px;padding:0 15px}
  .avb-app .cp-copy{min-height:44px;padding:0 16px}
  .avb-app .cp-tags a{min-height:40px;display:inline-flex;align-items:center;padding:0 12px}
  .avb-app .cc-exp{min-height:44px;display:inline-flex;align-items:center;padding:0 10px;
    border:1px solid var(--line);border-radius:6px}
  .avb-app .cp-peers a{min-height:52px}
  /* ⚠️ 40, not 32. This block already existed and already meant to be the touch floor; it
     just set a number below it, and a later same-specificity rule silently beat the newer
     one added in the pointer:coarse block above. Corrected here rather than fought there. */
  .avb-app .cp-crumbs a{min-height:40px;display:inline-flex;align-items:center}
  /* The back link is a NAVIGATION control that happens to be styled as a link, not a link
     inside a sentence — WCAG's inline-text exception does not cover it. Measured at 19px
     tall on a phone, under the 24px floor. */
  .avb-app .cp-backlink a{display:inline-flex;align-items:center;min-height:44px}
}


@media (max-width:640px){
  /* ── CHART HEADER ──────────────────────────────────────────────────────────────────────
     Three segmented controls measure 142 + 131 + 135 = 408px plus gaps against 358px of
     room, so they were wrapping wherever they happened to land — and the caption then sat
     alone on a third row because of its margin-left:auto. Two deliberate rows instead:
     denomination and chart type share the first, the horizon takes the second at full
     width. `order` does it without touching the DOM, which keeps the tab order sensible. */
  .avb-app .cp-charthd{gap:8px}
  .avb-app .cp-seg--denom{order:1}
  .avb-app .cp-seg--type{order:2}
  /* ☢️ THE PANEL MUST BE ORDERED TOO. This block re-stacks the header with `order`, and an
     item with no order declared defaults to 0 — which put the custom-range popover ABOVE the
     controls that open it, on phones only. Anything added to .cp-charthd needs a place in
     this sequence or it silently jumps to the front. */
  .avb-app .cp-pick{order:4}
  .avb-app .cp-seg--lens{order:3;flex:1 0 100%}
  .avb-app .cp-seg--lens button{flex:1}
  /* The caption said "SOL/BTC · base channel": the pair is the page's own <h1> and the
     aggregation is named in the note under the chart. It is the one thing here that is pure
     duplication, so it is what gives way rather than the controls. */
  .avb-app .cp-cap{display:none}

  /* ── TABLES ────────────────────────────────────────────────────────────────────────────
     At 8px side padding the $1,000 table came to 364px against 358px — a six-pixel overflow,
     which is the worst kind: it reads as a broken layout rather than as a scrollable table.
     6px padding brings returns to 282px and the stake table to 348px, both inside the
     viewport. Markets is 467px and genuinely has to scroll — six columns of real venue data
     do not fit a phone, and cutting a column would be hiding data a trader came for. */
  .avb-app .cp-table th,.avb-app .cp-table td{padding:9px 6px}

  .avb-app .cp-sec{padding:26px 0 0}
  .avb-app .cp-stats>div{padding:12px 13px}
  /* One column made every stat block four full-width rows and the page endless. Two fit:
     "584,161,287" at 16px mono is 161px against 178px of column. */
  /* ☢️ minmax(0,1fr), NOT 1fr. `1fr` is `minmax(auto,1fr)` and a track will not shrink below
     its content's min-content width — so one unbreakable 250px number in a 178px column
     widens the grid, and the whole PAGE then scrolls sideways. The zero-width breaks that
     fmtSupply inserts handle the typography; this handles the geometry, and either alone is
     not enough. */
  .avb-app .cp-stats{grid-template-columns:repeat(2,minmax(0,1fr))}
  .avb-app .cp-stats dd{font-size:16px;overflow-wrap:anywhere}
  .avb-app .cp-vols{grid-template-columns:repeat(3,minmax(0,1fr))}
  .avb-app .cp-vols li{padding:11px 12px}
  .avb-app .cp-read{padding:10px 12px 4px}
  .avb-app .cp-readpx{font-size:19px}
}

/* ── THE SCROLL IS ONLY USEFUL IF IT IS VISIBLE ──────────────────────────────────────────
   The markets table overflows a phone by 109px and nothing said so. These four layers are
   the standard pure-CSS shadow: two `local` gradients painted in the panel colour that
   scroll away from the edges, and two `scroll` shadows fixed to them — so a shadow appears
   only on a side there is more content on, and no JavaScript measures anything.
   ⚠️ Must sit on the SCROLLER itself, and the panel-coloured covers must be opaque or the
   shadow shows through at rest. */
.avb-app .cp-tablewrap{
  background:
    linear-gradient(to right,var(--panel) 40%,transparent) left center/28px 100% no-repeat local,
    linear-gradient(to left,var(--panel) 40%,transparent) right center/28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%,var(--shadow),rgba(0,0,0,0)) left center/12px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%,var(--shadow),rgba(0,0,0,0)) right center/12px 100% no-repeat scroll,
    var(--panel);
}

/* ═══════════════════════════════════════════════════════════════════════════════════════
   ☢️ THE COIN ARTICLE IS A FLEX ITEM, AND FLEX ITEMS DO NOT SHRINK BY DEFAULT.
   `.avb-app .main` is `display:flex;flex-direction:column`, and <AppShell identity> renders
   the article as its DIRECT child — so `.cp` is a flex item, and a flex item's default
   `min-width:auto` forbids it from going narrower than its own min-content. Any one
   descendant with a wide min-content therefore pushes the whole article past the viewport,
   while `.sh` — a sibling flex item whose min-content is small — stays exactly viewport-wide.
   That asymmetry is the bleed: the header stops at the screen edge and the content runs on
   past it. min-width:0 is the fix, and it is needed regardless of which child is the wide one.

   overflow-x:clip is the backstop, and it is CLIP rather than HIDDEN on purpose: `hidden`
   makes the element a scroll container, which breaks `position:sticky` on anything inside it
   and lets a stray focus scroll the content sideways with no way back. `clip` just clips.
   ═══════════════════════════════════════════════════════════════════════════════════════ */
.avb-app .cp{min-width:0;max-width:min(1180px,100%);overflow-x:clip}

/* The same defect, one level down: every un-floored `1fr` is `minmax(auto,1fr)` and will not
   shrink under its content. These two were the last of them on this page. */
@media (max-width:860px){
  .avb-app .cp-price{grid-template-columns:repeat(2,minmax(0,1fr))}
}
.avb-app .cp-hzcard dl{grid-template-columns:minmax(0,1fr) auto}
.avb-app .cp-tablewrap{max-width:100%}
/* A grid/flex child that holds a long unbroken token — a contract address, a supply figure —
   still needs somewhere to put it once its track is allowed to shrink. */
.avb-app .cp-hzcard dd,.avb-app .cp-price dd{overflow-wrap:anywhere}

/* The board's own wrapper is the SAME defect one class over: `.fp` is a flex item of the
   column-flex `.main` and carries min-height:0 but not min-width:0, so a wide child pushes
   the board past the viewport exactly as it did the coin article. It also matters more here
   than it looks — the grid measures `.hm-gridwrap`'s clientWidth to choose its column count,
   so an over-wide wrapper does not merely bleed, it picks the wrong layout. */
.avb-app .fp{min-width:0}

/* The verdict headline: "$CYS vs $BTC (5/6)". Mono, because it is a readout rather than a
   sentence — the prose version now lives only in the page's meta description. */
.avb-app .cp-vline{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px 14px;
  font-family:var(--mono);font-size:clamp(21px,3.4vw,32px);font-weight:700;letter-spacing:-.01em}
.avb-app .cp-vpair{color:var(--ink);white-space:nowrap}
.avb-app .cp-vx{color:var(--faint);font-weight:600;font-size:.62em;text-transform:uppercase;letter-spacing:.12em}
.avb-app .cp-vscore{font-variant-numeric:tabular-nums}
.avb-app .cp-vscore.pos{color:var(--up)}
.avb-app .cp-vscore.neg{color:var(--down)}
.avb-app .cp-vscore.flat{color:var(--dim)}
.avb-app .cp-vsub{margin:5px 0 13px;font-family:var(--mono);font-size:11px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--faint)}

/* ── The beat-Bitcoin pips: ONE ROW ON A PHONE ────────────────────────────────────────────
   They wrapped, which put a lone 1Y or YTD on a line of its own under six siblings and read
   as a stray rather than as the last of a set. Measured across all 1,000 pages: up to 7 pips,
   and the widest value on the board is "+6462%" — 6 glyphs, which is what the type has to be
   sized to clear.

   `flex:1 1 0` with `min-width:0` is what actually holds the line: the pips SHARE the row
   whatever their number, instead of each demanding its content width and pushing the last one
   over. The 62px floor they carry on desktop has to be released here or it alone forces a wrap
   (7 x 62 + gaps = 458px against 358px of phone).

   The value scales with the viewport rather than sitting at a fixed size, so the row fits a
   375px phone and a 414px one without a second breakpoint: at 2.6vw a 6-glyph value is 35.7px
   on the narrow one and 45.5px on the wide, and 7 of either clears the room available. */
@media (max-width:640px){
  .avb-app .cp-pips{flex-wrap:nowrap;gap:4px}
  .avb-app .cp-pips li{flex:1 1 0;min-width:0;padding:6px 3px;overflow:hidden}
  .avb-app .cp-pips .pl{font-size:8.5px;letter-spacing:.04em}
  .avb-app .cp-pips .pv{font-size:clamp(8.5px,2.6vw,12px)}
}

/* ── CONTACT ──────────────────────────────────────────────────────────────────────────────
   The header button and its dialog. Sized and scrimmed like the sign-in card so the site has
   one idea of what a dialog is, but with its own class run: this one carries a form the other
   does not, and sharing selectors between two dialogs is how one of them ends up restyled by
   a change meant for the other. */
.avb-app .sh-contact{border:0;background:none;font:inherit;letter-spacing:inherit;
  text-transform:inherit;cursor:pointer;color:var(--dim);transition:color .12s ease}
.avb-app .sh-contact:hover{color:var(--text)}
.ct-backdrop{position:fixed;inset:0;z-index:60;display:grid;place-items:center;padding:24px;
  background:var(--veil);backdrop-filter:blur(3px);animation:hm-fade .14s ease;overflow-y:auto}
.ct-card{position:relative;width:100%;max-width:520px;background:var(--panel);
  border:1px solid var(--line);border-radius:var(--r);padding:26px 26px 22px;
  animation:hm-pop .16s cubic-bezier(.2,.8,.2,1)}
.ct-x{position:absolute;top:10px;right:12px;width:28px;height:28px;display:flex;
  align-items:center;justify-content:center;border:0;background:none;color:var(--faint);
  font-size:18px;line-height:1;cursor:pointer;border-radius:var(--r)}
.ct-x:hover{color:var(--ink);background:var(--raise)}
.ct-h{margin:0 0 6px;font-size:19px;font-weight:700;letter-spacing:-.02em;color:var(--ink)}
.ct-sub{margin:0 0 18px;font-size:13.5px;line-height:1.5;color:var(--dim)}
.ct-lbl{display:block;margin:0 0 5px;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.09em;text-transform:uppercase;font-weight:600;color:var(--faint)}
.ct-opt{text-transform:none;letter-spacing:.02em;color:var(--faint);font-weight:500}
.ct-in{width:100%;box-sizing:border-box;margin:0 0 14px;padding:9px 11px;font:inherit;
  font-size:14px;color:var(--ink);background:var(--well);border:1px solid var(--line);
  border-radius:var(--r);transition:border-color .12s ease}
.ct-in:focus{outline:none;border-color:var(--btc)}
.ct-area{resize:vertical;min-height:110px;line-height:1.5;margin-bottom:4px}
/* Two abreast where there is room; a phone stacks them rather than halving a name field. */
.ct-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media (max-width:520px){.ct-row{grid-template-columns:1fr;gap:0}}
.ct-count{margin:0 0 14px;text-align:right;font-family:var(--mono);font-size:11px;color:var(--faint)}
.ct-count.low{color:var(--btc)}
.ct-err{margin:0 0 12px;font-size:13px;color:var(--down)}
.ct-send{width:100%;padding:11px 14px;font:inherit;font-size:14px;font-weight:700;
  color:#0A0C0F;background:var(--btc);border:0;border-radius:var(--r);cursor:pointer;
  transition:filter .12s ease}
.ct-send:hover:not(:disabled){filter:brightness(1.08)}
.ct-send:disabled{opacity:.45;cursor:not-allowed}
/* ☢️ THE HONEYPOT IS HIDDEN WITHOUT display:none. A field that is display:none or hidden is
   skipped by many bots precisely BECAUSE it is obviously a trap, and some browsers decline to
   autofill it. Moved off-screen it stays a real, fillable field that no person will ever see. */
.ct-pot{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.ct-done{text-align:center;padding:14px 0 4px}
.ct-done-mark{width:44px;height:44px;margin:0 auto 14px;display:flex;align-items:center;
  justify-content:center;border-radius:50%;background:rgba(31,206,143,.14);color:var(--up);
  font-size:22px;font-weight:700}
@media (max-width:620px){.ct-backdrop{padding:12px;place-items:start center}}

/* ── the board while its data is in flight (lib/boardStore.ts) ── */
.avb-app .hm-loading{min-height:52vh;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;color:var(--dim);font:500 12px var(--mono);letter-spacing:.08em;text-transform:uppercase}
.avb-app .hm-loading p{margin:0}
.avb-app .hm-loading-ring{width:104px;height:104px;border-radius:50%;border:2px dashed var(--btc-bd);position:relative;animation:hm-spin 6s linear infinite}
.avb-app .hm-loading-ring::after{content:"";position:absolute;inset:26px;border-radius:50%;background:radial-gradient(circle at 40% 35%,#FFB347,var(--btc) 55%,#C46A05);opacity:.9}
@keyframes hm-spin{to{transform:rotate(360deg)}}

/* ── header additions: the search button and the watchlist count ── */
.avb-app .sh-search{display:inline-flex;align-items:center;gap:8px;margin-left:auto;align-self:center;height:30px;padding:0 10px 0 9px;
  background:var(--field-bg);border:1px solid var(--line-2);border-radius:6px;color:var(--dim);cursor:pointer;
  font-family:var(--mono);font-size:11px;letter-spacing:.06em}
.avb-app .sh-search:hover{color:var(--ink);border-color:var(--field-line)}
.avb-app .sh-kbd{font:500 9.5px var(--mono);border:1px solid var(--line-2);border-radius:3px;padding:1px 4px;color:var(--faint)}
.avb-app .sh-count{display:inline-block;margin-left:6px;min-width:16px;padding:1px 5px;border-radius:3px;background:var(--raise);color:var(--ink);font-size:10px;text-align:center}
.avb-app .sh-acct{display:flex;align-items:stretch;gap:2px}
.avb-app .sh-util{gap:8px}

/* ── the site footer ── */
.avb-app .ft{margin-top:auto;padding:22px var(--gutter) 26px;border-top:1px solid var(--line);color:var(--dim);font-size:13px}
.avb-app .ft-row{display:flex;flex-wrap:wrap;gap:12px 28px;align-items:center;justify-content:space-between}
.avb-app .ft-clock{display:flex;flex-wrap:wrap;gap:6px 8px;align-items:baseline;font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}
.avb-app .ft-v{color:var(--ink-2);letter-spacing:.02em;text-transform:none;font-size:12px}
.avb-app .ft-nav{display:flex;flex-wrap:wrap;gap:4px 18px;font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase}
.avb-app .ft-nav a,.avb-app .ft-nav button{color:var(--dim);background:none;border:0;padding:0;cursor:pointer;font:inherit;letter-spacing:inherit;text-transform:inherit}
.avb-app .ft-nav a:hover,.avb-app .ft-nav button:hover{color:var(--btc)}
.avb-app .ft-disc{margin:14px 0 0;max-width:78ch;color:var(--faint);font-size:12.5px;line-height:1.5}

/* ── the phone tab bar ── */
.avb-app .tb{display:none;position:fixed;left:0;right:0;bottom:0;z-index:45;grid-template-columns:repeat(5,1fr);height:58px;
  background:var(--glass);backdrop-filter:blur(10px);border-top:1px solid var(--line);padding-bottom:env(safe-area-inset-bottom)}
.avb-app .tb-tab{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;color:var(--dim);
  font-family:var(--mono);font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;text-decoration:none}
.avb-app .tb-tab.on{color:var(--btc)}
.avb-app .tb-tab svg{opacity:.85}

/* ── ⌘K ── */
.avb-app .ck-scrim{position:fixed;inset:0;z-index:80;background:var(--scrim);display:flex;align-items:flex-start;justify-content:center;padding:12vh 16px 16px}
.avb-app .ck{width:min(640px,100%);background:var(--panel);border:1px solid var(--line-2);border-radius:12px;box-shadow:0 30px 80px var(--shadow);overflow:hidden}
.avb-app .ck-in{display:flex;align-items:center;gap:10px;padding:12px 14px;border-bottom:1px solid var(--line);color:var(--dim)}
.avb-app .ck-in input{flex:1;background:transparent;border:0;outline:0;color:var(--ink);font:15px var(--sans)}
.avb-app .ck-in kbd{font:500 10px var(--mono);border:1px solid var(--line-2);border-radius:3px;padding:2px 5px;color:var(--faint)}
.avb-app .ck-list{list-style:none;margin:0;padding:6px;max-height:min(52vh,420px);overflow:auto}
.avb-app .ck-list li{display:grid;grid-template-columns:24px auto 1fr;gap:10px;align-items:center;padding:8px 10px;border-radius:6px;cursor:pointer;color:var(--ink-2)}
.avb-app .ck-list li.on{background:var(--raise);color:var(--ink)}
.avb-app .ck-logo{display:inline-flex;width:20px;height:20px}
.avb-app .ck-logo img,.avb-app .ck-logo svg,.avb-app .ck-logo span{width:20px!important;height:20px!important}
.avb-app .ck-dot{width:8px;height:8px;border-radius:50%;background:var(--btc);margin-left:6px}
.avb-app .ck-lab{font:600 13.5px var(--mono)}
.avb-app .ck-sub{color:var(--dim);font-size:12.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.avb-app .ck-none{color:var(--dim);padding:14px 10px;grid-template-columns:1fr}
.avb-app .ck-foot{display:flex;gap:16px;padding:8px 14px;border-top:1px solid var(--line);font:500 10px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}

/* ── the half-bullseye's side toggle (components/SplitBullseye.tsx, portrait only) ── */
/* The disc sits ON the chord and hangs into the bar: the SVG must not clip it, and the bar
   must not paint over it — so the bar's top 48px are transparent and inert. */
.avb-app .hm-split .hm-radial-svg{overflow:visible}
/* ── THE SIDE TOGGLE (portrait) ────────────────────────────────────────────────
   Two tabs over the half-bullseye: Up vs BTC and Down vs BTC. They replaced a scrollable
   strip of loser tiles — 746 coins in 52px of filmstrip — and the board they switch between
   is the SAME fan, so the buttons carry the only thing that differs: direction and count.
   ☢️ THE COLOUR IS THE STATE, AND THE UNSELECTED SIDE IS NOT GREY. Both keep their own hue
   so the pair reads as up/down at a glance; selection is carried by FILL and border weight,
   not by draining one of them, or the switch stops looking like two choices. */
/* ☢️ THE FOOT, NOT THE HEAD — the top of this board is already spoken for. In portrait the
   zoom cluster moves to top-left (globals.css ~3243) and the full-screen and camera buttons
   hold the top-right; a bar across the head landed under all three. The foot is the band the
   losers' strip used to occupy, so it is known to be clear, and it puts the switch directly
   under Bitcoin's own line — the axis the two buttons are choosing a side of. */
/* ☢️ THE TOP 48px ARE TRANSPARENT AND INERT, AND THAT IS NOT DECORATION — IT IS THE DISC.
   The medallion is drawn AT the origin, which sits 4px above this bar, and hangs BELOW it by
   MEDALLION_R x zoom — 41.6px at the portrait default. An opaque 46px bar buried the bottom
   37.6px of the disc: the "$78.9K" line and the "USD · <window>" line both live below the
   origin, so two of the readout's three lines simply vanished, and the bar swallowed every tap
   on the disc's lower half. The strip this replaced reserved the same head for the same reason
   (its comment is two rules up) and it must not be lost twice.
   ⚠️ pointer-events:none on the BOX, auto on the buttons — a transparent pixel that still eats
   the tap is the same bug wearing a different coat.
   ⚠️ The dashed border rides the box's TOP edge, 4px under the origin: that line IS Bitcoin's
   own level, which is what makes the disc read as sitting on it. */
.avb-app .sb-sides{position:absolute;bottom:0;left:0;right:0;height:100px;z-index:5;
  display:grid;grid-template-columns:1fr 1fr;gap:6px;padding:52px 8px 6px;
  pointer-events:none;
  background:linear-gradient(to bottom,transparent 0,transparent 48px,var(--panel) 48px);
  border-top:1px dashed var(--btc-bd)}
.avb-app .sb-side{pointer-events:auto;display:flex;align-items:center;justify-content:center;gap:6px;
  border-radius:8px;cursor:pointer;font-family:var(--mono);font-size:11.5px;font-weight:700;
  letter-spacing:.04em;text-transform:uppercase;
  /* 1.5px so the selected 2px does not resize the button and shunt its neighbour */
  border:1.5px solid currentColor;background:transparent;
  transition:background .14s ease,border-color .14s ease,color .14s ease}
.avb-app .sb-side--up{color:var(--up)}
.avb-app .sb-side--down{color:var(--down)}
/* The lit tab: its own colour becomes the ground and the ink goes to the panel behind it. */
.avb-app .sb-side.is-on{border-width:2px;color:var(--panel)}
.avb-app .sb-side--up.is-on{background:var(--up)}
.avb-app .sb-side--down.is-on{background:var(--down)}
.avb-app .sb-side:focus-visible{outline:2px solid var(--text);outline-offset:2px}
/* A side the filters emptied cannot be chosen — tapping it would give a board holding nothing
   but the medallion and no reason why. */
.avb-app .sb-side[disabled]{opacity:.4;cursor:not-allowed}
.avb-app .sb-side-arrow{font-size:13px;line-height:1}
.avb-app .sb-side-n{font-weight:500;opacity:.75;font-size:10px}
/* Below ~330px the count is the first thing to go — the direction is the reading. */
@media (max-width:340px){.avb-app .sb-side-n{display:none}}
/* the tab bar rule has to come after its base rule */
@media (max-width:640px){.avb-app .tb{display:grid}}

/* ── the Read strip (components/ReadStrip.tsx) ── */
.avb-app .rs{display:flex;flex-wrap:wrap;gap:10px 36px;align-items:flex-end;padding:12px 0 6px;width:100%}
.avb-app .rs-kpi{display:flex;flex-direction:column;gap:3px;min-width:0}
.avb-app .rs-k{font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint);white-space:nowrap}
.avb-app .rs-v{font-family:var(--mono);font-size:26px;font-weight:600;line-height:1;color:var(--ink);white-space:nowrap}
.avb-app .rs-v small{font-size:13px;font-weight:400;color:var(--dim);margin-left:4px}
/* The count is the coins in the side list. It keeps the small's size and only changes
   enough to read as something you can press. */
.avb-app .rs-count{font:inherit;color:var(--btc);background:none;border:0;padding:0;margin:0;cursor:pointer;text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px}
.avb-app .rs-count:hover{color:var(--ink)}
.avb-app .rs-count:focus-visible{outline:2px solid var(--btc);outline-offset:2px}
.avb-app .rs-v--btc{color:var(--btc)}
.avb-app .rs-v.pos{color:var(--up)} .avb-app .rs-v.neg{color:var(--down)}
.avb-app .rs-read{margin:0;font-family:var(--serif);font-style:italic;font-size:15px;line-height:1.45;color:var(--ink-2);max-width:60ch}

@media (max-width:640px){.avb-app .rs{gap:8px 12px;padding:8px 0 4px}.avb-app .rs-v{font-size:19px}.avb-app .rs-k{font-size:9px;white-space:normal}.avb-app .rs-read{font-size:14px}}
.avb-app .hm-caption{color:var(--faint);margin-right:14px}

/* ── the board's controls on a phone: two short rows, no captions (redesign spec §6.2) ── */
@media (max-width:640px){
  .avb-app .hm-searchrow,.avb-app .hm-live,.avb-app .hm-ctl-lbl{display:none}
  .avb-app .hm-controls{gap:8px}
  .avb-app .hm-controls .hm-ctl{width:100%;gap:0}
  /* Preset and Reset share one row: Reset is the way back from the Preset, not a row of its own. */
  .avb-app .hm-controls .hm-ctl--preset{width:auto;flex:1 1 auto}
  .avb-app .hm-controls .hm-ctl--preset .hm-cat,.avb-app .hm-controls .hm-ctl--preset .hm-cat-btn{width:100%}
  .avb-app .hm-controls .hm-resetctl{width:auto;flex:0 0 auto}
  .avb-app .hm-controls .hm-seg{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;width:100%;max-width:100%}
  .avb-app .hm-controls .hm-seg::-webkit-scrollbar{display:none}
  .avb-app .hm-controls .hm-segbtn{white-space:nowrap;flex:0 0 auto}
  .avb-app .hm-more-btn,.avb-app .hm-moved{flex:1 1 auto;justify-content:center}
  .avb-app .hm-zoom{bottom:auto;top:10px;left:10px;right:auto}
  .avb-app .hm-caption{display:none}
  .avb-app .pagehead-title{font-size:18px}
  .avb-app .rs-live{display:inline-block}
}
.avb-app .rs-live{display:none;align-self:center;margin-left:0;font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--up);vertical-align:middle}

/* ── under the board (components/BoardModules.tsx) ── */
.avb-app .bm{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr) minmax(0,1fr);gap:16px;padding:18px var(--gutter) 30px}
.avb-app .bm-mod{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:14px 16px;min-width:0}
.avb-app .bm-h{margin:0 0 10px;font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink);font-weight:600}
.avb-app .bm-h a{color:var(--ink)} .avb-app .bm-h a:hover{color:var(--btc)}
.avb-app .bm-hs{color:var(--faint);font-weight:500;letter-spacing:.08em}
.avb-app .bm-row{display:flex;flex-wrap:wrap;gap:6px}
.avb-app .bm-cell{display:grid;grid-template-columns:auto auto;grid-template-rows:auto auto;align-items:center;column-gap:7px;row-gap:1px;
  padding:7px 10px 7px 8px;border:0;border-radius:7px;cursor:pointer;font-family:var(--mono);text-align:left;min-width:0}
.avb-app .bm-cell:hover{filter:brightness(1.12)}
.avb-app .bm-logo{grid-row:1/3;grid-column:1;display:inline-flex;width:22px;height:22px}
.avb-app .bm-logo img,.avb-app .bm-logo span,.avb-app .bm-logo svg{width:22px!important;height:22px!important}
.avb-app .bm-sym{font-size:12px;font-weight:700;letter-spacing:.02em}
.avb-app .bm-pct{font-size:11px;font-weight:500;opacity:.92}
.avb-app .bm-sub{grid-column:2;font-size:9.5px;opacity:.75;letter-spacing:.04em}
.avb-app .bm-empty{margin:0;color:var(--dim);font-size:13.5px;line-height:1.5}
.avb-app .bm-empty a{color:var(--btc)}
.avb-app .bm-brief{margin:0 0 10px;font-family:var(--serif);font-style:italic;font-size:15px;line-height:1.5;color:var(--ink-2)}
.avb-app .bm-more{font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--btc)}
@media (max-width:1180px){.avb-app .bm{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.avb-app .bm-mod--brief{grid-column:1/-1}}
@media (max-width:640px){.avb-app .bm{grid-template-columns:minmax(0,1fr);padding:14px var(--gutter) 24px}}

/* ── the report, restructured (redesign spec §6.3) ── */
.avb-app .cp-head{position:sticky;top:var(--hdr);z-index:30;background:var(--bg);align-items:center;gap:18px 28px;padding:12px 0;margin-bottom:0;border-bottom:1px solid var(--line)}
.avb-app .cp-head .cp-h1{font-size:30px;margin:0}
.avb-app .cp-head .cp-name{margin:2px 0 0;display:flex;flex-wrap:wrap;gap:6px 10px;align-items:baseline}
.avb-app .cp-head .cp-tags{display:inline-flex;gap:6px}
.avb-app .cp-head .cp-tags a{font-family:var(--mono);font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--dim);border:1px solid var(--line-2);border-radius:4px;padding:2px 6px}
.avb-app .cp-head .cp-tags a:hover{color:var(--btc);border-color:var(--btc-bd)}
.avb-app .cp-head .cp-price{text-align:left;gap:6px 26px;margin-left:auto}
.avb-app .cp-head .cp-px{font-size:20px}
.avb-app .cp-acts{display:flex;gap:8px;align-items:center}
.avb-app .cp-alert{display:inline-flex;align-items:center;min-height:34px;padding:0 12px;border-radius:6px;cursor:pointer;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--btc);background:var(--btc-tint);border:1px solid var(--btc-bd)}
.avb-app .cp-alert:hover{background:rgba(247,147,26,.2)}
.avb-app .cp-alert.on{color:var(--up);background:var(--up-tint);border-color:var(--up-bd)}
.avb-app .cp-secnav{position:sticky;top:calc(var(--hdr) + 86px);z-index:29;display:flex;gap:4px 18px;overflow-x:auto;scrollbar-width:none;padding:8px 0;margin:0 0 18px;background:var(--bg);border-bottom:1px solid var(--line);
  font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase}
.avb-app .cp-secnav::-webkit-scrollbar{display:none}
.avb-app .cp-secnav a{color:var(--dim);white-space:nowrap;padding:2px 0;border-bottom:2px solid transparent}
.avb-app .cp-secnav a.on{color:var(--btc);border-bottom-color:var(--btc)}
.avb-app .cp-verdict{align-items:center}
.avb-app .cp-vsent{margin:0 0 14px;font-family:var(--serif);font-style:italic;font-size:21px;line-height:1.45;color:var(--ink);display:flex;gap:14px;align-items:flex-start}
.avb-app .cp-vsent .cp-vscore{flex:0 0 auto;font-family:var(--mono);font-style:normal;font-weight:700;font-size:22px;padding:2px 10px;border-radius:6px;background:var(--raise)}
.avb-app .cp-vsent .cp-vscore.pos{color:var(--up)} .avb-app .cp-vsent .cp-vscore.neg{color:var(--down)} .avb-app .cp-vsent .cp-vscore.flat{color:var(--base)}
.avb-app .cp-segs{list-style:none;display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:3px;margin:0;padding:0}
.avb-app .cp-segs li{display:flex;flex-direction:column;align-items:center;gap:1px;padding:6px 2px;border-radius:4px;font-family:var(--mono);background:var(--raise);color:var(--dim)}
.avb-app .cp-segs .pl{font-size:9px;letter-spacing:.1em}
.avb-app .cp-segs .pv{font-size:12px;font-weight:700}
.avb-app .cp-segs li.won{background:rgba(43,223,95,.22);color:var(--up)}
.avb-app .cp-segs li.lost{background:rgba(241,51,52,.22);color:var(--down-ink)}
.avb-app .cp-segs li.flat{background:rgba(138,148,166,.18);color:var(--ink-2)}
.avb-app .cp-segs li.blank{opacity:.45}
.avb-app .cp-segkey{margin:8px 0 0;font-family:var(--mono);font-size:10px;letter-spacing:.06em;color:var(--faint)}
.avb-app .cp-vstake{flex:0 1 300px;background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:14px 16px}
.avb-app .cp-vstake-k{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);margin-bottom:8px}
.avb-app .cp-vstake-row{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.avb-app .cp-vstake-row div{display:flex;flex-direction:column;gap:2px}
.avb-app .cp-vstake-row span{font-family:var(--mono);font-size:10px;color:var(--faint)}
.avb-app .cp-vstake-row b{font-family:var(--mono);font-size:17px;font-weight:600}
.avb-app .cp-vstake-row b.pos{color:var(--up)} .avb-app .cp-vstake-row b.neg{color:var(--down)}
.avb-app .cp-hz{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.avb-app .cp-details{margin:0 0 34px;border:1px solid var(--line);border-radius:10px;background:var(--panel)}
.avb-app .cp-details summary{cursor:pointer;padding:14px 18px;display:flex;flex-wrap:wrap;gap:6px 16px;align-items:baseline;list-style:none}
.avb-app .cp-details summary::-webkit-details-marker{display:none}
.avb-app .cp-details summary h2{margin:0;font-size:18px}
.avb-app .cp-details summary h2::before{content:"▸";display:inline-block;margin-right:10px;color:var(--btc);transition:transform .15s}
.avb-app .cp-details[open] summary h2::before{transform:rotate(90deg)}
.avb-app .cp-details-hint{color:var(--dim);font-size:13px}
.avb-app .cp-details>.cp-sec{padding:0 18px 8px}
.avb-app .cp-peers{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:8px}
.avb-app .cp-peers li a{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:baseline;padding:10px 12px;border-radius:8px;border:0;font-family:var(--mono)}
.avb-app .cp-peers .psym{font-weight:700;font-size:13px} .avb-app .cp-peers .pnm{font-size:11px;opacity:.8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .avb-app .cp-peers .pv{font-weight:600;font-size:12px}
@media (max-width:900px){
  .avb-app .cp-head{position:static;padding:10px 0}
  .avb-app .cp-head .cp-price{margin-left:0;grid-template-columns:repeat(2,auto)}
  .avb-app .cp-secnav{top:0}
  .avb-app .cp-vsent{font-size:17px}
}
@media (max-width:640px){
  .avb-app .cp-hz{grid-template-columns:minmax(0,1fr)}
  .avb-app .cp-segs .pv{font-size:10.5px}
  .avb-app .cp-vstake{flex-basis:100%}
}

/* ── macro: the grouped rail and the stale stamp ── */
.avb-app .mc-group{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap;padding-right:14px;margin-right:6px;border-right:1px solid var(--line)}
.avb-app .mc-group:last-of-type{border-right:0}
.avb-app .mc-group-lbl{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint);margin-right:2px}
.avb-app .mc-asof.stale{color:var(--base)}
.avb-app .rs--macro{padding:10px 0 4px}

/* ── the Brief (components/brief/BriefView.tsx) ── */
.avb-app .bf{max-width:760px;margin:0 auto;padding:28px var(--gutter) 60px}
.avb-app .bf-eyebrow{margin:0 0 12px;font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--btc)}
.avb-app .bf-h1{margin:0 0 14px;font-size:30px;line-height:1.15;font-weight:700;letter-spacing:-.01em;text-wrap:balance}
.avb-app .bf-lede{margin:0 0 20px;font-family:var(--serif);font-style:italic;font-size:18px;line-height:1.5;color:var(--ink-2)}
.avb-app .bf-kpis{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-bottom:28px}
.avb-app .bf-kpis div{background:var(--panel);border:1px solid var(--line);border-radius:8px;padding:12px 14px;display:flex;flex-direction:column;gap:4px}
.avb-app .bf-kpis span{font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.avb-app .bf-kpis b{font-family:var(--mono);font-size:22px;font-weight:600}
.avb-app .bf-kpis b small{font-size:12px;color:var(--dim);font-weight:400}
.avb-app .bf-kpis b.btc{color:var(--btc)} .avb-app .bf-kpis b.pos{color:var(--up)} .avb-app .bf-kpis b.neg{color:var(--down)}
.avb-app .bf-sec{margin:0 0 26px;padding-top:18px;border-top:1px solid var(--line)}
.avb-app .bf-sec h2{margin:0 0 10px;font-size:17px}
.avb-app .bf-sec h2 small{font-weight:400;font-size:12.5px;color:var(--dim);margin-left:6px}
.avb-app .bf-sec p{margin:0 0 8px;line-height:1.55;color:var(--ink-2)}
.avb-app .bf-sec a{color:var(--btc)}
.avb-app .bf-muted{color:var(--faint)!important}
.avb-app .bf-mv2{display:grid;grid-template-columns:1fr 1fr;gap:18px}
.avb-app .bf-movers h3{margin:0 0 6px;font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--dim)}
.avb-app .bf-movers ul,.avb-app .bf-bases{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}
.avb-app .bf-movers li a{display:grid;grid-template-columns:22px auto auto 1fr;gap:10px;align-items:center;padding:7px 10px;border-radius:6px;background:var(--panel);border:1px solid var(--line);font-family:var(--mono);color:var(--ink)}
.avb-app .bf-movers li a b{font-size:13px} .avb-app .bf-movers li a span{font-size:12.5px} .avb-app .bf-movers li a small{font-size:10.5px;color:var(--dim);text-align:right}
.avb-app .bf-movers .pos{color:var(--up)} .avb-app .bf-movers .neg{color:var(--down)}
.avb-app .bf-logo{display:inline-flex;width:22px;height:22px}
.avb-app .bf-logo img,.avb-app .bf-logo span,.avb-app .bf-logo svg{width:22px!important;height:22px!important}
.avb-app .bf-bases li a{display:flex;gap:10px;align-items:baseline;padding:7px 10px;border-radius:6px;background:var(--panel);border:1px solid var(--line);color:var(--ink)}
.avb-app .bf-bases li a b{font-family:var(--mono);font-size:13px} .avb-app .bf-bases li a span{font-size:12.5px;color:var(--dim)}
.avb-app .bf-nav{display:flex;justify-content:space-between;gap:12px;margin:26px 0 12px;font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase}
.avb-app .bf-nav a{color:var(--btc)}
.avb-app .bf-foot{font-size:12.5px;color:var(--faint)} .avb-app .bf-foot a{color:var(--dim)}
@media (max-width:640px){.avb-app .bf-kpis{grid-template-columns:minmax(0,1fr)}.avb-app .bf-mv2{grid-template-columns:minmax(0,1fr)}.avb-app .bf-h1{font-size:24px}}

/* ── /watchlist ── */
.avb-app .wl{max-width:1100px;margin:0 auto;padding:22px var(--gutter) 60px}
.avb-app .wl-head{margin-bottom:16px}
.avb-app .wl-sub{margin:4px 0 0;color:var(--dim);font-size:13.5px} .avb-app .wl-sub a{color:var(--btc)}
.avb-app .wl-empty{color:var(--dim);line-height:1.55} .avb-app .wl-empty a{color:var(--btc)}
.avb-app .wl-ctl{display:flex;gap:10px;align-items:center;margin:8px 0 12px}
.avb-app .wl-cells{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:18px}
.avb-app .wl-cell{display:grid;grid-template-columns:auto auto;column-gap:8px;align-items:center;padding:8px 12px 8px 9px;border-radius:8px;font-family:var(--mono)}
.avb-app .wl-cell b{font-size:13px} .avb-app .wl-cell span{font-size:11.5px;opacity:.92;grid-column:2}
.avb-app .wl-logo{grid-row:1/3;grid-column:1;display:inline-flex;width:24px;height:24px}
.avb-app .wl-logo img,.avb-app .wl-logo span,.avb-app .wl-logo svg{width:24px!important;height:24px!important}
.avb-app .tblwrap{overflow-x:auto;border:1px solid var(--line);border-radius:10px;background:var(--panel)}
.avb-app .wl-tbl{margin-bottom:30px}
.avb-app .wl-tbl th[scope=row] a{color:var(--ink)} .avb-app .wl-tbl th[scope=row] small{color:var(--dim);font-weight:400;margin-left:6px}
.avb-app .wl-tbl td.pos{color:var(--up)} .avb-app .wl-tbl td.neg{color:var(--down)}
.avb-app .wl-x{background:none;border:1px solid var(--line-2);color:var(--dim);border-radius:4px;width:26px;height:26px;cursor:pointer;font-size:15px;line-height:1}
.avb-app .wl-x:hover{color:var(--down);border-color:var(--down-bd)}
.avb-app .wl-rules{padding-top:22px;border-top:1px solid var(--line)}
.avb-app .wl-rules h2{margin:0 0 12px;font-size:20px} .avb-app .wl-rules h2 small{font-size:12.5px;color:var(--dim);font-weight:400;margin-left:6px}
.avb-app .wl-form{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end;margin-bottom:12px}
.avb-app .wl-form label{display:flex;flex-direction:column;gap:4px;font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.avb-app .wl-form input,.avb-app .wl-form select{background:var(--field-bg);border:1px solid var(--field-line);color:var(--ink);border-radius:6px;padding:8px 10px;font:13px var(--mono);min-width:150px}
.avb-app .wl-note{color:var(--dim);font-size:13px} .avb-app .wl-note a{color:var(--btc)}
.avb-app .wl-rulelist{list-style:none;margin:0 0 12px;padding:0;display:flex;flex-direction:column;gap:6px}
.avb-app .wl-rulelist li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 12px;align-items:center;padding:10px 12px;border-radius:8px;background:var(--panel);border:1px solid var(--line)}
.avb-app .wl-rulelist li.fired{border-color:var(--base-bd);background:var(--base-tint)}
.avb-app .wl-rtext{font-size:14px;color:var(--ink)} .avb-app .wl-rstate{grid-column:1;font-family:var(--mono);font-size:11px;color:var(--dim)}
.avb-app .wl-rulelist li.fired .wl-rstate{color:var(--base)}
.avb-app .wl-rulelist .wl-x{grid-column:2;grid-row:1/3}
.avb-app .wl-foot{color:var(--faint);font-size:12.5px;line-height:1.5;max-width:70ch} .avb-app .wl-foot a{color:var(--dim)}

/* ── /reports index ── */
.avb-app .ri{max-width:1100px;margin:0 auto;padding:22px var(--gutter) 60px}
.avb-app .ri-sub{margin:4px 0 14px;color:var(--dim);font-size:13.5px}
.avb-app .ri-ctl{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;margin-bottom:12px}
.avb-app .ri-q{background:var(--field-bg);border:1px solid var(--field-line);color:var(--ink);border-radius:6px;padding:8px 12px;font:13.5px var(--mono);min-width:240px}
.avb-app .ri-chk{display:inline-flex;gap:6px;align-items:center;font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--dim)}
.avb-app .ri-chk input{accent-color:var(--btc)}
.avb-app .ri-tbl th[scope=row] a{display:inline-flex;align-items:center;gap:8px;color:var(--ink)}
.avb-app .ri-tbl th[scope=row] small{color:var(--dim);font-weight:400}
.avb-app .ri-logo{display:inline-flex;width:20px;height:20px}
.avb-app .ri-logo img,.avb-app .ri-logo span,.avb-app .ri-logo svg{width:20px!important;height:20px!important}
.avb-app .ri-n{color:var(--faint);width:44px}
.avb-app .ri-tbl td.pos{color:var(--up)} .avb-app .ri-tbl td.neg{color:var(--down)}
.avb-app .ri-base{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--base);border:1px solid var(--base-bd);border-radius:3px;padding:1px 5px}
.avb-app .ri-more{margin:14px auto;display:block}
.avb-app .ri-foot{color:var(--faint);font-size:12.5px;max-width:70ch}

/* ── /membership, /methodology, /status ── */
.avb-app .mb,.avb-app .md,.avb-app .st{max-width:820px;margin:0 auto;padding:28px var(--gutter) 60px}
.avb-app .mb-h1{margin:0 0 12px;font-size:32px;line-height:1.15;font-weight:700;letter-spacing:-.01em;text-wrap:balance}
.avb-app .mb-lede{margin:0 0 26px;font-family:var(--serif);font-style:italic;font-size:18px;line-height:1.5;color:var(--ink-2);max-width:62ch}
.avb-app .mb-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:34px}
.avb-app .mb-plan{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:20px 22px;display:flex;flex-direction:column}
.avb-app .mb-plan--member{border-color:var(--btc-bd);background:linear-gradient(180deg,rgba(247,147,26,.06),transparent 45%),var(--panel)}
.avb-app .mb-plan h2{margin:0 0 12px;font-size:20px;display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.avb-app .mb-plan h2 span{font-family:var(--mono);font-size:12px;color:var(--dim);font-weight:500}
.avb-app .mb-plan ul{margin:0 0 18px;padding-left:18px;color:var(--ink-2);line-height:1.6;flex:1}
.avb-app .mb-cta{display:inline-flex;justify-content:center;align-items:center;min-height:40px;padding:0 16px;border-radius:7px;font-family:var(--mono);font-size:11.5px;letter-spacing:.08em;text-transform:uppercase}
.avb-app .mb-cta--ghost{border:1px solid var(--line-2);color:var(--ink)}
.avb-app .mb-cta--soon{border:1px dashed var(--btc-bd);color:var(--btc);cursor:default}
.avb-app .mb-fine{margin:10px 0 0;font-size:12px;color:var(--faint)}
.avb-app .mb-faq h2,.avb-app .md h2{font-size:19px;margin:26px 0 8px}
.avb-app .mb-faq dt{font-weight:600;margin-top:12px} .avb-app .mb-faq dd{margin:4px 0 0;color:var(--ink-2);line-height:1.55}
.avb-app .mb-faq a,.avb-app .md a{color:var(--btc)}
.avb-app .md p{color:var(--ink-2);line-height:1.6;max-width:70ch}
.avb-app .md code{font-family:var(--mono);font-size:.92em;background:var(--raise);padding:1px 5px;border-radius:4px}
.avb-app .st-row{display:grid;grid-template-columns:200px 1fr;gap:12px;margin:0;padding:12px 0;border-bottom:1px solid var(--line)}
.avb-app .st-row dt{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.avb-app .st-row dd{margin:0;color:var(--ink-2)} .avb-app .st-row dd.ok{color:var(--up)} .avb-app .st-row dd.bad{color:var(--base)}
.avb-app .st-row code{font-family:var(--mono);font-size:12px}
@media (max-width:640px){.avb-app .mb-grid{grid-template-columns:minmax(0,1fr)}.avb-app .st-row{grid-template-columns:minmax(0,1fr)}}
.avb-app .wl-rulelist li.wl-empty{display:block;color:var(--dim)}
@media (max-width:640px){
  .avb-app .hm-more .hm-ctl-lbl{display:block;margin-bottom:2px}
  .avb-app .hm-more{bottom:58px;max-height:calc(100vh - 58px - 80px)}
}

/* ── the side list: the ranked table docked on the right of the board. Breadth opens it. ── */
/* ☢️ NOWRAP, SAID OUTRIGHT: the list must never wrap under the chart when the window narrows —
   a toolbar rule that once shared this class name did exactly that (2026-10-07). Below 901px the
   list is hidden instead (lib/usePortrait SIDE_LIST_MIN_W). tests/boardRow.test.ts pins it. */
.avb-app .hm-row{display:flex;flex-wrap:nowrap;align-items:stretch;min-width:0}
.avb-app .hm-side{order:2;position:relative;flex:0 0 auto;align-self:flex-start;height:var(--hm-side-h,320px);width:26px;display:flex;background:var(--panel);border-left:1px solid var(--line);border-bottom:1px solid var(--line);margin-right:var(--gutter);transition:width .18s ease}
.avb-app .hm-row.side-open .hm-side{width:var(--hm-side-w,min(548px,44vw))}
/* The "of N" count lights the list it counts, long enough to find and gone before it nags. */
.avb-app .hm-side.is-pointed{animation:hm-point 1.2s ease}
@keyframes hm-point{0%{box-shadow:0 0 0 2px var(--btc),inset 0 0 0 1px var(--btc)}100%{box-shadow:0 0 0 2px transparent,inset 0 0 0 1px transparent}}
@media (prefers-reduced-motion:reduce){.avb-app .hm-side.is-pointed{animation:none;box-shadow:0 0 0 2px var(--btc)}}
.avb-app .hm-row.is-resizing .hm-side{transition:none}
.avb-app .hm-row.is-resizing{user-select:none;cursor:col-resize}
/* the grip: an 8px strip astride the list's left edge, the seam with the board */
.avb-app .hm-side-grip{position:absolute;top:0;bottom:0;left:-4px;width:8px;z-index:4;cursor:col-resize;touch-action:none}
.avb-app .hm-side-grip::after{content:"";position:absolute;top:0;bottom:0;left:3px;width:2px;background:transparent;transition:background .12s ease}
.avb-app .hm-side-grip:hover::after,.avb-app .hm-side-grip:focus-visible::after,.avb-app .hm-row.is-resizing .hm-side-grip::after{background:var(--btc)}
.avb-app .hm-side-grip:focus-visible{outline:none}
.avb-app .hm-side-tab{position:absolute;right:0;top:0;bottom:0;width:26px;z-index:3;border:0;border-left:1px solid var(--line);border-right:1px solid var(--line);background:var(--panel);color:var(--dim);cursor:pointer;
  display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:10px;padding-top:12px;font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase}
.avb-app .hm-side-tab:hover{color:var(--ink);background:var(--raise)}
.avb-app .hm-side-lbl{writing-mode:vertical-rl;transform:rotate(180deg)}
.avb-app .hm-side-arrow{font-size:12px;color:var(--btc)}
.avb-app .hm-side-body{position:absolute;left:0;right:26px;top:0;bottom:0;overflow:auto;min-width:0}
.avb-app .hm-side-main{order:1;flex:1 1 auto;min-width:0;display:flex;flex-direction:column}
/* The tab IS the board's right edge: the board's own right gutter would leave a gap beside it. */
.avb-app .hm-side-main .avb-heatmap{height:var(--hm-panel-h);padding-right:0}
.avb-app .rk--compact{border-top:0;padding-inline:0}
.avb-app .rk--compact .rk-head{display:none}
.avb-app .rk--compact .rk-name,.avb-app .rk--compact .rk-trend,.avb-app .rk--compact .rk-table th.rk-trend{display:none}
.avb-app .rk--compact .rk-table{font-size:11.5px}
.avb-app .rk--compact .rk-table th,.avb-app .rk--compact .rk-table td{padding:6px 6px}
.avb-app .rk--compact .rk-table thead th{position:sticky;top:0;background:var(--panel);z-index:2}
.avb-app .rk--compact .rk-scroll{overflow:visible}
@media (max-width:900px){.avb-app .hm-side{display:none}}
/* compact side list: nine columns in ~500px, like the mock */
.avb-app .rk--compact .rk-table{font-size:10.5px;table-layout:auto}
.avb-app .rk--compact .rk-table th.rk-coin,.avb-app .rk--compact .rk-table td.rk-coin{min-width:0;width:auto}
.avb-app .rk--compact .rk-coin-in{gap:5px}
.avb-app .rk--compact .rk-coin-in .ico{width:16px;height:16px}
.avb-app .rk--compact .rk-sym{letter-spacing:.02em}
.avb-app .rk--compact .rk-table th,.avb-app .rk--compact .rk-table td{padding:5px 4px;white-space:nowrap}
.avb-app .rk--compact .rk-table th.rk-num,.avb-app .rk--compact .rk-table td.rk-num{padding-left:6px}
.avb-app .rk--compact .rk-table td.rk-w,.avb-app .rk--compact .rk-table th.rk-w{text-align:right}
.avb-app .rk--compact .rk-more{padding:8px}
.avb-app .hm-side-body{scrollbar-width:thin}

/* The bar's two rows (components/HeatmapControls): row 1 steers, row 2 measures. Each wraps on
   its own and stays left-aligned — the old single run pushed Colour to the far right on a half
   row. The basket summary closes row 1.
   ☢️ NOT `.hm-row`: that name is the board + side-list row below, and this rule's wrap on it let
   the ranked list drop under the chart on a narrower window (Kevin, 2026-10-07). */
.avb-app .hm-tbrow{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;width:100%;min-width:0}
@media (max-width:640px){.avb-app .hm-tbrow{gap:8px}}

/* the scheme buttons carry a five-cell swatch of their own ramp: down → neutral → up */
.avb-app .hm-swatchbtn{display:inline-flex;align-items:center;gap:7px}
.avb-app .hm-swatch{display:inline-flex;gap:1px;height:10px;border-radius:2px;overflow:hidden;background:var(--hm-gap);padding:1px;opacity:.72}
.avb-app .hm-swatch i{display:block;width:6px;height:100%}
.avb-app .hm-swatchbtn:hover .hm-swatch,.avb-app .hm-swatchbtn.on .hm-swatch{opacity:1}

/* THE THEME SWITCH — one icon button beside Search: a sun on the dark site, a moon on the
   light one (it shows what you get, like the scheme swatches). Same height and border as the
   search field so the two read as one utility group. */
.avb-app .sh-theme{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;align-self:center;margin-left:6px;padding:0;
  background:var(--field-bg);border:1px solid var(--line);border-radius:6px;color:var(--dim);cursor:pointer}
.avb-app .sh-theme:hover{color:var(--ink);border-color:var(--field-line)}
.avb-app .sh-theme:focus-visible{outline:2px solid var(--btc);outline-offset:2px}
.avb-app .sh-theme + .sh-acct{margin-left:4px}

/* the mark, by theme: white letters on dark, ink letters on light (see SiteHeader.tsx) */
.avb-app .sh-logo--light{display:none}
:root[data-theme="light"] .avb-app .sh-logo--dark{display:none}
:root[data-theme="light"] .avb-app .sh-logo--light{display:block}

/* THE READ STRIP SITS BESIDE THE HEADLINE, NOT UNDER IT (Kevin, 2026-09-08). Every line
   above the board is a line the disc does not get: the three KPIs share the headline's row,
   right-aligned, and the controls run takes the whole next row. Below 900px the head is a
   column (see above) and the strip falls back to its own full-width row. */
.avb-app .hm-head .rs{width:auto;flex:0 1 auto;margin-left:auto;padding:0;gap:6px 26px;align-items:flex-end;align-self:center}
.avb-app .hm-head .rs-v{font-size:22px}
.avb-app .hm-head .hm-head-copy{align-self:center}
.avb-app .hm-head .hm-controls{width:100%}
@media (max-width:900px){.avb-app .hm-head .rs{width:100%;margin-left:0;padding:4px 0 0}}

/* the member price, veiled until it is set: blurred and unselectable, still visibly a price */
.avb-app .mb-price--veiled{filter:blur(6px);user-select:none;pointer-events:none;opacity:.85}

/* THE FLYOUT — the coin card, out of the list's left edge, level with the picked row.
   Absolute in the aside, above the board, no backdrop: the board behind it is live. */
.avb-app .hm-flyout{position:absolute;right:calc(100% + 8px);z-index:7;width:min(420px,46vw);max-height:calc(var(--hm-side-h,320px) - 16px);overflow:auto;border-radius:16px;box-shadow:0 18px 50px var(--shadow),0 0 0 1px var(--line);animation:hm-fly .16s cubic-bezier(.2,.8,.2,1)}
/* ☢️ The SCROLLER IS THE FLYOUT, NOT THE CARD: the snapshot measures the card's own box
   (lib/snapshotDom.ts) and would export only the visible slice of a card that scrolls. */
.avb-app .hm-flyout .hm-sheet{width:100%;animation:none;box-shadow:none}
@keyframes hm-fly{from{opacity:0;transform:translateX(8px)}to{opacity:1;transform:none}}
/* the picked row, quietly marked: the accent as a bar on the edge nearest the card and a faint wash */
.avb-app .rk-row.is-sel{background:var(--btc-tint);box-shadow:inset 3px 0 0 var(--btc)}
.avb-app .rk-row.is-sel td{color:var(--ink)}
@media (prefers-reduced-motion:reduce){.avb-app .hm-flyout{animation:none}}

/* the sort glyph on the lit heading: best first ▾, worst first ▴ */
.avb-app .rk-table th.rk-w .rk-sort{margin-left:3px;font-size:10px;opacity:.9}

/* ═══ A MACRO PAIR'S OWN PAGE (/macro/<slug>) ══════════════════════════════════════════════
   Built on the coin report's bones (.cp container, .cp-sec, .cp-stats, .cp-table) so the two
   detail pages read as one family; only what differs is named here. */
.avb-app .mp-head{display:flex;flex-wrap:wrap;align-items:flex-end;gap:16px 32px;padding:14px 0 16px;border-bottom:1px solid var(--line)}
.avb-app .mp-idcol{flex:1 1 320px;min-width:0}
.avb-app .mp-h1{margin:0;font-family:var(--mono);font-size:clamp(26px,4vw,40px);font-weight:700;letter-spacing:-.01em;color:var(--ink);
  display:flex;align-items:center;gap:12px;line-height:1.1}
.avb-app .mp-h1 i{width:12px;height:12px;border-radius:50%;flex:none}
.avb-app .mp-desc{margin:6px 0 0;font-size:14.5px;line-height:1.5;color:var(--dim);max-width:70ch}
.avb-app .mp-formula{margin:5px 0 0;font-family:var(--mono);font-size:11.5px;letter-spacing:.04em;color:var(--faint)}
.avb-app .mp-now{display:flex;flex-direction:column;gap:3px;font-family:var(--mono);flex:none}
.avb-app .mp-now-k{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint)}
.avb-app .mp-now-v{font-size:clamp(24px,3.4vw,34px);font-weight:700;color:var(--ink);line-height:1.05;font-variant-numeric:tabular-nums}
.avb-app .mp-now-c{font-size:14px;font-weight:700}
.avb-app .mp-now-c small{font-weight:600;font-size:10px;letter-spacing:.1em;color:var(--faint)}
/* The open month under the close: "59.49% · Sep so far". */
.avb-app .mp-now-live{font-size:13px;font-weight:700;color:var(--btc);margin-top:2px}
.avb-app .mp-now-live small{font-weight:600;font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.avb-app .mp-nav{display:flex;gap:8px;flex:none;font-family:var(--mono);font-size:12px;font-weight:700}
.avb-app .mp-nav a{color:var(--dim);text-decoration:none;padding:7px 11px;border:1px solid var(--line);border-radius:var(--r);background:var(--panel-2);white-space:nowrap}
.avb-app .mp-nav a:hover{color:var(--ink);border-color:var(--btc-bd)}
.avb-app .mp-read{margin:16px 0 14px;font-family:var(--serif);font-style:italic;font-size:16px;line-height:1.55;color:var(--ink);max-width:90ch}
/* The chart: controls on the dashboard's segmented buttons, a readout where a lane label would be. */
.avb-app .mp-chartctl{margin-bottom:10px}
.avb-app .mp-readout{display:flex;align-items:baseline;gap:10px;font-family:var(--mono);flex-wrap:wrap;min-height:30px}
.avb-app .mp-readout b{font-size:20px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.avb-app .mp-readout span{font-size:13px;font-weight:700}
.avb-app .mp-readout em{font-style:normal;font-size:11.5px;color:var(--faint)}
.avb-app .mp-chartwrap{position:relative;width:100%;min-width:0;height:clamp(300px,52vh,560px);
  border:1px solid var(--line);border-radius:13px;background:var(--panel);
  touch-action:pan-y;contain:inline-size;overflow:hidden}
.avb-app .mp-legs{margin-top:12px;border:1px solid var(--line);border-radius:9px;background:var(--panel);overflow-x:auto}
.avb-app .mp-legdot{display:inline-block;width:8px;height:8px;border-radius:50%;vertical-align:middle;margin-right:2px}
.avb-app .mp-legdot.up{background:var(--up)} .avb-app .mp-legdot.down{background:var(--down)}
.avb-app .mp .cp-table th.n,.avb-app .mp .cp-table td.n{text-align:right;font-variant-numeric:tabular-nums}
.avb-app .mp .pos{color:var(--up)} .avb-app .mp .neg{color:var(--down)}
.avb-app .mp-stats+.mp-stats{margin-top:10px}
.avb-app .mp-stats dd small{font-size:11px;font-weight:600;color:var(--faint);margin-left:2px}
.avb-app .mp-sub{font-family:var(--mono);font-size:11px;line-height:1.45;color:var(--faint)}
.avb-app .mp-sub b{font-weight:700}
.avb-app .mp-role{display:inline-block;font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint);min-width:86px}
.avb-app .mp-related{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:10px}
.avb-app .mp-relcard{display:flex;flex-direction:column;gap:6px;padding:13px 15px;border:1px solid var(--line);border-radius:11px;
  background:var(--panel);text-decoration:none;color:inherit;font-family:var(--mono);transition:border-color .12s}
.avb-app .mp-relcard:hover{border-color:var(--btc-bd)}
.avb-app .mp-relnm{display:flex;align-items:center;gap:7px;font-size:12.5px;font-weight:700;color:var(--ink)}
.avb-app .mp-relnm i{width:8px;height:8px;border-radius:50%;flex:none}
.avb-app .mp-relv{font-size:17px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.avb-app .mp-relc{font-size:11.5px;font-weight:700}
.avb-app .mp-all{display:flex;flex-wrap:wrap;gap:8px}
.avb-app .mp-all a,.avb-app .mp-all span{display:inline-flex;align-items:center;gap:7px;padding:7px 12px;border:1px solid var(--line);border-radius:100px;
  background:var(--panel);font-family:var(--mono);font-size:12px;font-weight:700;color:var(--dim);text-decoration:none}
.avb-app .mp-all a:hover{color:var(--ink);border-color:var(--btc-bd)}
.avb-app .mp-all span.on{color:var(--ink);border-color:var(--btc-bd);background:var(--raise)}
.avb-app .mp-all i{width:8px;height:8px;border-radius:50%;flex:none}
.avb-app .mp-method{margin-top:34px}
@media (max-width:760px){
  .avb-app .mp-head{align-items:flex-start}
  .avb-app .mp-nav{width:100%;justify-content:space-between}
  .avb-app .mp-chartwrap{height:clamp(260px,min(52vh,90vw),420px)}
  .avb-app .mp-role{display:block;min-width:0}
}
@media (pointer: coarse){.avb-app .mp-nav a,.avb-app .mp-all a,.avb-app .mp-all span{min-height:40px}}

/* ── BREADTH — the header's "alts beating BTC", charted day by day ─────────────────────────
   A board view like the other four, so it lives in the same panel and borrows the board's own
   segmented controls (.hm-ctl / .hm-seg). Only what is new to it is declared here. */
.avb-app .br{display:flex;flex-direction:column;gap:12px;width:100%;min-width:0;padding:16px 18px 12px;
  border-radius:var(--r);background:var(--panel);box-sizing:border-box}
.avb-app .br-head{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;flex-wrap:wrap}
.avb-app .br-read{display:flex;flex-direction:column;gap:2px;min-width:0}
.avb-app .br-k{font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-2)}
.avb-app .br-v{font-family:var(--mono);font-weight:700;font-size:clamp(30px,4.2vw,44px);line-height:1.05;color:var(--text);
  font-variant-numeric:tabular-nums}
.avb-app .br-v small{margin-left:10px;font-size:13px;font-weight:500;letter-spacing:.04em;color:var(--dim)}
.avb-app .br-stats{display:flex;gap:26px;margin:0}
.avb-app .br-stats div{display:flex;flex-direction:column;gap:2px}
.avb-app .br-stats dt{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--dim)}
.avb-app .br-stats dd{margin:0;font-family:var(--mono);font-size:15px;font-weight:600;color:var(--text);font-variant-numeric:tabular-nums}
.avb-app .br-stats dd small{margin-left:4px;font-size:11px;font-weight:500;color:var(--dim)}
.avb-app .br-custom{display:inline-flex;align-items:center;gap:2px;padding:0 8px;font-family:var(--mono);font-size:12px;color:var(--dim)}
.avb-app .br-custom input{width:52px;padding:4px 2px;border:0;border-bottom:1px solid var(--line);background:transparent;
  color:var(--text);font:inherit;text-align:right;font-variant-numeric:tabular-nums;-moz-appearance:textfield}
.avb-app .br-custom input::-webkit-outer-spin-button,.avb-app .br-custom input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.avb-app .br-custom input:focus{outline:0;border-bottom-color:var(--amber)}
/* The plot takes whatever the panel's floor leaves, and never less than a readable chart — the
   panel grows rather than the plot shrinking (see the minHeight note in Breadth.tsx). */
.avb-app .br-plot{position:relative;flex:1 1 280px;min-height:280px}
.avb-app .br-chart{position:absolute;inset:0}
.avb-app .br-shot{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;opacity:0}
.avb-app .br-note{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;margin:0;padding:0 12%;
  text-align:center;font-size:13px;line-height:1.55;color:var(--dim);pointer-events:none}
.avb-app .br-foot{margin:0;font-size:11.5px;line-height:1.5;color:var(--dim)}
.avb-app .br-foot em{font-style:normal;color:var(--ink-2)}
@media (max-width:760px){
  .avb-app .br{padding:12px 12px 10px}
  .avb-app .br-stats{gap:16px}
}

/* ── ALTCOIN SUPER METRIC (/macro/super-metric, 2026-10-13) ─────────────────────────────────────
   Heat is ONE warm ramp (Warming a wash, Hot the full tint); Cold is a grey, Neutral nothing. The
   component grid uses the same accent, opacity = rank. */
.avb-app .sm{--sm-heat:#FF6A2B;--sm-cold:rgba(138,148,162,.10)}
:root[data-theme="light"] .avb-app .sm{--sm-heat:#C2410C;--sm-cold:rgba(94,104,117,.10)}
.avb-app .sm-now{display:grid;grid-template-columns:auto auto 1fr;gap:14px 34px;align-items:center;margin:16px 0 14px;padding:14px 16px;
  border:1px solid var(--line);border-left:4px solid var(--line-2);border-radius:var(--r);background:var(--panel)}
.avb-app .sm-now--hot{border-left-color:var(--sm-heat)}
.avb-app .sm-now--warming{border-left-color:color-mix(in srgb,var(--sm-heat) 55%,var(--line))}
.avb-app .sm-now-main{display:flex;flex-direction:column;gap:2px;font-family:var(--mono)}
.avb-app .sm-now-v{font-size:clamp(30px,4.4vw,44px);font-weight:700;color:var(--ink);line-height:1;font-variant-numeric:tabular-nums}
.avb-app .sm-now-v small{font-size:13px;color:var(--faint);font-weight:600;margin-left:3px}
.avb-app .sm-regime{font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--dim)}
.avb-app .sm-now--hot .sm-regime,.avb-app .sm-now--warming .sm-regime{color:var(--sm-heat)}
.avb-app .sm-now-parts{display:flex;gap:22px;margin:0;font-family:var(--mono)}
.avb-app .sm-now-parts dt{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint)}
.avb-app .sm-now-parts dd{margin:2px 0 0;font-size:20px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.avb-app .sm-now-parts dd small{font-size:11px;color:var(--faint)}
.avb-app .sm-now-checks{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:3px 18px;
  font-family:var(--mono);font-size:11.5px;color:var(--faint)}
.avb-app .sm-now-checks li.on{color:var(--ink)}
.avb-app .sm-now-checks li.na{opacity:.6}
.avb-app .sm-legend{display:flex;flex-wrap:wrap;gap:6px 16px;font-family:var(--mono);font-size:11px;color:var(--dim);margin:4px 0 6px}
.avb-app .sm-legend span{display:inline-flex;align-items:center;gap:6px}
.avb-app .sm-key{display:inline-block;width:16px;height:9px;border-radius:2px}
.avb-app .sm-key--score{height:3px;background:var(--ink)}
.avb-app .sm-key--level{height:0;border-top:1.5px dashed var(--dim)}
.avb-app .sm-key--mom{height:0;border-top:1.5px dotted var(--sm-heat)}
.avb-app .sm-peakkey{color:var(--faint)}
.avb-app .sm-chart{width:100%;min-width:0;border:1px solid var(--line);border-radius:var(--r);background:var(--panel);padding:6px 0 4px;touch-action:pan-y}
.avb-app .sm-chart svg{display:block}
.avb-app .sm-band--hot{fill:var(--sm-heat);fill-opacity:.30;background:color-mix(in srgb,var(--sm-heat) 30%,transparent)}
.avb-app .sm-band--warming{fill:var(--sm-heat);fill-opacity:.12;background:color-mix(in srgb,var(--sm-heat) 12%,transparent)}
.avb-app .sm-band--cold{fill:var(--sm-cold);background:var(--sm-cold)}
.avb-app .sm-axis{stroke:var(--line-2);stroke-width:1}
.avb-app .sm-guide{stroke:var(--line-2);stroke-width:1;stroke-dasharray:3 4}
.avb-app .sm-tick{fill:var(--faint);font-family:var(--mono);font-size:10px}
.avb-app .sm-peak line{stroke:var(--dim);stroke-width:1;stroke-dasharray:2 3;opacity:.7}
.avb-app .sm-peak text{fill:var(--dim);font-family:var(--mono);font-size:9.5px}
.avb-app .sm-line{fill:none;stroke-linejoin:round;stroke-linecap:round}
.avb-app .sm-line--score{stroke:var(--ink);stroke-width:2.2}
.avb-app .sm-line--level{stroke:var(--dim);stroke-width:1.2;stroke-dasharray:4 3}
.avb-app .sm-line--mom{stroke:var(--sm-heat);stroke-width:1.2;stroke-dasharray:1.5 2.5;opacity:.85}
.avb-app .sm-cursor line,.avb-app .sm-cursor-l{stroke:var(--ink-2);stroke-width:1;opacity:.5}
.avb-app .sm-cursor circle{fill:var(--ink);stroke:var(--panel);stroke-width:2}
.avb-app .sm-grid{margin-top:8px;border-top:1px solid var(--line-soft);padding-top:6px}
.avb-app .sm-cell{fill:var(--sm-heat)}
.avb-app .sm-check{fill:var(--ink-2);opacity:.55}
.avb-app .sm-rowlabel{fill:var(--ink-2);font-family:var(--mono);font-size:9.5px}
.avb-app .sm-gridctl{margin:10px 0 0}
.avb-app .sm-ctl{display:inline-flex;flex-direction:column;gap:5px;font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--faint)}
.avb-app .sm-ctl .mc-seg button{text-transform:none;letter-spacing:0;font-size:12px;padding:4px 9px}
.avb-app .sm-ctls{display:flex;flex-wrap:wrap;gap:14px 22px;align-items:flex-end}
.avb-app .sm-blend input{width:200px;accent-color:var(--sm-heat)}
.avb-app .sm-weights{display:grid;grid-template-columns:repeat(auto-fill,minmax(270px,1fr));gap:12px;margin-top:18px}
.avb-app .sm-wgroup{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);padding:8px 12px 10px;margin:0;min-width:0}
.avb-app .sm-wgroup legend{font-family:var(--mono);font-size:11px;font-weight:700;color:var(--ink);padding:0 4px}
.avb-app .sm-wgroup legend em{font-style:normal;color:var(--dim);margin-left:6px}
.avb-app .sm-wgroup legend b{font-size:9px;letter-spacing:.12em;text-transform:uppercase;color:var(--sm-heat);margin-left:8px}
.avb-app .sm-wrow{display:grid;grid-template-columns:minmax(0,1fr) 110px 34px;gap:8px;align-items:center;font-family:var(--mono);font-size:11.5px;color:var(--ink-2);padding:3px 0}
.avb-app .sm-wrow span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.avb-app .sm-wrow input{width:100%;accent-color:var(--sm-heat)}
.avb-app .sm-wrow em{font-style:normal;text-align:right;color:var(--dim);font-variant-numeric:tabular-nums}
.avb-app .sm-reset{margin-top:14px;font-family:var(--mono);font-size:12px;font-weight:700;color:var(--dim);background:var(--panel-2);
  border:1px solid var(--line);border-radius:var(--r);padding:7px 12px;cursor:pointer}
.avb-app .sm-reset:hover{color:var(--ink)}
.avb-app .sm-warn{color:var(--dim)}
.avb-app .sm-h2{margin-top:26px!important}
.avb-app .sm-steps{margin:0 0 14px;padding-left:20px;font-size:14.5px;line-height:1.6;color:var(--ink-2);max-width:80ch}
.avb-app .sm-steps li{margin-bottom:6px}
.avb-app .sm-rules{margin:0 0 12px;padding-left:0;list-style:none;font-size:14px;line-height:1.55;color:var(--ink-2);max-width:80ch}
.avb-app .sm-rules li{padding:3px 0 3px 12px;border-left:3px solid var(--line)}
.avb-app .sm-rule--hot{border-left-color:var(--sm-heat)!important}
.avb-app .sm-rule--warming{border-left-color:color-mix(in srgb,var(--sm-heat) 45%,var(--line))!important}
.avb-app .sm-rule--cold{border-left-color:var(--line-2)!important}
@media (max-width:760px){
  .avb-app .sm-now{grid-template-columns:1fr 1fr}
  .avb-app .sm-now-checks{grid-column:1/-1;grid-template-columns:1fr}
  .avb-app .sm-blend input{width:100%}
}
.avb-app .sm-entry{display:inline-flex;flex-wrap:wrap;align-items:baseline;gap:4px 8px;margin-top:12px;font-family:var(--mono);font-size:13px;font-weight:700;
  color:var(--ink);text-decoration:none;border:1px solid var(--line);border-left:3px solid #FF6A2B;border-radius:var(--r);background:var(--panel);padding:8px 12px}
.avb-app .sm-entry em{font-style:normal;font-weight:500;font-size:11.5px;color:var(--faint)}
.avb-app .sm-entry:hover{border-color:var(--line-2)}
.avb-app .sm-labelbg{fill:var(--panel);opacity:.86}
.avb-app .sm-busy,.avb-app .sm-busy~.sm-chart{opacity:.55;transition:opacity .2s}
.avb-app .sm-chart--wait{height:520px}
.avb-app .sm-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
/* ============================================================================
   THE CARD LANGUAGE, SITE-WIDE (2026-09-26)

   The snapshot card (lib/snapshot.ts frameSvg) was the first surface drawn in this language,
   and Kevin asked for the site to read the same way. The card, reduced to rules:
     1. GROUND — never flat black: a glow the colour of the verdict rises from the lower left
        over a quiet dot grid. Green beat Bitcoin, red lost, orange is the reference/no verdict.
     2. NO PANEL BOXES — surfaces float: a faint ink wash, a hairline, a generous radius.
     3. WINDOW CHIPS — the label quiet above, the value coloured by its sign.
     4. SUBJECT + HEADLINE — icon · Name · TICKER, one big sans number, a signed line under it.
     5. CHARTS — one line, a soft gradient, a lit last point, quiet axes (in the components).
   Everything numeric below the headline stays mono; only the headline number is sans.

   This file loads AFTER globals.css (app/layout.tsx), so a rule here at equal specificity
   wins by order. It restyles; it does not restructure — every selector already exists.
   ============================================================================ */

:root{
  --glow-rgb:247,147,26;
  --card-fill:rgba(233,239,246,.035); --card-fill-2:rgba(233,239,246,.06);
  --card-line:rgba(233,239,246,.075); --card-line-2:rgba(233,239,246,.13);
  --card-r:14px; --chip-r:10px;
  --glow-a:.20; --glow-b:.07; --dot:rgba(233,239,246,.07);
  --bar-bg:color-mix(in srgb,var(--bg) 78%,transparent);
  --board-glow-a:.30; --board-glow-b:.09;
}
:root[data-theme="light"]{
  --card-fill:rgba(255,255,255,.62); --card-fill-2:rgba(255,255,255,.8);
  --card-line:rgba(14,20,32,.08); --card-line-2:rgba(14,20,32,.15);
  --glow-a:.13; --glow-b:.045; --dot:rgba(14,20,32,.09);
  --board-glow-a:.18; --board-glow-b:.05;
}

/* ── 1. THE GROUND ──────────────────────────────────────────────────────────
   A fixed layer behind the whole app. `isolation` makes .avb-app the stacking context, so
   z-index:-1 paints above the body's --bg and below every piece of content, without giving
   any child a z-index of its own (the sticky bars and popovers keep theirs untouched).
   The verdict is read from the page: a coin or macro page stamps data-verdict on its root. */
.avb-app{isolation:isolate;background:transparent}
.avb-app::before{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(120% 85% at 22% 108%,rgba(var(--glow-rgb),var(--glow-a)) 0%,rgba(var(--glow-rgb),var(--glow-b)) 42%,rgba(var(--glow-rgb),0) 75%),
    radial-gradient(circle,var(--dot) 1px,transparent 1.3px) 0 0/14px 14px;
  /* the grid lives where the glow is and fades out toward the header, as on the card */
  -webkit-mask-image:linear-gradient(to top,#000 0%,#000 40%,rgba(0,0,0,.55) 100%);
          mask-image:linear-gradient(to top,#000 0%,#000 40%,rgba(0,0,0,.55) 100%);
}
.avb-app:has([data-verdict="up"])::before{--glow-rgb:43,223,95}
.avb-app:has([data-verdict="down"])::before{--glow-rgb:241,51,52}
:root[data-theme="light"] .avb-app:has([data-verdict="up"])::before{--glow-rgb:14,160,70}
:root[data-theme="light"] .avb-app:has([data-verdict="down"])::before{--glow-rgb:212,39,40}

/* Sticky bars let the ground through instead of cutting an opaque band across it.
   ☢️ THE BLUR LIVES ON A PSEUDO-ELEMENT, NEVER ON THE BAR. backdrop-filter makes an element the
   containing block for its position:fixed descendants, and the header renders the sign-in
   scrim and the command palette INSIDE .sh — on the bar itself they would be clipped to a
   52px strip instead of covering the screen. Every bar here is already positioned (sticky)
   with a z-index, so the ::before at -1 sits behind its content and in front of the page. */
.avb-app .sh,.avb-app .cp-head{background:transparent}
.avb-app .sh::before,.avb-app .cp-head::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;background:var(--bar-bg);
  -webkit-backdrop-filter:blur(12px) saturate(1.2);backdrop-filter:blur(12px) saturate(1.2)}
/* ⚠️ The section nav takes the blur ON ITSELF: it is a sideways scroll container, so an
   absolute ::before would scroll away with its links; and it holds only <a>s, no fixed layer. */
.avb-app .cp-secnav{background:var(--bar-bg);-webkit-backdrop-filter:blur(12px) saturate(1.2);backdrop-filter:blur(12px) saturate(1.2)}
/* Where a bar turns static (globals.css: .sh ≤760px, .cp-head ≤900px) it no longer overlaps
   anything, and an absolute ::before would escape to the next positioned ancestor. */
@media (max-width:760px){.avb-app .sh::before{display:none}}
@media (max-width:900px){.avb-app .cp-head::before{display:none}}
.avb-app .ft{background:transparent}

/* ── 2. SURFACES FLOAT ─────────────────────────────────────────────────────── */
.avb-app .card,
.avb-app .mc-card,
.avb-app .mc-chartwrap,
.avb-app .cp-tablewrap,
.avb-app .tblwrap,
.avb-app .cp-hzcard,
.avb-app .cp-vstake,
.avb-app .mp-relcard,
.avb-app .bf-kpis div,
.avb-app .bm-mod,
.avb-app .wl-rulelist li{
  background:var(--card-fill);border-color:var(--card-line);border-radius:var(--card-r)}
.avb-app .mc-card:hover,.avb-app .mp-relcard:hover{border-color:var(--card-line-2);background:var(--card-fill-2)}
.avb-app .wl-rulelist li.fired{border-color:var(--base-bd);background:var(--base-tint)}
.avb-app .bf-movers li a{background:var(--card-fill);border-color:var(--card-line);border-radius:var(--chip-r)}
.avb-app .bf-movers li a:hover{background:var(--card-fill-2);border-color:var(--card-line-2)}
/* The stat grids drew their separators with a 1px gap over a --line ground — a ground a
   translucent cell would show through. Each cell is its own chip now, gap as air. */
.avb-app .cp-stats{background:transparent;border:0;border-radius:0;overflow:visible;gap:8px}
.avb-app .cp-stats>div{background:var(--card-fill);border:1px solid var(--card-line);border-radius:var(--chip-r)}

/* Segmented controls: the chip's wash, not a boxed well. */
.avb-app .tf,.avb-app .mc-seg{background:var(--card-fill);border-color:var(--card-line);border-radius:11px}
.avb-app .tf button.on,.avb-app .mc-seg button.on{background:var(--card-fill-2);box-shadow:inset 0 0 0 1px var(--card-line-2)}
/* The board's control row (globals.css .hm-seg is unscoped, 0,1,0 — this wins on specificity). */
.avb-app .hm-seg{background:var(--card-fill);border-color:var(--card-line);border-radius:10px;padding:3px}
.avb-app .hm-segbtn{border-radius:7px}
.avb-app .hm-segbtn.on{background:var(--card-fill-2);box-shadow:inset 0 0 0 1px var(--card-line-2)}

/* ── 3. WINDOW CHIPS ──────────────────────────────────────────────────────────
   The coin page's verdict strip painted each window as a solid red/green tile; the card's
   chip says the same thing with the colour in the NUMBER, which is where the eye reads it. */
.avb-app .cp-segs{gap:6px}
.avb-app .cp-segs li,
.avb-app .cp-segs li.won,.avb-app .cp-segs li.lost,.avb-app .cp-segs li.flat{
  background:var(--card-fill);border:1px solid var(--card-line);border-radius:var(--chip-r);padding:9px 2px 8px;gap:3px;color:var(--dim)}
.avb-app .cp-segs .pl{color:var(--dim);font-weight:600;letter-spacing:.08em}
.avb-app .cp-segs .pv{font-size:14px}
.avb-app .cp-segs li.won .pv{color:var(--up)}
.avb-app .cp-segs li.lost .pv{color:var(--down)}
.avb-app .cp-segs li.flat .pv{color:var(--ink-2)}
.avb-app .hm-sheet .hm-cell{background:var(--card-fill);border:1px solid var(--card-line);border-radius:var(--chip-r)}
.avb-app .hm-sheet .hm-rows{gap:5px}
.avb-app .cp-pips li{border-radius:var(--chip-r)}

/* ── 4. SUBJECT + HEADLINE ────────────────────────────────────────────────────
   Coin page: the icon leads the sticky head, and the number that matters (the price IN
   BITCOIN) is the one set large in sans; its neighbours stay the mono readout layer. */
.avb-app .cp-subj{display:flex;align-items:center;gap:12px;min-width:0}
.avb-app .cp-subj .cp-ico{display:flex;flex:none}
.avb-app .cp-subj .cp-ico .ico{width:38px;height:38px;font-size:13px}
.avb-app .cp-head .cp-h1{font-family:var(--sans);letter-spacing:-.015em}
/* ⚠️ 22px, not the card's 38: the sticky head is one row (idcol + price) at 1080px and
   cp-secnav sticks at a fixed offset under it — a bigger number wraps the head and the nav
   rides over it. The number leads by FACE and colour here, not by size. */
.avb-app .cp-head .cp-px--btc{font-family:var(--sans);font-size:22px;letter-spacing:-.01em}
.avb-app .cp-price dt{color:var(--dim)}
/* Macro pair page: the same head. */
.avb-app .mp-h1{font-family:var(--sans);letter-spacing:-.015em}
.avb-app .mp-h1 i{width:40px;height:40px}
.avb-app .mp-now-v{font-family:var(--sans);letter-spacing:-.015em}
/* The coin sheet over the board: glass on the glow, and the big number in sans. */
.avb-app .hm-sheet{border-radius:18px;border-color:var(--card-line-2)}
.avb-app .hm-sheet .hm-big{font-family:var(--sans);letter-spacing:-.015em}
/* The board's and the macro page's read strip, and the brief's KPIs: the headline number is
   the card's bold sans; its "of 1,046" tail stays in the mono readout voice. */
.avb-app .rs-v{font-family:var(--sans);font-weight:700;letter-spacing:-.015em}
.avb-app .rs-v small{font-family:var(--mono);letter-spacing:0}
.avb-app .bf-kpis b{font-family:var(--sans);font-weight:700;font-size:26px;letter-spacing:-.015em}
.avb-app .bf-kpis b small{font-family:var(--mono)}

@media (max-width:640px){
  .avb-app .cp-subj .cp-ico .ico{width:34px;height:34px}
  .avb-app .mp-h1 i{width:28px;height:28px}
  .avb-app .cp-segs{gap:3px}
  .avb-app .cp-segs li,.avb-app .cp-segs li.won,.avb-app .cp-segs li.lost,.avb-app .cp-segs li.flat{padding:7px 1px 6px;border-radius:8px}
  .avb-app .cp-segs .pv{font-size:clamp(9.5px,2.8vw,12px)}
}

/* ── 5. CHARTS ────────────────────────────────────────────────────────────────
   The coin chart's panel floats like every other surface; the canvas is already transparent
   (PairChart.tsx paints no background), so the glow shows through the plot as on the card.
   Segments take the chip radius; the active one keeps the site's amber, which is what "on"
   means everywhere on this site. */
.avb-app .cp-chart{background:var(--card-fill);border-color:var(--card-line);border-radius:var(--card-r)}
.avb-app .cp-charthd{border-color:var(--card-line)}
.avb-app .cp-chartnote{border-color:var(--card-line)}
.avb-app .cp-seg{border-color:var(--card-line);border-radius:9px;background:var(--card-fill)}
.avb-app .cp-seg button+button{border-left-color:var(--card-line)}
.avb-app .mp-chartwrap{background:var(--card-fill);border-color:var(--card-line);border-radius:var(--card-r)}
.avb-app .mp-legs{background:var(--card-fill);border-color:var(--card-line);border-radius:var(--card-r)}

/* ── 6. THE BOARD SITS ON THE GROUND ──────────────────────────────────────────
   Kevin (2026-09-27): the boards should look like their snapshot — the bullseye, grid,
   bubbles and list floating on the glow, as the report and macro pages already do — not on
   the flat --hm-gap panel. So every container between the page and the board goes clear.
   ⚠️ .hm-grid KEEPS --hm-gap: its 2px gaps ARE the grid's cell separators (the bullseye's
   are stroked in the same colour), and a clear gap would dissolve the mosaic into the glow.
   ⚠️ --hm-gap is still the colour the lens-dimmed fills blend toward in JS (lib/heatmap.ts);
   that stays right — it is a dark, not a ground any more. */
.avb-app .hm-gridwrap,.avb-app .rk{background:transparent}
/* The board panel carries the CARD'S OWN ground, anchored to the panel as it is in the
   snapshot, not only the page's (fixed to the viewport, so a board in the middle of the
   screen sat in its faintest part). No base colour: it lays over the page's ground. */
.avb-app .avb-heatmap{
  --glow-rgb:247,147,26;
  background:
    radial-gradient(95% 95% at 28% 105%,rgba(var(--glow-rgb),var(--board-glow-a)) 0%,rgba(var(--glow-rgb),var(--board-glow-b)) 45%,rgba(var(--glow-rgb),0) 100%),
    radial-gradient(circle,var(--dot) 1px,transparent 1.3px) 0 0/14px 14px}
.avb-app .avb-heatmap[data-verdict="up"]{--glow-rgb:43,223,95}
.avb-app .avb-heatmap[data-verdict="down"]{--glow-rgb:241,51,52}
:root[data-theme="light"] .avb-app .avb-heatmap[data-verdict="up"]{--glow-rgb:14,160,70}
:root[data-theme="light"] .avb-app .avb-heatmap[data-verdict="down"]{--glow-rgb:212,39,40}
/* The panel's lower edge (grip) and its caption rule: part of the card, not bars across it. */
.avb-app .hm-edgebar,.avb-app .hm-foot-rule{background:transparent;border-top-color:var(--card-line)}
.avb-app .hm-side{background:var(--card-fill);border-color:var(--card-line)}
.avb-app .hm-side-tab{background:var(--card-fill);border-left-color:var(--card-line)}
.avb-app .hm-side-tab:hover{background:var(--card-fill-2)}
/* The compact list's sticky head scrolled rows under an opaque panel; now it frosts them. */
.avb-app .rk--compact .rk-table thead th{background:var(--bar-bg);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}

/* FULL SCREEN. A fullscreen element is lifted into the top layer, where the page's ::before
   ground cannot reach, and the UA paints it black — so it carries the same ground itself.
   Its verdict is read from the board inside it, as the page's is. */
.avb-app .avb-heatmap:fullscreen,.avb-app .rk:fullscreen,.avb-app .hm-row:fullscreen{
  --glow-rgb:247,147,26;
  background:
    radial-gradient(95% 95% at 28% 105%,rgba(var(--glow-rgb),var(--board-glow-a)) 0%,rgba(var(--glow-rgb),var(--board-glow-b)) 45%,rgba(var(--glow-rgb),0) 100%),
    radial-gradient(circle,var(--dot) 1px,transparent 1.3px) 0 0/14px 14px,
    var(--bg)}
.avb-app .avb-heatmap[data-verdict="up"]:fullscreen,.avb-app .hm-row:fullscreen:has([data-verdict="up"]){--glow-rgb:43,223,95}
.avb-app .avb-heatmap[data-verdict="down"]:fullscreen,.avb-app .hm-row:fullscreen:has([data-verdict="down"]){--glow-rgb:241,51,52}

/* ── 7. BREADTH ───────────────────────────────────────────────────────────────
   The fifth board layout gets the same treatment as the other four: its panel goes clear so
   the board's glow and dot grid show behind the chart; the headline number is the card's sans;
   high / low / history read as chips. The chart itself (Breadth.tsx) draws a baseline with
   fading fills, a lit last point and no vertical grid. */
.avb-app .br{background:transparent}
.avb-app .br-v{font-family:var(--sans);letter-spacing:-.015em}
.avb-app .br-v small{font-family:var(--mono);letter-spacing:.04em}
.avb-app .br-stats{gap:8px}
.avb-app .br-stats div{background:var(--card-fill);border:1px solid var(--card-line);border-radius:var(--chip-r);padding:8px 12px}
.avb-app .br-stats dd{font-family:var(--sans);font-weight:700;font-size:16px;letter-spacing:-.01em}
.avb-app .br-stats dd small{font-family:var(--mono);letter-spacing:0}

/* One header line: the headline, ONE summary sentence beside it, the stat chips at the end
   (Kevin, 2026-10-07: three columns of guide text was "so wordy"). The right padding clears the
   panel's full-screen and camera buttons, which sit absolutely in that corner and used to cover
   the History chip. Below ~1100px the sentence takes its own row under the headline. */
.avb-app .br-head{align-items:center;padding-right:44px}
.avb-app .br-sum{flex:1 1 360px;margin:0;max-width:62ch;font-size:13px;line-height:1.5;color:var(--dim)}
.avb-app .br-sum b{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
.avb-app .br-sum b.pos{color:var(--up)} .avb-app .br-sum b.neg{color:var(--down)}
/* Macro overlays: the menu's colour dots, and the key over the plot's top-left corner — clear of
   the price axis on the right and of the line, which the scale margins keep below the top 10%. */
.avb-app .br-ovdot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:7px;vertical-align:1px}
.avb-app .br-ovmenu{min-width:min(360px,calc(100vw - 16px));max-height:min(70vh,560px);overflow:auto}
.avb-app .br-ovlegend{position:absolute;top:4px;left:48px;z-index:2;display:flex;flex-wrap:wrap;gap:4px 12px;margin:0;padding:0;
  list-style:none;max-width:calc(100% - 80px);pointer-events:none;font-family:var(--mono);font-size:10.5px;letter-spacing:.04em;color:var(--dim)}
.avb-app .br-ovlegend li{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;background:var(--veil,rgba(10,13,20,.6));padding:2px 6px;border-radius:4px}
.avb-app .br-ovlegend i{width:10px;height:2px;border-radius:1px}
.avb-app .br-ovlegend b{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
/* A chip is grabbable (lib/overlayScale): click shows that overlay's own axis, a vertical drag
   moves the overlay. The list itself still lets the plot through between the chips. */
.avb-app .br-ovlegend li{pointer-events:auto;cursor:ns-resize;user-select:none;touch-action:none;border:1px solid transparent}
.avb-app .br-ovlegend li:hover{color:var(--ink)}
.avb-app .br-ovlegend li.on{border-color:currentColor;color:var(--ink)}
/* Match the native Breadth axis typography and spacing, tinted for its comparison. */
.avb-app .br-ovaxis{position:absolute;top:0;z-index:4;cursor:ns-resize;touch-action:none;user-select:none;
  background:transparent;border-left:1px solid var(--line)}
.avb-app .br-ovaxis-tick{position:absolute;left:7px;transform:translateY(-50%);
  font-weight:400;line-height:normal;color:var(--ov);white-space:nowrap;pointer-events:none}
@media (max-width:640px){
  .avb-app .br-head{padding-right:40px}
  /* ☢️ ON A PHONE THE BREADTH PANEL GROWS TO ITS CONTENT. The board panel is a fixed-height
     window (overflow hidden) sized for a mosaic; the breadth view stacks headline, summary and
     stats above its chart, and the fixed window clipped the plot to a sliver. */
  .avb-app .fp .avb-heatmap:has(.br){height:auto;max-height:none}
}

/* ── 8. THE SIDEBAR (components/SideNav.tsx) ──────────────────────────────────
   Desktop only. The layouts lead — named, drawn and described — then the pages. Fixed under
   the header; the page column steps right by its width. The rail (64px) is a per-visitor
   choice stamped on <html data-side="rail"> before paint (lib/themeBoot.ts), so it is read
   here, not from React state. Below 1180px nothing changes: header tabs, the phone tab bar
   and the board's own Layout control carry on as before. */
:root{--side-w:236px}
:root[data-side="rail"]{--side-w:64px}
/* 1180–1359px: the full sidebar would squeeze the 980px list into a sideways scroll, so the
   rail is the default there — unless the visitor chose "open" (critic, 2026-09-27). */
@media (min-width:1180px) and (max-width:1359px){:root:not([data-side="open"]){--side-w:64px}}
.avb-app .sn{position:fixed;top:var(--hdr);left:0;bottom:0;width:var(--side-w);z-index:34;box-sizing:border-box;
  display:flex;flex-direction:column;gap:14px;padding:18px 12px 12px;overflow-y:auto;overflow-x:hidden;scrollbar-width:none;
  border-right:1px solid var(--card-line);background:var(--bar-bg);
  -webkit-backdrop-filter:blur(12px) saturate(1.2);backdrop-filter:blur(12px) saturate(1.2);transition:width .18s ease}
.avb-app .sn-sec{display:flex;flex-direction:column;gap:3px}
.avb-app .sn-sec+.sn-sec{padding-top:14px;border-top:1px solid var(--card-line)}
.avb-app .sn-k{font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim);padding:0 10px 6px}
.avb-app .sn-item{position:relative;display:flex;align-items:center;gap:12px;width:100%;box-sizing:border-box;padding:8px 10px;
  border:1px solid transparent;border-radius:10px;background:none;color:var(--dim);font:inherit;text-align:left;text-decoration:none;cursor:pointer;
  transition:background .12s ease,color .12s ease,border-color .12s ease}
.avb-app .sn-item:hover{color:var(--ink);background:var(--card-fill)}
.avb-app .sn-item:focus-visible{outline:2px solid var(--btc);outline-offset:-2px}
.avb-app .sn-item.on{color:var(--ink);background:var(--card-fill-2);border-color:var(--card-line-2)}
/* the active edge — the same orange that marks the active tab everywhere else on the site */
.avb-app .sn-item.on::before{content:"";position:absolute;left:-12px;top:9px;bottom:9px;width:3px;border-radius:0 3px 3px 0;background:var(--btc)}
.avb-app .sn-item.on .sn-ico{color:var(--btc)}
.avb-app .sn-ico{flex:none}
.avb-app .sn-txt{display:flex;flex-direction:column;min-width:0}
.avb-app .sn-lbl{font-family:var(--sans);font-size:14px;font-weight:600;line-height:1.2;white-space:nowrap}
.avb-app .sn-layout{padding:10px}
.avb-app .sn-layout .sn-lbl{font-size:15px;font-weight:700;letter-spacing:-.005em}
.avb-app .sn-what{margin-top:3px;font-size:11.5px;line-height:1.25;color:var(--dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.avb-app .sn-item.on .sn-what{color:var(--ink-2)}
.avb-app .sn-count{margin-left:auto;min-width:18px;padding:1px 6px;border-radius:9px;box-sizing:border-box;text-align:center;
  font-family:var(--mono);font-size:10.5px;font-weight:700;color:var(--btc);background:var(--btc-tint)}
.avb-app .sn-fold{margin-top:auto;padding-top:9px;padding-bottom:9px}
:root[data-side="rail"] .avb-app .sn{padding-left:10px;padding-right:10px}
:root[data-side="rail"] .avb-app .sn-txt,:root[data-side="rail"] .avb-app .sn-k,:root[data-side="rail"] .avb-app .sn-count{display:none}
:root[data-side="rail"] .avb-app .sn-item{justify-content:center;padding:10px 0}
:root[data-side="rail"] .avb-app .sn-item.on::before{left:-10px}
@media (min-width:1180px) and (max-width:1359px){
:root:not([data-side="open"]) .avb-app .sn{padding-left:10px;padding-right:10px}
:root:not([data-side="open"]) .avb-app .sn-txt,:root:not([data-side="open"]) .avb-app .sn-k,:root:not([data-side="open"]) .avb-app .sn-count{display:none}
:root:not([data-side="open"]) .avb-app .sn-item{justify-content:center;padding:10px 0}
:root:not([data-side="open"]) .avb-app .sn-item.on::before{left:-10px}
}
@media (min-width:1180px){
  .avb-app .main,.avb-app .ft{margin-left:var(--side-w);transition:margin-left .18s ease}
  /* the sidebar carries both: page tabs out of the header, the layout switch out of the board */
  .avb-app .sh-nav{display:none}
  .avb-app .hm-ctl--layout{display:none}
}
@media (max-width:1179px){.avb-app .sn{display:none}}
@media (prefers-reduced-motion:reduce){.avb-app .sn,.avb-app .main,.avb-app .ft{transition:none}}

/* ── Breadth's drawing tools (components/BreadthDraw.tsx) ─────────────────────────────────────
   A slim vertical bar down the plot's left edge, TradingView's place for it; the plot itself
   is the canvas. The SVG lets every pointer through to the chart unless a tool is armed, and
   each drawing takes clicks on its own stroke so it can be selected in cursor mode. */
.avb-app .brd-bar{position:absolute;top:4px;left:0;z-index:3;display:flex;flex-direction:column;align-items:center;gap:2px;
  padding:4px 3px;border:1px solid var(--card-line,var(--line));border-left:0;border-radius:0 8px 8px 0;background:var(--veil,rgba(10,13,20,.72));
  /* on a short plot (a phone) the bar is taller than the chart: it scrolls rather than run off it */
  max-height:calc(100% - 8px);overflow-y:auto;scrollbar-width:none}
.avb-app .brd-bar::-webkit-scrollbar{display:none}
.avb-app .brd-btn{display:grid;place-items:center;width:28px;height:26px;border:0;border-radius:5px;background:transparent;color:var(--dim);cursor:pointer}
.avb-app .brd-btn svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.avb-app .brd-btn:hover:not(:disabled){color:var(--ink);background:rgba(255,255,255,.06)}
.avb-app .brd-btn.on{color:var(--btc,#F5B748);background:rgba(245,183,72,.12)}
.avb-app .brd-btn:disabled{opacity:.35;cursor:default}
.avb-app .brd-btn:focus-visible,.avb-app .brd-swatch:focus-visible{outline:2px solid var(--btc,#F5B748);outline-offset:1px}
.avb-app .brd-sep{width:18px;height:1px;margin:3px 0;background:var(--card-line,var(--line))}
.avb-app .brd-swatch{width:14px;height:14px;margin:2px 0;border:0;border-radius:50%;cursor:pointer;box-shadow:0 0 0 1px rgba(0,0,0,.4)}
.avb-app .brd-swatch.on{box-shadow:0 0 0 2px var(--panel,#0A0D14),0 0 0 3.5px currentColor;color:var(--ink)}
/* ☢️ THE PLOT RUNS TO THE SIDEBAR'S EDGE (Kevin, 2026-10-07): the line, the grid and the date
   axis start where the sidebar ends, and the tool bar sits flush against it, over the plot. The
   plot is pulled left through the board's gutter (.avb-heatmap padding-inline) and the card's own
   padding (.br, 18px / 12px); the board clips at its edge, so nothing reaches past the sidebar.
   The chart and the drawings share ONE left edge — the SVG's coordinates are the chart's own. */
.avb-app .br-plot{margin-left:calc(-1 * (var(--gutter) + 18px))}
@media (max-width:760px){.avb-app .br-plot{margin-left:calc(-1 * (var(--gutter) + 12px))}}
.avb-app .brd-svg{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;z-index:2;pointer-events:none;overflow:hidden}
.avb-app .brd-lvl{font-family:var(--mono);font-size:10.5px;font-variant-numeric:tabular-nums;pointer-events:none}
/* hovering a drawing's hit band lights the drawing — the sign that it can be taken */
.avb-app .brd-shape:hover .brd-vis,.avb-app .brd-shape.is-sel .brd-vis{filter:brightness(1.3) drop-shadow(0 0 3px rgba(255,255,255,.25))}
@media (max-width:640px){.avb-app .brd-btn{width:30px;height:28px}}

/* Reserve a separate right axis for the selected comparison; keep the breadth axis intact. */
.avb-app .br-plot--overlay .br-chart{right:var(--overlay-axes-width,74px)}
.avb-app .br-ovaxis:focus-visible{outline:2px solid var(--ov);outline-offset:-2px}
.avb-app .br-ovlegend li:focus-visible{outline:2px solid var(--ink)}
/* The coin camera starts at the article's left edge; open inward so its menu stays visible. */
.avb-app .snap--coin .snap-menu{left:0;right:auto}

.avb-app .br-ovaxis-last{position:absolute;left:0;transform:translateY(-50%);padding:2px 7px;background:var(--ov);color:#fff;font-weight:400;line-height:14px;white-space:nowrap;pointer-events:none}
