@import "https://assets.elements.dev/assets/app/shared/styles/page.1e55b09d07a60454.css";

.home-page { color: var(--ink); }

.home-wrap {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  position: relative;
}

.home-main { flex: 1; }

/* ---- hero ---- */

.hero {
  /* Top air recreates Feed's: 4rem from <PageChrome>.page-chrome-main
     (var(--space-16)) + 2rem from the canonical h1 margin-top = 6rem
     total. /home doesn't use PageChrome, so we put the combined
     value (var(--space-24)) on .hero directly. The result is that the
     top line of the hero headline sits at the same Y as the page title
     on /feed, /learn, /install, so clicking between them doesn't jump. */
  padding: var(--space-24) 0 0;
}

.hero-title {
  /* Logo mark + wordmark as one lockup row. gap + align in em so both
     track the clamped title size. */
  display: flex;
  align-items: center;
  gap: 0.14em;
  font-family: var(--font-sans);
  /* The tagline is the heaviest heading on the page: base sits at bold
     and the glimmer phrase lifts to black, so it out-weighs the section
     headers below it. */
  font-weight: var(--weight-bold);
  /* Display scale straight off the type system: --text-6xl (72px)
     floor on phones up to the --text-8xl (128px) cap on wide screens,
     10vw riding between. */
  font-size: clamp(var(--text-6xl), 10vw, var(--text-8xl));
  letter-spacing: var(--tracking-tighter);
  line-height: var(--leading-none);
  /* The intro paragraph carries the breathing room down to the CTAs,
     but at desktop display sizes the title needs real clearance above
     the paragraph or the pair reads crammed. */
  margin: 0 0 var(--space-6);
}

/* Terminal card in the hero: shows the getting-started command flow.
   Deep ink card so it reads as a real terminal on the white page and
   holds up in dark mode. */
.hero-terminal {
  /* Full width of the content column so the right edge aligns with the
     headline's right edge. */
  width: 100%;
  margin: 0 0 var(--space-8);
  border-radius: var(--radius-xl);
  overflow: hidden;
  background: #0d1b28;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 24px 48px -24px rgba(16, 44, 66, 0.5);
}
.term-bar {
  display: flex;
  gap: 6px;
  padding: 10px 14px;
  background: rgba(255, 255, 255, 0.04);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.term-dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
}
.term-body {
  margin: 0;
  padding: 16px 18px;
  font-family: var(--font-mono);
  font-size: 14px;
  line-height: 1.75;
  color: #c6d3de;
  overflow-x: auto;
  /* Render like a real TUI: no ligatures, so => stays => and !== stays !==. */
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
}
.term-body .line { white-space: pre; }
/* The global ::selection sets color: var(--ink), which is dark ink. On this
   card the surface is fixed dark in both themes, so a selected command lost
   its text entirely. The .terminal component in @elements/style solves this
   for itself; the hero card is hand-rolled and never inherited that. Keep
   the glyph color and tint the wash instead. */
.hero-terminal ::selection {
  background: rgba(255, 255, 255, 0.22);
  color: inherit;
}
.term-body .line.gap { height: 0.9em; }

.term-body .p { color: #6d7d8b; }
.term-body .c { color: #f2f7fb; font-weight: var(--weight-medium); }
.term-body .ok { color: #5fd0a0; font-weight: var(--weight-bold); }
.term-body .lbl { color: #e6edf3; font-weight: var(--weight-bold); display: inline-block; width: 9ch; }
/* Package rows in the install demo. The compiler folds runs of spaces in a
   text node, so the columns cannot be padded with literal spaces the way the
   real terminal output is. Same fix as .lbl above: give the cell a width. */
.term-body .pkg  { display: inline-block; width: 18ch; padding-left: 2ch; }
.term-body .pkgv { display: inline-block; width: 10ch; }
.term-body .dim { color: #8b98a5; }
.term-body .link { color: var(--accent); }
.term-body .arrow { color: var(--accent); }

/* Startup animation. Command lines type out one character at a time
   (a steps() sweep over an overflow-hidden inline-block), then the
   fast-boot output snaps in as a block to sell the 22µs startup. */
.term-body.animate .cmd { opacity: 0; }
.term-body.animate .cmd .c {
  display: inline-block;
  overflow: hidden;
  white-space: nowrap;
  vertical-align: bottom;
  width: 0;
}
/* Three commands type in sequence, each starting 100ms after the one
   above finishes. Durations are per-command because steps() must match
   the exact character count:
     c1 "elements create app" 19ch — 150ms  →  630ms
     c2 "cd app"               6ch — 730ms  →  910ms
     c3 "elements start"      14ch — 1010ms → 1390ms
   Changing a command's text means changing its char count in BOTH the
   steps() and the matching @keyframes width. */
.term-body.animate .c1 { animation: term-reveal 1ms linear 150ms forwards; }
.term-body.animate .c1 .c { animation: type-37 900ms steps(37) 150ms forwards; }
@keyframes term-reveal { to { opacity: 1; } }
/* +1ch buffer past the exact character count so the final glyph never
   clips when the mono font's metrics round narrow (seen on mobile).
   The extra width is trailing blank on the dark card, so it's invisible. */
@keyframes type-37 { to { width: 38ch; } }

/* The agent's steps land one at a time after the prompt finishes typing
   (150 + 900 = 1050ms), each a quick fade. The gap before the failing build
   and again before the green one is deliberate: the pause is where a reader
   registers that it broke and then fixed itself. */
.term-body.animate .s1,
.term-body.animate .s2,
.term-body.animate .s3,
.term-body.animate .s4,
.term-body.animate .s5,
.term-body.animate .s6 {
  opacity: 0;
  transform: translateY(3px);
}
.term-body.animate .s1 { animation: term-line 150ms ease-out 1150ms forwards; }
.term-body.animate .s2 { animation: term-line 150ms ease-out 1400ms forwards; }
.term-body.animate .s3 { animation: term-line 150ms ease-out 1650ms forwards; }
.term-body.animate .s4 { animation: term-line 150ms ease-out 2000ms forwards; }
.term-body.animate .s5 { animation: term-line 150ms ease-out 2500ms forwards; }
.term-body.animate .s6 { animation: term-line 150ms ease-out 2800ms forwards; }
@keyframes term-line {
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .term-body.animate .cmd,
  .term-body.animate .line:not(.cmd) {
    opacity: 1;
    transform: none;
    animation: none;
  }
  .term-body.animate .cmd .c { width: auto; }
}

/* Sentence headline variant: block layout, smaller than the wordmark
   scale, with the lead words in ink and only "elements" accented. */
.hero-title.is-sentence {
  display: block;
  /* Sized down from the 5xl→7xl range the short "for web apps."
     headline used. This sentence is longer, and at 7xl it ran to four
     lines and pushed the feed off the first screen. */
  /* 4rem, not 4.25: at 68px the sentence broke to three lines in the 756px
     column and stranded "apps with AI." on its own. 64px is the largest size
     that holds it to two at every desktop width. */
  font-size: clamp(var(--text-4xl), 5.5vw, 4rem);
  letter-spacing: var(--tracking-tight);
  /* The sentence ends on "with AI", two characters and a period, which the
     greedy algorithm drops on a line of its own at most desktop widths.
     balance evens the lines out instead, so the break lands at a phrase
     rather than stranding the last word. It only applies to short blocks,
     which a headline is. */
  text-wrap: balance;
  line-height: 1.1;
  margin-bottom: var(--space-6);
}

/* The scope claim inside the headline, lifted into accent and italic so the
   phrase that says how much Elements covers reads before the sentence around
   it. Italic on its own is too quiet at this weight; the color carries it. */
.hero-title .hero-accent {
  color: var(--accent);
  font-style: italic;
}
.hero-para {
  font-size: var(--text-md);
  line-height: var(--leading-relaxed);
  color: var(--ink-soft);
  /* Fills the content column so its edges align with the headline and
     terminal above/below. A single short intro paragraph reads fine at
     the column width; the ~66ch readability cap is for long-form body
     copy, not a three-sentence hero blurb. */
  max-width: none;
  margin: 0 0 var(--space-8);
}

/* The glimmering blue "elements" in the hero tagline. On load it does
   a one-time bright sweep (wave), then settles into a slow, subtle
   infinite glimmer — same treatment as the generator boilerplate's
   home page. The gradient runs accent → deep → accent so the sweep
   reads as a highlight travelling across the word. */

@keyframes hero-wave {
  from { background-position: 100% 50%; }
  to   { background-position:   0% 50%; }
}

@keyframes hero-glimmer {
  0%   { background-position:  0% 50%; }
  50%  { background-position: 30% 50%; }
  100% { background-position:  0% 50%; }
}

/* ---- mobile ---- */

@media (max-width: 700px) {
  /* Half the canonical 48px above-h1 air the other pages carry. Home
     gives that air up on phones to buy the terminal room: at 48px the
     paste block's last two commands sat below the fold on a 844px
     iPhone viewport, and the point of the block is that a visitor can
     read it without scrolling. */
  .hero { padding: var(--space-10) 0 0; }
  .hero-title {
    max-width: none;
    /* Small gap to the subtitle on mobile. */
    margin-bottom: var(--space-3);
  }
  /* The 2.5rem cap was here to keep the home feed preview above the fold.
     That preview is gone, so the headline no longer has to make room for
     anything and the extra line it costs is free. */
  .hero-title.is-sentence {
    font-size: clamp(2.25rem, 12vw, 3.25rem);
  }
}

/* ---- landscape phones ---- */

/* Phones in landscape exceed the 700px max-width above (iPhone 14
   Pro = 844px wide rotated) but the viewport height collapses to
   ~390px. The desktop hero padding of 8rem 0 6rem leaves only a
   thin strip of content visible above the fold. Compress to phone-
   like padding when the viewport is short and wide. */
@media (orientation: landscape) and (max-height: 500px) {
  .hero { padding: var(--space-10) 0 0; }
  .hero-title { max-width: none; margin-bottom: var(--space-2); }
}

/* ---- reduced motion ---- */

/* CTA framed as a full-width band — a distinct action strip spanning the
   viewport so the CTAs aren't lost. Buttons sit in the content column,
   left-aligned, Introducing then Install so the eye lands on Install. */
/* Buttons stand alone under the terminal — no band framing. They sit in
   the hero flow, left-aligned like the copy and terminal above; the blue
   Install carries the emphasis on its own. The terminal's space-8 bottom
   margin sets the gap above; margin-bottom sets the gap down to the feed. */
.cta-band {
  /* Extra air above the button so it doesn't crowd the terminal box.
     Uses padding, not margin: a margin here just collapses into the
     terminal's space-8 bottom margin (larger wins) and does nothing,
     so padding is what actually adds to the gap. 32px + 32px = 64px. */
  padding-top: var(--space-8);
  /* Air under the button before the band closes. The button is the last
     thing on the page now, so this is the bottom of the hero, not a gap to
     whatever came next. */
  margin-bottom: var(--space-8);
}
.cta-band-inner {
  /* flex + fit-content keeps the button shrink-wrapped and left-aligned
     rather than stretching to the container. */
  display: flex;
  width: fit-content;
  align-items: center;
  gap: var(--space-3);
}
.cta-band-btn {
  font-size: var(--text-lg);
  padding: 0.9rem 1.9rem;
  border-radius: var(--radius-xl);
  /* No drop shadow. Stacked on mobile it fell straight onto the outline
     button below and ate its top border, and the lift reads fine without
     it. */
  transition: transform 140ms ease;
  white-space: nowrap;
}
.cta-band-btn:hover {
  transform: translateY(-1px);
}
/* Secondary "Watch the intro" — same size/shape as the primary but the
   base outlined button chrome (transparent fill, rule border), so it
   reads as the quieter of the two actions. */
.start-head .start-label { margin-bottom: 0; }
/* Watch link on the terminal's title bar, opposite COPY. Mono and dim
   so it reads as terminal chrome, not as a second CTA competing with
   Install below. */
@media (max-width: 700px) {
  .cta-band { margin-bottom: var(--space-10); }
  .cta-band-inner {
    /* Stack. Side by side, the two nowrap buttons are wider than a phone
       and pushed the whole page into horizontal scroll. */
    flex-direction: column;
    align-items: stretch;
    width: 100%;
    gap: var(--space-3);
  }
  .cta-band-btn,
  .cta-band-watch {
    width: 100%;
    justify-content: center;
    text-align: center;
  }
  /* Keep the label on one line. Wrapping put "(1 min)" on a row of its
     own, orphaned to the right, which read as broken. Smaller type and
     tighter side padding buy the width instead. */
  }

/* ─── Marketing sections (below the hero) ───────────────────────────
   The page makes one argument in three numbered acts, and each act is
   a category masthead followed by feature children. A child is copy
   stacked over a dark terminal or code card: the claim, then the thing
   itself. Lifted from the pre-v1 mockup at app/pages/mockups/home,
   which is where these were designed. */

/* Stacked, not side by side: the pitch reads first, then the demo card
   gets the full content width below it. Section cards are static (no
   typing) so they don't compete with the hero's animation. */
.split-demo .hero-terminal { margin-bottom: 0; }

/* Child headline: clearly smaller than the category title above it,
   and semibold rather than bold. */

/* Two cards side by side for the before/after: what an agent writes
   with nothing under it, and what it writes on Elements. Stacks on
   narrow screens, where the left card reads first and still lands as
   the setup. */

/* ---- terminal extras used by the section cards ---- */

.term-body .line.ind { padding-left: 1.6ch; }

/* One diagnostic: the error number in its own column, the whole body in
   the next. Matches the errors list in the build's TUI, where the number
   is column one and everything about the error (path, message, code
   frame, call stack, tags) goes in column two, so the body reads as a
   block hanging off its number instead of running back under it. */
.term-body .ediag {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 1ch;
  padding-left: 1.6ch;
}
.term-body .ediag .enum { text-align: right; }
.term-body .ediag .ebody { min-width: 0; }

/* The code frame inside a body: a right-aligned line-number gutter and
   the source beside it, the same two-column shape one level down. */
.term-body .snip {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 1ch;
}
.term-body .snip .ln { text-align: right; color: #525964; }
/* The line the error sits on gets a red number, as it does in the TUI. */
.term-body .snip .ln.e { color: #f7768e; }
.term-body .snip .sl { white-space: pre; }
.term-body .err { color: #f7768e; font-weight: var(--weight-bold); }
.term-body .warn { color: #e0af68; }
.term-body .jk { color: #7dcfff; }

/* Test-tree rows: label left, right-aligned [pass] tag, matching the
   elements test TUI. Flex keeps the tag aligned instead of padding it
   out with spaces. */
.term-body .tline {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.5rem;
}
.term-body .tline.ind { padding-left: 1.6ch; }
.term-body .tpath { color: #c6d3de; }
.term-body .tree { color: #c6d3de; }
.term-body .pass { color: #5fd0a0; font-weight: var(--weight-bold); }

/* File rows in the project-shape cards: name in a fixed column, the
   note about it in muted text beside it. */
.term-body .frow {
  display: grid;
  grid-template-columns: 15ch auto;
  column-gap: 1.25rem;
  align-items: baseline;
}
.term-body .fname { color: #c6d3de; }

/* ---- code cards (framework syntax boxes) ---- */

.term-bar .term-name {
  margin-left: 8px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: #6d7d8b;
}

/* Code cards show a filename in the bar, no window dots. */
.code-card .term-dot { display: none; }
.code-card .term-bar .term-name { margin-left: 0; }

/* ---- category masthead ---- */

/* A brand-tinted band behind each act's masthead, mixed from --accent
   and --bg so it adapts to light and dark on its own. */
/* A light hairline on a near-black ground reads far fainter than a dark
   one on white, so raise the alpha in dark mode. */

/* A big pale ordinal above each masthead (01 / 02 / 03) makes the three
   acts read as a set, clearly apart from the children beneath them. */
.home-main { counter-reset: category; }
.group-head .shell-marketing::before {
  content: counter(category, decimal-leading-zero);
  display: inline-block;
  border-top: 3px solid var(--accent);
  padding-top: var(--space-3);
  font-family: var(--font-mono);
  font-weight: var(--weight-bold);
  font-size: clamp(var(--text-2xl), 3vw, var(--text-4xl));
  color: var(--ink-faint);
  letter-spacing: 0.02em;
  line-height: 1;
  margin-bottom: var(--space-5);
}

/* ---- scroll-triggered reveals ---- */

/* Sections fade and rise as they enter the viewport, driven by the CSS
   view() timeline. No JS. Guarded by @supports so unsupported browsers
   just show the content. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .group-head .shell-marketing,
    .tool-section .split-copy {
      animation: reveal-up linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 55%;
    }
      }
}
@keyframes reveal-up {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: none; }
}

/* ---- closing cta ---- */

/* Full-bleed dark band as the final beat: one contrast moment against
   all the white, echoing the hero, and the loudest place for the #1
   action. */

/* A section can carry a second paragraph. .split-lead has no bottom margin
   so the copy block ends flush with the demo card, which leaves two leads
   running together without this. */

/* Wider name column for rows whose left side is a phrase rather than a
   filename. */
.term-body .frow.is-wide { grid-template-columns: 24ch auto; }

/* ---- get started box ---- */

/* The copy button sits in the title bar rather than floating over the code,
   because the box is four commands tall and an overlay would cover one of
   them at some width. */
.start-box .term-bar { align-items: center; }
.start-box .term-name { flex: 1; }

/* Same chip as the one on /install, to the pixel.

   The source of truth is `.terminal > .copy` in app/shared/styles/site.css,
   which is itself an override of the package default (that one is tighter:
   4px vertical, a hard 6.5rem). This terminal is not a `.terminal`, so it
   cannot inherit the rule and the values are repeated here. Change one and
   change the other: two copy buttons that are almost the same size read as a
   bug in whichever one you see second.

   min-width rather than width is what stops the chip resizing when the label
   flips to "copied". */
.start-copy {
  height: auto;
  min-height: 0;
  min-width: 6.5rem;
  width: auto;
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-align: center;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-xs);
  color: rgba(255, 255, 255, 0.72);
  cursor: pointer;
  box-shadow: none;
  flex-shrink: 0;
  transition: color 120ms, border-color 120ms, background 120ms;
}
.start-copy:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.16);
}

/* Agent picker, left of the copy chip: a native select dressed as a dark chip,
   the same type, height and radius as .start-copy so the title bar is one
   family. A select rather than pills because the list grows over time and a
   row of pills stops fitting a phone-width bar at four. color-scheme: dark
   asks the browser for a dark popup so the open list matches the card. */
.term-agent {
  /* The copy chip is border + padding + one line at its font size, and it
     sets line-height 1. A select's line-height is `normal` regardless, which
     came out 3px taller and read as a mismatch. State the same sum here. */
  height: calc(var(--text-2xs) + 2 * var(--space-2) + 2px);
  min-height: 0;
  width: auto;
  padding: 0 var(--space-6) 0 var(--space-3);
  margin-right: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.72);
  color-scheme: dark;
  background-color: rgba(255, 255, 255, 0.06);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='rgba(255,255,255,0.72)' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-2-5) center;
  background-size: 10px 6px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-xs);
  box-shadow: none;
  cursor: pointer;
  flex-shrink: 0;
  transition: color 120ms, border-color 120ms, background-color 120ms;
}
.term-agent:hover {
  color: #fff;
  background-color: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.16);
}
.term-agent:focus-visible {
  outline: none;
  border-color: rgba(255, 255, 255, 0.4);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.18);
}
.term-agent option {
  text-transform: none;
  background: #0d1b28;
  color: #f2f7fb;
}

/* Under 24rem the name, the picker and the copy chip no longer share a row with
   the three dots: the chip slid past the card edge. The dots are decoration and
   the chip's reserved width is for the "copied" flip, so both give way here. */
@media (max-width: 24rem) {
  .start-box .term-dot { display: none; }
  .start-box .start-copy { min-width: 0; }
}

/* Both labels are always in the DOM and swapped with display, so the button
   never changes width between states and never moves under the cursor that
   just clicked it. */
.start-copy .start-copy-done    { display: none; }
.start-copy.is-copied .start-copy-default { display: none; }
.start-copy.is-copied .start-copy-done    { display: inline; }
.start-copy.is-copied,
.start-copy.is-copied:hover {
  color: #5fd0a0;
  border-color: rgba(95, 208, 160, 0.5);
}

/* One command per line, scrolled rather than wrapped. Wrapping the install
   line broke a single command across two rows, which read as two commands
   and made the block look longer and messier than it is. */
.start-box .term-body { overflow-x: auto; }
.start-box .term-body .line { white-space: pre; }
.start-box .term-body .line.gap { height: 0.75em; }

/* A section can show two cards, when the point is that they are two views of
   one thing. The first has no bottom margin so a single card ends flush with
   the copy, so the gap goes on the second. */
.split-demo .hero-terminal + .hero-terminal { margin-top: var(--space-5); }

/* Inline code in a section lead. The prose names real commands, and a command
   set in the body face reads as a phrase rather than a thing you type. */

/* Label above the get-started box. Small and quiet: it is an instruction, not
   a heading, and the box below it is the thing being looked at. */
.start-label {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  color: var(--ink);
  /* Enough air that the label reads as introducing the terminal below
     rather than clinging to it. */
  margin: 0 0 var(--space-3);
  max-width: none;
}

/* The label names the block; this says what running it does. Prose, so it
   takes the body face at normal weight rather than continuing the mono label
   and reading as more heading. */

/* t 20665 */

/* t2 6789 */

/* ---- hero sheet ---- */

/* The hero was ruled paper: a 24px grid across the band. It is off as of
   2026-09-15 to see the hero with nothing behind the type. The layer stays,
   carrying only the two hairlines, since home drops the topbar's own bottom
   border and takes the opening rule from here. The ruling and its
   --sheet-rule tokens are in the history of this file if it comes back. */

/* Home drops the topbar's own bottom edge. The sheet below it opens on a
   ruled line of its own, and two hairlines a hair apart is the misalignment
   this is avoiding. The band carries the separator instead, at exactly the
   grid's first rule. */
.home-page .topbar.topbar-v2 { border-bottom: 0; }

.hero-wrap {
  position: relative;
  isolation: isolate;
  background: var(--bg);
  padding-bottom: var(--space-12);
}
.hero-wrap::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: -1;
  pointer-events: none;
  height: 100%;
  /* The opening rule under the nav, and nothing closing the band: the hero
     runs into the page below it. A layer rather than a border on .hero-wrap,
     since a border sits outside the padding box and painted a pixel off from
     anything drawn inside it. Home drops the topbar's own bottom border and
     takes this line instead, so this is the only thing separating the two. */
  background-image: linear-gradient(var(--chrome-rule), var(--chrome-rule));
  background-size: 100% 1px;
  background-position: 0 0;
  background-repeat: no-repeat;
}

/* Install follows the paste block: the reader gets the claim, then the four
   commands, then the button for anyone who would rather not paste. It lives
   inside the hero so the band carries it too, and so the gap above it is
   tuned here rather than by a separate section's padding. */
.hero-actions {
  margin-top: var(--space-6);
}

/* Phones: the paste block and the button both have to clear a 844px fold, so
   the terminal gives up the type size it does not need. At 14px/1.75 the
   button landed ~90px under the fold on an iPhone viewport. */
/* Phones: the bar keeps all three controls by giving up padding and a
   little type, rather than folding. */
@media (max-width: 480px) {
  .card-head { padding: 8px; gap: 6px; }
  .seg-btn { padding: 6px 10px; }
  .card-head .bar-select { padding: var(--space-2) 8px; }
  .card-head .start-copy { min-width: 5rem; padding: var(--space-2) 8px; }
}

@media (max-width: 700px) {
  .term-body {
    font-size: 11.5px;
    line-height: 1.5;
    padding: 12px 14px;
  }
  .term-body .line.gap { height: 0.55em; }
  .hero-actions { margin-top: var(--space-3); }
  /* Every gap in the hero gives up a few pixels for the same reason: on a
     844px viewport the four blocks only fit if none of them keeps the air it
     would have on a desktop. */
  .hero-title.is-sentence { font-size: clamp(2.1rem, 10vw, 2.75rem); }
  .hero-para {
    margin-bottom: var(--space-5);
    /* Relaxed leading is for long-form reading. Nine lines of hero copy at
       1.75 spend 30px on air the fold cannot afford. */
    line-height: 1.6;
  }
  .start-label { margin-top: 0.9rem; }
}

/* A slow sheen across the accent phrase. The band is narrow and the light
   stop is one step off --accent (#1F6BA8 → #3f8cc9), not a pale blue: the
   earlier version ran to #9fd4ff and read as a rendering fault rather than as
   a highlight. It never leaves the blue, so any frame of it looks deliberate.
   Text stays --accent for anyone who has asked for less motion. */
.hero-accent {
  background-image:
    linear-gradient(102deg,
      var(--accent) 0%,
      var(--accent) 38%,
      #3f8cc9 47%,
      var(--accent) 56%,
      var(--accent) 100%);
  background-size: 300% 100%;
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  /* background-clip: text paints inside the inline box, which is the sum of
     the glyphs' advance widths. Italic ink leans past that on the last
     character, so the final letter loses its top right corner and reads as a
     rendering fault. The padding widens the paintable box; the negative
     margin gives the space back, so nothing moves. */
  padding-right: 0.1em;
  margin-right: -0.1em;
  animation: hero-glimmer-slow 7s ease-in-out infinite;
}

@keyframes hero-glimmer-slow {
  0%   { background-position: 115% 50%; }
  55%  { background-position: -15% 50%; }
  100% { background-position: -15% 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .hero-accent {
    animation: none;
    background-image: none;
    -webkit-text-fill-color: var(--accent);
  }
}

/* Air under the last block of the hero, down to the rule that closes the band.
   Lives after the .hero-wrap block above, not in the mobile media query
   earlier in the file, which loses to it on source order. */
.hero-wrap { padding-bottom: 54px; }

@media (max-width: 700px) {
  .hero-wrap { padding-bottom: 68px; }
}

/* ---- the one box ---- */

/* Two layers, kept apart on purpose. `.start-controls` is ours: it selects
   which picture to show. Below it is the picture, and a picture of a terminal
   has to look like a terminal, an agent composer like an agent composer. The
   moment our switches sit inside their chrome, neither is believable. */

/* The demo band. Full bleed, so what marks the section is the page changing
   colour rather than another rectangle drawn around the content. The windows
   inside keep their own frames; this only says where the demo starts and
   ends. */
/* Paper, in both themes. These were literals and stayed light when the rest
   of the page went dark, which left light text on a white band. */
.home-page {
  --paper:       #faf9f7;
  --paper-panel: #faf9f7;
  --paper-high:  #fffefc;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .home-page {
    --paper:       #0e141a;
    --paper-panel: #161e27;
    --paper-high:  #1f2935;
  }
}
:root[data-theme="dark"] .home-page {
  --paper:       #0e141a;
  --paper-panel: #161e27;
  --paper-high:  #1f2935;
}

.start-band {
  position: relative;
  isolation: isolate;
  width: 100%;
  padding: var(--space-10) 0 var(--space-12);
  /* Paper: the exact ground the agent window sits on, so the band and the
     box are one surface. A different grey left a seam between them. */
  background: var(--paper);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}



.start { margin: 0; }

/* The line that hands the reader over to the box. Same weight and face as it
   had above the old paste block, so the hero still ends on an invitation. */
/* The line that hands the reader to the box. A step up in size and real air
   under it: it opens the section, so it should not sit on the controls. */
.start .start-label {
  font-family: var(--font-mono);
  font-size: var(--text-base);
  font-weight: var(--weight-bold);
  color: var(--ink);
  margin: 0 0 var(--space-6);
}

/* Wraps. At 320 the segment and the tools together are wider than the column,
   and nowrap pushed the copy chip 31px off the right edge with no scrollbar to
   find it by. The row stays on one line at every width where it fits. */

.start-controls {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-bottom: var(--space-3);
}

/* Agent or Terminal. Two words, nothing else.
 *
 * Specificity matters here: the style package's own button rules set a white
 * ground and zero the border, so a bare `.seg-btn` lost both the transparent
 * background and the underline (computed: rgb(255,255,255) and 0px none).
 * Scoping to .start-controls wins, and the underline is an inset shadow so no
 * border shorthand anywhere can flatten it again. */
/* The style package draws a bordered white chip on this span from inside a
   @layer, which is why it kept reappearing: it does not show up in a plain
   scan of document.styleSheets. Neutralised explicitly. */
.start-controls .seg {
  display: inline-flex;
  align-items: center;
  gap: var(--space-5);
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  padding: 0;
}

.start-controls .seg .seg-btn {
  appearance: none;
  font: inherit;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  height: auto;
  min-height: 0;
  width: auto;
  padding: 0 0 6px;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  color: var(--ink-3);
  cursor: pointer;
  transition: color 120ms, box-shadow 120ms;
}
.start-controls .seg .seg-btn:hover {
  color: var(--ink-2);
  background: transparent;
}
.start-controls .seg .seg-btn.is-on {
  color: var(--ink);
  background: transparent;
  box-shadow: inset 0 -2px 0 var(--accent);
}

.start-tools {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

/* The chip in the options row. Quiet: the sentence under the box is the
   instruction, this is the shortcut for somebody already reaching. */
.start-controls .start-copy {
  height: auto;
  min-height: 0;
  min-width: 5.5rem;
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-align: center;
  border: 1px solid var(--rule);
  border-radius: var(--radius-xs);
  background: var(--bg);
  color: var(--ink-2);
  cursor: pointer;
  box-shadow: none;
}
.start-controls .start-copy:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 4%, var(--bg)); }
.start-controls .start-copy.is-copied {
  color: #14724d;
  border-color: rgba(31, 157, 107, 0.5);
  background: rgba(31, 157, 107, 0.1);
}

/* Centred, and sized to its own label plus room for the caret. Left aligned
   in a box wider than the text, it read as a half-filled input. */
.start-select {
  text-align: center;
  text-align-last: center;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  height: auto;
  min-height: 0;
  width: auto;
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--rule);
  border-radius: var(--radius-xs);
  background: var(--bg);
  color: var(--ink-2);
  cursor: pointer;
}

/* The instruction, with the click inside it. The copy word carries the weight
   the button used to: accent, bold, underlined, and it turns green when the
   clipboard has the text. The page's one filled button is Install, below. */
.do {
  margin: var(--space-5) 0 0;
  font-size: var(--text-base);
  color: var(--ink-2);
}
.do a { color: var(--accent); }
.do a + a::before { content: ", "; color: var(--ink-3); }

.do-copy {
  appearance: none;
  font: inherit;
  font-weight: var(--weight-bold);
  height: auto;
  min-height: 0;
  width: auto;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--accent);
  text-decoration: underline;
  /* Continuous, and clear of the descenders in "Copy this prompt": ink-skip
     chopped the rule into pieces around the p and the y. */
  text-decoration-thickness: 1px;
  text-decoration-skip-ink: none;
  text-underline-offset: 4px;
  cursor: pointer;
}
.do-copy:hover { color: color-mix(in srgb, var(--accent) 80%, #000); background: none; }
.do-copy.is-copied { color: #14724d; text-decoration: none; }

/* ---- the terminal, as a terminal ---- */

.term-window {
  width: 100%;
  border-radius: var(--radius-xl);
  overflow: hidden;
  background: #0d1b28;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 24px 48px -24px rgba(16, 44, 66, 0.5);
}

.term-window .term-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  background: rgba(255, 255, 255, 0.04);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.term-window .term-name {
  margin-left: 6px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: #8b98a5;
}

/* ---- the agent composer, as an agent composer ---- */

/* A window, like the terminal is a window. On the wash both modes then read
   as the same kind of object: chrome of their own, holding the thing you
   paste into. */
.agent-window {
  border: 1px solid var(--rule);
  border-radius: var(--radius-xl);
  overflow: hidden;
  padding: 16px;
  /* Warm, not white: the agent apps all sit on a paper-ish ground, and a flat
     white panel on a grey band reads as a dialog instead. */
  background: var(--paper-panel);
  box-shadow: 0 24px 48px -32px rgba(16, 44, 66, 0.35);
}

.composer-body {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  margin: 0 0 12px;
  padding: 22px 20px 22px 24px;
  background: var(--paper-high);
  border: 1px solid var(--rule);
  border-radius: 28px;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--ink-2);
}

.composer-text {
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  white-space: pre;
}

/* No return glyph. It looks like a button in a box that cannot be typed
   into, and a control that does nothing is worse than no control. */

.composer-chrome {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 8px 4px;
  font-size: var(--text-2xs);
  white-space: nowrap;
  color: var(--ink-3);
}

.chrome-icon,
.chrome-caret { width: 15px; height: 15px; color: var(--ink-3); }
.chrome-caret { width: 12px; height: 12px; margin-left: -4px; }
.chrome-mode { margin-left: 2px; }

/* Getting an agent, for somebody who has none. Below the box and quiet. */
/* The last thing in the band, with real air above it so it reads as a
   footnote to the demo rather than part of the instruction. */
.pick {
  margin: var(--space-10) 0 0;
  font-size: var(--text-sm);
  color: var(--ink-3);
}
.pick a { color: var(--accent); text-decoration: none; }
.pick a:hover {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-skip-ink: none;
  text-underline-offset: 4px;
}

/* The comma sits inside the next anchor, so a hover underline ran through it
   too. inline-block keeps the parent's line off it. */
/* inline-block keeps the hover underline off the comma, but it also collapses
   a trailing space, so the space is a non-breaking one in the content above. */
.pick a + a::before { display: inline-block; }
.pick a + a::before { content: ",\00a0"; color: var(--ink-3); }

.pick-pills { display: flex; gap: 6px; flex-wrap: wrap; }

.pill {
  padding: 4px 12px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--bg);
  color: var(--ink);
  text-decoration: none;
  font-size: var(--text-sm);
}
.pill:hover { border-color: var(--accent); color: var(--accent); }


/* ---- the install row, under the demo ---- */

.install-row {
  /* No margin: the band's padding is the only thing setting this row's air,
     so the space above and below stays identical. */
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-top: var(--space-6);
}

.install-note { font-size: var(--text-sm); color: var(--ink-3); }

/* The mode select is the phone's version of the Agent/Terminal words: at
   phone width the two words plus the scaffold picker and copy cannot share a
   row, and the words are what a dropdown says better anyway. */
.mode-select { display: none; }

@media (max-width: 620px) {
  /* Specific enough to beat `.start-controls .seg` above, which is why the
     word AGENT was rendering next to the AGENT dropdown. */
  .start-controls .seg { display: none; }

  .mode-select {
    display: inline-block;
    width: auto;
    height: auto;
    min-height: 0;
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    text-align: center;
    text-align-last: center;
    border: 1px solid var(--rule);
    border-radius: var(--radius-xs);
    background: var(--bg);
    color: var(--ink-2);
    cursor: pointer;
  }

  /* Phones give the band more of their width: at 1.5rem each side the pill
     inside two nested boxes had barely 60% of the screen for the prompt. */
  .start-band .shell-marketing { padding: 0 1rem; }
  .agent-window { padding: 10px; }
  .composer-body { padding: 18px 14px; }
  .start-band { padding: var(--space-8) 0 var(--space-10); }
  .start .start-label { margin-bottom: var(--space-5); }
}

/* The demo sits closer to the hero now: the hero's own bottom air plus the
   band's top air was a screen and a half of nothing between the paragraph and
   the thing to try. */
.home-page .hero-wrap { padding-bottom: var(--space-6); }

/* ---- install, its own section ---- */

/* One row: the line on the left, the button on the right, separated from the
   demo by a rule and air. No box, no fine print. */
/* Equal air above and below the row. The measured gaps were 64 and 49: the
   paddings differed, and the button's own height sits inside the row box. */
.install-band {
  width: 100%;
  padding: var(--space-12) 0;
  border-bottom: 1px solid var(--rule);
}

/* One row at every width. It never wraps: the type gives way instead, and the
   button keeps its size because it is the thing being clicked. */
.install-row {
  /* No margin: the band's padding is the only thing setting this row's air,
     so the space above and below stays identical. */
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: nowrap;
}

.install-row .button { flex: 0 0 auto; }

.install-title {
  margin: 0;
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight);
}

@media (max-width: 620px) {
  .install-band { padding: var(--space-10) 0; }
  .install-title { font-size: var(--text-lg); }
  .install-row .button { padding-left: var(--space-5); padding-right: var(--space-5); }
}

@media (max-width: 400px) {
  .install-title { font-size: var(--text-base); }
}

/* ---- copy button treatments, ?cta= ---- */

/* ink: outlined, the page's ink. Reads as the action of this section without
   claiming the page's one blue. */
.do-copy.is-ink {
  border: 1px solid var(--ink);
  background: var(--bg);
  color: var(--ink);
}
.do-copy.is-ink:hover { background: var(--ink); color: var(--bg); }

/* dark: solid ink. Loudest of the neutral options, and it echoes the
   terminal. */
.do-copy.is-dark {
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--bg);
}
.do-copy.is-dark:hover { background: color-mix(in srgb, var(--ink) 85%, #fff); }

/* blue: the same accent as Install. Two blues in a column, for comparison. */
.do-copy.is-blue {
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
}
.do-copy.is-blue:hover { background: color-mix(in srgb, var(--accent) 88%, #000); }

/* ghost: hairline and ink text. Quietest; the sentence carries the weight. */
.do-copy.is-ghost {
  border: 1px solid var(--rule);
  background: var(--bg);
  color: var(--ink-2);
}
.do-copy.is-ghost:hover { border-color: var(--ink-3); color: var(--ink); }


/* ─── The demo band, as a machine ─────────────────────────────────────
   2026-09-16. The band used to be paper: near-white in light mode, a dark
   grey in dark mode, following the page. The campaign landing pages gave
   the same composer a band that is dark in BOTH themes, and it reads
   better for a reason worth keeping: the band is the part of the page that
   runs, and a terminal is dark whether or not the visitor's OS is. Paper
   made it a section of the page. This makes it the machine on the page.

   Implemented as a local theme on .start-band rather than as edits spread
   through the rules above it. Every rule inside the band already reads
   --ink / --rule / --accent, so overriding the tokens here flips all of
   them at once and the band stays one place to tune.

   It also fixes a latent bug: --ink-2 and --ink-3 are used by a dozen rules
   in this file and are defined NOWHERE in the codebase, so every one of
   them was silently falling back to the inherited colour. They are real
   values inside the band now. The same tokens are still undefined outside
   it; that is a separate cleanup. */
.home-page .start-band {
  --stage:       #0B1826;
  --stage-panel: #14232f;
  --stage-field: #1b2d3b;

  --paper:       var(--stage);
  --paper-panel: var(--stage-panel);
  --paper-high:  var(--stage-field);

  --ink:      #eef4f9;
  --ink-2:    #b7c6d3;
  --ink-3:    #8497a6;
  --ink-soft: #b7c6d3;
  --ink-dim:  #8497a6;
  --rule:     rgba(255, 255, 255, 0.10);
  --bg:       rgba(255, 255, 255, 0.04);
  --accent:   var(--elements-blue-400);

  position: relative;
  isolation: isolate;
  background: var(--stage);
  border-top: 0;
  border-bottom: 0;
  color: var(--ink);
}

/* In dark mode the page is already near-black, so a slab at the light-mode
   value reads as a slightly different black instead of as a cut. The band
   lifts rather than drops, and stays the brightest surface on the page. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .home-page .start-band {
    --stage:       #12202E;
    --stage-panel: #1b2c3b;
    --stage-field: #233848;
  }
}
:root[data-theme="dark"] .home-page .start-band {
  --stage:       #12202E;
  --stage-panel: #1b2c3b;
  --stage-field: #233848;
}

/* No accent rule on the top edge. A half-width gradient reads as a broken
   border, and a solid one competes with the colour change for the same job.
   The slab is the separation. */

/* Composer geometry, matched to the campaign pages: a tighter window radius
   against a rounder field, and smaller type with more leading. The prompt is
   thirteen lines of monospace and the old setting ran them together. */
.home-page .start-band .agent-window {
  border-radius: 14px;
  padding: 14px;
  box-shadow: none;
}

.home-page .start-band .composer-body {
  padding: 20px 22px;
  border-radius: 22px;
  font-size: 0.8125rem;
  line-height: 1.75;
  font-family: var(--font-mono);
}

/* The terminal is its own window and has always been dark. On a dark band it
   needs an edge, or it dissolves into the slab behind it. */
.home-page .start-band .term-window {
  background: var(--stage-field);
  border-color: var(--rule);
  box-shadow: none;
}

.home-page .start-band .term-window .term-bar {
  background: rgba(255, 255, 255, 0.04);
  border-bottom-color: var(--rule);
}

/* The copy chip keeps the row's own language: mono, uppercase, the tight
   radius. It was briefly restyled to sans and sentence case, which is what
   the /c/* pages use, but there the chip stands alone. Here it sits in a row
   with the scaffold select and the Agent/Terminal control, both of which are
   uppercase mono at --radius-xs, and one control in a different face, case
   and radius does not read as a deliberate emphasis. It reads as a bug.

   Only the colours are overridden below, because the row moved onto a dark
   band and the light-mode values are unreadable on it. */
.home-page .start-band .start-controls .start-copy:hover {
  color: var(--ink);
  border-color: rgba(255, 255, 255, 0.22);
  background: rgba(255, 255, 255, 0.09);
}

.home-page .start-band .start-controls .start-copy.is-copied,
.home-page .start-band .start-controls .start-copy.is-copied:hover {
  color: #5FD0A0;
  border-color: rgba(95, 208, 160, 0.45);
  background: rgba(95, 208, 160, 0.14);
}

/* The scaffold and mode pickers are native selects, so the popup is drawn by
   the OS and follows the page, not the band. Only the closed control is ours
   to colour. */
.home-page .start-band .start-select,
.home-page .start-band .mode-select {
  color: var(--ink-2);
  background: var(--bg);
}

.home-page .start-band .start-select option,
.home-page .start-band .mode-select option {
  color: var(--ink);
  background: var(--stage-panel);
}

/* The copied state on the inline sentence button: the light-mode green is
   unreadable on the slab. */
.home-page .start-band .do-copy.is-copied { color: #5FD0A0; }
.home-page .start-band .do-copy:hover { color: var(--ink); }

/* ─── The headline, at the demo's scale ───────────────────────────────
   2026-09-16. The 4rem cap was set when the band below it was paper and
   the headline was the loudest thing on the page. The band is a dark
   machine now and it out-weighed the sentence introducing it, which is
   backwards: the claim should land before the demonstration of it.

   Same figures as the /c/* headlines, so the front door and the landing
   pages read as one family rather than as two scales of the same brand.
   The old note about 4rem being "the largest size that holds it to two
   lines" was measured in a 756px column; this page runs to the marketing
   column's full width and 5rem still breaks to two. */
.home-page .hero-title.is-sentence {
  font-size: clamp(2.75rem, 6.4vw, 5rem);
  letter-spacing: -0.035em;
  line-height: 0.97;
  /* No balance. It splits a two-line headline into equal halves, which on
     this sentence broke it early and left the line short of the column. */
  text-wrap: wrap;
}

@media (max-width: 700px) {
  .home-page .hero-title.is-sentence { font-size: clamp(2.25rem, 11vw, 3.25rem); }
}

/* ─── The install band, saying what is behind it ──────────────────────
   "It's time to build." was a slogan beside a button: it gave no reason to
   click and named nothing you would get. Devs do come looking for the
   install command, so the band stays, but it now says that is what it is,
   which platforms it covers, and that the trial costs nothing. The trial
   was not stated anywhere on this page before. */
.home-page .install-row {
  align-items: center;
  gap: var(--space-8);
}

/* The band holds one button. Left aligned with everything else on the page
   rather than centred, and not stretched: a full-width bar here would
   out-shout the paste above it, which is still the action this page wants. */
.home-page .install-row { justify-content: flex-start; }

/* Phones stack it. Two columns at phone width put a heading and a button in
   a squeezed row where the button ends up narrower than the text beside it,
   which reads as the smaller of two things to do. Stacked, the button is the
   full width of the column and is unmistakably the action. */
@media (max-width: 620px) {
  .home-page .install-row {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-5);
    flex-wrap: nowrap;
  }

  .home-page .install-row .button {
    width: 100%;
    justify-content: center;
  }
}


/* ─── The controls row is one height ──────────────────────────────────
   The copy chip and the scaffold select sit side by side and have to be
   the same box. They were not, twice:

     29px vs 32.3px   a button inherits line-height 1 from the base button
                      styles; a native select computes `normal`
     32px vs 32.3px   matching the line-height keyword got them within a
                      third of a pixel, which at 2x lands their borders on
                      different device pixels and still reads as crooked

   So neither control derives its height from font metrics any more. Both
   are pinned to the same value with the vertical padding removed, which is
   the only way two elements this different (a button and a native select)
   come out identical. The button already computes display grid with
   align-items center, and a select centres its text natively, so the label
   stays centred in both without further help. */
.start-controls .start-copy,
.start-controls .start-select {
  height: 2rem;
  min-height: 2rem;
  padding-top: 0;
  padding-bottom: 0;
}
