/* ─────────────────────────────────────────────────────────────
   unconventionalsingh.com
   Two rooms, one instrument. Dark: the lab with the lights off.
   Light: the same lab, lit. The plate resonates in both.
   ───────────────────────────────────────────────────────────── */

/* ── type: IBM Plex, self-hosted — no fonts fetched from anywhere ── */
@font-face {
  font-family: "IBM Plex Sans";
  src: url("../assets/fonts/ibm-plex-sans-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("../assets/fonts/ibm-plex-sans-400-italic.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("../assets/fonts/ibm-plex-sans-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../assets/fonts/ibm-plex-mono-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}

:root {
  /* dark — lights off (default) */
  --bg:        #0a0e12;   /* cool near-black          */
  --bg-2:      #121820;   /* raised surfaces          */
  --bg-3:      #1b2430;   /* deeper surfaces          */
  --fg:        #e9eef2;   /* primary text             */
  --fg-dim:    #a4b1bb;   /* secondary text           */
  --fg-faint:  #66737f;   /* tertiary / marks         */
  --accent:    #dd982f;   /* burnt amber               */
  --accent-hi: #f0b355;
  --accent-2:  #46c8b2;   /* laser teal                */
  --rule:      #202a34;
  --on-accent: #0a0e12;   /* text set on the accent    */
  --glow:      rgba(240, 179, 85, 0.32);

  --sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI",
          Helvetica, Arial, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", "Cascadia Code",
          Menlo, Consolas, monospace;

  --wrap: 68rem;
  --pad: clamp(1.25rem, 4vw, 3rem);
}

/* light — lights on */
:root[data-theme="light"] {
  --bg:        #eff6f5;   /* pale cool teal-white     */
  --bg-2:      #e2ecea;
  --bg-3:      #d2e0dd;
  --fg:        #101b19;
  --fg-dim:    #374743;
  --fg-faint:  #5d6f6b;
  --accent:    #17624c;   /* lab green ink             */
  --accent-hi: #114a39;
  --accent-2:  #145a41;   /* deep leaf                 */
  --rule:      #cbdbd8;
  --on-accent: #eff6f5;
  --glow:      rgba(23, 98, 76, 0.22);
}

/* No JS: the lab still starts with the lights off. Dark is the
   default everywhere until a visitor flips the switch. */

/* ── reset-ish ── */
*, *::before, *::after { box-sizing: border-box; }
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* `clip`, not `hidden`: `overflow-x: hidden` would make this a scroll
     container, which breaks fragment navigation and position: fixed. */
  overflow-x: clip;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-size: clamp(1.0625rem, 0.95rem + 0.4vw, 1.1875rem);
  line-height: 1.65;
}
/* The phase change: colours drift rather than cut. */
html.theme-shift body,
html.theme-shift .topbar,
html.theme-shift .footer,
html.theme-shift .plate {
  transition: background-color 0.7s ease, color 0.7s ease,
              border-color 0.7s ease;
}
img { max-width: 100%; height: auto; display: block; }
h1, h2, h3, h4 { line-height: 1.15; margin: 0 0 0.6em; font-weight: 700; }
p { margin: 0 0 1em; }
a { color: var(--accent-hi); text-decoration-color: color-mix(in srgb, var(--accent-hi) 45%, transparent); text-underline-offset: 3px; }
a:hover { color: var(--fg); text-decoration-color: var(--accent-hi); }
::selection { background: var(--accent); color: var(--on-accent); }

.wrap {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
}

/* ── accessibility ── */
.skip {
  position: absolute; left: -200vw; top: 0;
  background: var(--accent); color: var(--on-accent);
  padding: 0.6em 1em; z-index: 100; font-family: var(--mono);
}
.skip:focus { left: 0; }

:focus-visible {
  outline: 2px solid var(--accent-hi);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ─────────────────────────────────────────────────────────────
   The plate — fixed canvas behind everything
   ───────────────────────────────────────────────────────────── */
.plate {
  position: fixed; inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--bg);
}
#plate-canvas {
  width: 100%; height: 100%;
  display: block;
  opacity: 0.66;
  transition: opacity 0.6s ease;
}
/* Drive amplitude: how loudly the plate speaks. */
body[data-dial="1"] #plate-canvas { opacity: 0.34; }
body[data-dial="3"] #plate-canvas { opacity: 0.85; }
/* The lit lab needs denser ink for the same presence. */
:root[data-theme="light"] #plate-canvas { opacity: 0.85; }
:root[data-theme="light"] body[data-dial="1"] #plate-canvas { opacity: 0.45; }
:root[data-theme="light"] body[data-dial="3"] #plate-canvas { opacity: 1; }

/* No page-wide scrim. The old diagonal gradient dimmed the left half
   of the folded spectrum and drew a visible seam across the plate.
   Legibility is now handled locally, behind the text that needs it —
   see the .wrap veils in the hero, chapters and sections. The plate
   itself burns evenly edge to edge. */
/* film grain via tiny repeating conic pattern — cheap, no image */
.plate-grain {
  position: absolute; inset: 0;
  z-index: 2;   /* above the scrim, so grain sits on the whole composite */
  background-image: repeating-conic-gradient(
    color-mix(in srgb, var(--fg) 2%, transparent) 0% 25%,
    transparent 0% 50%);
  background-size: 3px 3px;
  mix-blend-mode: overlay;
}

main, .topbar, .footer { position: relative; z-index: 1; }

/* ─────────────────────────────────────────────────────────────
   Top bar
   ───────────────────────────────────────────────────────────── */
.topbar {
  position: sticky; top: 0;
  display: flex; align-items: center; gap: 1rem;
  padding: 0.65rem var(--pad);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--rule);
  z-index: 10;
}
.wordmark {
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-decoration: none;
  color: var(--fg);
  display: inline-flex; align-items: baseline; gap: 0.5em;
  white-space: nowrap;
}
.wordmark-k {
  color: var(--on-accent);
  background: var(--accent);
  padding: 0.15em 0.4em;
  border-radius: 2px;
  font-weight: 700;
}
.wordmark-full { color: var(--fg-dim); }
.wordmark:hover .wordmark-full { color: var(--fg); }
/* Two names share one grid cell, so the wordmark is always as wide
   as the longer of them — the crossfade never shifts the layout.
   While the hero is in view: the site. Past it: the person. */
.wordmark-full { display: inline-grid; }
.wordmark-name {
  grid-area: 1 / 1;
  white-space: nowrap;
  transition: opacity 0.45s ease;
}
.wordmark-name-person { opacity: 0; }
body.past-hero .wordmark-name-site { opacity: 0; }
body.past-hero .wordmark-name-person { opacity: 1; }

.nav {
  margin-left: auto;
  display: flex; gap: clamp(0.6rem, 2vw, 1.4rem);
  overflow-x: auto;
  /* Without this a flex item's min-width is `auto`, so the nav refuses
     to shrink below its content width and drags the whole document
     wider than the viewport. */
  min-width: 0;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}
.nav::-webkit-scrollbar { display: none; }
.nav a {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  color: var(--fg-dim);
  text-decoration: none;
  padding: 0.35em 0;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.nav a:hover { color: var(--fg); }
.nav a[aria-current="true"] {
  color: var(--accent-hi);
  border-bottom-color: var(--accent);
  animation: nav-pulse 0.7s ease;
}
/* Navigation as reaction pathway: arriving somewhere emits a pulse. */
@keyframes nav-pulse {
  0%   { text-shadow: 0 0 0 transparent; }
  35%  { text-shadow: 0 0 14px var(--glow); }
  100% { text-shadow: 0 0 0 transparent; }
}

.controls { display: inline-flex; align-items: center; gap: 0.45rem; }
.ctrl {
  display: inline-flex; align-items: center; gap: 0.45em;
  background: none;
  border: 1px solid var(--rule);
  border-radius: 999px;
  color: var(--fg-dim);
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  padding: 0.3em 0.7em;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.ctrl:hover { color: var(--fg); border-color: var(--fg-faint); }
.plate-toggle-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent-2);
  transition: background 0.2s;
}
.plate-toggle[aria-pressed="false"] .plate-toggle-dot { background: var(--fg-faint); }
.ctrl.is-hidden { display: none; }
#sound-toggle.sound-on { color: var(--accent-2); border-color: var(--accent-2); }

/* Sound is off by default, and says so: the muted convention, a
   thin diagonal stroke through the note. Enabling clears it. */
.sound-glyph { position: relative; display: inline-block; }
.sound-glyph::after {
  content: "";
  position: absolute;
  left: -0.18em; right: -0.18em; top: 50%;
  height: 1.5px;
  background: currentColor;
  border-radius: 1px;
  transform: rotate(-40deg);
  transition: opacity 0.2s ease;
}
#sound-toggle.sound-on .sound-glyph::after { opacity: 0; }

/* ── the drive-amplitude dial ────────────────────────────────
   Resting state: a small sine glyph whose amplitude is the
   setting. The word (calm / lively / full) surfaces on hover on
   fine pointers, or transiently after a tap on touch.           */
.ctrl-dial { padding-block: 0.22em; }
.dial-face {
  display: grid;
  place-items: center;
  min-width: 4.2em;   /* room for "lively" so the pill never resizes */
  min-height: 1.1em;
}
.dial-glyph, .dial-word { grid-area: 1 / 1; transition: opacity 0.25s ease; }
.dial-glyph {
  width: 1.7em; height: auto;
  display: block;
  overflow: visible;
}
.dial-wave {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  display: none;
}
body[data-dial="1"] .dial-wave-1 { display: block; }
body[data-dial="2"] .dial-wave-2 { display: block; }
body[data-dial="3"] .dial-wave-3 { display: block; }
.dial-word { opacity: 0; }
@media (hover: hover) and (pointer: fine) {
  .ctrl-dial:hover .dial-word { opacity: 1; }
  .ctrl-dial:hover .dial-glyph { opacity: 0; }
}
.ctrl-dial.show-word .dial-word { opacity: 1; }
.ctrl-dial.show-word .dial-glyph { opacity: 0; }

/* ─────────────────────────────────────────────────────────────
   Annotations — appear when the dial is turned up
   ───────────────────────────────────────────────────────────── */
.annot {
  display: none;
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  color: var(--accent-2);
  border-left: 2px solid var(--accent-2);
  padding-left: 0.8em;
  max-width: 40em;
  margin-block: 1rem;
}
body[data-dial="3"] .annot { display: block; animation: annot-in 0.5s ease; }
@keyframes annot-in {
  from { opacity: 0; translate: 0 0.3em; }
  to   { opacity: 1; translate: 0 0; }
}
/* At full dial, headings loosen their tie. */
body[data-dial="3"] .section-title { font-style: italic; }

/* ─────────────────────────────────────────────────────────────
   Hero
   ───────────────────────────────────────────────────────────── */
.hero {
  min-height: calc(100svh - 3.5rem);
  display: flex; flex-direction: column; justify-content: center;
  padding-block: clamp(4rem, 10vh, 7rem) 3rem;
  position: relative;
  /* The veil below bleeds 7rem past the column on each side. On a
     wide screen the column has that much slack; on a phone it does
     not, and the bleed dragged the document 112px wider than the
     viewport — a horizontal pan on Android. Clip it here rather
     than narrowing the veil, so the pool keeps its shape where it
     fits. `clip`, not `hidden`: no scroll container, and unlike
     `hidden` it leaves overflow-y visible. */
  overflow-x: clip;
}
/* Local veil: a soft pool of ground behind the hero text only,
   feathered to nothing so the plate stays untouched elsewhere. */
.hero .wrap { position: relative; }
.hero .wrap::before {
  content: "";
  position: absolute; inset: -5rem -7rem;
  /* closest-side: the transparent contour is inscribed in the box,
     so the veil dies before its own edge — no seam. */
  background: radial-gradient(closest-side at 50% 50%,
    color-mix(in srgb, var(--bg) 72%, transparent) 0%,
    color-mix(in srgb, var(--bg) 60%, transparent) 42%,
    color-mix(in srgb, var(--bg) 30%, transparent) 74%,
    transparent 100%);
  z-index: -1;
  pointer-events: none;
}
/* The lit lab reflects more: its veil must be denser for the same
   legibility. Dark-mode veils are untouched. */
:root[data-theme="light"] .hero .wrap::before {
  background: radial-gradient(closest-side at 50% 50%,
    color-mix(in srgb, var(--bg) 90%, transparent) 0%,
    color-mix(in srgb, var(--bg) 80%, transparent) 42%,
    color-mix(in srgb, var(--bg) 45%, transparent) 74%,
    transparent 100%);
}
.eyebrow {
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 1.2rem;
}
/* The name is the H1 — a personal site leads with the person. */
.hero-title {
  font-size: clamp(2.05rem, 0.9rem + 5.8vw, 5.5rem);
  letter-spacing: -0.02em;
  line-height: 1.02;
  margin-bottom: 1.1rem;
  text-wrap: balance;
}
/* The headline: what the name does. Quieter than the name,
   louder than everything below it. */
.hero-headline {
  font-size: clamp(1.3rem, 1rem + 1.6vw, 2.05rem);
  line-height: 1.3;
  color: var(--fg);
  margin-bottom: 1.1rem;
  max-width: 24em;
  text-wrap: balance;
}
.hero-headline .em {
  color: var(--accent-hi);
  font-style: italic;
}
/* The tagline: distinct by treatment, not size — the site's one
   dispersion gradient, muted, carried by the words themselves. */
.tagline {
  font-size: clamp(1.1rem, 1rem + 0.6vw, 1.4rem);
  font-style: italic;
  max-width: 34em;
  margin-bottom: 1.4rem;
  background: linear-gradient(90deg,
    #8a76c9, #4b8f96, #6f9f5f, #c08f3f, #c06f4f);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  width: fit-content;
}
.hero-role {
  font-family: var(--mono);
  font-size: clamp(0.78rem, 0.72rem + 0.3vw, 0.9rem);
  letter-spacing: 0.05em;
  color: var(--fg-dim);
  line-height: 1.9;
  max-width: 44em;
}

.hero-actions {
  display: flex; flex-wrap: wrap; gap: 0.8rem;
  margin-block: 1.8rem 2.4rem;
}
.btn {
  font-family: var(--mono);
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  text-decoration: none;
  color: var(--fg);
  border: 1px solid var(--fg-faint);
  border-radius: 2px;
  padding: 0.7em 1.2em;
  transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.btn:hover { border-color: var(--fg); color: var(--fg); }
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
}
.btn-primary:hover {
  background: var(--accent-hi);
  border-color: var(--accent-hi);
  color: var(--on-accent);
}

.hero-foot {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--fg-faint);
  max-width: 44em;
  line-height: 1.7;
}
.no-plate .hero-foot { display: none; }
/* Without JS there is no live plate — the caption would be a lie. */
html:not(.js) .hero-foot { display: none; }
.hero-foot-link {
  color: var(--fg-faint);
  text-decoration-style: dotted;
  text-decoration-color: var(--fg-faint);
  margin-left: 0.45em;
  white-space: nowrap;
}
.hero-foot-link:hover { color: var(--fg); }
.hero-foot-btns { white-space: nowrap; }
.hero-foot-btns .inline-btn { margin-left: 0.7em; }
.tick {
  display: inline-block;
  width: 0.55em; height: 0.55em;
  background: var(--accent-2);
  border-radius: 50%;
  margin-right: 0.5em;
  vertical-align: baseline;
}
.inline-btn {
  font: inherit;
  color: var(--accent-hi);
  background: none; border: none;
  border-bottom: 1px dashed var(--accent);
  cursor: pointer;
  padding: 0 0 1px;
}
.inline-btn:hover { color: var(--fg); }
.inline-btn[aria-pressed="true"] {
  color: var(--fg);
  border-bottom-style: solid;
}

.scroll-cue {
  position: absolute; left: 50%; bottom: 1.2rem;
  transform: translateX(-50%);
  width: 1px; height: 3rem;
  overflow: hidden;
}
.scroll-cue span {
  display: block; width: 1px; height: 100%;
  background: linear-gradient(var(--fg-faint), transparent);
  animation: cue 2.2s ease-in-out infinite;
}
@keyframes cue {
  0%   { transform: translateY(-100%); }
  60%  { transform: translateY(100%); }
  100% { transform: translateY(100%); }
}

/* ─────────────────────────────────────────────────────────────
   Chapters — computing beyond convention
   ───────────────────────────────────────────────────────────── */
.chapters { border-top: 1px solid var(--rule); }
.chapter {
  /* Fixed rhythm, not viewport staging: each line gets a beat of
     ground around it, but the plate never holds a half-screen of
     dead air between thoughts. Tight enough that the three
     statements and the coda read as one connected passage. */
  min-height: 0;
  padding-block: 2.75rem;
  display: flex; align-items: center;
  overflow-x: clip;   /* same veil bleed as the hero — see .hero */
}
.chapter:first-child { padding-top: 4.25rem; }
.chapter:last-child  { padding-bottom: 4.25rem; }
/* Same local veil as the hero: ground pooled behind the line itself.
   One shared column: as a flex item the wrap would otherwise
   shrink-to-fit its own content and centre at its own width —
   which let chapter 03 (with the coda) drift off the others'
   left edge. Pin every chapter to the same centred column. */
.chapter .wrap {
  position: relative;
  width: 100%;
  max-width: min(var(--wrap), 48rem);
}
.chapter .wrap::before {
  content: "";
  position: absolute; inset: -4rem -6rem;
  background: radial-gradient(closest-side at 50% 50%,
    color-mix(in srgb, var(--bg) 64%, transparent) 0%,
    color-mix(in srgb, var(--bg) 48%, transparent) 48%,
    transparent 100%);
  z-index: -1;
  pointer-events: none;
}
:root[data-theme="light"] .chapter .wrap::before {
  background: radial-gradient(closest-side at 50% 50%,
    color-mix(in srgb, var(--bg) 86%, transparent) 0%,
    color-mix(in srgb, var(--bg) 68%, transparent) 48%,
    transparent 100%);
}
.chapter-no {
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  color: var(--accent-2);
  margin-bottom: 0.8rem;
}
/* The three statements are setup, not headline: demoted to a
   quiet, unbolded line so the coda's question can carry the peak. */
.chapter-line {
  font-size: clamp(1.35rem, 1rem + 1.7vw, 2.1rem);
  font-weight: 400;
  letter-spacing: -0.005em;
  color: var(--fg-dim);
  max-width: 22em;
  margin: 0;
  text-wrap: balance;
}

/* Keyword treatments — one per substrate, each at the same quiet
   weight as .spectral, each a different flavour. */

/* switches — binary: the word set in the machine's own face,
   with a small 0→1 toggle raised beside it. */
.kw-binary {
  font-family: var(--mono);
  font-size: 0.95em;
  letter-spacing: 0.01em;
}
.kw-binary::after {
  content: "0\2192 1";
  font-size: 0.38em;
  letter-spacing: 0.1em;
  color: var(--fg-faint);
  vertical-align: 0.9em;
  margin-left: 0.45em;
}

/* reactions — equilibrium: the word itself leans forward and
   back — italic, tracking eased open, tinted toward the
   chemistry teal. The type carries it; no diagram attached. */
.kw-equilibrium {
  font-style: italic;
  letter-spacing: 0.045em;
  color: color-mix(in srgb, var(--accent-2) 55%, var(--fg-dim));
}

/* The coda is the highlight of the whole sequence: the question,
   not the answers. */
.chapter-coda {
  margin-top: 1.6rem;
  max-width: 34em;
}
.coda-setup {
  display: block;
  font-size: clamp(1.02rem, 1rem + 0.3vw, 1.2rem);
  color: var(--fg-dim);
  margin-bottom: 0.55rem;
}
.coda-question {
  display: block;
  font-size: clamp(1.9rem, 1.1rem + 3.8vw, 3.7rem);
  font-weight: 700;
  font-style: italic;
  line-height: 1.12;
  letter-spacing: -0.01em;
  color: var(--accent-hi);
  max-width: 15em;
  text-wrap: balance;
}

/* Dispersion, not neon: the one word allowed to split into a spectrum.
   Mid-saturation stops chosen to read on both phases. */
.spectral {
  background: linear-gradient(90deg,
    #8a76c9, #4b8f96, #6f9f5f, #c08f3f, #c06f4f);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Text diffusion: headings arrive dispersed, resolve into clarity.
   Gated on html.js so nothing is ever stuck blurred without JS. */
html.js .fx-resolve {
  opacity: 0.15;
  filter: blur(6px);
  letter-spacing: 0.06em;
  transition: opacity 0.9s ease, filter 0.9s ease, letter-spacing 0.9s ease;
}
html.js .fx-resolve.is-resolved {
  opacity: 1;
  filter: blur(0);
  letter-spacing: -0.01em;
}

/* ─────────────────────────────────────────────────────────────
   Sections
   ───────────────────────────────────────────────────────────── */
.section {
  padding-block: clamp(4rem, 10vh, 7.5rem);
  border-top: 1px solid var(--rule);
  /* Uniform wash — carries body-text legibility now that the page-wide
     scrim is gone. Even left to right, so the folded spectrum keeps
     its symmetry underneath. */
  background:
    linear-gradient(color-mix(in srgb, var(--bg) 72%, transparent),
                    color-mix(in srgb, var(--bg) 72%, transparent));
}
:root[data-theme="light"] .section {
  background:
    linear-gradient(color-mix(in srgb, var(--bg) 87%, transparent),
                    color-mix(in srgb, var(--bg) 87%, transparent));
}
.section-mark {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-2);
  margin-bottom: 0.9rem;
}
.section-title {
  font-size: clamp(1.9rem, 1.2rem + 3vw, 3.2rem);
  letter-spacing: -0.01em;
  max-width: 18em;
  text-wrap: balance;
  margin-bottom: 1.2rem;
}
.lead {
  font-size: clamp(1.08rem, 1rem + 0.4vw, 1.25rem);
  color: var(--fg-dim);
  max-width: 40em;
}
.lead em, .lead strong { color: var(--fg); }
.subhead {
  font-family: var(--mono);
  font-size: 0.85rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin: 3rem 0 1.4rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rule);
}
.hint {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  color: var(--fg-faint);
  margin: -0.9rem 0 1rem;
}

/* ── research strands ── */
.strands {
  display: grid;
  gap: 2.4rem;
  margin-top: 3rem;
}
@media (min-width: 860px) {
  .strands { grid-template-columns: repeat(3, 1fr); gap: 2.6rem; }
}
.strand h3 {
  font-size: 1.35rem;
  color: var(--accent-hi);
}
.strand-meta {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--fg-faint);
  margin: -0.4rem 0 1rem;
}
.strand p { color: var(--fg-dim); font-size: 0.98rem; }
.strand p strong, .strand p em { color: var(--fg); }
.strand-note {
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--fg-faint);
  border-left: 2px solid var(--accent-2);
  padding-left: 0.8em;
}

/* ── publications: ground state / excited state ── */
.pubs { list-style: none; margin: 0; padding: 0; }
.pub {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  gap: 1.2rem;
  padding-block: 1.1rem;
  border-bottom: 1px solid var(--rule);
  cursor: pointer;
}
.pub:last-child { border-bottom: none; }
.pub-year {
  font-family: var(--mono);
  font-size: 0.85rem;
  color: var(--fg-faint);
  padding-top: 0.25rem;
  transition: color 0.25s;
}
.pub-body h4 { font-size: 1.1rem; margin-bottom: 0.25rem; transition: color 0.25s; }
.pub-body h4 a { color: var(--fg); text-decoration: none; }
.pub-venue { font-size: 0.9rem; color: var(--fg-faint); margin-bottom: 0; transition: color 0.25s; }
.pub-authors { font-size: 0.92rem; color: var(--fg-dim); margin: 0.5rem 0 0.15rem; }
.pub-authors strong { color: var(--fg); }
.pub-gloss { font-size: 0.95rem; color: var(--fg-dim); font-style: italic; max-width: 44em; }
.pub-links { font-family: var(--mono); font-size: 0.72rem; margin: 0 0 0.4rem; }

/* The excited state: extra detail unfolds on hover, focus or tap. */
.pub-extra {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.35s ease;
}
.pub-extra > div { overflow: hidden; min-height: 0; }
.pub:hover .pub-extra,
.pub:focus-within .pub-extra,
.pub.excited .pub-extra { grid-template-rows: 1fr; }
.pub:hover .pub-year,
.pub:focus-within .pub-year,
.pub.excited .pub-year { color: var(--accent); }
.pub:hover .pub-venue,
.pub:focus-within .pub-venue,
.pub.excited .pub-venue { color: var(--fg-dim); }
.pub:hover h4 a { color: var(--accent-hi); }
.pub-pending .pub-year { color: var(--accent-2); }
.pub-pending .pub-body h4 { color: var(--fg-dim); }

/* ── talks ── */
.talks { list-style: none; margin: 0; padding: 0; }
.talks li {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  gap: 1.2rem;
  padding-block: 0.55rem;
  font-size: 0.95rem;
  color: var(--fg-dim);
}
.talk-year { font-family: var(--mono); font-size: 0.85rem; color: var(--accent); }
.talk-body strong { color: var(--fg); font-weight: 600; }

/* ── flip cards — experiments you turn over ──────────────────
   Both faces occupy the same grid cell, so the card's height is
   the taller of the two; nothing jumps when it flips.           */
.card {
  perspective: 1000px;
  cursor: pointer;
  outline-offset: 4px;
}
.card-inner {
  display: grid;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.card-front, .card-back {
  grid-area: 1 / 1;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: color-mix(in srgb, var(--bg-2) 82%, var(--bg));
  padding: 1.2rem 1.3rem;
}
.card-back { transform: rotateY(180deg); }
/* One flip mechanism per device class, so they never fight:
   fine pointers flip on hover; touch flips on tap (.flipped, set in
   JS only on coarse pointers); keyboard toggles .flipped everywhere.
   Focus alone does not flip — Enter/Space does, deliberately. */
@media (hover: hover) and (pointer: fine) {
  .card:hover .card-inner { transform: rotateY(180deg); }
}
.card.flipped .card-inner { transform: rotateY(180deg); }
.card-glyph {
  font-family: var(--mono);
  font-size: 0.9rem;
  color: var(--fg-faint);
  position: absolute;
  right: 0.9rem; bottom: 0.6rem;
}
.card-front { position: relative; }

/* ── projects ── */
.projects {
  display: grid; gap: 1.6rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.project-year {
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--accent-2);
  margin-bottom: 0.5rem;
}
.project h4 { font-size: 1.08rem; margin-bottom: 0; }
.project .card-back p { font-size: 0.92rem; color: var(--fg-dim); margin: 0; }
.project .card-back {
  border-color: color-mix(in srgb, var(--accent) 35%, var(--rule));
}

/* ── field notes ── */
.notes {
  list-style: none;
  margin: 1.6rem 0 0; padding: 0;
  display: grid; gap: 1.4rem;
  grid-template-columns: repeat(auto-fit, minmax(13.5rem, 1fr));
}
.note .card-front {
  border-top: 2px solid var(--accent-2);
  display: flex; flex-direction: column;
  align-items: flex-start; justify-content: space-between;
  gap: 1.2rem;
}
.note .card-back { border-top: 2px solid var(--accent-2); }
.note-glyph {
  font-size: 1.6rem;
  color: var(--accent-2);
  line-height: 1;
}
.note-tag {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-2);
  margin: 0;
}
.note .card-back p { font-size: 0.95rem; color: var(--fg-dim); margin: 0; }

/* ── rooms ── */
.rooms {
  display: grid; gap: 2rem;
  margin-top: 0.5rem;
}
@media (min-width: 860px) {
  .rooms { grid-template-columns: repeat(3, 1fr); }
}
.room { margin: 0; }
.room-img {
  aspect-ratio: 3 / 2;
  border: 1px solid var(--rule);
  border-radius: 3px;
  background:
    linear-gradient(160deg,
      color-mix(in srgb, var(--accent-2) 12%, var(--bg-2)),
      var(--bg-2) 70%);
  display: grid; place-items: center;
  margin-bottom: 1rem;
  overflow: hidden;
}
.room-img img { width: 100%; height: 100%; object-fit: cover; }
.room-placeholder {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: var(--fg-faint);
}
.room-where {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.4rem;
}
.room figcaption h4 { font-size: 1.05rem; margin-bottom: 0.3rem; }
.room-when {
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--fg-faint);
  margin-bottom: 0;
}
.room-when strong { color: var(--fg-dim); font-weight: 600; }
.rooms-note {
  margin-top: 2.4rem;
  font-size: 0.9rem;
  color: var(--fg-faint);
  max-width: 44em;
}

/* ── about ── */
.about-grid {
  display: grid;
  gap: 2.5rem;
  margin-top: 2.5rem;
}
@media (min-width: 780px) {
  .about-grid { grid-template-columns: 17rem 1fr; align-items: start; }
  .about-portrait { position: sticky; top: 5rem; }
}
.about-portrait img {
  border-radius: 3px;
  border: 1px solid var(--rule);
}
.about-portrait figcaption {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--fg-faint);
  margin-top: 0.6rem;
}
.about-text p { color: var(--fg-dim); max-width: 40em; }
.about-text p em, .about-text p strong { color: var(--fg); }
.about-text p:first-child::first-letter {
  font-size: 3.2em;
  float: left;
  line-height: 0.85;
  padding-right: 0.12em;
  color: var(--accent-hi);
}

/* ── contact ── */
.links {
  list-style: none;
  margin: 2.4rem 0; padding: 0;
  display: grid; gap: 0;
  max-width: 34rem;
  border-top: 1px solid var(--rule);
}
.links a {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem;
  padding: 0.9rem 0.2rem;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
}
.links a:hover { background: color-mix(in srgb, var(--bg-2) 80%, transparent); }
.link-label {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-faint);
}
.links a:hover .link-label { color: var(--accent-2); }
.link-value { color: var(--fg); font-size: 0.98rem; text-align: right; }
.address {
  font-size: 0.9rem;
  color: var(--fg-faint);
}
.links-note {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--fg-faint);
  margin: -1.6rem 0 2rem;
}

/* ── send a signal ───────────────────────────────────────────
   The quick-pick: revealed after the button, gone after the
   choice. The note is where the count answers back.            */
.signal-picker {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.5rem;
  margin: -0.2rem 0 1.2rem;
}
.signal-picker[hidden] { display: none; }
.pick {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  background: none;
  border: 1px solid var(--rule);
  border-radius: 999px;
  color: var(--fg-dim);
  padding: 0.42em 0.95em;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.pick:hover { color: var(--fg); border-color: var(--fg-faint); }
.pick-plain { border-style: dashed; color: var(--fg-faint); }
.signal-note {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  color: var(--accent-2);
  min-height: 1.3em;
  margin-bottom: 0.4rem;
}
html:not(.js) .signal-picker,
html:not(.js) .signal-note,
html:not(.js) #signal { display: none; }

/* ── the constellation ───────────────────────────────────────
   Every signal received, as a star behind the contact block.
   Painted by JS from one anonymous count; absent without it.   */
.section-contact { position: relative; overflow: hidden; }
.section-contact .wrap { position: relative; z-index: 1; }
.constellation {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  z-index: 0;
  pointer-events: none;
}
.constellation-count {
  position: absolute; right: 1.1rem; bottom: 0.9rem;
  z-index: 1;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  color: var(--fg-faint);
  pointer-events: none;
}
.no-plate .constellation, .no-plate .constellation-count,
html:not(.js) .constellation, html:not(.js) .constellation-count { display: none; }

/* ── colophon — the plate, explained ─────────────────────────
   Deliberately small: an appendix, not a chapter. It is the
   target of the hero's "how this works" link.                  */
.section-colophon {
  padding-block: clamp(2.8rem, 6vh, 4.5rem);
}
.colophon-title {
  font-size: 1.2rem;
  letter-spacing: 0;
  margin-bottom: 1.1rem;
}
.colophon-body p {
  font-size: 0.88rem;
  color: var(--fg-dim);
  max-width: 46em;
}
.colophon-body p:last-child {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.03em;
  color: var(--fg-faint);
  margin-bottom: 0;
}

/* ── footer ── */
.footer {
  border-top: 1px solid var(--rule);
  padding-block: 2.6rem 3.2rem;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
}
.colophon, .copy {
  font-size: 0.8rem;
  color: var(--fg-faint);
  max-width: 52em;
}
.copy { font-family: var(--mono); font-size: 0.72rem; margin-bottom: 0.5rem; }
/* The privacy line is the site's last word. */
.colophon { margin-bottom: 0; }

/* ─────────────────────────────────────────────────────────────
   Frequency bar — the folded spectrum, as instrumentation
   A hairline legend along the bottom edge: 662 nm at the centre,
   405 nm at both ends, exactly the plate's drive mapping. Two
   mirrored ticks mark the current drive. Fades in while the
   plate is being driven, out when it idles.
   ───────────────────────────────────────────────────────────── */
.freqbar {
  position: fixed; left: 0; right: 0; bottom: 0;
  height: 14px;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.9s ease;
}
.freqbar::before {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px;
  opacity: 0.8;
  background: linear-gradient(90deg,
    #9500ff 0%, #0c00ff 6.25%, #0095ff 12.5%, #00ff6e 18.75%,
    #56ff00 25%, #caff00 31.25%, #ffb900 37.5%, #ff3b00 43.75%,
    #ff0000 50%, #ff3b00 56.25%, #ffb900 62.5%, #caff00 68.75%,
    #56ff00 75%, #00ff6e 81.25%, #0095ff 87.5%, #0c00ff 93.75%,
    #9500ff 100%);
}
:root[data-theme="light"] .freqbar::before { opacity: 0.65; }
.freqbar.is-live { opacity: 1; }
.freqbar-mark {
  position: absolute; bottom: 0;
  width: 2px; height: 8px;
  margin-left: -1px;
  background: var(--fg);
}
.freqbar-hz {
  position: absolute; bottom: 11px;
  transform: translateX(-50%);
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  color: var(--fg-dim);
  white-space: nowrap;
  display: none;
}
.freqbar.has-hz .freqbar-hz { display: block; }
.no-plate .freqbar,
body.plate-paused .freqbar,
html:not(.js) .freqbar { display: none; }

/* ─────────────────────────────────────────────────────────────
   Fallbacks & modes
   ───────────────────────────────────────────────────────────── */

/* When the simulation is off (reduced motion, weak device, toggled off,
   or JS missing) the plate div still paints its ground, so nothing
   looks broken. */
.no-plate #plate-canvas { display: none; }

/* Reduced motion: still designed, just still. */
@media (prefers-reduced-motion: reduce) {
  .plate-toggle, #sound-toggle, .scroll-cue, .freqbar { display: none; }
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }
  html.js .fx-resolve {
    opacity: 1; filter: none; letter-spacing: -0.01em;
  }
}

/* Phones: the full wordmark and the nav cannot both have the row. */
@media (max-width: 640px) {
  .wordmark-full { display: none; }
  .wordmark { flex: none; }
  .controls { flex: none; }
}
@media (max-width: 480px) {
  .topbar { gap: 0.6rem; padding-inline: 0.9rem; }
  .nav { gap: 0.7rem; }
  .nav a { font-size: 0.72rem; }
  .plate-toggle-label { display: none; }
  .ctrl { padding: 0.3em 0.45em; }
  .controls { gap: 0.3rem; }
}

/* Print: ink on paper, no field */
@media print {
  .plate, .topbar, .scroll-cue, .hero-foot, .skip, .chapters, .freqbar { display: none !important; }
  body { background: #fff; color: #111; }
  a { color: #111; }
  .section { border: none; background: none; }
  .pub-extra { grid-template-rows: 1fr !important; }
  /* cards print their contents, not their trick */
  .card-inner { transform: none !important; }
  .card-front { display: none; }
  .card-back { transform: none !important; }
}
