/* ==========================================================================
   Ownerdeck — od.css
   The design system for the multi-page site. One neutral ramp, one accent,
   two themes, no build step.

   Rules this file keeps to:
   · Every colour is a token on a palette block. No literal hex below the
     palette — that is what makes the dark theme a nine-line override rather
     than a second stylesheet.
   · Nothing that hides content depends on JavaScript. Reveal rules are scoped
     to .js, which an inline script in <head> adds. With that script blocked
     the page renders complete instead of blank.
   · Motion is decoration. prefers-reduced-motion removes all of it and the
     layout is unchanged.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Palette
   Measured, not guessed. Ratios noted are against that theme's --paper.
   -------------------------------------------------------------------------- */
:root {
  --paper:    #FFFFFF;
  --paper-2:  #FAFAFA;
  --paper-3:  #F4F4F5;
  --rule:     #E4E4E7;
  --rule-2:   #D4D4D8;
  --faint:    #A1A1AA;   /* 2.5:1 — rules, dividers, list dots, chevrons.
                            NEVER text. It was text in five places and every
                            one of them failed; see the rules below. */
  --muted:    #52525B;   /* 7.73:1 — carries every lede, caption and
                            answer on the site, so it is set for reading
                            rather than for the minimum that passes */
  --ink-2:    #27272A;
  --ink:      #09090B;   /* 19.9:1 */
  --invert:   #FFFFFF;   /* text on an --ink surface */
  --live:     #16803C;   /* 5.02:1 — the only non-neutral, for live/confirmed */

  /* Glass. Eight-digit hex so the alpha travels with the token.
     62% is not an aesthetic choice, it is the floor. The header floats over
     the trade photographs, and a 30px blur flattens those to about mid grey;
     below 62% the nav label drops under 4.5:1 in dark mode. Light mode needs
     --on-glass regardless, because --muted fails over a photo even at 70%. */
  --glass:       #FFFFFF9E;   /* 62% */
  --glass-lift:  #FFFFFFC4;   /* 77%, once the page has scrolled under it */
  --glass-edge:  #09090B1F;
  --glass-top:   #FFFFFFF2;   /* the bevel, catching light along the top */
  --glass-under: #09090B12;   /* inner bottom shadow — reads as thickness */
  --glass-sheen: #FFFFFF52;   /* diagonal light-catch across the fill */
  --glass-shade: #09090B0A;
  /* Header labels sit over whatever the capsule floats above, and that
     includes the near-black call-to-action band. Measured against every
     backdrop on the site, this is the lightest value that clears 4.5:1 on all
     of them — 5.8:1 at worst. A lighter grey looked better and failed. */
  --on-glass:    #27272A;
  /* Photographs run in colour by default and are desaturated only in dark
     mode, where full-colour images glare against the ground. */
  --img-filter:  none;

  /* Accents for the hero's floating cards, sampled from the banner so the top
     of the page and the link preview agree with each other. Decorative only —
     nothing legible is ever painted in these, so they carry no contrast duty
     and are identical in both themes. */
  /* The operator card. A cooler cast than the rest of the palette, on
     purpose — it is the one panel claiming to be a live readout, and the
     blue-grey rules and gold make it read as instrumentation rather than
     as more page. */
  --blueprint: #E1E7EF;   /* rules inside the card */
  --label:     #55637A;   /* its uppercase labels, 6.08:1 on white */
  --pill:      #0A0F1A;   /* the LIVE badge */
  --pill-ink:  #FFFFFF;
  --gold:      #C5A059;   /* 7.8:1 inside the pill. Never used on paper. */

  /* The third accent. Legible as small text, which is the whole point —
     an accent that only survives at display sizes cannot mark a link or an
     eyebrow. 6.70:1 on paper. --accent-ink is for text sitting on it. */
  --accent:     #1D4ED8;
  --accent-ink: #FFFFFF;

  /* Scroll-expand hero. The day plate is near-white (mean luminance 205), so
     the white title the component ships with would be invisible on it. Both
     the type and the scrim are paired to the theme instead. */
  --se-img:   url("/img/hero-lot-day.webp");
  --se-title: #09090B;
  --se-scrim: 255 255 255;

  /* Hero backdrop (acid-bg.js). Pale to accent, and kept quiet: this sits
     under the headline and the one button that matters. */
  /* Multi-hue and deliberately loud, anchored on colours the palette already
     owns: --f-site violet in the middle, cyan at the dim end, magenta at the
     hot one. The hot end has to be the dark colour on paper — the shader
     writes brightness into alpha, so pale highlights would simply vanish
     into a white page. Measured at full brightness under the headline:
     8.90:1, so the type is safe even where the lattice is densest. */
  --acid-1: #7FD4E8;
  --acid-2: #6D4AFF;
  --acid-3: #C2185B;
  --acid-opacity: 0.42;

  --f-answer: #7C5CFF;
  --f-site:   #6D4AFF;
  --f-book:   #4A7CFF;
  --f-reach:  #25D366;
  --f-return: #F5A524;
  --f-shine:  #FFFFFF8C;   /* 1px bevel along the card's top edge */
  --f-gloss:  #FFFFFF3D;   /* the fixed specular on the card face */

  --shadow:   16 16 20;  /* rgb triplet, alpha applied at use */

  --wrap:     72rem;
  --measure:  38rem;

  --display: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --body:    var(--display);
  --mono:    "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --r-sm: 8px;
  --r:    12px;
  --r-lg: 18px;
  --r-xl: 26px;

  --s1: .25rem;  --s2: .5rem;   --s3: .75rem;  --s4: 1rem;
  --s5: 1.5rem;  --s6: 2rem;    --s7: 3rem;    --s8: 4.5rem;
  --s9: 7rem;

  /* One easing family, so nothing on the page moves in a different accent. */
  --ease:      cubic-bezier(.22, .61, .36, 1);
  --ease-out:  cubic-bezier(.16, 1, .3, 1);
  --t-fast: 140ms;
  --t:      240ms;
  --t-slow: 560ms;
}

:root[data-theme="dark"],
:root:not([data-theme="light"]) {
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* Cooled toward the banner's indigo rather than sitting on neutral black.
       The ground was rgb(10,10,11) — one step of blue, which reads as a void.
       These carry 7 to 20 steps, enough to feel like a colour without becoming
       one, and the steps between the three surfaces are wider so sections
       actually separate. Every text pair re-measured: 18.8:1, 15.5:1, 7.7:1. */
    --paper:   #0B0B12;
    --paper-2: #141420;
    --paper-3: #1D1D2B;
    --rule:    #2A2A3A;
    --rule-2:  #3A3A4E;
    --faint:   #6E6E78;
    --muted:   #A1A1AA;   /* 7.84:1 */
    --ink-2:   #E4E4E7;
    --ink:     #FAFAFA;   /* 18.1:1 */
    --invert:  #09090B;
    --live:    #4ADE80;   /* 11.4:1 */
    --glass:       #0B0B129E;
    --glass-lift:  #0B0B12C4;
    --glass-edge:  #FFFFFF2E;
    --glass-top:   #FFFFFF29;
    --glass-under: #09090B4D;
    --glass-sheen: #FFFFFF1A;
    --glass-shade: #09090B26;
    --on-glass:    #E4E4E7;   /* 4.6:1 at worst, over the light CTA band */
    --img-filter:  grayscale(1) contrast(1.04);
    --f-shine:  #FFFFFF33;
    --f-gloss:  #FFFFFF1F;
    --blueprint: #262E40;
    --label:     #98A6BC;
    --pill:      #404C66;
    --pill-ink:  #FFFFFF;
    --gold:      #D9B36B;
    --accent:     #8FB3FF;
    --se-img:   url("/img/hero-lot-night.webp");
    --se-title: #FAFAFA;
    --se-scrim: 0 0 0;
    --acid-1: #241A5C;
    --acid-2: #7C5CFF;
    --acid-3: #F5A524;
    --acid-opacity: 0.52;   /* 9.39:1 on the dark ground */
    --accent-ink: #0B0B12;
    --shadow:  0 0 0;
    color-scheme: dark;
  }
}

/* The explicit choice has to win in both directions, so the same block is
   repeated for the attribute. A media query alone cannot be overridden by a
   toggle, and an attribute alone cannot follow the system. */
:root[data-theme="dark"] {
  --paper:   #0B0B12;
  --paper-2: #141420;
  --paper-3: #1D1D2B;
  --rule:    #2A2A3A;
  --rule-2:  #3A3A4E;
  --faint:   #6E6E78;
  --muted:   #A1A1AA;
  --ink-2:   #E4E4E7;
  --ink:     #FAFAFA;
  --invert:  #09090B;
  --live:    #4ADE80;
  --glass:       #0B0B129E;
  --glass-lift:  #0B0B12C4;
  --glass-edge:  #FFFFFF2E;
  --glass-top:   #FFFFFF29;
  --glass-under: #09090B4D;
  --glass-sheen: #FFFFFF1A;
  --glass-shade: #09090B26;
  --on-glass:    #E4E4E7;
  --img-filter:  grayscale(1) contrast(1.04);
  --f-shine:  #FFFFFF33;
  --f-gloss:  #FFFFFF1F;
  --shadow:
  --blueprint: #262E40;
  --label:     #98A6BC;
  --pill:      #404C66;
  --pill-ink:  #FFFFFF;
  --gold:      #D9B36B;
  --accent:     #8FB3FF;
  --se-img:   url("/img/hero-lot-night.webp");
  --se-title: #FAFAFA;
  --se-scrim: 0 0 0;
  --acid-1: #241A5C;
  --acid-2: #7C5CFF;
  --acid-3: #F5A524;
  --acid-opacity: 0.52;   /* 9.39:1 on the dark ground */
  --accent-ink: #0B0B12;
  --shadow:  0 0 0;
  color-scheme: dark;
}

/* Compatibility aliases. chat-widget.css and the demo page predate this
   stylesheet and still ask for the retired brand's token names. These are
   aliases, not colours: var() resolves at use time, so they follow whichever
   palette block is active and the widget themes itself for free. Delete them
   once those two files are rewritten. */
:root {
  --bone:     var(--paper);
  --bone-2:   var(--paper-3);
  --ink-soft: var(--muted);
  --clay:     var(--rule-2);
  --clay-deep: var(--ink);
  --radius:   var(--r);
}

/* --------------------------------------------------------------------------
   2. Fonts
   Loaded from Google Fonts, which the site's CSP already allows for both the
   stylesheet and the font files. Nothing else external is permitted.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   3. Reset and base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6.5rem;   /* the floating header capsule */
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 1rem;
  line-height: 1.6;
  font-weight: 420;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg, video { max-width: 100%; height: auto; display: block; }
button, input, select, textarea { font: inherit; color: inherit; }

a { color: inherit; text-decoration-color: var(--rule-2); text-underline-offset: 3px; }
a:hover { text-decoration-color: currentColor; }

/* Links written into sentences, which until now inherited the body colour and
   were findable only by a faint underline. Scoped to <main> so the footer's
   list of links stays chrome, and to unclassed anchors so buttons, tiles and
   cards keep their own treatment — there are no classed anchors inside a <p>
   or <li> anywhere on the site, so this cannot catch one by accident. */
main p a:not([class]),
main li a:not([class]) {
  color: var(--accent);
  text-decoration-color: var(--accent);
  text-decoration-thickness: 1px;
}
main p a:not([class]):hover,
main li a:not([class]):hover { text-decoration-thickness: 2px; }

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 3px;
}

::selection { background: var(--ink); color: var(--invert); }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--invert);
  padding: var(--s3) var(--s5); border-radius: 0 0 var(--r) 0;
}
.skip-link:focus { left: 0; }

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

/* --------------------------------------------------------------------------
   4. Typography
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.03em;
  margin: 0 0 var(--s4);
  text-wrap: balance;
}

h1 { font-size: clamp(2.5rem, 1.6rem + 3.9vw, 4.25rem); }
h2 { font-size: clamp(1.9rem, 1.35rem + 2.3vw, 3rem); }
h3 { font-size: clamp(1.2rem, 1.05rem + .6vw, 1.5rem); letter-spacing: -0.02em; }
h4 { font-size: 1.0625rem; letter-spacing: -0.01em; }

/* Heading level is about the document outline; size is about the design. When
   an item is a top-level section of its page but should not read as loudly as
   one, the level stays honest and the size comes from here. */
.t-h3 { font-size: clamp(1.2rem, 1.05rem + .6vw, 1.5rem); letter-spacing: -0.02em; }
.t-h4 { font-size: 1.0625rem; letter-spacing: -0.01em; }

p { margin: 0 0 var(--s4); }
p:last-child { margin-bottom: 0; }

.lede {
  font-size: clamp(1.0625rem, 1rem + .35vw, 1.25rem);
  line-height: 1.62;
  color: var(--muted);
  max-width: 34rem;
  text-wrap: pretty;
}

.eyebrow {
  font-family: var(--mono);
  font-size: .75rem;          /* was .6875 — mono uppercase needs the size */
  letter-spacing: .14em;      /* and less tracking, which was hurting it */
  text-transform: uppercase;
  /* Was --muted, which made the section markers recede exactly where a
     reader is deciding whether to keep going. */
  color: var(--accent);
  margin: 0 0 var(--s4);
  font-weight: 550;
}

.measure { max-width: var(--measure); }

/* --------------------------------------------------------------------------
   5. Layout
   -------------------------------------------------------------------------- */
.wrap {
  width: min(100% - 2.5rem, var(--wrap));
  margin-inline: auto;
}
/* 16px of gutter had the content pressed against both edges while the
   sections floated in 224px of vertical nothing — cramped and stretched at
   the same time, which is what reads as squished. */
@media (max-width: 48rem) {
  :root { --s7: 2rem; --s8: 2.75rem; --s9: 3.5rem; }
  .wrap { width: min(100% - 2.5rem, var(--wrap)); }

  /* 24px between four children is 72px of gap in a 350px pill. With the tap
     targets at their proper 44px that pushed the menu button 15px outside
     the capsule. The spacer exists to hold the desktop nav apart and has
     nothing to separate once the nav is hidden. */
  .masthead__bar { gap: var(--s2); padding-inline: .4rem; }
  /* The spacer is what pushed the controls to the right edge; hiding it to
     save gap left them bunched against the wordmark with the rest of the
     pill empty. An auto margin does the same job and costs nothing. */
  .masthead__nav-spacer { display: none; }
  .masthead__tools { gap: var(--s1); margin-inline-start: auto; }
  .masthead__mark { padding-inline-start: .35rem; }
}

/* The switcher moves into the menu below 48rem (i18n.js), which frees the
   63px the wordmark needs. Trading the brand name for a control most people
   touch once was the wrong way round. */
.od-lang--in-menu { position: static; width: 100%; margin-top: var(--s2); }
.od-lang--in-menu .od-lang-btn {
  width: 100%; justify-content: center; height: 2.75rem;
}
.od-lang--in-menu .od-lang-menu {
  position: static; min-width: 0; margin-top: var(--s2);
  box-shadow: none; background: var(--paper-2);
}

.section { padding-block: var(--s9); }
/* A section that runs to the edges and supplies its own height. The scroll
   expand is a sticky stage inside a tall track, so the usual block padding
   would push the stage out of alignment with the viewport it sticks to. */
.section--flush { padding-block: 0; }

/* --- Hero, and the cards drifting behind it --------------------------------
   Ambient only. They sit under the content, never take the pointer, and carry
   no meaning — the hero reads identically with this whole block deleted. */
.section--hero { position: relative; overflow: hidden; }
/* Trimmed from the section default: every 16px here is 16px of the first
   screen that is not showing the visitor anything they can act on. */
.section--hero { padding-block: var(--s7) var(--s8); }
@media (max-width: 48rem) {
  .section--hero { padding-block: var(--s6) var(--s7); }
}
/* A single soft wash behind the hero. Large, very low opacity, and sitting
   under everything — enough to stop the top of the page reading as flat black
   without becoming a colour in its own right. */
.section--hero::before {
  content: ""; position: absolute; z-index: 0; pointer-events: none;
  inset-inline-start: -10%; top: -30%;
  width: 70%; aspect-ratio: 1;
  background: radial-gradient(circle, var(--f-site), transparent 68%);
  opacity: .07;
  filter: blur(40px);
}
.section--hero > .wrap { position: relative; z-index: 1; }

/* The shader canvas. Same layer as the wash above it — decorative, behind
   everything, and never in the way of a pointer. A mask fades it out toward
   the bottom so the lattice does not run into the section beneath. */
.acid-bg__canvas {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  display: block; pointer-events: none;
  /* currentColor, not a literal: a mask reads alpha only, so the hue is
     irrelevant and this keeps the palette rule honest. */
  -webkit-mask-image: linear-gradient(to bottom, currentColor 45%, transparent 92%);
          mask-image: linear-gradient(to bottom, currentColor 45%, transparent 92%);
}

.section--tight { padding-block: var(--s8); }
.section--edge { border-top: 1px solid var(--rule); }
.section--sunk { background: var(--paper-2); }

.grid { display: grid; gap: var(--s5); }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 62rem) {
  .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 40rem) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; }
}

.split {
  display: grid;
  grid-template-columns: 1.05fr .95fr;
  gap: var(--s8);
  align-items: center;
}
@media (max-width: 62rem) {
  .split { grid-template-columns: 1fr; gap: var(--s7); }
}

.hero-copy {
  /* Wider than --measure (38rem). At 38rem the h1 set to three lines and
     pushed the button row off a 720px laptop; 46rem takes it to two. */
  max-width: 46rem;
  margin-inline: auto;
  text-align: center;
}
/* The hero headline is the only one on the site that has to share a viewport
   with a call to action, so it is sized for the fold rather than for impact.
   4.25rem looked better in isolation and cost the button its place. */
.hero-copy h1 { font-size: clamp(2.15rem, 1.5rem + 2.6vw, 3.35rem); }
.hero-copy .lede { max-width: 40rem; margin-inline: auto; }
.hero-copy .btn-row,
.hero-copy .proof-strip {
  justify-content: center;
}
.hero-copy .proof-strip {
  margin-inline: auto;
}
.hero-copy .note {
  max-width: 34rem;
  margin-inline: auto;
}

.section__head { max-width: 44rem; margin-bottom: var(--s7); }

/* --------------------------------------------------------------------------
   6. Header
   -------------------------------------------------------------------------- */
/* A floating capsule, not a full-width bar. The sticky element itself is
   transparent and ignores the pointer, so the page scrolls past on either
   side of the pill; the glass is the bar inside it. */
.masthead {
  position: sticky; top: .75rem; z-index: 50;
  padding-block: .75rem;
  pointer-events: none;
}

.masthead__bar {
  pointer-events: auto;
  display: flex; align-items: center; gap: var(--s5);
  height: 3.5rem;
  padding-inline: .5rem .5rem;
  border-radius: 999px;
  /* A diagonal sheen over the fill, so one edge looks like it is catching the
     light instead of the whole pill being evenly lit. The gradient is a layer
     above the flat fill; both sit over whatever the backdrop-filter blurred. */
  background:
    linear-gradient(100deg,
      var(--glass-sheen) 0%,
      transparent 38%,
      transparent 68%,
      var(--glass-shade) 100%),
    var(--glass);
  /* 30px, not 22. A heavier blur is what makes the pill read as thick glass
     rather than tinted plastic, and it flattens whatever is behind it into a
     predictable wash — which is what keeps the label legible over a photo. */
  backdrop-filter: blur(30px) saturate(190%);
  -webkit-backdrop-filter: blur(30px) saturate(190%);
  border: 1px solid var(--glass-edge);
  /* Four layers. A hairline contact shadow, a wide soft one for lift, a bright
     inset bevel along the top, and an inset shade along the bottom — that last
     pair is the trick, because an edge lit on one side and shaded on the other
     is what the eye reads as thickness rather than as a flat outline. */
  box-shadow:
    0 1px 2px rgb(var(--shadow) / .05),
    0 12px 34px rgb(var(--shadow) / .10),
    inset 0 1px 0 var(--glass-top),
    inset 0 -1px 0 var(--glass-under);
  transition: background var(--t) var(--ease),
              box-shadow var(--t) var(--ease),
              border-color var(--t) var(--ease);
}

/* Once the page has moved under it, the glass thickens slightly and the lift
   deepens. Subtle on purpose — it should register without being noticed. */
.masthead.is-stuck .masthead__bar {
  background:
    linear-gradient(100deg,
      var(--glass-sheen) 0%,
      transparent 38%,
      transparent 68%,
      var(--glass-shade) 100%),
    var(--glass-lift);
  box-shadow:
    0 1px 2px rgb(var(--shadow) / .06),
    0 16px 44px rgb(var(--shadow) / .14),
    inset 0 1px 0 var(--glass-top),
    inset 0 -1px 0 var(--glass-under);
}

/* Safari and Firefox without backdrop-filter would show text over a
   half-transparent panel, so those get an opaque fill instead. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .masthead__bar { background: var(--paper); border-color: var(--rule); }
}

.masthead__mark { padding-inline-start: .65rem; }

.masthead__mark {
  display: inline-flex; align-items: center; gap: .55rem;
  font-weight: 600; font-size: 1.0625rem; letter-spacing: -0.02em;
  text-decoration: none; flex: 0 0 auto;
}
/* The OD monogram. A single alpha-mask PNG painted with currentColor, so it
   inherits whatever colour the wordmark next to it is using and needs no
   separate light and dark artwork. Sized by height with the file's own aspect
   ratio, so it stays optically level with the cap height of the word. */
.od-mark {
  display: block;
  height: 1.1rem;
  aspect-ratio: 506 / 284;
  flex: 0 0 auto;
  background: currentColor;
  -webkit-mask: url("/ownerdeck-mark-mask.png") no-repeat center / contain;
          mask: url("/ownerdeck-mark-mask.png") no-repeat center / contain;
}
/* Without mask support this would paint as a solid rectangle, which is worse
   than no mark at all. */
@supports not ((-webkit-mask: url("")) or (mask: url(""))) {
  .od-mark { display: none; }
}

.masthead__nav {
  display: flex; align-items: center; gap: var(--s2);
  margin-inline: auto;
}
.masthead__nav a {
  position: relative;
  padding: .45rem .7rem;
  border-radius: var(--r-sm);
  font-size: .9375rem;
  /* --on-glass, not --muted. These labels sit over whatever the capsule is
     floating above, which includes the photographs and the near-black call to
     action band. Measured over the latter, --muted comes out at 2.3:1. */
  color: var(--on-glass);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.masthead__nav a:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 6%, transparent); }
/* The active item gets its own filled pill inside the capsule, the way the
   selected tab does on a native bar. A tint rather than a solid, so the glass
   still shows through it. */
.masthead__nav a[aria-current="page"] {
  color: var(--ink); font-weight: 550;
  background: color-mix(in srgb, var(--ink) 8%, transparent);
}

.masthead__tools { display: flex; align-items: center; gap: var(--s2); flex: 0 0 auto; }

.icon-btn {
  /* 2.25rem is 36px, under the 44px floor for a touch target. */
  width: 2.75rem; height: 2.75rem;
  display: grid; place-items: center;
  background: none; border: 1px solid var(--rule);
  border-radius: 999px; color: var(--on-glass); cursor: pointer;
  transition: color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease);
}
.icon-btn:hover { color: var(--ink); border-color: var(--rule-2); background: color-mix(in srgb, var(--ink) 6%, transparent); }
.icon-btn svg { width: 17px; height: 17px; }

/* Theme toggle shows the icon of the theme you would switch *to*. */
.ic-moon { display: none; }
:root[data-theme="dark"] .ic-sun { display: none; }
:root[data-theme="dark"] .ic-moon { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ic-sun { display: none; }
  :root:not([data-theme="light"]) .ic-moon { display: block; }
}

/* --------------------------------------------------------------------------
   7. Language switcher
   A <details> element, so it opens, closes and takes keyboard focus with no
   JavaScript at all.
   -------------------------------------------------------------------------- */
/* The markup here is built by i18n.js, not written in the pages, so these
   selectors match that file's DOM and must not be renamed independently. */
.od-lang { position: relative; }

.od-lang-btn {
  display: inline-flex; align-items: center; gap: .35rem;
  height: 2.75rem; padding-inline: .8rem;
  background: none; border: 1px solid var(--rule); border-radius: 999px;
  color: var(--on-glass); cursor: pointer;
  transition: color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease);
}
.od-lang-btn:hover { color: var(--ink); border-color: var(--rule-2); background: color-mix(in srgb, var(--ink) 6%, transparent); }
.od-lang-btn svg { width: 15px; height: 15px; }
.od-lang-code {
  font-family: var(--mono); font-size: .6875rem; font-weight: 500;
  letter-spacing: .06em;
}

.od-lang-menu {
  position: absolute; inset-inline-end: 0; top: calc(100% + .5rem);
  min-width: 10.5rem; padding: var(--s2); z-index: 60;
  background: var(--paper); border: 1px solid var(--rule);
  border-radius: var(--r); box-shadow: 0 12px 34px rgb(var(--shadow) / .13);
  display: flex; flex-direction: column; gap: 1px;
}
/* display:flex above outranks the browser's default [hidden] rule, so the
   hidden state has to be restated or the menu is permanently open. */
.od-lang-menu[hidden] { display: none; }

.od-lang-menu button {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  width: 100%; text-align: start;
  background: none; border: 0; border-radius: var(--r-sm);
  padding: .5rem .65rem; cursor: pointer;
  font-size: .9375rem; color: var(--ink);
  transition: background var(--t-fast) var(--ease);
}
.od-lang-menu button:hover { background: var(--paper-3); }
.od-lang-menu button[aria-checked="true"]::after {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--ink); flex: 0 0 auto;
}

/* --------------------------------------------------------------------------
   8. Mobile menu
   -------------------------------------------------------------------------- */
.mmenu { display: none; position: relative; }
.mmenu > summary {
  list-style: none; cursor: pointer;
  /* 2.25rem is 36px. The other two header controls were taken to 44 for the
     tap-target floor and this one was missed — it is a <summary>, not a
     .icon-btn, so the rule that fixed them never reached it. */
  width: 2.75rem; height: 2.75rem;
  display: grid; place-items: center;
  border: 1px solid var(--rule); border-radius: 999px;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.mmenu > summary::-webkit-details-marker { display: none; }
.mmenu > summary:hover { border-color: var(--rule-2); background: color-mix(in srgb, var(--ink) 6%, transparent); }

.mmenu__bars { display: block; width: 15px; height: 11px; position: relative; }
.mmenu__bars i,
.mmenu__bars::before,
.mmenu__bars::after {
  content: ""; position: absolute; left: 0; right: 0; height: 1.5px;
  background: var(--ink); border-radius: 2px;
  transition: transform var(--t) var(--ease), opacity var(--t-fast) var(--ease);
}
.mmenu__bars::before { top: 0; }
.mmenu__bars i { top: 4.75px; }
.mmenu__bars::after { bottom: 0; }
.mmenu[open] .mmenu__bars::before { transform: translateY(4.75px) rotate(45deg); }
.mmenu[open] .mmenu__bars i { opacity: 0; }
.mmenu[open] .mmenu__bars::after { transform: translateY(-4.75px) rotate(-45deg); }

.mmenu__panel {
  position: absolute; inset-inline-end: 0; top: calc(100% + .6rem);
  width: min(17rem, calc(100vw - 2rem));
  padding: var(--s3);
  background: var(--paper); border: 1px solid var(--rule);
  border-radius: var(--r-lg); box-shadow: 0 16px 44px rgb(var(--shadow) / .15);
  display: flex; flex-direction: column; gap: 2px;
}
.mmenu:not([open]) .mmenu__panel { display: none; }

/* Unclassed links only. This rule is (0,2,1) and .btn--primary is (0,1,0),
   so before the :not() it was painting the Get started button's label in
   --ink on its --ink background — a solid block with no text in it — and
   overriding .mmenu__quiet's muted colour at the same time. Anything in
   here that carries a class brings its own styling. */
.mmenu__panel a:not([class]) {
  padding: .6rem .7rem; border-radius: var(--r-sm);
  text-decoration: none; font-size: .9375rem; color: var(--ink);
  transition: background var(--t-fast) var(--ease);
}
.mmenu__panel a:not([class]):hover { background: var(--paper-3); }
.mmenu__panel a:not([class])[aria-current="page"] { font-weight: 600; }
.mmenu__sep { height: 1px; background: var(--rule); margin: var(--s2) .3rem; }
.mmenu__panel .btn { margin-top: var(--s2); justify-content: center; }

/* 68rem, not 60: five nav labels plus the mark, the two icon buttons and the
   call to action need about 1080px before they start colliding. Measured at
   966px, where the labels were wrapping onto two lines. */
@media (max-width: 68rem) {
  .masthead__nav { display: none; }
  .mmenu { display: block; }
  /* Qualified with .masthead on purpose. The plain `.masthead__cta` selector
     ties with `.btn { display: inline-flex }` on specificity, and .btn is
     declared later in this file, so it won — the call to action stayed on
     screen at 375px and pushed the hamburger out of the viewport. */
  .masthead .masthead__cta { display: none; }
  .masthead__nav-spacer { margin-inline: auto; }
}

/* --------------------------------------------------------------------------
   9. Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .78rem 1.3rem;
  border-radius: 999px; border: 1px solid transparent;
  font-size: .9375rem; font-weight: 550; letter-spacing: -0.01em;
  text-decoration: none; cursor: pointer;
  transition: transform var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              box-shadow var(--t) var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn svg { width: 15px; height: 15px; flex: 0 0 auto; }
.btn__arrow { transition: transform var(--t) var(--ease); }
.btn:hover .btn__arrow { transform: translateX(3px); }

.btn--primary {
  background: var(--ink); color: var(--invert);
  box-shadow: 0 1px 2px rgb(var(--shadow) / .18);
}
.btn--primary:hover {
  background: var(--ink-2);
  box-shadow: 0 6px 18px rgb(var(--shadow) / .20);
}

.btn--ghost { color: var(--ink); border-color: var(--rule); background: var(--paper); }
.btn--ghost:hover { border-color: var(--rule-2); background: var(--paper-3); }

.btn--bare { color: var(--ink); padding-inline: .35rem; }
.btn--bare:hover { color: var(--muted); }

.btn-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); }
.btn--sm { padding: .55rem 1rem; font-size: .875rem; }

/* --------------------------------------------------------------------------
   10. Badge, pills and small pieces
   -------------------------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .34rem .8rem .34rem .65rem;
  border: 1px solid var(--rule); border-radius: 999px;
  font-size: .8125rem; color: var(--muted); background: var(--paper);
}
.badge::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: var(--ink); flex: 0 0 auto;
}
.badge--live::before { background: var(--live); }

.pill {
  display: inline-flex; align-items: center;
  padding: .3rem .7rem; border-radius: 999px;
  background: var(--paper-3); border: 1px solid var(--rule);
  font-size: .8125rem; color: var(--muted);
}

.note { font-size: .875rem; color: var(--muted); }
.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   11. Panels and cards
   -------------------------------------------------------------------------- */
.panel {
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--r-xl);
  padding: var(--s6);
}
.panel--flush { padding: 0; overflow: hidden; }
.panel--plain { background: var(--paper); }

.tile {
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  padding: var(--s5);
  display: flex; flex-direction: column; gap: var(--s3);
  transition: border-color var(--t) var(--ease),
              transform var(--t) var(--ease),
              box-shadow var(--t) var(--ease);
}
a.tile { text-decoration: none; }
a.tile:hover {
  border-color: var(--rule-2);
  transform: translateY(-3px);
  box-shadow: 0 12px 30px rgb(var(--shadow) / .09);
}
.tile__n {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .1em;
  color: var(--muted);
}
.tile h2, .tile h3 { margin: 0; }
.tile p { color: var(--muted); font-size: .9375rem; margin: 0; }

.tile__icon {
  width: 2.5rem; height: 2.5rem; border-radius: var(--r);
  display: grid; place-items: center;
  background: var(--paper-3); border: 1px solid var(--rule);
  color: var(--ink);
}
.tile__icon svg { width: 19px; height: 19px; }

/* Numbered reality list */
.numbered { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.numbered li {
  display: grid; grid-template-columns: 3rem 1fr; gap: var(--s4);
  align-items: baseline;
  padding-block: var(--s5);
  border-top: 1px solid var(--rule);
}
.numbered li:last-child { border-bottom: 1px solid var(--rule); }
.numbered b {
  font-family: var(--mono); font-size: .75rem; font-weight: 500;
  color: var(--muted); letter-spacing: .08em;
}
.numbered span { font-size: clamp(1.0625rem, 1rem + .4vw, 1.3125rem); letter-spacing: -0.015em; }

/* --------------------------------------------------------------------------
   12. Deck cards
   -------------------------------------------------------------------------- */
.deck { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s4); }
.deck--row { grid-auto-flow: column; grid-auto-columns: 1fr; }
@media (max-width: 62rem) { .deck--row { grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 40rem) { .deck--row { grid-template-columns: 1fr; } }

.dcard {
  display: flex; flex-direction: column; gap: var(--s2);
  padding: var(--s5) var(--s4);
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  background: var(--paper-2); text-decoration: none;
  transition: border-color var(--t) var(--ease),
              transform var(--t) var(--ease),
              background var(--t) var(--ease);
}
a.dcard:hover { border-color: var(--rule-2); background: var(--paper-3); transform: translateY(-3px); }
.dcard__name { font-weight: 600; letter-spacing: -0.02em; font-size: 1.0625rem; }
.dcard__line { font-size: .875rem; color: var(--muted); }
.dcard__i { width: 22px; height: 22px; color: var(--ink); margin-bottom: var(--s2); }

/* The little card chips used inside pricing plans */
/* .chips is a <ul> and every .chip is an <li>, so it needs the markers turned
   off here and not only inside .plan. Without this the home page tiles kept
   the browser's default discs — one down the left of every wrapped row, plus
   a stray marker rendering inside the pill itself, because a list item set to
   inline-flex still generates one. */
.chips { display: flex; flex-wrap: wrap; gap: .35rem; list-style: none; margin: 0; padding: 0; }
.chip {
  font-size: .75rem; padding: .22rem .55rem; border-radius: 999px;
  border: 1px solid var(--rule); color: var(--muted); background: var(--paper);
}
.chip[data-on="1"] { color: var(--ink); border-color: var(--rule-2); background: var(--paper-3); font-weight: 500; }

/* --------------------------------------------------------------------------
   13. Chat mock
   -------------------------------------------------------------------------- */
.mock {
  border: 1px solid var(--rule); border-radius: var(--r-xl);
  background: var(--paper); overflow: hidden;
  box-shadow: 0 22px 60px rgb(var(--shadow) / .10);
}
.mock__bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--s4) var(--s5); border-bottom: 1px solid var(--rule);
}
.mock__title { font-weight: 600; letter-spacing: -0.02em; }
.mock__meta {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .14em;
  color: var(--muted); text-transform: uppercase;
}
.mock__body { padding: var(--s5); display: flex; flex-direction: column; gap: var(--s3); }
.bub {
  max-width: 82%; padding: .7rem .95rem; border-radius: var(--r-lg);
  font-size: .9375rem; line-height: 1.5;
}
.bub--them { align-self: flex-start; background: var(--paper-3); border: 1px solid var(--rule); }
.bub--us { align-self: flex-end; background: var(--ink); color: var(--invert); }
.mock__foot {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s4) var(--s5); border-top: 1px solid var(--rule);
  background: var(--paper-2); font-size: .875rem; color: var(--muted);
}
.mock__tick {
  width: 1.35rem; height: 1.35rem; border-radius: 50%;
  background: var(--live); color: var(--paper);
  display: grid; place-items: center; flex: 0 0 auto;
}
.mock__tick svg { width: 12px; height: 12px; }

/* --------------------------------------------------------------------------
   14. Stats and proof
   -------------------------------------------------------------------------- */
/* The most checkable claims, pulled into the hero before the visitor has to
   decide whether the rest of the page is worth reading. Built as a readout
   rather than a banner: the badge straddles the top edge, and the three
   bands underneath are header, numbers, standing facts. */
.proof-strip {
  position: relative;
  width: 100%;
  max-width: 38rem;
  margin-top: var(--s6);
  border: 1px solid var(--blueprint);
  border-radius: var(--r);
  background: var(--paper);
  /* Long, shallow and barely there — the card should lift off the page
     without announcing a drop shadow. */
  box-shadow: 0 30px 80px -40px rgb(var(--shadow) / .28);
  text-align: start;
}

/* The badge sits across the border rather than inside the padding, which is
   what makes the card read as a device with a light on it. */
.proof-strip__live {
  position: absolute;
  top: -0.72rem; inset-inline-start: 1.25rem;
  display: inline-flex; align-items: center; gap: .5rem;
  margin: 0; padding: .32rem .7rem;
  border-radius: var(--r-sm);
  background: var(--pill); color: var(--pill-ink);
  font-family: var(--mono);
  font-size: .625rem; letter-spacing: .16em; text-transform: uppercase;
}
.proof-strip__dot {
  width: .375rem; height: .375rem; border-radius: 50%;
  background: var(--gold);
  animation: proofPulse 2.4s ease-in-out infinite;
}
@keyframes proofPulse { 0%, 100% { opacity: 1 } 50% { opacity: .35 } }
@media (prefers-reduced-motion: reduce) {
  .proof-strip__dot { animation: none; }
}

.proof-strip__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s4);
  padding: var(--s5) var(--s5) var(--s4);
  border-bottom: 1px solid var(--blueprint);
}
.proof-strip__who  { margin: 0; font-size: .8125rem; font-weight: 500; color: var(--ink); }
.proof-strip__span {
  margin: 0; font-family: var(--mono);
  font-size: .625rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--label); white-space: nowrap;
}

.proof-strip__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-bottom: 1px solid var(--blueprint);
}
.proof-metric { min-width: 0; padding: var(--s5); }
.proof-metric + .proof-metric { border-inline-start: 1px solid var(--blueprint); }
.proof-metric__n {
  display: block;
  font-size: clamp(1.5rem, 1rem + 1.6vw, 2.25rem);
  font-weight: 600; letter-spacing: -0.045em; line-height: 1;
  font-variant-numeric: tabular-nums; white-space: nowrap;
  color: var(--ink);
}
.proof-metric__l {
  display: block; margin-top: .55rem;
  font-family: var(--mono);
  font-size: .625rem; letter-spacing: .13em; text-transform: uppercase;
  line-height: 1.45; color: var(--label);
}

.proof-strip__foot {
  display: grid; grid-template-columns: repeat(3, 1fr);
  font-size: .75rem;
}
.proof-strip__foot > div { padding: var(--s4) var(--s5); min-width: 0; }
.proof-strip__foot > div + div { border-inline-start: 1px solid var(--blueprint); }
.proof-strip__k {
  display: block; color: var(--label);
  font-family: var(--mono); font-size: .5875rem;
  letter-spacing: .13em; text-transform: uppercase;
}
.proof-strip__v { display: block; margin-top: .2rem; font-weight: 600; color: var(--ink); }

@media (max-width: 34rem) {
  /* Three columns gave the labels 114px of width at 10px: it passed contrast
     and still had to be squinted at. Two columns buys the room to raise them;
     the third metric sits underneath, divided by a rule rather than a gap. */
  .proof-strip__grid { grid-template-columns: repeat(2, 1fr); }
  .proof-metric__l { font-size: .6875rem; letter-spacing: .1em; }
  .proof-strip__k  { font-size: .6875rem; letter-spacing: .1em; }
  .proof-metric:nth-child(odd) { border-inline-start: 0; }
  .proof-metric:nth-child(n+3) { border-top: 1px solid var(--blueprint); }
  .proof-metric { padding: var(--s4) var(--s3); }
  .proof-strip__foot > div { padding: var(--s3); }
  .proof-strip__head { padding: var(--s5) var(--s4) var(--s3); }
  .proof-strip__who { font-size: .75rem; }
}
/* Below this the three columns of prose stop fitting, so the standing facts
   go under each other while the numbers keep their row. */
@media (max-width: 25rem) {
  .proof-strip__foot { grid-template-columns: 1fr; }
  .proof-strip__foot > div + div {
    border-inline-start: 0; border-top: 1px solid var(--blueprint);
  }
}

.stat { display: flex; flex-direction: column; gap: var(--s1); }
.stat__n {
  font-size: clamp(3rem, 2rem + 4.5vw, 5.5rem);
  font-weight: 600; letter-spacing: -0.045em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.stat__l { color: var(--muted); font-size: .9375rem; max-width: 18rem; }

.ledger { border: 1px solid var(--rule); border-radius: var(--r-lg); overflow: hidden; }
.ledger__row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s4); padding: var(--s4) var(--s5);
  border-bottom: 1px solid var(--rule); font-size: .9375rem;
}
.ledger__row:last-child { border-bottom: 0; }
.ledger__row span:first-child { color: var(--muted); }
.ledger__row b { font-weight: 600; font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   15. Trade tiles with photography
   -------------------------------------------------------------------------- */
.trades { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s4);
          grid-template-columns: repeat(3, 1fr); }
@media (max-width: 62rem) { .trades { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 40rem) { .trades { grid-template-columns: 1fr; } }

.trade {
  position: relative; overflow: hidden;
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  background: var(--paper-2);
  display: flex; flex-direction: column;
  transition: border-color var(--t) var(--ease), transform var(--t) var(--ease);
}
.trade:hover { border-color: var(--rule-2); transform: translateY(-3px); }
.trade__img { aspect-ratio: 4 / 3; overflow: hidden; background: var(--paper-3); }
.trade__img img {
  width: 100%; height: 100%; object-fit: cover;
  filter: var(--img-filter);
  transition: filter var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
.trade:hover .trade__img img { filter: none; transform: scale(1.04); }
.trade__body { padding: var(--s4) var(--s5) var(--s5); }
.trade__body h2 { font-size: 1.0625rem; margin: 0 0 var(--s1); letter-spacing: -0.015em; }
.trade__body p { font-size: .875rem; color: var(--muted); margin: 0; }

/* --------------------------------------------------------------------------
   15a. Trade strip — the compact photo row on the home page
   Smaller and denser than .trades, because on the home page its job is
   recognition, not description. Six tiles, caption under the crop.
   -------------------------------------------------------------------------- */
.strip {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--s4);
  grid-template-columns: repeat(6, 1fr);
}
@media (max-width: 68rem) { .strip { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 34rem) { .strip { grid-template-columns: repeat(2, 1fr); } }

.strip li { display: flex; flex-direction: column; gap: var(--s3); }
.strip figure { margin: 0; }
.strip__img {
  aspect-ratio: 1 / 1; overflow: hidden;
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  background: var(--paper-3);
}
.strip__img img {
  width: 100%; height: 100%; object-fit: cover;
  filter: var(--img-filter);
  transition: filter var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
.strip li:hover .strip__img img { filter: none; transform: scale(1.05); }
.strip figcaption {
  font-size: .875rem; color: var(--muted); text-wrap: balance;
}

/* --------------------------------------------------------------------------
   15c. Name card — who you are dealing with
   Literally a card, because the whole brand is a deck of them.
   -------------------------------------------------------------------------- */
.namecard {
  border: 1px solid var(--rule); border-radius: var(--r-xl);
  background: var(--paper); padding: var(--s6);
  box-shadow: 0 22px 60px rgb(var(--shadow) / .10);
  max-width: 24rem;
}
.namecard__top {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s4); padding-bottom: var(--s5);
  border-bottom: 1px solid var(--rule);
}
.namecard__top svg { width: 22px; height: 22px; color: var(--ink); }
.namecard__name {
  font-family: var(--display); font-weight: 600; font-size: 1.5rem;
  letter-spacing: -0.03em; margin: var(--s5) 0 var(--s1);
}
.namecard__role { color: var(--muted); font-size: .9375rem; margin: 0 0 var(--s5); }
.namecard__facts { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s3); }
.namecard__facts li {
  display: grid; grid-template-columns: 1rem 1fr; gap: .6rem;
  font-size: .9375rem; align-items: start;
}
.namecard__facts li::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: var(--faint); margin-top: .6rem;
}

/* --------------------------------------------------------------------------
   15d. The get-started flow
   Every step is in the markup and visible by default. start.js adds
   .is-stepped once it runs, and only then does one question at a time appear —
   so with scripting off this is a long readable page, not a dead end.
   -------------------------------------------------------------------------- */
.flow { max-width: 46rem; margin-inline: auto; }
.flow__step { padding-block: var(--s6); }
.flow.is-stepped .flow__step { padding-block: 0; }
.flow.is-stepped .flow__step[hidden] { display: none; }

.js .flow.is-stepped .flow__step {
  opacity: 0; transform: translateY(10px);
  transition: opacity var(--t) var(--ease-out), transform var(--t) var(--ease-out);
}
.js .flow.is-stepped .flow__step.is-in { opacity: 1; transform: none; }

.flow__step h2 { font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.25rem); }
.flow__step h2:focus { outline: none; }

.flow__dots { display: flex; gap: .4rem; justify-content: center; margin-bottom: var(--s7); }
.flow__dots span {
  width: 2rem; height: 3px; border-radius: 2px; background: var(--rule);
  transition: background var(--t) var(--ease);
}
.flow__dots span.is-done { background: var(--rule-2); }
.flow__dots span[aria-current="step"] { background: var(--ink); }

.flow__grid { display: grid; gap: var(--s3); grid-template-columns: repeat(3, 1fr); }
@media (max-width: 48rem) { .flow__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 30rem) { .flow__grid { grid-template-columns: 1fr; } }

.pick {
  text-align: start; cursor: pointer;
  padding: var(--s4) var(--s5);
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  background: var(--paper-2); color: var(--ink);
  font-size: .9375rem; line-height: 1.4;
  transition: border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.pick:hover { border-color: var(--rule-2); background: var(--paper-3); transform: translateY(-2px); }
.pick:active { transform: translateY(0); }
.pick[aria-pressed="true"] {
  border-color: var(--ink); background: var(--paper);
  box-shadow: inset 0 0 0 1px var(--ink);
}
.pick b { display: block; font-weight: 600; letter-spacing: -0.015em; }
.pick span { display: block; color: var(--muted); font-size: .875rem; margin-top: .15rem; }

.flow textarea {
  width: 100%; min-height: 7rem; resize: vertical;
  padding: var(--s4); border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--paper-2); color: var(--ink); font-family: inherit; font-size: 1rem;
  transition: border-color var(--t-fast) var(--ease);
}
.flow textarea:focus-visible { border-color: var(--ink); outline: none; box-shadow: 0 0 0 1px var(--ink); }

.flow__summary {
  display: grid; grid-template-columns: 8rem 1fr; gap: var(--s3) var(--s4);
  padding: var(--s5); margin-block: var(--s5);
  border: 1px solid var(--rule); border-radius: var(--r-lg); background: var(--paper-2);
}
.flow__summary dt { color: var(--muted); font-size: .9375rem; }
.flow__summary dd { margin: 0; font-weight: 500; }
.flow__summary:empty { display: none; }
@media (max-width: 34rem) {
  .flow__summary { grid-template-columns: 1fr; gap: 0; }
  .flow__summary dt { margin-top: var(--s3); }
}

/* The deposit offer, and the confirmation when they come back from Stripe.
   Deliberately quieter than the WhatsApp button above it: it is an option, not
   the thing we are pushing. */
.deposit {
  display: flex; align-items: center; gap: var(--s5);
  padding: var(--s5); margin-top: var(--s5);
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  background: var(--paper-2);
}
.deposit--offer { justify-content: space-between; flex-wrap: wrap; }
.deposit[hidden] { display: none; }
.deposit__head { font-weight: 600; letter-spacing: -0.015em; margin: 0 0 .2rem; }
.deposit .note { margin: 0; max-width: 30rem; }
.deposit .btn { flex: 0 0 auto; }
.deposit__tick {
  width: 1.6rem; height: 1.6rem; border-radius: 50%;
  background: var(--live); color: var(--paper);
  display: grid; place-items: center; flex: 0 0 auto;
}
.deposit__tick svg { width: 14px; height: 14px; }
.deposit p { margin: 0; }
#flow-pay[aria-busy="true"] { opacity: .6; pointer-events: none; }
@media (max-width: 40rem) {
  .deposit--offer { flex-direction: column; align-items: stretch; gap: var(--s4); }
  .deposit--offer .btn { justify-content: center; }
}

.flow__back {
  background: none; border: 0; cursor: pointer; padding: 0;
  color: var(--muted); font-size: .875rem; margin-top: var(--s5);
  display: inline-flex; align-items: center; gap: .35rem;
  transition: color var(--t-fast) var(--ease);
}
.flow__back:hover { color: var(--ink); }

/* --------------------------------------------------------------------------
   15e. The "how many bookings pay for it" calculator
   -------------------------------------------------------------------------- */
.calc {
  padding: var(--s6);
  border: 1px solid var(--rule); border-radius: var(--r-xl);
  background: var(--paper-2);
}
.calc__row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s4); margin-bottom: var(--s2);
}
.calc__label { color: var(--muted); font-size: .9375rem; }
.calc__out {
  font-family: var(--display); font-weight: 600;
  font-size: 1.5rem; letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}

.calc__range {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 4px; margin: 0 0 var(--s6);
  border-radius: 2px; cursor: pointer;
  /* --fill is written by calc.js; the gradient is the only way to colour the
     track to the left of the thumb without a wrapper element. */
  background: linear-gradient(to right,
    var(--ink) 0 var(--fill, 33%), var(--rule) var(--fill, 33%) 100%);
}
.calc__range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--ink); border: 3px solid var(--paper-2);
  box-shadow: 0 1px 4px rgb(var(--shadow) / .3);
  cursor: grab;
}
.calc__range::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--ink); border: 3px solid var(--paper-2);
  cursor: grab;
}
.calc__range:focus-visible { outline: 2px solid var(--ink); outline-offset: 6px; }

.calc__select {
  width: 100%; margin-bottom: var(--s6);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--paper); color: var(--ink);
  font-family: inherit; font-size: 1rem; cursor: pointer;
}
.calc__select:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.calc__answer {
  margin: 0 0 var(--s3);
  font-size: clamp(1.25rem, 1.05rem + .8vw, 1.6rem);
  letter-spacing: -0.02em;
}
.calc__answer b {
  color: var(--accent);
  font-size: clamp(2.5rem, 1.9rem + 2.4vw, 3.5rem);
  font-weight: 600; letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  display: block; line-height: 1;
}

/* --------------------------------------------------------------------------
   16. Pricing
   -------------------------------------------------------------------------- */
.plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s4); align-items: start; }
@media (max-width: 62rem) { .plans { grid-template-columns: 1fr; max-width: 30rem; margin-inline: auto; } }

.plan {
  display: flex; flex-direction: column; gap: var(--s4);
  padding: var(--s6);
  border: 1px solid var(--rule); border-radius: var(--r-xl);
  background: var(--paper-2);
  transition: border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.plan:hover { border-color: var(--rule-2); box-shadow: 0 14px 36px rgb(var(--shadow) / .08); }
.plan--lead { background: var(--paper); border-color: var(--ink); }
.plan__top { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); }
.plan__name { font-size: 1.25rem; font-weight: 600; letter-spacing: -0.02em; margin: 0; }
.plan__flag {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--accent-ink); background: var(--accent);
  padding: .2rem .5rem; border-radius: 999px;
}
.plan__desc { color: var(--muted); font-size: .9375rem; margin: 0; }
.plan__price { display: flex; flex-direction: column; gap: .15rem; padding-block: var(--s2); }
.plan__build {
  font-size: clamp(2rem, 1.6rem + 1.4vw, 2.6rem); font-weight: 600;
  letter-spacing: -0.04em; line-height: 1; font-variant-numeric: tabular-nums;
}
.plan__unit { font-size: .875rem; color: var(--muted); }
.plan__then { font-size: 1rem; color: var(--ink); font-weight: 550; }
/* :not(.chips) matters. `.plan ul` is one class plus one type, which outranks
   the bare `.chips` rule above, so without this the row of card pills was
   being laid out as a full-width stack. */
.plan ul:not(.chips) { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); }
.plan ul:not(.chips) li {
  display: grid; grid-template-columns: 1.1rem 1fr; gap: .6rem;
  font-size: .9375rem; align-items: start; color: var(--ink-2);
}
.plan ul:not(.chips) li svg { width: 14px; height: 14px; margin-top: .34rem; color: var(--muted); }
.plan ul.chips { list-style: none; margin: 0; padding: 0; }
.plan .btn { margin-top: auto; justify-content: center; }

/* --------------------------------------------------------------------------
   17. FAQ
   -------------------------------------------------------------------------- */
.faq { border-top: 1px solid var(--rule); }
.faq details {
  border-bottom: 1px solid var(--rule);
}
.faq summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s5) 0;
  font-size: 1.0625rem; font-weight: 550; letter-spacing: -0.015em;
  transition: color var(--t-fast) var(--ease);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--muted); }
.faq summary::after {
  content: ""; flex: 0 0 auto; width: 11px; height: 11px;
  border-right: 1.5px solid var(--faint); border-bottom: 1.5px solid var(--faint);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--t) var(--ease);
}
.faq details[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.faq details > div { padding-bottom: var(--s5); max-width: var(--measure); color: var(--muted); }

/* --------------------------------------------------------------------------
   18. Legal pages
   -------------------------------------------------------------------------- */
.legal { padding-block: var(--s8) var(--s9); }
.legal h1 { margin-bottom: var(--s5); }
.legal h2 {
  font-size: 1.375rem; margin-top: var(--s7); margin-bottom: var(--s3);
  padding-top: var(--s5); border-top: 1px solid var(--rule);
}
.legal h3 { font-size: 1.0625rem; margin-top: var(--s5); margin-bottom: var(--s2); }
.legal p, .legal li { color: var(--ink-2); }
.legal ul, .legal ol { margin: 0 0 var(--s4); }
.legal li { margin-bottom: var(--s2); }

/* The browser's default disc was the only stock list marker left on the site —
   every other list is list-style:none with a marker drawn to match. These
   pages carry the longest prose, so an unstyled bullet stood out most exactly
   where it mattered. The dot is the one from the name card, at 5px in --faint.
   Logical properties throughout, so it flips with dir="rtl". */
.legal ul { list-style: none; padding-inline-start: 0; }
.legal ul > li { position: relative; padding-inline-start: 1.35rem; }
.legal ul > li::before {
  content: ""; position: absolute;
  inset-inline-start: .1rem; top: .62em;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--faint);
}
/* Numbered lists keep their numbers; only the colour and figure spacing
   change, so they line up with the dots above them. */
.legal ol { padding-inline-start: 1.6rem; }
.legal ol > li::marker { color: var(--faint); font-variant-numeric: tabular-nums; }
.legal dl { margin: 0 0 var(--s4); display: grid; grid-template-columns: 11rem 1fr; gap: var(--s2) var(--s4); }
.legal dt { color: var(--muted); font-size: .9375rem; }
.legal dd { margin: 0; }
@media (max-width: 40rem) {
  .legal dl { grid-template-columns: 1fr; gap: 0 0; }
  .legal dt { margin-top: var(--s3); }
}
.legal__meta { color: var(--muted); font-size: .875rem; margin-bottom: var(--s6); }

.back {
  display: inline-flex; align-items: center; gap: .45rem;
  font-size: .875rem; color: var(--muted); text-decoration: none;
  margin-bottom: var(--s5);
  transition: color var(--t-fast) var(--ease);
}
.back:hover { color: var(--ink); }
.back svg { width: 15px; height: 15px; }

/* --------------------------------------------------------------------------
   18b. Long-form guide pages
   The four SEO guides. Same reading measure as the legal pages, but headings
   sit closer to the text because these are read straight through rather than
   navigated by section.
   -------------------------------------------------------------------------- */
.longform { padding-block: var(--s8) var(--s9); }
.longform h1 { margin-bottom: var(--s5); }
.longform > .lede { margin-bottom: var(--s7); }
.longform h2 {
  font-size: 1.5rem; letter-spacing: -0.025em;
  margin-top: var(--s7); margin-bottom: var(--s3);
}
.longform h3 { font-size: 1.125rem; margin-top: var(--s5); margin-bottom: var(--s2); }
.longform p, .longform li { color: var(--ink-2); }
.longform ul, .longform ol { margin: 0 0 var(--s4); }
.longform li { margin-bottom: var(--s2); }

/* The browser's default disc was the only stock list marker left on the site —
   every other list is list-style:none with a marker drawn to match. These
   pages carry the longest prose, so an unstyled bullet stood out most exactly
   where it mattered. The dot is the one from the name card, at 5px in --faint.
   Logical properties throughout, so it flips with dir="rtl". */
.longform ul { list-style: none; padding-inline-start: 0; }
.longform ul > li { position: relative; padding-inline-start: 1.35rem; }
.longform ul > li::before {
  content: ""; position: absolute;
  inset-inline-start: .1rem; top: .62em;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--faint);
}
/* Numbered lists keep their numbers; only the colour and figure spacing
   change, so they line up with the dots above them. */
.longform ol { padding-inline-start: 1.6rem; }
.longform ol > li::marker { color: var(--faint); font-variant-numeric: tabular-nums; }
.longform strong { font-weight: 600; color: var(--ink); }

/* The guides' end-of-article box. Named .callout, not .note: od.css already
   uses .note for small muted text, and the guides were using the same class
   for a bordered panel. Two meanings, one name, so one of them had to move. */
.callout {
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  background: var(--paper-2); padding: var(--s5);
  margin-top: var(--s7); font-size: .9375rem;
}
.callout p { margin: 0; }

/* --------------------------------------------------------------------------
   19. Page navigation footer (prev / next between sub-pages)
   -------------------------------------------------------------------------- */
.pagenav {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s4);
  padding-block: var(--s7);
  border-top: 1px solid var(--rule);
}
@media (max-width: 40rem) { .pagenav { grid-template-columns: 1fr; } }
.pagenav a {
  display: flex; flex-direction: column; gap: .2rem;
  padding: var(--s5); border: 1px solid var(--rule); border-radius: var(--r-lg);
  text-decoration: none; background: var(--paper-2);
  transition: border-color var(--t) var(--ease), background var(--t) var(--ease);
}
.pagenav a:hover { border-color: var(--rule-2); background: var(--paper-3); }
.pagenav a:last-child { text-align: end; }
.pagenav small {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted);
}
.pagenav b { font-weight: 600; letter-spacing: -0.02em; font-size: 1.0625rem; }

/* --------------------------------------------------------------------------
   20. Call to action band
   -------------------------------------------------------------------------- */
.cta {
  border-radius: var(--r-xl);
  background: var(--ink); color: var(--invert);
  /* Nothing on the site puts an eyebrow or a prose link on this band today,
     but the accent is a paper colour and would be poor against it, so the
     band keeps its own contrast if one ever lands here. */
  padding: clamp(2.5rem, 1.5rem + 4vw, 4.5rem);
  text-align: center;
}
.cta h2 { color: var(--invert); }
.cta p { color: color-mix(in srgb, var(--invert) 68%, transparent); max-width: 36rem; margin-inline: auto; }
.cta .btn--primary { background: var(--paper); color: var(--ink); }
.cta .btn--primary:hover { background: var(--paper-3); }
.cta .btn-row { justify-content: center; margin-top: var(--s5); }
.cta .note { color: color-mix(in srgb, var(--invert) 55%, transparent); margin-top: var(--s5); }
/* The accent is a paper colour: 1.7:1 against this band in light mode. Nothing
   puts an eyebrow or an inline link here today, but both would be close to
   unreadable if they ever did, so the band keeps its own contrast. */
.cta .eyebrow { color: var(--invert); opacity: .78; }
.cta p a:not([class]),
.cta li a:not([class]) { color: var(--invert); text-decoration-color: var(--invert); }

/* --------------------------------------------------------------------------
   21. Footer
   -------------------------------------------------------------------------- */
.foot { border-top: 1px solid var(--rule); padding-block: var(--s8) var(--s6); margin-top: var(--s9); }
.foot__grid {
  display: grid; grid-template-columns: 1.6fr repeat(3, 1fr); gap: var(--s6);
}
@media (max-width: 62rem) { .foot__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 40rem) { .foot__grid { grid-template-columns: 1fr; gap: var(--s5); } }
.foot h2 {
  font-family: var(--mono); font-size: .75rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted); font-weight: 550;
  margin-bottom: var(--s3);
}
.foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); }
.foot a { color: var(--muted); text-decoration: none; font-size: .9375rem;
          transition: color var(--t-fast) var(--ease); }
.foot a:hover { color: var(--ink); }
.foot__blurb { color: var(--muted); font-size: .9375rem; max-width: 22rem; margin-top: var(--s3); }
.foot__base {
  display: flex; flex-wrap: wrap; gap: var(--s4); justify-content: space-between;
  margin-top: var(--s7); padding-top: var(--s5); border-top: 1px solid var(--rule);
  color: var(--muted); font-size: .8125rem;
}

/* --------------------------------------------------------------------------
   22. Motion
   Every rule that sets opacity:0 is scoped to .js. Without the inline
   bootstrap in <head> the page is simply visible.
   -------------------------------------------------------------------------- */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--t-slow) var(--ease-out),
              transform var(--t-slow) var(--ease-out);
  will-change: opacity, transform;
}
.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Page entrance. A keyframe animation, not a .js-scoped class, so it runs
   with scripting off and can never strand the page at zero opacity. */
@keyframes od-enter {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
main { animation: od-enter 460ms var(--ease-out) both; }

/* The matching fade out, added by od.js just before it follows a link. The
   animation is cancelled first, otherwise it keeps ownership of opacity and
   this transition never takes effect. */
:root.is-leaving main {
  animation: none;
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 180ms var(--ease), transform 180ms var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
  .js [data-reveal] { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   23. Right-to-left
   Future RTL language packs can set dir="rtl" on <html>; these are the only
   rules that are not already logical properties.
   -------------------------------------------------------------------------- */
[dir="rtl"] .btn__arrow { transform: scaleX(-1); }
[dir="rtl"] .btn:hover .btn__arrow { transform: scaleX(-1) translateX(3px); }
[dir="rtl"] .back svg { transform: scaleX(-1); }
[dir="rtl"] .pagenav a:last-child { text-align: start; }
[dir="rtl"] .faq summary::after { transform: rotate(135deg) translate(-2px, 2px); }
[dir="rtl"] .faq details[open] summary::after { transform: rotate(-45deg) translate(2px, -2px); }

/* --------------------------------------------------------------------------
   24. Mobile menu CTA and the sticky action bar
   -------------------------------------------------------------------------- */
.mmenu__cta { width: 100%; justify-content: center; margin-bottom: var(--s3); }
.mmenu__quiet {
  display: block; text-align: center; padding: var(--s2) 0;
  font-size: .875rem; color: var(--muted); text-decoration-color: var(--rule-2);
}

/* The homepage is thirteen screens on a phone. Someone convinced on screen
   nine had to scroll to fourteen, or back to one, to act on it. This appears
   once the hero's own buttons have left the viewport and not before, so it
   never competes with them. */
.sticky-cta {
  position: fixed; inset-inline: 0; z-index: 60;
  display: none;
  padding: .6rem .9rem calc(.6rem + env(safe-area-inset-bottom, 0px));
  background: color-mix(in srgb, var(--paper) 86%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-top: 1px solid var(--rule);
  /* Offset rather than transform. The transform version would not come up: the
     rule matched, the class was on the element, and even an inline !important
     translateY(0) still computed as translateY(110%). Animating `bottom` on a
     fixed bar this small costs nothing measurable and is unambiguous. */
  bottom: -7rem;
  transition: bottom var(--t) var(--ease);
}
.sticky-cta.is-up { bottom: 0; }
.sticky-cta .btn { width: 100%; justify-content: center; }
@media (max-width: 48rem) {
  .js .sticky-cta { display: block; }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .sticky-cta { background: var(--paper); }
}
@media (prefers-reduced-motion: reduce) {
  .sticky-cta { transition: none; }
}

/* --------------------------------------------------------------------------
   25. Scroll-expand hero
   A port of the React Bits ScrollExpand. The frame starts as a centred inset
   and opens to full bleed as the page scrolls; scroll-expand.js drives
   clip-path and transform, everything here is the resting state.

   Without scripting the frame is already open and the copy is already
   visible, so the section degrades to a photograph with a caption on it.
   -------------------------------------------------------------------------- */
/* Height in vh so the section is correct before the script measures it, and
   still correct if the script never runs. Scroll distance 1.1 plus hold 0.3
   plus the stage itself is 2.4 screens; the no-JS case needs only one. */
.se__track { position: relative; width: 100%; height: 100vh; }
.js .se__track { height: 185vh; }
.se__stage {
  position: sticky; top: 0;
  width: 100%; height: 100vh;
  overflow: hidden;
  --se-title-size: 4rem;
}
.se__frame { position: absolute; inset: 0; }
.js .se__frame {
  clip-path: inset(21% 29% 21% 29% round 24px);
  will-change: clip-path;
}

/* A div rather than an <img>: the two gradings are one theme token apart, and
   a background only fetches the file the theme actually asks for. */
.se__media {
  position: absolute; inset: 0;
  background: var(--se-img) center / cover no-repeat;
  transform-origin: center;
}
.js .se__media { will-change: transform; transform: scale(1.35); }

/* The component fades this in from nothing. At rest that left the title
   sitting on bare photograph, which the day plate cannot carry, so it starts
   part-way up and deepens from there. */
.se__scrim {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top,
    rgb(var(--se-scrim) / .75), rgb(var(--se-scrim) / .10) 45%, rgb(var(--se-scrim) / .35));
  opacity: .34;
}
.se__title {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  margin: 0; padding: 0 6%;
  text-align: center; text-wrap: balance;
  font-size: var(--se-title-size);
  font-weight: 600; letter-spacing: -0.035em; line-height: 1;
  color: var(--se-title);
  /* The scrim averages the plate down; this handles the outliers — the car's
     dark glass under the headline, the bright roof under the body copy. */
  text-shadow: 0 1px 2px rgb(var(--se-scrim) / .55), 0 0 18px rgb(var(--se-scrim) / .45);
  pointer-events: none;
}
.js .se__title { will-change: opacity, transform; }
.se__hint {
  position: absolute; inset-inline: 0; bottom: 1.5rem;
  text-align: center;
  font-family: var(--mono); font-size: .6875rem;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--se-title); opacity: .62;
  pointer-events: none;
}
.se__overlay {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: var(--s3); text-align: center; padding: 8%;
  color: var(--se-title);
  text-shadow: 0 1px 2px rgb(var(--se-scrim) / .55), 0 0 18px rgb(var(--se-scrim) / .45);
}
.js .se__overlay { opacity: 0; will-change: opacity, transform; }
.se__overlay h2 {
  margin: 0; max-width: 18ch; text-wrap: balance;
  font-size: clamp(1.5rem, 1.1rem + 2vw, 2.75rem);
  letter-spacing: -0.03em; line-height: 1.05;
  color: var(--se-title);
}
.se__overlay p {
  margin: 0; max-width: 44ch;
  font-size: clamp(.9375rem, .88rem + .3vw, 1.125rem);
  color: var(--se-title); opacity: .82;
}

/* The whole thing is a scroll effect. With motion reduced it is simply a
   photograph at full bleed, and the tall track that drives it is pointless. */
@media (prefers-reduced-motion: reduce) {
  .js .se__frame  { clip-path: inset(0 0 0 0 round 0); }
  .js .se__media  { transform: none; }
  .js .se__title  { opacity: 0; }
  .js .se__overlay { opacity: 1; }
  .se__track { height: 100vh !important; }
  .se__hint { display: none; }
}

/* Gone on a phone. Neither effect runs there, and what was left was a wide
   landscape plate forced into a tall box — the car small in the middle with
   the parking bays doing most of the work — carrying a line that restates
   what the hero already said two screens above. */
@media (max-width: 48rem) {
  .section--flush[data-scroll-expand] { display: none; }
}

/* --------------------------------------------------------------------------
   26. Edge page jumps
   Previous and next pinned to the left and right of the viewport, so moving
   on does not require reaching the bottom of the page. The bottom .pagenav
   block stays and carries the page names; this is the shortcut, not the
   replacement, and it is the copy that disappears first when space is short.

   Below 48rem the same two links survive, but not on the side edges: a 44px
   target on each edge of a 360px screen eats a quarter of the width, overlaps
   the text column and lands in the thumb path. They cluster in the bottom-left
   corner instead, and lift when the sticky action bar comes up.
   -------------------------------------------------------------------------- */
/* On a wide screen the wrapper does nothing: the children go back to being
   direct children of the body flow and fix themselves to opposite edges. It
   only becomes a box on a phone, where the two are a cluster in one corner. */
.pagejumps { display: contents; }
.pagejump { display: none; }

@media (min-width: 48rem) {
  .pagejump {
    position: fixed; top: 50%; transform: translateY(-50%);
    z-index: 40;
    display: inline-flex; align-items: center; gap: var(--s2);
    height: 2.75rem; padding-inline: .75rem;
    border: 1px solid var(--rule); border-radius: 999px;
    background: color-mix(in srgb, var(--paper) 84%, transparent);
    backdrop-filter: saturate(140%) blur(10px);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    color: var(--muted); text-decoration: none;
    box-shadow: 0 6px 20px rgb(var(--shadow) / .10);
    transition: color var(--t-fast) var(--ease),
                border-color var(--t-fast) var(--ease),
                background var(--t-fast) var(--ease);
  }
  .pagejump--prev { inset-inline-start: var(--s4); }
  .pagejump--next { inset-inline-end: var(--s4); flex-direction: row-reverse; }
  .pagejump svg { width: 1.25rem; height: 1.25rem; flex: none; }

  /* The destination name is held at zero width and opens on hover or focus.
     Collapsing the width rather than hiding the element keeps the name in
     the accessibility tree and lets the pill grow from the arrow. */
  .pagejump__name {
    /* Collapsed by width alone, not opacity. The reveal is a CSS hover, so
       it needs no script — and an opacity:0 rule without a .js guard is the
       exact pattern that hides content permanently when scripting fails. */
    max-width: 0; overflow: hidden; white-space: nowrap;
    font-size: .875rem; font-weight: 500;
    transition: max-width var(--t) var(--ease);
  }
  .pagejump:hover, .pagejump:focus-visible {
    color: var(--ink); border-color: var(--rule-2);
    background: color-mix(in srgb, var(--paper) 96%, transparent);
  }
  .pagejump:hover .pagejump__name,
  .pagejump:focus-visible .pagejump__name { max-width: 12rem; }
  .pagejump:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

  /* Below this the pills would sit on the text rather than beside it. */
  @media (max-width: 68rem) {
    .pagejump__name { display: none; }
    .pagejump { padding-inline: .55rem; }
  }
}

/* The phone arrangement. The side edges are not available here: a 44px target
   on each edge of a 360px screen overlaps a 320px text column, and the
   vertical middle is where the thumb scrolls. So the two become icon-only
   circles clustered in the bottom-left — the chat launcher owns bottom-right —
   and they ride up with the sticky bar the same way the launcher does. */
@media (max-width: 47.9375rem) {
  .pagejumps {
    display: flex; gap: .5rem;
    position: fixed; z-index: 40;
    inset-inline-start: var(--s4);
    inset-block-end: calc(var(--s5) + env(safe-area-inset-bottom, 0px));
    transition: inset-block-end var(--t) var(--ease);
  }
  #sticky-cta.is-up ~ .pagejumps {
    inset-block-end: calc(var(--s5) + 4.5rem + env(safe-area-inset-bottom, 0px));
  }
  .pagejump {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.75rem; height: 2.75rem; padding: 0;
    border: 1px solid var(--rule); border-radius: 999px;
    background: color-mix(in srgb, var(--paper) 84%, transparent);
    backdrop-filter: saturate(140%) blur(10px);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    color: var(--muted); text-decoration: none;
    box-shadow: 0 6px 20px rgb(var(--shadow) / .10);
  }
  .pagejump svg { width: 1.25rem; height: 1.25rem; flex: none; }
  /* The name is the accessible label's job here; aria-label already carries
     the destination, so the span would only duplicate it inside a circle. */
  .pagejump__name { display: none; }
  .pagejump:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .pagejump { background: var(--paper); }
}
@media (prefers-reduced-motion: reduce) {
  .pagejump, .pagejump__name, .pagejumps { transition: none; }
}

/* The chat launcher sits 1.5rem off the bottom and the sticky bar is about
   71px tall, so on a phone the two occupied the same corner. They are
   siblings under <body> — the bar is in the page, the widget is appended
   after it — so the launcher can lift only while the bar is actually up,
   and sit back down when it retreats. Scoped to the width where the bar
   exists at all: above it the bar is display:none but can still carry
   .is-up, which would otherwise lift the launcher over nothing. */
@media (max-width: 48rem) {
  #sticky-cta.is-up ~ .odc {
    inset-block-end: calc(var(--s5) + 4.5rem + env(safe-area-inset-bottom, 0px));
  }
  .odc { transition: inset-block-end var(--t) var(--ease); }
}
@media (max-width: 48rem) and (prefers-reduced-motion: reduce) {
  .odc { transition: none; }
}
