/* hollowpoint.tv/addit — the landing page.
 *
 * The page borrows Addit's own three layers rather than a web idiom:
 *
 *   chassis  BDO Grotesk on near-black. Everything that is just information.
 *   display  Departure Mono in Phosphor ice-cyan, on an 11px grid. Anything
 *            that reads as a measurement, a label on an instrument, or state.
 *            It is the page's only accent, and it never moves smoothly.
 *   field    The launch screen's palette (blue → green → amber → red, magenta
 *            rim). It lives in the hero and the illustrations, never in type.
 *
 * Its own stylesheet on purpose: addit.css still dresses the privacy and terms
 * pages and the waitlist's no-JavaScript reply, and none of them should move
 * because this page did. */

@font-face {
  font-family: "BDO Grotesk"; font-weight: 400; font-style: normal; font-display: swap;
  src: url("fonts/BDOGrotesk-Regular.woff2") format("woff2");
}
@font-face {
  font-family: "BDO Grotesk"; font-weight: 500; font-style: normal; font-display: swap;
  src: url("fonts/BDOGrotesk-Medium.woff2") format("woff2");
}
@font-face {
  font-family: "Departure Mono"; font-weight: 400; font-style: normal; font-display: swap;
  src: url("fonts/DepartureMono-Regular.woff2") format("woff2");
}

:root {
  color-scheme: dark;

  /* The launch field's unlit panel, kBackdrop in PixelRipple.metal. The whole
     page sits on it so the hero has no edge to find. */
  --void:    #030206;
  --chassis: #0a0a0e;
  --well:    #020204;
  --ink:     #eeede9;
  --ink-2:   rgba(238, 237, 233, 0.64);
  --ink-3:   rgba(238, 237, 233, 0.40);
  --rule:    rgba(238, 237, 233, 0.09);
  --rule-2:  rgba(238, 237, 233, 0.16);

  --lit:     #a8e4ff;                       /* Phosphor.lit */
  --lit-dim: rgba(168, 228, 255, 0.52);
  --glow:    0 0 7px rgba(168, 228, 255, 0.38);
  --lock:    #38ff14;                       /* the tracker's lock */

  --sans: "BDO Grotesk", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "Departure Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --m: 20px;                                /* page margin */
  --col: 1320px;
}
@media (min-width: 760px)  { :root { --m: 32px; } }
@media (min-width: 1200px) { :root { --m: 44px; } }

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html {
  background: var(--void);
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 88px;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  color: var(--ink);
  font: 400 17px/1.5 var(--sans);
  letter-spacing: -0.011em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
::selection { background: var(--lit); color: #020204; }

a { color: inherit; }
img { display: block; max-width: 100%; height: auto; }
h1, h2, h3, p, ol, ul, dl, dd, figure { margin: 0; padding: 0; }
ol, ul { list-style: none; }
code {
  font: 0.86em/1 var(--mono);
  color: var(--lit);
  letter-spacing: 0;
  white-space: nowrap;
}
b { font-weight: 500; }

.sr, .skip:not(:focus) {
  position: absolute !important;
  width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip:focus {
  position: fixed; z-index: 100; top: 12px; left: 12px;
  padding: 10px 14px; border-radius: 999px;
  background: var(--ink); color: var(--void); text-decoration: none;
}

:focus-visible { outline: 1px solid var(--lit); outline-offset: 3px; }

.wrap {
  width: 100%;
  max-width: calc(var(--col) + var(--m) * 2);
  margin: 0 auto;
  padding-inline: var(--m);
}

/* ── The display layer ────────────────────────────────────────────────── */

/* Departure Mono is drawn on an 11px grid: it is only crisp at multiples of
   eleven, so every readout on the page is set at exactly that. */
.readout {
  font-family: var(--mono);
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--lit);
  text-shadow: var(--glow);
  font-variant-numeric: tabular-nums;
}

.fig {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--lit);
  text-shadow: var(--glow);
  margin-right: 0.6em;
  white-space: nowrap;
}

.caption {
  font-size: 13px;
  line-height: 18px;
  color: var(--ink-2);
  letter-spacing: -0.003em;
  text-wrap: pretty;
}

/* The one accent a headline gets, and the page's answer to the editorial
   italic: a word set in the readout face, as if it were on the display rather
   than printed on the case. Departure Mono's cap height is 0.727 em against
   BDO Grotesk's 0.729, so at the same size the two share a cap line. */
.px {
  font-family: var(--mono);
  font-size: 0.97em;
  letter-spacing: -0.035em;
  color: var(--lit);
  text-shadow: 0 0 0.12em rgba(168, 228, 255, 0.45);
  white-space: nowrap;
}

.led {
  display: inline-block;
  width: 5px; height: 5px;
  margin-right: 8px;
  vertical-align: 1px;
  background: var(--lock);
  box-shadow: 0 0 6px rgba(56, 255, 20, 0.7);
  animation: led 3.2s steps(1, end) infinite;
}
@keyframes led {
  0%, 88% { opacity: 1; }
  88.01%, 94% { opacity: 0.18; }
  94.01%, 100% { opacity: 1; }
}

/* Display elements switch on rather than fade in: a few frames of an LED
   finding its level. The hero's readouts do it once the fill has run — the
   same 2.4 s the app's launch screen holds — and the pixel words do it as they
   arrive on screen. Pure CSS where it can be, so nothing hangs on a script. */
@keyframes power-on {
  0%   { opacity: 0; }
  18%  { opacity: 1; }
  30%  { opacity: 0.15; }
  44%  { opacity: 1; }
  56%  { opacity: 0.45; }
  70%, 100% { opacity: 1; }
}
.js .hero-foot { animation: power-on 420ms steps(1, end) 2.5s both; }
.js .px:not(.lit) { color: rgba(168, 228, 255, 0.16); text-shadow: none; }
.js .px.lit { animation: power-on 420ms steps(1, end) both; }
@media (prefers-reduced-motion: reduce) {
  .js .hero-foot, .js .px.lit, .led { animation: none; }
  .js .px:not(.lit) { color: var(--lit); text-shadow: 0 0 0.12em rgba(168, 228, 255, 0.45); }
}

/* ── Buttons ──────────────────────────────────────────────────────────── */

.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 34px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  background: var(--ink);
  color: #07070a;
  font: 500 14px/1 var(--sans);
  letter-spacing: -0.01em;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 120ms steps(2, end);
}
.pill:hover { background: #fff; }
.pill:active { transform: translateY(0.5px); }
.pill-lg { height: 44px; padding: 0 20px; font-size: 15px; }

/* ── The frame: fixed corners, as on a device ─────────────────────────── */

.frame {
  position: fixed;
  z-index: 50;
  inset: 0 0 auto 0;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: max(18px, env(safe-area-inset-top)) var(--m) 0;
  pointer-events: none;
}
.frame > * { pointer-events: auto; }
/* Not glass. A plain fall-off from the page colour, which does the job a
   frosted bar does — keeping the corners legible over whatever scrolls under
   them — without turning the header into an object. */
.frame::before {
  content: "";
  position: absolute;
  inset: 0 0 -44px 0;
  z-index: -1;
  background: linear-gradient(to bottom, rgba(3, 2, 6, 0.94) 0%, rgba(3, 2, 6, 0.72) 48%, rgba(3, 2, 6, 0) 100%);
  opacity: 0;
  transition: opacity 240ms ease;
  pointer-events: none;
}
.frame[data-scrolled]::before { opacity: 1; }

.brand {
  display: grid;
  text-shadow: 0 0 3px rgba(3, 2, 6, 0.9), 0 1px 1px rgba(3, 2, 6, 0.7);
  text-decoration: none;
  line-height: 19px;
}
.brand-name {
  font-size: 17px;
  font-weight: 500;
  letter-spacing: -0.025em;
}
.brand-line {
  font-size: 15px;
  color: var(--ink-2);
  letter-spacing: -0.015em;
}

.frame-end {
  display: flex;
  align-items: center;
  gap: 18px;
}
.status { display: none; }
@media (min-width: 640px) { .status { display: inline-flex; align-items: center; } }

/* ── Fig. 1: the hero ─────────────────────────────────────────────────── */

.hero {
  position: relative;
  height: 100vh;
  height: 100svh;
  min-height: 600px;
  max-height: 1200px;
  overflow: hidden;
  background: var(--void);
  cursor: crosshair;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
/* A still of the same field, for no JavaScript or no WebGL. Not shown while
   the live one starts: that begins on an empty panel, as the app's does, and a
   full field flashing to black first would be the worst of both. */
.no-js .hero, .hero.no-gl {
  background: var(--void) url("img/field-portrait.jpg") center / cover no-repeat;
}
@media (min-aspect-ratio: 4/5) {
  .no-js .hero, .hero.no-gl { background-image: url("img/field-landscape.jpg"); }
}
.hero-field, .hero-hud {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
.hero-hud { pointer-events: none; }
.hero.no-gl .hero-field, .hero.no-gl .hero-hud { display: none; }

/* The name, where the pixels spell it: invisible, but there to be read aloud,
   found and selected. Positioned by field.js on the mark it draws. */
.hero-mark {
  position: absolute;
  left: var(--mark-x, 50%);
  top: var(--mark-y, 47%);
  transform: translate(-50%, -50%) skewX(-14.6deg);
  font: 500 calc(var(--mark-cap, 48px) * 1.37) / 1 var(--sans);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: transparent;
  white-space: nowrap;
  user-select: text;
}
.hero-mark::selection { color: transparent; background: rgba(168, 228, 255, 0.25); }

/* A floor under the captions: the water runs to a blown-out crest, and the
   caption has to hold wherever one lands. Also where the panel meets the page,
   so the hero doesn't end on a hard line. */
.hero::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 190px;
  background: linear-gradient(to bottom, rgba(3, 2, 6, 0), rgba(3, 2, 6, 0.78) 58%, var(--void));
  pointer-events: none;
}
.hero::before {
  content: "";
  position: absolute;
  z-index: 1;
  inset: 0 0 auto 0;
  height: 120px;
  background: linear-gradient(to bottom, rgba(3, 2, 6, 0.7), rgba(3, 2, 6, 0));
  pointer-events: none;
}

.hero-foot {
  position: absolute;
  z-index: 2;
  inset: auto 0 0 0;
  display: flex;
  flex-direction: column-reverse;
  gap: 14px;
  padding: 0 var(--m) max(22px, env(safe-area-inset-bottom));
  pointer-events: none;
}
.hero-foot .caption {
  max-width: 34ch;
  color: rgba(238, 237, 233, 0.72);
  pointer-events: auto;
}
.hint { color: var(--ink); white-space: nowrap; }
.hint-tap { display: none; }
@media (hover: none) {
  .hint-click { display: none; }
  .hint-tap { display: inline; }
}
.hero.tapped .hint { color: var(--ink-3); }
.hero.no-gl .hint { display: none; }

.telemetry {
  display: grid;
  grid-template-columns: repeat(2, auto);
  justify-content: start;
  gap: 2px 22px;
}
.telemetry div { display: flex; gap: 10px; }
.telemetry dt { color: var(--lit-dim); min-width: 5.5ch; }
.telemetry .sym { text-transform: none; }
/* v̂ and λ̂ — the circumflex drawn as the face's own caret, since combining
   marks land wherever a pixel font's metrics put them. */
.hat { position: relative; display: inline-block; }
.hat::after {
  content: "^";
  position: absolute;
  left: 0; right: 0;
  top: -6px;
  text-align: center;
}
.telemetry small { font-size: inherit; color: var(--lit-dim); }
.hero.no-gl .telemetry { display: none; }

@media (min-width: 760px) {
  .hero-foot {
    flex-direction: row;
    align-items: flex-end;
    justify-content: space-between;
    padding-bottom: 28px;
  }
  .telemetry { grid-template-columns: auto; text-align: left; }
}

/* ── Thesis ───────────────────────────────────────────────────────────── */

.display {
  font-size: clamp(46px, 8.6vw, 136px);
  font-weight: 400;
  line-height: 0.93;
  letter-spacing: -0.052em;
  text-wrap: balance;
}
.display-s {
  font-size: clamp(38px, 5.4vw, 84px);
  line-height: 0.96;
  letter-spacing: -0.045em;
}

.thesis { padding-top: clamp(96px, 16vh, 200px); }
.thesis .display { max-width: 11.5em; }
.thesis-body {
  display: grid;
  gap: 14px;
  margin-top: clamp(40px, 7vw, 88px);
}
.lede {
  font-size: clamp(19px, 1.7vw, 23px);
  line-height: 1.42;
  letter-spacing: -0.018em;
  color: var(--ink-2);
  max-width: 34ch;
  text-wrap: pretty;
}
.label { color: var(--lit-dim); padding-top: 6px; }

@media (min-width: 900px) {
  .thesis-body { grid-template-columns: repeat(12, 1fr); column-gap: 24px; }
  .thesis-body .label { grid-column: 1 / 4; }
  .thesis-body .lede { grid-column: 4 / 11; }
}

/* ── Section heads ────────────────────────────────────────────────────── */

.section-head {
  display: grid;
  gap: 12px;
  margin-bottom: clamp(28px, 4vw, 48px);
}
.section-head h2 {
  font-size: clamp(30px, 3.5vw, 50px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.04em;
}
@media (min-width: 900px) {
  .section-head {
    grid-template-columns: 1fr auto;
    align-items: end;
  }
  .section-head .caption { max-width: 30ch; text-align: right; }
}

/* ── Fig. 2: the app, running ─────────────────────────────────────────── */

.reel {
  padding-top: clamp(120px, 18vh, 220px);
  display: grid;
  gap: 48px;
  align-items: center;
}
@media (min-width: 900px) {
  .reel { grid-template-columns: repeat(12, 1fr); column-gap: 24px; }
  .reel-body { grid-column: 1 / 7; }
  .phone { grid-column: 8 / 12; justify-self: center; }
}
.reel-head h2 {
  font-size: clamp(30px, 3.5vw, 50px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.04em;
}
.reel-head .caption { margin-top: 14px; max-width: 44ch; }

/* The recording's chapters, as a readout that follows the playhead. Buttons,
   because each one seeks — the list is also the scrubber. */
.chapters {
  margin-top: clamp(28px, 4vw, 44px);
  border-top: 1px solid var(--rule);
  counter-reset: chapter;
}
.chapters li { border-bottom: 1px solid var(--rule); }
.chapters button {
  all: unset;
  box-sizing: border-box;
  width: 100%;
  display: grid;
  grid-template-columns: 56px 1fr;
  align-items: baseline;
  gap: 12px;
  padding: 13px 0 12px;
  cursor: pointer;
  font-size: 16px;
  letter-spacing: -0.012em;
  color: var(--ink-3);
}
.chapters button:hover { color: var(--ink-2); }
.chapters button:focus-visible { outline: 1px solid var(--lit); outline-offset: 2px; }
.chapters .t { color: var(--lit-dim); text-shadow: none; }
.chapters .now button { color: var(--ink); }
.chapters .now .t { color: var(--lit); text-shadow: var(--glow); }

/* The phone. Drawn, not photographed: a bezel, the screen's own corner radius,
   and the island — just enough device that the recording reads as a phone and
   not as a tall picture. Proportions from a 402 × 874 pt screen. */
.phone { width: min(78vw, 340px); margin: 0; }
.phone-body {
  --r: 13.7%;
  position: relative;
  padding: 3%;
  border-radius: calc(var(--r) + 3%) / calc((var(--r) + 3%) * 402 / 874);
  background: #050506;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.10),
    inset 0 0 0 3px #0b0b0d,
    inset 0 1px 0 3px rgba(255, 255, 255, 0.05),
    0 50px 90px -40px rgba(0, 0, 0, 0.9),
    0 0 0 1px rgba(0, 0, 0, 0.6);
}
.phone-screen {
  position: relative;
  aspect-ratio: 402 / 874;
  border-radius: var(--r) / calc(var(--r) * 402 / 874);
  overflow: hidden;
  background: #000;
  isolation: isolate;
}
.phone-screen video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.phone-island {
  position: absolute;
  z-index: 1;
  top: 1.3%;
  left: 50%;
  translate: -50% 0;
  width: 31%;
  height: 4.2%;
  border-radius: 999px;
  background: #000;
}

/* ── Fig. 2: one folder, seen twice ───────────────────────────────────── */

.folder { padding-top: clamp(120px, 18vh, 220px); }

.folder-pair {
  display: grid;
  gap: 12px;
}
@media (min-width: 900px) {
  .folder-pair { grid-template-columns: 1fr 72px 1fr; gap: 0; align-items: stretch; }
}

.pane {
  position: relative;
  border-radius: 20px;
  background: var(--chassis);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.045),
    inset 0 0 0 1px rgba(255, 255, 255, 0.04),
    0 30px 60px -30px rgba(0, 0, 0, 0.8);
  padding: 20px 20px 18px;
  display: flex;
  flex-direction: column;
}
.pane-title { color: var(--lit-dim); margin-bottom: 18px; }
.pane-note {
  margin-top: auto;
  padding-top: 16px;
  font-size: 13px;
  color: var(--ink-3);
}

/* Google's side is set deliberately plain — the folder as a file listing,
   which is exactly what it is until something reads it. */
.crumbs {
  font-size: 13px;
  color: var(--ink-3);
  margin-bottom: 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.crumbs b { font-weight: 400; margin: 0 0.3em; }
.files { border-top: 1px solid var(--rule); }
.file {
  position: relative;
  display: grid;
  grid-template-columns: 18px 1fr auto;
  align-items: center;
  gap: 12px;
  height: 42px;
  border-bottom: 1px solid var(--rule);
  font-size: 15px;
  color: var(--ink-2);
  letter-spacing: -0.01em;
}
.file span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file em {
  font: 11px/1 var(--mono);
  font-style: normal;
  color: var(--ink-3);
  letter-spacing: 0.02em;
  padding-right: 30px;
}
.ico {
  width: 14px; height: 16px;
  border: 1px solid var(--ink-3);
  border-radius: 2px;
  position: relative;
}
.ico::after {                       /* a music file's two notes, as a tick */
  content: "";
  position: absolute; left: 3px; right: 3px; bottom: 3px; height: 1px;
  background: var(--ink-3);
  box-shadow: 0 -3px 0 var(--ink-3);
}
.ico-img::after { box-shadow: none; height: 5px; bottom: 3px; background: linear-gradient(135deg, transparent 45%, var(--ink-3) 46%); }
.ico-data { border-color: var(--lit-dim); }
.ico-data::after { background: var(--lit-dim); box-shadow: 0 -3px 0 var(--lit-dim); }
.file-meta span { color: var(--ink); }
.file-meta[data-callout="1"] span { font-family: var(--mono); font-size: 13px; color: var(--lit); letter-spacing: 0; }

/* Callout keys: numbered squares, as an instrument manual keys its drawings. */
[data-callout] { position: relative; }
[data-callout]::after {
  content: attr(data-callout);
  position: absolute;
  right: 0;
  top: 50%;
  translate: 0 -50%;
  width: 18px; height: 18px;
  display: grid;
  place-items: center;
  font: 11px/1 var(--mono);
  color: #020204;
  background: var(--lit);
  box-shadow: 0 0 8px rgba(168, 228, 255, 0.45);
}
.album-cover[data-callout]::after { top: 8px; right: 8px; translate: 0 0; }
.tracks[data-callout]::after { top: -9px; right: 0; translate: 0 0; }

.folder-arrow {
  display: grid;
  place-items: center;
  height: 36px;
}
.folder-arrow span {
  width: 1px; height: 100%;
  background: repeating-linear-gradient(to bottom, var(--lit-dim) 0 2px, transparent 2px 5px);
  position: relative;
}
.folder-arrow span::after {
  content: "";
  position: absolute; left: 50%; bottom: -1px;
  width: 7px; height: 7px;
  border: solid var(--lit);
  border-width: 0 1px 1px 0;
  transform: translateX(-50%) rotate(45deg);
}
@media (min-width: 900px) {
  .folder-arrow { height: auto; }
  .folder-arrow span {
    width: 44px; height: 1px;
    background: repeating-linear-gradient(to right, var(--lit-dim) 0 2px, transparent 2px 5px);
  }
  .folder-arrow span::after {
    left: auto; right: -1px; bottom: auto; top: 50%;
    transform: translateY(-50%) rotate(-45deg);
  }
}

/* Addit's side */
.album {
  display: grid;
  grid-template-columns: 112px 1fr;
  gap: 16px;
  align-items: end;
  margin-bottom: 20px;
}
@media (min-width: 1100px) { .album { grid-template-columns: 144px 1fr; } }
.album-cover {
  border-radius: 8px;
  overflow: hidden;
  aspect-ratio: 1;
  background: #0d0a14;
  box-shadow: 0 16px 30px -12px rgba(0, 0, 0, 0.9), 0 0 0 1px rgba(255, 255, 255, 0.05);
}
.album-cover img { width: 100%; height: 100%; object-fit: cover; }
.album-title { font-size: 22px; font-weight: 500; letter-spacing: -0.035em; line-height: 1.1; }
.album-artist { font-size: 15px; color: var(--ink-2); margin-top: 2px; }
.album-info { color: var(--lit-dim); margin-top: 10px; text-shadow: none; }

.tracks { border-top: 1px solid var(--rule); }
.tracks li {
  display: grid;
  grid-template-columns: 26px 1fr auto;
  align-items: center;
  gap: 10px;
  height: 42px;
  border-bottom: 1px solid var(--rule);
  font-size: 15px;
  letter-spacing: -0.012em;
}
.tracks .n { font: 11px/1 var(--mono); color: var(--ink-3); }
.tracks .d { font: 11px/1 var(--mono); color: var(--ink-3); letter-spacing: 0.02em; }
.tracks .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tracks .playing .t, .tracks .playing .d { color: var(--lit); }
.tracks .playing .d { text-shadow: var(--glow); }

/* The playing row's meter: three bars that step, never glide. */
.eq { display: inline-flex; align-items: flex-end; gap: 2px; height: 11px; }
.eq b {
  width: 3px;
  background: var(--lit);
  box-shadow: 0 0 5px rgba(168, 228, 255, 0.55);
  animation: eq 1.1s steps(1, end) infinite;
}
.eq b:nth-child(2) { animation-duration: 0.83s; animation-delay: -0.3s; }
.eq b:nth-child(3) { animation-duration: 1.37s; animation-delay: -0.7s; }
@keyframes eq {
  0% { height: 4px; } 16% { height: 11px; } 33% { height: 6px; }
  50% { height: 9px; } 66% { height: 3px; } 83% { height: 8px; }
}

.notes {
  display: grid;
  gap: 22px;
  margin-top: clamp(28px, 4vw, 44px);
}
@media (min-width: 760px) { .notes { grid-template-columns: repeat(3, 1fr); gap: 24px; } }
.notes li { display: grid; grid-template-columns: 18px 1fr; gap: 14px; }
.notes .mark {
  width: 18px; height: 18px;
  display: grid; place-items: center;
  background: var(--lit); color: #020204;
  text-shadow: none;
  box-shadow: 0 0 8px rgba(168, 228, 255, 0.45);
  margin-top: 2px;
}
.notes p { font-size: 15px; line-height: 1.5; color: var(--ink-2); text-wrap: pretty; }
.notes b { color: var(--ink); }

/* ── Fig. 3: modules ──────────────────────────────────────────────────── */

.modules { padding-top: clamp(120px, 18vh, 220px); }
.grid {
  display: grid;
  gap: 40px 18px;
}
@media (min-width: 760px) { .grid { grid-template-columns: repeat(3, 1fr); } }

.module h3 {
  margin-top: 16px;
  font-size: 17px;
  font-weight: 500;
  letter-spacing: -0.02em;
}
.module p {
  margin-top: 4px;
  font-size: 15px;
  line-height: 1.47;
  color: var(--ink-2);
  max-width: 38ch;
  text-wrap: pretty;
}

/* A display inset into the chassis: a recessed well, and behind whatever it
   shows, the unlit emitters — so an empty corner of a panel still reads as a
   panel that happens to be dark there. */
.screen {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: 18px;
  overflow: hidden;
  background:
    radial-gradient(circle at center, rgba(168, 228, 255, 0.07) 0 1px, transparent 1.4px) 0 0 / 8px 8px,
    var(--well);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.05),
    inset 0 18px 40px -10px rgba(0, 0, 0, 0.9),
    0 1px 0 rgba(255, 255, 255, 0.05);
}
.screen canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

.screen-clouds {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8%;
}
.screen-clouds img { width: 26%; filter: drop-shadow(0 14px 24px rgba(0, 0, 0, 0.7)); }
.screen-clouds img + img { width: 34%; }
.screen-clouds .local {
  position: absolute;
  left: 50%; bottom: 16px;
  translate: -50% 0;
  white-space: nowrap;
  padding: 3px 7px;
  border: 1px solid rgba(168, 228, 255, 0.35);
}

.screen-share {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 14px;
  padding: 0 12%;
}
.screen-share .card {
  width: 100%;
  display: grid;
  grid-template-columns: 52px 1fr;
  gap: 12px;
  align-items: center;
  padding: 10px;
  border-radius: 14px;
  background: #1c1c21;
  box-shadow: 0 18px 30px -14px rgba(0, 0, 0, 0.9);
}
.screen-share .card img { border-radius: 6px; aspect-ratio: 1; object-fit: cover; }
.screen-share .card p { display: grid; font-size: 13px; line-height: 1.3; letter-spacing: -0.01em; }
.screen-share .card b { font-weight: 500; }
.screen-share .card span { color: var(--ink-3); }
.screen-share .bubble {
  justify-self: end;
  max-width: 80%;
  padding: 8px 12px;
  border-radius: 16px 16px 4px 16px;
  background: var(--lit);
  color: #041018;
  font-size: 13px;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

/* ── Fig. 5: the object ───────────────────────────────────────────────── */

/* The D-1 gets the page's full width: it is the one figure you can pick up,
   and a frame round it would be a box it had to stay inside. The stage is
   the page's own void with the faintest ice-blue pool under the object, so
   the clear edges have something to be lit against. */
.object { padding-top: clamp(120px, 18vh, 220px); }
.object .section-head { margin-bottom: 0; }
.object-stage {
  position: relative;
  height: min(88vw, 520px);
  background: radial-gradient(46% 42% at 50% 54%, rgba(168, 228, 255, 0.045), transparent 72%);
  -webkit-user-select: none;
  user-select: none;
}
.object-stage canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
  opacity: 0;
  transition: opacity 0.9s ease;
  cursor: grab;
  /* vertical swipes still scroll the page; sideways ones turn the object */
  touch-action: pan-y;
  outline: none;
}
.object-stage canvas.held { cursor: grabbing; }
.object-stage canvas:focus-visible { box-shadow: inset 0 0 0 1px var(--lit-dim); }
.object-stage.live canvas { opacity: 1; }
.object-loading {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: var(--lit-dim);
  pointer-events: none;
  transition: opacity 0.4s steps(2, end);
}
.object-stage.live .object-loading, .object-stage.no-gl .object-loading, .no-js .object-loading { opacity: 0; }
.no-js .object-stage, .object-stage.no-gl {
  background: url("device/still.webp") center / contain no-repeat,
              radial-gradient(46% 42% at 50% 54%, rgba(168, 228, 255, 0.045), transparent 72%);
}
/* On a phone the readouts sit under the object; wider, they're laid over the
   bottom of the stage the way the hero's are, and device.js frames the object
   in the part of the stage they leave clear. */
.object-foot {
  position: relative;
  display: flex;
  flex-direction: column-reverse;
  gap: 12px;
  pointer-events: none;
}
.object-hint { max-width: 36ch; }
.object-stage.no-gl ~ .object-foot .object-hint, .no-js .object-hint,
.object-stage.no-gl ~ .object-foot .telemetry, .no-js .object-foot .telemetry { display: none; }
@media (min-width: 760px) {
  .object-stage { height: clamp(460px, 62vw, 84vh); max-height: 900px; }
  .object-foot {
    margin-top: -86px;
    min-height: 86px;
    flex-direction: row;
    align-items: flex-end;
    justify-content: space-between;
    padding-bottom: 18px;
  }
  .object-hint { text-align: right; order: 2; }
}

/* ── Specifications ───────────────────────────────────────────────────── */

.spec {
  padding-top: clamp(140px, 20vh, 240px);
  display: grid;
  gap: 40px;
}
.spec-head .lede { margin-top: 22px; }
@media (min-width: 1000px) {
  .spec { grid-template-columns: repeat(12, 1fr); column-gap: 24px; }
  .spec-head { grid-column: 1 / 6; align-self: start; position: sticky; top: 120px; }
  .sheet { grid-column: 7 / 13; }
}
.sheet { border-top: 1px solid var(--rule-2); }
.sheet div {
  display: grid;
  grid-template-columns: 112px 1fr;
  gap: 16px;
  padding: 15px 0 14px;
  border-bottom: 1px solid var(--rule);
}
@media (min-width: 640px) { .sheet div { grid-template-columns: 150px 1fr; } }
.sheet dt {
  font: 11px/22px var(--mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--lit-dim);
}
.sheet dd { font-size: 17px; line-height: 22px; letter-spacing: -0.015em; text-wrap: pretty; }

/* ── Fig. 4: join ─────────────────────────────────────────────────────── */

.join {
  padding-top: clamp(140px, 20vh, 240px);
  padding-bottom: clamp(100px, 14vh, 160px);
  display: grid;
  gap: 44px;
  align-items: center;
}
/* On a phone the form comes first — "Get the beta" lands here, and it should
   land on the thing it promised, with the house as the coda under it. */
.join-body { order: -1; }
@media (min-width: 960px) {
  .join { grid-template-columns: repeat(12, 1fr); column-gap: 24px; }
  .house { grid-column: 1 / 6; }
  .join-body { grid-column: 7 / 13; order: 0; }
}

.house-well {
  position: relative;
  aspect-ratio: 1;
  border-radius: 24px;
  overflow: hidden;
  background: radial-gradient(120% 90% at 50% 38%, #120c1c 0%, #060409 55%, var(--well) 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05), inset 0 30px 60px -20px rgba(0, 0, 0, 0.9);
}
.house-well canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0;
}
.house-well.live canvas { opacity: 1; }
/* The same house, still, where nothing can draw it live. A background rather
   than an <img> so a browser that can draw it never downloads it. */
.no-js .house-well, .house-well.no-gl {
  background-image: url("img/house.png"), radial-gradient(120% 90% at 50% 38%, #120c1c 0%, #060409 55%, var(--well) 100%);
  background-size: cover, auto;
}
.house .caption { margin-top: 14px; max-width: 42ch; }

.join-body .lede { margin-top: 26px; }
.join-body .display .px { font-size: 0.8em; letter-spacing: -0.06em; }

.join-cta { margin-top: 36px; }
.join-note {
  margin-top: 16px;
  font-size: 14px;
  color: var(--ink-2);
  max-width: 44ch;
}
.aside {
  margin-top: 26px;
  padding-top: 16px;
  border-top: 1px solid var(--rule);
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-3);
  max-width: 52ch;
}

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

.foot {
  display: grid;
  gap: 18px;
  padding-top: 26px;
  padding-bottom: max(34px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--rule);
  font-size: 14px;
  color: var(--ink-2);
}
.foot-brand { display: flex; gap: 10px; align-items: baseline; }
.foot-brand .brand-name { color: var(--ink); }
.foot-brand a { color: inherit; text-decoration: none; }
.foot-brand a:hover { color: var(--ink); }
.foot-links { display: flex; flex-wrap: wrap; gap: 22px; }
.foot-links a { text-decoration: none; }
.foot-links a:hover { color: var(--ink); }
.foot-meta { color: var(--ink-3); text-shadow: none; }
@media (min-width: 900px) {
  .foot { grid-template-columns: 1fr auto 1fr; align-items: baseline; }
  .foot-meta { justify-self: end; }
}
