/* ===========================================================================
 * The landing page's entire design. Consumes tokens.css; the product's
 * application.css is deliberately not linked on this host.
 *
 * The direction, in one paragraph: warm paper, Instrument Sans set tight and
 * large for display, Geist Mono kept for the things that are data — eyebrows,
 * step numerals, captions, and the address bar of the window frames. Every
 * screenshot sits in a CSS window whose bar carries the *client's* domain,
 * because "their own domain, their own certificate" is the product's central
 * claim and the frame is the cheapest place to prove it. The page runs on one
 * plane of paper from the hero to the FAQ, and inverts exactly once — the demo
 * band — so the form is the last and highest-contrast object on the page.
 *
 * Two conventions worth knowing before editing:
 *   1. Green is action (--primary), blue is link (--accent). Nothing else
 *      carries colour except the product's own pass/fail vocabulary, borrowed
 *      once for the white-label ticks.
 *   2. Every container — header, band, hero, footer — is inset by the same
 *      expression, `max(--pad, (100% - --col) / 2)`. A band that bleeds simply
 *      zeroes that padding on one side, which is how the window frames reach
 *      the viewport edge without a single negative margin or overflow rule.
 * ======================================================================== */

.marketing {
  /* ThemesController renders these per tenant at request time and never runs
   * on this host, so tokens.css leaves them undeclared and the marketing
   * surface declares its own. --ring (tokens.css) references --primary from
   * :root, where it is still undefined here; this file therefore never uses
   * --ring, and draws focus with outlines, which sit better on both planes. */
  --primary: #1a7f37;
  --accent: #0b5394;

  --col: 72rem;                             /* the content column           */
  --pad: clamp(1.25rem, 4vw, 2rem);         /* the gutter beside it         */
  --section: clamp(2.5rem, 4.5vw, 3.75rem); /* half the rhythm between bands */
  --inset: max(var(--pad), calc((100% - var(--col)) / 2));

  /* --- the depth layer -----------------------------------------------------
   * Every value below is mixed from the two brand colours above or from
   * --text/--surface, so a repaint of the palette carries the atmosphere and
   * the shadows with it. Nothing here introduces a colour of its own; #fff and
   * #000 appear only as the lightening and darkening legs of a color-mix,
   * which is the same exception application.css is held to.
   *
   * On paper the light is green, and only green. Blue at these alphas over a
   * warm ground composites to a cool grey — it reads as a smudge on the page
   * rather than as light on it — so --accent's turn comes on the dark band,
   * where a low-alpha blue stays blue, and in the gradient of the primary
   * button. One hue on paper, two on the shell.
   *
   * Two rules govern where a wash may go, and both come from measurement
   * rather than taste:
   *   1. Never under --text-3. It lands on paper at 4.56:1, six hundredths
   *      above AA, so any tint at all fails it. That rules the wash out of
   *      the hero's eyebrow and every figcaption.
   *   2. Reach transparent before the band's own top and bottom edge. A
   *      gradient cut off by a section boundary reads as a smudge with a
   *      straight edge; one that fades out inside its band reads as light.
   *      Horizontal clipping is fine — that edge is the viewport, and light
   *      running off the side of the screen is what light does. */
  --wash-green: color-mix(in srgb, var(--primary) 20%, transparent);
  --glow:       color-mix(in srgb, var(--primary) 38%, transparent);

  /* Glass: translucent paper, a hairline that is more light than line, and a
   * one-pixel inner highlight along the top edge. 62% surface over the
   * strongest wash still reads --text at 15.6:1 and --text-2 at 6.8:1. */
  --glass:      color-mix(in srgb, var(--surface) 62%, transparent);
  --glass-line: color-mix(in srgb, var(--border-strong) 55%, transparent);
  --glass-hi:   color-mix(in srgb, #fff 70%, transparent);
  --blur: blur(16px) saturate(1.35);

  /* Shadow ink is --text, which is the colour tokens.css already writes its
   * shadows in (#18181b). Three layers: a contact edge, a mid lift, and a
   * long soft one that does the actual floating. */
  --lift:   0 1px 2px color-mix(in srgb, var(--text) 5%, transparent),
            0 6px 14px -8px color-mix(in srgb, var(--text) 14%, transparent),
            0 20px 36px -22px color-mix(in srgb, var(--text) 20%, transparent);
  /* The window frame's lift. Every layer's spread is set against its blur so
   * the shadow's nominal reach below the frame is about 5px, because a
   * figcaption in --text-3 sits underneath with no contrast to spare. The
   * numbers are measured, not guessed: the first pass at -28px of spread on a
   * 56px blur put that caption on #f0efec and 4.20:1. The long layer was then
   * shortened again — 34px of blur at 26% still left one unit of grey on the
   * caption's row, which is 4.52:1 and no margin at all. */
  --lift-2: 0 1px 2px color-mix(in srgb, var(--text) 5%, transparent),
            0 8px 16px -14px color-mix(in srgb, var(--text) 18%, transparent),
            0 14px 26px -26px color-mix(in srgb, var(--text) 20%, transparent);

  --r-xl: calc(var(--r-lg) + 4px);
  --ease: cubic-bezier(0.2, 0.65, 0.25, 1);

  background: var(--bg);
  color: var(--text);
  font: 400 1.0625rem/1.65 "Instrument Sans", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  margin: 0;
}

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

/* Margins are declared per component below, never inherited from the browser:
 * it is the only way a page of eight sections keeps one rhythm. :where() so
 * this costs no specificity and a plain `.eyebrow { margin-bottom }` still
 * wins — a reset that has to be fought with !important is not a reset. */
.marketing :where(h1, h2, h3, p, ul, ol, figure, figcaption) { margin: 0; }

/* So the header's own nav does not land a section under the header. Deliberately
 * without `scroll-behavior: smooth`: a smoothly scrolling document makes every
 * driver-issued click land at the pre-animation coordinates, which cost this
 * page a working submit button under Selenium before it cost anyone a test.
 *
 * interpolate-size is the second declaration's whole reason for existing: it
 * turns `auto` into a keyword a transition can land on, which is what lets a
 * FAQ answer open to its own height instead of snapping. Browsers without it
 * drop the line and open the panels instantly, exactly as this page shipped. */
html {
  scroll-padding-top: 5.5rem;
  interpolate-size: allow-keywords;
}

/* --- type ---------------------------------------------------------------- */

.marketing h1,
.marketing h2 { font-weight: 600; text-wrap: balance; }

.marketing h1 {
  font-size: clamp(2.5rem, 4.6vw, 3.5rem);
  line-height: 1.04;
  letter-spacing: -0.033em;
}

.marketing h2 {
  font-size: clamp(1.75rem, 3vw, 2.375rem);
  line-height: 1.14;
  letter-spacing: -0.026em;
}

.marketing h3 {
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.012em;
}

.eyebrow {
  font: 500 0.75rem/1 var(--mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: var(--space-5);
}

.lede,
.band__lede {
  font-size: clamp(1.0625rem, 1.3vw, 1.1875rem);
  line-height: 1.6;
  color: var(--text-2);
  text-wrap: pretty;
}

.marketing code {
  font: 500 0.9em/1 var(--mono);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.15em 0.35em;
  white-space: nowrap;
}

/* --- controls ------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;                      /* 44px, on every surface       */
  padding: 0.625rem 1.125rem;
  border: 1px solid transparent;
  border-radius: var(--r);
  font: 600 0.9375rem/1 var(--ui);
  letter-spacing: -0.006em;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease,
              box-shadow 0.2s ease, transform 0.2s var(--ease);
}

/* The fill runs green → teal along the diagonal rather than light → dark down
 * the button. A light stop is what a gradient button usually reaches for, and
 * it is exactly what this one cannot have: --surface on --primary is 5.04:1,
 * so lifting the top stop 12% toward white drops the label to 4.06:1. Mixing
 * toward --accent instead only ever darkens — the far stop is 6.1:1 — so the
 * worst pixel under the label is --primary itself, and the button is allowed
 * to be a gradient. */
.btn--primary {
  background: var(--primary);
  background-image: linear-gradient(135deg,
    var(--primary) 0%,
    color-mix(in srgb, var(--primary) 58%, var(--accent)) 100%);
  color: var(--surface);
  box-shadow: 0 1px 1px color-mix(in srgb, var(--text) 12%, transparent),
              0 8px 18px -10px color-mix(in srgb, var(--primary) 60%, transparent);
}
/* Every hover state that moves or lifts something lives inside
 * `@media (hover: hover)`. A touch device has no hover to leave: it synthesises
 * one on tap and keeps it until the next tap somewhere else, so an ungated
 * `translateY(-4px)` leaves a card stuck in the air — a state the reader cannot
 * undo and did not ask for. Colour-only hovers (links, fields, the FAQ's
 * marker) stay ungated: a border that stays warm after a tap is feedback, not
 * a stuck object. */
@media (hover: hover) {
  .btn--primary:hover {
    background: color-mix(in srgb, var(--primary) 86%, #000);
    background-image: linear-gradient(135deg,
      color-mix(in srgb, var(--primary) 90%, #000) 0%,
      color-mix(in srgb, var(--primary) 50%, var(--accent)) 100%);
    transform: translateY(-1px);
    box-shadow: 0 1px 1px color-mix(in srgb, var(--text) 12%, transparent),
                0 12px 26px -10px color-mix(in srgb, var(--primary) 70%, transparent);
  }
  .btn--primary:active { transform: translateY(0); }
}
/* The lift above is hover-world -- it only ever cancels a translateY a touch
 * tap never applied. The colour is not: a finger gets no hover to confirm a
 * press before it lands, so this half of :active runs ungated, on every
 * pointer, and is the only answer a tap on "Book a demo" gets on a phone. */
.btn--primary:active {
  background: color-mix(in srgb, var(--primary) 86%, #000);
  background-image: linear-gradient(135deg,
    color-mix(in srgb, var(--primary) 90%, #000) 0%,
    color-mix(in srgb, var(--primary) 50%, var(--accent)) 100%);
  box-shadow: 0 1px 1px color-mix(in srgb, var(--text) 12%, transparent),
              0 4px 10px -8px color-mix(in srgb, var(--primary) 55%, transparent);
}

.btn--ghost {
  background: var(--surface);
  border-color: var(--border-strong);
  color: var(--text);
}
/* Glass, where the browser has it. The base rule above is the fallback and is
 * a solid, fully legible chip on its own — see the note on .card. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .btn--ghost {
    background: var(--glass);
    border-color: var(--glass-line);
    -webkit-backdrop-filter: var(--blur);
    backdrop-filter: var(--blur);
  }
}
@media (hover: hover) {
  .btn--ghost:hover {
    background: var(--surface);
    border-color: var(--text-3);
    transform: translateY(-1px);
    box-shadow: var(--lift);
  }
  .btn--ghost:active { transform: translateY(0); }
}
/* Same split as .btn--primary above: the lift is hover-only, the pressed
 * border and shadow are not. */
.btn--ghost:active {
  border-color: var(--text-3);
  box-shadow: 0 2px 6px -4px color-mix(in srgb, var(--text) 20%, transparent);
}

.btn--big {
  min-height: 3rem;
  padding: 0.8125rem 1.5rem;
  font-size: 1rem;
}

.marketing :is(a, button, input, select, summary):focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* --- the shell: header and footer ---------------------------------------- */

.site-head {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 3vw, 2.5rem);
  min-height: 4rem;
  padding-block: 0.625rem;
  padding-inline: var(--inset);
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
@supports (backdrop-filter: blur(1px)) {
  .site-head {
    /* Only just translucent: the bar crosses the dark demo band, and anything
     * thinner than this reads there as a grey smear rather than paper. */
    background: color-mix(in srgb, var(--bg) 93%, transparent);
    backdrop-filter: blur(12px) saturate(1.4);
  }
}

.site-head__word {
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.035em;
  color: var(--text);
  text-decoration: none;
}

.site-head__nav {
  display: flex;
  gap: clamp(1rem, 2.5vw, 1.75rem);
}
.site-head__nav a {
  font-size: 0.9375rem;
  color: var(--text-2);
  text-decoration: none;
}
.site-head__nav a:hover { color: var(--text); }

.site-head__cta { margin-left: auto; }

.site-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4) var(--space-6);
  padding-block: var(--space-6);
  padding-inline: var(--inset);
  border-top: 1px solid var(--border);
  font: 400 0.8125rem/1.5 var(--mono);
  color: var(--text-3);
}
.site-foot nav { display: flex; gap: var(--space-5); }
.site-foot a { color: var(--text-2); text-decoration: none; }
.site-foot a:hover { color: var(--text); text-decoration: underline; }

/* --- section rhythm ------------------------------------------------------ */

.band {
  padding-block: var(--section);
  padding-inline: var(--inset);
}

.band > h2 { margin-bottom: var(--space-6); }

/* --- the hero ------------------------------------------------------------ */

.hero {
  display: grid;
  gap: clamp(2.5rem, 5vw, 3.5rem);
  padding-block: clamp(2.5rem, 5vw, 4rem) var(--section);
  padding-inline: var(--inset);
}

.hero .lede {
  margin-top: var(--space-5);
  max-width: 34rem;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-6);
}

/* --- the window frame ----------------------------------------------------
 * A figure is a window: a bar with three dots and the client's own domain,
 * then a fixed-height viewport onto the screenshot. The image is positioned
 * rather than scaled to fit, so every shot renders at a constant, legible
 * fraction of the size it was captured at (78% for the two 1440px captures,
 * 1:1 for the report) and the frame crops to the part that carries the claim.
 * The crop anchor is what differs per shot, not the scale. */

.shot { margin: 0; }

.shot__view {
  --bar: 2.125rem;
  position: relative;
  overflow: hidden;
  height: var(--shot-h, 19rem);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  /* --lift-2 puts the window on the paper; the two layers after it are the
   * brand light behind it. Two, because one glow cannot be both near and wide:
   * a rim and a bloom. Both are pulled in by their spread so the light pools
   * around the frame and reaches neither of the two rows it must not touch.
   *
   * Below, that row is the figcaption — --text-3, no contrast to spend on a
   * tint. Above, it is the hero's own top edge. The sticky header paints an
   * opaque bar across it, so any glow still alive at that line is chopped into
   * a straight horizontal edge under the header's hairline: light with a
   * ruler-drawn top, which reads as fog pinned to the page rather than as
   * spill from the window. The first pass lifted the bloom 46px on a 120px
   * blur, which put its tail exactly there and measured a +5.5 green step at
   * 1440 and +7.5 at 1024. Both layers are now short enough to die inside the
   * hero: measured, the seam is flat to the page's own paper. */
  box-shadow: var(--lift-2),
              0 -4px 30px -10px var(--glow),
              0 -10px 64px -30px var(--glow);
}

.shot__view::before {
  /* The address bar. The second declaration adds empty alternative text so
   * the domain is drawn but not announced — the figure's alt already says it.
   * Browsers without the `content / alt` syntax keep the first declaration. */
  content: var(--shot-url, "");
  content: var(--shot-url, "") / "";
  position: absolute;
  inset: 0 0 auto 0;
  z-index: 2;
  display: block;
  height: var(--bar);
  text-align: center;
  padding-inline: 3.75rem;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  font: 400 0.75rem/1 var(--mono);
  line-height: var(--bar);
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.shot__view::after {
  content: "";
  position: absolute;
  z-index: 3;
  top: calc(var(--bar) / 2 - 3.5px);
  left: 1rem;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--border-strong);
  box-shadow: 12px 0 var(--border-strong), 24px 0 var(--border-strong);
}

.shot__view img {
  position: absolute;
  top: var(--bar);
  left: 0;
  width: var(--shot-w, 1120px);
  max-width: none;
  height: auto;
}

/* 32px, not 12. This line cannot afford to sit in the frame's shadow at all,
 * and a blur's tail runs further than its nominal radius: at 24px of clearance
 * it measured 4.51:1, one hundredth above the line. The extra air is what buys
 * the lift.
 *
 * The colour is --text-3 leaned a sixth of the way toward --text-2, and that
 * is arithmetic rather than taste. --text-3 on bare paper is 4.557:1 — so a
 * caption with a *perfectly* clean backdrop still has six thousandths of
 * headroom, and no amount of shadow surgery can buy more. Shortening the tail
 * (see --lift-2) gets the backdrop back to paper; this gets the line off the
 * edge, to 4.8:1, without making a 13px note read like body copy. The shared
 * token is untouched: it is the whole product's, and this is one line on one
 * page. */
.shot figcaption {
  margin-top: var(--space-6);
  font: 400 0.8125rem/1.5 var(--mono);
  color: color-mix(in srgb, var(--text-3) 84%, var(--text-2));
  max-width: 34rem;
}

.shot--hero   { --shot-url: "testing.arvobank.com/cycles/release-3-4"; }
.shot--report { --shot-url: "testing.arvobank.com/reports/release-3-4"; }
.shot--drawer { --shot-url: "testing.arvobank.com/cycles/release-3-4"; }

/* The drawer's payload — the evidence and the Jira key it filed — sits at the
 * bottom right of that page, so that corner is what the window shows. */
.shot--drawer .shot__view img {
  top: auto;
  left: auto;
  right: 0;
  bottom: 0;
}

/* --- the problem: three cards -------------------------------------------- */

/* What the glass is glass over: one wide, low light pooled under the card row.
 * Every word in this band is --text or --text-2, and at the centre of the wash
 * — the darkest point there is — they measure 12.8:1 and 5.6:1. */
.marketing #pain {
  background-image:
    radial-gradient(66% 40% at 48% 58%, var(--wash-green) 0%, transparent 92%);
}

.cards {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
}

/* The base rule is the fallback, and it is the card this page shipped with:
 * solid --surface, hairline border, no blur. The @supports block below only
 * ever trades that for translucency where the browser can blur what is behind
 * it — a browser without backdrop-filter gets an opaque card rather than a
 * transparent one, which is the failure mode worth designing for. */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: clamp(1.25rem, 2.4vw, 1.75rem);
  box-shadow: var(--shadow-xs);
  transition: transform 0.25s var(--ease), box-shadow 0.25s ease, border-color 0.2s ease;
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card {
    background: var(--glass);
    border-color: var(--glass-line);
    -webkit-backdrop-filter: var(--blur);
    backdrop-filter: var(--blur);
    box-shadow: var(--shadow-xs), inset 0 1px 0 var(--glass-hi);
  }
}
@media (hover: hover) {
  .card:hover {
    transform: translateY(-4px);
    border-color: color-mix(in srgb, var(--primary) 22%, var(--border-strong));
    box-shadow: var(--lift), inset 0 1px 0 var(--glass-hi);
  }
}
.card h3 { margin-bottom: var(--space-3); }
.card p { color: var(--text-2); font-size: 1rem; }

/* --- how it works: a numbered sequence ------------------------------------
 * The numerals are honest here: catalogue, cycle, run, report is an order, and
 * a reader who does step three first gets nothing. Each step hangs off its own
 * hairline, so the four rules read as one rail across the row. */

/* Explicit column counts, not auto-fit: for a fixed four-item row, auto-fit's
 * "however many fit" logic has no way to say "4, or 2×2, or 1 — never 3+1",
 * and some width in every minmax floor tried landed on that orphan. Four
 * across only opens at the same 64rem the rest of the page turns desktop. */
.steps {
  counter-reset: step;
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--space-6) var(--space-6);
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) {
  .steps { grid-template-columns: repeat(2, 1fr); }
}

/* The rail is a meter. Each step's rule carries a lit segment as long as the
 * step is far along — a quarter, a half, three quarters, the whole rule — so
 * four columns read left to right as one thing filling rather than four
 * headings that happen to be numbered. It is the product's own vocabulary
 * borrowed for the page's structure: the report step four ends at is a sheet
 * of coverage bars, and this row is the same bar, drawn once per step.
 *
 * It is also where this band's light lives. #how takes no wash, and cannot:
 * its numerals are --primary at 14px and land at 4.79:1 on bare paper, so any
 * tint under them fails AA. Putting the green on the structure instead of
 * behind the text buys the band its atmosphere at no cost to a single word —
 * the glow is 14px of blur on a 2px bar against 16px of clearance, and the
 * numerals sample exactly where they did before it. */
.steps li {
  position: relative;
  counter-increment: step;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-strong);
}

.steps li::after {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  width: var(--fill, 0);            /* a fifth step would light nothing */
  height: 2px;
  border-radius: 2px;
  background: var(--primary);
  box-shadow: 0 0 14px 1px color-mix(in srgb, var(--primary) 42%, transparent);
}
.steps li:nth-child(1) { --fill: 25%; }
.steps li:nth-child(2) { --fill: 50%; }
.steps li:nth-child(3) { --fill: 75%; }
.steps li:nth-child(4) { --fill: 100%; }

.steps li::before {
  content: counter(step);
  display: block;
  margin-bottom: var(--space-3);
  font: 600 0.875rem/1 var(--mono);
  letter-spacing: 0.08em;
  color: var(--primary);
}

.steps h3 { margin-bottom: var(--space-2); }
.steps p { color: var(--text-2); font-size: 1rem; }

/* --- the two feature bands ----------------------------------------------- */

/* The light behind the window, on the side the window is on. Both stops are
 * chosen so the wash is transparent again well above the figcaption — see the
 * two rules in the token block. */
.band--feature {
  display: grid;
  gap: clamp(2.5rem, 5vw, 3.5rem);
  background-image:
    radial-gradient(50% 38% at 76% 42%, var(--wash-green) 0%, transparent 90%);
}
.band--flip {
  background-image:
    radial-gradient(50% 38% at 24% 42%, var(--wash-green) 0%, transparent 90%);
}

.feature__copy p { color: var(--text-2); margin-top: var(--space-4); max-width: 34rem; }

/* The product's own pass mark, borrowed at list size. */
.ticks {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-5);
}
.ticks li {
  position: relative;
  padding-left: 1.9rem;
  color: var(--text-2);
  font-size: 1rem;
}
.ticks li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.28em;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 50%;
  background: var(--ok-bg);
  border: 1px solid var(--ok-bd);
}
.ticks li::after {
  content: "";
  position: absolute;
  left: 0.375rem;
  top: 0.5em;
  width: 0.3rem;
  height: 0.55rem;
  border: solid var(--ok);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}

/* --- the statement band --------------------------------------------------- */

.band--statement {
  text-align: center;
  padding-block: calc(var(--section) * 1.15);
}

/* The one place on the page where the wash is the composition rather than an
 * undertone: a single halo, centred, with the sentence sitting inside it. The
 * band is set entirely in --text and --text-2, and sampled on the rendered
 * page the heading measures 15.7:1 and the lede 6.8:1 where the halo is
 * strongest. */
.marketing #evidence {
  background-image:
    radial-gradient(40% 50% at 50% 50%, var(--wash-green) 0%, transparent 88%);
}

.band--statement > h2 { margin-inline: auto; max-width: 24ch; margin-bottom: var(--space-4); }
.band--statement .band__lede {
  margin-inline: auto;
  max-width: 46rem;
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
}

/* --- the FAQ -------------------------------------------------------------- */

/* Panels rather than a ruled list: the reader is scanning discrete blocks, so
 * the page gives them blocks. These are the one surface here that does *not*
 * take the glass treatment, and that is measured rather than inconsistent.
 * Glass needs something behind it to be glass over. This band has no wash, so
 * 62% surface over bare paper composites to #fdfbf9 against paper's #faf8f5 —
 * three units, the whole panel carried by a hairline, and the solid
 * non-blur fallback separated better than the treatment it was falling back
 * from. So the panel is simply the surface it claims to be, with the cards'
 * depth arrived at from the other side: a lit top edge and a real shadow.
 * The <details>/<summary> semantics are untouched; only the paint changed. */
.faq { display: grid; gap: var(--space-3); }

.faq details {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding-inline: var(--space-5);
  box-shadow: var(--shadow-sm), inset 0 1px 0 var(--glass-hi);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.faq details:hover { border-color: var(--border-strong); }
/* Open, the panel casts green rather than grey — the same light the frames and
 * the steps rail carry, spent on the one panel the reader chose. It falls into
 * the 12px gap and onto the opaque panel below it, never onto text. */
.faq details[open] {
  border-color: color-mix(in srgb, var(--primary) 24%, var(--border-strong));
  box-shadow: var(--shadow-sm),
              inset 0 1px 0 var(--glass-hi),
              0 12px 26px -16px color-mix(in srgb, var(--primary) 45%, transparent);
}

/* The smooth open. ::details-content is the answer's own box, and with
 * interpolate-size set on <html> it can be transitioned from 0 to auto;
 * content-visibility rides along as a discrete step so the text is not
 * findable-but-invisible mid-animation. Browsers without the pseudo-element
 * never match this rule at all and open the panel instantly. */
.faq details::details-content {
  block-size: 0;
  overflow: hidden;
  transition: block-size 0.3s var(--ease), content-visibility 0.3s allow-discrete;
}
.faq details[open]::details-content { block-size: auto; }

.faq summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-4);
  min-height: 2.75rem;
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.012em;
}
.faq summary::-webkit-details-marker { display: none; }

.faq summary::after {
  content: "+";
  flex: none;
  font: 400 1.25rem/1 var(--mono);
  color: var(--text-3);
  transition: transform 0.25s var(--ease), color 0.2s ease;
}
.faq summary:hover::after { color: var(--primary); }
.faq details[open] summary::after { transform: rotate(45deg); color: var(--primary); }

.faq details p {
  padding-bottom: var(--space-5);
  color: var(--text-2);
  font-size: 1rem;
  max-width: 62ch;
}

/* --- the demo band: the page's one inversion ------------------------------ */

/* Two lights on the dark plane — green where the heading sits, blue behind
 * the form — over a shell → shell-2 → shell wash that keeps the band from
 * reading as a flat black rectangle. Both glows are capped where they are
 * because --shell-text has to survive them: the green's centre over the
 * lightest point of the linear leaves it at 5.5:1, the blue at 6.0:1. */
.band--demo {
  padding-block: calc(var(--section) * 1.6);
  background: var(--shell);
  background-image:
    radial-gradient(58% 54% at 10% 16%, color-mix(in srgb, var(--primary) 20%, transparent) 0%, transparent 64%),
    radial-gradient(56% 62% at 90% 86%, color-mix(in srgb, var(--accent) 22%, transparent) 0%, transparent 62%),
    linear-gradient(168deg, var(--shell-2) 0%, var(--shell) 52%, var(--shell-2) 100%);
  color: var(--shell-text);
}
.band--demo > h2 { color: var(--shell-text-hi); margin-bottom: var(--space-4); }
.band--demo .band__lede { color: var(--shell-text); max-width: 34rem; }

/* The card is 96% opaque and not a point less. Below that, --ok on it — the
 * confirmation heading, 18px semibold, so AA wants 4.5:1 — falls under the
 * line: 96% measures 4.60:1, 95% measures 4.48:1. What makes it read as glass
 * is the lit hairline, the inner top highlight and the blur behind it, none of
 * which cost the form a drop of legibility. */
#demo-form {
  margin-top: var(--space-6);
  padding: clamp(1.5rem, 3vw, 2rem);
  background: var(--surface);
  color: var(--text);
  border-radius: var(--r-xl);
  box-shadow: 0 1.5rem 3rem -1rem color-mix(in srgb, #000 45%, transparent),
              0 0 0 1px color-mix(in srgb, #fff 10%, transparent);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  #demo-form {
    background: color-mix(in srgb, var(--surface) 96%, transparent);
    -webkit-backdrop-filter: blur(24px) saturate(1.2);
    backdrop-filter: blur(24px) saturate(1.2);
    box-shadow: 0 1.5rem 3rem -1rem color-mix(in srgb, #000 45%, transparent),
                0 0 0 1px color-mix(in srgb, #fff 12%, transparent),
                inset 0 1px 0 color-mix(in srgb, #fff 75%, transparent);
  }
}

.demo-form { display: grid; gap: var(--space-4); }

.field { display: grid; gap: 0.375rem; }
.field label {
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: -0.006em;
  color: var(--text-2);
}
.field :is(input, select) {
  width: 100%;
  min-height: 2.75rem;
  padding: 0.5rem 0.75rem;
  font: 400 1rem/1.4 var(--ui);        /* 16px: iOS must not zoom on focus */
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r);
  transition: border-color 0.15s ease;
}
.field :is(input, select):hover { border-color: var(--text-3); }
.field :is(input, select):focus { border-color: var(--primary); }

/* A rejected submission's error panel, on the form card itself — the same
 * plane the fields sit on, not the dark shell behind it. */
.demo-form__errors {
  display: grid;
  gap: 0.375rem;
  padding: var(--space-4);
  background: var(--bad-bg);
  border: 1px solid var(--bad-bd);
  border-radius: var(--r);
  color: var(--bad);
  font-size: 0.9375rem;
}
.demo-form__errors p { font-weight: 600; }
.demo-form__errors ul { list-style: none; padding: 0; display: grid; gap: 0.25rem; }

/* The confirmation, replacing the form inside the same #demo-form card. The
 * card's own light-on-dark-shell styling above already does the framing —
 * this only sets the type inside it. */
.demo-form__done { text-align: center; padding-block: var(--space-4); }
.demo-form__done h3 { color: var(--ok); margin-bottom: var(--space-3); }
.demo-form__done p { color: var(--text-2); font-size: 1rem; }

.demo-form__notice {
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--text-2);   /* a purpose notice is read, not glanced at */
}
.demo-form__notice a { color: var(--accent); text-underline-offset: 2px; }

.demo-form .btn--big { width: 100%; }

/* --- the privacy notice --------------------------------------------------- */

/* The measure caps the blocks, not the article: .band already spends the
 * page's inset on padding, and a max-width on the article itself would be
 * that padding plus a column, which is how the notice ended up 288px wide. */
.prose > * { max-width: 36rem; }     /* ~70 characters at this body size */
.prose h1 {
  font-size: clamp(2rem, 3.4vw, 2.75rem);
  margin-bottom: var(--space-6);
}
.prose h2 {
  font-size: 1.3125rem;
  letter-spacing: -0.018em;
  margin: var(--space-7) 0 var(--space-3);
}
.prose p { color: var(--text-2); margin-bottom: var(--space-4); }
.prose a { color: var(--accent); text-underline-offset: 2px; }

/* --- the honeypot's hiding place ------------------------------------------
 * Clip-rect rather than display:none: a bot that renders CSS skips fields it
 * cannot see, and this one must look real to it. See Marketing::LeadsController. */

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- the reveal -----------------------------------------------------------
 * The hidden state is behind `.reveals`, and nothing on the page adds that
 * class except marketing.js, immediately before it starts observing. A
 * visitor with JavaScript off, or blocked, or still downloading never matches
 * these selectors and reads a page where everything is simply visible — which
 * is the only acceptable failure mode for a page whose whole job is to be
 * read. The class goes on the root element rather than the body so it is set
 * in the same task that queries the elements, with no reflow in between.
 *
 * The hero has no [data-reveal] on purpose. It is above the fold on every
 * width, and an above-the-fold reveal is a promise the script cannot keep on
 * a slow connection: it either lands late or flickers. Everything that
 * animates is something the reader scrolls to. */

/* The offset is the independent `translate` property, not `transform`, and
 * that is a correctness fix rather than a style preference. Three of the
 * twenty [data-reveal] blocks are .card, and `.reveals [data-reveal]` scores
 * one class higher than `.card:hover` — so written as `transform` the reveal
 * won, and the card's hover lift never moved a pixel once the card had been
 * revealed. `translate` composes with `transform` instead of replacing it, so
 * the reveal owns the arrival and :hover owns the lift, and neither has to
 * out-specify the other. A browser too old for the property drops both
 * declarations and the reveal becomes a plain fade, which is a fine thing to
 * degrade into. */
.reveals [data-reveal] {
  opacity: 0;
  translate: 0 1rem;
  transition: opacity 0.6s var(--ease), translate 0.6s var(--ease);
}
.reveals [data-reveal].is-visible {
  opacity: 1;
  translate: none;
}

/* The stagger. Only the two real groups get it — three cards and four steps,
 * both of which the eye reads as one row — and it is 70ms, which is enough to
 * feel dealt rather than dropped and short enough that the last one is not
 * still arriving when the reader has moved on. */
.reveals :is(.cards, .steps) > [data-reveal]:nth-child(2) { transition-delay: 70ms; }
.reveals :is(.cards, .steps) > [data-reveal]:nth-child(3) { transition-delay: 140ms; }
.reveals :is(.cards, .steps) > [data-reveal]:nth-child(4) { transition-delay: 210ms; }

/* --- two columns, and the windows reach the edge --------------------------
 * Below this width every band is a single column and the frames are fully
 * contained; above it, copy and window sit side by side and the window's
 * frame runs off the page edge — its border and radius drop on that side, so
 * the window reads as continuing past the viewport rather than stopping at a
 * suspiciously convenient margin. No overflow, no negative margins: the band
 * simply stops padding the side the window leaves through. */

@media (min-width: 64rem) {
  .hero,
  .band--feature {
    display: grid;
    align-items: center;
    gap: clamp(2rem, 4vw, 3.5rem);
  }

  /* The hero's wash waits for two columns, and this is why: below 64rem the
   * copy runs the full width and the eyebrow — 12px of --text-3 — ends up
   * inside any wash big enough to sit behind the window. With the columns
   * split the two never meet — sampled, the eyebrow sits on bare #faf8f5 and
   * 4.56:1 at both 1440 and 1024. Narrow screens get the frame's glow instead.
   *
   * The ellipse is centred on the window, not on the band: its peak sits at
   * the frame's own middle and it reaches zero at 11% of the hero's height —
   * below the frame's top edge, and a long way below the header's hairline.
   * Light that starts at the object it comes from reads as spill; light that
   * starts at the top of the page reads as fog. */
  .hero {
    background-image:
      radial-gradient(50% 38% at 73% 46%, var(--wash-green) 0%, transparent 92%);
  }

  .hero,
  .band--feature:not(.band--flip) { padding-right: 0; }
  .band--flip { padding-left: 0; padding-right: var(--inset); }

  .hero { grid-template-columns: minmax(0, clamp(22rem, 34%, 30rem)) minmax(0, 1fr); }
  .band--feature { grid-template-columns: minmax(0, clamp(20rem, 32%, 28rem)) minmax(0, 1fr); }
  .band--flip { grid-template-columns: minmax(0, 1fr) minmax(0, clamp(20rem, 32%, 28rem)); }
  .band--flip .feature__copy { grid-column: 2; }
  .band--flip .shot { grid-column: 1; grid-row: 1; }
  .band--flip .shot figcaption { padding-left: var(--pad); }

  :is(.hero, .band--feature:not(.band--flip)) .shot__view {
    border-right: 0;
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
  }
  .band--flip .shot__view {
    border-left: 0;
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
  }

  .shot--hero   { --shot-h: 30rem; }
  .shot--report { --shot-h: 28rem; }
  .shot--drawer { --shot-h: 29rem; }

  .steps { grid-template-columns: repeat(4, 1fr); }

  /* Two equal rows, the heading hung from the bottom of the first and the
   * lede from the top of the second: the pair then centres itself against
   * whatever height the form turns out to be, without a wrapper element. */
  .band--demo {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 30rem);
    grid-template-rows: 1fr 1fr;
    column-gap: clamp(3rem, 6vw, 5rem);
    row-gap: var(--space-4);
  }
  .band--demo > h2 { grid-area: 1 / 1; align-self: end; margin-bottom: 0; }
  .band--demo > .band__lede { grid-area: 2 / 1; align-self: start; }
  .band--demo > #demo-form { grid-column: 2; grid-row: 1 / span 2; margin-top: 0; }

  .band--faq {
    display: grid;
    grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
    column-gap: clamp(2rem, 5vw, 4rem);
  }
  .band--faq > h2 { margin-bottom: 0; }
  .band--faq .faq { max-width: 44rem; }
}

/* The nav is three links and a button on a 4rem bar; below this the button is
 * the one that has to survive. */
@media (max-width: 47.99rem) {
  .site-head__nav { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .marketing *,
  .marketing *::before,
  .marketing *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }

  /* Killing the duration is not enough for the reveal: a zero-length
   * transition still starts from opacity 0, so the reader would watch content
   * pop in as the observer caught up. Here the hidden state simply does not
   * exist, and the page is fully painted the moment it arrives. */
  .reveals [data-reveal] {
    opacity: 1;
    translate: none;
    transition-delay: 0s !important;
  }

  /* Nothing moves under the pointer either. Colour and shadow still respond,
   * so every hover target still confirms itself. */
  .btn:hover,
  .btn:active,
  .card:hover { transform: none; }
}

/* --- the pricing page ----------------------------------------------------- */

/* The price is the headline, so it is set as one: the figure carries the
 * display size an h1 would, and the unit sits beside it in the mono face the
 * eyebrows use, small enough that the number reads first. Baseline-aligned
 * rather than centred — a $49 whose unit floats at its middle reads as a
 * price tag, and this is a rate, not a sticker. */
.band--price { padding-block: clamp(2.5rem, 5vw, 4rem) var(--section); }

.price-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: 0 0 var(--space-5);
  font-weight: 400; /* the figure sets its own weight; the h1 default would leak onto the unit */
}

.price-head__figure {
  font: 600 clamp(3.25rem, 9vw, 5.5rem)/0.9 var(--ui);
  letter-spacing: -0.04em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  margin: 0;
}

.price-head__unit {
  font: 500 0.85rem/1.35 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
  margin: 0;
}

.band--price .lede { max-width: 54ch; margin-bottom: var(--space-6); }

/* The ticks list is a two-column feature grid here rather than the single
 * column it is inside a feature band: this page lists every capability at
 * once, and eight items in one column pushes the arithmetic below the fold. */
#included .ticks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: var(--space-3) var(--space-6);
}

/* The pricing page's closing band borrows the demo band's dark ground but not
 * its two-column grid: that grid exists to seat #demo-form in the second
 * column, and with no form here the actions land alone in an empty column,
 * floating clear of the copy they belong to. Source order carries this over
 * the grid rule — same specificity, declared later — so it holds at every
 * width without an !important or a deeper selector. */
.band--cta { display: block; }
.band--cta .hero__actions { margin-top: var(--space-6); }

/* .btn--ghost is built for the light ground: its --surface fill and --text
 * label read as a pale slab once the band underneath goes dark. Same glass
 * idea, inverted — a lit hairline over the band instead of a fill on top of
 * it. AA holds: --shell-text-hi on this band measures well past 4.5:1. */
.band--cta .btn--ghost {
  background: color-mix(in srgb, #fff 8%, transparent);
  border-color: color-mix(in srgb, #fff 24%, transparent);
  color: var(--shell-text-hi);
}
.band--cta .btn--ghost:hover {
  background: color-mix(in srgb, #fff 14%, transparent);
  border-color: color-mix(in srgb, #fff 36%, transparent);
}
/* The grid's row-gap went with the grid, leaving only the shared h2 margin
 * between heading and lede — too tight under a heading this size. */
.band--cta > h2 { margin-bottom: var(--space-5); }
