/* Osmotic landing: the app's design tokens (Sources/Osmotic/Views/Theme.swift) in CSS.
   Dark only, like the app. No web fonts: system UI and system mono.
   Motion: transform and opacity only, ease-out entrances (never ease-in), 30–80 ms staggers,
   hover only on devices that hover, and an opacity-only variant for Reduce Motion. */

:root {
  --plate-top: rgb(36 36 35);
  --plate-bottom: rgb(29 29 28);
  --metal-top: rgb(47 47 46);
  --metal-bottom: rgb(40 40 39);
  --grey-top: rgb(66 66 65);
  --grey-bottom: rgb(53 53 52);
  --edge-light: rgb(255 255 255 / 0.09);
  --lip: rgb(255 255 255 / 0.06);
  --slot: rgb(17 17 16);
  --ink: rgb(232 229 222);
  --muted: rgb(160 157 150);
  --accent: rgb(238 92 36);
  --accent-top: rgb(206 70 20);
  --accent-bottom: rgb(180 58 14);
  --lcd: rgb(16 16 15);
  --lcd-text: rgb(255 146 52);
  --lcd-caption: rgb(236 228 214 / 0.55);
  --led-green: rgb(74 222 128);

  --s1: 4px; --s2: 8px; --s3: 16px; --s4: 24px; --s5: 32px; --s6: 48px; --s7: 72px;
  --radius-s: 5px; --radius-m: 9px; --radius-l: 14px;

  /* Depth tokens */
  --contact: 0 1px 1.5px rgb(0 0 0 / 0.28);
  --ambient: 0 6px 14px rgb(0 0 0 / 0.14);
  --inset-deep: inset 0 2px 4px rgb(0 0 0 / 0.75);

  /* Motion tokens */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --press: 90ms var(--ease-out);
  --release: 160ms var(--ease-out);

  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  color-scheme: dark;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  padding-inline: max(var(--s3), env(safe-area-inset-left));
  /* Material, not flat colour: a 128-px grain tile over the plate gradient (scripts/make_textures.swift). */
  background:
    url("textures/grain.webp") 0 0 / 128px 128px repeat,
    linear-gradient(var(--plate-top), var(--plate-bottom)) fixed;
  background-color: var(--plate-bottom);
  color: var(--ink);
  font: 16px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--ink); text-decoration-color: rgb(238 92 36 / 0.6); text-underline-offset: 3px; transition: text-decoration-color 150ms ease; }
:focus-visible { outline: 2px solid var(--lcd-text); outline-offset: 3px; border-radius: 3px; }
code, kbd { font-family: var(--mono); font-size: 0.88em; }
kbd { padding: 0 5px; border-radius: 3px; background: var(--slot); box-shadow: inset 0 -1px 0 rgb(255 255 255 / 0.08); }
strong { color: #fff; font-weight: 600; }

.skip { position: absolute; left: -9999px; }
.skip:focus { left: var(--s3); top: var(--s3); z-index: 10; background: var(--slot); padding: var(--s2) var(--s3); }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ---- Top bar ------------------------------------------------------------------------------ */
/* Top: just the wordmark, on the centre line (the version lives in the footer). */
.topbar {
  max-width: 1120px; margin: 0 auto; padding-block: var(--s5) var(--s3);
  display: flex; flex-direction: column; align-items: center;
}

/* The keys follow the reader: in the flow under the wordmark, then stuck to the top of the window,
   where they close into a pill (main.js flips .is-stuck when the sentinel scrolls past). */
.nav-sentinel { height: 1px; }
.navdock {
  position: sticky; top: 0; z-index: 20;
  display: flex; justify-content: center;
  padding-bottom: var(--s5);
}
.navdock .bank {
  transition: background-color 200ms var(--ease-out), box-shadow 200ms var(--ease-out),
    border-radius 200ms var(--ease-out);
}
/* Docked: the slot squares off against the top edge of the window and lights its own backdrop,
   the way a module seats into the bezel. It slides the last few pixels home once. */
.navdock.is-stuck .bank {
  border-radius: 0 0 var(--radius-m) var(--radius-m);
  background: rgb(20 20 19 / 0.74);
  -webkit-backdrop-filter: blur(18px) saturate(1.1);
  backdrop-filter: blur(18px) saturate(1.1);
  box-shadow:
    inset 0 -1px 0 rgb(255 255 255 / 0.05),
    inset 0 0 0 1px rgb(255 255 255 / 0.04),
    0 12px 28px rgb(0 0 0 / 0.5);
  animation: dock-in 220ms var(--ease-out) both;
}
@keyframes dock-in {
  from { transform: translateY(-6px); }
  to { transform: none; }
}
.wordmark { font-weight: 800; font-size: 22px; letter-spacing: -0.02em; text-decoration: none; display: inline-flex; align-items: baseline; gap: 3px; }
/* "osmotic." : the dot on the baseline, like a period (the app icon's "o."). */
.dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 5px rgb(238 92 36 / 0.5); }
.status { margin: 0; display: inline-flex; align-items: center; gap: var(--s2); font-size: 11px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; }

/* LEDs: a lens sunk into its bezel. Unlit it is dark glass; lit, the dome lights from the middle,
   keeps a specular dot at the top left and throws a little light on the plate. Opacity only. */
.led {
  position: relative; width: 11px; height: 11px; border-radius: 50%; flex: none;
  background:
    radial-gradient(circle at 36% 30%, rgb(255 255 255 / 0.07) 0 22%, transparent 40%),
    radial-gradient(circle at 50% 60%, rgb(52 52 50), rgb(15 15 14) 78%);
  box-shadow:
    inset 0 1.5px 2px rgb(0 0 0 / 0.8),          /* the hole it sits in */
    0 0 0 1px rgb(0 0 0 / 0.5),                  /* bezel */
    0 1px 0 rgb(255 255 255 / 0.07);             /* the bezel's lit top edge */
}
.led::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%; opacity: 0;
  background:
    radial-gradient(circle at 36% 28%, rgb(255 255 255 / 0.92) 0 10%, transparent 32%),
    radial-gradient(circle at 50% 58%, #e2ffee 0 6%, var(--led-green) 44%, #12703a 92%);
  box-shadow:
    inset 0 0 3px rgb(255 255 255 / 0.45),
    0 0 7px 1px rgb(74 222 128 / 0.5),
    0 0 18px 3px rgb(74 222 128 / 0.18);
}
.led--on::after { opacity: 1; }
/* The bigger stage lights show the mesh of a real panel lamp. */
.led--stage::after {
  background:
    radial-gradient(circle at 36% 28%, rgb(255 255 255 / 0.9) 0 9%, transparent 30%),
    repeating-radial-gradient(circle at 50% 58%, rgb(0 0 0 / 0.14) 0 0.6px, transparent 0.6px 2.2px),
    radial-gradient(circle at 50% 58%, #e2ffee 0 6%, var(--led-green) 44%, #12703a 92%);
}

/* ---- Keys (CassetteKeyStyle) ----------------------------------------------------------------- */
.bank {
  display: inline-flex; flex-wrap: wrap; gap: 2px;
  padding: 4px 4px 0; border-radius: 7px;
  background: var(--slot);
  box-shadow: var(--inset-deep), 0 1px 0 var(--lip);
}
.key {
  --skirt: rgb(36 36 36);
  --travel: 6px;
  --face-top: var(--grey-top);
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; height: 40px; padding: 0 20px; margin-bottom: calc(var(--travel) + 4px);
  font: 600 11.5px/1 var(--sans); letter-spacing: 0.11em; text-transform: uppercase; text-decoration: none;
  white-space: nowrap;  /* a key label never wraps: it is printed on the key */
  color: var(--ink);
  background: url("textures/grain.webp") 0 0 / 96px 96px repeat, linear-gradient(var(--face-top), var(--grey-bottom));
  border-radius: 2.5px;
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.12),
    inset 1px 0 0 rgb(255 255 255 / 0.07),
    inset -1px 0 0 rgb(0 0 0 / 0.3),
    0 var(--travel) 0 var(--skirt),
    0 calc(var(--travel) + 1px) 2px rgb(0 0 0 / 0.35);
  transition: transform var(--release), box-shadow var(--release);
}
/* Pressed: the face drops into the slot (the app's Motion.press / .release). */
.key:active {
  transform: translateY(calc(var(--travel) - 1.5px));
  box-shadow: inset 0 3px 5px rgb(0 0 0 / 0.38), 0 1.5px 0 var(--skirt);
  transition: transform var(--press), box-shadow var(--press);
}
.key--primary {
  --skirt: rgb(133 51 13);
  color: #fff;
  background: url("textures/grain.webp") 0 0 / 96px 96px repeat, linear-gradient(var(--accent-top), var(--accent-bottom));
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.3),
    inset 1px 0 0 rgb(255 255 255 / 0.07),
    inset -1px 0 0 rgb(0 0 0 / 0.3),
    0 var(--travel) 0 var(--skirt),
    0 calc(var(--travel) + 1px) 2px rgb(0 0 0 / 0.35),
    0 0 18px rgb(238 92 36 / 0.18);
}
.key--compact { --travel: 4px; height: 28px; padding: 0 12px; font-size: 10px; }

/* Hover, on devices that hover: the hardware reacts to a hand near it. Transform and opacity only,
   ease-out, and nothing moves more than a couple of pixels. */
@media (hover: hover) and (pointer: fine) {
  a:hover { text-decoration-color: var(--accent); }
  /* A key rises off its skirt before you press it. */
  .key:hover {
    transform: translateY(-1px);
    box-shadow:
      inset 0 1px 0 rgb(255 255 255 / 0.14),
      inset 1px 0 0 rgb(255 255 255 / 0.07),
      inset -1px 0 0 rgb(0 0 0 / 0.3),
      0 calc(var(--travel) + 1px) 0 var(--skirt),
      0 calc(var(--travel) + 3px) 5px rgb(0 0 0 / 0.4);
  }
  .key--primary:hover {
    box-shadow:
      inset 0 1px 0 rgb(255 255 255 / 0.32),
      inset 1px 0 0 rgb(255 255 255 / 0.07),
      inset -1px 0 0 rgb(0 0 0 / 0.3),
      0 calc(var(--travel) + 1px) 0 var(--skirt),
      0 calc(var(--travel) + 3px) 5px rgb(0 0 0 / 0.4),
      0 0 26px rgb(238 92 36 / 0.3);
  }
  .key:active { transform: translateY(calc(var(--travel) - 1.5px)); }
  /* The wordmark's dot is an LED: it brightens when you point at it. */
  .wordmark:hover .dot { box-shadow: 0 0 12px rgb(238 92 36 / 0.85); }
  /* Icon pockets: the glyph lights and the pocket deepens. */
  .icons li:hover svg { stroke: #fff; box-shadow: inset 0 3px 5px rgb(0 0 0 / 0.65), 0 1px 0 var(--lip); }
  .icons li:hover span { color: var(--ink); }
  /* Panels lift a little, as if picked up. */
  .panel:hover, .faq details:hover { transform: translateY(-2px); box-shadow: inset 0 1px 0 var(--edge-light), var(--contact), 0 10px 22px rgb(0 0 0 / 0.26); }
  .cta .panel:hover, .stages:hover { transform: none; }
  .faq summary:hover { color: #fff; }
  .faq summary:hover::after { color: var(--lcd-text); }
  /* A table row lights its segments. */
  .lcd--table tbody tr:hover th, .lcd--table tbody tr:hover td { color: var(--lcd-text); text-shadow: 0 0 8px rgb(255 146 52 / 0.5); }
  .lcd--table tbody tr:hover td.on { color: var(--led-green); text-shadow: 0 0 8px rgb(74 222 128 / 0.5); }
  /* Screenshots rise like a tray being pulled out. */
  .shot:hover img { transform: translateY(-4px); }
  .chips a:hover { transform: translateY(-1px); color: var(--ink); }
}

.panel, .faq details, .shot img, .icons svg, .icons span, .dot, .faq summary, .faq summary::after,
.lcd--table tbody tr th, .lcd--table tbody tr td {
  transition: transform 180ms var(--ease-out), box-shadow 180ms var(--ease-out), color 140ms ease,
    stroke 140ms ease, text-shadow 140ms ease;
}

/* The section the reader is in shows on its key, latched like the app's tabs. */
.navdock .key.is-current {
  color: #fff;
  background: linear-gradient(var(--grey-bottom), var(--grey-bottom));
  box-shadow:
    inset 0 3px 0 var(--accent),
    inset 0 4px 6px rgb(0 0 0 / 0.35),
    0 var(--travel) 0 var(--skirt),
    0 calc(var(--travel) + 1px) 2px rgb(0 0 0 / 0.35),
    0 0 14px rgb(238 92 36 / 0.16);
}

/* ---- LCD ----------------------------------------------------------------------------------- */
.lcd {
  background:
    repeating-linear-gradient(to bottom, rgb(255 255 255 / 0.014) 0 1px, transparent 1px 3px),
    linear-gradient(to bottom, rgb(255 255 255 / 0.022), transparent 40%),
    var(--lcd);
  border-radius: var(--radius-l);
  box-shadow: var(--inset-deep), 0 1px 0 var(--lip);
  color: var(--lcd-text);
  font-family: var(--mono);
  text-transform: uppercase; letter-spacing: 0.14em;
  text-shadow: 0 0 6px rgb(255 146 52 / 0.35);
}
.lcd .label { color: var(--lcd-caption); text-shadow: none; }
.lcd-line { margin: 0; display: flex; flex-wrap: wrap; gap: 0 var(--s3); font-size: 14px; }
.lcd-line--big { font-size: clamp(22px, 4vw, 30px); margin-bottom: var(--s2); }
/* Used by 404.html: a centred readout block. */
.lcd--hero { display: inline-block; text-align: center; padding: var(--s4) var(--s6); margin-bottom: var(--s5); max-width: 100%; }
.lcd--hero .lcd-line { justify-content: center; }
.readout { margin: 0 0 var(--s2); font: 500 13px/1 var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--lcd-text); text-shadow: 0 0 6px rgb(255 146 52 / 0.3); }
.readout .label { color: var(--muted); text-shadow: none; }

/* ---- Hero ---------------------------------------------------------------------------------- */
main { max-width: 1120px; margin: 0 auto; }
.hero { padding-block: var(--s4) var(--s4); text-align: center; }
h1 { font-size: clamp(38px, 7vw, 68px); line-height: 1.04; letter-spacing: -0.035em; margin: 0 0 var(--s3); font-weight: 700; }
.lede { max-width: 640px; margin: 0 auto var(--s5); color: var(--muted); font-size: clamp(16px, 2vw, 19px); }
.actions { display: flex; flex-direction: column; align-items: center; gap: var(--s2); margin-bottom: var(--s6); }
.fine { margin: 0; font-size: 13px; color: var(--muted); }
.fine--left { text-align: left; margin-top: var(--s3); }
.fine--proof { margin-top: var(--s2); }

.shot { margin: 0; }
.shot img { width: 100%; }
/* The hero video is the bare window: the corners and the shadow are drawn here, so the file
   carries no transparent margin (video has no alpha). */
.demo-video {
  display: block; width: 100%; height: auto; aspect-ratio: 1400 / 966;
  border-radius: 12px; background: #1d1d1c;
  box-shadow: 0 0 0 1px rgb(255 255 255 / 0.1), 0 14px 38px rgb(0 0 0 / 0.45), 0 2px 6px rgb(0 0 0 / 0.3);
}
/* A video is its own pause control (main.js), so it takes focus like one. */
.demo-video, .step-shot video { cursor: pointer; }
.demo-video:focus-visible, .step-shot video:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.shot--hero { margin-inline: 0; }

.lcd--proof {
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s2) var(--s5);
  margin: var(--s5) auto 0; padding: var(--s3) var(--s5); max-width: 860px; font-size: 14px;
}
.lcd--proof p { margin: 0; }

/* ---- Sections ------------------------------------------------------------------------------ */
.section { padding-block: var(--s7) 0; }
/* A section title sits in the middle of its own engraved rule, like a legend printed on a plate. */
.index {
  display: flex; align-items: center; justify-content: center; gap: var(--s3);
  margin: 0 0 var(--s5);
  font-size: 12px; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; text-align: center;
}
.index::before, .index::after {
  content: ""; flex: 1; height: 1px; background: rgb(255 255 255 / 0.1); box-shadow: 0 1px 0 rgb(0 0 0 / 0.4);
}
.index::before { transform-origin: right center; }
.index::after { transform-origin: left center; }
.intro { max-width: 720px; margin: 0 0 var(--s5); color: var(--muted); font-size: 18px; }

h3 { font-size: clamp(22px, 3vw, 30px); letter-spacing: -0.02em; line-height: 1.15; margin: 0 0 var(--s3); }
.feature { display: grid; grid-template-columns: 5fr 7fr; gap: var(--s5); align-items: center; margin-bottom: var(--s6); }
.feature--flip { grid-template-columns: 7fr 5fr; }  /* the picture keeps the wide column */
.feature--flip .feature-text { order: 2; }
.feature p { color: var(--muted); margin: 0 0 var(--s3); font-size: 18px; }
.feature h3 { font-size: clamp(26px, 3.4vw, 36px); }

/* Raised panel (raisedPanel) with corner screws */
.panel {
  position: relative;
  background:
    url("textures/grain.webp") 0 0 / 128px 128px repeat,
    linear-gradient(to bottom, rgb(255 255 255 / 0.03), transparent 30%),
    linear-gradient(var(--metal-top), var(--metal-bottom));
  border-radius: var(--radius-l);
  box-shadow: inset 0 1px 0 var(--edge-light), var(--contact), var(--ambient);
  padding: var(--s4);
}
.panel--screws {
  --screw: radial-gradient(circle, rgb(20 20 19) 0 2px, rgb(255 255 255 / 0.06) 2px 2.6px, transparent 2.8px);
  background:
    var(--screw) 10px 10px / 6px 6px no-repeat,
    var(--screw) calc(100% - 10px) 10px / 6px 6px no-repeat,
    var(--screw) 10px calc(100% - 10px) / 6px 6px no-repeat,
    var(--screw) calc(100% - 10px) calc(100% - 10px) / 6px 6px no-repeat,
    url("textures/grain.webp") 0 0 / 128px 128px repeat,
    linear-gradient(to bottom, rgb(255 255 255 / 0.03), transparent 30%),
    linear-gradient(var(--metal-top), var(--metal-bottom));
  padding: var(--s5);
}

/* How it works: the connecting screen's stage lights */
.stages { list-style: none; margin: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s4); }
/* Between one light and the next, the run of copper the signal travels. Drawn per stage so it
   lines up with the lenses whatever the panel's padding is. */
.stages li { position: relative; }
.stages li + li::before {
  content: ""; position: absolute; top: 7px; height: 2px;
  left: calc(-50% - var(--s4) + 13px); right: calc(50% + 13px);
  background: linear-gradient(90deg, rgb(255 146 52 / 0.2), rgb(255 146 52 / 0.5));
  box-shadow: 0 0 6px rgb(255 146 52 / 0.2);
  transform-origin: left center;
}
.stages li { display: grid; justify-items: center; text-align: center; gap: var(--s2); }
.stages .led { width: 16px; height: 16px; }
.stage-name { font-size: 12px; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; }
.stages p { margin: 0; color: var(--muted); font-size: 15px; }

/* The details: an icon grid (Liqoria-style density), each glyph in a sunken pocket like the app's
   camera glyphs. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.icons { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--s5) var(--s3); }
.icons li { display: grid; justify-items: center; gap: var(--s2); text-align: center; }
.icons svg {
  width: 52px; height: 52px; padding: 13px; border-radius: var(--radius-m);
  fill: none; stroke: var(--ink); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
  background: url("textures/grain.webp") 0 0 / 96px 96px repeat, rgb(25 25 24);
  box-shadow: inset 0 2px 3px rgb(0 0 0 / 0.55), 0 1px 0 var(--lip);
}
.icons span { font-size: 14px; color: var(--muted); line-height: 1.3; }

.tag { display: inline-block; margin: 0; padding: 3px 8px; border-radius: 4px; font: 500 11px/1.4 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--lcd-caption); background: var(--lcd); box-shadow: var(--inset-deep); }
.muted { color: var(--muted); }

.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s3); }
.steps li { display: grid; grid-template-columns: 40px 1fr; gap: var(--s2); align-items: baseline; }
.steps p { margin: 0; font-size: 17px; }
.steps--row { grid-template-columns: repeat(3, 1fr); }
.steps--row li { grid-template-columns: 1fr; gap: var(--s3); align-content: start; }
.steps--row p { font-size: 16px; }
.steps--row li { align-content: space-between; }
.step-shot { margin: 0; }
.step-shot img, .step-shot video {
  display: block; width: 100%; height: auto; aspect-ratio: 900 / 520; border-radius: var(--radius-m);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.06), var(--contact);
}
.n { font: 700 15px/1 var(--mono); color: var(--lcd-text); }

.lcd--table {
  padding: var(--s3) var(--s4); overflow-x: auto;
  background:
    radial-gradient(circle, rgb(255 146 52 / 0.055) 0 1px, transparent 1.4px) 0 0 / 14px 14px,
    repeating-linear-gradient(to bottom, rgb(255 255 255 / 0.014) 0 1px, transparent 1px 3px),
    var(--lcd);
}
.lcd--table:focus-visible { border-radius: var(--radius-l); }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 12px var(--s3) 12px 0; font-weight: 400; vertical-align: top; }
thead th { color: var(--lcd-caption); text-shadow: none; font-size: 11px; white-space: nowrap; }
tbody tr + tr th, tbody tr + tr td { border-top: 1px solid rgb(255 146 52 / 0.1); }
tbody th { color: var(--lcd-text); white-space: nowrap; }
td { color: rgb(255 146 52 / 0.72); }
td.on { color: var(--led-green); text-shadow: 0 0 6px rgb(74 222 128 / 0.35); }

.faq { display: grid; gap: var(--s2); }
.faq details { background: url("textures/grain.webp") 0 0 / 128px 128px repeat, linear-gradient(var(--metal-top), var(--metal-bottom)); border-radius: var(--radius-m); box-shadow: inset 0 1px 0 var(--edge-light), var(--contact); }
.faq summary { cursor: pointer; list-style: none; padding: var(--s3) var(--s4); font-weight: 600; display: flex; justify-content: space-between; gap: var(--s3); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+" / ""; font-family: var(--mono); color: var(--accent); transition: transform 200ms var(--ease-out); }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq details p { margin: 0; padding: 0 var(--s4) var(--s3); color: var(--muted); }


.cta { text-align: center; padding-block: var(--s7) var(--s6); }
.cta .panel { display: grid; justify-items: center; gap: var(--s4); padding-block: var(--s5); }
/* Punched grille: a dark hole with a lit lip under it, repeated. */
.grille {
  width: min(420px, 70%); height: 34px; border-radius: 6px;
  background:
    radial-gradient(circle at 50% 62%, rgb(255 255 255 / 0.055) 0 1.9px, transparent 2.2px) 0 0 / 9px 9px,
    radial-gradient(circle at 50% 50%, rgb(10 10 9) 0 1.7px, transparent 2px) 0 0 / 9px 9px,
    linear-gradient(var(--metal-top), var(--metal-bottom));
  box-shadow: inset 0 1px 0 var(--lip);
}
.cta-line { font-size: clamp(22px, 3vw, 30px); font-weight: 700; letter-spacing: -0.02em; margin: 0 0 var(--s4); }

/* Footer: the maker's signature first (as on smithplus's other sites), then credits and legal, small. */
.footer {
  max-width: 1120px; margin: 0 auto; padding-block: var(--s5) var(--s6);
  border-top: 1px solid rgb(255 255 255 / 0.08);
  text-align: center; color: var(--muted);
}
.footer p { margin: 0 auto var(--s2); max-width: 760px; }
.footer a { color: inherit; }
.footer-sig { font-size: 13px; color: var(--ink); }
.footer-sig a { color: var(--ink); }
.footer-credits, .footer-legal { font-size: 12px; line-height: 1.6; opacity: 0.8; }
@media (hover: hover) and (pointer: fine) { .footer a:hover { color: var(--ink); } }

/* ---- Motion -------------------------------------------------------------------------------- */

/* Page load, like the app switching on: the LCD warms up in steps, then the rest rises in. */
@keyframes lcd-boot {
  0% { opacity: 0; }
  20% { opacity: 0.55; }
  32% { opacity: 0.12; }
  50% { opacity: 0.8; }
  62% { opacity: 0.35; }
  100% { opacity: 1; }
}
@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}
@keyframes tray {
  from { opacity: 0; transform: translateY(20px) scale(0.985); }
  to { opacity: 1; transform: none; }
}
.lcd--hero .lcd-line { animation: lcd-boot 520ms steps(1, end) both; }
.reveal-ready .lcd--proof.is-in p { animation: lcd-boot 460ms steps(1, end) both; }
.reveal-ready .lcd--proof.is-in p:nth-child(2) { animation-delay: 70ms; }
.reveal-ready .lcd--proof.is-in p:nth-child(3) { animation-delay: 140ms; }
.reveal-ready .lcd--proof.is-in p:nth-child(4) { animation-delay: 210ms; }
.hero h1 { animation: rise 500ms var(--ease-out) 80ms both; }
.hero .lede { animation: rise 500ms var(--ease-out) 140ms both; }
.hero .actions { animation: rise 500ms var(--ease-out) 200ms both; }
.shot--hero { animation: tray 600ms var(--ease-out) 120ms both; }
.status .led::after { opacity: 0; animation: led-on 1ms linear 600ms forwards; }
/* While a meter is settling, its digits sit a shade brighter, like a needle still moving. */
.lcd--proof p.is-counting { color: #ffd9b0; text-shadow: 0 0 10px rgb(255 146 52 / 0.55); }
.lcd--proof p { transition: color 260ms var(--ease-out), text-shadow 260ms var(--ease-out); }
@keyframes led-on { to { opacity: 1; } }

/* Scroll reveals (main.js adds .reveal-ready, then .is-in as each block comes into view). */
.reveal-ready [data-reveal] { opacity: 0; transform: translateY(10px); }
.reveal-ready [data-reveal="tray"] { transform: translateY(20px) scale(0.985); }
.reveal-ready [data-reveal].is-in {
  opacity: 1; transform: none;
  transition: opacity 450ms var(--ease-out), transform 550ms var(--ease-out);
  transition-delay: calc(var(--i, 0) * 50ms);
}
/* The rules draw out from the title, like a line being printed either way. */
.reveal-ready .index::before, .reveal-ready .index::after { transform: scaleX(0); }
.reveal-ready .index.is-in::before, .reveal-ready .index.is-in::after {
  transform: scaleX(1); transition: transform 600ms var(--ease-out) 80ms;
}
/* Order for staggered items, in CSS so the strict CSP (no inline styles) holds. Reset first:
   the parent block carries its own --i, which would otherwise be inherited by the first item. */
.stages li, .lcd--table tbody tr { --i: 0; }
.stages li:nth-child(2), .lcd--table tbody tr:nth-child(2) { --i: 1; }
.stages li:nth-child(3), .lcd--table tbody tr:nth-child(3) { --i: 2; }
.stages li:nth-child(4), .lcd--table tbody tr:nth-child(4) { --i: 3; }
.lcd--table tbody tr:nth-child(5) { --i: 4; }
.lcd--table tbody tr:nth-child(6) { --i: 5; }
/* Each run of copper draws just before the light at its end comes on. */
.reveal-ready .stages li + li::before { transform: scaleX(0); }
.reveal-ready .stages.is-in li + li::before {
  transform: scaleX(1);
  transition: transform 280ms var(--ease-out);
  transition-delay: calc(400ms + (var(--i, 1) - 1) * 320ms);
}
/* A feature's screenshot slides in from the side it sits on, like a tray pulled out. */
.reveal-ready .feature .shot { transform: translate(16px, 20px) scale(0.985); }
.reveal-ready .feature--flip .shot { transform: translate(-16px, 20px) scale(0.985); }
.reveal-ready .feature .shot.is-in { transform: none; }
/* Step numbers light like a readout. */
.reveal-ready .steps--row li.is-in .n { animation: lcd-boot 420ms steps(1, end) 120ms both; }
/* One pass of light across the grille when the download plate arrives. */
.cta .panel { position: relative; overflow: hidden; }
.cta .panel::after {
  content: ""; position: absolute; inset: -20% -40%; pointer-events: none; opacity: 0;
  background: linear-gradient(105deg, transparent 38%, rgb(255 255 255 / 0.05) 50%, transparent 62%);
}
.reveal-ready .cta .panel.is-in::after { opacity: 1; animation: sweep 1100ms var(--ease-out) 260ms both; }
@keyframes sweep {
  from { transform: translateX(-60%); }
  to { transform: translateX(60%); }
}
/* Stage lights come on one after another, as they do while connecting. */
.reveal-ready .stages.is-in .led::after { opacity: 1; transition: opacity 120ms steps(2, end); transition-delay: calc(350ms + var(--i, 0) * 320ms); }
.stages .led::after { opacity: 1; }  /* lit without JS */
.reveal-ready .stages:not(.is-in) .led::after { opacity: 0; }
/* LCD rows light up in order, like segments. */
.reveal-ready .lcd--table tbody tr { opacity: 0; }
.reveal-ready .lcd--table.is-in tbody tr { opacity: 1; transition: opacity 160ms steps(2, end); transition-delay: calc(200ms + var(--i, 0) * 70ms); }

/* ---- Narrow screens ------------------------------------------------------------------------ */
@media (max-width: 860px) {
  .stages li + li::before { display: none; }  /* the stages wrap: nothing to connect sideways */
  .feature { grid-template-columns: 1fr; gap: var(--s3); }
  .feature--flip .feature-text { order: 0; }
  .icons { grid-template-columns: repeat(3, 1fr); }
  .stages { grid-template-columns: 1fr 1fr; }
  .steps--row { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  /* Stacked keys fill the slot: a key half as wide as its bank reads as a mistake. */
  .actions .bank, .cta .bank { display: flex; flex-direction: column; align-items: stretch; width: 100%; }
  .actions .key, .cta .key { width: 100%; }
  /* Five columns don't fit a phone: the comparison becomes one LABEL: value line per option,
     the way the app's readouts are written. */
  .lcd--pairs { overflow-x: visible; }
  .lcd--pairs table, .lcd--pairs tbody, .lcd--pairs tr, .lcd--pairs th, .lcd--pairs td { display: block; }
  .lcd--pairs thead { display: none; }
  .lcd--pairs tbody tr { padding: var(--s3) 0; }
  .lcd--pairs tbody tr + tr { border-top: 1px solid rgb(255 146 52 / 0.1); }
  .lcd--pairs tbody th { padding: 0 0 6px; white-space: normal; }
  .lcd--pairs tbody td { display: flex; justify-content: space-between; gap: var(--s3); padding: 3px 0; border: 0; }
  .lcd--pairs tbody td::before { content: attr(data-label); color: var(--lcd-caption); }
  /* The cameras table fits once its names may wrap. */
  .lcd--table tbody th { white-space: normal; }
  .lcd--table th, .lcd--table td { padding-right: var(--s2); }
  .navdock .bank { flex-wrap: nowrap; }
  .navdock .key--compact { padding: 0 8px; font-size: 9.5px; letter-spacing: 0.05em; }
  .navdock { padding-bottom: var(--s4); }
  .stages { grid-template-columns: 1fr; }
  .icons { grid-template-columns: 1fr 1fr; }
  .panel--screws { padding: var(--s4); }
  .lcd--proof { justify-content: flex-start; padding: var(--s3) var(--s4); }
  .section { padding-block: var(--s6) 0; }
}

/* Touch: a finger needs more room than a cursor, and the dock is the only place with small keys. */
@media (pointer: coarse) {
  .key--compact { height: 40px; padding: 0 14px; }
  .faq summary { padding-block: var(--s3); }
}

/* Printing: reveals never run on paper. */
@media print {
  .reveal-ready [data-reveal], .reveal-ready .lcd--table tbody tr, .reveal-ready .stages .led::after { opacity: 1 !important; transform: none !important; }
}

/* Reduce Motion: keep the fades (they carry meaning), drop every movement. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .navdock.is-stuck .bank { animation: none; }
  /* Hover keeps its light, loses its movement. */
  .panel, .faq details, .shot img, .icons svg { transition: box-shadow 140ms ease, color 140ms ease; }
  .key:hover, .panel:hover, .faq details:hover, .shot:hover img, .chips a:hover { transform: none; }
  .key, .key:active { transition: none; }
  .key:active { transform: none; }
  .lcd--hero .lcd-line, .hero h1, .hero .lede, .hero .actions, .shot--hero,
  .reveal-ready .lcd--proof.is-in p { animation: fade 300ms linear both; }
  @keyframes fade { from { opacity: 0; } to { opacity: 1; } }
  .reveal-ready [data-reveal], .reveal-ready [data-reveal="tray"] { transform: none; }
  .reveal-ready [data-reveal].is-in { transition: opacity 300ms linear; transition-delay: 0ms; }
  .reveal-ready .index::after { transform: none; }
  .reveal-ready .stages .led::after, .reveal-ready .lcd--table tbody tr { transition-delay: 0ms !important; }
  .reveal-ready .stages li + li::before, .reveal-ready .stages.is-in li + li::before { transform: none; transition: none; }
  .reveal-ready .index::before, .reveal-ready .index::after { transform: none; }
  .reveal-ready .feature .shot, .reveal-ready .feature--flip .shot { transform: none; }
  .reveal-ready .steps--row li.is-in .n, .reveal-ready .cta .panel.is-in::after { animation: none; }
  .cta .panel::after { display: none; }
}
