/* ============================================================
   BigCap site — stylesheet

   Architecture: mobile-first. Base rules describe the smallest
   screen; `min-width` blocks at the bottom of this file add
   capability as space becomes available. Most sizing is fluid
   (clamp/min/max) and tuned so every value lands exactly on the
   original desktop measurement at 1280px, so the desktop
   composition is unchanged.

   Breakpoints (rem @ 16px root):
     base           0        — small phone
     30rem          480px    — large phone
     48rem          768px    — tablet portrait
     64rem         1024px    — tablet landscape / small laptop
     80rem         1280px    — desktop  + desktop navigation
     90rem         1440px    — wide desktop

   Navigation is a hamburger drawer below 80rem, full desktop bar
   at 80rem and up. See "Header / navigation".

   Palette is the source-of-truth app UI palette
   (see WEB-DESIGNER-HANDOFF.md §3).
   ============================================================ */

/* ---------- Design tokens ---------- */
:root {
  /* Brand palette */
  --bg:          #0E1116; /* page background */
  --bg-deep:     #0B0E13; /* footer */
  --bg-alt:      #10141b; /* inset / mock chrome */
  --panel:       #161B24; /* cards / sections */
  --panel-2:     #1D2430; /* raised elements */
  --panel-3:     #141922; /* large feature cards */
  --line:        #283041; /* borders, dividers */
  --text:        #E6E9EF; /* primary text */
  --muted:       #8A93A6; /* secondary text — 6.0:1 on --bg */
  --muted-2:     #B8BFCE; /* brighter secondary text */
  --accent:      #1E6BFF; /* primary CTA / fills / borders */
  --accent-2:    #0A4FD6; /* CTA gradient bottom / hover */
  --warn:        #F0B429; /* notices */
  --danger:      #FF5D5D; /* errors */
  --success:     #3DDC84; /* live/session indicators */

  /* Accent, lightened for *text* on dark surfaces. #1E6BFF is only
     3.5:1 against --bg, which fails WCAG AA for body-size links;
     this tint is 6.0:1. Fills and borders keep the pure accent. */
  --accent-link: #5B8DFF;
  --focus:       #9DC0FF; /* focus ring — reads against dark bg and blue fills */

  /* Accent tints (derived from --accent) */
  --accent-30:   rgba(30, 107, 255, 0.30);
  --accent-33:   rgba(30, 107, 255, 0.33); /* #1E6BFF55 */
  --accent-35:   rgba(30, 107, 255, 0.35);
  --accent-40:   rgba(30, 107, 255, 0.40); /* #1E6BFF66 */
  --accent-45:   rgba(30, 107, 255, 0.45);
  --accent-53:   rgba(30, 107, 255, 0.53); /* #1E6BFF88 */

  /* Effects */
  --accent-gradient: linear-gradient(180deg, var(--accent), var(--accent-2));
  --shadow-btn-sm:   0 4px 16px  var(--accent-35);
  --shadow-btn:      0 8px 30px  var(--accent-45);
  --shadow-btn-xl:   0 0 40px    var(--accent-35);
  --shadow-card:     0 30px 80px rgba(0, 0, 0, 0.55);
  --shadow-float:    0 24px 60px rgba(0, 0, 0, 0.45);
  --shadow-mascot:   0 24px 48px rgba(0, 0, 0, 0.50);
  /* `closest-side` is deliberate: the ending shape lands on the nearest
     edge of the box, so the wash is guaranteed to have reached full
     transparency by every edge whatever the hero's size or aspect ratio.
     A `farthest-corner` gradient (the default) overshoots the near edge
     and gets sliced off there. */
  --hero-glow: radial-gradient(ellipse closest-side at 60% 40%, rgba(30, 107, 255, 0.18), transparent);
  /* Text halos for the privacy band (text over an image) */
  --halo:    0 2px 10px rgba(14, 17, 22, 0.95), 0 0 22px rgba(14, 17, 22, 0.90);
  --halo-lg: 0 2px 12px rgba(14, 17, 22, 0.95), 0 0 28px rgba(14, 17, 22, 0.90), 0 0 46px rgba(14, 17, 22, 0.80);

  /* Typography */
  --font-sans: -apple-system, "Segoe UI", Roboto, system-ui, sans-serif;
  --font-mono: ui-monospace, "Cascadia Mono", Consolas, monospace;

  /* Fluid type scale. Each ramp runs from its small-phone size at
     320px to the original desktop size at 1280px, then holds. */
  --fs-hero:      clamp(2.125rem,  1.625rem + 2.50vw, 3.625rem); /* 34 → 58 */
  --fs-download:  clamp(1.75rem,   1.417rem + 1.67vw, 2.75rem);  /* 28 → 44 */
  --fs-section:   clamp(1.625rem,  1.417rem + 1.04vw, 2.25rem);  /* 26 → 36 */
  --fs-privacy:   clamp(1.5rem,    1.292rem + 1.04vw, 2.125rem); /* 24 → 34 */
  --fs-formats:   clamp(1.5rem,    1.333rem + 0.83vw, 2rem);     /* 24 → 32 */
  --fs-card:      clamp(1.1875rem, 1.125rem + 0.31vw, 1.375rem); /* 19 → 22 */
  --fs-spotlight: clamp(1.3125rem, 1.25rem  + 0.31vw, 1.5rem);   /* 21 → 24 */
  --fs-hero-sub:  clamp(1rem,      0.938rem + 0.31vw, 1.1875rem);/* 16 → 19 */
  --fs-lead:      clamp(1rem,      0.950rem + 0.16vw, 1.0625rem);/* 16 → 17 */
  --fs-btn-xl:    clamp(1rem,      0.917rem + 0.42vw, 1.25rem);  /* 16 → 20 */

  /* Radii */
  --radius-sm:   7px;
  --radius:     10px;
  --radius-lg:  12px;
  --radius-xl:  20px;
  --radius-pill: 999px;

  /* Layout. The gutter is fluid (16px on a small phone → 40px from
     1280px up) and never smaller than a display cutout inset. */
  --container:      1200px;
  --container-wide: 1140px; /* docs layout */
  --container-mid:  1100px; /* privacy band */
  --container-text:  780px; /* long-form legal copy */
  --gutter: max(
    clamp(1rem, 0.5rem + 2.5vw, 2.5rem),
    env(safe-area-inset-left),
    env(safe-area-inset-right)
  );
  --nav-h: 4rem; /* header height — drawer offset + anchor scroll offset */

  /* Minimum comfortable touch target (WCAG 2.2 AA target size) */
  --tap: 44px;
}

/* ---------- Base / reset ---------- */
* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* Keeps text zoom and OS font-size scaling working. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Offset in-page anchor targets so they clear the sticky header */
:target,
[id] { scroll-margin-top: calc(var(--nav-h) + 1rem); }

html,
body {
  margin: 0;
  padding: 0;
  background: var(--bg);
}

body {
  color: var(--text);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  /* The mascots are decorative art deliberately positioned to bleed
     past their sections. `clip` (not `hidden`) contains that bleed
     WITHOUT creating a scroll container — which would otherwise break
     `position: sticky` on the header. Every layout that could
     genuinely overflow has been fixed at source; this is only here
     for the intentional off-canvas artwork. */
  overflow-x: clip;
}

/* Scroll lock while the navigation drawer is open. The padding replaces
   the width the hidden scrollbar was occupying, so the page behind the
   drawer does not jump sideways. */
html.nav-open {
  overflow: hidden;
  padding-right: var(--scrollbar-gap, 0px);
}

::selection { background: var(--accent-33); }

.screen {
  min-height: 100vh;
  min-height: 100svh; /* small-viewport unit: no jump as browser chrome moves */
}

h1, h2, h3, p, ul { margin: 0; }

img, svg, video {
  max-width: 100%;
  height: auto;
}

/* <picture> is a source-selection wrapper, not a box — this keeps every
   existing `.some__image` layout rule applying to the <img> itself. */
picture { display: contents; }

/* Visible, high-contrast focus ring everywhere. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 3px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: fixed;
  top: 0;
  left: var(--gutter);
  z-index: 100;
  padding: 0.75rem 1.25rem;
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--accent);
  color: #fff;
  font-size: 0.875rem;
  font-weight: 700;
  text-decoration: none;
  transform: translateY(-150%);
  transition: transform 0.15s ease;
}
/* `:focus`, not `:focus-visible` — a skip link is only ever reached by
   keyboard or assistive tech, and it must reveal itself the moment it
   takes focus. */
.skip-link:focus { transform: none; }

/* ---------- Shared atoms ---------- */
.dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  display: inline-block;
  flex-shrink: 0;
}
.dot--success { width: 8px; height: 8px; background: var(--success); }

/* Tick mark for feature lists. A background image rather than an <img>:
   it is purely decorative and the SVG carries its own colors, so there
   is nothing to inherit and nothing to announce. Each list sets its own
   margin-top to optically centre it on that list's first line box. */
.bullet-list__mark,
.spotlight__mark {
  flex: none;
  width: 20px;
  height: 20px;
  background: url("assets/checkbox.svg") center / contain no-repeat;
}

/* Revealing list. Add `reveal-list` to a <ul> and its lines fade in one
   after another, hold, then all clear together and the pass repeats.
   Gated on `.is-playing`, which the script sets while the list is on
   screen — the same treatment the browser mock and the preset chips get.

   The stagger is baked into the keyframes rather than expressed as
   `animation-delay`, because a delay offsets the whole timeline: the
   exit would inherit the same stagger and the lines would leave one by
   one. Sharing one timeline is what lets them leave at once. Every ramp
   is 10% of the cycle (0.6s), so lines arrive at 0.6 / 1.2 / 1.8s and
   all go at 5.28s. Three ramps, so lists longer than three lines need a
   fourth keyframe block. */
@keyframes list-line-1 {
  0%   { opacity: 0; transform: translateY(6px); }
  10%  { opacity: 1; transform: translateY(0); }
  88%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(6px); }
}
@keyframes list-line-2 {
  0%,
  10%  { opacity: 0; transform: translateY(6px); }
  20%  { opacity: 1; transform: translateY(0); }
  88%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(6px); }
}
@keyframes list-line-3 {
  0%,
  20%  { opacity: 0; transform: translateY(6px); }
  30%  { opacity: 1; transform: translateY(0); }
  88%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(6px); }
}
/* Hidden until the first pass brings them up. `is-armed` is set by the
   script, and only once it has committed to running the loop — if there
   is no script, no IntersectionObserver, or reduced motion is asked
   for, the class never lands and the lines are simply visible. Content
   is never left hidden by a stylesheet alone. */
.reveal-list.is-armed > li { opacity: 0; }
/* Longhands, not the shorthand: the shorthand would reset
   `animation-name` back to `none` and fight the per-line rules below. */
.reveal-list.is-playing > li {
  animation-duration: 6s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-fill-mode: both;
}
.reveal-list.is-playing > li:nth-child(1) { animation-name: list-line-1; }
.reveal-list.is-playing > li:nth-child(2) { animation-name: list-line-2; }
.reveal-list.is-playing > li:nth-child(3) { animation-name: list-line-3; }

.badge {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--panel);
  font-size: 13px;
  color: var(--muted);
}

/* Camera glyph built from borders (used in buttons / mock toolbar) */
.icon-camera {
  width: 18px;
  height: 18px;
  border: 2px solid currentColor;
  border-radius: 4px;
  display: inline-block;
  position: relative;
  flex-shrink: 0;
}
.icon-camera::after {
  content: "";
  position: absolute;
  left: 4px;
  right: 4px;
  bottom: -2px;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
}
.icon-camera--sm { width: 13px; height: 13px; border-radius: 3px; }
.icon-camera--sm::after { left: 2px; right: 2px; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border: none;
  cursor: pointer;
  text-decoration: none;
  color: #fff;
  font-weight: 700;
  background: var(--accent-gradient);
  border-radius: var(--radius);
  transition: filter 0.15s ease, transform 0.15s ease;
}
/* inline-block so the hover bob below has something to transform. */
.btn__glyph { font-size: 20px; line-height: 1; display: inline-block; }
@keyframes btn-glyph-bob {
  0%,
  100% { transform: translateY(-3px); }
  50%  { transform: translateY(3px); }
}

.btn--sm {
  min-height: 36px;
  padding: 8px 18px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  box-shadow: var(--shadow-btn-sm);
}
.btn--lg {
  min-height: var(--tap);
  padding: 15px clamp(1.25rem, 0.75rem + 2.5vw, 1.875rem);
  font-size: clamp(0.9375rem, 0.896rem + 0.21vw, 1.0625rem); /* 15 → 17 */
  box-shadow: var(--shadow-btn);
}
.btn--xl {
  min-height: var(--tap);
  padding: clamp(1rem, 0.917rem + 0.42vw, 1.125rem) clamp(1.25rem, 0.583rem + 3.33vw, 2.625rem);
  border-radius: 14px;
  font-size: var(--fs-btn-xl);
  background: var(--accent);
  box-shadow: var(--shadow-btn-xl);
  text-align: center;
  text-wrap: balance;
}
/* Keeps the glyph a step above the label, which is what the 20px glyph
   does against .btn--lg's 17px. */
.btn--xl .btn__glyph { font-size: 24px; }

/* Hover affordances are for pointer devices only — on touch they
   latch after a tap and read as a stuck state. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover { filter: brightness(1.1); }
  /* The 1px lift stays: the scale reads as the button coming forward,
     the lift is what keeps it off the page. */
  .btn--lg:hover,
  .btn--xl:hover { transform: translateY(-1px) scale(1.05); }
  /* Runs only while hovered, so neither download call to action is
     animating at rest. */
  .btn--lg:hover .btn__glyph,
  .btn--xl:hover .btn__glyph { animation: btn-glyph-bob 0.9s ease-in-out infinite; }
}

/* ============================================================
   Header / navigation

   Below 80rem: brand + hamburger button; the link list becomes a
   fixed slide-in drawer with a scrim, focus trap and scroll lock
   (behaviour in assets/site.js).
   At 80rem and up: the drawer styles are unset and the list is the
   original inline desktop bar.
   ============================================================ */
.site-nav {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: var(--nav-h);
  /* 44px trigger + 2×9px + 1px border = 63px, so --nav-h (64px) is the
     used height in both nav modes. The drawer is offset by exactly
     --nav-h; keeping the bar at-or-above that height means text zoom
     can only make them overlap, never leave a gap. */
  padding: 9px var(--gutter);
  border-bottom: 1px solid var(--line);
}
/* The translucent blur lives on a pseudo-element, not on .site-nav
   itself: `backdrop-filter` on an element makes it a containing block
   for fixed-position descendants, which would break the drawer. */
.site-nav::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(14, 17, 22, 0.85);
  backdrop-filter: blur(12px);
}

.site-nav__brand { display: flex; align-items: center; gap: 12px; min-width: 0; }
.site-nav__home { display: inline-flex; text-decoration: none; }
.site-nav__logo { height: 26px; width: auto; display: block; }
/* Dropped on the narrowest phones so the brand and the trigger never
   compete for the bar; restored in the 30rem block. */
.site-nav__by {
  display: none;
  font-size: 12px;
  color: var(--muted);
  border-left: 1px solid var(--line);
  padding-left: 12px;
  white-space: nowrap;
}


/* Hamburger trigger. Hidden until the `js` class is set (inline script
   in <head>), because the drawer it controls is script-driven — with
   scripting off the links stay in the flow as a plain wrapped list. */
.nav-toggle { display: none; }
.js .nav-toggle {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: var(--tap);
  min-width: var(--tap);
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
}
.nav-toggle__bars {
  position: relative;
  width: 18px;
  height: 12px;
  flex-shrink: 0;
}
.nav-toggle__bars span {
  position: absolute;
  left: 0;
  right: 0;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform 0.25s ease, opacity 0.15s ease;
}
.nav-toggle__bars span:nth-child(1) { top: 0; }
.nav-toggle__bars span:nth-child(2) { top: 5px; }
.nav-toggle__bars span:nth-child(3) { top: 10px; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* No-JS baseline: the links simply wrap onto a second row of the bar. */
.site-nav { flex-wrap: wrap; }
.site-nav__menu {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 16px;
  padding-bottom: 6px;
}

/* Drawer */
.js .site-nav { flex-wrap: nowrap; }
.js .site-nav__menu {
  position: fixed;
  z-index: 1; /* within .site-nav's stacking context — above the scrim */
  top: var(--nav-h);
  right: 0;
  bottom: 0;
  width: min(22rem, 86vw);
  flex: none;
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: 2px;
  padding:
    1.25rem
    max(1.25rem, env(safe-area-inset-right))
    max(1.5rem, env(safe-area-inset-bottom))
    1.25rem;
  background: var(--panel);
  border-left: 1px solid var(--line);
  box-shadow: -24px 0 60px rgba(0, 0, 0, 0.5);
  overflow-y: auto;
  overscroll-behavior: contain;
  transform: translateX(100%);
  visibility: hidden; /* keeps links out of the tab order when closed */
  transition: transform 0.28s ease, visibility 0s linear 0.28s;
}
.js .site-nav__menu[data-open="true"] {
  transform: none;
  visibility: visible;
  transition: transform 0.28s ease;
}
.site-nav__link {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0.5rem 0.75rem;
  border-radius: 8px;
  color: var(--text);
  text-decoration: none;
  font-size: 1rem;
}
.site-nav__menu .btn { margin-top: 1rem; min-height: var(--tap); }

.nav-scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(6, 8, 12, 0.6);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.28s ease, visibility 0s linear 0.28s;
}
html.nav-open .nav-scrim {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.28s ease;
}

@media (hover: hover) and (pointer: fine) {
  .site-nav__link:hover { color: var(--accent-link); }
  .nav-toggle:hover { border-color: var(--accent-40); }
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  width: min(100%, var(--container));
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-block:
    clamp(2.5rem, 1.5rem + 5vw, 5.5rem)      /* 40 → 88 */
    clamp(3.5rem, 2.667rem + 4.17vw, 6rem);  /* 56 → 96 */
  display: grid;
  gap: clamp(2rem, 1.667rem + 1.67vw, 3rem); /* 32 → 48 */
  align-items: center;
}
/* Positioned only so it paints above the glow, which precedes it in the
   DOM — avoids a negative z-index. */
.hero__copy {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: clamp(1rem, 0.667rem + 1.67vw, 1.5rem);
}
.hero__title {
  font-size: var(--fs-hero);
  line-height: 1.05;
  font-weight: 800;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.hero__subtitle {
  font-size: var(--fs-hero-sub);
  line-height: 1.6;
  color: var(--muted);
  max-width: 46ch;
  text-wrap: pretty;
}
/* Stacked on a small phone so the CTA gets the full column width;
   side-by-side from 30rem, as on desktop. */
.hero__cta {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 14px;
  margin-top: 8px;
}
.hero__meta { font-size: 13px; color: var(--muted); line-height: 1.5; }
.hero__visual { position: relative; }
/* Spans the whole hero container — which is the full viewport width up
   to --container, and stays centred beyond it. Never overflows, because
   it is pinned to its containing block rather than to `100vw` (which
   would include the scrollbar). */
.hero__glow {
  position: absolute;
  inset-block: -60px;
  inset-inline: 0;
  background: var(--hero-glow);
  pointer-events: none;
}
.hero__screenshot {
  position: relative;
  width: 100%;
  max-width: 480px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-card);
  display: block;
  /* Slow hover/float. Transform-only, so it runs on the compositor and
     never triggers layout — no reflow, no layout shift. The mascot
     stays planted, which reads as the window hovering above it. */
  animation: hero-float 7s ease-in-out infinite;
}
@keyframes hero-float {
  0%,
  100% { transform: translateY(0); }
  50%  { transform: translateY(-50px); }
}
/* Mascot is sized against the viewport so it stays a garnish on a
   phone instead of dominating the hero. */
.hero__mascot {
  position: absolute;
  right: 0;
  bottom: -1.5rem;
  width: clamp(120px, 30vw, 210px);
  height: auto;
  filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.5));
  pointer-events: none;
}

/* ---------- "Why it's different" strip ---------- */
.why {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}
.why__grid {
  width: min(100%, var(--container));
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-block: clamp(2.5rem, 2.167rem + 1.67vw, 3.5rem); /* 40 → 56 */
  display: grid;
  /* Intrinsic: 1 column on a small phone, 2 from ~480px,
     3 from ~768px, 4 from ~1024px. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: clamp(1.5rem, 1.333rem + 0.83vw, 2rem); /* 24 → 32 */
}
.why__item { display: flex; flex-direction: column; gap: 8px; }
.why__title { font-size: 15px; font-weight: 700; color: var(--text); }
.why__body { font-size: 14px; line-height: 1.55; color: var(--muted); }

/* ---------- Section headings ---------- */
.section__title {
  margin: 0 0 12px;
  font-size: var(--fs-section);
  font-weight: 800;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.section__lead {
  margin: 0 0 clamp(1.75rem, 1.417rem + 1.67vw, 2.5rem); /* 28 → 40 */
  font-size: var(--fs-lead);
  color: var(--muted);
  max-width: 60ch;
  text-wrap: pretty;
}

/* ---------- Features grid ---------- */
.features {
  width: min(100%, var(--container));
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-block:
    clamp(3.5rem, 2.667rem + 4.17vw, 6rem)   /* 56 → 96 */
    clamp(2rem, 1.667rem + 1.67vw, 3rem);    /* 32 → 48 */
}
.features__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1rem, 0.917rem + 0.42vw, 1.25rem); /* 16 → 20 */
}
.feature-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.25rem, 1.125rem + 0.63vw, 1.625rem); /* 20 → 26 */
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* Positioned so the hover lift can raise it above its neighbours. */
  position: relative;
  transition: border-color 0.15s ease, background-color 0.15s ease, transform 0.2s ease;
  user-select: none;
}
.feature-card__icon {
  width: 38px;
  height: 38px;
  border-radius: 9px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent-link);
  font-size: 18px;
  font-weight: 700;
  transition:
    transform 0.2s ease,
    background-color 0.2s ease,
    border-color 0.2s ease,
    color 0.2s ease;
}
.feature-card__title { font-size: 16px; font-weight: 700; }
.feature-card__body { font-size: 14px; line-height: 1.6; color: var(--muted); }

@media (hover: hover) and (pointer: fine) {
  .feature-card:hover {
    border-color: var(--accent-40);
    background-color: var(--panel-2);
    /* Grows over the 20px grid gap, so it has to paint above the
       cards it now overlaps. */
    transform: scale(1.1);
    z-index: 1;
  }
  /* Scale is applied about the centre first, then the lift, so the card
     rises by the stated amount rather than that plus half its growth. */
  .output-card:hover {
    transform: translateY(-20px) scale(1.02);
    background-color: var(--panel-2);
    z-index: 1;
  }

  /* The tile fills with the pure brand accent and its glyph flips to
     white. Nested inside the card's own scale, so the icon reads as
     1.2 against the card it sits on. */
  .feature-card:hover .feature-card__icon {
    transform: scale(1.2);
    background-color: var(--accent);
    border-color: var(--accent);
    color: #fff;
  }
}

/* ---------- Browse & Capture spotlight ---------- */
.spotlight {
  width: min(100%, var(--container));
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-block: clamp(1.5rem, 1rem + 2.5vw, 3rem); /* 24 → 48 */
}
.spotlight__panel {
  position: relative;
  display: grid;
  gap: clamp(2rem, 1.5rem + 2.5vw, 3.5rem); /* 32 → 56 */
  align-items: center;
  background: var(--panel-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  padding-block: clamp(1.75rem, 1rem + 3.75vw, 4rem);   /* 28 → 64 */
  padding-inline: clamp(1.25rem, 0.5rem + 3.75vw, 3.5rem); /* 20 → 56 */
}
/* Decorative standing figure. Rendered as a background image inside
   the 80rem block so phones and tablets never download it. */
.spotlight__mascot { display: none; }

.spotlight__copy { display: flex; flex-direction: column; gap: 18px; }
.spotlight__eyebrow {
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 600;
  color: var(--accent-link);
}
.spotlight__title {
  font-size: var(--fs-spotlight);
  font-weight: 600;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.spotlight__text {
  font-size: var(--fs-lead);
  line-height: 1.7;
  color: var(--muted);
  text-wrap: pretty;
}
.spotlight__list {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.spotlight__item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 15px;
  line-height: 1.5;
  color: var(--text);
}
.spotlight__mark { margin-top: 1px; }


/* ---------- Mock in-app browser window ---------- */
.browser {
  position: relative;
  /* The mock address bar is `white-space: nowrap`, giving this element a
     ~550px min-content width. Below the desktop breakpoint that would
     push the single-column spotlight panel wider than the viewport — the
     original stylesheet papered over exactly this with
     `min-width: 1020px` plus a document-level overflow clip. Inline-size
     containment makes the mock size from its grid track instead, so it
     ellipsizes rather than overflowing.

     Dropped again at 80rem: up there the same intrinsic width is what
     widens the panel's right column past the bare 1.15fr ratio, and that
     is the original desktop proportion. Size containment only — no
     layout containment — so .browser__session still positions against
     this element. */
  contain: inline-size;
}
.browser__frame {
  border-radius: 14px;
  overflow: hidden;
  box-shadow: var(--shadow-float);
  border: 1px solid var(--line);
}
/* Small phone: the chevrons go, the address bar takes its own row and
   the capture button fills the second — nothing squeezed, nothing
   clipped. Restored to a single row at 30rem (see breakpoints). */
.browser__toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  padding: 12px;
  background: var(--bg-alt);
}
.browser__nav-btns { display: none; gap: 8px; color: var(--muted); font-size: 15px; }
.browser__address {
  flex: 1 1 100%;
  order: -1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.browser__url {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.browser__capture {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 10px 18px;
  border-radius: 9px;
  background: var(--accent);
  color: #fff;
  flex: 1;
  font-size: 14px;
  font-weight: 700;
  white-space: nowrap;
}

/* Captured page — intentionally a light "website" inside the dark UI.
   These greys are illustrative content, not brand tokens. */
.browser__page {
  background: #fff;
  position: relative; /* anchors the capture flash overlay */
}
/* Shutter flash. Idle at opacity 0, so it is invisible unless the demo
   loop is running; clipped to the rounded frame by .browser__frame. */
.browser__page::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--accent);
  opacity: 0;
  pointer-events: none;
}
.browser__page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid #E5E8EE;
}
.browser__brand { display: flex; align-items: center; gap: 10px; }
.browser__brand-dot { width: 14px; height: 14px; border-radius: 50%; background: var(--accent); flex-shrink: 0; }
.browser__brand-bar { width: 90px; height: 9px; border-radius: 5px; background: #DDE2EA; }
.browser__signed-in {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px 6px 6px;
  border-radius: var(--radius-pill);
  background: #EEF1F5;
  font-size: 12px;
  font-weight: 600;
  color: #3A4354;
  white-space: nowrap;
}
.browser__avatar { width: 18px; height: 18px; border-radius: 50%; background: #C3CAD6; flex-shrink: 0; }
.browser__body {
  display: grid;
  /* Narrow sidebar so the content column stays usable on a phone;
     back to the original 130px at 30rem. */
  grid-template-columns: 72px minmax(0, 1fr);
  min-height: 200px;
}
.browser__sidebar {
  padding: 14px 10px;
  border-right: 1px solid #E5E8EE;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.browser__content {
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.browser__heading { width: 34%; height: 11px; border-radius: 5px; background: #D4D9E2; }
.browser__cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.browser__card { height: 44px; border-radius: 8px; border: 1px solid #E5E8EE; background: #fff; }
.browser__block {
  border: 1px solid #E5E8EE;
  border-radius: 8px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.skeleton { height: 8px; border-radius: 4px; background: #E2E6ED; }
.browser__sidebar .skeleton:nth-child(1) { width: 85%; background: #A9C4FF; }
.browser__sidebar .skeleton:nth-child(2) { width: 95%; }
.browser__sidebar .skeleton:nth-child(3) { width: 70%; }
.browser__sidebar .skeleton:nth-child(4) { width: 88%; }
.browser__block .skeleton:nth-child(1) { width: 92%; }
.browser__block .skeleton:nth-child(2) { width: 78%; }
.browser__block .skeleton:nth-child(3) { width: 85%; }
.browser__block .skeleton:nth-child(4) { width: 60%; }
.browser__session {
  position: absolute;
  right: 18px;
  bottom: -16px;
  max-width: calc(100% - 36px);
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 9px 16px;
  border-radius: var(--radius-pill);
  background: var(--panel-2);
  border: 1px solid var(--line);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}
.browser__session-text { font-family: var(--font-mono); font-size: 12px; color: var(--muted-2); }

/* Demo loop: the capture button is pressed, then the session pill pops
   back in. Only runs while the mock is on screen — assets/site.js adds
   `is-playing` from an IntersectionObserver — so it also restarts from
   the button press each time it is scrolled into view rather than being
   joined mid-cycle.

   Both keyframes share one duration so they stay in step, and both begin
   and end in the component's resting state, so starting and stopping the
   loop never produces a jump. */
@keyframes capture-press {
  0%,
  16%       { transform: none; filter: none; }
  20%,
  24%       { transform: scale(0.94); filter: brightness(0.82); }
  30%,
  100%      { transform: none; filter: none; }
}

/* Fires as the button releases. `linear` timing with the shape carried
   by the stops: a near-instant rise, then a fast decay and a tail —
   which is what reads as a camera flash. */
@keyframes capture-flash {
  0%,
  24%       { opacity: 0; }
  25%       { opacity: 0.75; }
  28%       { opacity: 0.35; }
  33%,
  100%      { opacity: 0; }
}

@keyframes session-pop {
  0%,
  8%        { opacity: 0; transform: none; }
  14%,
  26%       { opacity: 0; transform: translateY(8px) scale(0.85); }
  34%       { opacity: 1; transform: translateY(0) scale(1.06); } /* slight overshoot */
  40%,
  95%      { opacity: 1; transform: none; }
  100%      { opacity: 0; transform: none; }
}

.browser.is-playing .browser__capture {
  animation: capture-press 5.5s ease-in-out infinite;
}
.browser.is-playing .browser__page::after {
  animation: capture-flash 5.5s linear infinite;
}
.browser.is-playing .browser__session {
  animation: session-pop 5.5s ease-in-out infinite;
}

/* ---------- Formats ---------- */
.formats {
  width: min(100%, var(--container));
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-block:
    clamp(1.5rem, 1rem + 2.5vw, 3rem)          /* 24 → 48 */
    clamp(3.5rem, 2.667rem + 4.17vw, 6rem);    /* 56 → 96 */
  display: grid;
  gap: clamp(2rem, 1.5rem + 2.5vw, 3.5rem);    /* 32 → 56 */
  align-items: center;
}
/* DOM order is heading-then-illustration (the reading order that makes
   sense on a phone and to a screen reader); the desktop block below
   places the illustration on the left. */
.formats__visual { position: relative; display: flex; justify-content: center; }
/* Sized by the image inside it, so the clip that overlays it needs no
   dimensions of its own and cannot shift the layout. */
.formats__media { position: relative; width: 100%; max-width: 400px; }
.formats__image { width: 100%; max-width: 400px; border-radius: var(--radius-lg); display: block; }
.formats__copy { display: flex; flex-direction: column; gap: 20px; }
.formats__title { font-size: var(--fs-formats); font-weight: 800; letter-spacing: -0.01em; text-wrap: balance; }
.chips { display: flex; flex-wrap: wrap; gap: 10px; }
.chip-tag {
  padding: 6px 16px;
  border-radius: 8px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
}

/* The accent fill walks the three formats, 2s each. One shared 6s
   keyframe; the offsets come from negative delays, so the chips are in
   step from the very first frame rather than lighting up late one after
   another. `step-end` holds each value and then switches, with no
   interpolation — a background tween between two chips would read as a
   crossfade rather than a selection moving. Same treatment as the size
   presets in the spotlight. */
@keyframes chip-cycle {
  0% {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
  }
  33.334%,
  100% {
    background: var(--panel-2);
    border-color: var(--line);
    color: var(--text);
  }
}
.chips.is-playing .chip-tag { animation: chip-cycle 6s step-end infinite; }
.chips.is-playing .chip-tag:nth-child(2) { animation-delay: -4s; }
.chips.is-playing .chip-tag:nth-child(3) { animation-delay: -2s; }
.bullet-list {
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.bullet-list li {
  display: flex;
  align-items: flex-start; /* mark stays on the first line when text wraps */
  gap: 12px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--muted);
}
.bullet-list__mark { margin-top: 2px; }

/* ---------- Output cards ("dialed in") ---------- */
.output {
  width: min(100%, var(--container));
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-bottom: clamp(3.5rem, 2.667rem + 4.17vw, 6rem); /* 56 → 96 */
}
.output__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1rem, 0.833rem + 0.83vw, 1.5rem); /* 16 → 24 */
}
.output-card {
  background: var(--panel-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  padding: clamp(1.25rem, 0.833rem + 2.08vw, 2.5rem) clamp(1.25rem, 0.833rem + 2.08vw, 2.5rem) 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow: hidden; /* crops the app mock — the "peek" effect is intentional */
  /* Positioned so the hover lift can raise it above the sibling card. */
  position: relative;
  transition: transform 0.25s ease, background-color 0.15s ease;
  user-select: none;
}
.output-card__title { font-size: var(--fs-card); font-weight: 700; }
.output-card__text {
  margin: 0 0 18px;
  font-size: 15px;
  line-height: 1.7;
  color: var(--muted);
  text-wrap: pretty;
}

/* App-window mock shared by both output cards.
   A container, so its internal controls reflow against the card they
   sit in rather than the viewport. */
.app-mock {
  container-type: inline-size;
  container-name: appmock;
  max-width: 480px;
  width: 100%;
  margin: 0 auto;
  background: var(--bg-alt);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* The mock is deliberately cropped by .output-card — a "peek" into the
     app. Narrow columns make the panel taller, so the cut can land
     mid-row; the mask turns that hard edge into a fade. Desktop keeps
     the original hard crop, which lands between rows. */
  max-height: 420px;
  mask-image: linear-gradient(to bottom, #000 84%, transparent 100%);
}
.app-mock__browse {
  padding: 11px 16px;
  border: 1px solid var(--line);
  border-radius: 9px;
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted-2);
}
.menu-tabs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.menu-tab {
  padding: 11px 16px;
  border: 1px solid var(--line);
  border-radius: 9px;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.menu-tab__caret { font-size: 10px; color: var(--muted); }
.menu-tab--active { border-color: var(--accent-53); background: var(--panel); }
.menu-tab--active .menu-tab__caret { color: var(--accent-link); }

.app-panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.app-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 16px;
}
.field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.field--end { align-items: flex-end; }
.field__label { font-size: 12px; font-weight: 600; color: var(--muted); }
.field__note { font-size: 12px; color: var(--muted); }
.field__note strong { color: var(--muted-2); }

.value {
  display: inline-block;
  padding: 8px 14px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  min-width: 70px;
}
.chip {
  padding: 6px 14px;
  background: var(--bg-alt);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.unit { font-size: 12px; color: var(--muted); }

/* Segmented scale control (1× / 2×) */
.scale { display: inline-flex; }
.scale__opt { padding: 8px 14px; border: 1px solid var(--line); font-size: 13px; font-weight: 600; }
.scale__opt--on {
  background: var(--panel-2);
  border-color: var(--accent-53);
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  color: var(--text);
  font-weight: 700;
}
.scale__opt--off {
  background: transparent;
  border-left: none;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--muted);
}

/* Preset chips (Mobile / Tablet / Desktop / Large) */
.presets { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.preset {
  padding: 8px 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  text-align: center;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-2);
  white-space: nowrap;
}
.preset span { color: var(--muted); font-weight: 400; }
.preset--active { border-color: var(--accent); color: var(--text); font-weight: 700; }
.preset--active span { color: var(--accent-link); font-weight: 600; }

/* Demo loop: the active highlight steps through the four presets, two
   seconds each — one 8s cycle. Each chip runs the same keyframes offset
   by a negative delay, so they are all in step from the very first frame
   rather than starting late one after another.

   `step-end` means the value holds and then switches, with no
   interpolation — a font-weight or border-color tween would read as a
   blur rather than a selection. Keyframed values also outrank the static
   `.preset--active` rule while the loop runs, so Desktop hands the
   highlight over and takes it back on cue; when the loop is stopped the
   card falls back to Desktop being active, exactly as designed. */
@keyframes preset-cycle {
  0%        { border-color: var(--accent); color: var(--text); font-weight: 700; }
  25%,
  100%      { border-color: var(--line); color: var(--muted-2); font-weight: 600; }
}
@keyframes preset-cycle-value {
  0%        { color: var(--accent-link); font-weight: 600; }
  25%,
  100%      { color: var(--muted); font-weight: 400; }
}

.presets.is-playing .preset {
  animation: preset-cycle 8s step-end infinite;
}
.presets.is-playing .preset span {
  animation: preset-cycle-value 8s step-end infinite;
}
.presets.is-playing .preset:nth-child(2),
.presets.is-playing .preset:nth-child(2) span { animation-delay: -6s; }
.presets.is-playing .preset:nth-child(3),
.presets.is-playing .preset:nth-child(3) span { animation-delay: -4s; }
.presets.is-playing .preset:nth-child(4),
.presets.is-playing .preset:nth-child(4) span { animation-delay: -2s; }

/* Four presets across need ~26rem of mock; below that they go 2×2
   rather than overflowing the card. */
@container appmock (max-width: 26rem) {
  .presets { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Format segmented control (PNG / JPEG / PDF) */
.format-seg {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}
.format-seg__opt { padding: 10px; text-align: center; font-size: 13px; font-weight: 600; color: var(--muted); }
.format-seg__opt + .format-seg__opt { border-left: 1px solid var(--line); }
.format-seg__opt--active { font-weight: 700; color: var(--text); background: var(--panel-2); }

/* Toggle switch */
.toggle {
  width: 38px;
  height: 21px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  position: relative;
  display: inline-block;
  flex-shrink: 0;
}
.toggle::after {
  content: "";
  position: absolute;
  top: 2px;
  right: 2px;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: #fff;
}
.toggle--off { background: #3A4354; }
.toggle--off::after { right: auto; left: 2px; background: var(--text); }

/* Option row (Max Length / Break) */
.opt-row {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 9px;
  padding: 14px 16px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.opt-row--flush { border-radius: 9px 9px 0 0; border-bottom: none; padding: 14px 16px 6px; }
.opt-row__label { font-size: 14px; font-weight: 700; color: var(--text); }
.opt-row__control { display: flex; align-items: center; gap: 10px; }

/* Delay block (Options card) */
.opt-block {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 9px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.opt-block__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.opt-block__label { font-size: 15px; font-weight: 700; color: var(--text); }
.opt-block__value { display: flex; align-items: center; justify-content: flex-end; gap: 10px; }

/* Checkbox list (Options card) */
.checklist { display: flex; flex-direction: column; gap: 13px; padding: 4px 2px; }
.check-row {
  display: flex;
  align-items: flex-start; /* keeps the box on the first line when labels wrap */
  gap: 12px;
  font-size: 14px;
  line-height: 1.4;
  color: var(--text);
}
.check-row__hint { color: var(--muted); font-size: 12px; }
.check {
  width: 16px;
  height: 16px;
  margin-top: 2px;
  border-radius: 4px;
  border: 1.5px solid #5A6478;
  flex-shrink: 0;
}
.check--on {
  border: none;
  background: var(--accent);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ---------- Privacy band ---------- */
.privacy {
  position: relative;
  z-index: 1;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, #10151d, var(--bg));
}
.privacy__inner { position: relative; max-width: var(--container-mid); margin: 0 auto; }
/* Decorative. Painted as a background image in the 80rem block so it
   is never downloaded on phones or tablets. */
.privacy__mascot { display: none; }
.privacy__content {
  position: relative;
  padding-inline: var(--gutter);
  padding-block: clamp(3rem, 2.333rem + 3.33vw, 5rem); /* 48 → 80 */
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}
.privacy__eyebrow {
  font-size: 13px;
  font-weight: 700;
  color: var(--accent-link);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-shadow: var(--halo);
}
.privacy__title {
  font-size: var(--fs-privacy);
  font-weight: 800;
  letter-spacing: -0.01em;
  text-wrap: balance;
  text-shadow: var(--halo-lg);
}
.privacy__text {
  font-size: 16px;
  line-height: 1.65;
  color: var(--muted-2);
  max-width: 62ch;
  text-wrap: pretty;
  text-shadow: var(--halo);
}
.privacy__link {
  position: relative;
  /* `left` rather than a transform, so the link stays a plain inline box
     and keeps wrapping the way it does now. An explicit 0 is needed —
     the default is `auto`, which has nothing to animate from. */
  left: 0;
  color: var(--accent-link);
  text-decoration: none;
  font-size: 15px;
  font-weight: 600;
  border-bottom: 1px solid var(--accent-33);
  text-shadow: var(--halo);
  text-wrap: balance;
  transition: left 0.2s ease, border-bottom-color 0.15s ease;
}
/* Extends the hit area to 44px tall without moving the underline
   away from the text. */
.privacy__link::after {
  content: "";
  position: absolute;
  inset: -11px 0;
}
@media (hover: hover) and (pointer: fine) {
  .privacy__link:hover {
    left: 20px;
    border-bottom-color: var(--accent-link);
  }
}

/* ---------- Download CTA ---------- */
.download {
  width: min(100%, var(--container));
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-block:
    clamp(4rem, 3.042rem + 4.79vw, 6.875rem)  /* 64 → 110 */
    clamp(4.5rem, 3.5rem + 5vw, 7.5rem);      /* 72 → 120 */
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.download__logo {
  height: clamp(2rem, 1.667rem + 1.67vw, 3rem); /* 32 → 48 */
  width: auto;
  display: block;
  margin-bottom: clamp(1.25rem, 1.042rem + 1.04vw, 1.75rem);
}
.download__title {
  margin: 0 0 clamp(1.5rem, 1.25rem + 1.25vw, 2.25rem); /* 24 → 36 */
  font-size: var(--fs-download);
  font-weight: 700;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.download__meta { font-size: 15px; color: var(--muted); margin-top: 22px; text-wrap: balance; }
.notice {
  max-width: 860px;
  width: 100%;
  margin-top: clamp(1.75rem, 1.417rem + 1.67vw, 2.5rem);
  padding: clamp(1.25rem, 1.125rem + 0.63vw, 1.625rem) clamp(1.25rem, 0.917rem + 1.67vw, 2rem);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
  text-align: left;
  display: flex;
  gap: 14px;
  align-items: flex-start;
}
.notice__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--warn);
  display: inline-block;
  flex-shrink: 0;
  margin-top: 7px;
}
.notice__text { font-size: clamp(0.9375rem, 0.896rem + 0.21vw, 1rem); line-height: 1.75; color: var(--muted-2); }
.notice__text strong { color: var(--text); }

/* ---------- Footer ---------- */
.site-footer {
  position: relative;
  border-top: 1px solid var(--line);
  background: var(--bg-deep);
}
/* Decorative. Background image in the 80rem block — see mascots note. */
.site-footer__mascot { display: none; }
.site-footer__inner {
  position: relative;
  width: min(100%, var(--container));
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-block: clamp(2.25rem, 2rem + 1.25vw, 3rem); /* 36 → 48 */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
}
/* The publisher mark, in place of the wordmark this used to be. The SVG
   is white, so it needs the dark footer under it; `alt` carries the name
   because nothing else in this slot does. */
.site-footer__brand {
  display: block;
  width: 64px;
  height: auto;
  margin-bottom: 2px;
}
.site-footer__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 10px;
  font-size: 14px;
}
.site-footer__link { color: var(--accent-link); text-decoration: none; }
.site-footer__version { font-family: var(--font-mono); font-size: 13px; color: var(--muted); }
.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0 20px;
  font-size: 13px;
  margin-top: 8px;
}
/* This row wraps on narrow screens, where a dot separator strands at the
   end of a line. Spacing carries the separation instead; the dots come
   back at 80rem, where the row is always single-line. */
.site-footer__legal .site-footer__sep { display: none; }
.site-footer__legal-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding-inline: 2px;
  color: var(--muted);
  text-decoration: none;
}
.site-footer__sep { color: var(--line); }
/* Deliberately the quietest line on the page, but still AA on
   --bg-deep (was opacity:.7 on --muted, which fell to ~3.3:1). */
.site-footer__copy { font-size: 12px; color: #78808F; }

@media (hover: hover) and (pointer: fine) {
  .site-footer__link:hover { text-decoration: underline; }
  .site-footer__legal-link:hover { color: var(--accent-link); }
}

/* ---------- Legal / document pages (EULA, Trust & Privacy) ---------- */
.doc-nav__brand {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  text-decoration: none;
}
.doc-nav__back {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  color: var(--accent-link);
  text-decoration: none;
  font-size: 14px;
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .doc-nav__back:hover { text-decoration: underline; }
}
/* `width: auto` matters now that the markup carries width/height
   attributes: without it the intrinsic 677px width wins and the logo
   renders as a 300×75 slab instead of 96×24. */
.doc-nav__logo {
  height: 24px;
  width: auto;
  max-width: 300px;
  display: block;
}
.doc {
  max-width: var(--container-text);
  margin: 0 auto;
  padding-inline: var(--gutter);
  padding-block:
    clamp(2.5rem, 1.833rem + 3.33vw, 4.5rem)   /* 40 → 72 */
    clamp(3.5rem, 2.667rem + 4.17vw, 6rem);    /* 56 → 96 */
  font-size: 15px;
  line-height: 1.7;
}
.doc__title { margin: 0 0 8px; font-size: var(--fs-section); font-weight: 800; letter-spacing: -0.01em; text-wrap: balance; }
.doc h2 { margin: 40px 0 12px; font-size: clamp(1.1875rem, 1.146rem + 0.21vw, 1.3125rem); font-weight: 700; }
.doc h3 { margin: 24px 0 10px; font-size: clamp(1rem, 0.979rem + 0.10vw, 1.0625rem); font-weight: 700; }
.doc p { margin: 0 0 16px; color: var(--muted-2); }
.doc p:last-child { margin-bottom: 0; }
.doc ul,
.doc ol {
  margin: 0 0 16px;
  padding-left: 22px;
  color: var(--muted-2);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.doc a { color: var(--accent-link); text-decoration: none; }
.doc code {
  font-family: var(--font-mono);
  font-size: 13px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 1px 6px;
  /* Long paths like %APPDATA%\BigCap must not push the page wide. */
  overflow-wrap: anywhere;
}
@media (hover: hover) and (pointer: fine) {
  .doc a:hover { text-decoration: underline; }
}

/* Dimmer, all-caps notices (e.g. the EULA "IMPORTANT" preamble) */
.doc p.doc__important { color: var(--muted); }

/* Document metadata band under the title */
.doc-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin: 16px 0 36px;
  padding: 16px 20px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: 13px;
  color: var(--muted);
}
.doc-meta strong { color: var(--text); }

/* Quoted copy that must stay word-for-word identical to another surface —
   the privacy policy quotes the marketing page's trust line back at itself. */
.doc blockquote {
  margin: 0 0 16px;
  padding: 14px 18px;
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--panel);
  color: var(--text);
}

/* ---------- Legal drafts ----------
   Both of these are scaffolding for documents that have not been through
   counsel yet, and both are meant to be deleted at sign-off: the banner as
   a block, the [TK] spans as they are each resolved. They are styled to be
   impossible to miss for exactly that reason. */
.legal-draft {
  margin: 0 0 32px;
  padding: 16px 20px;
  border: 1px solid var(--warn);
  border-left-width: 4px;
  border-radius: var(--radius);
  background: rgba(240, 180, 41, 0.08);
  font-size: 14px;
  color: var(--muted-2);
}
.legal-draft strong { color: var(--warn); }
.tk {
  border-radius: 4px;
  padding: 1px 6px;
  background: rgba(240, 180, 41, 0.14);
  color: var(--warn);
  font-size: 0.94em;
  overflow-wrap: anywhere;
}

/* Cross-links to the other three documents, above the fine print */
.doc__siblings {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  margin: 0 0 20px;
  font-size: 14px;
}

/* Closing fine print */
.doc__rule { border: none; border-top: 1px solid var(--line); margin: 48px 0 24px; }
.doc p.doc__fine { margin: 0 0 12px; font-size: 13px; color: var(--muted); }
.doc p.doc__fine:last-child { margin-bottom: 0; }
.doc p.doc__fine--italic { font-style: italic; }

/* ---------- Documentation page ---------- */
.docs-layout {
  max-width: var(--container-wide);
  margin: 0 auto;
  padding-inline: var(--gutter);
  padding-block:
    clamp(2rem, 1.5rem + 2.5vw, 3.5rem)        /* 32 → 56 */
    clamp(3.5rem, 2.667rem + 4.17vw, 6rem);    /* 56 → 96 */
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.75rem;
  align-items: start;
}

/* Table of contents.
   Below 80rem it is a collapsed disclosure so eleven links do not
   push the guide off screen; from 80rem it is the sticky sidebar.
   `open` is the markup default, so with JS disabled the desktop
   sidebar is still correct. */
.docs-toc__panel {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
}
.docs-toc__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: var(--tap);
  padding: 0.5rem 1rem;
  cursor: pointer;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  list-style: none;
}
.docs-toc__summary::-webkit-details-marker { display: none; }
.docs-toc__summary::after {
  content: "";
  width: 8px;
  height: 8px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.2s ease;
  flex-shrink: 0;
}
.docs-toc__panel[open] > .docs-toc__summary::after { transform: translateY(2px) rotate(-135deg); }
.docs-toc__list {
  list-style: none;
  margin: 0;
  padding: 0.25rem 0.75rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.docs-toc__link {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: 6px 10px;
  border-radius: 6px;
  border-left: 1px solid transparent;
  color: var(--muted);
  text-decoration: none;
  font-size: 14px;
  line-height: 1.4;
}
@media (hover: hover) and (pointer: fine) {
  .docs-toc__link:hover { color: var(--text); border-left-color: var(--accent); }
}

/* Content column reuses .doc typography; drop the .doc container framing */
.docs-content { max-width: none; margin: 0; padding: 0; }

/* Screenshot figures */
.docs-figure { margin: 24px 0; }
.docs-figure img {
  display: block;
  width: 100%;
  max-width: 380px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-card);
}
.docs-figure figcaption { margin-top: 10px; font-size: 13px; color: var(--muted); }

/* Small "(default)" annotation next to a heading */
.doc-inline-note { font-size: 13px; font-weight: 400; color: var(--muted); }

/* Callouts (tips / notices) */
.callout {
  margin: 20px 0;
  padding: 14px 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  font-size: 14px;
  line-height: 1.6;
  color: var(--muted-2);
}
.callout strong { color: var(--text); }
.callout--warn { border-left-color: var(--warn); }

/* Tables — scroll the table, never the page. The wrapper is
   focusable (see markup) so it can also be scrolled from a keyboard. */
.docs-table-wrap {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  margin: 20px 0;
  border-radius: var(--radius-sm);
}
.docs-table-wrap:focus-visible { outline-offset: 0; }
/* Shared with the legal documents, which table their third-party components. */
.docs-content table,
.doc table {
  width: 100%;
  min-width: 30rem; /* below this, columns crush — scroll instead */
  border-collapse: collapse;
  font-size: 14px;
}
.docs-content th,
.docs-content td,
.doc th,
.doc td {
  text-align: left;
  padding: 10px 14px;
  border: 1px solid var(--line);
  vertical-align: top;
}
.docs-content thead th,
.doc thead th { background: var(--panel); color: var(--text); font-weight: 700; }
.docs-content tbody td,
.doc tbody td { color: var(--muted-2); }

/* ============================================================
   Breakpoints
   ============================================================ */

/* ---------- Large mobile — 480px ---------- */
@media (min-width: 30rem) {
  .site-nav__by { display: block; }

  .hero__cta {
    flex-direction: row;
    align-items: center;
    gap: 18px;
  }

  /* Browser mock returns to its full single-row chrome. */
  .browser__toolbar { flex-wrap: nowrap; padding: 14px 18px; }
  .browser__nav-btns { display: flex; }
  .browser__address { flex: 1 1 8rem; order: 0; }
  .browser__capture { flex: 0 1 auto; }
  .browser__page-header { padding: 14px 20px; }
  .browser__body { grid-template-columns: 130px 1fr; min-height: 300px; }
  .browser__sidebar { padding: 20px 16px; }
  .browser__content { padding: 22px; }
  .browser__card { height: 64px; }
}

/* ---------- Tablet portrait — 768px ---------- */
@media (min-width: 48rem) {
  .features__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .formats {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
    align-items: center;
  }
  .formats__visual { grid-column: 1; grid-row: 1; }
  .formats__copy   { grid-column: 2; grid-row: 1; }
}

/* ---------- Tablet landscape / small laptop — 1024px ---------- */
@media (min-width: 64rem) {
  /* Enough width for the two-up hero, at a smaller visual than desktop. */
  .hero { grid-template-columns: minmax(0, 1fr) minmax(280px, 440px); }
  .hero__visual { min-height: 420px; }

  .features__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .output__grid   { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Two columns, but still no standing mascot: it needs ~400px of
     panel width of its own and would sit on top of the copy here. */
  .spotlight__panel { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); }
}

/* ---------- Desktop + desktop navigation — 1280px ---------- */
@media (min-width: 80rem) {

  /* Navigation returns to the inline bar; the drawer styling is
     unset rather than overridden piecemeal. */
  .js .nav-toggle { display: none; }
  .site-nav,
  .js .site-nav { padding-block: 13px; gap: 24px; flex-wrap: nowrap; } /* 36 + 26 = 64px */
  .site-nav__menu,
  .js .site-nav__menu {
    position: static;
    width: auto;
    flex: none;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    gap: 28px;
    padding: 0;
    background: none;
    border-left: none;
    box-shadow: none;
    overflow: visible;
    transform: none;
    visibility: visible;
    transition: none;
  }
  .site-nav__link { min-height: 0; padding: 0; font-size: 14px; }
  .site-nav__menu .btn { margin-top: 0; min-height: 36px; }
  .nav-scrim { display: none; }

  /* Back to the original tight footer row (still ≥24px, WCAG 2.5.8). */
  .site-footer__legal-link { min-height: 24px; }
  .site-footer__legal { gap: 2px 10px; }
  .site-footer__legal .site-footer__sep { display: inline; }

  /* Hero: copy left, app window + mascot right */
  .hero { grid-template-columns: minmax(0, 1fr) minmax(380px, 520px); }
  .hero__visual { min-height: 480px; }

  /* There is guaranteed room for the full URL here, so the address bar
     goes back to contributing its intrinsic width to the spotlight's
     column split — that split is what sets the original desktop
     proportions of the panel. Narrower viewports keep min-width:0 and
     truncate instead of overflowing. */
  .app-mock { mask-image: none; }
  .browser { contain: none; }
  .browser__address { flex: 1; min-width: auto; }
  /* `auto` (not 0) minimums: the mock's intrinsic width is what widens
     the right column past the bare 1.15fr ratio, which is the original
     desktop proportion of this panel. */
  .spotlight__panel { grid-template-columns: 1fr 1.15fr; }
  .hero__mascot { right: -36px; bottom: -70px; width: 210px; }

  /* These lists are single-line at desktop, so they keep the original
     leading; the extra leading in the base rules is for wrapped lines. */
  .spotlight__item,
  .check-row { line-height: normal; }

  /* Spotlight: the standing figure returns, centred across the seam */
  .spotlight__mascot {
    display: block;
    position: absolute;
    left: 50%;
    top: -48px;
    height: calc(100% + 96px);
    aspect-ratio: 1024 / 1536;
    transform: translateX(-50%);
    z-index: 2;
    background-image: url("assets/boy-login.png");
    background-image: image-set(
      url("assets/boy-login-800.webp") type("image/webp"),
      url("assets/boy-login.png") type("image/png")
    );
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
    filter: drop-shadow(var(--shadow-mascot));
    pointer-events: none;
  }

  /* Privacy band: figure on the left, copy clears it */
  .privacy__mascot {
    display: block;
    position: absolute;
    left: 12px;
    top: -52px;
    height: calc(100% + 104px);
    aspect-ratio: 682 / 979;
    background-image: url("assets/boy-laptop.png");
    background-image: image-set(
      url("assets/boy-laptop-600.webp") type("image/webp"),
      url("assets/boy-laptop.png") type("image/png")
    );
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
    filter: drop-shadow(var(--shadow-mascot));
    pointer-events: none;
  }
  /* Room reserved for .privacy__mascot at its rendered width. */
  .privacy__content { margin-left: 400px; }

  /* Footer figure */
  .site-footer__mascot {
    display: block;
    position: absolute;
    right: 3%;
    bottom: 0;
    height: calc(100% + 80px);
    aspect-ratio: 1292 / 1037;
    z-index: 2;
    background-image: url("assets/boy-close.png");
    background-image: image-set(
      url("assets/boy-close-840.webp") type("image/webp"),
      url("assets/boy-close.png") type("image/png")
    );
    background-size: contain;
    background-position: bottom center;
    background-repeat: no-repeat;
    pointer-events: none;
  }

  /* Docs: sticky sidebar instead of a disclosure */
  .docs-layout {
    grid-template-columns: 220px minmax(0, 1fr);
    gap: 56px;
  }
  .docs-toc {
    position: sticky;
    top: calc(var(--nav-h) + 1rem);
  }
  .docs-toc__panel { border: none; background: none; }
  .docs-toc__summary { padding: 0 0 14px; min-height: 0; }
  .docs-toc__summary::after { display: none; }
  .docs-toc__list {
    padding: 0;
    border-left: 1px solid var(--line);
  }
  .docs-toc__link {
    min-height: 0;
    margin-left: -1px;
    padding: 6px 0 6px 16px;
    border-radius: 0;
    font-size: 13px;
  }
}

/* ---------- Wide desktop — 1440px ----------
   Intentionally no breakpoint. Every region is already capped by
   --container / --container-wide / --container-mid / --container-text
   and centred, so past 1440px the margins grow and the composition
   does not stretch. Adding a rule here would only shift the desktop
   design that is meant to be preserved. */

/* ---------- Mascot clips ----------
   Short looping WebM versions of the four mascot stills. Every one of
   them is decorative, so the still image is what the markup actually
   ships and what stays on screen if any of this does not apply:

     - no `src` until the script attaches one, so a browser that never
       runs the script — or never reaches 1280px — downloads nothing;
     - attached at >=1280px only. Together the four clips are ~2.5 MB,
       which is an order of magnitude more than the whole mobile page,
       and the two standing figures are desktop-only artwork anyway;
     - never attached when reduced motion is requested.

   The three standing figures carry a real alpha channel (VP9 alpha, so
   the cut-out survives over the white browser mock the same way the
   PNGs did). The format clip does not, and does not need one: it is a
   framed illustration on its own dark field, like the JPEG it covers. */
.mascot-video { display: none; }
.mascot-replaced { display: none; }

@media (min-width: 80rem) {
  .mascot-video { display: block; }

  /* Both standing figures: the clip fills the box the background image
     was painting, so it inherits position, size and aspect ratio and
     there is nothing to keep in sync. */
  .spotlight__mascot .mascot-video,
  .privacy__mascot .mascot-video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
  /* Once the clip is playing, the still behind it is dead weight — and
     it would show through wherever the animation moves outside the
     silhouette it was cut from. The box keeps its drop shadow, which
     now traces the clip's own alpha and follows the figure as it moves. */
  .spotlight__mascot.mascot-live,
  .privacy__mascot.mascot-live { background-image: none; }

  /* The hero clip is framed wider than the still — the arms swing past
     the pose the still was cut from — so it gets its own box, sized to
     stand the figure at the still's height and planted on the same
     baseline. The overhang is capped at 76px because the gap between
     .hero__visual and the viewport edge bottoms out at 80px (at exactly
     1280px, and only there); anything more is real horizontal overflow
     rather than art bleeding into the margin. */
  .mascot-video--hero {
    position: absolute;
    right: -76px;
    bottom: -72px;
    width: 330px;
    height: auto;
    filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.5));
    pointer-events: none;
  }

  /* Opaque artwork on its own dark field, exactly like the still it
     covers — so it simply sits on top of it, with the same corners. */
  .mascot-video--formats {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: var(--radius-lg);
  }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* `!important` is warranted: this must beat every component
     transition without duplicating each of them here. */
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Zeroing the duration would only turn the hover lift into an instant
     jump, which is the motion this preference is asking us to drop. The
     border-color cue still identifies the hovered card. */
  .feature-card:hover,
  .feature-card:hover .feature-card__icon,
  .output-card:hover,
  .btn--lg:hover,
  .btn--xl:hover { transform: none; }
  .privacy__link:hover { left: 0; }

  /* Continuous motion is exactly what this preference rules out. Belt
     and braces alongside the script's own check, so the loop stays off
     if the preference is turned on after load. */
  .hero__screenshot,
  .browser.is-playing .browser__capture,
  .browser.is-playing .browser__page::after,
  .browser.is-playing .browser__session,
  .presets.is-playing .preset,
  .presets.is-playing .preset span,
  .chips.is-playing .chip-tag,
  .reveal-list.is-playing > li,
  .btn--lg:hover .btn__glyph,
  .btn--xl:hover .btn__glyph { animation: none; }

  /* Covers the preference being turned on mid-visit, after the script
     has already armed the lists. */
  .reveal-list.is-armed > li { opacity: 1; }

  /* The script never attaches a source under this preference, and hands
     the stills back if it is turned on after load. This is the belt to
     that script's braces. */
  .mascot-video { display: none; }
}
