/* ============================================================
   Bitcoin Hull — design system (task 01, locked)
   Dark-only. Tokens are the contract — panels use roles, not hex.
   ============================================================ */

:root {
  color-scheme: dark;

  /* surfaces */
  --bg:        #0b0e13;
  --surface:   #131822;
  --surface-2: #1a2130;
  --border:    rgba(255, 255, 255, 0.08);

  /* ink — whitened (Joe, 2026-07-26: "the grey is too hard to see").
     The old ramp was measured, not guessed: --ink-mut #6b7484 came in at
     3.77:1 on --surface, UNDER the 4.5:1 AA floor, and it carried the
     smallest type on the page (9.5px credits, 10px hero-subs, the 11.5px
     integrity note). Both muted steps move up; --ink is already white and
     stays put, so the three-step hierarchy survives at roughly
     7.6 / 11.9 / 16.1 against --surface instead of 3.8 / 8.4 / 16.1. */
  --ink:     #f2f4f8;  /* 16.14:1 on --surface */
  --ink-2:   #ccd4e0;  /* 11.90:1 — was #aab3c2, 8.41:1 */
  --ink-mut: #a0aaba;  /*  7.58:1 — was #6b7484, 3.77:1 (AA fail) */

  /* brand */
  --accent: #f7931a;

  /* status (validated set — never reuse as series colors).
     Re-lit with the ink ramp (Joe, 2026-07-26: "make it tight"). Each is
     measured as TEXT on its own tinted pill, which is the hardest case —
     the pill tint is the same hue as the label, so it eats contrast. The
     old set had --critical at 3.32:1, a worse AA failure than the grey
     that started this, and invisible in the audit because nothing was
     broken at the time. Hue relationships are preserved, so the palette
     still reads as the same four states: the serious/critical gap is 18°
     against the old set's 17°, warn/accent 8° unchanged. */
  --good:     #34d058;  /* 7.06:1 on its pill — was #0ca30c, 4.61:1 */
  --warn:     #fab219;  /* 7.74:1 — already clear, left alone */
  --serious:  #f4a583;  /* 7.18:1 — was #ec835a, 5.66:1 */
  --critical: #fa9d9d;  /* 6.78:1 — was #d03b3b, 3.32:1 (AA fail) */

  --radius: 10px;
  --radius-sm: 8px;
  --font: system-ui, -apple-system, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.45;
  min-height: 100vh;
  padding: 6px clamp(14px, 3vw, 32px) 24px;
  max-width: 1360px;
  margin: 0 auto;
}

::selection { background: rgba(247, 147, 26, 0.35); }

/* every live value: no width jitter, vertical alignment in rows */
.val, .hero-num, .tip-num { font-variant-numeric: tabular-nums; }

/* ---------------- header ---------------- */

.hull-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 0 2px 3px;
}

.wordmark {
  font-size: 26px;
  letter-spacing: 0.14em;
  color: var(--accent);
  font-weight: 400;
  white-space: nowrap;
}
.wordmark b { color: var(--ink); font-weight: 700; }

/* the brand ship sails to the RIGHT of the wordmark (task 20, Joe;
   upsized task 21, +50% again task 26 — name 26px, ship 132px; the
   SVG viewBox is cropped to the artwork so the box stays short) */
.brand { display: flex; align-items: center; gap: 16px; min-width: 0; }
.brand-ship { width: 132px; height: 63px; flex: none; }

.header-right {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
}

.tip { white-space: nowrap; }
.tip-label {
  font-size: 11px;
  letter-spacing: 0.12em;
  color: var(--ink-mut);
  margin-right: 6px;
}
.tip-num {
  font-size: 26px;
  font-weight: 700;
  color: var(--accent);
}

/* ---------------- chips & pills (status: always dot + TEXT) ---------------- */

.chip, .pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
}
.chip .dot, .pill .dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

.chip-static  { color: var(--ink-mut);  background: rgba(255,255,255,0.06); }
.chip-live, .pill-good     { color: var(--good);     background: rgba(12,163,12,0.12); }
.chip-polling              { color: var(--ink-2);    background: rgba(255,255,255,0.07); }
.chip-degraded, .pill-warn { color: var(--warn);     background: rgba(250,178,25,0.12); }
.pill-serious              { color: var(--serious);  background: rgba(236,131,90,0.12); }
.chip-down, .pill-critical { color: var(--critical); background: rgba(208,59,59,0.14); }
.pill-plain                { color: var(--ink-2);    background: rgba(255,255,255,0.07); }

/* ---------------- grid & panels ---------------- */

/* task 17 (Joe, 2026-07-18): density pass — stat blocks at ~half their
   v1.1 footprint so two major rows fit above the fold. Type floors are
   legibility-bound, not literal 50% (11.5px rows / 10px labels). */
.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 5px;
}

.span-12 { grid-column: span 12; }
.span-4  { grid-column: span 4; }

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 5px 10px 5px;
  min-width: 0;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 3px;
}

.panel-head h2 {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.panel-side { font-size: 12.5px; color: var(--ink-mut); white-space: nowrap; }
.panel-side .val { color: var(--ink-2); font-weight: 600; }

/* ---------------- hero metric ---------------- */

.metric-hero {
  display: flex;
  align-items: baseline;
  gap: 5px;
  margin: 0;
}
.hero-num {
  font-size: clamp(17px, 1.55vw, 20px);
  font-weight: 650;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.hero-unit { font-size: 10.5px; color: var(--ink-mut); font-weight: 500; }
.hero-cur  { align-self: flex-start; margin-top: 3px; }
.hero-sub  { font-size: 10px; color: var(--ink-mut); margin-bottom: 0; }
/* task 28: a hero-sub may carry a courtesy-credit link (lightning panel) —
   same muted treatment as .panel-credit a */
.hero-sub a { color: var(--ink-2); text-decoration: none; }
.hero-sub a:hover, .hero-sub a:focus-visible { text-decoration: underline; }

/* ---------------- label/value rows ---------------- */

.rows { margin-top: 0; }
.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 2px 0;
  border-top: 1px solid var(--border);
  font-size: 11px;
  color: var(--ink-2);
}
.row .val { color: var(--ink); font-weight: 600; white-space: nowrap; }

/* progress bars: bar is decoration, the % TEXT is the datum */
.row-bar .bar-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  max-width: 62%;
}
.bar {
  flex: 1;
  height: 6px;
  background: var(--surface-2);
  border-radius: 3px;
  overflow: hidden;
}
.bar-fill {
  display: block;
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
}
/* integrity bar fill carries the verdict's status color — never alone,
   the pill beside it always holds the text label (house rule) */
.bar-fill.fill-good     { background: var(--good); }
.bar-fill.fill-warn     { background: var(--warn); }
.bar-fill.fill-serious  { background: var(--serious); }
.bar-fill.fill-critical { background: var(--critical); }

/* ---------------- BitcoinHull Integrity strip ---------------- */

details.integrity { padding: 0; }

.integrity summary {
  display: flex;
  align-items: center;
  flex-wrap: wrap; /* the note wraps to its own line under the bar */
  gap: 14px;
  padding: 5px 14px;
  cursor: pointer;
  list-style: none;
  /* the whole strip is the control (Joe, 2026-07-26) — so it lights up as
     one. Corners follow the panel's own radius: shut, the summary IS the
     panel; open, only its top corners are round. */
  border-radius: var(--radius) var(--radius) 0 0;
  transition: background 0.15s ease;
}
.integrity:not([open]) summary { border-radius: var(--radius); }
.integrity summary:hover { background: rgba(255, 255, 255, 0.04); }
.integrity summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* always-visible note under the bar (Joe, 2026-07-17) */
.integrity-note {
  flex-basis: 100%;
  font-size: 11.5px;
  color: var(--ink-mut);
  margin-top: -2px;
}

.integrity summary::-webkit-details-marker { display: none; }

.integrity-title {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
}

.integrity-helm { color: var(--accent); font-size: 15px; margin-right: 7px; vertical-align: -1px; }
.integrity-brand { color: var(--accent); }

/* the hull gauge: taller track, inset depth, notches at the verdict-band
   thresholds (40/65/85 — decoration only, the pill carries the verdict),
   glossed fill with a glow in the verdict's own status color */
.integrity-bar {
  height: 12px;
  border-radius: 6px;
  position: relative;
  overflow: visible; /* the glow must escape the track */
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.55);
}
.integrity-bar::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: 6px;
  background:
    linear-gradient(90deg, transparent calc(40% - 1px), rgba(255,255,255,0.20) calc(40% - 1px), rgba(255,255,255,0.20) calc(40% + 1px), transparent calc(40% + 1px)),
    linear-gradient(90deg, transparent calc(65% - 1px), rgba(255,255,255,0.20) calc(65% - 1px), rgba(255,255,255,0.20) calc(65% + 1px), transparent calc(65% + 1px)),
    linear-gradient(90deg, transparent calc(85% - 1px), rgba(255,255,255,0.20) calc(85% - 1px), rgba(255,255,255,0.20) calc(85% + 1px), transparent calc(85% + 1px));
}
.integrity-bar .bar-fill {
  border-radius: 6px;
  background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0) 60%);
  transition: width 0.6s ease;
}
.integrity-bar .bar-fill.fill-good     { box-shadow: 0 0 12px color-mix(in srgb, var(--good) 50%, transparent); }
.integrity-bar .bar-fill.fill-warn     { box-shadow: 0 0 12px color-mix(in srgb, var(--warn) 50%, transparent); }
.integrity-bar .bar-fill.fill-serious  { box-shadow: 0 0 12px color-mix(in srgb, var(--serious) 50%, transparent); }
.integrity-bar .bar-fill.fill-critical { box-shadow: 0 0 12px color-mix(in srgb, var(--critical) 50%, transparent); }

.integrity-score { white-space: nowrap; }
.integrity-score .val { font-size: 24px; font-weight: 700; }
.integrity-outof { font-size: 12px; color: var(--ink-mut); margin-left: 2px; }

/* the dropdown affordance (Joe, 2026-07-26). A bare muted ▾ read as
   decoration — nothing on the strip said "there is more under this". So the
   caret now sits in an accent chip that says it in WORDS and flips its label
   on open, the row lights on hover/focus above, and the caret nudges three
   times while the panel is shut. It rides the summary's FIRST line: the
   task-21 fit bar (12 panels + strip ≤ 940 px at 1280) means this strip
   cannot grow a row on desktop. */
.integrity-toggle {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 50%, transparent);
  transition: background 0.15s ease, border-color 0.15s ease;
}
.integrity summary:hover .integrity-toggle,
.integrity summary:focus-visible .integrity-toggle {
  background: color-mix(in srgb, var(--accent) 28%, transparent);
  border-color: var(--accent);
}
/* one label is always display:none, so the summary's accessible name carries
   exactly the state the user can act on — "BELOW DECK" shut, "HIDE" open */
.integrity-toggle-open { display: none; }
.integrity[open] .integrity-toggle-shut { display: none; }
.integrity[open] .integrity-toggle-open { display: inline; }

/* deliberately OVERSIZED against the 11px label (Joe, 2026-07-26) — the
   arrow is the part people read as "clickable", so it outweighs the words.
   line-height 1 keeps the bigger glyph inside the chip's own height, so the
   strip still costs the fit bar nothing. */
.integrity-caret {
  color: inherit;
  font-size: 16px;
  line-height: 1;
  transition: transform 0.15s ease;
}
.integrity[open] .integrity-caret { transform: rotate(180deg); }

/* discoverability, not decoration: three beats and it stops on its own */
@keyframes hull-caret-nudge {
  0%, 70%, 100% { transform: translateY(0); }
  80%           { transform: translateY(3px); }
}
.integrity:not([open]) .integrity-caret {
  animation: hull-caret-nudge 2.2s ease-in-out 3;
}

/* the click cue on the always-visible note — retired once the panel is open */
.integrity-cue { color: var(--ink-2); }
.integrity[open] .integrity-cue { display: none; }

.integrity-detail {
  border-top: 1px solid var(--border);
  padding: 10px 18px 14px;
}
.integrity-blurb { font-size: 12.5px; color: var(--ink-mut); margin-bottom: 4px; }
/* tiny polarity note beside a dropdown metric label (task 21) */
.int-note { font-size: 10px; color: var(--ink-mut); margin-left: 4px; }

/* ---------------- chain-tip block strip ---------------- */

.block-strip {
  display: flex;
  gap: 7px;
  overflow-x: auto;
  padding-bottom: 2px;
  scrollbar-width: thin;
  scrollbar-color: var(--surface-2) transparent;
}

.block-tile {
  flex: 1 0 92px;
  min-width: 92px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 3px 7px;
}

.bt-height {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  margin-bottom: 2px;
}
.bt-line { font-size: 10.5px; color: var(--ink-mut); line-height: 1.5; }
.bt-line .val { color: var(--ink-2); font-weight: 600; }
.bt-age {
  margin-top: 2px;
  font-size: 10px;
  color: var(--ink-mut);
}

.block-next {
  background: transparent;
  border: 1px dashed rgba(247, 147, 26, 0.45);
}
.block-next .bt-height { color: var(--accent); letter-spacing: 0.08em; }
.block-next .bt-age { color: var(--accent); }

/* ---------------- mempool mini-viz (fed by js/panels/05-mempool.js) ---------------- */

.mini-viz {
  display: flex;
  gap: 2px; /* the 2px surface gap between adjacent fills */
  height: 12px;
  margin: 5px 0 2px;
}
.viz-caption {
  font-size: 9.5px;
  color: var(--ink-mut);
  margin: 0 0 4px;
}
.mini-viz .seg {
  position: relative;
  background: var(--surface-2);
  border-radius: 3px;
  min-width: 4px;
}
.mini-viz .seg-label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 600;
  color: var(--ink); /* light ink for the ramp's dark steps */
  font-variant-numeric: tabular-nums;
  white-space: nowrap; /* a label that doesn't fit is skipped by JS, never cropped */
}
.mini-viz .seg-label-dark { color: var(--bg); } /* dark ink for the ramp's light steps */

/* per-panel data credit (task 12 — Clark-style, permanent) */
.panel-credit {
  margin-top: 6px;
  font-size: 9.5px;
  color: var(--ink-mut);
}
.panel-credit a { color: var(--ink-2); text-decoration: none; }
.panel-credit a:hover, .panel-credit a:focus-visible { text-decoration: underline; }

/* minor tier RETIRED (task 19, Joe 2026-07-18): one equal-size tier,
   all 12 panels visible at once. The .panel-minor / .asof classes died
   with it. */

/* ---------------- honest states (contract for tasks 02+) ---------------- */

/* Stale dimming is a REDUNDANT cue — the STALE tag and the dashed-out values
   carry the meaning (house rule: state never rides on colour alone), so this
   only has to whisper. At 0.55 it was shouting over the text: the whole panel
   composites against the page, dragging --ink-mut to 3.10:1 and --ink-2 to
   4.34:1, both under AA, in the one state whose entire job is to be read.
   (Before the 2026-07-26 ink pass it was 1.95:1 — effectively unreadable.)
   0.80 still reads as visibly dimmed and keeps every token above AA. The
   binding case is NOT the panel surface — it is the block tiles on the
   lighter --surface-2, where --ink-mut lands ~0.5 lower; 0.75 cleared the
   panel body at 4.76 but left the tiles at 4.45, so the whole-page stale
   sweep is the check that matters, not a single panel. */
.panel.stale { opacity: 0.80; }
.stale-tag {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--warn);
  /* pill boundary: amber-on-orange hue contrast alone is ~1.25:1 since the
     panel titles went accent — the box is what reads as "tag" now */
  background: rgba(250, 178, 25, 0.14);
  padding: 1px 5px;
  border-radius: 3px;
}
.loading { color: var(--ink-mut); }
.val.loading, .panel-side .val.loading { color: var(--ink-mut); font-weight: 400; }

/* since-last-block escalation — color always paired with the SLOW text tag */
.slow-tag { font-size: 10px; font-weight: 700; letter-spacing: 0.1em; }
.since-warn, .panel-side .val.since-warn { color: var(--warn); }
.since-serious, .panel-side .val.since-serious { color: var(--serious); }

@keyframes hull-flash {
  0%   { background: rgba(247, 147, 26, 0.22); }
  100% { background: transparent; }
}
.flash { animation: hull-flash 0.9s ease-out; }

/* the quieter sibling: value changed, but it's routine (price ticks) —
   dim→normal ink, no color pulse */
@keyframes hull-flash-dim {
  0%   { color: var(--ink-mut); }
  100% { color: var(--ink); }
}
.flash-dim { animation: hull-flash-dim 0.9s ease-out; }

/* the loud sibling for the block strip: a block just landed (task 09) —
   accent wash that settles back into the tile's own surface */
@keyframes hull-flash-tile {
  0%   { background: rgba(247, 147, 26, 0.26); border-color: rgba(247, 147, 26, 0.55); }
  100% { background: var(--surface-2); border-color: var(--border); }
}
.flash-tile { animation: hull-flash-tile 0.9s ease-out; }

@media (prefers-reduced-motion: reduce) {
  .flash, .flash-dim, .flash-tile { animation: none; }
  .integrity-caret { transition: none; }
  /* same specificity as the rule that sets it, and later in the file */
  .integrity:not([open]) .integrity-caret { animation: none; }
  .integrity-bar .bar-fill { transition: none; }
  .integrity summary, .integrity-toggle { transition: none; }
}

/* ---------------- footer ---------------- */

.hull-footer {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 16px 2px 0;
  font-size: 11.5px;
  color: var(--ink-mut);
}
.hull-footer a { color: var(--accent); text-decoration: none; }
.hull-footer a:hover, .hull-footer a:focus-visible { text-decoration: underline; }

/* the Clark Moody credit — permanent, always the last line of the page */
.foot-credit { flex-basis: 100%; color: var(--ink-2); }

/* ---------------- responsive ---------------- */

@media (max-width: 1100px) {
  .span-4 { grid-column: span 6; }
}

@media (max-width: 720px) {
  .span-4 { grid-column: span 12; }
  body { padding: 14px 12px 20px; }
  .tip-num { font-size: 22px; }
  /* task 26: the upsized brand must still fit a 375px header line */
  .wordmark { font-size: 20px; }
  .brand-ship { width: 100px; height: 48px; }
  .panel-side { white-space: normal; text-align: right; }
  .block-tile { flex: 0 0 92px; }
  .integrity summary { flex-wrap: wrap; gap: 10px; }
  .integrity-bar { flex-basis: 100%; order: 5; }
  /* phones scroll (task 25), so the toggle stops competing for the title's
     line and becomes a full-width button under the gauge — the affordance
     the desktop chip can only imply, plus a real tap target */
  .integrity-toggle {
    order: 6;
    flex-basis: 100%;
    justify-content: center;
    padding: 7px 10px;
  }
  /* task 25: the 11px density floor exists for the DESKTOP fold; phones
     scroll anyway — give rows and titles back some size */
  .row { font-size: 12.5px; }
  /* task 31: an integrity row now carries current + 3-yr median + trajectory,
     which is past a 375px line — let it wrap rather than push the panel wide
     (same treatment as .panel-side above; other panels keep their nowrap) */
  .integrity-detail .row .val { white-space: normal; text-align: right; }
  .panel-head h2 { font-size: 11px; }
  .hero-sub { font-size: 11.5px; }
  /* single-column read order (Joe, 2026-07-19) — visual only, the DOM keeps
     the desktop order; integrity stays first at its default order:0 */
  #panel-price        { order: 1; }
  #panel-mining       { order: 2; }
  #panel-nodes        { order: 3; }
  #panel-blockchain   { order: 4; }
  #panel-supply       { order: 5; }
  #panel-halving      { order: 6; }
  #panel-mempool      { order: 7; }
  #panel-fees         { order: 8; }
  #panel-retarget     { order: 9; }
  #panel-transactions { order: 10; }
  #panel-lightning    { order: 11; }
  #panel-treasuries   { order: 12; }
  #panel-chain        { order: 13; }
}
