/* ==========================================================================
   Walked — site styles.

   Updated 2026-09-03 alongside the app after a contrast audit against WCAG
   2.2: `accent`, `accentDim`, `textFaint` and `borderStrong` all failed here
   too, because these tokens are copied from the app and so were its failures.

   The tokens below are COPIED FROM THE APP, not re-chosen. `walked-app/src/
   theme/index.ts` is the source of truth; if a colour here disagrees with it,
   this file is the one that is wrong. A marketing site that is a different
   product to the app it markets is a small lie told before anyone installs.

   The two typefaces carry meaning, exactly as in the app (design spec §1.1):
     Inter          — what is stated.
     JetBrains Mono — what was measured, and anything uncertain.
   Mono is not decoration here. Every real figure on this site is set in it.
   ========================================================================== */

:root {
  --bg: #161826;
  --surface: #1b1d2c;
  --raised: #232532;
  --text: #e9e9ed;
  --text-2: #b2b6ca;
  --muted: #9397ab;
  --faint: #8a8ea1;
  --accent: #a99cf0;
  --accent-dim: #6f63c4;
  --accent-wash: rgba(169, 156, 240, 0.06);
  --border: rgba(233, 233, 237, 0.10);
  --border-strong: rgba(233, 233, 237, 0.42);
  --positive: #7fb894;
  --caution: #d9bb84;

  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --wrap: 1080px;
  --radius: 14px;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.56;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--text); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.narrow { max-width: 720px; }

/* --- the "not out yet" bar. First thing on the page, every page. ---------- */
.banner {
  background: var(--accent-wash);
  border-bottom: 1px solid var(--border);
  font-family: var(--mono);
  font-size: 12.5px;
  letter-spacing: .02em;
  color: var(--text-2);
  padding: 10px 0;
}
.banner strong { color: var(--accent); font-weight: 400; }

/* --- header --------------------------------------------------------------- */
.site-head {
  display: flex; align-items: center; gap: 24px;
  padding: 22px 0 18px;
  border-bottom: 1px solid var(--border);
}
.mark { display: inline-block; text-decoration: none; }
.mark b {
  display: block;
  font-weight: 500; font-size: 25px; letter-spacing: -.9px; color: var(--text);
}
.mark i { display: block; height: 2px; width: 68px; background: var(--accent); margin-top: 5px; }
.site-nav { margin-left: auto; display: flex; gap: 22px; flex-wrap: wrap; }
.site-nav a {
  font-family: var(--mono); font-size: 13px; color: var(--muted); text-decoration: none;
}
.site-nav a:hover, .site-nav a[aria-current="page"] { color: var(--accent); }

/* --- type ----------------------------------------------------------------- */
h1, h2, h3, h4 { font-weight: 500; margin: 0; }
h1 { font-size: clamp(38px, 7vw, 62px); line-height: 1.06; letter-spacing: -2.2px; }
h2 { font-size: clamp(26px, 4vw, 33px); line-height: 1.16; letter-spacing: -1px; margin-top: 0; }
h3 { font-size: 19px; line-height: 1.35; letter-spacing: -.2px; }
p { margin: 0 0 18px; }
.lede { font-size: clamp(17px, 2.2vw, 20px); line-height: 1.6; color: var(--text-2); }
.muted { color: var(--muted); }
.faint { color: var(--faint); }

.eyebrow {
  font-family: var(--mono); font-size: 11px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--faint);
  margin: 0 0 12px;
}
.mono { font-family: var(--mono); }
.small { font-size: 13.5px; line-height: 1.6; }

section { padding: 68px 0; }
section + section { border-top: 1px solid var(--border); }

/* --- buttons -------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 50px; padding: 0 24px;
  border-radius: var(--radius); border: 1px solid var(--border-strong);
  background: var(--raised); color: var(--text);
  font-family: var(--sans); font-size: 16px; font-weight: 500;
  text-decoration: none; cursor: pointer;
}
.btn:hover { border-color: var(--accent); color: var(--text); }
.btn-primary { border-color: var(--accent); background: var(--accent-wash); color: var(--accent); }
.btn-primary:hover { background: rgba(169, 156, 240, 0.14); }

/* --- cards ---------------------------------------------------------------- */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 24px;
}
.grid { display: grid; gap: 16px; }
@media (min-width: 700px) { .grid-2 { grid-template-columns: 1fr 1fr; } }
@media (min-width: 860px) { .grid-3 { grid-template-columns: repeat(3, 1fr); } }

/* ==========================================================================
   STORE BADGES — placeholders, and deliberately NOT Apple's or Google's art.

   Both stores' brand guidelines require their official badge to link to a LIVE
   listing, and reproducing the artwork before one exists is a trademark
   problem on top of being a dead link. So these are the site's own tiles,
   clearly marked "coming to", in Walked's visual language and nobody else's.

   To go live: set `live` on the anchor (see assets/site.js), drop in the
   official SVGs from
     Apple  — developer.apple.com/app-store/marketing/guidelines/
     Google — play.google.com/intl/en_us/badges/
   and point href at the real listing. The markup slot is already the right
   shape, so that is a swap, not a rebuild.
   ========================================================================== */
.stores { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }
.store {
  display: flex; align-items: center; gap: 12px;
  min-width: 208px; padding: 11px 18px;
  border: 1px dashed var(--border-strong); border-radius: 12px;
  background: var(--surface); color: var(--text-2);
  text-decoration: none; cursor: not-allowed;
}
.store[data-live="true"] { border-style: solid; cursor: pointer; }
.store:hover { border-color: var(--accent-dim); }
.store svg { flex: none; opacity: .82; }
.store span { display: block; font-family: var(--mono); font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase; color: var(--faint); }
.store b { display: block; font-weight: 500; font-size: 15.5px; color: var(--text); letter-spacing: -.2px; }

/* --- notify form ---------------------------------------------------------- */
.notify { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
.notify input[type="email"] {
  flex: 1 1 260px; min-height: 50px; padding: 0 16px;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  font-family: var(--mono); font-size: 14px;
}
.notify input::placeholder { color: var(--faint); }
.notify input:focus { border-color: var(--accent); outline: none; }
.notify-note { font-family: var(--mono); font-size: 12px; color: var(--faint); margin-top: 12px; }
.notify-said { font-family: var(--mono); font-size: 13px; color: var(--positive); margin-top: 12px; }
.notify-said[data-bad="true"] { color: var(--caution); }

/* ==========================================================================
   PHONE FRAMES

   The screens inside are BUILT IN HTML from the app's real tokens, not
   photographed. That is honest for a marketing page and it stays pin-sharp at
   any density — but it is a recreation, so it can drift from the app if nobody
   maintains it.

   ⚠️ Before store submission these are replaced by real device captures: both
   stores REQUIRE genuine screenshots, and a store listing that shows a mockup
   is a rejection risk as well as a small lie.
   ========================================================================== */
.phones { display: flex; gap: 28px; flex-wrap: wrap; justify-content: center; }
.phone {
  width: 268px; flex: none;
  border-radius: 34px; padding: 9px;
  background: #0d0e16;
  border: 1px solid var(--border-strong);
  box-shadow: 0 22px 60px rgba(0,0,0,.45);
}

/* ==========================================================================
   THE STACK — phones overlapped, not lined up.

   A row of three screenshots is a spec sheet. Overlapping them with rotation,
   scale and a glow behind reads as one object with depth, and the eye lands on
   the middle one instead of scanning left to right. The two behind are dimmed
   and pushed back so they suggest "there is more in here" without competing.

   Built with transforms only — no images, no library, nothing to download.
   ========================================================================== */
.stage {
  position: relative;
  /* COLUMN, not row: the caption and dots are siblings of the stack and must
     sit under it. As a centring row they lined up beside the phones. */
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 660px; padding-bottom: 12px;
  isolation: isolate;
}
/* The depth cue that does the most work for the least weight. */
.stage::before {
  content: ""; position: absolute; z-index: 0;
  width: min(680px, 92%); aspect-ratio: 1;
  background: radial-gradient(circle, rgba(169, 156, 240,.20) 0%, rgba(169, 156, 240,.07) 42%, transparent 68%);
  filter: blur(12px);
  animation: breathe 11s ease-in-out infinite;
}
@keyframes breathe {
  0%, 100% { transform: scale(1); opacity: .85; }
  50%      { transform: scale(1.09); opacity: 1; }
}

.stack { position: relative; width: 100%; height: 600px; z-index: 1; }

/* ── SLOTS, NOT SOURCE ORDER ──────────────────────────────────────────────
   Position comes from `data-slot`, which the script rotates — not from
   `nth-of-type`. That is the whole carousel: the DOM never moves, only the
   attribute changes, so every transition is a pure transform between two
   states the browser can interpolate. Reordering elements instead would make
   the phones jump rather than travel, and would move focus out from under
   anyone using a keyboard. */
.stack .phone {
  position: absolute; top: 0; left: 50%;
  transform-origin: 50% 60%;
  transition: transform .72s var(--ease), opacity .72s var(--ease), filter .72s var(--ease);
  will-change: transform;
  cursor: pointer;
}
.stack .phone[data-slot="left"] {
  transform: translateX(calc(-50% - 190px)) rotate(-8deg) scale(.83);
  opacity: .5; z-index: 1; filter: saturate(.75) brightness(.8);
}
.stack .phone[data-slot="right"] {
  transform: translateX(calc(-50% + 190px)) rotate(8deg) scale(.83);
  opacity: .5; z-index: 1; filter: saturate(.75) brightness(.8);
}
/* The selected one comes fully forward — upright, full colour, readable.
   Bringing it "slightly" forward was the bug: two of three screens could
   never actually be read, which defeats showing three screens. */
.stack .phone[data-slot="center"] {
  transform: translateX(-50%) translateY(-14px) scale(1.02);
  opacity: 1; z-index: 3; filter: none;
  box-shadow: 0 40px 90px rgba(0,0,0,.6), 0 0 0 1px rgba(169, 156, 240,.22);
  animation: hover-drift 7s ease-in-out infinite;
  cursor: default;
}
@keyframes hover-drift {
  0%, 100% { margin-top: 0; }
  50%      { margin-top: -13px; }
}
/* Pointer affordance on the two that are actually clickable. */
.stack .phone[data-slot="left"]:hover  { transform: translateX(calc(-50% - 206px)) rotate(-6deg) scale(.88); opacity: .8; filter: none; }
.stack .phone[data-slot="right"]:hover { transform: translateX(calc(-50% + 206px)) rotate(6deg) scale(.88); opacity: .8; filter: none; }
.stack .phone:focus-visible { outline: 2px solid var(--accent); outline-offset: 8px; }

/* --- caption + dots --------------------------------------------------- */
.stack-bar {
  position: relative; z-index: 4;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  margin-top: 8px;
}
.stack-cap { font-family: var(--mono); font-size: 13px; color: var(--text-2); margin: 0; text-align: center; }
.stack-cap b { color: var(--text); font-weight: 500; }
.stack-dots { display: flex; gap: 9px; }
.stack-dots button {
  width: 34px; height: 4px; padding: 0; border: 0; border-radius: 99px;
  background: rgba(233,233,237,.16); cursor: pointer;
  transition: background-color .5s var(--ease), width .5s var(--ease);
}
.stack-dots button[aria-current="true"] { background: var(--accent); width: 52px; }
.stack-hint { font-family: var(--mono); font-size: 11px; color: var(--faint); margin: 0; }

@media (max-width: 900px) {
  .stage { min-height: 560px; }
  .stack { height: 520px; }
  .stack .phone { zoom: .84; }
  .stack .phone[data-slot="left"]  { transform: translateX(calc(-50% - 128px)) rotate(-9deg) scale(.8); opacity: .38; }
  .stack .phone[data-slot="right"] { transform: translateX(calc(-50% + 128px)) rotate(9deg) scale(.8); opacity: .38; }
}
@media (max-width: 560px) {
  .stage { min-height: 500px; }
  .stack { height: 470px; }
  .stack .phone { zoom: .74; }
  /* Tighter fan: the outer two are a hint of an edge to tap, not a screen to
     read. Tapping one brings it fully forward, which is how you read it. */
  .stack .phone[data-slot="left"]  { transform: translateX(calc(-50% - 96px)) rotate(-10deg) scale(.78); opacity: .3; }
  .stack .phone[data-slot="right"] { transform: translateX(calc(-50% + 96px)) rotate(10deg) scale(.78); opacity: .3; }
}

/* ==========================================================================
   MOVEMENT — reveal on scroll.

   Everything is VISIBLE BY DEFAULT and the script opts elements into being
   hidden. A reveal effect that starts from `opacity: 0` in CSS leaves the
   whole page blank for anyone whose JavaScript did not run, which is a far
   worse outcome than no animation.
   ========================================================================== */
.rise { opacity: 1; transform: none; }
.js .rise {
  opacity: 0; transform: translateY(22px);
  transition: opacity .7s cubic-bezier(.22,.7,.3,1), transform .7s cubic-bezier(.22,.7,.3,1);
}
.js .rise.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .stage::before, .stack .phone[data-slot="center"] { animation: none; }
  .js .rise { opacity: 1; transform: none; transition: none; }
  /* The carousel still WORKS with reduced motion — it just cuts rather than
     travels. Disabling the interaction would remove the only way to read the
     two side screens. */
  .stack .phone { transition: none; }
}
.phone-screen {
  border-radius: 26px; overflow: hidden;
  background: var(--bg); height: 545px;
  display: flex; flex-direction: column;
  position: relative;
}
.phone-notch {
  position: absolute; top: 9px; left: 50%; transform: translateX(-50%);
  width: 76px; height: 5px; border-radius: 3px; background: rgba(255,255,255,.14);
}
.phone-cap {
  text-align: center; font-family: var(--mono); font-size: 12px;
  color: var(--muted); margin-top: 14px;
}
.scr { padding: 30px 16px 14px; flex: 1; display: flex; flex-direction: column; gap: 10px; }
.scr-h { font-size: 17px; font-weight: 500; letter-spacing: -.3px; }
.scr-eyebrow { font-family: var(--mono); font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--faint); }
.scr-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 10px; }
.scr-money { font-size: 25px; font-weight: 500; letter-spacing: -.7px; font-variant-numeric: tabular-nums; }
.scr-sm { font-family: var(--mono); font-size: 10px; color: var(--muted); }
.scr-faint { font-family: var(--mono); font-size: 9.5px; color: var(--faint); }
.scr-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.scr-tile { background: var(--surface); border: 1px solid var(--border); border-radius: 9px; padding: 8px; }
.scr-tile .v { font-size: 15px; font-weight: 500; letter-spacing: -.3px; font-variant-numeric: tabular-nums; margin-top: 2px; }
.scr-tile .v.dash { font-family: var(--mono); color: var(--muted); }

/* the little bar chart inside the Stats phone */
.scr-chart { display: flex; align-items: flex-end; gap: 4px; height: 74px; }
.scr-chart i { flex: 1; background: var(--accent-dim); border-radius: 2px; display: block; }
.scr-chart i.on { background: var(--accent); }
.scr-chart i.gap { height: 2px !important; background: var(--border); }

/* weekday rows */
.scr-row { display: flex; align-items: center; gap: 7px; }
.scr-row .d { font-family: var(--mono); font-size: 10px; color: var(--text-2); width: 22px; }
.scr-row .t { flex: 1; height: 5px; border-radius: 3px; background: var(--raised); overflow: hidden; }
.scr-row .t i { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.scr-row .v { font-family: var(--mono); font-size: 10px; width: 52px; text-align: right; }
.scr-row .n { font-family: var(--mono); font-size: 10px; width: 18px; text-align: right; color: var(--text-2); }

/* keypad */
.scr-keys { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; background: var(--surface); margin: 0 -16px -14px; padding: 10px 16px 16px; }
.scr-keys b { background: var(--raised); border-radius: 8px; text-align: center; padding: 9px 0; font-size: 16px; font-weight: 500; }

/* month grid */
.scr-month { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.scr-month i {
  aspect-ratio: 1; border-radius: 5px; background: var(--surface);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 8.5px; color: var(--faint); font-style: normal;
}
.scr-month i.has { background: var(--accent-wash); border: 1px solid var(--accent-dim); color: var(--text-2); }
/* The WEEK the gap card is asking about — a whole row, because the check is
   weekly. Marking a single day would draw the eye to a claim the app cannot
   make. Dashed, because it is a question, not a verdict. */
.scr-month i.wk { border: 1px dashed rgba(217,187,132,.45); }
.scr-month i.wk.has { border-style: solid; }

/* --- lists / steps -------------------------------------------------------- */
ol.steps { counter-reset: s; list-style: none; padding: 0; margin: 0; }
ol.steps > li {
  counter-increment: s; position: relative;
  padding: 0 0 22px 46px; margin: 0;
}
ol.steps > li::before {
  content: counter(s); position: absolute; left: 0; top: 0;
  width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid var(--accent-dim); color: var(--accent);
  font-family: var(--mono); font-size: 13px;
  display: flex; align-items: center; justify-content: center;
}
ol.steps h3 { margin-bottom: 4px; }

.kv { border-collapse: collapse; width: 100%; font-size: 14.5px; }
.kv th, .kv td { text-align: left; padding: 11px 12px; border-bottom: 1px solid var(--border); vertical-align: top; }
.kv th { font-family: var(--mono); font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--faint); font-weight: 400; }
.kv td:first-child { font-family: var(--mono); font-size: 13px; color: var(--text-2); white-space: nowrap; }
.table-scroll { overflow-x: auto; }

.callout {
  border-left: 2px solid var(--accent); background: var(--accent-wash);
  padding: 16px 20px; border-radius: 0 10px 10px 0; margin: 24px 0;
}
.callout.warn { border-left-color: var(--caution); background: rgba(217, 187, 132, .05); }

/* --- footer --------------------------------------------------------------- */
.site-foot {
  border-top: 1px solid var(--border); padding: 40px 0 56px;
  font-family: var(--mono); font-size: 12.5px; color: var(--faint);
}
.site-foot nav { display: flex; gap: 20px; flex-wrap: wrap; margin-bottom: 16px; }
.site-foot a { color: var(--muted); text-decoration: none; }
.site-foot a:hover { color: var(--accent); }

/* ══════════════════════════════════════════════════════════════════════════
   PREMIUM LAYER — added 2026-09-02, second design pass.

   Applied from the `high-end-visual-design` skill: nested "double-bezel"
   enclosures, squircle radii, macro whitespace, spring-physics easing,
   button-in-button CTAs, and a blur-resolving scroll reveal.

   ⚠️ ONE RULE OF THAT SKILL IS DELIBERATELY NOT FOLLOWED: it bans Inter.
   Walked's design spec §1.1 makes Inter and JetBrains Mono load-bearing —
   "Inter states what the app knows, JetBrains Mono states what the app
   measured" — and the app ships custom tabular-figure Inter builds. Swapping
   the marketing site to a display face would make it a different product to
   the thing it markets. Where generic taste guidance and this product's own
   ratified identity disagree, the product wins.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Spring-ish. Overshoot-free but heavy — things arrive, they don't snap. */
  --ease: cubic-bezier(.32, .72, 0, 1);
  --r-shell: 30px;
  --r-core: 24px;   /* concentric: shell minus the 6px bezel */
}

/* --- film grain. Fixed, pointer-events-none, never on a scrolling layer. --- */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 40; pointer-events: none;
  opacity: .028; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --- the header becomes a floating glass island, detached from the edge --- */
.site-head {
  margin: 22px auto 0; padding: 10px 12px 10px 20px;
  border-bottom: 0;
  border: 1px solid rgba(233,233,237,.09);
  border-radius: 999px;
  background: rgba(27,29,44,.62);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  box-shadow: 0 1px 0 rgba(255,255,255,.05) inset, 0 18px 44px rgba(0,0,0,.34);
}
.site-nav a {
  padding: 8px 13px; border-radius: 999px;
  transition: color .45s var(--ease), background-color .45s var(--ease);
}
.site-nav a:hover, .site-nav a[aria-current="page"] { background: rgba(169, 156, 240,.10); }
@media (max-width: 620px) {
  .site-head { border-radius: var(--r-core); padding: 14px 16px; }
}

/* --- macro whitespace. The page has to breathe or none of this reads. --- */
section { padding: 116px 0; }
@media (max-width: 700px) { section { padding: 78px 0; } }

/* --- eyebrow becomes a pill badge --- */
.eyebrow {
  display: inline-block; margin-bottom: 22px;
  padding: 6px 14px; border-radius: 999px;
  border: 1px solid rgba(169, 156, 240,.24);
  background: rgba(169, 156, 240,.07);
  color: var(--accent); letter-spacing: .2em;
}

/* ── DOUBLE BEZEL ─────────────────────────────────────────────────────────
   Nothing premium sits flat on the background. The card reads as a plate
   seated in a machined tray: a lit top edge, a hairline, then two spread-only
   rings standing off the body.

   BUILT FROM RINGS, NOT FROM AN INNER ELEMENT WITH MARGINS. The first attempt
   used an inset ::before and pushed the content in with child margins — which
   any `style="margin:0"` in the markup silently defeats, dropping the text
   flat against the edge. Several cards on the other pages have exactly that.
   Shadows cannot be overridden by a child, so this version cannot come apart
   no matter what the content does. */
.card {
  position: relative;
  padding: 28px;
  border-radius: var(--r-shell);
  background: linear-gradient(180deg, rgba(35,37,50,.94), rgba(27,29,44,.94));
  border: 1px solid rgba(233,233,237,.075);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.055),
    0 0 0 6px rgba(233,233,237,.028),
    0 0 0 7px rgba(233,233,237,.055),
    0 26px 60px rgba(0,0,0,.34);
  transition: transform .6s var(--ease), box-shadow .6s var(--ease);
}
.card:hover {
  transform: translateY(-4px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.07),
    0 0 0 6px rgba(169, 156, 240,.06),
    0 0 0 7px rgba(169, 156, 240,.26),
    0 34px 70px rgba(0,0,0,.42);
}
/* The rings live outside the border box, so the grid needs room for them. */
.grid { gap: 26px; }

/* --- store tiles, same architecture --- */
.store {
  border-radius: 999px; padding: 13px 22px;
  background: rgba(233,233,237,.035);
  border: 1px solid rgba(233,233,237,.09);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
  transition: transform .5s var(--ease), border-color .5s var(--ease);
}
.store[data-live="true"]:hover { transform: translateY(-2px); border-color: rgba(169, 156, 240,.4); }

/* ── BUTTON-IN-BUTTON ─────────────────────────────────────────────────────
   The arrow never floats naked beside the label; it lives in its own disc,
   flush to the inner padding, and drifts on hover so the button has internal
   kinetic tension rather than just a colour change. */
.btn {
  border-radius: 999px; padding: 0 8px 0 26px; min-height: 54px; gap: 14px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
  transition: transform .5s var(--ease), background-color .5s var(--ease), border-color .5s var(--ease);
}
.btn:active { transform: scale(.978); }
.btn .disc {
  width: 34px; height: 34px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px; background: rgba(233,233,237,.08);
  font-size: 14px; line-height: 1;
  transition: transform .5s var(--ease), background-color .5s var(--ease);
}
.btn:hover .disc { transform: translate(3px, -1px) scale(1.06); background: rgba(169, 156, 240,.22); }
.btn-primary .disc { background: rgba(169, 156, 240,.18); }
/* A button with no trailing disc keeps symmetric padding. */
.btn:not(:has(.disc)) { padding: 0 28px; }

/* --- notify field, bezelled to match --- */
.notify input[type="email"] {
  border-radius: 999px; padding: 0 22px; min-height: 54px;
  background: rgba(233,233,237,.035);
  border: 1px solid rgba(233,233,237,.09);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
  transition: border-color .5s var(--ease);
}

/* ── REVEAL — resolves out of blur, not just opacity ────────────────────── */
.js .rise {
  opacity: 0; transform: translateY(30px); filter: blur(7px);
  transition: opacity .95s var(--ease), transform .95s var(--ease), filter .95s var(--ease);
}
.js .rise.in { opacity: 1; transform: none; filter: blur(0); }

@media (prefers-reduced-motion: reduce) {
  .js .rise { opacity: 1; transform: none; filter: none; transition: none; }
  .card:hover, .btn:hover .disc, .store:hover { transform: none; }
}

/* ── STATS BARS — grow in rather than appear pre-filled ────────────────────
   Same progressive-enhancement rule as .rise: a no-JS visitor, or a script
   that fails to run, sees the finished chart immediately. Only `.js` collapses
   the bars, and only `site.js` decides when to grow them back — see the
   "PLAY THE STATS SCREEN" section there. Animated via `transform` only, never
   height/width, so this never triggers layout during the transition. */
.js .scr-chart i:not(.gap) {
  transform: scaleY(0); transform-origin: bottom;
  transition: transform .64s var(--ease);
}
.js .scr-chart i.grown:not(.gap) { transform: scaleY(1); }

.js .scr-row .t i {
  transform: scaleX(0); transform-origin: left;
  transition: transform .64s var(--ease);
}
.js .scr-row .t i.grown { transform: scaleX(1); }

@media (prefers-reduced-motion: reduce) {
  .js .scr-chart i:not(.gap), .js .scr-row .t i { transform: none; transition: none; }
}

/* Macro whitespace does the separating now — hairline dividers between
   sections read as a documentation template, not a product page. */
section + section { border-top: 0; }

/* The glass island goes vertical on narrow screens. Left as a single flex row
   it wraps into ragged columns — the mark floats mid-height while the four
   links break across three lines, which reads as broken rather than compact. */
@media (max-width: 620px) {
  .site-head { flex-direction: column; align-items: flex-start; gap: 12px; padding: 16px; }
  .site-nav { margin-left: 0; width: 100%; gap: 4px; }
  .site-nav a { padding: 7px 11px; }
  .mark b { font-size: 22px; }
}

/* --- guide screenshots ---------------------------------------------------- */
.shot-fig { margin: 0; max-width: 300px; }
.shot {
  display: block; width: 100%; height: auto;
  border-radius: 20px; border: 1px solid var(--border-strong);
  box-shadow: 0 18px 44px rgba(0,0,0,.4);
}
.shotcap { font-family: var(--mono); font-size: 12px; line-height: 1.5; color: var(--faint); margin-top: 12px; }
