@font-face {
  font-family: "Geist E";
  src: url("/lp/assets/geist-latin-wght-normal-Dm3htQBi.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/**
 * Landing E - the 2026 relaunch front door.
 *
 * Light mode only, by decision (Jem, 2026-08-10: "Everything light mode,
 * nothing dark mode."). There is deliberately no prefers-color-scheme block
 * and no [data-theme] override here. A dark variant would be a new decision,
 * not a missing default.
 *
 * TYPE. The serif is carried over from prototype route B, the typography Jem
 * picked out. It does the formal, explanatory work: headlines and the "what
 * is an AI brain" section. The sans carries everything operational, the mono
 * everything that is data or a label.
 *
 * VISUALS. Current SaaS practice has moved away from abstract 3D and
 * illustration in the hero toward showing the actual product, and toward
 * bento grids for capability sections. Both are applied here: the hero holds
 * a real representation of the product home screen, and the capability
 * section is a bento. Every visual is CSS/SVG, so nothing is an image
 * request and nothing can fail to load.
 *
 * MOTIF. The waveform is from route C and appears on voice only, so it reads
 * as voice rather than as decoration.
 */

.e {
  /* THE TWO NUMBERS THE FOLD IS BUILT ON, declared here because the fold needs
     them and the nav is not its ancestor.

     `--e-nav-h` is the nav's real height, and the nav's padding is DERIVED from
     it below rather than written beside it: the two used to be separate
     literals in three media queries, which is a drift waiting to happen the
     first time somebody tunes one. Every nav control carries `min-height:44px`,
     so height = 44 + 2 * padding, and the calc is that arithmetic run backwards.

     `--e-hero-top` is the hero's own top padding. The fold subtracts both from
     100svh, which is what makes "one screen" mean the screen the visitor
     actually has rather than the screen minus a nav nobody accounted for. */
  --e-nav-h: 80px;
  --e-hero-top: 52px;
  --paper: #fdfbf8;
  --paper-2: #f7f2ec;
  --ink: #12131a;
  --ink-2: #5c5850;
  --ink-3: #8d867c;
  --line: #eae3da;
  --line-2: #f2ece4;
  /* One accent: the brain, and everything that reads from it. */
  --accent: #2b5ce6;
  --accent-2: #5b86f5;
  --accent-soft: #eef2fe;
  /* THE AI GRADIENT. Indigo to violet to rose.
     It started as one word of the headline - the "AI" in "All-in-one AI
     customer support" - and it is now the page's call-to-action colour as
     well, so it is declared once here rather than twice by coincidence.
     Jem: "make it the same colour as the AI in the header so it's synced, and
     then run that across wherever this input box and CTA is on the website."
     Change it here and the headline, the three submit buttons and the nav CTA
     all move together, which is the whole point of a token. */
  --e-ai: linear-gradient(120deg, var(--accent) 0%, #7c5cff 52%, var(--warm) 100%);
  /* The same gradient, darkened 10%, for anything carrying WHITE TEXT.
     Measured against #fff at each stop: #2b5ce6 5.56:1, #7c5cff 4.24:1,
     #d24215 4.64:1 - so the violet in the middle of the button missed the
     4.5:1 a label this size is owed, and only the middle. A flat 10% black
     over the whole ramp takes the three to 6.4:1, 5.18:1 and 5.51:1 and is
     invisible next to the headline. Do not use `--e-ai` behind white text. */
  --e-ai-ink:
    linear-gradient(0deg, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1)),
    linear-gradient(120deg, var(--accent) 0%, #7c5cff 52%, var(--warm) 100%);
  /* The revenue thread. Leads only, so the colour carries meaning. */
  --warm: #d24215;
  --warm-soft: #fdf1ec;
  --good: #17795e;

  --serif: "Iowan Old Style", Charter, Georgia, "Times New Roman", serif;
  --sans: "Geist E", -apple-system, BlinkMacSystemFont, "Helvetica Neue", system-ui, sans-serif;
  --mono: "SF Mono", ui-monospace, Menlo, monospace;

  /* The page-wide wash. Fixed attachment so the ground shifts hue as you
     scroll, and layered over the paper colour in the SAME declaration so
     nothing can paint on top of it. */
  background-color: var(--paper);
  background-image:
    radial-gradient(70% 48% at 4% 2%, rgba(255, 176, 100, 0.5), transparent 62%),
    radial-gradient(64% 44% at 98% 20%, rgba(43, 92, 230, 0.3), transparent 62%),
    radial-gradient(60% 42% at 0% 46%, rgba(210, 66, 21, 0.24), transparent 62%),
    radial-gradient(68% 46% at 100% 66%, rgba(124, 92, 255, 0.28), transparent 62%),
    radial-gradient(74% 48% at 12% 92%, rgba(255, 168, 96, 0.4), transparent 62%);
  background-attachment: fixed;
  background-repeat: no-repeat;
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  /* The hero splash bleeds past the content column on purpose. `clip` keeps
     that bleed from widening the document (a right-hand scrollbar) without
     creating a scroll container the way `hidden` would. */
  overflow-x: clip;
}

.e *,
.e *::before,
.e *::after {
  box-sizing: border-box;
}

.e-wrap {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 24px;
}

/* Grid children default to min-width:auto, which lets long content force the
   page wider than the phone. This is the single most common cause of a
   horizontally scrolling mobile layout. */
.e-grid > * {
  min-width: 0;
}

/* ---------- Nav ---------- */

.e-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  /* 44px is the min-height every control in this bar carries, so this resolves
     to the 18px it always was and the bar is exactly `--e-nav-h` tall. */
  padding: calc((var(--e-nav-h) - 44px) / 2) 0;
}

.e-brand {
  font-family: var(--mono);
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: -0.02em;
  text-decoration: none;
  color: var(--ink);
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

.e-brand-mark {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  background: linear-gradient(140deg, var(--accent), var(--accent-2));
  flex: 0 0 auto;
}

.e-nav-right {
  display: flex;
  align-items: center;
  gap: 6px;
}

.e-navlink {
  font-size: 14.5px;
  color: var(--ink-2);
  text-decoration: none;
  padding: 0 13px;
  border-radius: 8px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

.e-navlink:hover {
  color: var(--ink);
  background: var(--paper-2);
}

/* ---------- Hero ---------- */

.e-hero {
  padding: var(--e-hero-top) 0 24px;
  text-align: center;
  position: relative;
}

/* The colour splash. Sits behind the hero, bleeds past the content column,
   and fades out before the product shot so the UI stays on clean ground. */
.e-hero::before {
  content: "";
  position: absolute;
  inset: -160px -30vw auto;
  height: 680px;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(36% 44% at 50% 28%, rgba(43, 92, 230, 0.15), transparent 70%),
    radial-gradient(32% 42% at 80% 20%, rgba(232, 130, 60, 0.15), transparent 70%),
    radial-gradient(30% 40% at 20% 26%, rgba(240, 180, 110, 0.16), transparent 70%),
    radial-gradient(50% 50% at 50% 8%, rgba(255, 236, 214, 0.6), transparent 72%);
  -webkit-mask-image: linear-gradient(180deg, #000 52%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 52%, transparent 100%);
}

.e-h1 {
  font-family: var(--serif);
  font-weight: 400;
  /* Much bigger, and it keeps growing with the viewport instead of capping
     early. This is the first thing anyone reads; it should dominate. */
  font-size: clamp(46px, 8vw, 100px);
  line-height: 0.98;
  letter-spacing: -0.032em;
  margin: 0 auto;
  max-width: 15ch;
  text-wrap: balance;
  color: var(--ink);
}

/* One word carries the colour, so the line has a focal point rather than
   being an even wall of type. */
.e-h1 em {
  font-style: normal;
  /* The literal ramp used to live here. It is `--e-ai` now, because the field
     and its button wear the same one and two copies of a gradient drift. */
  background: var(--e-ai);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.e-sub {
  font-size: 17.5px;
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 58ch;
  margin: 14px auto 0;
  text-wrap: pretty;
}

.e-sub b {
  color: var(--ink);
  font-weight: 600;
}

/* ---------- The URL field: the primary action ---------- */

.e-url {
  margin: 34px auto 0;
  max-width: 540px;
  text-align: left;
}

/* The persistent field label. A placeholder alone let a visitor read the field
   as a chat box (Clarity, 2026-09-03); this stays put while they type. */
.e-url-label {
  display: block;
  margin: 0 0 7px 2px;
  font-size: 13px;
  font-weight: 560;
  color: var(--ink-2);
  letter-spacing: 0.01em;
}

.e-url-row {
  display: flex;
  gap: 8px;
  align-items: stretch;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 13px;
  padding: 6px;
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.04),
    0 8px 24px rgba(18, 19, 26, 0.05);
}

.e-url-input {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: 16px; /* under 16px, iOS Safari zooms the page on focus */
  padding: 13px 14px;
  border: 0;
  border-radius: 9px;
  background: transparent;
  color: var(--ink);
  min-height: 48px;
}

.e-url-input::placeholder {
  color: var(--ink-3);
}

.e-url-input:focus {
  outline: none;
}

.e-url-row:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.e-btn {
  font: inherit;
  font-size: 15.5px;
  font-weight: 560;
  padding: 13px 22px;
  min-height: 48px;
  border-radius: 9px;
  border: 0;
  background: linear-gradient(135deg, var(--accent) 0%, #4d3ae0 100%);
  color: #fff;
  cursor: pointer;
  white-space: nowrap;
  box-shadow:
    0 1px 2px rgba(43, 92, 230, 0.28),
    0 6px 18px rgba(43, 92, 230, 0.24);
  transition:
    transform 0.14s ease,
    box-shadow 0.14s ease,
    filter 0.14s ease;
}

.e-btn:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
  box-shadow:
    0 2px 4px rgba(43, 92, 230, 0.3),
    0 10px 24px rgba(43, 92, 230, 0.3);
}

@media (prefers-reduced-motion: reduce) {
  .e-btn {
    transition: none;
  }
  .e-btn:hover {
    transform: none;
  }
}

.e-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.e-btn[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

.e-url-note {
  margin: 18px auto 0;
  white-space: nowrap;
  max-width: none;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-3);
  text-align: center;
}

@media (max-width: 620px) {
  .e-url-note {
    white-space: normal;
  }
}

/* The add-on pricing note under the plan cards. At ~797px it is the longest
   `.e-url-note` on the page, so the 620px wrap threshold above left it
   CLIPPED mid-price by an overflow-hidden ancestor everywhere between 621 and
   ~860px (tablet portrait's 768 included): "…$20 a month each, on any pa|",
   a garbled price claim (mobile wave-1 QA, 2026-09-01). Wrapping is always
   allowed for this one; on a desktop line that fits, `normal` never wraps,
   so wide layouts are pixel-identical. */
.e-price-addons {
  white-space: normal;
}

.e-url-error {
  margin: 11px 2px 0;
  font-size: 14px;
  color: var(--warm);
  text-align: center;
}

@media (max-width: 540px) {
  .e-url-row {
    flex-direction: column;
    padding: 8px;
  }
  /* Scoped to this form on purpose. Unscoped, `width: 100%` also hit the
     sticky bar's button, and because a flex item sizes from its `width`
     before it flexes, that button claimed most of the row: measured at
     390px it took 180px of a 332px form and squeezed the field down to
     129px, which is why the placeholder read "yourbakery.co". */
  .e-url-row .e-btn {
    width: 100%;
  }
}

/* ---------- Hero product shot ---------- */
/* Real product surface rather than an abstract graphic: the Today inbox,
   which is the logged-in home screen we are building. */

.e-shot {
  margin: 56px auto 0;
  max-width: 1040px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow:
    0 2px 4px rgba(18, 19, 26, 0.04),
    0 24px 60px rgba(18, 19, 26, 0.08);
  overflow: hidden;
  text-align: left;
}

.e-shot-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--line-2);
  background: var(--paper);
}

.e-shot-dot {
  width: 9px;
  height: 9px;
  border-radius: 99px;
  background: #dededa;
}

.e-shot-title {
  margin-left: 8px;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-3);
}

.e-shot-body {
  display: grid;
  grid-template-columns: 186px 1fr;
}

@media (max-width: 720px) {
  .e-shot-body {
    grid-template-columns: 1fr;
  }
  /* The sidebar is NOT hidden here any more. Hiding it took the only control
     for the cycler away from the exact visitors who most need to drive it,
     leaving a phone user watching a 6.4s timer with nothing to press. It
     becomes a horizontal tab rail instead; see the small-screen section at
     the end of this file. */
}

.e-shot-side {
  border-right: 1px solid var(--line-2);
  padding: 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.e-navitem {
  font-size: 14px;
  color: var(--ink-2);
  padding: 9px 11px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 9px;
}

.e-navitem.on {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 560;
}

.e-navdot {
  width: 6px;
  height: 6px;
  border-radius: 99px;
  background: currentColor;
  opacity: 0.5;
}

.e-shot-main {
  padding: 24px 26px 26px;
  /* Fixed height: the panels have different row counts, and without this the
     whole shot resizes every time the tab advances, which is exactly the
     jump Jem flagged. */
  min-height: 342px;
}

.e-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-bottom: 18px;
}

.e-stat {
  background: var(--paper);
  border: 1px solid var(--line-2);
  border-radius: 11px;
  padding: 13px 14px;
}

.e-stat-n {
  font-size: 23px;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.e-stat-l {
  font-size: 12.5px;
  color: var(--ink-3);
  margin-top: 3px;
}

.e-stat.warm .e-stat-n {
  color: var(--warm);
}

.e-row {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 2px;
  border-top: 1px solid var(--line-2);
  font-size: 14.5px;
}

.e-pill {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 8px;
  border-radius: 5px;
  background: var(--paper-2);
  color: var(--ink-3);
  flex: 0 0 auto;
}

.e-pill.need {
  background: var(--warm-soft);
  color: var(--warm);
}

.e-pill.lead {
  background: var(--accent-soft);
  color: var(--accent);
}

.e-pill.done {
  background: #eef6f2;
  color: var(--good);
}

.e-row-t {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-row-m {
  margin-left: auto;
  font-size: 13px;
  color: var(--ink-3);
  white-space: nowrap;
  flex: 0 0 auto;
}

@media (max-width: 560px) {
  .e-stats {
    grid-template-columns: 1fr;
    gap: 8px;
  }
  .e-row-m {
    display: none;
  }
}

/* ---------- Sections ---------- */

.e-section {
  /* No divider rules: Jem asked for them gone. Sections are separated by a
     change of ground colour and by generous vertical space instead, which
     reads softer than a hairline. */
  padding: 88px 0;
  position: relative;
}

.e-section.tint {
  /* No background on the box itself. A painted box always ends in a hard
     edge where its gradient stops, which is the seam Jem spotted. */
  background: none;
}

/* The wash lives on a pseudo-element instead, and is masked to fully
   transparent at BOTH ends. Because the alpha reaches zero before the
   element's own boundary, there is no edge left to see, regardless of what
   colour the sections above and below happen to be. */
.e-section.tint::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* Just enough to separate a tinted band from a plain one. The page-scale
     wash behind everything carries the colour now. */
  background: linear-gradient(180deg, rgba(255, 252, 246, 0.62), rgba(255, 252, 246, 0.62));
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 20%, #000 80%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 20%, #000 80%, transparent 100%);
}

.e-center {
  text-align: center;
}

.e-kicker {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 16px;
}

.e-h2 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(32px, 4.4vw, 50px);
  line-height: 1.08;
  letter-spacing: -0.022em;
  margin: 0;
  max-width: 23ch;
  text-wrap: balance;
}

.e-center .e-h2 {
  margin-inline: auto;
}

/* W5 (Jem, 2026-09-01): a heading split into exactly two lines by hand.
   Block spans, so the browser cannot re-wrap the sentence at any width -
   line one carries "Teach your AI brain once," and line two "it never
   forgets." wherever the column ends up. */
.e-h2-line {
  display: block;
}

.e-body {
  font-size: 17px;
  line-height: 1.65;
  color: var(--ink-2);
  max-width: 60ch;
  margin: 18px 0 0;
  text-wrap: pretty;
}

.e-center .e-body {
  margin-inline: auto;
}

/* ---------- The brain diagram ---------- */
/* Jem: "super visual, easily understood, so people can see visually what an
   AI brain is." Sources feed one centre; every channel reads from it. */

.e-diagram {
  margin: 52px auto 0;
  max-width: 860px;
}

.e-dia-svg {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;
}

.e-dia-node {
  fill: #fff;
  stroke: var(--line);
  stroke-width: 1;
}

.e-dia-core {
  fill: url(#e-core-grad);
}

.e-dia-core-ring {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.2;
  opacity: 0.22;
}

.e-dia-label {
  font-family: var(--sans);
  font-size: 13px;
  fill: var(--ink-2);
}

.e-dia-label.strong {
  fill: var(--ink);
  font-weight: 600;
}

.e-dia-core-label {
  font-family: var(--sans);
  font-size: 13.5px;
  font-weight: 600;
  fill: #fff;
}

.e-dia-wire {
  fill: none;
  stroke: var(--line);
  stroke-width: 1.4;
}

.e-dia-wire.live {
  stroke: var(--accent);
  stroke-width: 1.6;
  opacity: 0.5;
  stroke-dasharray: 5 7;
  animation: e-flow 2.6s linear infinite;
}

@keyframes e-flow {
  to {
    stroke-dashoffset: -24;
  }
}

@media (prefers-reduced-motion: reduce) {
  .e-dia-wire.live {
    animation: none;
    stroke-dasharray: none;
  }
}

/* ---------- Bento grid ---------- */
/* Now the dominant pattern for SaaS capability sections. Tiles are sized by
   importance, not uniformly, so the eye is led. */

.e-bento {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-top: 48px;
}

/* Six tiles, three up, two rows, and the rows took their own content heights:
   397 above, 427.8 below at 1440 (qa-new W18, 2026-08-27). Nothing in this
   grid spans, so there is no reason for one row of the same six tiles to be
   30px shorter than the other. `1fr` rows in an auto-height grid all resolve
   to the tallest row's content, which is the parity Jem's eye checks. Only
   at three columns: at two the pairing changes and at one a shared height
   would be dead space under every short tile on a phone. */
@media (min-width: 861px) {
  .e-bento {
    grid-auto-rows: 1fr;
  }
}

.e-tile {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.03),
    0 10px 26px rgba(18, 19, 26, 0.05);
}

/* 🔴 NOTHING IN THIS GRID SPANS TWO COLUMNS ANY MORE, 2026-08-18. Jem, on two
   more panels being too wide - the same complaint that squared the pair of
   closers in the feature bento further down this file.

   THE TWO WERE FOUND BY MEASUREMENT, NOT BY EYE, because that is the method
   that found the right pair last time. Every panel on the page was measured at
   1440 (a panel being any block with a radius, a fill or a border, padding of
   at least 14px and real copy inside it). Sorted by width-to-height, the page
   was in three tight bands and two things stood outside them:

     6.67:1   1072x161   .e-tile.full   the channels strip   <- outlier
     1.92:1    347x181   .e-plan-steps li, all three of them
     1.70:1    710x417   .e-tile.wide   the AI chatbot tile  <- outlier
     1.45:1    529x366   .e-feat.big x2
     1.31:1    529x403   .e-feat.big x2
     1.13:1    258x227   .e-feat x6     (the pair squared on 2026-08-18)
     0.87:1    348x399   .e-tile x3
     0.83:1    348x417   .e-tile
     0.50:1    259x515   .e-plan x4

   The three step cards are NOT the answer even though they sit between the two
   outliers numerically: they are a set of three identical cards, each carrying
   a number, a heading and two full lines, and they were photographed and read
   as correctly filled. The complaint is a SHAPE plus a HOLE - "there's too much
   white space at the bottom" - and the two that had both are the two that span
   more than one column of this grid, which is also the only structural thing
   the page had left of that kind.

   WHAT EACH ONE ACTUALLY LOOKED LIKE. The chatbot tile was 710px of card
   holding a 664x261 demo with two short lines in it, so roughly half of the
   biggest tile in the section was empty. The channels strip was a 1072px band
   161px tall - a 6.67:1 letterbox, more than twice as wide-for-its-height as
   the 2.97:1 pair Jem pointed at last time.

   ONE COLUMN FIXES BOTH, AND IT ALSO CLOSES THE HOLE THE OLD SHAPE LEFT. Six
   tiles into three equal columns is exactly two rows with no gaps - the packing
   defect this grid was repacked to avoid ("it shouldn't have empty space") -
   and at two columns it is exactly three rows. Measured after: 348x417 and
   348x428, so 0.81:1 to 0.83:1, in the same band as the four tiles that were
   already right. */
.e-tile.wide,
.e-tile.full {
  grid-column: span 1;
}

@media (max-width: 860px) {
  .e-bento {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 600px) {
  .e-bento {
    grid-template-columns: 1fr;
  }
}

/* ---------- The channels card ---------- */
/* Restored 2026-08-11 (Jem: "I'd quite like to get that back because I think
   it works"). A quiet card by design: it is the last thing in a section of
   three loud demo tiles, and its job is to say "and these too" without
   competing with them. Marks at reading size, names as real text beside them,
   one row that wraps. */

.e-also-row {
  list-style: none;
  padding: 0;
  margin: 4px 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
}

/* 🔴 THE CHIPS STACK ONCE THE CARD IS A COLUMN, 2026-08-18. The card stopped
   spanning the row on the same day (see `.e-tile.wide, .e-tile.full` above),
   and a wrapping ROW inside a 348px column is what the square would have cost:
   eight chips wrap to five ragged lines about 255px tall inside a cell the
   grid stretches to ~400px, so squaring the card would have moved the white
   space rather than removed it. Measured before this rule: 142px of dead card
   under the last chip. With it: 1px, and the card is now the tallest thing in
   its row rather than the emptiest.

   `space-between` and not `flex-start`, because the row height is set by
   whichever tile is tallest and that is not guaranteed to stay this one. If a
   sibling ever grows, the chips distribute into the height instead of leaving
   a hole under the last of them.

   ONLY WHERE THE CARD IS NARROW. Below 601px the bento is a single column, the
   card is the full width of the page again, and a wrapping row is right - so
   this is scoped to the widths where the card is a column. */
@media (min-width: 601px) {
  .e-tile.full .e-also-row {
    flex: 1 1 auto;
    flex-direction: column;
    align-items: flex-start;
    justify-content: space-between;
    gap: 6px;
  }
}

.e-also-row li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  /* 44px of touch target on a phone, per the tap-target floor, even though
     these are not controls: a row of 30px chips reads as pressable and then
     is not, which is worse than a row that is comfortably sized. */
  min-height: 38px;
  padding: 8px 13px;
  border-radius: 999px;
  background: var(--line-2);
  border: 1px solid var(--line);
  font-size: 14px;
  font-weight: 550;
  color: var(--ink-2);
  white-space: nowrap;
}

.e-also-row svg {
  flex: none;
}

/* The long tail, in the page's own quiet register rather than as an eighth
   brand. */
.e-also-row li.more {
  background: transparent;
  border-style: dashed;
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.01em;
}

@media (max-width: 600px) {
  .e-also-row {
    gap: 8px;
  }
  .e-also-row li {
    min-height: 44px;
    padding: 10px 13px;
  }
}

/* BALANCED ROWS, MEASURED NOT GUESSED (orphan-row sweep, 2026-08-27, every
   viewport px from 360 to 600 against the measured chip widths). Seven brand
   chips and the 190px "9,000+ more via Zapier" chip in a left-packed wrap
   leave the long tail alone on the last line at 420-448 (3+2+2+1) and at
   554-600 (4+3+1). Inside those bands the row is a grid: two columns in the
   first (2+2+2+2) and three in the second, where the long-tail chip spans the
   last two cells so the final line reads [Zapier][9,000+ more]. Tracks are
   `auto` and the grid stretches, so every chip in a column is one width and
   the rows fill the card; the content is centred in the stretched chip.

   NOT A FULL-WIDTH FOOTER CHIP. Letting the long tail take its own 100% line
   was tried first and measured: it pairs up nothing, so wherever the seven
   brand chips do not divide (2+2+2+1 at 369-419, 3+3+1 at 449-553) Zapier is
   the one left alone just above it. The two grids are the only packings that
   leave no chip alone anywhere in 360-600, and they hold with a few px to
   spare on both edges of each band (two columns need 325px of a row that is
   340 or wider, three need 382px of one that is 474 or wider). From 601 the
   card is a bento column and this list stacks one chip per line (see above),
   so nothing here reaches it. */
@media (min-width: 414px) and (max-width: 452px) {
  .e-also-row {
    display: grid;
    grid-template-columns: repeat(2, auto);
  }
  .e-also-row li {
    justify-content: center;
  }
}

@media (min-width: 548px) and (max-width: 600px) {
  .e-also-row {
    display: grid;
    grid-template-columns: repeat(3, auto);
  }
  .e-also-row li {
    justify-content: center;
  }
  .e-also-row li.more {
    grid-column: span 2;
  }
}

.e-tile-label {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.e-tile-h {
  font-size: 18.5px;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0;
}

.e-tile-p {
  font-size: 14.8px;
  line-height: 1.58;
  color: var(--ink-2);
  margin: 0;
}

.e-tile-art {
  margin-top: 16px;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  /* 🔴 SMALLER AND SQUARE, 2026-08-26 (W04). Jem, walking /v2: "Same with this
     too much white space ... it should be smaller and square."

     WHAT THE WHITE SPACE ACTUALLY WAS. Measured at 1440 before this cap: the
     tiles were 348x417 and 348x428, i.e. 0.83:1 and 0.81:1 portrait, and the
     demo panel inside each one was 197-225 tall while its content needed as
     little as 110 (the email card: three lines and 24px of padding). The panel
     had `flex: 1 1 auto` and the note under this rule said "Demo panels grow
     into whatever height the row gives them" - so the tallest art in the row
     set the height and every other panel padded itself out with nothing to
     reach it. The empty band at the top of the email card was that slack.

     A CEILING, NOT A HEIGHT. `max-height` lets a panel that needs less stay
     smaller; it only stops one growing past the point where the tile stops
     being square. 150px is the arithmetic: the tile is 348 wide, its non-art
     content (label 16, heading 28, description 70, gaps and 22px padding) is
     ~198, so 348 - 198 = 150 would be the art height at which the card is
     exactly as tall as it is wide.

     🔴 IT IS 190, NOT 150, AND THE 40px IS NOT A ROUNDING. 150 clipped real
     content, twice, and a clipped card is a defect where a 0.88 card is only a
     preference. Measured with a test that walks every text node in the art box
     and compares its bounding rect to the box's own: at 150 the voice card lost
     "CALLER" and "Can I move my appointment?" (34px over) and the lead-capture
     card lost its third lead, Priya K (31px over). Both survive at 190, at
     every width. The `.e-tile` scrollHeight check MISSED both, because the
     overflow is inside the art panel and the tile itself never overflows -
     which is why the gate is a per-text-node rect test and not a scroll test.

     So the card is 348x388, 0.90:1, against the 348x417 (0.83:1) it was. */
  max-height: 190px;
}

/* Demo panels grow into whatever height the row gives them, up to the
   `max-height` ceiling above that keeps the card square. */

.e-wave {
  display: flex;
  align-items: center;
  gap: 3px;
  height: 38px;
}

.e-wave i {
  width: 3px;
  min-height: 3px;
  border-radius: 99px;
  background: var(--accent);
  animation: e-w 1.2s ease-in-out infinite;
}

@keyframes e-w {
  0%,
  100% {
    height: 14%;
  }
  50% {
    height: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .e-wave i {
    animation: none;
    height: 34%;
  }
}

.e-bubbles {
  display: flex;
  flex-direction: column;
  gap: 6px;
  height: 38px;
  justify-content: center;
}

.e-bubble {
  height: 9px;
  border-radius: 99px;
  background: var(--accent-soft);
}

.e-bubble.b {
  background: var(--accent);
  opacity: 0.3;
}

.e-lines {
  display: flex;
  flex-direction: column;
  gap: 7px;
  height: 38px;
  justify-content: center;
}

.e-line {
  height: 2px;
  border-radius: 99px;
  background: var(--line);
}

/* ---------- Leads ---------- */

.e-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
  align-items: center;
}

@media (max-width: 880px) {
  .e-split {
    grid-template-columns: 1fr;
    gap: 32px;
  }
}

.e-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  overflow: hidden;
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.03),
    0 14px 34px rgba(18, 19, 26, 0.05);
}

.e-card-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line-2);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.e-card-row {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line-2);
  font-size: 14.8px;
}

.e-card-row:last-child {
  border-bottom: 0;
}

.e-card-name {
  font-weight: 550;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-card-meta {
  margin-left: auto;
  font-size: 13px;
  color: var(--ink-3);
  white-space: nowrap;
  flex: 0 0 auto;
}

/* ---------- Pricing strip ---------- */

.e-price {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-top: 44px;
  align-items: stretch;
}

@media (max-width: 1000px) {
  .e-price {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 560px) {
  .e-price {
    grid-template-columns: 1fr;
  }
}

.e-plan {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 24px;
  text-align: left;
}

.e-plan.mid {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.e-plan-n {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.e-plan-p {
  font-family: var(--serif);
  font-size: 34px;
  letter-spacing: -0.02em;
  margin: 12px 0 0;
  font-variant-numeric: tabular-nums;
}

.e-plan-p span {
  font-family: var(--sans);
  font-size: 14px;
  color: var(--ink-3);
  letter-spacing: 0;
}

.e-plan-l {
  flex: 1 1 auto;
  list-style: none;
  padding: 0;
  margin: 16px 0 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.e-plan-l li {
  font-size: 14.6px;
  color: var(--ink-2);
  display: flex;
  gap: 9px;
  align-items: flex-start;
  line-height: 1.5;
}

.e-tick {
  color: var(--accent);
  flex: 0 0 auto;
  margin-top: 1px;
}

/* ---------- Footer ---------- */

.e-footer {
  padding: 40px 0 56px;
  color: var(--ink-3);
  font-size: 14px;
}

.e-footer a {
  color: var(--ink-2);
  text-decoration: none;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

.e-footer a:hover {
  color: var(--ink);
}

.e-footer-row {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  align-items: center;
  justify-content: space-between;
}

/* ---------- Header logo ---------- */

.e-brand-img {
  height: 22px;
  width: auto;
  display: block;
}

/* ---------- Inline emoji ---------- */
/* Paired with the word it illustrates, never replacing it. Nudged down a
   touch: emoji sit high against a serif baseline. */

.e-emo {
  font-size: 0.92em;
  line-height: 1;
  display: inline-block;
  vertical-align: baseline;
  transform: translateY(0.04em);
}

/* ---------- The reply being written ---------- */

.e-type {
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: 12px;
  background: var(--paper);
}

.e-type-to {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line-2);
  margin-bottom: 7px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-type-line {
  display: flex;
}

/* The text is revealed by animating max-width over a fixed string, so no
   per-character re-render and no chance of drifting out of sync. The caret is
   the right border, which therefore travels with the reveal edge. */
.e-type-text {
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  border-right: 1.5px solid var(--accent);
  /* Starts closed and stays closed until the demo is on screen; `.run` is
     added by useRunOnView. Running on mount meant nobody ever saw these, and
     looping would re-erase the answer the visitor is still reading. */
  max-width: 0;
}

@keyframes e-typing {
  from {
    max-width: 0;
  }
  to {
    max-width: 100%;
  }
}

@keyframes e-caret {
  0% {
    border-right-color: var(--accent);
  }
  50% {
    border-right-color: transparent;
  }
  /* Ends transparent, so no stray rule is left sitting after the line lands. */
  100% {
    border-right-color: transparent;
  }
}

@media (prefers-reduced-motion: reduce) {
  .e-type-text {
    animation: none;
    max-width: 100%;
    border-right-color: transparent;
    white-space: normal;
  }
}

/* Ask + source lines for the chat and refusal demos. */

.e-type-ask {
  font-size: 12.5px;
  color: var(--ink-3);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line-2);
  margin-bottom: 7px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-type.run .e-type-text {
  animation:
    e-typing 2.6s steps(44, end) 0.2s both,
    e-caret 0.8s step-end 0.2s 4 forwards;
}

.e-type-src {
  margin-top: 7px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--accent);
  opacity: 0;
}

.e-type-src.warn {
  color: var(--warm);
}

@keyframes e-src {
  from {
    opacity: 0;
    transform: translateY(3px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.e-type.run .e-type-src {
  animation: e-src 0.5s ease 2.9s both;
}

.e-type-reply {
  color: var(--ink);
}

.e-type-unsure {
  color: var(--warm);
  border-right-color: var(--warm);
}

@media (prefers-reduced-motion: reduce) {
  .e-type-src {
    animation: none;
    opacity: 1;
  }
}

/* ---------- The question flow ---------- */
/* Questions arrive from real people, converge on one AI brain, and answers go
   back out on every channel. Staggered CSS keyframes only: no JS, no per-frame
   cost, and it cannot drift out of step. */

.e-flow {
  margin: 52px auto 0;
  max-width: 940px;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 28px;
  text-align: left;
}

@media (max-width: 860px) {
  .e-flow {
    grid-template-columns: 1fr;
    gap: 22px;
    justify-items: center;
  }
}

.e-flow-asks,
.e-flow-replies {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
  width: 100%;
}

.e-ask,
.e-reply {
  display: flex;
  align-items: center;
  gap: 10px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 11px 13px;
  font-size: 14.5px;
  color: var(--ink-2);
  box-shadow: 0 1px 2px rgba(18, 19, 26, 0.04);
  opacity: 0;
}

.e-ask {
  animation: e-ask-in 3.6s ease-in-out infinite;
}

.e-reply {
  animation: e-reply-in 3.6s ease-in-out infinite;
  border-color: rgba(43, 92, 230, 0.28);
}

.e-ask-who,
.e-reply-icon {
  font-size: 17px;
  line-height: 1;
  flex: 0 0 auto;
}

.e-ask-q {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-reply-label {
  font-weight: 560;
  color: var(--ink);
}

.e-reply-tick {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--good);
  background: #eef6f2;
  padding: 4px 8px;
  border-radius: 5px;
  flex: 0 0 auto;
}

/* Questions slide in from the left and settle. */
@keyframes e-ask-in {
  0% {
    opacity: 0;
    transform: translateX(-14px);
  }
  14%,
  62% {
    opacity: 1;
    transform: none;
  }
  78%,
  100% {
    opacity: 0;
    transform: translateX(10px);
  }
}

/* Answers emerge on the other side, slightly later. */
@keyframes e-reply-in {
  0%,
  10% {
    opacity: 0;
    transform: translateX(-8px) scale(0.97);
  }
  26%,
  72% {
    opacity: 1;
    transform: none;
  }
  88%,
  100% {
    opacity: 0;
    transform: translateX(10px);
  }
}

/* The brain in the middle, pulsing as it takes each question. */
.e-flow-core {
  position: relative;
  display: grid;
  place-items: center;
  width: 132px;
  height: 132px;
  flex: 0 0 auto;
}

.e-flow-pulse {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: radial-gradient(circle, rgba(43, 92, 230, 0.22), transparent 68%);
  animation: e-pulse 3.6s ease-in-out infinite;
}

@keyframes e-pulse {
  0%,
  100% {
    transform: scale(0.82);
    opacity: 0.45;
  }
  22% {
    transform: scale(1.08);
    opacity: 1;
  }
  55% {
    transform: scale(0.92);
    opacity: 0.7;
  }
}

.e-flow-brain {
  position: relative;
  display: grid;
  place-items: center;
  gap: 2px;
  width: 96px;
  height: 96px;
  border-radius: 999px;
  background: linear-gradient(140deg, var(--accent) 0%, #4d3ae0 100%);
  color: #fff;
  box-shadow: 0 8px 26px rgba(43, 92, 230, 0.34);
}

.e-flow-brain-emo {
  font-size: 26px;
  line-height: 1;
}

.e-flow-brain-label {
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.95;
}

@media (prefers-reduced-motion: reduce) {
  .e-ask,
  .e-reply {
    animation: none;
    opacity: 1;
    transform: none;
  }
  .e-flow-pulse {
    animation: none;
    opacity: 0.6;
  }
}

/* ---------- The question pile-up (the problem) ---------- */
/* Cards drop from the top and land ON TOP of each other, so the stack reads as
   an avalanche rather than a tidy list. Nothing fades out and nothing repeats:
   the pile only ever grows, which is the point. */

.e-pile {
  margin: 52px auto 0;
  max-width: 640px;
  text-align: left;
}

.e-pile-view {
  position: relative;
  height: 400px;
  overflow: hidden;
  /* Fades top and bottom so cards enter and leave the frame instead of being
     chopped off by a hard edge. */
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 10%, #000 100%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 10%, #000 100%);
}

.e-pile-track {
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}

.e-pile-card {
  display: flex;
  align-items: center;
  gap: 11px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 13px;
  padding: 13px 15px;
  min-height: 48px;
  font-size: 15px;
  color: var(--ink);
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.05),
    0 8px 18px rgba(18, 19, 26, 0.06);
  opacity: 0;
  transform: translateY(-12px);
  transition:
    opacity 0.34s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.34s cubic-bezier(0.16, 1, 0.3, 1);
}

.e-pile-card.in {
  opacity: 1;
  transform: none;
}

.e-pile-who {
  font-size: 19px;
  line-height: 1;
  flex: 0 0 auto;
}

.e-pile-q {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-pile-via {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--warm);
  background: var(--warm-soft);
  padding: 5px 9px;
  border-radius: 6px;
  flex: 0 0 auto;
}

.e-pile-count {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 30px;
  text-align: center;
}

.e-pile-alarm {
  font-size: 26px;
  line-height: 1;
  transform-origin: center;
  /* scale + opacity are driven from JS as the counter climbs. */
  transition:
    transform 0.2s linear,
    opacity 0.2s linear;
}

.e-pile-count-n {
  font-family: var(--serif);
  font-size: 52px;
  color: var(--warm);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  min-width: 2.8ch;
  text-align: right;
}

.e-pile-count-l {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 16px;
  color: var(--ink-2);
  /* Wide enough that the punchline stays on ONE line. */
  max-width: none;
  text-align: left;
  line-height: 1.45;
  white-space: nowrap;
}

@media (max-width: 720px) {
  .e-pile-count-l {
    white-space: normal;
    text-align: center;
  }
}

.e-pile-count-l b {
  color: var(--warm);
  font-weight: 600;
}

@media (max-width: 560px) {
  .e-pile-via {
    display: none;
  }
  .e-pile-view {
    height: 340px;
  }
  .e-pile-count-l {
    text-align: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .e-pile-card {
    transition: none;
  }
  .e-pile-alarm {
    transition: none;
  }
}

/* ---------- Product shot: nav items are real buttons now ---------- */

.e-navitem {
  font: inherit;
  font-size: 14px;
  color: var(--ink-2);
  padding: 9px 11px;
  border: 0;
  background: transparent;
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  text-align: left;
  cursor: pointer;
  min-height: 40px;
}

.e-navitem:hover {
  background: var(--paper-2);
}

.e-navitem.on {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 560;
}

.e-navitem.quiet {
  cursor: default;
  opacity: 0.75;
}

/* Panels cross-fade as the tab changes (keyed on tab, so it remounts). */
.e-shot-main {
  animation: e-fade 1.15s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes e-fade {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  35% {
    opacity: 0.55;
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------- Channels panel ---------- */

.e-chan {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 2px;
  border-top: 1px solid var(--line-2);
  font-size: 14.5px;
}

.e-chan:first-child {
  border-top: 0;
}

.e-chan-icon {
  font-size: 19px;
  line-height: 1;
  flex: 0 0 auto;
}

.e-chan-t {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.e-chan-t b {
  font-weight: 600;
}

.e-chan-t span {
  font-size: 12.8px;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-chan-on,
.e-chan-add {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 5px 9px;
  border-radius: 6px;
  flex: 0 0 auto;
}

.e-chan-on {
  color: var(--good);
  background: #eef6f2;
}

.e-chan-add {
  color: var(--accent);
  background: var(--accent-soft);
}

.e-chan.off {
  opacity: 0.72;
}

/* ---------- Brain diagram extras ---------- */

.e-dia-emo {
  font-size: 15px;
}

.e-dia-core-emo {
  font-size: 22px;
}

.e-dia-node.out {
  stroke: rgba(43, 92, 230, 0.3);
}

.e-dia-orbit {
  fill: none;
  stroke: var(--accent);
  opacity: 0.2;
}

.e-dia-orbit.o1 {
  stroke-dasharray: 3 9;
  animation: e-spin 22s linear infinite;
  transform-origin: 440px 160px;
}

.e-dia-orbit.o2 {
  stroke-dasharray: 2 7;
  animation: e-spin 16s linear infinite reverse;
  transform-origin: 440px 160px;
}

@keyframes e-spin {
  to {
    transform: rotate(360deg);
  }
}

.e-dia-dot.in {
  fill: var(--ink-3);
  opacity: 0.55;
}

.e-dia-dot.out {
  fill: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  .e-dia-orbit.o1,
  .e-dia-orbit.o2 {
    animation: none;
  }
  .e-dia-dot {
    display: none;
  }
}

/* ---------- Human handover ---------- */

.e-ho-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.03),
    0 14px 34px rgba(18, 19, 26, 0.05);
}

.e-ho-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 14.5px;
  line-height: 1.5;
}

.e-ho-row .e-pill {
  flex: 0 0 auto;
  margin-top: 1px;
}

.e-ho-t {
  min-width: 0;
}

.e-ho-row.ai .e-ho-t {
  color: var(--ink-2);
}

.e-ho-hand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  padding: 8px 0;
  border-top: 1px dashed var(--line);
  border-bottom: 1px dashed var(--line);
}

.e-ho-arrow {
  font-size: 13px;
}

/* ---------- Reveal on scroll ---------- */
/* Long and soft on purpose. Short transitions and any overshoot both read as
   flicker; this settles rather than snaps. One property group, GPU-friendly. */

/* 🔴 THIS BLOCK IS INTENTIONALLY EMPTY OF MOTION, 2026-08-18.
 *
 * `.e-reveal` used to fade the whole section in (0.9s, 22px) and then rise its
 * `.e-h2`, `.e-body` and `.e-kicker` behind it on 0.06s / 0.14s / 0s delays.
 * That is the mechanism behind Jem's "I scroll here, the H1 is already there,
 * then the animation starts below": the observer fires on the SECTION, and a
 * section is 600-2000px tall, so it is intersecting long before its own heading
 * is comfortable in the viewport. The heading's rise ran while it was still
 * under the fold and was over by the time anyone looked at it. Only the cards
 * further down, which had their own per-element observer, still had motion left
 * to show.
 *
 * Two rules could not simply be retimed, they had to GO: those three child
 * animations set `animation-fill-mode: both`, and an animation's computed
 * values beat a plain declaration in the cascade, so any per-element `opacity:
 * 0` on a heading would have been overridden by its section's rule and the
 * heading would have arrived early anyway - silently, and only in a browser.
 *
 * Arrival is per element now: see `usePageReveal` in landing-e.tsx and the
 * `.will-reveal` block further down this file. `.e-reveal` stays as a class the
 * sections carry so there is one obvious place to hang section-level behaviour
 * if it is ever wanted again - it has no rules at all today, and that is the
 * whole point of it. `@keyframes e-rise` went with the three rules that were
 * its only callers; the hero arrival at the end of this file declares its own
 * (`e-hero-in`, 18px rather than 12px) rather than borrowing one that a section
 * might want back.
 */

/* ---------- Page-level colour, drawing the eye down ---------- */
/* A single fixed wash behind everything, so the ground shifts hue as you
   scroll instead of every section carrying its own background. Fixed
   attachment means no repaint cost while scrolling. */

/* Column headings and the agent sub-labels on the brain diagram. */
.e-dia-head {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.12em;
  fill: var(--ink-3);
}

.e-dia-sub {
  font-family: var(--sans);
  font-size: 11.5px;
  fill: var(--ink-3);
}

/* ---------- The long tail, under the three agents ---------- */

.e-dia-more {
  margin-top: 34px;
  text-align: center;
}

.e-dia-more-h {
  font-size: 15px;
  color: var(--ink-2);
  margin: 0 0 14px;
}

.e-dia-more-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  list-style: none;
  padding: 0;
  margin: 0;
}

.e-dia-more-list li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: var(--ink-2);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 9px 13px;
  min-height: 42px;
}

/* The two balanced-row media grids that stood here (418-535px six-track
   bricks, 762-856px four columns) were measured for the old SEVEN-chip row
   (orphan-row sweep, 2026-08-27) and retired with W6: the row is now two
   direct chips plus a separately-labelled six-chip Zapier row, and the
   measured spans would misplace both. A centred flex wrap carries 2 and 6
   without orphans at every width (6 wraps 3+3 or 2+2+2, never n+1). */

/* W6 (Jem, 2026-09-01): the labelled groups under the direct integrations -
   the native Bookings group (heading first, chips under it) and the Zapier
   breadth group, whose label was re-ruled the same day to "(9,000+ more via
   Zapier)": that text counts beyond the chips shown, so it trails the list
   (`.trail`) instead of heading it. */
.e-dia-more-zap {
  margin-top: 16px;
}

.e-dia-more-zaph {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 10px;
  font-size: 13.5px;
  font-weight: 550;
  color: var(--ink-2);
}

.e-dia-more-zaph.trail {
  margin: 10px 0 0;
}

.e-dia-more-sub {
  margin: 14px 0 0;
  font-size: 14px;
  color: var(--ink-3);
}

/* ---------- Leads: a captured contact, not another row list ---------- */

.e-leadcap {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 18px;
  overflow: hidden;
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.04),
    0 10px 26px rgba(18, 19, 26, 0.07),
    0 30px 60px rgba(18, 19, 26, 0.08);
}

.e-leadcap-top {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 18px;
  border-bottom: 1px solid var(--line-2);
  background: linear-gradient(180deg, var(--warm-soft), transparent);
}

/* `.e-leadcap-plan` was here: the tier line inside the captured-lead card.
   Deleted 2026-08-11 with every other tier name outside the pricing table. */

.e-leadcap-avatar {
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #fff;
  border: 1px solid var(--line);
  display: grid;
  place-items: center;
  font-size: 21px;
  flex: 0 0 auto;
}

.e-leadcap-id {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.e-leadcap-id b {
  font-size: 15.5px;
  font-weight: 600;
}

.e-leadcap-id span {
  font-size: 13px;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-leadcap-badge {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--warm);
  background: #fff;
  border: 1px solid var(--warm-soft);
  padding: 6px 10px;
  border-radius: 6px;
  flex: 0 0 auto;
}

.e-leadcap-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  margin: 0;
  padding: 0;
}

.e-leadcap-fields > div {
  padding: 14px 18px;
  border-bottom: 1px solid var(--line-2);
  min-width: 0;
}

.e-leadcap-fields > div:nth-child(odd) {
  border-right: 1px solid var(--line-2);
}

.e-leadcap-fields dt {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.e-leadcap-fields dd {
  margin: 4px 0 0;
  font-size: 14.5px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-leadcap-out {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 15px 18px;
}

.e-leadcap-out-l {
  font-size: 13.5px;
  color: var(--ink-3);
}

.e-leadcap-chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.e-leadcap-chips i {
  font-style: normal;
  font-size: 12.5px;
  color: var(--accent);
  background: var(--accent-soft);
  padding: 6px 10px;
  border-radius: 999px;
}

@media (max-width: 480px) {
  .e-leadcap-fields {
    grid-template-columns: 1fr;
  }
  .e-leadcap-fields > div:nth-child(odd) {
    border-right: 0;
  }
}

/* ---------- Handover: a baton pass between two actors ---------- */

.e-ho {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.e-ho-actor {
  display: grid;
  grid-template-columns: 46px 1fr;
  grid-template-rows: auto auto;
  column-gap: 13px;
  align-items: center;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 16px;
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.04),
    0 10px 24px rgba(18, 19, 26, 0.06);
}

.e-ho-face {
  grid-row: 1 / 3;
  width: 46px;
  height: 46px;
  border-radius: 999px;
  display: grid;
  place-items: center;
  font-size: 23px;
}

.e-ho-actor.ai .e-ho-face {
  background: var(--accent-soft);
}

.e-ho-actor.human .e-ho-face {
  background: #eef6f2;
}

.e-ho-who {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.e-ho-actor.human .e-ho-who {
  color: var(--good);
}

.e-ho-said {
  font-size: 15px;
  line-height: 1.45;
  color: var(--ink);
  margin-top: 3px;
}

/* The pass itself: a baton that travels the gap between the two actors. */
.e-ho-pass {
  position: relative;
  height: 64px;
  display: grid;
  place-items: center;
}

.e-ho-pass::before {
  content: "";
  position: absolute;
  top: 6px;
  bottom: 6px;
  left: 39px;
  width: 2px;
  background: linear-gradient(180deg, var(--accent), var(--good));
  opacity: 0.35;
}

.e-ho-baton {
  position: absolute;
  left: 35px;
  width: 10px;
  height: 10px;
  border-radius: 999px;
  background: var(--accent);
  box-shadow: 0 0 0 5px rgba(43, 92, 230, 0.16);
  animation: e-baton 2.4s cubic-bezier(0.5, 0, 0.5, 1) infinite;
}

@keyframes e-baton {
  0% {
    top: 4px;
    background: var(--accent);
    opacity: 0;
  }
  18%,
  22% {
    opacity: 1;
  }
  82% {
    background: var(--good);
    opacity: 1;
  }
  100% {
    top: 50px;
    background: var(--good);
    opacity: 0;
  }
}

.e-ho-passlabel {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin-left: 26px;
}

.e-ho-ctx {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-top: 16px;
  font-size: 13.5px;
  color: var(--good);
}

@media (prefers-reduced-motion: reduce) {
  .e-ho-baton {
    animation: none;
    top: 27px;
    opacity: 1;
  }
}

/* PRERENDER TAKEOVER (see e.css section R): the baton loops from the first
   frame (0ms delay), so it STARTS on the static #home-prerender copy AND again
   on the live copy React mounts ~460ms later - a second `animationstart`. The
   baton is an infinite loop, so the LIVE copy must keep looping; it is the
   PRERENDER copy's baton that must not also start (it is removed ~460ms in and,
   below the fold, never seen). Scoped to the prerender node so the live loop is
   untouched; held at its rest frame, like reduced motion above. No-op wherever
   #home-prerender is absent (/v2, dev, tests). */
#home-prerender .e-ho-baton {
  animation: none !important;
  top: 27px;
  opacity: 1;
}

/* Sandbox reassurance under the primary action. */
.e-url-safe {
  margin: 10px auto 0;
  max-width: 46ch;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-3);
  text-align: center;
}

/* A kicker line inside a heading, so "The good news" reads as its own beat
   rather than running into the sentence. */
.e-h2-kick {
  display: block;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--warm);
  margin-bottom: 14px;
}

/* ---------- Feature highlights ---------- */

/* ---------- The capability bento ---------- */
/* Jem: "The bento boxes work well but we could push the visuals a bit further
   and make this a bit more appealing."
   Ten cards of one size is a list in a grid's clothes. So four capabilities
   take two columns and two rows and carry a real picture of themselves, six
   stay one column, flat and quiet, and the CONTRAST between the two is the
   design. Plain auto-placement, no `dense`: the order of the FEATURES array is
   the order on screen, at every width. */

.e-feats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: minmax(176px, auto);
  gap: 14px;
  margin-top: 48px;
  text-align: left;
}

.e-feat.big {
  grid-column: span 2;
  grid-row: span 2;
}

/* 🔴 RENAMED `.wide` -> `.trust` FOR ALL SIX CLOSERS, 2026-08-27, and the two
   paragraphs below are why one of them may never be a two-column card again.
   The class the two carried was doing nothing (`.e-feat.wide` and a bare
   `.e-feat` were both one column), so it could not express "these six are one
   group" - which is what the full-row repack underneath this rule needs. Same
   geometry at every width this rule covers; only the name changed.

   🔴 THE TWO CLOSERS ARE ONE COLUMN NOW, 2026-08-18. Jem, walking the page and
   pointing at "Your branding, not ours" and "Your data never trains anyone's
   model": "these two don't need to be so wide, there's too much white space at
   the bottom, just make them squares, smaller."

   HE WAS LOOKING AT THE ONLY TWO PANELS ON THE PAGE THAT ARE ACTUALLY WIDE.
   Measured at 1440: these two were 529x178, a 2.97:1 letterbox; the four `big`
   art cards are 1.31-1.45:1 and the six quiet cards 1.13:1. Two lines of
   reassurance in a 529px box is what put the space under the text, and it is
   worse the moment the grid drops to two columns, where a `wide` card was the
   whole ~950px row for one capped 62ch sentence.

   ONE COLUMN MAKES THEM SQUARE FOR FREE. At 258px the same copy wraps to the
   same shape as the six cards beside it - measured 258x266 and 258x244, so
   1.0:1 and 0.94:1 - and the box is smaller in both dimensions than the 529x178
   it replaces. The `--feat-p-max: 62ch` cap went with the width: a 258px column
   is already narrower than 62 characters, so the cap could only ever be inert
   here, and leaving it would have been a rule that reads as load-bearing and
   is not. */
.e-feat.trust {
  grid-column: span 1;
}

/* THE SIX CLOSERS ARE ONE GRID OF THEIR OWN. They pack three-up at twelve
   columns and two-up below, and their rows took their own heights: 201.6 and
   227.1 at 1440 (qa-new W18, 2026-08-27), one paragraph wrapping one line
   further than its neighbours. Rows of the outer grid cannot be equalised on
   their own without dragging the big cards' rows along (one `fr` unit per
   grid), so the six sit in a nested grid whose `1fr` rows share the tallest
   closer's height. It spans the full outer row at every width, keeps the
   outer gap, and its columns follow the outer grid's breakpoints exactly, so
   the widths the cards had as direct children are the widths they have now
   ((W - 28) / 3 at twelve columns, half at two, all of it at one). The reveal
   stagger groups by parent, so the six now arrive as their own sequence. */
.e-feats-trust {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: 1fr;
  gap: 14px;
}

.e-feats-trust > * {
  min-width: 0;
}

/* THE PAIR IS CENTRED, because at four columns it is the last row and there are
   only two of them: left alone they sit in columns 1 and 2 and leave two holes
   at the end of the section, which is the exact defect this bento was repacked
   to close on 2026-08-18 ("it shouldn't have empty space"). Starting the first
   one in column 2 puts the pair under the middle of the grid, so the section
   closes on a deliberate centred coda rather than on a short row.

   `:nth-last-child(2)` and not a name: every child of `.e-feats` is one of
   these articles, so it means "the second from last", and it is guarded by
   `.wide` so it can only ever fire while the last two cards really are the two
   quiet closers.

   🔴 THAT GUARD IS WEAKER THAN THE SENTENCE THAT USED TO FOLLOW IT, which read
   "Add an eleventh feature and this rule stops applying rather than
   mis-applying." It does not. The guard is `.wide`, not "is one of the two
   closers", so adding any further `.wide` card puts a DIFFERENT card in the
   second-from-last slot and this rule shunts THAT one into column 2. Measured
   2026-08-26 at 1440 when six trust cards were added for W05/W06: the last
   eight packed 4 / 2 / 2 instead of 4 / 4, with two holes, because
   "Sign in with the identity you already use" was `.wide` and second from last.

   The six new cards therefore carry no `size` at all. `.e-feat.wide` and a
   plain `.e-feat` are both one column, so the class was buying nothing except
   a match on this selector. The rule now never fires - the section no longer
   ENDS on a short row of two, which is the only thing it was for - and it is
   left in place because the two closers are still `.wide` and a future repack
   that puts them last again should still centre them. */
/* 🔴 EVERY ROW IS A FULL ROW, 2026-08-27. Jem, walking /v2: "There are two
   empty boxes here which don't work. It needs to be full rows figure it out."

   THE HOLE WAS ARITHMETIC, NOT ORDER. At four columns a `big` card is 2x2 = 4
   cells and the ten quiet cards are 1 each, so the section asks the grid for
   4x4 + 10 = 26 cells. 26 is not a multiple of 4, so NO ordering of these
   fourteen cards can close on a full row - the last row packed 2 of 4 and left
   the two holes he saw, and any reshuffle just moves them.

   TWELVE COLUMNS, NOT FOUR, IS WHAT MAKES IT DIVIDE. The grid is the same
   geometry read at three times the resolution: `big` spans 6 (still half the
   row), the four quiet capability cards span 3 (still a quarter, still 258px),
   and the six trust cards span 4 - three to a row instead of four, so six of
   them are exactly two full rows.

     rows 1-2   big + big                       12/12
     row 3      phone, re-crawl, seats, files   12/12
     rows 4-5   big + big                       12/12
     row 6      three trust cards               12/12
     row 7      three trust cards               12/12

   NOT BY WIDENING THE LAST TWO, which is the other way to make 26 into 28 and
   is the one thing this grid may not do: a two-column quiet card is the 529x178
   letterbox Jem had already rejected on 2026-08-18 ("these two don't need to be
   so wide, there's too much white space at the bottom"). Three-up makes the
   trust card 348px, which is not a new width on this page - it is exactly the
   `.e-tile` width in the capability bento above.

   ONLY AT FOUR-COLUMN WIDTHS. Below 1001px the grid is two columns and ten
   quiet cards already pack 2-up into five full rows with no hole, so the
   media queries under this one are untouched.

   `.e-feats > .e-feat.wide:nth-last-child(2) { grid-column: 2 }` stood here and
   is deleted. It centred a trailing pair of two so a short row read as a coda;
   there is no short row left to centre, and its own comment recorded that the
   positional guard had already mis-fired once. */
@media (min-width: 1001px) {
  .e-feats {
    grid-template-columns: repeat(12, 1fr);
    /* The two pairs of big cards did not match: the first pair's rows were
       stretched by their own art to 187.4px each (388.8 tall) while the
       second pair sat on the 176px floor (366 tall) - qa-new W18, 2026-08-27.
       Naming the four rows the big cards span as flexible tracks makes them
       ONE size: in an auto-height grid every `fr` row takes the largest
       content share, so both pairs come out at the taller pair's height and
       the quiet row between them (auto) keeps its own. The order is the order
       of FEATURES in landing-e.tsx: big pair, quiet four, big pair, then the
       six closers in their own grid. */
    grid-template-rows: repeat(2, minmax(176px, 1fr)) auto repeat(2, minmax(176px, 1fr));
  }
  .e-feat {
    grid-column: span 3;
  }
  .e-feat.big {
    grid-column: span 6;
  }
  .e-feats-trust {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (max-width: 1000px) {
  .e-feats {
    grid-template-columns: repeat(2, 1fr);
  }
  /* Two columns: a big card is the full row, and the quiet four sit two-up
     underneath it. The rhythm survives, the reading width does not shrink.
     `.e-feat.trust` is NOT in here any more - it is a one-column card at every
     width below 1001px, so at two columns the six closers sit two-up and fill
     three rows exactly. */
  .e-feat.big {
    grid-column: span 2;
  }
  /* And it stops reserving two rows. Full width across two columns, the art
     already has the room it needs, so a forced 2-row minimum only opens dead
     space under the shortest of them. */
  .e-feat.big {
    grid-row: auto;
  }
}

@media (max-width: 620px) {
  .e-feats {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
  }
  .e-feat.big,
  .e-feat.trust {
    grid-column: span 1;
  }
  .e-feat.big {
    grid-row: span 1;
  }
  /* One column: no shared row height, a short closer stays short. */
  .e-feats-trust {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
  }
}

.e-feat {
  display: flex;
  flex-direction: column;
  /* THE QUIET DEFAULT. Flat, on the paper's own second tone, no shadow. A
     small card that is also elevated and white competes with the big ones,
     and then nothing leads. */
  background: var(--line-2);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 20px;
  /* Passed DOWN to the heading and the paragraph rather than reached back up
     for. `.e-feat.big .e-feat-h` would out-specify the phone's own type rules
     further down the file, so the big card would keep its desktop heading size
     at 390px, which is exactly the bug the mobile block exists to prevent. */
  --feat-h: 17px;
  --feat-p-max: none;
}

/* THE LOUD ONES. White, and the only cards with art. The white ground, the
   bigger heading and the picture are what make them lead; the box itself is
   the same box as the ten quiet cards. They used to carry 24px of padding and
   a 34px drop shadow on top of the white. Measured by the sibling-parity check
   on 2026-08-27 (every `.e-feat` in one grid, sampled at 1440): four cards at
   24px with a shadow against ten at 20px with a hairline was the one group on
   the page whose members did not share one padding and one border treatment.
   The estate is flat, hairline not glow, so the four came down to the ten
   rather than the ten going up to the four. */
.e-feat.big {
  background: #fff;
  --feat-h: 20px;
}

/* `.e-feat.wide { --feat-p-max: 62ch }` stood here. It capped the closers'
   paragraph so it did not run the full 1120px measure, which was the right
   rule while they were 529px letterboxes. They are one-column squares now (see
   the block by `.e-feat.wide` above), so the column is narrower than 62
   characters at every width and the cap can never bind. Deleted rather than
   left inert: a rule that cannot fire still reads as load-bearing to whoever
   changes the width next. */

/* THE TIER, OPPOSITE THE ICON.
   In the flow on the icon's own row, so it reads as metadata about the tile
   rather than as part of the sentence, and the heading below keeps the full
   width of the card to break on. */
.e-feat-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

/* `.e-feat-plan` (and its `.free` variant) was here: the tier badge on each
   of the ten feature tiles. Deleted 2026-08-11 on Jem's ruling. `.e-feat-top`
   survives it - it is what gives the icon its own row above the heading. */

.e-feat-icon {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent);
  /* The bottom margin moved to `.e-feat-top`, which now owns the row. */
  flex: none;
}

.e-feat-h {
  font-size: var(--feat-h, 17px);
  font-weight: 600;
  letter-spacing: -0.012em;
  margin: 0;
}

.e-feat-p {
  font-size: 14.8px;
  line-height: 1.58;
  color: var(--ink-2);
  margin: 8px 0 0;
  max-width: var(--feat-p-max, none);
  text-wrap: pretty;
}

/* A plan qualifier under a section that describes a gated capability. Muted,
   because it is a caveat and not a sales line, but --ink-2 rather than --ink-3
   so it is genuinely readable: a disclosure nobody can read is not one. */
.e-plan-note {
  margin: 18px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  /* 15px, like every other body string on the page. Measured at 390px on
     2026-08-11: the three lines that carried plan truth were the only three
     set below 15px, and a caveat set smaller than the copy it qualifies is a
     caveat the page is hoping you skim. This is the last of the three. */
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-2);
}

/* `.e-shot-plan` was here: the tier banner on the product shot's channels and
   leads panels. Deleted 2026-08-11. The channels panel keeps itself honest by
   its picture instead - one channel live, the rest unthrown switches. */

/* Leads carry the revenue colour wherever they appear. */
.e-feat-icon.warm {
  background: var(--warm-soft);
  color: var(--warm);
}

/* ---------- The four feature visuals ---------- */
/* Each one is the capability, drawn, rather than an icon standing in for it.
   They sit in the space a two-row card has left over, so they stretch rather
   than being given a fixed height: the row is whatever the tallest card in it
   needs, and the art fills what is under the paragraph. */

/* CENTRED IN WHATEVER IS LEFT, NOT PINNED TO THE FLOOR.
   A row is as tall as the tallest card in it, so the leads list sets the
   height of row one and the handover thread has slack. Bottom-aligned, that
   slack opened a hole between the paragraph and the picture and the two
   stopped reading as one card. Centred, the card looks composed at every
   height the grid gives it. */
.e-feat-art {
  margin-top: 16px;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* The lead list. Three rows, in the revenue colour, the same three people the
   product shot's leads panel names. */
.e-fa-leads {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  /* 5px, not 8px, 2026-08-26. Three lead rows at an 8px gap needed 196px inside
     an art box the square-card ceiling caps at 190, and the 6px difference
     trimmed the bottom row's lower edge - no text rect fell outside the box, so
     only the scrollHeight half of the clip gate caught it. Three gaps of 5
     recovers 6px exactly and the list still reads as a list. Trimming the gap
     rather than raising the ceiling keeps the card at 0.88:1 instead of 0.86:1,
     which is the whole point of the ceiling. */
  gap: 5px;
}

.e-fa-leads li {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 12px;
  border-radius: 12px;
  background: var(--paper);
  border: 1px solid var(--line);
}

.e-fa-av {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--line-2);
  font-size: 15px;
  line-height: 1;
}

.e-fa-who {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  flex: 1 1 auto;
}

.e-fa-who b {
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.e-fa-who em {
  font-style: normal;
  font-size: 12.5px;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-fa-src {
  flex: none;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 8px;
  border-radius: 999px;
  background: var(--line-2);
  color: var(--ink-3);
}

.e-fa-src.new {
  background: var(--warm-soft);
  color: var(--warm);
}

/* The handover, as two beats and a baton. Compact enough to sit inside a card
   without restating the full-size version 600px up the page. */
.e-fa-ho {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.e-fa-ho-line {
  display: flex;
  align-items: center;
  gap: 10px;
}

.e-fa-bub {
  flex: 1 1 auto;
  min-width: 0;
  padding: 9px 13px;
  border-radius: 12px 12px 12px 4px;
  background: var(--accent-soft);
  color: var(--ink-2);
  font-size: 13.5px;
  line-height: 1.4;
}

.e-fa-ho-line.human .e-fa-bub {
  background: var(--paper);
  border: 1px solid var(--line);
  color: var(--ink);
  font-weight: 550;
}

.e-fa-ho-pass {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-left: 14px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* One dot travelling the short gap between the two speakers, once every three
   seconds. It is the only thing moving on this card. */
.e-fa-ho-baton {
  width: 2px;
  height: 16px;
  border-radius: 99px;
  background: linear-gradient(var(--accent), transparent);
  position: relative;
}

.e-fa-ho-baton::after {
  content: "";
  position: absolute;
  left: -2px;
  top: 0;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  animation: e-fa-pass 3s ease-in-out infinite;
}

@keyframes e-fa-pass {
  0%,
  20% {
    top: -2px;
    opacity: 0;
  }
  35% {
    opacity: 1;
  }
  70%,
  100% {
    top: 14px;
    opacity: 0;
  }
}

.e-fa-ho-ctx {
  margin: 4px 0 0 14px;
  font-size: 12.5px;
  color: var(--good);
}

/* The language switcher. Every language written in its own language, so it
   needs no caption, and the highlight walks the list. */
.e-fa-langs {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

.e-fa-langs li {
  border-radius: 999px;
  background: var(--paper);
  border: 1px solid var(--line);
  font-size: 13px;
  color: var(--ink-3);
  transition:
    background 0.35s ease,
    color 0.35s ease,
    border-color 0.35s ease,
    transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

/* W13 (Jem, 2026-09-01): the chips are buttons now - picking one switches
   the whole card into that language. The li keeps the pill look it always
   had; the button inside it carries the padding so the entire pill is the
   hit area, and inherits every colour so `.on` keeps working unchanged. */
.e-fa-langs li button {
  display: block;
  width: 100%;
  padding: 6px 11px;
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  border-radius: inherit;
  cursor: pointer;
}

.e-fa-langs li button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.e-fa-langs li.on {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  transform: translateY(-1px);
}

/* BALANCED ROWS, MEASURED NOT GUESSED (orphan-row sweep, 2026-08-27, every
   viewport px from 360 to 1440 against the measured chip widths). Fourteen
   pills of fourteen different widths in a left-packed flex wrap leave Hindi
   alone on the last line in four bands: 360-374 (3+3+3+4+1), 400-446
   (4+4+5+1), 558-612 (6+7+1) and from 1114 up (6+7+1 again, once the big card
   came down to 20px of padding and the row gained 8px). Inside those bands the
   row is a grid with a column count that divides fourteen into full rows, and
   every pill in a column is the width of the widest, so the rows read as a
   keypad rather than a cloud. The count per band is the largest that fits the
   row's widest columns: three columns need 266px, four 344px, five 421px, and
   six 499px, which is why 400-421 takes three (a fourth column would overflow
   the card there) and the desktop band takes five (six would overflow 487px).
   Each band overruns the measured edge by a few px on both sides so a font
   that renders a pixel wider does not open a one-pixel window. Everywhere else
   the flex wrap already lands on a full last line and is left alone. */
@media (min-width: 360px) and (max-width: 376px), (min-width: 398px) and (max-width: 421px),
  (min-width: 422px) and (max-width: 452px), (min-width: 552px) and (max-width: 618px), (min-width: 1108px) {
  .e-fa-langs {
    display: grid;
    grid-template-columns: repeat(3, minmax(max-content, 1fr));
  }
  .e-fa-langs li {
    text-align: center;
  }
}

@media (min-width: 422px) and (max-width: 452px) {
  .e-fa-langs {
    grid-template-columns: repeat(4, minmax(max-content, 1fr));
  }
}

@media (min-width: 552px) and (max-width: 618px), (min-width: 1108px) {
  .e-fa-langs {
    grid-template-columns: repeat(5, minmax(max-content, 1fr));
  }
}

/* The gap report. The counts are the point: an unanswered question with a
   number beside it is a priority, without one it is a complaint. */
.e-fa-gaps {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.e-fa-gaps li {
  display: grid;
  grid-template-columns: 1fr 34px;
  align-items: center;
  gap: 4px 10px;
}

.e-fa-gap-q {
  font-size: 13.5px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.e-fa-gap-n {
  grid-row: 1 / span 2;
  grid-column: 2;
  justify-self: end;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  color: var(--warm);
}

.e-fa-gap-bar {
  grid-column: 1;
  display: block;
  height: 8px;
  border-radius: 99px;
  background: var(--line-2);
  overflow: hidden;
}

/* The bars grow once, when the card arrives, and the FINISHED width is the
   default. Only a card the reveal observer has actually taken charge of
   (`.will-reveal`, and not yet `.is-in`) is held at zero, so a browser with no
   IntersectionObserver, a server render and reduced motion all get a readable
   chart rather than three empty tracks. */
.e-fa-gap-bar i {
  display: block;
  height: 100%;
  width: var(--w);
  border-radius: 99px;
  background: linear-gradient(90deg, var(--warm), #f0764a);
  transition: width 1.1s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: 0.2s;
}

.e-feat.will-reveal:not(.is-in) .e-fa-gap-bar i {
  width: 0;
}

@media (prefers-reduced-motion: reduce) {
  .e-fa-gap-bar i {
    transition: none;
  }
  .e-fa-ho-baton::after {
    animation: none;
    top: 6px;
    opacity: 1;
  }
  .e-fa-langs li {
    transition: none;
  }
}

/* The specific moments a human is worth pulling in. Naming them is the point:
   "sometimes it hands over" is a shrug, a list is a promise. */
.e-triggers {
  list-style: none;
  padding: 0;
  margin: 20px 0 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.e-triggers li {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--ink);
}

.e-triggers li span {
  font-size: 17px;
  line-height: 1.35;
  flex: 0 0 auto;
}

/* ---------- Plan cards ---------- */

.e-plan {
  position: relative;
  /* 🔴 THE CARD'S ROWS ARE THE GRID'S ROWS, 2026-08-27. This was a flex
     column, and the four cards lined up their dashed notes only because the
     list carried `flex: 1 1 auto` and the note and the strapline reserved a
     fixed number of lines each (the min-heights below). That held while every
     card had the same parts. The full-list expander broke it in a way the
     reserves cannot reach: with the four lists open, the bodies started at
     different heights (measured at 1440: 558 / 519 / 499 / 538 from the top
     of the section), because each card's bullets and each card's list wrap
     differently and the flex column can only pin the bottom.

     Subgrid pins every row. The card is six rows of the pricing grid: name,
     price, strapline, bullets, expander, note. Each row is as tall as the
     tallest card's content for that row, so the four notes, the four
     expanders and the four open lists all start on one line by construction,
     in every state, at every width, and the reserves become belt and braces
     rather than the thing holding the row up. The gap between rows is the
     children's own margins, not the grid's, so the cards look as they did. */
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 6;
  row-gap: 0;
}

.e-plan-tag {
  position: absolute;
  top: -11px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #fff;
  background: linear-gradient(135deg, var(--accent), #4d3ae0);
  padding: 5px 11px;
  border-radius: 999px;
  white-space: nowrap;
}

.e-plan-line {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--ink-3);
  margin: 10px 0 0;
  min-height: 2.9em;
}

.e-plan-more {
  margin: 16px 0 0;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--accent);
  font-weight: 550;
  /* 🔴 TWO LINES' WORTH, AND NOW IT ACTUALLY IS, 2026-08-27. Jem, walking /v2:
     "the lines of the bottom aren't right. Advanced has two lines for the
     customers can send files and photos."

     He is pointing at the dashed rule, and it was 15px higher on Advanced than
     on the other three. The four cards are equal height and this note is the
     last child of a flex column whose list carries `flex: 1 1 auto`, so the
     note's BOTTOM was already aligned at 490 on all four - the rule that draws
     across its TOP can therefore only line up if all four notes are the same
     HEIGHT. "Customers can send files and photos" wraps to two lines where
     "API access" is one, so Advanced was 53px against 38px.

     THE RESERVE WAS ALREADY HERE AND WAS SHORT BY THE PADDING. `box-sizing:
     border-box` is global (line 110), so `min-height: 2.8em` was the height of
     the whole box - the 14px `padding-top` and the 1px border came OUT of it,
     leaving 22.8px of content, i.e. 1.2 lines. The comment said two lines and
     the number bought one. Measured at 1440: dividers at 453/453/438/453.

     Written as the sum of what is above it in this rule rather than as a
     rounder number, so it stays correct if the type or the padding moves:
     2.8em is two lines at this `line-height`, and 15px is `padding-top` plus
     the border that border-box counts in. Measured after: 453 on all four. */
  min-height: calc(2.8em + 15px);
  display: flex;
  align-items: center;
}

/* ---------- Everything in a tier, opened in place ----------
   Jem, 2026-08-27: "full visibility of everything under the tier." A native
   <details> on each card, between the selling bullets and the dashed note.
   Same plus-that-becomes-a-minus as the FAQ, smaller, because it is a line
   inside a card and not a heading. The card's flex column and the grid's
   stretch are what keep the four dashed rules level while one of these is
   open; see the note in landing-e.tsx where it is rendered. */

.e-plan-all {
  margin: 14px 0 0;
}

.e-plan-all-s {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 32px;
  cursor: pointer;
  list-style: none;
  font-size: 13.5px;
  font-weight: 550;
  color: var(--ink-2);
}

.e-plan-all-s::-webkit-details-marker {
  display: none;
}

.e-plan-all-s:hover {
  color: var(--accent);
}

.e-plan-all-s:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

.e-plan-all-mark {
  position: relative;
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
}

.e-plan-all-mark::before,
.e-plan-all-mark::after {
  content: "";
  position: absolute;
  top: 6px;
  left: 1px;
  width: 12px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform 0.22s ease;
}

.e-plan-all-mark::after {
  transform: rotate(90deg);
}

.e-plan-all[open] .e-plan-all-mark::after {
  transform: rotate(180deg);
}

.e-plan-all[open] .e-plan-all-s {
  color: var(--accent);
}

.e-plan-all-b {
  padding: 6px 0 4px;
}

.e-plan-all-g + .e-plan-all-g {
  margin-top: 14px;
}

.e-plan-all-cat {
  margin: 0 0 6px;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.e-plan-all-l {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.e-plan-all-l li {
  position: relative;
  padding-left: 14px;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--ink-2);
}

.e-plan-all-l li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent-2);
}

/* A row the tier does not have: greyed, with the table's dash where the dot
   was. Kept rather than dropped so four lists open to one height and so the
   row a visitor is missing sits beside the card that has it. */
.e-plan-all-l li.e-plan-all-no {
  color: var(--ink-3);
}

.e-plan-all-l li.e-plan-all-no::before {
  top: 0.72em;
  width: 6px;
  height: 2px;
  border-radius: 1px;
  background: var(--ink-3);
  opacity: 0.55;
}

@media (prefers-reduced-motion: reduce) {
  .e-plan-all-mark::before,
  .e-plan-all-mark::after {
    transition: none;
  }
}

/* ---------- Sticky conversion bar ---------- */
/* The page stays light everywhere else; this is a single dark surface whose
   whole job is to interrupt someone mid-read, so it is allowed to be loud.
   See the ruling history on .e-sticky-in below before touching its ground. */

.e-sticky {
  /* A transparent fixed frame. The glass itself lives on .e-sticky-in, which
     is what makes the bar float as a rounded card rather than run edge to
     edge. Nothing here paints, so the page shows through the gutters. */
  position: fixed;
  /* `--e-sticky-top` is the nav's bottom edge while the nav is on screen and
     0 once it has scrolled away, written per frame by the effect next to the
     latch in landing-e.tsx. The bar is fixed at the top of the viewport and
     the nav is in flow at the top of the page, so with `top: 0` the latched
     bar sat ON the nav whenever the visitor came back up: qa-new F26,
     2026-08-27, elementFromPoint at the centre of "Get started free" returned
     the bar at 53 of 55 widths from 360 to 1440. The class still never
     changes (Jem: "Once shown it should stay"); only where the bar rests
     does, and only for the top `--e-nav-h` of the page. */
  top: var(--e-sticky-top, 0px);
  left: 0;
  right: 0;
  z-index: 50;
  padding: 14px 18px 0;
  transform: translateY(-115%);
  opacity: 0;
  transition:
    transform 0.42s cubic-bezier(0.16, 1, 0.3, 1),
    opacity 0.42s cubic-bezier(0.16, 1, 0.3, 1);
  pointer-events: none;
}

.e-sticky.in {
  transform: none;
  opacity: 1;
  pointer-events: auto;
}

.e-sticky-in {
  /* 🔴 DARK INK, IN THE SYSTEM'S OWN COLOURS (Jem, launch-night walk
     2026-09-02, with a screenshot): "this colour has gone to white, it needs
     to stand out more." The 2026-09-01 restyle made this the system's paper
     card, and a paper card fixed over a paper page is invisible: the one
     surface whose whole job is to interrupt disappeared into what it floats
     over. The ground is now `--ink`, the page's own near-black, NOT the old
     indigo glass: no backdrop-filter, no gradient wash, no emoji, and the CTA
     keeps the flat accent (2026-08-26 ruling). The 09-01 "one visual system"
     ruling still holds; only the value of the ground flipped. Text goes
     `--paper` on ink (16.7:1), the white field pops hard against the dark,
     and the drop shadow is strong enough to read as a distinct layer over
     any section it lands on. The border matches the ground so the card's
     height does not move by 2px with the restyle.
     `.e-wrap` is on this element too, so its max-width and auto margins are
     overridden here: the frame's padding is what sets the gutter, and letting
     both apply left them uneven (18px against 29px).
     🔴 And `.e-wrap`'s 767px rule LATER in this file shorthand-zeroes this
     padding at equal specificity, which is why every sticky padding in the
     small-screen section is `.e-sticky .e-sticky-in` (see the note there). */
  max-width: 940px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 12px 18px;
  border-radius: 16px;
  color: var(--paper);
  background: var(--ink);
  border: 1px solid var(--ink);
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.06),
    0 16px 40px -8px rgba(18, 19, 26, 0.3);
}

.e-sticky-t {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

/* `.e-sticky-emoji` is gone with the ⚡ it sized (Jem, 2026-09-01): the bar
   carries the system's two lines of ink, nothing decorative. */

.e-sticky-t-main {
  display: block;
  font-size: 15.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

.e-sticky-t-sub {
  display: block;
  font-size: 12.5px;
  /* 66% white over `--ink`, a value already in this file (the port pills'
     veil): about 7.5:1, visibly a step under the `--paper` title. */
  color: rgba(255, 255, 255, 0.66);
  white-space: nowrap;
  margin-top: 1px;
}

/* The hero's field at a smaller scale: white ground, `--line` hairline, and
   the hero row's three-shadow AI glow. The glow was DESIGNED to survive this
   dark ground (see section K: "It also survives being put on the dark sticky
   bar"); it is what makes the white field read as the page's one lit control
   rather than a grey hole in the bar. Rest state carries the focus-state
   alphas from section K because the dark ground eats the resting ones. */
.e-sticky-form {
  display: flex;
  align-items: stretch;
  gap: 7px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 13px;
  padding: 5px;
  flex: 0 1 520px;
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.06),
    -14px 12px 30px -12px rgba(43, 92, 230, 0.55),
    0 18px 40px -14px rgba(124, 92, 255, 0.55),
    14px 12px 30px -12px rgba(210, 66, 21, 0.4);
}

/* The same focus answer as the hero row: the accent ring first, because it is
   the visible focus indicator, not decoration. The ring is `--accent-soft`
   (pale blue), which reads clearly against the ink ground; the glow widens a
   step, the same answer `.e-url-row:focus-within` gives. */
.e-sticky-form:focus-within {
  border-color: var(--accent-2);
  box-shadow:
    0 0 0 3px var(--accent-soft),
    0 1px 2px rgba(18, 19, 26, 0.06),
    -16px 14px 34px -12px rgba(43, 92, 230, 0.55),
    0 20px 46px -14px rgba(124, 92, 255, 0.55),
    16px 14px 34px -12px rgba(210, 66, 21, 0.4);
}

.e-sticky-form .e-url-input {
  min-height: 42px;
  padding: 9px 14px;
  color: var(--ink);
  background: transparent;
}

.e-sticky-form .e-url-input::placeholder {
  color: #a9a49b;
}

/* 🔴 THE CTA IS THE SYSTEM'S CTA: FLAT #2b5ce6, 12px RADIUS, NO GRADIENT
   (Jem's 2026-08-26 ruling, restated verbatim by check-design-tokens' banner,
   and re-asked 2026-09-01 with a screenshot of this exact button). This
   button has now been gold-to-amber and indigo-to-rose in turn; both were a
   second primary language on a one-accent page. Only the compact sizing is
   local -- face, label colour and states are the hero button's, one step
   smaller, so the bar reads as the hero input re-docked. White on #2b5ce6 is
   5.56:1. */
.e-sticky-form .e-btn {
  min-height: 42px;
  padding: 9px 20px;
  font-size: 14.8px;
  font-weight: 600;
  color: #fff;
  background: var(--accent);
  border-radius: 12px;
  box-shadow: 0 1px 2px rgba(43, 92, 230, 0.28);
}

.e-sticky-form .e-btn:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
  box-shadow:
    0 2px 4px rgba(43, 92, 230, 0.3),
    0 6px 16px -4px rgba(43, 92, 230, 0.3);
}

/* Base `.e-btn:focus-visible` (accent outline) applies unchanged: the white
   outline that the dark glass needed is gone with the glass. */

/* The bar used to drop `.e-sticky-t` entirely below 900px, which left a phone
   visitor looking at a naked field and a gold button with nothing telling them
   what pressing it does. That copy is the reassurance, and mobile is where
   most visitors are, so it is the last thing that should go. The bar is
   re-laid-out for narrow widths in the small-screen section at the end of this
   file instead: it keeps the copy and stacks. */
@media (max-width: 900px) {
  .e-sticky-form {
    flex: 1 1 auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .e-sticky {
    transition: none;
  }
  .e-sticky-form .e-btn:hover {
    transform: none;
  }
}

/* ---------- Nav ---------- */

.e-nav-mid {
  display: flex;
  align-items: center;
  gap: 2px;
}

@media (max-width: 900px) {
  .e-nav-mid {
    display: none;
  }
}

.e-nav-cta {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 18px;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font-size: 14.5px;
  font-weight: 550;
  text-decoration: none;
  white-space: nowrap;
  /* This was an <a> when the pill was styled; as a <button> it inherits
     cursor: default, which reads as inert on the page's primary CTA. */
  cursor: pointer;
  transition:
    background 0.14s ease,
    transform 0.14s ease;
}

.e-nav-cta:hover {
  background: #000;
  transform: translateY(-1px);
}

/* ---------- Footer ---------- */

.e-footer {
  padding: 64px 0 40px;
  color: var(--ink-3);
  font-size: 14px;
  border-top: 1px solid var(--line);
  background: rgba(255, 253, 250, 0.6);
}

.e-foot-top {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 2.2fr);
  gap: 48px;
}

@media (max-width: 900px) {
  .e-foot-top {
    grid-template-columns: 1fr;
    gap: 36px;
  }
}

.e-foot-brand p {
  margin: 16px 0 0;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 42ch;
}

.e-foot-tp {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px !important;
  color: var(--ink-2);
}

.e-foot-stars {
  color: #00b67a;
  letter-spacing: 0.06em;
}

.e-foot-cols {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
}

@media (max-width: 640px) {
  .e-foot-cols {
    grid-template-columns: repeat(2, 1fr);
    gap: 28px 20px;
  }
}

.e-foot-cols h3 {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink);
  margin: 0 0 12px;
}

.e-foot-cols div {
  display: flex;
  flex-direction: column;
}

.e-foot-cols a {
  font-size: 14.5px;
  color: var(--ink-2);
  text-decoration: none;
  min-height: 36px;
  display: inline-flex;
  align-items: center;
}

.e-foot-cols a:hover {
  color: var(--accent);
}

.e-foot-bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  justify-content: space-between;
  align-items: center;
  margin-top: 44px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
  font-size: 13.5px;
}

/* Anchor targets sit under the sticky bar without it, so every heading the nav
   points at reserves the bar's height plus a little breathing room.
   🔴 MEASURED, NOT GUESSED (team-qa #13): `--e-sticky-clear` is written per
   frame by the bar's placement effect in landing-e.tsx -- resting offset plus
   rendered height plus 20px -- because the flat 168px undershot whenever the
   bar stacked (640px and under), grew an error line, or rested under the nav,
   and the landed heading sat underneath it. 168px stays as the fallback for
   the pre-latch jump, when the bar is still off screen. */
.e [id] {
  scroll-margin-top: var(--e-sticky-clear, 168px);
}

/* ---------- Voice: a live call, not an empty card ---------- */

.e-call {
  border: 1px solid var(--line);
  border-radius: 13px;
  overflow: hidden;
  background: linear-gradient(160deg, rgba(43, 92, 230, 0.06), rgba(124, 92, 255, 0.05));
}

.e-call-top {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line-2);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.e-call-live {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--good);
  animation: e-callpulse 1.6s ease-in-out infinite;
}

@keyframes e-callpulse {
  0%,
  100% {
    opacity: 0.4;
    transform: scale(0.85);
  }
  50% {
    opacity: 1;
    transform: scale(1.15);
  }
}

.e-call-time {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}

/* 🔴 THE BAR STRIP IS GONE FROM THIS CARD, 2026-08-18. Four rules stood here
   sizing `.e-wave` inside it - a 52px strip, then the same bars again at 3px
   with a gradient. Jem, on this tile: make it more sophisticated. It carries
   the same sphere as the channel demo now, at `sm`, so the body's only job is
   to centre one object. `.e-wave` itself is untouched and still in this file:
   the channels surface imports this stylesheet and refines it. */
.e-call-body {
  padding: 14px 12px;
  display: grid;
  place-items: center;
}

/* THE CAPTION, IN THE DEMO'S OWN GRAMMAR. It was `<b>Caller:</b> "quote"` on one
   clipped `nowrap` line. It is the speaker as a monospace tag ABOVE the words
   now, centred under the sphere, which is the same `.e-vwho` / `.e-vtext` pair
   the big demo's subtitles use - so the two voice surfaces on this page finally
   agree with each other. It may wrap: a caption that ellipsises is a caption
   that has decided the second half of the sentence does not matter. */
.e-call-said {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 0 12px 14px;
  margin: 0;
  text-align: center;
}

/* Tile scale. The demo sets 16.5px for its panel (400px wide since 2026-08-27,
   560px before that); this is a 258px card. */
.e-call-said .e-vtext {
  font-size: 13.5px;
  line-height: 1.45;
}

/* ---------- Social proof, in the hero ---------- */
/* Directly under the field, where it answers "should I trust this enough to
   type my website in", rather than buried in the footer. */

.e-hero-proof {
  /* Inline flow, not flex: a flex container puts its gap either side of every
     child, which is what was padding out the emphasised words. */
  margin: 22px auto 0;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--ink-2);
  text-align: center;
}

.e-hero-stars {
  color: #00b67a;
  font-size: 15px;
  letter-spacing: 0.09em;
  margin-right: 8px;
}

/* 🔴 THE HALF STAR. Used by the hero proof line and the footer Trustpilot
   line, both of which drew FIVE solid stars against a real TrustScore of 4.4
   (measured 2026-08-25, 41 reviews). See the note at the hero's markup in
   landing-e.tsx; the live site's own footer (landing/v3-footer.tsx:92) has
   drawn four-plus-a-half since 2026-08-25 and this is the same treatment in a
   text glyph, so the two front doors finally agree.

   Half-fill by clipping a hard-stop gradient to the glyph: the left 50% is the
   Trustpilot green the other four stars use, the right 50% is the same hue at
   low alpha so the star's SHAPE still reads. `color: transparent` is what lets
   the background show through the letterform, so the fallback for a browser
   without background-clip:text would be an invisible star, not a solid one -
   which is why the -webkit- prefix is kept alongside the standard property.
   Every current target supports it; the failure direction is understated, not
   overstated, which is the right way round for a claim. */
.e-star-half {
  background-image: linear-gradient(90deg, #00b67a 50%, rgba(0, 182, 122, 0.3) 50%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

@media (max-width: 560px) {
  .e-hero-proof-sep {
    display: none;
  }
  .e-hero-proof {
    gap: 6px 9px;
  }
}

/* Registered address in the footer. */
.e-foot-addr {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-style: normal;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-2);
  margin-top: 18px;
}

.e-foot-addr b {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 3px;
}

.e-foot-addr span {
  color: var(--ink-3);
}

/* ---------- Customer and infrastructure proof ---------- */
/* Sits UNDER the product shot: the shot is the hook, the logos are the
   reassurance that follows it. */

/* 🔴 THE RULE ABOVE "Trusted by teams at" IS GONE, 2026-08-18. Jem, walking
   the homepage: remove the line directly above it. It was a `border-top` on
   this block, drawn the full 1120px of the wrap, and it was doing the job the
   PAGE already does - the proof strip is its own section under a full-height
   hero, so it needs no drawn edge to be read as separate.

   THE LOGOS AND THE SPACING BOTH STAY. He asked for the line, not the strip,
   so `padding-top` is kept exactly as it was: dropping it with the border would
   have pulled the strip 40px up into the hero and changed the one thing he did
   not ask to change. The hairline INSIDE the block (`.e-logos-powered`) also
   stays - that one separates the two arguments (who uses it / what it runs on)
   and is a different line in a different place. */
.e-logos {
  margin: 56px auto 0;
  padding-top: 40px;
  text-align: center;
}

.e-logos-l {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 22px;
}

.e-logos-powered {
  margin: 36px 0 0;
  padding-top: 28px;
  border-top: 1px solid var(--line);
}

.e-logos-powered .e-logos-l {
  margin-bottom: 20px;
}

.e-logos-row {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 40px;
}

/* These marks ship WHITE, for the dark strip on the current site. Greyscale
   left them invisible on a light ground; brightness(0) forces them to solid
   black, which is the correct treatment here and keeps every mark legible. */
.e-logos-row img {
  height: 26px;
  width: auto;
  filter: brightness(0);
  opacity: 0.72;
  transition: opacity 0.18s ease;
}

.e-logos-row img:hover {
  opacity: 1;
}

.e-logos-row-sm {
  gap: 30px;
  /* One height for the whole strip, so a phone tunes seven marks by changing
     one number rather than seven. */
  --mark-h: 21px;
}

.e-logos-row-sm img {
  height: 20px;
}

/* THE INFRASTRUCTURE MARKS, OPTICALLY EQUALISED.
   These are the vendors' real logos, so their boxes disagree wildly: AWS is
   1.7:1, Anthropic is a squat wordmark. Sizing them all to one box makes AWS
   shout. Height is set per mark and width follows the viewBox, using the same
   ratios already tuned by eye on the production homepage pill
   (landing/styles-page.css).

   The Pinecone mark this comment used to cite is GONE, 2026-08-26: we do not
   use Pinecone, we use Qdrant, and both the mark and the claim were removed
   from every surface. Left as a note rather than a silent edit so nobody
   re-adds a mark to "restore" the row. */
.e-mark {
  display: block;
  width: auto;
  height: var(--mark-h);
  /* Quiet: credibility, not a feature. Full colour would put a four-colour
     Google and a purple Mixpanel in competition with the product shot
     directly above them. */
  opacity: 0.72;
  filter: saturate(0.9);
  transition:
    opacity 0.18s ease,
    filter 0.18s ease;
}

.e-mark:hover {
  opacity: 1;
  filter: none;
}

.e-mark[data-mark="anthropic"],
.e-mark[data-mark="aws"] {
  height: calc(var(--mark-h) * 0.76);
}

.e-mark[data-mark="mixpanel"],
.e-mark[data-mark="digitalocean"] {
  height: calc(var(--mark-h) * 0.94);
}

/* Visible to screen readers and crawlers; the marks themselves are decorative. */
.e-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 760px) {
  .e-logos-row {
    gap: 26px;
  }
  .e-logos-row img {
    height: 20px;
  }
  .e-logos-row-sm {
    /* Seven marks wrap to two or three lines on a phone. Tighter and smaller
       so they read as one quiet block rather than as a second logo section. */
    gap: 22px 24px;
    --mark-h: 17px;
  }
  .e-logos-row-sm img {
    height: 16px;
  }
}

/* FIVE MARKS NEVER LEAVE ONE BEHIND, 2026-08-27 (orphan-row sweep, every
   viewport px from 360 to 1440 against the measured mark widths). The customer
   row is five marks of ~89px at the phone size and ~116px above it. Centred
   flex wrap put four on a line and the fifth alone underneath at 458-584 and
   again at 761-786, where the marks have grown to 26px and 40px gutters but the
   row has not yet reached the 738px five of them need.

   Below 600 the row is a six-track grid: every mark spans two tracks, so the
   first line holds three, and the last two are placed on tracks 2-3 and 4-5,
   so the second line holds two, centred under the first. Tracks are
   max-content and the grid is centred, which is exactly the 3+2 the wrap
   itself lands on below 458px, only guaranteed. At 761-792 the gutter is 30px
   instead of 40: five 116px marks with four 30px gutters are 698px, and the
   row is 713px or wider there, so one line holds all five. From 787 the 40px
   gutter fits on its own. Scoped to the customer row: the seven "Powered by"
   marks share the class, wrap 4+2 at every width, and are left alone. */
@media (min-width: 452px) and (max-width: 599px) {
  .e-logos-row:not(.e-logos-row-sm) {
    display: grid;
    grid-template-columns: repeat(6, max-content);
    justify-content: center;
  }
  .e-logos-row:not(.e-logos-row-sm) img {
    grid-column: span 2;
  }
  .e-logos-row:not(.e-logos-row-sm) img:nth-child(4) {
    grid-column: 2 / span 2;
  }
  .e-logos-row:not(.e-logos-row-sm) img:nth-child(5) {
    grid-column: 4 / span 2;
  }
}

@media (min-width: 761px) and (max-width: 792px) {
  .e-logos-row:not(.e-logos-row-sm) {
    gap: 30px;
  }
}

/* `.e-logos-txt` lived here: Anthropic, Google and DigitalOcean set as type
   because we had no mark on disk for them. All three now have their real
   logos, so the rule is gone rather than left behind to rot. */

/* ---------- The diagram, in the hero ---------- */
/*
 * ONE BRAIN, FOUR CAPABILITIES, EVERY CHANNEL. It was a left-to-right rail of
 * chips with an arrow in it, which reads as a list with a typo; it is a
 * top-down diagram now, so the row states a RELATIONSHIP rather than an
 * inventory.
 *
 * WHAT CAME FROM WHERE. The vertical stack, the fan of four curves out of one
 * point and the small-screen stem are hero 32's. The chips themselves are hero
 * 31's: compact pills with a bare noun and a drawn glyph, one lighting at a
 * time, rather than 32's four tall cards with a second line of copy each - at
 * fold size the cards were the thing that stopped it being readable in three
 * seconds.
 *
 * THE FAN'S STOPS ARE THE CHIP CENTRES BY CONSTRUCTION, not by eye: the chips
 * are a four-column grid of equal columns and the curves land at 1/8, 3/8, 5/8
 * and 7/8 of the same width. Change the number of capabilities and both follow
 * `HERO_CAPABILITIES.length` together.
 */

.e-mech {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 20px auto 0;
  max-width: 100%;
  font-size: 15px;
}

.e-mech-brain,
.e-mech-ch {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 13px;
  border-radius: 999px;
  white-space: nowrap;
}

.e-mech-brain {
  background: linear-gradient(135deg, var(--accent), #4d3ae0);
  color: #fff;
  font-weight: 600;
}

.e-mech-ch {
  background: #fff;
  border: 1px solid var(--line);
  color: var(--ink);
  transition:
    border-color 260ms ease,
    box-shadow 260ms ease,
    transform 260ms ease;
}

/* The glyph is the only thing in the chip that changes colour, which is what
   lets one capability be "live" without the row flashing. */
.e-mech-ico {
  display: inline-flex;
  color: #b0a89e;
  transition: color 260ms ease;
}

/* The live chip keeps the SAME border, shadow and position as its siblings.
   Jem, 2026-08-27, on a screenshot of this row with one chip haloed and lifted:
   "these are mismatched and this is the kind of stuff you need to find and
   fix from a visual perspective". The glyph colour below is the whole signal,
   which is what the comment above always said the design was. */
.e-mech-ch.on {
  border-color: var(--line);
  box-shadow: none;
  transform: none;
}

.e-mech-ch.on .e-mech-ico {
  color: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  .e-mech-ch {
    transition: none;
  }
}

/* Four curves from one point. `preserveAspectRatio: none` plus a non-scaling
   stroke means the fan stretches to whatever the column is without the
   hairline getting fatter at 1440 or thinner at 900. */
.e-fan {
  display: block;
  width: min(900px, 100%);
  height: 48px;
  margin: 0 auto;
}

/* The stem only exists below the breakpoint, where the fan cannot aim. */
.e-mech-stem {
  display: none;
}

.e-mech-caps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  justify-items: center;
  gap: 10px;
  width: min(900px, 100%);
  margin: 0 auto;
}

/* EVERY CHANNEL THE BRAIN REACHES, under the capabilities that reach them.
   Jem: "show people that this AI brain will channel every single one of your
   channels." Quieter than the capability chips on purpose - it is the long
   tail, not a fifth capability - and every name is real text, never a tooltip
   on a logo. */
.e-mech-ports {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 7px;
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
}

.e-mech-ports li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 11px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.66);
  color: var(--ink-2);
  font-size: 13.5px;
  white-space: nowrap;
}

.e-mech-ports svg {
  flex: 0 0 auto;
}

/* W4 (Jem, 2026-09-01): the two group pills. The Zapier one's visible label
   is the claim - "(9,000+ more via Zapier)", Jem's exact text, count first,
   trailing the six marks it counts beyond - and the Bookings one
   (`.e-book-group`) leads with its label because "Bookings" names what the
   four native marks are. Either may wrap INTERNALLY on a narrow screen -
   label on one line, marks on another - which is why they override the
   row's nowrap. The dashed border is what says "a grouping, not another
   direct channel chip". */
.e-mech-ports li.e-zap-group {
  flex-wrap: wrap;
  justify-content: center;
  white-space: normal;
  gap: 6px 9px;
  border-style: dashed;
}

.e-zap-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 550;
}

.e-zap-marks {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.e-zap-mark {
  display: inline-flex;
  align-items: center;
}

/* The 500-840px four-column balancing grid that stood here was measured for
   the old SEVEN-chip row (qa-new sweep, 2026-08-27) and retired with W4: the
   row is two direct chips plus one wide group now, and a centred flex wrap
   lands that on full lines by itself, while four max-content columns would
   have parked three items against an empty fourth track. */

/* THE GREEN OUTCOME CHIP, restored 2026-08-12 at Jem's request, carrying
   "Answers your customers, day and night" instead of the lead-capture claim
   that got the original deleted. It closes the diagram from the bottom now
   rather than ending a line, because the diagram runs downward.

   Green because it is the only element here that is an OUTCOME rather than a
   part: the capability chips are white-on-line and deliberately uniform, so a
   single tinted chip closes the sequence without competing with the brain pill
   that opens it.

   Measured against the tinted ground this sits on, not against white: #0f6b3f
   on #eaf6ef is 6.7:1, so it clears AA at this size with room to spare. */
.e-mech-out {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 14px;
  padding: 8px 13px;
  border-radius: 999px;
  white-space: nowrap;
  background: #eaf6ef;
  border: 1px solid #b8e0c8;
  color: #0f6b3f;
  font-weight: 600;
}

/* `.e-mech-arrow` was here: the "->" that used to sit between the brain and
   the first chip and between the last chip and the outcome. The fan and the
   stem say the same thing with geometry, and an arrow inside a wrapping row
   points at the edge of the screen as often as it points at anything.

   `.e-mech-plan` was here too: the tier pill, taken off by Jem on 2026-08-11 -
   "we don't need to highlight it everywhere" - and there is nothing left on
   the page for it to style. The chip-count test asserts it stays at zero. */

@media (max-width: 760px) {
  /* Four curves aimed at four evenly spaced stops land on nothing once the
     chips wrap into two centred rows, and a fan that misses is worse than no
     fan. The SVG goes, one hairline takes its place, and the diagram is still
     a diagram - it has just stopped pretending to be aimed. */
  .e-fan {
    display: none;
  }

  .e-mech-stem {
    display: block;
    width: 1px;
    height: 26px;
    margin: 0 auto;
    background: #ded6cb;
  }

  /* A centred wrapping row rather than a rigid two-by-two: "AI email
     management" is half again as wide as "AI chatbot", and fixed columns give
     the widest chip a cell it does not fit in while the narrowest sits in a
     cell half empty. */
  .e-mech-caps {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    width: auto;
  }
}

/* Same measurement as the ports rule above: below 760 the caps flex-wrap
   lands 3+1 from 500 to 640px. Four balances only as 2+2, and this sits AFTER
   the flex rule on purpose, because the cascade, not the media query, decides
   which display wins. */
@media (min-width: 481px) and (max-width: 659px) {
  .e-mech-caps {
    display: grid;
    grid-template-columns: repeat(2, max-content);
    justify-content: center;
  }
}

/* Below 372px four chips do not fit a line (measured: 372 wraps 3+4, 373 wraps 4+3), so seven cannot balance and
   wrap 3+3+1. wags's ruling (2026-08-27, relay 17376): the seventh chip takes
   whole last line, centred. Below 760 these items carry no border or fill, so
   a full-width item with centred content reads as a centred chip, and the
   100% basis is what tells a layout check the lone item is deliberate. */
@media (max-width: 371px) {
  .e-mech-ports li:last-child {
    flex: 0 0 100%;
    justify-content: center;
  }
}

/* ---------- The lede, restored ---------- */
/* Desktop is the design surface, and at 1440px the headline had nothing under
   it but a row of chips. This is the sentence that makes the promise, and it
   is sized to be read as the second thing on the page rather than as a caption
   to the first. */

.e-lede {
  margin: 22px auto 0;
  max-width: 46ch;
  font-size: clamp(18px, 1.45vw, 21px);
  line-height: 1.55;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* ---------- What free actually is ---------- */
/* Sits directly under the field that recruits into it, because the honest
   place to name a plan's contents is next to the button that joins it. Four
   ticks, then one muted line naming what is NOT included and what it costs. */

.e-free {
  margin: 26px auto 0;
  max-width: 760px;
  text-align: left;
  padding: 18px 22px 16px;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.62);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.e-free-l {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 650;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.e-free-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 9px 22px;
}

.e-free-list li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 15.5px;
  line-height: 1.42;
  color: var(--ink);
}

.e-free-list svg {
  flex: none;
  margin-top: 2px;
}

/* `.e-free-not` was here. It carried the hero's one tier disclosure, putting
   branding on the Starter tier and phone, email and lead capture on Advanced,
   and it is deleted with the sentence, 2026-08-11. The sentence itself is not
   reproduced in this repo any more: `routes/product-home/p6` pins website copy
   by reading it off disk, and a pin that passes on a comment is worse than a
   pin that fails.

   The free panel above it now scopes free on its own, positively: all four of
   its ticks are about the website. Nothing needs to negate anything. */

@media (max-width: 620px) {
  .e-free-list {
    grid-template-columns: 1fr;
  }
  .e-free {
    padding: 16px 18px 14px;
  }
}

/* ---------- Three-channel showcase ---------- */
/* Leading with the widget alone is what makes people read us as a chatbot
   company. Chat, voice and email get equal billing here. */

/* 🔴 THE THREE TABS ARE ONE WIDTH, 2026-08-27. Jem, walking /v2: "these three
   boxes need to be the same width. I'm very pedantic when it comes to padding
   styling consistency."

   They were content-sized, so the label decided the box: measured at 1440 they
   were 171 / 188 / 231, because "AI chatbot" is nine characters and "AI email
   management" is twenty. Three tabs of a set, three different widths.

   `flex: 1 1 0` on the tab makes the basis the same for all three whatever the
   label, and the cap on the row is what stops equal-width becoming full-width
   across a 1072px wrap. 720 is the widest of the three (231) times three plus
   the two 8px gaps, rounded up, so nothing has to shrink to fit.

   Below 720px the tab is already `flex: 1 1 100%` (see its media query) and
   stacks one per row, which is unchanged by this. */
.e-chan-tabs {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
  margin: 40px auto 0;
  /* min(), not a bare 720px: the "anything wide gets its own scroll container"
     guard further down used to re-declare `max-width: 100%` on this selector
     and, being later with the same specificity, won whatever was set here. The
     guard's intent is folded in rather than fought. */
  max-width: min(720px, 100%);
}

.e-chan-tab {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  font: inherit;
  text-align: left;
  padding: 11px 18px;
  min-height: 56px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink-2);
  cursor: pointer;
  transition:
    border-color 0.16s ease,
    color 0.16s ease,
    transform 0.16s ease;
}

.e-chan-tab:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
}

/* THE SELECTED TAB IS A FILL, NOT A GLOW, 2026-08-27. It carried a 20px blue
   drop shadow and a transparent border, so the three siblings in one rail had
   two border colours and two shadows between them; the sibling-parity check
   measured it, and a 20px glow is the thing this flat estate does not do. The
   fill (the page's own primary, the same gradient as the CTA) plus white type
   is the whole visual difference now, and the hairline is the one every tab
   wears. The state is announced too: the button carries `aria-selected` and
   the rail is a `tablist` (landing-e.tsx). */
.e-chan-tab.on {
  color: #fff;
  background: linear-gradient(135deg, var(--accent), #4d3ae0);
}

.e-chan-tab-t {
  display: flex;
  flex-direction: column;
  line-height: 1.25;
}

.e-chan-tab-t b {
  font-size: 14.5px;
  font-weight: 600;
}

.e-chan-tab-t em {
  font-style: normal;
  font-size: 12.5px;
  opacity: 0.72;
}

.e-chan-stage {
  margin-top: 34px;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  /* 🔴 THE RESERVE IS THE TALLER OF THE TWO PANELS, NOT THE WIDGET, 2026-08-27.
     It was 760px, fixed to the 743px chat widget, and `.e-chan-demo` below took
     `align-self: stretch` to fill it - so the voice and email cards were padded
     out from the 485px and 397px they actually need to a flat 760px. That slack
     is the "too much white space" Jem pointed at: 275px of empty card under the
     call, 363px under the draft.

     What the old number bought was that no tab switch moves the page, and that
     is worth keeping for the two panels that share this shell, so the reserve
     stays - set to the taller of THEM (voice, 485) rather than to the widget.
     Voice and email are now the same height as each other, the card is only as
     tall as its content, and the chat widget grows the stage past the reserve
     the way any taller child would.

     🔴 500 -> 520, 2026-08-27 (second pass). The two panels are 400px wide now
     rather than 560, and the email one carries the customer's original message,
     so the taller of THEM is 520 (email) against 457 (voice). 500 was under the
     email card, which is the one thing this reserve exists to prevent: the
     stage grew past it on the email tab and the page moved when he clicked
     between the two. Measured at 1440: voice 457, email 520. */
  min-height: 520px;
  animation: e-fade 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

@media (max-width: 640px) {
  .e-chan-stage {
    min-height: 0;
  }
}

/* Shared frame for the voice and email views, matched to the widget's width so
   switching tabs does not resize the section.

   🔴 THE 560 CAP WAS DEAD FOR AS LONG AS IT HAS BEEN WRITTEN HERE, 2026-08-27.
   Jem: "Both of these boxes, one for voice, one for email are too big, there's
   too much white space." He was right and the cause was the cascade, not the
   number: `.e-shot, .e-card, .e-leadcap, .e-chan-demo, .e-ho-actor` in section
   9 re-declared `max-width: 100%` on the same selector with the same
   specificity and sits LATER in this file, so the later one won and the panel
   took the full 1072px of the wrap - 2.7x the 400px chat widget it is supposed
   to match. Measured at 1440 before the fix: 1072x760.

   `.e-chan-demo` is out of that group now and the guard's intent is folded in
   here with min(), so the panel is capped AND can still never be wider than
   the space it is in.

   🔴 THE CAP IS 400, NOT 560, 2026-08-27 (second pass). Jem: "these three boxes
   need to be the same width." 560 was chosen that morning and the comment above
   it claimed it was "matched to the widget's width" - it was not. Measured at
   1440 after that pass, the three panels were 400 (chat) / 560 (voice) / 560
   (email), so two of the three still disagreed with the one he can compare them
   against by clicking a tab.

   400 IS NOT A TASTE NUMBER, it is the only one available: the chat panel is
   the real widget and `.w-shell` is `max-width: 400px` because the deployed
   widget is 400x743 (widget.css, citing src/routes/widget-panel.tsx). Matching
   THEM to it is the only direction that keeps the page showing the real thing.
   Measured after: 400 / 400 / 400. */
.e-chan-demo {
  width: 100%;
  max-width: min(400px, 100%);
  /* Not `stretch`: that is what made the card grow into the reserve above
     instead of ending where its content ends. The stage's own
     `align-items: flex-start` now applies. */
  display: flex;
  flex-direction: column;
  text-align: left;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 20px;
  overflow: hidden;
  box-shadow:
    0 2px 6px rgba(18, 19, 26, 0.05),
    0 22px 60px rgba(18, 19, 26, 0.12);
}

.e-chan-demo-top {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line-2);
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent);
}

.e-mail-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--warm);
}

.e-chan-demo-body {
  flex: 1 1 auto;
  padding: 20px;
}

.e-vwave {
  padding: 6px 0 16px;
}

.e-vwave .e-wave {
  width: 100%;
  height: 46px;
  gap: 4px;
}

.e-vwave .e-wave i {
  flex: 1 1 auto;
  width: auto;
  background: linear-gradient(180deg, var(--accent), #7c5cff);
}

.e-vline {
  display: grid;
  grid-template-columns: 78px 1fr;
  gap: 12px;
  padding: 9px 0;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--ink);
  border-top: 1px solid var(--line-2);
}

.e-vwho {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-top: 4px;
}

.e-vline.ai .e-vwho {
  color: var(--accent);
}

.e-vdone {
  margin-top: 14px;
  padding-top: 13px;
  border-top: 1px solid var(--line-2);
  font-size: 13.5px;
  color: var(--good);
  display: flex;
  align-items: center;
  gap: 8px;
}

/* 🔴 THE ORIGINAL EMAIL, ABOVE THE DRAFT, 2026-08-27. See the markup note in
   `EmailShowcase`. Tinted rather than ruled, because the two halves of this
   card are "what they sent" and "what Dante wrote back" and a rule would have
   read as one more field of the same form. Padding is 12/14 against the body's
   own 20, so the inset sits inside the body's gutter instead of fighting it. */
.e-mail-in {
  margin: 0 0 14px;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--paper-2);
}

.e-mail-in-tag {
  display: block;
  margin-bottom: 5px;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.e-mail-in-q {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-2);
}

.e-mail-meta {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding-bottom: 13px;
  border-bottom: 1px solid var(--line-2);
  font-size: 13.5px;
  color: var(--ink-2);
}

.e-mail-meta b {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-right: 8px;
}

.e-mail-body {
  margin: 14px 0 0;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--ink);
}

.e-mail-body p {
  margin: 0 0 10px;
}

.e-mail-body p:last-child {
  margin-bottom: 0;
}

.e-mail-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 18px;
  padding-top: 15px;
  border-top: 1px solid var(--line-2);
}

.e-mail-send {
  background: linear-gradient(135deg, var(--accent), #4d3ae0);
  color: #fff;
  font-size: 13.5px;
  font-weight: 550;
  padding: 9px 15px;
  border-radius: 9px;
}

.e-mail-edit {
  border: 1px solid var(--line);
  color: var(--ink-2);
  font-size: 13.5px;
  padding: 9px 15px;
  border-radius: 9px;
}

/* 🔴 ITS OWN LINE, ALWAYS, 2026-08-27. `margin-left: auto` put it hard right
   on the buttons' row, and the `max-width: 720px` block below re-declared it as
   a full-width line for narrow screens. The card is 400px at EVERY viewport now
   (see `.e-chan-demo`), so the row always wraps and the auto-margin only ever
   produced a lone right-aligned line under two left-aligned buttons. The narrow
   rule was the correct one, so it is the only one. */
.e-mail-src {
  width: 100%;
  font-size: 12.5px;
  color: var(--ink-3);
}

@media (max-width: 720px) {
  .e-chan-tab {
    flex: 1 1 100%;
  }
  .e-vline {
    grid-template-columns: 1fr;
    gap: 3px;
  }
}

/* ---------- The three-step plan ---------- */
/* The element the story was missing: a customer needs to see the path before
   they will start walking it. Numbered because this genuinely is a sequence. */

.e-plan-steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin: 48px 0 0;
  padding: 0;
  list-style: none;
  text-align: left;
  counter-reset: step;
}

@media (max-width: 820px) {
  .e-plan-steps {
    grid-template-columns: 1fr;
    gap: 14px;
  }
}

.e-plan-steps li {
  position: relative;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 24px;
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.03),
    0 10px 26px rgba(18, 19, 26, 0.05);
}

.e-plan-steps .e-step-n {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--accent), #4d3ae0);
  color: #fff;
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 16px;
}

.e-plan-steps h3 {
  font-size: 17.5px;
  font-weight: 600;
  letter-spacing: -0.012em;
  margin: 0;
}

.e-plan-steps p {
  font-size: 14.8px;
  line-height: 1.58;
  color: var(--ink-2);
  margin: 8px 0 0;
  text-wrap: pretty;
}

/* ---------- Reveal on scroll ---------- */
/* usePageReveal has been writing these classes since it was added, but no rule
   ever defined them, so the whole scroll-arrival effect was inert. This is the
   missing half. Long and soft: short transitions read as flicker. */

/* APPLE'S PACE, AND THESE THREE NUMBERS ARE THE WHOLE OF IT: a 0.72s ease-out,
   26px of travel, and 90ms between neighbours (`REVEAL_STEP`, in the tsx). Long
   enough to read as a settle rather than a snap, short enough that a fast
   scroller is never waiting for the page to catch up, and no overshoot anywhere
   - a bounce is the difference between Apple's pace and a template's. */
.e .will-reveal {
  --rt: 0.72s;
  opacity: 0;
  transform: translateY(26px);
  transition:
    opacity var(--rt) cubic-bezier(0.16, 1, 0.3, 1),
    transform var(--rt) cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: var(--rd, 0ms);
  will-change: opacity, transform;
}

.e .will-reveal.is-in {
  opacity: 1;
  transform: none;
}

/* Scrolled PAST faster than the observer: the element is already inside the
   viewport when its callback runs, so it paints where it stands instead of
   performing an arrival nobody is early enough to watch. Applied by
   usePageReveal alongside `.is-in` (team-qa #18); `--rd` is zeroed there so
   the stagger cannot hold a visible element blank either. */
.e .will-reveal.e-reveal-now {
  transition: none;
}

/* 🔴 HALF SPEED, ON THE LOGO AND INTEGRATION ROWS ONLY. Jem: "the animation of
   these icons, coming at half the speed." The other half of the halving is the
   gap between neighbours, which is doubled in `usePageReveal` - see
   `ICON_ROW_SELECTOR` there for which rows carry this and why. */
.e .will-reveal.e-slow-reveal {
  --rt: 1.44s;
}

/* Logos fade rather than travel: several marks sliding at once reads as noise. */
.e .e-logos-row img.will-reveal,
.e .e-logos-row .e-mark.will-reveal {
  transform: translateY(8px) scale(0.985);
}

.e .e-logos-row img.will-reveal.is-in,
.e .e-logos-row .e-mark.will-reveal.is-in {
  transform: none;
}

/* ---------- Contrast, measured ---------- */
/* --ink-3 was #8d867c: 3.49:1 on paper against a 4.5:1 requirement, and worse
   over the warm wash. Darkened to clear AA on both grounds. */
.e {
  --ink-3: #6a645c;
}

/* ---------- Layout defects found by QA ---------- */

/* The sticky form could not shrink below its 415px min-content width, so its
   CTA ran off the right edge of every phone. */
.e-sticky-form {
  min-width: 0;
}

/* `.e-hero { padding: 64px 0 24px }` is a shorthand, so it was resetting the
   left/right gutter that `.e-wrap` sets on the same element. Below ~1120px the
   hero had no horizontal padding at all. */
.e-hero {
  padding-inline: 24px;
}

/* The product shot's grid children kept min-width:auto and overflowed their own
   card, silently cut by overflow:hidden. */
.e-shot-body > * {
  min-width: 0;
}

.e-row-t {
  min-width: 0;
}

/* This used to force the shot's sidebar to `display: none` below 720px (the
   earlier attempt lost the cascade to the base rule, so this one restated it).
   Both are gone: the sidebar is the cycler's only control, and removing it on
   phones left nothing to press. The small-screen section at the end of this
   file turns it into a horizontal tab rail instead. */

/* Reduced-motion leaks the earlier blocks missed. */
@media (prefers-reduced-motion: reduce) {
  .e-call-live,
  .e-sticky-pulse,
  .e-pile-alarm {
    animation: none;
  }

  .e-shot-main,
  .e-chan-stage {
    animation: none;
  }

  .e .will-reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ---------- Scoped overrides ---------- */
/* Declared last on purpose: these refine .e-type, .e-call and .e-wave, so
   they must come AFTER those base rules or the cascade reads as descending
   specificity and the override is the one that loses. */

.e-tile-art > .e-type,
.e-tile-art > .e-call {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.e-tile-art > .e-call {
  justify-content: flex-start;
}

/* The body takes the slack in the card, so the sphere sits on the tile's own
   optical centre rather than jammed under the header. `justify-content` is the
   line that changed: this rule used to centre a full-width bar strip on the
   cross axis only, and a strip needs no main-axis centring because it fills the
   row. A sphere is 88px in a 234px body, so without it the object sat hard
   against the left edge - which typechecks, passes every test, and is only
   visible in a screenshot.

   `.e-tile-art > .e-call .e-wave` stood underneath here, stretching the old bar
   strip to the same slack. */
.e-tile-art > .e-call .e-call-body {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 104px;
}

/* ---------- Channel signatures ---------- */

/* The sticky field wraps the form so an error can sit beneath it without
   stretching the bar's flex row. */
.e-sticky-field {
  flex: 0 1 520px;
  min-width: 0;
  position: relative;
}

.e-sticky-field .e-sticky-form {
  flex: 1 1 auto;
  width: 100%;
}

/* Absolutely positioned so showing it cannot change the bar's height and
   shove the whole page down.

   🔴 IT THEREFORE HANGS OUTSIDE THE BAR'S GLASS, AND SO IT CARRIES ITS OWN.
   Without a background this was pale orange text laid straight over whatever
   the page was showing at that scroll position: at 390 it landed on the "7
   missed in a week" block and was genuinely unreadable, which turns a message
   that names the fix into no message at all. Walked 2026-08-12 at 390 and
   1440. The panel matches the bar so it reads as attached to it. */
.e-sticky-error {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 8px);
  margin: 0;
  padding: 8px 12px;
  border-radius: 12px;
  font-size: 13px;
  line-height: 1.4;
  /* The system's error voice (`.e-url-error` is `--warm` on paper), on its
     own card because this hangs outside the bar over arbitrary page content.
     The dark glass went with the bar's. */
  color: var(--warm);
  background: var(--warm-soft);
  border: 1px solid rgba(210, 66, 21, 0.28);
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.06),
    0 8px 24px -8px rgba(18, 19, 26, 0.18);
}

@media (max-width: 900px) {
  .e-sticky-field {
    flex: 1 1 auto;
  }
}

/* =========================================================================
   SMALL SCREENS: phone and tablet
   =========================================================================
   Jem reviews this page on a phone, so mobile is the reference surface and
   not the thing desktop gets cut down into. Everything below is a real
   small-screen layout rather than a wide one squeezed: nothing is hidden to
   make it fit, and where something genuinely could not fit at its desktop
   shape it has been rebuilt for the width instead.

   Declared last on purpose. Several of the rules here override a base rule
   at equal specificity, which only works from below.

   The four widths this was measured at: 390 (iPhone), 768 (iPad portrait),
   1024 (iPad landscape), 1440 (desktop reference, unchanged).
   ========================================================================= */

/* ---------- 1. The sticky bar keeps its copy ---------- */
/* The highest-value copy on the page: it is what tells someone that typing
   their website in is safe. It survives at every width. From 900px down the
   bar stops being one row and becomes two, so the copy sits above the field
   at full size rather than competing with it for horizontal space. */

/* 641-900px: still one row, but the copy is allowed to wrap instead of being
   the reason the row will not fit. `nowrap` is what forced the bar to be as
   wide as the whole sentence, and hiding the sentence was the workaround. An
   iPad keeps the compact bar this way rather than losing 50px of screen to a
   stack it does not need.

   🔴 EVERY PADDING IN THESE STICKY BLOCKS IS `.e-sticky .e-sticky-in`, NOT
   `.e-sticky-in` (Jem, launch-night round 2, 2026-09-02: "padding is wrong,
   it needs to be perfect everywhere"). The card is also `.e-wrap`, and the
   767px `.e-wrap { padding: 0 18px }` rule sits LATER in this file than this
   whole section, so at equal specificity its shorthand zeroed the card's
   vertical padding across the entire 0-767 range: measured at 390 before the
   fix, the title's glyphs sat 1px from the card's top edge and the field 1px
   from its bottom. This is the same shorthand shadow the `.e-hero` comment
   next to that rule documents. Two classes make the padding immune to where
   the mobile passes sit in the file.

   Sides are 18px to match the desktop card, so the row layout carries one
   inset at every width; vertical stays 12px, which measures symmetric
   (glyph top inset = sub bottom inset) around the centered row. */
@media (max-width: 900px) {
  .e-sticky .e-sticky-in {
    gap: 16px;
    padding: 12px 18px;
  }

  .e-sticky-t-main,
  .e-sticky-t-sub {
    white-space: normal;
  }

  .e-sticky-t-main {
    font-size: 15px;
    line-height: 1.25;
  }

  .e-sticky-t-sub {
    font-size: 12.5px;
    line-height: 1.3;
    margin-top: 2px;
  }
}

/* 640px and under: no row can hold copy and a field at a readable size, so the
   bar becomes two rows. Copy, then field, then button, straight down.
   The stacked card gets ONE inset, 14px on all four sides, so the copy and
   the field's white edge share the same left inset and the space above the
   title equals the space under the field. 12px between the sub-line and the
   field keeps the copy attached to the control it explains. */
@media (max-width: 640px) {
  .e-sticky .e-sticky-in {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    padding: 14px;
  }

  .e-sticky-t {
    justify-content: flex-start;
    gap: 11px;
  }

  .e-sticky-t-main {
    font-size: 15.5px;
  }

  .e-sticky-t-sub {
    font-size: 13px;
  }

  .e-sticky-field,
  .e-sticky-field .e-sticky-form {
    flex: 1 1 auto;
    width: 100%;
  }
}

@media (max-width: 560px) {
  /* Tighter frame gutters buy the card back ~8px of field width. The card's
     own 14px inset from the 640 block stays: the frame is what gives, not
     the breathing room inside the dark bar. */
  .e-sticky {
    padding: 10px 12px 0;
  }

  .e-sticky-t-main {
    font-size: 15px;
  }

  .e-sticky-t-sub {
    font-size: 12.5px;
  }
}

/* The bar's own CTA was 42px tall, under the 44px minimum for a finger.
   Scoped to touch: unscoped it also grew the desktop bar from 80px to 84px,
   and desktop is the reference here, not the thing being fixed. */
@media (max-width: 900px), (hover: none) {
  .e-sticky-form .e-btn,
  .e-sticky-form .e-url-input {
    min-height: 46px;
  }
}

@media (max-width: 560px) {
  .e-sticky-form .e-btn {
    padding: 9px 16px;
    font-size: 14.5px;
  }
}

/* 360px and under (iPhone SE and the like). The longest placeholder the hero
   types is "yourrestaurant.com", which needs 142px; at 320px the field was
   26px short of that and clipped it. These four trims give the field 30px
   back, which is enough for the worst case rather than the average one. */
@media (max-width: 360px) {
  .e-sticky {
    padding: 8px 8px 0;
  }

  /* Still one uniform inset, two steps down: the field width is what 320px
     is short of, not air. 12px clears the 142px placeholder with margin. */
  .e-sticky .e-sticky-in {
    padding: 12px;
  }

  .e-sticky-form {
    padding: 4px;
    gap: 5px;
  }

  .e-sticky-form .e-btn {
    padding: 9px 12px;
  }

  .e-sticky-form .e-url-input {
    padding-inline: 11px;
  }
}

/* ---------- 2. The brain diagram, stacked ---------- */
/* The wide SVG is 940 units across. At 390px it renders at 0.36 scale, which
   puts the 13px labels on screen at 4.7px. Below 900px it is replaced by the
   vertical layout rather than shrunk further: feeds, then the brain, then the
   agents, every label at reading size. */

.e-dia-stack {
  display: none;
}

@media (max-width: 900px) {
  .e-dia-svg {
    display: none;
  }

  .e-dia-stack {
    display: block;
    /* Wide enough to look deliberate on an iPad, and it simply becomes the
       full column on a phone. */
    max-width: 480px;
    margin: 0 auto;
    text-align: left;
  }
}

.e-dia-stack-head {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 12px;
  text-align: center;
}

.e-dia-stack-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.e-dia-stack-list li {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  min-height: 48px;
  padding: 11px 14px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 12px;
  font-size: 15px;
  line-height: 1.35;
  color: var(--ink-2);
}

.e-dia-stack-list.out li {
  border-color: rgba(43, 92, 230, 0.3);
  align-items: flex-start;
}

.e-dia-stack-emo {
  font-size: 18px;
  line-height: 1.2;
  flex: 0 0 auto;
}

/* A brand mark rather than an emoji (Notion, Google Drive). Boxed to the same
   width an 18px emoji occupies so every label in the column keeps one left
   edge, and centred in it because the two marks are not the same shape. */
.e-dia-stack-emo.logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 21px;
  height: 21px;
}

.e-dia-stack-emo.logo svg {
  display: block;
}

.e-dia-stack-t {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.e-dia-stack-t b {
  font-size: 15.5px;
  font-weight: 600;
  color: var(--ink);
}

.e-dia-stack-t em {
  font-style: normal;
  font-size: 13.5px;
  color: var(--ink-3);
  margin-top: 1px;
}

/* The connector. Same idea as the SVG's animated wires: something travels
   from what you put in, to the brain, to what answers. */
.e-dia-stack-pipe {
  position: relative;
  width: 2px;
  height: 40px;
  margin: 14px auto;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--line), var(--accent));
}

.e-dia-stack-pipe.out {
  background: linear-gradient(180deg, var(--accent), var(--accent-2));
}

.e-dia-stack-pipe span {
  position: absolute;
  left: -3px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--accent);
  animation: e-dia-drop 2.4s ease-in-out infinite;
}

@keyframes e-dia-drop {
  0% {
    top: -6px;
    opacity: 0;
  }
  18%,
  78% {
    opacity: 1;
  }
  100% {
    top: 38px;
    opacity: 0;
  }
}

.e-dia-stack-core {
  width: 104px;
  height: 104px;
  margin: 0 auto;
  border-radius: 999px;
  display: grid;
  place-items: center;
  gap: 3px;
  background: linear-gradient(140deg, var(--accent) 0%, #4d3ae0 100%);
  color: #fff;
  box-shadow: 0 10px 30px rgba(43, 92, 230, 0.34);
}

.e-dia-stack-core-emo {
  font-size: 30px;
  line-height: 1;
}

.e-dia-stack-core-label {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  opacity: 0.95;
}

@media (prefers-reduced-motion: reduce) {
  .e-dia-stack-pipe span {
    animation: none;
    top: 16px;
  }
}

/* ---------- 3. Fixed furniture must not sit on the page's own calls to action ---------- */
/* Two fixed elements are painted over the end of this document: the chat
   launcher (ours) and the cookie consent banner (global, and not a file this
   page owns). Measured on a 390x844 phone, the banner runs 72px tall anchored
   12px up, and the launcher sits inside that band: `elementFromPoint` at the
   launcher's centre returned the banner, so the button could not be pressed at
   all. The clearances below are measured against that band, not guessed.
   `:has()` means the space is only reserved while the banner is actually on
   screen, and is released the moment consent is given. */

.e-footer {
  padding-bottom: 96px;
}

body:has([data-cookie-consent]) .e-footer {
  padding-bottom: 184px;
}

/* The launcher's half of this lives beside its own positioning in widget.css. */

@media (max-width: 767px) {
  .e-footer {
    padding-bottom: 88px;
  }

  body:has([data-cookie-consent]) .e-footer {
    padding-bottom: 188px;
  }
}

/* ---------- 4. Long body copy reads left-aligned on a narrow column ---------- */
/* Headings, kickers and the hero lede stay centred: they are short, balanced
   display lines and centring is doing work there. Multi-line body copy is a
   different job - centred, it went ragged on both edges and read as a column
   of loose lines. The block stays centred; only the text inside it changes. */

@media (max-width: 767px) {
  .e-center .e-body,
  .e-dia-more-sub,
  .e-plan-steps p,
  .e-tile-p,
  .e-feat-p {
    text-align: left;
  }
}

/* ---------- 5. Body copy never below 15px on a phone ---------- */
/* Labels, timestamps and mono kickers are excluded on purpose: they are not
   body copy and shrinking them is what keeps the surrounding copy dominant. */

@media (max-width: 767px) {
  .e-tile-p,
  .e-feat-p,
  .e-plan-steps p {
    font-size: 15.5px;
  }

  .e-plan-l li,
  .e-triggers li,
  .e-mail-body,
  .e-vline,
  .e-card-row {
    font-size: 15.5px;
  }

  .e-url-note,
  .e-url-safe,
  .e-dia-more-sub,
  .e-dia-more-h,
  .e-hero-proof,
  .e-foot-brand p,
  .e-plan-line,
  .e-plan-more,
  .e-plan-all-s,
  .e-plan-all-l li {
    font-size: 15px;
  }

  /* The base rule sets this one with `!important`, so it has to be matched. */
  .e-foot-tp {
    font-size: 15px !important;
  }

  .e-call-said,
  .e-mail-meta,
  .e-mail-in-q,
  .e-vdone {
    font-size: 14px;
  }

  .e-sub {
    font-size: 16.5px;
  }
}

/* ---------- 6. Tap targets ---------- */
/* Keyed on `hover: none` as well as width: an iPad in landscape is 1024px wide
   and is still a thumb, so a width-only rule would have left the whole tablet
   range on 36px footer links. A mouse-driven desktop matches neither arm and
   is untouched. */

@media (max-width: 900px), (hover: none) {
  .e-foot-cols a {
    min-height: 44px;
  }

  .e-navitem {
    min-height: 44px;
  }

  .e-chan-tab {
    min-height: 60px;
  }
}

/* ---------- 7. The product shot's tab rail ---------- */
/* Below 720px the sidebar becomes a horizontal rail above the panel rather
   than disappearing. It scrolls inside itself, so the four tabs stay reachable
   without the page ever moving sideways. */

@media (max-width: 720px) {
  .e-shot-side {
    flex-direction: row;
    align-items: center;
    gap: 6px;
    border-right: 0;
    border-bottom: 1px solid var(--line-2);
    padding: 10px 12px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* The four tabs are wider than a phone, so the last one starts off the end
       of the rail. Softening the right edge is what says "there is more this
       way": reachable but with nothing to suggest it is the same as missing.
       A plain gradient, deliberately: a scroll-driven version that retracts at
       the end depends on `animation-timeline`, and a 0s animation is what runs
       where that is unsupported. */
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 30px), transparent 100%);
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 30px), transparent 100%);
  }

  .e-shot-side::-webkit-scrollbar {
    display: none;
  }

  .e-navitem {
    width: auto;
    flex: 0 0 auto;
    white-space: nowrap;
  }

  /* "Settings" is scenery on desktop where there is room for it. On a phone
     rail it would push a real tab out of reach for nothing. */
  .e-navitem.quiet {
    display: none;
  }

  .e-shot-main {
    padding: 18px 16px 20px;
  }
}

@media (max-width: 560px) {
  /* The panels have different row counts. Stacked stats make the dashboard
     panel the tallest, so the floor is set from that one: without it the whole
     shot resizes every time the tab advances, which is the jump this height
     exists to stop in the first place. */
  .e-shot-main {
    min-height: 404px;
  }

  .e-stat {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 11px 13px;
  }

  .e-stat-l {
    margin-top: 0;
    font-size: 13.5px;
  }
}

/* ---------- 8. Section sweep ---------- */

@media (max-width: 880px) {
  /* Lead with the heading, not the illustration. On one column the handover
     art came first and the section opened on a diagram with no title. */
  .e-handover-art {
    order: 2;
  }
}

@media (max-width: 767px) {
  .e-wrap {
    padding: 0 18px;
  }

  .e-hero {
    /* A token, not a literal, so the fold's `calc(100svh - ...)` sees the same
       number the padding does. The 40 is overridden to 18 by the section-A
       block further down, exactly as the two literals did before it.

       🔴 THE LONGHAND IS NOT OPTIONAL. `.e-hero` is also `.e-wrap`, and the
       `.e-wrap { padding: 0 18px }` three rules above sets padding-top to ZERO
       at this width - it is a shorthand, and it sits later in the file than the
       hero's own `padding:` rule, so it wins. The literal that used to be here
       was the thing quietly putting the top padding back. Replacing it with
       only a custom property left nothing to override `.e-wrap`, and the hero
       lost 18px of top padding while the fold went on subtracting it. Measured,
       not reasoned: hero padding-top read 0px at 390 with the token reading
       18px. */
    --e-hero-top: 40px;
    padding-top: var(--e-hero-top);
    padding-inline: 18px;
  }

  .e-section {
    padding: 64px 0;
  }

  /* The bento and feature tiles carry their own padding; at 18px gutters the
     inner text column was getting tight. */
  .e-tile,
  .e-feat,
  .e-plan-steps li {
    padding: 20px 18px;
  }
}

@media (max-width: 560px) {
  /* One column, so the reserved lines that bottom-align four cards across a
     row are just dead space. */
  .e-plan-line,
  .e-plan-more {
    min-height: 0;
  }

  /* "Most popular" hangs 11px above its card. In one column the 12px row gap
     left it almost touching the card above. */
  .e-price {
    gap: 22px;
  }

  .e-plan {
    padding: 22px 18px;
  }

  .e-logos-row {
    gap: 22px;
  }
}

/* ---------- 9. Anything wide gets its own scroll container ---------- */
/* The body must never move sideways. `.e` carries `overflow-x: clip` for the
   hero splash bleed, which would silently cut a genuinely-too-wide child
   instead of letting anyone see it, so wide content is given somewhere of its
   own to scroll. */

/* `.e-chan-tabs` and `.e-chan-demo` used to be in these two groups and were
   removed on 2026-08-27: both wanted a real cap of their own, and a later
   `max-width: 100%` at the same specificity silently overrode it. Each now
   carries `max-width: min(<cap>, 100%)` at its own rule, which is this guard's
   promise plus the cap, in one declaration that nothing downstream undoes. */
.e-leadcap-chips {
  max-width: 100%;
}

.e-shot,
.e-card,
.e-leadcap,
.e-ho-actor {
  max-width: 100%;
}

/* Every grid and flex child that holds text: without this the content sets the
   track width and the whole row overflows the phone. */
.e-flow-asks > *,
.e-flow-replies > *,
.e-chan > *,
.e-card-row > *,
.e-leadcap-top > *,
.e-leadcap-out > *,
.e-ho-actor > *,
.e-dia-stack-list > li > *,
.e-mail-actions > *,
.e-pile-card > * {
  min-width: 0;
}

/* ==========================================================================
   MOBILE-FIRST PASS, 2026-08-10
   Designed at 390px and let to grow, not shrunk down from the desktop.
   ========================================================================== */

/* ---------- A. The first screen fits on a phone ----------
 *
 * THE BUG. The cookie consent banner is fixed to the bottom of the viewport,
 * is roughly 72px tall and sits 12px up, so it owns the bottom ~84px of every
 * phone screen. Measured on an iPhone SE at 375x667 before this pass:
 * `elementFromPoint` at seven points across the hero's URL field AND its
 * submit button returned the consent banner, not the control. The primary
 * action of the whole funnel could not be pressed on the most common small
 * phone in circulation, and the reassurance line under it was next.
 *
 * THE FIX IS HEIGHT, NOT Z-INDEX. Raising the hero above the banner would
 * only have moved the collision to whatever the banner landed on next, and
 * the banner is a global component this page does not own. So the hero was
 * made to fit instead: the lede paragraph is gone (it restated the headline),
 * and every remaining gap above the field is tightened on a phone. The whole
 * of the hero down to and including "Free forever. No card needed." now
 * finishes above the banner's band on every viewport from 375x667 up.
 *
 * Verified by hit test rather than by eye, at eight widths, both before and
 * after. The test lives in landing-e.test.tsx alongside the handoff pin.
 */

@media (max-width: 767px) {
  /* Was `.e-nav { padding: 10px 0 }` and `.e-hero { padding-top: 18px }`. Both
     are tokens now, so the fold's arithmetic follows them instead of being told
     the desktop numbers on a phone. Same pixels, one source. */
  .e {
    --e-nav-h: 64px;
  }

  .e-hero {
    --e-hero-top: 18px;
    padding-bottom: 16px;
  }

  /* The mechanism row: three channels reading from one brain. Tighter chips
     so the sequence still fits two lines rather than three. */
  .e-mech {
    gap: 6px;
    margin-top: 18px;
    font-size: 14px;
  }

  .e-mech-brain,
  .e-mech-ch {
    padding: 7px 12px;
    gap: 6px;
  }

  .e-url {
    margin-top: 20px;
  }

  .e-url-note {
    margin-top: 12px;
  }

  .e-hero-proof {
    margin-top: 14px;
  }
}

/* The narrowest phones still in circulation. The headline is the only thing
   with enough mass left to give back, and one step down keeps it three lines
   instead of four. */
@media (max-width: 380px) {
  .e-h1 {
    font-size: 40px;
  }

  .e-mech {
    font-size: 13.5px;
  }

  /* 🔴 THE ONE CHIP THAT IS WIDER THAN THE PHONE.
     `.e-mech-out` carries the longest string in the row ("Answers your
     customers, day and night") and `white-space: nowrap`, so it is a single
     unbreakable flex item ~333px wide. Making the ROW wrap cannot help: flex
     wraps between items, never inside one, so at 320px the chip still ran off
     the edge and `.e`'s `overflow-x: clip` cut the last ~31px off clean.

     Below 380 the nowrap is what has to give. Two lines inside the pill costs
     nothing (it is a rounded chip, not a tab) and the sentence arrives whole,
     which is the entire point of it: it is the row's closing beat and a
     half-eaten outcome is worse than a wrapped one. Above 380 the chip fits on
     one line and this rule does not apply. */
  .e-mech-out {
    white-space: normal;
    max-width: 100%;
    text-align: left;
  }
}

/* ---------- B. What survives gets bigger ----------
 * A third of the words came out. The reward for the ones that stayed is size:
 * the section headings, the step numbers, the prices and the pile-up counter
 * all carry more weight on a phone than they did, because there is now room
 * for them to.
 */

@media (max-width: 767px) {
  .e-h2 {
    font-size: clamp(30px, 8.2vw, 40px);
    line-height: 1.03;
  }

  .e-tile-h,
  .e-feat-h {
    font-size: 19px;
    line-height: 1.22;
  }

  .e-plan-steps h3 {
    font-size: 19px;
  }

  /* Matches the base rule's specificity on purpose: `.e-plan-steps .e-step-n`
     is (0,2,0), so a bare `.e-step-n` here would lose and the number would
     silently stay at 14px. */
  .e-plan-steps .e-step-n {
    width: 38px;
    height: 38px;
    font-size: 16px;
  }

  .e-plan-p {
    font-size: 40px;
  }

  .e-body {
    font-size: 17px;
    line-height: 1.5;
  }
}

/* ---------- C. Labels a visitor is expected to READ ----------
 * Chrome inside the fake product screenshots stays small on purpose: it is a
 * picture of an interface, and blowing it up would make the picture the loudest
 * thing on the page. These are the ones that are page copy rather than picture,
 * and they were all under 15px on a phone.
 */

@media (max-width: 767px) {
  .e-dia-stack-head,
  .e-dia-more-h {
    font-size: 12.5px;
  }

  .e-dia-stack-list li,
  .e-dia-stack-t b,
  .e-dia-more-list li {
    font-size: 16px;
  }

  .e-dia-stack-t em,
  .e-chan-tab em {
    font-size: 14px;
  }

  .e-dia-stack-core-label {
    font-size: 12px;
  }

  .e-kicker {
    font-size: 12px;
  }

  .e-leadcap-fields dt {
    font-size: 12px;
  }

  .e-leadcap-fields dd {
    font-size: 15.5px;
  }
}

/* ---------- D. The FAQ, as an accordion ----------
 * Six answers open at once ran 1,900px down a phone. The questions are what a
 * visitor scans; the answers open when one of them is actually theirs. Native
 * <details>, so it needs no JavaScript, is keyboard-operable for free, and
 * keeps every answer in the markup for an answer engine to lift whether the
 * item is open or not.
 */

.e-faq {
  max-width: 780px;
  margin: 36px auto 0;
  border-top: 1px solid var(--line);
}

.e-faq-item {
  border-bottom: 1px solid var(--line);
}

.e-faq-q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  min-height: 64px;
  padding: 16px 4px;
  cursor: pointer;
  list-style: none;
  font-family: var(--serif);
  font-size: 20px;
  line-height: 1.25;
  letter-spacing: -0.012em;
  color: var(--ink);
}

.e-faq-q::-webkit-details-marker {
  display: none;
}

.e-faq-q:hover {
  color: var(--accent);
}

.e-faq-q:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 8px;
}

/* A plus that becomes a minus. Two bars, one rotated, so there is no icon
   font and no second asset to fail to load. */
.e-faq-mark {
  position: relative;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
}

.e-faq-mark::before,
.e-faq-mark::after {
  content: "";
  position: absolute;
  top: 9px;
  left: 2px;
  width: 16px;
  height: 2px;
  border-radius: 2px;
  background: var(--ink-3);
  transition: transform 0.22s ease;
}

.e-faq-mark::after {
  transform: rotate(90deg);
}

.e-faq-item[open] .e-faq-mark::after {
  transform: rotate(180deg);
}

.e-faq-item[open] .e-faq-q {
  color: var(--accent);
}

.e-faq-item[open] .e-faq-mark::before,
.e-faq-item[open] .e-faq-mark::after {
  background: var(--accent);
}

.e-faq-a {
  margin: 0;
  padding: 0 4px 22px;
  max-width: 68ch;
  font-size: 16.5px;
  line-height: 1.6;
  color: var(--ink-2);
}

@media (prefers-reduced-motion: reduce) {
  .e-faq-mark::before,
  .e-faq-mark::after {
    transition: none;
  }
}

@media (max-width: 767px) {
  .e-faq {
    margin-top: 28px;
  }

  .e-faq-q {
    font-size: 18.5px;
    padding: 14px 2px;
  }

  .e-faq-a {
    font-size: 16px;
    padding: 0 2px 20px;
  }
}

/* ---------- E. Pricing: the compare link is a real tap target ----------
 * It used to be an `.e-navlink` with its padding zeroed inline, which also
 * zeroed the 44px minimum height that class exists to guarantee.
 */

/* THE CANCELLATION LINE, UNDER THE PRICES. It is NOT `.e-url-note`, which is
   the page's quiet caveat style and carries `white-space: nowrap` above 620px
   - this sentence is 130 characters and would have run off the side of a
   1024px laptop. It is a size up from that caveat and in the body ink rather
   than the third tone, because it is a reason to buy rather than a footnote
   about buying, and it is capped at a reading measure so it breaks into two
   centred lines instead of one very long one. */
/* The one call to action under the four cards. Same button as the hero's, so
   "start" looks the same wherever it is pressed; centred, because it belongs
   to the row and not to any one card. */
.e-price-cta {
  margin: 28px 0 0;
  display: flex;
  justify-content: center;
}

.e-price-cancel {
  margin: 26px auto 0;
  max-width: 56ch;
  font-size: 15.5px;
  line-height: 1.55;
  color: var(--ink-2);
  text-align: center;
}

.e-price-cancel b {
  color: var(--ink);
  font-weight: 650;
}

.e-price-compare {
  margin: 12px 0 0;
  text-align: center;
}

.e-price-compare .e-navlink {
  font-size: 15.5px;
  color: var(--accent);
}

/* ---------- F. Footer: three columns, because there are three ----------
 * Was a fixed four-track grid. One of the four columns was removed (its three
 * links all pointed at the same anchor) and two more links went with it, so a
 * fixed `repeat(4, 1fr)` left an empty track.
 */

.e-foot-cols {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 640px) {
  .e-foot-cols {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- G. The phone no longer needs a reordered hero ----------
 *
 * 🔴 THIS SECTION USED TO REORDER THE HERO WITH FLEX `order`, AND IT IS GONE
 * ON PURPOSE, NOT BY ACCIDENT.
 *
 * The old desktop hero ran headline, mechanism, field. A phone has no room for
 * a mechanism row above the ask, so below 767px the hero became a flex column
 * and every child was numbered by hand - headline 0, field 1, lede 2, free
 * panel 3, mechanism 5, everything else 6 - to pull the field up to second.
 * That worked, and it cost a rule that is easy to break: visual order and tab
 * order only agreed because the mechanism row happened to contain no
 * focusable elements, and the catch-all had already been wrong once (it was 3,
 * which silently stranded the mechanism row about 2,000px below the headline
 * it explains).
 *
 * BOTH OF THE NEW HERO STRUCTURES PUT THE FIELD WHERE THEY PUT IT AT EVERY
 * WIDTH. Version A (hero 31) is headline, diagram, lede, field; version B
 * (hero 32) is headline, lede, field, diagram. Neither wants a different
 * sequence on a phone, because the fold in section N is what buys the space
 * the reorder used to buy. So the DOM order IS the reading order at 1440, 768
 * and 390, and there is nothing left for `order` to fix.
 *
 * It also had to go rather than be left behind: the fold wrapper `.e-fold` is
 * now the hero's first child, so `.e-hero > * { order: 6 }` with `.e-free {
 * order: 3 }` would have printed the free panel ABOVE the headline. A dead
 * rule in a stylesheet is not inert.
 *
 * What the phone still gets is in section N, with the rest of the fold.
 */

/* ---------- H. The narrowest phones, where the banner is tallest ----------
 * The consent banner is a single row at 375px and three rows at 320px, so the
 * screen it leaves is 100px smaller exactly where the screen is smallest. The
 * headline is the only element with enough mass left to give any back.
 */

@media (max-width: 380px) {
  .e {
    --e-nav-h: 56px;
  }

  .e-hero {
    --e-hero-top: 10px;
  }

  .e-h1 {
    font-size: 36px;
  }

  .e-url {
    margin-top: 18px;
  }
}

/* ---------- I. Nothing a visitor is expected to READ is under 15px ----------
 *
 * Set at the base rather than inside a phone media query, because a 768px
 * tablet is held at the same distance as a phone and was falling between the
 * two: the `max-width: 767px` block missed it by one pixel.
 *
 * The line drawn here, deliberately, is between PAGE COPY and PICTURES OF THE
 * PRODUCT. The fake dashboard, the widget mock, the lead card, the handover
 * diagram and the little typing panels inside the bento tiles are screenshots
 * we happen to have drawn in CSS; their chrome is 10-14px for the same reason
 * a screenshot's chrome is small, and blowing it up would make the picture
 * shout over the copy beside it. Mono uppercase eyebrows (.e-kicker,
 * .e-logos-l, the footer column headings) are letterspaced labels, not
 * sentences, and stay small on purpose.
 *
 * Everything below is a sentence, a price, a plan name or a control.
 */

/* The primary action of the entire funnel was set at 15.5px, and 14.5px in
   the sticky bar. It is now the biggest interface text on the page. */
.e-btn {
  font-size: 16.5px;
}

.e-navlink,
.e-nav-cta,
.e-foot-cols a {
  font-size: 15.5px;
}

.e-url-note {
  font-size: 15px;
}

.e-hero-proof {
  font-size: 15.5px;
}

.e-mech {
  font-size: 15px;
}

.e-sticky-t-sub {
  font-size: 13.5px;
}

/* Plan name and the "most popular" flag: the two words a visitor scans a
   pricing table for were 11px and 9.5px. */
.e-plan-n {
  font-size: 13px;
}

.e-plan-tag {
  font-size: 11px;
}

.e-plan-p span {
  font-size: 15px;
}

.e-chan-tab b {
  font-size: 16px;
}

.e-chan-tab em {
  font-size: 14.5px;
}

.e-ho-ctx span,
.e-leadcap-out-l {
  font-size: 15px;
}

.e-foot-addr,
.e-foot-bottom {
  font-size: 14.5px;
}

/* ---------- J. Visible keyboard focus, in the page's own colours ---------- */
/* Both controls fell back to the browser default outline, which is visible but
   is not the same ring as the field and the button beside them. */

.e-navlink:focus-visible,
.e-nav-cta:focus-visible,
.e-foot-cols a:focus-visible,
.e-chan-tab:focus-visible,
.e-navitem:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- K. The field and its CTA, in the H1's AI gradient ----------

   Jem, walking /v2: "drop shadow, glow, CTA a bit more prominent, maybe a
   different colour, maybe make it the same colour as the AI in the header so
   it's synced, and then run that across wherever this input box and CTA is on
   the website."

   ALL THREE PLACEMENTS, because there are three and they are the same action:
   the hero form, the sticky bar's form and the closing call to action. The
   hero and the closing form are both `.e-url`, so they share every rule here;
   the sticky bar overrides sizes and its own dark ground below.

   THE DEPTH IS REAL, NOT A BORDER. The field sits on a soft cast shadow AND a
   blurred copy of the gradient behind it, so the ramp reads as light coming
   off the control rather than as a second outline. The glow is `::before` at
   `z-index: -1` under an `isolation: isolate` parent, which keeps it behind
   the white field and out of everything else's stacking context.

   THE BUTTON IS RAISED ABOVE THE FIELD, not level with it: its own shadow is
   tighter and darker than the field's, which is what makes one control read as
   sitting on the other. That is the "CTA a bit more prominent" half.

   SCOPED TO THE URL FORMS ON PURPOSE. `.e-btn` on its own is also the leads
   prototype's one button, and that page is not this call to action.

   Contrast: white on `--e-ai-ink` measures 5.18:1 at its weakest point. The
   tap target stays 48px here and 44px in the sticky bar, both over the 44px
   minimum. */

/* THE GLOW IS THREE COLOURED SHADOWS, NOT A BLURRED GRADIENT BEHIND THE ROW.

   The blurred-gradient version was written first and walked at 1440px on
   2026-08-11: the field's interior came out lilac instead of white. The reason
   is worth writing down because it looks like a z-index bug and is not.
   `isolation: isolate` makes `.e-url-row` a stacking context, and inside a
   stacking context the painting order is (1) the element's own background,
   (2) its negative-z-index children. So `::before { z-index: -1 }` paints ON
   TOP of the white field it was meant to sit behind. Dropping `isolation`
   fixes the tint and hands the glow to the hero's stacking context instead,
   where `.e-hero::before` (the colour wash) is waiting to cover it.

   Three shadows do the same job with no stacking context at all: indigo cast
   from the left, violet straight down, rose from the right - the H1's ramp,
   read left to right, as light rather than as a fill. It also survives being
   put on the dark sticky bar, which a blurred light gradient does not. */
.e-url-row {
  position: relative;
  border-radius: 15px;
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.06),
    0 4px 12px rgba(18, 19, 26, 0.05),
    -14px 12px 30px -12px rgba(43, 92, 230, 0.42),
    0 18px 40px -14px rgba(124, 92, 255, 0.42),
    14px 12px 30px -12px rgba(210, 66, 21, 0.3);
  transition:
    box-shadow 0.18s ease,
    border-color 0.18s ease;
}

/* Focus brightens the glow instead of only redrawing the border, so the field
   answers the cursor with the same language it uses at rest. The accent ring
   stays first in the list: it is the visible focus indicator, it is not
   decorative, and a ring drawn under a 30px blur is not a ring. */
.e-url-row:focus-within {
  box-shadow:
    0 0 0 3px var(--accent-soft),
    0 1px 2px rgba(18, 19, 26, 0.06),
    -16px 14px 34px -12px rgba(43, 92, 230, 0.55),
    0 20px 46px -14px rgba(124, 92, 255, 0.55),
    16px 14px 34px -12px rgba(210, 66, 21, 0.4);
}

/* Scoped to the HERO row only. `.e-sticky-form .e-btn` used to share this
   gradient, and it is exactly the "purple-to-orange" button Jem screenshotted
   on 2026-09-01: the sticky bar's CTA is now the FLAT system accent (see the
   sticky section above, and the 2026-08-26 flat-CTA ruling). The hero keeps
   the `--e-ai-ink` treatment it was given by name on 2026-08-11. */
.e-url-row .e-btn {
  background: var(--e-ai-ink);
  color: #fff;
  box-shadow:
    0 1px 2px rgba(43, 92, 230, 0.3),
    0 8px 20px -4px rgba(96, 60, 200, 0.45);
}

.e-url-row .e-btn:hover {
  filter: brightness(1.07);
  box-shadow:
    0 2px 4px rgba(43, 92, 230, 0.34),
    0 12px 28px -4px rgba(96, 60, 200, 0.55);
}

/* The gold CTA's white hairline and the dark-cast shadows that lifted the
   old glass bar's controls stood here. They went with the glass: the bar's
   field and button carry their elevation where they are declared, in the
   sticky section above (since the 2026-09-02 dark-ink restyle that includes
   the field's three-shadow AI glow, stated there in full). */

/* 44px, not 42. The sticky bar's field and button were the only two controls
   in this funnel under the 44px minimum, and they are the copy of the primary
   action that a visitor meets for the whole rest of the page. Two pixels each,
   four on the bar's height. */
.e-sticky-form .e-url-input,
.e-sticky-form .e-btn {
  min-height: 44px;
}

@media (prefers-reduced-motion: reduce) {
  .e-url-row {
    transition: none;
  }
}

/* ---------- L. The nav's two controls ----------

   "Get started free" was a flat near-black pill. Jem: "This CTA is not doing
   anything for me."

   IT IS NOW IN THE SAME FAMILY AS THE FIELD, DELIBERATELY ONE STEP DOWN.
   The hero field is the primary action of the whole page and the nav sits
   directly above it, so a second solid gradient pill would be two primaries
   arguing 60px apart. This one carries the gradient as a tinted ground and a
   gradient-coloured label: unmistakably the same language, visibly the lighter
   weight of it. On hover it fills in, which is the affordance doing the work
   the flat pill never did.

   The label is solid `--accent`, not clipped gradient text. Computed against
   the tint it sits on: the ramp's rose end, #d24215 on #f8e8e1, is 3.91:1, so
   gradient-clipped text would have failed AA across the right-hand third of
   every label. Solid accent measures 4.76:1 at the violet end of the tint and
   4.69:1 at the rose end - the whole control clears 4.5:1. */

.e-nav-cta {
  position: relative;
  background: linear-gradient(
    120deg,
    rgba(43, 92, 230, 0.1),
    rgba(124, 92, 255, 0.1) 52%,
    rgba(210, 66, 21, 0.1)
  );
  color: var(--accent);
  font-weight: 600;
  box-shadow: inset 0 0 0 1px rgba(124, 92, 255, 0.28);
  transition:
    background 0.16s ease,
    color 0.16s ease,
    box-shadow 0.16s ease,
    transform 0.16s ease;
}

.e-nav-cta:hover {
  background: var(--e-ai-ink);
  color: #fff;
  box-shadow:
    inset 0 0 0 1px transparent,
    0 6px 16px -4px rgba(96, 60, 200, 0.5);
  transform: translateY(-1px);
}

/* "Sign in" is a <button> now, not an <a>: it opens the auth dialog over the
   page instead of navigating to /login. It has to keep looking like the link
   it was, so it inherits `.e-navlink` and only unsets the button chrome. */
.e-navlink-btn {
  font: inherit;
  font-size: 15.5px;
  border: 0;
  background: none;
  cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
  .e-nav-cta {
    transition: none;
  }
  .e-nav-cta:hover {
    transform: none;
  }
}

/* ---------- M. The phone's front door: one control, one screen ----------
 *
 * 🔴 AT 390 THIS PAGE HAD NO DESTINATIONS AT ALL, AND THE PRICE WAS 74% OF THE
 * PAGE AWAY. `.e-nav-mid` is `display: none` from 900px down (see the Nav
 * block above), so the four places the desktop row points at existed only for
 * desktop. Measured on this build at innerWidth 390 before this section, on
 * load: the document is 17,261px tall and `#price-h` sits at pageY 12,864.
 * Mobile is most of our traffic, so that was the front door's most expensive
 * gap.
 *
 * WHY ONE CONTROL AND NOT FOUR LINKS IN THE BAR. There is no room. Measured at
 * 390, where `.e-wrap` is 354px wide: brand 85 + gap 16 + "Sign in" 74 + gap 6
 * + "Get started free" 155 = 336 of 354 before anything is added, so even a
 * 44px icon-only control is 32px more than the row has (arithmetic on those
 * measured widths, not a fifth measurement). A second nav row under the bar was
 * the other option and it is worse - section A of this file spends two
 * paragraphs and every gap in the hero winning back vertical space on a phone,
 * and a nav row would spend it again on navigation.
 *
 * So the bar keeps its one loud action and gains one quiet control, and the
 * screen behind that control carries every destination at 33px. "Sign in"
 * moves onto that screen to pay for the space: it is the returning visitor's
 * door, not the acquisition action, it is still one press away, and it still
 * opens the dialog over the page rather than navigating off it.
 *
 * DESKTOP IS UNTOUCHED. The trigger is `display: none` until 900px, which is
 * the same width `.e-nav-mid` disappears at, so the two are never on screen
 * together and `display: none` also takes the trigger out of the tab order and
 * the accessibility tree.
 */

.e-nav-menu {
  display: none;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 12px;
  border: 0;
  border-radius: 999px;
  background: none;
  font: inherit;
  font-size: 15.5px;
  font-weight: 500;
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
}

/* Three lines drawn from one element and its two pseudo-elements, so the glyph
   costs no markup and inherits the label's colour. */
.e-nav-menu-bars {
  position: relative;
  flex: 0 0 auto;
  width: 17px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
}

.e-nav-menu-bars::before,
.e-nav-menu-bars::after {
  content: "";
  position: absolute;
  left: 0;
  width: 17px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
}

.e-nav-menu-bars::before {
  top: -6px;
}

.e-nav-menu-bars::after {
  top: 6px;
}

.e-nav-menu:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* 🔴 THE ROW OVERRIDES ARE SCOPED WITH `:has()`, AND THAT IS NOT DECORATION.
   This file is imported by 40-odd other modules, and `pricing-chrome.tsx`
   renders its own `.e-nav` / `.e-nav-right` / `.e-nav-cta` off these very
   classes - so /pricing, /pricing/compare and /leads would all have taken a
   changed nav gap from a rule written for a control they do not have. Only
   this page's nav contains `.e-nav-menu`, so `:has()` is the exact boundary.
   `:has()` is already load-bearing in this file (`body:has([data-cookie-
   consent])` at the end of the cookie block).
   `.e-nav-menu` and `.e-nav-signin` are new class names nothing else uses, so
   those two need no scoping. */
@media (max-width: 900px) {
  .e-nav-menu {
    display: inline-flex;
  }

  /* On the sheet from here down, not in the bar. */
  .e-nav-signin {
    display: none;
  }

  /* The row is now brand + trigger + CTA, and at 375px it needs every pixel
     the gaps are holding. */
  .e-nav:has(.e-nav-menu) {
    gap: 10px;
  }

  .e-nav:has(.e-nav-menu) .e-nav-right {
    gap: 4px;
  }
}

/* The narrowest phones, where the row runs out. THE NEW CONTROL PAYS FIRST.
 *
 * 🔴 THE ROW DOES NOT OVERFLOW WHEN IT RUNS OUT - THE LOGO SHRINKS. `.e-brand`
 * is a flex item holding an <img>, so pressure on the row is absorbed by the
 * wordmark rather than by the page. Measured at 320 with the desktop paddings
 * forced back on: the logo renders 36px instead of 85 and `documentElement`
 * still reports scrollWidth 320 === clientWidth 320. So the thing these trims
 * protect is the brand, and the way to see the damage is to read the logo's
 * width, not to look for a horizontal scrollbar.
 *
 * Measured on the built page, brand / trigger / CTA, before this change (the
 * row reconstructed in the live document as brand + "Sign in" + CTA) and after:
 *
 *   390   before 85 / -  / 155     after 85 / 79 / 155    logo unchanged
 *   375   before 85 / -  / 155     after 85 / 79 / 147    logo unchanged
 *   360   before 82 / -  / 155     after 84 / 79 / 147    logo +2
 *   320   before 50 / -  / 155     after 51 / 72 / 147    logo +1
 *
 * "Get started free" keeps its full 155px at 390, which is the width this was
 * briefed at, and gives up padding only - never a letter of its label, never a
 * pixel under 44px tall. The word "Menu" stays at every width too: a bare glyph
 * is a guess.
 */
@media (max-width: 390px) {
  .e-nav-menu {
    gap: 7px;
    padding: 0 8px;
    font-size: 15px;
  }
}

@media (max-width: 380px) {
  .e-nav:has(.e-nav-menu) .e-nav-cta {
    padding: 0 14px;
  }
}

/* 320px, where the logo was already being squeezed to 50px before any of this
   and the trigger took it to 44. Seven more pixels out of the trigger's own
   padding hands them back, and then some.
   🔴 The bound is 361, and it took THREE goes to find, which is the lesson.
   Written first as `max-width: 340px` and verified at 320/360/375/390 -- four
   widths sitting either side of the gap, so the samples never touched it. A
   sweep then found the wordmark still squeezing across 344-356 and it was
   moved to 356; a 1px sweep of the whole 320-420 range found the squeeze
   STILL live at 357-361 (worst case 20.09px, and 42 of 81 widths affected at
   340 versus 35 at 361). Each round-number guess landed just short.
   Widths BETWEEN your samples are where a media query fails: sweep the range,
   never sample the round numbers.
   The neighbouring `@media (max-width: 360px)` above targets `.e-sticky`, a
   different selector, so these two bounds do not interact. */
@media (max-width: 361px) {
  .e-nav-menu {
    gap: 6px;
    padding: 0 5px;
  }
}

/* ---------- The sheet ---------- */

.e-menu {
  position: fixed;
  inset: 0;
  /* ABOVE THE STICKY BAR (z 50) AND THE CONSENT BANNER (z 100), and below the
     anon takeover (z 110), which is the one screen on this page entitled to be
     on top of everything. */
  z-index: 105;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* The page's own ground, so this reads as the same site rather than as a
     panel from somewhere else. */
  background-color: var(--paper);
  background-image:
    radial-gradient(70% 48% at 4% 2%, rgba(255, 176, 100, 0.5), transparent 62%),
    radial-gradient(64% 44% at 98% 20%, rgba(43, 92, 230, 0.3), transparent 62%),
    radial-gradient(68% 46% at 100% 78%, rgba(124, 92, 255, 0.28), transparent 62%);
  background-repeat: no-repeat;
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  animation: e-menu-in 0.22s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

@keyframes e-menu-in {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .e-menu {
    animation: none;
  }
}

.e-menu-panel {
  width: 100%;
  max-width: 560px;
  min-height: 100%;
  margin: 0 auto;
  padding: 14px 18px 32px;
  display: flex;
  flex-direction: column;
}

.e-menu-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;
}

.e-menu-kicker {
  margin: 0;
}

.e-menu-close {
  width: 44px;
  height: 44px;
  /* Sits where the trigger was, allowing for the bar's own gutter. */
  margin-right: -10px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--ink);
  cursor: pointer;
}

.e-menu-close svg {
  width: 22px;
  height: 22px;
}

.e-menu-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Takes the whole screen between the eyebrow and the sign-in line and centres
   the four rows in it. Left at the top of the panel the list sat in the first
   third with 400px of nothing under it, which is the "simple and flat" the
   brief warns about; centred, the destinations are the screen. */
.e-menu-links {
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
  justify-content: center;
  margin-top: 12px;
}

/* The page's headline serif, at headline size. This screen has one idea and
   four answers to it, so the four answers are the biggest thing on it. */
.e-menu-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 76px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(30px, 8.6vw, 40px);
  line-height: 1.05;
  letter-spacing: -0.022em;
  color: var(--ink);
  text-decoration: none;
}

.e-menu-link:first-child {
  border-top: 1px solid var(--line);
}

.e-menu-link svg {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  color: var(--ink-3);
}

.e-menu-link:active {
  color: var(--accent);
}

.e-menu-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

/* Last, quiet, and at the bottom of the screen: the returning visitor knows to
   look for it and the new one is not being asked to sign in to read a price. */
.e-menu-signin {
  margin-top: auto;
  padding: 22px 0 0;
  align-self: flex-start;
  min-height: 44px;
  border: 0;
  background: none;
  cursor: pointer;
  font: inherit;
  font-size: 15.5px;
  color: var(--ink-2);
}

.e-menu-signin b {
  color: var(--ink);
  font-weight: 600;
}

.e-menu-signin:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- N. The fold, the field and the wire ----------
 *
 * Hero 35's discipline, applied to the real page and to both structures
 * identically: headline, the four capabilities, the field and its reassurance
 * line inside ONE screen at 1440, at 768 and at 390, with nothing dropped at
 * any of them. Jem: "People have a very short attention span and need to 100%
 * understand how we can help their business WITHIN THREE SECONDS." Three
 * seconds is not enough time to scroll.
 *
 * TWO PROPERTIES ARE LOAD-BEARING AND NEITHER IS COSMETIC.
 *
 *   `100svh`, NOT `100vh`. On iOS Safari `vh` is the tallest the viewport ever
 *   gets, so a fold built on it puts its own button under the browser chrome
 *   on first paint. The button is the one element here that must never be off
 *   screen, so this is the difference between the fold working and the fold
 *   hiding the conversion.
 *
 *   `min-height`, NOT `height`. The screen is a FLOOR. A visitor at 200% text
 *   size gets a taller hero that scrolls rather than a hero that clips its own
 *   field. A layout that only holds while the text is small is not a layout.
 *   It is also why `justify-content: center` is safe here: min-height cannot
 *   cap the box, so the content can never overflow the container it is being
 *   centred in, and nothing can end up behind the nav.
 *
 * The nav and the hero's own top padding are subtracted, from the tokens at
 * the top of this file, because "one screen" has to mean the screen the
 * visitor actually has left.
 */

.e-fold {
  /* ONE RHYTHM, DECLARED ONCE. Jem, 2026-08-18: "add more space between
     trustpilot and header." The fix is not a margin on the H1: five blocks in a
     column, each carrying its own hand-tuned margin, is exactly how they drift
     apart again the next time somebody edits one of them. The column owns the
     spacing with `gap`, every child's block margin is zeroed below, and the two
     numbers that decide the whole fold's density live here.

     `--e-fold-lead` is the extra air under the credibility line, so it reads as
     its own object rather than as the top of the headline block. It is a NAMED
     part of the layout, not a one-off, which is why tightening the fold on a
     short screen can move it in one place. */
  --e-fold-gap: 18px;
  --e-fold-lead: 34px;
  min-height: calc(100svh - var(--e-nav-h) - var(--e-hero-top));
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--e-fold-gap);
  padding-bottom: 10px;
}

/* `margin-block`, not `margin`: the lede and the field are centred with
   `margin-inline: auto` and zeroing that would left-align both. */
.e-fold > * {
  margin-block: 0;
}

.e-fold .e-hero-proof {
  margin-bottom: calc(var(--e-fold-lead) - var(--e-fold-gap));
}

/* Two steps down from the page's own headline scale. The whole argument has to
   share one screen with a 76px field, a four-node diagram and seven channel
   names, and the headline is the only element with that much room to give. It
   is still the largest thing on the page by a wide margin. */
.e-fold .e-h1 {
  font-size: clamp(38px, 5.2vw, 76px);
}

.e-fold .e-lede {
  margin-top: 16px;
  font-size: clamp(16px, 1.2vw, 19px);
  line-height: 1.5;
}

/* ---------- The field, grown ----------
 *
 * Jem: "have that input box REALLY PROMINENT."
 *
 * 76px tall against the 56 it was, which makes it the largest object in the
 * hero after the headline. The gradient button and the resting glow are
 * section K's and are unchanged: they were already right, and two glows
 * arguing would have been the same mistake as two primaries.
 *
 * SIZE IS THE SMALLER HALF OF THE ANSWER AND IT IS SAID HERE ON PURPOSE. Hero
 * 32's argument is that prominence is POSITION: a big field below a diagram is
 * still below a diagram. That is what /v2b is for, and it is why this block is
 * identical on both routes - the size is a constant so that the position is
 * the variable.
 *
 * SCOPED TO THE HERO FORM. The same `.e-url` is the sticky bar's control and
 * the closing call to action, and neither of those is the front door. */
.e-hero-form .e-url {
  /* The gap on `.e-fold` is what separates the field from the lede now. */
  margin-top: 0;
  max-width: 620px;
}

.e-hero-form .e-url-row {
  padding: 7px;
  border-radius: 17px;
}

.e-hero-form .e-url-input {
  min-height: 62px;
  font-size: 17px;
  padding: 0 16px;
}

.e-hero-form .e-url-row .e-btn {
  min-height: 62px;
  padding: 0 26px;
  font-size: 17px;
  border-radius: 12px;
}

/* W3 (Jem, 2026-09-01): more air around "Free forever. No card needed.
   Nothing goes live until you decide." The fold is a min-height floor, so
   the extra rhythm pushes the diagram down rather than clipping anything. */
.e-hero-form .e-url-note {
  margin-top: 20px;
  margin-bottom: 8px;
}

/* ---------- The wire, and where the blue dots went ----------
 *
 * 🔴 HERO 32 RAN FOUR ANIMATED DOTS ALONG THE FAN, DIRECTLY UNDER THE FIELD.
 * Jem: "I'm just wondering if the blue dots on 32 are a little bit too much
 * and distracting and it's taking people from the input box." He is right, and
 * the mechanism is worth writing down rather than just deferring to: four
 * objects in perpetual motion below the field are four competing fixation
 * points, and the field itself was static - so the only moving thing on the
 * screen was the one thing that was not the action.
 *
 * There is ONE dot now and it runs on this segment alone, downward, away from
 * the field and into the brain. That keeps 32's whole argument (the diagram is
 * the consequence of typing) on a quarter of the movement. The fan carries no
 * dots at all: which capability is live is said by one chip taking the accent
 * colour, which is a change of state rather than a fourth thing crossing the
 * screen.
 *
 * REDUCED MOTION IS HANDLED TWICE, IN JS AND IN CSS, ON PURPOSE. The `.still`
 * class comes from `useReducedMotionPref` and the media query below is the
 * belt to its braces: if the hook is ever removed or the class ever fails to
 * land, the dot still stops. It parks partway down rather than vanishing, so
 * the picture still reads as connected. */
.e-wire {
  display: block;
  position: relative;
  width: 1px;
  height: 34px;
  /* No top margin: the fold's gap already sits above the diagram this wire
     opens, and a second gap here would put a hole in the connector. */
  margin: 0 auto;
  background: #ded6cb;
}

.e-wire i {
  position: absolute;
  left: -2.5px;
  top: 0;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0.8;
  animation: e-wire-run 2.2s ease-in infinite;
}

@keyframes e-wire-run {
  0% {
    transform: translateY(-4px);
    opacity: 0;
  }
  18% {
    opacity: 0.8;
  }
  100% {
    transform: translateY(30px);
    opacity: 0;
  }
}

.e-wire.still i {
  animation: none;
  top: 16px;
}

@media (prefers-reduced-motion: reduce) {
  .e-wire i {
    animation: none;
    top: 16px;
  }
}

/* `.e-hero-wire .e-mech { margin-top: 0 }` was here. The fold's `gap` owns
   every vertical distance in the column now, so there is no per-variant margin
   left to cancel: both structures get the same rhythm by construction, which is
   what makes the two tabs comparable. */

/* ---------- The fold on a phone ----------
 * Every number below is bought back from somewhere the fold can afford it, and
 * nothing is dropped: all four capabilities, all seven channel names, the
 * whole lede and the whole reassurance line are on the first screen at 390 as
 * they are at 1440. A product we only admit to on a desktop is a product the
 * phone half of the traffic does not know we have.
 */
@media (max-width: 767px) {
  .e-fold .e-h1 {
    font-size: clamp(30px, 8.1vw, 38px);
  }

  /* The Trustpilot line arrived above the H1 on 2026-08-18 and cost the phone
     fold about 50px it did not have. Everything below is bought back from air
     rather than from content: nothing is dropped, and the field is not shrunk
     past the 44px tap minimum. */
  .e-fold {
    --e-fold-gap: 10px;
    --e-fold-lead: 17px;
    padding-bottom: 2px;
  }

  .e-fold .e-lede {
    font-size: 15.5px;
    line-height: 1.4;
  }

  /* W3: proportionally more air on a phone too, without spending a fold. */
  .e-hero-form .e-url-note {
    margin-top: 13px;
    margin-bottom: 5px;
  }

  /* 🔴 FOUR CHIPS, TWO ROWS, AND THE MARGIN WAS FOUR PIXELS. Measured at 390
     with the desktop padding: "AI email management" is 197px and "AI lead
     capture" 153, which is 358 against a 354px column, so the second row
     wrapped to a third by 4px and the fold went over by exactly that row.
     Tighter padding, a tighter gap and a 15px glyph take the pair to 337 and
     the row back to two. The TEXT is not shrunk - a capability name is
     something a visitor reads, and 14px is where section I of this file puts
     the floor for that. */
  .e-mech-brain,
  .e-mech-ch {
    padding: 6px 10px;
    gap: 5px;
  }

  .e-mech-ico svg {
    width: 15px;
    height: 15px;
  }

  .e-mech-caps {
    gap: 6px;
  }

  /* THE PILL CHROME COMES OFF THE CHANNEL ROW ON A PHONE, and the names do
     not. Seven pills at 22px of horizontal padding each is 154px of nothing,
     which is a whole extra row on a 354px column: measured 3 rows with the
     chrome, 2 without, at the same font size. It reads as a logo strip rather
     than as seven more chips competing with the four above it, which is what
     the long tail should look like anyway. */
  .e-mech-ports {
    margin-top: 8px;
    gap: 7px 12px;
  }

  .e-mech-ports li {
    padding: 0;
    border: 0;
    background: none;
    gap: 6px;
  }

  .e-mech-out {
    margin-top: 8px;
    padding: 7px 12px;
  }

  .e-mech-stem {
    height: 16px;
  }

  .e-wire {
    height: 20px;
  }

  @keyframes e-wire-run {
    0% {
      transform: translateY(-4px);
      opacity: 0;
    }
    18% {
      opacity: 0.8;
    }
    100% {
      transform: translateY(26px);
      opacity: 0;
    }
  }
}

/* The stacked field is the right shape on a phone - a full-width button is a
   full-width target - but two 62px rows plus the reassurance line is more of
   the fold than the control is worth. 54 each keeps it well over the 44px
   minimum and buys back 16px. */
@media (max-width: 540px) {
  .e-hero-form .e-url-input,
  .e-hero-form .e-url-row .e-btn {
    min-height: 52px;
  }
}

/* ---------- The fold on a LAPTOP-HEIGHT viewport ----------
 *
 * 🔴 THE AXIS THAT BROKE THIS TWICE IS HEIGHT, NOT WIDTH.
 *
 * A 1440-wide window is not a tall window. Maximised on a 900px screen a
 * browser leaves about 800 of viewport, and 1440x800 is the single most common
 * desktop shape we see. It fitted before the Trustpilot line went in above the
 * H1 on 2026-08-18 and it did not afterwards: measured 80px over, while
 * 1440x900 still fitted with 15px to spare. A width-only breakpoint cannot see
 * that difference, which is why this block and the two below it are keyed on
 * height alone and sweep from 900 down.
 *
 * Nothing is dropped at any step. The headline gives up scale, the column
 * gives up air, and every capability, every channel name and the whole
 * reassurance line stay on the first screen.
 */
/* 🔴 `min-width: 768px` IS LOAD-BEARING, NOT DECORATION. These height blocks
   sit AFTER the width blocks in this file, so an unguarded `max-height: 900px`
   ALSO matches a 390x844 phone and overwrites the tighter numbers the phone
   block just set - measured: the phone fold went from 13px of slack to 7px OVER
   the moment this block was added unguarded. The two tighter height blocks
   below need no such guard because their values are tighter than the phone's in
   every case, so a phone that matches them is a phone that wanted them. */
@media (min-width: 768px) and (max-height: 900px) {
  .e-fold {
    --e-fold-gap: 12px;
    --e-fold-lead: 24px;
  }

  .e-fold .e-h1 {
    font-size: clamp(34px, 4.6vw, 64px);
  }

  .e-fold .e-lede {
    font-size: clamp(15.5px, 1.15vw, 17.5px);
    line-height: 1.45;
  }

  .e-fan {
    height: 40px;
  }

  .e-wire {
    height: 26px;
  }

  .e-mech-ports {
    margin-top: 10px;
  }

  .e-mech-out {
    margin-top: 10px;
  }
}

/* ---------- The fold on a SHORT viewport ----------
 *
 * The three sizes Jem named are 1440, 768 and 390, and all three of them are
 * tall: 900, 1024, 844. The sizes that break a fold are the short ones - an
 * iPhone SE is 667 tall, and a browser window that is not maximised on a 900px
 * screen leaves about 700. Height is the axis a width-only breakpoint cannot
 * see, so this block is keyed on height and nothing else.
 *
 * Nothing is dropped here either. Every one of the four capabilities, all seven
 * channel names, the whole lede and the whole reassurance line are still on the
 * screen: what gives is the headline's scale and the air between the parts.
 * Where even that is not enough the min-height FLOOR does its job and the hero
 * simply gets taller and scrolls, which is the designed behaviour - a clipped
 * field would not be.
 */
@media (max-height: 780px) {
  .e-fold {
    padding-bottom: 6px;
  }

  .e-fold .e-h1 {
    font-size: clamp(31px, 4.2vw, 52px);
  }

  .e-fold {
    --e-fold-gap: 9px;
    --e-fold-lead: 17px;
  }

  .e-fold .e-lede {
    font-size: clamp(15px, 1.05vw, 17px);
    line-height: 1.45;
  }

  /* W3: same breathing room, scaled for the short-viewport fold. */
  .e-hero-form .e-url-note {
    margin-top: 14px;
    margin-bottom: 5px;
  }

  .e-mech-caps {
    gap: 8px;
  }

  .e-fan {
    height: 38px;
  }

  .e-mech-stem {
    height: 20px;
  }

  .e-mech-ports {
    margin-top: 10px;
  }

  .e-mech-out {
    margin-top: 10px;
  }

  .e-wire {
    height: 26px;
    margin-top: 9px;
  }

  @keyframes e-wire-run {
    0% {
      transform: translateY(-4px);
      opacity: 0;
    }
    18% {
      opacity: 0.8;
    }
    100% {
      transform: translateY(22px);
      opacity: 0;
    }
  }
}

/* Short AND narrow: a 375x667 phone is the tightest real device left, and the
   field's two stacked 54px rows are the biggest single block on it. 48 is still
   four pixels over the 44px tap-target minimum. */
@media (max-height: 780px) and (max-width: 540px) {
  .e-hero-form .e-url-input,
  .e-hero-form .e-url-row .e-btn {
    min-height: 48px;
  }

  .e-fold .e-lede {
    font-size: 15px;
  }

  /* The same chip tightening the narrowest phones get by width, applied here by
     HEIGHT: a 390px phone that is only 667 tall needs it for exactly the same
     reason a 360px phone does, and a width-only rule cannot see that. */
  .e-mech-brain,
  .e-mech-ch {
    padding: 6px 9px;
  }

  .e-mech-caps {
    gap: 6px;
  }

  .e-mech-ports {
    margin-top: 8px;
    gap: 7px 10px;
  }

  .e-mech-out {
    margin-top: 8px;
  }
}

/* Shorter still: a 667-tall phone, or a desktop window at about two thirds of
   a 1080 screen. The headline takes the last step it has, and every remaining
   gap goes to its minimum. Below this the floor takes over and the hero
   scrolls rather than clipping - which is the point of a floor. */
@media (max-height: 700px) {
  .e-fold .e-h1 {
    font-size: clamp(26px, 3vw, 38px);
  }

  .e-fold .e-lede {
    font-size: 15px;
    line-height: 1.4;
  }

  .e-fold {
    --e-fold-gap: 7px;
    --e-fold-lead: 12px;
    padding-bottom: 0;
  }

  .e-mech-ports {
    margin-top: 8px;
  }

  .e-mech-out {
    margin-top: 8px;
  }

  .e-wire {
    height: 18px;
  }

  .e-mech-stem {
    height: 14px;
  }

  .e-fan {
    height: 28px;
  }
}

/* The narrowest phones still in circulation. At 320 and 360 the column is
   324px or less, the four capability chips need three rows rather than two,
   and the outcome chip wraps to two lines - so the diagram is taller here than
   it is at 390 and the fold was clearing by a single pixel. Tighter chips and
   tighter gaps, and nothing removed. */
@media (max-width: 380px) {
  .e-mech-brain,
  .e-mech-ch {
    padding: 6px 9px;
  }

  .e-mech-caps {
    gap: 6px;
  }

  .e-mech-ports {
    margin-top: 8px;
    gap: 7px 10px;
  }

  .e-mech-out {
    margin-top: 8px;
  }
}

/* ---------- O. The proof strip, directly under the hero ----------
 *
 * Jem, 2026-08-18: "maybe this can go directly under the hero, it's good
 * proof." `.e-logos` was the last block inside the hero; it is its own section
 * now, immediately after </header>.
 *
 * The block's own rules are unchanged and deliberately so. `.e-logos` keeps its
 * rule and its top padding, `.e-logos-powered` keeps the hairline that separates
 * the two arguments (who uses it, what it runs on), and `.e-mark` keeps its
 * per-logo sizing - which is tuned optically per `data-mark` rather than to a
 * common height, because the seven POWERED_BY marks have wildly different
 * aspect ratios and ink densities. All three live on the elements, not on the
 * container, so moving the container cannot change any of them.
 *
 * This wrapper therefore adds one thing only: the space under the block, which
 * used to come from the hero's own bottom padding and now has to be its own.
 */
.e-proofstrip {
  padding-bottom: 8px;
}

/* ---------- P. The dev-only signup bypass ----------
 *
 * 🔴 REMOVE THIS BLOCK WITH `DEV_SIGNUP_BYPASS` IN landing-e.tsx, BEFORE
 * LAUNCH. Jem asked for the control on 2026-08-18 to walk the real flow
 * locally without creating an account; it is on the go-live checklist as a
 * thing to delete.
 *
 * It is styled to be impossible to mistake for product: a dashed magenta rule,
 * mono type, and a colour that appears nowhere else on this page. If it ever
 * turns up in a screenshot, the screenshot is wrong and this is how you can
 * tell at a glance. The button only renders under `import.meta.env.DEV`, so
 * these rules are dead weight in a production stylesheet and nothing else.
 */
/* 🔴 QUIETENED 2026-08-27. This was a FULL-WIDTH DASHED MAGENTA BAR sitting
   directly between the hero CTA and the content below it -- after the headline,
   the loudest thing on the front door. It is dev-only and can never ship, but
   Jem walks this page to judge look and feel, and a dev affordance that
   dominates the hero corrupts the only judgement the page exists to receive.

   Now a small muted link, still obviously not-production (mono, uppercase,
   dotted underline) and still one click, but it no longer competes with the
   thing a visitor is meant to look at. Behaviour is untouched -- this is
   presentation only. */
.e-devonly {
  display: block;
  margin: 10px auto 0;
  padding: 2px 4px;
  border: 0;
  background: none;
  color: #a78bab;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  opacity: 0.55;
  cursor: pointer;
}

.e-devonly:hover {
  opacity: 1;
  color: #86198f;
}

.e-devonly:focus-visible {
  outline: 2px solid #c026d3;
  outline-offset: 2px;
}

/* ── THE VOICE ENGINE SPHERE ──────────────────────────────────────────────
   Replaces a flat bar strip over a mail-thread-shaped transcript. Jem, walking
   it: "it doesn't represent an AI voice agent, it looks like an email. Make it
   super technological, like a sphere, animated, tech subtitles."
   Everything below animates transform and opacity only, so it composites on the
   GPU and adds no layout work to a page that already carries a heavy hero. */

/* 🔴 SAME PADDING AS THE EMAIL PANEL, 2026-08-27. Jem: "I'm very pedantic when
   it comes to padding styling consistency." This body carried `30px 24px 26px`
   against the shared `.e-chan-demo-body` 20px, so the two panels of one family
   were inset by three different amounts on four edges. It is the shared 20px
   now and only the flex centring the sphere needs is kept. */
.e-chan-demo-body.voice {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* 22px was tuned against the 132px sphere in a 560px card. Both moved on
     2026-08-27 (88px sphere, 400px card) and the old gap left the three parts
     reading as three separate blocks rather than one call. */
  gap: 18px;
}

/* 🔴 EVERY DIMENSION IS A TOKEN, 2026-08-18, so the sphere can be two sizes
   without becoming two components. The tile in the capability bento carries the
   same object at `sm` (see `VoiceOrb` in landing-e.tsx). The six numbers on
   `.e-orb` are the ones the big sphere always had, written out rather than
   derived, so the 132px original is pixel-identical to what it was and cannot
   drift by a rounding error when the small one is retuned. */
.e-orb {
  --orb-size: 132px;
  --orb-ring: 108px;
  --orb-ring-2: 86px;
  --orb-core: 58px;
  --orb-bar: 9px;
  /* Where the frequency bars are pushed out to. Read by the inline transform on
     every bar, which is what lets one line of JS serve both sizes. */
  --orb-r: -46px;
  position: relative;
  width: var(--orb-size);
  height: var(--orb-size);
  flex: 0 0 auto;
  display: grid;
  place-items: center;
}

/* THE TILE SIZE. Two thirds of the sphere, tuned rather than scaled: a plain
   `transform: scale(.65)` would have taken the 1px orbit hairlines down to
   0.65px, which a browser renders as a grey smudge, and the whole point of the
   rings is that they read as machinery. */
.e-orb.sm {
  --orb-size: 88px;
  --orb-ring: 72px;
  --orb-ring-2: 57px;
  --orb-core: 38px;
  --orb-bar: 6px;
  --orb-r: -31px;
}

/* 🔴 THE SPHERE SHRINKS INSIDE A BENTO TILE, 2026-08-26 (W04). The `max-height`
   ceiling on `.e-tile-art` that squares these cards is 150px, and the voice
   panel wanted ~198: header 28, body 28 of padding around an 88px sphere, and
   a 54px caption. Capping alone CLIPPED THE CAPTION - measured on the running
   page, "CALLER" and the line "Can I move my appointment?" were cut off at the
   bottom edge of the card.

   THE CAPTION IS THE CONTENT AND THE SPHERE IS THE DECORATION, so the sphere
   is what gives way. It is the same question this card asks as the email card
   next to it, and the fix there was to ADD the customer's words; losing them
   here to win a ratio would have made the pair contradict each other.

   58px fits the arithmetic exactly: 150 - 28 header - 16 padding - 48 caption.
   Scoped to `.e-tile-art` on purpose - `.e-orb.sm` is also used by the channels
   surface, which imports this stylesheet and is not height-constrained, so
   editing the shared `.sm` block would have shrunk a sphere on a screen in a
   different directory to fix one here. */
.e-tile-art .e-orb.sm {
  --orb-size: 58px;
  --orb-ring: 48px;
  --orb-ring-2: 38px;
  --orb-core: 25px;
  --orb-bar: 4px;
  --orb-r: -20px;
}

.e-tile-art .e-call-body {
  padding: 8px 12px;
}

.e-orb > * {
  position: absolute;
  border-radius: 50%;
}

/* Presence. Slow, wide, and never fully out, so the object always looks awake. */
.e-orb-glow {
  width: var(--orb-size);
  height: var(--orb-size);
  background: radial-gradient(
    circle,
    rgba(43, 92, 230, 0.34) 0%,
    rgba(124, 92, 255, 0.14) 45%,
    transparent 68%
  );
  animation: e-orb-breathe 3.6s ease-in-out infinite;
}

/* Machinery. Two orbits, counter-rotating, deliberately not concentric in speed
   so the pair never looks like one spinning object. */
.e-orb-ring {
  width: var(--orb-ring);
  height: var(--orb-ring);
  border: 1px solid rgba(43, 92, 230, 0.3);
  border-top-color: rgba(124, 92, 255, 0.85);
  animation: e-orb-spin 4.2s linear infinite;
}

.e-orb-ring.two {
  width: var(--orb-ring-2);
  height: var(--orb-ring-2);
  border-color: rgba(124, 92, 255, 0.22);
  border-bottom-color: rgba(43, 92, 230, 0.75);
  animation: e-orb-spin 6.8s linear infinite reverse;
}

/* The agent itself. */
.e-orb-core {
  width: var(--orb-core);
  height: var(--orb-core);
  background:
    radial-gradient(circle at 34% 30%, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0) 42%),
    linear-gradient(140deg, #2b5ce6 0%, #7c5cff 55%, #d24215 130%);
  box-shadow: 0 6px 22px -6px rgba(43, 92, 230, 0.7);
  animation: e-orb-breathe 3.6s ease-in-out infinite;
}

/* Frequency, RADIAL rather than a strip, so the sound belongs to the sphere. */
.e-orb-bars {
  width: var(--orb-size);
  height: var(--orb-size);
  background: none;
}

.e-orb-bars i {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2px;
  height: var(--orb-bar);
  margin-left: -1px;
  border-radius: 1px;
  transform-origin: 50% 0;
  background: linear-gradient(180deg, rgba(124, 92, 255, 0.95), rgba(43, 92, 230, 0.25));
  animation: e-orb-bar 1.15s ease-in-out infinite;
}

@keyframes e-orb-spin {
  to {
    rotate: 360deg;
  }
}

@keyframes e-orb-breathe {
  0%,
  100% {
    scale: 1;
    opacity: 0.9;
  }
  50% {
    scale: 1.07;
    opacity: 1;
  }
}

@keyframes e-orb-bar {
  0%,
  100% {
    scale: 1 0.4;
    opacity: 0.45;
  }
  50% {
    scale: 1 1.5;
    opacity: 1;
  }
}

/* ── the subtitles ─────────────────────────────────────────────────────── */

.e-vsubs {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: 100%;
  max-width: 46ch;
  text-align: center;
}

.e-vsub {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin: 0;
}

/* The speaker is a tag ABOVE the words, not a column beside them. A label in a
   left-hand column is the thing that made this read as an inbox.

   UNSCOPED FROM `.e-vsub` ON 2026-08-18, because the capability tile's caption
   (`.e-call-said`) now uses the same pair and a rule that only fires inside a
   subtitle line would have left the tag unstyled there - which is the failure
   that looks like nothing at all in a test and like a bug in a screenshot. */
.e-vwho {
  font-family: var(--e-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #8b8578;
}

.e-vsub.ai .e-vwho {
  color: #2b5ce6;
}

.e-vtext {
  font-size: 16.5px;
  line-height: 1.45;
  color: #12131a;
}

.e-vsub.ai .e-vtext {
  font-weight: 520;
}

@media (prefers-reduced-motion: reduce) {
  .e-orb-glow,
  .e-orb-core,
  .e-orb-ring,
  .e-orb-ring.two,
  .e-orb-bars i {
    animation: none;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   R. THE HERO ARRIVAL
   ══════════════════════════════════════════════════════════════════════════

   Jem, 2026-08-18, verbatim: "make this hero animate in really nicely. H1
   first. Subtitle next. Input box next. Trustpilot next and then your AI brain,
   everything underneath coming in, and then 'Free forever, no card needed,
   nothing goes live until you decide' typed out, and then the CTA starts
   flickering or doing whatever."

   🔴 THE ORDER HE ASKED FOR IS NOT THE ORDER IN THE MARKUP, AND THE MARKUP DID
   NOT MOVE. `.e-hero-proof` sits ABOVE `.e-h1` in the DOM - deliberately, and
   pinned by `landing-e.test.tsx`, because the credibility line is meant to be
   read in the same glance as the headline. His arrival order puts it fourth.
   Reordering the DOM to match would have broken the reading order, the tab
   order and the test, to win an animation. So the sequence is assigned in SLOTS
   here instead: every element keeps its place in the document and is told when
   to arrive. The two orders are allowed to disagree, and this comment is where
   they are reconciled.

   THE SLOTS, and they are the seven beats in his sentence. The figures are the
   ones in the rules below, not the first pass's: "Apple pace" (see the note on
   the shared rule) tripled every gap after they were first written.
     1   200ms  .e-h1            the headline
     2  1000ms  .e-lede          the subtitle
     -  FRAME 1 .e-hero-form     THE FIELD HAS NO SLOT ANY MORE. It is at rest
                                 and fully visible in the first painted frame -
                                 see "THE ASK ARRIVES WITH THE HEADLINE" below.
     4  2600ms  .e-hero-proof    Trustpilot
     5  3350ms  .e-mech          the AI brain diagram - and as of 2026-08-18 it
                                 no longer arrives as ONE object. It builds
                                 itself part by part between 3350ms and
                                 ~5760ms, on Jem's instruction, and the whole
                                 of that timeline is section R2 immediately
                                 below. `.e-mech` itself has no slot here any
                                 more; its parts have their own.
     -  FRAME 1 .e-url-note      NOR IS THE REASSURANCE LINE TYPED ANY MORE. It
                                 lives inside the field's own form, so it
                                 arrives with the field: static text, first
                                 frame. Same reason, same section below.
     -  GONE    .e-btn           THE CTA HAS NO SLOT ANY MORE. Its sheen ran
                                 at 6450ms, then 8180ms, then 5920ms, always
                                 "~154ms after the hero's last beat". Jem
                                 dropped it entirely on 2026-09-07 (section
                                 R3). The button is at rest in the first
                                 painted frame and stays there.

   NOTHING HERE MOVES LAYOUT. Every slot animates `opacity` and `transform`
   only, so each element occupies its final box from the first frame: the fold's
   arithmetic (section N) holds while the sequence plays, and a visitor who
   lands mid-sequence never sees the field jump. It is also why the note can
   type without the diagram beneath it shifting - every character is in the
   layout at `opacity: 0` before it is typed.

   IT RUNS ON LOAD, NOT ON INTERSECTION, because the hero IS the first screen.
   `usePageReveal` is scoped to `.e-section` precisely so it cannot reach in
   here and animate any of this a second time. */

@keyframes e-hero-in {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.e-fold .e-h1,
.e-fold .e-lede,
.e-fold .e-hero-proof {
  /* `both`, so the element is held at the FROM frame through its delay. Without
     it every one of these paints at full opacity for the first frame and the
     whole sequence starts with a flash of the finished hero. */
  /* 🔴 APPLE PACE, NOT WEB PACE. Jem, 2026-08-18: "the hero on V2 needs to come
     in much slower. Like Apple. Pace, slow, confident. Let people read, absorb,
     and feel the emotion."
     The first pass ran the whole sequence in ~1s with 240ms between elements,
     which is a UI transition: it tells you the page has loaded. This is a
     REVEAL: each line gets long enough to be read before the next arrives, so
     the eye is led rather than caught up with. 1.15s travel, ~800ms apart. */
  animation: e-hero-in 1.15s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.e-fold .e-h1 {
  animation-delay: 200ms;
}

.e-fold .e-lede {
  animation-delay: 1000ms;
}

/* ── THE ASK ARRIVES WITH THE HEADLINE ──────────────────────────────────────
   🔴 `.e-fold .e-hero-form` IS DELIBERATELY ABSENT FROM THE RULE ABOVE. It
   used to be slot 3, `animation-delay: 1800ms`, and `both` held it at the FROM
   frame (`opacity: 0`) for the whole of that delay. Measured on prod
   (2026-09-03): of 110 humans who landed on `/` and never started signup, 107
   never typed a character, and 60 of them had clicked a forward CTA first -
   they engaged, reached the ask, and stopped. Every one of those CTAs ends in
   this same form.

   THE ARITHMETIC IS WHY. `/` is served as the prerender (see the takeover
   below), whose static copy paints first; React mounts ~460ms later and the
   live copy restarts the sequence, so the field only finished fading in about
   460 + 1800 + 1150 = ~3.4s after first paint, and the reassurance under it
   was still typing itself out until ~8.5s. A visitor who arrives, reads the
   headline and looks for what to do next is looking at nothing.

   So the field is now AT REST FROM THE FIRST FRAME, and the fix is the absence
   of an animation rather than a zero delay: a zero-delay `e-hero-in` would
   start on the prerender copy, then start AGAIN on the live copy at takeover,
   which is exactly the "loading twice" flash the H1 exemption below exists to
   stop. With no animation at all there is nothing to replay on either copy and
   nothing for the takeover to exempt - which is why `html.home-prerendered`
   below still names only the H1.

   NOTHING ELSE MOVED. The headline still opens at 200ms, the subtitle at
   1000ms, Trustpilot at 2600ms and the diagram from 3350ms: the hero still
   performs, it just performs AROUND an ask that was already there. */

.e-fold .e-hero-proof {
  animation-delay: 2600ms;
}

/* ── PRERENDER TAKEOVER: THE HERO ARRIVAL STARTS EXACTLY ONCE ────────────────
   The served `/` ships a static #home-prerender copy of this whole page
   (scripts/build-home.mjs). It paints ~460ms before React mounts the live copy
   into #root and removes the prerender (landing-e.tsx takeover effect). Any
   on-load animation whose delay elapses inside that window therefore STARTS on
   BOTH copies - a second `animationstart`, seen as the hero "loading twice".
   Only two elements have a short enough delay to hit this: the H1 (200ms) and
   the handover baton (0ms, below); everything later (lede 1000ms, proof 2600ms,
   the whole diagram 3350ms+) never starts on the prerender before the swap, so
   it already arrives exactly once on the live copy. THE HERO FORM IS NOT IN
   EITHER LIST any more: it has no arrival animation at all (see "THE ASK
   ARRIVES WITH THE HEADLINE" above), so both copies paint it at rest and there
   is nothing here to exempt. That is the point - an exemption would only have
   held the LIVE copy still, and the field has to be there on the prerender's
   first paint too, which is the frame the visitor actually sees first.

   The prerender's H1 KEEPS its fade: it is what reveals the headline for a
   crawler that runs no JS, and it is the single arrival the visitor watches
   begin. The LIVE copy, taking that already-faded headline over, must NOT
   replay it - so it is held at its finished frame, exactly as reduced motion
   holds the whole sequence (below). `home-prerendered` is set by the takeover
   effect ONLY when a prerender was present, so a fresh SPA load (/v2, client
   nav, tests) is unflagged and plays the H1 arrival as designed. */
html.home-prerendered .e-fold .e-h1 {
  animation: none !important;
}

/* ══════════════════════════════════════════════════════════════════════════
   R2. THE DIAGRAM BUILDS ITSELF, PART BY PART
   ══════════════════════════════════════════════════════════════════════════

   Jem, 2026-08-18, verbatim: "the AI brain animates in first, then the lines
   underneath one by one with a bit of a glimmer or glisten, then 'Answers your
   customers day and night' fades in, and the emoji ticks."

   🔴 `.e-mech` NO LONGER HAS A SLOT OF ITS OWN, and that is the change. It used
   to be the fifth line of the arrival above, arriving as ONE object - the
   comment there said so in as many words, "everything under it arrives with it
   as one object... so it reads as one machine switching on rather than as
   twelve separate chips landing". He has now asked for the opposite, and the
   opposite is a better argument: a machine that assembles itself in front of
   you EXPLAINS itself, where a machine that appears whole only announces
   itself. The wrapper is therefore untouched from the first frame (no opacity,
   no transform, no fill) and every part inside it owns its own arrival.
   Nothing moves layout: every part is in its final box from frame one, exactly
   as the outer sequence requires.

   🔴 WHICH WAY THE ROOM WAS MADE. His brief allowed either fitting the whole
   sequence into the 850ms between the diagram's old slot (3350ms) and the
   note's typing (4200ms), or extending the later slots. 850ms is not a
   sequence, it is a flinch: six beats in it would be 140ms apart, which is
   below the ~200ms at which the eye reads two things as consecutive rather
   than simultaneous, and it would have contradicted the "Apple pace" ruling
   that set the outer sequence at ~800ms a beat three hours earlier. SO THE
   LATER SLOTS MOVED. The diagram runs 3350ms -> 5760ms, and everything after
   it is pushed by the same amount:

     NOTE_TYPE_START   4200ms -> 5850ms   (landing-e.tsx, one constant)
     .e-fold .e-btn    6450ms -> 8180ms   (the CTA sheen, below)

   🔴 THE FIRST OF THOSE TWO NO LONGER EXISTS, 2026-09-04. The reassurance
   line does not type any more (section R), so `NOTE_TYPE_START` is deleted and
   the sheen's delay is derived from THIS list instead: the tick ends the
   diagram at 5380 + 380 = 5760ms, and the sheen keeps its "~154ms after the
   hero's last beat" rule at 5920ms. The row above is left standing because it
   is the record of why the diagram's own beats sit where they do; it is the
   consequence, not the input.

   🔴 AND THE SECOND ROW IS NOW HISTORY TOO, 2026-09-07. Jem dropped the CTA
   sheen outright, so `.e-fold .e-btn` has no delay to push and no slot in this
   sequence at all. Both rows above are kept as the record of why the diagram's
   beats sit where they do; neither is an input to anything that still runs.
   The tombstone is section R3.

   THE COST, RESTATED. This paragraph used to say "the button is pressable and
   the field is typeable from the first frame throughout - only the sheen
   waits". Pressable, yes. VISIBLE, no: the field was held at `opacity: 0`
   until ~3.0s and the line under it until ~8.0s, and an invisible control
   being technically focusable is not an ask a visitor can answer. Both are now
   at rest in the first frame (section R), so the sentence is finally true as
   written. The hero's SHOW still runs to ~5.8s; the ASK no longer waits on it.

   THE BEATS, in his order:

     3350ms  .e-wire            the connector out of the field draws downward
     3350ms  .e-mech-brain      the brain pill rises in
     3760ms  .e-fan-line        curve 0 draws, then 1, 2, 3, 130ms apart
     3900ms  .e-fan-glow        a glimmer travels each curve 140ms behind its
                                own draw, and leaves the hairline behind it
     3760ms  .e-mech-stem       what the fan becomes below 760px (one hairline,
                                grown from the top, since four aimed curves
                                cannot aim once the chips wrap)
     4200ms  .e-mech-ch         the four capability chips, 120ms apart
     4720ms  .e-mech-ports li   the channel chips, 38ms apart - a ripple across
                                one row rather than seven arrivals
     5060ms  .e-mech-out        the green outcome pill fades
     5380ms  .e-mech-out .e-emo and the tick pops, last, on its own
     ~5760ms the diagram is finished

   🔴 `backwards`, NOT `both`, ON EVERY ONE OF THESE. `both` holds the TO frame
   forever, and an animation's computed value beats a plain declaration for as
   long as it is held - the same trap that kept the CTA's sheen off `box-shadow`
   back when there was one (section R3 below records it).
   Two things here would have been broken by it outright: `.e-mech-ch.on`'s
   `transform: translateY(-1px)`, which is how a live capability is shown and
   which a held `transform: none` would have cancelled for the life of the
   page, and the fan's `stroke-dashoffset`, which must be free to sit at its
   own default once drawn. `backwards` gives what is actually wanted - hidden
   through the delay, then out of the way - because every keyframe below ENDS
   on the element's natural resting style. */

.e-fold .e-mech-brain,
.e-fold .e-mech-ch,
.e-fold .e-mech-ports li,
.e-fold .e-mech-out {
  animation: e-hero-in 0.62s cubic-bezier(0.16, 1, 0.3, 1) backwards;
}

/* The brain opens the diagram, on the same frame the diagram's old slot used
   to start, so nothing before it has moved. */
.e-fold .e-mech-brain {
  animation-duration: 0.66s;
  animation-delay: 3350ms;
}

/* THE CONNECTOR, VERSION B ONLY. Drawn from the field downward, which is the
   direction the whole hero is travelling. `scaleY` from the top rather than an
   animated `height`, so the 34px it occupies is reserved from the first frame
   and the diagram under it never moves. */
.e-fold .e-wire {
  transform-origin: top center;
  animation: e-wire-draw 0.46s cubic-bezier(0.16, 1, 0.3, 1) 3350ms backwards;
}

@keyframes e-wire-draw {
  from {
    transform: scaleY(0);
  }
  to {
    transform: none;
  }
}

/* The dot waits for the wire it travels on. It is an infinite animation, so
   this is a delay before the first pass and not a one-shot: without it the dot
   runs its first two laps down a wire that is not drawn yet. */
.e-fold .e-wire i {
  animation-delay: 3700ms;
}

/* THE FOUR CURVES, ONE BY ONE. `pathLength="1"` on the paths (see HeroDiagram)
   is what lets one dash figure mean the same thing on all four: `1` is the
   whole curve, so offsetting by 1 hides it and offsetting by 0 shows it drawn.
   `--i` is the curve's index, set from the same map that draws it. */
.e-fold .e-fan-line {
  stroke-dasharray: 1;
  animation: e-fan-draw 0.5s cubic-bezier(0.33, 0, 0.2, 1) backwards;
  animation-delay: calc(3760ms + var(--i) * 130ms);
}

@keyframes e-fan-draw {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

/* THE GLIMMER. A dash 14% of the curve long travelling the whole of it, on a
   second stroke over the first, so the hairline is still there after the light
   has passed - which is the difference between a glisten and a colour change.

   THE OFFSETS, because they are the kind of thing that gets "fixed" backwards.
   A dash pattern of `0.14 1` with offset `d` puts the bright segment across
   [-d, 0.14 - d] of the curve. At d = 0.14 it sits entirely BEFORE the start,
   at d = -1 entirely PAST the end, so 0.14 -> -1 travels it from the brain
   down to the chip. It fades up over the first fifth and away over the last
   quarter so it arrives and leaves rather than switching on and off, and it
   ends at `opacity: 0` so `backwards` has nothing to hold. */
.e-fold .e-fan-glow {
  opacity: 0;
  stroke-dasharray: 0.14 1;
  animation: e-fan-glimmer 0.62s cubic-bezier(0.4, 0, 0.3, 1) backwards;
  animation-delay: calc(3900ms + var(--i) * 130ms);
}

@keyframes e-fan-glimmer {
  0% {
    opacity: 0;
    stroke-dashoffset: 0.14;
  }
  20% {
    opacity: 0.9;
  }
  75% {
    opacity: 0.9;
  }
  100% {
    opacity: 0;
    stroke-dashoffset: -1;
  }
}

/* Below 760px the fan is `display: none` and this hairline is the diagram's
   only connector, so it carries the same beat the first curve would have. */
.e-fold .e-mech-stem {
  transform-origin: top center;
  animation: e-wire-draw 0.52s cubic-bezier(0.16, 1, 0.3, 1) 3760ms backwards;
}

/* The capabilities the curves are pointing AT, so they land after the curves
   have started arriving rather than before. */
.e-fold .e-mech-ch {
  animation-duration: 0.48s;
  animation-delay: calc(4200ms + var(--i) * 120ms);
}

/* One ripple across the row. 38ms is deliberately below the ~200ms at which
   the eye separates two events: seven channels arriving one at a time would be
   seven beats in a sequence that only has room for one. */
.e-fold .e-mech-ports li {
  animation-duration: 0.42s;
  animation-delay: calc(4720ms + var(--i) * 38ms);
}

.e-fold .e-mech-out {
  animation-duration: 0.54s;
  animation-delay: 5060ms;
}

/* THE TICK, LAST AND ON ITS OWN. It is a CHILD of the pill, so the pill's own
   fade would have carried it in already - it is held at `opacity: 0` through
   its delay by `backwards` instead, which is why the pill arrives empty-handed
   and then gets its tick. The overshoot to 1.18 is what makes it a pop rather
   than a fade; it is a 15px glyph, so the extra 18% is under 3px and moves no
   text beside it. */
.e-fold .e-mech-out .e-emo {
  animation: e-mech-tick 0.38s cubic-bezier(0.34, 1.56, 0.64, 1) 5380ms backwards;
}

/* EVERY FRAME CARRIES `.e-emo`'S OWN `translateY(0.04em)`, which is the
   optical baseline nudge every emoji on this page sits on. `transform` is one
   property: writing `scale()` alone would drop that nudge for the length of
   the animation and then snap it back on the last frame, which is a
   half-pixel hop on the last thing the hero does. It is spelled out here
   rather than inherited because there is no way to inherit half a transform.
   No `display: inline-block` either - `.e-emo` already carries it, which is
   what makes it transformable at all. */
@keyframes e-mech-tick {
  from {
    opacity: 0;
    transform: translateY(0.04em) scale(0.3);
  }
  60% {
    opacity: 1;
    transform: translateY(0.04em) scale(1.18);
  }
  to {
    opacity: 1;
    transform: translateY(0.04em) scale(1);
  }
}

/* 🔴 AND THEN THE WHOLE ARRIVAL IS SWITCHED OFF. `.done` is set once, 6.2s
   after the diagram mounts, by `useArrivalDone` in landing-e.tsx - the full
   reasoning is on that hook, but the short version is a defect this suite of
   rules created and this rule closes: an animation on a `display: none`
   element does not run, it starts fresh when the element is first displayed.
   The fan is hidden below 760px and the stem above it, so widening a window
   past that breakpoint restarted a 3,760ms delay and left the connector
   missing for nearly four seconds. Reproduced, then fixed here.

   It is deliberately every one-shot in the sequence rather than only the two
   that break: after the performance nothing about this diagram should still be
   under animation control. `.e-wire i` is NOT in the list - that is the
   travelling dot, which is infinite by design and goes on travelling. */
.e-mech.done .e-wire,
.e-mech.done .e-mech-brain,
.e-mech.done .e-fan-line,
.e-mech.done .e-fan-glow,
.e-mech.done .e-mech-stem,
.e-mech.done .e-mech-ch,
.e-mech.done .e-mech-ports li,
.e-mech.done .e-mech-out,
.e-mech.done .e-mech-out .e-emo {
  animation: none;
}

/* 🔴 THE TYPING IS GONE, 2026-09-04, AND THIS IS WHERE IT WAS. `.e-typed
   .e-tc` gave every character of "Free forever. No card needed. Nothing goes
   live until you decide." its own 1ms opacity switch at
   `5850 + i * 34`ms, so the sentence was not readable until ~8.0s into the
   page - ~8.5s behind the prerender's first paint. It is the line that tells a
   visitor the ask is safe to answer, and it was arriving long after the 107 of
   110 non-typers had already decided not to. The line is now static text
   inside the form (`UrlNote` in landing-e.tsx), so it arrives with the field in
   the first frame and needs no rule here at all. */

/* ---------- R3. THE CTA SHEEN, REMOVED ----------
 *
 * 🔴 DROPPED ENTIRELY, 2026-09-07, ON JEM'S RULING. `.e-fold .e-btn` used to
 * carry a third background layer - a 300%-wide white band swept across the
 * button's gradient by `@keyframes e-cta-sheen`, 3.2s, infinite, first glint
 * at 5920ms (6450ms until 2026-08-18, then 8180ms, then 5920ms when the typed
 * line was retired). It is gone: the rule, the keyframes, and the button's
 * line in the reduced-motion block that existed only to cancel it.
 *
 * WHY, IN HIS WORDS: a shimmer on the primary CTA is decoration on the one
 * control the whole funnel depends on, and the KISS ruling is to make the one
 * thing BIG, not shiny. Shortening the delay a third time, or A/B testing it,
 * were both on the table and both declined.
 *
 * 🔴 THE RULE STAYS. ONLY ITS SHEEN GOES, AND DELETING THE REST WOULD
 * RECOLOUR THE BUTTON. The first draft of this change removed `.e-fold .e-btn`
 * outright, reasoning that its second background layer,
 * `linear-gradient(135deg, var(--accent) 0%, #4d3ae0 100%)`, is byte-for-byte
 * the `background` the base `.e-btn` already sets, so nothing was holding the
 * colour up. That reasoning skips one rule. `.e-url-row .e-btn` (section L)
 * sets `background: var(--e-ai-ink)` at the SAME (0,2,0) specificity and the
 * hero button IS inside `.e-url-row`, so the base rule is not what the hero
 * falls back to. This rule is later in the file, which is the only reason its
 * `background-image` has been winning, and with it gone `--e-ai-ink` takes the
 * button.
 *
 * MEASURED, NOT REASONED ABOUT. On the live homepage the hero button computes
 * `linear-gradient(135deg, rgb(43,92,230) 0%, rgb(77,58,224) 100%)`. Deleting
 * both copies of this rule from the running CSSOM flipped it to
 * `linear-gradient(0deg, rgba(0,0,0,0.1), rgba(0,0,0,0.1)),
 * linear-gradient(120deg, rgb(43,92,230) 0%, rgb(124,92,255) 52%,
 * rgb(210,66,21) 100%)`: blue-to-violet becoming purple-to-orange, which the
 * comment on `.e-url-row .e-btn` itself names as the button Jem screenshotted
 * on 2026-09-01. Nothing else moved in that experiment - box 126x62,
 * min-height, padding, border-radius, font-size, font-weight, colour and
 * box-shadow were all identical - so the gradient was the whole of it, and a
 * colour change is not what was ruled on today.
 *
 * SO THE THREE DECLARATIONS BELOW ARE NOT LEFTOVERS, THEY ARE THE POINT. They
 * restate the surviving layer with the exact values the sheen rule gave it:
 * the second entry of `background-size: 300% 100%, 100% 100%` and of
 * `background-repeat: no-repeat, no-repeat`. Stated rather than left to the
 * initial value, the whole computed background is comparable term by term and
 * the "resting appearance unchanged" claim is checkable instead of asserted.
 * Re-measured with them in place: every property above is byte-identical and
 * the only differences left are the sheen layer leaving each multi-value list,
 * plus `animation-name: e-cta-sheen -> none`, which is the ruling.
 *
 * 🔴 AN OPEN COLOUR QUESTION, DELIBERATELY NOT ANSWERED HERE. The stylesheet
 * INTENDS the hero to take `--e-ai-ink` - see the comment on `.e-url-row
 * .e-btn`, "The hero keeps the `--e-ai-ink` treatment it was given by name on
 * 2026-08-11" - and it has never once got it, because the sheen rule has
 * overridden it since the day it landed. That is a real latent bug and it is
 * worth putting to Jem. It is a COLOUR question, it is not the one he answered
 * today, and it does not ride along in a change titled "drop the sheen".
 * Nothing here decides it either way: the button keeps painting exactly what it
 * paints on prod this morning.
 *
 * WHAT NOT TO RE-DERIVE. The two design constraints the old comment recorded
 * are still true and are why this was a background layer in the first place:
 * a `::after` sweep needs `overflow: hidden` on the button, which then clips
 * anything that ever wants to sit outside it; and an animated `box-shadow`
 * beats `.e-btn:hover`'s plain declaration for as long as it runs - which was
 * forever - so the button would have stopped answering the pointer. If a glint
 * is ever wanted again, it is a background layer, and it needs Jem. */

.e-fold .e-btn {
  background-image: linear-gradient(135deg, var(--accent) 0%, #4d3ae0 100%);
  background-size: 100% 100%;
  background-repeat: no-repeat;
}

/* REDUCED MOTION TAKES THE WHOLE SEQUENCE, not just the travel. A visitor who
   has asked for less motion gets the finished hero on the first frame: every
   slot at rest and the diagram already built. THE BUTTON IS NOT IN THIS LIST
   AND DOES NOT NEED TO BE: since 2026-09-07 (section R3) it has no animation
   for anyone, so there is nothing here left to cancel. */
@media (prefers-reduced-motion: reduce) {
  .e-fold .e-h1,
  .e-fold .e-lede,
  .e-fold .e-hero-proof,
  /* ...and every part of the diagram's own sequence (section R2). Each of
     these keyframes ends on the element's natural resting style, which is why
     cancelling them outright leaves the finished diagram rather than a hole:
     the brain, the chips, the channels and the pill sit at full opacity, the
     four curves at `stroke-dashoffset: 0` (drawn), and the glimmer at the
     `opacity: 0` its base rule already carries, so no light is parked
     mid-curve. */
  .e-fold .e-wire,
  .e-fold .e-mech-brain,
  .e-fold .e-fan-line,
  .e-fold .e-fan-glow,
  .e-fold .e-mech-stem,
  .e-fold .e-mech-ch,
  .e-fold .e-mech-ports li,
  .e-fold .e-mech-out,
  .e-fold .e-mech-out .e-emo {
    animation: none;
  }
}

/* ---------- Q. The Summoned Field ----------
 *
 * The nav's "Get started free" no longer sends the visitor to the hero: the
 * pressed pill EXPANDS into a card anchored to its own corner, over a scrim,
 * holding the page's one action - the shared URL form - with the cursor
 * already in it. Founder direction (Jem): "does it need to pop up a card?
 * Which has the input?"
 *
 * NAMED `.e-summon`, NOT `.e-card`, ON PURPOSE: `.e-card` already exists in
 * this file (the product-shot card at ~1108, uppercase mono `.e-card-h`
 * header rows) and is reused by channels-e/voice-e on a live product
 * surface, so reusing the name would have fixed-positioned and hidden every
 * one of those cards. Measured on the running page before the rename: the
 * dialog's heading painted in the product shot's uppercase mono.
 *
 * THE Z-LADDER, WRITTEN DOWN: scrim 107 / card 108. Above the sticky bar
 * (50), the consent banner (100) and the menu sheet (105); below the anon
 * takeover (110), the one screen on this page entitled to be on top of
 * everything.
 *
 * THE CARD IS THE SYSTEM'S CARD. White ground, `--line` hairline, the sticky
 * bar's quiet elevation, 18px radius: the same card language as everything
 * else on the page, no new tokens and no new colours. The form inside is the
 * `.e-url` family as-is, so the input keeps its 16px font (under 16px iOS
 * Safari zooms the page on focus) and 48px min-height, and the scoped
 * `@media (max-width: 540px)` stacking rule already gives a full-width input
 * over a full-width button on a phone.
 *
 * ANCHORING IS MEASURED, NOT GUESSED. `--e-summon-top` is written by the
 * component: the nav's own bottom edge plus 10px, re-measured on resize
 * while open, clamped at 0 so the card pins 10px from the viewport top if
 * the nav has been scrolled away. `right` mirrors the content edge: the
 * wrap is 1120px with a 24px gutter, so at any viewport the card's right
 * edge sits where the pressed button's right edge sits. */

.e-summon-scrim {
  position: fixed;
  inset: 0;
  /* No blur: the page stays readable behind the card, just stepped back. */
  background: rgba(18, 19, 26, 0.3);
  z-index: 107;
  opacity: 0;
  pointer-events: none;
  /* Closing: quicker than opening, an exit is an answer not a performance. */
  transition: opacity 180ms ease-out;
}

.e-summon-scrim.in {
  opacity: 1;
  pointer-events: auto;
  transition: opacity 200ms ease-out;
}

.e-summon {
  position: fixed;
  z-index: 108;
  top: var(--e-summon-top, 10px);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 18px 20px 20px;
  box-shadow:
    0 1px 2px rgba(18, 19, 26, 0.06),
    0 12px 32px -8px rgba(18, 19, 26, 0.16);
  /* Closed: invisible, untouchable, and out of the accessibility tree via
     aria-hidden + tabIndex -1 in the markup (the sticky bar's pattern). */
  opacity: 0;
  pointer-events: none;
  transform: translateY(-8px) scale(0.94);
  /* The pill it grows out of sits at its top right corner. */
  transform-origin: top right;
  transition:
    opacity 160ms ease,
    transform 160ms ease;
}

.e-summon.in {
  opacity: 1;
  pointer-events: auto;
  transform: none;
  transition:
    opacity 380ms cubic-bezier(0.16, 1, 0.3, 1),
    transform 380ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* THE GLINT: the pressed pill's own light, expanding. The EXACT `.e-nav-cta`
   120deg three-stop ramp (section L) across the card's top third, breathing
   from 0.14 down to a resting 0.06 as the card lands. The stops are the
   ramp's three colours at full value and the ALPHA is carried by `opacity`,
   which is the only way an alpha can animate; masked to nothing at its lower
   edge so the light dissolves into the card rather than ending on a line. */
.e-summon::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 33%;
  border-radius: 18px 18px 0 0;
  background: linear-gradient(120deg, rgb(43, 92, 230), rgb(124, 92, 255) 52%, rgb(210, 66, 21));
  -webkit-mask-image: linear-gradient(to bottom, #000, transparent);
  mask-image: linear-gradient(to bottom, #000, transparent);
  opacity: 0;
  pointer-events: none;
}

.e-summon.in::before {
  animation: e-summon-glint 500ms ease-out forwards;
}

@keyframes e-summon-glint {
  from {
    opacity: 0.14;
  }
  to {
    opacity: 0.06;
  }
}

/* Desktop: hung from the nav's right edge, one column wide. */
@media (min-width: 900px) {
  .e-summon {
    width: 400px;
    right: max(24px, calc((100vw - 1120px) / 2 + 24px));
  }
}

/* Phones and small tablets: the full width the page has, tucked 8px under
   the nav rather than 10 - the same measured `--e-summon-top` (nav bottom
   + 10px), corrected by the 2px difference rather than measured twice. */
@media (max-width: 899px) {
  .e-summon {
    left: 12px;
    right: 12px;
    top: calc(var(--e-summon-top, 10px) - 2px);
  }
}

/* The way out, where the way in was pressed: 44px hit area, the menu
   sheet's close control one size down. */
.e-summon-close {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--ink);
  cursor: pointer;
}

.e-summon-close svg {
  width: 18px;
  height: 18px;
}

.e-summon-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* The sticky bar's two lines, at card scale. Room on the right for the X. */
.e-summon-h {
  margin: 2px 44px 0 0;
  font-size: 17.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.e-summon-sub {
  margin: 3px 0 0;
  font-size: 13.5px;
  color: var(--ink-2);
}

/* The shared form, docked into the card: the hero's 34px approach and 540px
   centring belong to a page section, not a 400px card. Everything else -
   row, input, button, glow, error - is the `.e-url` family untouched. */
.e-summon .e-url {
  margin: 14px 0 0;
  max-width: none;
}

/* The Free-forever note is written to sit on one line under a 540px hero
   field; inside the card it wraps instead of overflowing. */
.e-summon .e-url-note {
  white-space: normal;
}

/* The trigger holds its hover fill for as long as the card it opened is up,
   so the pill and the card read as one pressed object. Same face as
   `.e-nav-cta:hover` (section L), minus the hover's lift. */
.e-nav-cta[aria-expanded="true"] {
  background: var(--e-ai-ink);
  color: #fff;
  box-shadow:
    inset 0 0 0 1px transparent,
    0 6px 16px -4px rgba(96, 60, 200, 0.5);
}

/* Reduced motion: the card appears and disappears instantly, the glint is
   its resting 0.06 with no breath, and the focus order is unchanged because
   none of it lived in the motion. */
@media (prefers-reduced-motion: reduce) {
  .e-summon-scrim,
  .e-summon {
    transition: none;
  }
  .e-summon.in::before {
    animation: none;
    opacity: 0.06;
  }
}

/* ---------- R. The header knows you are already signed in ----------
 *
 * 🔴 THE SIGNED-OUT CONTROLS ARE THE SIZER. They stay in the flex row and keep
 * holding exactly the width they have always held; only their paint is turned
 * off. The door is then absolutely positioned over the space they are holding,
 * so the right-hand group measures the same in both states at every breakpoint
 * and the header cannot reflow when `/auth/me` lands after first paint.
 *
 * WHY `visibility: hidden` AND NOT `display: none`. `display: none` would
 * collapse the box, which is the reflow this exists to prevent. `visibility`
 * also does the two things a hidden control must do and `opacity: 0` does not:
 * it takes the element out of the tab order and out of the accessibility tree,
 * so a signed-in visitor can neither Tab to "Sign in" nor hear it read out.
 * The JSX adds `aria-hidden` and `tabIndex={-1}` on top of that, which is
 * belt-and-braces for any context where this stylesheet has not applied.
 *
 * SCOPED WITH A CLASS, AND THAT SCOPE IS LOAD-BEARING. `.e-nav-right` is also
 * rendered by `pricing-chrome.tsx`, so /pricing, /pricing/compare and /leads
 * read every rule written for it. Each rule below is gated on
 * `.e-nav-right-in`, a class only this page's header sets and only in the
 * signed-in state, so signed out there is not one changed declaration on this
 * page or on those three. `.e-nav-door` and `.e-menu-door` are new names
 * nothing else uses, which is why they need no gate of their own.
 *
 * `top: 50%` + `translate` rather than `transform`: `.e-nav-cta:hover` (section
 * L) sets `transform: translateY(-1px)`, and a hover written into `transform`
 * would have thrown the centring away at the moment of the press. `translate`
 * is its own property, so the lift composes with the centring instead of
 * replacing it.
 */

/* The second selector in each list is the PRERENDER's copy of this state.
   dist/home.html (scripts/build-home.mjs) links this stylesheet and carries a
   static, signed-out copy of the header with the door baked in; an inline head
   script sets `html.home-session` when the session-hint cookie is present,
   before <body> exists, so it cannot put `.e-nav-right-in` on the group itself.
   One rule, two ways in, so the static and the live header can never hide the
   sizer differently. See docs/BUG_LANDING_HEADER_SIGNED_IN_LAG.md. */
.e-nav-right-in,
html.home-session #home-prerender .e-nav-right {
  position: relative;
}

.e-nav-right-in > .e-nav-signin,
.e-nav-right-in > .e-nav-cta:not(.e-nav-door),
html.home-session #home-prerender .e-nav-right > .e-nav-signin,
html.home-session #home-prerender .e-nav-right > .e-nav-cta:not(.e-nav-door) {
  visibility: hidden;
}

.e-nav-door {
  position: absolute;
  right: 0;
  top: 50%;
  translate: 0 -50%;
  /* Bounds the box to the group. "Dashboard" is shorter than "Get started
     free" at every width, so today this never binds; it is here so a future
     label can never make the header wider than the space the sizer is holding,
     which below 900px is the difference between sitting beside the Menu
     trigger and sitting on top of it. */
  max-width: 100%;
}

/* The phone sheet's door. `.e-menu-signin` was written for a <button>, and the
   two properties a <button> gets for free are the two an <a> needs said out
   loud: content centred over the row's 44px, and no underline.

   🔴 A FLEX CONTAINER SPLITS ITS OWN SENTENCE. Whatever this wraps must be a
   SINGLE element child. With bare text beside a <b>, flex makes two anonymous
   items and the space between them is gone: measured on the built page, the
   text run ended at x=91.78 and the bold began at x=91.78, so the sheet read
   "Go to yourdashboard". The JSX therefore puts the whole label in one <span>,
   and says why. */
.e-menu-door {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

/* 🔴 THE TREATMENT BAR HOLDS A BUTTON, NOT A FIELD, SO IT MUST NOT KEEP THE
   FIELD'S SLOT. `.e-sticky-field` is `flex: 0 1 520px` because it normally
   holds a URL input; with only a button inside, the button floated in the
   middle of the bar with a dead gap either side. Jem, 2026-09-08: "this does
   not look good on Arm B."
   The copy takes the room it needs and the button sits at the end, which is
   the shape every other CTA row on this page already uses. */
.e-sticky.cta-only .e-sticky-field {
  flex: 0 0 auto;
}

/* 🔴 AND IT MUST NOT KEEP THE FULL-WIDTH BAR EITHER. Jem, 2026-09-08: "too
   wide maybe?" -- with a 520px input gone, `space-between` pushed the copy and
   the button to opposite ends of a 940px bar and left ~500px of black nothing
   between two things that belong together. Width was never a design choice
   here; it was the width a URL field needed.
   Shrink to content and centre it. The bar becomes a pill the size of what it
   says, which is what the rest of the page does with its own CTA rows. */
.e-sticky.cta-only .e-sticky-in {
  justify-content: flex-start;
  gap: 28px;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
}

/* #6080 homepage experiment, TREATMENT ARM ONLY (lib/ab.ts
   HOMEPAGE_SELLING_EXPERIMENT). Inert until added to LIVE_EXPERIMENTS; a
   natural visitor never renders these rules. E1 is the primary button, reusing
   .e-btn so the ask looks exactly like every other primary action on the page.
   E2 "See pricing →" sits directly underneath, then the demoted website link. */
.e-hero-sell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
.e-hero-sell-cta {
  white-space: normal;
}
.e-hero-sell-pricing,
.e-hero-sell-url {
  font: inherit;
  font-size: 15px;
  color: var(--accent);
  background: none;
  border: 0;
  padding: 2px 0;
  cursor: pointer;
  text-decoration: none;
}
.e-hero-sell-pricing:hover,
.e-hero-sell-url:hover {
  text-decoration: underline;
}
.e-hero-sell-url {
  font-size: 14px;
  color: inherit;
  opacity: 0.8;
}
