/* ============================================================
   APPS PAGES — shared styles for the /apps/ clusters
   (renamed from splitr.css 2026-08: it was always the stylesheet
   for every app page, not just the bill splitter's. Apps renamed
   2026-08-13: Splitr -> Fairsies, Meridian -> Solander.)
   ------------------------------------------------------------
   Companion to styles.css (loaded after it). Covers:
     1. Apps hub (/apps/)
     2. Fairsies marketing page (/apps/fairsies/)
     3. Fairsies support page (/apps/fairsies/support/)
     4. Fairsies legal pages (/apps/fairsies/privacy/, /apps/fairsies/terms/)
     5. The CSS iPhone (bezel, status bar) shared by the hero
        walkthrough and the four static "How it works" screens
     6. The four in-app screen recreations (.as-*), verified
        against the Fairsies Xcode project (Theme.swift + Features/)
        on 2026-08-11.

   Marketing palette = site tokens (styles.css :root).
   In-app palette   = the app's own Theme.swift values, scoped
   below as --as-* custom properties. Do not swap one for the
   other — the phone screens deliberately look like the app,
   not like the website.
   ============================================================ */

/* ------------------------------------------------------------
   0. Shared bits for all Fairsies pages
   ------------------------------------------------------------ */

/* Section labels come straight from styles.css (.section-label).
   AUDIT 2026-08: the old .sp-eyebrow duplicated it property-for-
   property, so it's gone. Only the dark-band colour shift lives
   here, mirroring .principles .section-label on the homepage. */
.sp-dark .section-label { color: var(--color-sage-glow); }

/* Measure caps for section headers (were inline styles) */
.sp-measure { max-width: 820px; }
/* .sp-measure-narrow removed 2026-08-12 — its only user was the
   Fairsies "Help & legal" header, now a grid column (.sp-help-copy). */

/* Numbered points (privacy band, "why we make our own") */
.sp-num {
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.15em;
  color: var(--color-coral);
  margin-bottom: 1rem;
}
.sp-dark .sp-num { color: var(--color-coral-bright); }

/* App cluster bar — a slim tonal band above the global footer on all
   four pages of one app (overview, support, privacy, licence). The
   global footer stays app-agnostic; this bar is where app-scoped
   navigation lives. aria-current marks the page you are on. */
.sp-cluster {
  padding: 1rem 0;
  background: var(--color-bg-mint);
}
.sp-cluster-inner {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.6rem 2rem;
}
.sp-cluster-name {
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--color-text);
}
.sp-cluster-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.75rem;
}
/* padding-block, not line-height: these are standalone nav links, so
   the 22px text box was the whole tap target. 0.6rem each side takes
   it to ~42px; the band's own padding came down to 1rem to keep the
   overall height where it was. */
.sp-cluster-links a {
  display: inline-block;
  padding-block: 0.6rem;
  font-size: 0.85rem;
  font-weight: 300;
  color: var(--color-text-muted);
  transition: color var(--transition);
}
.sp-cluster-links a:hover { color: var(--color-accent); }
.sp-cluster-links a[aria-current] { color: var(--color-text); font-weight: 500; }

/* Dark band base (privacy band, apps "why" band) */
.sp-dark {
  padding: var(--space-3xl) 0;
  background: var(--color-dark-section);
}
.sp-dark .section-title { color: var(--color-mint-pale); }
.sp-dark .section-intro { color: rgba(246, 250, 254, 0.75); }
/* REDESIGN 2026-08-12: was repeat(auto-fit, minmax(280px, 1fr)), which
   dropped to two columns at about 1090px and left the third card
   stranded on a row of its own with dead space beside it — the exact
   thing the .sp-steps note below calls out. It now holds three across
   until they genuinely stop fitting (~900px) and then becomes the
   standard swipe carousel, like every other card row on the site. */
.sp-dark-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 3.5rem 4rem;
  align-items: start;
}
@media (max-width: 1180px) {
  .sp-dark-grid { gap: 3rem 2.5rem; }
}
@media (max-width: 900px) {
  .sp-dark-grid {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    gap: var(--space-lg);
    padding-bottom: var(--space-xs);
  }
  .sp-dark-grid::-webkit-scrollbar { display: none; }
  .sp-dark-grid > div { flex: 0 0 85%; scroll-snap-align: center; }
  /* The shared dots live behind a 640px query in styles.css; this row
     now carousels above that, so its dot styling is repeated here for
     its full active range (same pattern as .sp-steps). */
  .scroll-dots[data-for="sp-dark-grid"] {
    display: flex;
    justify-content: center;
    gap: 0;
    padding-top: 0;
  }
  .scroll-dots[data-for="sp-dark-grid"] .scroll-dot {
    width: 24px;
    height: 40px;
    display: grid;
    place-items: center;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .scroll-dots[data-for="sp-dark-grid"] .scroll-dot::before {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(246, 250, 254, 0.28);
    transition: background 0.25s, transform 0.25s;
  }
  .scroll-dots[data-for="sp-dark-grid"] .scroll-dot.is-active::before {
    background: var(--color-sage-glow);
    transform: scale(1.25);
  }
}
.sp-dark-grid h3 {
  font-size: 1.35rem;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--color-mint-pale);
  margin-bottom: 0.75rem;
}
.sp-dark-grid p {
  font-size: 0.98rem;
  font-weight: 300;
  line-height: 1.75;
  color: rgba(246, 250, 254, 0.75);
  text-wrap: pretty;
}

/* Gradient run-in for a phrase inside an otherwise solid headline.
   The site rations the coral→teal gradient (see styles.css); the
   2026-08 apps redesign spends it on the last phrase of each H1
   rather than the whole line. */
.sp-grad {
  background: linear-gradient(to right, var(--color-grad-warm) 0%, var(--color-grad-cool) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* Pre-release marker: apps hub card + Fairsies hero brand row. Remove
   both at launch (each carries a LAUNCH STATE comment in its page). */
.sp-app-badge {
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-coral);
  white-space: nowrap;
}
/* Hairline dot between meta items. Deliberately lighter than
   --color-text-dim so it separates without competing. */
.sp-meta-sep { color: #BEC7D1; }

/* Icon bob. Behind a no-preference query so it never runs for
   reduced-motion users (the design doc's raw keyframe did). */
@keyframes sp-float-y {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}

/* ------------------------------------------------------------
   1. Apps hub  — redesigned 2026-08-12
      Hero → catalogue band → dark "why" band → light CTA.
   ------------------------------------------------------------ */

.sp-apps-hero {
  padding: clamp(7rem, 14vw, 10rem) 0 clamp(4.5rem, 9vw, 8rem);
  background: var(--color-bg);
}
.sp-apps-hero .section-label { margin-bottom: clamp(1.25rem, 2.6vw, 2.25rem); }
/* Display-scale H1 — larger than .section-title, which tops out at
   3.5rem and read as a subhead at the top of an otherwise empty page. */
.sp-apps-hero h1 {
  max-width: 1280px;
  font-size: clamp(2.25rem, 1.1rem + 5.2vw, 5.875rem);
  font-weight: 300;
  line-height: 1.02;
  letter-spacing: -0.035em;
  color: var(--color-text);
  padding-bottom: 0.06em;
  /* Helps the rag in engines that balance across a forced break
     (Safari). Chrome skips it here, which is why both apps H1s also
     carry explicit <br>s at their intended break points. */
  text-wrap: balance;
}
.sp-apps-hero-lead { margin-top: clamp(2rem, 4.4vw, 4rem); }
.sp-apps-hero-lead p {
  max-width: 660px;
  font-size: clamp(1.05rem, 0.96rem + 0.4vw, 1.1875rem);
  font-weight: 300;
  line-height: 1.7;
  color: var(--color-text-muted);
  text-wrap: pretty;
}

.sp-apps-list {
  padding: clamp(4.5rem, 8vw, 7rem) 0 clamp(5rem, 9vw, 8rem);
  background: var(--color-bg-warm);
}
.sp-catalogue-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
  margin-bottom: clamp(1.75rem, 3vw, 2.75rem);
}
.sp-catalogue-head .section-label { margin-bottom: 0; }
.sp-catalogue-meta {
  font-size: 0.7rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  /* muted, not dim: --color-text-dim is 4.0:1 on --color-bg-warm,
     below AA at this size. Weight 400 keeps it recessive against
     the teal .section-label opposite it. */
  color: var(--color-text-muted);
}

.sp-app-card {
  display: block;
  color: inherit;
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  padding: clamp(1.75rem, 3.4vw, 3rem);
  box-shadow: 0 32px 64px rgba(23, 28, 31, 0.05);
  transition: box-shadow var(--transition);
}
.sp-app-card + .sp-app-card { margin-top: 0.75rem; }
a.sp-app-card:hover,
a.sp-app-card:focus-visible {
  color: inherit;
  box-shadow: 0 40px 80px rgba(23, 28, 31, 0.1);
}
.sp-app-card.is-placeholder { box-shadow: none; }

/* Four columns while they fit: index, icon, copy, CTA. The CTA drops
   under the copy first, then the whole thing folds to two columns —
   the same "hold the row until it stops fitting" behaviour the rest
   of the site's card rows use. */
.sp-app-card-inner {
  display: grid;
  grid-template-columns: 3.5rem auto minmax(0, 1fr) auto;
  grid-template-areas: "idx art body cta";
  gap: 0 clamp(1.5rem, 3.4vw, 3rem);
  align-items: center;
}
.sp-app-index {
  grid-area: idx;
  font-size: clamp(2rem, 1.2rem + 2vw, 3.25rem);
  font-weight: 200;
  line-height: 1;
  color: var(--color-border);
}
.sp-app-card-art { grid-area: art; }
.sp-app-card-body { grid-area: body; max-width: 620px; }
.sp-app-card-cta { grid-area: cta; }

.sp-app-card-icon {
  width: clamp(96px, 12vw, 168px);
  height: clamp(96px, 12vw, 168px);
  /* 38/168 — the iOS icon curvature, held as a ratio so it stays
     right at every clamped size. */
  border-radius: 22.6%;
}
@media (prefers-reduced-motion: no-preference) {
  img.sp-app-card-icon { animation: sp-float-y 7s ease-in-out infinite; }
}
.sp-app-card-icon--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-bg-warm);
}
.sp-app-card-icon--empty img { width: 42%; height: auto; opacity: 0.22; }

.sp-app-card-meta {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 0.875rem;
}
.sp-app-card-meta .sp-platform {
  font-size: 0.68rem; font-weight: 500; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--color-text-dim);
}
.sp-app-card h2 {
  font-size: clamp(1.9rem, 1.25rem + 2.4vw, 3.375rem);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.03em;
  color: var(--color-text);
  margin-bottom: 1rem;
}
.sp-app-card.is-placeholder h2,
.sp-app-card.is-placeholder .sp-app-card-desc { color: var(--color-text-dim); }
.sp-app-card-desc {
  font-size: 1.0625rem;
  font-weight: 300;
  line-height: 1.7;
  color: var(--color-text-muted);
  margin-bottom: var(--space-md);
  text-wrap: pretty;
}
.sp-app-card.is-placeholder .sp-app-card-desc { margin-bottom: 0; }

/* The CTA drops under the copy first. Index and icon top-align from
   here on: centred across two rows they drifted into the middle of
   the card and read as unattached to the title. */
@media (max-width: 1180px) {
  .sp-app-card-inner {
    grid-template-columns: 3.5rem auto minmax(0, 1fr);
    grid-template-areas:
      "idx art body"
      "idx art cta";
    align-items: start;
  }
  .sp-app-index { padding-top: 0.1em; }
  .sp-app-card-cta { margin-top: 1.5rem; }
}
@media (max-width: 820px) {
  .sp-app-card-inner {
    grid-template-columns: 3rem minmax(0, 1fr);
    grid-template-areas:
      "idx  art"
      "body body"
      "cta  cta";
    row-gap: 1.75rem;
    align-items: center;
  }
  .sp-app-card-cta { margin-top: 0; }
}

.sp-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0; }
.sp-chip {
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  background: var(--color-tag-bg);
  padding: 0.4rem 0.9rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

/* ------------------------------------------------------------
   2. Fairsies marketing page
   ------------------------------------------------------------ */

/* One screen tall, contents centred in it, so the whole device is in
   view without scrolling (2026-08-12). The vertical padding is the
   phone's height budget: fairsies.js reads these two values off this
   element and sizes the device to whatever is left, so the two can
   never drift apart. Padding is in vh rather than vw because it is
   competing for vertical space, not horizontal — 14vw gave a 182px
   top margin on a wide-but-short laptop and pushed the phone's feet
   below the fold, which is what this fixes.
   svh, not vh: on mobile, vh is the LARGE viewport (toolbars hidden),
   so 100vh would again be taller than the screen actually is on load.

   2026-08-13 (Paul): the two channels around the device now MATCH —
   nav pill to phone, and phone to the colour change below. They only
   read as equal if the top padding pays for the fixed header first,
   so it is --sp-nav-h + --sp-hero-gap against --sp-hero-gap alone
   rather than two hand-tuned clamps. --sp-nav-h is the pill's visual
   foot: header padding 1rem + pill (0.55rem x2 + the 52px logo);
   below 1024px the header pads 0.6rem and the pill 0.5rem, so the
   foot sits ~8px higher. Writing it as one token means the phone's
   height budget (heroChrome() in fairsies.js / solander.js reads these
   same two values) still cannot drift from the padding.

   Any slack left when the phone hits its scale ceiling is split by
   align-items: center, so it lands equally top and bottom and the
   two channels stay level whatever the viewport. */
.sp-hero {
  --sp-nav-h: 85.6px;   /* 1rem header pad + 0.55rem x2 pill pad + 52px logo */
  --sp-hero-gap: clamp(2.5rem, 5vh, 4rem);
  position: relative;
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  padding: calc(var(--sp-nav-h) + var(--sp-hero-gap)) 0 var(--sp-hero-gap);
  background: var(--color-bg);
  overflow: hidden;
}
@media (max-width: 1024px) { .sp-hero { --sp-nav-h: 77.6px; } } /* 0.6rem + 0.5rem x2 + 52px */
/* The 2026-08-12 three-column hero (.sp-hero-layout / .sp-hero-head /
   .sp-hero-detail and their intro and media rules) was retired on
   2026-08-13 when both app pages moved to the option-1a / option-2a
   heroes at the foot of this file, and its rules were pruned as the
   handoff invited (docs/Handover - Design/"Fairsies and Solander hero
   options", design_handoff_hero_1a_2a/README.md). The pieces the new
   heroes still share — .sp-hero itself, the brand row, lead, actions,
   scalebox and the intro gate — live on below unchanged. */
/* App lockup above the headline: icon, name, pre-release badge */
.sp-hero-brand {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.7rem;
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
}
.sp-hero-brand img {
  width: 46px;
  height: 46px;
  border-radius: 10.5px; /* iOS icon curvature at this size */
}
.sp-hero-brand-name {
  font-size: 1.05rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--color-text);
}

/* Hero lead and buttons — shared by both 2026-08-13 heroes (the H1s
   are per-page: .va-h1 / .ma-h1 at the foot of this file). */
.sp-hero-lead {
  /* The measure the 1a/2a prototypes were signed off with — their
     34rem copy columns cap the block, this caps the line. */
  max-width: 31rem;
  font-size: clamp(1rem, 0.94rem + 0.3vw, 1.125rem);
  font-weight: 300;
  line-height: 1.7;
  color: var(--color-text-muted);
  text-wrap: pretty;
}
.sp-hero-actions {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  align-items: center;
  margin-top: var(--space-lg);
}

/* The hero's Requires / Price / Data collected row was removed
   2026-08-12 — it outweighed the headline column. Its label/value
   type lives on in .sp-spec-card, which absorbed the three facts. */
/* A11y: --color-text-dim (#6F7881) is only ~4.3:1 on --color-bg and
   3.4:1 on --color-bg-mint, which fails AA for text this small. These
   labels use --color-text-muted instead (8.8:1 and 6.9:1). */
.sp-spec-card dt {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin-bottom: 0.55rem;
}
.sp-spec-card dd {
  font-size: clamp(0.95rem, 0.87rem + 0.3vw, 1.0625rem);
  font-weight: 300;
  line-height: 1.5;
  color: var(--color-text);
}

/* ---- Hero intro (2026-08-12) ------------------------------------
   The phone fades up alone, holds while the walkthrough plays its
   opening scene, then the copy assembles beside it, staggered.

   The phone never moves — it is already where the settled layout
   puts it. Only the copy animates, and only its opacity and
   transform, so layout is identical throughout and cumulative layout
   shift is zero. These are the LAYOUT-NEUTRAL bones: which side each
   piece enters from is finished per hero in the 1a/2a blocks at the
   foot of this file (1a's copy lives right of the phone and enters
   from +28px; 2a's lives left and enters from -28px).

   Gated on .sp-intro, which the inline script in the page head adds
   before first paint and removes on a failsafe timer. Without that
   class none of this applies and the hero is simply assembled. */
.sp-intro .sp-phone-scalebox { opacity: 0; }
.sp-intro-in .sp-phone-scalebox {
  opacity: 1;
  transition: opacity 0.7s var(--ease-out);
}

/* Staggered per element, top to bottom of the copy block: headline
   (per-page class, its 0s slot lives in the 1a/2a blocks), brand row
   beneath it, lead, buttons.
   2026-08-13 (Paul): the copy read as slow — 1.4s travel over 28px
   with 0.15s steps took ~1.9s to finish. Now 0.85s over 20px with
   0.08s steps (~1.1s total): the same decel curve over less distance
   in less time reads as one swift settle rather than four arrivals.
   Keep HOLD_MS and ASSEMBLE_MS in fairsies.js / solander.js in step
   with these figures. */
.sp-intro .sp-hero-brand,
.sp-intro .sp-hero-lead,
.sp-intro .sp-hero-actions { opacity: 0; }
.sp-intro .sp-hero-brand { transform: translateX(-20px); }
.sp-intro .sp-hero-lead,
.sp-intro .sp-hero-actions { transform: translateX(20px); }
/* Stacked, there is no beside to come in from. */
@media (max-width: 1100px) {
  .sp-intro .sp-hero-brand,
  .sp-intro .sp-hero-lead,
  .sp-intro .sp-hero-actions { transform: translateY(16px); }
}

.sp-intro-settle .sp-hero-brand,
.sp-intro-settle .sp-hero-lead,
.sp-intro-settle .sp-hero-actions {
  opacity: 1;
  transform: none;
  transition: opacity 0.85s var(--ease-out) var(--sp-in-delay, 0s),
              transform 0.85s var(--ease-out) var(--sp-in-delay, 0s);
}
.sp-intro-settle .sp-hero-brand   { --sp-in-delay: 0.08s; }
.sp-intro-settle .sp-hero-lead    { --sp-in-delay: 0.16s; }
.sp-intro-settle .sp-hero-actions { --sp-in-delay: 0.24s; }

/* A print job during the intro shouldn't come out blank. */
@media print {
  .sp-intro .sp-phone-scalebox,
  .sp-intro .sp-hero-brand,
  .sp-intro .sp-hero-lead,
  .sp-intro .sp-hero-actions { opacity: 1 !important; transform: none !important; }
}

/* Scale wrapper. fairsies.js sets --sp-phone-scale from the viewport's
   width AND height (see fitPhone); the wrapper's own width/height
   follow so layout never reserves the unscaled box.
   The values below are the no-JS / pre-paint fallback — a coarse
   height ladder that lands near whatever the script will compute, so
   there is no visible resize on load. */
.sp-phone-scalebox {
  --sp-phone-scale: 0.50;
  width: calc(416px * var(--sp-phone-scale));
  height: calc(870px * var(--sp-phone-scale));
}
/* Each step is (viewport height - the hero's padding) / 870, i.e. the
   same sum fitPhone() does, so the pre-script paint lands within a
   couple of pixels of the final size. A coarse ladder here cost 0.037
   of cumulative layout shift on its own: the device painted at one
   size, then the script resized it. Ascending order, so the largest
   matching step wins. */
/* Re-cut 2026-08-13 for the equal-channels padding above: the hero now
   spends --sp-nav-h more of the viewport, so every step is
   (height - 85.6 - 2 x gap) / 870. Stepped every 40px rather than the
   old 40-80, which halves the worst mid-step gap between this and
   fitPhone (~28px of device to ~14px). Each figure is rounded DOWN, so
   the script only ever grows the device — never shrinks it. */
@media (min-height: 620px) { .sp-phone-scalebox { --sp-phone-scale: 0.522; } }
@media (min-height: 660px) { .sp-phone-scalebox { --sp-phone-scale: 0.568; } }
@media (min-height: 700px) { .sp-phone-scalebox { --sp-phone-scale: 0.614; } }
@media (min-height: 740px) { .sp-phone-scalebox { --sp-phone-scale: 0.660; } }
@media (min-height: 780px) { .sp-phone-scalebox { --sp-phone-scale: 0.706; } }
@media (min-height: 820px) { .sp-phone-scalebox { --sp-phone-scale: 0.749; } }
@media (min-height: 860px) { .sp-phone-scalebox { --sp-phone-scale: 0.791; } }
/* The ladder used to climb to 0.850; the 1a hero's signed-off ceiling
   is 0.80 (see fitPhone in fairsies.js), so it parks there — a taller
   pre-paint would only be resized down. */
@media (min-height: 880px) { .sp-phone-scalebox { --sp-phone-scale: 0.800; } }
.sp-phone-scalebox > .sp-device {
  transform: scale(var(--sp-phone-scale));
  transform-origin: top left;
}
/* No-JS on a narrow screen: width, not height, is the binding budget. */
@media (max-width: 480px) {
  .no-js .sp-phone-scalebox { --sp-phone-scale: 0.70; }
}

/* How it works — the page's dark chapter since the 2026-08-12
   redesign. Padding and ground come from .sp-dark on the same
   element; only the on-dark text colours are set here. */
.sp-how-header { margin-bottom: clamp(3rem, 6vw, 5.5rem); max-width: 900px; }
/* Scoped to .sp-dark, not .sp-how, since 2026-08-13: Solander's "Four
   tabs" band went light when its page started alternating dark/light
   from the Nightfall hero down (Paul), while Fairsies's "whole app"
   band stays on ink. A light sp-how simply falls back to the base
   caption and dot colours. */
.sp-how.sp-dark .sp-step-caption h3 { color: var(--color-text-on-dark); }
.sp-how.sp-dark .sp-step-caption p { color: var(--color-text-on-dark-muted); }
/* The steps carousel dots sit on ink there, so the shared pale-border
   dot and the deep-teal active state both fall under 3:1. */
.sp-how.sp-dark .scroll-dots[data-for="sp-steps"] .scroll-dot::before { background: rgba(246, 250, 254, 0.28); }
.sp-how.sp-dark .scroll-dots[data-for="sp-steps"] .scroll-dot.is-active::before { background: var(--color-sage-glow); }
/* The light variant of the band, for pages whose hero is already
   dark. The warm section tone rather than base bg, so it still reads
   as its own chapter between the ink hero above and what follows. */
.sp-how--light {
  padding: var(--space-3xl) 0;
  background: var(--color-bg-warm);
}
/* AUDIT 2026-08 (2nd pass): the four phones now behave like every
   other card row on the site — they fill the container edge-to-edge
   while they fit on one line, and the moment they stop fitting they
   become the standard swipe carousel (scroll-snap + dots) instead of
   wrapping into ragged rows with dead space on the right. */
.sp-steps {
  display: flex;
  flex-wrap: nowrap;
  gap: 2.5rem 2rem;
  justify-content: space-between;
}
@media (max-width: 1319px) {
  .sp-steps {
    justify-content: flex-start;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    padding-bottom: var(--space-xs);
  }
  .sp-steps::-webkit-scrollbar { display: none; }
  .sp-step { scroll-snap-align: center; }
  /* The shared dot indicators live behind a 640px media query in
     styles.css; the steps carousel runs wider than that, so the
     same dot styling is repeated here for its full active range. */
  .scroll-dots[data-for="sp-steps"] {
    display: flex;
    justify-content: center;
    gap: 0;
    padding-top: 0;
  }
  .scroll-dots[data-for="sp-steps"] .scroll-dot {
    width: 24px;
    height: 40px;
    display: grid;
    place-items: center;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .scroll-dots[data-for="sp-steps"] .scroll-dot::before {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--color-border);
    transition: background 0.25s, transform 0.25s;
  }
  .scroll-dots[data-for="sp-steps"] .scroll-dot.is-active::before {
    background: var(--color-accent);
    transform: scale(1.25);
  }
}
.sp-step { flex: 0 0 281px; display: flex; flex-direction: column; }
/* AUDIT 2026-08: no overflow clip here. The scaled device (280.8 x 587.25)
   fits the box, and clipping sliced its ambient shadow into a hard square —
   the hero phone (.sp-phone-scalebox) never clipped, so the steps looked
   different from it. Shadows are meant to paint past the box. */
.sp-step-phone { width: 281px; height: 588px; }
.sp-step-phone > .sp-device {
  transform: scale(0.675);
  transform-origin: top left;
}
/* 2.25rem, not 1.75: the parallax drift in fairsies.js moves the phone
   up to 18px down the page, and this margin is the headroom it eats. */
.sp-step-caption { margin-top: 2.25rem; }
.sp-step-caption .sp-num { margin-bottom: 0.5rem; }
.sp-step-caption h3 {
  font-size: 1.15rem;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--color-text);
  margin-bottom: 0.5rem;
}
.sp-step-caption p {
  font-size: 0.92rem;
  font-weight: 300;
  line-height: 1.6;
  color: var(--color-text-muted);
  text-wrap: pretty;
}

/* The short version — REDESIGN 2026-08-12.
   Replaces three separate chapters (a dark "Privacy" band, "The
   Maths", and the "App details" strip) that all circled the same
   claim. Claim on the left, evidence and the spec card on the right. */
.sp-short { padding: var(--space-3xl) 0; background: var(--color-bg-warm); }
.sp-short-layout {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: 0 clamp(2.5rem, 6vw, 6rem);
  align-items: start;
}
/* Sized against its own 5-of-12 column rather than the viewport —
   the shared .section-title clamp is tuned for a full-width header
   and orphaned "up." on its own line all the way down from 1300px. */
.sp-short-copy .section-title {
  font-size: clamp(1.85rem, 1.1rem + 2.4vw, 3.375rem);
  text-wrap: balance;
}
.sp-short-copy .section-intro { max-width: 440px; line-height: 1.75; }
.sp-short-cards { display: flex; flex-direction: column; gap: 0.75rem; }
/* Below the fit point the two columns stack, so the copy needs its
   own bottom gap where the grid column-gap no longer applies. */
@media (max-width: 1024px) {
  .sp-short-layout { grid-template-columns: minmax(0, 1fr); }
  .sp-short-copy { margin-bottom: clamp(2.5rem, 6vw, 3.5rem); }
  .sp-short-copy .section-intro { max-width: 620px; }
}

.sp-card {
  padding: clamp(1.5rem, 2.6vw, 2rem) clamp(1.5rem, 3vw, 2.25rem);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}
.sp-card h3 {
  font-size: clamp(1.05rem, 0.98rem + 0.25vw, 1.25rem);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.3;
  margin-bottom: 0.55rem;
  color: var(--color-text);
}
.sp-card p {
  font-size: clamp(0.95rem, 0.91rem + 0.15vw, 1rem);
  font-weight: 300;
  line-height: 1.7;
  color: var(--color-text-muted);
  text-wrap: pretty;
}

/* Spec card — the old .sp-details strip, folded into the stack as a
   two-by-two. Tonal rather than white so it reads as a footnote to
   the three cards above it, not a fourth claim. */
.sp-spec-card {
  display: grid;
  /* Five facts since the hero row folded in here — three across so the
     last row is one short rather than three. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.75rem 2.5rem;
  padding: clamp(1.75rem, 3vw, 2.25rem);
  border-radius: var(--radius-lg);
  background: var(--color-bg-mint);
}
@media (max-width: 380px) {
  .sp-spec-card { grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
}

/* Label/value pair reused by the support page's contact cards */
.sp-detail-label {
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--color-text-dim);
  margin-bottom: 0.5rem;
}

/* Support & legal link cards */
.sp-help { padding: var(--space-3xl) 0; background: var(--color-bg); }
.sp-help-layout {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: 0 clamp(2.5rem, 6vw, 5rem);
  align-items: start;
}
.sp-help-copy h2 {
  font-size: clamp(1.6rem, 1.2rem + 1.4vw, 2.25rem);
  font-weight: 300;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--color-text);
}
.sp-link-cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.75rem;
}
@media (max-width: 1024px) {
  .sp-help-layout { grid-template-columns: minmax(0, 1fr); }
  .sp-help-copy { margin-bottom: clamp(2rem, 5vw, 3rem); }
}
@media (max-width: 720px) {
  .sp-link-cards { grid-template-columns: minmax(0, 1fr); }
}
.sp-link-card {
  display: flex;
  flex-direction: column;
  padding: var(--space-lg) 2rem;
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  color: inherit;
  transition: background var(--transition);
}
.sp-link-card:hover,
.sp-link-card:focus-visible { background: var(--color-bg-warm); color: inherit; }
.sp-link-card h3 {
  font-size: 1.25rem;
  font-weight: 400;
  letter-spacing: -0.02em;
  margin-bottom: 0.6rem;
  color: var(--color-text);
}
.sp-link-card p {
  font-size: 0.95rem;
  font-weight: 300;
  line-height: 1.7;
  color: var(--color-text-muted);
}
.sp-link-card .sp-link-cta {
  display: inline-block;
  margin-top: auto;
  padding-top: var(--space-md);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--color-grad-cool);
}

/* Press kit removed 2026-08-12 — see the note in the Fairsies page. */

/* Light close — REDESIGN 2026-08-12.
   styles.css says the page rhythm is "hero light, one dark chapter,
   light again, dark close", and the global footer is the dark close.
   Both apps pages already have their own dark chapter, so the
   standard ink .cta-section stacked a third dark band straight onto
   the footer. Same component, inverted: light ground, solid heading,
   primary button instead of the on-dark outline. Opt-in — every
   other page keeps the dark CTA. */
.cta-section--light { background: var(--color-bg); }
.cta-section--light .cta-content h2 {
  background: none;
  background-clip: border-box;
  -webkit-background-clip: border-box;
  -webkit-text-fill-color: currentColor;
  color: var(--color-text);
}
.cta-section--light .cta-content p { color: var(--color-text-muted); }
/* Warm ground for the light CTA, so a page whose closing section is
   already --color-bg doesn't finish on two identical bands. */
.cta-section--light.cta-section--warm { background: var(--color-bg-warm); }

/* ------------------------------------------------------------
   3. Support page
   ------------------------------------------------------------ */

/* REDESIGN 2026-08-12: brought into line with the hub and the Fairsies
   overview. Was an icon beside a one-word "Support" H1; it is now the
   same display-scale hero the other two use, with the brand lockup
   carrying the icon and the H1 doing actual work. */
.sp-support-hero {
  padding: clamp(7rem, 14vw, 10rem) 0 clamp(4.5rem, 9vw, 8rem);
  background: var(--color-bg);
}
.sp-support-hero-head h1 {
  max-width: 1100px;
  font-size: clamp(2.1rem, 1.1rem + 4.4vw, 5rem);
  font-weight: 300;
  line-height: 1.03;
  letter-spacing: -0.035em;
  color: var(--color-text);
  padding-bottom: 0.06em;
  text-wrap: balance;
}
/* The label sits inline in the brand lockup here, not above a
   heading, so its stacking margin has to come off. */
.sp-support-hero .sp-hero-brand .section-label { margin-bottom: 0; }
.sp-support-hero-lead { margin-top: clamp(2rem, 4.4vw, 3.5rem); }
.sp-support-hero-lead p {
  max-width: 620px;
  font-size: clamp(1.05rem, 0.96rem + 0.4vw, 1.1875rem);
  font-weight: 300;
  line-height: 1.7;
  color: var(--color-text-muted);
  text-wrap: pretty;
}
.sp-support-hero-route {
  margin-top: 1.25rem;
  font-size: 0.95rem !important;
  color: var(--color-text-dim) !important;
}
.sp-support-hero-route a { color: var(--color-grad-cool); }
.sp-support-hero-route a:hover { color: var(--color-text); }

/* Closing contact band. Was the page's second section on --color-bg
   with no ground of its own; it now ends the page, so it takes the
   warm tone the CTA band does elsewhere in the cluster. */
.sp-contact { padding: var(--space-3xl) 0; background: var(--color-bg-warm); }
.sp-contact-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.75rem;
  align-items: stretch;
}
@media (max-width: 720px) {
  .sp-contact-grid { grid-template-columns: minmax(0, 1fr); }
}
.sp-contact-card {
  display: flex;
  flex-direction: column;
  padding: var(--space-lg) 2rem;
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}
.sp-contact-card .sp-detail-label { margin-bottom: 0.75rem; }
/* 1rem, down from 1.15: in the three-across band the card's content
   box is ~179px and "support@mirentha.com" needed 184px at the old
   size, so it snapped to "…mirentha.co / m". break-word is the last
   resort for a genuinely unbreakable string, not the layout. */
.sp-contact-card > a {
  font-size: 1rem;
  font-weight: 400;
  color: var(--color-grad-cool);
  overflow-wrap: break-word;
}
.sp-contact-card > a:hover { color: var(--color-text); }
.sp-contact-card p {
  font-size: 0.9rem;
  font-weight: 300;
  line-height: 1.7;
  color: var(--color-text-muted);
  margin-top: 0.75rem;
}
.sp-contact-card address {
  font-style: normal;
  font-size: 0.95rem;
  font-weight: 300;
  line-height: 1.7;
  color: var(--color-text-muted);
}

/* Accordions (Fixing a scan / Questions)
   REDESIGN 2026-08-12: header above a full-width list became the
   asymmetric split the rest of the cluster uses — heading holds the
   left column, the list runs down the right. Same .sp-acc component,
   plus an on-ink variant for the "Fixing a scan" chapter. */
/* Warm ground: the running order on the support page is
   hero --color-bg → Fixing a scan (ink) → Questions → Known limits
   → contact, and it has to alternate. Questions and contact take the
   warm tone, the hero and Known limits take --color-bg. */
.sp-acc-section { padding: var(--space-3xl) 0; background: var(--color-bg-warm); }
.sp-acc-layout {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
  gap: 0 clamp(2.5rem, 6vw, 5.5rem);
  align-items: start;
}
.sp-acc-header h2 {
  font-size: clamp(1.75rem, 1.15rem + 2.2vw, 3rem);
  font-weight: 300;
  line-height: 1.08;
  letter-spacing: -0.03em;
  color: var(--color-text);
  padding-bottom: 0.06em;
  text-wrap: balance;
}
.sp-acc-header > p {
  margin-top: 1rem;
  max-width: 380px;
  font-size: 1rem;
  font-weight: 300;
  line-height: 1.75;
  color: var(--color-text-muted);
  text-wrap: pretty;
}
@media (max-width: 1024px) {
  .sp-acc-layout { grid-template-columns: minmax(0, 1fr); }
  .sp-acc-header { margin-bottom: clamp(2rem, 5vw, 3rem); }
  .sp-acc-header > p { max-width: 620px; }
}
.sp-acc-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.sp-acc {
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  overflow: hidden;
}
.sp-acc summary {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md) 2rem;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  list-style: none;
}
.sp-acc summary::-webkit-details-marker { display: none; }
.sp-acc summary:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -2px; border-radius: var(--radius-lg); }
.sp-acc summary h3 {
  flex: 1 1 auto;
  font-size: 1.05rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  margin: 0;
  line-height: 1.4;
  color: var(--color-text);
}
/* currentColor since 2026-08-12 (was a hard-coded #6F7881) so the
   chevron follows its band instead of vanishing on ink. */
.sp-acc-chevron {
  flex: 0 0 auto;
  color: var(--color-text-dim);
  transition: transform var(--transition);
}
.sp-acc[open] .sp-acc-chevron { transform: rotate(180deg); }

/* ---- On-ink variant: the "Fixing a scan" chapter ---------------
   Cards lift off the ground with a translucent white rather than a
   solid, so the band still reads as one surface. All four text
   colours clear AA on --color-dark-section. */
.sp-acc-section--dark { background: var(--color-dark-section); }
.sp-acc-section--dark .section-label { color: var(--color-sage-glow); }
.sp-acc-section--dark .sp-acc-header h2 { color: var(--color-text-on-dark); }
.sp-acc-section--dark .sp-acc-header > p { color: var(--color-text-on-dark-muted); }
.sp-acc-section--dark .sp-acc { background: rgba(246, 250, 254, 0.06); }
.sp-acc-section--dark .sp-acc summary h3 { color: var(--color-text-on-dark); }
.sp-acc-section--dark .sp-acc-chevron { color: var(--color-text-on-dark-dim); }
.sp-acc-section--dark .sp-acc-panel p { color: var(--color-text-on-dark-muted); }
.sp-acc-section--dark .sp-acc summary:focus-visible { outline-color: var(--color-sage-glow); }
.sp-acc-panel {
  padding: 0 2rem 1.6rem;
}
.sp-acc-panel p {
  font-size: 0.95rem;
  font-weight: 300;
  line-height: 1.75;
  color: var(--color-text-muted);
  margin: 0;
  text-wrap: pretty;
}
/* Open/close reveal */
.sp-acc .sp-acc-panel { overflow: hidden; }
@supports (interpolate-size: allow-keywords) {
  .sp-acc::details-content {
    transition: height 0.35s var(--ease-out), content-visibility 0.35s allow-discrete;
    height: 0;
    overflow: clip;
  }
  .sp-acc[open]::details-content { height: auto; }
  :root { interpolate-size: allow-keywords; }
}

/* Known limits — REDESIGN 2026-08-12: the bespoke .sp-limit-card
   stack is gone; it reuses .sp-short-layout / .sp-card so the page
   shares a vocabulary with the Fairsies overview instead of inventing
   a third card style. Warm ground keeps it distinct from the light
   FAQ above and the closing contact band below. */
.sp-limits { padding: var(--space-3xl) 0; background: var(--color-bg); }
.sp-limits .sp-short-copy .section-intro a { color: var(--color-grad-cool); }
.sp-limits .sp-short-copy .section-intro a:hover { color: var(--color-text); }

/* Support page: one column split for the whole page.
   .sp-short-layout (5fr/6fr) and .sp-help-layout (4fr/8fr) are tuned
   for the Fairsies overview, where they appear once each. Reused here
   alongside .sp-acc-layout they gave three different left edges for
   the right-hand column down a single page. Everything below the
   hero now lines up on 4fr/7fr. Scoped above the shared stack point
   so it can't defeat the single-column rules. */
@media (min-width: 1025px) {
  .sp-limits .sp-short-layout,
  .sp-contact .sp-help-layout {
    grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
    column-gap: clamp(2.5rem, 6vw, 5.5rem);
  }
}
/* ...and one heading scale. .sp-help-copy h2 tops out at 2.25rem,
   which read as a subhead next to the 3rem accordion headings. */
.sp-contact .sp-help-copy h2 {
  font-size: clamp(1.75rem, 1.15rem + 2.2vw, 3rem);
  line-height: 1.08;
  letter-spacing: -0.03em;
}
.sp-limits .sp-short-copy .section-title {
  font-size: clamp(1.75rem, 1.15rem + 2.2vw, 3rem);
  line-height: 1.08;
}

/* ------------------------------------------------------------
   4. Legal pages — reuse .legal-page/.legal-body from styles.css;
      just the summary card is new.
   ------------------------------------------------------------ */

/* App-name UI labels referenced inside legal prose ("Type a total
   instead", "Send it to the group chat") — emphatic, not italic. */
.legal-body .em-ui { font-style: normal; color: var(--color-text); }

.sp-short-card {
  max-width: 780px;
  padding: var(--space-lg);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  margin-bottom: 3rem;
}
.sp-short-card h2 {
  font-size: 1.15rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  margin-bottom: 0.75rem;
  color: var(--color-text);
}
.sp-short-card p {
  font-size: 0.95rem;
  font-weight: 300;
  line-height: 1.75;
  color: var(--color-text-muted);
}

/* ------------------------------------------------------------
   5. The CSS iPhone
      Outer .sp-device = 416 x 870 (13px bezel around a 390 x 844
      screen — the app's real point grid, same as the walkthrough).
   ------------------------------------------------------------ */

/* 2026-08-12 (Solander): the three fixed numbers became variables so a
   second app can bring its own reference device without a second copy
   of this component. The defaults ARE the Fairsies phone — 390 x 844
   screen, 13px bezel — so every existing use is byte-for-byte
   unchanged. Solander's screens are drawn on a 440 x 956 grid (see
   .sp-device--md below), which is the grid its handover was built on;
   rescaling them to 390 would have meant re-deriving every position in
   the spec, and the spec's first line is "do not invent values". */
.sp-device {
  --sp-bezel: 13px;
  --sp-screen-w: 390px;
  --sp-screen-h: 844px;
  --sp-screen-r: 55px;
  width: calc(var(--sp-screen-w) + var(--sp-bezel) * 2);
  height: calc(var(--sp-screen-h) + var(--sp-bezel) * 2);
  padding: var(--sp-bezel);
  border-radius: calc(var(--sp-screen-r) + var(--sp-bezel));
  background: linear-gradient(150deg, #2C3138 0%, #0C0E12 38%, #14181E 62%, #33383F 100%);
  box-shadow:
    0 34px 80px rgba(20, 16, 10, 0.34),
    0 3px 10px rgba(20, 16, 10, 0.2),
    inset 0 0 0 1.4px rgba(255, 255, 255, 0.14);
  box-sizing: border-box;
  flex: 0 0 auto;
}
/* The larger reference device — iPhone 16 Pro Max's 440 x 956 points,
   which is the grid the Solander handover is drawn on. 62pt screen
   radius is that device's real corner; the bezel adds its own 14. */
.sp-device.sp-device--md {
  --sp-bezel: 14px;
  --sp-screen-w: 440px;
  --sp-screen-h: 956px;
  --sp-screen-r: 62px;
}

.sp-screen {
  position: relative;
  width: var(--sp-screen-w, 390px);
  height: var(--sp-screen-h, 844px);
  border-radius: var(--sp-screen-r, 55px);
  overflow: hidden;
  /* AUDIT 2026-08 (2nd pass): belt-and-braces rounded clip. Inside a
     scaled ancestor some renderers promote children (e.g. the
     keyboard) to their own layer and skip the border-radius clip —
     the grey board stuck out square below the bezel. clip-path is
     honoured on composited layers everywhere. */
  clip-path: inset(0 round var(--sp-screen-r, 55px));
  -webkit-clip-path: inset(0 round var(--sp-screen-r, 55px));
  background: var(--as-cream);
  /* The app's own type stack — the screens must look like iOS,
     not like the marketing site. */
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Helvetica Neue", system-ui, sans-serif;
  /* In-app palette (Theme.swift) */
  --as-cream: #F4EFE4;
  --as-card: #FFFDF7;
  --as-ink: #1B2430;
  --as-brand: #22395C;
  --as-text2: #6B6A63;
  --as-quiet: #88867C;
  --as-positive: #146C46;
  --as-negative: #A63E28;
  --as-sand: #EDE6D4;
  --as-sand-ink: #5A5344;
  --as-sep: #EFE9DB;
  --as-camera: #11161F;
}
.sp-screen, .sp-screen * { box-sizing: border-box; }

/* Status bar + home bar (shared chrome, drawn above every screen) */
.sp-statusbar {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 59px;
  pointer-events: none;
  z-index: 30;
}
.sp-statusbar .sb-time {
  position: absolute; left: 34px; top: 18px;
  font-size: 16px; font-weight: 600; letter-spacing: -0.2px;
  color: var(--as-ink);
}
.sp-statusbar .sb-island {
  position: absolute; left: 132.5px; top: 11px;
  width: 125px; height: 37px; border-radius: 20px;
  background: #07090C;
}
.sp-statusbar .sb-glyphs {
  position: absolute; right: 32px; top: 21px;
  display: flex; align-items: flex-end; gap: 5px;
  color: var(--as-ink);
}
.sp-screen.is-dark .sp-statusbar .sb-time,
.sp-screen.is-dark .sp-statusbar .sb-glyphs { color: var(--as-cream); }
.sp-homebar {
  position: absolute;
  left: 125px; bottom: 8px;
  width: 140px; height: 5px; border-radius: 3px;
  background: rgba(27, 36, 48, 0.3);
  pointer-events: none;
  z-index: 30;
}
.sp-screen.is-dark .sp-homebar { background: rgba(244, 239, 228, 0.45); }

/* ------------------------------------------------------------
   6. The four in-app screens (static recreations)
      Layout metrics from the app source / walkthrough:
      SAFE_TOP 59, SAFE_BOTTOM 34, inset 20, radii 18/14/20/16.
   ------------------------------------------------------------ */

.as-screen { position: absolute; inset: 0; background: var(--as-cream); }

.as-perf {
  height: 1px;
  flex: 0 0 auto;
  background: repeating-linear-gradient(to right, var(--as-sep) 0 5px, transparent 5px 10px);
}

.as-avatar {
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  flex: 0 0 auto;
  background: var(--as-sand);
  color: var(--as-sand-ink);
}
.as-avatar.is-you, .as-avatar.is-on { background: var(--as-brand); color: var(--as-cream); }
.as-avatar.is-dim { color: rgba(90, 83, 68, 0.5); }

/* --- start --- */
.as-start-toprow {
  position: absolute; left: 10px; right: 10px; top: 59px;
  display: flex; justify-content: space-between;
}
.as-start-toprow .as-iconbtn {
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  color: var(--as-brand);
}
.as-start-art {
  position: absolute; left: 45px; top: 268px;
  width: 300px; height: 298px;
}
.as-btn-primary {
  position: absolute; left: 20px; right: 20px;
  height: 54px; border-radius: 14px;
  background: var(--as-brand); color: var(--as-cream);
  display: flex; align-items: center; justify-content: center; gap: 9px;
  font-size: 17px; font-weight: 600; letter-spacing: -0.3px;
}
.as-start .as-btn-primary { top: 732px; }

/* --- table --- */
.as-nav {
  position: absolute; left: 20px; right: 20px; top: 59px;
  height: 44px;
  display: flex; align-items: center; justify-content: space-between;
  font-size: 17px; letter-spacing: -0.4px; color: var(--as-brand);
}
.as-table-block { position: absolute; left: 20px; right: 20px; top: 109px; }
.as-table-merchant {
  font-size: 26px; font-weight: 700; letter-spacing: -0.5px;
  line-height: 31px; color: var(--as-ink);
}
.as-table-total {
  margin-top: 4px; height: 50px;
  display: flex; align-items: center;
  font-size: 50px; font-weight: 600; letter-spacing: -1.8px;
  color: var(--as-ink);
  font-variant-numeric: tabular-nums;
}
.as-table-q { margin-top: 20px; font-size: 20px; font-weight: 600; letter-spacing: -0.4px; color: var(--as-ink); }
.as-table-sub { margin-top: 5px; font-size: 14px; line-height: 1.45; color: var(--as-text2); }
.as-table-card {
  position: absolute; left: 20px; right: 20px; top: 281px;
  background: var(--as-card); border-radius: 18px; padding: 16px;
}
.as-chiprow { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.as-chip {
  height: 40px; border-radius: 20px; background: var(--as-sand);
  display: flex; align-items: center; gap: 8px; padding: 0 6px;
  flex: 0 0 auto;
}
.as-chip .as-avatar { width: 28px; height: 28px; font-size: 11px; background: rgba(90, 83, 68, 0.14); }
.as-chip .as-chip-name { font-size: 15px; letter-spacing: -0.2px; color: var(--as-ink); white-space: nowrap; }
.as-chip .as-chip-x { width: 26px; height: 26px; margin-right: 3px; display: flex; align-items: center; justify-content: center; }
.as-chip.is-you { background: var(--as-brand); }
.as-chip.is-you .as-avatar { background: rgba(244, 239, 228, 0.2); color: var(--as-cream); }
.as-chip.is-you .as-chip-name { color: var(--as-cream); }
.as-caret-slot { height: 40px; display: flex; align-items: center; padding: 0 4px; min-width: 24px; }
.as-caret { width: 2px; height: 21px; margin-left: 1px; background: var(--as-brand); }
.as-table-card .as-perf { margin-top: 16px; margin-bottom: 12px; }
.as-table-count {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  font-size: 13px;
}
.as-table-count .l { color: var(--as-text2); }
.as-table-count .r { color: var(--as-quiet); font-variant-numeric: tabular-nums; }
.as-table .as-btn-primary { top: 742px; }

/* The iOS keyboard, up because the name field has the caret (static
   table screen only — the walkthrough types too fast to need one).
   Metrics: keys 42pt tall, 6pt gaps, 12pt row gaps, light-mode board.
   Sits over the CTA exactly as the real keyboard does on the device. */
.as-kbd {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 260px;
  padding: 8px 3px 0;
  background: #D2D5DB;
  /* No z-index: DOM order already stacks it above the CTA, and a
     z-index promoted it to a compositor layer that escaped the
     screen's rounded clip in some browsers. */
}
.as-kbd-row { display: flex; gap: 6px; margin-bottom: 12px; }
.as-kbd-row-mid { padding: 0 19px; }
.as-key {
  flex: 1 1 0;
  height: 42px;
  border-radius: 5px;
  background: #FFFFFF;
  box-shadow: 0 1px 0 rgba(122, 126, 133, 0.85);
  display: flex; align-items: center; justify-content: center;
  font-size: 22px; font-weight: 400;
  color: #10151B;
}
.as-key-fn { background: #AEB4BE; flex: 0 0 44px; color: #10151B; }
.as-kbd-bottom .as-key-123, .as-kbd-bottom .as-key-return { flex: 0 0 92px; font-size: 16px; }
.as-key-space { font-size: 16px; }

/* --- assign --- */
.as-assign-title { position: absolute; left: 20px; right: 20px; top: 115px; }
.as-assign-title h2 {
  font-size: 28px; font-weight: 700; letter-spacing: -0.6px;
  line-height: 33px; color: var(--as-ink); margin: 0;
}
.as-assign-status {
  margin-top: 7px; height: 17px;
  display: flex; align-items: baseline; gap: 6px;
  font-size: 14px;
}
.as-assign-status .amt { font-weight: 600; color: var(--as-negative); font-variant-numeric: tabular-nums; }
.as-assign-status .txt { color: var(--as-text2); }
.as-personbar {
  position: absolute; left: 20px; right: 20px; top: 186px;
  height: 90px; background: var(--as-card); border-radius: 18px;
  display: flex; align-items: center;
}
.as-personbar-people { display: flex; gap: 10px; padding-left: 14px; }
.as-person { width: 60px; display: flex; flex-direction: column; align-items: center; gap: 5px; }
.as-person .as-avatar { width: 44px; height: 44px; font-size: 16px; }
.as-person .as-person-amt { font-size: 11px; color: var(--as-quiet); font-variant-numeric: tabular-nums; }
.as-person.is-on .as-person-amt { font-weight: 600; color: var(--as-ink); }
.as-personbar-tick {
  width: 54px; height: 54px; margin-left: auto; margin-right: 6px;
  border-radius: 16px; background: var(--as-brand);
  display: flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
}
.as-assign-scroll {
  position: absolute; left: 0; right: 0; top: 276px; bottom: 34px;
  overflow: hidden;
  /* AUDIT 2026-08: the list is taller than the screen (that's the point —
     it scrolls in the app), but a hard clip cut the card mid-row into a
     square edge that read as broken. The mask fades the last 52px out,
     the way a real scroll view disappears under the safe area. */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 52px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 52px), transparent);
}
.as-items-card {
  margin: 12px 20px 0;
  background: var(--as-card); border-radius: 18px; overflow: hidden;
}
.as-item {
  display: flex; align-items: flex-start;
  padding: 14px 16px; height: 74px;
}
.as-item.is-recent { background: rgba(34, 57, 92, 0.06); }
.as-item .as-item-main { flex: 1 1 auto; }
.as-item .as-item-name {
  font-size: 17px; letter-spacing: -0.3px; line-height: 20px; color: var(--as-ink);
}
.as-item.is-unclaimed .as-item-name, .as-item.is-unclaimed .as-item-amt { color: var(--as-quiet); }
.as-item .as-item-sub {
  margin-top: 6px; height: 20px;
  display: flex; align-items: center; gap: 8px;
}
.as-item .as-item-sub .who { display: flex; }
.as-item .as-item-sub .as-avatar {
  width: 20px; height: 20px; font-size: 10px;
  box-shadow: 0 0 0 1.5px var(--as-card);
}
.as-item .as-item-sub .as-avatar + .as-avatar { margin-left: -6px; }
.as-item .as-item-sub .cap { font-size: 12px; color: var(--as-quiet); }
.as-item .as-item-sub .cap.is-brand { font-weight: 600; color: var(--as-brand); }
.as-item .as-item-sub .cap.is-neg { color: var(--as-negative); }
.as-item .as-item-amt {
  margin-left: 14px;
  font-size: 17px; letter-spacing: -0.2px; color: var(--as-ink);
  font-variant-numeric: tabular-nums;
}
.as-items-card .as-perf { margin-left: 16px; margin-right: 16px; }
.as-add-row {
  display: flex; align-items: center; gap: 10px;
  padding: 15px 16px; color: var(--as-brand);
  font-size: 15px; font-weight: 600; letter-spacing: -0.2px;
}
.as-service-card {
  margin: 12px 20px 0;
  background: var(--as-card); border-radius: 18px;
  display: flex; align-items: flex-start;
  padding: 14px 16px;
}
.as-service-card > div:first-child { flex: 1 1 auto; }
.as-service-card .t { font-size: 17px; letter-spacing: -0.3px; color: var(--as-ink); }
.as-service-card .s { margin-top: 4px; font-size: 12px; color: var(--as-quiet); }
.as-service-card .as-item-amt { margin-left: auto; }
.as-see-scan {
  margin-top: 8px; padding: 12px 0;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  color: var(--as-brand); font-size: 13px; font-weight: 600; letter-spacing: -0.2px;
}

/* --- damage --- */
.as-damage-hero { position: absolute; left: 20px; right: 20px; top: 216px; }
.as-label {
  font-size: 12px; letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--as-quiet);
}
.as-damage-amt {
  margin-top: 10px; height: 65px;
  display: flex; align-items: center;
  font-size: 68px; font-weight: 600; letter-spacing: -2.6px;
  color: var(--as-ink); font-variant-numeric: tabular-nums;
}
.as-damage-why {
  margin-top: 10px; font-size: 14px; line-height: 1.45;
  color: var(--as-text2); text-wrap: pretty;
}
.as-damage-card {
  position: absolute; left: 20px; right: 20px; top: 381px;
  background: var(--as-card); border-radius: 18px; overflow: hidden;
}
.as-damage-row {
  display: flex; align-items: center; gap: 12px;
  padding: 15px 16px; height: 64px;
}
.as-damage-row .as-avatar { width: 34px; height: 34px; font-size: 13px; }
.as-damage-row .n { font-size: 17px; letter-spacing: -0.3px; color: var(--as-ink); flex: 1 1 auto; }
.as-damage-row .a {
  font-size: 24px; font-weight: 600; letter-spacing: -0.7px;
  color: var(--as-ink); font-variant-numeric: tabular-nums;
}
.as-damage-card .as-perf { margin: 0 16px; }
.as-damage-recon {
  position: absolute; left: 24px; right: 24px; top: 587px;
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  font-size: 13px;
}
.as-damage-recon .l { color: var(--as-quiet); }
.as-damage-recon .r { font-weight: 600; color: var(--as-positive); font-variant-numeric: tabular-nums; }
.as-damage .as-btn-primary { top: 716px; }
.as-damage-foot {
  position: absolute; left: 20px; right: 20px; top: 784px;
  text-align: center; font-size: 12px; line-height: 1.5;
  color: var(--as-quiet);
}

/* ------------------------------------------------------------
   7. Hero walkthrough stage
      The wrapper the animation renders into. The walkthrough JS
      draws its own screens; these rules only host it.
   ------------------------------------------------------------ */

.sp-walkthrough .sp-screen > .sp-wt-layer {
  position: absolute;
  inset: 0;
  visibility: hidden;
}
/* The walkthrough's touch indicator */
.sp-finger {
  position: absolute;
  width: 0; height: 0;
  z-index: 20;
  pointer-events: none;
}
.sp-finger .dot {
  position: absolute;
  left: -22px; top: -22px;
  width: 44px; height: 44px;
  border-radius: 50%;
}
.sp-finger .ripple {
  position: absolute;
  border-radius: 50%;
}

/* Reduced motion: the walkthrough never starts (handled in JS);
   the hero keeps the static start screen. */
@media (prefers-reduced-motion: reduce) {
  .sp-acc .sp-acc-chevron { transition: none; }
}

/* ------------------------------------------------------------
   8. Small-screen tidy-ups
   ------------------------------------------------------------ */

@media (max-width: 600px) {
  .sp-acc summary { padding: 1.1rem 1.25rem; }
  .sp-acc-panel { padding: 0 1.25rem 1.25rem; }
  .sp-contact-card { padding: 1.5rem 1.25rem; }
  .sp-app-card { padding: 1.5rem 1.25rem; }
}

/* AUDIT 2026-08-13 (mobile pass): these uppercase micro-labels are
   0.68-0.6875rem, which renders at 10.9px — legible on a desktop
   monitor, squinty on a phone. 0.75rem = 12px wherever the pointer is
   coarse, which catches a phone in landscape too; a width query
   missed those. Selectors are doubled up where the base rule is
   itself nested (.sp-app-card-meta .sp-platform) so this actually
   wins on specificity. */
@media (pointer: coarse) {
  .sp-app-badge,
  .sp-catalogue-meta,
  .sp-detail-label,
  .sp-spec-card dt,
  .sp-hero-brand .sp-app-badge,
  .sp-app-card-meta .sp-platform { font-size: 0.75rem; }
}

/* The email links in the support page's contact cards are standalone
   targets, not links inside a sentence, so WCAG 2.5.8's inline
   exemption doesn't cover them. Padding plus a matching negative
   margin lifts the tap target to ~44px without moving anything. */
.sp-contact-card > a {
  display: inline-block;
  padding-block: 0.55rem;
  margin-block: -0.55rem;
}

/* ------------------------------------------------------------
   6. Launch-notify band (2026-08-13, rebuilt)

   The "Get notified at launch" ask, which used to be a link into
   the contact form.

   Built out of what the site already has rather than out of new
   geometry: .sp-help-layout for the column split (same left edge
   as the link cards above), .sp-contact-card's surface treatment
   for the panel, and .form-group / .btn-full from styles.css for
   the field and the button, so this form is componentwise the
   contact form. Field, then check, then full-width button.

   Nothing here names Fairsies: a second app page gets the band by
   copying the markup and changing data-app.
   ------------------------------------------------------------ */
.sp-notify { padding: var(--space-3xl) 0; background: var(--color-bg-warm); }

.sp-notify-panel {
  padding: var(--space-lg) 2rem;
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

/* The same rhythm as .contact-form, restated rather than borrowed:
   that class is a GSAP scrub target on the homepage, and putting it
   on this form would hand the index choreography an element on a
   page it never runs on. The honeypot is absolutely positioned, so
   it is out of flow and takes no gap. */
.sp-notify-form { display: flex; flex-direction: column; gap: var(--space-md); }

/* Turnstile is interaction-only, so on almost every visit it renders
   nothing at all. Left as an empty flex item it would still take a
   full gap, leaving a hole between the field and the button. */
.sp-notify-form .cf-turnstile:empty { display: none; }

/* Status and small print travel together as one flex item, so the
   note sits close under the confirmation instead of a --space-md
   away from it. */
.sp-notify-foot > p { margin: 0; }
.sp-notify-status {
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--color-accent);
}
.sp-notify-status:empty { display: none; }
.sp-notify-status.is-error { color: #C0392B; }
.sp-notify-status:not(:empty) + .sp-notify-note { margin-top: 0.6rem; }

.sp-notify-note {
  font-size: 0.82rem;
  font-weight: 300;
  line-height: 1.6;
  color: var(--color-text-dim);
}
.sp-notify-note a { color: var(--color-text-muted); text-decoration: underline; text-underline-offset: 2px; }
.sp-notify-note a:hover { color: var(--color-accent); }

/* Once someone is on the list the form stops being a form. Showing
   them an empty box again only invites a second submission. */
.sp-notify-form.is-done .form-group,
.sp-notify-form.is-done .cf-turnstile,
.sp-notify-form.is-done .btn,
.sp-notify-form.is-done .sp-notify-note { display: none; }
.sp-notify-form.is-done .sp-notify-status {
  font-size: 1rem;
  color: var(--color-text);
}

@media (max-width: 380px) {
  .sp-notify-panel { padding: 1.5rem 1.25rem; }
}

/* ============================================================
   8. SOLANDER — the in-app screens (.mw-*)
   ------------------------------------------------------------
   Drawn by solander-walkthrough.js on the app's own 440 x 956
   point grid. Every number below is traced to the handover's
   solander-spec.md; treat them as the app's, not the site's.

   THE PALETTE FLIPS. Solander's UI crossfades from parchment to
   night as the scrubbed clock crosses sunset, so the app's tokens
   arrive as --p-* custom properties written on .mw-screen once
   per frame. Anything that must NOT flip (the run-of-light card
   is pinned light, the night cards and the dial are pinned dark)
   carries its literal value here instead. Do not "tidy" a literal
   into a var without checking which side of that line it is on.
   ============================================================ */

.mw-screen {
  position: relative;
  overflow: hidden;
  background: var(--p-bg, #05070B);
  color: var(--p-ink, #ECEFF5);
  font-family: -apple-system, "SF Pro Text", "SF Pro Display", system-ui, "Helvetica Neue", Arial, sans-serif;
  line-height: normal;
  letter-spacing: normal;
}
.mw-screen * { box-sizing: border-box; }
.mw-tab { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }
.mw-sp { flex: 1; }
.mw-scr { position: absolute; inset: 0; overflow: hidden; }
.mw-stars { position: absolute; inset: 0; pointer-events: none; }
.mw-micro {
  font-size: 10.5px; font-weight: 700; letter-spacing: 1.3px;
  text-transform: uppercase; line-height: 1.25; white-space: nowrap;
}
.mw-act { color: var(--p-actInk); }
.mw-hint { font-size: 11px; color: var(--p-ink3); white-space: nowrap; }
.mw-secthead { display: flex; align-items: baseline; height: 14px; }
.mw-moonbadge { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.mw-moonbadge-cap { font-size: 8.5px; font-weight: 700; letter-spacing: 1.1px; white-space: nowrap; }
.mw-moon { display: block; }

/* ---- header bar (PageChrome / StateHeaderBar) ---- */
.mw-header { display: flex; gap: 7px; align-items: center; height: 32px; }
.mw-header-abs { position: absolute; left: 20px; right: 20px; top: 59px; }
.mw-header-map, .mw-header-live { left: 14px; right: 14px; }
.mw-pill {
  display: flex; gap: 5px; align-items: center;
  padding: 0 11px; height: 26px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600;
}
.mw-pill b { font-size: 8px; font-weight: 700; }
.mw-circle {
  width: 32px; height: 32px; border-radius: 999px;
  display: flex; align-items: center; justify-content: center; gap: 2.5px;
}
.mw-circle u { width: 3px; height: 3px; border-radius: 3px; text-decoration: none; }
.mw-circle-i i { font: italic 600 13px Georgia, "Times New Roman", serif; }
/* over imagery */
.mw-header.is-over .mw-pill,
.mw-header.is-over .mw-circle {
  border: 1px solid rgba(255, 255, 255, 0.14);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}
.mw-header.is-over .mw-pill { background: rgba(255, 255, 255, 0.10); color: #fff; }
.mw-header.is-over .mw-circle { background: rgba(0, 0, 0, 0.22); color: #fff; }
.mw-header.is-over .mw-pill svg { fill: #E4B454; }
.mw-header.is-over .mw-pill b { color: rgba(255, 255, 255, 0.5); }
.mw-header.is-over .mw-circle u { background: #fff; }
/* on paper */
.mw-header:not(.is-over) .mw-pill,
.mw-header:not(.is-over) .mw-circle {
  background: var(--p-quietFill);
  border: 1px solid var(--p-cardStroke);
  color: var(--p-ink);
}
.mw-header:not(.is-over) .mw-pill svg { fill: var(--p-actInk); }
.mw-header:not(.is-over) .mw-pill b,
.mw-header:not(.is-over) .mw-circle u { color: var(--p-ink3); background: var(--p-ink3); }
.mw-header:not(.is-over) .mw-pill b { background: none; }

/* ============ SKY ============ */
.mw-sky { background: var(--p-bg); }
.mw-hero { position: absolute; left: 0; top: 0; width: 440px; height: 336px; overflow: hidden; }
.mw-hero-grad { position: absolute; inset: 0; }
.mw-horizon { position: absolute; left: 0; bottom: 0; }
.mw-hero-block {
  position: absolute; left: 20px; right: 20px; bottom: 44px;
  display: flex; align-items: flex-end;
}
.mw-hero-block > .mw-moonbadge { margin-bottom: 4px; }
.mw-hero-copy { display: flex; flex-direction: column; gap: 3px; }
.mw-eyebrow { display: flex; gap: 7px; align-items: center; height: 14px; }
.mw-eyebrow span {
  font-size: 10.5px; font-weight: 700; letter-spacing: 1.4px;
  color: rgba(255, 255, 255, 0.82); white-space: nowrap;
}
.mw-verdict {
  width: 8px; height: 8px; border-radius: 8px;
  background: #6FCF97; box-shadow: 0 0 4px #6FCF97; flex: 0 0 auto;
}
.mw-clockrow { display: flex; align-items: flex-end; gap: 12px; height: 70px; }
.mw-clock {
  width: 144px; font-size: 58px; font-weight: 600;
  letter-spacing: -2.2px; color: #fff; line-height: 70px;
}
.mw-acc { width: 150px; height: 40px; position: relative; margin-bottom: 7px; }
.mw-acc-live, .mw-acc-back { position: absolute; left: 0; bottom: 0; }
.mw-acc-in { font-size: 9px; font-weight: 700; letter-spacing: 1.1px; color: rgba(255, 255, 255, 0.55); }
.mw-acc-cd { font-size: 21px; font-weight: 600; color: rgba(255, 255, 255, 0.95); }
.mw-acc-back {
  width: 124px; height: 24px; display: flex; gap: 6px;
  align-items: center; justify-content: center;
  border-radius: 999px; background: rgba(255, 255, 255, 0.14);
}
.mw-acc-back span { font-size: 10px; font-weight: 700; letter-spacing: 1.2px; color: #fff; white-space: nowrap; }
.mw-window { font-size: 13px; font-weight: 500; color: rgba(255, 255, 255, 0.86); margin-top: 4px; white-space: nowrap; }
.mw-chips { display: flex; gap: 8px; margin-top: 8px; }
.mw-chip {
  display: flex; gap: 6px; align-items: center;
  padding: 4px 9px; border-radius: 999px; background: rgba(255, 255, 255, 0.13);
}
.mw-chip i { width: 6px; height: 6px; border-radius: 6px; flex: 0 0 auto; }
.mw-chip span { font-size: 10.5px; font-weight: 600; color: #fff; white-space: nowrap; }

/* the run of light — a picture of daylight, so pinned LIGHT in both
   appearances (Theme.raised / cardStroke / ink from the light column) */
.mw-run { position: absolute; left: 20px; right: 20px; top: 310px; }
.mw-run-card {
  margin-top: 10px; padding: 4px 0;
  background: #FAF8F1; border: 1px solid rgba(35, 32, 26, 0.08);
  border-radius: 18px; box-shadow: 0 5px 10px rgba(48, 40, 20, 0.14);
}
.mw-row { position: relative; display: flex; align-items: center; gap: 12px; padding: 8px 14px; }
.mw-row:not(.is-last)::after {
  content: ""; position: absolute; left: 14px; right: 0; bottom: 0;
  height: 1px; background: rgba(35, 32, 26, 0.08);
}
.mw-row-edge {
  position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: #9C7420; border-radius: 0 3px 3px 0; opacity: 0;
}
.mw-row-t { width: 44px; font-size: 14px; font-weight: 600; color: #23201A; flex: 0 0 auto; }
.mw-row-dot { width: 9px; height: 9px; border-radius: 9px; flex: 0 0 auto; }
.mw-row-n { font-size: 13.5px; font-weight: 600; color: #23201A; white-space: nowrap; }
.mw-row-n em { font-weight: 400; font-style: normal; color: #767061; }
.mw-row-c { font-size: 11px; font-weight: 600; color: #2E9E63; white-space: nowrap; }
.mw-row-c.is-gold { color: #9C7420; }

/* Tonight — a picture of the night, so pinned DARK in both */
.mw-tonight { position: absolute; left: 20px; right: 20px; top: 518px; }
.mw-night-card {
  margin-top: 10px; padding: 10px 0 8px;
  border-radius: 20px; border: 1px solid rgba(255, 255, 255, 0.09);
  position: relative; overflow: hidden; background: #10141F;
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
}
.mw-night-wash { position: absolute; inset: 0; background: linear-gradient(to bottom, #181F33, rgba(24, 31, 51, 0) 50%); }
.mw-night-moonwash { position: absolute; inset: 0; background: radial-gradient(circle at 86% 14%, rgba(201, 212, 232, 0.13), transparent 150px); }
.mw-night-stars { opacity: 0.42; }
.mw-night-arc { position: relative; height: 176px; display: flex; justify-content: center; }
.mw-dial-slot { position: absolute; left: 0; right: 0; bottom: 0; display: flex; justify-content: center; }
.mw-dial { display: block; overflow: visible; }
.mw-dial-centre {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: 24px; width: 196px; text-align: center;
}
.mw-dial-val { font-size: 34px; font-weight: 600; letter-spacing: -1px; color: #ECEFF5; line-height: 40px; }
.mw-dial-sub { font-size: 12px; color: #8A93A5; margin-top: 4px; }
.mw-dial-ideal { font-size: 12px; font-weight: 600; color: #6FCF97; margin-top: 4px; }
.mw-verdict-row { display: flex; gap: 6px; align-items: center; justify-content: center; margin-top: 7px; }
.mw-verdict-row i { width: 7px; height: 7px; border-radius: 7px; background: #6FCF97; box-shadow: 0 0 3px #6FCF97; }
.mw-verdict-row span { font-size: 12px; font-weight: 700; color: #6FCF97; }
.mw-dial-centre--sm { bottom: 16px; width: 168px; }
.mw-dial-centre--sm .mw-dial-val { font-size: 23px; letter-spacing: -0.6px; line-height: normal; }
.mw-dial-centre--sm .mw-dial-sub,
.mw-dial-centre--sm .mw-dial-ideal { font-size: 10.5px; margin-top: 3px; }
.mw-dial-centre--sm .mw-verdict-row { gap: 5px; margin-top: 5px; }
.mw-dial-centre--sm .mw-verdict-row i { width: 6px; height: 6px; }
.mw-dial-centre--sm .mw-verdict-row span { font-size: 11px; }
.mw-legend-slot { position: relative; margin-top: 6px; margin-bottom: 2px; }
.mw-legend { display: flex; gap: 14px; justify-content: center; align-items: center; }
.mw-legend-item { display: flex; gap: 5px; align-items: center; }
.mw-legend-item i { width: 14px; height: 5px; border-radius: 3px; }
.mw-legend-item span { font-size: 10.5px; color: #A6AEBD; }

/* ============ MAP ============ */
.mw-map { background: #0a1120; }
.mw-map-plate { position: absolute; left: 0; top: 0; width: 440px; height: 956px; display: block; }
.mw-map-svg { position: absolute; inset: 0; }
.mw-mapchip {
  position: absolute; transform: translate(-50%, -50%);
  padding: 4px 8px; border-radius: 999px;
  background: rgba(5, 7, 11, 0.85); border: 1px solid currentColor;
  font-size: 10px; font-weight: 700; white-space: nowrap;
}
.mw-osm { position: absolute; left: 6px; bottom: 62px; font-size: 8px; color: rgba(236, 239, 245, 0.4); }
.mw-console {
  position: absolute; left: 0; right: 0; bottom: 159px;
  padding: 10px 16px 9px;
  background: var(--p-raised); border-top: 1px solid var(--p-divider);
  display: flex; align-items: center; gap: 10px;
}
.mw-console-flag { font-size: 8.5px; font-weight: 800; letter-spacing: 1px; color: var(--p-ink3); }
.mw-console-hm { font-size: 25px; font-weight: 600; color: var(--p-actInk); line-height: 29px; }
.mw-console-read { flex: 1; min-width: 0; }
.mw-console-r1 { font-size: 12px; font-weight: 500; color: var(--p-ink); white-space: nowrap; }
.mw-console-r2 { font-size: 11px; color: var(--p-ink2); white-space: nowrap; }
.mw-console-now {
  padding: 0 11px; height: 38px; display: flex; align-items: center;
  border-radius: 999px; background: var(--p-actFill);
  font-size: 11.5px; font-weight: 700; color: var(--p-actInk);
}
.mw-console-cloud {
  width: 38px; height: 38px; border-radius: 999px; background: var(--p-quietFill);
  display: flex; align-items: center; justify-content: center; color: var(--p-ink2); flex: 0 0 auto;
}
.mw-console-save {
  padding: 0 14px; height: 38px; display: flex; align-items: center;
  border-radius: 999px; background: var(--p-actionFill);
  font-size: 13px; font-weight: 700; color: var(--p-onAction);
}
/* the tool rail sits over imagery, so it keeps the dark tokens */
.mw-rail { position: absolute; right: 16px; top: 105px; display: flex; flex-direction: column; gap: 8px; }
.mw-rail-tile {
  width: 44px; height: 44px; border-radius: 14px;
  background: rgba(14, 17, 26, 0.85); border: 1px solid rgba(255, 255, 255, 0.06);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  color: #ECEFF5;
}
.mw-rail-tile span { font-size: 9px; font-weight: 700; letter-spacing: 0.3px; color: #8A93A5; }

/* ============ ASTRO ============ */
.mw-astro { background: var(--p-bg); }
.mw-tiles { position: absolute; left: 20px; right: 20px; top: 111px; display: flex; gap: 10px; }
.mw-tile {
  flex: 1; height: 92px; border-radius: 16px;
  background: var(--p-quietFill); border: 1px solid var(--p-cardStroke);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 9px; position: relative; color: var(--p-ink);
}
.mw-tile span { font-size: 13.5px; font-weight: 600; color: var(--p-ink); }
.mw-tile-dot {
  position: absolute; top: 10px; right: 10px;
  width: 7px; height: 7px; border-radius: 7px;
  background: var(--p-milkyWay); box-shadow: 0 0 4px var(--p-milkyWay);
}
.mw-instr {
  position: absolute; left: 20px; right: 20px; top: 219px;
  border-radius: 24px; border: 1px solid rgba(255, 255, 255, 0.09);
  overflow: hidden; background: linear-gradient(to bottom, #181F33, #10141F);
  padding: 14px 0 10px; box-shadow: 0 12px 25px rgba(0, 0, 0, 0.45);
}
.mw-instr-stars { opacity: 0.55; }
.mw-instr-top { position: relative; padding: 0 16px; display: flex; align-items: flex-start; min-height: 48px; }
.mw-instr-top .mw-micro { padding-top: 6px; color: #8A93A5; }
.mw-instr-arc { position: relative; margin-top: 4px; height: 228px; display: flex; justify-content: center; }
.mw-instr-hair { position: relative; height: 1px; background: rgba(255, 255, 255, 0.07); margin: 8px 16px 0; }
.mw-week { position: relative; padding: 8px 6px 4px; }
.mw-week-head { padding: 0 4px 6px; }
.mw-week-head .mw-hint { font-size: 10.5px; color: #788195; }
.mw-week-cells { display: flex; gap: 4px; }
.mw-wcell {
  flex: 1; border-radius: 10px; padding: 6px 0 4px;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  border: 1px solid transparent;
}
.mw-wcell b { font-size: 12px; font-weight: 700; color: #8A93A5; }
.mw-wcell em { font-size: 10.5px; font-weight: 400; font-style: normal; color: #8A93A5; }
.mw-wcell.is-best { background: rgba(228, 180, 84, 0.16); border-color: rgba(228, 180, 84, 0.5); }
.mw-wcell.is-best b { font-weight: 800; color: #E4B454; }
.mw-wcell.is-best em { font-weight: 700; color: #E4B454; }
.mw-wcell.is-tonight { background: rgba(255, 255, 255, 0.05); }
.mw-wcell.is-tonight b { color: #ECEFF5; }
.mw-door {
  position: absolute; left: 20px; right: 20px; top: 670px;
  border-radius: 16px; background: var(--p-quietFill); border: 1px solid var(--p-cardStroke);
  padding: 13px 15px; display: flex; align-items: center; gap: 12px;
}
.mw-door-line { font-size: 13.5px; font-weight: 600; color: var(--p-ink); margin-top: 2px; white-space: nowrap; }
.mw-door-dot { width: 7px; height: 7px; border-radius: 7px; background: var(--p-ok); box-shadow: 0 0 3px var(--p-ok); }
.mw-door-chev { font-size: 10px; font-weight: 700; color: var(--p-ink3); }
.mw-header-paper { height: 42px; background: var(--p-bg); }
.mw-header-paper::after {
  content: ""; position: absolute; left: -20px; right: -20px; bottom: 0;
  height: 1px; background: var(--p-divider);
}

/* ============ LIVE (AR) ============ */
.mw-live { background: #04060B; }
.mw-live-view {
  position: absolute; inset: 0;
  background: linear-gradient(to bottom, #04060F 0%, #080E20 34%, #0E1830 64%, #0A101F 100%);
}
.mw-live-milky {
  position: absolute; left: -18%; top: -6%; width: 136%; height: 78%;
  transform: rotate(-24deg);
  background: radial-gradient(ellipse 42% 16% at 50% 50%, rgba(157, 139, 214, 0.20), rgba(120, 130, 190, 0.07) 55%, transparent 72%);
  filter: blur(6px);
}
.mw-live-horizon { position: absolute; left: 0; bottom: 0; }
.mw-live-info {
  position: absolute; left: 16px; top: 103px; max-width: 268px;
  padding: 12px; border-radius: 14px; background: rgba(0, 0, 0, 0.45);
}
.mw-live-point { font-size: 13px; font-weight: 700; color: #fff; margin-top: 5px; }
.mw-live-when { font-size: 10px; color: rgba(228, 180, 84, 0.9); margin-top: 4px; }
.mw-live-finder {
  position: absolute; left: 50%; top: 44%; transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  color: #7DF3DC;
}
.mw-live-finder svg { filter: drop-shadow(0 0 6px rgba(125, 243, 220, 0.8)); }
.mw-live-finder span {
  font-size: 10px; font-weight: 700; color: #fff;
  background: rgba(0, 0, 0, 0.5); border-radius: 999px; padding: 3px 8px; white-space: nowrap;
}
.mw-live-bar {
  position: absolute; left: 16px; right: 16px; bottom: 173px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
}
.mw-live-showing {
  padding: 5px 11px; border-radius: 999px;
  background: rgba(0, 0, 0, 0.55); border: 1px solid rgba(228, 180, 84, 0.4);
  font-size: 11px; font-weight: 600; color: #E4B454;
}
.mw-live-chips { display: flex; gap: 8px; }
.mw-lchip {
  height: 34px; padding: 0 11px; border-radius: 999px;
  display: flex; align-items: center; gap: 6px;
  background: rgba(0, 0, 0, 0.35); color: rgba(255, 255, 255, 0.55);
}
.mw-lchip.is-on { background: rgba(0, 0, 0, 0.55); color: var(--lc); }
.mw-lchip span { font-size: 11px; font-weight: 600; }

/* ============ THE DOCK ============ */
.mw-dock {
  position: absolute; left: 0; right: 0; top: 797px; height: 159px;
  background: var(--p-raised); border-top: 1px solid var(--p-divider);
}
.mw-wheel {
  position: absolute; left: 20px; top: 8px; width: 400px; height: 56px;
  border-radius: 13px; overflow: hidden;
  border: 1px solid var(--p-imageFrame); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
}
.mw-wheel-canvas { display: block; }
.mw-wheel-curve {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.38), rgba(0, 0, 0, 0) 22%, rgba(255, 255, 255, 0.05) 42%, rgba(0, 0, 0, 0) 62%, rgba(0, 0, 0, 0.45));
}
.mw-tabbar {
  position: absolute; left: 0; right: 0; top: 71px;
  display: flex; height: 54px; padding: 0 4px; align-items: stretch;
}
.mw-tab-cell {
  width: 86.2px; position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  color: var(--p-tabInactive);
}
.mw-tab-cell.is-on { color: var(--p-actInk); }
.mw-tab-cell span { font-size: 9.5px; font-weight: 600; }
.mw-tab-div { width: 1px; align-self: center; height: 26px; background: var(--p-divider); }
.mw-badge {
  position: absolute; top: 6px; left: 49.1px;
  min-width: 15px; height: 15px; padding: 0 3px; border-radius: 999px;
  background: var(--p-actInk); color: var(--p-bg);
  font-size: 9.5px; font-weight: 700; font-style: normal;
  display: flex; align-items: center; justify-content: center;
  font-variant-numeric: tabular-nums;
}

/* ============ STATUS BAR / HOME / TOUCH ============ */
.mw-status {
  position: absolute; left: 0; right: 0; top: 0; height: 59px;
  display: flex; align-items: center; padding: 0 32px; z-index: 30; pointer-events: none;
}
.mw-status-time { flex: 1; text-align: center; font-size: 15.5px; font-weight: 600; color: #fff; }
.mw-status-glyphs { flex: 1; display: flex; justify-content: center; align-items: center; gap: 6px; }
.mw-island { position: absolute; left: 157px; top: 11px; width: 126px; height: 37px; border-radius: 24px; background: #000; }
.mw-home {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: 8px;
  width: 139px; height: 5px; border-radius: 100px;
  background: rgba(255, 255, 255, 0.55); z-index: 30; pointer-events: none;
}
.mw-finger {
  position: absolute; left: 0; top: 0; width: 0; height: 0;
  z-index: 40; pointer-events: none; opacity: 0;
}
.mw-finger i {
  position: absolute; left: -22px; top: -22px; width: 44px; height: 44px;
  border-radius: 999px; background: rgba(255, 255, 255, 0.28);
  border: 1.5px solid rgba(255, 255, 255, 0.78);
  box-shadow: 0 0 0 1.5px rgba(0, 0, 0, 0.26), 0 2px 10px rgba(0, 0, 0, 0.35);
}

/* ------------------------------------------------------------
   Solander's scale wrapper. Same job as .sp-phone-scalebox, sized
   against the larger device (468 x 984). The ladder is the same sum
   solander.js does — (viewport height - the hero's own padding) /
   984 — so the pre-script paint lands within a pixel or two of the
   final size and the page does not shift when the script runs.
   ------------------------------------------------------------ */
.sp-phone-scalebox.sp-phone-scalebox--md {
  --sp-phone-scale: 0.44;
  width: calc(468px * var(--sp-phone-scale));
  height: calc(984px * var(--sp-phone-scale));
}
/* Re-cut 2026-08-13 alongside the Fairsies ladder, same 40px steps and
   the same (height - 85.6 - 2 x gap) budget the equal-channels
   padding leaves. */
@media (min-height: 620px)  { .sp-phone-scalebox.sp-phone-scalebox--md { --sp-phone-scale: 0.461; } }
@media (min-height: 660px)  { .sp-phone-scalebox.sp-phone-scalebox--md { --sp-phone-scale: 0.502; } }
@media (min-height: 700px)  { .sp-phone-scalebox.sp-phone-scalebox--md { --sp-phone-scale: 0.543; } }
@media (min-height: 740px)  { .sp-phone-scalebox.sp-phone-scalebox--md { --sp-phone-scale: 0.583; } }
@media (min-height: 780px)  { .sp-phone-scalebox.sp-phone-scalebox--md { --sp-phone-scale: 0.624; } }
@media (min-height: 820px)  { .sp-phone-scalebox.sp-phone-scalebox--md { --sp-phone-scale: 0.663; } }
@media (min-height: 860px)  { .sp-phone-scalebox.sp-phone-scalebox--md { --sp-phone-scale: 0.699; } }
/* The 880/960/1040 steps used to climb to 0.850; the 2a hero's
   signed-off ceiling is 0.72 (see fitPhone in solander.js), so the
   ladder parks there for anything taller. */
@media (min-height: 900px)  { .sp-phone-scalebox.sp-phone-scalebox--md { --sp-phone-scale: 0.72; } }
@media (max-width: 480px) {
  .no-js .sp-phone-scalebox.sp-phone-scalebox--md { --sp-phone-scale: 0.62; }
}

/* The four step phones. .sp-step-phone's 281 x 588 box is sized for
   the Fairsies device at 0.675; Solander's is bigger, so it takes its
   own scale and box. 0.60 x 468 = 280.8 wide, which lands the two
   apps' step rows on the same column width. */
.sp-step-phone.sp-step-phone--md { width: 281px; height: 591px; }
.sp-step-phone.sp-step-phone--md > .sp-device { transform: scale(0.60); transform-origin: top left; }

/* The no-JS / pre-script poster inside every Solander phone. It is
   removed the moment the real screen is built, so it only ever shows
   if the script is blocked or throws. */
.md-poster {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.75rem; padding: 3.5rem 2rem;
  background: linear-gradient(to bottom, #04060F 0%, #0B1226 38%, #35304E 72%, #D99A52 96%);
  color: #fff; text-align: center;
  font-family: -apple-system, "SF Pro Text", system-ui, sans-serif;
}
.md-poster b { font-size: 34px; font-weight: 600; letter-spacing: -1px; }
.md-poster span { font-size: 13px; font-weight: 500; color: rgba(255, 255, 255, 0.8); }
.md-poster em {
  font-style: normal; font-size: 10.5px; font-weight: 700;
  letter-spacing: 1.3px; text-transform: uppercase; color: rgba(228, 180, 84, 0.95);
}

/* Solander's screen starts on night, not Fairsies's parchment, so the
   corner behind the poster (and any frame before the renderer runs)
   is the app's own ground rather than a flash of cream. */
/* :not(.mw-screen) so this is only the pre-render ground. Once the
   renderer has run it owns the background, because that one follows
   the palette as it crossfades from parchment to night. */
.sp-screen--md:not(.mw-screen) { background: #05070B; }


/* ------------------------------------------------------------
   HERO 1a — "The app leads" (2026-08-13 hero redesign, Fairsies)
   Phone left, copy right; pair centred as one unit. One gap token
   (--g) is both the column gap and the side padding, per the
   equal-channels principle of the old hero. From the handoff bundle
   (docs/Handover - Design/"Fairsies and Solander hero options",
   design_handoff_hero_1a_2a/fairsies-1a) — appended verbatim EXCEPT
   the two floating .va-chip fragments and their rules, which Paul
   asked to leave out (no floating boxes over the phone animation,
   2026-08-13). The device halo stays: it is ground, not a box.
   ------------------------------------------------------------ */
/* --g runs 5.5vw, up from the handoff's 4.5 (2026-08-13, Paul, second
   pass): another ~14px of channel at 1440 on top of the copy nudge
   below. Widening the shared gap grows the centred pair symmetrically,
   so both outer margins give up the same few pixels and stay level.
   Third pass (2026-08-13, Paul): the phone-to-copy channel widens
   again, but through its OWN token --gc (6.6vw, ~+16px at 1440) so
   only the column gap moves. Keeping padding-inline on --g leaves the
   stacked layout below 1100px untouched, and leaves the two-column
   breakpoint the same room it had. Nothing resizes: the phone scales
   from the viewport (fitPhone in fairsies.js), the copy track is a
   fixed 34rem, and the centred pair still hands the same few pixels
   back to each outer margin, so the two channels stay level. */
.va-grid { --g: clamp(2rem, 5.5vw, 6.25rem); --gc: clamp(2rem, 6.6vw, 7.5rem); position: relative; z-index: 1; width: 100%; display: grid; grid-template-columns: auto minmax(0, 34rem); justify-content: center; align-items: center; column-gap: var(--gc); padding-inline: var(--g); }
.va-h1 { font-size: clamp(2.2rem, 4.4vw, 4.25rem); font-weight: 300; line-height: 1.06; letter-spacing: -0.035em; color: var(--color-text); padding-bottom: 0.06em; text-wrap: balance; }
/* 2.25rem, up from the handoff's 1.25 (2026-08-13, Paul): the copy sat
   too close to the device, so it moves another 16px right. That would
   have pushed its right edge past the phone's left-hand margin, so the
   hero buttons below give those pixels back — the two together keep
   the outer gaps level (phone to window on one side, text to window
   on the other; ~249px each at 1440). */
.va-copy { transform: translateX(2.25rem); }
.va-copy .sp-hero-actions .btn { padding-inline: 1.8rem; }
.va-copy .sp-hero-lead { margin-top: 1.5rem; }
/* The brand row sits UNDER the headline on both app heroes since
   2026-08-13 (Paul) — a signature beneath the claim. Its base
   margin-bottom was sized for the lockup-above arrangement, so it
   flips here; the lead's own 1.5rem margin provides the next gap. */
.va-copy .sp-hero-brand,
.ma-copy .sp-hero-brand { margin: 1.4rem 0 0; }
.va-phone { position: relative; }
.va-phone::before { content: ""; position: absolute; inset: -5% -16%; border-radius: 50%; background: radial-gradient(closest-side, rgba(223, 227, 231, 0.55), rgba(246, 250, 254, 0)); }
.va-phone .sp-phone-scalebox { position: relative; }
@media (max-width: 1100px) {
  .va-grid { grid-template-columns: minmax(0, 1fr); justify-items: center; text-align: center; row-gap: clamp(2rem, 5vw, 3rem); }
  /* Stacked, the ANIMATION leads and the copy follows (2026-08-13,
     Paul — the text bunched at the top and the phone sat below the
     fold). DOM order is already phone-first, so the handoff's
     order:-1 on the copy simply goes; only the desktop nudge is
     cancelled. */
  .va-copy { transform: none; }
  .va-copy .sp-hero-actions .btn { padding-inline: 2rem; }
  .va-copy .sp-hero-brand, .va-copy .sp-hero-actions { justify-content: center; }
  .va-copy .sp-hero-lead { margin-inline: auto; }
}

/* Intro gate wiring for 1a. The generic .sp-intro rules in this file
   already cover .sp-hero-brand / .sp-hero-lead / .sp-hero-actions;
   these extend them to the new H1 class and flip the brand's entry
   direction (all copy now lives in the RIGHT column, so everything
   enters from +28px). */
.sp-intro .va-h1 { opacity: 0; transform: translateX(20px); }
.sp-intro .va-grid .sp-hero-brand { transform: translateX(20px); }
.sp-intro-settle .va-h1 { opacity: 1; transform: none; transition: opacity 0.85s var(--ease-out) var(--sp-in-delay, 0s), transform 0.85s var(--ease-out) var(--sp-in-delay, 0s); }
.sp-intro-settle .va-h1 { --sp-in-delay: 0s; } /* headline leads; brand follows at 0.08s now it sits beneath */
@media (max-width: 1100px) { .sp-intro .va-h1, .sp-intro .va-grid .sp-hero-brand { transform: translateY(16px); } }
@media print { .sp-intro .va-h1 { opacity: 1 !important; transform: none !important; } }


/* ------------------------------------------------------------
   HERO 2a — "Nightfall" (2026-08-13 hero redesign, Solander)
   Full dark hero: ink ground, faint stars, golden sun-path arc drawn
   the way the app's Map tab draws it, phone right. Merges into the
   dark "whole app" chapter below. From the same handoff bundle
   (design_handoff_hero_1a_2a/solander-2a), appended verbatim.
   ------------------------------------------------------------ */
.sp-hero.sp-hero--night { background: linear-gradient(180deg, #171C1F 0%, #11161A 55%, #171C1F 100%); }
.ma-sky { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.ma-stars { position: absolute; top: 0; left: 0; width: 2px; height: 2px; border-radius: 50%; background: transparent; box-shadow: 12vw 14vh 0 0.5px rgba(236,239,245,0.5), 26vw 8vh 0 0 rgba(236,239,245,0.35), 38vw 22vh 0 0.5px rgba(236,239,245,0.42), 52vw 10vh 0 0 rgba(236,239,245,0.3), 64vw 30vh 0 0.5px rgba(236,239,245,0.45), 71vw 6vh 0 0 rgba(236,239,245,0.4), 82vw 18vh 0 0.5px rgba(236,239,245,0.5), 91vw 34vh 0 0 rgba(236,239,245,0.35), 14vw 29vh 0 0 rgba(236,239,245,0.28), 47vw 36vh 0 0.5px rgba(236,239,245,0.32), 6vw 42vh 0 0 rgba(236,239,245,0.25), 58vw 52vh 0 0 rgba(236,239,245,0.2), 88vw 56vh 0 0.5px rgba(236,239,245,0.28), 50vw 47vh 0 0 rgba(236,239,245,0.18), 76vw 44vh 0 0 rgba(236,239,245,0.3), 96vw 12vh 0 0 rgba(236,239,245,0.4); }
.ma-arc { position: absolute; inset: 0; width: 100%; height: 100%; }
@media (prefers-reduced-motion: no-preference) { .ma-sun-halo { animation: maPulse 5.5s ease-in-out infinite; } }
@keyframes maPulse { 0%, 100% { opacity: 0.14; } 50% { opacity: 0.3; } }
/* --g runs 6.2vw, up from the handoff's 4.5 in two passes (2026-08-13,
   Paul): more air between copy and phone. Widening the shared gap
   grows the centred pair symmetrically, so the two outer margins
   shrink by the same few pixels and stay level with each other.
   Third pass (2026-08-13, Paul), matched to Fairsies: the channel
   widens by its own token --gc (7.3vw, ~+16px at 1440) so only the
   column gap moves; padding-inline stays on --g and the stacked
   layout below 1100px is untouched. Element sizes are unchanged
   (phone scale comes from the viewport in solander.js, copy track is
   a fixed 34rem), so both outer margins give up the same amount. */
.ma-grid { --g: clamp(2rem, 6.2vw, 6.5rem); --gc: clamp(2rem, 7.3vw, 7.6rem); position: relative; z-index: 2; width: 100%; display: grid; grid-template-columns: minmax(0, 34rem) auto; justify-content: center; align-items: center; column-gap: var(--gc); padding-inline: var(--g); }
.ma-h1 { font-size: clamp(2.2rem, 4.4vw, 4.25rem); font-weight: 300; line-height: 1.06; letter-spacing: -0.035em; color: var(--color-mint-pale); padding-bottom: 0.06em; text-wrap: balance; }
.ma-grad { background: linear-gradient(90deg, #E4B454 0%, #2D9CDB 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; box-decoration-break: clone; -webkit-box-decoration-break: clone; }
.ma-copy .sp-hero-lead { margin-top: 1.5rem; color: rgba(246, 250, 254, 0.72); }
.ma-copy .sp-hero-brand-name { color: var(--color-mint-pale); }
.ma-copy .sp-app-badge { color: #E4B454; } /* coral fails contrast on ink; gold is the app's own act-ink token */
.ma-copy .sp-meta-sep { color: rgba(246, 250, 254, 0.35); }
.sp-hero--night .btn-outline { color: var(--color-mint-pale); border-color: rgba(246, 250, 254, 0.28); }
.sp-hero--night .btn-outline:hover { border-color: var(--color-sage-glow); color: #FFFFFF; }
@media (max-width: 1100px) {
  .ma-arc { display: none; } /* desktop composition element; its fixed geometry crosses the stacked copy */
  .ma-grid { grid-template-columns: minmax(0, 1fr); justify-items: center; text-align: center; row-gap: clamp(2rem, 5vw, 3rem); }
  /* Stacked, the ANIMATION leads (2026-08-13, Paul) — same order as
     the Fairsies hero. Here the DOM is copy-first, so the phone takes
     the order the Fairsies page gets for free. */
  .ma-phone { order: -1; }
  .ma-copy .sp-hero-brand, .ma-copy .sp-hero-actions { justify-content: center; }
  .ma-copy .sp-hero-lead { margin-inline: auto; }
}

/* Intro gate wiring for 2a: all copy is the LEFT column, so lead and
   actions flip to enter from -28px; new H1 gets the 0.15s slot; the
   sky art fades in with the phone. */
.sp-intro .ma-h1 { opacity: 0; transform: translateX(-20px); }
.sp-intro .ma-grid .sp-hero-lead, .sp-intro .ma-grid .sp-hero-actions { transform: translateX(-20px); }
.sp-intro .ma-sky { opacity: 0; }
.sp-intro-in .ma-sky { opacity: 1; transition: opacity 0.7s var(--ease-out); }
.sp-intro-settle .ma-h1 { opacity: 1; transform: none; transition: opacity 0.85s var(--ease-out) var(--sp-in-delay, 0s), transform 0.85s var(--ease-out) var(--sp-in-delay, 0s); }
.sp-intro-settle .ma-h1 { --sp-in-delay: 0s; } /* headline leads; brand follows at 0.08s now it sits beneath */
@media (max-width: 1100px) { .sp-intro .ma-h1, .sp-intro .ma-grid .sp-hero-lead, .sp-intro .ma-grid .sp-hero-actions { transform: translateY(16px); } }
@media print { .sp-intro .ma-h1, .sp-intro .ma-sky { opacity: 1 !important; transform: none !important; } }


/* ------------------------------------------------------------
   SOLANDER BAND ALTERNATION (2026-08-13, Paul)
   With the Nightfall hero dark, the page now alternates ink and
   light all the way down: hero (ink) → Four tabs (light, via
   .sp-how--light above) → the short version (ink) → help (light) →
   notify (ink) → CTA (light) → footer (ink). The shared .sp-dark
   class brings each ink band's ground, padding and heading colours;
   the rules here restate the components that sit INSIDE two of those
   bands — cards, spec card, form — in the dark surface language
   (tonal layering: a faintly lifted pane on ink, per DESIGN.md).
   Fairsies's page keeps its original rhythm and none of this applies
   to it. */
/* Stated explicitly because the cascade would get it wrong: the base
   .sp-short / .sp-notify rules set the warm ground LATER in the file
   than .sp-dark sets ink, so on equal specificity warm would win. */
.sp-short.sp-dark,
.sp-notify.sp-dark { background: var(--color-dark-section); }
.sp-short.sp-dark .sp-card { background: rgba(246, 250, 254, 0.055); }
.sp-short.sp-dark .sp-card h3 { color: var(--color-mint-pale); }
.sp-short.sp-dark .sp-card p { color: var(--color-text-on-dark-muted); }
.sp-short.sp-dark .sp-spec-card { background: rgba(246, 250, 254, 0.09); }
.sp-short.sp-dark .sp-spec-card dt { color: var(--color-text-on-dark-muted); }
.sp-short.sp-dark .sp-spec-card dd { color: var(--color-mint-pale); }

/* The notify band's headline is a bare h2 (not .section-title), so
   the generic .sp-dark heading rule doesn't reach it. Inputs keep
   their light fill — a light field on an ink panel is the highest-
   contrast thing on the band, which is where the eye should land.
   The Turnstile widget's theme is set in the markup (data-theme). */
.sp-notify.sp-dark .sp-help-copy h2 { color: var(--color-mint-pale); }
.sp-notify.sp-dark .sp-notify-panel { background: rgba(246, 250, 254, 0.055); }
.sp-notify.sp-dark .form-group label { color: var(--color-text-on-dark-muted); }
.sp-notify.sp-dark .sp-notify-note { color: rgba(246, 250, 254, 0.62); }
.sp-notify.sp-dark .sp-notify-note a { color: rgba(246, 250, 254, 0.82); }
.sp-notify.sp-dark .sp-notify-note a:hover { color: var(--color-mint-pale); }
.sp-notify.sp-dark .sp-notify-status { color: var(--color-mint-pale); }
.sp-notify.sp-dark .sp-notify-status.is-error { color: var(--color-coral-bright); }
