/* =========================================================================
   PANOpeak landing page

   The design language is taken from the wordmark, which is a line drawing:
   flat sage strokes, mitred corners, a mountain contour, ONE terracotta dot,
   and — carrying the whole thing — a heavy horizontal rule the letters stand
   on. So the page is built out of rules, not cards. Sections are separated by
   full-bleed hairlines; a section's title sits under a 2px rule the same
   weight as the mark's baseline; stats, plans and the demo row are ruled
   tables with dividers rather than boxes with radii and shadows.

   Three rules for anyone editing this file:

     1. Colour comes from design-tokens.css. Never hardcode a hex here.
     2. Terracotta appears ONCE per screenful, and it means "live". The
        guardrail marker and the live-demo state are the only things entitled
        to it. If you add a second one, one of them is decoration.
     3. No section-heading eyebrows, no floating badge pills, no tilted
        screenshots in fake browser chrome, no radial glows. Those were all
        here before and they are what made the page look generated.
   ========================================================================= */

html { scroll-behavior: smooth; }
body { font-size: var(--fs-xl); }

/* ---- Phase switching -------------------------------------------------- */
/* The phase is set on <html data-phase="waitlist|live"> (see js/landing.js) */
[data-phase="waitlist"] [data-p2] { display: none !important; }
[data-phase="live"]     [data-p1] { display: none !important; }

/* ---- Layout primitives ------------------------------------------------- */
.container {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 32px;
}
@media (max-width: 720px) { .container { padding: 0 20px; } }

.section { padding: 104px 0; }
@media (max-width: 720px) { .section { padding: 64px 0; } }

/*
 * Section divider. Full-bleed on purpose: a rule that stops at the container
 * edge reads as the bottom of a card, and a rule that crosses the whole
 * viewport reads as the page itself being ruled. That is the difference the
 * whole layout rests on.
 *
 * The old version centred a rotated square on the line as an ornament; it is
 * gone. The mark has no ornaments in it.
 */
.mountain-rule {
  height: 1px;
  border: 0;
  background: var(--border-default);
  margin: 0;
}

/* ---- Display type ------------------------------------------------------
 * One mixin, applied by every heading below. Archivo's wdth axis is pushed to
 * 115 so headings echo the wordmark's stretched letterforms, and tracking is
 * pulled in to compensate — wide letterforms at default tracking look loose.
 */
.hero h1,
.section-head h2,
.floor-band h2,
.final-cta h2,
.step h3,
.legal-head h1,
.legal h2 {
  font-family: var(--font-display);
  font-variation-settings: "wdth" var(--wdth-display);
  font-weight: 600;
  letter-spacing: -0.025em;
  color: var(--fg-strong);
  text-wrap: balance;
}

/* ---- Buttons -----------------------------------------------------------
 * Square. The 8px-radius pill was the single strongest thing making this page
 * look like every other landing page, and the mark it sits under does not
 * contain one curve that isn't a letter or the dot.
 */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: 550;
  line-height: 1;
  letter-spacing: 0.005em;
  padding: 15px 26px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.btn-primary {
  background: var(--accent-primary);
  color: var(--accent-primary-fg);
}
.btn-primary:hover { background: var(--accent-primary-hover); }

.btn-ghost {
  background: transparent;
  color: var(--fg-strong);
  border-color: var(--border-strong);
}
.btn-ghost:hover { border-color: var(--fg-strong); background: transparent; }

.btn-sm { padding: 10px 16px; font-size: var(--fs-base); }

/* ---- Navbar ------------------------------------------------------------
 * Opaque, not frosted. The blurred translucent bar is a stock effect and it
 * made the sage wordmark sit on a smeared version of whatever scrolled under
 * it; on paper stock the mark should sit on paper.
 */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--bg-canvas);
  border-bottom: 1px solid var(--border-default);
}
.nav-inner {
  display: flex;
  align-items: center;
  gap: 32px;
  height: 68px;
}
.nav-logo {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--fg-strong);
}
.nav-logo .brandmark-text {
  font-size: var(--fs-xl);
  letter-spacing: 0.04em;
  font-weight: 600;
}
.brandmark-img {
  height: 26px;
  width: auto;
  display: block;
  /* Optical centring, and it is a property of the FILE rather than a fudge.
     The mark's ink spans rows 24-497 of its 520-unit box, but that includes
     the terracotta dot floating above the A (rows 24-101): the letterforms
     themselves run 141-419, whose centre sits at 53.85% of the height, not
     50%. Centring the bounding box therefore hangs the wordmark 3.85% of its
     own height too low beside any text. Measured off the rendered pixels, not
     the paths — the file is a VTracer raster trace, so its 85 paths are
     anti-aliasing fringes and their bboxes say nothing. A percentage rather
     than a pixel count so it survives the height changing. */
  transform: translateY(-3.85%);
}
/* The header mark. Its own rule rather than a variant of .brandmark-img,
   because the -3.85% optical shift there is measured off the WORDMARK's ink
   and means nothing for this file: the mark's viewBox is already trimmed to
   its own ink, so its bounding box and its optical centre are the same thing.
   The full wordmark still runs everywhere else on the site, footer included. */
.brandmark-mark {
  height: 28px;
  width: auto;
  display: block;
}
.nav-links {
  display: flex;
  gap: 28px;
  margin-right: auto;
}
/* Hover is an underline at the mark's own baseline offset, not a grey pill. */
.nav-links a {
  color: var(--fg-muted);
  text-decoration: none;
  font-size: var(--fs-md);
  padding: 4px 0;
  /* The transparent TOP border earns its place: the bottom one is the hover
     underline, and 2px on one side only makes flex centring put the text 1px
     above the box's own centre — which reads as the logo beside it hanging
     low. Balancing it costs 2px of height in a 68px bar and nothing else. */
  border-top: 2px solid transparent;
  border-bottom: 2px solid transparent;
}
.nav-links a:hover { color: var(--fg-strong); border-bottom-color: var(--fg-strong); }
.nav-cta { display: flex; gap: 12px; align-items: center; }

/* ---- Nav hamburger (mobile/tablet-narrow only) -------------------------- */
.nav-toggle-checkbox { display: none; }
.nav-toggle-label { display: none; }

@media (max-width: 860px) {
  .nav-inner {
    flex-wrap: wrap;
    height: auto;
    row-gap: 10px;
    padding-top: 14px;
    padding-bottom: 14px;
    gap: 12px;
  }
  .nav-logo { order: 1; }
  .nav-cta {
    order: 2;
    margin-left: auto;
    flex-wrap: wrap;
    justify-content: flex-end;
    row-gap: 8px;
  }
  .nav-cta .btn { white-space: nowrap; }
  .nav-toggle-label {
    order: 3;
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 4px;
    width: 34px;
    height: 34px;
    margin-left: 4px;
    cursor: pointer;
    border: 1px solid var(--border-strong);
    border-radius: var(--r-sm);
  }
  .nav-toggle-label span {
    display: block;
    width: 16px;
    height: 2px;
    background: var(--fg-strong);
  }
  .nav-links {
    order: 4;
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    gap: 0;
    margin: 0;
    border-top: 1px solid var(--border-default);
    padding-top: 4px;
  }
  .nav-toggle-checkbox:checked ~ .nav-links { display: flex; }
  .nav-links a {
    padding: 12px 0;
    border-bottom: 1px solid var(--border-subtle);
  }
  .nav-links a:hover { border-bottom-color: var(--border-subtle); }
}

@media (max-width: 400px) {
  .nav-cta .btn-sm { padding: 9px 12px; font-size: var(--fs-sm); }
}

/* ---- Hero --------------------------------------------------------------
 * Asymmetric and left-set, and it ends on a 2px rule that runs the full width
 * of the viewport — the wordmark's baseline, at page scale. That rule is the
 * hero's whole visual idea, which is why there is no glow behind it and no
 * badge above the H1.
 */
.hero { padding: 96px 0 0; position: relative; }
.hero-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr 1.02fr;
  gap: 64px;
  align-items: end;
  padding-bottom: 72px;
}
@media (max-width: 960px) {
  .hero-grid { grid-template-columns: 1fr; gap: 44px; padding-bottom: 56px; }
}

.hero h1 {
  font-size: clamp(2.75rem, 6.4vw, 4.75rem);
  line-height: 0.98;
  margin: 0 0 28px;
}
/* Archivo ships no italic in the subset vendored here, so an <em> would be a
   sheared roman. Colour carries the emphasis instead. */
.hero h1 em { font-style: normal; color: var(--accent-primary); }

.hero-sub {
  font-size: var(--fs-2xl);
  line-height: 1.62;
  color: var(--fg-muted);
  max-width: 30em;
  margin: 0 0 36px;
}
.hero-cta-row { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }

/*
 * Deliberately empty of the "no credit card · 14-day trial · setup in 60
 * seconds" line that used to live here. If there is a real, specific offer to
 * make it belongs in the pricing section next to the prices it modifies, and
 * it is stated there once.
 */
.hero-micro { display: none; }

.hero-counter {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--fg-muted);
  margin-top: 28px;
  display: none; /* shown by JS only when count ≥ 50 — never fake it */
}

.hero-visual { position: relative; align-self: end; }

/* The contour from the mark, drawn once, at the size of the page: a filled
   ridge sitting on the hero's baseline rule, in the palest sage. It is the only
   ornament on the page and it is the logo's own shape, not a generic blob. */
.hero-mountain-bg {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /*
   * `width: 100%` is load-bearing, not redundant with left/right.
   *
   * An <svg> with a viewBox and no width attribute is a replaced element with
   * an intrinsic aspect ratio (600x300 here, so 2:1). For an absolutely
   * positioned replaced element, `width: auto` resolves to the INTRINSIC width
   * — aspect ratio times the definite height — and left/right/width are then
   * over-constrained, so `right` is dropped. The mountain was therefore always
   * 2 x 46% of the hero's HEIGHT, whatever the hero's width: 911px inside an
   * 870px hero at desktop, and 760px inside a 375px one on a phone, where it
   * pushed the whole page into horizontal scroll.
   *
   * With an explicit width the auto/intrinsic path is never taken and the band
   * spans exactly its container. `preserveAspectRatio="none"` on the element
   * means the path stretches to fill rather than being letterboxed, which is
   * what a decorative band across the hero wants.
   */
  width: 100%;
  height: 46%;
  z-index: 0;
  color: var(--sage-100);
  pointer-events: none;
}
/* --sage-100 is a fixed light value, not a themed token, so on the dark ground
   it lit up as a near-white mountain across the whole hero. Dark gets its own
   fill: one step off the canvas, visible but not competing with the headline. */
[data-theme="dark"] .hero-mountain-bg { color: oklch(0.195 0.020 145); }

/* No rotation, no drop shadow, no lift-on-hover. A product screenshot shown
   flat and square is a screenshot; the same one tilted in perspective with a
   soft shadow is a stock illustration of a screenshot. */
.hero-frame { position: relative; z-index: 1; }

/* The mark's baseline, at page width. */
.hero::after {
  content: "";
  display: block;
  height: 2px;
  background: var(--fg-strong);
}

/* ---- Screenshot frames --------------------------------------------------
 * `.app-frame-bar` — the traffic-light dots and the fake URL pill — is removed
 * from the markup. It dressed real screenshots up as mockups.
 */
.app-frame {
  background: none;
  border: 0;
  border-radius: var(--r-xl);
  margin: 0;
}
/* <picture> is an inline element, and an inline box around a block image still
   contributes a line box: without this the frame gains a few pixels of
   descender space under every screenshot. The AVIF sources hang off these
   wrappers (scripts/optimize-images.mjs writes the files). */
.app-frame picture { display: block; }

/* The rule goes on the image, not on a wrapper, so the caption below it sits
   outside the frame the way a plate caption does. */
.app-frame img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border-strong);
}

/* Caption under a screenshot: which screen this actually is. Replaces the
   fake address bar with the same information, stated as a caption. */
.app-frame-caption {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.04em;
  color: var(--fg-subtle);
  margin-top: 10px;
}

/* ---- Marketplace strip --------------------------------------------------- */
.proof-strip {
  border-top: 1px solid var(--border-default);
  border-bottom: 1px solid var(--border-default);
  padding: 22px 0;
}
/*
 * Two rows, not two columns. The grouping is the point — direct integrations
 * versus Mirakl storefronts — but this sits in a band under the hero, and two
 * stacked lists would make it five lines tall. A mono label plus an inline run
 * of names carries the same hierarchy in two.
 */
.proof-inner {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.proof-row {
  display: flex;
  align-items: baseline;
  gap: 18px;
  flex-wrap: wrap;
}
.proof-label {
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-primary);
  /* Fixed so the two rows' names start on the same x — the grouping only reads
     as a grouping if the second column lines up. */
  flex: 0 0 88px;
}
.proof-names { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0; }
.proof-name {
  font-size: var(--fs-base);
  color: var(--fg-strong);
  font-weight: 500;
  white-space: nowrap;
}
/*
 * Separator drawn by CSS, not typed into the markup, so no translator has to
 * carry punctuation and no name can be shipped without its dot.
 *
 * ::after on every name but the last, NOT ::before on every name but the
 * first. A leading dot belongs to the box that follows it, so when the run
 * wraps the browser puts the dot at the START of the new line and you get
 * "· TikTok Shop" hanging off the left margin. Trailing it keeps the dot with
 * the name it follows.
 */
.proof-name:not(:last-child)::after {
  content: "\00b7";
  color: var(--fg-subtle);
  font-weight: 400;
  padding: 0 10px;
}
.proof-note {
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  color: var(--fg-subtle);
}
@media (max-width: 560px) {
  /* Under the label rather than beside it: at this width a fixed 88px gutter
     leaves the names about four characters of room. */
  .proof-row { flex-direction: column; gap: 4px; }
  .proof-label { flex: none; }
}

/*
 * The channel marker on the live-demo listing row. NOT proof-strip furniture:
 * this one mirrors the `Marketplace` component in the app, because that row is
 * a picture of the product and the pill is what the product actually renders.
 * Only bol survives — the other five colours went with the old strip, which
 * was the only thing using them.
 */
.mk-pill {
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: #fff;
  border-radius: var(--r-full);
  padding: 4px 7px;
  line-height: 1;
}
.mk-bol { background: oklch(0.45 0.16 262); }

/* ---- Section headers -----------------------------------------------------
 * A masthead, not a centred stack: 2px rule, then the title on the left and
 * the standfirst on the right. Nothing sits above the title — the small caps
 * tag that used to ("THE PROBLEM", "HOW IT WORKS", … on all seven sections)
 * is gone, and the section's <h2> says the same thing in words.
 */
.section-head {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 24px 56px;
  align-items: start;
  border-top: 2px solid var(--fg-strong);
  padding-top: 26px;
  margin-bottom: 64px;
}
@media (max-width: 820px) {
  .section-head { grid-template-columns: 1fr; gap: 16px; margin-bottom: 44px; }
}

/* The centred variant is intentionally inert. Every section using it now gets
   the same left-set masthead; three centred stacks down one page was the
   symmetry that made it all feel machine-laid-out. */
.section-head--center { margin-left: 0; margin-right: 0; text-align: left; }
.text-center { text-align: left; }

.section-head h2 {
  font-size: clamp(2rem, 4vw, 3rem);
  line-height: 1.02;
  margin: 0;
}
.section-head p {
  font-size: var(--fs-lg);
  line-height: 1.62;
  color: var(--fg-muted);
  margin: 0;
  padding-top: 6px;
}

/* ---- Problem stats -------------------------------------------------------
 * Three ruled columns, not three cards. Same three facts, no boxes, no
 * shadows, no radii — the dividers do the separating.
 */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border-top: 1px solid var(--border-default);
  border-bottom: 1px solid var(--border-default);
  margin-bottom: 56px;
}
@media (max-width: 820px) {
  .stat-grid { grid-template-columns: 1fr; }
}
.stat-card {
  background: none;
  border: 0;
  border-right: 1px solid var(--border-default);
  /* No radius: this is a RULE, not a box — see the note on .demo-row. */
  border-radius: 0;
  box-shadow: none;
  padding: 30px 32px 32px 0;
  padding-left: 32px;
}
.stat-card:first-child { padding-left: 0; }
.stat-card:last-child { border-right: 0; }
@media (max-width: 820px) {
  .stat-card {
    border-right: 0;
    border-bottom: 1px solid var(--border-default);
    padding: 24px 0;
  }
  .stat-card:last-child { border-bottom: 0; }
}
/* Two of the three values are words ("every 30 sec", "6+ hours"), so these are
   set in the display face rather than forced into the mono figure style. */
.stat-num {
  font-family: var(--font-display);
  font-variation-settings: "wdth" var(--wdth-display);
  font-weight: 600;
  letter-spacing: -0.02em;
  font-size: var(--fs-display-xl);
  line-height: 1.05;
  color: var(--fg-strong);
  margin: 14px 0 10px;
}
.stat-num .accent-loss { color: var(--accent-warm); }
.stat-sub { font-size: var(--fs-md); color: var(--fg-muted); line-height: 1.55; margin: 0; }

.problem-narrative {
  font-size: var(--fs-lg);
  line-height: 1.7;
  color: var(--fg-muted);
  max-width: 62ch;
  margin: 0;
}

/* ---- How it works --------------------------------------------------------- */
.steps { display: flex; flex-direction: column; gap: 0; }
.step {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: 56px;
  align-items: center;
  padding: 56px 0;
  border-top: 1px solid var(--border-default);
}
.step:first-child { border-top: 0; padding-top: 0; }
.step:nth-child(even) .step-copy { order: 2; }
@media (max-width: 900px) {
  .step, .step:nth-child(even) { grid-template-columns: 1fr; gap: 28px; }
  .step:nth-child(even) .step-copy { order: 0; }
}
/* The index sits in the margin as a figure, alongside a short rule — the way a
   spec sheet numbers a clause. */
.step-num {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--accent-primary);
  letter-spacing: 0.1em;
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 18px;
}
.step-num::after {
  content: "";
  height: 1px;
  width: 44px;
  background: var(--accent-primary);
}
.step h3 {
  font-size: var(--fs-display-sm);
  line-height: 1.08;
  margin: 0 0 14px;
}
.step p { font-size: var(--fs-lg); line-height: 1.62; color: var(--fg-muted); margin: 0; }
.step .app-frame { box-shadow: none; }

/* ---- Floor guarantee (inverted band) ---------------------------------------
 * A genuinely inverted spread, in deep forest rather than black, with the rule
 * system carried through. No spotlight gradient behind it.
 */
.floor-band {
  background: var(--bg-canvas);
  color: var(--fg-default);
  border-top: 2px solid var(--fg-strong);
  border-bottom: 2px solid var(--fg-strong);
  padding: 96px 0;
}
.floor-grid {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 72px;
  /* `start` left the card hanging from the top of a column as tall as the
     prose beside it, so it read as a small object stranded in the dark rather
     than as the other half of a two-part statement. Centring it against the
     text is what makes the band look composed; the card is deliberately short,
     so the fix is where it sits, not how big it is. */
  align-items: center;
}
@media (max-width: 900px) { .floor-grid { grid-template-columns: 1fr; gap: 44px; } }
.floor-band h2 {
  font-size: clamp(2rem, 4.2vw, 3.125rem);
  line-height: 1.02;
  margin: 0 0 24px;
}
.floor-band p {
  font-size: var(--fs-lg);
  line-height: 1.7;
  color: var(--fg-muted);
  max-width: 56ch;
  margin: 0;
}

/* Margin-guardrails widget. Flat and ruled; terracotta is reserved for the
   live price and nothing else on this screen.

   SPACING: one rhythm, stated once. The old version set a 28px margin under
   the title AND a 30px margin over the track, which read as a 58px hole nobody
   had chosen, then let the labels collide with the note's rule. Every gap here
   is deliberate and the reserved line for the limit message means dragging to
   an end does not shunt the note down. */
.guardrail-card {
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  padding: 26px 26px 24px;
  box-shadow: none;
}
.guardrail-title {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-subtle);
  margin: 0 0 24px;
}
/* The live price: the number the slider is FOR, so it leads the card. */
.guardrail-readout { margin: 0 0 18px; }
.guardrail-price {
  font-family: var(--font-display);
  font-variation-settings: "wdth" var(--wdth-display);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-display-xs);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--fg-strong);
}
.guardrail-range {
  display: block;
  width: 100%;
  margin: 0 0 10px;
  /* Terracotta, because the thumb is the live price and that is the one thing
     this palette paints warm. */
  accent-color: var(--accent-warm);
  cursor: pointer;
}
.guardrail-range:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.guardrail-labels {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-sm);
  color: var(--fg-subtle);
}
/* The wall. A reserved line rather than one that appears and disappears: the
   card must not resize while a thumb is under the visitor's finger. */
.guardrail-limit {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.04em;
  margin: 16px 0 0;
  /* One line reserved, so the card never resizes while a thumb is under the
     visitor's finger. All five translations fit on one line at this size
     (the longest, French at 32 characters, measures ~349px against ~439px of
     inner width). A sixth language that does not fit would wrap and reintroduce
     the shift, so check it against this width before adding one. */
  min-height: 1.3em;
  color: var(--accent-warm);
  opacity: 0;
  transition: opacity 120ms ease;
}
.guardrail-limit.is-shown { opacity: 1; }
.guardrail-note {
  font-size: var(--fs-base);
  line-height: 1.6;
  color: var(--fg-muted);
  border-top: 1px solid var(--border-default);
  margin: 4px 0 0;
  padding-top: 16px;
}
.guardrail-note strong {
  color: var(--fg-strong);
  font-family: var(--font-mono);
  font-size: var(--fs-mono-inline);
  font-weight: 600;
}

/* ---- Live demo -------------------------------------------------------------
 * A ruled row of the same shape the product's own listing table uses.
 */
.demo-row {
  background: none;
  border: 0;
  border-top: 1px solid var(--border-default);
  border-bottom: 1px solid var(--border-default);
  /*
   * NO RADIUS. This is a ruled row, not a card: `background: none` and a border
   * on two edges only.
   *
   * Soft Sage's token remap (31fe66f) mapped all fourteen hardcoded
   * `border-radius: 0` in this file onto the ladder, by each element's ROLE.
   * Six of those roles were read wrong — this one, `.stat-card`, `.plan`,
   * `.founding-banner`, `.waitlist-form` and `.legal-draft-note` all draw a
   * rule or an accent rail on one or two edges and fill nothing. A radius on a
   * partial border curves the ends of that rule inward with no adjacent edge to
   * meet, which renders as a hook hanging in space — the "broken pill" this
   * fixes.
   *
   * The test before adding a radius here: does the element have a background or
   * a border on all four sides? If not, it has no corners to round.
   */
  border-radius: 0;
  box-shadow: none;
  padding: 26px 0;
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: 40px;
  align-items: center;
  max-width: none;
  margin: 0;
}
@media (max-width: 760px) {
  .demo-row { grid-template-columns: 1fr auto; gap: 20px 24px; }
}
.demo-product { min-width: 0; }
.demo-title { font-size: var(--fs-md); font-weight: 600; color: var(--fg-strong); }
.demo-sku {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  margin-top: 6px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.demo-price-label {
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-subtle);
  margin-bottom: 6px;
}
.demo-price {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-4xl);
  font-weight: 600;
  color: var(--fg-strong);
  transition: color 300ms ease;
}
.demo-price.drop { color: var(--terra-500); }
.demo-price.rise { color: var(--accent-primary); }

/* Square, ruled, no fill — a state label, not a badge. */
.demo-badge {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  border-radius: var(--r-full);
  padding: 6px 10px;
  white-space: nowrap;
  border: 1px solid currentColor;
}
.demo-badge.win  { background: transparent; color: var(--accent-primary); }
.demo-badge.loss { background: transparent; color: var(--terra-600); }
.demo-caption {
  text-align: left;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--fg-subtle);
  margin-top: 18px;
  min-height: 18px;
}

/* ---- Pricing -----------------------------------------------------------------
 * A price table: three columns divided by vertical rules. Not three floating
 * cards, and the recommended plan is marked by a rule and an inline label
 * rather than a pill hovering over its top edge.
 */
.founding-banner {
  background: none;
  color: var(--fg-default);
  border: 0;
  border-left: 2px solid var(--terra-500);
  /* No radius: this is a RULE, not a box — see the note on .demo-row. */
  border-radius: 0;
  font-size: var(--fs-md);
  padding: 4px 0 4px 16px;
  text-align: left;
  margin-bottom: 44px;
}
.billing-toggle {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
  margin-bottom: 36px;
  font-size: var(--fs-md);
  color: var(--fg-muted);
}
/* The switch keeps its radius: it is a switch, and a square one reads broken. */
.toggle-switch {
  position: relative;
  width: 44px; height: 24px;
  border-radius: var(--r-full);
  background: var(--bg-overlay);
  border: 1px solid var(--border-strong);
  cursor: pointer;
  padding: 0;
  flex: none;
}
.toggle-switch::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--bg-base);
  box-shadow: var(--elev-1);
  transition: transform 150ms ease;
}
.toggle-switch[aria-checked="true"] { background: var(--accent-primary); border-color: var(--accent-primary); }
.toggle-switch[aria-checked="true"]::after { transform: translateX(20px); }
.toggle-chip {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: none;
  color: var(--accent-primary);
  border: 1px solid var(--accent-primary);
  border-radius: var(--r-full);
  padding: 4px 8px;
}
.plans {
  display: grid;
  /* Three. Task 202 added a fourth plan (`solo`) and this deliberately does NOT
     show it: the live-phase table is not yet the decided pricing UI — the
     waitlist phase shows task 205's configurator instead, and which of the two
     the live site keeps is settled at the phase flip (apps/landing/README.md).
     A fourth column is one line here and one card in the markup when it is. */
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  align-items: stretch;
  border-top: 1px solid var(--border-default);
  border-bottom: 1px solid var(--border-default);
}
@media (max-width: 900px) { .plans { grid-template-columns: 1fr; } }
@media (min-width: 641px) and (max-width: 900px) { .plans { grid-template-columns: repeat(2, 1fr); } }

.plan {
  background: none;
  border: 0;
  border-right: 1px solid var(--border-default);
  /* No radius: this is a RULE, not a box — see the note on .demo-row. */
  border-radius: 0;
  padding: 32px 32px 32px 0;
  padding-left: 32px;
  display: flex;
  flex-direction: column;
  gap: 0;
  box-shadow: none;
  position: relative;
}
.plan:first-child { padding-left: 0; }
.plan:last-child { border-right: 0; }
/*
 * The STACKED presentation: no vertical divider, a horizontal one instead, and
 * no side padding because each plan now spans the container.
 *
 * 640, NOT 900 — the same off-by-one-breakpoint as the `.plan-name`
 * compensation below. `.plans` only collapses to a single column at 640; from
 * 641 to 900 it is still `repeat(2, 1fr)`. Applied across the whole <=900
 * range this stripped the vertical rule AND all 32px of side padding while the
 * columns were still side by side, so the left column's value and the right
 * column's label ended up touching — "100SKUs" with no gap at all.
 */
@media (max-width: 640px) {
  .plan {
    border-right: 0;
    border-bottom: 1px solid var(--border-default);
    padding: 28px 0;
  }
  .plan:last-child { border-bottom: 0; }
}

/*
 * Two-up: the wrapped third plan needs a rule above it, since the vertical
 * dividers alone do not say where one grid row ends.
 */
@media (min-width: 641px) and (max-width: 900px) {
  .plan:nth-child(n + 3) { border-top: 1px solid var(--border-default); }
  /*
   * The vertical rule belongs BETWEEN the two columns, never at the
   * container's right edge. `.plan:last-child` is the desktop test for that
   * and it stops being true the moment the grid wraps: at two-up the last
   * child sits in column ONE of row two, so the rule was suppressed where it
   * was wanted and drawn where it was not.
   */
  .plan:nth-child(even) { border-right: 0; }
  .plan:nth-child(odd):last-child { border-right: 0; }
}
/* The recommended plan: a heavy rule across the top of its column. */
.plan.popular { box-shadow: inset 0 2px 0 0 var(--accent-primary); }

.plan-chip {
  position: static;
  transform: none;
  align-self: flex-start;
  background: none;
  color: var(--accent-primary);
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border-radius: var(--r-full);
  padding: 0;
  /* line-height 1 so the label's box is exactly --fs-3xs tall, which is what
     the sibling columns compensate for below. Any other value and the three
     plan names stop sharing a baseline. */
  line-height: 1;
  margin-bottom: 10px;
  white-space: nowrap;
}
/* Keeps the three plan names on one baseline even though only one column has
   a "most popular" label above it. */
/*
 * Reserve the "Most popular" chip's height in the columns that do not have
 * one, so all three plan names — and therefore every row beneath them — share
 * a baseline. Without it the popular column sits exactly `--fs-3xs` + 10px
 * lower than its neighbours, and a pricing table you cannot read across is
 * not doing its one job.
 */
.plan:not(.popular) .plan-name { margin-top: calc(var(--fs-3xs) + 10px); }
/*
 * 640, NOT 900. The compensation is only pointless once the cards are STACKED,
 * and they stack at 640 — between 641 and 900 `.plans` is still
 * `repeat(2, 1fr)` (see the rule above). Zeroing it across the whole <=900
 * range switched the alignment off while the columns were still side by side,
 * so on a tablet the Growth column's rows sat 21px below Starter's.
 */
@media (max-width: 640px) { .plan:not(.popular) .plan-name { margin-top: 0; } }

.plan-name {
  font-size: var(--fs-md);
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  color: var(--fg-strong);
  margin: 0;
}
.plan-price-row { display: flex; align-items: baseline; gap: 6px; margin: 18px 0 4px; }
.plan-price {
  font-family: var(--font-display);
  font-variation-settings: "wdth" var(--wdth-display);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-display-lg);
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--fg-strong);
}
.plan-per { font-size: var(--fs-base); color: var(--fg-subtle); }
.plan-annual-note {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  min-height: 16px;
  margin: 0 0 24px;
}
.plan ul {
  list-style: none;
  margin: 0 0 28px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  flex: 1;
}
.plan li {
  font-size: var(--fs-sm);
  color: var(--fg-muted);
  display: flex;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 1px solid var(--border-subtle);
  padding: 9px 0;
}
.plan li:first-child { border-top: 1px solid var(--border-subtle); }
.plan li .val {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-sm);
  color: var(--fg-strong);
}
.plan .btn { width: 100%; text-align: center; }
.pricing-footnote {
  text-align: left;
  font-size: var(--fs-base);
  color: var(--fg-subtle);
  margin-top: 28px;
}
.pricing-footnote a { color: var(--accent-primary); }

/* ---- Pricing configurator [P1] ------------------------------------------------
 * Task 205. Deliberately NOT a fourth plan card: it is separated from the
 * price table by a rule, its price is set in the display face at a smaller
 * size than a real plan's, and the note under it says it buys nothing. It
 * should read as a question the page is asking the visitor, not as an offer.
 */
.configurator {
  border-top: 1px solid var(--border-default);
  margin-top: 44px;
  padding-top: 40px;
}
.configurator-title {
  font-family: var(--font-display);
  font-variation-settings: "wdth" var(--wdth-display);
  font-size: var(--fs-2xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--fg-strong);
  margin: 0;
}
.configurator-sub {
  font-size: var(--fs-md);
  color: var(--fg-muted);
  max-width: 62ch;
  margin: 10px 0 32px;
}
.configurator-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 56px;
  align-items: start;
}
@media (max-width: 900px) {
  .configurator-grid { grid-template-columns: 1fr; gap: 32px; }
}
.configurator-range {
  width: 100%;
  accent-color: var(--accent-primary);
  cursor: pointer;
}
.configurator-range:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.configurator-skus {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--fg-muted);
  margin: 10px 0 0;
}
.configurator-skus .val {
  font-variant-numeric: tabular-nums;
  color: var(--fg-strong);
}
.configurator-output {
  border-left: 2px solid var(--fg-strong);
  /* No radius: this is a RULE, not a box. */
  padding-left: 20px;
}
@media (max-width: 900px) {
  .configurator-output { border-left: 0; border-top: 2px solid var(--fg-strong); padding: 24px 0 0; }
}
.configurator-readout { margin: 0; }
.configurator-price {
  font-family: var(--font-display);
  font-variation-settings: "wdth" var(--wdth-display);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-display-sm);
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--fg-strong);
}
/* The prompt that stands in for a price before anything is picked: same slot,
   deliberately not the same voice, so an empty configurator never looks like a
   product that costs nothing. That is why it stays sans rather than display and
   keeps no tabular figures — the shape of a price is what would read as "free".
   It is still the one instruction the panel exists to give, though, so it is
   set well above body size rather than below it. */
.configurator-price.is-empty {
  font-family: var(--font-sans);
  font-size: var(--fs-display-xs);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--fg-strong);
}
.configurator-annual {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  min-height: 16px;
  margin: 4px 0 20px;
}
.configurator-included {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
}
.configurator-included li {
  font-size: var(--fs-sm);
  color: var(--fg-muted);
  line-height: 1.5;
  border-bottom: 1px solid var(--border-subtle);
  padding: 9px 0;
}
.configurator-included li:first-child { border-top: 1px solid var(--border-subtle); }
/* Empty whenever every selected marketplace pushes, and an empty one still
   painted its 2px rule and padding: a stray terracotta stub under the list. */
.configurator-sweep:empty { display: none; }
.configurator-sweep {
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--fg-muted);
  border-left: 2px solid var(--terra-500);
  /* No radius: a RULE, not a box, like .founding-banner. */
  padding: 2px 0 2px 14px;
  margin: 0 0 24px;
}
.configurator-output .btn { width: 100%; text-align: center; }
.configurator-status {
  font-size: var(--fs-sm);
  color: var(--fg-muted);
  margin: 12px 0 0;
  min-height: 1px;
}
.configurator-note {
  font-size: var(--fs-base);
  color: var(--fg-subtle);
  max-width: 72ch;
  margin-top: 32px;
}

/* ---- FAQ ----------------------------------------------------------------------
 * Already a ruled list before this redesign, and it was the one section that
 * did not need rescuing. Retuned to the new type only.
 */
.faq-list { max-width: none; margin: 0; }
.faq-item { border-bottom: 1px solid var(--border-default); }
.faq-item:first-child { border-top: 1px solid var(--border-default); }
.faq-q {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  background: none;
  border: none;
  text-align: left;
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: 550;
  color: var(--fg-strong);
  padding: 22px 0;
  cursor: pointer;
}
.faq-q::after {
  content: "+";
  font-family: var(--font-mono);
  font-size: var(--fs-3xl);
  font-weight: 400;
  color: var(--fg-subtle);
  transition: transform 150ms ease;
  flex-shrink: 0;
  line-height: 1;
}
.faq-item[data-open] .faq-q::after { transform: rotate(45deg); }
.faq-a {
  display: none;
  font-size: var(--fs-md);
  line-height: 1.7;
  color: var(--fg-muted);
  padding: 0 0 26px;
  max-width: 68ch;
}
.faq-item[data-open] .faq-a { display: block; }

/* ---- Final CTA / waitlist form ---------------------------------------------------
 * Two columns: the ask on the left, the form on the right. The form has no box
 * around it — it sits on the page like the rest of the content, separated by
 * a rule.
 */
.final-cta { text-align: left; }
.final-cta .container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 72px;
  align-items: start;
}
@media (max-width: 900px) {
  .final-cta .container { grid-template-columns: 1fr; gap: 40px; }
}
.final-cta h2 {
  font-size: clamp(2rem, 4.4vw, 3.25rem);
  line-height: 1.02;
  margin: 0;
  max-width: 14ch;
}
.waitlist-form {
  max-width: none;
  margin: 0;
  text-align: left;
  background: none;
  border: 0;
  border-top: 2px solid var(--fg-strong);
  /* No radius: this is a RULE, not a box — see the note on .demo-row. */
  border-radius: 0;
  padding: 28px 0 0;
  box-shadow: none;
}
.form-field { margin-bottom: 24px; }
/* Direct child only. The marketplace checkboxes are themselves <label>s
   nested inside a .form-field, and an unscoped selector turned every one of
   them into an uppercase mono field caption. */
.form-field > label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  color: var(--fg-strong);
  margin-bottom: 10px;
}
.form-field > label .opt { color: var(--fg-subtle); font-weight: 400; }
.form-field input[type="email"],
.form-field select {
  width: 100%;
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  color: var(--fg-strong);
  background: var(--bg-base);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  padding: 12px 14px;
}
.form-field input:focus-visible,
.form-field select:focus-visible,
.chip-check input:focus-visible + span {
  outline: none;
  box-shadow: var(--focus-ring);
}
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
.chip-check { cursor: pointer; }
.chip-check input { position: absolute; opacity: 0; pointer-events: none; }
.chip-check span {
  display: inline-block;
  font-size: var(--fs-sm);
  color: var(--fg-muted);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  padding: 7px 12px;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}
.chip-check input:checked + span {
  background: var(--accent-soft-bg);
  color: var(--accent-soft-fg);
  border-color: var(--accent-primary);
}
.consent-row {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--fg-muted);
  margin-bottom: 26px;
}
.consent-row input { margin-top: 3px; accent-color: var(--accent-primary); }
.consent-row a { color: var(--accent-primary); }
.waitlist-form .btn { width: 100%; }
.form-error {
  display: none;
  color: var(--terra-600);
  font-size: var(--fs-sm);
  margin-top: 12px;
}
.form-success { text-align: left; padding: 24px 0; }
.form-success .check {
  font-size: var(--fs-display-lg);
  color: var(--accent-primary);
  display: block;
  margin-bottom: 12px;
}
/* Honeypot — visually removed, still in the DOM for bots */
.hp-field {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* ---- Footer ------------------------------------------------------------------------ */
.footer { padding: 56px 0 72px; }
.footer-grid {
  display: flex;
  justify-content: space-between;
  gap: 48px;
  flex-wrap: wrap;
}
.footer-brand { max-width: 34ch; }
.footer-tag { font-size: var(--fs-sm); color: var(--fg-muted); margin-top: 16px; line-height: 1.6; }
.footer-links { display: flex; gap: 56px; flex-wrap: wrap; }
.footer-links ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.footer-links a {
  font-size: var(--fs-sm);
  color: var(--fg-muted);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.footer-links a:hover { color: var(--fg-strong); border-bottom-color: var(--fg-strong); }
.footer-meta {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  border-top: 1px solid var(--border-default);
  margin-top: 56px;
  padding-top: 20px;
}
.lang-switch { display: flex; gap: 10px; }
.lang-switch span[aria-current] { color: var(--fg-strong); }

/* ---- A11y / focus ----------------------------------------------------------------- */
a:focus-visible, button:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--r-sm);
}
.skip-link {
  position: absolute;
  left: -9999px;
  background: var(--bg-base);
  color: var(--fg-strong);
  padding: 10px 16px;
  z-index: 100;
  border: 1px solid var(--fg-strong);
  border-radius: var(--r-sm);
}
.skip-link:focus { left: 16px; top: 12px; }

/* ---- Breadcrumb (task 212) ----------------------------------------------
 * Legal subpages and 404 only — the homepage is the root and needs none.
 */
.breadcrumb { margin-bottom: 24px; }
.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--fg-subtle);
}
.breadcrumb li { display: flex; align-items: center; gap: 8px; }
.breadcrumb li:not(:last-child)::after {
  content: "/";
  color: var(--fg-subtle);
}
.breadcrumb a { color: var(--fg-muted); text-decoration: none; }
.breadcrumb a:hover { color: var(--fg-strong); text-decoration: underline; }
.breadcrumb li[aria-current="page"] { color: var(--fg-strong); }

/* ---- Legal pages (privacy / terms) ------------------------------------------------- */
.legal-head { max-width: 62ch; }
.legal-head h1 {
  font-size: clamp(2.25rem, 5vw, 3.5rem);
  line-height: 1.02;
  margin: 0 0 16px;
}
.legal-meta {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
  font-size: var(--fs-sm);
  color: var(--fg-subtle);
  margin: 0;
}
.legal-draft-note {
  max-width: 62ch;
  font-size: var(--fs-base);
  line-height: 1.6;
  color: var(--fg-muted);
  background: none;
  border: 0;
  border-left: 2px solid var(--terra-500);
  /* No radius: this is a RULE, not a box — see the note on .demo-row. */
  border-radius: 0;
  padding: 4px 0 4px 16px;
  margin: 28px 0 0;
}
.legal {
  max-width: 68ch;
  margin-top: 48px;
}
.legal h2 {
  font-size: clamp(1.5rem, 3vw, 2rem);
  line-height: 1.12;
  border-top: 1px solid var(--border-default);
  padding-top: 24px;
  margin: 52px 0 14px;
}
.legal h2:first-child { margin-top: 0; border-top: 0; padding-top: 0; }
.legal h3 {
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--fg-strong);
  margin: 28px 0 8px;
}
.legal p {
  font-size: var(--fs-md);
  line-height: 1.75;
  color: var(--fg-default);
  margin: 0 0 16px;
}
.legal ul {
  margin: 0 0 16px;
  padding-left: 22px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.legal li {
  font-size: var(--fs-md);
  line-height: 1.7;
  color: var(--fg-default);
}
.legal a {
  color: var(--accent-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.legal a:hover { color: var(--accent-primary-hover); }
.legal strong { color: var(--fg-strong); font-weight: 600; }
.legal .placeholder {
  font-family: var(--font-mono);
  font-size: var(--fs-base);
  /* --accent-warm, not --terra-600 directly: the palette step is fixed and the
     semantic token is not, so on a dark ground this was still the DARK
     terracotta and came out at 3.1:1. --accent-warm is terra-600 in light,
     where this already read correctly, and terra-400 in dark. */
  color: var(--accent-warm);
}
.legal-table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 20px;
  font-size: var(--fs-sm);
}
.legal-table th,
.legal-table td {
  text-align: left;
  vertical-align: top;
  padding: 12px 14px 12px 0;
  border-bottom: 1px solid var(--border-default);
  line-height: 1.55;
  color: var(--fg-default);
}
.legal-table th {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-subtle);
  border-bottom: 1px solid var(--fg-strong);
}
.legal-table td:first-child {
  font-weight: 600;
  color: var(--fg-strong);
  white-space: nowrap;
}
@media (max-width: 640px) {
  .legal-table td:first-child { white-space: normal; }
}

/* ---- Sticky mobile CTA bar (task 210) ---------------------------------
 * The hero's own CTA row scrolls out of view almost immediately on a phone,
 * so below the same 860px breakpoint the nav hamburger uses, a fixed bar
 * carries the one primary action for the rest of the scroll. Hidden by
 * `display: none` rather than `opacity`, both at desktop widths (the media
 * query) and once the waitlist form is in view (js/landing.js toggles
 * `.is-hidden`), so it never sits in the tab order or the accessibility
 * tree when it is not visibly there — a hidden focusable button below the
 * fold is worse than none. Reuses [data-p1]/[data-p2], not a second phase
 * check: the two buttons below are the same markup as the nav/hero CTAs,
 * just narrower.
 */
.mobile-cta-bar {
  display: none;
}
@media (max-width: 860px) {
  .mobile-cta-bar {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 55;
    padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
    background: var(--bg-canvas);
    border-top: 1px solid var(--border-default);
  }
  .mobile-cta-bar.is-hidden {
    display: none;
  }
  .mobile-cta-bar .btn {
    flex: 1;
    text-align: center;
  }
}

/* ---- Social-proof scaffolding (task 214) — NOT LIVE -----------------------
 * Styles for four sections that exist ONLY as an HTML comment block in
 * index.html: real testimonials, case studies, a team photo and a
 * location/map all need content PANOpeak doesn't have yet (paying customers,
 * an office — see this phase's header note in docs/BACKLOG.md and the
 * comment in index.html). Kept here, unreferenced by any rendered page today,
 * so a future editor drops in real content and gets the layout for free
 * instead of building it from scratch. Card look borrows `.app-frame`'s own
 * vocabulary (flat, one border, `--r-xl` radius) rather than inventing a new
 * "boxed card" style the rest of this page deliberately avoids.
 */
.testimonial-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}
@media (max-width: 900px) { .testimonial-grid { grid-template-columns: 1fr; } }
.testimonial-card {
  border: 1px solid var(--border-default);
  border-radius: var(--r-xl);
  padding: 28px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.testimonial-quote { font-size: var(--fs-lg); line-height: 1.6; color: var(--fg-default); margin: 0; }
.testimonial-author { display: flex; align-items: center; gap: 12px; }
.testimonial-avatar { width: 40px; height: 40px; border-radius: 999px; background: var(--bg-overlay); flex-shrink: 0; }
.testimonial-name { font-weight: 600; color: var(--fg-strong); font-size: var(--fs-sm); }
.testimonial-role { color: var(--fg-muted); font-size: var(--fs-sm); }

.case-study-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}
@media (max-width: 900px) { .case-study-grid { grid-template-columns: 1fr; } }
.case-study-card {
  display: block;
  border: 1px solid var(--border-default);
  border-radius: var(--r-xl);
  padding: 28px;
  text-decoration: none;
  color: inherit;
  transition: border-color 120ms ease;
}
.case-study-card:hover { border-color: var(--fg-strong); }
.case-study-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-subtle);
}
.case-study-title { font-size: var(--fs-lg); font-weight: 600; color: var(--fg-strong); margin: 8px 0; }
.case-study-result { color: var(--fg-muted); font-size: var(--fs-sm); }

.team-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
}
@media (max-width: 900px) { .team-grid { grid-template-columns: repeat(2, 1fr); } }
.team-card { text-align: center; }
.team-photo { width: 100%; aspect-ratio: 1; border-radius: var(--r-xl); background: var(--bg-overlay); margin-bottom: 12px; }
.team-name { font-weight: 600; color: var(--fg-strong); }
.team-role { color: var(--fg-muted); font-size: var(--fs-sm); }

.location-section {
  border: 1px solid var(--border-default);
  border-radius: var(--r-xl);
  padding: 32px;
}
.location-map { width: 100%; aspect-ratio: 16 / 9; border-radius: var(--r-sm); background: var(--bg-overlay); }
.location-address { margin-top: 16px; color: var(--fg-muted); font-size: var(--fs-sm); }
