/* ═══════════════════════════════════════════════════
   v2.css : self-hosted type for the v2 language
   Clash Display (display) + General Sans (text) + Zodiak italic (serif moments)
   Fontshare / Indian Type Foundry, Fontshare Free Font License.
   Loaded by v2 pages only. Legacy pages keep Google Fonts until their refit.
═══════════════════════════════════════════════════ */

@font-face {
  font-family: 'Clash Display';
  src: url('fonts/clash-display-500.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Clash Display';
  src: url('fonts/clash-display-600.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Clash Display';
  src: url('fonts/clash-display-700.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('fonts/general-sans-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('fonts/general-sans-500.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('fonts/general-sans-600.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Zodiak';
  src: url('fonts/zodiak-400-italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'Zodiak';
  src: url('fonts/zodiak-700-italic.woff2') format('woff2');
  font-weight: 700; font-style: italic; font-display: swap;
}

/* v2 family roles (consumed by v2 pages; tokens live in tokens.css) */
:root {
  --v2-display: 'Clash Display', system-ui, sans-serif;
  --v2-text: 'General Sans', system-ui, sans-serif;
  --v2-serif: 'Zodiak', Georgia, serif;
}

/* ═══════════════════════════════════════════════════
   Red-pen mark : a hand-drawn stroke under a number that
   actually cost something. Used sparingly, twice on the index.
   Draws on scroll-in; static under reduced motion.
═══════════════════════════════════════════════════ */
.rp {
  position: relative;
  white-space: nowrap;
  color: inherit;
}
.rp::after {
  content: "";
  position: absolute;
  left: -0.12em;
  right: -0.12em;
  bottom: -0.22em;
  height: 0.42em;
  background: no-repeat left center / 100% 100%
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 16' preserveAspectRatio='none'><path d='M 3 11 C 42 4, 88 14, 128 8 C 156 4, 180 10, 197 6' fill='none' stroke='%23e0454f' stroke-width='2.4' stroke-linecap='round'/></svg>");
  /* clipped to nothing until it is seen */
  clip-path: inset(0 100% 0 0);
  pointer-events: none;
}
.rp.rp-in::after {
  clip-path: inset(0 0 0 0);
  transition: clip-path 620ms cubic-bezier(.22,.61,.36,1) 80ms;
}
@media (prefers-reduced-motion: reduce) {
  .rp::after { clip-path: inset(0 0 0 0); }
  .rp.rp-in::after { transition: none; }
}

/* ═══════════════════════════════════════════════════
   THE SHELL
   One nav, one mobile takeover, one colophon, on every page but sp500.
   Scoped to the shell only: page bodies keep their own language until the
   interior refits (P5/P6). Nothing here touches styles.css.
═══════════════════════════════════════════════════ */

/* ── nav: a thin stage-strip that arrives on scroll ── */
/* The strip is unconditional. Several pages paint their own light nav bar when
   #nav is not .scrolled, and bone type on that bar is invisible, so the shell
   owns the background in both states and only the hairline arrives on scroll. */
#nav {
  padding: 20px 0;
  background: color-mix(in srgb, var(--v2-stage) 86%, transparent) !important;
  backdrop-filter: saturate(140%) blur(14px);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: background 320ms ease, border-color 320ms ease,
              padding 320ms ease, backdrop-filter 320ms ease;
}
#nav.scrolled {
  background: color-mix(in srgb, var(--v2-stage) 94%, transparent) !important;
  border-bottom: 1px solid var(--v2-grid) !important;
  padding: 12px 0;
}

/* the wordmark, in the display face */
#nav .nav-logo,
body:has(.signals-hero) .nav-logo, body:has(.hz-hero) .nav-logo,
body:has(.er-hero) .nav-logo, body:has(.fs-hero) .nav-logo,
body:has(.cm-hero) .nav-logo, body:has(.os-hero) .nav-logo,
#nav.scrolled .nav-logo {
  font-family: var(--v2-display);
  font-weight: 600;
  font-size: 21px;
  letter-spacing: -0.02em;
  color: var(--v2-bone);
}
#nav .nav-logo span { color: var(--v2-signal); }
#nav .nav-logo:hover { color: var(--v2-counter); }

/* the links */
#nav .nav-links a,
#nav.scrolled .nav-links a {
  font-family: var(--v2-text);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.005em;
  color: color-mix(in srgb, var(--v2-bone) 78%, transparent);
  transition: color 200ms ease;
}
#nav .nav-links a:hover,
#nav.scrolled .nav-links a:hover { color: var(--v2-bone); }

/* the red-pen marker under the page you are on */
#nav .nav-links a.nav-active,
#nav .nav-links a.nav-spy-active,
#nav.scrolled .nav-links a.nav-active {
  color: var(--v2-bone) !important;
  position: relative;
}
#nav .nav-links a.nav-active::after,
#nav .nav-links a.nav-spy-active::after {
  content: "";
  position: absolute;
  left: -2px; right: -2px; bottom: -7px;
  height: 7px;
  background: no-repeat center / 100% 100%
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 10' preserveAspectRatio='none'><path d='M 2 6 C 30 2, 74 9, 118 4' fill='none' stroke='%23e0454f' stroke-width='2.2' stroke-linecap='round'/></svg>");
  pointer-events: none;
}

/* The one filled control. styles.css, signals.css and horizon2040.css each set
   this button with !important, so the shell has to answer in kind or the CTA
   reverts to a different colour on those pages. */
#nav .nav-links a.nav-cta,
#nav.scrolled .nav-links a.nav-cta {
  /* A filled button is text on colour, so it has to clear AA as text. Crimson
     at its display lightness gives 4.32:1 against bone; one step darker gives
     4.7:1 and is visually indistinguishable. The mark colour itself is
     unchanged, since rules and underlines are graphic, not type. */
  background: oklch(0.54 0.19 15) !important;
  border-color: oklch(0.54 0.19 15) !important;
  color: var(--v2-bone) !important;
  font-family: var(--v2-text) !important;
  font-weight: 600 !important;
  font-size: 14px !important;
  padding: 9px 18px !important;
  border-radius: 2px !important;
  border: 1px solid var(--v2-signal) !important;
  transition: background 200ms ease, border-color 200ms ease,
              transform 200ms ease !important;
}
#nav .nav-links a.nav-cta:hover,
#nav.scrolled .nav-links a.nav-cta:hover {
  background: var(--v2-counter) !important;
  border-color: var(--v2-counter) !important;
  color: var(--v2-stage) !important;   /* cyan is light, so stage is correct here */
  transform: translateY(-1px);
}
#nav .nav-links a.nav-cta::after { display: none; }

/* Buttons do not inherit the page face at any width. The previous fix lived
   inside the mobile media query, so at desktop the close control fell to
   Arial. */
button, .mobile-close, .hamburger { font-family: var(--v2-text); }

/* The takeover's type is sized inside the mobile query, but its FACE has to be
   set unconditionally: the panel is only translated off-canvas at desktop, not
   removed, so it kept styles.css's Fraunces and flashed it mid-transition. */
.mobile-menu a { font-family: var(--v2-display); }

/* hamburger bars ride the same bone */
#nav .hamburger span { background: var(--v2-bone) !important; }

/* ── mobile: a full-screen stage takeover, not a drawer ── */
@media (max-width: 900px) {
  .mobile-menu {
    width: 100%;
    max-width: none;
    background: var(--v2-stage);
    border-left: none;
    box-shadow: none;
    padding: 104px 30px 40px;
    transform: translateY(-100%);
    transition: transform 460ms cubic-bezier(.76,0,.24,1);
  }
  .mobile-menu.open { transform: translateY(0); }
  .mobile-menu ul {
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-align: left;
    align-items: flex-start;
    padding: 0;
    list-style: none;
  }
  .mobile-menu li { width: 100%; text-align: left; }
  .mobile-menu a {
    display: block;
    text-align: left;
    font-family: var(--v2-display);
    font-weight: 600;
    font-size: clamp(2rem, 9vw, 3.2rem);
    line-height: 1.04;
    letter-spacing: -0.03em;
    text-transform: uppercase;
    color: var(--v2-bone);
    /* word-slam: each line arrives from below, transform only */
    transform: translateY(46px);
    opacity: 1;
    transition: transform 520ms cubic-bezier(.16,1,.3,1), color 200ms ease;
  }
  .mobile-menu.open a { transform: translateY(0); }
  .mobile-menu.open li:nth-child(1) a { transition-delay: 60ms; }
  .mobile-menu.open li:nth-child(2) a { transition-delay: 105ms; }
  .mobile-menu.open li:nth-child(3) a { transition-delay: 150ms; }
  .mobile-menu.open li:nth-child(4) a { transition-delay: 195ms; }
  .mobile-menu.open li:nth-child(5) a { transition-delay: 240ms; }
  .mobile-menu.open li:nth-child(6) a { transition-delay: 285ms; }
  .mobile-menu.open li:nth-child(7) a { transition-delay: 330ms; }
  .mobile-menu.open li:nth-child(8) a { transition-delay: 375ms; }
  .mobile-menu a:hover, .mobile-menu a:active { color: var(--v2-signal); }
  .mobile-close {
    color: var(--v2-bone);
    font-size: 26px;
    background: none;
    border: none;
  }
  .mobile-close:hover { color: var(--v2-signal); }
  /* the takeover must clear the strip it came from */
  .mobile-menu { z-index: 300; }
}

/* ── the colophon: a footer that reads as marginalia ── */
.site-footer, .hz-footer, .er-footer, .cm-footer, .colophon, body > footer {
  background: var(--v2-stage);
  border-top: 1px solid var(--v2-grid);
  color: color-mix(in srgb, var(--v2-bone) 70%, transparent);
  font-family: var(--v2-text);
}
.site-footer .footer-name, body > footer .footer-name {
  font-family: var(--v2-display);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: color-mix(in srgb, var(--v2-bone) 88%, transparent);
}
.site-footer .footer-mono, body > footer .footer-mono,
.hz-footer .hz-footer-copy, .er-footer, .cm-footer, .colophon {
  font-family: var(--v2-text) !important;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--v2-bone) 62%, transparent);
}
.hz-footer .hz-footer-links a, .site-footer a, body > footer .footer-links a,
.er-footer a, .cm-footer a, .colophon a {
  font-family: var(--v2-text);
  color: color-mix(in srgb, var(--v2-bone) 74%, transparent);
  transition: color 180ms ease;
}
.hz-footer .hz-footer-links a:hover, .site-footer a:hover,
body > footer .footer-links a:hover, .er-footer a:hover, .cm-footer a:hover,
.colophon a:hover { color: var(--v2-signal); }

/* ── page transitions: native, progressive, no library ──
   Browsers without the API simply navigate instantly. That IS the fallback. */
@view-transition { navigation: auto; }
::view-transition-old(root) {
  animation: v2-vt-out 180ms cubic-bezier(.4,0,1,1) both;
}
::view-transition-new(root) {
  animation: v2-vt-in 320ms cubic-bezier(0,0,.2,1) both;
}
@keyframes v2-vt-out { to { opacity: 0; transform: translateY(-8px); } }
@keyframes v2-vt-in { from { opacity: 0; transform: translateY(10px); } }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
  .mobile-menu { transition: none; }
  .mobile-menu a { transform: none; transition: none; }
}

/* ═══════════════════════════════════════════════════
   THE INTERIOR (P5)
   Dossiers and project pages. Same move as the index body: remap the shared
   design tokens at body scope and the whole page follows, so the page's own
   stylesheet keeps working and never needs rewriting rule by rule.
   Opt-in via <body class="v2i">.
═══════════════════════════════════════════════════ */
body.v2i {
  /* ground */
  --paper: var(--v2-stage);
  --bg: var(--v2-stage);
  --bg2: var(--v2-stage-2);
  --card: var(--v2-stage-2);
  --dark: var(--v2-stage);
  --dark-ink: var(--v2-stage);
  --dark-surface: var(--v2-stage-2);

  /* type */
  --ink: var(--v2-bone);
  --text: var(--v2-bone);
  --dark-text: var(--v2-bone);
  --cream-on-dark: var(--v2-bone);
  --dim: var(--v2-bone-dim);
  --subtle: var(--v2-bone-dim);
  --dark-dim: var(--v2-bone-dim);

  /* structure */
  --border: var(--v2-grid);
  --border2: var(--v2-grid);
  --dark-border: var(--v2-grid);

  /* accents: crimson is the mark, ice cyan is the annotation */
  --oxblood: var(--v2-signal);
  --oxblood-on-dark: var(--v2-signal);
  --accent: var(--v2-signal);
  --accent2: var(--v2-signal);
  --red: var(--v2-signal);
  --ochre: var(--v2-counter);
  --teal: var(--v2-counter);
  --teal-bright: var(--v2-counter);
  --amber: var(--v2-counter);
  --lavender: var(--v2-counter);

  /* --white carries translucent overlays on these dark pages, so it has to
     become bone, not paper, or every scrim inverts (learned on the index) */
  --white: var(--v2-bone);

  background: var(--v2-stage);
  color: var(--v2-bone);
  font-family: var(--v2-text);

  /* ── THE FENCE ──
     The record instruments stay warm and ride inside the cold stage. The
     chokepoints globe keeps its gold by explicit prior decision, and the seven
     canvas hero-scenes read these same tokens, so re-pinning them here keeps
     both alive without touching hero-scenes.js or the globe code. */
  --globe-node:     oklch(0.78 0.14 78);
  --globe-arc:      oklch(0.58 0.16 28);
  --globe-arc-glow: oklch(0.72 0.135 78);
  --globe-grat:     oklch(0.92 0.009 75);
  --globe-land:     color-mix(in srgb, oklch(0.92 0.009 75) 32%, transparent);
  --globe-dark:     var(--v2-stage);
}

/* headings take the display face and the v2 caps grammar */
body.v2i h1, body.v2i h2, body.v2i h3 {
  font-family: var(--v2-display);
  letter-spacing: -0.025em;
}
body.v2i h1, body.v2i h2 { line-height: 0.99; }

/* the kicker system: one cyan eyebrow, never a pile-up */
body.v2i .hz-eyebrow, body.v2i .hz-kicker, body.v2i .er-eyebrow,
body.v2i .cm-eyebrow, body.v2i .signals-eyebrow, body.v2i .eyebrow,
body.v2i .section-label {
  color: var(--v2-counter);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 600;
}

/* Every number takes the display face and aligns. */
body.v2i .hz-stat-num, body.v2i .hz-impact-num, body.v2i .cp-data-cell-num,
body.v2i .sw-detail-metric-val, body.v2i .er-stat-value, body.v2i .cm-stat-value {
  font-family: var(--v2-display);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
body.v2i .hz-stat, body.v2i .hz-impact-stat { border-color: var(--v2-grid); }

/* The red pen goes ONLY on the four hero impact figures. There are ~190 numbers
   across these pages; marking them all would make the mark mean nothing. */
body.v2i .hz-impact-num {
  position: relative;
  display: inline-block;
}
body.v2i .hz-impact-num::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -0.18em;
  height: 2px;
  background: var(--v2-signal);
}

/* the labels under them were sized for mono; General Sans needs the room back */
body.v2i .hz-impact-label {
  color: var(--v2-bone-dim);
  letter-spacing: 0.06em;
  line-height: 1.5;
}

/* the ripple blocks read as marginalia running beside the argument */
body.v2i .hz-ripple, body.v2i .hz-ripples {
  border-inline-start: 1px solid var(--v2-grid);
  background: none;
}
body.v2i .hz-ripple-label {
  color: var(--v2-counter);
  font-family: var(--v2-text);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* pull quotes stay the pen's voice */
body.v2i blockquote, body.v2i .hz-lean, body.v2i .hz-pullquote {
  font-family: var(--v2-serif);
  font-style: italic;
  border-inline-start-color: var(--v2-signal);
}

/* numbers keep aligning */
body.v2i table, body.v2i .hz-table { font-variant-numeric: tabular-nums; }

/* Neither Clash Display nor General Sans ships an italic cut, so any italic
   set in them gets synthesised into a fake slanted roman. Zodiak is the only
   face here with a drawn italic, so every italic on every v2 page goes to it.
   Global, not scoped: the index needs this exactly as much as the interior. */
h1 em, h2 em, h3 em, h4 em, h1 i, h2 i, h3 i, h4 i,
em, i, cite, var, dfn,
.about-arc, .now-thought, .now-book-title, .thesis-lean, .blog-subtitle {
  font-family: var(--v2-serif);
  font-style: italic;
}
h1 em, h2 em, h3 em, h4 em, h1 i, h2 i, h3 i, h4 i { letter-spacing: -0.015em; }
/* An italic asked for inline gets the serif too. font-synthesis-style:none was
   the wrong answer here: it removes the fake slant and leaves the text upright,
   which loses the author's emphasis instead of honouring it. */
[style*="italic"], [style*="italic"] * { font-family: var(--v2-serif) !important; }

/* the interior's own italic idioms, and the SVG chart labels, which set their
   face as an attribute rather than through the cascade */
body.v2i .cp-data-cell-caveat, body.v2i .cp-source, body.v2i .cp-oneliner,
body.v2i .hz-caveat, body.v2i .hz-source, body.v2i .sw-source {
  font-family: var(--v2-serif);
  font-style: italic;
}
body.v2i svg text, body.v2i svg tspan {
  font-family: var(--v2-text);
  font-variant-numeric: tabular-nums;
}

/* how-i-research rides blog.css and the project pages still touch styles.css.
   Neither file is in this phase's scope to edit (blog.css is P6, styles.css is
   never edited), so the interior claims its type here instead. */
body.v2i, body.v2i p, body.v2i li, body.v2i span, body.v2i div, body.v2i td,
body.v2i th, body.v2i a, body.v2i label, body.v2i figcaption, body.v2i small,
body.v2i blockquote, body.v2i dt, body.v2i dd, body.v2i strong, body.v2i b {
  font-family: var(--v2-text);
}
body.v2i h1, body.v2i h2, body.v2i h3, body.v2i h4, body.v2i h5, body.v2i h6 {
  font-family: var(--v2-display);
}
body.v2i em, body.v2i i, body.v2i blockquote, body.v2i .blog-subtitle {
  font-family: var(--v2-serif);
}
/* the drop cap and any deliberate serif moment stay in the serif */
body.v2i .blog-body > p:first-of-type::first-letter {
  font-family: var(--v2-serif);
  color: var(--v2-signal);
}

/* Italic containers pass their slant down to children, but the broad
   `body.v2i p` rule was handing those children the sans, so the inherited
   italic came out as a fake oblique. The container hands down its face too. */
body.v2i .hz-hero-quote, body.v2i .hz-hero-quote *,
body.v2i .blog-pullquote, body.v2i .blog-pullquote *,
body.v2i .cp-data-notes, body.v2i .cp-data-notes *,
body.v2i .cp-source, body.v2i .cp-source *,
body.v2i .cp-oneliner, body.v2i .cp-oneliner *,
body.v2i blockquote * {
  font-family: var(--v2-serif);
}
/* an attribution that deliberately asks for the text face is not an italic */
body.v2i [style*="--v2-text"] { font-style: normal; }

/* --white does double duty in these stylesheets: mostly ink (which is why it
   maps to bone), but a handful of panels use it as a solid surface. At bone
   those became light cards sitting on the dark stage. The low-alpha uses
   (3-7%) are already correct as subtle lifts, so only the solid ones invert. */
body.v2i .hz-thesis-nav-card,
body.v2i .er-company-card {
  background: color-mix(in srgb, var(--v2-bone) 5%, transparent) !important;
  border: 1px solid var(--v2-grid) !important;
  color: var(--v2-bone);
}
body.v2i .hz-thesis-nav-card:hover,
body.v2i .hz-thesis-nav-card:focus {
  background: color-mix(in srgb, var(--v2-bone) 9%, transparent) !important;
  border-color: color-mix(in srgb, var(--v2-counter) 45%, transparent) !important;
}
/* their contents were coloured for a light card */
body.v2i .chart-panel *, body.v2i .status-cell *, body.v2i .er-company-card * {
  border-color: var(--v2-grid);
}

/* ═══════════════════════════════════════════════════
   THE INSTRUMENTS READ AS PAPER
   Charts sit on the dark stage as light panels. Plotted data needs the
   highest contrast on the page, and a chart drawn on the stage itself loses
   its gridlines and hairlines into the background. This is the same document
   move as the Writing section: the stage is the wall, the instrument is the
   page pinned to it.

   The Chart.js palette was already light-register (dark teal, crimson, warm
   grey grid) — it was the surface underneath that had gone dark.
═══════════════════════════════════════════════════ */
body.v2i .chart-panel,
body.v2i .status-cell {
  background: var(--v2-doc) !important;
  border: 1px solid oklch(0.86 0.008 95) !important;
  color: var(--v2-doc-ink) !important;
  box-shadow: 0 1px 3px oklch(0.1 0.01 285 / 0.35), 0 10px 30px oklch(0.1 0.01 285 / 0.22);
}

/* everything printed on the panel takes document ink */
body.v2i .chart-panel .chart-panel-title,
body.v2i .chart-panel .chart-reading-val,
body.v2i .status-cell .sc-name,
body.v2i .status-cell .sc-val {
  color: var(--v2-doc-ink) !important;
}
body.v2i .chart-panel .chart-interpretation,
body.v2i .chart-panel .chart-reading-label,
body.v2i .chart-panel .chart-reading-unit,
body.v2i .status-cell .sc-sub,
body.v2i .status-cell .sc-unit {
  color: oklch(0.44 0.01 285) !important;
}
body.v2i .chart-panel .chart-panel-source,
body.v2i .status-cell .sc-asof {
  color: oklch(0.52 0.01 285) !important;
}
/* the manual/live tag and the as-of stamp keep their escalation, on paper */
body.v2i .status-cell .sc-asof--stale { color: oklch(0.48 0.11 195) !important; }
body.v2i .status-cell .sc-asof--old   { color: var(--v2-signal) !important; }

/* hairlines inside a panel are drawn on paper, not on the stage */
body.v2i .chart-panel .chart-panel-header,
body.v2i .chart-panel .chart-reading,
body.v2i .chart-panel *,
body.v2i .status-cell * { border-color: oklch(0.88 0.008 95); }

/* the red/amber/green state wash has to work on paper too */
body.v2i .status-cell.sc-green { background: oklch(0.965 0.02 150) !important; }
body.v2i .status-cell.sc-amber { background: oklch(0.97 0.035 85) !important; }
body.v2i .status-cell.sc-red   { background: oklch(0.965 0.025 25) !important; }

/* links out of a panel */
body.v2i .chart-panel a { color: var(--v2-signal) !important; }
body.v2i .chart-panel a:hover { color: oklch(0.42 0.155 28) !important; }

/* .status-matrix paints its hairlines with the gap trick: a 1px grid gap over
   a coloured container background. With --border remapped that container went
   dark, so the slots left over at the end of the grid read as a hole punched
   in the sheet. The cells draw their own borders now, so the container can be
   paper and the leftover slots disappear into it. */
body.v2i .status-matrix {
  background: var(--v2-doc) !important;
  border: 1px solid oklch(0.86 0.008 95);
}
body.v2i .status-cell:hover {
  background: oklch(0.995 0.001 95) !important;
}

/* an empty-state box sits inside a light panel, so it is drawn on paper */
body.v2i .chart-error {
  background: oklch(0.945 0.004 95) !important;
  border: 1px dashed oklch(0.82 0.01 95) !important;
  color: oklch(0.44 0.01 285) !important;
}
