/* NoBrainer pre-launch marketing site.
 *
 * Tokens are lifted verbatim from the design canvas (board 2a) — see
 * design-reference in the handoff. Day values on :root, dark values under
 * [data-theme="dark"] on <html>, because the site chooses the theme by LOCAL
 * TIME rather than by the OS setting (19:00–07:00 is dark), with a user
 * override. prefers-color-scheme is therefore not the switch; it is only the
 * first guess before the clock is read.
 */
:root {
  --bg: #FAF7F2;
  --card: #fff;
  --line: #EAE4DA;
  --txt: #1C1B26;
  --txt2: #5B5766;
  --cta-bg: #1C1B26;
  --cta-txt: #FAF7F2;
  --price: #FFC529;
  --badge-bg: #1C1B26;
  --badge-txt: #FAF7F2;
  --tick-bg: #1C1B26;
  --tint-l: #EAF6FB;
  --tint-c: #F2EFFE;
  --tint-p: #FDF1E5;
  --tint-b: #FBEDF0;
  /* Day accents are the shade that holds 4.5:1 as TEXT on its own tint (the
     teaser titles): #7A5AF8, #E8842C and #C94B62 measured 3.99, 2.43 and
     3.96. Dark keeps the lighter set, which already passes. */
  --acc-c: #6A4CF0;
  --acc-p: #A3540F;
  --acc-b: #B23A52;
  /* The active service's accent as TEXT on its tint: #2E9BC4 itself is 2.89:1
     on --tint-l by day. */
  --svc-accent-txt: #1F6F8F;
  --pillbg: #F3EFE8;
  /* Drawer row numbers (board 5a): zest-deep on cream, zest on ink. Zest
     itself fails contrast on the light background, hence the deeper tone. */
  --num: #8A6400;
  --cursor: rgba(28, 27, 38, .85);
  --foot: #1C1B26;
  --foot-line: #34323F;
  --hero-glow: transparent;
  --shadow: rgba(28, 27, 38, .16);

  /* Constant across both themes. */
  --zest: #FFC529;
  --zest-deep: #8A6400;
  --ok: #2E9E63;
  --danger: #D6455D;
  /* MUST equal the active service's `accent` in content/site/services.json.
     It is a literal here because the stylesheet is not templated — lint rule
     9 fails the build if the two drift, so the comment is enforced rather
     than merely asserted. */
  --svc-accent: #2E9BC4;

  --font-display: "Bricolage Grotesque", "Segoe UI", system-ui, sans-serif;
  --font-ui: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  /* Icon slots draw colour emoji. Inter has no emoji, so a codepoint without
     U+FE0F fell to whatever font had it: the stopwatch came from a maths font. */
  --font-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
}

html[data-theme="dark"] {
  --bg: #17161F;
  --card: #201F2B;
  --line: #2B2A38;
  --txt: #FAF7F2;
  --txt2: #A9A5B4;
  --cta-bg: #FFC529;
  --cta-txt: #1C1B26;
  --price: #1C1B26;
  --badge-bg: #FAF7F2;
  --badge-txt: #1C1B26;
  --tick-bg: #121118;
  --tint-l: #1D2A33;
  --tint-c: #241F3A;
  --tint-p: #2E2117;
  --tint-b: #2C181D;
  --acc-c: #B9A8FF;
  --acc-p: #F4B183;
  --acc-b: #F093A6;
  --svc-accent-txt: #5FB7DA;
  --pillbg: #26252F;
  --num: #FFC529;
  --cursor: rgba(250, 247, 242, .9);
  --foot: #121118;
  --foot-line: #24232E;
  --hero-glow: radial-gradient(closest-side, rgba(255, 197, 41, .13), transparent);
  --shadow: rgba(0, 0, 0, .45);
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--txt);
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: 1.5;
}

/* The design's 0.4s theme cross-fade, scoped to the properties that change.
   Transitioning `all` would animate layout on every hover. */
body, header, section, footer, div, a, span, h1, h2, h3, p, input, button {
  transition: background-color .4s ease, color .4s ease, border-color .4s ease;
}

a { color: var(--txt); text-decoration: none; }
a:hover { color: var(--zest-deep); }
html[data-theme="dark"] a:hover { color: var(--zest); }

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

h1, h2, h3 { font-family: var(--font-display); margin: 0; text-wrap: balance; }
/* Display headings set on body leading (1.5) stood a 44px title on a 66px
   line. Rules that want tighter still set their own. */
h1, h2 { line-height: 1.1; }
p { margin: 0; }
/* No one-word last line under a paragraph or a pill. */
p, .eyebrow { text-wrap: pretty; }
img, svg { display: block; max-width: 100%; }

/* ONE container: the side gutter lives HERE, 48px (18px on phones), and bands
   set only their block padding. When each band brought its own gutter, the
   ones that forgot (the page hero, the legal pages) sat flush against the
   screen edge, and the ones that padded outside an inner .shell (footer,
   waitlist) drew a second left edge 48px off the first above 1440px. */
.shell { max-width: 1440px; margin-inline: auto; padding-inline: 48px; }

/* Screen-reader-only, for the skip link and the labels the design shows as
   placeholder text only. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip:focus {
  position: fixed; inset-inline-start: 16px; inset-block-start: 16px;
  width: auto; height: auto; clip: auto; margin: 0; padding: 12px 18px;
  background: var(--cta-bg); color: var(--cta-txt); border-radius: 14px;
  z-index: 100; font-weight: 700;
}

@keyframes nb-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes nb-bob { 0%, 100% { transform: rotate(-6deg) translateY(0); } 50% { transform: rotate(-6deg) translateY(-14px); } }
/* The mobile phone bobs on the vertical only — board 3a stands it upright. */
@keyframes nb-bob2 { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }
@keyframes nb-glow { 0%, 100% { box-shadow: 0 0 90px rgba(255, 197, 41, .18); } 50% { box-shadow: 0 0 150px rgba(255, 197, 41, .38); } }

/* The handoff is explicit: reduced motion disables the marquee scroll, the bob
   and the glow, and shows them static rather than hiding them. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }

  /* THE TILT LIVES INSIDE THE KEYFRAMES. nb-bob is
     `rotate(-6deg) translateY(...)`, so killing the animation leaves the phone
     bolt upright — a different composition, not a stiller one. Re-declared
     here so the reduced-motion view is the design standing still. */
  .phone { transform: rotate(-6deg) !important; }
  /* ...but board 3a's phone is upright, so the mobile one stands still
     straight rather than acquiring a tilt it never had. */
  @media (max-width: 860px) { .phone { transform: none !important; } }

  /* The marquee is the other one: frozen mid-scroll it shows a half-word at
     the seam, so it is reset to the start of the loop. */
  .ticker-track { animation: none !important; transform: none !important; }
}

/* ── Topbar ─────────────────────────────────────────────────────────────── */
/* --tick-bg, not a literal. The desktop board hard-codes #1C1B26 in both
   themes while BOTH mobile boards darken it to #121118 — the boards
   contradict each other on the identical element, so "recreate the board"
   does not decide it. Tokenised to match the mobile boards and the ticker
   strip directly below it, which uses the same token. Flagged for sign-off. */
.topbar {
  background: var(--tick-bg);
  color: #FAF7F2;
  text-align: center;
  font-size: 12px;
  font-weight: 600;
  padding: 9px 20px;
  letter-spacing: .03em;
  /* Two even lines, not "Limassol" alone on the second, below 340px. */
  text-wrap: balance;
}

/* ── Nav ────────────────────────────────────────────────────────────────── */
.nav { display: flex; align-items: center; justify-content: space-between; padding: 20px 48px; gap: 20px; }
.brand { display: flex; align-items: center; gap: 10px; }
.brand svg { width: 34px; height: 34px; }
.wordmark {
  font-family: var(--font-display);
  font-weight: 800; font-size: 22px; letter-spacing: -.02em; color: var(--txt);
}
.wordmark i { color: var(--zest); font-style: normal; }
.nav-links { display: flex; gap: 28px; font-size: 13.5px; font-weight: 600; }
/* The desktop nav does not fit between 861 and 940px — it wrapped to two lines
   in the first 80px above the breakpoint, which is where a small laptop and
   most tablets in landscape sit. Tighten rather than move the breakpoint, so
   the mobile block below stays authoritative under 861. */
@media (min-width: 861px) and (max-width: 940px) {
  .nav { padding: 20px 24px; gap: 14px; }
  .nav-links { gap: 16px; }
}
/* SIX LINKS since "For partners" (29 Sep). A link never breaks inside itself
   ("How it / works" read as two links), and below 1100px the row has no room
   for six links AND both actions, so the WhatsApp pill steps aside there: the
   floating WhatsApp bubble (.wa-bubble, every page) is the same control. */
.nav-links a { white-space: nowrap; }
@media (min-width: 861px) and (max-width: 1100px) {
  .nav-actions .pill-ghost { display: none; }
}
.nav-actions { display: flex; gap: 10px; align-items: center; }

.pill-ghost {
  display: inline-flex; align-items: center; gap: 7px;
  border: 1.5px solid var(--line); background: var(--card);
  border-radius: 999px; padding: 9px 16px; font-size: 12.5px; font-weight: 700;
  color: var(--txt);
}
.pill-ghost:hover { color: var(--txt); border-color: var(--txt2); }
.btn-primary {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--cta-bg); color: var(--cta-txt);
  border-radius: 14px; padding: 11px 18px;
  font-size: 13.5px; font-weight: 700; border: 0; cursor: pointer;
  font-family: var(--font-ui);
}
.btn-primary:hover { color: var(--cta-txt); filter: brightness(.94); }
.nav .btn-primary { font-size: 13px; padding: 11px 20px; box-shadow: 0 8px 20px var(--shadow); }
.nav-toggle { display: none; }

/* ── Hero ───────────────────────────────────────────────────────────────── */
/* overflow: clip keeps the 1000px glow box from adding horizontal scroll on
   viewports narrower than it. */
.hero { position: relative; overflow: clip; display: grid; grid-template-columns: 1.05fr .95fr; gap: 24px; padding-block: 48px 64px; align-items: center; }
.hero::before {
  content: ""; position: absolute; top: -140px; left: 50%;
  transform: translateX(-50%); width: 1000px; height: 640px;
  background: var(--hero-glow); pointer-events: none; z-index: 0;
}
.hero > * { position: relative; z-index: 1; }

.eyebrow {
  display: inline-block; background: var(--zest); color: #1C1B26;
  font-size: 10.5px; font-weight: 800; text-transform: uppercase;
  letter-spacing: .1em; padding: 6px 14px; border-radius: 999px;
}
.hero h1 {
  /* 104px wrapped to 3 or 4 lines in the 861-1110 column; 9vw keeps 2. */
  font-size: clamp(72px, 9vw, 104px); font-weight: 800; line-height: .92; letter-spacing: -.03em;
  margin: 22px 0 0;
}
.hero h1 .dot { color: var(--zest); }
.hero-sub { margin-top: 26px; font-size: 18px; line-height: 1.65; color: var(--txt2); max-width: 44ch; }

.badges { display: flex; gap: 12px; align-items: center; margin-top: 32px; flex-wrap: wrap; }
/* Pre-launch: these are NOT links. 60% opacity and no href, per the handoff —
   faking a store link before the app exists is the one thing it forbids. */
.badge {
  display: inline-flex; align-items: center; gap: 9px;
  background: var(--badge-bg); color: var(--badge-txt);
  border-radius: 14px; padding: 10px 16px; opacity: .6; cursor: default;
}
.badge .glyph { display: flex; align-items: center; line-height: 1; }
.badge .glyph svg { width: 19px; height: 22px; fill: currentColor; }
.badge small { display: block; font-size: 9px; font-weight: 600; opacity: .85; }
.badge strong { display: block; font-size: 16px; font-weight: 700; letter-spacing: -.01em; }
.sticker {
  /* Inter, not the display face: the board inherits the body font here, and
     the tracking is what makes it read as a stamped sticker. */
  font-family: var(--font-ui); font-weight: 800; font-size: 11px; letter-spacing: .08em;
  background: var(--zest); color: #1C1B26; padding: 8px 14px; border-radius: 999px;
  transform: rotate(-3deg); white-space: nowrap;
  box-shadow: 0 8px 20px rgba(138, 100, 0, .2);
}
.hero-caption { margin-top: 16px; font-size: 12px; color: var(--txt2); max-width: 46ch; }
/* Ink text on a 2px zest bar, not a browser underline — a brand detail the
   board is specific about. */
.hero-caption a {
  color: var(--txt); font-weight: 700; text-decoration: none;
  box-shadow: inset 0 -2px 0 var(--zest);
}
html[data-theme="dark"] .hero-caption a { color: var(--txt); }

/* ── Phone mockup ───────────────────────────────────────────────────────── */
.phone-col { display: flex; justify-content: center; position: relative; }
.phone {
  width: 300px; background: #1C1B26; border-radius: 44px; padding: 10px;
  box-shadow: 0 50px 90px var(--shadow);
  /* board 3a's phone sits lower — see the mobile override below */
  transform: rotate(-6deg);
  animation: nb-bob 7s ease-in-out infinite;
}
/* Board 2a bobs in BOTH themes and uses nb-glow nowhere; the pulsing glow is a
   MOBILE-dark treatment (3a-mobile-dark), applied in the media query below. */
/* overflow: hidden because the demo's tab bar is full-bleed (margin: 0 -14px
   -14px) and square-cornered, so without a clip it paints straight over the
   screen's rounded bottom corners. Every board wrapper carries this. */
.phone-screen { background: #FAF7F2; border-radius: 36px; padding: 0 14px 14px; color: #1C1B26; overflow: hidden; }
/* The desktop screen stays light in both themes (board 2a pins it), so its
   tint chips must too — they were following the dark theme inside a light
   phone, which put dark-mode tints behind light-mode content. */
.stub-title {
  margin-top: 18px; font-family: var(--font-display); font-weight: 800;
  font-size: 44px; line-height: 1.05; letter-spacing: -.02em;
}
@media (max-width: 860px) { .stub-title { font-size: 34px; } }
.phone-status {
  display: flex; justify-content: space-between;
  padding: 14px 6px 4px; font-size: 11.5px; font-weight: 700;
}
.phone-status span + span { letter-spacing: 2px; font-size: 9px; }
/* Signal bars, drawn: the block glyphs they replace came from whichever system
   font had them (Helvetica and Hiragino here), so their weight changed by device. */
.phone-bars { display: flex; align-items: center; }
.phone-bars svg { width: 17px; height: 10px; fill: currentColor; }
.phone-sticker {
  position: absolute; top: -6px; right: 28px; transform: rotate(7deg);
  font-family: var(--font-display); font-weight: 800; font-size: 16px;
  background: var(--zest); color: #1C1B26; padding: 12px 18px; border-radius: 14px;
  box-shadow: 0 12px 30px rgba(138, 100, 0, .25); z-index: 2;
}
.tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 14px; }
.tile { background: #fff; border: 1px solid #EAE4DA; border-radius: 16px; padding: 12px; position: relative; }
.tile .icon {
  width: 32px; height: 32px; border-radius: 11px;
  background: var(--tile-tint, var(--tint-l));
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; margin-bottom: 7px;
}
.tile .name { font-size: 12px; font-weight: 700; margin-top: 6px; }
.tile .meta { font-size: 10px; color: #5B5766; }
/* The services that are coming but not bookable (car wash, blood tests):
   locked and greyed, with the SOON pill. Named since CLIENT allowed it
   (6 Oct 2026), so their icons are no longer blurred. */
.tile.locked { opacity: .55; filter: grayscale(.35); }
.tile .soon {
  position: absolute; top: 8px; right: 8px;
  font-size: 7.5px; font-weight: 800; letter-spacing: .08em;
  background: #F3EFE8; border: 1px solid #EAE4DA; color: #5B5766;
  padding: 2px 7px; border-radius: 999px;
}
.tabbar { display: flex; justify-content: space-around; margin-top: 0; padding: 10px 0 14px; border-top: 1px solid #EAE4DA; font-size: 8px; color: #5B5766; text-align: center; }
.tabbar span { flex: 1; }
.tabbar span.active { color: #1C1B26; font-weight: 700; }
.tabbar span i { display: block; font-style: normal; font-size: 15px; margin-bottom: 1px; }

/* ── Ticker ─────────────────────────────────────────────────────────────── */
.ticker { background: var(--tick-bg); overflow: hidden; padding: 13px 0; }
.ticker-track { display: flex; width: max-content; animation: nb-marquee 22s linear infinite; }
.ticker-track span {
  font-family: var(--font-display); font-weight: 800; font-size: 15px;
  color: var(--zest); letter-spacing: .14em; white-space: nowrap; padding-right: 0;
}

/* ── Steps ──────────────────────────────────────────────────────────────── */
.section { padding-block: 64px; }
.section h2 { font-size: 44px; font-weight: 800; letter-spacing: -.02em; }
.section .lede { color: var(--txt2); font-size: 16px; margin-top: 12px; max-width: 60ch; }
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 34px; }
.step {
  background: var(--card); border: 1px solid var(--line); border-radius: 20px;
  padding: 28px; transition: transform .25s ease, box-shadow .25s ease, background-color .4s ease, border-color .4s ease;
}
.step:nth-child(1) { transform: rotate(-1.2deg); }
.step:nth-child(2) { transform: rotate(.9deg); }
.step:nth-child(3) { transform: rotate(-.6deg); }
.step:hover { transform: rotate(0); box-shadow: 0 10px 26px var(--shadow); }
.step .num {
  width: 44px; height: 44px; border-radius: 999px; background: var(--zest); color: #1C1B26;
  font-family: var(--font-display); font-weight: 800; font-size: 18px;
  display: grid; place-items: center;
}
.step h3 { font-size: 22px; font-weight: 800; margin-top: 16px; }
.step p { font-size: 14px; color: var(--txt2); margin-top: 8px; }

/* ── Active-service panel ──────────────────────────────────────────────────────── */
.svc { display: grid; grid-template-columns: 1.15fr .85fr; gap: 20px; }
.svc-left { background: var(--tint-l); border-radius: 24px; padding: 44px; }
.pill-launch {
  /* Ink, not white: white on the accent is 3.18:1, ink 5.35:1. */
  display: inline-block; background: var(--svc-accent); color: #1C1B26;
  font-size: 10.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  padding: 7px 14px; border-radius: 999px;
}
.svc-left h2 { font-size: 38px; margin-top: 18px; }
.svc-left h2 .dot { color: var(--svc-accent); }
.svc-left p { color: var(--txt2); font-size: 15px; margin-top: 14px; max-width: 52ch; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; }
.chip {
  background: var(--card); border: 1px solid var(--line); border-radius: 999px;
  padding: 8px 14px; font-size: 12.5px; font-weight: 600; color: var(--txt);
}
.svc-cta { display: inline-block; margin-top: 24px; }
.timeline-card { background: var(--card); border: 1px solid var(--line); border-radius: 24px; padding: 32px; }
.timeline-card h3 { font-size: 18px; font-weight: 800; }
.timeline { list-style: none; margin: 20px 0 0; padding: 0; }
.timeline li { display: flex; gap: 14px; align-items: flex-start; padding-bottom: 22px; position: relative; }
.timeline li:last-child { padding-bottom: 0; }
.timeline li::after {
  content: ""; position: absolute; left: 5px; top: 16px; bottom: 0; width: 2px; background: var(--line);
}
.timeline li:last-child::after { display: none; }
.timeline .dot { width: 12px; height: 12px; border-radius: 999px; background: var(--line); flex: none; margin-top: 3px; position: relative; z-index: 1; }
.timeline .dot.done { background: var(--ok); }
.timeline .dot.now { background: var(--svc-accent); box-shadow: 0 0 0 5px rgba(46, 155, 196, .18); }
.timeline .label { font-size: 14px; font-weight: 700; }
.timeline .note { font-size: 12.5px; color: var(--txt2); }

/* ── Mystery teasers ────────────────────────────────────────────────────── */
.teasers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 34px; }
.teaser { border-radius: 24px; padding: 36px; text-align: center; position: relative; }
.teaser.c { background: var(--tint-c); }
.teaser.p { background: var(--tint-p); }
.teaser.b { background: var(--tint-b); }
/* Every card names its service now (CLIENT, 6 Oct 2026), so no icon is blurred. */
.teaser .emoji { font-size: 64px; line-height: 1; user-select: none; }
.teaser h3 { font-family: var(--font-display); font-weight: 800; font-size: 22px; margin-top: 18px; }
.teaser.c h3 { color: var(--acc-c); }
.teaser.p h3 { color: var(--acc-p); }
.teaser.b h3 { color: var(--acc-b); }
.teaser p { font-size: 13.5px; color: var(--txt2); margin-top: 8px; }
.teaser .soon {
  position: absolute; top: 16px; right: 16px;
  font-size: 9px; font-weight: 800; letter-spacing: .08em;
  /* Ink chip in BOTH themes. --cta-bg flips to zest in dark, which turned this
     quiet "soon" marker into a loud yellow badge — the boards draw it the same
     restrained way in both. */
  background: #1C1B26; color: #FAF7F2; padding: 4px 9px; border-radius: 999px;
}
/* An ANNOUNCED service in the row (pet grooming, first in Limassol; CLIENT
   29 Sep): open, so it carries the waitlist link; the coming ones have none. */
.teaser.open .emoji { filter: none; }
.teaser-cta { display: inline-block; margin-top: 14px; font-size: 13.5px; font-weight: 700; color: var(--txt); text-decoration: underline; text-underline-offset: 3px; }

/* ── Why grid ───────────────────────────────────────────────────────────── */
.why { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 34px; }
.why-card { background: var(--card); border: 1px solid var(--line); border-radius: 20px; padding: 24px; }
.why-card .icon { font-size: 22px; font-family: var(--font-emoji); }
.why-card h3 { font-size: 15.5px; font-weight: 800; margin-top: 12px; }
.why-card p { font-size: 13px; color: var(--txt2); margin-top: 6px; }

/* ── Waitlist band ──────────────────────────────────────────────────────── */
/* Zest in BOTH themes — the handoff calls this out explicitly. */
.waitlist { background: var(--zest); color: #1C1B26; padding-block: 64px; }
.waitlist h2 { font-size: 40px; font-weight: 800; color: #1C1B26; }
.waitlist h2 .dot { color: #FAF7F2; }
.waitlist p { margin-top: 12px; font-size: 16px; color: #1C1B26; max-width: 56ch; }
.waitlist-form { display: flex; gap: 10px; margin-top: 24px; flex-wrap: wrap; }
.waitlist input {
  width: 300px; max-width: 100%; background: #FAF7F2; border: 0; border-radius: 16px;
  padding: 15px 18px; font-size: 15px; font-family: var(--font-ui); color: #1C1B26;
}
.waitlist button { background: #1C1B26; color: #FAF7F2; border-radius: 16px; padding: 15px 24px; font-size: 15px; }
.waitlist button:hover { filter: brightness(1.15); color: #FAF7F2; }
/* The global focus ring is zest, and this band IS zest — the indicator was
   invisible exactly where the only form on the site lives. Ink is ~9:1 here. */
.waitlist :focus-visible { outline-color: #1C1B26; }
.waitlist-note { margin-top: 12px; font-size: 13px; min-height: 1.2em; }
.waitlist-note[data-state="error"] { font-weight: 700; }

/* ── Footer ─────────────────────────────────────────────────────────────── */
/* The bottom padding holds the WhatsApp bubble's corner (58px + 22px), so the
   footer's last line can be scrolled clear of it. */
.footer { background: var(--foot); color: #FAF7F2; padding-block: 56px calc(28px + 58px + 22px); }
.footer a { color: #FAF7F2; }
.footer a:hover { color: var(--zest); }
.footer-cols { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1.2fr; gap: 32px; }
/* display:contents so the two link columns become direct grid items of
   .footer-cols and the desktop row is four columns, not three.
   IN CSS, NOT INLINE: an inline display:contents cannot be overridden by the
   mobile media query below, which left the columns stacked full-width and made
   the footer 974px tall on a 375px screen — three times the design. */
.footer-links-grid { display: contents; }
.footer h4 { font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: #A9A5B4; margin: 0 0 14px; }
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; font-size: 13.5px; }
.footer-blurb { font-size: 13.5px; color: #A9A5B4; margin-top: 14px; max-width: 34ch; }
.pill-whatsapp {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 16px;
  background: var(--ok); color: #fff; border-radius: 999px; padding: 10px 16px;
  font-size: 13px; font-weight: 700;
}
.pill-whatsapp:hover { color: #fff; filter: brightness(1.08); }
.footer-badges { display: grid; gap: 8px; }
.footer-badge {
  display: inline-flex; align-items: center; gap: 8px; opacity: .55;
  border: 1px solid var(--foot-line); border-radius: 12px; padding: 8px 12px; font-size: 12px;
}
.footer-join { display: inline-block; margin-top: 10px; color: var(--zest); font-weight: 700; font-size: 13px; }
.footer-bottom {
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  border-top: 1px solid var(--foot-line); margin-top: 36px; padding-top: 20px;
  font-size: 12px; color: #A9A5B4;
}
.footer .footer-dev { display: inline-flex; align-items: center; gap: 8px; color: #A9A5B4; }
.footer .footer-dev:hover { color: #FAF7F2; }
.footer-dev-mark { display: block; height: 20px; width: auto; aspect-ratio: 172 / 44; }

/* ── Overlays ───────────────────────────────────────────────────────────── */
.wa-bubble {
  /* ── Overlay stacking order, in one place ────────────────────────────────
     40  WhatsApp bubble      page furniture
     45  drawer scrim         dims the page
     46  drawer               above everything it dims
     47  topbar               board 5a keeps the strip visible above the drawer
     48  cookie strip         below 415px only; it steps aside while the drawer
                              is open. From 415px the banner is in the flow.
     The cookie bar used to sit at 45 — above the drawer — so opening the menu
     with consent still pending painted the banner across the drawer's footer,
     hiding the teaser pills and half the legal links. */
  position: fixed; right: 22px; bottom: 22px; z-index: 40;
  width: 58px; height: 58px; border-radius: 999px; background: var(--ok);
  display: grid; place-items: center; font-size: 26px;
  box-shadow: 0 10px 26px rgba(28, 27, 38, .22);
  transition: transform .2s ease;
}
.wa-bubble:hover { transform: scale(1.08); }
/* Until a number is configured, app.js marks every WhatsApp control
   aria-disabled and swallows the click. Nothing showed that, so all four read
   as live buttons that silently do nothing. Same dimmed-until-live convention
   the pre-launch store badges already use. */
[data-wa][aria-disabled="true"] { opacity: .55; cursor: default; }
[data-wa][aria-disabled="true"]:hover { transform: none; filter: none; }
/* The cookie banner. From 415px it is a band at the top of the page, in the
   flow, above the topbar: it pushes the page down rather than lying over it,
   so it covers no heading or button, at first paint or anywhere in the scroll.
   At the foot of the window, where it was, it covered section headings and
   buttons at 415-1920px. Its edges line up with .shell's. Below 415px it is
   the strip over the header (further down). */
.cookie {
  background: #1C1B26; color: #FAF7F2; border-bottom: 1px solid var(--foot-line);
  padding: 10px max(48px, calc((100% - 1440px) / 2 + 48px));
  display: flex; gap: 14px; align-items: center; flex-wrap: nowrap;
}
.cookie p { font-size: 13px; flex: 1 1 240px; }
/* The link to the privacy page's Cookies section: underlined, not bold, so
   the text keeps its width and the strip its height. */
.cookie a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.cookie a:hover { color: var(--zest); }
/* The buttons are ONE flex item, so they wrap together, never one per row. */
.cookie-actions { display: flex; gap: 10px; flex: none; margin-inline-start: auto; }
.cookie button { border: 0; cursor: pointer; font-family: var(--font-ui); font-size: 13px; font-weight: 700; border-radius: 12px; padding: 10px 16px; min-height: 44px; }
.cookie .ghost { background: transparent; color: #FAF7F2; border: 1px solid #34323F; }
.cookie .ok { background: var(--zest); color: #1C1B26; border: 1px solid var(--zest); }
[hidden] { display: none !important; }

/* ── Mobile (board 3a, design width 390) ────────────────────────────────── */
@media (max-width: 860px) {
  .topbar { font-size: 10.5px; }
  .nav { padding: 14px 18px; }
  .nav-links { display: none; }
  .nav-actions .pill-ghost { display: none; }
  /* Board 3a's nav CTA is COMPACT — 11.5px in an 8x14 box, not the desktop
     13px/11x20. At desktop size it wrapped to two lines at every mobile width
     including the 390px design width, swallowing the row and squeezing the
     burger. nowrap so it can never wrap again; flex: none on the brand mark so
     the fixed-size items stop absorbing the row's overflow. */
  .nav .btn-primary {
    font-size: 11.5px; padding: 8px 14px; border-radius: 12px;
    white-space: nowrap; flex: none; box-shadow: none;
  }
  .brand svg { flex: none; }
  .brand { flex: none; min-width: 0; }
  .nav-toggle {
    /* flex: none, or the two fixed-size items absorb the row's overflow and
       the 44px tap target shrinks to 31px below 398px — breaking the minimum
       this stylesheet declares for every other control. */
    flex: none;
    display: grid; place-items: center; width: 44px; height: 44px;
    background: var(--card); border: 1.5px solid var(--line); border-radius: 14px;
    font-size: 18px; cursor: pointer; color: var(--txt); padding: 0;
  }
  /* The button holds BOTH glyphs and shows one, so the swap costs no reflow —
     but only if something actually hides the other. Without these two rules
     the grid stacked them and the closed button rendered a bars-over-cross.
     Keyed on aria-expanded so the visual state cannot drift from the state
     assistive tech is told: there is one source of truth, not two. */
  .nav-toggle .ex { display: none; }
  .nav-toggle[aria-expanded="true"] .bars { display: none; }
  .nav-toggle[aria-expanded="true"] .ex { display: block; }
  header { position: relative; }

  /* The MOBILE phone follows the theme, the desktop one does not. That is not
     an inconsistency in this stylesheet, it is what the two boards say: the 3a
     dark phone screen carries color:#FAF7F2 and a dark ground, while 2a pins
     #FAF7F2/#1C1B26 as literals in both themes. The demo spec is explicit that
     "in dark mode the app itself renders dark", and the demo is mobile-only.
     Without this the demo painted var(--bg) #17161F under inherited #1C1B26
     text — near-black on near-black. */
  .phone-screen {
    /* The APP's ground, not the site's. The status strip lives here, outside
       .nbd, so painting it with the site's --bg (#17161F) left a hard seam
       above an app screen painted #121118 — the app appeared to start a third
       of the way down the device. Board 3a paints one ground for the whole
       screen, status row included. */
    background: var(--app-bg); color: var(--app-tx);
    /* The mobile hero centres its column, and that inherited into every demo
       screen — the boards keep the app's content left-aligned. .nbd-screen
       .centred re-declares center on screens 3 and 5, so those still centre. */
    text-align: start;
  }

  .shell { padding-inline: 18px; }
  .hero { grid-template-columns: 1fr; text-align: center; padding-block: 32px 44px; gap: 32px; }
  .hero::before { top: -90px; width: 420px; height: 380px; }
  /* 3a-mobile-dark: on a phone the glow replaces the bob. */
  /* Board 3a's phone sits STRAIGHT and bobs on the vertical only (nb-bob2);
     the -6deg tilt is the desktop board's treatment. Its frame is tighter too:
     40/9/33 against the desktop's 44/10/36. */
  .phone {
    transform: none; border-radius: 40px; padding: 9px;
    /* 0 40px 70px, not the desktop board's 0 50px 90px — a 270px phone under a
       300px phone's shadow reads as floating off the page. */
    box-shadow: 0 40px 70px var(--shadow);
    animation: nb-bob2 7s ease-in-out infinite;
  }
  /* The floating "Consider it done." sticker is a DESKTOP treatment — board 2a
     has it, both 3a boards have none. On a 270px phone it covered the app bar
     and the first line of the screen it was decorating. The phrase still
     appears in the demo's own confirm screen, which is where 3a puts it. */
  .phone-sticker { display: none; }
  .phone-screen { border-radius: 33px; position: relative; }
  /* Board 3a dark rings the screen with a 1px #2C2A38 hairline — the app's own
     midnight `line` token. Without it a #121118 screen inside a #000 bezel has
     no edge and the device reads as one soft mass. An overlay ring rather than
     an inset shadow, so the full-bleed tab bar cannot paint over it. */
  html[data-theme="dark"] .phone-screen::after {
    content: ""; position: absolute; inset: 0; border-radius: inherit;
    box-shadow: inset 0 0 0 1px var(--app-line); pointer-events: none; z-index: 1;
  }
  /* Black, not ink. Board 3a dark builds the device on #000; at #1C1B26 the
     bezel was LIGHTER than the midnight page around it, so the phone read as a
     grey slab rather than a device. (No hairline ring here — nb-glow writes
     box-shadow on every keyframe and would erase it.) */
  html[data-theme="dark"] .phone { background: #000; animation: nb-glow 5s ease-in-out infinite; }
  /* The homepage hero centres; the page heroes stay left-aligned. */
  .hero .hero-sub, .hero .hero-caption { margin-inline: auto; }
  .hero h1 { font-size: 56px; }
  .badges { flex-direction: column; align-items: center; }
  .badge { width: 200px; justify-content: center; }
  .phone { width: 270px; }

  .ticker { padding: 10px 0; }
  .ticker-track span { font-size: 12px; }

  .section { padding-block: 44px; }
  .section h2 { font-size: 30px; }
  .steps { grid-template-columns: 1fr; gap: 14px; }
  .step { transform: none !important; display: grid; grid-template-columns: 44px 1fr; gap: 4px 16px; align-content: start; align-items: start; padding: 20px; }
  .step h3 { margin-top: 0; }
  .step .num { grid-row: span 2; }

  .svc { grid-template-columns: 1fr; }
  .svc-left { padding: 26px; }
  .svc-left h2 { font-size: 28px; }
  .timeline-card { padding: 24px; }

  .teasers { grid-template-columns: 1fr; gap: 12px; }
  .teaser .emoji { grid-row: span 2; }
  .teaser { display: grid; grid-template-columns: 54px 1fr; gap: 16px; text-align: start; padding: 20px; align-items: center; }
  .teaser .emoji { font-size: 34px; }
  .teaser.open .emoji { filter: none; grid-row: span 3; }
  .teaser-cta { grid-column: 2; margin-top: 6px; }
  .teaser h3 { margin-top: 0; font-size: 18px; }

  .why { grid-template-columns: 1fr 1fr; gap: 12px; }
  .why-card { padding: 18px; }

  .waitlist { padding-block: 44px; }
  .waitlist h2 { font-size: 28px; }

  .footer { padding-block: 40px calc(24px + 48px + 14px); }
  .footer-cols { grid-template-columns: 1fr; gap: 28px; }
  /* Board 3a: "footer single column with 2-col link grid". The two link
     columns pair up instead of each taking a full-width row. */
  .footer-links-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
  /* Board 3a's mobile footer is FLATTER than the desktop one, and that is what
     keeps it short: no section headings, and no app column at all. The store
     badges are decorative pre-launch spans and the waitlist band sits directly
     above this footer on mobile, so neither is lost — but stacked, they were
     most of the footer's height. */
  .footer-links-grid h4 { display: none; }
  .footer-app { display: none; }

  /* Leaves room for the 48px bubble, per the handoff. */
  .wa-bubble { width: 48px; height: 48px; font-size: 22px; right: 14px; bottom: 14px; }
  .cookie { padding: 10px 18px; }
  .cookie p { font-size: 12px; }

  /* Tap targets >= 44px. */
  .nav-links a, .footer ul a { min-height: 44px; display: flex; align-items: center; }
  .brand { min-height: 44px; }
  .teaser-cta { display: inline-flex; align-items: center; min-height: 44px; }
  .topic-chip span, .legal-tab { min-height: 44px; display: inline-flex; align-items: center; }
  main .btn-primary { min-height: 44px; }
  /* The header CTA stays compact (board 3a); its hit area does not. */
  .nav .btn-primary { position: relative; }
  .nav .btn-primary::before { content: ""; position: absolute; inset: -6px -3px; }
}
/* F3 on a phone. At the foot of the screen the banner (138px at 375x667)
   hid the legal h1 and the service pages' hero button at first paint, and
   at 320x568 that button ends 28px above the bottom, so no height clears it
   there. Below 415px it is a compact strip across the TOP, over the header,
   the text beside the two buttons. It sits above the topbar (z 47), so it
   steps aside while the drawer is open. */
@media (max-width: 414px) {
  .cookie {
    position: fixed; top: 0; left: 0; right: 0; z-index: 48; flex-wrap: nowrap; gap: 10px; padding: 8px 12px;
    border-radius: 0 0 16px 16px; border: 1px solid var(--foot-line); border-top: 0; box-shadow: 0 30px 80px rgba(0, 0, 0, .45);
  }
  .cookie p { flex: 1 1 0; min-width: 0; line-height: 1.3; }
  .cookie-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } /* Decline as wide as Okay */
  .cookie button { padding-inline: 10px; }
  body.drawer-open .cookie { display: none; }
  /* While the strip shows, a link to an anchor (/privacy#cookies, from the
     banner and the footer) lands below it, not under it. The strip is at
     most 96px tall. */
  html:has(#cookie:not([hidden])) { scroll-padding-top: 104px; }
}
/* The waitlist form is a column on a phone only; from 600px it is a row. */
@media (max-width: 599px) {
  .waitlist-form { flex-direction: column; }
  .waitlist input, .waitlist button { width: 100%; }
}
/* H3: two "Why" cards side by side are 136px wide at 320, and their titles
   wrap to different heights, so the copy beside them starts out of line. */
@media (max-width: 374px) {
  .why { grid-template-columns: 1fr; }
}
/* Below 375px the logo, the waitlist button and the 44px menu button did not
   fit in one row: the page scrolled sideways by 36px at 320 and 16px at 340.
   Tighten the header row only (scoped to .nav, so the drawer and footer logos
   keep their size); the menu button stays 44px and the button one line. */
@media (max-width: 374px) {
  .nav { gap: 8px; }
  .nav .brand { gap: 6px; }
  .nav .brand svg { width: 28px; height: 28px; }
  .nav .wordmark { font-size: 17px; }
  .nav .btn-primary { padding: 8px 10px; }
  .nav-actions { gap: 6px; }
}

/* Per-breakpoint copy. Both strings ship in the document — they are short, and
   hiding one is cheaper and more honest than swapping text in JS after paint. */
.only-narrow { display: none; }
/* Flex variants: the ticker track must stay a flex row when shown, so it
   cannot use the `inline` value the text spans use. */
.only-narrow-flex { display: none; }
.only-wide-flex { display: flex; }
@media (max-width: 860px) {
  .only-wide { display: none; }
  .only-narrow { display: inline; }
  .only-wide-flex { display: none; }
  .only-narrow-flex { display: flex; }
}

/* ── Theme override ─────────────────────────────────────────────────────── */
/* The handoff makes the control optional and puts it in the footer; the drawer
   copy is there because the burger is where a phone reaches for settings.
   Both are the same component and both write the same localStorage key. */
.footer-theme { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 32px; }
.footer-theme-label { font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: #A9A5B4; }
.theme-switch { display: inline-flex; gap: 4px; background: var(--card); border: 1px solid var(--line); border-radius: 999px; padding: 4px; }
.footer .theme-switch { background: transparent; border-color: var(--foot-line); }
.theme-switch button {
  border: 0; cursor: pointer; font-family: var(--font-ui);
  font-size: 11.5px; font-weight: 700; border-radius: 999px; padding: 8px 14px;
  background: transparent; color: var(--txt2); min-height: 36px;
}
/* Each button is a drawn icon and its word. */
.theme-switch button { display: inline-flex; align-items: center; gap: 6px; }
.footer .theme-switch button { color: #A9A5B4; }
.theme-switch button[aria-pressed="true"] { background: var(--zest); color: #1C1B26; }
.footer .theme-switch button[aria-pressed="true"] { background: var(--zest); color: #1C1B26; }
.drawer-theme { display: none; }
@media (max-width: 860px) {
  /* Inside the drawer only — the desktop nav has no room and the footer
     control already covers it. */
  .drawer .drawer-theme { display: inline-flex; justify-content: center; }
  .theme-switch button { min-height: 44px; }
}


/* ── Mobile burger drawer (board 5a) ──────────────────────────────────────
   A full-screen drawer on --bg, NOT a partial sheet. It sits outside <header>
   so the topbar strip stays visible above it, which is what the board shows.

   [hidden] is the closed state and is authoritative: the element is out of the
   accessibility tree and untabbable when shut. .open is added a frame later so
   the transition has a from-state to animate out of — setting both in one tick
   makes the drawer appear instantly with no slide. */
.drawer,
.drawer-scrim { display: none; }

@media (max-width: 860px) {
  .drawer-scrim {
    display: block; position: fixed; inset: var(--drawer-top, 0px) 0 0 0; z-index: 45;
    background: rgba(0, 0, 0, .4); opacity: 0;
    transition: opacity 280ms ease-out;
  }
  .drawer-scrim.open { opacity: 1; }
  .drawer-scrim[hidden] { display: none; }

  .drawer {
    display: flex; flex-direction: column;
    /* Starts BELOW the topbar, not behind it. The topbar paints above it
       — above the drawer, by design, because board 5a keeps the strip visible
       — so a drawer at top:0 had its header row (mark + close) cropped by it.
       --drawer-top is measured from the topbar's live bottom edge in app.js,
       which also handles the half-scrolled case; 0 is the correct fallback if
       the script never runs, since then nothing is painted over it either. */
    position: fixed; top: var(--drawer-top, 0px); right: 0; bottom: 0;
    width: 100%; max-width: 430px; z-index: 46;
    background: var(--bg); color: var(--txt);
    transform: translateX(100%);
    transition: transform 280ms ease-out;
    /* SCROLLS. Every child is flex: 0 0 auto and the stack is ~830px tall, so
       on any viewport shorter than that the bottom simply vanished: at 375x667
       the Appearance switch was cut in half and the whole footer was gone, and
       in landscape two nav rows and the primary CTA were unreachable. There was
       no scrollbar and no touch scroll — only Tab scrolled the container, so the
       drawer jumped for keyboard users and was truncated for everyone else.
       margin-top:auto on .drawer-foot still pins the footer on tall viewports,
       because auto margins only consume FREE space. */
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }
  .drawer.open { transform: none; }
  .drawer[hidden] { display: none; }

  /* The topbar strip stays visible above the drawer (board 5a). */
  .topbar { position: relative; z-index: 47; }

  /* Scroll lock. position:fixed on <body> would jump the page to the top on
     open and lose the reading position on close; overflow:hidden holds it. */
  body.drawer-open { overflow: hidden; }

  .drawer-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 14px 18px 18px; flex: 0 0 auto;
    /* Sticky: a scrolled drawer used to take the close button off screen. */
    position: sticky; top: 0; z-index: 1; background: var(--bg);
  }
  /* A link focused while tabbing back up stops below the head, not under it. */
  .drawer { scroll-padding-top: 76px; }
  .drawer-head .brand svg { width: 26px; height: 26px; }
  .drawer-head .wordmark { font-size: 17px; }
  .drawer-close { color: var(--txt); }

  .drawer-links { display: flex; flex-direction: column; padding: 10px 22px 0; flex: 0 0 auto; }
  .drawer-links a {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 10px;
    padding: 19px 2px; min-height: 56px;
    border-bottom: 1px solid var(--line); color: var(--txt);
  }
  .drawer-links a:last-child { border-bottom: 0; }
  .drawer-row-l { display: flex; align-items: baseline; gap: 12px; }
  /* margin-inline-start: auto keeps the pill and arrow right-aligned when the
     row is too narrow for both halves (320-340) and they wrap under the label. */
  .drawer-row-r { display: flex; align-items: center; gap: 8px; margin-inline-start: auto; }
  .drawer-num {
    font-size: 10px; font-weight: 800; font-variant-numeric: tabular-nums;
    color: var(--num); letter-spacing: .02em;
  }
  .drawer-label {
    font-family: var(--font-display); font-weight: 700;
    font-size: 26px; letter-spacing: -.02em;
  }
  .drawer-pill {
    font-size: 9px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
    background: var(--tint-l); color: var(--svc-accent-txt); border-radius: 999px; padding: 3px 8px;
    white-space: nowrap;
  }
  .drawer-arrow { color: var(--zest); font-size: 18px; font-weight: 700; line-height: 1; }

  .drawer-ctas { display: flex; flex-direction: column; gap: 10px; padding: 18px 22px 0; flex: 0 0 auto; }
  .drawer-cta {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    background: var(--cta-bg); color: var(--cta-txt); border-radius: 16px;
    padding: 16px 0; font-size: 14.5px; font-weight: 700;
    box-shadow: 0 10px 26px var(--shadow); min-height: 44px;
  }
  .drawer-cta span { color: var(--price); }
  .drawer-wa {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    background: #2E9E63; color: #fff; border-radius: 16px;
    padding: 15px 0; font-size: 13.5px; font-weight: 700; min-height: 44px;
  }

  /* margin-top:auto pins the footer to the bottom without position:absolute,
     so a short viewport pushes it down instead of overlapping the CTAs. */
  .drawer-theme-row {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 18px 22px 0; flex: 0 0 auto;
  }
  .drawer-theme-row .footer-theme-label { color: var(--txt2); }

  .drawer-foot { margin-top: auto; flex: 0 0 auto; }
  .drawer-foot-row {
    display: flex; justify-content: space-between; align-items: flex-end;
    padding: 0 22px 16px; gap: 16px;
    /* At 320px the pills and the legal links together exceed the row and
       "Privacy" was clipped off the edge. Wrap instead of overflow. */
    flex-wrap: wrap;
  }
  .drawer-legal { flex: none; }
  .drawer-soon { display: flex; gap: 6px; margin-bottom: 10px; }
  .drawer-soon-pill {
    display: flex; align-items: center; gap: 5px;
    font-size: 9px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
    background: var(--pillbg); border: 1px solid var(--line); color: var(--txt2);
    border-radius: 999px; padding: 4px 9px;
  }
  .drawer-soon-pill .drawer-soon-icon { font-size: 11px; }
  .drawer-soon-cap { font-size: 10.5px; color: var(--txt2); font-weight: 500; }
  .drawer-legal { display: flex; gap: 12px; font-size: 11px; font-weight: 600; flex: 0 0 auto; }
  .drawer-legal a { color: var(--txt2); display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 44px; }
  .drawer-ticker { border: 0; border-radius: 0; }

  /* Rows stagger in 40ms apart (fade + 12px rise). --i is set in app.js from
     the row's index; the delay is only paid on OPEN. */
  .drawer.open .drawer-links a,
  .drawer.open .drawer-ctas > * {
    animation: nb-drawer-row 260ms ease-out backwards;
    animation-delay: calc(120ms + var(--i, 0) * 40ms);
  }
}

@keyframes nb-drawer-row {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

/* prefers-reduced-motion: plain fade, no slide and no stagger. */
@media (prefers-reduced-motion: reduce) {
  .drawer { transition: opacity 160ms ease-out; transform: none; opacity: 0; }
  .drawer.open { opacity: 1; }
  .drawer.open .drawer-links a,
  .drawer.open .drawer-ctas > * { animation: none; }
}


/* The app's own tokens (Thread v0.3), for the phones that depict the app —
   this hero loop and the partner tour. Midnight is a deeper ground than the
   site's dark (#121118 vs #17161F) on purpose: the phone should read as a
   screen, not a hole in the page. */
.nbd,
.nbd-tabbar,
.phone-screen,
.pd-phone {
  --app-bg: #FAF7F2;
  --app-card: #fff;
  --app-line: #EAE4DA;
  --app-line2: #D8D2C8;
  --app-tx: #1C1B26;
  --app-tx2: #5B5766;
  --app-tx3: #8B8695;
  --app-cta-bg: #1C1B26;
  --app-cta-tx: #FAF7F2;
  --app-zest-tx: #8A6400;
  --app-cursor: rgba(28, 27, 38, .85);
}
html[data-theme="dark"] .nbd,
html[data-theme="dark"] .nbd-tabbar,
html[data-theme="dark"] .phone-screen,
html[data-theme="dark"] .pd-phone {
  --app-bg: #121118;
  --app-card: #1A1922;
  --app-line: #2C2A38;
  --app-line2: #4A4658;
  --app-tx: #FAF7F2;
  --app-tx2: #8B8695;
  /* Board 3a dark gives the SERVICES eyebrow, the ghost SOON pill and the
     footer caption #5F5B6B — a level BELOW tx2. */
  --app-tx3: #5F5B6B;
  --app-cta-bg: #FFC529;
  --app-cta-tx: #1C1B26;
  --app-zest-tx: #FFC529;
  --app-cursor: rgba(250, 247, 242, .9);
}

/* ── Hero phone: the customer app as it is (main d949ffe3) ───────────────────
   One booking, Home to a rating, on a 19s loop at every width; the v5
   desktop board is retired (BRIEF-SITE-CUSTOMER-DEMO, 29 Sep). Eight screens
   stacked absolutely and cross-faded, a push, a toast and a cursor that taps
   MEASURED targets (app.js). The screens depict the APP, so they carry the
   app's own tokens (--app-*, on .phone-screen above) and render dark in the
   dark theme at every width. Copy: demo.* in content/site/site.json.

   Every amount is a .nbd-fig. Empty (the case until the site may show tagged
   sample figures) it draws as a blank bar; the "Sample figures" tag shows by
   default and hides only while every figure is empty. */
.phone[data-customer-demo] .phone-screen {
  --app-info-bg: #EAF6FB; --app-info-tx: #247797; --app-info: #2D96BE;
  --app-ok-bg: #E9F6EF; --app-ok-tx: #257D4F; --app-ok: #2E9E63;
  --app-dan: #D6455D; --app-well: #EAF6FB;
  position: relative; padding: 0; text-align: start;
  background: var(--app-bg); color: var(--app-tx);
}
html[data-theme="dark"] .phone[data-customer-demo] .phone-screen {
  --app-info-bg: #1D2A33; --app-info-tx: #5FB7DA; --app-info: #5FB7DA;
  --app-ok-bg: #15251C; --app-ok-tx: #3FBF7C; --app-ok: #3FBF7C;
  --app-dan: #F0788C; --app-well: #0E2833;
}
.phone[data-customer-demo] .phone-status { padding: 14px 20px 4px; }
.phone[data-customer-demo] .nbd { display: block; margin-inline: 0; position: relative; height: 540px; overflow: hidden; }
.nbd-screen { position: absolute; inset: 0; padding: 8px 14px 0; background: var(--app-bg); color: var(--app-tx); opacity: 0; overflow: hidden; }
.nbd-s1 { opacity: 1; }
.nbd b, .nbd strong { font-weight: 700; }

/* A figure, or a blank where it goes. */
.nbd-fig { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.nbd-fig:empty { display: inline-block; width: 26px; height: 6px; border-radius: 3px; background: var(--app-line2); vertical-align: middle; }
.nbd-fig.cta:empty { width: 34px; height: 8px; background: color-mix(in srgb, var(--app-cta-tx) 45%, transparent); }
.nbd-sample {
  position: absolute; top: 44px; right: 14px; z-index: 8;
  font-size: 7px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  background: var(--app-card); color: var(--app-tx2); border: 1px solid var(--app-line2);
  border-radius: 999px; padding: 2px 7px;
}
.phone[data-customer-demo]:not(:has(.nbd-fig:not(:empty))) .nbd-sample { display: none; }
/* The partner hooks (who does it, where): empty until lanes L7 and L4b land. */
.nbd-hook:empty { display: none; }
.nbd-hook { font-size: 8.5px; color: var(--app-tx2); margin-top: 6px; }

/* ── Home ───────────────────────────────────────────────────────────────── */
.nbd-appbar { display: flex; align-items: center; gap: 6px; padding-top: 2px; }
.nbd-appbar svg:first-child { width: 15px; height: 15px; flex: none; }
.nbd-wordmark { font-family: var(--font-display); font-weight: 800; font-size: 10.5px; letter-spacing: -.02em; }
.nbd-wordmark i { font-style: normal; color: var(--zest); }
.nbd-spacer { flex: 1; }
.nbd-address { font-size: 7.5px; font-weight: 600; color: var(--app-tx2); }
.nbd-bell { width: 11px; height: 11px; color: var(--app-tx2); flex: none; }
.nbd-greet { font-size: 8px; color: var(--app-tx2); font-weight: 600; margin-top: 12px; }
.nbd-ask { font-family: var(--font-display); font-weight: 800; font-size: 17px; letter-spacing: -.02em; line-height: 1.05; margin-top: 2px; max-width: 150px; }
.nbd-q { color: var(--app-zest-tx); }
.nbd-thread { display: block; width: 100%; height: 12px; margin-top: 3px; overflow: visible; }
.nbd-thread path { stroke-dasharray: 160; }
.nbd-thread .glow { filter: blur(3px); opacity: .7; }
.nbd-promo {
  display: flex; align-items: center; gap: 8px; margin-top: 8px; padding: 9px 10px;
  background: var(--app-card); border: 1px solid var(--app-line); border-radius: 14px;
}
.nbd-promo-badge {
  flex: none; display: grid; place-items: center; width: 24px; height: 24px; border-radius: 8px;
  background: #FFC529; color: #1C1B26; font-size: 7px; font-weight: 800;
}
.nbd-promo-t { min-width: 0; font-size: 8.5px; }
.nbd-promo-t b { display: block; font-size: 9px; }
.nbd-promo-sub { display: grid; color: var(--app-tx2); font-size: 7.5px; margin-top: 1px; }
.nbd-promo-sub > span { grid-area: 1 / 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nbd-p1 { opacity: 0; }
.nbd-eyebrow {
  font-size: 7px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--app-tx3); margin: 11px 0 6px;
}
/* The service grid is the page's tiles block (services.json): the coming
   services' tiles are named and locked. Drawn here as the app's orb wells. */
.nbd .nbd-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 0; }
.nbd .tile { background: var(--app-card); border: 1px solid var(--app-line); border-radius: 12px; padding: 8px; position: relative; }
.nbd .tile .icon {
  width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font-size: 11px;
  background: var(--tile-tint);
}
.nbd .tile .name { font-size: 8.5px; font-weight: 700; margin-top: 5px; color: var(--app-tx); }
.nbd .tile .meta { font-size: 7px; color: var(--app-tx2); }
.nbd .tile.locked { opacity: .45; filter: none; }
/* A service open in another city (pet grooming, Limassol's): the Beirut app
   cannot book it, so it is the app's locked tile (45%, SOON pill, "Soon."),
   named and not blurred because CLIENT named it. build.mjs gives it class
   "elsewhere" and the SOON pill. */
.nbd .tile.elsewhere { opacity: .45; }
/* The ghost SOON pill. The app draws ONE (SoonPill): on a locked tile, and
   on the Pay step's Card tile while card is coming soon, so both read the same. */
.nbd .tile .soon,
.nbd-paycard .soon {
  font-size: 5.5px; font-weight: 800; letter-spacing: .06em;
  padding: 1px 5px; border-radius: 999px; background: transparent; color: var(--app-tx3); border: 1px solid var(--app-line);
}
.nbd .tile .soon { position: absolute; top: 7px; right: 7px; }
.nbd .tabbar.nbd-tabbar {
  position: absolute; left: 0; right: 0; bottom: 0; display: flex; justify-content: space-around;
  margin: 0; padding: 7px 0 10px; border-top: 1px solid var(--app-line); background: var(--app-bg);
  font-size: 7px; color: var(--app-tx2); text-align: center;
}
.nbd .tabbar.nbd-tabbar span { flex: 1; font-weight: 600; }
.nbd .tabbar.nbd-tabbar span.active { color: var(--app-tx); font-weight: 700; }
.nbd .tabbar.nbd-tabbar span i { display: block; font-style: normal; font-size: 12px; margin-bottom: 1px; }
/* The drawn tab icons (build.mjs TAB_ICONS) are the size of the glyphs they
   replaced. An SVG with a viewBox and no size filled the tab: 84px at 375. */
.tabbar span i svg { width: 1em; height: 1em; margin-inline: auto; }
.nbd .tabbar.nbd-tabbar b { display: block; width: 4px; height: 4px; border-radius: 50%; margin: 2px auto 0; background: transparent; }
.nbd .tabbar.nbd-tabbar span.active b { background: var(--zest); }
.nbd-toast {
  position: absolute; left: 14px; right: 14px; bottom: 52px; z-index: 3; padding: 8px 10px; border-radius: 999px;
  background: var(--app-tx); color: var(--app-bg); font-size: 8px; font-weight: 600; text-align: center; opacity: 0;
}

/* ── The booking flow: Items, Slots, Review & pay ───────────────────────── */
.nbd-head { display: flex; align-items: center; gap: 8px; padding-top: 2px; }
.nbd-back {
  width: 22px; height: 22px; border-radius: 8px; border: 1px solid var(--app-line); flex: none;
  display: grid; place-items: center; font-size: 13px; line-height: 1;
}
.nbd-title { font-size: 12.5px; font-weight: 700; }
.nbd-cathero { margin-top: 8px; padding: 8px 10px; border-radius: 14px; background: var(--app-well); font-size: 8.5px; font-weight: 700; }
.nbd-stepper { display: flex; gap: 4px; margin-top: 9px; }
.nbd-stepper i { flex: 1; height: 3px; border-radius: 99px; background: var(--app-line); }
.nbd-stepper i.on { background: #FFC529; box-shadow: 0 0 6px rgba(255, 197, 41, .6); }
.nbd-item {
  display: flex; align-items: center; gap: 8px; margin-bottom: 6px; padding: 7px 9px;
  background: var(--app-card); border: 1px solid var(--app-line); border-radius: 12px;
}
.nbd-item-i { font-size: 13px; line-height: 1; }
.nbd-item-t { flex: 1; min-width: 0; font-size: 7.5px; color: var(--app-tx2); }
.nbd-item-t b { display: block; font-size: 9px; color: var(--app-tx); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nbd-item-t > span { display: flex; align-items: center; gap: 1px; margin-top: 1px; }
.nbd-step { display: flex; align-items: center; gap: 5px; flex: none; }
.nbd-step > i {
  width: 18px; height: 18px; border-radius: 50%; display: grid; place-items: center; font-style: normal;
  border: 1px solid var(--app-line2); font-size: 10px; font-weight: 700; color: var(--app-tx2);
}
.nbd-qty { display: inline-grid; min-width: 9px; text-align: center; font-size: 9.5px; font-weight: 700; }
.nbd-qty > span { grid-area: 1 / 1; }
.nbd-qty .q1, .nbd-qty .q2, .nbd-qty .q3 { opacity: 0; }
.nbd-express { margin-top: 2px; }
.nbd-switch { width: 30px; height: 17px; border-radius: 999px; background: var(--app-line); padding: 2px; flex: none; box-sizing: border-box; }
.nbd-switch i { display: block; width: 13px; height: 13px; border-radius: 50%; background: #FFFFFF; }
.nbd-cta {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 36px; padding: 0 14px;
  border-radius: 13px; background: var(--app-cta-bg); color: var(--app-cta-tx); font-size: 10.5px; font-weight: 800;
}
.nbd-cta-items, .nbd-cta-slots, .nbd-cta-pay { position: absolute; left: 14px; right: 14px; bottom: 12px; }
.nbd-days { display: flex; gap: 5px; }
.nbd-days span { font-size: 8px; padding: 4px 9px; border-radius: 999px; border: 1px solid var(--app-line); background: var(--app-card); }
.nbd-days span.sel { border-color: #FFC529; }
.nbd-rails { display: grid; }
.nbd-rails > .nbd-rail { grid-area: 1 / 1; }
.nbd-rail-pickup { opacity: 0; }
.nbd-rail { position: relative; padding-left: 12px; margin-top: 6px; }
.nbd-rail::before { content: ""; position: absolute; left: 2px; top: 4px; bottom: 4px; width: 1.5px; background: var(--app-line); }
.nbd-win {
  position: relative; display: flex; align-items: center; margin-bottom: 5px; padding: 7px 9px; font-size: 9px;
  background: var(--app-card); border: 1px solid var(--app-line); border-radius: 11px;
}
.nbd-win > i { position: absolute; left: -12.5px; width: 6px; height: 6px; border-radius: 50%; background: var(--app-line); }
.nbd-win span { flex: 1; }
.nbd-win b { color: var(--app-zest-tx); font-size: 8px; opacity: 0; }
/* The drawn window check: unsized, it collapsed to 0 x 0 and never showed. */
.nbd-win b svg { width: 1.25em; height: 1.25em; }
.nbd-xnote { font-size: 7.5px; color: var(--app-tx2); margin-top: 6px; }
.nbd-noterow { margin-top: 6px; padding: 7px 9px; font-size: 7.5px; color: var(--app-tx2); border: 1px dashed var(--app-line2); border-radius: 11px; }
.nbd-scrollbox { position: absolute; left: 0; right: 0; top: 34px; bottom: 58px; overflow: hidden; }
.nbd-scroll { padding: 0 14px 10px; }
.nbd-card { background: var(--app-card); border: 1px solid var(--app-line); border-radius: 13px; padding: 8px 10px; }
.nbd-where { margin-top: 10px; }
.nbd-where-t { display: flex; justify-content: space-between; gap: 6px; font-size: 9px; }
.nbd-where-t b { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nbd-where-t span { color: var(--app-zest-tx); font-weight: 700; font-size: 8px; flex: none; }
.nbd-where-s { font-size: 8px; color: var(--app-tx2); margin-top: 2px; }
/* A method tile as the app draws it: brand plate, name and line, then the
   radio on the right. The selected border and radio are ink on Daylight and
   zest on Midnight, which is the CTA's fill in each theme. */
.nbd-paycard {
  display: flex; align-items: center; gap: 8px; margin-bottom: 5px; padding: 7px 9px;
  background: var(--app-card); border: 1.5px solid var(--app-line); border-radius: 12px;
}
.nbd-paycard.on { border-color: var(--app-cta-bg); }
.nbd-radio { width: 11px; height: 11px; border-radius: 50%; border: 1.5px solid var(--app-line2); flex: none; box-sizing: border-box; }
.nbd-paycard.on .nbd-radio { border-color: var(--app-cta-bg); box-shadow: inset 0 0 0 2.5px var(--app-card); background: var(--app-cta-bg); }
/* The plates' colours are fixed in both themes, as the app's are. */
.nbd-plate {
  flex: none; display: grid; place-items: center; width: 26px; height: 17px; border-radius: 4px;
  font-size: 4.5px; font-weight: 800; letter-spacing: .04em; color: #fff;
}
.nbd-plate.card { background: #D97706; }
.nbd-plate.cash { background: #334155; }
/* Card while it is coming soon (the market's switch; Lebanon until card works
   there): the locked tile's 45%, plate and all, the SOON pill where the radio
   sits, and never selected. The cursor never taps it. */
.nbd-paycard.locked { opacity: .45; }
.nbd-paycard .soon { flex: none; }
.nbd-promo-row { font-size: 8.5px; padding: 7px 9px; border-radius: 11px; background: var(--app-card); border: 1px solid var(--app-line); }
.nbd-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.nbd-chips span { font-size: 7.5px; padding: 4px 8px; border-radius: 999px; border: 1px solid var(--app-line); background: var(--app-card); }
.nbd-chips span.once { border-color: #FFC529; }
.nbd-repeat-note {
  font-size: 7px; color: var(--app-tx2); margin-top: 5px; line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.nbd-sum { padding: 4px 10px; }
.nbd-sum-r { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 4px 0; font-size: 8.5px; color: var(--app-tx2); }
.nbd-sum-r.total { color: var(--app-tx); font-weight: 700; border-top: 1px dashed var(--app-line2); }
.nbd-footer { font-size: 7.5px; color: var(--app-tx2); text-align: center; margin-top: 7px; }

/* ── Confirm ────────────────────────────────────────────────────────────── */
.nbd-s5 { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 0 18px; justify-content: center; }
.nbd-tick { width: 70px; height: 70px; }
.nbd-tick path { stroke-dashoffset: 0; filter: drop-shadow(0 0 8px rgba(255, 197, 41, .55)); }
.nbd-big { font-family: var(--font-display); font-weight: 800; font-size: 19px; letter-spacing: -.02em; margin-top: 8px; }
.nbd-sub { font-size: 8.5px; color: var(--app-tx2); margin-top: 4px; }
.nbd-chip {
  display: inline-flex; align-items: center; gap: 2px; margin-top: 10px; padding: 5px 10px; border-radius: 999px;
  background: var(--app-card); border: 1px solid var(--app-line); font-size: 8px; white-space: nowrap;
}
.nbd-cta-track { justify-content: center; align-self: stretch; margin-top: 16px; }
.nbd-ghost {
  display: flex; align-items: center; justify-content: center; min-height: 32px; margin-top: 7px; align-self: stretch;
  border-radius: 12px; border: 1.5px solid var(--app-line); font-size: 10px; font-weight: 700;
}

/* ── Home with the order live, the push ─────────────────────────────────── */
.nbd-live {
  margin-top: 8px; padding: 8px 10px; border: 1px solid rgba(255, 197, 41, .55); border-radius: 13px;
  background: linear-gradient(90deg, var(--app-card) 55%, rgba(255, 197, 41, .12));
}
.nbd-live-h { display: flex; justify-content: space-between; align-items: center; font-size: 9px; font-weight: 700; }
.nbd-bar { display: block; height: 3px; border-radius: 99px; background: var(--app-line); margin: 6px 0 5px; overflow: hidden; }
.nbd-bar i { display: block; width: 20%; height: 100%; background: #FFC529; }
.nbd-live-f { display: flex; justify-content: space-between; gap: 6px; font-size: 7.5px; color: var(--app-tx2); }
.nbd-live-f b { color: var(--app-zest-tx); font-weight: 700; flex: none; }
.nbd-pill {
  flex: none; font-size: 6px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  border-radius: 999px; padding: 2px 6px; background: var(--app-line); color: var(--app-tx2);
}
.nbd-pill.zest { background: #FFC529; color: #1C1B26; }
.nbd-pill.info { background: var(--app-info-bg); color: var(--app-info-tx); }
.nbd-pill.ok { background: var(--app-ok-bg); color: var(--app-ok-tx); }
/* A system notification, in a neutral badge: never WhatsApp green. */
.nbd-push {
  position: absolute; left: 8px; right: 8px; top: 4px; z-index: 5; display: flex; gap: 8px; align-items: flex-start;
  padding: 8px 10px; border-radius: 16px; background: var(--app-card); border: 1px solid var(--app-line);
  box-shadow: 0 10px 24px rgba(28, 27, 38, .18); font-size: 8.5px; transform: translateY(-140%);
}
.nbd-push-app {
  width: 18px; height: 18px; border-radius: 50%; flex: none; display: grid; place-items: center;
  background: #1C1B26; color: #FAF7F2; font-size: 8px; font-weight: 800;
}
html[data-theme="dark"] .nbd-push-app { background: #FAF7F2; color: #1C1B26; }
.nbd-push-t { flex: 1; min-width: 0; }
.nbd-push-h { display: flex; justify-content: space-between; }
.nbd-push-h em { font-style: normal; color: var(--app-tx3); font-size: 7.5px; }
.nbd-push-t > span:last-child { display: block; margin-top: 1px; }

/* ── Track, and the rating ──────────────────────────────────────────────── */
.nbd-track { margin-top: 10px; }
.nbd-track-h { display: flex; justify-content: space-between; align-items: center; gap: 6px; font-size: 9px; }
.nbd-track-m { font-size: 7.5px; color: var(--app-tx2); margin-top: 3px; display: flex; align-items: center; gap: 1px; flex-wrap: wrap; }
.nbd-tl { margin-top: 8px; }
.nbd-tl-row { position: relative; display: flex; align-items: center; gap: 10px; height: 23px; font-size: 9px; padding-left: 2px; }
.nbd-tl-row::before { content: ""; position: absolute; left: 5px; top: -11px; height: 23px; width: 1.5px; background: var(--app-line); }
.nbd-tl-row:first-child::before { display: none; }
.nbd-tl-row.done::before, .nbd-tl-row.now::before { background: var(--app-info); }
.nbd-tl-dot { position: relative; z-index: 1; width: 7px; height: 7px; border-radius: 50%; background: var(--app-line); flex: none; margin-left: 0.5px; }
.nbd-tl-row.done .nbd-tl-dot { background: var(--app-info); }
.nbd-tl-row.now .nbd-tl-dot { width: 10px; height: 10px; margin-left: -1px; border: 2px solid var(--app-info); background: var(--app-card); box-sizing: border-box; }
.nbd-tl-row.now { color: var(--app-info-tx); }
.nbd-tl-row.next { color: var(--app-tx3); }
.nbd-link { text-align: center; font-size: 8.5px; font-weight: 600; color: var(--app-tx2); margin-top: 10px; }
.nbd-link.danger { color: var(--app-dan); }
.nbd-s7 .nbd-ghost { margin-top: 8px; }
.nbd-rate { margin-top: 8px; font-size: 9px; }
.nbd-stars { display: flex; gap: 5px; margin-top: 6px; }
.nbd-stars span { font-size: 15px; line-height: 1; color: var(--app-line2); }
.nbd-cta-rate { justify-content: center; margin-top: 8px; min-height: 30px; opacity: 0; }

/* The cursor. */
.nbd-cursor {
  position: absolute; left: 0; top: 0; z-index: 7; width: 24px; height: 24px; border-radius: 50%;
  background: var(--app-cursor); border: 2.5px solid #FFC529; box-shadow: 0 8px 20px rgba(28, 27, 38, .35); opacity: 0;
}

/* ── The loop: 19s ──────────────────────────────────────────────────────────
   Home 0-13.5% · Items -27% · Slots -41% · Review & pay -56% · Confirm -64%
   · Home and the push -72% · Track -85% · Completed and the rating -97%. */
.nbd-s1 { animation: nbd-s1 19s linear infinite; }
.nbd-s2 { animation: nbd-s2 19s linear infinite; }
.nbd-s3 { animation: nbd-s3 19s linear infinite; }
.nbd-s4 { animation: nbd-s4 19s linear infinite; }
.nbd-s5 { animation: nbd-s5 19s linear infinite; }
.nbd-s6 { animation: nbd-s6 19s linear infinite; }
.nbd-s7 { animation: nbd-s7 19s linear infinite; }
.nbd-s8 { animation: nbd-s8 19s linear infinite; }
.nbd-cursor { animation: nbd-cursor 19s cubic-bezier(.4, 0, .2, 1) infinite; }
.nbd-s1 .nbd-thread path { animation: nbd-under 19s linear infinite; }
.nbd-s1 .nbd-p0 { animation: nbd-p0 19s linear infinite; }
.nbd-s1 .nbd-p1 { animation: nbd-p1 19s linear infinite; }
.nbd-toast { animation: nbd-toast 19s linear infinite; }
.nbd-s1 .nbd-promo { animation: nbd-press-promo 19s linear infinite; }
.nbd-s1 .tile:first-child { animation: nbd-press-tile 19s linear infinite; }
.nbd-qty .q0 { animation: nbd-q0 19s linear infinite; }
.nbd-qty .q1 { animation: nbd-q1 19s linear infinite; }
.nbd-qty .q2 { animation: nbd-q2 19s linear infinite; }
.nbd-qty .q3 { animation: nbd-q3 19s linear infinite; }
.nbd-item [data-tap="3"] { animation: nbd-press-plus 19s linear infinite; }
.nbd-switch { animation: nbd-switch 19s linear infinite; }
.nbd-switch i { animation: nbd-thumb 19s linear infinite; }
.nbd-cta-items { animation: nbd-cta-items 19s linear infinite; }
.nbd-cta-slots { animation: nbd-cta-slots 19s linear infinite; }
.nbd-days-pickup span:nth-child(1) { animation: nbd-day-off 19s linear infinite; }
.nbd-days-pickup span:nth-child(2) { animation: nbd-day-on 19s linear infinite; }
.nbd-rail-today { animation: nbd-rail-today 19s linear infinite; }
.nbd-rail-pickup { animation: nbd-rail-pickup 19s linear infinite; }
.nbd-rail-pickup .nbd-win.pick { animation: nbd-pick-p 19s linear infinite; }
.nbd-rail-pickup .nbd-win.pick b, .nbd-rail-pickup .nbd-win.pick i { animation: nbd-pick-p-mark 19s linear infinite; }
.nbd-rail-return .nbd-win.pick { animation: nbd-pick-r 19s linear infinite; }
.nbd-rail-return .nbd-win.pick b, .nbd-rail-return .nbd-win.pick i { animation: nbd-pick-r-mark 19s linear infinite; }
.nbd-chips .once { animation: nbd-chip-off 19s linear infinite; }
.nbd-chips .two { animation: nbd-chip-on 19s linear infinite; }
.nbd-scroll { animation: nbd-scroll 19s cubic-bezier(.4, 0, .2, 1) infinite; }
.nbd-cta-pay { animation: nbd-press-pay 19s linear infinite; }
.nbd-s5 .nbd-ghost { animation: nbd-press-home 19s linear infinite; }
.nbd-tick path { animation: nbd-tick 19s linear infinite; }
.nbd-push { animation: nbd-push 19s cubic-bezier(.2, .8, .2, 1) infinite; }
.nbd-stars span { animation: nbd-star 19s linear infinite; }
.nbd-cta-rate { animation: nbd-rate 19s linear infinite; }
.nbd-stars span { animation-delay: calc(var(--i) * .1s); }

@keyframes nbd-s1 { 0%,13.5% { opacity: 1 } 15%,97% { opacity: 0 } 98.5%,100% { opacity: 1 } }
@keyframes nbd-s2 { 0%,13.5% { opacity: 0; transform: translateY(14px) } 15%,27% { opacity: 1; transform: none } 28.5%,100% { opacity: 0; transform: none } }
@keyframes nbd-s3 { 0%,27% { opacity: 0; transform: translateY(14px) } 28.5%,41% { opacity: 1; transform: none } 42.5%,100% { opacity: 0; transform: none } }
@keyframes nbd-s4 { 0%,41% { opacity: 0; transform: translateY(14px) } 42.5%,56% { opacity: 1; transform: none } 57.5%,100% { opacity: 0; transform: none } }
@keyframes nbd-s5 { 0%,56% { opacity: 0; } 57.5%,64% { opacity: 1; } 65.5%,100% { opacity: 0; } }
@keyframes nbd-s6 { 0%,64% { opacity: 0; } 65.5%,72% { opacity: 1; } 73.5%,100% { opacity: 0; } }
@keyframes nbd-s7 { 0%,72% { opacity: 0; transform: translateY(14px) } 73.5%,85% { opacity: 1; transform: none } 86.5%,100% { opacity: 0; transform: none } }
@keyframes nbd-s8 { 0%,85% { opacity: 0; } 86.5%,97% { opacity: 1; } 98.5%,100% { opacity: 0; } }
@keyframes nbd-cursor {
  0% { transform: translate(calc(var(--t1x, var(--f1x)) + 40px), calc(var(--t1y, var(--f1y)) + 80px)) scale(1); opacity: 0 }
  3% { transform: translate(calc(var(--t1x, var(--f1x)) + 40px), calc(var(--t1y, var(--f1y)) + 80px)) scale(1); opacity: 0 }
  4% { transform: translate(var(--t1x, var(--f1x)), var(--t1y, var(--f1y))) scale(1); opacity: 1 }
  5.3% { transform: translate(var(--t1x, var(--f1x)), var(--t1y, var(--f1y))) scale(0.78); opacity: 1 }
  6% { transform: translate(var(--t1x, var(--f1x)), var(--t1y, var(--f1y))) scale(1); opacity: 1 }
  10.3% { transform: translate(var(--t2x, var(--f2x)), var(--t2y, var(--f2y))) scale(1); opacity: 1 }
  11.6% { transform: translate(var(--t2x, var(--f2x)), var(--t2y, var(--f2y))) scale(0.78); opacity: 1 }
  12.3% { transform: translate(var(--t2x, var(--f2x)), var(--t2y, var(--f2y))) scale(1); opacity: 1 }
  16.1% { transform: translate(var(--t3x, var(--f3x)), var(--t3y, var(--f3y))) scale(1); opacity: 1 }
  17.4% { transform: translate(var(--t3x, var(--f3x)), var(--t3y, var(--f3y))) scale(0.78); opacity: 1 }
  18.1% { transform: translate(var(--t3x, var(--f3x)), var(--t3y, var(--f3y))) scale(1); opacity: 1 }
  18.2% { transform: translate(var(--t3x, var(--f3x)), var(--t3y, var(--f3y))) scale(1); opacity: 1 }
  19.5% { transform: translate(var(--t3x, var(--f3x)), var(--t3y, var(--f3y))) scale(0.78); opacity: 1 }
  20.2% { transform: translate(var(--t3x, var(--f3x)), var(--t3y, var(--f3y))) scale(1); opacity: 1 }
  20.3% { transform: translate(var(--t3x, var(--f3x)), var(--t3y, var(--f3y))) scale(1); opacity: 1 }
  21.6% { transform: translate(var(--t3x, var(--f3x)), var(--t3y, var(--f3y))) scale(0.78); opacity: 1 }
  22.3% { transform: translate(var(--t3x, var(--f3x)), var(--t3y, var(--f3y))) scale(1); opacity: 1 }
  22.9% { transform: translate(var(--t6x, var(--f6x)), var(--t6y, var(--f6y))) scale(1); opacity: 1 }
  24.2% { transform: translate(var(--t6x, var(--f6x)), var(--t6y, var(--f6y))) scale(0.78); opacity: 1 }
  24.9% { transform: translate(var(--t6x, var(--f6x)), var(--t6y, var(--f6y))) scale(1); opacity: 1 }
  25% { transform: translate(var(--t7x, var(--f7x)), var(--t7y, var(--f7y))) scale(1); opacity: 1 }
  26.3% { transform: translate(var(--t7x, var(--f7x)), var(--t7y, var(--f7y))) scale(0.78); opacity: 1 }
  27% { transform: translate(var(--t7x, var(--f7x)), var(--t7y, var(--f7y))) scale(1); opacity: 1 }
  28.7% { transform: translate(var(--t8x, var(--f8x)), var(--t8y, var(--f8y))) scale(1); opacity: 1 }
  30% { transform: translate(var(--t8x, var(--f8x)), var(--t8y, var(--f8y))) scale(0.78); opacity: 1 }
  30.7% { transform: translate(var(--t8x, var(--f8x)), var(--t8y, var(--f8y))) scale(1); opacity: 1 }
  31.3% { transform: translate(var(--t9x, var(--f9x)), var(--t9y, var(--f9y))) scale(1); opacity: 1 }
  32.6% { transform: translate(var(--t9x, var(--f9x)), var(--t9y, var(--f9y))) scale(0.78); opacity: 1 }
  33.3% { transform: translate(var(--t9x, var(--f9x)), var(--t9y, var(--f9y))) scale(1); opacity: 1 }
  35% { transform: translate(var(--t10x, var(--f10x)), var(--t10y, var(--f10y))) scale(1); opacity: 1 }
  36.3% { transform: translate(var(--t10x, var(--f10x)), var(--t10y, var(--f10y))) scale(0.78); opacity: 1 }
  37% { transform: translate(var(--t10x, var(--f10x)), var(--t10y, var(--f10y))) scale(1); opacity: 1 }
  38.7% { transform: translate(var(--t11x, var(--f11x)), var(--t11y, var(--f11y))) scale(1); opacity: 1 }
  40% { transform: translate(var(--t11x, var(--f11x)), var(--t11y, var(--f11y))) scale(0.78); opacity: 1 }
  40.7% { transform: translate(var(--t11x, var(--f11x)), var(--t11y, var(--f11y))) scale(1); opacity: 1 }
  44% { transform: translate(var(--t12x, var(--f12x)), var(--t12y, var(--f12y))) scale(1); opacity: 1 }
  45.3% { transform: translate(var(--t12x, var(--f12x)), var(--t12y, var(--f12y))) scale(0.78); opacity: 1 }
  46% { transform: translate(var(--t12x, var(--f12x)), var(--t12y, var(--f12y))) scale(1); opacity: 1 }
  52.9% { transform: translate(var(--t13x, var(--f13x)), var(--t13y, var(--f13y))) scale(1); opacity: 1 }
  54.2% { transform: translate(var(--t13x, var(--f13x)), var(--t13y, var(--f13y))) scale(0.78); opacity: 1 }
  54.9% { transform: translate(var(--t13x, var(--f13x)), var(--t13y, var(--f13y))) scale(1); opacity: 1 }
  61.3% { transform: translate(var(--t14x, var(--f14x)), var(--t14y, var(--f14y))) scale(1); opacity: 1 }
  62.6% { transform: translate(var(--t14x, var(--f14x)), var(--t14y, var(--f14y))) scale(0.78); opacity: 1 }
  63.3% { transform: translate(var(--t14x, var(--f14x)), var(--t14y, var(--f14y))) scale(1); opacity: 1 }
  67.5% { transform: translate(calc(var(--t15x, var(--f15x)) + 60px), calc(var(--t15y, var(--f15y)) + 40px)) scale(1); opacity: 0 }
  69.7% { transform: translate(var(--t15x, var(--f15x)), var(--t15y, var(--f15y))) scale(1); opacity: 1 }
  71% { transform: translate(var(--t15x, var(--f15x)), var(--t15y, var(--f15y))) scale(0.78); opacity: 1 }
  71.7% { transform: translate(var(--t15x, var(--f15x)), var(--t15y, var(--f15y))) scale(1); opacity: 1 }
  73% { transform: translate(var(--t15x, var(--f15x)), var(--t15y, var(--f15y))) scale(1); opacity: 0 }
  85.2% { transform: translate(calc(var(--t16x, var(--f16x)) + 40px), calc(var(--t16y, var(--f16y)) + 50px)) scale(1); opacity: 0 }
  87.7% { transform: translate(var(--t16x, var(--f16x)), var(--t16y, var(--f16y))) scale(1); opacity: 1 }
  89% { transform: translate(var(--t16x, var(--f16x)), var(--t16y, var(--f16y))) scale(0.78); opacity: 1 }
  89.7% { transform: translate(var(--t16x, var(--f16x)), var(--t16y, var(--f16y))) scale(1); opacity: 1 }
  92.9% { transform: translate(var(--t17x, var(--f17x)), var(--t17y, var(--f17y))) scale(1); opacity: 1 }
  94.2% { transform: translate(var(--t17x, var(--f17x)), var(--t17y, var(--f17y))) scale(0.78); opacity: 1 }
  94.9% { transform: translate(var(--t17x, var(--f17x)), var(--t17y, var(--f17y))) scale(1); opacity: 1 }
  96.5% { transform: translate(var(--t17x, var(--f17x)), var(--t17y, var(--f17y))) scale(1); opacity: 0 }
  100% { transform: translate(var(--t17x, var(--f17x)), var(--t17y, var(--f17y))) scale(1); opacity: 0 }
}

/* Where the cursor taps before app.js measures, and without JavaScript: the
   positions app.js measured on the 300px desktop phone and the 270px phone at
   860px and under (the phone's insides are fixed-size, so these hold unless a
   font fails to load). app.js's --tNx/--tNy win whenever they are set. */
.nbd { --f1x: 128px; --f1y: 121px; --f2x: 64px; --f2y: 207px; --f3x: 235px; --f3y: 117px; --f6x: 229px; --f6y: 309px; --f7x: 128px; --f7y: 498px; --f8x: 79px; --f8y: 107px; --f9x: 134px; --f9y: 139px; --f10x: 134px; --f10y: 299px; --f11x: 128px; --f11y: 498px; --f12x: 157px; --f12y: 337px; --f13x: 128px; --f13y: 498px; --f14x: 128px; --f14y: 366px; --f15x: 128px; --f15y: 15px; --f16x: 101px; --f16y: 266px; --f17x: 128px; --f17y: 296px; }
@media (max-width: 860px) { .nbd { --f1x: 114px; --f1y: 121px; --f2x: 57px; --f2y: 207px; --f3x: 207px; --f3y: 117px; --f6x: 201px; --f6y: 309px; --f7x: 114px; --f7y: 498px; --f8x: 79px; --f8y: 107px; --f9x: 120px; --f9y: 139px; --f10x: 120px; --f10y: 299px; --f11x: 114px; --f11y: 498px; --f12x: 157px; --f12y: 337px; --f13x: 114px; --f13y: 498px; --f14x: 114px; --f14y: 366px; --f15x: 114px; --f15y: 21px; --f16x: 101px; --f16y: 266px; --f17x: 114px; --f17y: 296px; } }
@keyframes nbd-under { 0%,1% { stroke-dashoffset: 160 } 7%,100% { stroke-dashoffset: 0 } }
@keyframes nbd-p0 { 0%,5.6% { opacity: 1 } 5.8%,97% { opacity: 0 } 98%,100% { opacity: 1 } }
@keyframes nbd-p1 { 0%,5.6% { opacity: 0 } 5.8%,97% { opacity: 1 } 98%,100% { opacity: 0 } }
@keyframes nbd-toast { 0%,6% { opacity: 0; transform: translateY(8px) } 6.8%,11% { opacity: 1; transform: none } 12%,100% { opacity: 0; transform: none } }
@keyframes nbd-q0 { 0%,17.5% { opacity: 1 } 17.6%,100% { opacity: 0 } }
@keyframes nbd-q1 { 0%,17.5% { opacity: 0 } 17.6%,19.6% { opacity: 1 } 19.7%,100% { opacity: 0 } }
@keyframes nbd-q2 { 0%,19.6% { opacity: 0 } 19.7%,21.7% { opacity: 1 } 21.8%,100% { opacity: 0 } }
@keyframes nbd-q3 { 0%,21.7% { opacity: 0 } 21.8%,100% { opacity: 1 } }
@keyframes nbd-switch { 0%,24.3% { background: var(--app-line) } 24.9%,100% { background: var(--app-ok) } }
@keyframes nbd-thumb { 0%,24.3% { transform: none } 24.9%,100% { transform: translateX(13px) } }
@keyframes nbd-cta-items { 0%,17.5% { opacity: .45 } 17.6%,26% { opacity: 1; transform: none } 26.3% { opacity: 1; transform: scale(.96) } 27.1%,100% { opacity: 1; transform: none } }
@keyframes nbd-cta-slots { 0%,36.4% { opacity: .45 } 36.5%,39.7% { opacity: 1; transform: none } 40% { opacity: 1; transform: scale(.96) } 40.8%,100% { opacity: 1; transform: none } }
@keyframes nbd-day-off { 0%,30.1% { border-color: #FFC529 } 30.2%,100% { border-color: var(--app-line) } }
@keyframes nbd-day-on { 0%,30.1% { border-color: var(--app-line) } 30.2%,100% { border-color: #FFC529 } }
@keyframes nbd-rail-today { 0%,30.2% { opacity: 1 } 30.9%,100% { opacity: 0 } }
@keyframes nbd-rail-pickup { 0%,30.2% { opacity: 0 } 30.9%,100% { opacity: 1 } }
@keyframes nbd-pick-p { 0%,32.7% { border-color: var(--app-line); box-shadow: none } 32.8%,100% { border-color: #FFC529; box-shadow: 0 0 12px rgba(255, 197, 41, .25) } }
@keyframes nbd-pick-p-mark { 0%,32.7% { opacity: 0 } 32.8%,100% { opacity: 1; background: #FFC529 } }
@keyframes nbd-pick-r { 0%,36.4% { border-color: var(--app-line); box-shadow: none } 36.5%,100% { border-color: #FFC529; box-shadow: 0 0 12px rgba(255, 197, 41, .25) } }
@keyframes nbd-pick-r-mark { 0%,36.4% { opacity: 0 } 36.5%,100% { opacity: 1; background: #FFC529 } }
@keyframes nbd-chip-off { 0%,45.4% { border-color: #FFC529 } 45.5%,100% { border-color: var(--app-line) } }
@keyframes nbd-chip-on { 0%,45.4% { border-color: var(--app-line) } 45.5%,100% { border-color: #FFC529 } }
/* Pay scrolls to the summary and stops with its top edge in the gap above PROMO,
   so no card is cut under the header (measured: the Cash card ends at 229px, PROMO starts at 239px). */
@keyframes nbd-scroll { 0%,47% { transform: none } 50.5%,100% { transform: translateY(-232px) } }
@keyframes nbd-tick { 0%,56.8% { stroke-dashoffset: 120 } 59.5%,100% { stroke-dashoffset: 0 } }
@keyframes nbd-push { 0%,66.5% { transform: translateY(-140%) } 68.2%,71.6% { transform: none } 73%,100% { transform: translateY(-140%) } }
@keyframes nbd-star { 0%,88.6% { color: var(--app-line2); transform: none } 89.2% { color: #FFC529; transform: scale(1.2) } 90%,100% { color: #FFC529; transform: none } }
@keyframes nbd-rate { 0%,90% { opacity: 0 } 91%,93.8% { opacity: 1; transform: none } 94.2% { opacity: 1; transform: scale(.96) } 95%,100% { opacity: 1; transform: none } }
@keyframes nbd-press-promo { 0%,4.9% { transform: none } 5.3% { transform: scale(.94) } 6.1%, 100% { transform: none } }
@keyframes nbd-press-tile { 0%,11.2% { transform: none } 11.6% { transform: scale(.94) } 12.4%, 100% { transform: none } }
@keyframes nbd-press-plus { 0%,17% { transform: none } 17.4% { transform: scale(.94) } 18.2%, 19.1% { transform: none } 19.5% { transform: scale(.94) } 20.3%, 21.2% { transform: none } 21.6% { transform: scale(.94) } 22.4%, 100% { transform: none } }
@keyframes nbd-press-pay { 0%,53.8% { transform: none } 54.2% { transform: scale(.94) } 55%, 100% { transform: none } }
@keyframes nbd-press-home { 0%,62.2% { transform: none } 62.6% { transform: scale(.94) } 63.4%, 100% { transform: none } }

/* Off screen, app.js pauses the loop: compositing for a phone nobody is
   looking at is battery someone else is paying for. */
.nbd.paused, .nbd.paused * { animation-play-state: paused !important; }

/* prefers-reduced-motion: one still, the order on its Track screen — the
   screen that shows the most (the order, its stage, its timeline, and what
   can be done with it). Not a slower loop: a demo that still changes what it
   says is still motion. */
@media (prefers-reduced-motion: reduce) {
  /* Everything animated in the demo, listed so a new moving part cannot be
     added without deciding what it does here. */
  .nbd-screen, .nbd-cursor, .nbd-thread path, .nbd-p0, .nbd-p1, .nbd-toast, .nbd-promo, .nbd .tile,
  .nbd-qty span, .nbd-step > i, .nbd-switch, .nbd-switch i, .nbd-cta, .nbd-ghost, .nbd-days span, .nbd-rail,
  .nbd-win, .nbd-win b, .nbd-win i, .nbd-chips span, .nbd-scroll, .nbd-tick path, .nbd-push, .nbd-stars span { animation: none !important; }
  .nbd-screen, .nbd-cursor, .nbd-push, .nbd-toast { display: none; }
  .nbd-s7 { display: block; opacity: 1; }
}

/* ══════════════════════════════════════════════════════════════════════════
   For partners (home) — BRIEF-SITE-PARTNERS; CLIENT, 29 Sep
   ══════════════════════════════════════════════════════════════════════════
   A tour of the partner app: tabs (Today · Crew · Money · Business · Alerts),
   the words for the chosen area, and the phone showing it. On a phone the
   order is heading, tabs, phone, words, so the picture sits between the tab
   and what it means. Without JavaScript the tabs stay hidden and the five
   panels read as one list. */
.partners-panel {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 22px 64px;
  grid-template-areas: "head demo" "tabs demo" "panels demo" "cta demo";
  grid-template-rows: auto auto auto 1fr; align-items: start;
  background: var(--card); border: 1px solid var(--line); border-radius: 28px;
  padding: 52px 56px;
}
.partners-head { grid-area: head; }
.partners-head h2 { margin-top: 18px; }
.partners-head h2 .dot { color: var(--zest); }
.partners-demo { grid-area: demo; align-self: center; display: flex; justify-content: center; }
.partners-tabs { grid-area: tabs; display: flex; gap: 8px; flex-wrap: wrap; }
.partners-tabs [role="tab"] {
  min-height: 40px; padding: 8px 16px; border-radius: 999px; cursor: pointer;
  border: 1.5px solid var(--line); background: var(--bg); color: var(--txt);
  font-family: var(--font-ui); font-size: 13.5px; font-weight: 700;
}
.partners-tabs [role="tab"]:hover { border-color: var(--txt2); }
.partners-tabs [role="tab"][aria-selected="true"] { background: var(--cta-bg); border-color: var(--cta-bg); color: var(--cta-txt); }
.partners-panels { grid-area: panels; display: grid; gap: 22px; }
/* The tour shows one panel at a time; the min-height keeps the call to
   action from jumping as a shorter panel replaces a longer one. */
.partners-panel.is-tour .partners-panels { min-height: 190px; align-content: start; }
.partners-tabpanel h3 { font-size: 20px; font-weight: 800; }
.partners-tabpanel ul { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 10px; }
.partners-tabpanel li { position: relative; padding-left: 26px; font-size: 15px; color: var(--txt2); max-width: 56ch; }
/* A zest tick, drawn as a 2-segment border rather than a glyph, so it cannot
   fall back to a different font's check mark. */
.partners-tabpanel li::before {
  content: ""; position: absolute; left: 3px; top: 5px; width: 7px; height: 12px;
  border: solid var(--zest-deep); border-width: 0 2.5px 2.5px 0; transform: rotate(40deg);
}
html[data-theme="dark"] .partners-tabpanel li::before { border-color: var(--zest); }
.partners-tabpanel:focus-visible { outline-offset: 6px; }
.partners-cta { grid-area: cta; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.partners-cta p { font-size: 13px; color: var(--txt2); }

@media (max-width: 860px) {
  .partners-panel {
    grid-template-columns: 1fr; grid-template-rows: none;
    grid-template-areas: "head" "tabs" "demo" "panels" "cta";
    padding: 28px 20px; gap: 22px; border-radius: 24px;
  }
  /* Five tabs across a 390 phone: 314px of panel, so tight pills; below
     360px they wrap to a second row rather than scroll out of sight. */
  .partners-tabs { gap: 4px; }
  .partners-tabs [role="tab"] { flex: 1 1 auto; min-height: 44px; padding: 8px 9px; font-size: 12px; }
  .partners-panel.is-tour .partners-panels { min-height: 0; }
  .partners-tabpanel li { font-size: 14px; }
  .partners-cta { flex-direction: column; align-items: stretch; text-align: center; }
  .partners-cta .btn-primary { min-height: 48px; }
}
/* Below 390 the five pills do not fit one row, and "Alerts" wrapped alone
   onto a full-width second row. Three over two, each row full width. */
@media (max-width: 389px) {
  .partners-tabs { display: grid; grid-template-columns: repeat(6, 1fr); }
  .partners-tabs [role="tab"] { grid-column: span 2; padding-inline: 6px; }
  .partners-tabs [role="tab"]:nth-last-child(-n + 2) { grid-column: span 3; }
}
/* The narrowest phones: the 290px device does not fit a 320 screen's panel,
   so it is drawn smaller. zoom, not transform, so the layout (and the
   cursor's measured targets, which live inside it) shrink with it. */
@media (max-width: 374px) {
  .partners-panel { padding: 24px 12px; }
  .pd-phone { zoom: .82; }
}
/* 861-1100: the two columns keep a readable text column beside the phone. */
@media (min-width: 861px) and (max-width: 1100px) {
  .partners-panel { padding: 40px 32px; gap: 22px 36px; }
}

/* ── The partner phone ──────────────────────────────────────────────────────
   The PARTNER side of the same app, in the app's own tokens (the --app-* set
   above, which .pd-phone joins), so it renders dark in the dark theme like
   the hero's mobile demo. Upright and still: the hero phone is the one that
   bobs. Sizes are the app's at about three quarters (290px for 390). */
.pd-phone {
  --app-info-bg: #EAF6FB; --app-info-tx: #247797; --app-info: #2D96BE;
  --app-ok-bg: #E9F6EF; --app-ok-tx: #257D4F; --app-ok: #2E9E63;
  --app-pill-bg: #F1EEE8; --app-scrim: rgba(28, 27, 38, .45);
  --app-lock: linear-gradient(170deg, #F4E7C8 0%, #F1D9A6 45%, #E9C98A 100%);
  --app-note: rgba(255, 255, 255, .72);
  width: 290px; flex: none; background: #1C1B26; border-radius: 42px; padding: 10px;
  box-shadow: 0 40px 70px var(--shadow);
}
html[data-theme="dark"] .pd-phone {
  --app-info-bg: #1D2A33; --app-info-tx: #5FB7DA; --app-info: #5FB7DA;
  --app-ok-bg: #15251C; --app-ok-tx: #3FBF7C; --app-ok: #3FBF7C;
  --app-pill-bg: #1F1E28; --app-scrim: rgba(0, 0, 0, .6);
  --app-lock: linear-gradient(170deg, #2A2537 0%, #1B1926 50%, #121118 100%);
  --app-note: rgba(44, 42, 56, .78);
  background: #000;
}
.pd-glass {
  position: relative; overflow: hidden; border-radius: 33px;
  background: var(--app-bg); color: var(--app-tx); text-align: start;
}
html[data-theme="dark"] .pd-glass::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: inset 0 0 0 1px var(--app-line); pointer-events: none; z-index: 9;
}
.pd-glass .phone-status { padding: 14px 20px 4px; }
.pd-strip {
  display: flex; align-items: center; gap: 7px; height: 34px; padding: 0 12px;
  background: var(--app-card); border-bottom: 1px solid var(--app-line);
}
.pd-avatar {
  width: 18px; height: 18px; border-radius: 50%; flex: none;
  display: grid; place-items: center; background: #FFC529; color: #1C1B26;
  font-family: var(--font-display); font-weight: 800; font-size: 8.5px;
}
.pd-strip-name {
  flex: 1; min-width: 0; font-size: 7.5px; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--app-tx2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pd-app { font-size: 9.5px; font-weight: 700; }

.pd { position: relative; height: 502px; overflow: hidden; }
/* One group per tab; the phone's data-tab (set by app.js) shows one. */
.pd-group { position: absolute; inset: 0; opacity: 0; visibility: hidden; transition: opacity .35s ease, visibility .35s; }
.pd-phone[data-tab="today"] .pd-g-today,
.pd-phone[data-tab="crew"] .pd-g-crew,
.pd-phone[data-tab="money"] .pd-g-money,
.pd-phone[data-tab="business"] .pd-g-business { opacity: 1; visibility: visible; }
.pd-screen { position: absolute; inset: 0 0 50px; padding: 12px 12px 0; background: var(--app-bg); opacity: 0; overflow: hidden; }
.pd-s1, .pd-k1, .pd-m1, .pd-b1 { opacity: 1; }
.pd-day { font-size: 9.5px; color: var(--app-tx2); display: flex; align-items: center; gap: 6px; }
.pd-title {
  font-family: var(--font-display); font-weight: 800; font-size: 21px;
  letter-spacing: -.02em; margin-top: 1px; white-space: nowrap; display: flex; align-items: center; gap: 6px;
}
.pd-title .dot { color: #FFC529; margin-left: -6px; }
.pd-count {
  display: inline-grid; font-family: var(--font-ui); font-size: 10.5px; font-weight: 600;
  letter-spacing: 0; color: var(--app-tx2); margin-top: 5px;
}
/* The two counts share one cell and cross-fade: "0 new" before the card
   lands, "1 new" once it has. */
.pd-count > span { grid-area: 1 / 1; }
.pd-c1 { opacity: 0; }
.pd-h { font-size: 12.5px; font-weight: 700; margin-top: 12px; }
.pd-h span { font-size: 9.5px; font-weight: 600; color: var(--app-tx2); }

.pd-card {
  position: relative; background: var(--app-card); border: 1px solid var(--app-line);
  border-radius: 15px; padding: 11px 12px;
}
.pd-new { margin-top: 10px; padding-left: 16px; box-shadow: 0 8px 22px rgba(28, 27, 38, .08); }
.pd-rail {
  position: absolute; left: 0; top: 13px; bottom: 13px; width: 3px; border-radius: 0 3px 3px 0;
  background: #FFC529; box-shadow: 0 0 8px rgba(255, 197, 41, .8);
}
.pd-eyebrow-row { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; }
.pd-kind { font-size: 7.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--app-zest-tx); }
.pd-age { font-size: 8.5px; font-weight: 700; color: var(--app-tx2); }
.pd-when {
  font-family: var(--font-display); font-weight: 800; font-size: 16px;
  letter-spacing: -.01em; margin-top: 4px; white-space: nowrap;
}
.pd-when span { font-family: var(--font-ui); font-size: 9.5px; font-weight: 600; color: var(--app-tx2); letter-spacing: 0; }
.pd-when.sm { font-size: 12.5px; margin-top: 0; }
.pd-abs { font-size: 9px; color: var(--app-tx2); margin-top: 1px; }
.pd-what { font-size: 9.5px; color: var(--app-tx2); margin-top: 2px; line-height: 1.45; }
.pd-pay { display: flex; justify-content: space-between; align-items: center; margin-top: 9px; font-size: 9.5px; color: var(--app-tx2); }
.pd-pay-fig { display: inline-flex; align-items: center; gap: 4px; font-size: 8.5px; font-weight: 600; }
/* MONEY: SAMPLE FIGURES, OR A BLANK. Every figure is content (demo.fig) and
   stays empty until tools/lint.mjs rule 2 admits clearly marked sample
   figures; an empty one draws as a neutral bar, the app's own skeleton
   shape. Filled, it reads as text, and the "Sample figures" tag appears. */
.pd-fig { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--app-tx); white-space: nowrap; }
.pd-fig:empty { display: inline-block; width: 30px; height: 7px; border-radius: 4px; background: var(--app-line2); vertical-align: middle; }
.pd-fig.big { font-family: var(--font-display); font-size: 19px; font-weight: 800; }
.pd-fig.big:empty { width: 50px; height: 15px; border-radius: 5px; }
.pd-fig.sm:empty { width: 22px; height: 6px; }
.pd-fig.lead { display: block; font-family: var(--font-display); font-size: 24px; font-weight: 800; margin-top: 4px; }
.pd-fig.lead:empty { width: 96px; height: 22px; border-radius: 6px; }
/* Below the strip, not in it: in the strip it covered the business name and
   "App ›". Right of each screen's first row, which is empty on every tab that
   carries a figure; Alerts carries none and its clock sits there, so it hides. */
.pd-sample {
  display: block; position: absolute; top: 86px; right: 12px; z-index: 8;
  font-size: 7.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  background: var(--app-pill-bg); color: var(--app-tx2); border: 1px solid var(--app-line2);
  border-radius: 999px; padding: 2px 7px;
}
/* Shown by default; hidden only while every figure is empty. A browser without
   :has() drops this rule and still shows the tag, never figures without it. */
.pd-phone:not(:has(.pd-fig:not(:empty))) .pd-sample { display: none; }
.pd-phone[data-tab="alerts"] .pd-sample { display: none; }
.pd-accept {
  display: flex; align-items: center; justify-content: center; min-height: 38px;
  margin-top: 10px; border-radius: 13px; background: var(--app-cta-bg); color: var(--app-cta-tx);
  font-size: 12px; font-weight: 800;
}
.pd-pass { text-align: center; font-size: 9px; font-weight: 600; color: var(--app-tx2); margin-top: 8px; }

.pd-stack { display: flex; flex-direction: column; gap: 7px; margin-top: 8px; }
.pd-job-head { display: flex; justify-content: space-between; align-items: center; gap: 6px; }
.pd-pill {
  flex: none; display: inline-block; font-family: var(--font-ui); font-size: 7px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; line-height: 1.4;
  border-radius: 999px; padding: 2px 7px; background: var(--app-pill-bg); color: var(--app-tx2);
  border: 1px solid var(--app-line2);
}
.pd-pill.moving { background: var(--app-info-bg); color: var(--app-info-tx); border-color: var(--app-info); }
.pd-pill.ok { background: var(--app-ok-bg); color: var(--app-ok-tx); border-color: var(--app-ok); }
.pd-addr, .pd-call { display: flex; align-items: center; gap: 5px; font-size: 9.5px; margin-top: 6px; }
.pd-addr svg, .pd-call svg { width: 11px; height: 11px; flex: none; }
.pd-call { font-weight: 700; color: var(--app-info-tx); }
.pd-advance {
  display: flex; align-items: center; justify-content: center; min-height: 36px; margin-top: 9px;
  border-radius: 12px; background: var(--app-cta-bg); color: var(--app-cta-tx); font-size: 11px; font-weight: 800;
}
.pd-quiet { text-align: center; font-size: 8.5px; font-weight: 600; color: var(--app-tx2); margin-top: 7px; }
.pd-row {
  display: flex; align-items: center; gap: 7px; background: var(--app-card);
  border: 1px solid var(--app-line); border-radius: 12px; padding: 9px 10px; font-size: 9.5px;
}
.pd-row-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--app-info); flex: none; }
.pd-row-t { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pd-row-v { font-weight: 700; color: var(--app-tx2); }

/* Crew: the assign sheet over the job, then the crew list. The sheet screen
   covers the tab bar, as a bottom sheet does. */
.pd-g-crew .pd-k1 { inset: 0; z-index: 3; }
.pd-scrim { position: absolute; inset: 0; background: var(--app-scrim); }
.pd-sheet {
  position: absolute; left: 0; right: 0; bottom: 0; background: var(--app-card);
  border-radius: 20px 20px 0 0; padding: 8px 14px 18px;
}
.pd-grip { display: block; width: 32px; height: 4px; border-radius: 4px; background: var(--app-line2); margin: 0 auto 10px; }
.pd-sheet-title { font-family: var(--font-display); font-size: 15px; font-weight: 800; }
.pd-sheet-meta { font-size: 9px; color: var(--app-tx2); margin-top: 2px; }
.pd-pick, .pd-crew { display: flex; align-items: center; gap: 8px; font-size: 9.5px; }
.pd-pick { margin-top: 8px; padding: 8px 9px; border: 1.5px solid var(--app-line); border-radius: 12px; }
.pd-ava {
  width: 22px; height: 22px; border-radius: 50%; flex: none; display: grid; place-items: center;
  background: var(--app-pill-bg); border: 1px solid var(--app-line2); font-size: 9px; font-weight: 800;
}
.pd-pick-t { flex: 1; min-width: 0; }
.pd-pick-t b { display: block; font-size: 10px; }
.pd-pick-t span { display: block; font-size: 8.5px; color: var(--app-tx2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pd-confirm {
  display: flex; align-items: center; justify-content: center; min-height: 36px; margin-top: 10px;
  border-radius: 12px; background: var(--app-cta-bg); color: var(--app-cta-tx); font-size: 11px; font-weight: 800;
}
.pd-list { padding: 2px 11px; margin-top: 8px; }
.pd-crew { padding: 8px 0; }
.pd-crew + .pd-crew, .pd-st + .pd-st, .pd-price + .pd-price { border-top: 1px solid var(--app-line); }
.pd-edit { font-size: 8.5px; font-weight: 700; color: var(--app-tx2); flex: none; }
.pd-add {
  display: flex; align-items: center; gap: 8px; margin-top: 8px; padding: 9px 11px; font-size: 9.5px;
  border: 1.5px dashed var(--app-line2); border-radius: 12px;
}
.pd-add > span:first-child { font-size: 14px; font-weight: 700; color: var(--app-zest-tx); }
.pd-add b { display: block; font-size: 10px; }
.pd-add em { display: block; font-style: normal; font-size: 8.5px; color: var(--app-tx2); }

/* Money: this week's statement; then it scrolls to past statements and ratings. */
.pd-m1 { padding: 0; }
.pd-scroll { padding: 12px 12px 16px; }
.pd-hero { margin-top: 8px; }
.pd-hero-l { font-size: 9.5px; font-weight: 700; color: var(--app-tx2); }
.pd-hero-s { font-size: 8.5px; color: var(--app-tx2); margin-top: 2px; }
.pd-split { display: flex; justify-content: space-between; align-items: center; gap: 8px; font-size: 9.5px; padding-top: 6px; margin-top: 6px; border-top: 1px solid var(--app-line); }
.pd-split span { color: var(--app-tx2); }
.pd-split.total { border-top-style: dashed; border-top-color: var(--app-line2); font-weight: 700; }
.pd-split.total span { color: var(--app-tx); }
.pd-table { padding: 4px 11px; margin-top: 8px; }
.pd-tr { display: grid; grid-template-columns: 1fr 50px 50px; align-items: center; gap: 6px; padding: 6px 0; font-size: 9.5px; }
.pd-tr + .pd-tr { border-top: 1px solid var(--app-line); }
.pd-tr.head { font-size: 7.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--app-tx3); }
.pd-tr > :not(:first-child) { justify-self: end; }
.pd-st, .pd-price { display: flex; align-items: center; gap: 8px; padding: 8px 0; font-size: 9.5px; }
.pd-st > span:first-child, .pd-price > span:first-child { flex: 1; min-width: 0; }
.pd-rate { margin-top: 8px; }
.pd-stars { color: #FFC529; font-size: 12px; letter-spacing: 1px; }
.pd-stars span { color: var(--app-tx2); font-size: 9px; letter-spacing: 0; margin-left: 4px; }
.pd-review { font-size: 9.5px; margin-top: 4px; }
.pd-review em { font-style: normal; color: var(--app-tx2); margin-left: 3px; }

/* Business: jobs a day, closed days, your prices. */
.pd-cap { display: flex; align-items: center; gap: 8px; margin-top: 8px; font-size: 10px; font-weight: 700; }
.pd-cap > span:first-child { flex: 1; }
.pd-step { display: inline-flex; align-items: center; border: 1px solid var(--app-line2); border-radius: 10px; overflow: hidden; }
.pd-step i { font-style: normal; width: 22px; text-align: center; color: var(--app-tx2); font-weight: 700; }
.pd-step b { min-width: 24px; text-align: center; border-inline: 1px solid var(--app-line2); padding: 3px 0; }
.pd-cap-u { font-size: 9px; font-weight: 600; color: var(--app-tx2); }
.pd-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.pd-chips span {
  font-size: 9px; font-weight: 600; padding: 5px 9px; border-radius: 999px;
  background: var(--app-card); border: 1px solid var(--app-line);
}
.pd-chips span.add { border-style: dashed; border-color: var(--app-line2); color: var(--app-tx2); }
.pd-suggest {
  display: flex; align-items: center; justify-content: center; min-height: 34px; margin-top: 10px;
  border-radius: 12px; border: 1.5px solid var(--app-line2); font-size: 10.5px; font-weight: 800;
}

.pd-tabs {
  position: absolute; left: 0; right: 0; bottom: 0; height: 50px; z-index: 2;
  display: flex; justify-content: space-around; padding: 7px 4px 0;
  background: var(--app-card); border-top: 1px solid var(--app-line);
}
.pd-tabs span {
  display: flex; flex-direction: column; align-items: center; gap: 2px; min-width: 48px;
  font-size: 7.5px; font-weight: 600; color: var(--app-tx2);
}
.pd-tabs svg { width: 16px; height: 16px; }
.pd-tabs b { width: 4px; height: 4px; border-radius: 50%; background: transparent; }
.pd-phone[data-tab="today"] .pd-tab-today,
.pd-phone[data-tab="money"] .pd-tab-money,
.pd-phone[data-tab="crew"] .pd-tab-business,
.pd-phone[data-tab="business"] .pd-tab-business { color: var(--app-tx); font-weight: 700; }
.pd-phone[data-tab="today"] .pd-tab-today b,
.pd-phone[data-tab="money"] .pd-tab-money b,
.pd-phone[data-tab="crew"] .pd-tab-business b,
.pd-phone[data-tab="business"] .pd-tab-business b { background: #FFC529; }

/* Alerts: the lock screen, over the whole glass. */
.pd-lock {
  position: absolute; inset: 0; z-index: 7; background: var(--app-lock); color: var(--app-tx);
  opacity: 0; visibility: hidden; transition: opacity .35s ease, visibility .35s; text-align: center;
}
.pd-phone[data-tab="alerts"] .pd-lock { opacity: 1; visibility: visible; }
.pd-lock-date { font-size: 11px; font-weight: 600; margin-top: 20px; color: var(--app-tx2); }
.pd-lock-time { font-family: var(--font-display); font-size: 64px; font-weight: 700; letter-spacing: -.03em; line-height: 1; margin-top: 2px; }
.pd-note-card {
  margin: 14px 10px 0; padding: 10px 12px; border-radius: 18px; text-align: start;
  background: var(--app-note); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 6px 18px rgba(28, 27, 38, .12); font-size: 10px;
}
.pd-note-card + .pd-note-card { margin-top: 8px; }
.pd-note-app { display: flex; align-items: center; gap: 6px; font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--app-tx2); }
.pd-note-app em { margin-left: auto; font-style: normal; font-weight: 600; text-transform: none; letter-spacing: 0; }
.pd-note-ico { width: 14px; height: 14px; border-radius: 4px; flex: none; }
/* The NoBrainer app's own icon, as the header draws it: the yellow tile and its tick. */
.pd-note-ico.app { overflow: hidden; }
.pd-note-ico.app svg { display: block; width: 100%; height: 100%; }
.pd-note-ico.mail { background: #2D96BE; }
/* Partner push is not built yet: the app notification wears a ghost SOON
   pill, the hero Card tile's shape a shade darker to read on the glass, where
   its time would be. The Mail card, which does go today, keeps "now". */
.pd-note-app em.pd-soon {
  font-size: 6.5px; font-weight: 800; letter-spacing: .06em; line-height: 1.4;
  padding: 1px 5px; border-radius: 999px; color: var(--app-tx2); border: 1px solid var(--app-line2);
}
.pd-note-card b { display: block; margin-top: 5px; font-size: 10.5px; }
.pd-note-card p { margin-top: 1px; line-height: 1.4; }

.pd-cursor {
  position: absolute; left: 0; top: 0; z-index: 6; width: 24px; height: 24px; border-radius: 50%;
  background: var(--app-cursor); border: 2.5px solid #FFC529;
  box-shadow: 0 8px 20px rgba(28, 27, 38, .35); opacity: 0;
}

/* ── The tour's timing ──────────────────────────────────────────────────────
   app.js holds each tab for its own time (Today 9.6s, Crew 7.2s, Money 6s,
   Business 6s, Alerts 5s) and moves on; each tab's animations run on that
   same span and restart when the tab comes round again. Without JavaScript
   the Today tab simply loops. */
.pd-phone[data-tab="today"] .pd-s1 { animation: pt-s1 9.6s linear infinite; }
.pd-phone[data-tab="today"] .pd-s2 { animation: pt-s2 9.6s linear infinite; }
.pd-phone[data-tab="today"] .pd-s3 { animation: pt-s3 9.6s linear infinite; }
.pd-phone[data-tab="today"] .pd-new { animation: pt-new 9.6s cubic-bezier(.2, .8, .2, 1) infinite; }
.pd-phone[data-tab="today"] .pd-c0 { animation: pt-c0 9.6s linear infinite; }
.pd-phone[data-tab="today"] .pd-c1 { animation: pt-c1 9.6s linear infinite; }
.pd-phone[data-tab="today"] .pd-s1 .pd-accept { animation: pt-press-accept 9.6s linear infinite; }
.pd-phone[data-tab="today"] .pd-s2 .pd-advance { animation: pt-press-advance 9.6s linear infinite; }
.pd-phone[data-tab="today"] .pd-cursor { animation: pt-cur-today 9.6s cubic-bezier(.4, 0, .2, 1) infinite; }
.pd-phone[data-tab="crew"] .pd-k1 { animation: pt-crew1 7.2s linear infinite; }
.pd-phone[data-tab="crew"] .pd-k2 { animation: pt-crew2 7.2s linear infinite; }
.pd-phone[data-tab="crew"] .pd-scrim { animation: pt-scrim 7.2s linear infinite; }
.pd-phone[data-tab="crew"] .pd-sheet { animation: pt-sheet 7.2s cubic-bezier(.2, .8, .2, 1) infinite; }
.pd-phone[data-tab="crew"] .pd-pick-sam { animation: pt-sam 7.2s linear infinite; }
.pd-phone[data-tab="crew"] .pd-confirm { animation: pt-confirm 7.2s linear infinite; }
.pd-phone[data-tab="crew"] .pd-cursor { animation: pt-cur-crew 7.2s cubic-bezier(.4, 0, .2, 1) infinite; }
.pd-phone[data-tab="money"] .pd-scroll { animation: pt-scroll 6s cubic-bezier(.4, 0, .2, 1) infinite; }
.pd-phone[data-tab="business"] .pd-suggest { animation: pt-press-suggest 6s linear infinite; }
.pd-phone[data-tab="business"] .pd-cursor { animation: pt-cur-business 6s cubic-bezier(.4, 0, .2, 1) infinite; }
.pd-phone[data-tab="alerts"] .pd-n1 { animation: pt-n1 5s cubic-bezier(.2, .8, .2, 1) infinite; }
.pd-phone[data-tab="alerts"] .pd-n2 { animation: pt-n2 5s cubic-bezier(.2, .8, .2, 1) infinite; }

@keyframes pt-s1 { 0%,30% { opacity: 1 } 34%,95% { opacity: 0 } 98%,100% { opacity: 1 } }
@keyframes pt-s2 { 0%,30% { opacity: 0; transform: translateY(12px) } 34%,64% { opacity: 1; transform: none } 68%,100% { opacity: 0; transform: none } }
@keyframes pt-s3 { 0%,64% { opacity: 0 } 68%,95% { opacity: 1 } 98%,100% { opacity: 0 } }
@keyframes pt-new { 0%,4% { opacity: 0; transform: translateY(-14px) } 10%,94% { opacity: 1; transform: none } 95%,100% { opacity: 0; transform: translateY(-14px) } }
@keyframes pt-c0 { 0%,7% { opacity: 1 } 9%,94% { opacity: 0 } 95%,100% { opacity: 1 } }
@keyframes pt-c1 { 0%,7% { opacity: 0 } 9%,94% { opacity: 1 } 95%,100% { opacity: 0 } }
@keyframes pt-press-accept { 0%,23.6% { transform: none } 24% { transform: scale(.96) } 25.5%,100% { transform: none } }
@keyframes pt-press-advance { 0%,54.6% { transform: none } 55% { transform: scale(.96) } 56.5%,100% { transform: none } }
@keyframes pt-crew1 { 0%,55% { opacity: 1 } 59%,96% { opacity: 0 } 99%,100% { opacity: 1 } }
@keyframes pt-crew2 { 0%,55% { opacity: 0; transform: translateY(12px) } 59%,96% { opacity: 1; transform: none } 99%,100% { opacity: 0; transform: none } }
@keyframes pt-scrim { 0%,2% { opacity: 0 } 8%,100% { opacity: 1 } }
@keyframes pt-sheet { 0%,2% { transform: translateY(100%) } 10%,100% { transform: none } }
@keyframes pt-sam { 0%,22.9% { border-color: var(--app-line); box-shadow: none } 23%,100% { border-color: #FFC529; box-shadow: 0 0 14px rgba(255, 197, 41, .25) } }
@keyframes pt-confirm { 0%,22.9% { opacity: .45 } 23%,39.6% { opacity: 1; transform: none } 40% { opacity: 1; transform: scale(.96) } 41.5%,100% { opacity: 1; transform: none } }
@keyframes pt-scroll { 0%,38% { transform: none } 60%,100% { transform: translateY(-212px) } }
@keyframes pt-press-suggest { 0%,51.6% { transform: none } 52% { transform: scale(.96) } 53.5%,100% { transform: none } }
@keyframes pt-n1 { 0%,8% { opacity: 0; transform: translateY(-12px) } 16%,100% { opacity: 1; transform: none } }
@keyframes pt-n2 { 0%,38% { opacity: 0; transform: translateY(-12px) } 46%,100% { opacity: 1; transform: none } }
/* The cursor's targets are MEASURED into these variables by app.js, as the
   hero's are: Accept, Mark picked up, the crew member, Assign, Suggest. */
@keyframes pt-cur-today {
  0%,10%    { transform: translate(var(--p0x, 190px), var(--p0y, 430px)) scale(1); opacity: 0 }
  15%,22%   { transform: translate(var(--p1x, 120px), var(--p1y, 250px)) scale(1); opacity: 1 }
  24%       { transform: translate(var(--p1x, 120px), var(--p1y, 250px)) scale(.78); opacity: 1 }
  25.5%,27% { transform: translate(var(--p1x, 120px), var(--p1y, 250px)) scale(1); opacity: 1 }
  30%       { transform: translate(var(--p1x, 120px), var(--p1y, 250px)) scale(1); opacity: 0 }
  36%       { transform: translate(var(--p2x, 120px), calc(var(--p2y, 280px) + 60px)) scale(1); opacity: 0 }
  44%,53%   { transform: translate(var(--p2x, 120px), var(--p2y, 280px)) scale(1); opacity: 1 }
  55%       { transform: translate(var(--p2x, 120px), var(--p2y, 280px)) scale(.78); opacity: 1 }
  56.5%,58% { transform: translate(var(--p2x, 120px), var(--p2y, 280px)) scale(1); opacity: 1 }
  62%,100%  { transform: translate(var(--p2x, 120px), var(--p2y, 280px)) scale(1); opacity: 0 }
}
@keyframes pt-cur-crew {
  0%,8%     { transform: translate(var(--p0x, 190px), var(--p0y, 430px)) scale(1); opacity: 0 }
  14%,20.5% { transform: translate(var(--p4x, 120px), var(--p4y, 300px)) scale(1); opacity: 1 }
  22%       { transform: translate(var(--p4x, 120px), var(--p4y, 300px)) scale(.78); opacity: 1 }
  23.5%,26% { transform: translate(var(--p4x, 120px), var(--p4y, 300px)) scale(1); opacity: 1 }
  33%,38%   { transform: translate(var(--p5x, 120px), var(--p5y, 440px)) scale(1); opacity: 1 }
  40%       { transform: translate(var(--p5x, 120px), var(--p5y, 440px)) scale(.78); opacity: 1 }
  41.5%,43% { transform: translate(var(--p5x, 120px), var(--p5y, 440px)) scale(1); opacity: 1 }
  47%,100%  { transform: translate(var(--p5x, 120px), var(--p5y, 440px)) scale(1); opacity: 0 }
}
@keyframes pt-cur-business {
  0%,20%    { transform: translate(var(--p0x, 190px), var(--p0y, 430px)) scale(1); opacity: 0 }
  32%,49%   { transform: translate(var(--p6x, 120px), var(--p6y, 380px)) scale(1); opacity: 1 }
  52%       { transform: translate(var(--p6x, 120px), var(--p6y, 380px)) scale(.78); opacity: 1 }
  53.5%,56% { transform: translate(var(--p6x, 120px), var(--p6y, 380px)) scale(1); opacity: 1 }
  62%,100%  { transform: translate(var(--p6x, 120px), var(--p6y, 380px)) scale(1); opacity: 0 }
}

/* Off-viewport, app.js pauses the tour and its animations, as the hero's. */
.pd-phone.paused, .pd-phone.paused * { animation-play-state: paused !important; }

/* prefers-reduced-motion: no auto-advance (app.js) and no animation — one
   still per tab, chosen to show the most of that area: the job in hand, the
   assign sheet with its choice made, the statement, the business settings,
   and both alerts. A tour that changes on its own is still motion. */
@media (prefers-reduced-motion: reduce) {
  /* Everything animated in the partner tour, listed so a new moving part
     cannot be added without deciding what it does here. */
  .pd-screen, .pd-new, .pd-c0, .pd-c1, .pd-accept, .pd-advance, .pd-cursor, .pd-scrim, .pd-sheet,
  .pd-pick-sam, .pd-confirm, .pd-scroll, .pd-suggest, .pd-n1, .pd-n2 { animation: none !important; }
  .pd-group, .pd-lock { transition: none; }
  .pd-s1, .pd-s3, .pd-k2, .pd-cursor { display: none; }
  .pd-s2 { opacity: 1; }
  .pd-pick-sam { border-color: #FFC529; }
}

/* ══════════════════════════════════════════════════════════════════════════
   v6 inner pages — boards 6a service / 6b about+FAQ / 6c contact / 6d legal
   ══════════════════════════════════════════════════════════════════════════
   Logical properties throughout (inline-start/-end), because Arabic RTL is a
   priced option the structure has to be ready for even though it is not built.
   Every interactive element carries the full state set — hover, focus-visible,
   active, disabled — since the inner pages introduce the site's first real
   forms and a keyboard user meeting an unstyled focus ring is a bug. */

/* Block padding only: the gutter comes from .shell. */
.page-hero { padding-block: 56px 24px; }
/* The floor follows the viewport below 334px (10.2vw): at 34px "Not your
   problem." needed 326px of screen and broke onto a third line at 320-325. */
.page-hero h1 { font-size: clamp(min(34px, 10.2vw), 7vw, 54px); line-height: 1.03; letter-spacing: -.02em; margin-block: 18px 0; }
/* The brand full stop, as on the homepage. */
.page-hero h1 .dot, .section-title .dot, .legal-body h1 .dot { color: var(--zest); }
/* The lede is the secondary voice under the headline, not body ink. */
.page-hero .lede { max-width: 58ch; margin-block-start: 16px; color: var(--txt2); font-size: 17px; line-height: 1.6; }
.lede-tail { margin-block-start: 14px; }
/* .section .section-title, not .section-title: .section h2 (44px, 30px on
   phones) outranked the bare class, so this clamp never applied. */
.section .section-title { font-size: clamp(26px, 4vw, 40px); line-height: 1.1; margin-block-end: 22px; }
.page-cta { display: flex; flex-wrap: wrap; gap: 12px; margin-block-start: 26px; }
/* The pair is one size: the primary was 13.5px in an 11x18 box beside a 15px
   ghost in 15x22. The border matches the ghost's 1px. */
.page-cta .btn-primary { font-size: 15px; padding: 15px 22px; border-radius: 16px; border: 1px solid var(--cta-bg); }

.btn-ghost {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 15px 22px; border-radius: 16px;
  border: 1px solid var(--line); background: var(--card); color: var(--txt);
  font-weight: 700; font-size: 15px; text-decoration: none;
  transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.btn-ghost:hover { border-color: var(--txt2); transform: translateY(-1px); }
.btn-ghost:active { transform: translateY(0); }

/* ── 6a: pricing honesty. Numbers are the STEP index, never a price. ─────── */
.price-steps { list-style: none; display: grid; gap: 14px; padding: 0; margin: 0; }
.price-step {
  display: flex; gap: 16px; align-items: flex-start;
  background: var(--card); border: 1px solid var(--line);
  border-radius: 20px; padding: 20px 22px;
}
.price-num {
  flex: 0 0 auto; inline-size: 30px; block-size: 30px; border-radius: 999px;
  display: grid; place-items: center;
  background: var(--cta-bg); color: var(--cta-txt);
  font-weight: 800; font-size: 13px; font-variant-numeric: tabular-nums;
}
.price-step h3 { font-size: 17px; font-weight: 700; margin: 0 0 4px; }
.price-step p { margin: 0; color: var(--txt2); font-size: 15px; }
/* Three across on a desktop, the number above the text; one column, the
   number beside it, on a phone. As one column they were 1344px bars. */
@media (min-width: 861px) {
  .price-steps { grid-template-columns: repeat(3, 1fr); }
  .price-step { flex-direction: column; gap: 14px; padding: 24px; }
}

/* Four cards: 1, then 2 + 2, then 4 in a row. auto-fit left one alone at
   754-1057px. */
.svc-grid {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: 14px; grid-template-columns: 1fr;
}
@media (min-width: 560px) { .svc-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .svc-grid { grid-template-columns: repeat(4, 1fr); } }
.svc-card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: 20px; padding: 22px;
  transition: border-color .18s ease, transform .18s ease;
}
.svc-card:hover { border-color: var(--txt2); transform: translateY(-2px); }
.svc-icon { font-size: 26px; line-height: 1; display: block; margin-block-end: 12px; font-family: var(--font-emoji); }
.svc-card h3 { font-size: 17px; font-weight: 700; margin: 0 0 6px; }
.svc-card p { margin: 0; color: var(--txt2); font-size: 14.5px; }
.rate-note { margin-block-start: 18px; color: var(--txt2); font-size: 13.5px; max-width: 62ch; }

/* ── Services: /services and every service page, generated per service ────
   One card (build.mjs serviceCard) serves the index and each page's row of
   the others: an open service links to its page, the whole card being the
   hit area; a coming one has a SOON pill and no link. Each card takes its
   service's tint and accent from data (--card-tint, --card-acc). Titles stay
   in the text colour: an accent on its own tint is under 3:1. */
.crumbs { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; color: var(--txt2); margin-block-end: 14px; }
.crumbs a { position: relative; color: var(--txt2); text-decoration: none; box-shadow: inset 0 -1.5px 0 var(--line); }
/* A 44px tap target round the 20px link, without moving the line it sits on. */
.crumbs a::before { content: ""; position: absolute; inset: -12px -6px; }
.crumbs a:hover { color: var(--txt); }
.crumbs [aria-current] { color: var(--txt); }

.svc-hero { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(280px, .75fr); gap: 40px; align-items: center; }
.svc-facts { background: var(--card-tint); border: 1px solid var(--line); border-radius: 24px; padding: 24px; }
.svc-facts-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; margin-block-end: 14px; }
/* No min-width: 0. The longest word is the name's minimum, so when the name
   and the nowrap pill do not fit one row, the pill wraps to its own; with
   min-width: 0 the name shrank under the pill and the two painted over each other. */
.svc-facts-name { flex: 1 1 auto; font-family: var(--font-display); font-weight: 800; font-size: 22px; }
.svc-facts-pill {
  font-size: 9.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  background: #1C1B26; color: #FAF7F2; padding: 4px 9px; border-radius: 999px; white-space: nowrap;
}
.svc-facts dl { margin: 0; }
.svc-facts dl > div { display: grid; grid-template-columns: 60px 1fr; gap: 12px; padding: 12px 0; border-block-start: 1px solid var(--line); }
.svc-facts dt { font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--txt2); padding-block-start: 2px; }
/* balance: a value runs one to three lines, and without it "soon" or "live"
   sat alone on the last one. The card body below gets it too: in Chromium,
   text-wrap: pretty still left "adorable." alone there. */
.svc-facts dd { margin: 0; font-size: 14.5px; font-weight: 600; text-wrap: balance; }

/* Columns by card count, for ANY count, so no card is left alone in a row (the
   cards come from services.json): one column on a phone; from 560px, two
   across when the count is even; from 700px, three across, the last row's
   cards widened to fill it (4: 2 + 2, 5: 3 + 2, 7: 3 + 2 + 2); from 1100px,
   four across when the count is a multiple of four. On 12 tracks each is a span. */
.svc-index {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: 14px; grid-template-columns: repeat(12, minmax(0, 1fr));
}
.svc-index > li { grid-column: span 12; }
@media (min-width: 560px) and (max-width: 699px) {
  .svc-index:has(> li:first-child:nth-last-child(2n)) > li { grid-column: span 6; }
}
@media (min-width: 700px) {
  .svc-index > li { grid-column: span 4; }
  .svc-index:has(> li:first-child:nth-last-child(3n+4)) > li:nth-last-child(-n+4),
  .svc-index:has(> li:first-child:nth-last-child(3n+2)) > li:nth-last-child(-n+2) { grid-column: span 6; }
  .svc-index > li:only-child { grid-column: span 12; }
}
/* :nth-child(n) matches every card; it only lifts this rule over the 3n+4 one. */
@media (min-width: 1100px) {
  .svc-index:has(> li:first-child:nth-last-child(4n)) > li:nth-child(n) { grid-column: span 3; }
}
.svc-index-card {
  position: relative; display: flex; flex-direction: column;
  background: var(--card-tint); border: 1px solid var(--line); border-radius: 24px; padding: 26px;
  transition: transform .18s ease, border-color .18s ease;
}
.svc-index-card:not(.is-coming):hover { transform: translateY(-2px); border-color: var(--txt2); }
.svc-index-icon {
  inline-size: 48px; block-size: 48px; border-radius: 16px; flex: none;
  display: grid; place-items: center; font-size: 25px; line-height: 1; font-family: var(--font-emoji);
  background: var(--card); border: 1.5px solid var(--card-acc);
}
.svc-index-card h3 { font-family: var(--font-display); font-weight: 800; font-size: 22px; margin: 18px 0 4px; }
.svc-index-where { margin: 0; font-size: 12.5px; font-weight: 700; color: var(--txt); }
.svc-index-body { margin: 10px 0 0; font-size: 14.5px; color: var(--txt2); text-wrap: balance; }
.svc-index-link {
  margin-block-start: auto; padding-block-start: 18px;
  font-size: 14px; font-weight: 700; color: var(--txt); text-decoration: underline; text-underline-offset: 3px;
}
.svc-index-link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.svc-index-link:focus-visible { outline: none; }
.svc-index-card:has(.svc-index-link:focus-visible) { outline: 2px solid #FFC529; outline-offset: 3px; }
.svc-index-card .soon {
  position: absolute; inset-block-start: 16px; inset-inline-end: 16px;
  font-size: 9px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  background: #1C1B26; color: #FAF7F2; padding: 4px 9px; border-radius: 999px;
}
/* After the rules it overrides, not in the phone block near the top: that block
   comes earlier in the file, so the desktop .page-hero padding beat it. */
@media (max-width: 860px) {
  .page-hero { padding-block: 36px 8px; }
  .svc-hero { grid-template-columns: 1fr; gap: 24px; }
}

/* Three cards: one column, then three across from 700px. auto-fit left the
   third alone at 550-813 and 861-873. */
.principles {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: 14px; grid-template-columns: 1fr;
}
@media (min-width: 700px) { .principles { grid-template-columns: repeat(3, 1fr); } }
.principle { background: var(--card); border: 1px solid var(--line); border-radius: 20px; padding: 22px; }
.principle-icon { font-size: 22px; display: block; margin-block-end: 10px; font-family: var(--font-emoji); }
.principle h3 { font-size: 16px; font-weight: 700; margin: 0 0 6px; }
.principle p { margin: 0; color: var(--txt2); font-size: 14.5px; }

/* ── 6b: the model card is the argument the business rests on ───────────── */
.model-card {
  background: var(--tint-l); border-radius: 24px; padding: 30px;
  border: 1px solid var(--line);
}
.model-card h2 { font-size: clamp(22px, 3.4vw, 30px); margin: 10px 0 12px; line-height: 1.12; }
.model-card p { margin: 0; color: var(--txt2); max-width: 62ch; }

/* ── 6b: FAQ. A question with no answer yet is DISABLED, not an empty panel. */
.faq { list-style: none; padding: 0; margin: 0; border-block-start: 1px solid var(--line); }
.faq-item { border-block-end: 1px solid var(--line); }
.faq-item h3 { margin: 0; font-size: inherit; font-weight: inherit; }
.faq-q {
  inline-size: 100%; display: flex; align-items: center; justify-content: space-between; gap: 16px;
  background: none; border: 0; cursor: pointer; text-align: start;
  padding: 20px 4px; color: var(--txt);
  font-family: inherit; font-size: 17px; font-weight: 700;
  transition: color .18s ease;
}
.faq-q:hover { color: var(--zest-deep, #8A6400); }
html[data-theme="dark"] .faq-q:hover { color: var(--zest); }
.faq-mark { font-size: 20px; color: var(--txt2); flex: 0 0 auto; }
.faq-a { padding: 0 4px 22px; color: var(--txt2); max-width: 68ch; }
.faq-a p { margin: 0; }
/* A link in an answer looks like one: ink, bold, on the zest bar. */
.faq-a a { color: var(--txt); font-weight: 700; box-shadow: inset 0 -2px 0 var(--zest); }
.faq-item.is-pending .faq-q { opacity: .45; cursor: not-allowed; }
.faq-item.is-pending .faq-q:hover { color: var(--txt); }

/* ── 6c: WhatsApp first. It is the fastest channel, so it leads. ─────────── */
.reach { display: grid; gap: 14px; margin-block-end: 18px; }
.reach-wa, .reach-mail {
  display: flex; align-items: center; gap: 16px;
  border-radius: 20px; padding: 20px 22px; text-decoration: none;
  border: 1px solid var(--line); background: var(--card); color: var(--txt);
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.reach-wa { background: #2E9E63; border-color: #2E9E63; color: #fff; }
.reach-wa:hover, .reach-mail:hover { transform: translateY(-2px); }
.reach-mail:hover { border-color: var(--txt2); }
.reach-icon { font-size: 24px; flex: 0 0 auto; font-family: var(--font-emoji); }
.reach-text { display: grid; gap: 3px; }
.reach-text strong { font-size: 17px; font-weight: 800; }
.reach-text span { font-size: 13.5px; opacity: .85; text-wrap: pretty; }
.reach-mail .reach-text span { color: var(--txt2); opacity: 1; }
.reach-arrow { margin-inline-start: auto; font-size: 20px; }

.partner-card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: 24px; padding: 28px;
}
.partner-card h2 { font-size: clamp(21px, 3.2vw, 28px); margin: 8px 0 10px; }
.partner-card p { margin: 0; color: var(--txt2); max-width: 60ch; }

/* ── 6c: the lead form. Topic chips are what route the enquiry. ──────────── */
.lead-form { display: grid; gap: 16px; max-width: 560px; }
.topics { display: flex; flex-wrap: wrap; gap: 8px; border: 0; padding: 0; margin: 0 0 4px; }
.topic-chip { position: relative; }
.topic-chip input {
  position: absolute; opacity: 0; inline-size: 100%; block-size: 100%;
  margin: 0; cursor: pointer;
}
.topic-chip span {
  display: inline-block; padding: 9px 15px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card); color: var(--txt2);
  font-size: 13.5px; font-weight: 700; transition: all .16s ease;
}
.topic-chip input:checked + span {
  background: var(--cta-bg); color: var(--cta-txt); border-color: var(--cta-bg);
}
.topic-chip input:focus-visible + span { outline: 2px solid #FFC529; outline-offset: 2px; }
.topic-chip:hover span { border-color: var(--txt2); }

.field { display: grid; gap: 6px; }
.field label { font-size: 13px; font-weight: 800; letter-spacing: .02em; }
.field .hint { font-weight: 500; color: var(--txt2); letter-spacing: 0; }
.field input, .field textarea {
  font-family: inherit; font-size: 15px; color: var(--txt);
  background: var(--card); border: 1px solid var(--line);
  border-radius: 14px; padding: 13px 15px;
  transition: border-color .16s ease, box-shadow .16s ease;
}
.field textarea { resize: vertical; min-block-size: 96px; }
.field input::placeholder, .field textarea::placeholder { color: var(--txt2); opacity: 1; }
.field input:hover, .field textarea:hover { border-color: var(--txt2); }
.field input:focus-visible, .field textarea:focus-visible {
  outline: none; border-color: #FFC529; box-shadow: 0 0 0 3px rgba(255, 197, 41, .28);
}
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"] { border-color: #D6455D; }
.lead-privacy { font-size: 13px; color: var(--txt2); margin: 0; }
.lead-note { margin-block-start: 14px; font-weight: 700; min-block-size: 1.4em; }
.lead-form button[disabled] { opacity: .45; cursor: not-allowed; }

/* ── 6d: one legal template, two documents ──────────────────────────────── */
.legal-wrap { display: grid; gap: 34px; padding-block: 46px 30px; }
.legal-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-block-end: 20px; }
.legal-tab {
  padding: 9px 13px; border-radius: 999px; text-decoration: none;
  border: 1px solid var(--line); background: var(--card); color: var(--txt2);
  font-size: 13.5px; font-weight: 700; transition: all .16s ease;
}
.legal-tab:hover { border-color: var(--txt2); }
.legal-tab.is-current { background: var(--cta-bg); color: var(--cta-txt); border-color: var(--cta-bg); }
.legal-rail ol { list-style: none; padding: 0; margin: 0; display: grid; gap: 2px; }
.legal-rail a {
  display: block; padding: 8px 12px; border-radius: 10px;
  color: var(--txt2); text-decoration: none; font-size: 13.5px;
  border-inline-start: 2px solid var(--line);
  transition: color .16s ease, border-color .16s ease, background .16s ease;
}
.legal-rail a:hover { color: var(--txt); border-inline-start-color: #FFC529; background: var(--card); }
.legal-body { max-width: 68ch; }
.legal-meta { color: var(--txt2); font-size: 13.5px; margin-block: 8px 22px; }
.legal-draft {
  display: inline-block; padding: 3px 9px; border-radius: 999px;
  background: var(--pillbg); color: var(--txt2);
  font-size: 10.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
}
.legal-summary {
  background: rgba(255, 197, 41, .14); border: 1px solid rgba(255, 197, 41, .4);
  border-radius: 18px; padding: 18px 20px; margin-block-end: 30px;
}
.summary-label {
  display: block; font-size: 10.5px; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; color: var(--num);
  margin-block-end: 6px;
}
.legal-summary p { margin: 0; font-size: 15px; }
.legal-section { margin-block-end: 26px; }
.legal-section h2 { font-size: 18px; font-weight: 800; margin: 0 0 8px; }
.legal-section p { margin: 0; color: var(--txt2); font-size: 15px; line-height: 1.65; }
.legal-section p + p { margin-block-start: 10px; }
/* Italic marks it as a placeholder; opacity took it under 4.5:1. */
.legal-todo { font-style: italic; }

/* 861, not 860: every other layout switch happens at 861, and at exactly
   860 this grid opened under the phone header. 264px holds the first two
   document tabs on one row. */
@media (min-width: 861px) {
  .legal-wrap { grid-template-columns: 264px 1fr; align-items: start; }
  .legal-side { position: sticky; inset-block-start: 90px; }
  .reach { grid-template-columns: 1fr 1fr; }
}

/* A short page (the 404) still ends at the bottom of the window. */
body { min-height: 100svh; display: flex; flex-direction: column; }
main { flex: 1 0 auto; }

/* Below about 1350 the sticker sat over the phone's signal bars. Up to 1220
   there is no room to move it (above, the hero clips it; to the right, the
   window would), so it steps aside, as it does on a phone; from 1221 a 32px
   nudge right clears the bars. */
@media (min-width: 861px) and (max-width: 1220px) {
  .phone-sticker { display: none; }
}
@media (min-width: 1221px) and (max-width: 1360px) {
  .phone-sticker { right: -4px; }
}
