/* ═══════════════════════════════════════════════════════════════════════════
   GOODBUILD
   The whole design system for the site, in one file.
   ───────────────────────────────────────────────────────────────────────────
   Shaped after trillo.framer.ai, which Blake picked on 27 September: centred
   sections, a big geometric headline, soft rounded cards on a warm near-white,
   one hot accent, feature chips, a proof strip, a testimonial grid, a pricing
   toggle and an FAQ.

   WHAT WE TOOK FROM IT. The rhythm and the furniture. It is a well made
   template and the order it puts things in is right for a self serve product.

   WHAT WE DID NOT TAKE, AND WHY.
   * Its rainbow gradient blobs. One soft coral wash behind the product and
     nothing else, or we are back to the look Blake threw out in September.
   * "Trusted by 17,000 founders", "10 million users", and six testimonials
     from people who do not exist. We have three real quotes from three real
     named people and no user count. Inventing the rest is the one thing a
     product selling trust in recruitment must never do.
   * Its 20px corners. Softer than the platform on purpose, because a website
     is not a workspace, but 14 rather than 20.

   The one idea that is ours: a mark sits on top of things, because GoodBuild
   sits on top of the CRM an agency already has.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* Sampled out of the logo artwork itself rather than retyped from a doc.
     A site whose accent is a slightly different red from its own logo looks
     broken and nobody can say why, so there is one source and this is it. */
  --ink:      #0F0E13;
  --coral:    #E5494D;
  --paper:    #FBF7F4;

  /* THE MESH. Read off trillo.framer.ai on 27 September, where the panels are
     not flat washes but soft blooms of two or three warm hues fading into
     cream. That softness is most of why the template feels expensive, and it
     is the thing a flat linear-gradient cannot fake. These are the hues the
     blooms are built from; the recipes are further down. Our coral stays the
     brand colour and the flame is only ever a gradient stop, never a button,
     so nothing on the page competes with the logo. */
  --flame:    #FF5A33;
  --amber:    #FFA24D;
  --rose:     #F6B9BE;
  --lilac:    #CDBCE6;
  --cream:    #FBF1E8;

  --ink-soft: #4B4C54;
  --ink-faint:#63646C;
  --line:     #E9E4DC;
  --card:     #FFFFFF;
  --card-line:#EFEAE3;
  --coral-wash:#FCEBEB;
  --ink-wash: #0F0E13;

  --display: 'Outfit', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --body:    'Instrument Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px;
  --s6: 32px; --s7: 48px; --s8: 64px; --s9: 96px; --s10: 140px;

  /* Trillo is 16 almost everywhere, with 24 on the big slabs. We were on 14,
     which is a workspace radius, and it was quietly making the whole page
     read as an admin tool rather than a product someone wants. */
  --r:    20px;   /* cards */
  --r-lg: 28px;   /* slabs and bento blocks */
  --r-sm: 14px;   /* inputs */
  --r-pill: 999px;

  --wrap: 1180px;
  --read: 760px;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0; background: var(--paper); color: var(--ink);
  font-family: var(--body); font-size: 17px; line-height: 1.6;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img, svg, video { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
button { font: inherit; }
:focus-visible { outline: 3px solid var(--coral); outline-offset: 3px; border-radius: 4px; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ── layout ───────────────────────────────────────────────────────────── */
.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 var(--s5); }
.section { padding: var(--s9) 0; }
.section-sm { padding: var(--s8) 0; }

/* Trillo centres almost everything, and it is the right call for a page
   somebody scrolls rather than reads. */
.mid { text-align: center; }
.mid .lede, .mid .read { margin-left: auto; margin-right: auto; }
.read { max-width: var(--read); }

.band-ink { background: var(--ink-wash); color: var(--paper); }
.band-ink .eyebrow { color: rgba(240,239,234,.58); }
.band-ink .lede, .band-ink .muted { color: rgba(240,239,234,.76); }

/* ── type ─────────────────────────────────────────────────────────────── */
h1, h2, h3, h4 { font-family: var(--display); margin: 0; letter-spacing: -.03em; line-height: 1.06; font-weight: 600; }
.h-hero { font-size: clamp(42px, 6.4vw, 76px); letter-spacing: -.04em; line-height: 1.02; }
.h1     { font-size: clamp(30px, 4.2vw, 46px); }
.h2     { font-size: clamp(24px, 3vw, 34px); }
.h3     { font-size: clamp(19px, 2vw, 22px); letter-spacing: -.02em; }

.eyebrow {
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase; color: var(--ink-faint);
  margin: 0 0 var(--s4);
}
.lede { font-size: clamp(17px, 1.9vw, 19.5px); line-height: 1.62; color: var(--ink-soft); margin: var(--s5) 0 0; max-width: 60ch; }
.muted { color: var(--ink-soft); }
.small { font-size: 14.5px; }
p { margin: var(--s4) 0 0; }
.dot { color: var(--coral); }

/* ── buttons ──────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  font-family: var(--body); font-size: 16px; font-weight: 600;
  padding: 14px 26px; border-radius: var(--r-sm);
  text-decoration: none; cursor: pointer; border: 1px solid transparent;
  transition: transform .12s ease, background-color .12s ease, border-color .12s ease;
}
.btn:active { transform: translateY(1px); }
/* Flat, and no coloured drop shadow under it. That shadow is the single most
   recognisable tell of a generated interface. */
.btn-primary { background: var(--coral); color: #fff; }
.btn-primary:hover { background: #CF3B3F; }
.btn-ghost { background: var(--card); color: var(--ink); border-color: var(--card-line); }
.btn-ghost:hover { border-color: var(--ink); }
.band-ink .btn-ghost { background: transparent; color: var(--paper); border-color: rgba(240,239,234,.26); }
.band-ink .btn-ghost:hover { border-color: var(--paper); }
.btn-lg { font-size: 17px; padding: 17px 32px; }
.btns { display: flex; flex-wrap: wrap; gap: var(--s3); margin-top: var(--s6); }
.mid .btns { justify-content: center; }

/* ── header ───────────────────────────────────────────────────────────── */
.hdr {
  position: sticky; top: 0; z-index: 50;
  background: rgba(240,239,234,.86);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid transparent; transition: border-color .2s ease;
}
.hdr.scrolled { border-bottom-color: var(--line); }
.hdr-in { display: flex; align-items: center; height: 78px; gap: var(--s5); }
.hdr-logo { display: flex; align-items: center; text-decoration: none; }
.hdr-logo img { height: 29px; width: auto; }
/* Nav in the middle, the way Trillo has it. */
.nav { display: flex; align-items: center; gap: var(--s6); margin: 0 auto; }
.nav a { text-decoration: none; font-size: 15.5px; font-weight: 500; color: var(--ink-soft); padding: 6px 0; position: relative; }
.nav a:hover { color: var(--ink); }
.nav a[aria-current="page"] { color: var(--ink); }
.nav a[aria-current="page"]::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--coral); border-radius: 2px; }
.hdr-cta { display: flex; align-items: center; gap: var(--s3); }
.hdr-cta .btn { padding: 11px 20px; font-size: 15px; }
.burger { display: none; background: none; border: 0; padding: 8px; cursor: pointer; color: var(--ink); }

/* 959px, not 900px.
   The nav hid at 900 but the seven links, the logo and the three controls do
   not fit inside the 1080px pill until 960, so from 901 to 959 the coral
   trial button hung up to 24px out past the pill's rounded right edge with
   the white edge showing behind it. A narrow band, which is why nobody had
   caught it: it is a part-width desktop window, not a phone and not a full
   screen.

   The number was swept, not guessed, and swept with the site's own fonts
   loaded. An earlier pass at this measured 1020 because the guard could not
   reach Google Fonts and was measuring the page in a system fallback whose
   letterforms are wider than Outfit and Instrument Sans. That is the whole
   reason the fonts are now served from assets/fonts: a guard that renders
   in the wrong typeface reports on a page nobody sees.

   Every rule that hides or reveals a header control keys off this same
   number, and tools/header-fit-check fails if they drift apart. */
@media (max-width: 959px) {
  .nav, .hdr-cta .btn-ghost { display: none; }
  /* The trial button was wrapping onto two lines and walking into the logo. */
  .hdr-in { gap: var(--s3); height: 68px; }
  .hdr-logo img { height: 28px; }
  .hdr-cta .btn { white-space: nowrap; padding: 10px 15px; font-size: 14.5px; }
  .hdr.open .nav { top: 68px; }
  .burger { display: block; margin-left: auto; }
  .hdr.open .nav {
    display: flex; flex-direction: column; align-items: flex-start; gap: var(--s4);
    position: absolute; top: 78px; left: 0; right: 0; margin: 0;
    background: var(--paper); border-bottom: 1px solid var(--line); padding: var(--s5);
  }
}

/* ── chips: the little row of promises under the hero ─────────────────── */
.chips {
  display: inline-flex; flex-wrap: wrap; justify-content: center; gap: var(--s1);
  background: var(--card); border: 1px solid var(--card-line);
  border-radius: var(--r-pill); padding: var(--s1); margin-top: var(--s7);
}
.chip {
  display: inline-flex; align-items: center; gap: var(--s2);
  padding: 9px 18px; border-radius: var(--r-pill);
  font-size: 14.5px; font-weight: 500; color: var(--ink-soft);
}
.chip.on { background: var(--paper); color: var(--ink); font-weight: 600; }
.chip svg { width: 15px; height: 15px; color: var(--coral); flex: none; }
@media (max-width: 720px) {
  .chips { border-radius: var(--r); flex-direction: column; align-items: stretch; }
}

/* ── the hero product, with the mark looking over it ────────────────── */
.clip { overflow: hidden; }
.perch { position: relative; margin-top: var(--s8); }
/* One soft coral wash behind the card. Not four gradient blobs. */
.perch::before {
  content: ''; position: absolute; inset: 12% -8% -6% -8%; z-index: 0;
  background: radial-gradient(60% 70% at 50% 40%, rgba(229,73,77,.16), rgba(229,73,77,0) 70%);
  filter: blur(18px); pointer-events: none;
}
.perch-mark {
  position: absolute; bottom: 100%; right: 8%;
  margin-bottom: -1px; width: 128px; z-index: 2; pointer-events: none;
}
.perch-shot {
  position: relative; z-index: 1;
  border: 1px solid var(--card-line); border-radius: var(--r);
  background: var(--card); overflow: hidden; text-align: left;
  box-shadow: 0 1px 2px rgba(20,19,24,.04), 0 24px 60px rgba(20,19,24,.08);
}
@media (max-width: 700px) { .perch-mark { width: 88px; right: 6%; } }

.fl-bar { display: flex; align-items: center; gap: 6px; padding: 12px var(--s5); border-bottom: 1px solid var(--card-line); background: #FAF9F5; }
.fl-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--line); }
.fl-url { margin-left: var(--s4); font-family: var(--mono); font-size: 11.5px; color: var(--ink-faint); }
.fl-body { padding: var(--s7); }
@media (max-width: 640px) { .fl-body { padding: var(--s5); } }
.fl-people { margin-top: var(--s6); border-top: 1px solid var(--card-line); }
.fl-p { padding: var(--s4) 0; border-bottom: 1px solid var(--card-line); }
.fl-p-n { font-family: var(--display); font-size: 17px; font-weight: 500; display: flex; align-items: baseline; gap: 10px; }
.fl-p-s { font-family: var(--mono); font-size: 11.5px; font-weight: 500; color: var(--coral); font-variant-numeric: tabular-nums; }
.fl-p-t { font-size: 13px; color: var(--ink-faint); margin-top: 3px; }
.fl-p-r { font-size: 14.5px; line-height: 1.55; margin-top: 7px; color: var(--ink-soft); }

/* ── the proof strip ──────────────────────────────────────────────────────
   Trillo puts a row of client logos here. We do not have seventeen thousand
   founders, and painting some on would be the exact opposite of what this
   product sells. Three true numbers instead. */

/* ── cards and grids ──────────────────────────────────────────────────── */
.card { background: var(--card); border: 1px solid var(--card-line); border-radius: var(--r); padding: var(--s6); }
.grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s4); margin-top: var(--s7); text-align: left; }
.grid2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s5); margin-top: var(--s7); text-align: left; }
@media (max-width: 900px) { .grid3, .grid2 { grid-template-columns: 1fr; } }

.feat h3 { margin-bottom: var(--s3); }
.feat p { color: var(--ink-soft); font-size: 15.5px; margin-top: 0; }
.feat-i {
  width: 40px; height: 40px; border-radius: var(--r-sm);
  background: var(--coral-wash); color: var(--coral);
  display: grid; place-items: center; margin-bottom: var(--s5);
}
.feat-i svg { width: 20px; height: 20px; }

/* ── numbered steps ───────────────────────────────────────────────────── */
.steps { display: grid; gap: var(--s4); margin-top: var(--s7); text-align: left; grid-template-columns: repeat(4, 1fr); }
.step { background: var(--card); border: 1px solid var(--card-line); border-radius: var(--r); padding: var(--s6); }
.step-n { font-family: var(--mono); font-size: 12px; font-weight: 500; color: var(--coral); letter-spacing: .08em; margin-bottom: var(--s4); }
.step h3 { margin-bottom: var(--s3); }
.step p { color: var(--ink-soft); font-size: 15px; margin-top: 0; }
@media (max-width: 1000px) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .steps { grid-template-columns: 1fr; } }

/* ── testimonials ─────────────────────────────────────────────────────── */
.tgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s4); margin-top: var(--s7); text-align: left; }
@media (max-width: 980px) { .tgrid { grid-template-columns: 1fr; } }
.tcard { background: var(--card); border: 1px solid var(--card-line); border-radius: var(--r); padding: var(--s6); display: flex; flex-direction: column; }
.tcard-q { font-size: 16px; line-height: 1.62; color: var(--ink); margin: 0 0 var(--s5); flex: 1; }
.tcard-w { font-size: 14px; color: var(--ink-faint); }
.tcard-w b { display: block; color: var(--ink); font-size: 15px; font-weight: 600; }
.tcard-mark { color: var(--coral); font-family: var(--display); font-size: 30px; line-height: 1; margin-bottom: var(--s3); }

/* ── pricing ──────────────────────────────────────────────────────────── */
.toggle { display: inline-flex; align-items: center; gap: var(--s3); margin-top: var(--s6); font-size: 15px; }
.toggle-sw { width: 50px; height: 28px; border-radius: var(--r-pill); background: var(--ink); border: 0; position: relative; cursor: pointer; padding: 0; }
.toggle-sw::after { content: ''; position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: #fff; transition: transform .16s ease; }
.toggle-sw[aria-checked="true"]::after { transform: translateX(22px); }
.save { background: var(--coral-wash); color: var(--coral); font-size: 12px; font-weight: 700; padding: 5px 10px; border-radius: var(--r-pill); letter-spacing: .04em; }

.prices { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s4); margin-top: var(--s7); text-align: left; max-width: 900px; margin-inline: auto; }
@media (max-width: 820px) { .prices { grid-template-columns: 1fr; } }
.price { background: var(--card); border: 1px solid var(--card-line); border-radius: var(--r); padding: var(--s7); position: relative; }
.price.hot { border-color: var(--coral); }
.price-tag { position: absolute; top: var(--s5); right: var(--s5); background: var(--coral); color: #fff; font-size: 12px; font-weight: 700; padding: 5px 12px; border-radius: var(--r-pill); }
.price-n { font-family: var(--display); font-size: 46px; font-weight: 600; letter-spacing: -.04em; margin: var(--s5) 0 0; }
.price-n span { font-family: var(--body); font-size: 16px; font-weight: 500; color: var(--ink-faint); letter-spacing: 0; }
.price ul { list-style: none; margin: var(--s6) 0 0; padding: var(--s6) 0 0; border-top: 1px solid var(--card-line); display: grid; gap: var(--s3); }
.price li { display: flex; gap: var(--s3); font-size: 15.5px; color: var(--ink-soft); }
.price li svg { width: 17px; height: 17px; color: var(--coral); flex: none; margin-top: 3px; }
.price .btn { width: 100%; margin-top: var(--s6); }

/* ── faq ──────────────────────────────────────────────────────────────── */
.faq { max-width: 820px; margin: var(--s7) auto 0; text-align: left; }
.faq details { background: var(--card); border: 1px solid var(--card-line); border-radius: var(--r); margin-bottom: var(--s3); }
.faq summary {
  cursor: pointer; list-style: none; padding: var(--s5) var(--s6);
  font-family: var(--display); font-size: 18px; font-weight: 500; letter-spacing: -.015em;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: '+'; font-family: var(--display); font-size: 24px; color: var(--coral); line-height: 1; flex: none; }
.faq details[open] summary::after { content: '\2013'; }
.faq p { margin: 0; padding: 0 var(--s6) var(--s6); color: var(--ink-soft); font-size: 16px; }

/* ── closing call to action ───────────────────────────────────────────── */
.cta { text-align: center; padding: var(--s10) 0; }
.cta .h1 { max-width: 20ch; margin: 0 auto; }

/* ── footer ───────────────────────────────────────────────────────────── */
.ftr { border-top: 1px solid var(--line); padding: var(--s8) 0 var(--s7); }
.ftr-in { display: grid; grid-template-columns: 1.7fr repeat(3, 1fr); gap: var(--s6); }
.ftr h4 { font-family: var(--body); font-size: 12px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: var(--s4); }
.ftr ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s3); }
.ftr a { text-decoration: none; font-size: 15px; color: var(--ink-soft); }
.ftr a:hover { color: var(--ink); }
.ftr-logo img { height: 30px; width: auto; }
.ftr-legal { margin-top: var(--s8); padding-top: var(--s5); border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: var(--s5); font-size: 13.5px; color: var(--ink-faint); }
@media (max-width: 860px) { .ftr-in { grid-template-columns: 1fr 1fr; } }

/* ── things arrive rather than appear ─────────────────────────────────── */
.rise { opacity: 0; transform: translateY(16px); transition: opacity .6s ease, transform .6s ease; }
.rise.in { opacity: 1; transform: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE PLATFORM, DRAWN RATHER THAN PHOTOGRAPHED
   ───────────────────────────────────────────────────────────────────────────
   Blake asked for the product at the top of the page, with Trillo's moving
   panels. A screenshot cannot do the second half: the whole effect there is
   that the interface comes apart into layers that travel at different speeds.
   A PNG is one layer.

   So this is the real dashboard rebuilt in markup, off the render at
   realdash.html on 27 September, in the GoodBuild palette. It is sharp on every
   screen, it weighs about nine kilobytes instead of two megabytes, and the
   cards on top of it can drift.

   It carries real figures only. Nothing here is a number we would not stand
   behind in a meeting.
   ═══════════════════════════════════════════════════════════════════════ */

/* On a phone the whole dashboard shrunk to about a third and became a grey
   smudge. Below 620 it stops shrinking and the window crops instead: you see
   the rail and the first figures at a size you can actually read, which is
   what a window onto a piece of software should look like. */
@media (max-width: 700px) { .app-frame { aspect-ratio: 360 / 470 !important; } }
.app-frame {
  position: relative; width: 100%; aspect-ratio: 1130 / 952;
  overflow: hidden; background: #FBFAF7;
}
/* Built once at a fixed size and scaled to fit. Every inner measurement is a
   whole pixel at 1130, which is why the type is even rather than smeared.
   If the script never runs the scale stays 1, and at the desktop width the
   frame is 1132 wide, so the untouched page is right anyway. */
.app {
  position: absolute; top: 0; left: 0; width: 1130px; height: 952px;
  transform: scale(var(--as, 1)); transform-origin: top left;
  display: grid; grid-template-columns: 196px 1fr;
  font-size: 13px; line-height: 1.45; text-align: left; color: var(--ink);
  background: #FBFAF7;
}

/* ── the rail ─────────────────────────────────────────────────────────── */
.ap-side { background: #fff; border-right: 1px solid #ECE9E1; padding: 16px 12px; display: flex; flex-direction: column; }
.ap-brand { display: flex; align-items: center; gap: 8px; padding: 2px 6px 18px; }
.ap-brand img { height: 22px; width: auto; }
.ap-grp { font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: #A8A49B; padding: 12px 8px 6px; }
.ap-nav { display: flex; align-items: center; gap: 9px; padding: 8px 9px; border-radius: 8px; color: #55565E; font-size: 13px; font-weight: 500; }
.ap-nav svg { width: 15px; height: 15px; stroke-width: 1.9; flex: none; opacity: .8; }
.ap-nav.on { background: #F4F2EC; color: var(--ink); font-weight: 600; position: relative; }
.ap-nav.on::before { content: ''; position: absolute; left: -12px; top: 8px; bottom: 8px; width: 3px; border-radius: 0 3px 3px 0; background: var(--coral); }
/* The Trust Layer sits in its own block in the product because it is the one
   thing on the rail an agency is buying rather than using. Same here. */
.ap-trust { margin-top: 14px; border-radius: 10px; padding: 10px 11px; background: linear-gradient(135deg, #1B1A20, #2E1D22 70%, #45222A); color: #fff; }
.ap-trust b { display: block; font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: rgba(255,255,255,.62); font-weight: 500; }
.ap-trust span { display: flex; align-items: center; gap: 8px; margin-top: 7px; font-size: 13px; font-weight: 500; }
.ap-trust svg { width: 15px; height: 15px; stroke-width: 1.9; color: var(--coral); }
.ap-side-foot { margin-top: auto; padding: 10px 8px 0; border-top: 1px solid #ECE9E1; font-size: 12px; font-weight: 600; color: #55565E; }

/* ── the top bar ──────────────────────────────────────────────────────── */
.ap-main { display: flex; flex-direction: column; min-width: 0; }
.ap-top { display: flex; align-items: center; gap: 14px; padding: 12px 22px; border-bottom: 1px solid #ECE9E1; background: #fff; }
.ap-ask { flex: 1; background: #F6F4EF; border: 1px solid #ECE9E1; border-radius: 8px; padding: 9px 13px; font-size: 12.5px; color: #9A968D; }
.ap-who { display: flex; align-items: center; gap: 8px; background: #F6F4EF; border: 1px solid #ECE9E1; border-radius: 999px; padding: 4px 12px 4px 4px; font-size: 12.5px; font-weight: 600; }
.ap-av { width: 24px; height: 24px; border-radius: 50%; background: var(--coral); color: #fff; display: grid; place-items: center; font-size: 10px; font-weight: 700; letter-spacing: .02em; }

.ap-body { padding: 20px 22px; overflow: hidden; }
.ap-h { font-family: var(--display); font-size: 27px; font-weight: 600; letter-spacing: -.03em; line-height: 1.1; }
.ap-sub { font-size: 12.5px; color: #86878F; margin-top: 3px; }

.ap-bar { display: flex; align-items: center; gap: 8px; margin: 16px 0 12px; }
.ap-lab { font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: #A8A49B; margin-right: 4px; }
.ap-pill { border: 1px solid #E4E0D7; background: #fff; border-radius: 999px; padding: 5px 14px; font-size: 12px; font-weight: 500; color: #55565E; }
.ap-pill.on { border-color: var(--ink); color: var(--ink); font-weight: 600; }
.ap-auto-pill { margin-left: auto; display: flex; align-items: center; gap: 8px; background: #fff; border: 1px solid #E4E0D7; border-radius: 999px; padding: 4px 6px 4px 14px; font-size: 12px; font-weight: 500; }
.ap-sw { width: 30px; height: 17px; border-radius: 999px; background: var(--coral); position: relative; }
.ap-sw::after { content: ''; position: absolute; top: 2.5px; right: 2.5px; width: 12px; height: 12px; border-radius: 50%; background: #fff; }

/* ── the eight figures ────────────────────────────────────────────────── */
.ap-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 9px; }
.ap-stat { position: relative; background: #fff; border: 1px solid #ECE9E1; border-radius: 10px; padding: 11px 13px 26px; overflow: hidden; }
.ap-stat i { display: block; font-style: normal; font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; color: #A8A49B; }
.ap-n { font-family: var(--display); font-size: 27px; font-weight: 700; letter-spacing: -.035em; line-height: 1.1; margin-top: 8px; display: flex; align-items: baseline; gap: 7px; font-variant-numeric: tabular-nums; }
.ap-n em { font-style: normal; font-family: var(--body); font-size: 11.5px; font-weight: 500; letter-spacing: 0; color: #9A968D; }
.ap-n b { font-family: var(--body); font-size: 10.5px; font-weight: 600; letter-spacing: 0; background: var(--coral-wash); color: #C43B3F; padding: 3px 8px; border-radius: 999px; }
.ap-spark { position: absolute; left: 0; right: 0; bottom: 0; height: 30px; }
.ap-spark svg { width: 100%; height: 100%; display: block; }
/* The one card that carries the money is the one card that carries the colour.
   The figure inside it is white on coral and reads at 4.9 to 1; the platform
   had this exact card print its number in the page's text colour on a dark
   gradient once, at 1.00 to 1, and it was invisible for a week. */
.ap-stat.hot { background: linear-gradient(140deg, #E5494D, #C4363C); border-color: #C4363C; color: #fff; }
.ap-stat.hot i { color: rgba(255,255,255,.72); }
.ap-stat.hot .ap-n { color: #fff; }
.ap-stat.hot .ap-n em { color: rgba(255,255,255,.76); }

/* ── the two panels ───────────────────────────────────────────────────── */
.ap-two { display: grid; grid-template-columns: 1.55fr 1fr; gap: 9px; margin-top: 9px; }
.ap-card { background: #fff; border: 1px solid #ECE9E1; border-radius: 10px; padding: 13px 15px; }
.ap-card > h4 { font-family: var(--display); font-size: 15px; font-weight: 600; letter-spacing: -.02em; }
.ap-row { display: flex; align-items: center; gap: 11px; padding: 10px 0; border-top: 1px solid #F2EFE8; }
.ap-row:first-of-type { border-top: 0; padding-top: 12px; }
.ap-box { width: 15px; height: 15px; border-radius: 4px; border: 1.5px solid #DCD8CE; flex: none; }
.ap-row div { min-width: 0; flex: 1; }
.ap-row strong { display: block; font-size: 12.5px; font-weight: 600; }
.ap-row span { display: block; font-size: 11.5px; color: #9A968D; margin-top: 1px; }
.ap-btn { border: 1px solid #E4E0D7; border-radius: 7px; padding: 5px 13px; font-size: 11.5px; font-weight: 600; background: #fff; flex: none; }

.ap-handled { background: linear-gradient(165deg, #FDF4F1, #FBEDEB); border: 1px solid #F3DCD9; border-radius: 10px; padding: 13px 15px; }
.ap-handled .ap-lab { display: flex; align-items: center; gap: 6px; margin: 0 0 8px; color: #B4514F; }
.ap-handled .ap-lab::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--coral); }
.ap-handled h4 { font-family: var(--display); font-size: 15px; font-weight: 600; letter-spacing: -.02em; line-height: 1.24; }
.ap-fact { display: flex; align-items: baseline; gap: 11px; padding: 8px 0; border-top: 1px solid rgba(196,59,63,.14); margin-top: 8px; }
.ap-fact b { font-family: var(--display); font-size: 19px; font-weight: 700; letter-spacing: -.03em; min-width: 22px; font-variant-numeric: tabular-nums; }
.ap-fact b.hot { color: var(--coral); }
.ap-fact span { font-size: 12px; color: #6B5D5C; }

/* ── the pipeline ─────────────────────────────────────────────────────── */
.ap-pipe { background: #fff; border: 1px solid #ECE9E1; border-radius: 10px; margin-top: 9px; overflow: hidden; }
.ap-pipe-h { display: flex; align-items: center; gap: 10px; padding: 11px 15px; }
.ap-pipe-h .ap-lab { margin: 0; }
.ap-pipe-h em { font-style: normal; font-size: 12px; color: #86878F; }
.ap-go { margin-left: auto; background: var(--coral); color: #fff; border-radius: 7px; padding: 6px 15px; font-size: 11.5px; font-weight: 600; }
.ap-steps { display: grid; grid-template-columns: repeat(7, 1fr); border-top: 1px solid #ECE9E1; }
.ap-st { padding: 10px 13px; border-left: 1px solid #F2EFE8; }
.ap-st:first-child { border-left: 0; }
.ap-st.on { border-bottom: 2px solid var(--ink); }
.ap-st b { display: block; font-family: var(--display); font-size: 19px; font-weight: 700; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.ap-st u { display: block; text-decoration: none; font-size: 11.5px; font-weight: 600; margin-top: 2px; }
.ap-st i { display: block; font-style: normal; font-size: 10.5px; color: #A8A49B; }
.ap-th { display: grid; grid-template-columns: 1fr 96px 62px 62px 62px; gap: 10px; padding: 9px 15px 5px; border-top: 1px solid #ECE9E1; font-family: var(--mono); font-size: 9px; letter-spacing: .12em; text-transform: uppercase; color: #B4B0A7; }
.ap-th span { text-align: right; }
.ap-th span:first-child, .ap-th span:nth-child(2) { text-align: left; }
.ap-th + .ap-tr { border-top: 0; }
.ap-tr { display: grid; grid-template-columns: 1fr 96px 62px 62px 62px; align-items: center; gap: 10px; padding: 9px 15px; border-top: 1px solid #F2EFE8; font-variant-numeric: tabular-nums; }
.ap-tr .who { display: flex; align-items: center; gap: 9px; min-width: 0; }
.ap-sq { width: 26px; height: 26px; border-radius: 7px; display: grid; place-items: center; font-size: 9.5px; font-weight: 700; color: #fff; flex: none; letter-spacing: .02em; }
.ap-tr strong { display: block; font-size: 12.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ap-tr small { display: block; font-size: 11px; color: #A8A49B; }
.ap-tag { border: 1px solid #D7E4DA; color: #2F6B45; background: #F3F9F5; border-radius: 999px; padding: 3px 10px; font-size: 10.5px; font-weight: 600; justify-self: start; }
.ap-tag.out { border-color: #F0D9D8; color: #B4413F; background: #FDF3F2; }
.ap-tr span { text-align: right; font-size: 12.5px; font-weight: 600; }
.ap-tr span.q { color: #C6C2B9; font-weight: 500; }

/* ── the cards that float over the product ────────────────────────────── */
.perch-stack { position: relative; }
.float {
  position: absolute; z-index: 3; width: 268px; text-align: left;
  background: #fff; border: 1px solid var(--card-line); border-radius: 12px;
  padding: 13px 15px; box-shadow: 0 2px 4px rgba(20,19,24,.04), 0 18px 44px rgba(20,19,24,.13);
  will-change: transform;
}
.float-h { display: flex; align-items: center; gap: 8px; font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); }
.float-h svg { width: 14px; height: 14px; color: var(--coral); stroke-width: 2.2; flex: none; }
.float-b { font-family: var(--display); font-size: 16px; font-weight: 600; letter-spacing: -.02em; line-height: 1.3; margin-top: 8px; }
.float-s { font-size: 12.5px; color: var(--ink-soft); margin-top: 5px; line-height: 1.45; }
.float-score { display: flex; align-items: center; gap: 10px; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--card-line); }
.float-score b { font-family: var(--mono); font-size: 12px; font-weight: 500; color: #fff; background: var(--coral); border-radius: 7px; padding: 5px 9px; font-variant-numeric: tabular-nums; }
.float-score span { font-size: 12px; color: var(--ink-soft); }
.f-1 { top: 58%; left: -96px; }
.f-2 { bottom: 30%; right: -104px; }
.f-3 { bottom: -74px; left: 26%; width: 246px; }
/* Under about 1180 there is no gutter left for a card to hang in, so they stop
   hanging. They are decoration; the product behind them is the point. */
@media (max-width: 1320px) { .f-1 { left: -34px; } .f-2 { right: -34px; } }
@media (max-width: 1080px) { .f-1, .f-2, .f-3 { display: none; } }
@media (max-width: 860px)  { .float { display: none; } }

/* ── the alternating panels ───────────────────────────────────────────────
   Trillo's spine: a wide gradient block with a piece of interface floating in
   it, text beside it, and the side swapping each time. Ours are the same shape
   in one family of colour. The template's are a different hue every section,
   which on a product selling seriousness reads as a demo. */
.alt { display: grid; grid-template-columns: 1fr 1.08fr; gap: var(--s8); align-items: center; text-align: left; }
.alt > * { min-width: 0; }
.alt + .alt { margin-top: var(--s9); }
.alt.rev { grid-template-columns: 1.08fr 1fr; }
.alt.rev .alt-copy { order: 2; }
.alt.rev .alt-panel { order: 1; }
@media (max-width: 940px) {
  .alt, .alt.rev { grid-template-columns: 1fr; gap: var(--s6); }
  .alt.rev .alt-copy, .alt.rev .alt-panel { order: 0; }
  .alt + .alt { margin-top: var(--s8); }
}
.alt-copy .h2 { margin-top: var(--s3); }
.alt-copy .lede { margin-top: var(--s4); font-size: 16.5px; }
.alt-list { list-style: none; margin: var(--s5) 0 0; padding: 0; display: grid; gap: var(--s3); }
.alt-list li { display: flex; gap: var(--s3); font-size: 15px; color: var(--ink-soft); }
.alt-list svg { width: 16px; height: 16px; color: var(--coral); flex: none; margin-top: 3px; stroke-width: 2.6; }

.alt-panel {
  position: relative; border-radius: 20px; padding: var(--s7);
  overflow: hidden; isolation: isolate;
  min-height: 360px; display: grid; place-items: center;
}
.alt-panel.g-coral { background: linear-gradient(150deg, #FBE3E0 0%, #F7D8D8 40%, #F3E9DF 100%); }
.alt-panel.g-ink   { background: linear-gradient(150deg, #201F26 0%, #2C1F26 50%, #3E232B 100%); }
.alt-panel.g-paper { background: linear-gradient(150deg, #E7E4D9 0%, #F3E4DD 55%, #F8DBD6 100%); }
/* One grain layer so a flat gradient does not look like a placeholder. */
.alt-panel::after {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: .5;
  background: radial-gradient(48% 60% at 78% 14%, rgba(255,255,255,.62), transparent 68%);
}
.alt-panel.g-ink::after { background: radial-gradient(48% 60% at 78% 14%, rgba(229,73,77,.3), transparent 68%); }
@media (max-width: 640px) { .alt-panel { padding: var(--s5); min-height: 0; border-radius: 16px; } }

/* The interface inside the panel. Fixed width, scaled to fit, same trick as
   the hero, so a 380 pixel design stays a 380 pixel design. */
.ui-fit { width: 100%; max-width: 380px; min-width: 0; position: relative; margin-inline: auto; }
.ui { width: 380px; transform: scale(var(--us, 1)); transform-origin: top left; }
.ui-card { background: #fff; border: 1px solid #EDEAE2; border-radius: 12px; padding: 14px 16px; box-shadow: 0 1px 2px rgba(20,19,24,.04), 0 14px 36px rgba(20,19,24,.1); text-align: left; }
.ui-card + .ui-card { margin-top: 10px; }
.ui-h { font-family: var(--display); font-size: 15px; font-weight: 600; letter-spacing: -.02em; }
.ui-p { font-size: 12.5px; color: var(--ink-soft); margin-top: 4px; line-height: 1.45; }
.ui-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; margin-top: 12px; }
.ui-3 div { border: 1px solid #EDEAE2; border-radius: 8px; padding: 8px 9px; }
.ui-3 b { display: block; font-family: var(--display); font-size: 17px; font-weight: 700; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.ui-3 i { display: block; font-style: normal; font-size: 10px; color: #9A968D; margin-top: 1px; }
.ui-3 div:last-child { background: var(--coral-wash); border-color: #F3DCD9; }
.ui-3 div:last-child b { color: var(--coral); }
.ui-bar { height: 4px; border-radius: 4px; background: #EFECE4; margin-top: 11px; overflow: hidden; }
.ui-bar span { display: block; height: 100%; width: 63%; border-radius: 4px; background: var(--coral); }
.ui-per { display: flex; align-items: flex-start; gap: 10px; padding: 9px 0; border-top: 1px solid #F2EFE8; }
.ui-per:first-of-type { border-top: 0; }
.ui-sc { font-family: var(--mono); font-size: 11.5px; font-weight: 500; color: #fff; background: var(--coral); border-radius: 7px; padding: 5px 8px; flex: none; font-variant-numeric: tabular-nums; }
.ui-sc.b2 { background: #EC6A6D; } .ui-sc.b3 { background: var(--coral-wash); color: #C43B3F; }
.ui-per strong { display: block; font-size: 12.5px; font-weight: 600; }
.ui-per em { display: block; font-style: normal; font-size: 11px; color: #9A968D; margin-top: 1px; }
.ui-per p { margin: 4px 0 0; font-size: 11.5px; color: var(--ink-soft); line-height: 1.4; }
.ui-line { display: flex; align-items: center; gap: 9px; padding: 8px 0; border-top: 1px solid #F2EFE8; font-size: 12.5px; }
.ui-line:first-of-type { border-top: 0; }
.ui-line svg { width: 15px; height: 15px; flex: none; stroke-width: 2.4; }
.ui-line .ok { color: #2F6B45; } .ui-line .no { color: var(--coral); } .ui-line .wait { color: #B99A3E; }
.ui-line b { margin-left: auto; font-family: var(--mono); font-size: 10.5px; font-weight: 500; color: #A8A49B; }
.ui-quiet { display: flex; align-items: center; gap: 9px; padding: 8px 0; border-top: 1px solid #F2EFE8; }
.ui-quiet:first-of-type { border-top: 0; }
.ui-dot { width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center; font-size: 9.5px; font-weight: 700; color: #fff; flex: none; }
.ui-quiet strong { display: block; font-size: 12.5px; font-weight: 600; }
.ui-quiet em { display: block; font-style: normal; font-size: 11px; color: #9A968D; }
.ui-quiet .tag { margin-left: auto; font-family: var(--mono); font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--coral); background: var(--coral-wash); padding: 4px 9px; border-radius: 999px; flex: none; }

/* ── motion ───────────────────────────────────────────────────────────────
   Two rules, and both of them fail safe.
   1. Everything that moves is moved with transform only, so nothing here can
      reflow the page while somebody is reading it.
   2. Nothing is hidden by the stylesheet that the script has to reveal, apart
      from .rise, whose class is only ever added. If this script never loads,
      the page is simply a still page. */
.drift { will-change: transform; }
.tilt { transform: perspective(2200px) rotateX(var(--tilt, 0deg)) scale(var(--tscale, 1)); transform-origin: 50% 0%; will-change: transform; }
@media (prefers-reduced-motion: reduce) { .tilt { transform: none; } .drift { transform: none !important; } }

/* Scaling only ever shrinks, and only when the script is there to also fix the
   height. Untouched, a 380 pixel card sits at 380 pixels in a panel that is
   wider than that, which is the desktop case and the common one. */
.ui-fit.scaled .ui { position: absolute; top: 0; left: 0; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE TRILLO PASS
   ───────────────────────────────────────────────────────────────────────────
   Blake looked at the first build and said it was not enough like the
   template. He was right. I had taken the furniture and left the thing that
   actually makes it feel expensive.

   What I went back and measured on trillo.framer.ai:
     * the panels are soft multi-hue BLOOMS, not flat two stop gradients
     * the hero product sits ON a gradient slab, offset down and right, not
       on the page background
     * sixteen pixel corners, not fourteen
     * headlines at weight 500 with letter spacing near minus four per cent
     * the page ends on a full bleed gradient band with white type

   What I still did not take: its second accent, a bright lime, because we
   already have one colour that has to mean something. And no invented proof.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── the blooms ───────────────────────────────────────────────────────────
   Four overlapping radial gradients over a warm base. Overlapping soft edged
   circles is what a mesh gradient is; the template ships them as images and
   this does the same job in about four hundred bytes, stays sharp at any
   size, and can be recoloured from the tokens above. */
.mesh-warm {
  background:
    radial-gradient(58% 64% at 16% 20%, rgba(255,90,51,.42) 0%, rgba(255,90,51,0) 62%),
    radial-gradient(52% 58% at 76% 14%, rgba(255,162,77,.40) 0%, rgba(255,162,77,0) 60%),
    radial-gradient(64% 72% at 86% 82%, rgba(205,188,230,.52) 0%, rgba(205,188,230,0) 64%),
    radial-gradient(60% 66% at 24% 90%, rgba(246,185,190,.50) 0%, rgba(246,185,190,0) 62%),
    linear-gradient(140deg, #FCEFE7 0%, #F8F1E8 100%);
}
.mesh-hot {
  background:
    radial-gradient(62% 70% at 22% 26%, #FF5A33 0%, rgba(255,90,51,0) 64%),
    radial-gradient(58% 64% at 78% 16%, #FFA24D 0%, rgba(255,162,77,0) 62%),
    radial-gradient(72% 78% at 88% 86%, #E9C4DE 0%, rgba(233,196,222,0) 66%),
    radial-gradient(66% 72% at 12% 88%, #EFA6AE 0%, rgba(239,166,174,0) 64%),
    linear-gradient(140deg, #F5C9B8 0%, #F0D8CE 100%);
}
.mesh-dusk {
  background:
    radial-gradient(58% 66% at 82% 16%, rgba(255,90,51,.44) 0%, rgba(255,90,51,0) 62%),
    radial-gradient(56% 62% at 10% 82%, rgba(190,60,90,.30) 0%, rgba(190,60,90,0) 64%),
    radial-gradient(70% 76% at 44% 50%, rgba(205,188,230,.12) 0%, rgba(205,188,230,0) 68%),
    linear-gradient(145deg, #15141D 0%, #201822 52%, #33202A 100%);
}

/* ── the hero slab ────────────────────────────────────────────────────────
   The single biggest difference between the template and what I built first.
   Trillo does not float its product on the page colour. It lays down a wide
   soft slab and sits the window on it, offset down and to the right, so the
   slab shows along two edges. That offset is the whole trick: it reads as
   depth without a drop shadow doing the work. */
.slab {
  position: relative; border-radius: var(--r-lg);
  padding: 84px 0 0 88px; margin: var(--s7) 0 0 -44px;
}
.slab > .slab-fill {
  position: absolute; inset: 0; border-radius: var(--r-lg); z-index: 0;
}
.slab > * { position: relative; }
@media (max-width: 860px) { .slab { padding: 26px 0 0 26px; margin: var(--s6) 0 0 -14px; border-radius: var(--r); } }

/* The old soft wash behind the product is gone: the slab is the background
   now, and two of them fight. */
.perch::before { display: none; }
.perch { margin-top: 0; }
.perch-shot {
  border-radius: var(--r) var(--r) var(--r) 0;
  box-shadow: 0 2px 6px rgba(15,14,19,.05), 0 30px 70px rgba(15,14,19,.14);
}
/* The window runs off the right and bottom of the slab the way it does on the
   template, so the eye reads it as a panel you are looking through. */
.slab .perch { margin-right: 0; margin-bottom: -40px; }
@media (max-width: 860px) { .slab .perch { margin-right: 0; margin-bottom: -10px; } }

/* The chip row belongs on top of the slab's edge, not floating above it. */
.chips { margin-top: var(--s7); box-shadow: 0 1px 2px rgba(15,14,19,.04), 0 12px 30px rgba(15,14,19,.08); border-radius: var(--r-pill); }
.perch-stack { margin-top: -26px; }

/* ── type, closer to the template's ───────────────────────────────────── */
h1, h2, h3, h4 { font-weight: 500; }
.h-hero { font-size: clamp(44px, 7vw, 82px); letter-spacing: -.045em; line-height: .98; font-weight: 500; }
.h1     { font-size: clamp(31px, 4.4vw, 46px); letter-spacing: -.034em; line-height: 1.12; font-weight: 500; }
.h2     { font-size: clamp(26px, 3.2vw, 38px); letter-spacing: -.032em; line-height: 1.16; font-weight: 500; }
.h3     { font-size: clamp(19px, 2vw, 21px); letter-spacing: -.02em; font-weight: 600; }
.lede   { color: #4B4C54; }

/* ── the statement card ───────────────────────────────────────────────────
   Trillo's "Grow 10x faster" block: one tall bloom, white type, white pill
   chips along the bottom. It is the loudest thing on their page and it earns
   it by saying one thing. Ours says the only sentence that matters. */
.say {
  position: relative; overflow: hidden; border-radius: var(--r-lg);
  padding: clamp(32px, 5vw, 68px); color: #fff; text-align: left;
  min-height: 420px; display: flex; flex-direction: column;
}
.say-h { display: flex; align-items: center; gap: 9px; font-family: var(--mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; }
.say-h svg { width: 17px; height: 17px; stroke-width: 2.2; }
.say-q { font-family: var(--display); font-weight: 500; letter-spacing: -.035em; line-height: 1.1; font-size: clamp(28px, 4.2vw, 46px); margin: var(--s5) 0 0; max-width: 17ch; }
.say-s { margin-top: var(--s5); font-size: 17px; line-height: 1.55; max-width: 46ch; }
.say-pills { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: auto; padding-top: var(--s8); }
.say-pill { background: rgba(255,255,255,.94); color: var(--ink); border-radius: var(--r-pill); padding: 10px 18px; font-size: 14.5px; font-weight: 500; }

/* ── the panels become blooms ─────────────────────────────────────────── */
.alt-panel { border-radius: var(--r-lg); min-height: 420px; }
.alt-panel.g-coral { background: none; }
.alt-panel.g-paper { background: none; }
.alt-panel.g-ink   { background: none; }
.alt-panel::after { display: none; }
.ui-card { border-radius: var(--r); box-shadow: 0 2px 5px rgba(15,14,19,.05), 0 18px 44px rgba(15,14,19,.12); }

/* ── everything squarer gets rounder ──────────────────────────────────── */
.card, .step, .tcard, .price, .faq details, .perch-shot { border-radius: var(--r); }
.btn { border-radius: var(--r-sm); }
.feat-i { border-radius: 13px; }

/* ── Trillo wraps its pricing and its questions in one white block ────── */
.bento {
  background: var(--card); border: 1px solid var(--card-line);
  border-radius: var(--r-lg); padding: clamp(28px, 4vw, 64px) clamp(20px, 3vw, 48px);
  margin-top: var(--s7);
}
.bento .prices, .bento .faq { margin-top: var(--s7); }
.bento .faq details { background: #FAF8F4; }

/* ── the page ends on a bloom ─────────────────────────────────────────────
   Full bleed, white type, and the only place on the site where the coral is
   allowed to take the whole screen. */
.cta.band-mesh { color: #fff; padding: clamp(72px, 10vw, 148px) 0; position: relative; overflow: hidden; }
.cta.band-mesh .h1 { color: #fff; max-width: 18ch; }

.cta.band-mesh .btn-primary { background: #fff; color: var(--ink); }
.cta.band-mesh .btn-primary:hover { background: #F2EDE6; }
.cta.band-mesh .btn-ghost { background: rgba(255,255,255,.12); color: #fff; border-color: rgba(255,255,255,.42); }
.cta.band-mesh .btn-ghost:hover { background: rgba(255,255,255,.2); border-color: #fff; }
.cta.band-mesh .dot { color: #fff; }

/* ── the proof figures sit in the warm block too ──────────────────────── */

/* The chip row overlaps the top edge of the slab rather than floating clear
   of it, which is how the template stitches the two together. */
.chips { position: relative; z-index: 4; margin-bottom: -26px; }
.perch-stack { margin-top: 0; }
/* A second bloom with the warm corner on the other side, so the first and
   third panels are not the same picture twice. */
.mesh-dawn {
  background:
    radial-gradient(58% 64% at 84% 22%, rgba(255,90,51,.40) 0%, rgba(255,90,51,0) 62%),
    radial-gradient(52% 58% at 22% 16%, rgba(255,162,77,.38) 0%, rgba(255,162,77,0) 60%),
    radial-gradient(64% 72% at 14% 84%, rgba(205,188,230,.50) 0%, rgba(205,188,230,0) 64%),
    radial-gradient(60% 66% at 74% 92%, rgba(246,185,190,.48) 0%, rgba(246,185,190,0) 62%),
    linear-gradient(220deg, #FCEFE7 0%, #F8F1E8 100%);
}

/* ── the saturated blooms, for anywhere white type sits on colour ─────────
   The first pass of these was pastel, and white body copy on it measured
   about 1.6 to 1. Trillo gets away with white type because its band is a
   real orange at full strength, not a tint of one. So these are built at
   full strength and the pale versions above are only ever used where the
   type sits inside a white card on top. Proved with a pixel probe under
   every white run of text, not by looking at it. */
.mesh-flame {
  background:
    radial-gradient(58% 80% at 14% 26%, #BE2F3D 0%, rgba(190,47,61,0) 62%),
    radial-gradient(56% 74% at 88% 16%, #DE6B25 0%, rgba(222,107,37,0) 62%),
    radial-gradient(74% 88% at 46% 104%, #9E2C4A 0%, rgba(158,44,74,0) 66%),
    linear-gradient(115deg, #CB3A38 0%, #CB4A36 48%, #AB3352 100%);
}
.mesh-flame-r {
  background:
    radial-gradient(58% 80% at 86% 24%, #BE2F3D 0%, rgba(190,47,61,0) 62%),
    radial-gradient(56% 74% at 12% 18%, #CE6323 0%, rgba(206,99,35,0) 62%),
    radial-gradient(74% 88% at 54% 104%, #9E2C4A 0%, rgba(158,44,74,0) 66%),
    linear-gradient(245deg, #CB3A38 0%, #C24636 48%, #A33354 100%);
}
/* The hero slab carries no type, so it can stay light. It was too light to
   register as a slab at all, though, so the blooms are up by half. */
.mesh-slab {
  background:
    radial-gradient(52% 60% at 10% 32%, rgba(255,90,51,.62) 0%, rgba(255,90,51,0) 62%),
    radial-gradient(48% 54% at 42% 6%, rgba(244,150,176,.58) 0%, rgba(244,150,176,0) 60%),
    radial-gradient(56% 64% at 90% 22%, rgba(255,162,77,.70) 0%, rgba(255,162,77,0) 62%),
    radial-gradient(62% 68% at 74% 96%, rgba(196,176,228,.62) 0%, rgba(196,176,228,0) 64%),
    radial-gradient(50% 58% at 16% 96%, rgba(244,168,176,.66) 0%, rgba(244,168,176,0) 62%),
    linear-gradient(140deg, #F9DFD4 0%, #F6E8DC 100%);
}
/* Solid white, not ninety four per cent of it. Translucent white over a warm
   bloom is a colour nobody chose, it measures differently in every part of
   the panel, and the probe cannot see it as type at all. */
.say-h { color: #fff; }
.say-s { color: #fff; }
.cta.band-mesh .lede { color: #fff; }
/* The outline button was a white film, which lightened its own bed and took
   its label down to 3.8 to 1. Darkening the bed instead fixes both. */
.cta.band-mesh .btn-ghost { background: rgba(26,10,13,.34); border-color: rgba(255,255,255,.62); color: #fff; }
.cta.band-mesh .btn-ghost:hover { background: rgba(26,10,13,.46); border-color: #fff; }


/* ── what is true about security, and only what is true ──────────────────
   Both the Satori playback and Alex's audit flag the same hole: every rival
   shows a trust mark and this site shows none. Certifications we do not hold
   are not going on a page, so this strip carries the four things that are
   actually enforced in the database today and nothing else. */
.trust-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s4); margin-top: var(--s7); text-align: left; }
@media (max-width: 900px) { .trust-strip { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .trust-strip { grid-template-columns: 1fr; } }
.ts { background: var(--card); border: 1px solid var(--card-line); border-radius: var(--r); padding: var(--s5); }
.ts svg { width: 19px; height: 19px; color: var(--coral); stroke-width: 2; }
.ts b { display: block; font-family: var(--display); font-size: 16px; font-weight: 600; letter-spacing: -.02em; margin: var(--s4) 0 6px; }
.ts span { font-size: 14px; color: var(--ink-soft); line-height: 1.5; }

/* The one competitor number on the page. It is published, it is checkable,
   and it carries the date it was read, because a price quoted without a date
   is a price that will be wrong by Christmas. */
.vs { background: var(--card); border: 1px solid var(--card-line); border-radius: var(--r); padding: var(--s6); margin-top: var(--s6); text-align: left; max-width: 720px; margin-inline: auto; }
.vs-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s4); padding: var(--s3) 0; border-top: 1px solid var(--card-line); }
.vs-row:first-of-type { border-top: 0; }
.vs-row b { font-family: var(--display); font-size: 19px; font-weight: 600; letter-spacing: -.02em; white-space: nowrap; }
.vs-row span { font-size: 15px; color: var(--ink-soft); }
.vs-note { font-size: 13px; color: var(--ink-faint); margin-top: var(--s4); }

/* Client Finder's card runs a little taller than the others. */
.ui-firm { display: flex; align-items: flex-start; gap: 10px; padding: 9px 0; border-top: 1px solid #F2EFE8; }
.ui-firm:first-of-type { border-top: 0; }
.ui-firm strong { display: block; font-size: 12.5px; font-weight: 600; }
.ui-firm p { margin: 3px 0 0; font-size: 11.5px; color: var(--ink-soft); line-height: 1.4; }
.ui-firm .ui-sc { margin-left: auto; }

/* These two were h4 inside the product mock and one was a footer column
   label sitting straight under an h2. Alex's audit flagged the skip on all
   six pages of the live site as a template fix; this is that fix. The mock
   is aria-hidden, so nothing in it was ever a heading to a reader anyway. */
.ap-cardh, .ap-autoh { font-family: var(--display); font-size: 15px; font-weight: 600; letter-spacing: -.02em; }
.ap-autoh { line-height: 1.24; }
.ftr-h { font-family: var(--body); font-size: 12px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-faint); margin: 0 0 var(--s4); }

/* ═══════════════════════════════════════════════════════════════════════════
   THE LUMARA PASS
   ───────────────────────────────────────────────────────────────────────────
   Blake: "right now it's meh average". Fair. The Trillo pass got the colour
   right and left the page feeling like a stack of boxes on a flat background.

   Read off lumara.framer.website on 27 September. Four moves, and one of them
   does most of the work:

   1. THE WHOLE PAGE FLOATS ON A SOFT FIELD. Lumara does not put colour in a
      box under the hero. The entire page sits on a pale wash and white cards
      float on it. That one change is most of the difference between a page
      that looks built and a page that looks designed.
   2. THE NAV IS A FLOATING PILL, detached from the top edge.
   3. A PROOF PILL sits above the headline.
   4. BENTO CARDS ARE TINTED, with a white pane inside holding the interface.

   And it is 7,300 pixels tall against our 13,200. Half the page, same
   argument. So this pass also takes the air out.

   What we did not take: its indigo, its stock photography of smiling people,
   and its staggered grid. Blake asked for things to line up, and a grid that
   is deliberately off by twenty pixels is the opposite of that.
   ═══════════════════════════════════════════════════════════════════ */

/* ── 1. the field ─────────────────────────────────────────────────────────
   Fixed, so it does not scroll: the page moves and the light does not, which
   is calmer than parallax and costs one paint. Every value is low enough that
   body text over it still clears its contrast ratio, which the pixel probe
   checks rather than trusting. */
body::before {
  content: ''; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(46% 40% at 12% 6%,  rgba(255,124,92,.17)  0%, rgba(255,124,92,0)  62%),
    radial-gradient(42% 36% at 88% 2%,  rgba(255,178,110,.16) 0%, rgba(255,178,110,0) 60%),
    radial-gradient(50% 44% at 94% 58%, rgba(196,176,232,.18) 0%, rgba(196,176,232,0) 64%),
    radial-gradient(44% 38% at 4% 66%,  rgba(246,172,182,.17) 0%, rgba(246,172,182,0) 62%),
    radial-gradient(56% 40% at 50% 104%,rgba(255,150,120,.13) 0%, rgba(255,150,120,0) 64%);
}
@media (prefers-reduced-motion: reduce) { body::before { background-attachment: scroll; } }

/* ── 2. the nav floats ────────────────────────────────────────────────── */
.hdr { position: sticky; top: 0; z-index: 50; background: none; backdrop-filter: none; border: 0; padding: 14px 0; }
.hdr.scrolled { border: 0; }
.hdr-in {
  max-width: 1080px; height: 62px; gap: var(--s5);
  padding: 0 8px 0 22px; border-radius: var(--r-pill);
  background: rgba(255,255,255,.82);
  backdrop-filter: saturate(170%) blur(16px); -webkit-backdrop-filter: saturate(170%) blur(16px);
  border: 1px solid rgba(15,14,19,.055);
  box-shadow: 0 1px 2px rgba(15,14,19,.04), 0 10px 28px rgba(15,14,19,.07);
  transition: box-shadow .2s ease;
}
.hdr.scrolled .hdr-in { box-shadow: 0 1px 2px rgba(15,14,19,.05), 0 14px 38px rgba(15,14,19,.11); }
.hdr-logo img { height: 26px; }
.nav a { font-size: 15px; }
.hdr-cta .btn { padding: 11px 22px; font-size: 14.5px; }
@media (max-width: 959px) {
  .hdr { padding: 10px 0; }
  .hdr-in { height: 58px; padding: 0 8px 0 16px; }
  /* With the nav hidden its auto margins go with it, so the trial button was
     left glued to the logo with 619px of nothing between it and the burger.
     The two controls group on the right instead, which is where a thumb is. */
  .hdr-cta { margin-left: auto; }
  .burger  { margin-left: 0; }
  .hdr.open .nav { top: 68px; left: 12px; right: 12px; border: 1px solid var(--card-line); border-radius: var(--r); box-shadow: 0 14px 38px rgba(15,14,19,.12); }
}

/* Buttons are pills here. Trillo's are rounded rectangles and Lumara's are
   pills, and against a page this soft the rectangle was the thing making it
   feel like an admin tool. */
.btn { border-radius: var(--r-pill); }
.btn-primary { box-shadow: 0 1px 2px rgba(190,47,61,.16), 0 8px 20px rgba(190,47,61,.18); }
.btn-primary:hover { box-shadow: 0 1px 2px rgba(190,47,61,.2), 0 10px 26px rgba(190,47,61,.24); }

/* ── 3. the proof pill over the headline ──────────────────────────────────
   Lumara's says "5000+ 5 Star Review" over three stock faces. We have three
   real people who have really said something, and no user count, so the pill
   carries their initials and goes to what they actually said. */
.hero-pill {
  display: inline-flex; align-items: center; gap: 10px; text-decoration: none;
  background: rgba(255,255,255,.9); border: 1px solid rgba(15,14,19,.06);
  border-radius: var(--r-pill); padding: 6px 18px 6px 7px; margin-bottom: var(--s6);
  font-size: 14px; font-weight: 500; color: var(--ink-soft);
  box-shadow: 0 1px 2px rgba(15,14,19,.04), 0 8px 22px rgba(15,14,19,.06);
  transition: transform .14s ease, box-shadow .14s ease;
}
.hero-pill:hover { transform: translateY(-1px); box-shadow: 0 1px 2px rgba(15,14,19,.05), 0 12px 28px rgba(15,14,19,.1); }
.hero-pill .avs { display: flex; }
.hero-pill .av {
  width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center;
  font-family: var(--mono); font-size: 9.5px; font-weight: 500; color: #fff;
  border: 2px solid #fff; margin-left: -9px;
}
.hero-pill .av:first-child { margin-left: 0; }
.hero-pill svg { width: 14px; height: 14px; color: var(--coral); stroke-width: 2.4; }

/* ── 4. tinted bento, white pane inside ───────────────────────────────── */
.bento-card {
  border-radius: var(--r-lg); padding: 12px 12px 26px;
  border: 1px solid rgba(15,14,19,.05); text-align: left;
}
.bento-card .pane {
  background: #fff; border-radius: var(--r); padding: var(--s5) var(--s5) var(--s6);
  box-shadow: 0 1px 2px rgba(15,14,19,.04);
}
.bento-card .below { padding: var(--s5) var(--s4) 0; }
.bento-card h3 { margin-bottom: 8px; }
.bento-card p { color: var(--ink-soft); font-size: 15px; margin: 0; }
.tint-coral { background: #FBEBE6; }
.tint-sand  { background: #F6EFE4; }
.tint-lilac { background: #F0ECF7; }
.tint-blush { background: #FAEAEE; }
.step-big { font-family: var(--display); font-size: 40px; font-weight: 600; letter-spacing: -.04em; line-height: 1; color: var(--coral); }
.step-rule { height: 4px; border-radius: 4px; background: rgba(15,14,19,.09); margin-top: var(--s5); }
.step-rule span { display: block; height: 100%; border-radius: 4px; background: var(--coral); }

/* ── the hero, no longer in a box ─────────────────────────────────────────
   The slab is gone. Blake's screenshot showed the window hanging off the
   right of it and getting cut, and the honest reading is that the offset was
   never worth the alignment it cost. With a field behind the whole page the
   product can sit square in the measure, edges lined up with every other
   section on the page, and still be on colour. */
.slab { padding: 0; margin: var(--s7) 0 0; border-radius: 0; }
.slab > .slab-fill { display: none; }
.slab .perch { margin: 0; }
.perch-shot {
  border-radius: var(--r);
  box-shadow: 0 2px 8px rgba(15,14,19,.06), 0 36px 80px rgba(15,14,19,.16);
}
.chips { margin-bottom: 0; }
.perch-stack { margin-top: var(--s7); }
/* A local bloom under the product, stronger than the page field, so the
   window has something to sit on rather than floating in the middle. */
.perch::after {
  content: ''; position: absolute; z-index: -1; inset: 12% -10% 4% -10%;
  background: radial-gradient(52% 58% at 50% 46%, rgba(229,73,77,.2), rgba(229,73,77,0) 68%);
  filter: blur(26px); pointer-events: none;
}

/* ── two tone quote mark, as Lumara draws it ──────────────────────────── */
.qmark { display: flex; gap: 3px; margin-bottom: var(--s5); }
.qmark span { font-family: var(--display); font-size: 58px; line-height: .78; font-weight: 700; }
.qmark span:first-child { color: var(--coral); }
.qmark span:last-child { color: #D9D4CA; }
.tcard-mark { display: none; }

/* ── take the air out ─────────────────────────────────────────────────────
   Lumara says the same amount in 7,300 pixels that this page was taking
   13,200 to say. Nothing is being cut here, the gaps are just smaller. */
.section { padding: 82px 0; }
.section-sm { padding: 54px 0; }
.alt + .alt { margin-top: var(--s8); }
.alt-panel { min-height: 400px; }
.grid3, .grid2, .steps, .tgrid { margin-top: var(--s6); }
.cta { padding: clamp(78px, 9vw, 122px) 0; }

/* Cards lift very slightly, the way every card on Lumara does. */
.card, .step, .tcard, .price, .ts {
  box-shadow: 0 1px 2px rgba(15,14,19,.035), 0 7px 18px rgba(15,14,19,.05);
  transition: transform .16s ease, box-shadow .16s ease;
}
.card:hover, .tcard:hover, .ts:hover { transform: translateY(-2px); box-shadow: 0 1px 2px rgba(15,14,19,.04), 0 14px 30px rgba(15,14,19,.09); }
.bento { box-shadow: 0 1px 2px rgba(15,14,19,.035), 0 10px 26px rgba(15,14,19,.05); }

/* The proof figures sit on the field now, not on their own wash. */

/* ── the product lines up with everything else from the first frame ───────
   The tilt used to scale the window from .965 to 1 as you scrolled in, so
   until you moved, the hero shot was about twenty pixels narrower than every
   other section on the page. That is exactly the kind of thing Blake means
   by out of place. Only the rotation animates now. The window's left and
   right edges sit on the measure, always. */
.tilt { transform: perspective(2400px) rotateX(var(--tilt, 0deg)); }

/* ── air, second pass ─────────────────────────────────────────────────────
   Down from 13,010 to about 11,000. Lumara is 7,300, but Lumara does not
   carry a whole dashboard, three deep feature panels, a security strip and
   eight questions. Cutting to its number would mean cutting the strategy
   that went in this morning, which is the wrong trade. */
.section { padding: 72px 0; }
.say { min-height: 360px; padding: clamp(30px, 4.4vw, 58px); }
.say-pills { padding-top: var(--s7); }
.alt-panel { min-height: 356px; padding: var(--s6); }
.alt + .alt { margin-top: var(--s7); }
.alt { gap: var(--s7); }
.bento { padding: clamp(20px, 2.6vw, 40px) clamp(16px, 2.2vw, 36px); margin-top: var(--s6); }
.faq details { margin-bottom: 10px; }
.faq summary { padding: var(--s4) var(--s5); font-size: 17px; }
.faq p { padding: 0 var(--s5) var(--s5); }
.vs { padding: var(--s5) var(--s6); }
.price { padding: var(--s6); }
.trust-strip { margin-top: var(--s6); }

/* Two things the later rules in this file had quietly taken back.
   The reduced-motion override for .tilt was declared before the rule that
   redefined .tilt, so source order beat it. Media queries do not add
   specificity; only position in the file does. And the panel padding for
   small screens was overridden by the tightening pass, which cost sixteen
   pixels of card width on a phone. */
@media (prefers-reduced-motion: reduce) { .tilt { transform: none; } }
@media (max-width: 640px) { .alt-panel { padding: var(--s5); } }

/* A centred section with a max-width on a paragraph does not centre the
   paragraph: .mid only gives auto margins to .lede and .read. The hero
   caption was therefore sitting left of centre under a centred product,
   which is small and which is exactly the kind of thing that reads as
   sloppy without anyone being able to say why. */
.mid .small.muted, .mid .muted.small { margin-left: auto; margin-right: auto; }

/* ── the statement card had an empty right half ───────────────────────────
   Trillo leaves its one loud card two thirds empty and gets away with it
   because the bloom is the picture. Ours is a wider card and it read as
   unfinished, so the claim on the left now has the thing it is claiming
   sitting next to it. */
.say { position: relative; }
.say-shot {
  position: absolute; right: clamp(24px, 4vw, 56px); top: 50%; transform: translateY(-50%);
  width: 320px; background: #fff; border-radius: var(--r); padding: 16px 18px;
  box-shadow: 0 2px 6px rgba(15,14,19,.1), 0 24px 54px rgba(15,14,19,.22);
  text-align: left; color: var(--ink);
}
.say-shot .ui-h { font-size: 14px; }
.say-shot .ui-p { font-size: 12px; }
.say-shot .ui-firm { padding: 8px 0; }
/* Below this the card would sit on top of the words, so it goes. The left
   hand column is the message; the picture is support. */
@media (max-width: 1080px) { .say-shot { display: none; } }

/* ── room for things that paint outside their own box ────────────────────
   The alignment guard found two real collisions that looking at the page at
   one width would not have.

   1. rotateX tips the bottom of the product toward the viewer, so the window
      paints lower than the box the layout reserved for it, and the caption
      underneath was being overrun. The cards that hang below it need
      clearing too.
   2. On a tablet the mark, which hangs above the product, was landing on
      the right hand end of the chip row. */
.perch-stack { padding-bottom: 104px; }
@media (max-width: 1080px) { .perch-stack { padding-bottom: 26px; } }
.mid .small.muted { margin-top: var(--s5) !important; }
@media (max-width: 1000px) {
  .perch-stack { margin-top: var(--s8); }
  .perch-mark { width: 82px; right: 3%; }
}

/* The bottom card hung 74px below the product and then drifted up to another
   38px further down as the page moved, which put it through the caption. It
   sits on the product's lower edge now, where it looks like it belongs to
   the window rather than to the paragraph underneath. The padding below the
   stack only has to clear the tilt overhang, measured at 45px. */
.f-3 { bottom: 30px; left: 24%; }
.perch-stack { padding-bottom: 58px; }
@media (max-width: 1080px) { .perch-stack { padding-bottom: 20px; } }

/* ═══════════════════════════════════════════════════════════════════════════
   MARQUEES, VIDEO, ADD-ONS AND THE REPORTING SCREEN
   ═══════════════════════════════════════════════════════════════════════ */

/* ── the moving lanes ─────────────────────────────────────────────────────
   Two lanes travelling opposite ways, which is what the GoodBuild site does
   and the reason it reads as movement rather than as a slideshow. The track
   holds the list twice and slides exactly half its width, so the loop has no
   seam. Paused on hover and frozen completely for anyone who has asked for
   less motion, because a marquee is the single worst thing on a page for
   somebody with vestibular trouble. */
.lanes { position: relative; overflow: hidden; margin-top: var(--s6);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent); }
.lane { display: flex; width: max-content; gap: var(--s3); padding: 6px 0; will-change: transform; }
.lane.a { animation: laneL 44s linear infinite; }
.lane.b { animation: laneR 52s linear infinite; margin-top: var(--s3); }
.lanes:hover .lane { animation-play-state: paused; }
@keyframes laneL { from { transform: translate3d(0,0,0); }    to { transform: translate3d(-50%,0,0); } }
@keyframes laneR { from { transform: translate3d(-50%,0,0); } to { transform: translate3d(0,0,0); } }
@media (prefers-reduced-motion: reduce) {
  .lane { animation: none !important; flex-wrap: wrap; width: 100%; justify-content: center; }
}
.ipill {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  height: 62px; min-width: 156px; padding: 0 var(--s5);
  background: rgba(255,255,255,.78); border: 1px solid rgba(15,14,19,.055);
  border-radius: var(--r); backdrop-filter: blur(6px);
}
.ipill img { max-height: 24px; width: auto; opacity: .82; }
.tname { display: inline-flex; align-items: center; gap: 10px; flex: none; height: 74px; padding: 0 var(--s6); }
.tname img { max-height: 40px; width: auto; opacity: .7; filter: grayscale(1); transition: opacity .2s ease, filter .2s ease; }
.tname:hover img { opacity: 1; filter: none; }
.tname b { font-family: var(--display); font-size: 17px; font-weight: 600; letter-spacing: -.02em; color: var(--ink-soft); white-space: nowrap; }
.tname b u { text-decoration: none; font-weight: 400; }

/* ── the video panels ─────────────────────────────────────────────────── */
.vgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s4); margin-top: var(--s6); text-align: left; }
@media (max-width: 1000px) { .vgrid { grid-template-columns: 1fr; } }
.vcard { border-radius: var(--r-lg); padding: 12px 12px 26px; border: 1px solid rgba(15,14,19,.05); }
.vcard .pane { background: #fff; border-radius: var(--r); overflow: hidden; box-shadow: 0 1px 2px rgba(15,14,19,.05); }
.vcard video, .vcard img.still { display: block; width: 100%; height: auto; aspect-ratio: 1600 / 796; object-fit: cover; background: #F3F0EA; }
.vcard .below { padding: var(--s5) var(--s4) 0; }
.vcard h3 { margin-bottom: 8px; }
.vcard p { color: var(--ink-soft); font-size: 15px; margin: 0; }

/* ── add-ons ──────────────────────────────────────────────────────────── */
.addons { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s4); margin-top: var(--s6); text-align: left; }
@media (max-width: 940px) { .addons { grid-template-columns: 1fr; } }
.addon { background: var(--card); border: 1px solid var(--card-line); border-radius: var(--r); padding: var(--s6); display: flex; flex-direction: column; }
.addon-i { width: 38px; height: 38px; border-radius: 12px; background: var(--coral-wash); color: var(--coral); display: grid; place-items: center; margin-bottom: var(--s5); }
.addon-i svg { width: 19px; height: 19px; stroke-width: 2; }
.addon h3 { margin-bottom: 6px; }
.addon p { color: var(--ink-soft); font-size: 14.5px; margin: 0 0 var(--s5); flex: 1; }
.addon-p { font-family: var(--display); font-size: 27px; font-weight: 600; letter-spacing: -.03em; }
.addon-p span { font-family: var(--body); font-size: 14px; font-weight: 500; color: var(--ink-faint); letter-spacing: 0; }
.addon-n { font-size: 13px; color: var(--ink-faint); margin-top: 6px; }
.addon.inc { border-color: var(--coral); background: #FFF7F5; }
.addon.inc .addon-n { color: #B0403C; font-weight: 600; }

/* The 500 tier is the one to land on, so it gets the ring and the badge and
   the other one does not. Blake's call on 27 September: drive to 500. */
.price.hot { border-color: var(--coral); border-width: 1.5px; box-shadow: 0 2px 6px rgba(190,47,61,.1), 0 18px 44px rgba(190,47,61,.14); }
.price-was { font-size: 13.5px; color: var(--ink-faint); margin-top: 8px; }

/* ── the reporting screen, drawn in GoodBuild colours ──────────────────────
   Chart palette: #CB3A38 coral, #2E6FB8 blue, #B08A16 ochre. Not chosen by
   eye. Run through the six checks (lightness band, chroma floor, colour
   vision separation, normal vision floor, contrast against the card) and it
   passes all of them; coral with an amber beside it, which is what the brand
   wanted, failed three. Coral leads so the brand still reads.             */
.rep { width: 100%; margin: var(--s7) auto 0; background: #fff;
  border: 1px solid var(--card-line); border-radius: var(--r-lg); overflow: hidden;
  box-shadow: 0 2px 8px rgba(15,14,19,.06), 0 30px 70px rgba(15,14,19,.12); text-align: left; }
.rep-top { display: flex; align-items: center; gap: 10px; padding: 14px 20px; border-bottom: 1px solid var(--card-line); background: #FCFBF8; }
.rep-top .ap-lab { margin: 0; }
.rep-top em { font-style: normal; font-size: 12.5px; color: var(--ink-faint); }
.rep-seg { margin-left: auto; display: flex; gap: 3px; background: #F3F0EA; border-radius: var(--r-pill); padding: 3px; }
.rep-seg span { font-size: 11.5px; font-weight: 600; color: var(--ink-soft); padding: 5px 13px; border-radius: var(--r-pill); }
.rep-seg span.on { background: #fff; color: var(--ink); box-shadow: 0 1px 2px rgba(15,14,19,.07); }
.rep-kpis { display: grid; grid-template-columns: repeat(4, 1fr); border-bottom: 1px solid var(--card-line); }
.rep-k { padding: 16px 20px; border-left: 1px solid #F3F0EA; }
.rep-k:first-child { border-left: 0; }
.rep-k i { display: block; font-style: normal; font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); }
.rep-k b { display: block; font-family: var(--display); font-size: 26px; font-weight: 700; letter-spacing: -.035em; margin-top: 7px; font-variant-numeric: tabular-nums; }
.rep-k u { display: block; text-decoration: none; font-size: 11.5px; margin-top: 3px; color: #2F6B45; font-weight: 600; }
.rep-k u.down { color: #B0403C; }
.rep-body { display: grid; grid-template-columns: 1.5fr 1fr; }
@media (max-width: 820px) { .rep-body { grid-template-columns: 1fr; } .rep-kpis { grid-template-columns: 1fr 1fr; } }
.rep-pane { padding: 18px 20px 20px; border-left: 1px solid #F3F0EA; }
.rep-pane:first-child { border-left: 0; }
/* Was an inline font-size on the element, which meant the mobile floor
   could not reach it without !important. Same 12.5px, somewhere a
   stylesheet can argue with. */
.rep-note { font-size: 12.5px; }
.rep-h { font-family: var(--display); font-size: 15px; font-weight: 600; letter-spacing: -.02em; }
.rep-sub { font-size: 12px; color: var(--ink-faint); margin-top: 2px; }
/* A legend is present for every chart with two or more series, so identity
   is never carried by colour alone. */
.rep-leg { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 11px; }
.rep-leg span { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--ink-soft); }
.rep-leg i { width: 9px; height: 9px; border-radius: 3px; display: inline-block; }
.rep-chart { margin-top: 12px; }
.rep-chart svg { width: 100%; height: auto; display: block; overflow: visible; }
.rep-bars { display: grid; gap: 11px; margin-top: 14px; }
.rep-bar b { display: flex; justify-content: space-between; font-size: 12.5px; font-weight: 600; }
.rep-bar b span { color: var(--ink-soft); font-weight: 500; font-variant-numeric: tabular-nums; }
.rep-track { height: 9px; border-radius: 5px; background: #F1EEE7; margin-top: 6px; overflow: hidden; display: flex; gap: 2px; }
.rep-track i { display: block; height: 100%; border-radius: 5px; }

/* ── logos are not all the same shape ────────────────────────────────────
   A wordmark is wide and short, a monogram is square. Capping both by
   height alone makes every square mark look half the size of every
   wordmark, which is what the first render did to Loxo, Manatal and
   Greenhouse. Height for wordmarks, a bigger box for the square ones, and
   a ceiling on width so a long wordmark cannot bully the row. */
.ipill img { max-height: 25px; max-width: 124px; width: auto; object-fit: contain; }
.ipill img[src*="loxo"], .ipill img[src*="manatal"], .ipill img[src*="greenhouse"],
.ipill img[src*="lever"], .ipill img[src*="gem"] { max-height: 34px; }
.tname img { height: auto; max-height: 30px; max-width: 168px; object-fit: contain; border-radius: 5px; }
.tname img[src*="multisearch"], .tname img[src*="ssg"] { max-height: 40px; }
.tname img[src*="talentus"] { max-height: 22px; }
.tname img[src*="revised"] { max-height: 34px; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE SETUP DIAGRAM
   ───────────────────────────────────────────────────────────────────────────
   Two tracks, five stages each, stages lined up column against column. What
   differs is the clock under each stage and the speed of the bar: the top
   track finishes while the bottom one is still on stage two.

   HOW THE DOTS LIGHT. The first version gave every dot its own animation
   with its own delay and a step-end timing function, which fires at the END
   of the cycle rather than at the delay, so nothing ever lit. Ten delays
   kept in sync with two bars by hand was the wrong idea anyway. Instead
   there are two identical rows of dots, a grey one underneath and a coral
   one on top, and the coral row is clipped by the same animation that draws
   the bar. The dots cannot drift out of step with the bar because they are
   the same element.

   HONESTY NOTE. The two speeds on screen are about five to one. The real gap
   is ninety seconds against six months, nearer a hundred and seventy
   thousand to one, which does not fit on a screen at any scale. The caption
   says so rather than letting the animation imply a ratio it is not showing.
   ═══════════════════════════════════════════════════════════════════ */
.flow { margin-top: var(--s7); text-align: left; display: grid; gap: var(--s4); }
.flow-row { background: var(--card); border: 1px solid var(--card-line); border-radius: var(--r-lg); padding: var(--s5) var(--s6) var(--s6); }
.flow-row.them { background: rgba(255,255,255,.55); }
.flow-head { display: flex; align-items: center; gap: 10px; margin-bottom: var(--s6); }
.flow-head img { height: 22px; width: auto; }
.flow-head b { font-family: var(--display); font-size: 16px; font-weight: 600; letter-spacing: -.02em; }
.flow-head span { margin-left: auto; font-family: var(--mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  background: var(--coral); color: #fff; padding: 5px 12px; border-radius: var(--r-pill); }
.flow-row.them .flow-head span { background: #EDE9E1; color: var(--ink-soft); }
.flow-row.them .flow-head b { color: var(--ink-soft); }

/* The track stops where the last dot is, at four fifths of the row, so the
   fifth dot sits exactly above the start of the fifth label. */
.flow-track { position: relative; height: 4px; width: 80%; border-radius: 4px; background: #EDE9E1; }
.flow-dots { position: absolute; inset: 0; }
.flow-dots i { position: absolute; top: -6px; width: 15px; height: 15px; border-radius: 50%;
  background: #fff; border: 3px solid #DCD7CD; box-sizing: border-box; }
.flow-dots i:nth-child(1) { left: 0 }
.flow-dots i:nth-child(2) { left: calc(25% - 3.75px) }
.flow-dots i:nth-child(3) { left: calc(50% - 7.5px) }
.flow-dots i:nth-child(4) { left: calc(75% - 11.25px) }
.flow-dots i:nth-child(5) { left: calc(100% - 15px) }
/* The clipped layer is taller than the track on purpose. clip-path cuts to
   the element's own box, and the first version of this had that box at the
   track's 4px, which sliced the top and bottom off every dot and left a
   coral sliver across their middles. The layer now stands 8px proud above
   and below, and the bar and the dot row are positioned back down inside
   it, so the clip only ever cuts horizontally. */
.flow-lit { position: absolute; left: 0; right: 0; top: -8px; bottom: -8px; clip-path: inset(0 0 0 0); }
.flow-bar { position: absolute; left: 0; right: 0; top: 8px; height: 4px; border-radius: 4px; background: var(--coral); }
.flow-lit .flow-dots { top: 8px; bottom: 8px; }
.flow-lit .flow-dots i { border-color: var(--coral); }
.flow-row.them .flow-bar { background: #A9A49A; }
.flow-row.them .flow-lit .flow-dots i { border-color: #A9A49A; }

.flow-steps { display: grid; grid-template-columns: repeat(5, 1fr); margin-top: 20px; }
.flow-step b { display: block; font-size: 13.5px; font-weight: 600; padding-right: var(--s4); }
.flow-step i { display: block; font-style: normal; font-family: var(--mono); font-size: 10.5px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-faint); margin-top: 5px; }
.flow-step.last b { color: var(--coral); }
.flow-row.them .flow-step.last b { color: var(--ink-soft); }
@media (max-width: 860px) {
  .flow-track { display: none; }
  .flow-steps { grid-template-columns: 1fr; gap: var(--s4); margin-top: 0; }
  .flow-step { padding-left: 16px; border-left: 3px solid var(--coral); }
  .flow-row.them .flow-step { border-left-color: #DCD7CD; }
}

/* One animation per row drives the bar and its dots together. */
@keyframes flowFast { 0% { clip-path: inset(0 100% 0 0) } 20% { clip-path: inset(0 0 0 0) } 100% { clip-path: inset(0 0 0 0) } }
@keyframes flowSlow { 0% { clip-path: inset(0 100% 0 0) } 92% { clip-path: inset(0 0 0 0) } 100% { clip-path: inset(0 0 0 0) } }
.flow.go .flow-row.us   .flow-lit { animation: flowFast 13s cubic-bezier(.4,0,.2,1) infinite; }
.flow.go .flow-row.them .flow-lit { animation: flowSlow 13s linear infinite; }

/* With motion off, or with no script at all, the clip stays fully open: both
   rows show complete and every dot is lit, which is the end state and reads
   correctly as a still diagram. Nothing here is only visible when animated. */
@media (prefers-reduced-motion: reduce) { .flow .flow-lit { animation: none !important; clip-path: inset(0 0 0 0) !important; } }

/* ── the careers page ─────────────────────────────────────────────────────
   Each role is a details element so the page opens as three headlines and
   not as four thousand words. The summary carries everything somebody needs
   to decide whether to open it: the tags, the title, the money and the
   place. Nobody should have to expand a role to find out what it pays. */
.role summary { padding: var(--s5) var(--s6); align-items: flex-start; }
.role summary::after { margin-top: 4px; }
.role-sum { display: block; }
.role-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.role-tags b { font-family: var(--mono); font-size: 9.5px; font-weight: 500; letter-spacing: .1em; text-transform: uppercase;
  background: #F1EDE5; color: var(--ink-soft); padding: 4px 10px; border-radius: var(--r-pill); }
.role-tags b.hot { background: var(--coral); color: #fff; }
.role-name { display: block; font-family: var(--display); font-size: clamp(21px,2.4vw,26px); font-weight: 600; letter-spacing: -.028em; }
.role-meta { display: block; font-family: var(--body); font-size: 14px; font-weight: 500; color: var(--ink-soft); margin-top: 6px; letter-spacing: 0; }
.role-body { padding: 0 var(--s6) var(--s6); border-top: 1px solid var(--card-line); margin: 0 var(--s6); padding-left: 0; padding-right: 0; }
.role-body h3 { margin: var(--s6) 0 var(--s3); }
.role-body p { font-size: 15.5px; color: var(--ink-soft); margin: 0 0 var(--s3); max-width: 74ch; }
.role-body p b, .role-list b { color: var(--ink); }
.role-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; max-width: 74ch; }
.role-list li { position: relative; padding-left: 20px; font-size: 15px; color: var(--ink-soft); }
.role-list li::before { content: ''; position: absolute; left: 3px; top: 9px; width: 6px; height: 6px; border-radius: 50%; background: var(--coral); }
.role-pack { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s3); margin: var(--s6) 0 0; }
@media (max-width: 720px) { .role-pack { grid-template-columns: 1fr 1fr; } }
.role-pack div { background: #FAF7F2; border: 1px solid var(--card-line); border-radius: var(--r-sm); padding: var(--s4); }
.role-pack i { display: block; font-style: normal; font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-faint); }
.role-pack b { display: block; font-family: var(--display); font-size: 17px; font-weight: 600; letter-spacing: -.02em; margin-top: 5px; }
.role-pack span { display: block; font-size: 12px; color: var(--ink-faint); margin-top: 2px; min-height: 1em; }
.role-apply { margin-top: var(--s6); padding-top: var(--s5); border-top: 1px solid var(--card-line); font-size: 15px; color: var(--ink-soft); }
.role-apply b { font-size: 16px; }
.role-apply a { color: var(--coral); }

/* ── the brand colour and the action colour are not the same colour ──────
   The pixel probe had never been pointed at a button label. Once it was, it
   found white on our coral at 3.89 to 1, which fails for anything smaller
   than 24px. That is every primary button on the site, the pricing badge,
   the score chips and the hiring tag.

   #E5494D stays the brand: it is sampled from the logo and it is right on a
   logo, an icon, a rule or a dot, where contrast rules do not apply.
   Anything carrying WHITE TEXT uses the deeper step below, which measures
   4.63 to 1. They are close enough to read as one colour and far enough
   apart to be legal. This is a normal thing for a design system to have and
   we should have had it from the start. */
:root { --coral-act: #D4413E; }
.btn-primary { background: var(--coral-act); }
.btn-primary:hover { background: #BE3936; }
.price-tag, .ap-go, .ui-sc, .ui-sc.b2, .role-tags b.hot { background: var(--coral-act); }
.cta.band-mesh .btn-primary { background: #fff; }
/* The score chips were three tints of coral, and the middle one measured
   3.07. The tint never carried any meaning: the number is the data. One
   colour for the chip, and the third stays a light wash with dark type. */
.ui-sc.b3 { background: var(--coral-wash); color: #B03734; }
.ap-stat.hot { background: linear-gradient(140deg, #D4413E, #B33438); border-color: #B33438; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE REAL RECORDINGS
   ───────────────────────────────────────────────────────────────────────────
   Two clips off the live product, replacing the three that carried the
   GoodBuild name. They are different shapes, so they are not forced into a
   grid of three equal cards: the CV clip is 2.4 to 1 and gets the full
   measure, the competence check is nearly square and sits in a panel beside
   its copy, which is the layout that shape wants.

   WHAT CAME OUT OF THE CV CLIP, AND WHY. Four seconds of it was a macOS file
   picker showing a folder named "Airwallex Back up Codes" next to a Proton
   Drive and a machine name. That is a signpost to where payment credentials
   live and it is not going on a public website. The left rail came off too,
   because it says "Ask GoodBuild" in every frame, and the bottom strip came
   off because the support bubble is purple. Nothing was slowed down, sped up
   or faked: it is thirty seven seconds of the product doing the thing.
   ═══════════════════════════════════════════════════════════════════ */
.vshot { position: relative; border-radius: var(--r-lg); padding: 14px; overflow: hidden; }
.vshot video { display: block; width: 100%; height: auto; border-radius: var(--r);
  background: #F3F0EA; box-shadow: 0 2px 6px rgba(15,14,19,.07), 0 22px 54px rgba(15,14,19,.14); }
.vcap { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s3) var(--s5); margin-top: var(--s5); text-align: left; }
.vcap h3 { margin: 0; }
.vcap p { margin: 0; color: var(--ink-soft); font-size: 15.5px; flex: 1 1 340px; }
/* A live badge, so it is obvious this is a recording and not a mock. */
.vlive { display: inline-flex; align-items: center; gap: 7px; font-family: var(--mono); font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-soft);
  background: rgba(255,255,255,.86); border: 1px solid rgba(15,14,19,.06);
  border-radius: var(--r-pill); padding: 6px 13px; }
.vlive::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--coral-act); }
.alt-panel .vshot { padding: 0; }
.alt-panel .vshot video { max-height: 460px; width: auto; margin: 0 auto; }

/* ── the three numbers, second attempt ────────────────────────────────────
   The first attempt was a full width near black band with 104px figures and
   a count that ran as you reached it. Blake's verdict on seeing it live was
   that it looked dog shite, and he was right for a reason worth writing
   down: the page is warm and light the whole way through, and a black band
   two screens in does not read as emphasis, it reads as a different site.
   The count then had to fight the band for attention, so the numbers grew
   until they were shouting, which is exactly what a page about not
   exaggerating should never do.

   So: back to the light card, and earn the attention instead of demanding
   it. A real 1px border rather than a tint that dissolves. Hairline
   dividers so the eye counts three things. A short coral rule under each
   figure, the only brand colour in the block. A label line so each number
   has a name before it has a sentence. Nothing animates and nothing needs
   script: the figures are text in the markup.
   ─────────────────────────────────────────────────────────────────────── */
.figs-wrap {
  border-radius: var(--r-lg);
  padding: clamp(32px, 4vw, 48px) clamp(20px, 3vw, 40px);
  /* Translucent rather than solid, so the page's own warm field shows
     through and the card belongs to this page instead of sitting on it.
     No mesh class on the markup any more: a gradient behind text this small
     was the thing that made the old card look like a smudge. */
  background: linear-gradient(180deg, rgba(255,255,255,.93), rgba(255,255,255,.74));
  border: 1px solid rgba(15, 14, 19, .10);
  box-shadow: 0 1px 2px rgba(15, 14, 19, .03), 0 18px 44px -28px rgba(15, 14, 19, .18);
  backdrop-filter: blur(6px);
}
.figs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; text-align: left; }
.fig { min-width: 0; padding: 0 clamp(14px, 2.4vw, 34px); }

/* The dividers sit on the items rather than on the grid, so the first one
   never gets a line on its left and a single column layout gets none at all. */
.fig + .fig { border-left: 1px solid rgba(15, 14, 19, .09); }

.fig-n {
  font-family: var(--display); font-weight: 650; letter-spacing: -.045em; line-height: .95;
  font-size: clamp(42px, 5.2vw, 62px); font-variant-numeric: tabular-nums;
  color: var(--ink); display: block; margin: 0;
}
.fig-n small { font-size: .4em; font-weight: 600; letter-spacing: -.01em; margin-left: .1em; color: var(--ink-soft); }

/* Short on purpose. A rule the full width of the column turns three figures
   back into one striped block. */
.fig-r { width: 34px; height: 3px; border-radius: 3px; background: var(--coral); margin: var(--s4) 0; }

.fig-k { font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); }
.fig-l { font-size: 15px; line-height: 1.5; color: #5A5B63; margin: var(--s3) 0 0; max-width: 30ch; }

@media (max-width: 820px) {
  .figs { grid-template-columns: 1fr; }
  .fig { padding: var(--s6) 0; }
  .fig + .fig { border-left: 0; border-top: 1px solid rgba(15, 14, 19, .09); }
  .fig-l { max-width: none; }
}

/* A one line caption under a clip that is inside a panel, so the reader
   knows what they are looking at without leaving the panel to find out. */
.vsub { font-size: 13px; line-height: 1.45; color: var(--ink-soft); margin: var(--s4) 0 0; text-align: left; }

/* WHY overflow goes visible here: .vshot clips to a large radius so a video
   with square corners sits inside a rounded card. Inside an alt-panel the
   padding is zero and the video carries its own radius, so the clip has no
   job left, and the caption underneath was losing the first letter of its
   second line to the corner arc. Caught by the corner assertion in
   tools/site-video-check.cjs, which now fails if any text enters a rounded
   clipping corner. */
.alt-panel .vshot { display: flex; flex-direction: column; overflow: visible; }

/* ── the roadmap page ─────────────────────────────────────────────────────
   A roadmap is the easiest page on a website to get wrong, because the
   design wants to make everything look equally real. The whole visual job
   here is the opposite: make the difference between shipped and imagined
   impossible to miss at a glance, from across the room, before anybody has
   read a word.

   So the status tag is the loudest element in each card, it carries colour
   rather than the card does, and the two speculative groups sit on darker
   or flatter ground than the live one. A reader who only skims should come
   away knowing which third of the page they can buy.
   ─────────────────────────────────────────────────────────────────────── */

/* ── the tags ─────────────────────────────────────────────────────────── */
.rm-tag {
  display: inline-block; font-family: var(--mono); font-size: 10px; font-weight: 500;
  letter-spacing: .13em; text-transform: uppercase; white-space: nowrap;
  padding: 5px 10px; border-radius: var(--r-pill); border: 1px solid transparent;
}
/* Colour carries meaning here, so it never carries it alone: the label is a
   word, in every tag, at a readable size. Nothing on this page depends on
   telling green from coral. */
.rm-tag.is-live    { background: rgba(31, 90, 78, .16);  color: #17453C; border-color: rgba(31, 90, 78, .26); }
.rm-tag.is-build   { background: rgba(212, 65, 62, .10); color: #A3312F; border-color: rgba(212, 65, 62, .20); }
.rm-tag.is-next    { background: rgba(15, 14, 19, .055); color: #4B4C55; border-color: rgba(15, 14, 19, .10); }
.rm-tag.is-explore { background: transparent;            color: #5A5B63; border-color: rgba(15, 14, 19, .22); }

/* ── the key block ────────────────────────────────────────────────────── */
.rm-key {
  border-radius: var(--r-lg); padding: clamp(26px, 3.4vw, 40px);
  background: linear-gradient(180deg, rgba(255,255,255,.93), rgba(255,255,255,.74));
  border: 1px solid rgba(15, 14, 19, .10);
  box-shadow: 0 1px 2px rgba(15,14,19,.03), 0 18px 44px -28px rgba(15,14,19,.18);
}
.rm-key-h p:not(.eyebrow) { margin: var(--s4) 0 0; color: var(--ink-soft); font-size: 16px; line-height: 1.55; max-width: 74ch; }
.rm-key-list { list-style: none; margin: var(--s6) 0 0; padding: 0; display: grid; gap: var(--s4); }
.rm-key-list li { display: grid; grid-template-columns: 104px 1fr; gap: var(--s5); align-items: start; }
/* A grid item fills its column by default, which stretched every tag to the
   full 104px and turned four pills into four identical grey bars. The tag
   has to be the width of its own word or it stops reading as a tag. */
.rm-key-list li > .rm-tag { justify-self: start; }
.rm-key-list li > span:last-child { font-size: 15px; line-height: 1.5; color: #5A5B63; }
@media (max-width: 620px) {
  .rm-key-list li { grid-template-columns: 1fr; gap: var(--s2); }
}
/* The rule is the load bearing sentence on the page, so it is set apart
   rather than buried as the last line of a paragraph. */
.rm-rule {
  margin: var(--s6) 0 0; padding: var(--s5) var(--s5) var(--s5) var(--s6);
  border-left: 3px solid var(--coral); background: rgba(15, 14, 19, .028);
  border-radius: 0 var(--r) var(--r) 0;
  font-size: 15.5px; line-height: 1.55; color: var(--ink);
}
.rm-rule b { font-weight: 650; }

/* ── the item cards ───────────────────────────────────────────────────── */
.rm-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s5); align-items: start; }
@media (max-width: 1020px) { .rm-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 680px)  { .rm-grid { grid-template-columns: 1fr; } }

.rm-item {
  border-radius: var(--r-lg); padding: var(--s6);
  background: rgba(255, 255, 255, .78);
  border: 1px solid rgba(15, 14, 19, .08);
  box-shadow: 0 1px 2px rgba(15,14,19,.03);
  text-align: left;
}
.rm-item h3 { font-family: var(--display); font-size: 19px; font-weight: 650; letter-spacing: -.02em;
  line-height: 1.25; margin: var(--s4) 0 0; color: var(--ink); }
.rm-item p { font-size: 15px; line-height: 1.55; color: #5A5B63; margin: var(--s3) 0 0; }

/* ── the thesis ───────────────────────────────────────────────────────── */
.rm-thesis {
  max-width: 74ch; margin: 0 auto; display: grid; gap: var(--s5);
}
.rm-thesis p { font-size: 17.5px; line-height: 1.65; color: var(--ink-soft); margin: 0; }
.rm-thesis p b { color: var(--ink); font-weight: 650; }

/* A block sat here and is parked. See parked/ at the repo root. */

/* ── the teaser on the home page ──────────────────────────────────────── */
.rm-teaser {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s7);
  text-decoration: none; color: inherit; text-align: left;
  border-radius: var(--r-lg); padding: clamp(26px, 3.2vw, 40px);
  background: linear-gradient(180deg, rgba(255,255,255,.90), rgba(255,255,255,.70));
  border: 1px solid rgba(15, 14, 19, .10);
  box-shadow: 0 1px 2px rgba(15,14,19,.03), 0 18px 44px -28px rgba(15,14,19,.18);
  transition: border-color .25s, box-shadow .25s, transform .25s;
}
.rm-teaser:hover { border-color: rgba(15,14,19,.18); transform: translateY(-2px);
  box-shadow: 0 1px 2px rgba(15,14,19,.04), 0 26px 54px -30px rgba(15,14,19,.24); }
.rm-teaser h3 { margin: var(--s3) 0 0; }
.rm-teaser > div > p:last-child { margin: var(--s4) 0 0; color: var(--ink-soft); font-size: 16px; line-height: 1.55; max-width: 62ch; }
.rm-teaser-go { display: inline-flex; align-items: center; gap: 9px; white-space: nowrap;
  font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  /* --coral-act measured 4.47 here against the translucent card, just under
     the 4.5 small text floor. This is the same darker coral the Building tag
     uses, which clears it. */
  color: #A3312F; }
/* flex:0 0 auto matters. Without it the arrow is a flex item beside nowrap
   text, the text takes the whole line, and the icon is shrunk to zero width
   while still claiming width:16px in the stylesheet. Caught by assertion I
   in tools/align-check.cjs, which exists because of this exact bug. */
.rm-teaser-go svg { flex: 0 0 auto; width: 16px; height: 16px; transition: transform .25s; }
.rm-teaser:hover .rm-teaser-go svg { transform: translateX(3px); }
@media (max-width: 860px) {
  .rm-teaser { flex-direction: column; align-items: flex-start; gap: var(--s5); }
}
@media (prefers-reduced-motion: reduce) {
  .rm-teaser, .rm-teaser-go svg { transition: none; }
  .rm-teaser:hover { transform: none; }
}

/* An eyebrow is --ink-faint, which is tuned against the paper canvas. On a
   tinted mesh the background lifts and the same grey measured 4.37, under
   the 4.5 floor for small text. Anywhere an eyebrow sits on a mesh it steps
   down to --ink-soft. This was only ever found because the roadmap put an
   eyebrow on a gradient and the glyph probe was pointed at the page. */
.mesh-dawn .eyebrow,
.mesh-warm .eyebrow,
.mesh-slab .eyebrow,
.mesh-hot  .eyebrow { color: var(--ink-soft); }
/* Not on the dark ones, which set their own light colour above. */
.mesh-dusk .eyebrow { color: rgba(255,255,255,.80); }

/* ── the roadmap timeline ─────────────────────────────────────────────────
   Blake asked for a glowing arrow that runs down the page as you scroll,
   revealing each release and the quarter it lands in.

   The rule that shapes all of it: the animation must never be load bearing.
   So the default state in this stylesheet is the finished state. The track
   is drawn, every row is lit and legible, and the arrow is invisible. The
   script adds .tl-armed, and only then do rows dim and wait to be lit. If
   the script never runs, throws, or the reader has reduced motion on, they
   get a complete roadmap with no animation rather than a column of faint
   grey text nobody can read.
   ─────────────────────────────────────────────────────────────────────── */
.tl { position: relative; padding-left: 86px; margin-top: var(--s8); }
@media (max-width: 680px) { .tl { padding-left: 52px; } }

.tl-track { position: absolute; left: 31px; top: 6px; bottom: 6px; width: 2px;
  background: rgba(15, 14, 19, .10); border-radius: 2px; }
@media (max-width: 680px) { .tl-track { left: 17px; } }

/* The fill is a separate span so the track keeps its full height while the
   fill scales, which is what lets the arrow be positioned in pixels rather
   than guessed from a percentage. */
.tl-fill { position: absolute; inset: 0; overflow: hidden; }
.tl-fill span { display: block; width: 100%; height: 100%; transform-origin: top;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--coral) 0%, #FF7A4D 55%, var(--coral) 100%); }

.tl-arrow {
  /* Explicit width and height, and they matter. An absolutely positioned box
     with no width shrinks to fit its child, the child svg is clamped by the
     sheet's max-width:100%, and the two resolve each other to one pixel. The
     arrow was on the page, glowing, 1px wide. Assertion I in align-check only
     failed under 1px, so it slipped by exactly one pixel; its threshold is
     now 4px because of this. */
  position: absolute; left: 1px; top: 0; width: 26px; height: 26px; opacity: 0;
  color: var(--coral); pointer-events: none;
  transition: opacity .25s linear; }
.tl-arrow svg { display: block; width: 26px; height: 26px;
  /* the glow. Two shadows, a tight one for the edge and a wide soft one, so
     it reads as light rather than as a blurry copy of the arrow. */
  filter: drop-shadow(0 0 3px rgba(229, 73, 77, .95)) drop-shadow(0 0 14px rgba(255, 122, 77, .75)); }

/* era headings */
.tl-era { position: relative; margin: var(--s8) 0 var(--s5); }
.tl-era:first-of-type { margin-top: 0; }
.tl-era b { display: block; font-family: var(--display); font-size: 22px; font-weight: 700;
  letter-spacing: -.025em; color: var(--ink); }
.tl-era span { display: block; margin-top: 4px; font-size: 14px; color: var(--ink-soft); }
.tl-era::before { content: ''; position: absolute; left: -63px; top: 7px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--paper); border: 2px solid var(--coral); }
@media (max-width: 680px) { .tl-era::before { left: -42px; width: 14px; height: 14px; } }

/* rows */
.tl-row { position: relative; margin: 0 0 var(--s5); }
.tl-row::before { content: ''; position: absolute; left: -60px; top: 22px;
  width: 10px; height: 10px; border-radius: 50%;
  background: rgba(15, 14, 19, .18); transition: background .35s, box-shadow .35s; }
@media (max-width: 680px) { .tl-row::before { left: -39px; top: 20px; } }

.tl-q { position: absolute; left: -86px; top: -20px;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-faint); }
@media (max-width: 680px) { .tl-q { position: static; display: block; margin-bottom: 6px; } }

.tl-card { border-radius: var(--r-lg); padding: var(--s6);
  background: rgba(255, 255, 255, .80);
  border: 1px solid rgba(15, 14, 19, .08);
  box-shadow: 0 1px 2px rgba(15, 14, 19, .03);
  transition: transform .4s cubic-bezier(.2,.7,.2,1), box-shadow .4s, border-color .4s; }
.tl-card h3 { font-family: var(--display); font-size: 19px; font-weight: 650; letter-spacing: -.02em;
  line-height: 1.25; margin: var(--s4) 0 0; color: var(--ink); }
.tl-card p { font-size: 15px; line-height: 1.55; color: #5A5B63; margin: var(--s3) 0 0; }
.tl-card a { color: #A3312F; }

/* The two rows that carry the argument rather than a feature. */
.tl-star .tl-card { border-color: rgba(212, 65, 62, .22); }

/* ── armed: only once the script is running ── */
.tl-armed .tl-row { opacity: .42; transition: opacity .45s ease; }
.tl-armed .tl-row.lit { opacity: 1; }
.tl-armed .tl-row.lit::before { background: var(--coral);
  box-shadow: 0 0 0 4px rgba(229, 73, 77, .14), 0 0 12px rgba(229, 73, 77, .55); }
.tl-armed .tl-row.lit .tl-card { transform: translateY(-2px);
  border-color: rgba(15, 14, 19, .12);
  box-shadow: 0 1px 2px rgba(15,14,19,.04), 0 20px 44px -30px rgba(15,14,19,.30); }
.tl-armed .tl-fill span { transform: scaleY(0); }

/* filtered out */
.tl-off { display: none; }

@media (prefers-reduced-motion: reduce) {
  .tl-card, .tl-row, .tl-arrow, .tl-row::before { transition: none; }
  .tl-armed .tl-row { opacity: 1; }
}

/* ── the filter bar ───────────────────────────────────────────────────── */
.rm-bar { position: sticky; top: 74px; z-index: 40; padding: var(--s3) 0; }
.rm-bar-in { display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap;
  padding: 9px 14px; border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .84); backdrop-filter: blur(10px);
  border: 1px solid rgba(15, 14, 19, .08);
  box-shadow: 0 1px 2px rgba(15,14,19,.03), 0 14px 34px -26px rgba(15,14,19,.30); }
.rm-bar-l { font-family: var(--mono); font-size: 10px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-soft); }
.rm-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.rm-chip { font: inherit; font-size: 13.5px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px; border-radius: var(--r-pill);
  background: transparent; border: 1px solid rgba(15, 14, 19, .10); color: var(--ink-soft);
  transition: background .2s, color .2s, border-color .2s; }
.rm-chip i { font-style: normal; font-family: var(--mono); font-size: 10px;
  padding: 2px 6px; border-radius: var(--r-pill);
  background: rgba(15, 14, 19, .06); color: #4B4C55; }
.rm-chip:hover { border-color: rgba(15, 14, 19, .22); color: var(--ink); }
/* --coral-act measured 3.31 here rather than its usual 4.54, because the
   chip sits on a blurred translucent bar and the edge pixels lift. The count
   badge was worse: rgba(255,255,255,.22) lightens the ground under white
   text, which is the wrong direction. Darker coral, and the badge darkens
   its ground instead of lightening it. */
.rm-chip.on { background: #A3312F; border-color: #A3312F; color: #fff; }
.rm-chip.on i { background: rgba(0, 0, 0, .22); color: #fff; }
.rm-bar-say { margin: 0 0 0 auto; font-size: 13px; color: var(--ink-soft); }
@media (max-width: 860px) { .rm-bar-say { display: none; } }
@media (prefers-reduced-motion: reduce) { .rm-chip { transition: none; } }

/* ── the white label demo ─────────────────────────────────────────────────
   The mechanism is one idea: --coral, --coral-act and --coral-wash are
   inherited custom properties, and every product surface carries .wl. So
   re-pointing those three names ON .wl re-skins everything inside those
   subtrees and nothing outside them. Fifty one rules already use
   var(--coral) and not one of them had to change.

   The header, nav and page buttons sit outside .wl and keep GoodBuild's
   coral, which is the honest demo: the product white labels the app, not
   our marketing site.
   ─────────────────────────────────────────────────────────────────────── */
.wl {
  --coral:      var(--brand,      #E5494D);
  --coral-act:  var(--brand-act,  #D4413E);
  --coral-wash: var(--brand-wash, #FCEBEB);
}

/* The agency's name stands in for our logo inside the mock. */
.wl-mark { font-family: var(--display); font-weight: 700; font-size: 15px; letter-spacing: -.02em;
  color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 150px; }
.wl-mark::after { content: '.'; color: var(--coral); }

/* ── the control ──────────────────────────────────────────────────────── */
.wl-bar {
  display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap;
  margin: var(--s6) auto 0; width: fit-content; max-width: 100%;
  padding: 9px 9px 9px 18px; border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .78); backdrop-filter: blur(10px);
  border: 1px solid rgba(15, 14, 19, .09);
  box-shadow: 0 1px 2px rgba(15,14,19,.03), 0 16px 38px -28px rgba(15,14,19,.32);
}
.wl-lab { font-family: var(--mono); font-size: 10px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-soft); white-space: nowrap; }
.wl-in {
  font: inherit; font-size: 14.5px; color: var(--ink);
  width: 168px; padding: 8px 13px; border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .9); border: 1px solid rgba(15, 14, 19, .12);
}
.wl-in::placeholder { color: var(--ink-faint); }
.wl-in:focus-visible { outline: 2px solid var(--coral-act); outline-offset: 1px; }

.wl-sw { display: inline-flex; gap: 6px; }
.wl-c {
  width: 26px; height: 26px; padding: 0; cursor: pointer;
  border-radius: 50%; background: var(--s, #E5494D);
  border: 2px solid rgba(255, 255, 255, .9);
  box-shadow: 0 0 0 1px rgba(15, 14, 19, .14);
  transition: transform .18s, box-shadow .18s;
}
.wl-c:hover { transform: scale(1.12); }
.wl-c[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--ink); }
.wl-c:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* The any-colour swatch is a label wrapping a colour input, because a native
   colour picker is the one control nobody has to be taught. */
.wl-any { position: relative; overflow: hidden; display: inline-flex;
  background: conic-gradient(#E5494D, #C2410C, #B08A16, #0E7C5A, #1B17FF, #7A3BB5, #E5494D); }
.wl-any input { position: absolute; inset: -6px; width: 200%; height: 200%;
  opacity: 0; cursor: pointer; border: 0; padding: 0; }

.wl-reset { font: inherit; font-size: 13px; cursor: pointer; color: var(--ink-soft);
  background: transparent; border: 0; padding: 6px 10px; border-radius: var(--r-pill); }
.wl-reset:hover { color: var(--ink); background: rgba(15, 14, 19, .05); }
.wl-say { margin: 0; font-size: 12.5px; color: var(--ink-soft); }
.wl-say:empty { display: none; }

@media (max-width: 620px) {
  .wl-bar { width: 100%; justify-content: center; padding: 12px; gap: var(--s3); }
  .wl-in { width: 100%; }
  .wl-say { width: 100%; text-align: center; }
}
@media (prefers-reduced-motion: reduce) { .wl-c { transition: none; } }

/* White type on the brand, inside a product surface, must use the darkened
   action colour rather than the raw hue. With our own coral the two are
   near enough identical, which is why this was never noticed: --coral is
   already dark enough for white text. A visitor picking yellow is not.
   The hue sweep in tools/site-whitelabel-check.cjs found .ap-av at 1.07 to
   one on #FFFF00 and that is the only reason this block exists. Anything
   added later that paints white on the brand belongs in this list, and the
   sweep will say so the day it does not. */
.wl .ap-av,
.wl .ap-go,
.wl .ap-sw,
.wl .float-score b,
.wl .ui-sc,
.wl .ui-sc.b2,
.wl .ui-bar span,
.wl .ap-nav.on::before,
.wl .ap-handled .ap-lab::before { background: var(--coral-act); }

/* And the third score chip is the exception, which the sweep found one run
   after the block above was added. It is the quiet one: a wash background
   with dark type, not white type on the brand. The rule above had the same
   specificity and came later, so it captured .b3 as well and painted dark
   purple under dark red at 1.07 to one. It gets its pair back explicitly,
   with the action colour as the type so it is readable whatever the brand. */
.wl .ui-sc.b3 { background: var(--coral-wash); color: var(--brand-on-wash, #B03734); }

/* Every place inside a product surface that puts type ON the wash. Each of
   these had a hardcoded coral for the text, which is fine while the brand
   is coral and wrong the moment it is not: a black brand makes a grey wash
   and the red type landed at 3.99. --brand-on-wash is darkened against the
   wash it will actually sit on, not against white. Found one at a time by
   the hue sweep, which is the only way anyone was ever going to find them. */
.wl .ap-n b,
.wl .ui-quiet .tag,
.wl .save { color: var(--brand-on-wash, #B03734); }

/* [hidden] is display:none from the user agent sheet, and ANY explicit
   display in an author sheet beats it. .ap-brand img is display:block, so
   hiding it with the attribute did nothing and the mock showed the GoodBuild
   logo and the agency name side by side. This is the fix, and it is the
   reason [hidden] should never be trusted on an element you have styled. */
.ap-brand img[hidden], .wl-mark[hidden] { display: none !important; }
/* Room for a real agency name. The mark sits where our logo was, so it gets
   the width our logo had rather than a token 150px. */
.wl-mark { max-width: 190px; font-size: 16px; }

/* ── the last hardcoded corals inside the mock ────────────────────────────
   Sixteen warm hexes were written straight into the product rules back when
   the brand could only ever be coral. They are the big fees card, the tints
   behind the auto-pilot panel, the out-to-client tag and the sparklines,
   which between them are most of the red a visitor actually sees. With them
   hardcoded the demo changed the small chips and left the loud blocks
   behind, which reads as broken rather than clever.

   color-mix does the work, so a tint stays a tint of whatever the brand is
   rather than a fixed pink. Everything here is inside .wl, so the marketing
   page keeps its own coral untouched.
   ─────────────────────────────────────────────────────────────────────── */
.wl .ap-stat.hot {
  background: linear-gradient(150deg, var(--coral-act), color-mix(in srgb, var(--coral-act) 78%, #000));
  border-color: color-mix(in srgb, var(--coral-act) 80%, #000);
}
.wl .ap-handled {
  background: color-mix(in srgb, var(--coral) 15%, var(--paper));
  border-color: color-mix(in srgb, var(--coral) 26%, var(--paper));
}
.wl .ui-3 div:last-child { border-color: color-mix(in srgb, var(--coral) 26%, var(--paper)); }
.wl .ap-tag.out {
  background: color-mix(in srgb, var(--coral) 17%, var(--paper));
  color: var(--brand-on-wash, #B4413F);
}
.wl .ap-handled .ap-lab { color: var(--brand-on-wash, #B4514F); }
.wl .rep-k u.down { color: var(--coral-act); }

/* The sparklines carry their colours as attributes, and a stylesheet beats
   an attribute, so they can be reached without touching the markup. */
.wl .ap-spark svg path { fill: color-mix(in srgb, var(--coral) 16%, var(--paper)); }
.wl .ap-spark svg path + path { fill: none; stroke: color-mix(in srgb, var(--coral) 46%, var(--paper)); }
.wl .ap-stat.hot .ap-spark svg path { fill: rgba(255,255,255,.18); }
.wl .ap-stat.hot .ap-spark svg path + path { fill: none; stroke: rgba(255,255,255,.62); }


/* ══ the GoodBuild logo ══════════════════════════════════════════════════
   30 September. The site kept its layout and its colours and took
   GoodBuild's name and mark.

   THE WORDMARK IS TEXT, NOT AN IMAGE, and that was a decision rather than a
   shortcut. The obvious port of a PNG wordmark is another PNG wordmark, and
   the word is set in Outfit. Neither the machine that built this site nor
   the laptop beside it can reach Google Fonts, so a rendered wordmark would
   have shipped in whatever fallback face the renderer had lying about, and
   on a logo that is worse than shipping nothing. As text it is always the
   real typeface, always sharp on any display, and it scales with its slot
   instead of being resampled.

   The mark keeps its own colour and the word takes the ink of wherever it
   sits, so one component works in the header, the footer, the flow diagram
   and inside the screenshot of the app.
   ═══════════════════════════════════════════════════════════════════════ */
.gb-logo {
  display: inline-flex; align-items: center; gap: .36em;
  font-family: var(--display); font-weight: 700; letter-spacing: -.025em;
  line-height: 1; color: var(--ink); white-space: nowrap; text-decoration: none;
}
.gb-mark { width: 1.06em; height: 1.06em; flex: 0 0 auto; fill: var(--coral); display: block; }
.gb-word { display: block; }
/* The white label demo hides the logo and puts a customer's name there. It
   used to hide an img; hidden has to keep working on this. */
.gb-logo[hidden] { display: none !important; }

/* One size per slot, reproducing the heights the images had. */
.hdr-logo  .gb-logo { font-size: 25px; }
.ftr-logo  .gb-logo { font-size: 26px; }
.ap-brand  .gb-logo { font-size: 17px; }
.flow-head .gb-logo { font-size: 17px; }
@media (max-width: 959px) { .hdr-logo .gb-logo { font-size: 22px; } }

/* The mark sitting on top of the card, where the mark used to look over
   the edge. It is the same joke and it happens to be literally the product:
   the layer goes on top of what you already run. */
svg.perch-mark {
  width: 74px; height: 74px; fill: var(--coral);
  filter: drop-shadow(0 8px 18px rgba(229,73,77,.30));
}
@media (max-width: 700px) { svg.perch-mark { width: 56px; height: 56px; } }

/* Sign in is a text link, not a third button. Three buttons side by side in
   a header all shout at the same volume and the one that matters, Start free
   trial, stops standing out. Signing in is a thing people already know how
   to find. */
.hdr-signin {
  text-decoration: none; font-size: 15px; font-weight: 500;
  color: var(--ink-soft); padding: 6px 2px; white-space: nowrap;
}
.hdr-signin:hover { color: var(--ink); }
@media (max-width: 959px) { .hdr-signin { display: none; } }

/* Three controls in the header now, so they must not wrap. "Book a demo"
   broke onto two lines at 1280 and made the bar look broken. */
.hdr-cta .btn { white-space: nowrap; }
@media (max-width: 1150px) { .hdr-cta .btn { padding-left: 16px; padding-right: 16px; } }
@media (max-width: 1040px) { .nav { gap: 14px; } .nav a { font-size: 14.5px; } }

/* Book a demo and Sign in are buttons in the header on a desktop and are
   hidden below 959px, where the header only has room for the trial button.
   That left the demo booking reachable on a phone only from the footer,
   and most of the traffic that arrives from a post is on a phone. They go
   in the drawer instead, where somebody looking for them will look. */
.nav-mob { display: none !important; }
@media (max-width: 959px) {
  .hdr.open .nav .nav-mob { display: block !important; font-weight: 600; color: var(--ink); }
}

/* ══ the marks in the footer ═════════════════════════════════════════════
   30 September. Blake: "add this badge on the bottom of the page (a GDPR
   Badge) because we actually are GDPR compliant, we had a data specialist
   sign off on it now".

   WHAT THIS BADGE DOES NOT SAY, AND WHY.

   There is no such thing as a GDPR certification. Our own security page
   says so in as many words: nobody in this market is certified and anybody
   telling you they are is describing something that does not exist. A
   badge shaped like a certification would have contradicted that page two
   clicks away, which is worse than having no badge at all.

   So it states the fact instead: the position was reviewed and signed off
   by an external specialist, and it gives the month. A dated review by a
   named kind of person beats a logo, because a buyer's procurement team
   can ask for it and we can hand it over.

   The second mark is the one nobody else puts on a site: the things we do
   NOT hold, with the quarter we expect them. Saying "targeted, not held"
   out loud is the whole argument for believing the first mark.
   ═══════════════════════════════════════════════════════════════════════ */
.ftr-marks {
  display: block;
  margin-top: var(--s7); padding-top: var(--s6);
  border-top: 1px solid var(--line);
}
.gmark {
  display: inline-flex; align-items: flex-start; gap: 10px;
  text-decoration: none; padding: 12px 16px;
  border: 1px solid var(--card-line); border-radius: var(--r-sm);
  background: var(--card); max-width: 330px;
  transition: border-color .16s ease, background .16s ease;
}
.gmark:hover { border-color: var(--coral); background: var(--coral-wash); }
.gmark svg { width: 20px; height: 20px; flex: none; color: var(--coral); margin-top: 1px; }
.gmark span { display: block; font-size: 12.5px; line-height: 1.5; color: var(--ink-faint); }
.gmark b { display: block; font-size: 13.5px; font-weight: 700; color: var(--ink); margin-bottom: 2px; }
.gmark.is-soon svg { color: var(--ink-faint); }
@media (max-width: 700px) { .gmark { max-width: none; width: 100%; } }

/* ══ the logo is not a badge ═════════════════════════════════════════════
   30 September. Blake: "make sure the pills line up, make sure this
   goodbuild word is in the middle of this pill, the orange is a little
   more on the left".

   He had found a bug of mine, not a spacing problem. .flow-head span was
   written when the logo in that row was an <img>, so the only span in
   there was the "90 seconds" badge. The rebrand made the logo a span, so
   the badge rule caught it: our own logo was rendering as a coral pill
   with GOODBUILD in uppercase mono, letter-spaced, shoved right by the
   margin-left:auto meant for the badge. That is the pill in his
   screenshot. It was never meant to exist.

   The rule is scoped to the badge now, and the logo is put back to being
   a logo wherever it lands.

   AND THE CENTRING, WHICH IS REAL. letter-spacing adds its space AFTER the
   last letter as well as between letters, so a centred, letter-spaced word
   in a pill always sits visibly left of centre. Every pill on this page
   had it. The padding compensates rather than the text being nudged, so
   the box stays the size the text needs.
   ═══════════════════════════════════════════════════════════════════════ */
.flow-head > .gb-logo {
  margin-left: 0; background: none; padding: 0; border-radius: 0;
  font-family: var(--display); font-size: 17px; text-transform: none;
  letter-spacing: -.025em; color: var(--ink);
}
.flow-head > .gb-logo .gb-word {
  background: none; padding: 0; border-radius: 0;
  text-transform: none; letter-spacing: -.025em; color: inherit;
  font-family: inherit; font-size: inherit;
}
.flow-row.them .flow-head > .gb-logo { color: var(--ink-soft); }

/* The trailing letter-space, compensated so a centred word looks centred. */
.flow-head > span:not(.gb-logo),
.vlive,
.eyebrow {
  padding-right: calc(12px + .1em);
}
.flow-head > span:not(.gb-logo) { padding-left: 12px; }

/* ══ the GDPR seal ═══════════════════════════════════════════════════════
   30 September. Blake sent a blue circle of yellow stars with GDPR across
   it and asked for that instead of the words.

   THAT PARTICULAR BADGE COULD NOT GO ON. It is the EU emblem, whose use is
   restricted, and it reads as a certification issued by somebody. No GDPR
   certification exists to be issued. Our own security page says exactly
   that, one click away, so the badge would have called our own page a
   liar. It is also a stock image of unknown ownership.

   He was right about the format though. A paragraph in a footer is not a
   trust mark and nobody reads it. So this is a seal we drew, in our own
   brand, saying the thing that is actually true: reviewed, signed off,
   and the month it happened. A date somebody can ask you to produce beats
   a logo nobody issued.
   ═══════════════════════════════════════════════════════════════════════ */
.gseal {
  display: inline-flex; align-items: center; gap: 14px;
  text-decoration: none; padding: 12px 16px 12px 12px;
  border: 1px solid var(--card-line); border-radius: var(--r-sm);
  background: var(--card); max-width: 430px; width: 100%;
  cursor: pointer; font: inherit; color: inherit; text-align: left;
  transition: border-color .16s ease, background .16s ease;
}
.gseal:hover, .gseal[aria-expanded="true"] { border-color: var(--coral); background: var(--coral-wash); }
.gseal-d { width: 62px; height: 62px; flex: none; }
/* When the panel opens below the fold the script scrolls here, and the
   sticky header would otherwise land on top of the badge it scrolled to. */
.gseal { scroll-margin-top: 90px; }
.gseal-t { display: block; flex: 1 1 auto; font-size: 12.5px; line-height: 1.5; color: var(--ink-faint); }
.gseal-t b { display: block; font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: 3px; }
.gseal-go { width: 16px; height: 16px; flex: none; color: var(--ink-faint);
  transition: transform .18s ease, color .16s ease; }
.gseal:hover .gseal-go { color: var(--coral); }
.gseal[aria-expanded="true"] .gseal-go { transform: rotate(180deg); color: var(--coral); }

/* ══ what the badge opens ════════════════════════════════════════════════
   1 October. Blake sent a blue badge with a ring of EU stars on it and
   said: put the badge, then once they click it you can explain it all.

   The second half is right and this is it. A paragraph in a footer is not
   a trust mark, and the paragraph we had is the thing he called too much.
   So the footer carries a mark, the mark opens the detail, and the detail
   is the half nobody else shows: what we do NOT hold, with dates.

   The first half I did not do as he sent it. Those stars are the EU
   emblem, UK GDPR is UK law, and a ring of EU stars says a European body
   certified us. Nobody certified us, security.html says exactly that two
   clicks away, and this badge cannot be the least honest object on the
   site. So it is our seal, in our coral, with the padlock he liked and
   the month of the review on its face. A date somebody can ask you to
   produce beats an emblem nobody issued.

   Two columns, and the right hand one is the one that sells.
   ═══════════════════════════════════════════════════════════════════════ */
.gseal-panel {
  max-width: 820px; margin-top: var(--s4);
  border: 1px solid var(--card-line); border-radius: var(--r-sm);
  background: var(--card); padding: var(--s5);
}
.gseal-panel[hidden] { display: none; }
.gseal-panel:focus { outline: none; }
.gseal-panel:focus-visible { outline: 2px solid var(--coral); outline-offset: 2px; }
.gseal-lead { margin: 0 0 var(--s5); font-size: 13.5px; line-height: 1.65; color: var(--ink-soft); }
.gseal-cols { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: var(--s5); }
.gseal-col h4 {
  margin: 0 0 12px; font-family: var(--mono); font-size: 11px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-faint);
}
.gseal-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.gseal-col li {
  position: relative; padding-left: 20px;
  font-size: 12.5px; line-height: 1.55; color: var(--ink-faint);
}
.gseal-col li b { color: var(--ink); font-weight: 700; }
.gseal-col li::before {
  content: ''; position: absolute; left: 2px; top: 6px;
  width: 8px; height: 8px; border-radius: 50%; background: var(--coral);
}
/* Held is filled, not held is hollow. The shape carries the meaning so it
   still reads with the colour taken away. */
.gseal-col.is-not li::before {
  background: none; box-sizing: border-box; border: 1.6px solid var(--ink-faint);
}
.gseal-note {
  margin: var(--s5) 0 0; padding-top: var(--s4); border-top: 1px solid var(--line);
  font-size: 12.5px; line-height: 1.6; color: var(--ink-faint);
}
.gseal-acts { display: flex; flex-wrap: wrap; gap: 10px; margin-top: var(--s4); }
.gseal-acts .btn { font-size: 14px; padding: 11px 18px; }
@media (max-width: 700px) {
  .gseal { max-width: none; }
  .gseal-panel { max-width: none; padding: var(--s4); }
  .gseal-cols { grid-template-columns: minmax(0,1fr); gap: var(--s5); }
}

/* ══ the live Client Finder demo ═════════════════════════════════════════
   A real search on a public page. The company is real and shown; who to
   ring there is real and deliberately not, because that half is the
   product and it is also a person's working contact details.

   The blurred bars under the company are not a screenshot of anything.
   They are three empty divs, so there is nothing behind them to recover
   with a screen reader, a selection or the inspector. A blur over real
   text is a puzzle, not a lock.
   ═══════════════════════════════════════════════════════════════════════ */
.tryit {
  margin-top: var(--s9); padding: var(--s7) var(--s7) var(--s6);
  border: 1px solid var(--card-line); border-radius: var(--r-lg);
  background: var(--card);
  box-shadow: 0 1px 2px rgba(20,19,24,.04), 0 24px 60px rgba(20,19,24,.06);
}
.tryit-head { max-width: 58ch; }
.tryit-head .h2 { margin-top: var(--s3); }
.tryit-head .lede { margin-top: var(--s4); }

.tryit-bar { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: flex-end; margin-top: var(--s6); }
.tryit-f { display: flex; flex-direction: column; gap: 6px; flex: 1 1 200px; }
.tryit-f span { font-size: 12px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-faint); }
.tryit-f input {
  font: inherit; font-size: 16px; color: var(--ink);
  padding: 13px 15px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--paper); width: 100%;
}
.tryit-f input:focus { outline: none; border-color: var(--coral);
  box-shadow: 0 0 0 4px rgba(229,73,77,.13); }
.tryit-bar .btn { flex: 0 0 auto; padding: 14px 26px; }

.tryit-egs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--s4); }
.tryit-egs button {
  font: inherit; font-size: 13px; color: var(--ink-soft); cursor: pointer;
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-pill); padding: 7px 14px;
}
.tryit-egs button:hover { border-color: var(--coral); color: var(--coral); }

.tryit-out { margin-top: var(--s5); }
.tryit-card { border: 1px solid var(--card-line); border-radius: var(--r); background: var(--paper); padding: var(--s5); }
.tryit-card.is-wait p, .tryit-card.is-none p { margin: 0; color: var(--ink-faint); font-size: 14.5px; }

/* THE CARD THAT OFFERS THE CALL INSTEAD OF AN ANSWER.
   A paragraph and a button, in a card that had only ever held a paragraph.
   Measured at five widths, the gap between the two was zero at every one of
   them: the button's top edge sat exactly on the paragraph's line box, which
   reads as a collision even though nothing technically overlaps. Blake saw it
   and called it overlapping, which is the right word for what it looks like.

   A flex column with a gap, rather than a margin on the button, because
   margins here would have to be undone on the other states of this card and
   the first one somebody forgets is a regression nobody measures. */
.tryit-card.is-offer {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: var(--s4);
}
.tryit-card.is-offer p { margin: 0; max-width: 62ch; }
.tryit-card.is-offer .btn { flex: none; }
.tryit-card.is-wait p::after { content: ' .'; animation: tdot 1.1s steps(4) infinite; }
@keyframes tdot { 0%{content:' .'} 33%{content:' ..'} 66%{content:' ...'} }

.tryit-co { display: flex; align-items: center; gap: 14px; }
.tryit-av { width: 44px; height: 44px; flex: none; border-radius: 12px;
  background: var(--coral); color: #fff; display: grid; place-items: center;
  font-family: var(--display); font-weight: 700; font-size: 15px; }
.tryit-co > div { min-width: 0; flex: 1; }
.tryit-co b { display: block; font-family: var(--display); font-size: 19px;
  font-weight: 700; letter-spacing: -.02em; color: var(--ink); }
.tryit-co > div span { display: block; font-size: 13.5px; color: var(--ink-faint); margin-top: 2px; }
.tryit-n { flex: none; text-align: right; font-size: 12.5px; color: var(--ink-faint); }
.tryit-n b { display: block; font-family: var(--display); font-size: 22px; color: var(--coral); }

.tryit-lock { position: relative; margin-top: var(--s5); border-top: 1px solid var(--line); padding-top: var(--s5); }
/* The blur sits BEHIND and the ask sits in front, in normal flow. The first
   cut absolutely positioned the ask over the bars, so the copy ran across
   them and the button landed on the provenance line. Content decides the
   height of a box; a box should not decide the height of its content. */
.tryit-blur { position: absolute; inset: var(--s5) 0 auto 0; z-index: 0;
  display: grid; gap: 10px; filter: blur(5px); opacity: .45; user-select: none; }
.tryit-blur span { display: block; height: 13px; border-radius: 7px; background: var(--line); }
.tryit-blur span:nth-child(1) { width: 62%; }
.tryit-blur span:nth-child(2) { width: 44%; }
.tryit-blur span:nth-child(3) { width: 53%; }
.tryit-ask { position: relative; z-index: 1; display: flex;
  flex-direction: column; align-items: flex-start; gap: 8px; }
.tryit-ask b { font-family: var(--display); font-size: 16px; font-weight: 700; color: var(--ink); }
.tryit-ask p { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--ink-faint); max-width: 48ch; }
.tryit-ask .btn { margin-top: 6px; }

.tryit-prov { margin: var(--s4) 0 0; font-family: var(--mono); font-size: 11.5px;
  letter-spacing: .02em; color: var(--ink-faint); }
.tryit-note { margin-top: var(--s5); }

@media (max-width: 760px) {
  .tryit { padding: var(--s6) var(--s5) var(--s5); }
  .tryit-bar .btn { width: 100%; }
  .tryit-blur { display: none; }
}

/* ══ the hero takes turns ════════════════════════════════════════════════
   The photo is what you arrive at. The live one arrives the moment you
   touch the control above it. See the comment on goLive in index.html for
   why they are not both on screen at once.

   The photo carries its own browser chrome, so the frame the mock needs is
   only drawn once the mock is showing. Two sets of traffic lights on one
   window reads as a mistake.
   ═══════════════════════════════════════════════════════════════════════ */
.perch-shot.is-shot { border: 0; background: none; box-shadow: none; overflow: visible; }
.perch-shot.is-shot.is-live {
  border: 1px solid var(--card-line); background: var(--card);
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(20,19,24,.04), 0 24px 60px rgba(20,19,24,.08);
}
.shot-real {
  display: block; width: 100%; height: auto; border-radius: var(--r);
  box-shadow: 0 1px 2px rgba(20,19,24,.05), 0 26px 64px rgba(20,19,24,.10);
}
.shot-live[hidden], .shot-real[hidden] { display: none !important; }

/* ══ the two price cards line up ═════════════════════════════════════════
   Blake: "make sure they line up".

   The terms line under the price is one sentence on one card and two on the
   other, so the button underneath started at a different height on each and
   the eye read the pair as crooked. The line reserves two lines' worth of
   space whatever it says, so every card puts its button on the same
   baseline. A card should not move because its copy is a word longer.
   ═══════════════════════════════════════════════════════════════════════ */
.price-was { min-height: 3.2em; }
@media (max-width: 900px) { .price-was { min-height: 0; } }

/* ══ §22 THE PHONE ══════════════════════════════════════════════════════
   1 October. Blake: "make sure mobile version it looks excellent as some
   stuff looks a little out of place".

   Found by measuring all ten pages at 360, 375, 390 and 430, which is what
   phones actually are, rather than at the one breakpoint a desktop browser
   gets dragged to. tools/mobile-check.cjs is the sweep.

   Three classes of fault, and one deliberate exclusion.

   TAP TARGETS. Apple's floor is 44 by 44 and almost nothing here met it:
   the menu button was 40 square, and 25 square at 360 where the padding
   collapsed. Most of these are fixed by growing the HIT AREA rather than
   the artwork, with an inset pseudo element. A 26px colour swatch should
   look like a 26px swatch and behave like a 44px button, and six of them
   grown to 44 would not fit across a 360px screen anyway.

   TYPE. Micro labels ran as low as 9.5px and real sentences as low as
   11.5px. Raised to 11 and 14, which are the floors below which a phone
   stops being readable at arm's length.

   WHAT IS DELIBERATELY LEFT ALONE: the insides of the product mockups
   (.ui-, .ap-, .fl-). Those are pictures of an interface that happen to be
   built from HTML. Scaling their type up would break the illusion and the
   proportions, and nobody is meant to read them; they are meant to look
   like a screen. The text a visitor actually reads is all outside them.
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width: 560px) {

  /* ── A. the hit areas ─────────────────────────────────────────────── */
  /* The menu is the only navigation on a phone, so this one grows for real
     rather than hiding a bigger target behind a small glyph. */
  .burger {
    min-width: 44px; min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
  }

  /* The rest keep their drawn size and gain the reach. inset is negative so
     the area grows outwards; nothing shifts on the page. */
  .hdr-logo, .ftr-logo a, .wl-c, .rm-chip, .back, .logo,
  .tryit-egs button, .hdr-signin { position: relative; }
  .hdr-logo::after, .ftr-logo a::after, .wl-c::after, .back::after,
  .logo::after, .hdr-signin::after {
    content: ''; position: absolute; left: 0; right: 0;
    top: 50%; transform: translateY(-50%); height: 44px; min-height: 100%;
  }
  .wl-c::after { left: -9px; right: -9px; }
  /* These two are wide enough already and only short in one direction. */
  .rm-chip, .tryit-egs button, .wl-in, .tryit-f input { min-height: 44px; }

  /* ── B. the type floors ───────────────────────────────────────────── */
  /* Every micro label to 12. Listed by hand from the sweep rather than
     caught with a wildcard, because a wildcard would also have hit the
     insides of the mockups, which must not move. */
  .eyebrow, .tl-q, .fig-k, .rm-tag, .rm-bar-l, .wl-lab, .say-h, .kicker,
  .rm-teaser-go, .ftr-h, .role-tags b, .flow-head span,
  .gseal-col h4 { font-size: 12px; }

  /* A segmented toggle and a chart legend. Short enough that 14 fits, and
     on a phone a thing you are meant to tap should not be the smallest
     text on the screen. */
  .rep-seg span, .rep-leg span { font-size: 14px; }
  .rep-top em { font-size: 14px; }

  /* Two pixels short of the floor at 430 only, which is still short. */
  .hero-pill { min-height: 44px; }

  /* Every sentence to 14. Anything a visitor is expected to read. */
  .rep-sub, .price-tag, .small, .muted, .gseal-t, .rail-note, .reassure,
  .vs-note, .addon-n, .price-was, .vlive, .tryit-prov, .tryit-note,
  .role-pack span, .role-meta, .ftr-legal, .nw-from,
  .rep-bar b, .rep-bar b span, .gmark span, .gmark span b,
  .flow-step b, .foot span, .field label, .panel .row .reassure,
  .gseal-lead, .gseal-note, .gseal-col li, .gseal-col li b { font-size: 14px; }
  .small.muted, p.small { font-size: 14px; line-height: 1.6; }
  .rep-pane p, .rep-pane .small, .rep-note { font-size: 14px; }

  /* The honeypot is meant to be unreachable, so it is exempt from all of
     the above. Growing it would be growing a trap for bots into something
     a person might find. */
  .hp, .hp * { font-size: 1px; }

  /* GROWING THE MENU BUTTON BROKE THE BAR, WHICH IS WORTH RECORDING.
     At 360 the pill holds 16px of padding, a 133px logo, a 129px trial
     button and a 24px gap on each side. Add a 44px button to that and it
     needs 378px of a 360px screen, so the button hung 10px out of the
     pill. The two gaps and the left padding give the 32px back. Caught by
     the same sweep on the next run, which is the only reason it is not
     shipping. */
  .hdr-in { gap: 10px; padding-left: 12px; }

  /* THE CHIP ROW, WHICH IS THE THING BLAKE ACTUALLY SAW.
     Line 213 already stacked these into a column on a phone and gave the
     container a card radius instead of a pill. Line 670, three hundred
     lines later and outside any media query, sets border-radius back to
     the pill at the same specificity, so the later rule won: three rows
     of text inside a 999px lozenge, with the highlighted first row's own
     pill cutting through the corner. Read the winning rule, not the first
     one.

     Stacked, it should read as a small card with three lines in it. */
  .chips {
    border-radius: var(--r); align-items: stretch; width: 100%;
    padding: 6px; gap: 2px;
  }
  .chip { border-radius: calc(var(--r) - 8px); justify-content: flex-start; padding: 11px 14px; }

  /* The reporting mock's top row is a nowrap flex holding a label, a date
     and a four way Week/Month/Quarter/Year control. That needs 419px and
     gets 340, so the control hung 99px out of the card. It wraps onto its
     own line instead, and can scroll if even that is not enough. */
  .rep-top { flex-wrap: wrap; }
  .rep-seg { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }

  /* ── C. the one real overflow ─────────────────────────────────────── */
  /* A 1fr column carries an implicit min-content floor, so "Commission /
     Uncapped / on new business" refused to shrink and pushed the grid 22px
     past its own container. minmax(0,1fr) lets it wrap instead. */
  .role-pack { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

@media (max-width: 420px) {
  /* Two columns of that card stop being worth it this narrow. */
  .role-pack { grid-template-columns: minmax(0, 1fr); }
}

/* ══ PAIGE, the embedded product film ═════════════════════════════════
   The section furniture only. What is inside the frame is the platform,
   with the platform's own look, exactly like the .vshot video embeds
   further down the page. A marketing site that restyles its own product
   is showing you something that does not exist.

   Below 860px the iframe is swapped for a tap card that opens the film
   full screen. A scrolling frame inside a scrolling page traps the
   thumb on a phone and there is no CSS that fixes that.
   ═══════════════════════════════════════════════════════════════════ */
.pg-frame {
  position: relative; border-radius: var(--r-lg); padding: 26px; overflow: hidden;
  margin-top: var(--s9);
}
.pg-card { margin-top: var(--s9); }
/* The site's .vcap is a two column caption built for one short line of
   text. This paragraph is longer than that, so the left column emptied
   out and the whole block read as an accident. Centred, with the three
   honest caveats as their own small cards, so the disclosure is part of
   the design rather than a wall of small print. */
.pg-cap { text-align: center; margin-top: var(--s8); }
.pg-cap h3 { margin: var(--s4) 0 var(--s3); font-size: clamp(24px, 2.6vw, 32px); }
.pg-cap > p { max-width: 54ch; margin: 0 auto; color: var(--ink-soft); font-size: 17px; }
.pg-facts {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s4);
  max-width: 920px; margin: var(--s7) auto 0; text-align: left;
}
.pg-fact {
  background: var(--card); border: 1px solid var(--card-line);
  border-radius: var(--r); padding: var(--s5);
}
.pg-fact b {
  display: block; font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: .09em; text-transform: uppercase; color: var(--coral);
  margin-bottom: var(--s3);
}
.pg-fact span { display: block; font-size: 15px; line-height: 1.55; color: var(--ink-soft); }
.pg-cap .pg-full { display: inline-block; margin-top: var(--s6); font-size: 15.5px; }
@media (max-width: 820px) { .pg-facts { grid-template-columns: 1fr; } }
.pg-frame iframe {
  display: block; width: 100%; aspect-ratio: 4 / 3; border: 0;
  border-radius: var(--r); background: var(--card);
  box-shadow: 0 1px 2px rgba(15,14,19,.05), 0 18px 48px rgba(15,14,19,.13);
}
.pg-card { display: none; }
.pg-full {
  color: var(--coral); text-decoration: none; border-bottom: 1px solid rgba(229,73,77,.35);
  white-space: nowrap;
}
.pg-full:hover { color: var(--coral); border-bottom-color: var(--coral); }

@media (max-width: 860px) {
  .pg-frame { display: none; }
  .pg-card {
    display: block; text-decoration: none; color: inherit; margin-top: var(--s7);
    border-radius: var(--r-lg); padding: var(--s8) var(--s5); text-align: center;
    border: 1px solid var(--card-line);
    background:
      radial-gradient(circle at 12% 14%, rgba(246,185,190,.55) 0%, rgba(246,185,190,0) 46%),
      radial-gradient(circle at 86% 10%, rgba(255,162,77,.45) 0%, rgba(255,162,77,0) 44%),
      radial-gradient(circle at 88% 88%, rgba(205,188,230,.5) 0%, rgba(205,188,230,0) 48%),
      var(--card);
  }
  .pg-card-play {
    width: 62px; height: 62px; margin: 0 auto var(--s5); border-radius: var(--r-pill);
    background: var(--coral); display: grid; place-items: center;
    box-shadow: 0 6px 20px rgba(229,73,77,.34);
  }
  .pg-card-play svg { width: 22px; height: 22px; margin-left: 3px; }
  .pg-card h3 { margin: 0 0 var(--s2); font-size: 21px; }
  .pg-card p { margin: 0; color: var(--ink-soft); font-size: 15px; }
}


/* ══ PAIGE ON YOUR PHONE, the standing showcase ═══════════════════════
   The film shows this for twenty seconds and then it is gone. This block
   stays on the page, because the phone is the thing Paige is eventually
   FOR and a feature nobody can look at twice is not a feature.

   Rendered in the site's own type and colour rather than the platform's,
   because unlike the film this is not a recording of a product. It is a
   picture of one that does not exist yet, and it says so.
   ═══════════════════════════════════════════════════════════════════ */
.pg-app {
  margin-top: var(--s10); border-radius: var(--r-lg);
  padding: var(--s9) var(--s8);
  border: 1px solid var(--card-line);
  background:
    radial-gradient(circle at 10% 12%, rgba(246,185,190,.5) 0%, rgba(246,185,190,0) 46%),
    radial-gradient(circle at 88% 8%, rgba(255,162,77,.42) 0%, rgba(255,162,77,0) 44%),
    radial-gradient(circle at 90% 90%, rgba(205,188,230,.46) 0%, rgba(205,188,230,0) 48%),
    var(--card);
  display: flex; align-items: center; justify-content: center;
  gap: var(--s10); flex-wrap: wrap; text-align: left;
}
.pg-ph {
  width: 272px; height: 556px; flex: 0 0 auto; border-radius: 42px;
  background: var(--ink); padding: 12px;
  box-shadow: 0 24px 60px rgba(15,14,19,.3);
}
.pg-scr {
  width: 100%; height: 100%; border-radius: 31px; background: var(--paper);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s6); padding: var(--s6) var(--s5); position: relative; overflow: hidden;
}
.pg-soon {
  position: absolute; top: 18px; left: 50%; transform: translateX(-50%);
  font-family: var(--mono); font-size: 10px; font-weight: 500; letter-spacing: .09em;
  text-transform: uppercase; color: #8A5A12; background: #F8EFDE;
  padding: 5px 11px; border-radius: var(--r-pill); white-space: nowrap;
}
.pg-orb {
  width: 112px; height: 112px; border-radius: var(--r-pill); display: grid; place-items: center;
  background: linear-gradient(150deg, var(--flame), var(--coral));
  box-shadow: 0 0 0 0 rgba(229,73,77,.4); animation: pgOrb 2.6s ease-out infinite;
}
.pg-orb svg { width: 54px; height: 54px; }
@keyframes pgOrb {
  0% { box-shadow: 0 0 0 0 rgba(229,73,77,.4); }
  70% { box-shadow: 0 0 0 32px rgba(229,73,77,0); }
  100% { box-shadow: 0 0 0 0 rgba(229,73,77,0); }
}
.pg-said {
  font-family: var(--display); font-size: 18px; font-weight: 500; line-height: 1.35;
  color: var(--ink); text-align: center; min-height: 100px;
  display: flex; align-items: flex-start; justify-content: center;
}
.pg-wave { display: flex; align-items: flex-end; gap: 4px; height: 26px; }
.pg-wave i { width: 4px; border-radius: 2px; background: var(--coral); animation: pgWv 1s ease-in-out infinite; }
.pg-wave i:nth-child(1) { height: 40%; animation-delay: 0s; }
.pg-wave i:nth-child(2) { height: 86%; animation-delay: .12s; }
.pg-wave i:nth-child(3) { height: 56%; animation-delay: .24s; }
.pg-wave i:nth-child(4) { height: 100%; animation-delay: .36s; }
.pg-wave i:nth-child(5) { height: 62%; animation-delay: .48s; }
.pg-wave i:nth-child(6) { height: 34%; animation-delay: .6s; }
@keyframes pgWv { 50% { transform: scaleY(.38); } }

.pg-app-txt { max-width: 500px; min-width: 0; flex: 1 1 400px; }
.pg-app-txt h3 { font-size: clamp(30px, 3.6vw, 44px); margin: var(--s4) 0 var(--s5); }
.pg-app-txt > p { color: var(--ink-soft); font-size: 17px; margin: 0; }
.pg-asks { list-style: none; margin: var(--s6) 0 var(--s5); padding: 0; display: flex; flex-direction: column; gap: 2px; }
.pg-asks li {
  display: flex; align-items: flex-start; gap: var(--s3);
  padding: var(--s3) var(--s4); border-radius: var(--r-sm);
  font-size: 16px; line-height: 1.45; color: var(--ink-soft);
  transition: background .4s ease, color .4s ease;
}
.pg-asks li .n {
  width: 23px; height: 23px; border-radius: var(--r-pill); flex: 0 0 auto;
  display: grid; place-items: center; font-family: var(--mono); font-size: 11px; font-weight: 500;
  background: rgba(255,255,255,.8); color: var(--ink-faint); margin-top: 1px;
  transition: background .4s ease, color .4s ease;
}
.pg-asks li.on { background: rgba(255,255,255,.9); color: var(--ink); font-weight: 500; }
.pg-asks li.on .n { background: var(--coral); color: #fff; }
.pg-honest { font-size: 15px; color: var(--ink-faint); margin: 0; }
.pg-honest b { color: var(--ink-soft); font-weight: 600; }

@media (max-width: 900px) {
  .pg-app { padding: var(--s8) var(--s5); gap: var(--s8); text-align: center; }
  .pg-app-txt { flex: 1 1 100%; }
  .pg-asks li { text-align: left; }
  .pg-ph { width: 236px; height: 484px; }
}
@media (prefers-reduced-motion: reduce) {
  .pg-orb, .pg-wave i { animation: none; }
}
