/* Zielzeit landing page.
   Rubik, one accent, no external requests. */

/* Rubik, self-hosted, under the SIL Open Font License — fonts/OFL.txt travels
   with the woff2 files because the OFL requires the licence to accompany the
   font software, and this repo redistributes it.
   Google Fonts' own CDN is not used: the footer promises
   this page loads nothing from anyone else, and a webfont link is exactly the
   third-party request that would make that false. One variable file per subset
   (wght 300–900) rather than four static cuts, so the whole ramp costs 35 kB.
   Latin-ext is separate and only fetched by pages needing it; the German copy
   lives entirely in Latin-1 (ä ö ü ß), so in practice it never loads. */
@font-face {
  font-family: Rubik;
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("fonts/rubik-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: Rubik;
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("fonts/rubik-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --bg:       #ffffff;
  --alt:      #f5f8f7;
  --ink:      #101614;
  --body:     #56645f;
  --muted:    #85938e;
  --line:     #e2e8e5;
  --line-2:   #eef2f0;
  --accent:   #0e9e6b;
  --accent-d: #0a7a53;

  /* System fonts stay behind Rubik so a blocked or missing woff2 degrades to
     what the page used to be rather than to Helvetica. */
  --sans: Rubik, -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --pad: clamp(20px, 5vw, 32px);
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 76px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* Rubik is drawn on an even, upright rhythm and its default sidebearings are
     already tight. The negative tracking this page used to carry everywhere was
     compensating for SF Pro's optical sizing, which Rubik does not have; keep it
     and the caps close up. So: tracking is `normal` throughout, and the only
     letter-spacing left in the file is positive, on uppercase runs. */
  letter-spacing: normal;
}

img { max-width: 100%; height: auto; display: block; }
a { color: var(--accent-d); text-underline-offset: 3px; }
a:hover { color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 5px; }

.skip { position: absolute; left: -9999px; top: 0; background: var(--ink); color: #fff; padding: 10px 16px; z-index: 99; }
.skip:focus { left: 8px; top: 8px; }

.wrap { width: min(1000px, 100% - calc(var(--pad) * 2)); margin-inline: auto; }
/* Everything sits on one 1000px column, nav and stage included. */
.wrap--wide { width: min(1000px, 100% - calc(var(--pad) * 2)); }

.mono {
  font: 0.86em/1 var(--mono);
  background: rgba(14, 158, 107, 0.08);
  color: var(--accent-d);
  padding: 2px 5px;
  margin: 0 -1px;
  border-radius: 5px;
  white-space: nowrap;
}

/* ── Nav ───────────────────────────────────────────────────── */
.nav {
  position: sticky; top: 0; z-index: 40;
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: saturate(180%) blur(18px);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  border-bottom: 1px solid var(--line);
}
.nav__in {
  width: min(1000px, 100% - calc(var(--pad) * 2));
  margin-inline: auto;
  height: 60px;
  display: flex; align-items: center; gap: 28px;
}
.nav__brand {
  display: flex; align-items: center; gap: 9px;
  font-size: 16px; font-weight: 600;
  color: var(--ink); text-decoration: none;
}
.nav__brand img { border-radius: 6px; }
.nav__links { display: flex; gap: 22px; margin-left: auto; }
.nav__links a { font-size: 14.5px; color: var(--body); text-decoration: none; }
.nav__links a:hover { color: var(--ink); }

/* ── Buttons ───────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 16px; font-weight: 600;
  text-decoration: none;
  padding: 13px 24px;
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
  border: 1px solid var(--accent);
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.btn:hover { background: var(--accent-d); border-color: var(--accent-d); color: #fff; }
.btn--sm { padding: 7px 15px; font-size: 14.5px; border-radius: 8px; flex: none; }
.btn--plain { background: #fff; color: var(--ink); border-color: var(--line); }
.btn--plain:hover { background: var(--alt); border-color: #d2dad6; color: var(--ink); }

.actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin-bottom: 14px; }
.note { font-size: 14px; color: var(--muted); text-align: center; margin: 0; }

/* ── Hero ──────────────────────────────────────────────────── */
.hero {
  padding: clamp(52px, 8vw, 88px) 0 clamp(56px, 8vw, 88px);
  text-align: center;
  background: linear-gradient(180deg, #f2f8f6 0%, #ffffff 62%);
}

.kicker {
  display: inline-block;
  font-size: 13px; font-weight: 500;
  color: var(--accent-d);
  background: rgba(14, 158, 107, 0.09);
  padding: 5px 13px;
  border-radius: 999px;
  margin: 0 0 20px;
}

/* Display weight is 700, matching Rubik's own bold cut rather than the 640–650
   half-steps SF Pro's variable axis allowed. Rubik at 700 is the weight the
   family is designed to shout in; 650 lands between its drawn masters and reads
   muddy at 56px. Line-height 1.14 is Rubik's comfortable display ratio (its
   ascenders are short, so 1.07 clipped the diacritics on the German headline). */
h1 {
  font-size: clamp(34px, 5.2vw, 56px);
  font-weight: 700;
  line-height: 1.14;
  margin: 0 auto 20px;
  /* `ch` is the width of a "0", and Rubik's is wider than SF Pro's, so the same
     15ch that used to hold this headline on two lines now breaks it into three
     with "goal?" alone on the last. Widened to fit Rubik's measure, and
     `text-wrap: balance` evens the lines out rather than leaving whatever the
     greedy line-breaker produces. */
  max-width: 20ch;
  text-wrap: balance;
}

.sub {
  font-size: clamp(17px, 1.7vw, 19px);
  line-height: 1.58;
  color: var(--body);
  max-width: 60ch;
  margin: 0 auto 30px;
}
.sub--left { margin-inline: 0; margin-bottom: 44px; }

/* ── The stage: the app as it actually appears, hanging from the
      menu bar. The screenshot's own background is a flat #2b2b2b,
      so the bar is that exact colour and the seam disappears. ── */
.stage {
  position: relative;
  margin-top: clamp(44px, 6vw, 68px);
  /* A display's bezel. The children are absolutely positioned against the
     padding box, so the border sits outside them and the menu bar still runs
     edge to edge inside the screen rather than under the frame. */
  border: 7px solid #16191b;
  border-radius: 20px;
  overflow: hidden;
  /* The wallpaper, drawn rather than photographed: the page loads nothing from
     anyone else, and Apple's own desktop pictures are not redistributable. The
     layers do what a photograph would — a bloom top-left, a cool pool bottom-
     right, a diagonal light band across the middle, and a vignette to keep the
     corners from going flat. Order matters: the vignette is listed first so it
     paints on top of the colour beneath it. */
  background:
    radial-gradient(120% 90% at 50% 50%, transparent 42%, rgba(0, 0, 0, 0.38) 100%),
    linear-gradient(112deg, transparent 26%, rgba(122, 226, 199, 0.10) 44%, transparent 58%),
    radial-gradient(75% 60% at 18% 6%, rgba(64, 190, 155, 0.5) 0%, transparent 62%),
    radial-gradient(90% 70% at 12% 0%, #1d6f5e 0%, transparent 58%),
    radial-gradient(80% 70% at 92% 100%, #0d4257 0%, transparent 62%),
    linear-gradient(155deg, #0b2b28 0%, #113f39 52%, #0c3341 100%);
  box-shadow: 0 2px 6px rgba(16, 22, 20, 0.06), 0 30px 60px -28px rgba(16, 22, 20, 0.4);
  text-align: left;
  /* A real display's ratio now that the Dock has to fit: 1.6 is 16:10, what
     every MacBook is, where 1.72 was a crop chosen to hold the popover alone.
     The popover still runs past the bottom edge exactly as it would on a real
     screen, and the rest of it is shown in the feature rows below — it is not
     scaled to fit, because 344px is the one width at which the 688px capture
     lands pixel-exact. */
  aspect-ratio: 1.6;
}
.stage::after {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(70% 55% at 78% 8%, rgba(255, 255, 255, 0.09), transparent 62%);
  pointer-events: none;
}
.stage__bar {
  position: absolute; top: 0; left: 0; right: 0; z-index: 1;
  background: #2b2b2b; height: 44px; display: flex; justify-content: flex-end;
}
.stage__items { display: flex; align-items: center; gap: 15px; padding-right: 18px; color: #e9e9e9; }
/* 298x88 halved exactly, and the screenshot's own padding is the same
   #2b2b2b as the bar, so no cropping is needed and no seam shows. */
.stage__app { width: 149px; height: 44px; }
.sysicon { width: 17px; height: 13px; color: #e9e9e9; flex: none; }
.sysicon--batt { width: 25px; }
.stage__clock { font-size: 12.5px; color: #e9e9e9; letter-spacing: 0.01em; white-space: nowrap; }

.stage__pop {
  /* Above the Dock: see the note there for why the widget wins the z-order. */
  position: absolute; z-index: 3; top: 58px; right: 40px;
  width: 344px;
  border-radius: 12px;
  box-shadow: 0 24px 50px -12px rgba(0, 0, 0, 0.55);
}

/* ── The Dock ──────────────────────────────────────────────────
   It passes *behind* the popover, and that is a considered trade rather than an
   oversight. macOS draws the Dock above windows, and letting its glass blur the
   popover looks great — but the two cannot be kept apart at every width. The
   Dock is centred and the popover is anchored right, so as the stage narrows
   below about 990px they converge, and the glass lands on the slider labels,
   the one part of the shot that has to stay legible. Rather than tune a width
   where it happens to clear, the widget wins the z-order at every size. The
   blur still does its real job on the wallpaper behind it. ── */
.stage__dock {
  position: absolute; z-index: 1;
  left: 50%; transform: translateX(-50%);
  bottom: 9px;
  display: flex; align-items: flex-end; gap: 10px;
  padding: 8px;
  border-radius: 19px;
  background: rgba(190, 200, 205, 0.24);
  border: 1px solid rgba(255, 255, 255, 0.16);
  backdrop-filter: blur(22px) saturate(160%);
  -webkit-backdrop-filter: blur(22px) saturate(160%);
  box-shadow: 0 10px 26px -8px rgba(0, 0, 0, 0.45);
}
.dock__tile {
  width: 46px; height: 46px;
  border-radius: 11px;
  flex: none;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
}
.dock__tile img { width: 46px; height: 46px; border-radius: 11px; }
/* Neutral stand-ins, not anyone's app. Distinct enough in hue to read as a row
   of different apps at 46px, flat enough not to compete with the real icon. */
.dock__tile--1 { background: linear-gradient(160deg, #6fb2f5, #2c6fd1); }
.dock__tile--2 { background: linear-gradient(160deg, #ff8a8a, #d9455c); }
.dock__tile--3 { background: linear-gradient(160deg, #ffd479, #f0a52b); }
.dock__tile--4 { background: linear-gradient(160deg, #9be79b, #3aa55d); }
/* Five tiles, and no Trash separator past them: a centred Dock grows in both
   directions, so every extra tile reaches further under the popover. Five is
   enough to read as a Dock and short enough that most of it stays in view. */
.dock__tile--app { position: relative; background: none; box-shadow: none; }
/* The running dot: its popover is open above, so the app is running. */
.dock__tile--app::after {
  content: "";
  position: absolute; left: 50%; bottom: -6px;
  width: 4px; height: 4px; margin-left: -2px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
}
.fineprint { font-size: 13px; color: var(--muted); text-align: center; margin: 20px 0 0; }

/* ── The play pill and the film ─────────────────────────────────
   The pill sits inside `.stage` but changes nothing about it: the bezel, the
   drawn wallpaper, the bar, the Dock and the z-order rules above are untouched.
   It takes z-index 4 so it clears the popover at 3, and lives on the left for
   the reason the button's own comment gives.

   Nothing here autoplays. An autoplaying video above the fold would trade the
   page's largest paint for a loop nobody has scrolled to — the same reasoning
   that keeps demo.gif down in the feature rows — and it is also why
   `prefers-reduced-motion` needs no case: the film moves only when asked. ── */
.playpill {
  position: absolute; z-index: 4;
  left: clamp(20px, 4vw, 54px);
  top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; gap: 10px;
  min-height: 44px;
  padding: 12px 20px;
  font: inherit; font-size: 15px; font-weight: 600;
  color: #0b2b28;
  background: rgba(255, 255, 255, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: 999px;
  cursor: pointer;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 10px 26px -10px rgba(0, 0, 0, 0.5);
  transition: transform 0.16s ease, box-shadow 0.16s ease, background 0.16s ease;
}
.playpill:hover { transform: translateY(-50%) scale(1.03); background: #fff; }
.playpill:focus-visible { outline: 3px solid var(--accent, #0e9e6b); outline-offset: 3px; }
.playpill svg { width: 12px; height: 14px; flex: none; }

.filmbox {
  width: min(96vw, 1000px);
  padding: 0;
  border: 0;
  border-radius: 16px;
  background: #0d1a17;
  color: #e8efec;
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.7);
}
.filmbox::backdrop { background: rgba(8, 14, 12, 0.72); }
.filmbox__video {
  display: block;
  width: 100%; height: auto;
  border-radius: 16px 16px 0 0;
  background: #000;
}
.filmbox__close {
  position: absolute; top: 10px; right: 10px;
  width: 34px; height: 34px;
  font-size: 15px; line-height: 1;
  color: #fff;
  background: rgba(0, 0, 0, 0.5);
  border: 0; border-radius: 50%;
  cursor: pointer;
}
.filmbox__text { padding: 20px 26px 24px; font-size: 14.5px; line-height: 1.6; }
.filmbox__text p { margin: 0 0 10px; color: rgba(232, 239, 236, 0.72); }
.filmbox__text ol { margin: 0 0 12px; padding-left: 22px; }
.filmbox__text li { margin-bottom: 4px; }
.filmbox__text .fineprint { margin: 0; text-align: left; color: rgba(232, 239, 236, 0.5); }

/* ── Specs strip ───────────────────────────────────────────── */
/* ── Icons ─────────────────────────────────────────────────────
   Drawn here as inline SVG rather than pulled from an icon set: the page loads
   nothing from anyone else, and inlining also lets them inherit `currentColor`.
   One language throughout — 24px box, 1.75 stroke, round caps — chosen to sit
   with Rubik, whose strokes are even and upright rather than modulated. ── */
.ico {
  display: block;
  width: 24px; height: 24px;
  flex: none;
  color: var(--accent);
}
/* On the cards the glyph sits in a tinted tile. Two reasons beyond looks: a
   24px glyph alone read as an afterthought against a 24px-padded card, and the
   negative claims here need a slash, which only resolves at a larger size.
   box-sizing is border-box globally, so the padding holds the glyph at 24px. */
.ico--card {
  width: 42px; height: 42px;
  padding: 9px;
  margin-bottom: 15px;
  border-radius: 12px;
  background: rgba(14, 158, 107, 0.09);
  color: var(--accent-d);
}
/* In the callouts the icon leads the heading on one row. */
.ico--inline { width: 22px; height: 22px; }

/* ── Specs: five keycaps ───────────────────────────────────────
   The one dimensional element on the page, and the reason it is here rather
   than on the hero: a 3D transform resamples whatever it contains, and the
   hero holds a screenshot that is pixel-exact at 2x — tilting it would soften
   the very thing the page is selling. A keycap needs no transform. The lower
   edge is a hard-offset box-shadow, so the face stays flat to the viewer and
   the type on it stays crisp, and pressing on hover moves it down onto that
   edge. Specs are the page's hard facts; making them the physical thing you
   press is the one place the metaphor earns its keep. ── */
.specs { border-block: 1px solid var(--line); background: var(--alt); }
.specs ul {
  list-style: none; margin: 0; padding: 34px 0 38px;
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px;
}
.specs li {
  text-align: center;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 18px 12px 15px;
  box-shadow: 0 4px 0 #dbe4e0, 0 12px 20px -12px rgba(16, 22, 20, 0.3);
  transition: transform 0.16s ease, box-shadow 0.16s ease;
}
.specs li:hover {
  transform: translateY(4px);
  box-shadow: 0 0 0 #dbe4e0, 0 6px 12px -10px rgba(16, 22, 20, 0.3);
}
.specs .ico { margin: 0 auto 11px; }
.specs b { display: block; font-size: 15px; font-weight: 600; }
.specs span { display: block; font-size: 13px; color: var(--muted); margin-top: 2px; }

/* ── Bands ─────────────────────────────────────────────────── */
.band { padding: clamp(64px, 8vw, 100px) 0; }
.band--alt { background: var(--alt); border-block: 1px solid var(--line); }

.eyebrow {
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--accent-d);
  margin: 0 0 12px;
}

h2 {
  font-size: clamp(26px, 3.3vw, 36px);
  font-weight: 700;
  line-height: 1.18;
  margin: 0 0 22px;
  max-width: 28ch;
  text-wrap: balance;
}

h3 { font-size: 20px; font-weight: 600; line-height: 1.32; margin: 0 0 10px; }

/* ── Alternating feature rows ──────────────────────────────── */
.row {
  display: grid;
  grid-template-columns: 1fr 400px;
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
  padding: clamp(40px, 5vw, 56px) 0;
  border-top: 1px solid var(--line);
}
.row:first-of-type { margin-top: 14px; }
.row--flip .row__text { order: 2; }
.row--flip .row__art { order: 1; }
.row__text p { margin: 0 0 12px; font-size: 16px; line-height: 1.62; color: var(--body); }
.row__text p:last-child { margin-bottom: 0; }
.row__text em { font-style: normal; font-weight: 600; color: var(--ink); }
.row__art { display: flex; justify-content: center; }

/* A detail view: the real popover, cropped to the part being described.
   Offsets are in CSS pixels against the 344px-wide screenshot. */
.frame {
  width: 344px;
  border-radius: 12px;
  overflow: hidden;
  background: #0d1a17;
  border: 1px solid rgba(255, 255, 255, 0.09);
  box-shadow: 0 2px 5px rgba(16, 22, 20, 0.07), 0 22px 44px -22px rgba(16, 22, 20, 0.45);
}
.frame img { width: 344px; max-width: none; }
/* Every crop keeps roughly 9px of clear space above and below the block it
   shows, measured off the screenshot rather than set by eye: `height` is
   border-box, so the visible window is `height - 2` starting at `-margin-top`,
   and a window that merely *reaches* the last row reads as a cut edge rather
   than as a crop. Two of these are constrained by what sits next to them in the
   popover and cannot simply be padded:
     - The chart's "2033" annotation starts 2px under the progress bar, so the
       top pad here is 2px and the bottom pad carries the balance.
     - For the same reason the German crop stops after the today's-money line
       instead of including the progress bar: 1px of clearance under the bar is
       what made this one look broken, and the row is about the German text.
   The market chip's cycle glyph moved this block's top from y=17 to y=14, which
   is why the hero offset is -5 and not -8. Everything below y=44 was unmoved, so
   the other three crops did not need touching — but re-measure after any change
   to the popover's layout rather than assuming that again. */
.frame--hero    { height: 125px; }
.frame--hero img    { margin-top: -5px; }
.frame--chart   { height: 225px; }
.frame--chart img   { margin-top: -145px; }
.frame--sliders { height: 154px; }
.frame--sliders img { margin-top: -366px; }
.frame--facts   { height: 69px; }
.frame--facts img   { margin-top: -531px; }

/* ── Cards ─────────────────────────────────────────────────── */
.cards { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.cards--two { gap: 24px; }
.cards article {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 24px;
  min-width: 0;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
/* A real perspective tilt, but only on hover — held flat at rest so the code
   blocks inside are never sitting on a resampled transform layer. */
.cards article:hover {
  transform: perspective(900px) rotateX(1.5deg) translateY(-4px);
  box-shadow: 0 18px 34px -22px rgba(16, 22, 20, 0.4);
}
.cards h3 { font-size: 17.5px; }
.cards p { margin: 0 0 16px; font-size: 15.5px; line-height: 1.6; color: var(--body); }
/* The safety cards used to end with a command block, and the paragraph's bottom
   margin was the gap above it. With the commands moved into one disclosure the
   margin would hang below the last line as dead space. */
.cards p:last-child { margin-bottom: 0; }
.cards--two p { margin: 16px 0 0; }

pre {
  margin: 0;
  max-width: 100%;
  background: var(--alt);
  border: 1px solid var(--line-2);
  border-radius: 9px;
  padding: 12px 14px;
  overflow-x: auto;
}
pre code { font: 12.5px/1.65 var(--mono); color: var(--ink); white-space: pre; }
.dim { color: var(--muted); }

/* ── Proof, then the terminal behind it ────────────────────────
   The reader this section exists for is nervous about a third-party app reading
   their brokerage account, and is not necessarily a developer. So the visible
   layer is one sentence and a tick, and the command that backs it is a click
   away: a wall of monospace naming URLSession and Keychain reads as "this was
   written for someone else", which is the opposite of reassuring.
   The output inside is dark, alone on an otherwise light page — a pale
   "terminal" reads as a quotation of one, and the tick colour needs a dark
   ground to carry. It is 104 characters at its widest and will not fold, so it
   scrolls inside its own box and the page body never does. ── */
.proof {
  display: flex; align-items: flex-start; gap: 11px;
  margin: 26px 0 0;
  font-size: 16px;
}
.proof__tick {
  flex: none;
  width: 22px; height: 22px; margin-top: 1px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: 13px; font-weight: 700; line-height: 22px; text-align: center;
}
.proof b { font-weight: 600; }

.reveal {
  margin: 14px 0 40px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
}
.reveal summary {
  padding: 13px 18px;
  font-size: 15px; font-weight: 600;
  color: var(--accent-d);
  cursor: pointer;
  list-style: none;
}
/* The default triangle sits too high against a 15px line, and Safari draws its
   own marker unless both of these are set. */
.reveal summary::-webkit-details-marker { display: none; }
.reveal summary::after {
  content: '＋';
  float: right;
  font-weight: 400;
  color: var(--muted);
}
.reveal[open] summary::after { content: '－'; }
.reveal summary:hover { color: var(--accent); }
.reveal__body { padding: 0 18px 18px; }
.reveal__body p { margin: 0 0 14px; font-size: 15px; line-height: 1.6; color: var(--body); }
.reveal__body p:last-child { margin: 14px 0 0; }
.reveal__body code {
  font: 13px/1 var(--mono);
  background: var(--alt);
  border: 1px solid var(--line-2);
  border-radius: 5px;
  padding: 2px 5px;
}
.reveal__body pre code { border: 0; background: none; padding: 0; }
.audit__out {
  margin-top: 12px;
  background: #10201a;
  border-color: #1d3a2f;
  color: #d7e4de;
}
.audit__out code { color: #d7e4de; }
.audit__out b { color: #fff; font-weight: 600; }
.audit__out i { color: #4ede9e; font-style: normal; font-weight: 700; }
@media (max-width: 720px) {
  /* Small enough that 104 columns is a long horizontal scroll either way; the
     smaller type keeps the shape of the table legible while it scrolls. */
  .audit__out code { font-size: 11px; }
}

.callouts { display: grid; grid-template-columns: 1fr 1fr; gap: 28px 44px; margin-top: 40px; }
/* Icon and heading share the first row; the paragraph spans beneath both. */
.callouts > div { display: grid; grid-template-columns: auto 1fr; gap: 0 10px; align-items: center; }
/* Both cells are placed explicitly. With only the heading pinned, grid
   auto-placement gave it column 1 and pushed the icon to its right. */
.callouts .ico--inline { grid-column: 1; grid-row: 1; }
.callouts h3 { grid-column: 2; grid-row: 1; margin: 0; font-size: 17px; }
.callouts p { grid-column: 1 / -1; margin: 9px 0 0; font-size: 15.5px; line-height: 1.62; color: var(--body); }
.callouts b { color: var(--ink); font-weight: 600; }

/* ── Setup ─────────────────────────────────────────────────── */
.setup { display: grid; grid-template-columns: 1fr 344px; gap: clamp(36px, 5vw, 64px); align-items: start; }

.steps { list-style: none; counter-reset: s; margin: 0; padding: 0; }
.steps li { position: relative; padding: 0 0 30px 46px; min-width: 0; }
.steps li::before {
  counter-increment: s;
  content: counter(s);
  position: absolute; left: 0; top: 1px;
  width: 27px; height: 27px;
  display: grid; place-items: center;
  font-size: 13px; font-weight: 600;
  color: #fff;
  background: var(--accent);
  border-radius: 50%;
}
.steps li:last-child { padding-bottom: 0; }
.steps h3 { font-size: 18px; }
.steps p { margin: 0 0 14px; font-size: 15.5px; line-height: 1.62; color: var(--body); }

.warn { border-left: 2px solid #d9a441; padding-left: 14px; }
.warn b { color: var(--ink); font-weight: 600; }

.cmd {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  background: var(--alt);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 9px 9px 9px 14px;
  min-width: 0;
}
.cmd code { font: 13px/1.7 var(--mono); color: var(--ink); overflow-x: auto; min-width: 0; }
.cmd--multi { align-items: flex-end; }
/* The hero is centred and its wrap is wide, so the shared .cmd block — which fills
   its container inside the setup steps — would run most of the page width for a
   one-line command. Shrink it to the command and centre it. */
.cmd--hero { width: max-content; max-width: 100%; margin: 0 auto 14px; }

.copy {
  flex: none;
  font: 500 12.5px/1 var(--sans);
  color: var(--body);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 7px;
  padding: 7px 12px;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.copy:hover { color: var(--accent-d); border-color: rgba(14, 158, 107, 0.45); }
.copy[data-done] { color: var(--accent-d); border-color: rgba(14, 158, 107, 0.45); }

.shot { margin: 0; }
.shot img { width: 344px; margin-inline: auto; border-radius: 12px; border: 1px solid var(--line); box-shadow: 0 20px 40px -22px rgba(16, 22, 20, 0.45); }
.shot figcaption { margin-top: 14px; text-align: center; font-size: 13.5px; color: var(--muted); }

.build { margin-top: 48px; padding-top: 32px; border-top: 1px solid var(--line); }
.build h3 { font-size: 18px; }
.build p { margin: 0 0 14px; font-size: 15.5px; color: var(--body); }

/* ── Math ──────────────────────────────────────────────────── */
.aside {
  margin: 36px 0 24px;
  padding-left: 18px;
  border-left: 2px solid var(--accent);
  font-size: 16px;
  color: var(--body);
  max-width: 72ch;
}
.caveat {
  margin: 0;
  padding: 18px 20px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 12px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--body);
  max-width: 76ch;
}
.caveat b { color: var(--ink); font-weight: 600; }

/* ── Close ─────────────────────────────────────────────────── */
.close { padding: clamp(72px, 9vw, 108px) 0; text-align: center; border-top: 1px solid var(--line); }
.close img { margin: 0 auto 22px; border-radius: 14px; }
.close h2 { margin-inline: auto; margin-bottom: 28px; max-width: 20ch; }

/* ── Footer ────────────────────────────────────────────────── */
.foot { padding: 44px 0 56px; background: var(--alt); border-top: 1px solid var(--line); }
.foot__links { display: flex; flex-wrap: wrap; gap: 10px 24px; margin-bottom: 22px; }
.foot__links a { font-size: 14.5px; color: var(--body); text-decoration: none; }
.foot__links a:hover { color: var(--ink); }
.foot p { margin: 0 0 12px; font-size: 13px; line-height: 1.66; color: var(--muted); max-width: 82ch; }
.foot__c { margin-bottom: 0 !important; }

/* ── Responsive ────────────────────────────────────────────── */
@media (max-width: 1000px) {
  .row { grid-template-columns: 1fr; gap: 28px; }
  .row--flip .row__text, .row--flip .row__art { order: 0; }
  .setup { grid-template-columns: 1fr; }
  .shot { margin-inline: auto; }
  .specs ul { grid-template-columns: repeat(3, 1fr); gap: 18px; }
}

@media (max-width: 760px) {
  .nav__links { display: none; }
  .nav__in { gap: 16px; }
  .nav__brand { margin-right: auto; }
  .cards, .cards--two, .callouts { grid-template-columns: 1fr; }
  .specs ul { grid-template-columns: repeat(2, 1fr); }
  .actions .btn { width: 100%; }
  .cmd { flex-wrap: wrap; }
  /* Too narrow to crop to a screen shape: show the whole popover instead. */
  .stage { aspect-ratio: auto; border-width: 5px; border-radius: 16px; }
  .stage__bar { position: static; }
  .stage__pop { position: static; margin: 16px auto 20px; }
  .stage__items { gap: 10px; padding-right: 12px; }
  /* Nothing is a screen any more once the popover is stacked in flow, and a
     floating Dock with no desktop under it reads as a stray widget. */
  .stage__dock { display: none; }
  /* Same reason: with the popover in flow there is no empty left third to float
     over, so the pill joins the flow under it and reads as a caption. This rides
     the existing 760px breakpoint rather than adding one of its own — the pill
     has to move at exactly the width the stage stops being a screen. */
  .playpill {
    position: static; transform: none;
    margin: 0 auto 18px;
    display: flex; width: fit-content;
  }
  .playpill:hover { transform: scale(1.03); }
}

@media (max-width: 560px) {
  .filmbox { width: 100vw; border-radius: 0; }
  .filmbox__video { border-radius: 0; }
}

@media (max-width: 400px) {
  .frame, .frame img, .stage__pop, .shot img { width: 100%; }
  .frame img { width: 344px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
}
