/* WhaleFlows — CT/terminal aesthetic. Pure black, monospace, neon green/red.
   Mobile-first: layout starts in a single column; charts and flows reflow at
   wider breakpoints. No CSS framework — this is one file, hand-written. */

:root {
  --bg: #000000;
  --bg-elev: #0a0a0a;
  --bg-card: #0e0e0e;
  --border: #1a1a1a;
  --border-bright: #2a2a2a;
  --text: #e8e8e8;
  --text-dim: #888888;
  --text-faint: #555555;
  --up: #34d399;       /* tailwind emerald-400 */
  --down: #f87171;     /* tailwind red-400 */
  --accent: #34d399;   /* same green as 'up' for brand cohesion */
  --accent-dim: #1f6f57;
  --warn: #fbbf24;
  --mono: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, Consolas, "Roboto Mono", monospace;
  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html {
  scroll-behavior: smooth;
  /* Reserve scrollbar gutter permanently so the header doesn't shift
     width when navigating between short pages (no scrollbar) and long
     pages (scrollbar appears). Supported in all modern browsers. */
  scrollbar-gutter: stable;
}
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--mono);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.skip {
  position: absolute;
  left: -9999px;
  top: auto;
}
.skip:focus {
  position: static;
  display: inline-block;
  margin: 8px;
  padding: 8px 12px;
  background: var(--accent);
  color: var(--bg);
}

/* ──────────────── Hero ──────────────── */

.hero {
  /* No border-bottom — that line was the visible seam j73w spotted in pass 8.
     The hero ends, the mood gradient just continues underneath into the
     first content section. Background is also transparent so the page-wide
     mood gradient + matrix-drift canvas bleed through end-to-end. The
     subtle emerald radial accent above the brand stays as a translucent
     overlay (it composites OVER the mood, not as a replacement bg). */
  background: radial-gradient(1200px 400px at 50% -120px, rgba(52, 211, 153, 0.08), transparent 70%);
  padding: 24px 20px 28px;
}
.hero-inner {
  max-width: 1100px;
  margin: 0 auto;
}
.brand {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 28px;
  letter-spacing: -0.5px;
}
.brand-mark {
  color: var(--accent);
  font-weight: 700;
}
.brand-name {
  font-weight: 600;
  letter-spacing: -1px;
}
.brand-tld {
  color: var(--text-dim);
  font-weight: 400;
}
.tagline {
  margin: 14px 0 28px;
  color: var(--text-dim);
  max-width: 760px;
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.55;
}
.tagline a { color: var(--accent); }
/* Pass 11.0d — leaning the tagline into the brand mood. The leading >_
   matches the topnav brand-mark; ticker tokens (.tagline-em) glow in the
   up-color so ETH/BTC/LINK pop without being shouty; the trailing
   .tagline-cursor block uses the mono font + a blinking caret for that
   off-the-wire-terminal vibe. The animation honors prefers-reduced-motion
   below in the same block as the cred-cursor pulse. */
.tagline .tagline-mark {
  color: var(--up);
  font-family: var(--mono);
  font-weight: 700;
  letter-spacing: 1px;
  margin-right: 6px;
}
.tagline .tagline-em {
  color: var(--up);
  font-family: var(--mono);
  font-weight: 600;
  letter-spacing: 0.5px;
}
.tagline .tagline-cursor {
  font-family: var(--mono);
  color: var(--text-faint);
  font-size: 13px;
  letter-spacing: 0.5px;
}
.tagline .tagline-blink {
  display: inline-block;
  width: 0.55em;
  color: var(--up);
  animation: cred-blink 1.05s steps(1, end) infinite;
}
@media (prefers-reduced-motion: reduce) {
  .tagline .tagline-blink { animation: none; opacity: 0.85; }
}

/* Small "where the numbers come from" tag, sits between the tagline and the
   live price strip. Keeps the answer to "what feed is this?" one glance away
   without crowding the price card. */
.hero-source {
  margin: -12px 0 18px;
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.5px;
}
.hero-source-em {
  color: var(--text-dim);
}

.hero-strip {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin-top: 8px;
}
.strip-cell {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 14px 18px;
  display: flex;
  align-items: baseline;
  gap: 16px;
  flex-wrap: wrap;
}
.strip-label {
  font-size: 13px;
  color: var(--text-faint);
  letter-spacing: 1px;
  min-width: 36px;
}
.strip-price {
  font-size: 22px;
  font-weight: 600;
}
.strip-deltas {
  display: flex;
  gap: 10px;
  margin-left: auto;
  flex-wrap: wrap;
}
.strip-delta {
  font-size: 13px;
  color: var(--text-dim);
  white-space: nowrap;
}
.strip-delta .up { color: var(--up); }
.strip-delta .down { color: var(--down); }

@media (min-width: 720px) {
  .hero-strip { grid-template-columns: repeat(3, 1fr); }
  .strip-cell { padding: 14px 18px; }
  .strip-deltas { margin-left: auto; }
}

/* ──────────────── Pass-6 page chrome (matrix bg, mood, top-nav) ──────────
   Three additions:
     1. .matrix-bg — full-viewport fixed canvas behind everything.
     2. body[data-mood="..."] — page-background gradient swap per weather/time.
     3. .topnav — shared top navigation bar across THE_DECK + THE_LOGBOOK.
   The matrix canvas sits at z-index 0 with `position: fixed; inset: 0;` and
   `pointer-events: none` so it never intercepts clicks. The body's
   background gradient sits BEHIND it (page background, painted by browser).
   All content sits on z-index 1+ with its own opaque card backgrounds so the
   matrix is a "behind the cards" effect, not a "through the cards" effect. */

#matrix-bg {
  position: fixed;
  inset: 0;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: block;       /* inline default is 300×150 — stretches badly before JS runs */
  z-index: 0;            /* above body background, below content */
  pointer-events: none;
  opacity: 0;            /* deck: revealed once app.js sizes the canvas */
  transition: opacity 0.35s ease;
}
#matrix-bg.matrix-ready {
  opacity: 0.35;         /* matches pre-flash-fix visibility */
}
/* Auth pages run an inline matrix loop (not app.js) — keep the canvas visible. */
.auth-body #matrix-bg {
  opacity: 0.35;
}

/* Mood scene gradients. All variants share the same "moonlit ocean" DNA —
   a darker top, a darker bottom, with the top color shifting based on
   weather + time of day. Transitions over 1.5s on mood change so it doesn't
   pop. Default body bg is solid #050810 (pre-mood); the data-mood attribute
   layers a gradient on top. */
body {
  background: #050810;
  transition: background 1.5s ease;
}
body:not(.mood-ready) {
  transition: none;      /* no gradient flash on first paint / cache apply */
}
body[data-mood="night-clear"]  { background: radial-gradient(ellipse at 50% -10%, #0d2444 0%, #060d18 45%, #020308 100%); }
body[data-mood="night-cloudy"] { background: linear-gradient(180deg, #181d28 0%, #080c15 60%, #020308 100%); }
body[data-mood="night-rain"]   { background: linear-gradient(180deg, #0a1d28 0%, #060c15 60%, #020308 100%); }
body[data-mood="night-storm"]  { background: linear-gradient(180deg, #1a1024 0%, #080a12 60%, #020308 100%); }
body[data-mood="day-clear"]    { background: linear-gradient(180deg, #15324a 0%, #0a141d 60%, #020308 100%); }
body[data-mood="day-cloudy"]   { background: linear-gradient(180deg, #232934 0%, #0a141d 60%, #020308 100%); }
body[data-mood="day-rain"]     { background: linear-gradient(180deg, #1a2a35 0%, #0a141d 60%, #020308 100%); }
body[data-mood="day-storm"]    { background: linear-gradient(180deg, #20182a 0%, #08090f 60%, #020308 100%); }

/* All content stacks above the matrix canvas. */
body > :not(#matrix-bg) { position: relative; z-index: 1; }
body > #matrix-bg { z-index: 0; position: fixed; }

/* ─── Version watcher banner ──────────────────────────────────────────
   Slides down from the top when /version.json reports a build that
   differs from the meta tag baked into the HTML. Default state is
   HIDDEN — `[hidden]` ordinarily competes with class rules on
   specificity, so we default to `display: none` and reveal via
   `:not([hidden])` so the same CSS gotcha that bit pass-10.4's
   cadence-pending banner can't bite us here too. The actual slide
   animation is keyed off `.is-visible` which app.js toggles on the
   next animation frame after un-hiding (toggling display + class
   in the same frame skips the transition). */
.version-banner {
  display: none;
}
.version-banner:not([hidden]) {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  background: rgba(20, 60, 80, 0.94);
  border-bottom: 1px solid rgba(120, 220, 255, 0.7);
  color: #cdf3ff;
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 13px;
  line-height: 1.4;
  box-shadow: 0 4px 18px rgba(0,0,0,0.5);
  transform: translateY(-100%);
  transition: transform 280ms cubic-bezier(0.22, 1, 0.36, 1);
}
.version-banner.is-visible { transform: translateY(0); }
.version-banner-icon { font-size: 16px; flex-shrink: 0; }
.version-banner-text { flex: 1; }
.version-banner-btn {
  background: rgba(120, 220, 255, 0.18);
  border: 1px solid rgba(120, 220, 255, 0.7);
  color: #cdf3ff;
  font-family: inherit;
  font-size: 12px;
  padding: 5px 12px;
  border-radius: 3px;
  cursor: pointer;
  text-transform: lowercase;
  letter-spacing: 0.04em;
  transition: background 160ms;
}
.version-banner-btn:hover {
  background: rgba(120, 220, 255, 0.32);
}
.version-banner-close {
  background: transparent;
  border: none;
  color: #cdf3ff;
  font-size: 20px;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
  opacity: 0.7;
}
.version-banner-close:hover { opacity: 1; }

@media (max-width: 520px) {
  .version-banner:not([hidden]) {
    padding: 8px 10px;
    font-size: 12px;
    gap: 6px;
  }
  .version-banner-text {
    /* tighter on phones — drop the "since this tab opened" tail */
    font-size: 11px;
  }
  .version-banner-btn { padding: 4px 9px; font-size: 11px; }
}

@media (prefers-reduced-motion: reduce) {
  .version-banner:not([hidden]) { transition: none; }
}

/* Auth links injected into the topnav by initAuthTopnav() — see app.js.
   The greet ("· captain ·") sits between the [d33p th0u9ht] link and
   the [LOGOUT] button to make the "yes you're logged in" state obvious
   at a glance. Logout uses a tiny <form> so it's a real POST (CSRF-
   friendly + no GET-side-effects), but visually it's just another link. */
.topnav-greet {
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 12px;
  color: #9ab;
  letter-spacing: 0.02em;
  padding: 0 4px;
}
.topnav-profile-link {
  color: inherit;
  text-decoration: none;
}
.topnav-profile-link:hover { color: var(--accent, #5bd5c7); }
.topnav-logout-form { display: inline; margin: 0; padding: 0; }
.topnav-logout {
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-transform: none;
}
.topnav-link--soon {
  opacity: 0.55;
  cursor: not-allowed;
  border-style: dashed !important;
}

/* Top-nav — terminal-bracket styled, lives at the top of both pages.
   Same outer/inner pattern as .site-foot: the outer .topnav is a full-
   width chrome band with a 1px border + dark translucent wash + frost,
   the inner .topnav-inner is the 1100px content rail. The translucent
   wash here is the visual twin of .site-foot's; both bands now sit over
   the mood gradient as clearly-defined page chrome so the topnav doesn't
   look "naked" against the bright top of the gradient while the footer
   looks framed against the dark bottom (j73w spotted that mismatch). */
.topnav {
  background: rgba(6, 12, 22, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--border);
  padding: 14px 20px;
  margin-bottom: 0;
}
.topnav-inner {
  max-width: 1100px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  font-family: var(--mono);
}
.topnav-brand {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
  letter-spacing: 0.5px;
}
.topnav-brand:hover { color: var(--accent); }
.topnav-brand .brand-mark { color: var(--accent); font-weight: 700; }
.topnav-brand .brand-tld  { color: var(--text-faint); }

.topnav-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.topnav-link {
  display: inline-block;
  padding: 4px 8px;
  color: var(--text-dim);
  font-size: 12px;
  letter-spacing: 1px;
  text-decoration: none;
  border-radius: 3px;
  white-space: nowrap;
}
.topnav-link:hover { color: var(--text); }
.topnav-link.is-active {
  color: var(--accent);
  background: rgba(52, 211, 153, 0.08);
}

.back-to-deck {
  margin-top: 32px;
  font-family: var(--mono);
  font-size: 13px;
}
.back-to-deck a {
  color: var(--accent);
  text-decoration: none;
}
.back-to-deck a:hover { text-decoration: underline; }

.foot-mood {
  color: var(--text-faint);
  font-style: italic;
  font-size: 12px;
}

/* ──────────────── Weather widget (pass 8) ─────────────────
   Lives between the topnav and the hero on every page. Two-column flex
   row: 3-line ASCII art on the left, mood label + temperature on the
   right. Four states (live / prompt / denied / unsupported) — see
   renderWeatherWidget() in app.js. The widget is the PRIMARY visible
   affordance for the location/weather feature (replaces the easy-to-miss
   footer pill from pass 6). */
.weather-widget {
  max-width: 1100px;
  margin: 12px auto 0;
  padding: 10px 16px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-left-color: var(--text-faint);
  border-radius: 6px;
  display: flex;
  align-items: center;
  gap: 18px;
  font-family: var(--mono);
}
.weather-widget--live   { border-left-color: var(--accent); }
.weather-widget--prompt { border-left-color: var(--warn); }
.weather-widget--denied { border-left-color: var(--text-faint); }
.weather-widget--unsupported { border-left-color: var(--text-faint); }

.weather-loading {
  color: var(--text-faint);
  font-style: italic;
  font-size: 13px;
}
.weather-ascii {
  margin: 0;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.25;
  white-space: pre;
  flex: 0 0 auto;
  letter-spacing: 0.5px;
}
.weather-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1 1 auto;
}
.weather-mood {
  font-size: 14px;
  color: var(--text);
  font-weight: 600;
  letter-spacing: 0.5px;
}
.weather-sub {
  font-size: 11px;
  color: var(--text-faint);
  letter-spacing: 0.5px;
}
.weather-sub a { color: var(--text-dim); text-decoration: underline; }
.weather-sub a:hover { color: var(--accent); }
.weather-temp {
  color: var(--text);
  font-weight: 600;
}
.weather-optin {
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 3px;
  padding: 4px 10px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.5px;
  cursor: pointer;
  text-align: left;
  align-self: flex-start;
}
.weather-optin:hover { background: rgba(52, 211, 153, 0.10); }

/* Phones: ASCII column collapses; meta gets full width. */
@media (max-width: 600px) {
  .weather-widget { flex-direction: column; align-items: flex-start; gap: 8px; padding: 10px 14px; }
  .weather-ascii  { font-size: 11px; }
}

/* ──────────────── Headline banner ────────────────
   Single-panel "last 4h headline" above the hero grid. Sentiment classes
   tint the left border + ASCII glyph color so visual sentiment matches the
   pick. Mobile: ASCII column hides; metadata flows full width.
   Sentiment classes:
     .headline--bear      — extreme fear / bearish whale move into exchange
     .headline--bull      — extreme greed / bullish setup
     .headline--whale_in  — big whale tx INTO a tagged exchange wallet
     .headline--whale_out — big whale tx OUT OF a tagged exchange wallet
     .headline--swing     — F&G moved sharply in 24h
     .headline--calm      — default / quiet day */

.headline {
  /* Width-match the centered content column the rest of the page uses
     (.section + .status-banner both use 1100px). Horizontal padding 20px
     matches .section so the inner content lines up vertically with the
     hero grid and the sections below. */
  max-width: 1100px;
  margin: 18px auto 8px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-left: 4px solid var(--text-faint);
  border-radius: 6px;
  padding: 14px 20px;
}
.headline-loading {
  color: var(--text-faint);
  font-style: italic;
  padding: 8px 0;
}
.headline--bear,
.headline--whale_in   { border-left-color: var(--down); }
.headline--bull,
.headline--whale_out  { border-left-color: var(--up); }
.headline--swing      { border-left-color: var(--warn); }
.headline--calm       { border-left-color: var(--accent-dim, var(--text-faint)); }

.headline-tag {
  font-size: 10px;
  letter-spacing: 1.5px;
  color: var(--text-faint);
  font-family: var(--mono);
  margin-bottom: 6px;
}
.headline-title {
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
  margin-bottom: 6px;
}
.headline-sub {
  font-size: 13px;
  color: var(--text-dim);
  line-height: 1.5;
  margin: 0 0 8px;
}
.headline-link {
  color: var(--accent);
  font-size: 12px;
  text-decoration: none;
  font-family: var(--mono);
}
.headline-link:hover { text-decoration: underline; }
.headline-ascii {
  display: none;       /* hidden on phones */
  margin: 0;
  padding: 8px 12px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 10.5px;
  line-height: 1.3;
  color: var(--accent);
  white-space: pre;
  overflow: hidden;
  align-self: center;
  justify-self: end;
}
.headline--bear  .headline-ascii,
.headline--whale_in .headline-ascii { color: var(--down); }
.headline--bull  .headline-ascii,
.headline--whale_out .headline-ascii { color: var(--up); }
.headline--swing .headline-ascii { color: var(--warn); }

@media (min-width: 720px) {
  .headline { grid-template-columns: 1fr minmax(220px, 280px); }
  .headline-ascii { display: block; }
}

/* ──────────────── Unified chart panel ────────────────
   Replaces the two per-asset chart panels. One LightweightCharts instance,
   asset switcher across the top (driven by deltas.json tickers, sorted by
   24h volume), timeframe switcher next to it. On phones the asset switcher
   becomes horizontally scrollable so all tickers stay reachable without
   forcing the layout into multiple rows. */

.chart-card--unified .chart-header--unified {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: stretch;
  padding-bottom: 8px;
}
.asset-switcher {
  display: flex;
  gap: 4px;
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 4px;     /* leave room for the horizontal scrollbar */
  scrollbar-width: thin;
}
.asset-switcher::-webkit-scrollbar { height: 4px; }
.asset-switcher::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
.asset-btn {
  flex: 0 0 auto;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  padding: 6px 10px;
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 12px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  letter-spacing: 0.5px;
  white-space: nowrap;
}
.asset-btn:hover {
  border-color: var(--accent-dim);
  color: var(--text);
}
.asset-btn.is-active {
  background: var(--accent-dim, rgba(52, 211, 153, 0.12));
  border-color: var(--accent);
  color: var(--accent);
}
.asset-btn-tier {
  font-size: 10px;
  color: var(--text-faint);
}
.asset-btn.is-active .asset-btn-tier { color: inherit; }
.asset-switcher-empty {
  color: var(--text-faint);
  font-style: italic;
  padding: 6px 10px;
}

.chart-meta {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--text-dim);
  padding: 4px 0 10px;
  border-bottom: 1px dashed var(--border);
  margin-bottom: 10px;
}
.chart-meta .chart-meta-asset {
  color: var(--text);
  font-weight: 600;
}
.chart-meta .chart-meta-price {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.chart-meta .up { color: var(--up); }
.chart-meta .down { color: var(--down); }
.chart-meta .dim { color: var(--text-faint); }
.chart-source {
  margin: 8px 0 0;
  font-size: 11px;
  color: var(--text-faint);
  font-family: var(--mono);
  line-height: 1.5;
}

/* ──────────────── Ticker grid (multi-venue, multi-asset) ────────────────
   Replaces the legacy 3-cell hero strip. Auto-fits the number of columns to
   viewport width so we can grow the ticker count without redoing layout:
     - phone (<560px): 1 column
     - small (<860px): 2 columns
     - desktop:        3-4 columns via auto-fit minmax
   `.ticker-cell--price-only` is the visually-quieter tier for tickers we
   only price-track today (Fear & Greed has its own banner in .sentiment-row)
   sitting in the same grid. Cells are HEIGHT-PINNED to the same min-height
   so a price-only cell without deltas still aligns with a flow+price cell. */

.ticker-grid {
  margin-top: 8px;
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr;
}
@media (min-width: 560px) { .ticker-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 860px) { .ticker-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1080px){ .ticker-grid { grid-template-columns: repeat(4, 1fr); } }

.ticker-cell {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 12px 14px 10px;
  min-height: 132px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ticker-cell--loading {
  color: var(--text-faint);
  font-style: italic;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ticker-cell--price-only {
  /* Subtle visual cue that this tier is price-only. We still use the same
     border color so the grid stays consistent; the tag is what does the
     talking. */
  background: linear-gradient(180deg, var(--bg-card) 0%, rgba(20, 20, 20, 0.7) 100%);
}
/* (.ticker-cell--fng + .ticker-tier--fng removed in pass 8 — F&G no
   longer renders as a grid cell; it has its own banner in .sentiment-row.) */

.ticker-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}
.ticker-symbol {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--text);
}
.ticker-name {
  font-size: 11px;
  color: var(--text-faint);
  letter-spacing: 0.5px;
}
.ticker-tier {
  margin-left: auto;
  font-size: 9.5px;
  letter-spacing: 1px;
  text-transform: uppercase;
  padding: 1px 6px;
  border-radius: 3px;
  font-family: var(--mono);
  white-space: nowrap;
}
.ticker-tier--full {
  background: rgba(52, 211, 153, 0.12);
  color: var(--up);
  border: 1px solid rgba(52, 211, 153, 0.25);
}
.ticker-tier--price {
  background: rgba(251, 191, 36, 0.10);
  color: var(--warn);
  border: 1px solid rgba(251, 191, 36, 0.25);
}
.ticker-tier--price a {
  color: var(--warn);
  text-decoration: none;
}
.ticker-tier--price a:hover { text-decoration: underline; }

.ticker-price {
  font-size: 22px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  letter-spacing: -0.3px;
}
.ticker-deltas {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 12px;
  color: var(--text-dim);
}
.ticker-deltas .up { color: var(--up); }
.ticker-deltas .down { color: var(--down); }
.ticker-deltas .dim { color: var(--text-faint); }
.ticker-deltas-empty {
  color: var(--text-faint);
  font-style: italic;
  font-size: 11px;
}
.ticker-venues {
  margin-top: auto;
  font-size: 11px;
  color: var(--text-faint);
  font-family: var(--mono);
  letter-spacing: 0.2px;
  line-height: 1.5;
  /* On a narrow tile the per-venue line will wrap to a second row; that's
     fine, the cell grows to fit. The grid row-height tracks the tallest cell
     per row by default. */
}
.ticker-venues-label {
  color: var(--text-dim);
  margin-right: 2px;
}
.ticker-venue-name {
  color: var(--text-dim);
}
.ticker-venues-empty {
  color: var(--warn);
}

/* ──────────────── Sections ──────────────── */

.section {
  max-width: 1100px;
  margin: 0 auto;
  padding: 48px 20px 16px;
  border-bottom: 1px solid var(--border);
}
.section:last-of-type { border-bottom: none; }
.section-head {
  font-size: 13px;
  letter-spacing: 2px;
  color: var(--accent);
  margin: 0 0 4px;
  font-weight: 500;
}
.section-sub {
  margin: 0 0 24px;
  color: var(--text-dim);
  font-family: var(--sans);
  font-size: 14px;
}
.sub-head {
  font-size: 14px;
  letter-spacing: 1px;
  color: var(--text);
  margin: 28px 0 8px;
}

#about p, #about li {
  font-family: var(--sans);
  font-size: 15px;
  color: var(--text);
}
#about ul { padding-left: 22px; }
#about li { margin-bottom: 8px; }
#about a { color: var(--accent); }
.caveats-list strong { color: var(--warn); }
.caveats-list strong.up-color { color: var(--up); }
.caveats-list strong.warn-color { color: var(--warn); }
.warn-color { color: var(--warn); }
.muted {
  color: var(--text-faint);
  font-size: inherit;
}
.muted a, .meta-link {
  color: var(--accent);
  text-decoration: none;
}
.muted a:hover, .meta-link:hover { text-decoration: underline; }
.muted-note {
  color: var(--text-faint);
  font-size: 13px;
  font-style: italic;
  margin-bottom: 8px;
}

/* ──────────────── Status banner ──────────────── */
/*
   Two modifiers drive color: .is-warn (amber) for active incidents,
   .is-ok (green) for "all systems operational" / post-incident states.
   Defaults to .is-warn so an unmodified banner reads as cautionary. */

/* Sentiment row in the hero — moved here in pass 8. Holds .status-banner +
   .fng-panel as siblings. On phones they stack; on tablet/desktop they sit
   side-by-side at 65/35 to give the multi-sentence status body more room
   while the F&G card keeps a clean compact footprint. */
.sentiment-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin: 18px 0 18px;
}
@media (min-width: 720px) {
  .sentiment-row { grid-template-columns: minmax(0, 65fr) minmax(0, 35fr); }
}

/* Status banner + F&G panel share the same outer card pattern as .headline
   so all three read as visually identical siblings. The legacy .status-inner
   is now a no-op wrapper; styling lives on the outer .status-banner so the
   DOM doesn't need to change. */
.status-banner,
.fng-panel {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-left-color: var(--status-color, var(--text-faint));
  border-radius: 6px;
  padding: 14px 20px;
  margin: 0;
}
.status-banner {
  --status-color: var(--warn);
}
.status-banner.is-ok { --status-color: var(--up); }
.status-banner.is-warn { --status-color: var(--warn); }
.status-inner { /* no-op wrapper retained for legacy DOM */ }

/* F&G panel — same structural styling as the status banner; the F&G tag
   inherits its color from the panel's bucket class so a "fear" reading
   accents red, "greed" accents green. */
.fng-panel { --status-color: var(--text-faint); }
.fng-loading { color: var(--text-faint); font-style: italic; font-size: 14px; }
.fng-inner   { display: flex; flex-direction: column; gap: 4px; }
.fng-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}
.fng-tag {
  background: var(--text-dim);
  color: var(--bg);
  padding: 2px 7px;
  font-size: 11px;
  letter-spacing: 1.5px;
  font-weight: 600;
}
.fng-title { font-weight: 600; font-size: 14px; }
.fng-stamp { color: var(--text-dim); font-size: 12px; margin-left: auto; }
.fng-body {
  margin: 4px 0 0;
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.55;
}
.fng-link { color: var(--accent); text-decoration: none; }
.fng-link:hover { text-decoration: underline; }
.muted-color { color: var(--text-dim); }
.status-row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}
.status-tag {
  background: var(--status-color);
  color: var(--bg);
  padding: 2px 7px;
  font-size: 11px;
  letter-spacing: 1.5px;
  font-weight: 600;
}
.status-title {
  color: var(--status-color);
  font-weight: 600;
  font-size: 14px;
}
.status-stamp {
  color: var(--text-dim);
  font-size: 12px;
  margin-left: auto;
}
.status-body {
  margin: 6px 0 0;
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.55;
}

/* ──────────────── Charts ──────────────── */

.chart-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px;
  margin-bottom: 24px;
}
.chart-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
  flex-wrap: wrap;
  gap: 10px;
}
.chart-title {
  margin: 0;
  font-size: 18px;
  letter-spacing: 1px;
}
.tf-buttons {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}
.tf-btn {
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border-bright);
  border-radius: 4px;
  padding: 4px 10px;
  font-family: var(--mono);
  font-size: 12px;
  cursor: pointer;
  transition: all 100ms ease;
}
.tf-btn:hover {
  color: var(--text);
  border-color: var(--accent-dim);
}
.tf-btn.is-active {
  color: var(--bg);
  background: var(--accent);
  border-color: var(--accent);
  font-weight: 600;
}
.chart-container {
  width: 100%;
  height: 320px;
}
@media (min-width: 720px) {
  .chart-container { height: 400px; }
}

/* ──────────────── Net flows ──────────────── */

.flows-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}
@media (min-width: 720px) {
  .flows-grid { grid-template-columns: 1fr 1fr; }
}
.flow-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 20px;
}
.flow-asset {
  font-size: 12px;
  letter-spacing: 2px;
  color: var(--text-faint);
  margin-bottom: 6px;
}
.flow-amount {
  font-size: 28px;
  font-weight: 600;
  margin-bottom: 4px;
}
.flow-amount.up { color: var(--up); }
.flow-amount.down { color: var(--down); }
.flow-usd {
  font-size: 14px;
  color: var(--text-dim);
  margin-bottom: 10px;
}
.flow-delta {
  font-size: 13px;
  color: var(--text-dim);
}
.flow-delta .up { color: var(--up); }
.flow-delta .down { color: var(--down); }
/* Per-asset whale threshold tag, sat under the delta on each card so the
   "what counts as a whale here?" answer never requires a logbook trip.
   Mono font + faint border + uppercase tracking matches the brand-mark
   bracket aesthetic on the topnav. j73w pass 11.0d. */
.flow-threshold {
  margin-top: 10px;
  padding: 6px 10px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.5px;
  color: var(--text-faint);
  border: 1px dashed var(--border);
  border-radius: 4px;
  display: inline-block;
}
.flow-threshold strong {
  color: var(--text-dim);
  font-weight: 600;
}
.flow-note {
  margin-top: 16px;
  font-size: 13px;
  color: var(--text-dim);
  font-family: var(--sans);
}
.up-color { color: var(--up); }
.down-color { color: var(--down); }

/* ──────────────── Surface log ────────────────
   Each <li.surface> is one 4-hour surfacing the site self-publishes. When a new
   one arrives via the polling loop in app.js we prepend it and tag it with
   .surface--fresh so the border briefly lights up green; the modifier is
   removed after the animation so subsequent reflows are cheap. */

.surface-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}
.surface {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px 18px;
}
.surface--fresh {
  animation: surface-arrive 1.8s ease-out 1;
}
@keyframes surface-arrive {
  0%   { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), 0 0 18px rgba(52,211,153,0.35); }
  100% { border-color: var(--border); box-shadow: none; }
}
.surface-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  font-size: 12px;
  color: var(--text-faint);
  letter-spacing: 1px;
}
.surface-time {
  color: var(--text-faint);
}
.surface-link {
  color: var(--accent);
  font-size: 12px;
}
.surface-body {
  white-space: pre-wrap;
  font-family: var(--mono);
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text);
  margin: 0;
}
.surface-body .up { color: var(--up); }
.surface-body .down { color: var(--down); }
.surface-empty {
  color: var(--text-faint);
  list-style: none;
  text-align: center;
  padding: 28px;
}
@media (prefers-reduced-motion: reduce) {
  .surface--fresh { animation: none; }
}
.more-btn {
  margin-top: 16px;
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--accent-dim);
  border-radius: 4px;
  padding: 8px 14px;
  font-family: var(--mono);
  font-size: 13px;
  cursor: pointer;
}
.more-btn:hover {
  background: var(--accent);
  color: var(--bg);
}

/* ──────────────── WHATS_NEW carousel ────────────────
   Rotating panel of the last N shipped features. Each panel has a two-column
   layout: left = SHIP/EMBARKED/CARGO metadata (definition list), right =
   feature-matched ASCII art. On phones the ASCII column is hidden (it
   doesn't shrink well) and the metadata gets full width. Navigation:
   prev/next buttons on the sides + dots below. Keyboard: ← → when the
   carousel region is focused. */

.carousel {
  position: relative;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 18px 56px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  align-items: stretch;
}
.carousel:focus { outline: 1px solid var(--accent-dim); outline-offset: 2px; }

/* True-slider carousel (pass 10.3 — j73w wanted "consistently sized panes
   that animate through, plus phone swipe").

   Layout model:
     .carousel-window  is the viewport. Clips with overflow: hidden and
                       carries the consistent height as a min-height set
                       by JS to the tallest mounted panel. `touch-action:
                       pan-y` lets vertical page scroll pass through but
                       reserves horizontal gestures for our touch handler.
     .carousel-track   is a horizontal flex strip containing every panel
                       side-by-side. Slides via translateX. The transition
                       is normally on; JS turns it off during touch-drag
                       so the finger tracks 1:1, then back on for the
                       snap-to-page animation on release.
     .carousel-panel   each = 100% of the window width; never shrinks. The
                       slider position is purely `translateX(-i * 100%)`.
*/
.carousel-window {
  position: relative;
  overflow: hidden;
  width: 100%;
  /* Vertical page scroll passes through; we own horizontal gestures. */
  touch-action: pan-y;
}
.carousel-track {
  display: flex;
  align-items: stretch;
  width: 100%;
  transform: translate3d(0, 0, 0);
  transition: transform 320ms cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform;
}
/* JS adds this class during a finger-drag so the track is 1:1 with the
   user's finger (no easing). Removed on touchend so the snap-to-page
   release animation rides the normal transition above. */
.carousel-track.is-dragging { transition: none; }

.carousel-panel {
  flex: 0 0 100%;
  min-width: 100%;
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  /* All panels are visually mounted but only the active one is the user's
     focus target. ARIA hides the others from assistive tech without
     `display: none` (which would break the flex layout). */
  user-select: none;
}
.carousel-panel[aria-hidden="true"] {
  /* Stays in flow so the track keeps its width; visually it's just off-screen. */
}
.carousel-loading, .carousel-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 230px;
  color: var(--text-faint);
  font-style: italic;
}

/* Respect the OS-level "I get motion sick" preference — no slide easing,
   just instant page change. Touch drag still works, just snaps. */
@media (prefers-reduced-motion: reduce) {
  .carousel-track { transition: none; }
}

.carousel-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  width: 36px;
  height: 36px;
  border-radius: 6px;
  font-family: var(--mono);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.carousel-nav:hover {
  border-color: var(--accent-dim);
  color: var(--accent);
}
.carousel-prev { left: 10px; }
.carousel-next { right: 10px; }
.carousel-dots {
  grid-column: 1 / -1;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;            /* 20 dots wrap to multiple rows on phones */
  gap: 5px 4px;
  margin-top: 6px;
  max-width: 100%;
}
.carousel-dot {
  width: 7px;
  height: 7px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--text-faint);
  background: transparent;
  cursor: pointer;
}
.carousel-dot.is-active {
  background: var(--accent);
  border-color: var(--accent);
}

.feature-meta {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 6px;
}
.feature-fields {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.feature-field {
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: 10px;
  align-items: baseline;
}
.feature-field dt {
  font-size: 10px;
  letter-spacing: 1.5px;
  color: var(--accent);
  font-weight: 600;
  margin: 0;
  text-transform: uppercase;
}
.feature-field dd {
  margin: 0;
  color: var(--text);
}
.feature-ship {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.2px;
}
.feature-embarked {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-dim);
}
.feature-ago {
  margin-left: 6px;
  color: var(--text-faint);
}
.feature-cargo {
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-dim);
}

.feature-ascii {
  display: none;        /* hidden on phones */
  margin: 0;
  padding: 12px 14px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--accent);
  white-space: pre;
  overflow: hidden;
  align-self: center;
  justify-self: end;
}

@media (min-width: 720px) {
  .carousel-panel {
    grid-template-columns: 1fr minmax(220px, 280px);
  }
  .feature-ascii {
    display: block;
  }
}
@media (max-width: 480px) {
  /* Tighten the nav buttons + padding on narrow phones so the dots and
     metadata get more horizontal room. */
  .carousel { padding: 16px 44px; }
  .carousel-nav { width: 30px; height: 30px; font-size: 18px; }
  .carousel-prev { left: 6px; }
  .carousel-next { right: 6px; }
  .feature-field { grid-template-columns: 72px 1fr; gap: 8px; }
  .feature-ship { font-size: 15px; }
}

/* ──────────────── Surface log: today / trend / earlier blocks ────────
   The surface log used to be a single flat list that grew unbounded as the
   site self-published a new surfacing every 4 hours. Now it's split into
   three blocks (TODAY / TREND / EARLIER) rendered by app.js. These styles
   share the underlying .surface card from the block above; new bits below
   are mostly the block headers, the trend grid, and the per-UTC-day
   <details> groups. */

.surface-block {
  margin-bottom: 32px;
}
.surface-block:last-child { margin-bottom: 0; }
.surface-block-head {
  margin: 0 0 12px;
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  font-size: 13px;
  letter-spacing: 1px;
  color: var(--text);
  font-weight: 500;
}
.surface-block-label {
  color: var(--accent);
}
.surface-block-meta {
  color: var(--text-faint);
  font-size: 12px;
  letter-spacing: 0.5px;
  font-family: var(--mono);
  text-transform: none;
}

/* TREND sparkline cards. One 24h arc per flow-tracked asset (BTC/ETH/LINK today).
   auto-fit-minmax reflows to 1/2/3 columns without breakpoint maintenance. */
.trend-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
  max-width: 960px;
}
.trend-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  margin: 0;
}
.trend-caption {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 6px;
  font-family: var(--mono);
}
.trend-label {
  color: var(--text-dim);
  font-size: 12px;
  letter-spacing: 0.5px;
}
.trend-latest {
  color: var(--text);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
}
.trend-spark {
  height: 60px;
  width: 100%;
  display: block;
}
.trend-spark svg { display: block; width: 100%; height: 60px; }
.trend-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: var(--text-faint);
  font-size: 12px;
  font-style: italic;
}

/* EARLIER: per-UTC-day collapsible groups. <details>/<summary> gives us
   keyboard- and screen-reader-friendly expand/collapse for free; we just
   style around it. */
.surface-days {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.surface-day {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.surface-day[open] {
  border-color: var(--border-bright);
}
.surface-day-head {
  cursor: pointer;
  padding: 12px 16px;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  font-family: var(--mono);
  letter-spacing: 0.5px;
  /* Hide the default ▶ marker — we add a custom one via ::before so the
     rotation animation tracks the [open] state cleanly. */
  list-style: none;
}
.surface-day-head::-webkit-details-marker { display: none; }
.surface-day-head::before {
  content: '▶';
  color: var(--accent-dim);
  font-size: 10px;
  margin-right: 6px;
  transition: transform 0.15s ease-out;
}
.surface-day[open] > .surface-day-head::before {
  transform: rotate(90deg);
}
.surface-day-label {
  color: var(--text);
  font-size: 13px;
  flex: 1 1 auto;
}
.surface-day-count {
  color: var(--text-faint);
  font-size: 12px;
}
.surface-list--day {
  padding: 0 16px 16px;
  margin-top: 4px;
}
.surface-day .surface {
  /* Inside an already-bordered day group, drop the per-card border so the
     nested cards don't look like a doubled outline. */
  border-color: transparent;
  background: var(--bg-elev);
  padding: 12px 14px;
}

/* ──────────────── Footer ──────────────── */

.site-foot {
  background: rgba(6, 12, 22, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-top: 1px solid var(--border);
  padding: 28px 20px;
  margin-top: 24px;
}
/* Mobile-first: copyright / @whaleflows / "data as of …" stack one per line,
   each centered. Desktop turns this into a single row with the items pushed
   to the edges so the copyright lines up with the brand on the left and the
   timestamp lines up with the F&G panel on the right (both rows share the
   same 1100px container, so the alignment falls out naturally). */
.foot-inner {
  max-width: 1100px;
  margin: 0 auto;
  color: var(--text-faint);
  font-size: 12px;
  letter-spacing: 1px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  text-align: center;
}

/* ──────────────── Credit footer (hacker-terminal style) ────────────────
   Lives below .foot-inner. Mirrors that block's max-width + margin so the
   `>` prompt lines up flush under the `©` on the row above. Pure CSS blink,
   no JS. */

.foot-cred {
  max-width: 1100px;
  margin: 14px auto 0;
  padding: 12px 0 4px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 6px;
  font-family: var(--mono);
  /* Fluid sizing: 10.5px on a 320-CSS-px phone, 13px from ~720px up.
     Keeps "powered_by ... futur3_" on one line on every realistic mobile
     viewport without a media-query stairstep. */
  font-size: clamp(10.5px, 0.7vw + 8px, 13px);
  letter-spacing: clamp(0.5px, 0.3vw, 2px);
  color: var(--up);
  text-shadow:
    0 0 4px rgba(52, 211, 153, 0.6),
    0 0 12px rgba(52, 211, 153, 0.28),
    0 0 24px rgba(52, 211, 153, 0.12);
  user-select: none;
  border-top: 1px dashed var(--border);
}
.foot-cred .cred-prompt {
  color: var(--accent-dim);
  text-shadow: none;
}
.foot-cred .cred-tag {
  opacity: 0.96;
  /* Keep the whole credit string as a single visual unit. If it ever has to
     wrap on an extremely narrow phone, it wraps cleanly after the `>` prompt
     instead of breaking mid-word like "0ur / futur3_". */
  white-space: nowrap;
}
.foot-cred .cred-cursor {
  display: inline-block;
  width: 0.55em;
  color: var(--up);
  animation: cred-blink 1.05s steps(1, end) infinite;
}
@keyframes cred-blink {
  0%, 49.99%   { opacity: 1; }
  50%, 100%    { opacity: 0; }
}
/* Desktop: copyright pinned to the left edge of the 1100px container,
   "data as of ..." pinned to the right edge, @whaleflows balanced between
   them. Credit row stays centered at all viewports (the signature reads
   better as a centered tagline than left-pinned under the copyright). */
@media (min-width: 720px) {
  .foot-inner {
    flex-direction: row;
    justify-content: space-between;
    gap: 0 16px;
    text-align: left;
  }
}

@media (prefers-reduced-motion: reduce) {
  .foot-cred .cred-cursor { animation: none; opacity: 0.85; }
}

/* ──────────────── 404 page ──────────────── */

.page-404 {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background:
    radial-gradient(900px 360px at 50% 30%, rgba(52, 211, 153, 0.06), transparent 70%),
    var(--bg);
}
.four-oh-four { width: 100%; max-width: 560px; text-align: center; }
.four-oh-four-bar {
  margin-bottom: 22px;
  padding-bottom: 14px;
  border-bottom: 1px dashed var(--border);
  letter-spacing: 1px;
}
.four-oh-four-bar a {
  color: var(--text-dim);
  text-decoration: none;
  font-family: var(--mono);
  font-size: 13px;
}
.four-oh-four-bar a:hover { color: var(--accent); text-decoration: none; }
.four-oh-four-mark { color: var(--accent); margin-right: 4px; }
.four-oh-four-tld  { color: var(--accent); }

.four-oh-four-card {
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  background: var(--bg-card);
  padding: 28px 24px 30px;
}
.whale-art {
  color: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.15;
  margin: 0 0 18px;
  white-space: pre;
  text-shadow: 0 0 8px rgba(52, 211, 153, 0.35);
  animation: whale-bob 4.5s ease-in-out infinite;
}
@keyframes whale-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}
@media (prefers-reduced-motion: reduce) {
  .whale-art { animation: none; }
}

.four-oh-four-status {
  color: var(--accent);
  font-family: var(--mono);
  font-size: 18px;
  letter-spacing: 2px;
  margin: 0 0 6px;
  text-transform: uppercase;
}
.four-oh-four-msg {
  color: var(--up);
  font-family: var(--mono);
  font-size: 14px;
  margin: 0 0 18px;
  letter-spacing: 1px;
}
.four-oh-four-cursor {
  display: inline-block;
  width: 0.55em;
  margin-left: 2px;
  animation: cred-blink 1.05s steps(1, end) infinite;
}
@media (prefers-reduced-motion: reduce) {
  .four-oh-four-cursor { animation: none; opacity: 0.85; }
}
.four-oh-four-hint {
  color: var(--text-dim);
  font-family: var(--mono);
  font-size: 12px;
  margin: 0 0 22px;
}
.four-oh-four-link a {
  display: inline-block;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 1px;
  text-decoration: none;
  border: 1px solid var(--border);
  padding: 8px 14px;
}
.four-oh-four-link a:hover {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--bg);
  text-decoration: none;
}

/* ──────────────── Tiny utilities ──────────────── */

.up { color: var(--up); }
.down { color: var(--down); }
.dim { color: var(--text-dim); }

/* ─────────── d33p th0u9ht neon promo strip ──────────────────────────────────
   Sits at the top of <main>. A single card with a glowing teal border that
   pulses — the only animated card on the page (on purpose). Respects
   prefers-reduced-motion by killing the pulse and keeping the glow static.  */

@keyframes neon-border-pulse {
  0%,100% { box-shadow: 0 0 6px rgba(91,213,199,0.4), 0 0 18px rgba(91,213,199,0.15), inset 0 0 6px rgba(91,213,199,0.05); }
  50%      { box-shadow: 0 0 12px rgba(91,213,199,0.7), 0 0 36px rgba(91,213,199,0.3), inset 0 0 12px rgba(91,213,199,0.08); }
}
@keyframes neon-text-blink {
  0%,100% { opacity: 1; text-shadow: 0 0 6px #5bd5c7, 0 0 14px rgba(91,213,199,0.6); }
  50%     { opacity: 0.72; text-shadow: 0 0 3px #5bd5c7; }
}
@keyframes neon-badge-blink {
  0%,45%,55%,100% { opacity: 1; }
  48%,52%         { opacity: 0.35; }
}

.deep-teaser {
  margin: 16px 0;
  padding: 20px 22px 18px;
  border: 1px solid rgba(91,213,199,0.55);
  border-radius: 4px;
  background: rgba(6,9,10,0.72);
  animation: neon-border-pulse 2.4s ease-in-out infinite;
  position: relative;
}
.deep-teaser-header {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.deep-teaser-title {
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 700;
  color: #5bd5c7;
  letter-spacing: 0.08em;
  animation: neon-text-blink 2.4s ease-in-out infinite;
}
.deep-teaser-badge {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: #06090a;
  background: #5bd5c7;
  padding: 2px 7px;
  border-radius: 2px;
  animation: neon-badge-blink 1.8s step-end infinite;
}
.deep-teaser-badge--live {
  background: #28c840;
  color: #fff;
  animation: none;
  box-shadow: 0 0 8px rgba(40,200,64,0.6);
}
.deep-teaser-kudos {
  font-family: var(--mono);
  font-size: 11px;
  color: rgba(91,213,199,0.55);
  margin-left: auto;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.deep-teaser-body {
  font-family: var(--mono);
  font-size: 12px;
  color: #9ab;
  line-height: 1.7;
  margin: 0 0 10px;
}
.deep-teaser-body strong { color: #c0cdd6; }
.deep-teaser-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
}
.deep-teaser-list li {
  font-family: var(--mono);
  font-size: 11px;
  color: #7ab;
}
.deep-teaser-list li::before { content: '▸ '; color: #5bd5c7; }
.deep-teaser-cta {
  font-family: var(--mono);
  font-size: 11px;
  color: rgba(91,213,199,0.6);
  margin: 10px 0 0;
  letter-spacing: 0.04em;
}
.deep-teaser-cta a { color: #5bd5c7; }
@media (prefers-reduced-motion: reduce) {
  .deep-teaser { animation: none; box-shadow: 0 0 6px rgba(91,213,199,0.4); }
  .deep-teaser-title { animation: none; text-shadow: 0 0 4px #5bd5c7; }
  .deep-teaser-badge { animation: none; }
}

/* feature carousel: "coming next" panel gets the neon treatment */
@keyframes neon-panel-border-blink {
  0%,45%,55%,100% { border-color: rgba(91,213,199,0.72); }
  48%,52%         { border-color: rgba(91,213,199,0.08); }
}
.carousel-panel {
  padding: 20px 24px;
}
.carousel-panel.is-coming-next {
  border: 1px solid rgba(91,213,199,0.72);
  border-radius: 4px;
  animation: neon-panel-border-blink 1.8s step-end infinite;
}
.carousel-panel.is-coming-next .feature-coming-next-label {
  display: inline-block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: #06090a;
  background: #5bd5c7;
  padding: 1px 6px;
  border-radius: 2px;
  margin-left: 8px;
  vertical-align: middle;
  animation: neon-badge-blink 1.8s step-end infinite;
}
@media (prefers-reduced-motion: reduce) {
  .carousel-panel.is-coming-next { animation: none; border-color: rgba(91,213,199,0.55); }
  .carousel-panel.is-coming-next .feature-coming-next-label { animation: none; }
}

/* topnav d33p th0u9ht — live, full neon glow */
.topnav-link--chat {
  color: #00d4ff;
  text-shadow:
    0 0 6px rgba(0,212,255,0.7),
    0 0 14px rgba(0,212,255,0.4);
  font-weight: 600;
  letter-spacing: 0.02em;
}
.topnav-link--chat:hover {
  text-shadow:
    0 0 10px rgba(0,212,255,1),
    0 0 22px rgba(0,212,255,0.6);
}

/* logbook roadmap spotlight item */
.roadmap-spotlight {
  padding: 10px 14px;
  border: 1px solid rgba(91,213,199,0.45);
  border-radius: 4px;
  background: rgba(91,213,199,0.04);
  list-style: none !important;
  margin-bottom: 6px;
}
.roadmap-spotlight--live {
  border-color: #00d4ff;
  background: rgba(0,212,255,0.05);
  box-shadow: 0 0 12px rgba(0,212,255,0.12);
}
.roadmap-live-badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: #fff;
  background: #28c840;
  padding: 2px 6px;
  border-radius: 2px;
  box-shadow: 0 0 6px rgba(40,200,64,0.5);
  vertical-align: middle;
  margin-left: 4px;
}
.roadmap-neon {
  font-weight: 700;
  color: #00d4ff;
  text-shadow:
    0 0 6px rgba(0,212,255,0.7),
    0 0 14px rgba(0,212,255,0.35);
  letter-spacing: 0.05em;
}
/* carousel: once live, no longer needs the blinking neon border */
.carousel-panel.is-coming-next {
  border-color: #00d4ff;
  animation: none;
  box-shadow: 0 0 10px rgba(0,212,255,0.15);
}
.feature-coming-next-label {
  background: #28c840;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  padding: 2px 7px;
  border-radius: 2px;
  box-shadow: 0 0 6px rgba(40,200,64,0.5);
}
