:root {
  --bg: #faf9f7;
  --bg-raise: #ffffff;
  --bg-card: #ffffff;
  --line: #e6e3dc;
  --text: #1a1d23;
  --text-dim: #555b65;
  --text-faint: #868d98;
  --accent: #2b5ce6;
  --accent-dim: #2b5ce614;
  --good: #15803d;
  /* The dark surfaces that remain: code, the prompt, and the screenshots'
     own pixels. On a light page they read as windows into the product. */
  --ink: #0d1117;
  --ink-line: #2a313c;
  --ink-text: #e6e8eb;
  --ink-dim: #9aa3af;
  --ink-faint: #6e7681;
  /* A raised surface on a light page is a whisper of shadow, not a glow. */
  --lift: 0 1px 2px rgba(26, 21, 10, 0.04), 0 2px 8px rgba(26, 21, 10, 0.04);
  /* Screenshots get real depth: they are the heaviest objects on the page. */
  --shot-shadow: 0 2px 6px rgba(22, 18, 10, 0.08), 0 28px 60px -16px rgba(22, 18, 10, 0.28);
  --mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; color-scheme: light; }
pre, .snippet {
  scrollbar-width: thin;
  scrollbar-color: var(--ink-line) transparent;
}
pre::-webkit-scrollbar, .snippet::-webkit-scrollbar { height: 6px; }
pre::-webkit-scrollbar-thumb, .snippet::-webkit-scrollbar-thumb {
  background: var(--ink-line); border-radius: 3px;
}
body {
  background: var(--bg);
  color: var(--text);
  font: 16px/1.6 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}
::selection { background: var(--accent-dim); }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* `max()` and not a plain 24px: landscape on a notched phone puts the notch
   over the left gutter, and the header sits right under it. */
.wrap {
  max-width: 1020px; margin: 0 auto;
  padding-left: max(24px, env(safe-area-inset-left));
  padding-right: max(24px, env(safe-area-inset-right));
}

/* ---- header ----
   The one place on this page where glass is honest: real content scrolls
   under it, so there is something to refract. Opaque by default, translucent
   only where backdrop-filter exists (Chromium 76+, so never on an old TV). */
.header-bar {
  position: sticky; top: 0; z-index: 20;
  background: var(--bg);
  border-bottom: 1px solid transparent;
  transition: border-color 200ms ease;
}
.header-bar.scrolled { border-bottom-color: var(--line); }
/* Out of flow, 1px: a zero-area target is not reliably observable. */
.scroll-sentinel { position: absolute; top: 0; width: 1px; height: 1px; }
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .header-bar {
    background: rgba(250, 249, 247, 0.78);
    -webkit-backdrop-filter: blur(14px) saturate(1.6);
    backdrop-filter: blur(14px) saturate(1.6);
  }
}
header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 22px 0;
}
/* Anchor targets clear the sticky bar instead of hiding under it. */
section[id] { scroll-margin-top: 88px; }
.brand { font-weight: 700; font-size: 18px; letter-spacing: -0.02em; color: var(--text); }
.brand span { color: var(--accent); }
nav a { color: var(--text-dim); font-size: 14px; margin-left: 24px; white-space: nowrap; }
nav a:hover { color: var(--text); text-decoration: none; }

/* ---- hero ---- */
.hero { padding: 64px 0 40px; position: relative; }
.hero::before {
  /* One quiet tint, not a light show. Sized in pixels and centred, so the
     box crops it the same way the screen would: nothing bleeds sideways. */
  content: ""; position: absolute; inset: -120px 0 auto;
  height: 420px; pointer-events: none;
  background: radial-gradient(600px 260px at 50% 0%, #2b5ce611, transparent 70%);
}
h1 {
  font-size: 48px;
  font-size: clamp(34px, 6vw, 58px);
  line-height: 1.08;
  letter-spacing: -0.03em;
  font-weight: 750;
  max-width: 17ch;
}
.hero p.sub {
  margin: 22px 0 0;
  max-width: 54ch;
  font-size: 18px;
  color: var(--text-dim);
}
.hero p.sub strong { color: var(--text); font-weight: 600; }

/* Hero actions: margins, not flex gap, for the same TV browsers the
   hero-code row minds. */
.hero-actions { margin-top: 32px; display: flex; flex-wrap: wrap; }
.hero-actions .btn { margin: 0 12px 12px 0; }
.btn.ghost {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--line);
  padding: 11px 21px; /* the border eats the pixel the filled button has */
}
.btn.ghost:hover { border-color: var(--text-faint); filter: none; }
/* Both margins, because on a phone the two buttons are two rows: the
   horizontal one is the gap between them, the vertical one is the gap the
   wrapped row needs. `.cta-actions` carries the rest of the distance to the
   text above, so the two together stay the 14px this block was drawn with. */
.cta-actions .btn { margin: 12px 6px 0; }

/* ---- screenshots ----
   Intrinsic width/height are on every <img>, so the page never reflows when
   one lands; the dark placeholder is the colour the app itself paints. */
.shot {
  display: block; width: 100%; height: auto;
  border-radius: 14px;
  border: 1px solid rgba(22, 18, 10, 0.1);
  box-shadow: var(--shot-shadow);
  background: #101015;
}
.hero-shot { margin: 56px 0 8px; }
figcaption {
  margin-top: 14px;
  font-size: 13.5px;
  color: var(--text-faint);
  max-width: 64ch;
}
.hero-shot figcaption { text-align: center; margin-left: auto; margin-right: auto; }

/* ---- feature blocks (the three layers) ----
   Text beside image on a desktop, stacked on anything narrow. `.flip` only
   swaps the visual order; in the DOM the text always comes first, which is
   also the order the stacked layout reads in. */
.feature {
  margin-top: 64px;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 40px;
  align-items: center;
}
.feature-text h3 {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.2;
}
.feature-text p { margin-top: 12px; color: var(--text-dim); }
.feature-text .feature-links { margin-top: 14px; font-size: 15px; }
.feature.flip .feature-text { order: 2; }
.feature-shot { min-width: 0; }
/* Two phones share the image column; the frame radius follows the device. */
.phone-row { display: flex; justify-content: center; }
.phone-row .phone {
  width: min(44%, 250px);
  border-radius: 22px;
}
.phone-row .phone + .phone { margin-left: 20px; }
/* The two-column feature dies long before the page's one phone breakpoint:
   at ~880px the text column is down to unreadable widths. This is the one
   layout with its own threshold, and this rule is all of it. */
@media (max-width: 880px) {
  .feature { grid-template-columns: 1fr; gap: 24px; margin-top: 52px; }
  .feature.flip .feature-text { order: 0; }
}

/* Cards that talk to people, not to programmers: same card, plain type. */
.card.plain h3 {
  font-family: inherit;
  font-size: 16.5px;
  font-weight: 650;
  color: var(--text);
  letter-spacing: -0.01em;
}
.card.plain p a { overflow-wrap: anywhere; }
.badge {
  display: inline-block;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-dim);
  border-radius: 999px;
  padding: 4px 10px;
  margin-bottom: 12px;
}

/* The AI prompt: the one block on this page a non-programmer copies. Dark on
   purpose: it is the thing you paste into a terminal-coloured chat box. */
.prompt {
  margin-top: 34px;
  border: 1px solid var(--ink-line);
  border-radius: 12px;
  background: var(--ink);
  box-shadow: var(--lift);
  padding: 18px 20px;
}
.prompt pre {
  font-family: var(--mono);
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink-text);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.prompt .copy-btn {
  margin-top: 14px;
  color: var(--ink-dim);
  border-color: var(--ink-line);
}
.prompt .copy-btn:hover { color: var(--ink-text); border-color: var(--ink-faint); }

.hero-code {
  margin-top: 34px;
  display: inline-flex; align-items: center;
  background: var(--ink);
  border: 1px solid var(--ink-line);
  border-radius: 10px;
  padding: 14px 18px;
  font-family: var(--mono);
  font-size: 14.5px;
  color: var(--ink-text);
  box-shadow: var(--lift);
  max-width: 100%;
}
/* Only the code scrolls. The button used to sit inside the scroll area, so
   on a phone it was off-screen, exactly where the snippet matters most.
   Margin, not flex gap: gap in flexbox lands in Chromium 84, TVs are older. */
.hero-code .snippet {
  white-space: nowrap;
  overflow-x: auto;
  min-width: 0;
  margin-right: 14px;
}
.hero-code .tag { color: var(--ink-faint); }
.hero-code .attr { color: #79b8ff; }
.hero-code .val { color: #56d364; }
.hero-code .copy-btn { color: var(--ink-dim); border-color: var(--ink-line); }
.hero-code .copy-btn:hover { color: var(--ink-text); border-color: var(--ink-faint); }
.copy-btn {
  font: 12px/1 system-ui, sans-serif;
  color: var(--text-dim);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 7px 10px;
  flex: none;
  cursor: pointer;
  transition: transform 140ms var(--ease-out), color 140ms ease, border-color 140ms ease;
}
.copy-btn:hover { color: var(--text); border-color: var(--text-faint); }
.copy-btn:active { transform: scale(0.96); }

/* ---- live panel ---- */
.live {
  margin: 46px 0 0;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--bg-card);
  box-shadow: var(--lift);
  padding: 20px 22px;
}
.live-head { display: flex; align-items: flex-start; }
.dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--text-faint);
  flex: none;
  margin: 8px 14px 0 0;
  transition: background 300ms ease;
}
.live[data-state="hosted"] .dot { background: var(--good); box-shadow: 0 0 10px #15803d55; }
.live[data-state="waiting"] .dot { animation: pulse 1.4s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: 0.35; } }
.live b { font-weight: 600; color: var(--text); }
.live .msg { font-size: 15px; color: var(--text-dim); }
.live .msg code { font-family: var(--mono); font-size: 13px; color: var(--text); }

/* The readout: what the boot script actually found, in both states. */
.readout {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}
.readout .row { display: flex; align-items: baseline; padding: 4px 0; }
.readout dt {
  width: 132px; flex: none;
  font-family: var(--mono); font-size: 12px;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-faint);
}
.readout dd { font-family: var(--mono); font-size: 13.5px; color: var(--text-dim); }
.readout .val { color: var(--text); }
.tag-chip {
  display: inline-block;
  font-family: var(--mono); font-size: 12.5px;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 3px 8px;
  margin: 0 6px 4px 0;
}
.live[data-state="hosted"] .readout .cap { color: var(--accent); }

/* The one state change on this page worth animating: the answer fades in
   instead of teleporting over the "Checking…" line. */
.live .msg, .live .readout { transition: opacity 200ms ease; }
.live.swap .msg, .live.swap .readout { opacity: 0; }

/* ---- sections ---- */
section { padding: 72px 0 0; }
.kicker {
  font-family: var(--mono);
  font-size: 12.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}
h2 {
  font-size: 30px;
  font-size: clamp(24px, 3.6vw, 34px);
  line-height: 1.15;
  letter-spacing: -0.02em;
  font-weight: 700;
  margin-top: 10px;
  max-width: 24ch;
}
.lede { margin-top: 14px; max-width: 58ch; color: var(--text-dim); }

/* powers grid
   The track floor is what a card needs, but never more than the column it
   sits in: below ~326px the fixed 290px is wider than the page and the cards
   hang over the edge. Declared twice like the h1 size above, so a browser
   without `min()` keeps the plain floor it always had. Same for .steps. */
.grid {
  margin-top: 36px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  grid-template-columns: repeat(auto-fill, minmax(min(290px, 100%), 1fr));
  gap: 14px;
}
.card {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--bg-card);
  box-shadow: var(--lift);
  padding: 20px;
  transition: border-color 180ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .card:hover { border-color: #d4cfc5; }
}
.card.wide { grid-column: 1 / -1; }
.card h3 {
  font-family: var(--mono);
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--accent);
  letter-spacing: -0.01em;
}
.card p { margin-top: 8px; font-size: 14.5px; color: var(--text-dim); }
/* Code lines are hand broken to fit, and a narrow window breaks them again
   rather than scrolling sideways. `anywhere` because a url or a path has no
   space to break on; on a TV browser too old for it, `overflow-x` is still
   the fallback it always was. Nothing wraps at a width where the line fits,
   so this is invisible on a desktop. */
.card pre {
  margin-top: 14px;
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-dim);
  background: var(--ink);
  border: 1px solid var(--ink-line);
  border-radius: 8px;
  padding: 12px 14px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  overflow-x: auto;
}
.card pre .c { color: var(--ink-faint); }
.card pre .k { color: var(--ink-text); }

/* how it works */
.steps {
  margin-top: 36px; display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
}
.step {
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--bg-card); padding: 20px;
  box-shadow: var(--lift);
}
.step .n {
  font-family: var(--mono); font-size: 13px; color: var(--accent);
}
.step h3 { margin-top: 6px; font-size: 16px; font-weight: 650; line-height: 1.3; letter-spacing: -0.01em; }
.step p { margin-top: 6px; font-size: 14.5px; color: var(--text-dim); }
.step pre {
  margin-top: 12px; font-family: var(--mono); font-size: 12.5px; line-height: 1.55;
  color: var(--ink-dim); background: var(--ink);
  border: 1px solid var(--ink-line); border-radius: 8px; padding: 12px 14px;
  white-space: pre-wrap; overflow-wrap: anywhere; overflow-x: auto;
}
.step pre .k { color: var(--ink-text); }

/* platforms */
.platforms { margin-top: 24px; display: flex; flex-wrap: wrap; }
.chip {
  border: 1px solid var(--line); border-radius: 999px;
  padding: 8px 16px; font-size: 14px; color: var(--text-dim);
  background: var(--bg-card);
  margin: 0 10px 10px 0;
}
.chip b { color: var(--text); font-weight: 600; }

/* A statement of fact about the rollout, not a banner. */
.status {
  margin-top: 18px;
  border-left: 2px solid var(--accent);
  padding: 2px 0 2px 14px;
  color: var(--text-dim);
  font-size: 15px;
  max-width: 64ch;
}
.cta {
  margin: 64px 0 0;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: linear-gradient(180deg, var(--bg-raise), var(--bg));
  box-shadow: var(--lift);
  padding: 36px;
  text-align: center;
}
.cta h2 { margin: 0 auto; }
.cta p { margin: 12px auto 0; color: var(--text-dim); max-width: 50ch; }
/* The rest of the air between the pitch and the buttons: the buttons bring
   12px of it themselves, because on a phone they are two rows. */
.cta-actions { margin-top: 2px; }
.btn {
  display: inline-block;
  margin-top: 22px;
  background: var(--accent);
  color: #ffffff;
  font-weight: 650;
  font-size: 15px;
  border-radius: 9px;
  padding: 12px 22px;
  transition: transform 140ms var(--ease-out), filter 140ms ease;
}
.btn:hover { text-decoration: none; filter: brightness(1.08); }
.btn:active { transform: scale(0.97); }

footer {
  margin-top: 72px;
  border-top: 1px solid var(--line);
  padding: 28px 0 44px;
  display: flex; flex-wrap: wrap; gap: 12px 28px;
  justify-content: space-between;
  color: var(--text-faint);
  font-size: 13.5px;
}
footer code { font-family: var(--mono); color: var(--text-dim); }

/* ---- scroll reveal ----
   Decorative and strictly progressive: content is VISIBLE by default and
   only hidden when JS has marked the document (html.js); a TV browser
   where anything fails still shows the whole page. */
html.js .reveal {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 500ms var(--ease-out), transform 500ms var(--ease-out);
  transition-delay: var(--d, 0ms);
}
html.js .reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html.js .reveal { transform: none; transition: opacity 300ms ease; }
  .live[data-state="waiting"] .dot { animation: none; }
}

/* ---- focus ----
   On a TV the D-pad is the only way around this page. Browsers without
   :focus-visible drop the second rule and simply keep the ring on every
   focus. */
a:focus, .btn:focus, .copy-btn:focus {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
a:focus:not(:focus-visible),
.btn:focus:not(:focus-visible),
.copy-btn:focus:not(:focus-visible) { outline: none; }
/* ---- the addon index ----
   Its own page, the same shell. A row is a card like the ones above, laid out
   as a list because a list is what it is. */
.page { padding: 56px 0 0; }
.page h1 { max-width: 20ch; }
.addons {
  list-style: none; padding: 0; margin: 36px 0 0;
  display: grid; gap: 12px;
}
.addon {
  display: flex; gap: 16px; align-items: flex-start;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--bg-card);
  box-shadow: var(--lift);
  padding: 16px 18px;
}
.addon .icon {
  width: 40px; height: 40px; border-radius: 8px; flex: none;
  background: var(--bg); overflow: hidden;
}
.addon .icon img { display: block; width: 100%; height: 100%; object-fit: cover; }
.addon h3 { font-size: 15px; font-weight: 650; letter-spacing: -0.01em; }
.addon p { margin-top: 4px; color: var(--text-dim); font-size: 14px; }
.addon code {
  display: inline-block; margin-top: 8px;
  font-family: var(--mono); font-size: 12.5px; color: var(--text-faint);
}
.note { margin-top: 28px; color: var(--text-dim); font-size: 14px; }

/* ---- phones ----
   One breakpoint for the whole page (the feature grid above is the single
   exception and says why). 560px is where the hero snippet stops fitting
   next to its Copy button, and a second breakpoint somewhere else would only
   be a second answer to the same question. Everything that exists for small
   screens is here, not scattered over the components above. */
@media (max-width: 560px) {
  .wrap {
    padding-left: max(18px, env(safe-area-inset-left));
    padding-right: max(18px, env(safe-area-inset-right));
  }
  header { padding: 16px 0; }
  section[id] { scroll-margin-top: 74px; }
  /* Brand plus three links is exactly as wide as a 360px phone, so at that
     width the last link dropped to a second row and the sticky bar grew to
     110px: a third of the screen, and the anchor offset below was suddenly
     wrong. Smaller type and tighter spacing keep the header one row. */
  nav a { margin-left: 16px; font-size: 13px; }

  /* Vertical air that reads as rhythm on a desktop reads as scrolling
     through nothing on a phone. */
  .hero { padding: 40px 0 24px; }
  section { padding: 52px 0 0; }
  .cta { margin-top: 44px; padding: 28px 20px; }
  footer { margin-top: 52px; }

  .hero-shot { margin-top: 40px; }
  .shot { border-radius: 10px; }
  .phone-row .phone { border-radius: 16px; }
  .phone-row .phone + .phone { margin-left: 14px; }

  /* The snippet stays ONE line: a script tag broken mid-URL reads as three
     lines of noise, and the Copy button exists precisely so nobody has to
     select the text by hand. It scrolls sideways instead, and the button
     stacks below at a size a thumb hits. Stacked with a margin, not a flex
     gap, for the same reason the row above uses one. */
  .hero-code { display: flex; flex-direction: column; align-items: stretch; padding: 14px 16px; }
  .hero-code .snippet { font-size: 13px; margin: 0 0 12px; }
  .copy-btn { padding: 12px; font-size: 13px; }

  .live { padding: 18px; }
  .readout .row { display: block; padding: 8px 0 4px; }
  .readout dt { width: auto; margin-bottom: 6px; }

  .addon { padding: 14px; }
  .addon .icon { width: 32px; height: 32px; }
}

/* ---- touch ----
   A 16px line of text is a 16px target. On a pointer that is a fingertip the
   links get the height a finger needs, without moving anything on a mouse. */
@media (pointer: coarse) {
  .brand, nav a, footer a { display: inline-block; padding: 12px 0; }
  header { padding: 8px 0; }
  footer { padding-top: 16px; }
  .copy-btn { min-height: 44px; }
  .btn { padding: 15px 24px; }
}
