/* Marketing site: topbar/wordmark, pages, CTAs. */
/* ===== Marketing site =====
   Public pages (/ and /legal/*) rendered through layouts/marketing.html.slim.
   Reuses the theme tokens. Layout assumes body.marketing — the
   marketing layout sets that class so the marketing rules don't leak into
   the company. */

body.marketing {
  background: var(--bg);
  color: var(--text);
  overflow-x: clip;
  /* The topbar's height, which the cover pulls itself up under. */
  --marketing-bar: 3.5rem;
  /* Half the air between two floors: every floor pads itself by this top and
     bottom, so the page has one gap all the way down (8rem wide, 5rem
     stacked) instead of a sum of each floor's own exceptions. */
  --floor-pad: 4rem;
}

@media (max-width: 64rem) {
  body.marketing { --floor-pad: 2.5rem; }
}

/* Topbar */

.marketing-topbar {
  /* In the flow, not pinned: the page is read top to bottom and the one ask is
     on the cover and under the footer. Relative only so it paints over the
     cover, which is pulled up under it. */
  position: relative;
  z-index: 1;
  background: var(--bg);
  border-bottom: 1px solid var(--hairline);
}

/* The bar on an error page: the wordmark and the way in (the company for
   someone signed in, the sign-in for anyone else) side by side in the
   middle, no nav and no rule under it. There is nothing to navigate from a
   page that is not there, and with one picture and a few lines under it the
   rule was the page's loudest edge. */
.marketing-topbar:has(+ .marketing-main > .error-page) { border-bottom: 0; }
.marketing-topbar:has(+ .marketing-main > .error-page) .marketing-topbar__inner { justify-content: center; }
.marketing-topbar:has(+ .marketing-main > .error-page) .marketing-topbar__brandnav { flex: 0 0 auto; }
.marketing-topbar:has(+ .marketing-main > .error-page) .marketing-topbar__nav { display: none; }
.marketing-topbar:has(+ .marketing-main > .error-page) .marketing-topbar__actions { margin-left: 0; }

.marketing-topbar__inner {
  max-width: 80rem;
  margin: 0 auto;
  padding: 0 1.5rem;
  height: var(--marketing-bar);
  display: flex;
  align-items: center;
  gap: 2rem;
}

/* The wordmark is bigger than the nav links, so centering each box on its own
   leaves its baseline ~2px low. Group them and align that group on the baseline;
   the outer flex still centers the group in the bar. */
.marketing-topbar__brandnav {
  display: flex;
  align-items: baseline;
  gap: 2rem;
  flex: 1;
}

.marketing-topbar__nav {
  display: flex;
  gap: 1.5rem;
}

.marketing-topbar__nav a {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.9375rem;
  transition: color 120ms;
}

.marketing-topbar__nav a:hover {
  color: var(--text);
}

/* The bar is 3.5rem tall and its links one line of text in the middle of it.
   Padding with the same negative margin makes most of the bar the target
   without moving the baseline the group aligns on. */
.marketing-topbar__nav a,
.marketing-topbar .marketing-logo {
  padding-block: 0.75rem;
  margin-block: -0.75rem;
}

/* A picture has no baseline of its own to give the group: centred instead. */
.marketing-topbar .marketing-logo { align-self: center; }

/* A ghost, not a second accent: the page has one filled button and it is the
   cover's ask. This one is navigation for someone who already signed up. */

.marketing-topbar__cta {
  appearance: none;
  font: inherit;
  cursor: pointer;
  /* Signed in it is a link, signed out a form's button: as an inline box the
     link is sized by its font and the button by its line-height, which left
     the two states 6px apart in height. One flex box sizes both the same. */
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  --lh: 1.2;
  /* The same clay as the cover's ask, left uncoloured: a white pill lit from
     above with its underside in shade, so the corner reads pressed from the
     logo's material without spending the page's one accent. */
  background: var(--bg);
  border: 1px solid var(--hairline);
  color: var(--text);
  padding: 0.5rem 1.125rem;
  border-radius: var(--radius-pill);
  box-shadow:
    inset 0 2px 1px rgba(255, 255, 255, 0.9),
    inset 0 -3px 6px rgba(15, 23, 42, 0.08),
    0 3px 8px -4px rgba(15, 23, 42, 0.25);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.875rem;
  transition: background 120ms, border-color 120ms, transform 120ms;
}

.marketing-topbar__cta:hover {
  background: var(--fill-raised);
  border-color: var(--hairline-strong);
}

.marketing-topbar__cta:active {
  transform: translateY(1px);
}

/* Google's mark on its own white disc, as their brand rules ask, so the four
   colours hold on the cover's picture as well as on white. */
.marketing-topbar__g {
  display: inline-grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  margin-left: -0.5rem;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.2);
}

.marketing-topbar__g .google-g {
  width: 0.875rem;
  height: 0.875rem;
}

@media (max-width: 48em) {
  .marketing-topbar__nav { display: none; }
}

/* A phone's top edge sits under the status bar and a rounded corner, so the
   pill in a 3.5rem bar read as pressed against it. */
@media (max-width: 40rem) {
  body.marketing { --marketing-bar: 4.5rem; }
}

/* On a phone the cover carries headline, panel and ask in one fold, so the
   copy's own air is what gives. */
@media (max-width: 40rem) {
  /* No padding-top here: `.marketing-hero--cover`'s own shorthand is further
     down the sheet and resets it — the override that used to sit here never
     applied. The top band's air is the clamp in that shorthand. */
  .marketing-hero--cover .marketing-hero__h1 { margin-bottom: 1rem; }
  .marketing-hero--cover .marketing-hero__sub { margin-bottom: 1.25rem; }

  /* Promise, then the ask, then the terms. On a phone the price sentence above
     the button made three paragraphs to read before anything to press; under
     it, it is what it has always been — the small print that answers "what
     does it cost" once the button has been seen. */
  .marketing-hero--cover .marketing-hero__ask { flex-direction: column-reverse; gap: 0; }

  .marketing-hero__ask form,
  .marketing-hero__ask .marketing-cta {
    display: block;
    width: 100%;
    text-align: center;
  }
  .marketing-hero--cover .marketing-hero__ask p {
    margin: var(--space-3) 0 0;
    font-size: 0.875rem;
    color: rgba(255, 255, 255, 0.88);
    text-shadow: 0 1px 20px rgba(8, 15, 30, 0.5);
  }

  /* The panel is taller than the phone's fold has room for under the
     headline, so the ask goes first: price and button on the first screen,
     the demo's top edge showing under them as the reason to scroll. */
  .marketing-hero--cover .demo-stage { order: 1; }
}


/* Main */

.marketing-main {
  max-width: 72rem;
  margin: 0 auto;
  padding: 0 1.5rem;
}

/* A page shorter than the screen (a short document) ends on the footer at
   the screen's foot, not on the footer a hand under the text and a field of
   white under that: the body is a flex column the height of the screen
   (01_base), and the end block takes the room that is left above it. */
.marketing-end { margin-top: auto; }

/* The error page's bar is not pinned to the top: the wordmark, the picture
   and the words are one group, centred in the screen with the same air
   above and below (the body is the flex column). */
body.marketing:has(.error-page) { justify-content: center; }

.marketing-main:has(> .error-page) { width: 100%; }

/* Hero block */

.marketing-hero {
  padding: 6rem 0 4rem;
  text-align: left;
  max-width: 48rem;
}

.marketing-hero__h1 {
  font-size: round(clamp(2.25rem, 5vw, 3.75rem), 1px);
  font-weight: 700;
  letter-spacing: -0.025em;
  --lh: 1.1;
  margin-bottom: 1.25rem;
  color: var(--text);
  /* Share the words between the lines: a headline that ends on one word alone
     is the widow the brand brief rules out. */
  text-wrap: balance;
}

.marketing-hero__sub {
  font-size: round(clamp(1.0625rem, 1.6vw, 1.25rem), 1px);
  color: var(--text-muted);
  margin-bottom: 1rem;
}

.marketing-hero__strap {
  font-size: 0.9375rem;
  color: var(--text-muted);
  font-style: italic;
}

/* Section block */

/* No rule between floors: every one of them had switched it off, and the air
   is what parts them. */
.marketing-section {
  padding: var(--floor-pad) 0;
}

/* A heading set as a heading: tight leading, not the body's 1.6, which at
   36px opened 22px of air inside a two-line h2. One size for every floor's
   heading; the claim steps up from it and the three cards step down. */
.marketing-section h2,
.marketing-feature__text h2 {
  font-size: round(clamp(1.5rem, 3vw, 2.25rem), 1px);
  --lh: 1.15;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 1rem;
  color: var(--text);
  text-wrap: balance;
}

.marketing-section h3 {
  font-size: 1.125rem;
  font-weight: 600;
  margin-bottom: 0.5rem;
  color: var(--text);
}

.marketing-section p {
  color: var(--text-muted);
  margin-bottom: 1rem;
  max-width: 56rem;
}

.marketing-section ul,
.marketing-section ol {
  color: var(--text-muted);
  padding-left: 1.5rem;
  margin-bottom: 1rem;
  max-width: 56rem;
}

.marketing-section li {
  margin-bottom: 0.5rem;
}

.marketing-section li strong {
  color: var(--text);
}

/* The landing's closing ask, the last floor over the footer: one button,
   centred on a whole screen, and nothing around it but air. A glow smudged the page and a tinted
   strip made a second footer.

   2026-09-20: the glow was tried a second time by someone who had not read the
   line above, and smudged the page exactly as promised. What the screen took
   in the end was streaks — a field of them crossing behind the button, drawn
   further down. Air is still what a single button needs; a whole empty screen
   of it read as the page having run out.

   It rides up the last half-screen slower than the page does and settles into
   the centre, instead of turning over on a hinge: the hinge was the last leaf
   of a book falling flat, which needed a leaf — with the band a full screen and
   the button centred in it, the same rotation was a button doing a flip. Riding
   slow is also what gets it on screen before the halfway mark while leaving it
   level with the eye at the bottom; the two cannot both come from the layout,
   since a button centred on the last screen is half a screen from the end of
   the page by definition. The band's height is in the page from the start, and
   the scroll position alone says how far the button has come. */

/* The closing band and the footer under it are one screen between them: the
   band takes what the footer leaves. A whole screen for the band alone put
   the footer a screen further down, past where anyone scrolls, and the page
   ended on a field of white. svh, not vh, for the same reason the cover uses
   it — the URL bar must not sit over the button, and a dynamic unit would
   resize the band under the animation. */
.marketing-end:has(> .marketing-closer) {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}

.marketing-closer {
  flex: 1;
  /* A floor for the band where the footer is most of a screen (a phone): the
     button keeps air round it, and the pair runs a little past the screen. */
  min-height: 16rem;
  display: grid;
  /* Dead centre, so the button is level with the eye once the page has bottomed
     out. Nothing here buys it an earlier entrance — half a screen has to pass
     under it either way; that is the animation's job, below. */
  align-content: center;
  /* The band, not the button, is what the rise is timed against: the button is
     a button tall, and on its own timeline the whole move would be over in the
     inch it takes to clear the bottom edge. */
  view-timeline-name: --closer;
}

/* A screen of plain white under the footer read as the page having run out
   rather than as its last floor. What fills it is the work itself: the six
   marks from "What an agent can do", the same drawings, adrift. A glow was
   tried here first and thrown out — a coloured wash under a button is a
   gradient with nothing to say, and on a near-white field it reads as dirt on
   the screen. These say what the page spent three thousand pixels saying, at
   the weight of a watermark.

   `clip`, not `hidden`: hidden would make the band a scroll container and the
   view timeline the button rides on would have nothing left to measure. */
.marketing-closer {
  position: relative;
  isolation: isolate;
  overflow: clip;
}

/* The pipes board: the whole band, behind everything, with the button standing
   on it. The controller makes the canvas and draws into it; the band stays
   white, because the canvas has an alpha channel and the page shows through
   wherever no pipe is. */
.marketing-closer__pipes {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

/* Off until the screen has been left alone, and slower arriving than leaving:
   a screensaver fades up, and a visitor who has come back wants their page
   now. The 600ms is written out rather than taken from --dur, which is a real
   token in 01_base (220ms) — the fallback in var(--dur, 600ms) never fired,
   so the fade ran at a third of what the JS timer beside it was waiting for. */
.marketing-closer__pipes {
  opacity: 0;
  transition: opacity 600ms ease;
}

.marketing-closer__pipes.is-on {
  opacity: 1;
  transition-duration: 1600ms;
}

/* A full board clears the way a screensaver does: the picture goes, all of it,
   and the next one starts on an empty grid. Fading the pipes themselves means
   fading them towards the colour of the page, which is a renderer that has to
   know what is behind it. */
.marketing-closer__pipes.is-on.is-wiping {
  opacity: 0;
  transition-duration: 1200ms;
}

.marketing-closer__pipes canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.marketing-closer__inner {
  padding-inline: 1.5rem;
  text-align: center;
}

/* Scroll-driven: no observer, no timer, and off the compositor — transform and
   opacity only. Held behind @supports because without a view timeline the
   animation never runs, and its `from` keyframe would leave the button faint
   and low for good. Reduced motion gets it in place, which is the end of the
   animation, not the start of it. */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .marketing-closer__inner {
      animation: closer-rise both;
      animation-timeline: --closer;
      /* Entry progress reads off as the band's own height, so the button,
         centred, would clear the bottom edge at 50%. Starting six rem high it
         clears it at 40% instead, and the range ends a breath before the band
         is whole on screen — which is when the footer starts to show. */
      animation-range: entry 40% entry 95%;
      /* The house curve, so the button settles into its place rather than
         tracking the scroll one to one the whole way. */
      animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
    }
  }
}

@keyframes closer-rise {
  from {
    transform: translateY(-6rem);
    opacity: 0;
  }

  to {
    transform: none;
    opacity: 1;
  }
}

/* Bigger than the cover's: the cover's button sits on a photograph with a price
   line beside it, this one is alone on an empty page. */

.marketing-closer .marketing-cta {
  margin-top: 0;
  padding: 1.125rem 2.5rem;
  font-size: 1.125rem;
}

/* The landing ask, under the roster wheel. Centred column: one line of pain,
   the price anchor, the button, then the small print that answers the only
   question standing between reading and signing in (when am I charged). */
/* Negative top eats the ring stage's bottom slack (clearance kept there for the
   near tile's drop shadow), so the ask sits under the wheel instead of a hole. */
/* Feature floor: the demo on the left, the words on the right. The floor
   above it and the price floor below both put the words first, and three
   splits the same way round read as one template stamped down the page. In
   the markup the words still come first, which is the order they stack in. */

.marketing-feature {
  display: grid;
  grid-template-columns: 38rem minmax(0, 1fr);
  gap: 3rem;
  /* Top, not centre: beside a tall panel the copy floated in the middle of its
     column with air above and below it. */
  align-items: start;
  padding: var(--floor-pad) 0;
}

.marketing-feature__media { order: -1; }

/* The stream and the three cards under it are one block, four answers to one
   fear, so the cards follow at half a floor's gap. */
.marketing-feature--demo + .marketing-feature-pair { padding-top: 0; }

/* Two claims of equal weight on one floor: each column is its own little
   feature — the words, then the picture under them. */

/* Thirds on whole pixels: the first two rounded down, the last takes what is
   left, so the second and third start on a whole pixel (a third of 1024px less
   the gaps is 341.33; 2026-10-14). The FAQ and price floors repeat it. */
.marketing-feature-pair {
  display: grid;
  grid-template-columns: round(down, (100% - 5rem) / 3, 1px) round(down, (100% - 5rem) / 3, 1px) minmax(0, 1fr);
  gap: 2.5rem;
  padding: var(--floor-pad) 0;
}

/* The three headings wrap to different depths, so the pictures hang off the
   bottom of the row instead of the bottom of their own text: a column of art
   that steps up and down reads as three floors, not one. */
.marketing-feature-pair__item {
  display: flex;
  flex-direction: column;
  container-type: inline-size;
}

.marketing-feature-pair__item .marketing-feature__text {
  margin-bottom: 1.5rem;
}

.marketing-feature-pair__item .marketing-feature__img {
  margin-top: auto;
  /* 16:10 of a fluid column is a fraction (213.75px at 390), and every floor
     below stood on it: the height is the column's width over 1.6, rounded to a
     whole pixel; object-fit trims the sub-pixel difference (2026-10-14). */
  height: round(100cqi / 1.6, 1px);
}

/* No 30rem cap here: the column IS the measure, and a paragraph that stops
   short of a picture it sits on reads as a column that missed. */
.marketing-feature-pair__item .marketing-feature__text p {
  max-width: none;
}

/* A third of the wrap is a third of a floor, so these take the split title's
   size rather than the full-width floor's: three 32px claims across one row
   read as three pages. Tighter tracking and a shorter drop to the line under
   it, so name and clause read as one object. */
.marketing-feature-pair__item .marketing-feature__text h2 {
  font-size: round(clamp(1.25rem, 1.8vw, 1.5rem), 1px);
  letter-spacing: -0.025em;
  margin-bottom: 0.375rem;
}

/* A step down from the floors' body: at a third of the width the clause is a
   caption to the claim, not a paragraph of its own. */
.marketing-feature-pair__item .marketing-feature__text p {
  font-size: 0.9375rem;
  --lh: 1.6;
}



/* The sentence under a floor's heading, at the claim's lede size: the same
   job on the floor above it. */
.marketing-feature__text p {
  color: var(--text-muted);
  font-size: 1.0625rem;
  --lh: 1.55;
  max-width: 30rem;
}

.marketing-feature__img {
  display: block;
  width: 100%;
  /* The tag declares its box for the first paint; the column decides the rendered size. */
  height: auto;
  /* Fills its column and carries the browser window's frame: since one of the
     three floors shows the product itself, the other two have to present their
     art at the same size and in the same frame, or the middle floor reads as a
     different page. 16:10 is that window's ratio too. */
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: var(--radius);
  box-shadow: 0 1rem 2.5rem rgba(15, 23, 42, 0.16), 0 0 0 1px rgba(15, 23, 42, 0.06);
}

/* Three abreast only while each column can still hold its line in two rows:
   between this and the floors' own breakpoint the columns were narrow enough to
   push every body onto a third line, which is where a claim stops reading as a
   claim. */
@media (max-width: 75rem) {
  .marketing-feature-pair {
    grid-template-columns: 1fr;
    gap: 3rem;
  }
}

/* The demo's column is 38rem, so the floor stacks well before the phone, at
   the width where the copy beside it would be squeezed. */
@media (max-width: 64rem) {
  .marketing-feature {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }

  .marketing-feature__media { order: 0; }
}

/* Primary CTA button.

   Signed in it is an <a>; signed out it is a <button> inside a button_to form.
   The browser paints that second one with its own chrome — a 2px OUTSET
   border, light on the top-left and dark on the bottom-right, plus the system
   font — so the same control looked like two different things depending on who
   was looking at it. That dark edge down the right and bottom of the closing
   band's button was the outset border, and it was invisible to anyone testing
   while signed in.

   Neutralised on the class, not at the call site: the cover's copy had these
   four lines of its own, which is exactly why it was the only one that ever
   looked right. */
/* Pressed from the same clay as the logo: a pill, lit from above, the
   underside in its own shade, standing on a soft shadow. The bevel is the
   insets, so every call site that sets its own lift keeps it by adding
   var(--clay-bevel) first. */
.marketing-cta {
  --clay-bevel:
    inset 0 2px 1px rgba(255, 255, 255, 0.35),
    inset 0 -4px 8px rgba(15, 23, 42, 0.25);
  appearance: none;
  border: none;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  display: inline-block;
  background: var(--accent);
  color: var(--bg);
  padding: 0.75rem 1.5rem;
  border-radius: var(--radius-pill);
  box-shadow: var(--clay-bevel), 0 4px 10px -4px rgba(86, 110, 180, 0.55);
  text-shadow: 0 1px 1px rgba(15, 23, 42, 0.2);
  text-decoration: none;
  margin-top: 1rem;
  transition: background 120ms, transform 120ms, box-shadow 120ms;
}

.marketing-cta:active {
  transform: translateY(1px);
  box-shadow: var(--clay-bevel), 0 2px 4px -2px rgba(86, 110, 180, 0.5);
}

.marketing-cta:hover {
  background: var(--accent-hover);
}

/* Footer */

/* The floor above pads itself by half a gap; the same again makes the footer's
   rule one more floor away, not another empty screen. */
/* Straight under the closing band there is a screen of air already. */
.marketing-closer + .marketing-footer { margin-top: 0; }

.marketing-footer {
  margin-top: var(--floor-pad);
  border-top: 1px solid var(--hairline);
  padding: 4rem 0;
}

/* Brand on the left, the whole nav as one block flush right: three tracks of
   their own width, so the columns read as a unit instead of landing on an
   arbitrary quarter of the page. */
.marketing-footer__inner {
  max-width: 72rem;
  margin: 0 auto;
  padding: 0 1.5rem;
  display: grid;
  grid-template-columns: minmax(12rem, 1fr) auto;
  gap: 2.5rem;
}

/* One track per column, sized to its content: a column added to the nav
   doesn't have to be counted here too. */
.marketing-footer__nav {
  display: grid;
  grid-auto-flow: column;
  gap: 3rem;
}

/* 52em is where the brand and the tracks stop fitting side by side. The
   nav then flows in two balanced text columns, so a short group and a tall one
   pair up instead of leaving a column-high hole beside the last one. */
@media (max-width: 52em) {
  .marketing-footer__inner {
    grid-template-columns: 1fr;
    gap: 2rem;
  }

  .marketing-footer__nav {
    display: block;
    columns: 2;
    column-gap: 2rem;
  }

  .marketing-footer__col {
    break-inside: avoid;
  }

  .marketing-footer__col + .marketing-footer__col {
    margin-top: 1.5rem;
  }
}

.marketing-footer__col,
.marketing-footer__brand {
  display: flex;
  flex-direction: column;
}

/* Sits on the headings' cap line, not above them: the wordmark is bigger, so
   its own line-box is what has to move. */
.marketing-footer__brand {
  align-items: flex-start;
  gap: var(--space-4);
  padding-top: 0.125rem;
}

.marketing-footer__tagline {
  max-width: 18rem;
  margin: 0;
  font-size: 0.875rem;
  --lh: 1.5;
  color: var(--text-muted);
}

/* Drops to the foot of the brand column, so it lands level with the last link
   instead of hanging under the tagline. */
.marketing-footer__signoff {
  margin-top: auto;
  font-size: 0.8125rem;
  color: var(--text-muted);
}

/* The heading names the column and steps back; the links are what gets read
   and clicked, so they carry the text color. */
.marketing-footer__heading {
  font-size: 0.75rem;
  --lh: 1;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  font-weight: 600;
  margin-bottom: 0.75rem;
}

/* Each link is a full row: on a phone the footer is the site's only
   navigation, so there the rows grow to a thumb's height. */
.marketing-footer__col a {
  display: flex;
  align-items: center;
  min-height: 2rem;
  color: var(--text);
  text-decoration: none;
  font-size: 0.875rem;
  transition: color var(--dur-fast);
}

.marketing-footer__col a:hover {
  color: var(--accent);
}

.marketing-footer__col a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

@media (hover: none) {
  .marketing-footer__col a { min-height: 2.5rem; }
}


/* Marketing hero variants and FAQ */

.marketing-hero--landing {
  text-align: center;
  max-width: 56rem;
  margin: 0 auto;
  padding-bottom: 2.5rem;
}

/* Landing cover: full-bleed art, viewport tall, the copy sits on top of it.
   Breaks out of .marketing-main's 72rem column; body clips the vw overhang so
   a desktop scrollbar can't push the page sideways. The art is the LCP asset,
   so it's served as webp: cwebp -q 82 -resize 2400 0 hero-<name>.png. */

.marketing-hero--cover {
  position: relative;
  max-width: none;
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  /* The cover owns the fold: headline, the demo panel and the ask all ride on
     the art. svh, not vh: on mobile the dynamic viewport is what's actually
     visible, and 100vh puts the CTA under the URL bar. */
  min-height: 100vh;
  min-height: 100svh;
  /* The topbar plus its 1px rule; clear both or that rule shows as a hairline
     of page background above the art. */
  margin-top: calc(-1 * var(--marketing-bar) - 1px);
  display: flex;
  flex-direction: column;
  align-items: center;
  /* The whole cover — headline, panel, ask, cue — is centred in what the
     topbar leaves, so the air above it and below it is the same. `safe`, not
     plain `center`: on a short window the content outgrows the fold, and a
     centred overflow would push the headline up under the topbar where it
     cannot be scrolled back to. There the fold falls back to top-aligned. */
  justify-content: safe center;
  /* Equal floors above and below the centred group, plus the topbar's own
     height on top — so a window too short to centre still leaves the headline
     clear of the bar instead of butting it. */
  padding: calc(var(--marketing-bar) + 1px + 1rem) 1.5rem 1rem;
  background: var(--cover-art) center / cover no-repeat;
}

/* The art is pale and deliberately empty top and bottom, so the copy runs in
   the page's own dark ink — no scrim, and the picture keeps its colour. A soft
   light halo covers the crops where a character drifts under the text. */

.marketing-hero--cover::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 42% at 50% 0%, rgba(8, 15, 30, 0.62), rgba(8, 15, 30, 0) 78%),
    radial-gradient(120% 30% at 50% 100%, rgba(255, 255, 255, 0.45), rgba(255, 255, 255, 0) 78%);
}

/* The portrait fold, and it has to sit HERE: the two rules above set their
   backgrounds with the shorthand, so anything an earlier media block said
   about the crop or the wash was thrown away. */
@media (max-width: 40rem) {
  /* Portrait shows a quarter of this landscape scene, and the middle quarter
     is a face in soft focus — the copy sat on a blur. A quarter to the left is
     wall, sky and a palm; the characters keep their heads just above the
     panel. */
  .marketing-hero--cover { background-position: 25% 100%; }

  /* Slate ink on a mid-tone blur is unreadable at any crop, so the light wash
     the cover's floor already has is pulled up under the whole copy block. */
  .marketing-hero--cover::before {
    background:
      linear-gradient(to bottom,
        rgba(8, 15, 30, 0.86) 0%,
        rgba(8, 15, 30, 0.8) 28%,
        rgba(8, 15, 30, 0.58) 40%,
        rgba(8, 15, 30, 0) 54%),
      radial-gradient(150% 40% at 50% 100%, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 80%);
  }
}

.marketing-hero--cover > * {
  position: relative;
  color: var(--text);
  text-shadow: 0 1px 16px rgba(255, 255, 255, 0.75);
}

/* The headline sits in the shaded top band, so it flips to white ink. */

.marketing-hero--cover .marketing-hero__h1,
.marketing-hero--cover .marketing-hero__sub {
  color: #fff;
  text-shadow: 0 1px 20px rgba(8, 15, 30, 0.5);
}

/* The ask follows the demo panel rather than being pinned to the cover's
   floor — the panel is what it's answering. */
.marketing-hero--cover .marketing-hero__ask {
  margin-top: 0;
  padding-top: 0;
}

/* Scroll cue on the cover's floor. A chevron drawn from two borders, bobbing
   once every couple of seconds: enough motion to read as "there is more",
   little enough to ignore. The hit area is a real 44px target around it. */

/* On the cover's floor, out of the flow: in flow it read as a fifth line of
   the centred group instead of an edge marker, and it was what the group was
   being centred around. Absolute is safe here — when the content outgrows the
   fold the cue sits at the cover's own bottom, which is where it would have
   been in flow anyway. The glyph is small; the 44px hit area around it is
   not. In the corner rather than centred: under the button, on the axis the
   eye is already on, it competed with the one thing to press. */

.marketing-hero--cover .marketing-hero__scroll {
  position: absolute;
  left: 0.5rem;
  bottom: 0.25rem;
  margin-top: 0;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  color: var(--text);
  opacity: 0.4;
  transition: opacity 0.15s ease;
}

/* 10px, even like its 44px target: at 9 the chevron stood on a half pixel
   (2026-10-14). */
.marketing-hero--cover .marketing-hero__scroll-arrow {
  width: 0.625rem;
  height: 0.625rem;
}

.marketing-hero--cover .marketing-hero__scroll:hover,
.marketing-hero--cover .marketing-hero__scroll:focus-visible {
  opacity: 1;
}

.marketing-hero__scroll-arrow {
  width: 0.6875rem;
  height: 0.6875rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  rotate: 45deg;
  animation: hero-scroll-bob 2.4s ease-in-out infinite;
}

@keyframes hero-scroll-bob {
  0%, 100% { translate: 0 -0.125rem; }
  50%      { translate: 0 0.125rem; }
}

@media (prefers-reduced-motion: reduce) {
  .marketing-hero__scroll-arrow { animation: none; }
}

/* No cue on a phone: the demo's top edge already runs off the fold there, and
   a thumb scrolls without being told to. Here rather than in the phone block
   up the sheet, which the cue's own `display: grid` would override. */
@media (max-width: 40rem) {
  .marketing-hero--cover .marketing-hero__scroll { display: none; }
}

/* Marketing pages only — the app's own scrollers are driven from JS. */
html:has(body.marketing) {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html:has(body.marketing) { scroll-behavior: auto; }
}

/* The one ask, on the lower third of the cover. It carries its own frosted
   panel rather than dimming the whole picture — the art stays saturated and
   the copy still clears contrast wherever the crop lands. */

/* Button first, its terms beside it: one row instead of a sentence stacked on
   a button. The phone block up the sheet stacks them again, terms under. */
.marketing-hero__ask {
  margin-top: auto;
  display: flex;
  flex-direction: row-reverse;
  justify-content: center;
  align-items: center;
  gap: var(--space-6);
  padding-top: 3rem;
}

/* As wide as the panel above it, so the ask stays one line at desktop — the
   credit, the salary and the revenue share are one sentence. Where it must
   wrap, the lines share the words: a last word alone read as an afterthought. */
/* A 28px line, even like the 58px button it is centred on: at 27 it stood on
   a half pixel (2026-10-14). */
.marketing-hero__ask p {
  font-size: 1.0625rem;
  --lh: 1.65;
  max-width: 46rem;
  margin: 0;
  text-wrap: balance;
}

.marketing-hero__ask form {
  display: inline-block;
}

.marketing-hero__ask .marketing-cta {
  font-size: 1.0625rem;
  /* Wider than it is tall by a good margin: the presence comes from the plate
     and the lift, not from shouting in a bigger type. */
  padding: 1rem 2.25rem;
  margin-top: 0;
  /* Lifted off the picture. A flat rectangle on a photograph reads as a
     sticker; the glow is the accent's own hue, so the page still has one
     colour. */
  box-shadow:
    var(--clay-bevel),
    0 10px 24px -10px rgba(86, 110, 180, 0.65),
    0 2px 6px -2px rgba(15, 23, 42, 0.25);
  transition: background 120ms ease, transform 120ms ease, box-shadow 120ms ease;
}

/* Hover deepens the glow and stays put: a lift made the button jump under
   the cursor. */
.marketing-hero__ask .marketing-cta:hover {
  box-shadow:
    var(--clay-bevel),
    0 14px 30px -10px rgba(86, 110, 180, 0.72),
    0 3px 8px -2px rgba(15, 23, 42, 0.28);
}

/* Presses in rather than staying put: the one control on the cover should
   answer the finger. */
.marketing-hero__ask .marketing-cta:active {
  transform: translateY(1px);
  box-shadow: var(--clay-bevel), 0 6px 14px -8px rgba(86, 110, 180, 0.6);
}

@media (prefers-reduced-motion: reduce) {
  .marketing-cta,
  .marketing-hero__ask .marketing-cta { transition: background 120ms ease; }
}

/* Over the cover the topbar rides on the art: no plate, light ink. It scrolls
   away with the page, so there is nothing to fade back in. */

body:has(.marketing-hero--cover) .marketing-topbar {
  background: transparent;
  border-bottom-color: transparent;
}

body:has(.marketing-hero--cover) .marketing-topbar__nav a {
  color: rgba(255, 255, 255, 0.82);
}

body:has(.marketing-hero--cover) .marketing-topbar__nav a:hover {
  color: #fff;
}

/* On the art the clay turns to frosted glass: the picture shows through,
   the bevel keeps it a pressed pill rather than an outline. */
body:has(.marketing-hero--cover) .marketing-topbar__cta {
  color: #fff;
  background: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.4);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  text-shadow: 0 1px 1px rgba(15, 23, 42, 0.25);
  box-shadow:
    inset 0 2px 1px rgba(255, 255, 255, 0.35),
    inset 0 -4px 8px rgba(15, 23, 42, 0.18),
    0 6px 16px -8px rgba(15, 23, 42, 0.45);
}

body:has(.marketing-hero--cover) .marketing-topbar__cta:hover {
  background: rgba(255, 255, 255, 0.26);
  border-color: rgba(255, 255, 255, 0.7);
}

/* A section built on the floors' own two columns, so a page of alternating
   floors can carry a heading-plus-list block without changing grid. */

/* The line under a split's heading: without it the copy column is a heading
   and a hole beside a block several rows tall. */
.marketing-section .marketing-split__note {
  max-width: 22rem;
  margin-top: var(--space-3);
  font-size: 0.9375rem;
  --lh: 1.55;
  color: var(--text-muted);
}

/* A brand mark set in running text, where the sentence already names it.
   em again, and the optical nudge below the baseline that any mark needs
   beside lowercase. The gap is a word space, not a hair: this mark is a
   filled tile with no side bearing of its own, and tight against the S it
   read as one glued word. */
.marketing-inline-mark {
  width: round(1em, 1px);
  height: round(1em, 1px);
  vertical-align: round(-0.15em, 1px);
  margin-right: round(0.25em, 1px);
}

.marketing-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 38rem;
  gap: 3rem;
  align-items: start;
}

/* Collapses with the floors, and the rule sits here rather than with theirs:
   at equal specificity the later declaration wins, and this class is defined
   further down the sheet. */
@media (max-width: 64rem) {
  .marketing-split {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }
}

/* Inline links in the marketing prose. There was no rule for them at all, so
   every one on these pages — the FAQ's answers, the legal pages, this section's
   own note — came out in browser blue with a full underline: the one colour on
   the site that belongs to no palette. --accent-hover, because accent as TEXT
   is 4.1:1 and this is body copy. */

.marketing-section a:not(.marketing-cta) {
  color: var(--accent-hover);
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--accent-hover) 35%, transparent);
  text-underline-offset: round(0.15em, 1px);
  transition: color var(--dur-fast) ease, text-decoration-color var(--dur-fast) ease;
}

.marketing-section a:not(.marketing-cta):hover {
  color: var(--accent);
  text-decoration-color: currentColor;
}

/* Voices: a reel of testimonial cards before the FAQ. The form is the one a
   reader already recognises — card, stars, the business under
   it — so it is read as testimonials in a scroll-past; the discipline
   is in what it does not carry: no names, no portraits, no second colour.
   The stars are review gold, the colour a reader already reads as a rating.
   Each row is a scroller the reel controller drifts at a constant rate —
   eased, it would stop at every loop — and a finger swipes or holds. It runs
   the full width of the window, so the edges read as the window's and not as
   a box cutting cards off. */

.marketing-voices-reel {
  width: 100vw;
  margin: var(--space-8) calc(50% - 50vw) 0;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.marketing-section .marketing-voices {
  list-style: none;
  padding: 0;
  margin: 0;
  max-width: none;
  display: flex;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}

.marketing-section .marketing-voices::-webkit-scrollbar {
  display: none;
}

.marketing-voices-reel--narrow {
  display: none;
}

.marketing-section .marketing-voices + .marketing-voices {
  margin-top: var(--space-4);
}

/* A card the size of a review, not of a feature: under the table it is a
   coda, read in passing, and a smaller card lets a row carry more of them. */
.marketing-section .marketing-voice {
  width: 18rem;
  flex: none;
  margin: 0 var(--space-4) 0 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--bg-card);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius);
}

/* The mark hangs above the text as its own line rather than in front of the
   first word: hung into the margin it would need the card's padding to give
   it room, and a card with uneven padding reads as a mistake. */
.marketing-voice__quote {
  margin: 0;
  font-size: 1.0625rem;
  letter-spacing: -0.005em;
  --lh: 1.5;
  color: var(--text);
  text-wrap: pretty;
}

/* Five stars cut from one strip: the fill runs --stars steps of star + gap,
   the rest shows the empty colour through the same mask. */
.marketing-voice__stars {
  display: flex;
  gap: var(--space-1);
}

.marketing-voice__stars > img {
  width: 0.875rem;
  height: 0.875rem;
  object-fit: contain;
}

/* The star not given: the same clay, its colour taken out and faded back, so
   the row still reads as five places of which some are filled. */
.marketing-voice__stars > .is-off {
  filter: grayscale(1);
  opacity: 0.3;
}

.marketing-voice__who {
  margin-top: auto;
  padding-top: var(--space-2);
  font-size: 0.8125rem;
  --lh: 1.35;
  color: var(--text-muted);
}

@media (max-width: 56.25em) {
  .marketing-section .marketing-voice {
    width: 15rem;
    margin-right: var(--space-3);
  }

  .marketing-voices-reel--wide {
    display: none;
  }

  .marketing-voices-reel--narrow {
    display: block;
  }
}

/* Still, the reel is a strip the reader swipes through themselves: no drift,
   so no loop, and a card lands square. */
@media (prefers-reduced-motion: reduce) {
  .marketing-section .marketing-voices {
    scroll-snap-type: x mandatory;
  }

  .marketing-section .marketing-voice {
    scroll-snap-align: start;
  }

  .marketing-section .marketing-voice[inert] {
    display: none;
  }
}

/* FAQ: every answer in view, two columns of them beside a heading that stays
   put while they scroll. The split gives the questions the wider half here —
   the heading is two words and a line, the answers are the floor. A question
   is a small heading over its answer, the pair parted from the next by a
   hairline over it and air, not a box. */
/* The three claims' own thirds: the heading stands in the first, the two
   columns of questions under the second and third pictures' left edges. The
   price floor is the same split: the offer, then its terms. */
#faq.marketing-split,
.price.marketing-split { grid-template-columns: round(down, (100% - 5rem) / 3, 1px) round(down, (100% - 5rem) / 3, 1px) minmax(0, 1fr); gap: 2.5rem; }

#faq .marketing-split__side { position: sticky; top: calc(var(--marketing-bar) + 2rem); }

.faq {
  grid-column: span 2;
  display: grid;
  /* Halves on whole pixels, as the thirds above. */
  grid-template-columns: round(down, (100% - 2.5rem) / 2, 1px) minmax(0, 1fr);
  gap: var(--space-8) 2.5rem;
}

/* Pairs are parted by a hairline over each — except the first row, which
   has nothing above it to part from. */
.faq__item { padding-top: var(--space-4); border-top: 1px solid var(--hairline); }
.faq__item:nth-child(-n + 2) { padding-top: 0; border-top: 0; }

.marketing-section .faq__q {
  margin: 0 0 var(--space-2);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  --lh: 1.35;
  color: var(--text);
  text-wrap: balance;
}

.marketing-section .faq__a {
  margin: 0;
  font-size: 0.9375rem;
  --lh: 1.55;
  color: var(--text-muted);
  text-wrap: pretty;
}

@media (max-width: 64rem) {
  #faq.marketing-split,
  .price.marketing-split { grid-template-columns: minmax(0, 1fr); gap: var(--space-8); }
  #faq .marketing-split__side { position: static; }
  .faq { grid-column: auto; grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
  .faq__item:nth-child(2) { padding-top: var(--space-4); border-top: 1px solid var(--hairline); }
}

/* Legal documents — render Markdown via app/services/markdown_renderer.rb.
   The first section heading follows the preamble at the same distance every
   later one follows its section. */

/* A 40rem measure (about 80 characters at this size: a document, not a
   marketing column), the notes' 17rem column and the gap between. */
.legal-doc {
  max-width: 60rem;
  padding: 0 0 3rem;
  color: var(--text);
  --lh: 1.65;
}

.legal-doc h1,
.legal-doc h2,
.legal-doc h3 {
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--text);
  margin-top: 2.5rem;
  margin-bottom: 0.75rem;
}

.legal-doc h1 { font-size: 1.75rem; }
.legal-doc h2 { font-size: 1.375rem; }
.legal-doc h3 { font-size: 1.125rem; margin-top: 1.75rem; }

.legal-doc__intro { max-width: 40rem; }

.legal-doc__intro > :first-child { margin-top: 0; }

/* Full-strength ink: this is the text the reader came to read, and a policy
   set in the caption grey is a policy nobody reads. */
.legal-doc p,
.legal-doc ul,
.legal-doc ol {
  color: var(--text);
  margin-bottom: 1rem;
}

.legal-doc ul,
.legal-doc ol {
  padding-left: 1.5rem;
}

.legal-doc li {
  margin-bottom: 0.5rem;
}

.legal-doc strong {
  color: var(--text);
}

.legal-doc em {
  color: var(--text);
  font-style: italic;
}

.legal-doc hr {
  border: none;
  border-top: 1px solid var(--hairline);
  margin: 2.5rem 0;
}

.legal-doc table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.5rem 0;
}

.legal-doc th,
.legal-doc td {
  text-align: left;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--hairline);
  color: var(--text-muted);
}

.legal-doc th {
  color: var(--text);
  font-weight: 600;
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.legal-doc a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.legal-doc code {
  background: var(--bg-card);
  padding: round(0.1em, 1px) round(0.35em, 1px);
  border-radius: 0.25rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: round(0.9em, 1px);
  color: var(--text);
}

/* The sections are a grid: text down column one, the plain-words notes down
   column two. Every section is two rows, heading then body, numbered off the
   item's --i, so a note lands on its section's body row and starts level with
   the first paragraph; a row grows to the taller of text and note, so notes
   never overlap. The notes follow all the text in the DOM (see the view), so
   a selection stays in one column. */
.legal-doc__sections {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 17rem;
  column-gap: 3rem;
}

.legal-doc__heading { grid-column: 1; grid-row: calc(var(--i) * 2 + 1); }
.legal-doc__body    { grid-column: 1; grid-row: calc(var(--i) * 2 + 2); }
.legal-doc__note    { grid-column: 2; grid-row: calc(var(--i) * 2 + 2); }

/* The column's one label, in the first heading's row, sat on its floor so
   it stands just over the first note. */
.legal-doc__label {
  grid-column: 2;
  grid-row: 1;
  align-self: end;
  padding: 0 0 var(--space-2) calc(var(--space-4) + 2px);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* A section with no note beside it, such as an annex, takes the margin column
   as well: its table wants the room. Prose inside it keeps the document's
   measure, so only the table grows. */
.legal-doc__span { grid-column: 1 / -1; }

.legal-doc__body.legal-doc__span > :not(table) { max-width: 40rem; }

.legal-doc__note {
  align-self: start;
  margin-top: 0.125rem;
  padding-left: var(--space-4);
  border-left: 2px solid var(--hairline-strong);
  font-size: 0.875rem;
  --lh: 1.55;
  color: var(--text-muted);
}

.legal-doc__note blockquote,
.legal-doc__note p {
  margin: 0;
  color: inherit;
}

/* Narrow: one column, three rows a section, the note between heading and
   body as a tinted aside; the label goes with the column, and the first note
   carries it instead. */
@media (max-width: 56.25em) {
  .legal-doc__sections { grid-template-columns: minmax(0, 1fr); }

  .legal-doc__heading { grid-row: calc(var(--i) * 3 + 1); }
  .legal-doc__note    { grid-column: 1; grid-row: calc(var(--i) * 3 + 2); }
  .legal-doc__body    { grid-row: calc(var(--i) * 3 + 3); }

  .legal-doc__label { display: none; }

  .legal-doc__note {
    margin: 0 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-left: none;
    border-radius: var(--radius-sm);
    background: var(--bg-panel);
  }

  .legal-doc__note:first-of-type::before {
    content: "In plain words";
    display: block;
    margin-bottom: var(--space-1);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }
}


/* Marketing topbar actions + the lockup. */
.marketing-topbar__actions { margin-left: auto; }

/* The logo is one picture, the word on the clay tile; its height is in em
   so it scales with font-size across the marketing and app topbars. It
   overhangs the line, so a bar sized to text keeps its height. */
.marketing-logo {
  display: inline-flex;
  font-size: 0.9375rem;
  --lh: 1;
  text-decoration: none;
}

/* The width is worked from the file's own 283:120 and rounded down, the
   picture fitted inside: `width: auto` gave 56.59px, and everything after
   the logo in a bar stood on that fraction (2026-10-14). */
.marketing-logo__img {
  height: round(1.6em, 1px);
  width: round(down, 1.6em * 283 / 120, 1px);
  object-fit: contain;
  margin-block: round(-0.3em, 1px);
}


/* ===== Pricing (the landing's floor above the FAQ) =====
   Who ends up doing the work: the reader's pains down, what they would
   otherwise do across, each answer with a verdict, the cost in the last row. */
/* A floor like the others: the wrap's width, the heading on the left edge at
   the floors' size. A step more under it than a heading over prose takes:
   what follows is a table whose own head row sits close under it, and at two
   the question read as the table's caption rather than the floor's heading. */
#compare h2 { margin-bottom: var(--space-12); }

/* The same rows across every option; ours is one cobalt-tinted card running
   down the table, built from its cells so each row still lines up across. */
.versus__row {
  display: grid;
  /* Ours first, next to the pain it answers, and a little wider than the
     three it is weighed against. */
  --fr: calc((100% - 13.5rem) / 4.2);
  /* The shares rounded down and the last column taking what is left, so every
     column starts on a whole pixel (2026-10-14). */
  grid-template-columns: 13.5rem round(down, 1.2 * var(--fr), 1px) round(down, var(--fr), 1px) round(down, var(--fr), 1px) minmax(0, 1fr);
}

/* Every cell hangs from the row's top line, verdict on the first line of its
   words: centred, a one-line answer floated away from the pain it answers. */
.versus__row > span {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-4);
  font-size: 0.9375rem;
  --lh: 1.5;
  color: var(--text-muted);
}

.versus__text { text-wrap: pretty; }

.versus__row + .versus__row > span:not(.versus__us) {
  border-top: 1px solid var(--hairline);
}

/* The pain, in the reader's words, a step up and a touch heavier than the
   answers: it is the line the row is read from, and the lit column is still
   the loudest thing because it is the only colour. The stage sits over it in
   the smallest step, muted — the table's order made visible, not a heading. */
.versus__row > .versus__label {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
  padding-left: 0;
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  --lh: 1.3;
  color: var(--text);
  text-wrap: balance;
}

.versus__stage {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0;
  --lh: 1.2;
  color: var(--text-muted);
}

/* The price row stands apart from the verdicts: a heavier rule over it, and
   figures in ink, for the reader to weigh rather than be told. */
.versus__row.versus__row--price > span {
  border-top: 1.5px solid var(--hairline-strong);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.versus__row.versus__row--price > .versus__label {
  font-weight: 600;
}

/* No verdict on a price, but the figure starts where the answers' words do
   above it, so the column of text stays one column. Columns only: narrow,
   the text has a track of its own and needs no indent. */
@media (min-width: 52.01em) {
  .versus__row.versus__row--price > span:not(.versus__label) {
    padding-left: calc(var(--space-4) + 1.125rem + var(--space-2));
  }

  .versus__row.versus__row--price > span.versus__us {
    padding-left: calc(var(--space-6) + 1.125rem + var(--space-2));
  }
}

.versus__row > .versus__us {
  padding-inline: var(--space-6);
  background: var(--tint-chip);
  font-weight: 600;
  color: var(--text);
}

.versus__row + .versus__row > .versus__us {
  border-top: 1px solid rgb(86 110 180 / 0.14);
}

/* The options' names a step down from the pains: they are the columns, not
   the point. */
.versus__row--head > span {
  align-items: flex-end;
  padding-block: var(--space-4) var(--space-3);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text);
}

.versus__row--head > .versus__us {
  border-radius: var(--radius) var(--radius) 0 0;
}

/* The wordmark at the weight of the names beside it: a little taller than
   their marks, since it is a word and they are a glyph and a word. */
.versus__logo {
  height: 1.375rem;
  width: auto;
}

.versus__row--head > span:has(.versus__mark) {
  align-items: center;
  gap: var(--space-2);
}

/* The mark is the verdict's size, so a column's name starts where its
   answers do. */
.versus__mark {
  width: 1.125rem;
  height: 1.125rem;
}

.versus__row:last-child > .versus__us {
  border-radius: 0 0 var(--radius) var(--radius);
}

/* The verdict: a filled disc in the status colour it means — yes, partly,
   no — so the table reads by colour before a word of it is read. */
.verdict {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1.125rem;
  height: 1.125rem;
  margin-top: 0.125rem;
  border-radius: var(--radius-pill);
  color: #fff;
}

.verdict::after {
  content: "";
  width: 0.75rem;
  height: 0.75rem;
  background: currentColor;
  mask: var(--mark) center / contain no-repeat;
}

.verdict--yes  { background: var(--green); --mark: var(--mark-check); }
.verdict--no   { background: var(--red);   --mark: var(--mark-close); }
.verdict--part { background: var(--amber); }

.verdict--part::after {
  width: 0.5625rem;
  height: 2px;
  border-radius: 1px;
  mask: none;
}

/* Under a tablet the columns no longer fit: each row becomes its need over a
   list of answers, every answer named by its option, ours lit first. */
@media (max-width: 52em) {
  .versus__row { display: block; padding: var(--space-6) 0; }
  .versus__row.versus__row--head { display: none; }
  .versus__row + .versus__row { border-top: 1px solid var(--hairline); }
  .versus__row + .versus__row > span,
  .versus__row + .versus__row > span:not(.versus__us),
  .versus__row + .versus__row > .versus__us { border-top: 0; }
  .versus__row > span {
    display: grid;
    grid-template-columns: 5.5rem 1.25rem minmax(0, 1fr);
    padding: var(--space-2) 0;
  }
  /* The text keeps its own column whether or not a verdict sits before it. */
  .versus__text { grid-column: 3; }
  .versus__row > span::before {
    content: attr(data-col);
    font-weight: 600;
    color: var(--text);
  }
  .versus__row > .versus__label {
    display: flex;
    padding: 0 0 var(--space-3);
    font-size: 1.125rem;
  }
  .versus__row > .versus__label::before { content: none; }
  /* Ours leads each list: air under it, where the others begin. */
  .versus__row > .versus__us,
  .versus__row:last-child > .versus__us {
    margin: 0 calc(-1 * var(--space-3)) var(--space-2);
    padding: var(--space-3);
    border-radius: var(--radius-sm);
  }
}

/* Error pages (errors/show): one picture, the code's digits in clay with the
   scene on them, and the words centred under it. The picture is the page, so
   it takes the hero's air and most of the column; the words keep the hero's
   type at the measure a centred block can hold. */
.error-page {
  display: grid;
  justify-items: center;
  text-align: center;
  gap: var(--space-8);
  padding: 2rem 0 4rem;
}

/* As wide as the column allows and no taller than a bit under half the
   screen (16:9, so 80vh wide): the page is one screen, bar to button. */
.error-page__art {
  display: block;
  width: round(down, min(48rem, 100%, 80vh), 1px);
  height: auto;
}

.error-page__text {
  max-width: 36rem;
}

.error-page__text .marketing-hero__h1 {
  margin-bottom: 1rem;
}

/* The one press, centred under the words: the corner's own button, with
   the corner's own margin. */
.error-page__way {
  display: flex;
  justify-content: center;
  margin-top: var(--space-2);
}
