/* Self-hosted, latin subset. No CDN: the page makes zero third-party
   requests, which keeps it fast and keeps visitors' IPs out of a font
   host's logs. Two faces, 39KB total, against 208KB for the five static
   Inter/Instrument Serif files the site started with.

   Two, and only two. Archivo Black (SIL OFL) is the display face: every
   h1 and h2, and the wordmark. It arrived on the hero alone, which left
   the page carrying two display faces that never met, one for the
   headline and Fraunces for every heading under it. That is the kind of
   inconsistency nobody can name and everybody can see. Fraunces is gone;
   the 67KB went with it.

   Archivo Black ships a single weight and that weight is already black,
   so every rule below sets font-weight 400. Asking for 600 or 700 makes
   the browser synthesise a bold by thickening the outlines, and there is
   nothing here left to thicken. It also has no variable axes, so the
   font-optical-sizing the serif needed is gone too.

   Geist (SIL OFL) replaces Inter for everything else: body, UI, and the
   small h3 subheads, which are set at UI scale and would be shouting in a
   black grotesque. Inter is the most widely deployed UI sans on the web
   and reads as a template before a visitor consciously registers the
   typeface. */
@font-face {
  font-family: 'Geist';
  src: url('public/fonts/geist-var.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Archivo Black (SIL OFL), latin subset, 9.8KB. Self-hosted like the other
   two: the file is pulled from Google once, at authoring time, and served
   from here, so no visitor ever makes a request to fonts.gstatic.com.

   One weight, and that is the whole design of it. The family IS the black
   weight, which is why the declaration is 400 and not 900: asking for a
   bold it does not have makes the browser synthesise one by smearing the
   outlines, and this face has no room to spare. It sets the hero headline
   and nothing else. */
@font-face {
  font-family: 'Archivo Black';
  src: url('public/fonts/archivo-black.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ============================================================
   Dandelion tokens
   ============================================================ */

:root {
  /* brand */
  --ink-900: #0d201c;
  --ink-800: #14312a;
  --ink-700: #33473f;
  --ink-500: #5c716a;
  --ink-300: #a9b8b2;
  --hairline: #e2ddd7;
  --paper: #fffafb;
  --paper-dim: #f6f1ec;
  --paper-card: #fbf7f3;

  --teal: #2f9c88;
  --teal-strong: #1f6b5c;
  --mint: #7de2d1;
  --seal-dark: #08110f;

  /* type */
  /* Every display heading and the wordmark. There is one display face on
     this site, not two. */
  --font-display: "Archivo Black", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* spacing (4px base) */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;
  --sp-10: 40px;
  --sp-12: 48px;
  --sp-16: 64px;
  --sp-20: 80px;
  --sp-24: 96px;

  /* radius */
  --r-swatch: 8px;
  --r-button: 10px;
  --r-input: 15px;
  --r-card: 18px;
  --r-pill: 999px;

  /* panel-mock fills (dark surface, per chrome-extension-ui token system) */
  --fill-1: rgba(255,255,255,0.045);
  --fill-2: rgba(255,255,255,0.07);
  --fill-3: rgba(255,255,255,0.10);
  --edge: rgba(255,255,255,0.09);

  --max-measure: 68ch;
  --content-width: 1120px;
}

/* ============================================================
   Reset
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink-700);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
h1, h2, h3, p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
a { color: inherit; }
button { font: inherit; }

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--ink-900);
  color: var(--paper);
  padding: var(--sp-3) var(--sp-4);
  border-radius: 0 0 var(--r-swatch) 0;
  z-index: 10;
}
.skip-link:focus {
  left: 0;
}

:focus-visible {
  outline: 2px solid var(--ink-900);
  outline-offset: 3px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================
   Type
   ============================================================ */

h1 {
  font-family: var(--font-display);
  font-size: clamp(2.1rem, 4.4vw, 3.4rem);
  font-weight: 400;
  line-height: 1.1;
  color: var(--ink-900);
  letter-spacing: -0.025em;
  max-width: 18ch;
}
h2 {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--ink-900);
  max-width: 24ch;
}
h3 {
  font-family: var(--font-sans);
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink-900);
}
p { max-width: var(--max-measure); }
.section-lede {
  font-size: 1.1rem;
  color: var(--ink-700);
  max-width: 56ch;
}

/* ============================================================
   Buttons
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-6);
  border-radius: var(--r-button);
  border: none;
  font-weight: 600;
  font-size: 0.98rem;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 150ms ease, transform 150ms ease, box-shadow 150ms ease;
  white-space: nowrap;
}
.btn-primary {
  background: var(--ink-900);
  color: var(--paper);
}
.btn-primary:hover {
  background: var(--ink-800);
}
.btn-primary:active {
  transform: translateY(1px);
}
.btn-primary:disabled {
  background: var(--ink-300);
  color: var(--paper);
  cursor: not-allowed;
}
.btn-header {
  min-height: 44px;
  padding: 0 var(--sp-5);
  font-size: 0.9rem;
}

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

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: var(--content-width);
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-6);
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  text-decoration: none;
}
.brand-mark { border-radius: 50%; }
.brand-name {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--ink-900);
}

/* ============================================================
   Hero
   ============================================================ */

/* Centred, single column. The old split put the copy and the demo in a
   fight for horizontal space and the demo lost. At 42% width the draft
   was unreadable, which is the one thing a visitor needs to see. Centred
   means the demo gets the full container underneath. */
.hero {
  max-width: var(--content-width);
  margin: 0 auto;
  padding: var(--sp-12) var(--sp-6) var(--sp-16);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.hero-eyebrow {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 500;
  text-transform: uppercase;
  /* Wide positive tracking against the tight display serif below. The
     contrast between the two is the drama. Neither does it alone. */
  letter-spacing: 0.18em;
  color: var(--ink-500);
  background: var(--paper-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  padding: var(--sp-2) var(--sp-5);
  margin-bottom: var(--sp-10);
}

.hero h1 {
  /* Inherits the display face from the base h1 now. What stays here is the
     hero-only sizing: this is the one heading on the site that runs at
     display scale, and its measure is cut for the two clauses it holds. */
  /* 17ch, because the face is wide enough that 24ch overflowed the 1072px
     column outright. */
  max-width: 17ch;
  /* Set solid, a black grotesque closes up. This size needs the air back. */
  line-height: 1.06;
  /* Tighter than the serif's -0.02em. Heavy sans faces carry more
     sidebearing than they need at display size, and the words should read
     as one object rather than a row of letters. */
  letter-spacing: -0.03em;
  font-size: clamp(2.6rem, 6.4vw, 4.6rem);
}
/* Second clause in the accent, so one line reads as two beats and the eye
   has somewhere to land.

   Block, not inline. A measure can only ask for the break, it cannot say
   where: at 21ch the headline set as "Outreach on steroids. For the /
   solopreneur.", splitting the accent clause in half and stranding a word.
   Its own block puts the break between the two sentences by construction,
   at any width. */
.hero h1 .accent {
  color: var(--teal-strong);
  display: block;
}

/* 1.3rem at a tight measure breaks to a few short centred lines under the
   headline, a caption to it, the way both reference heroes set their sub.
   At 58ch it ran as one long line that competed with the h1 for the same
   width. Widened from 34ch when the sub took over the explaining from the
   headline: the longer sentence set to four thin lines at 34ch, which
   reads as a paragraph rather than a caption. */
.hero-sub {
  margin-top: var(--sp-5);
  font-size: 1.3rem;
  line-height: 1.45;
  color: var(--ink-700);
  max-width: 44ch;
}

.hero-actions {
  margin-top: var(--sp-6);
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
  justify-content: center;
  /* flex-start, not the default stretch: the Add-to-Chrome button carries a
     "Coming soon" note beneath it, and stretch would grow the primary
     button to match the pair's height. */
  align-items: flex-start;
}
.hero-note {
  margin-top: var(--sp-4);
  font-size: 0.88rem;
  color: var(--ink-500);
}

/* The browser frame + docked panel live in demo/demo.css, which owns them
   for both the site and the extension. Only the positioning context and
   the ground it sits on are here. */
.hero-visual {
  margin-top: var(--sp-8);
  width: 100%;
  text-align: left;
  position: relative;
  isolation: isolate;
}

/* Both demos used to need a ground: floating loose on the page background,
   a bare dark panel read as one more element in the stack rather than as
   the product.

   Neither needs it now. The hero gave the ground up when it moved into the
   laptop, and the CRM demo has since moved into one too, so the same
   reasoning applies to both: a machine sitting inside a bordered card is a
   frame around a frame, and the laptop's own shadow already lifts the demo
   off the page. */
.explainer-demo {
  background: none;
  border: none;
  padding: 0;
}


/* ============================================================
   The laptop

   A wrapper, never a parent inside the demo. demo/demo.css owns the
   browser frame and sets overflow:hidden on it, so a bezel drawn as a
   descendant would be clipped; the chassis is a backdrop and the live
   demo sits on top of it. None of this belongs in demo/demo.css, which
   is copied verbatim into the extension, and the extension has no
   laptop.
   ============================================================ */

.laptop-stage {
  position: relative;
  perspective: 1250px;
  perspective-origin: 62% 46%;
}

.laptop-shell {
  position: relative;
  aspect-ratio: 650 / 400;
  /* The reference pose: turned away to the right, dropped a little below
     eye line, and rocked a couple of degrees off true so it reads as an
     object photographed rather than a diagram drawn. */
  /* Scaled back below 1, because perspective makes the near edge larger
     than the box it is laid out in: at full size the chassis pushed past
     the viewport and body{overflow-x:hidden} silently amputated it. */
  transform: rotateX(9deg) rotateY(-31deg) rotateZ(2.5deg) scale(0.92);
  transform-origin: 58% 58%;
  /* flat, not preserve-3d. The demo's demo-in keyframe drops
     transform:none on every block it reveals, which z-fights against a
     3D context for the 260ms it runs. */
  transform-style: flat;
  transition: transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Straightening up. The pose sells the product on arrival; the moment
   someone is actually reading the draft it has to get out of the way,
   because the demo's type is sized for a 60% browser zoom and does not
   survive being turned 22 degrees away. Hover and focus are live; .is-flat
   is latched on by script.js on the first scroll or control press. */
.laptop-stage:hover .laptop-shell,
.laptop-stage:focus-within .laptop-shell,
.laptop-stage.is-flat .laptop-shell {
  transform: rotateX(0) rotateY(0) rotateZ(0) scale(1);
}

/* The CRM demo's machine, which is never turned. The hero's pose is an
   opening image and can afford to be a photograph of an object; this one
   holds a spreadsheet the visitor has to read, and a grid is the single
   worst thing to foreshorten. Flat from the start, with no perspective to
   transition out of, so it never animates on hover either. */
.laptop-stage-flat { perspective: none; }
.laptop-stage-flat .laptop-shell {
  transform: none;
  transition: none;
}

/* Between the 900px floor and a comfortable desktop there is not enough
   width to give away to a hard angle: the near edge runs out of page
   before the pose reads. Ease the turn rather than clipping the machine. */
@media (min-width: 900px) and (max-width: 1199px) {
  .laptop-stage { perspective: 1600px; }
  .laptop-shell {
    transform: rotateX(7deg) rotateY(-21deg) rotateZ(1.5deg) scale(0.9);
  }
}

.laptop-chassis {
  display: block;
  width: 100%;
  height: auto;
  /* Fills the artwork's screen rect, which the demo then covers. Brand
     deep rather than white so first paint is not a flash of paper. */
  color: #0e2a26;
  /* The float. One wide soft shadow for the drop, one tight dark one to
     seat the base, and a low teal pool so the machine picks up a hint of
     the brand from the surface it is standing on. */
  filter:
    drop-shadow(0 2px 3px rgba(13, 32, 28, 0.3))
    drop-shadow(0 44px 70px rgba(13, 32, 28, 0.3))
    drop-shadow(0 22px 40px rgba(45, 156, 136, 0.2));
}

/* The screen cutout, straight off the artwork: the rect at x 74.52,
   y 21.32, w 501.22, h 323.85 inside a 650x400 box. Its 1.548:1 aspect
   is within a percent of the demo's own composition, so the demo drops in
   without being stretched or rescaled. */
.laptop-screen {
  position: absolute;
  left: 11.464%;
  top: 5.33%;
  width: 77.111%;
  height: 80.963%;
  overflow: hidden;
  border-radius: 4px;
}

/* demo/demo.css pins the frame to min(72vh, 660px), which is a viewport
   measurement and knows nothing about the cutout it is now sitting in.
   Inside the laptop the cutout is the authority.

   Three classes deep on the frame, and that is load-bearing. demo.css
   sets the height on `.demo-root .browser-frame`, which is also (0,2,0),
   and demo.css is linked after this file, so a two-class override here
   loses the tie on source order and silently does nothing. The frame then
   kept its full 660px inside a 534px cutout: 124px hung below the bezel,
   and because the panel measured itself against a box it only appeared to
   have, its own overflow check (panel-mock.js) read false and its
   auto-scroll never ran, putting the send row out of reach entirely.
   This is the second time this exact tie has bitten this stylesheet; the
   first is written up at demo/demo.css:914. */
.laptop-screen .demo-root {
  height: 100%;
}
.laptop-screen .demo-root .browser-frame {
  height: 100%;
}
.laptop-screen .browser-frame {
  border-radius: 0;
  border: none;
}

.laptop-still { display: none; }

/* The controls used to be held in by the ground's 32px of padding. With the
   ground gone they spread to the full content width and the Pause and
   Replay buttons ended up at opposite edges of the page, a long way from
   the thing they control. Pull them back under the machine. */
#hero-demo-controls {
  /* The compact control row is a grid of auto/1fr/auto, so Play and Replay
     ride the container's edges however wide it is. At the full content
     width they ended up at opposite ends of the page from each other.
     Narrow enough that the pair reads as one control under the machine. */
  max-width: 460px;
  margin: 0 auto;
}


/* ============================================================
   Section rhythm
   ============================================================ */

section {
  max-width: var(--content-width);
  margin: 0 auto;
  padding: var(--sp-20) var(--sp-6);
}

.panel-flow { border-top: 1px solid var(--hairline); }
.panel-flow .section-lede { margin-top: var(--sp-4); }

.explainer { border-top: 1px solid var(--hairline); }
.explainer .section-lede { margin-top: var(--sp-4); margin-bottom: var(--sp-8); }
.explainer-video {
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
  border-radius: var(--r-card);
  border: 1px solid var(--hairline);
  background: var(--ink-900);
}

.steps {
  margin-top: var(--sp-12);
  display: grid;
  gap: var(--sp-8);
  max-width: 760px;
}
.step {
  display: grid;
  grid-template-columns: 40px 1fr;
  gap: var(--sp-5);
}
.step-num {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--paper-dim);
  color: var(--teal-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.step-copy h3 { margin-bottom: var(--sp-2); }
.step-copy p { color: var(--ink-700); }

/* --- send options: 3 cards, deliberately asymmetric section bg --- */

.send-options {
  background: var(--paper-dim);
  max-width: none;
  /* Inset from the viewport edge to the same content column every other
     section uses (centered content-width once the viewport is wide
     enough, sp-6 gutter below that). Children then need no margin/width
     rules of their own to line up at the shared left edge. */
  padding-left: max(var(--sp-6), calc((100% - var(--content-width)) / 2 + var(--sp-6)));
  padding-right: max(var(--sp-6), calc((100% - var(--content-width)) / 2 + var(--sp-6)));
}
.option-grid {
  margin-top: var(--sp-10);
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-6);
}
@media (min-width: 768px) {
  .option-grid { grid-template-columns: repeat(3, 1fr); }
}
.option-card {
  background: var(--paper);
  border: 1px solid var(--ink-500);
  border-radius: var(--r-card);
  padding: var(--sp-6);
}
.option-card h3 { margin-bottom: var(--sp-2); }
.option-card p { color: var(--ink-700); font-size: 0.95rem; }

/* --- what this is not: narrow, quiet, no card --- */

.not-this h2,
.not-this p {
  max-width: 760px;
}
.not-this p {
  margin-top: var(--sp-5);
  font-size: 1.05rem;
  line-height: 1.65;
}
.not-this-emphasis {
  color: var(--ink-900);
  font-weight: 600;
}

/* --- remembers: three plain items, no card chrome, hairline dividers --- */

.remember-grid {
  margin-top: var(--sp-10);
  display: grid;
  gap: 0;
  border-top: 1px solid var(--hairline);
}
.remember-item {
  padding: var(--sp-6) 0;
  border-bottom: 1px solid var(--hairline);
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-2);
}
.remember-item h3 { font-family: var(--font-display); font-size: 1.15rem; font-weight: 400; letter-spacing: -0.02em; }
.remember-item p { color: var(--ink-700); }

@media (min-width: 768px) {
  .remember-item {
    grid-template-columns: 260px 1fr;
    align-items: baseline;
    gap: var(--sp-8);
  }
}

/* --- final CTA --- */

.cta-final {
  background: var(--ink-900);
  color: var(--paper);
  max-width: none;
  border-radius: var(--r-card);
  margin: var(--sp-16) auto var(--sp-20);
  max-width: calc(var(--content-width) - var(--sp-6) * 2);
  padding: var(--sp-16) var(--sp-8);
}
.cta-final h2 { color: var(--paper); max-width: 18ch; }
.cta-final > p { color: rgba(255,255,255,0.75); margin-top: var(--sp-4); max-width: 54ch; }

.waitlist-form { margin-top: var(--sp-8); max-width: 480px; }
.waitlist-form label {
  display: block;
  font-size: 0.85rem;
  color: rgba(255,255,255,0.7);
  margin-bottom: var(--sp-2);
}
.form-row {
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.waitlist-form input[type="email"] {
  flex: 1;
  min-width: 220px;
  background: rgba(255,255,255,0.1);
  border: 1px solid rgba(255,255,255,0.4);
  border-radius: var(--r-input);
  padding: var(--sp-3) var(--sp-4);
  color: var(--paper);
  font-size: 0.98rem;
}
.waitlist-form input[type="email"]::placeholder { color: rgba(255,255,255,0.55); }
.waitlist-form input[type="email"]:focus-visible {
  outline: 2px solid var(--mint);
  outline-offset: 2px;
}
.waitlist-form input[type="email"][aria-invalid="true"] {
  border-color: #f2a99a;
}
.cta-final .btn-primary {
  background: var(--mint);
  color: var(--ink-900);
}
.cta-final .btn-primary:hover { background: #94e8da; }
.cta-final .btn-primary:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 2px;
}

.form-helper {
  margin-top: var(--sp-3);
  font-size: 0.82rem;
  color: rgba(255,255,255,0.55);
}
.form-status {
  margin-top: var(--sp-4);
  font-size: 0.92rem;
  min-height: 1.4em;
}
.form-status[data-state="success"] { color: var(--mint); }
.form-status[data-state="error"] { color: #f2a99a; }

.form-notice {
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: var(--r-input);
  padding: var(--sp-4);
  margin-top: var(--sp-6);
  font-size: 0.88rem;
  color: rgba(255,255,255,0.8);
  max-width: 480px;
}

.no-js-fallback {
  margin-top: var(--sp-6);
  font-size: 0.9rem;
  color: rgba(255,255,255,0.75);
}

/* --- final CTA entrance ---
   The section is the end of the argument, so arriving at it should feel
   like landing rather than like the page stopping. Its parts settle in
   one after another, heading first, then the thing you are asked to do.

   The hidden state is applied by script, never by this file on its own:
   without JavaScript, or under reduced motion where the script declines
   to arm any of this, .is-reveal-pending is never set and every line of
   the section is on screen the moment it is painted. */
.cta-final.is-reveal-pending .reveal-item {
  opacity: 0;
  transform: translateY(14px);
}
.cta-final.is-revealed .reveal-item {
  opacity: 1;
  transform: none;
  /* Named properties rather than "all", so a later transform used for
     something else here cannot get dragged into this timing by accident. */
  transition-property: opacity, transform;
  transition-duration: 520ms;
  transition-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: calc(var(--reveal-index, 0) * 90ms);
}

/* ============================================================
   Footer
   ============================================================ */

.site-footer {
  max-width: var(--content-width);
  margin: 0 auto;
  padding: var(--sp-12) var(--sp-6) var(--sp-16);
  display: grid;
  gap: var(--sp-3);
  border-top: 1px solid var(--hairline);
}
.footer-mark { border-radius: 50%; margin-bottom: var(--sp-2); }
.footer-placeholder {
  font-size: 0.85rem;
  color: var(--ink-500);
  font-style: italic;
}
.footer-copyright {
  font-size: 0.8rem;
  color: var(--ink-500);
  margin-top: var(--sp-3);
}

/* ============================================================
   Responsive
   ============================================================ */

@media (min-width: 900px) {
  .hero {
    grid-template-columns: 5fr 6fr;
    align-items: center;
    padding-top: var(--sp-16);
  }
}

/* Below 900px the demo dismantles its own browser frame (see the block at
   the foot of demo/demo.css) and leaves a bare panel card, so there is no
   window left to sit in a screen. The laptop stays, because a small
   machine still reads better than a loose rectangle, but it holds a frozen
   beat of the same demo instead of the live one, and it sits square on
   rather than turned: there is not enough width at this size to give up to
   a perspective angle. The controls go with the live demo. */
@media (max-width: 899px) {
  .laptop-stage { perspective: none; }
  .laptop-shell { transform: none; transition: none; }
  .laptop-screen #hero-demo,
  #hero-demo-controls { display: none; }
  .laptop-still {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* The still and the cutout are the same aspect to within a fifth of a
       percent, so cover takes almost nothing off. Centre it anyway: biasing
       to a corner would decide, if the two ever drift apart, that the edge
       to sacrifice is the one holding the draft. */
    object-position: center;
  }

  /* The CRM machine stays, and does exactly what the hero's does: swaps the
     live demo for a frozen beat of itself. It used to dissolve here, on the
     grounds that it had no still to fall back on. It has one now, so the
     two sections stop disagreeing about what a phone should see. */
  .laptop-screen #crm-demo,
  #crm-demo-controls { display: none; }
}

/* The tilt is decoration, and the demo engine already takes reduced motion
   seriously enough to swap itself for a manual stepper. Sit the machine
   square and let it alone. */
@media (prefers-reduced-motion: reduce) {
  .laptop-shell { transform: none; transition: none; }
}

@media (max-width: 767px) {
  .site-header { padding: var(--sp-4); }
  /* No gap: every child of the hero already carries its own top margin, so
     a 40px flex gap on top of those margins stacked into half a screen of
     dead space between the eyebrow and the buttons. */
  .hero { padding: var(--sp-6) var(--sp-4) var(--sp-12); gap: 0; }
  .hero-sub { font-size: 1.15rem; }
  .hero-visual { margin-top: var(--sp-6); }
  section { padding: var(--sp-12) var(--sp-4); }
  .explainer-demo { margin-top: var(--sp-8); }

  .cta-final { padding: var(--sp-10) var(--sp-5); margin: var(--sp-10) auto var(--sp-12); }
  .form-row { flex-direction: column; align-items: stretch; }
  .form-row .btn { width: 100%; }
}

/* ============================================================
   Install / download funnel
   ============================================================ */

.install { border-top: 1px solid var(--hairline); }
.install .section-lede { margin-top: var(--sp-4); }

.install-steps {
  list-style: none;
  margin: var(--sp-10) 0 0;
  padding: 0;
  display: grid;
  gap: var(--sp-6);
  max-width: var(--max-measure);
}
.install-step {
  display: flex;
  gap: var(--sp-4);
  align-items: flex-start;
}

.install-actions {
  margin-top: var(--sp-10);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-3);
}
.install-note {
  font-size: 0.92rem;
  color: var(--ink-500);
  max-width: 52ch;
  line-height: 1.55;
}

.demo-fallback {
  font-size: 0.92rem;
  color: var(--ink-500);
  padding: var(--sp-4);
  border: 1px solid var(--hairline);
  border-radius: var(--r-card);
  background: var(--paper-card);
}

.installed-hero { grid-template-columns: 1fr; }
.installed-hero .page-crumb {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--teal-strong);
  margin-bottom: var(--sp-3);
}

.key-links {
  list-style: none;
  margin: var(--sp-3) 0;
  padding: 0;
  display: grid;
  gap: var(--sp-2);
}
.key-links a { color: var(--teal-strong); }
.key-note {
  font-size: 0.82rem;
  color: var(--ink-500);
  margin-left: var(--sp-2);
}
.key-caveat {
  font-size: 0.88rem;
  color: var(--ink-500);
  margin-top: var(--sp-3);
}


/* Outlined companion to .btn-primary. Carries the Chrome glyph, so it reads
   as "install" at a glance rather than needing its label read. */
.btn-secondary {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  background: var(--paper);
  color: var(--ink-900);
  border: 1px solid var(--hairline);
}
.btn-secondary:hover { background: var(--paper-card); border-color: var(--ink-300); }
.btn-secondary svg { flex: none; }

.explainer { text-align: center; }
.explainer .hero-eyebrow { margin-bottom: var(--sp-6); }
/* The one h2 that runs at display scale rather than section scale. It keeps
   the size and drops the weight: 700 was asking Archivo Black for a bold it
   does not have, so the browser was smearing the outlines of the largest
   heading on the page. */
.explainer h2 {
  font-size: clamp(2.2rem, 5vw, 3.6rem);
  line-height: 1.04;
  letter-spacing: -0.03em;
}
.explainer .section-lede { margin: var(--sp-5) auto 0; max-width: 56ch; }
.explainer-demo { margin-top: var(--sp-12); text-align: left; }

/* Centred sections need their measure-capped headings re-centred: a
   max-width block with text-align:center still sits flush left. */
.explainer h2, .explainer .section-lede { margin-left: auto; margin-right: auto; }

.footer-links { font-size: 0.9rem; color: var(--ink-500); margin-top: var(--sp-2); }
.footer-links a { color: var(--ink-700); }
.footer-links a:hover { color: var(--teal-strong); }

/* --- demo playback controls ---------------------------------------
   demo.css styles these as paper pills with a hairline border and ink-900
   labels, which on the site put them at the same contrast as the hero CTA.
   Scoped to the site's two mounts so the extension's first-run tour, which
   shares demo.css, keeps its own weighting. */

#hero-demo-controls .demo-btn,
#crm-demo-controls .demo-btn {
  background: transparent;
  border-color: transparent;
  color: var(--ink-500);
  font-size: 0.78rem;
  font-weight: 500;
}
#hero-demo-controls .demo-btn:hover:not(:disabled),
#crm-demo-controls .demo-btn:hover:not(:disabled) {
  background: var(--paper);
  border-color: var(--hairline);
  color: var(--ink-900);
}
#hero-demo-controls .demo-chapter.is-active,
#crm-demo-controls .demo-chapter.is-active {
  background: var(--paper);
  font-weight: 500;
}

/* The eyebrow is light-on-dark inside the closing CTA. */
.cta-final .hero-eyebrow {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.18);
  color: var(--mint);
  margin-bottom: var(--sp-5);
}
