/* bulldial.com — the dial panel.
 *
 * Layered on bd.css. The instruments are mounted in cards: a surface, a
 * radius, an elevation and a band-tinted top rule, so each one reads as
 * one instrument rather than as a cell in a table. Everything a card
 * shows about its reading — the pill, the rail marker, the needle glow,
 * the chart fill — is driven by one custom property, --tone, which
 * dials.js sets from the sector the needle is in. Nothing can disagree.
 */

/* The page sits on the sunk ground so the cards float off it. */
body { background: var(--bg-sunk); }

/* ══════════════════════════════════════════════════════════ masthead ═══
   Title, one line of standfirst, and the collection's status as a small
   terminal line beneath — the whole header earns less than 120px so the
   master instrument below is the first thing on the page that matters. */

.masthead {
  padding: var(--sp-5) 0 var(--sp-4);
  border-bottom: 1px solid var(--line-2);
}
.masthead h1 {
  font-size: var(--t-h1); font-weight: 700; letter-spacing: -0.03em;
  line-height: 1.05; color: var(--ink);
}
@media (max-width: 720px) {
  .masthead { padding-top: var(--sp-4); }
}

.note { color: var(--ink-2); font-size: var(--t-sm); max-width: 74ch; margin-top: var(--sp-4); }
.vh {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* ════════════════════════════════════════════════════════════ the grid ═══ */

.panel-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-4); margin-top: var(--sp-5);
}

.instrument {
  --tone: var(--accent);
  position: relative; isolation: isolate; min-width: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  padding: var(--sp-5);
  box-shadow: var(--e-1);
  display: flex; flex-direction: column; gap: var(--sp-4);
  transition: border-color var(--d-2) var(--ease), box-shadow var(--d-2) var(--ease),
              transform var(--d-2) var(--ease);
}
.instrument:hover {
  border-color: var(--line-2); box-shadow: var(--e-2); transform: translateY(-2px);
}
/* Band-tinted cap rule, inset to the card's radius. The one piece of
   colour that identifies the instrument before any of it is read. */
.instrument::before {
  content: ""; position: absolute; inset: -1px -1px auto -1px; height: 3px;
  border-radius: var(--r-3) var(--r-3) 0 0;
  background: linear-gradient(90deg,
    var(--tone) 0%,
    color-mix(in srgb, var(--tone) 62%, transparent) 55%,
    color-mix(in srgb, var(--tone) 22%, transparent) 100%);
}

/* The two composites lead the panel at full width: instrument on the
   left, everything read off it on the right. */
.instrument.hero {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  gap: var(--sp-4) var(--sp-6); align-items: stretch;
}
.instrument.hero .i-head { grid-column: 1 / -1; }
.instrument.hero .i-main,
.instrument.hero .i-side {
  min-width: 0; display: flex; flex-direction: column; gap: var(--sp-4);
}
/* The hero chart takes whatever its column has left, so the two columns
   bottom out together and the history is drawn at the size it deserves.
   Below the breakpoint, where the side sits under the dial with no height
   to fill, the minimums keep it a chart rather than a line. */
.instrument.hero .i-side .i-chart {
  flex: 1; display: flex; flex-direction: column; min-height: 160px;
}
.instrument.hero .i-side .i-chart svg { flex: 1; min-height: 120px; }

/* ════════════════════════════════════════════════════════════── header ═══ */

.i-head { display: flex; align-items: center; gap: var(--sp-3); }
.i-head h3 {
  font-size: var(--t-h3); font-weight: 650; letter-spacing: -0.015em;
  color: var(--ink); flex: 1; min-width: 0;
}

/* The sector the needle sits in, named, in the sector's own colour. */
.i-band {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  padding: 4px 10px 4px 8px; border-radius: var(--r-full);
  background: color-mix(in srgb, var(--tone) 13%, transparent);
  color: var(--tone);
  font-size: var(--t-label); font-weight: 700; letter-spacing: 0.07em;
  text-transform: uppercase; white-space: nowrap;
}
.i-band::before {
  content: ""; width: 6px; height: 6px; border-radius: var(--r-full);
  background: currentColor; flex: none;
}
.i-band-off {
  background: var(--surface-3); color: var(--ink-3);
}

/* ══════════════════════════════════════════════════════════════ dial ═══ */

.i-dial { display: grid; place-items: center; }
.i-dial svg { width: 100%; max-width: 380px; height: auto; display: block; }
.instrument.hero .i-dial svg { max-width: 500px; }

/* Instrument face — token-based, so it reads in either theme. */
.d-face-bg { fill: url(#d-face-grad); }
.d-bezel { fill: none; stroke: var(--line-2); stroke-width: 1; }
.d-arc { stroke: var(--line-2); stroke-width: 1.5; }
.d-minor { stroke: var(--ink-3); stroke-width: 1; opacity: .5; }
.d-major { stroke: var(--ink-2); stroke-width: 2.2; }
.d-num { fill: var(--ink-3); font: 600 12px var(--font); letter-spacing: 0.02em; }
.d-hand { fill: var(--ink); }
.d-hub { fill: var(--surface); stroke: var(--line-3); stroke-width: 1.5; }
.d-cap { fill: var(--ink-2); }
.d-set { fill: var(--ink-3); }
.d-read {
  fill: var(--ink); font: 700 54px var(--font); letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
}
.d-unit { fill: var(--ink-3); font: 650 10px var(--font); letter-spacing: 0.2em; }
.d-face { fill: var(--ink-3); font: 600 9px var(--font); letter-spacing: 0.28em; opacity: .8; }
.d-end { fill: var(--ink-3); font: 500 9px var(--font); letter-spacing: 0.16em; opacity: .85; }
.d-read-sm { font-size: 42px; }

.d-needle {
  transform-box: view-box; transform-origin: 220px 222px;
  transition: transform 1400ms cubic-bezier(.22, 1, .28, 1);
  filter: drop-shadow(0 0 5px color-mix(in srgb, var(--tone) 42%, transparent));
}
@media (prefers-reduced-motion: reduce) { .d-needle { transition: none; } }

/* ══════════════════════════════════════════════════════════ band rail ═══
   The scale flattened into one bar, in the sectors' own colours, with the
   needle's position marked on it. It replaces the swatch list: a reader
   can see where the reading sits in its range without decoding a key. */

.i-rail { display: flex; flex-direction: column; gap: var(--sp-2); }
.rail-track {
  position: relative; display: flex; gap: 2px; height: 8px;
}
.rail-seg {
  height: 8px; min-width: 3px;
  transition: opacity var(--d-2) var(--smooth);
}
.rail-seg:first-child { border-radius: var(--r-full) 0 0 var(--r-full); }
.rail-seg:last-child { border-radius: 0 var(--r-full) var(--r-full) 0; }
/* Sectors the needle is not in step back, so the live one carries. */
.rail-seg:not(.on) { opacity: .34; }
.rail-now {
  position: absolute; top: -4px; width: 3px; height: 16px; border-radius: 2px;
  background: var(--ink); transform: translateX(-1.5px);
  box-shadow: 0 0 0 3px var(--surface);
  transition: left var(--d-4) var(--ease);
}
/* The 30-day-old reading, as a hollow tick behind the live marker. */
.rail-was {
  position: absolute; top: -1px; width: 2px; height: 10px; border-radius: 1px;
  background: var(--ink-3); opacity: .6; transform: translateX(-1px);
}
/* The key shares the track's proportions: each name sits in a column the
   width of its own segment. A name wider than its segment is hidden by
   measurement (dials.js fitRails) rather than ellipsised — half a word
   says less than no word, and the ring on the dial still carries the
   sector. The live sector's name always shows. */
.rail-key {
  display: flex; gap: 2px; list-style: none;
}
.rail-key li {
  min-width: 0; display: flex; flex-direction: column; gap: 1px;
  align-items: center; text-align: center;
  font-size: var(--t-label); white-space: nowrap; line-height: 1.35;
}
.rail-key li:first-child { align-items: flex-start; text-align: left; }
.rail-key li:last-child { align-items: flex-end; text-align: right; }
.rail-key li.clip { visibility: hidden; }
.rail-key .k-label {
  font-weight: 650; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--ink-3);
}
.rail-key li.on .k-label { color: var(--ink); }
.rail-key .k-range { color: var(--ink-3); opacity: .8; font-variant-numeric: tabular-nums; }

/* ═══════════════════════════════════════════════════════════ stat rail ═══
   Reading, where it was, and the distance between them — the three
   figures a reader compares, on one line, in one block. */

.i-stats {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-2); overflow: hidden;
}
.i-stat {
  padding: 9px 12px; min-width: 0;
  border-left: 1px solid var(--line);
}
.i-stat:first-child { border-left: 0; }
.i-stat dt {
  font-size: var(--t-label); font-weight: 650; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.i-stat dd {
  margin-top: 3px; font-size: var(--t-sm); font-weight: 650;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
  display: flex; align-items: center; gap: 6px;
}
/* Direction is carried by the glyph, not by colour: the panel measures,
   it does not call a rising reading good. */
.i-delta .arrow { color: var(--ink-3); font-size: .82em; }
.i-flat { color: var(--ink-3); }

/* Rows that only some instruments carry (channels, confidence, updated). */
.i-rows {
  display: flex; flex-wrap: wrap; gap: 4px var(--sp-4);
  font-size: var(--t-label); letter-spacing: 0.03em;
  color: var(--ink-3);
}
.i-rows > div { display: inline-flex; align-items: baseline; gap: 6px; }
.i-rows dt { font-weight: 650; letter-spacing: var(--track); text-transform: uppercase; }
.i-rows dd { color: var(--ink-2); font-weight: 600; font-variant-numeric: tabular-nums; }

.i-detail { font-size: var(--t-xs); color: var(--ink-2); line-height: 1.55; }

/* ══════════════════════════════════════════════════════════════ chart ═══
   History in the instrument's own units, filled in the band's colour,
   with the reading under the pointer named. Same behaviour as the front
   page's chart, at card scale. */

.i-chart {
  position: relative; margin-top: auto;
  border-top: 1px solid var(--line); padding-top: var(--sp-3);
}
.i-chart svg { width: 100%; display: block; overflow: visible; }

/* The area fill is a per-card gradient: it reads --tone, which is set on
   the card, so the gradient has to live inside the card's own subtree and
   is referenced by a per-card id from the fill attribute. A fill here
   would beat that attribute and point every card at one dead id. */
.sp-line {
  fill: none; stroke: var(--tone); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round;
}
.sp-dot { fill: var(--tone); stroke: var(--surface); stroke-width: 3; }
.sp-cursor { stroke: var(--ink-3); stroke-width: 1; stroke-dasharray: 3 3; opacity: 0; }
.i-chart.hovering .sp-cursor { opacity: 1; }

/* Layers under the curve, drawn only where the chart is tall enough to
   carry them (the master band's decade surface). The bands are the dial's
   sector ring flattened out; the dotted hairlines are thirds. */
.sp-band { opacity: .075; }
.sp-grid { stroke: var(--line-3); stroke-width: 1; stroke-dasharray: 2 5; opacity: .6; }

/* The live point breathes: a slow ring issuing from today's reading. It
   pauses while the pointer is reading a past day, and does not exist
   under reduced motion. */
.sp-pulse {
  fill: none; stroke: var(--tone); stroke-width: 1.5;
  transform-box: fill-box; transform-origin: center;
  animation: bd-sp-pulse 2.8s var(--ease) infinite;
}
@keyframes bd-sp-pulse {
  0% { transform: scale(.55); opacity: .75; }
  70%, 100% { transform: scale(3.1); opacity: 0; }
}
.i-chart.hovering .sp-pulse { animation-play-state: paused; opacity: 0; }
@media (prefers-reduced-motion: reduce) { .sp-pulse { display: none; } }

.sp-empty {
  fill: var(--ink-3); letter-spacing: 0.14em; font: 650 9px var(--font);
}

.sp-axis {
  display: flex; justify-content: space-between; gap: var(--sp-2);
  margin-top: 6px;
  font-size: var(--t-label); letter-spacing: 0.04em; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.sp-tip {
  position: absolute; pointer-events: none; z-index: 3; left: 0; top: 0;
  background: var(--surface-3); border: 1px solid var(--line-2);
  border-radius: var(--r-2); box-shadow: var(--e-2);
  padding: 6px 9px; white-space: nowrap;
  opacity: 0; transform: translate(-50%, -124%);
  transition: opacity var(--d-1) var(--smooth);
}
.i-chart.hovering .sp-tip { opacity: 1; }
.sp-tip b {
  display: block; font-size: var(--t-sm); font-weight: 700;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.sp-tip em {
  font-style: normal; font-size: var(--t-label); color: var(--ink-3);
  letter-spacing: 0.03em;
}

/* ══════════════════════════════════════════════════ price vs the crowd ═══ */

.divergence {
  border: 1px solid var(--line); border-radius: var(--r-2);
  background: var(--surface-2); padding: var(--sp-3) var(--sp-4) var(--sp-4);
}
.dv-head {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--sp-3); margin-bottom: var(--sp-2);
}
.dv-head h4 {
  font-size: var(--t-label); font-weight: 700; letter-spacing: var(--track);
  text-transform: uppercase; color: var(--ink-3);
}
.dv-row {
  display: grid; grid-template-columns: 168px minmax(0, 1fr) 44px;
  gap: var(--sp-3); align-items: center; padding: 7px 0;
}
.dv-label {
  font-size: var(--t-label); font-weight: 650; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--ink-2);
  display: flex; flex-direction: column; gap: 1px; min-width: 0;
}
.dv-label span {
  font-weight: 500; letter-spacing: 0.02em; text-transform: none;
  color: var(--ink-3); overflow: hidden; text-overflow: ellipsis;
}
.dv-val {
  font-size: var(--t-sm); font-weight: 650; letter-spacing: -0.02em;
  text-align: right; font-variant-numeric: tabular-nums;
}
@media (max-width: 620px) {
  .dv-row { grid-template-columns: minmax(0, 1fr) 44px; }
  .dv-row .g-track { grid-column: 1 / -1; order: 3; }
}

/* Linear gauge, used by the divergence bars. */
.g-track {
  position: relative; height: 8px; border-radius: var(--r-full);
  background: var(--surface-3); overflow: visible;
}
.g-fill {
  position: absolute; inset: 0 auto 0 0; border-radius: var(--r-full);
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--tone) 45%, transparent), var(--tone));
  transition: width var(--d-4) var(--ease);
}
.g-mark {
  position: absolute; top: -3px; width: 3px; height: 14px; border-radius: 2px;
  background: var(--ink); transform: translateX(-1.5px);
  box-shadow: 0 0 0 2.5px var(--surface-2);
  transition: left var(--d-4) var(--ease);
}

/* ════════════════════════════════════════════════════════════ card foot ═══
   The unit is a caption: what the number measures, up to two lines,
   above the line that says when it was read and where from. An ellipsis
   that eats "…200-day av…" says less than no caption at all. */

.c-unit {
  font-size: var(--t-label); color: var(--ink-3); line-height: 1.5;
  letter-spacing: .03em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  margin-bottom: 5px;
}
.c-meta {
  display: flex; justify-content: flex-start; align-items: baseline;
  gap: var(--sp-3); padding-top: var(--sp-1);
  font-size: var(--t-label); letter-spacing: 0.03em; color: var(--ink-3);
}
.c-meta a { color: var(--ink-3); transition: color var(--d-1) var(--smooth); }
.c-meta a:hover { color: var(--accent); }
.c-meta > span:last-child { flex: none; }
.c-when { color: var(--ink-2); font-weight: 600; font-variant-numeric: tabular-nums; }
.c-when.stale { color: var(--warn); }

/* ═════════════════════════════════════════════════════════════ footer ═══ */

/* ═══════════════════════════════════════════════════════════ narrow ═══ */

@media (max-width: 1000px) {
  .instrument.hero { grid-template-columns: 1fr; grid-template-rows: none; gap: var(--sp-4); }
  .instrument.hero .i-head { grid-column: auto; }
  .instrument.hero .i-dial svg { max-width: 380px; }
}
@media (max-width: 820px) {
  .panel-grid { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .instrument { padding: var(--sp-4); }
  .c-meta { flex-wrap: wrap; gap: 3px var(--sp-3); }
  .i-stats { grid-auto-flow: row; grid-auto-columns: auto; }
  .i-stat { border-left: 0; border-top: 1px solid var(--line); display: flex;
            align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
  .i-stat:first-child { border-top: 0; }
  .i-stat dd { margin-top: 0; }
}

/* Cadence chip: how often the collector refreshes this instrument. */
.i-cad {
  flex: none;
  font-size: var(--t-label); font-weight: 650; letter-spacing: .08em;
  color: var(--ink-3); border: 1px solid var(--line-2);
  border-radius: var(--r-1); padding: 2px 6px; white-space: nowrap;
}

/* The status line inside the masthead: the collection's own state as
   labels and counts on one terminal line. The dot is green only when
   every source answered its last pass. */
.ann-strip {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: var(--sp-3);
  font-size: var(--t-label); font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-3);
}
.ann-strip .live-dot { flex: none; }
.ann-sep { color: var(--ink-3); opacity: .45; }

.note.warn { color: var(--warn); }

/* ═══════════════════════════════════════════════════════════ cockpit ═══
   The panel as an instrument map. A left rail clusters every reading
   by type and carries each live value; the canvas carries the sections
   the rail names. Under 1000px the rail becomes a sticky chip scroller
   under the bar — a left panel is a desktop creature, and a phone
   keeps its vertical space. */

.cockpit {
  width: 100%; max-width: var(--wide); margin: 0 auto;
  display: grid; grid-template-columns: 236px minmax(0, 1fr);
  gap: var(--sp-6);
  padding: 0 max(var(--sp-5), var(--safe-l)) calc(var(--sp-8) + var(--safe-b));
}
@media (max-width: 720px) {
  .cockpit { padding: 0 var(--sp-4) calc(var(--sp-7) + var(--safe-b)); }
}
@media (max-width: 860px) {
  body.has-tabbar .cockpit { padding-bottom: calc(var(--tabbar-h) + var(--safe-b) + var(--sp-6)); }
}
@media (max-width: 1000px) {
  .cockpit { grid-template-columns: minmax(0, 1fr); gap: 0; }
}

.canvas { min-width: 0; }
.canvas .masthead { padding-top: var(--sp-5); }

/* -- the rail --------------------------------------------------------- */

.rail {
  align-self: start; position: sticky;
  top: calc(var(--bar-h) + var(--safe-t) + 12px);
  max-height: calc(100svh - var(--bar-h) - 32px);
  overflow-y: auto; scrollbar-width: thin;
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--sp-7) 0 var(--sp-4);
}
.r-group {
  font-size: var(--t-label); font-weight: 650; letter-spacing: var(--track);
  text-transform: uppercase; color: var(--ink-3);
  margin: var(--sp-3) 0 3px; padding: 0 10px;
}
.r-group:first-child { margin-top: 0; }
.r-item {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: var(--r-2);
  font-size: var(--t-sm); color: var(--ink-2);
  transition: background var(--d-1) var(--smooth), color var(--d-1) var(--smooth);
}
.r-item:hover { background: var(--surface-2); color: var(--ink); }
.r-item.on { background: var(--surface-2); color: var(--ink); box-shadow: inset 2px 0 0 var(--accent); }
.r-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.r-dot.off { background: var(--ink-3); }
.r-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.r-val { margin-left: auto; font-weight: 650; white-space: nowrap; }

@media (max-width: 1000px) {
  .rail {
    position: sticky; z-index: 40;
    top: calc(var(--bar-h) + var(--safe-t) + 8px);
    flex-direction: row; align-items: center; gap: var(--sp-2);
    max-height: none; overflow-x: auto; overflow-y: hidden;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
    background: var(--bg); border-bottom: 1px solid var(--line);
    padding: 9px 0;
  }
  .rail::-webkit-scrollbar { display: none; }
  .r-group { display: none; }
  .r-item {
    flex: none; padding: 6px 12px;
    border: 1px solid var(--line-2); border-radius: var(--r-full);
    background: var(--surface);
  }
  .r-item.on {
    border-color: var(--accent); color: var(--accent);
    background: var(--accent-sunk); box-shadow: none;
  }
  .cgroup { scroll-margin-top: 56px; }
}

/* -- canvas sections --------------------------------------------------- */

.cgroup { margin-top: var(--sp-7); }
.cgroup:first-of-type { margin-top: var(--sp-5); }
.cgroup-h {
  display: flex; align-items: baseline; gap: var(--sp-3);
  border-bottom: 1px solid var(--line-2);
  padding-bottom: 9px; margin-bottom: var(--sp-4);
}
.cgroup-h h2 { font-size: var(--t-h2); font-weight: 700; letter-spacing: -0.02em; }
.cgroup-h .btn { margin-left: auto; }

/* -- component cards ---------------------------------------------------- */

.bucket + .bucket { margin-top: var(--sp-5); }
.bucket-h { display: flex; align-items: baseline; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.bucket-h h3 { font-size: var(--t-h3); font-weight: 650; color: var(--ink); }
.bucket-score {
  font-size: var(--t-sm); font-weight: 700; color: var(--ink);
  background: var(--surface-3); border-radius: var(--r-1); padding: 2px 8px;
}
.bucket-share { margin-left: auto; font-size: var(--t-xs); color: var(--ink-3); }
.bucket-empty { font-size: var(--t-sm); color: var(--ink-3); padding: var(--sp-2) 0; }

.cc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: var(--sp-3); }
.cc { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-3); padding: var(--sp-4); }
.cc.off { opacity: .6; }
.cc-head { display: flex; align-items: baseline; gap: var(--sp-2); }
.cc-head h4 { font-size: var(--t-body); font-weight: 600; color: var(--ink); flex: 1; min-width: 0; }
.cc-score { font-size: 1.1rem; font-weight: 650; }
.cc .meter { margin-top: var(--sp-3); }
.cc-val { margin-top: var(--sp-3); font-size: var(--t-sm); font-weight: 600; color: var(--ink); }
.cc-val span { display: block; font-size: var(--t-xs); font-weight: 400; color: var(--ink-3); margin-top: 2px; }
.cc-unit { font-size: var(--t-xs); color: var(--ink-3); margin-top: 4px; }
.cc-spark { width: 100%; height: 30px; margin-top: var(--sp-3); color: var(--accent); }
.cc-spark path { fill: none; stroke: currentColor; stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.cc-spark-area { fill: currentColor; opacity: .1; stroke: none; }
.cc-spark-dot { fill: currentColor; stroke: var(--surface); stroke-width: 1.5; }
.cc-meta {
  display: flex; gap: var(--sp-2); flex-wrap: wrap;
  margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--line);
  font-size: var(--t-xs); color: var(--ink-3);
}
.cc-meta a { color: var(--ink-2); }
.cc-meta a:hover { color: var(--accent); }

.prov-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 9px 0; border-bottom: 1px solid var(--line);
  font-size: var(--t-sm);
}
.prov-row:last-child { border-bottom: 0; }
.prov-label { color: var(--ink); font-weight: 550; }
.prov-val { color: var(--ink-2); }
.prov-days { margin-left: auto; color: var(--ink-3); font-size: var(--t-xs); }

/* -- system section ------------------------------------------------------ */

.sys-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 8px 0; border-bottom: 1px solid var(--line);
  font-size: var(--t-sm);
}
.sys-row:last-child { border-bottom: 0; }
.sys-row .live-dot { flex: none; }
.sys-src { color: var(--ink-3); font-size: var(--t-xs); }
.sys-as { margin-left: auto; color: var(--ink-3); white-space: nowrap; }
/* ════════════════════════════════════════════════════════ design pass ═══
   The 2026-08-26 pass, folded in after preview approval. Surface,
   hierarchy and feedback only — the layout beneath is the cockpit from
   PR #10. Every change traces to a named practice at a named competitor
   or is rejected with a reason; the benchmark table lives in
   docs/design-pass-2026-08-26.md, and each block carries its reference
   inline. */

/* 1 · The rail reads as structure, not a list ═══════════════════════
   Glassnode's sidebar: a hairline separates navigation from content, the
   nav column is wide enough for its values, and groups are typography
   rather than boxes. A list floating in gap-less space reads as a widget;
   the same list against a rule reads as the frame of the page. */

.cockpit { grid-template-columns: 244px minmax(0, 1fr); gap: 0 40px; }

.rail {
  border-right: 1px solid var(--line);
  padding-right: 22px;
  top: calc(var(--bar-h) + var(--safe-t) + 16px);
}

.r-group {
  display: flex; align-items: center; gap: 10px;
  margin: 20px 0 5px; padding: 0;
}
.r-group:first-child { margin-top: 0; }
.r-group::after { content: ""; flex: 1; height: 1px; background: var(--line); }

/* ═══ 2 · The active rail item is a pill, not a bar ════════════════════
   Linear/Vercel product standard: selection is a soft tinted pill with
   the label carrying the accent. The shipped inset bar works but the
   pill survives small screens better and matches the mobile chips. The
   value text stays neutral ink — colour is the sector dot's job, never
   the number's (charter: no judgement colouring on figures). */

.r-item { border-radius: var(--r-full); padding: 6px 12px 6px 10px; }
.r-item:hover { background: var(--surface-2); }
.r-item.on {
  background: var(--accent-sunk);
  color: var(--ink);
  box-shadow: none;
}
.r-item.on .r-label { color: var(--accent); font-weight: 650; }
.r-val { font-weight: 600; }

/* ═══ 3 · Section headers: numbered, calmer ════════════════════════════
   Vercel/Linear heading pattern: a small numbered kicker, the title,
   the sub, the action — with a short accent tick under the group rather
   than a full-width rule. Full-width rules at every section stack into
   stripes; one 56px tick anchors the hierarchy with less ink. */

.cgroup { margin-top: 52px; }
.cgroup:first-of-type { margin-top: var(--sp-6); }

.cgroup-h {
  border-bottom: 0;
  position: relative;
  gap: 10px;
  padding-bottom: 12px;
  margin-bottom: var(--sp-5);
}
.cgroup-h::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 56px; height: 2px; border-radius: 2px; background: var(--accent);
}
.cgroup-h h2 { font-size: 1.22rem; letter-spacing: -0.022em; }
.ck {
  font-size: var(--t-label); font-weight: 700; letter-spacing: .18em;
  color: var(--ink-3); align-self: center;
  border: 1px solid var(--line-2); border-radius: var(--r-1);
  padding: 3px 7px;
}

/* ═══ 4 · Cards answer the pointer ═════════════════════════════════════
   Industry-standard affordance on Glassnode/CryptoQuant metric cards:
   hover darkens the border and lifts a pixel with a soft shadow. The
   cards are not links, but they are the objects on the page, and an
   object that acknowledges the pointer reads as finished. Durations
   stay on the token scale; bd.css's reduced-motion rule clamps them. */

.instrument, .cc {
  transition: border-color var(--d-2) var(--smooth),
              transform var(--d-2) var(--ease),
              box-shadow var(--d-2) var(--ease);
}
.instrument:hover, .cc:hover {
  border-color: var(--line-2);
  transform: translateY(-1px);
  box-shadow: var(--e-2);
}

/* ═══ 5 · The status line tightens ═════════════════════════════════════
   Kept on CryptoQuant's evidence (status as a first-class line); it now
   sits inline in the masthead rather than in its own boxed strip, so the
   panel's first instrument lands sooner. */

.ann-strip { gap: 14px; letter-spacing: .1em; }
.ann-sep { opacity: .4; }

/* ═══ 6 · System section as a table ════════════════════════════════════
   CryptoQuant's tables: a column header row, hairline rows, right-set
   timestamps. The shipped plain rows have no header, so "what these
   three columns are" is inferred; a header says it once. */

.sys-panel {
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  background: var(--surface);
  padding: 4px 18px 8px;
}
.sys-head, .sys-row {
  display: grid;
  grid-template-columns: 18px minmax(0, 1.5fr) minmax(0, 1fr) 96px;
  gap: 12px;
  align-items: center;
}
.sys-head {
  font-size: var(--t-label); font-weight: 650; letter-spacing: var(--track);
  text-transform: uppercase; color: var(--ink-3);
  padding: 10px 0 8px;
  border-bottom: 1px solid var(--line-2);
}
.sys-row { padding: 9px 0; }
.sys-row:last-child { border-bottom: 0; }

/* ═══ 7 · Hero scannability ════════════════════════════════════════════
   CFGI/alternative.me's one honest strength: the number is huge and
   instant. The hero cards' stat values step up one size so the reading
   is legible at a scroll's distance without enlarging the dial. */

.instrument.hero .i-stat dd { font-size: 1.06rem; }

/* ═══ 8 · Mobile chip bar gains the bar's own glass ════════════════════
   The sticky top bar blurs (bd.css); the shipped chip bar did not,
   so content scrolled behind it as a solid band — visible seam. Same
   backdrop as the bar: the page reads as one continuous instrument. */

@media (max-width: 1000px) {
  .cockpit { grid-template-columns: minmax(0, 1fr); }
  .rail {
    border-right: 0; padding-right: 0;
    background: color-mix(in srgb, var(--bg) 86%, transparent);
    -webkit-backdrop-filter: saturate(180%) blur(16px);
    backdrop-filter: saturate(180%) blur(16px);
  }
  .r-item.on { background: var(--accent-sunk); }
  .cgroup { margin-top: 40px; scroll-margin-top: 60px; }
}

/* ═══ 10 · Components: each bucket reads as one instrument group ═══════
   CryptoQuant's group framing: the bucket header is a band with its
   summary figure prominent, and inside each card ONE number leads. The
   score leads — it is the dial's currency — and the concrete reading
   (views/day, $/day) steps down to the secondary line. An empty bucket
   or a burn-in collector renders as an instrument being installed
   (dashed outline), which is what it is, rather than as a gap. */

.bucket-h {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  padding: 10px 14px;
  margin-bottom: var(--sp-4);
}
.bucket-h h3 { font-size: 0.98rem; }
.bucket-score {
  font-size: 1.3rem; font-weight: 650; letter-spacing: -0.01em;
  background: none; padding: 0;
}
.bucket + .bucket { margin-top: var(--sp-6); }

.cc-head { align-items: baseline; gap: var(--sp-3); }
.cc-score { font-size: 1.45rem; font-weight: 650; letter-spacing: -0.01em; }
.cc-val { margin-top: var(--sp-2); font-weight: 500; color: var(--ink-2); }

.bucket-empty {
  border: 1px dashed var(--line-3);
  border-radius: var(--r-3);
  padding: var(--sp-4) var(--sp-5);
  text-align: center;
}
.prov-row {
  border: 1px dashed var(--line-2);
  border-radius: var(--r-2);
  padding: 9px 14px;
  margin-bottom: var(--sp-2);
}
.prov-row:last-child { margin-bottom: 0; }

/* ══════════════════════════════════════════════════════════ the opening ═══
   The participation index opens the panel as the master instrument
   (above); the FOMO meter follows as the section's hero at full width —
   dial and its readings side by side, stacking below 1000px. */

#g-composite .panel-grid .instrument.hero { grid-column: 1 / -1; }
#g-composite .instrument.hero .i-dial svg { max-width: 380px; }

/* ════════════════════════════════════════════════════════ master band ═══
   The participation index as the panel's opening instrument — the page's
   namesake, at the scale that deserves. One card, three registers:
   the dial (left), the reading with the composite's buckets (right),
   and the decade of published readings as one scrub surface (below).
   Trace that surface and the needle winds to the day under the
   pointer — readout, band, tone and the face engraving follow it; leave
   it and the instrument eases back to today. */

.instrument.master {
  grid-column: 1 / -1;
  padding: var(--sp-6);
  gap: var(--sp-5);
  /* The master sits on the sunk ground like every card, but its tone cap
     is doubled: the index is the page's subject, and the band it is in
     gets more than 3px of ink at the top edge. */
}
.instrument.master::before { height: 4px; }

.m-grid {
  display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  gap: var(--sp-5) var(--sp-7);
  align-items: center;
}
.m-dial { display: grid; place-items: center; }
.m-dial svg { width: 100%; max-width: 440px; height: auto; }
/* The dial's own digital readout steps down a size: the giant figure in
   the side column is the reading at display scale, and the two should
   read as primary and secondary, not compete. */
.instrument.master .d-read { font-size: 40px; }

.m-side {
  min-width: 0;
  display: flex; flex-direction: column; gap: var(--sp-4);
}

.m-readrow {
  display: flex; align-items: baseline; gap: var(--sp-3) var(--sp-4);
  flex-wrap: wrap;
}
.m-read {
  font-size: clamp(3rem, 2.2rem + 2.6vw, 4.35rem);
  font-weight: 700; letter-spacing: -0.045em; line-height: 0.95;
  color: var(--ink);
}
/* "/ 100" sits on the number's baseline — a unit, not a label. */
.m-read-unit {
  font-size: var(--t-sm); font-weight: 650; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3);
}
.m-readrow .i-band { order: 3; }
.m-readrow .i-cad { order: 4; }

.m-stats {
  grid-auto-flow: row; grid-auto-columns: auto;
  grid-template-columns: 1fr 1fr;
}
.m-stats .i-stat { border-left: 0; border-top: 1px solid var(--line); }
.m-stats .i-stat:nth-child(-n+2) { border-top: 0; }
.m-stats .i-stat:nth-child(even) { border-left: 1px solid var(--line); }
.m-stats .i-stat dd { font-size: 1.06rem; }

/* The composite's buckets: what the index is made of, as four meters on
   the same 0–100 scale the needle reads. A bucket still in burn-in shows
   an empty track and a dash — an instrument being installed. */
.m-buckets {
  display: grid; gap: 9px;
  padding-top: var(--sp-1);
}
.m-bucket {
  display: grid; grid-template-columns: 108px minmax(0, 1fr) 30px;
  gap: var(--sp-3); align-items: center;
}
.m-bk-label {
  font-size: var(--t-label); font-weight: 650; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.m-bk-score {
  font-size: var(--t-sm); font-weight: 650; color: var(--ink);
  text-align: right;
}
/* A bucket still in burn-in: no meter, no dash — the row says what it is
   doing, right-set where a score would sit. */
.m-bucket.off {
  grid-template-columns: 108px minmax(0, 1fr);
}
.m-bucket.off .m-bk-state {
  font-size: var(--t-label); font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3);
  text-align: right; align-self: center;
  border-bottom: 1px dashed var(--line-2);
  padding-bottom: 4px;
}

/* The decade surface: the tallest chart on the page, sector-banded,
   gridded, with the domain named between the first and last dates. */
.m-history .i-chart { flex: none; min-height: 196px; display: flex; flex-direction: column; }
.m-history .i-chart.tall svg { flex: 1; min-height: 164px; }

/* While the pointer reads a past day the needle answers it directly —
   the 1400ms instrument ease is for arriving, not for following. */
.instrument.master.scrubbing .d-needle { transition-duration: 110ms; }
/* The crosshair on the master is a full-height rule in the ink, not the
   dotted hairline the small cards use: it is the query. */
.m-history .sp-cursor { stroke-dasharray: none; stroke: var(--ink-2); opacity: .55; }
.m-history .i-chart.hovering .sp-cursor { opacity: .55; }

@media (max-width: 1000px) {
  .instrument.master { padding: var(--sp-5); }
  .m-grid { grid-template-columns: 1fr; gap: var(--sp-4); }
  .m-dial svg { max-width: 360px; margin: 0 auto; }
  .m-history .i-chart { min-height: 150px; }
  .m-history .i-chart.tall svg { min-height: 128px; }
}
@media (max-width: 560px) {
  .instrument.master { padding: var(--sp-4); }
  .m-dial svg { max-width: 300px; }
  .m-stats { grid-template-columns: 1fr; }
  .m-stats .i-stat { border-left: 0 !important; border-top: 1px solid var(--line); }
  .m-stats .i-stat:first-child { border-top: 0; }
  .m-bucket { grid-template-columns: 96px minmax(0, 1fr) 28px; }
  .m-bucket.off { grid-template-columns: 96px minmax(0, 1fr); }
}
