/* /features, the tour chapters (2026-10-18; the owner's pick of
   .tmp/mockups/whole-features-page-zoomed-out-20261018-0138). The page opens
   on "explore superbot" and the four route tiles (kept at the owner's ask,
   2026-10-18: "I like those buttons we had where they can select them and
   they see the other content"); "I want the app" shows the tour page, which
   sells superbot as its own model: a split hero card, four tours
   (make, works, everywhere, look), a quiet list of the rest, and the close. The
   other three tiles show the relay, API and MCP views of 093823400~1. The
   home page splices the same <main> in as #more (lander-agent.html), so every
   rule here is scoped under .features, the class #more takes with it.
   Look plan:
   - Palette: canvas --bg #000000, card --card #0d0d0d, hairline --line
     #262626, ink --fg #ececec, muted --muted #b3b3b3, accent --accent
     #4d8aff. site.css tokens only; its light ladder repaints all of them.
   - Accent: --accent on the hero's try-bar send, its two run lines and its
     playing step's bar, the
     active tour item's bar (on a phone, the active
     pill's outline), the picked route tile's ring, the relay card's picked
     tab bar and on focus; in the
     relay, API and MCP views as they were (the step numbers, Mint key, the
     MCP copy button, the code cards' syntax family). The Install buttons are
     the site's .sb-btn, its storm action unchanged.
   - Type: --font-ui throughout (site.css body); display headings take
     --tracking-tight.
   - Radius: --r-control (8px) on the tabs, the links, the key row and the
     code cards, --r-surface (16px) on the route tiles, the product windows,
     the hero card, its try bar, its desktop frame and its phone outline. A
     phone's pills and the step numbers take the --r-pill shape.
   - The one bold thing: the hero's live desktop screen with the phone over
     its corner (2026-10-18, the owner's pick), then the real app windows
     that swap as you move through each tour. The card's round send is the
     app's accent send, the one accent fill on the page.
   Hero exemplar borrowed: Mural "Easy account administration" (mobbin
   99799044-99d1-4a43-b4cd-388563b9bbed): copy on the left, the real product
   large on the right.
   Exemplar borrowed: incident.io's features tour (mobbin section
   0e8ee7bc-4aa3-4f1b-805f-89117f5d5d68): a list of outcomes with the active
   one lit beside ONE framed product window that changes with it.
   Motion is always on (motion.mdc, no reduced-motion guard): the hero card's
   one entrance (site.css .sb-reveal), the hero's run lines (transform) and
   held disc (opacity), the window's cross-fade (opacity), the active bar
   (transform), colour on a control's hover. */

/* page-scoped values site.css does not carry (site.css is outside this
   page's unit; each is named once here and read below) */
.features {
  --fx-display: clamp(2.5rem, 1.4rem + 3.6vw, 3.75rem);  /* the hero and the close: 40px on a phone, 60px from about 1280 */
  --fx-title: clamp(1.75rem, 1.2rem + 1.5vw, 2.25rem);   /* each chapter's heading: 28px to 36px */
  --fx-tight: 1.1;                                       /* the display leading */
  --fx-list-w: calc(var(--sp-16) * 5);                   /* the tour list's column, 320px: "keeps going while you're away" on one line at --fs-lg */
  --fx-ratio: calc(15 / 11);                             /* the product window: the tour captures' own shape (1200x880 at 2x) */
  --fx-step: 60svh;                                      /* how far a reader scrolls per tour item while the tour is pinned */
  --fx-bar: 2px;                                         /* the tab rail and the active bar on it */
  --fx-head: calc(var(--sp-16) * 3);                     /* a pinned stage's room above the window (the heading and its gaps), 192px */
  --fx-mark: calc(var(--sp-16) * 2);                     /* the hero card's mark, 128px */
  --fx-name-fit: 21cqi;                                  /* the hero name never outgrows its column: "superbot" sets about 4.6em wide */
  --fx-desk-w: 80%;                                      /* the hero's desktop screen, of its column */
  --fx-desk-ratio: calc(1600 / 1124);                    /* the hero's desktop screen: the computer-use loop's own shape, so cover trims none of it */
  --fx-phone-w: 29%;                                     /* the hero's phone, of the same column: its height lands at about the desktop's */
  --fx-phone-land-w: 44%;                                /* the hero's phone on its side (data-orient="landscape"): over the desktop's lower right third */
  --fx-zoom: 1;                                          /* site.css's wide-screen zoom, restated below: viewport units resolve that much too large inside it */
  --fx-screen: calc(100svh / var(--fx-zoom));            /* one screen's height in this page's CSS px, at any zoom tier */
  --f-gap: var(--sp-12);                                 /* the route views' rhythm: above each view and between its rows, 48px */
}
@media (min-width: 1200px) { .features { --fx-zoom: 1.25; } } /* site.css: html { zoom: 1.25 } from 1200px */

.features {
  max-width: var(--container); margin: 0 auto;
  /* the notch rides the shorthand through --gutter-l/-r (site.css 196), and the
     shorthand must stay a shorthand in the CSSOM to be read: a longhand after
     it in the SAME rule makes Chromium expand it, and the declaration text then
     holds padding-left/right only, which the mobile matrix's source check reads
     as no notch padding at all (docs.css 483 learned the same on main#main).
     The longhands are the other reading, for a checker that enumerates style[i];
     they live in their own rule below so they cannot force the expansion. */
  padding: 0 var(--gutter-r) var(--sp-section) var(--gutter-l);
}
@media (pointer: coarse) {
  .features { padding-left: var(--gutter-l); padding-right: var(--gutter-r); }
}
.fx-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.fx-ic { flex: none; width: var(--sp-5); height: var(--sp-5); }

/* ---- the route tiles (2026-10-09, restored 2026-10-18 at the owner's ask):
   "explore superbot" over four tiles, each the tab of one panel below. The
   tiles copy /download's picker (download.html .route-tiles and .route-tile:
   the same recipe, the same icons, the same phone stack); the tiles are
   buttons, so the picked one reads aria-selected. A tap only swaps
   aria-selected, tabindex and hidden: nothing moves and nothing animates on
   the click frame (features-page.js mountRouteTabs). */
.f-route { display: grid; gap: var(--sp-6); padding-top: var(--sp-12); scroll-margin-top: calc(var(--nav-h) + var(--sp-6)); }
.f-route h1 { font-size: var(--fs-h1); line-height: var(--fx-tight); letter-spacing: var(--tracking-tight); max-width: 16ch; }
.route-tiles { width: 100%; display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: 0; }
.route-tiles > .route-tile { flex: 1 1 calc(var(--sp-16) * 2 + var(--sp-8)); min-width: 0; }
@media (max-width: 768px) { .route-tiles > .route-tile { flex-basis: calc(50% - var(--sp-3)); } }
.route-tile {
  appearance: none; font: inherit; cursor: pointer;
  display: grid; justify-items: center; align-content: center; gap: var(--sp-4);
  min-height: calc(var(--sp-16) + var(--sp-12)); padding: var(--sp-8) var(--sp-2);
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-surface);
  color: var(--muted); text-align: center; text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--dur-2) var(--ease-std), background-color var(--dur-2) var(--ease-std), border-color var(--dur-2) var(--ease-std), box-shadow var(--dur-2) var(--ease-std);
}
.route-tile-ico { width: var(--sp-16); height: var(--sp-16); }
.route-tile-label { font-size: var(--fs-base); line-height: var(--lh-base); text-wrap: balance; }
@media (hover: hover) { .route-tile:hover { background: var(--raised); color: var(--fg); } }
.route-tile:active { background: var(--raised); }
/* picked: a 2px accent ring (the 1px border plus 1px inset, so the tile never changes size) */
.route-tile[aria-selected='true'] { color: var(--fg); border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
@media (max-width: 480px) {
  /* a phone: the four tiles stack, each a compact row, the icon left of its label (download.html, the same rule) */
  .route-tiles { flex-direction: column; flex-wrap: nowrap; gap: var(--sp-2); }
  .route-tiles > .route-tile { flex: none; }
  .route-tile { display: flex; justify-content: flex-start; align-items: center; gap: var(--sp-3); min-height: var(--target); padding: var(--sp-2) var(--sp-4); }
  .route-tile-ico { flex: none; width: var(--sp-6); height: var(--sp-6); }
}

/* the panels: one shows; the others are hidden and stay in the page for their
   links. Every panel follows the tile row (or a hidden panel), so each takes
   one --f-gap above it; the app panel's model card starts right there. */
.route-panel[hidden] { display: none; }
.f-route ~ .route-panel { margin-top: var(--f-gap); }

/* ---- the hero: the split card (2026-10-18, the owner's pick #3 of
   .tmp/mockups/features-hero-with-computer-use-lead-20261018-1246, "i like
   #3, impl"): one --card surface on a hairline at --r-surface. The mark, the
   name, two lines (one sentence each) and the try bar in its left two
   fifths, a hairline between; in the right three fifths the live desktop
   screen, a frame at --r-surface, with the phone over its lower right
   corner, a device outline at the same --r-surface. Each frame carries a
   thin --accent line along its bottom edge that follows the run
   (features-page.js mountHero). Pressing the desktop screen holds the run:
   on the press frame its play disc fades in and the lines go --muted. The
   run's steps sit under the screens (.fx-steps). Both
   frames are dark islands in the light theme too (the captures are the dark
   app). Install now sits under the card. Stacked under 840px, the copy
   first, the screens under it at the same proportions. */
.fx-hero { display: grid; justify-items: center; gap: var(--sp-8); padding: 0 0 var(--sp-section); }
.fx-card {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); align-items: center; width: 100%;
  padding: var(--sp-8); background: var(--card); border: 1px solid var(--line); border-radius: var(--r-surface);
}
.fx-id {
  display: grid; justify-items: center; align-content: center; gap: var(--sp-2); min-width: 0; align-self: stretch;
  padding-right: var(--sp-8); border-right: 1px solid var(--line); text-align: center; container-type: inline-size;
}
.fx-mark { width: var(--fx-mark); height: auto; margin-bottom: var(--sp-4); }
.fx-hero h2 { font-size: min(var(--fx-display), var(--fx-name-fit)); line-height: var(--fx-tight); letter-spacing: var(--tracking-tight); }
.fx-close h2 { font-size: var(--fx-display); line-height: var(--fx-tight); letter-spacing: var(--tracking-tight); }
/* one sentence per line: each span is its own line, and each fits one line from 320px up */
.fx-lede { margin-bottom: var(--sp-6); color: var(--muted); font-size: var(--fs-lg); line-height: var(--lh-lg); }
.fx-lede span { display: block; }
/* the ask box: the home hero's ask (hero-ask.css .hero-ask) in this card's dress; hero-ask.js runs it and hero-ask.css draws
   the words' Rise on the press. The box carries the focus ring, not the field inside it. */
.fx-try {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; min-height: var(--control-h);
  padding: 0 var(--sp-2) 0 var(--sp-4); background: var(--raised); border: 1px solid var(--line); border-radius: var(--r-surface);
  text-align: left; transition: border-color var(--dur-2) var(--ease-std);
}
.fx-try-in {
  flex: 1; min-width: 0; align-self: stretch; padding: 0; background: none; border: 0; border-radius: 0;
  color: var(--fg); font: inherit; font-size: var(--fs-base); line-height: var(--lh-base);
}
.fx-try-in::placeholder { color: var(--muted); }
.fx-try .fx-try-in:focus-visible { outline: none; border-color: transparent; box-shadow: none; }
.fx-try:has(.fx-try-in:focus-visible) { outline: var(--focus-w) solid var(--accent); outline-offset: var(--focus-w); }
.fx-try[data-sent] .fx-try-in { color: transparent; caret-color: transparent; }
.fx-send { flex: none; display: grid; place-items: center; width: var(--target); height: var(--target); padding: 0; border: 0; border-radius: 50%; background: var(--accent); color: var(--accent-ink); cursor: pointer; }
.fx-send .fx-ic { width: var(--sp-4); height: var(--sp-4); }
@media (hover: hover) {
  .fx-try:hover { border-color: var(--line-strong); }
}
/* the screens: the desktop in flow at --fx-desk-w of the column, the phone
   pinned to the column's lower right at --fx-phone-w (about the desktop's
   height), dropping --sp-6 below the desktop's bottom edge; the run's steps
   under them (.fx-steps, below) */
.fx-live { min-width: 0; margin-left: var(--sp-8); }
.fx-screens { position: relative; padding-bottom: var(--sp-6); }
.fx-desk {
  position: relative; width: var(--fx-desk-w); aspect-ratio: var(--fx-desk-ratio); overflow: hidden;
  background: var(--bg); border: 1px solid var(--line-strong); border-radius: var(--r-surface);
}
.fx-desk .fx-screen { display: block; width: 100%; height: 100%; object-fit: cover; }
/* the phone: a device outline, a --sp-1 black bezel inside a --fx-bar edge, at the desktop's --r-surface */
.fx-phone {
  position: absolute; right: 0; bottom: 0; width: var(--fx-phone-w); overflow: hidden;
  background: var(--bg); border: var(--sp-1) solid var(--bg); border-radius: var(--r-surface);
  outline: var(--fx-bar) solid var(--line-strong);
}
.fx-phone .fx-screen { display: block; width: 100%; height: auto; }
/* data-orient names the capture's shape: "portrait" (the still today) stands
   about the desktop's height; "landscape" (a phone turned on its side, the
   re-shoot's) lies wider and lower over the desktop's lower right corner, its
   height from the capture's own width and height */
.fx-phone[data-orient="landscape"] { width: var(--fx-phone-land-w); }
/* the run's line on each frame's bottom edge: a --line track, the --accent
   part grown from the left by transform only (mountHero sets scaleX) */
.fx-desk::before, .fx-phone::before, .fx-prog { position: absolute; left: 0; right: 0; bottom: 0; height: var(--fx-bar); pointer-events: none; }
.fx-desk::before, .fx-phone::before { content: ""; background: var(--line); }
.fx-prog { background: var(--accent); transform: scaleX(0); transform-origin: left center; }
.fx-live:has(.fx-hold[aria-pressed="true"]) .fx-prog { background: var(--muted); }
/* the hold: the whole desktop screen is the toggle; held, a play disc fades in at its centre */
.fx-hold {
  position: absolute; inset: 0; display: grid; place-items: center; width: 100%; margin: 0; padding: 0;
  border: 0; background: none; color: var(--fg); font: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.fx-hold:focus-visible { outline: var(--focus-w) solid var(--accent); outline-offset: calc(var(--focus-w) * -1); }
.fx-hold-disc {
  display: grid; place-items: center; width: var(--sp-12); height: var(--sp-12); border-radius: 50%;
  background: var(--card); border: 1px solid var(--line-strong); opacity: 0; transition: opacity var(--dur-2) var(--ease-std);
}
.fx-hold[aria-pressed="true"] .fx-hold-disc { opacity: 1; }
/* the run's steps (features-page.js mountHero draws one button per entry of
   the clip's data-chapters): a row under the screens, each step a hairline
   over its number and label. The playing step (aria-current) lights its bar
   in --accent (opacity) and its ink in --fg; held, the bar goes --muted with
   the run lines. A press only marks the step; the seek waits for the bar's
   fade (settle). Every label keeps one line: a row too narrow for all of them
   scrolls sideways inside itself, never the page. The row's own --sp-1 inset
   (cancelled by its margin) keeps a focus ring inside its scroll box. */
.fx-steps {
  position: relative; display: flex; gap: var(--sp-3); min-height: calc(var(--target) + var(--sp-2));
  margin: var(--sp-3) calc(var(--sp-1) * -1) 0; padding: var(--sp-1); list-style: none;
  overflow-x: auto; scrollbar-width: none; overscroll-behavior-x: contain;
}
.fx-steps::-webkit-scrollbar { display: none; }
.fx-steps > li { flex: 1 1 0; min-width: max-content; }
.fx-step {
  position: relative; display: flex; align-items: center; gap: var(--sp-2); width: 100%; min-height: var(--target);
  margin: 0; padding: var(--sp-2) 0 0; border: 0; border-radius: var(--r-control); background: none;
  color: var(--muted); font: inherit; font-size: var(--fs-sm); line-height: var(--lh-sm); white-space: nowrap; text-align: left;
  cursor: pointer; -webkit-tap-highlight-color: transparent; transition: color var(--dur-2) var(--ease-std);
}
.fx-step::before, .fx-step::after { content: ""; position: absolute; top: 0; left: 0; right: 0; height: var(--fx-bar); pointer-events: none; }
.fx-step::before { background: var(--line); }
.fx-step::after { background: var(--accent); opacity: 0; transition: opacity var(--dur-2) var(--ease-std); }
.fx-step-n { font-variant-numeric: tabular-nums; }
.fx-step[aria-current="step"], .fx-step:active { color: var(--fg); }
.fx-step[aria-current="step"]::after { opacity: 1; }
.fx-live:has(.fx-hold[aria-pressed="true"]) .fx-step::after { background: var(--muted); }
.fx-step:focus-visible { outline: var(--focus-w) solid var(--accent); outline-offset: var(--focus-w); }
@media (hover: hover) { .fx-step:hover { color: var(--fg); } }
.fx-cta, .features .foot { margin: 0; }
.fx-cta .sb-btn, .features .foot .sb-btn { min-height: var(--control-h); padding: 0 var(--sp-8); font-size: var(--fs-lg); }

/* ---- the tours: a tablist beside one framed product window ---- */
.fx-tour, .fx-more, .fx-close { border-top: 1px solid var(--line); }
.fx-stage { padding: var(--sp-section) 0; }
.fx-tour h2, .fx-more h2 { margin-bottom: var(--sp-8); font-size: var(--fx-title); line-height: var(--fx-tight); letter-spacing: var(--tracking-tight); }
.fx-tour-body { display: grid; grid-template-columns: var(--fx-list-w) minmax(0, 1fr); gap: var(--sp-12); align-items: start; }
.fx-tour.is-mirror .fx-tour-body { grid-template-columns: minmax(0, 1fr) var(--fx-list-w); }
.fx-tour.is-mirror .fx-list { order: 2; }

/* the list: a hairline rail on the left, the active item's bar lit on it */
.fx-list { position: relative; display: grid; align-content: start; min-width: 0; }
.fx-list::before { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: var(--fx-bar); background: var(--line); }
.fx-tab {
  position: relative; display: flex; align-items: center; gap: var(--sp-3);
  min-height: var(--sp-12); padding: var(--sp-2) var(--sp-4) var(--sp-2) var(--sp-5);
  border: 0; border-radius: var(--r-control); background: none;
  color: var(--muted); font-size: var(--fs-lg); line-height: var(--lh-lg); text-align: left; cursor: pointer;
  transition: color var(--dur-2) var(--ease-std);
}
.fx-tab::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: var(--fx-bar); background: var(--accent);
  transform: scaleY(0); transition: transform var(--dur-3) var(--ease-out);
}
.fx-tab[aria-selected="true"] { color: var(--fg); }
.fx-tab[aria-selected="true"]::before { transform: scaleY(1); }
@media (hover: hover) { .fx-tab:hover { color: var(--fg); } }

/* the window: one frame, every item's capture stacked in it; the picked one
   fades in over the last (features-page.js holds the clip's work until the
   fade's own transitionend). A dark island in the light theme too: the
   captures are the dark app. */
.fx-window { display: grid; width: 100%; aspect-ratio: var(--fx-ratio); background: var(--card); border: 1px solid var(--line); border-radius: var(--r-surface); overflow: hidden; }
.fx-shot { grid-area: 1 / 1; min-width: 0; min-height: 0; opacity: 0; transition: opacity var(--dur-4) var(--ease-std); }
.fx-shot[data-on] { opacity: 1; }
.fx-shot:focus-visible { outline-offset: calc(var(--focus-w) * -1); }
.fx-media { display: block; width: 100%; height: 100%; object-fit: contain; }
/* the phone capture stands in the window at its own shape, a screen with the
   window's radius and hairline */
.fx-shot.is-phone { display: grid; grid-template-rows: minmax(0, 1fr); justify-items: center; padding: var(--sp-6); }
.fx-shot.is-phone .fx-media { width: auto; max-width: 100%; height: 100%; border: 1px solid var(--line); border-radius: var(--r-surface); }
/* a tour loop longer than 5 s carries the hero's hold (.fx-hold, above): the
   whole clip is the toggle, the play disc fades in at its centre while held */
.fx-shot.is-loop { position: relative; }

/* pinned (features-page.js sets .is-scrolly and --n on a wide, tall enough
   screen): the stage holds still under the header while the reader scrolls
   --fx-step per item through the section, and the scroll picks the item */
.fx-tour.is-scrolly { height: calc(var(--fx-screen) - var(--nav-h) + (var(--n, 1) - 1) * var(--fx-step) / var(--fx-zoom)); }
.fx-tour.is-scrolly .fx-stage { position: sticky; top: var(--nav-h); display: grid; align-content: center; min-height: calc(var(--fx-screen) - var(--nav-h)); padding: var(--sp-8) 0; }
.fx-tour.is-scrolly .fx-window { justify-self: end; width: min(100%, calc((var(--fx-screen) - var(--nav-h) - var(--fx-head)) * var(--fx-ratio))); }
.fx-tour.is-scrolly.is-mirror .fx-window { justify-self: start; }

/* ---- and a lot more: one compact list of links, hairline rows, no cards */
.fx-more { padding: var(--sp-section) 0; }
.fx-more ul { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--line); }
.fx-more li { min-width: 0; border-bottom: 1px solid var(--line); }
.fx-more a {
  display: flex; align-items: center; gap: var(--sp-3); min-height: var(--sp-16);
  padding: var(--sp-3) var(--sp-4) var(--sp-3) 0; border-radius: var(--r-control);
  color: var(--fg); text-decoration: none;
}
.fx-more .fx-ic { color: var(--muted); }
@media (hover: hover) { .fx-more a:hover span { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: var(--sp-1); } }

/* ---- the close: the ask again, then the developers' way in */
.fx-close { display: grid; justify-items: center; gap: var(--sp-8); padding-top: var(--sp-section); text-align: center; }
.fx-dev { color: var(--muted); font-size: var(--fs-sm); line-height: var(--lh-sm); }
.fx-dev a { color: var(--fg); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: var(--sp-1); }

/* ---- the relay, API and MCP views (2026-10-09 to 10-10, restored 2026-10-18
   as they were at 093823400~1). The explainer is always the left column and
   the picture always the right (user decision, 2026-10-09, every panel);
   stacked on a phone the explainer comes first, then the picture. The
   picture is the real desktop screen in a dark rounded window. The relay
   opens on its card (.relay-card, below): the tagline, the key box and three
   figures, beside a tabbed window of the real Relay app. */
.feature-view { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-8); align-items: center; }
@media (min-width: 768px) {
  .feature-view { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); column-gap: var(--sp-10); }
  .feature-view-text { grid-column: 1; grid-row: 1; }
  .feature-view-shot { grid-column: 2; grid-row: 1; }
}
.feature-view-text { display: grid; align-content: start; gap: var(--sp-4); min-width: 0; }
.feature-view h2 { margin: 0; font-size: var(--fs-h1); line-height: var(--fx-tight); letter-spacing: var(--tracking-tight); }
.feature-view-lede { margin: 0; color: var(--muted); font-size: var(--fs-lg); line-height: var(--lh-lg); }
/* the step numbers of the API and MCP views: dark ink on the one accent, which clears 4.5:1 (#000 on #4d8aff, 6.4:1) */
.feature-view-n { flex: none; display: grid; place-items: center; width: var(--sp-10); height: var(--sp-10); border-radius: var(--r-pill); background: var(--accent); color: var(--bg); font-size: var(--fs-sm); line-height: 1; font-weight: 650; }
.feature-view-shot { margin: 0; min-width: 0; }
.feature-view-win { position: relative; container-type: inline-size; background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-surface); overflow: hidden; }
.feature-view-win img { display: block; width: 100%; height: auto; }

/* the relay's key (2026-10-10, the picked "Key Left" variant, then trimmed the same day on the user's word: "remove the blue highlight
   around the url itself and remove mint key button"). The key row is bare: no outlined box, just the URL field and Copy (and, on the API
   tab, Mint key, which moved there), with two stat chips under it on the relay tab. --font-mono for the URL alone; --r-control on the URL
   field, Copy, Mint key and the chips. No breakpoint: the row wraps, so the URL fills a row and Copy sits beside it when they fit, else
   Copy and Mint key share the next row. The URL wraps rather than scrolls (a value to copy is shown whole). */
.relay-key { display: flex; flex-wrap: wrap; align-items: stretch; gap: var(--sp-3); min-width: 0; }
.relay-key-url { flex: 1 1 auto; display: flex; align-items: center; min-width: 0; min-height: var(--target); padding: 0 var(--sp-3); background: var(--card); border: var(--hairline) solid var(--line); border-radius: var(--r-control); color: var(--fg); font-family: var(--font-mono); font-size: var(--fs-sm); line-height: var(--lh-sm); white-space: normal; overflow-wrap: anywhere; }
/* Copy and Mint key are the page's own flat controls, not .sb-btn: .sb-btn paints the storm ramp and breathes, and the key's one blue
   is the flat --accent (the same flat fill .mcp-copy wears). Ink on the fill is --accent-ink. Hover and press are a tint, no motion. */
.relay-key-copy, .relay-key-mint { flex: none; display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); min-height: var(--target); padding: 0 var(--sp-4); border: var(--hairline) solid var(--line); border-radius: var(--r-control); font: inherit; font-size: var(--fs-sm); line-height: var(--lh-sm); font-weight: 600; white-space: nowrap; text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent; transition: color var(--dur-2) var(--ease-std), background-color var(--dur-2) var(--ease-std), border-color var(--dur-2) var(--ease-std); }
.relay-key-copy { background: var(--card); color: var(--fg); }
.relay-key-mint { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
@media (hover: hover) {
  .relay-key-copy:hover { border-color: var(--line-strong); }
  .relay-key-mint:hover { background: color-mix(in srgb, var(--accent) 86%, var(--fg)); border-color: transparent; }
}
.relay-key-copy:active { background: var(--raised); }
.relay-key-mint:active { background: color-mix(in srgb, var(--accent) 78%, var(--bg)); }
.relay-key-copy.copied { color: var(--accent); border-color: var(--accent); }
.relay-key-copy.blocked { color: var(--fg); }
.relay-key .cpy-ico { flex: none; width: var(--sp-4); height: var(--sp-4); }
/* the relay's three 30 day figures (2026-10-18, the owner's pick, round 3): stacked, each a large --fg figure over its --muted words, no
   chip. The saving wears the app's own savings green (the desktop's saved.css: 70% of the status-ok ink over the body ink); --ok is that
   token's own value, the desktop's color.status.ok #23a559 (superbot-desktop packages/tokens dist/tokens.css), scoped here because the
   site has no status green in a sheet this page loads. .relay-figs stacks the list (it follows .relay-stats, so it wins). */
.relay-stats { --ok: #23a559; list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.relay-figs { flex-direction: column; flex-wrap: nowrap; gap: var(--sp-6); margin-top: var(--sp-4); }
.relay-stat { display: grid; gap: var(--sp-1); color: var(--muted); font-size: var(--fs-base); line-height: var(--lh-base); white-space: nowrap; }
.relay-stat b { color: var(--fg); font-size: var(--fx-title); line-height: var(--fx-tight); letter-spacing: var(--tracking-tight); font-weight: 600; font-variant-numeric: tabular-nums; }
.relay-stat b.relay-stat-save { color: color-mix(in oklch, var(--ok) 70%, var(--fg)); }

/* ---- the relay card (2026-10-18, the owner's pick of .tmp/mockups/relay-card-tabs-round-3-20261018-0608): ONE --card surface on a
   hairline at --r-surface, inside the page's margins (the same width as the route tiles above it). The intro takes its own width (the
   endpoint row on one line, about a third of the card at 1440) and the tabbed window the rest, a vertical hairline between them. The card's
   padding is the same on all four sides, so the window's right edge sits as far inside the card as the intro's left edge does. The tabs:
   a hairline under the row, the picked tab's --accent bar on it (transform only), the tab numbers a real sequence. The window is the
   relay views' own frame (.feature-view-win) holding one capture per tab, stacked; the picked one fades in (.fx-shot's opacity), and only
   after its capture has decoded (features-page.js mountRelayTabs). Under 1200px the card stacks, the intro first, a hairline under it. */
.relay-card {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); width: 100%;
  padding: var(--sp-8); background: var(--card); border: var(--hairline) solid var(--line); border-radius: var(--r-surface);
}
.relay-intro { display: grid; align-content: start; gap: var(--sp-4); min-width: 0; padding-bottom: var(--sp-6); border-bottom: var(--hairline) solid var(--line); }
.relay-intro h2 { margin: 0; font-size: var(--fs-h1); line-height: var(--fx-tight); letter-spacing: var(--tracking-tight); }
.relay-tour { display: grid; align-content: start; gap: var(--sp-6); min-width: 0; }
/* side by side from site.css's 1200px step, where the tab row has room for its three labels at --fs-lg beside the intro */
@media (min-width: 1200px) {
  .relay-card { grid-template-columns: auto minmax(0, 1fr); gap: 0; }
  .relay-intro { padding: 0 var(--sp-8) 0 0; border-bottom: 0; border-right: var(--hairline) solid var(--line); }
  .relay-tour { padding-left: var(--sp-8); }
}
.relay-tabs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-bottom: var(--hairline) solid var(--line); }
.relay-tab {
  position: relative; justify-self: start; min-height: var(--sp-12); padding: 0 var(--sp-4);
  border: 0; border-radius: var(--r-control); background: none;
  color: var(--muted); font: inherit; font-size: var(--fs-lg); line-height: var(--lh-lg); white-space: nowrap; cursor: pointer;
  -webkit-tap-highlight-color: transparent; transition: color var(--dur-2) var(--ease-std);
}
.relay-tab::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: calc(var(--hairline) * -1); height: var(--fx-bar); background: var(--accent);
  transform: scaleX(0); transition: transform var(--dur-3) var(--ease-out);
}
.relay-tab[aria-selected="true"] { color: var(--fg); }
.relay-tab[aria-selected="true"]::after { transform: scaleX(1); }
@media (hover: hover) { .relay-tab:hover { color: var(--fg); } }
.relay-window { display: grid; }
.relay-shot img { display: block; width: 100%; height: auto; }
@media (hover: hover) { .relay-window:has(.shot-open:hover) { border-color: var(--line-strong); } }

/* the API and MCP views: the relay's two columns, the numbered explainer left and the visual right, stacked on a phone with the list
   first. Each snippet is ONE near-black rounded card, the mono text on it with no box of its own, breaking only at spaces; a small Copy
   sits pinned in the card's top-right corner, and the text keeps clear of it. The MCP visual is a drawn terminal in the captures' own
   style (.fig-terminal, term.css). */
.feature-view-steps { list-style: none; margin: var(--sp-4) 0 0; padding: 0; display: grid; gap: var(--sp-4); }
.feature-view-step { display: grid; gap: var(--sp-3); min-width: 0; }
.feature-view-step-head { margin: 0; display: flex; align-items: center; gap: var(--sp-3); color: var(--fg); font-size: var(--fs-lg); line-height: var(--lh-lg); }
.feature-view-note { margin: 0; color: var(--muted); font-size: var(--fs-sm); line-height: var(--lh-sm); padding-left: calc(var(--sp-10) + var(--sp-3)); }
.feature-view-cmd { position: relative; min-width: 0; max-width: 100%; background: var(--card); border: 1px solid var(--line); border-radius: var(--r-control); transition: border-color var(--dur-2) var(--ease-std); }
.feature-view-cmd code { display: block; min-width: 0; overflow-x: auto; padding: calc(var(--sp-2) + var(--sp-8)) var(--sp-4) var(--sp-3) var(--sp-4); margin: 0; background: none; border: 0; border-radius: 0; font-family: var(--font-mono); font-size: var(--fs-xs); line-height: var(--lh-xs); color: var(--fg); white-space: pre; }
@media (hover: hover) { .feature-view-cmd:has(.cpy:hover) { border-color: var(--line-strong); } }
.feature-view-cmd .cpy { position: absolute; top: var(--sp-2); right: var(--sp-2); display: inline-flex; align-items: center; gap: var(--sp-2); min-height: var(--target-sm); padding: 0 var(--sp-2); background: none; border: 0; color: var(--muted); font: inherit; font-size: var(--fs-xs); line-height: var(--lh-xs); white-space: nowrap; cursor: pointer; -webkit-tap-highlight-color: transparent; transition: color var(--dur-2) var(--ease-std); }
.feature-view-cmd .cpy:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (hover: hover) { .feature-view-cmd .cpy:hover { color: var(--fg); } }
.feature-view-cmd .cpy.copied { color: var(--accent); }
.feature-view-cmd .cpy.blocked { color: var(--fg); }
.feature-view-cmd .cpy-ico { flex: none; width: var(--sp-4); height: var(--sp-4); }
.feature-view-term { background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-surface); overflow: hidden; }
.feature-view-term figcaption { padding: var(--sp-3) var(--sp-4); color: var(--muted); font-size: var(--fs-xs); line-height: var(--lh-xs); border-top: 1px solid var(--line); }
/* .fig-terminal: a real terminal window, a title bar (three dots on the line/raised tokens, the command as a mono window title) over a
   canvas-token body. No new radius: the frame is clipped by the figure's own --r-surface. */
.fig-terminal .term-bar { display: flex; align-items: center; gap: 6px; height: 28px; padding: 0 var(--sp-4); border-bottom: 1px solid var(--line); background: var(--card); }
.fig-terminal .term-bar i { width: 7px; height: 7px; border-radius: 50%; flex: none; border: 1px solid var(--line); background: var(--raised); }
.fig-terminal .term-bar span { margin-left: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-mono); font-size: var(--fs-xs); line-height: var(--lh-xs); color: var(--muted); }

/* the relay's rows below the key (2026-10-10, the zig-zag): each is a .feature-view of a heading, one muted line of prose per sentence and
   one picture, spaced under the one above. The text is always first in the markup, so a phone stacks text then picture; a flipped row
   (.feature-view-flip) puts its picture on the left at tablet and up. A picture may carry two small thumbnails under it, each captioned. */
.feature-view + .feature-view, .relay-card + .feature-view { margin-top: var(--f-gap); }
.feature-view-thumbs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); margin-top: var(--sp-3); }
.feature-view-thumb { margin: 0; min-width: 0; }
.feature-view-thumb .feature-view-win { border-radius: var(--r-control); }
.feature-view-thumb figcaption { margin-top: var(--sp-2); color: var(--muted); font-size: var(--fs-xs); line-height: var(--lh-xs); }
@media (min-width: 768px) {
  .feature-view-flip { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .feature-view-flip .feature-view-text { grid-column: 2; grid-row: 1; }
  .feature-view-flip .feature-view-shot { grid-column: 1; grid-row: 1; }
}

/* the API view: the three steps are plain text at the left, and the right column is the code, three cards in a stack: the env and curl
   cards copy (their buttons are .feature-view-cmd's), the response card does not (it is an example of what comes back, not a command). */
.feature-view-cards { display: grid; gap: var(--sp-3); align-content: start; min-width: 0; }
.feature-view-fig { margin: 0; min-width: 0; }
.feature-view-fig figcaption { margin-top: var(--sp-2); color: var(--muted); font-size: var(--fs-xs); line-height: var(--lh-xs); }
.feature-view-card-label { position: absolute; top: var(--sp-2); left: var(--sp-4); margin: 0; color: var(--muted); font-size: var(--fs-xs); line-height: var(--lh-xs); }
/* the API cards' syntax, "superbot blue" (2026-10-09): coloured by role in ONE accent family, not by term.css's terminal palette. Env
   names, the curl command and $VARs read in --fg; flags, JSON keys and URLs in --accent; strings and numbers in a lighter tint of the accent
   (55% accent, the rest --fg, mixed in oklab); punctuation, braces, the backslash, = and the ellipsis in --muted. */
.feature-view-cards .api-tk-name { color: var(--fg); }
.feature-view-cards .api-tk-key, .feature-view-cards .api-tk-flag, .feature-view-cards .api-tk-url, .mcp-prompt .api-tk-url { color: var(--accent); }
.feature-view-cards .api-tk-str, .feature-view-cards .api-tk-num { color: color-mix(in oklab, var(--accent) 55%, var(--fg)); }
.feature-view-cards .api-tk-punct { color: var(--muted); }
/* the three code blocks scroll sideways (.feature-view-cmd code), so each is a keyboard stop with its own ring: an inward outline, as the shot pictures draw theirs */
.feature-view-cards code:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.feature-view-step-head a { color: var(--accent); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: var(--sp-1); }
.feature-view-step-head a:hover { text-decoration-thickness: 2px; }

/* each view's closing control (2026-10-10): the relay view ends on its /download card, centred under the view; the API view installs
   nothing, so its control is the reference, left under its steps with the OpenAPI spec as a plain link beside it. The button is the
   close's size (.features .foot .sb-btn), full width on a phone like the close's. */
.route-cta { margin: var(--f-gap) 0 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--sp-3) var(--sp-6); }
.route-cta-start { margin-top: var(--sp-4); justify-content: flex-start; }
.route-cta .sb-btn { min-height: var(--control-h); padding: 0 var(--sp-8); font-size: var(--fs-lg); border-radius: var(--r-control); }
.route-cta-link { color: var(--accent); font-size: var(--fs-base); line-height: var(--lh-base); text-decoration: underline; text-underline-offset: var(--sp-1); white-space: nowrap; }
@media (max-width: 600px) { .route-cta:not(.route-cta-start) .sb-btn { width: 100%; } }

/* the MCP view (2026-10-10, "in terminal"): step 1's copy is ONE wide accent button, the view's one filled control, and the terminal's
   first input is the whole prompt, soft-wrapped with a hanging indent after "> ". The "> " is a ::before, so Copy (innerText) takes the
   three lines and nothing else. A URL may break only at a "/" (the <wbr> after it). The terminal's other lines are no-wrap rows. */
.mcp-copy { display: flex; align-items: center; justify-content: center; gap: var(--sp-3); width: 100%; min-height: var(--target); padding: var(--sp-3) var(--sp-4); border: 1px solid var(--accent); border-radius: var(--r-control); background: var(--accent); color: var(--bg); font-family: var(--font-ui); font-size: var(--fs-base); line-height: var(--lh-base); font-weight: 550; cursor: pointer; -webkit-tap-highlight-color: transparent; transition: filter var(--dur-2) var(--ease-std), background-color var(--dur-2) var(--ease-std), color var(--dur-2) var(--ease-std); }
.mcp-copy .cpy-label { white-space: nowrap; }
.mcp-copy-ico { flex: none; width: var(--sp-5); height: var(--sp-5); }
.mcp-copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (hover: hover) { .mcp-copy:hover { filter: brightness(1.08); } }
.mcp-copy:active { filter: brightness(0.94); }
.mcp-copy.copied { background: var(--raised); border-color: var(--accent); color: var(--accent); }
.mcp-copy.blocked { background: var(--raised); color: var(--fg); }
.feature-view-term .mcp-term { margin: 0; padding: var(--sp-4); background: var(--bg); color: var(--fg); font-family: var(--font-mono); font-size: var(--fs-xs); line-height: var(--lh-sm); white-space: normal; overflow-x: auto; }
@media (pointer: coarse) { .feature-view-term .mcp-term { font-size: var(--fs-sm); line-height: var(--lh-sm); } }
.mcp-prompt { display: block; margin: 0 0 var(--sp-3); padding-left: 2ch; text-indent: -2ch; white-space: normal; overflow-wrap: normal; word-break: normal; }
.mcp-prompt::before { content: "> "; }
.mcp-row { display: block; white-space: pre; }

/* the full-size pictures (2026-10-10, features-page.js mountShots): each raster picture of a relay view is a button that fills its window
   and shows the picture unchanged. Zoom-in cursor; a quiet border on the window under (hover: hover); a 2px inner ring for the keyboard.
   The one dialog (.shot-dialog) is a native <dialog> opened with showModal(): the picture at its natural size (capped to the viewport,
   never upscaled), a Close control at the top right, and a backdrop that dismisses. Motion is always on (motion.mdc): opacity and
   transform only. */
.shot-open { display: block; width: 100%; margin: 0; padding: 0; border: 0; background: none; font: inherit; color: inherit; cursor: zoom-in; border-radius: calc(var(--r-surface) - 1px); }
.shot-open img { display: block; width: 100%; height: auto; }
.shot-open:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.feature-view-thumb .shot-open { border-radius: calc(var(--r-control) - 1px); }
@media (hover: hover) { .feature-view-win:has(> .shot-open:hover) { border-color: var(--line-strong); } }
.shot-dialog { position: fixed; inset: 0; box-sizing: border-box; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: calc(var(--target) + var(--sp-8)) var(--sp-4) var(--sp-8); border: 0; background: transparent; color: var(--fg); overflow: hidden; }
.shot-dialog[open] { display: grid; justify-content: center; align-content: center; animation: shot-in var(--dur-2) var(--ease-std) both; }
.shot-dialog.is-closing { animation: shot-out var(--dur-2) var(--ease-std) both; }
.shot-dialog::backdrop { background: var(--bg); }
@keyframes shot-in { from { opacity: 0; transform: scale(0.98); } to { opacity: 1; transform: none; } }
@keyframes shot-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(0.98); } }
.shot-frame { display: grid; justify-items: center; gap: var(--sp-3); min-width: 0; max-width: 100%; margin: 0; }
.shot-frame img { display: block; width: auto; height: auto; max-width: 100%; max-height: calc(100vh - var(--target) - var(--sp-8) * 2); border: 1px solid var(--line); border-radius: var(--r-surface); background: var(--card); }
.shot-close { position: absolute; top: var(--sp-4); right: var(--sp-4); min-width: var(--target); min-height: var(--target); padding: 0 var(--sp-3); border: 1px solid var(--line); border-radius: var(--r-control); background: var(--card); color: var(--fg); font: inherit; font-size: var(--fs-sm); line-height: var(--lh-sm); cursor: pointer; }
.shot-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (hover: hover) { .shot-close:hover { border-color: var(--line-strong); } }
html.is-shot-open { overflow: hidden; }

/* ---- under 840px (Material's medium and compact classes): every tour
   stacks, its list a row of pills above the window that scrolls sideways
   edge to edge; nothing pins */
@media (max-width: 839px) {
  .fx-card { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); padding: var(--sp-6); }
  .fx-id { padding: 0 0 var(--sp-6); border-right: 0; border-bottom: 1px solid var(--line); }
  .fx-live { margin-left: 0; }
  .relay-card { padding: var(--sp-6); }
  .relay-tabs { display: flex; justify-content: space-between; }
  .relay-tab { padding: 0 var(--sp-2); font-size: var(--fs-base); line-height: var(--lh-base); }
  .fx-tour-body, .fx-tour.is-mirror .fx-tour-body { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); }
  .fx-tour.is-mirror .fx-list { order: 0; }
  .fx-tour h2, .fx-more h2 { margin-bottom: var(--sp-6); }
  .fx-list {
    display: flex; gap: var(--sp-2); overflow-x: auto; scrollbar-width: none;
    margin: 0 calc(var(--gutter-r) * -1) 0 calc(var(--gutter-l) * -1);
    padding: var(--sp-1) var(--gutter-r) var(--sp-1) var(--gutter-l);
    padding-left: var(--gutter-l); padding-right: var(--gutter-r);
    scroll-padding-inline: var(--gutter-l) var(--gutter-r);
  }
  .fx-list::-webkit-scrollbar { display: none; }
  .fx-list::before, .fx-tab::before { content: none; }
  .fx-tab {
    flex: none; gap: var(--sp-2); min-height: var(--target); padding: 0 var(--sp-4);
    border: 1px solid var(--line); border-radius: var(--r-pill);
    font-size: var(--fs-sm); line-height: var(--lh-sm); white-space: nowrap;
  }
  .fx-tab[aria-selected="true"] { border-color: var(--accent); }
  .fx-tab .fx-ic { width: var(--sp-4); height: var(--sp-4); }
  .fx-more ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
  .fx-card, .relay-card { padding: var(--sp-5); }
  .relay-tab { padding: 0 var(--sp-1); font-size: var(--fs-sm); line-height: var(--lh-sm); }
  .fx-cta, .features .foot { justify-self: stretch; }
  /* a phone: the hero's steps are wider than the card, so the row scrolls; its far edge fades (alpha only) so a
     cut step reads as more to scroll, and its end room lets the last step clear the fade */
  .fx-steps { padding-right: var(--sp-8); -webkit-mask-image: linear-gradient(to right, var(--fg) calc(100% - var(--sp-8)), transparent); mask-image: linear-gradient(to right, var(--fg) calc(100% - var(--sp-8)), transparent); }
  .fx-cta .sb-btn, .features .foot .sb-btn { width: 100%; }
}
/* the narrowest phones (site.css's 360px step): the relay tabs' three labels take the caption size so they keep one row in the card */
@media (max-width: 360px) { .relay-tab { font-size: var(--fs-xs); line-height: var(--lh-xs); } }
