/* 00-tokens.css */
/* Tokens, reset and type.
 *
 * Every value here is taken from the app's own brand kit (docs/fnder-ad-brief.md)
 * and theme (lib/app/theme/app_colors.dart) so the site and the product are
 * recognisably the same thing: the warm off-white ground, the single green
 * accent, the red reserved for the pin, Inter for type and Open Sans for long
 * sentences.
 *
 * The one rule worth restating from the app: the green is a FILL colour, not a
 * text colour. At #21C063 on near-white it is 2.3:1 — enough to pick a button
 * out by, nowhere near enough to read. Anything that has to be read uses
 * --accent-ink, which is the same hue taken down to 4.8:1.
 */

:root {
  color-scheme: light dark;

  /* brand */
  --accent: #21c063;
  --accent-ink: #0f7a3d;
  --accent-strong: #157a3f;
  --on-accent: #06291a;
  --brand-red: #ee262a;

  /* light ground */
  --bg: #faf9f5;
  --bg-sunk: #f2f0e8;
  --surface: #ffffff;
  --surface-2: #f6f4ee;
  --line: #e7e3d8;
  --line-strong: #d8d3c5;

  --ink: #1c1c1e;
  --ink-2: #46464a;
  --ink-3: #6e6e73;

  --accent-wash: #e9f9ef;
  --shadow-sm: 0 1px 2px rgb(28 28 30 / 0.05), 0 1px 1px rgb(28 28 30 / 0.04);
  --shadow-md: 0 4px 16px -4px rgb(28 28 30 / 0.1), 0 2px 6px -2px rgb(28 28 30 / 0.06);
  --shadow-lg: 0 24px 48px -24px rgb(28 28 30 / 0.22), 0 8px 24px -12px rgb(28 28 30 / 0.1);
  --shadow-phone: 0 48px 80px -40px rgb(28 28 30 / 0.4), 0 12px 32px -16px rgb(28 28 30 / 0.18);

  /* category tints, straight from ListingCategory */
  --cat-sale-bg: #e7faec;      --cat-sale-ink: #1b7a38;
  --cat-rent-bg: #eeeefb;      --cat-rent-ink: #3e3ca6;
  --cat-service-bg: #fff3e0;   --cat-service-ink: #a35e00;
  --cat-job-bg: #e6f1ff;       --cat-job-ink: #0059b8;
  --cat-free-bg: #fff8de;      --cat-free-ink: #8a6d00;
  --cat-wanted-bg: #ffeceb;    --cat-wanted-ink: #b3261e;

  /* type */
  --font-ui: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-body: "Open Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --step--1: clamp(0.82rem, 0.8rem + 0.1vw, 0.88rem);
  --step-0: clamp(1rem, 0.97rem + 0.14vw, 1.08rem);
  --step-1: clamp(1.15rem, 1.08rem + 0.34vw, 1.35rem);
  --step-2: clamp(1.38rem, 1.24rem + 0.68vw, 1.8rem);
  --step-3: clamp(1.7rem, 1.42rem + 1.36vw, 2.5rem);
  --step-4: clamp(2.1rem, 1.6rem + 2.4vw, 3.5rem);
  --step-5: clamp(2.3rem, 1.6rem + 3.2vw, 3.9rem);

  /* space and shape */
  --gutter: clamp(1rem, 0.6rem + 2vw, 2rem);
  --shell: 1180px;
  --radius-sm: 10px;
  --radius: 16px;
  --radius-lg: 24px;
  --radius-xl: 32px;

  --section-y: clamp(4rem, 2.5rem + 6vw, 7.5rem);
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Dark is the app's dark: a true near-black ground, cards one step up from it,
 * and the accent used for text as well as fills because at #21C063 on #0B0B0B
 * it reads at 8.3:1. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0b0b0b;
    --bg-sunk: #080808;
    --surface: #17181a;
    --surface-2: #242626;
    --line: #2c2c2c;
    --line-strong: #3a3b3b;

    --ink: #fafafa;
    --ink-2: #d6d6d6;
    --ink-3: #949494;

    --accent-ink: #4ed88a;
    --accent-strong: #21c063;
    --accent-wash: #11291d;

    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.5);
    --shadow-md: 0 4px 16px -4px rgb(0 0 0 / 0.6);
    --shadow-lg: 0 24px 48px -24px rgb(0 0 0 / 0.8), 0 8px 24px -12px rgb(0 0 0 / 0.5);
    --shadow-phone: 0 48px 80px -40px rgb(0 0 0 / 0.9), 0 12px 32px -16px rgb(0 0 0 / 0.6);

    --cat-sale-bg: #13301f;      --cat-sale-ink: #8fe9b4;
    --cat-rent-bg: #1d1d33;      --cat-rent-ink: #b5b3f5;
    --cat-service-bg: #2e2716;   --cat-service-ink: #f0c678;
    --cat-job-bg: #13243a;       --cat-job-ink: #8fc2ff;
    --cat-free-bg: #2e2716;      --cat-free-ink: #e8cb78;
    --cat-wanted-bg: #351c1b;    --cat-wanted-ink: #ff9d96;
  }
}

:root[data-theme="dark"] {
  --bg: #0b0b0b;
  --bg-sunk: #080808;
  --surface: #17181a;
  --surface-2: #242626;
  --line: #2c2c2c;
  --line-strong: #3a3b3b;

  --ink: #fafafa;
  --ink-2: #d6d6d6;
  --ink-3: #949494;

  --accent-ink: #4ed88a;
  --accent-strong: #21c063;
  --accent-wash: #11291d;

  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.5);
  --shadow-md: 0 4px 16px -4px rgb(0 0 0 / 0.6);
  --shadow-lg: 0 24px 48px -24px rgb(0 0 0 / 0.8), 0 8px 24px -12px rgb(0 0 0 / 0.5);
  --shadow-phone: 0 48px 80px -40px rgb(0 0 0 / 0.9), 0 12px 32px -16px rgb(0 0 0 / 0.6);

  --cat-sale-bg: #13301f;      --cat-sale-ink: #8fe9b4;
  --cat-rent-bg: #1d1d33;      --cat-rent-ink: #b5b3f5;
  --cat-service-bg: #2e2716;   --cat-service-ink: #f0c678;
  --cat-job-bg: #13243a;       --cat-job-ink: #8fc2ff;
  --cat-free-bg: #2e2716;      --cat-free-ink: #e8cb78;
  --cat-wanted-bg: #351c1b;    --cat-wanted-ink: #ff9d96;
}

/* --------------------------------------------------------------------------
   fonts
   -------------------------------------------------------------------------- */
/* Both are variable faces, latin subset, served from this origin — see
   tool/fetch-fonts.mjs. `swap` so first paint never waits on them. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/fonts/inter-latin.woff2") format("woff2");
}

@font-face {
  font-family: "Open Sans";
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url("/assets/fonts/open-sans-latin.woff2") format("woff2");
}

/* --------------------------------------------------------------------------
   reset
   -------------------------------------------------------------------------- */

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchor targets clear the sticky header instead of hiding under it. */
  scroll-padding-top: 5.5rem;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg, video, canvas { display: block; max-width: 100%; }
img { height: auto; }

button, input, textarea, select { font: inherit; color: inherit; }

a { color: var(--accent-ink); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-strong); }

h1, h2, h3, h4 {
  font-family: var(--font-ui);
  font-weight: 650;
  line-height: 1.12;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

p { text-wrap: pretty; }

ul, ol { padding-left: 1.2em; }

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

::selection { background: var(--accent); color: var(--on-accent); }

.skip-link {
  position: absolute;
  left: 50%;
  top: 0.5rem;
  translate: -50% -200%;
  z-index: 100;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.6rem 1rem;
  font-weight: 600;
  text-decoration: none;
  box-shadow: var(--shadow-md);
  transition: translate 0.2s var(--ease);
}
/* :focus, not :focus-visible. A skip link is reached by Tab and by nothing
 * else, so there is no mouse case to hide it from — and :focus-visible does
 * not match a focus() call, which made it untestable as well as fragile. */
.skip-link:focus { translate: -50% 0; }

/* Screen-reader-only, for the labels that explain a graphic. */
.vh {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* 10-layout.css */
/* The frame: shell, section rhythm, header, footer. */

.shell {
  width: min(100% - (var(--gutter) * 2), var(--shell));
  margin-inline: auto;
}

.shell--narrow { --shell: 760px; }

section { position: relative; }

.section { padding-block: var(--section-y); }
.section--sunk { background: var(--bg-sunk); }
.section--tight { padding-block: clamp(3rem, 2rem + 4vw, 5rem); }

/* A section's standing head: eyebrow, title, one line of lead. */
.section-head {
  max-width: 62ch;
  margin-bottom: clamp(2rem, 1.4rem + 2.4vw, 3.5rem);
}
.section-head--center { margin-inline: auto; text-align: center; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin-bottom: 0.9rem;
}
.eyebrow::before {
  content: "";
  width: 1.6em;
  height: 2px;
  background: var(--accent);
  border-radius: 2px;
}
.section-head--center .eyebrow::before { display: none; }

.section-title {
  font-size: var(--step-3);
  margin-bottom: 0.9rem;
}

.section-lead {
  font-family: var(--font-body);
  font-size: var(--step-1);
  line-height: 1.55;
  color: var(--ink-2);
}

/* --------------------------------------------------------------------------
   header
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: saturate(1.6) blur(14px);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s var(--ease), background 0.25s var(--ease);
}
.site-header.is-stuck {
  border-bottom-color: var(--line);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 4.25rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  text-decoration: none;
  color: var(--ink);
  font-weight: 700;
  letter-spacing: -0.03em;
  font-size: 1.3rem;
  line-height: 1;
}
.brand__mark { width: 1.45em; height: auto; }
.brand:hover { color: var(--ink); }
.brand--footer { font-size: 1.5rem; }

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

.site-nav__list {
  display: flex;
  align-items: center;
  gap: clamp(0.5rem, 0.1rem + 1.1vw, 1.4rem);
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-nav__list a {
  display: inline-block;
  padding: 0.5rem 0.25rem;
  color: var(--ink-2);
  font-size: 0.95rem;
  font-weight: 500;
  text-decoration: none;
  position: relative;
}
.site-nav__list a::after {
  content: "";
  position: absolute;
  left: 0.25rem; right: 0.25rem; bottom: 0.25rem;
  height: 2px;
  background: var(--accent);
  border-radius: 2px;
  scale: 0 1;
  transform-origin: left;
  transition: scale 0.25s var(--ease);
}
.site-nav__list a:hover { color: var(--ink); }
.site-nav__list a:hover::after,
.site-nav__list a[aria-current="page"]::after { scale: 1 1; }
.site-nav__list a[aria-current="page"] { color: var(--ink); }

.site-header__actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-left: 0.4rem;
}

.theme-toggle {
  display: grid;
  place-items: center;
  width: 2.3rem;
  height: 2.3rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease),
              background 0.2s var(--ease);
}
.theme-toggle:hover { color: var(--ink); border-color: var(--line-strong); }
.theme-toggle > svg { grid-area: 1 / 1; }
.theme-toggle__moon { display: none; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle__sun { display: none; }
  :root:not([data-theme="light"]) .theme-toggle__moon { display: block; }
}
:root[data-theme="dark"] .theme-toggle__sun { display: none; }
:root[data-theme="dark"] .theme-toggle__moon { display: block; }
:root[data-theme="light"] .theme-toggle__sun { display: block; }
:root[data-theme="light"] .theme-toggle__moon { display: none; }

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 2.4rem;
  height: 2.4rem;
  padding: 0 0.45rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
}
.nav-toggle__bar {
  display: block;
  height: 2px;
  background: var(--ink);
  border-radius: 2px;
  transition: translate 0.25s var(--ease), rotate 0.25s var(--ease),
              opacity 0.15s var(--ease);
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) { translate: 0 7px; rotate: 45deg; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) { translate: 0 -7px; rotate: -45deg; }

@media (max-width: 860px) {
  .nav-toggle { display: flex; }
  .site-header__cta { display: none; }

  .site-nav {
    position: fixed;
    inset: 4.25rem 0 auto;
    margin: 0;
    background: var(--bg);
    border-bottom: 1px solid var(--line);
    padding: 0.5rem var(--gutter) 1.5rem;
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    visibility: hidden;
    transition: grid-template-rows 0.3s var(--ease), opacity 0.2s var(--ease),
                visibility 0.3s;
  }
  .site-nav.is-open {
    grid-template-rows: 1fr;
    opacity: 1;
    visibility: visible;
    box-shadow: var(--shadow-lg);
  }
  .site-nav__list {
    overflow: hidden;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  .site-nav__list a {
    padding: 0.9rem 0.25rem;
    font-size: 1.05rem;
    border-bottom: 1px solid var(--line);
  }
  .site-nav__list a::after { display: none; }
  .site-nav__list li:last-child a { border-bottom: 0; }
}

/* --------------------------------------------------------------------------
   footer
   -------------------------------------------------------------------------- */

.site-footer {
  background: var(--surface-2);
  border-top: 1px solid var(--line);
  padding-block: clamp(3rem, 2rem + 4vw, 4.5rem) 2rem;
  margin-top: var(--section-y);
}

.site-footer__inner {
  display: grid;
  gap: clamp(2rem, 1rem + 4vw, 4rem);
}

@media (min-width: 900px) {
  .site-footer__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr); }
  .site-footer__bar { grid-column: 1 / -1; }
}

.site-footer__blurb {
  font-family: var(--font-body);
  color: var(--ink-2);
  max-width: 38ch;
  margin-top: 1rem;
  font-size: 0.95rem;
}

.site-footer__status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1.1rem;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--ink-3);
}
.dot {
  width: 0.5rem; height: 0.5rem;
  border-radius: 999px;
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}

.site-footer__nav {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 2rem 1.5rem;
}
.site-footer__heading {
  font-size: 0.8rem;
  font-weight: 650;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 0.9rem;
}
.site-footer__col ul {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.55rem;
}
.site-footer__col a {
  color: var(--ink-2);
  text-decoration: none;
  font-size: 0.93rem;
}
.site-footer__col a:hover { color: var(--accent-ink); text-decoration: underline; }
.site-footer__note {
  margin-top: 0.9rem;
  font-size: 0.8rem;
  color: var(--ink-3);
  max-width: 28ch;
}

.site-footer__bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--line);
  font-size: 0.85rem;
  color: var(--ink-3);
}


/* 20-components.css */
/* Buttons, pills, cards — the pieces every section is assembled from. */

.btn {
  --btn-bg: var(--surface);
  --btn-ink: var(--ink);
  --btn-line: var(--line-strong);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  padding: 0.85em 1.5em;
  border: 1px solid var(--btn-line);
  border-radius: 999px;
  background: var(--btn-bg);
  color: var(--btn-ink);
  font-size: 0.98rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: translate 0.18s var(--ease), box-shadow 0.18s var(--ease),
              background 0.18s var(--ease), border-color 0.18s var(--ease);
}
.btn:hover { translate: 0 -2px; box-shadow: var(--shadow-md); color: var(--btn-ink); }
.btn:active { translate: 0; box-shadow: none; }

/* The accent as a fill, with the near-black ink the app uses on top of it —
 * white on this green is 2.4:1 and unreadable. */
.btn--primary {
  --btn-bg: var(--accent);
  --btn-ink: var(--on-accent);
  --btn-line: transparent;
  box-shadow: 0 1px 2px rgb(6 41 26 / 0.18);
}
.btn--primary:hover { --btn-bg: #1cae59; }

.btn--ghost { --btn-bg: transparent; --btn-line: var(--line-strong); }
.btn--ghost:hover { --btn-bg: var(--surface); }

.btn--sm { padding: 0.6em 1.1em; font-size: 0.9rem; }
.btn--lg { padding: 1em 1.9em; font-size: 1.05rem; }

.btn__icon { width: 1.15em; height: 1.15em; flex: none; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
}

/* A pill that states a fact — "2, 5 or 10 km", "no trackers". */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.4em 0.85em;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 0.85rem;
  font-weight: 550;
  color: var(--ink-2);
}
.pill--accent {
  background: var(--accent-wash);
  border-color: color-mix(in srgb, var(--accent) 28%, transparent);
  color: var(--accent-ink);
}
.pill__dot {
  width: 0.45em; height: 0.45em;
  border-radius: 999px;
  background: var(--accent);
  flex: none;
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.25rem, 1rem + 1vw, 1.9rem);
  position: relative;
  overflow: hidden;
  transition: translate 0.3s var(--ease), box-shadow 0.3s var(--ease),
              border-color 0.3s var(--ease);
}
.card__title {
  font-size: var(--step-1);
  margin-bottom: 0.45rem;
  letter-spacing: -0.02em;
}
.card__text {
  font-family: var(--font-body);
  color: var(--ink-2);
  font-size: 0.95rem;
  line-height: 1.6;
}

/* The icon plate at the top of a feature card. The tint pair is set per card
 * from the category's own two colours, so the grid reads like the app's
 * category chips rather than like a stock icon set. */
.card__plate {
  width: 3rem;
  height: 3rem;
  display: grid;
  place-items: center;
  border-radius: 14px;
  background: var(--tint-bg, var(--accent-wash));
  color: var(--tint-ink, var(--accent-ink));
  margin-bottom: 1.1rem;
  transition: rotate 0.4s var(--ease), scale 0.4s var(--ease);
}
.card__plate svg { width: 1.5rem; height: 1.5rem; }

.card--interactive:hover {
  translate: 0 -4px;
  box-shadow: var(--shadow-lg);
  border-color: color-mix(in srgb, var(--tint-ink, var(--accent)) 35%, var(--line));
}
.card--interactive:hover .card__plate { rotate: -4deg; scale: 1.06; }

/* A quiet band of facts under a heading. */
.fact-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.6rem;
}

.note {
  display: flex;
  gap: 0.9rem;
  padding: 1.1rem 1.25rem;
  border-radius: var(--radius);
  background: var(--accent-wash);
  border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
  font-size: 0.93rem;
  color: var(--ink-2);
  font-family: var(--font-body);
}
.note svg { flex: none; width: 1.25rem; height: 1.25rem; color: var(--accent-ink); margin-top: 0.15rem; }
.note strong { color: var(--ink); font-family: var(--font-ui); }

.note--plain {
  background: var(--surface-2);
  border-color: var(--line);
}
.note--plain svg { color: var(--ink-3); }

/* Icons are <use> references into the sprite at the top of the body; the
 * class only has to size them and let them inherit colour. */
.i {
  width: 1em;
  height: 1em;
  flex: none;
}


/* 30-phone.css */
/* The device mockup and the app UI drawn inside it.
 *
 * These are recreations of the shipped screens, built from the real widget
 * layout (lib/features/.../listing_card.dart, feed_header.dart) and the real
 * tokens — the same card structure, the same category pills, the same quiet
 * counts line. Drawn in CSS rather than dropped in as PNGs for three reasons:
 * they stay crisp at any density, they follow the site's theme the way the app
 * follows the device's, and they cost no image bytes at all.
 *
 * Everything inside `.phone__screen` is marked aria-hidden in the markup and
 * described by a caption, because a screen reader should get the sentence, not
 * a transcription of a user interface.
 */

.phone {
  --phone-w: 300px;
  --screen-bg: var(--bg);
  --screen-card: var(--surface);
  --screen-sunk: var(--bg-sunk);

  position: relative;
  width: var(--phone-w);
  aspect-ratio: 1080 / 2190;
  border-radius: 42px;
  padding: 9px;
  background: linear-gradient(160deg, #3a3b3f, #17181a 40%, #0d0e10);
  box-shadow: var(--shadow-phone), inset 0 0 0 1px rgb(255 255 255 / 0.1);
  flex: none;
}

/* The side buttons. Small thing; its absence is what makes a mockup look like
 * a rounded rectangle rather than a phone. */
.phone::before,
.phone::after {
  content: "";
  position: absolute;
  left: -2px;
  width: 2px;
  border-radius: 2px 0 0 2px;
  background: #27282b;
}
.phone::before { top: 110px; height: 28px; }
.phone::after { top: 152px; height: 46px; }

.phone__screen {
  position: relative;
  height: 100%;
  border-radius: 34px;
  overflow: hidden;
  background: var(--screen-bg);
  display: flex;
  flex-direction: column;
  font-size: 10px;
  line-height: 1.35;
  color: var(--ink);
}

/* Punch-hole camera, as on the device these screens were captured from. */
.phone__cam {
  position: absolute;
  top: 10px;
  left: 50%;
  translate: -50% 0;
  width: 7px; height: 7px;
  border-radius: 999px;
  background: #0b0b0c;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.12);
  z-index: 5;
}

/* --------------------------------------------------------------------------
   status bar
   -------------------------------------------------------------------------- */

.ui-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 9px 14px 3px;
  font-size: 9px;
  font-weight: 600;
  color: var(--ink);
  flex: none;
}
.ui-status__icons { display: flex; align-items: center; gap: 3px; }
.ui-status__icons svg { width: 9px; height: 9px; }

/* --------------------------------------------------------------------------
   feed header: place line, search, category chips
   -------------------------------------------------------------------------- */

.ui-head { padding: 2px 12px 8px; flex: none; }

.ui-head__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 7px;
}
.ui-head__brand {
  display: flex;
  align-items: center;
  gap: 4px;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: -0.03em;
}
.ui-head__brand img { width: 13px; height: auto; }
.ui-head__avatar {
  width: 20px; height: 20px;
  border-radius: 999px;
  background: var(--cat-rent-bg);
  color: var(--cat-rent-ink);
  display: grid;
  place-items: center;
  font-size: 9px;
  font-weight: 700;
}

.ui-place {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 9.5px;
  color: var(--ink-3);
  margin-bottom: 7px;
}
.ui-place svg { width: 9px; height: 9px; color: var(--accent-ink); }
.ui-place b { color: var(--ink-2); font-weight: 600; }

.ui-search {
  display: flex;
  align-items: center;
  gap: 5px;
  background: var(--screen-sunk);
  border-radius: 999px;
  padding: 6px 10px;
  color: var(--ink-3);
  font-size: 9.5px;
  margin-bottom: 7px;
}
.ui-search svg { width: 10px; height: 10px; }

.ui-chips { display: flex; gap: 4px; overflow: hidden; }
.ui-chip {
  padding: 3.5px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 8.5px;
  font-weight: 600;
  white-space: nowrap;
  color: var(--ink-2);
  background: var(--screen-card);
}
.ui-chip--on {
  background: var(--accent);
  border-color: transparent;
  color: var(--on-accent);
}

/* --------------------------------------------------------------------------
   the feed itself
   -------------------------------------------------------------------------- */

.ui-feed {
  flex: 1;
  overflow: hidden;
  background: var(--screen-sunk);
  padding: 7px 8px 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
  mask-image: linear-gradient(to bottom, #000 82%, transparent);
}

.ui-card {
  background: var(--screen-card);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  flex: none;
}

.ui-card__head {
  display: flex;
  gap: 6px;
  padding: 8px 9px 7px;
  border-bottom: 1px solid var(--line);
}
.ui-avatar {
  width: 24px; height: 24px;
  border-radius: 999px;
  display: grid;
  place-items: center;
  font-size: 10px;
  font-weight: 700;
  flex: none;
  background: var(--cat-sale-bg);
  color: var(--cat-sale-ink);
}
.ui-card__who { min-width: 0; flex: 1; }
.ui-card__name {
  font-weight: 700;
  font-size: 10px;
  letter-spacing: -0.01em;
  display: flex;
  align-items: center;
  gap: 3px;
}
.ui-card__name svg { width: 9px; height: 9px; color: var(--accent); }
.ui-card__sub { font-size: 8.5px; color: var(--ink-3); }
.ui-card__meta {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 8.5px;
  color: var(--ink-3);
  margin-top: 1px;
}
.ui-tag {
  padding: 1.5px 6px;
  border-radius: 999px;
  font-size: 7.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  background: var(--tint-bg);
  color: var(--tint-ink);
}
.ui-dist {
  font-variant-numeric: tabular-nums;
  font-weight: 650;
  color: var(--accent-ink);
}

.ui-card__body { padding: 8px 9px 6px; }
.ui-card__title {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: -0.02em;
  line-height: 1.25;
}
.ui-card__price {
  font-size: 12px;
  font-weight: 750;
  margin-top: 3px;
  letter-spacing: -0.02em;
}
.ui-card__price small { font-size: 8.5px; font-weight: 500; color: var(--ink-3); }
.ui-card__desc {
  font-size: 9px;
  color: var(--ink-2);
  margin-top: 3px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ui-photos {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 2px;
  height: 74px;
  margin-top: 6px;
}
.ui-photos__side { display: grid; grid-template-rows: 1fr 1fr; gap: 2px; }
.ui-photo {
  background: var(--screen-sunk);
  position: relative;
  overflow: hidden;
}
/* Stand-in artwork: a flat two-tone shape per photo rather than a stock image,
 * so the mockup never implies a product that does not exist. */
.ui-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(70% 80% at 28% 115%, color-mix(in srgb, var(--tint-ink) 45%, transparent), transparent 72%),
    linear-gradient(145deg, color-mix(in srgb, var(--tint-bg) 92%, var(--tint-ink)), var(--screen-sunk));
}
.ui-photo__count {
  position: absolute;
  inset: auto 3px 3px auto;
  z-index: 2;
  background: rgb(0 0 0 / 0.55);
  color: #fff;
  border-radius: 999px;
  padding: 1px 5px;
  font-size: 7.5px;
  font-weight: 650;
}

.ui-counts {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 9px;
  font-size: 8.5px;
  color: var(--ink-3);
  border-top: 1px solid var(--line);
}
.ui-counts span { display: inline-flex; align-items: center; gap: 3px; }
.ui-counts svg { width: 9px; height: 9px; }
.ui-counts .is-on { color: var(--accent-ink); font-weight: 650; }

/* --------------------------------------------------------------------------
   bottom bar
   -------------------------------------------------------------------------- */

.ui-tabs {
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 7px 10px 11px;
  border-top: 1px solid var(--line);
  background: var(--screen-bg);
  flex: none;
  position: relative;
}
.ui-tab {
  display: grid;
  justify-items: center;
  gap: 2px;
  font-size: 7.5px;
  font-weight: 600;
  color: var(--ink-3);
}
.ui-tab svg { width: 14px; height: 14px; }
.ui-tab.is-on { color: var(--accent-ink); }

.ui-fab {
  position: absolute;
  top: -20px;
  left: 50%;
  translate: -50% 0;
  width: 38px; height: 38px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  display: grid;
  place-items: center;
  box-shadow: 0 6px 16px -6px rgb(33 192 99 / 0.9);
  border: 3px solid var(--screen-bg);
}
.ui-fab svg { width: 16px; height: 16px; }

/* --------------------------------------------------------------------------
   the chat screen, used in the "how it works" and stories sections
   -------------------------------------------------------------------------- */

.ui-adbar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 9px;
  background: var(--screen-sunk);
  border-bottom: 1px solid var(--line);
  flex: none;
}
.ui-adbar__thumb {
  width: 22px; height: 22px;
  border-radius: 5px;
  background: linear-gradient(145deg, var(--cat-sale-bg), var(--screen-sunk));
  flex: none;
}
.ui-adbar__title { font-size: 9px; font-weight: 650; }
.ui-adbar__price { font-size: 8.5px; color: var(--ink-3); }

.ui-thread {
  flex: 1;
  padding: 9px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  justify-content: flex-end;
  background: var(--screen-bg);
}
.ui-msg {
  max-width: 78%;
  padding: 6px 9px;
  border-radius: 13px;
  font-size: 9px;
  background: var(--screen-sunk);
  border: 1px solid var(--line);
  border-bottom-left-radius: 4px;
}
.ui-msg--mine {
  align-self: flex-end;
  background: var(--accent);
  color: var(--on-accent);
  border-color: transparent;
  border-bottom-left-radius: 13px;
  border-bottom-right-radius: 4px;
}
.ui-msg__time {
  display: block;
  font-size: 7px;
  opacity: 0.65;
  text-align: right;
  margin-top: 1px;
}
.ui-safety {
  align-self: center;
  text-align: center;
  background: var(--cat-free-bg);
  color: var(--cat-free-ink);
  border-radius: 8px;
  padding: 5px 8px;
  font-size: 7.5px;
  font-weight: 600;
  max-width: 88%;
}

.ui-composer {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 9px 11px;
  border-top: 1px solid var(--line);
  flex: none;
}
.ui-composer__field {
  flex: 1;
  background: var(--screen-sunk);
  border-radius: 999px;
  padding: 6px 10px;
  font-size: 9px;
  color: var(--ink-3);
}
.ui-composer__send {
  width: 24px; height: 24px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  display: grid;
  place-items: center;
  flex: none;
}
.ui-composer__send svg { width: 12px; height: 12px; }

/* --------------------------------------------------------------------------
   the compose wizard
   -------------------------------------------------------------------------- */

.ui-steps {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 8px 12px;
  flex: none;
}
.ui-step-dot {
  width: 16px; height: 16px;
  border-radius: 999px;
  display: grid;
  place-items: center;
  font-size: 8px;
  font-weight: 700;
  background: var(--screen-sunk);
  color: var(--ink-3);
}
.ui-step-dot.is-on { background: var(--accent); color: var(--on-accent); }
.ui-step-line { flex: 1; height: 1.5px; background: var(--line); border-radius: 2px; }
.ui-step-line.is-on { background: var(--accent); }

.ui-form { padding: 4px 12px; display: grid; gap: 7px; }
.ui-label { font-size: 8.5px; font-weight: 650; color: var(--ink-2); }
.ui-field {
  border: 1px solid var(--line);
  border-radius: 9px;
  padding: 7px 9px;
  font-size: 9px;
  color: var(--ink);
  background: var(--screen-card);
}
.ui-field--muted { color: var(--ink-3); }
.ui-field--focus { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 22%, transparent); }

.ui-spotted {
  border: 1px solid var(--line);
  border-radius: 9px;
  padding: 7px 9px;
  background: var(--accent-wash);
  display: grid;
  gap: 5px;
}
.ui-spotted__head { font-size: 8px; font-weight: 700; color: var(--accent-ink); }
.ui-spotted__chips { display: flex; flex-wrap: wrap; gap: 3px; }
.ui-spotted__chip {
  background: var(--screen-card);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 2px 6px;
  font-size: 7.5px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 3px;
}
.ui-spotted__chip svg { width: 7px; height: 7px; color: var(--accent-ink); }
.ui-spotted__warn { font-size: 7px; color: var(--cat-service-ink); font-weight: 600; }

.ui-photo-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.ui-photo-slot {
  aspect-ratio: 1;
  border-radius: 7px;
  background: var(--screen-sunk);
  position: relative;
  overflow: hidden;
}
.ui-photo-slot--empty {
  border: 1.5px dashed var(--line-strong);
  background: transparent;
  display: grid;
  place-items: center;
  color: var(--ink-3);
}
.ui-photo-slot--empty svg { width: 12px; height: 12px; }
.ui-photo-slot__cover {
  position: absolute;
  inset: auto auto 3px 3px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 6.5px;
  font-weight: 750;
  letter-spacing: 0.04em;
  border-radius: 4px;
  padding: 1px 4px;
  z-index: 2;
}


/* 40-sections.css */
/* The home page's sections. */

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

.hero {
  position: relative;
  padding-block: clamp(2.5rem, 1.5rem + 5vw, 5.5rem) clamp(3rem, 2rem + 5vw, 6rem);
  overflow: hidden;
}

/* Ground: a warm wash, a green bloom behind the phone, and a faint street grid
 * that gives the section a sense of place without an image request. */
.hero__ground {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(90% 70% at 78% 12%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 62%),
    radial-gradient(60% 50% at 8% 0%, color-mix(in srgb, var(--brand-red) 7%, transparent), transparent 70%);
}
.hero__grid {
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0.5;
  background-image:
    linear-gradient(to right, var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: 68px 68px;
  mask-image: radial-gradient(70% 60% at 50% 25%, #000, transparent 75%);
}

.hero__inner {
  display: grid;
  gap: clamp(2.5rem, 1rem + 6vw, 4rem);
  align-items: center;
}
@media (min-width: 940px) {
  .hero__inner { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); }
}

.hero__badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.4rem 0.35rem 0.75rem;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  font-size: 0.82rem;
  font-weight: 550;
  color: var(--ink-2);
  margin-bottom: 1.5rem;
}
.hero__badge b {
  background: var(--accent-wash);
  color: var(--accent-ink);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
  font-weight: 650;
}

.hero__title {
  font-size: var(--step-5);
  letter-spacing: -0.035em;
  font-weight: 700;
  margin-bottom: 1.25rem;
}
/* The one word the whole pitch turns on, marked with a hand-drawn underline
 * that draws itself in once. */
/* inline-block so the phrase and the underline drawn beneath it stay one
 * object: an inline span that wraps mid-phrase would leave the absolutely
 * positioned stroke spanning both lines. max-width keeps it inside the column
 * at every size rather than relying on the type scale to be small enough. */
.hero__title .mark {
  position: relative;
  display: inline-block;
  max-width: 100%;
  color: var(--accent-ink);
}
.hero__title .mark svg {
  position: absolute;
  left: 0; right: 0; bottom: -0.12em;
  width: 100%;
  height: 0.28em;
  overflow: visible;
  color: var(--accent);
}
.hero__title .mark path {
  fill: none;
  stroke: currentColor;
  stroke-width: 7;
  stroke-linecap: round;
  stroke-dasharray: 420;
  stroke-dashoffset: 420;
  animation: draw-underline 1s var(--ease) 0.5s forwards;
}

.hero__lead {
  font-family: var(--font-body);
  font-size: var(--step-1);
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 46ch;
  margin-bottom: 2rem;
}

.hero__proof {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 2rem;
}

.hero__stage {
  position: relative;
  display: flex;
  justify-content: center;
  isolation: isolate;
}

/* The two cards that float either side of the phone. On narrow screens they
 * would crowd the device, so they go. */
.hero__float {
  position: absolute;
  z-index: 2;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 0.7rem 0.9rem;
  font-size: 0.8rem;
  display: grid;
  gap: 0.15rem;
  min-width: 150px;
}
.hero__float b { font-size: 0.86rem; font-weight: 650; letter-spacing: -0.01em; }
.hero__float span { color: var(--ink-3); font-size: 0.75rem; }
.hero__float--radius { left: -8%; top: 6%; }
.hero__float--chat { right: -5%; bottom: 12%; }
.hero__float__row { display: flex; align-items: center; gap: 0.45rem; }
.hero__float__row svg { width: 0.95rem; height: 0.95rem; color: var(--accent-ink); flex: none; }

@media (max-width: 620px) {
  .hero__float { display: none; }
}

/* --------------------------------------------------------------------------
   logo / fact strip
   -------------------------------------------------------------------------- */

.strip {
  border-block: 1px solid var(--line);
  background: var(--surface);
}
.strip__inner {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 1px;
  background: var(--line);
}
.strip__item {
  background: var(--surface);
  padding: 1.5rem 1.25rem;
  text-align: center;
}
.strip__value {
  font-size: var(--step-2);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.1;
  color: var(--ink);
}
.strip__label {
  font-size: 0.82rem;
  color: var(--ink-3);
  margin-top: 0.3rem;
}

/* --------------------------------------------------------------------------
   about: text beside the radius illustration
   -------------------------------------------------------------------------- */

.about__inner {
  display: grid;
  gap: clamp(2.5rem, 1rem + 6vw, 4.5rem);
  align-items: center;
}
@media (min-width: 900px) {
  .about__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .about__art { order: 2; }
}

.prose-block p {
  font-family: var(--font-body);
  color: var(--ink-2);
  font-size: 1.02rem;
  line-height: 1.7;
}
.prose-block p + p { margin-top: 1rem; }
.prose-block strong { color: var(--ink); font-weight: 650; }

.about__list {
  list-style: none;
  padding: 0;
  margin-top: 1.75rem;
  display: grid;
  gap: 0.9rem;
}
.about__list li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.75rem;
  align-items: start;
  font-size: 0.97rem;
  color: var(--ink-2);
  font-family: var(--font-body);
}
.about__list svg {
  width: 1.25rem; height: 1.25rem;
  color: var(--accent-ink);
  margin-top: 0.15rem;
  flex: none;
}
.about__list b { color: var(--ink); font-family: var(--font-ui); font-weight: 650; }

/* The radius diagram: concentric rings over a street grid, with pins on it. */
.radius-art {
  position: relative;
  aspect-ratio: 1;
  max-width: 520px;
  margin-inline: auto;
  width: 100%;
}
.radius-art svg { width: 100%; height: 100%; overflow: visible; }

/* --------------------------------------------------------------------------
   how it works
   -------------------------------------------------------------------------- */

.steps {
  display: grid;
  gap: clamp(2.5rem, 1rem + 5vw, 4.5rem);
  counter-reset: step;
}

.step {
  display: grid;
  gap: clamp(1.5rem, 1rem + 3vw, 3.5rem);
  align-items: center;
}
@media (min-width: 880px) {
  .step { grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr); }
  .step:nth-child(even) .step__art { order: -1; }
}

.step__n {
  counter-increment: step;
  display: inline-grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 750;
  font-size: 1.05rem;
  margin-bottom: 1.1rem;
  box-shadow: 0 6px 18px -8px color-mix(in srgb, var(--accent) 90%, transparent);
}
.step__n::after { content: counter(step); }

.step__title { font-size: var(--step-2); margin-bottom: 0.6rem; }
.step__text {
  font-family: var(--font-body);
  color: var(--ink-2);
  font-size: 1.02rem;
  line-height: 1.7;
  max-width: 48ch;
}
.step__detail {
  margin-top: 1.1rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.step__art {
  display: flex;
  justify-content: center;
  position: relative;
}
.step__art .phone { --phone-w: 258px; }

/* --------------------------------------------------------------------------
   features
   -------------------------------------------------------------------------- */

/* Explicit counts rather than auto-fit: six cards in an auto-fit grid land as
 * 4 + 2 at desktop widths and leave a two-card hole. 1 / 2 / 3 always divides
 * six evenly. */
.feature-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}
@media (min-width: 620px) { .feature-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .feature-grid { grid-template-columns: repeat(3, 1fr); } }

.feature-grid--wide { margin-top: 1rem; }
@media (min-width: 980px) {
  .feature-grid--wide { grid-template-columns: repeat(2, 1fr); }
}

.feature-wide {
  display: grid;
  gap: 1.5rem;
  align-items: center;
  background: var(--surface);
}
@media (min-width: 640px) {
  .feature-wide { grid-template-columns: minmax(0, 1fr) auto; }
}
/* A square plate, centred — stretched to the card's full height it became a
 * tall empty column with a small drawing adrift in the middle of it. */
.feature-wide__art {
  display: grid;
  place-items: center;
  align-self: center;
  width: 184px;
  aspect-ratio: 1;
  border-radius: var(--radius);
  background:
    radial-gradient(90% 90% at 50% 115%, var(--accent-wash), transparent 70%),
    var(--surface-2);
  border: 1px solid var(--line);
}
.feature-wide__art svg { width: 148px; height: 148px; }

@media (max-width: 639px) {
  .feature-wide__art { justify-self: center; }
}

.card__list {
  list-style: none;
  padding: 0;
  margin-top: 1rem;
  display: grid;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--ink-2);
  font-family: var(--font-body);
}
.card__list li { display: grid; grid-template-columns: auto 1fr; gap: 0.55rem; }
.card__list svg { width: 1rem; height: 1rem; color: var(--accent-ink); margin-top: 0.22rem; }

/* --------------------------------------------------------------------------
   stories — "how fnder helps"
   -------------------------------------------------------------------------- */

.story-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: 1rem;
}

/* Four children, so four rows — and the slack belongs to the paragraph. With
 * three rows declared, the 1fr landed on the heading and opened a gap between
 * each title and its own text. */
.story {
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 1.6rem;
  overflow: hidden;
  transition: translate 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.story:hover { translate: 0 -4px; box-shadow: var(--shadow-lg); }

/* A tinted plate bled to the card's edges, so the illustration reads as part
 * of the card rather than as clipart floating in the padding.
 *
 * The SVG inside is sized explicitly rather than with height:100%: in an
 * auto-sized grid row a percentage height resolves to auto, the SVG falls back
 * to its default 150px, and with overflow:visible it then draws straight over
 * the heading underneath — which is exactly what it did. */
.story__art {
  height: 158px;
  margin: -1.6rem -1.6rem 1.4rem;
  display: grid;
  place-items: center;
  background:
    radial-gradient(80% 90% at 50% 120%, var(--story-tint, var(--accent-wash)), transparent 72%),
    var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.story__art svg { height: 118px; width: auto; max-width: 80%; }

.story__title { font-size: var(--step-1); margin-bottom: 0.5rem; }
.story__text {
  font-family: var(--font-body);
  color: var(--ink-2);
  font-size: 0.95rem;
  line-height: 1.65;
}
.story__foot {
  margin-top: 1.3rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-size: 0.82rem;
  color: var(--ink-3);
  display: flex;
  align-items: center;
  gap: 0.45rem;
}
.story__foot svg { width: 0.95rem; height: 0.95rem; color: var(--accent-ink); }

/* --------------------------------------------------------------------------
   showcase
   -------------------------------------------------------------------------- */

.showcase__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  justify-content: center;
  margin-bottom: clamp(2rem, 1rem + 3vw, 3rem);
  padding: 0.3rem;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  width: fit-content;
  margin-inline: auto;
}
.showcase__tab {
  border: 0;
  background: transparent;
  border-radius: 999px;
  padding: 0.55rem 1.1rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink-3);
  cursor: pointer;
  transition: background 0.2s var(--ease), color 0.2s var(--ease);
}
.showcase__tab:hover { color: var(--ink); }
.showcase__tab[aria-selected="true"] {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}

.showcase__stage {
  display: grid;
  gap: clamp(1.5rem, 1rem + 3vw, 3rem);
  align-items: center;
}
@media (min-width: 860px) {
  .showcase__stage { grid-template-columns: auto minmax(0, 1fr); }
}

.showcase__panel[hidden] { display: none; }
.showcase__panel {
  display: grid;
  gap: clamp(1.5rem, 1rem + 3vw, 3rem);
  align-items: center;
  animation: panel-in 0.4s var(--ease);
}
@media (min-width: 860px) {
  .showcase__panel {
    grid-template-columns: auto minmax(0, 520px);
    justify-content: center;
  }
}

.showcase__caption { max-width: 46ch; }
.showcase__caption h3 { font-size: var(--step-2); margin-bottom: 0.7rem; }
.showcase__caption p {
  font-family: var(--font-body);
  color: var(--ink-2);
  line-height: 1.7;
}
.showcase__points {
  list-style: none;
  padding: 0;
  margin-top: 1.4rem;
  display: grid;
  gap: 0.7rem;
}
.showcase__points li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.65rem;
  font-size: 0.95rem;
  color: var(--ink-2);
  font-family: var(--font-body);
}
.showcase__points svg { width: 1.05rem; height: 1.05rem; color: var(--accent-ink); margin-top: 0.25rem; }

.showcase__shots { display: flex; justify-content: center; }

/* --------------------------------------------------------------------------
   closing call to action
   -------------------------------------------------------------------------- */

.cta {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-xl);
  background: var(--surface);
  border: 1px solid var(--line);
  padding: clamp(2.5rem, 1.5rem + 5vw, 4.5rem) clamp(1.5rem, 1rem + 4vw, 4rem);
  text-align: center;
  box-shadow: var(--shadow-md);
}
.cta::before {
  content: "";
  position: absolute;
  inset: -40% -10% auto;
  height: 150%;
  background: radial-gradient(50% 50% at 50% 0%, color-mix(in srgb, var(--accent) 18%, transparent), transparent 70%);
  z-index: 0;
}
.cta > * { position: relative; z-index: 1; }

.cta__title {
  font-size: var(--step-4);
  letter-spacing: -0.03em;
  margin-bottom: 1rem;
}
.cta__lead {
  font-family: var(--font-body);
  font-size: var(--step-1);
  color: var(--ink-2);
  max-width: 52ch;
  margin-inline: auto;
  margin-bottom: 2rem;
}
.cta .btn-row { justify-content: center; }
.cta__small {
  margin-top: 1.5rem;
  font-size: 0.85rem;
  color: var(--ink-3);
}
.cta__pin {
  width: 3.2rem;
  margin: 0 auto 1.5rem;
}

/* On a phone the hero's two buttons stack, and two stacked pills of different
 * widths read as a mistake rather than a hierarchy. Full width for both. */
@media (max-width: 520px) {
  .hero .btn-row,
  .cta .btn-row { flex-direction: column; align-items: stretch; }
  .hero .btn-row .btn,
  .cta .btn-row .btn { width: 100%; }
}


/* 50-prose.css */
/* Legal and long-form pages: the policy, the terms, the guidelines.
 *
 * These are the pages somebody reads when they are worried, or when a store
 * review is waiting on them. They get a measure that is actually readable, a
 * table of contents that sticks, and headings that can be linked to. */

.page-head {
  padding-block: clamp(2.5rem, 1.5rem + 4vw, 4.5rem) clamp(1.5rem, 1rem + 2vw, 2.5rem);
  border-bottom: 1px solid var(--line);
  background:
    radial-gradient(70% 100% at 85% 0%, color-mix(in srgb, var(--accent) 10%, transparent), transparent 70%),
    var(--surface);
}
.page-head__title {
  font-size: var(--step-4);
  letter-spacing: -0.03em;
  margin-bottom: 0.75rem;
}
.page-head__lead {
  font-family: var(--font-body);
  font-size: var(--step-1);
  color: var(--ink-2);
  max-width: 60ch;
}
.page-head__dates {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1.5rem;
}

.doc {
  display: grid;
  gap: clamp(2rem, 1rem + 4vw, 4rem);
  padding-block: clamp(2.5rem, 1.5rem + 4vw, 4rem);
  align-items: start;
}
/* Without this a grid item is sized by its content's minimum — and one
 * nowrap table cell is then enough to push the whole page sideways on a
 * phone. Found by tool/qa.mjs at 390px on /privacy/ and /data-deletion/. */
.doc > * { min-width: 0; }

@media (min-width: 980px) {
  .doc { grid-template-columns: 230px minmax(0, 1fr); }
  .doc__toc { position: sticky; top: 5.5rem; }
}

.doc__toc {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 1.1rem 1.25rem;
}
.doc__toc h2 {
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 0.8rem;
}
.doc__toc ol {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.4rem;
  counter-reset: toc;
}
.doc__toc a {
  display: block;
  font-size: 0.88rem;
  color: var(--ink-2);
  text-decoration: none;
  padding: 0.15rem 0;
  border-left: 2px solid transparent;
  padding-left: 0.7rem;
  margin-left: -0.7rem;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.doc__toc a:hover,
.doc__toc a.is-current {
  color: var(--accent-ink);
  border-left-color: var(--accent);
}

.prose {
  max-width: 100%;
  width: min(100%, 72ch);
  overflow-wrap: break-word;
  font-family: var(--font-body);
  font-size: 1.02rem;
  line-height: 1.75;
  color: var(--ink-2);
}
.prose > * + * { margin-top: 1.1rem; }

.prose h2 {
  font-family: var(--font-ui);
  font-size: var(--step-2);
  color: var(--ink);
  margin-top: 2.75rem;
  scroll-margin-top: 5.5rem;
}
.prose h2:first-child { margin-top: 0; }

.prose h3 {
  font-family: var(--font-ui);
  font-size: var(--step-1);
  color: var(--ink);
  margin-top: 1.9rem;
  scroll-margin-top: 5.5rem;
}

.prose strong { color: var(--ink); font-weight: 650; }
.prose a { font-weight: 550; }

.prose ul, .prose ol { padding-left: 1.3em; display: grid; gap: 0.5rem; }
.prose li::marker { color: var(--accent-ink); }

.prose table {
  width: 100%;
  max-width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
  font-family: var(--font-ui);
  display: block;
  overflow-x: auto;
}
.prose thead th {
  text-align: left;
  font-weight: 650;
  color: var(--ink);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line-strong);
}
.prose th, .prose td {
  padding: 0.7rem 0.8rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
.prose tbody tr:last-child td { border-bottom: 0; }
.prose td:first-child { font-weight: 600; color: var(--ink); white-space: nowrap; }

.prose__callout {
  border-left: 3px solid var(--accent);
  background: var(--accent-wash);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 1rem 1.25rem;
  font-size: 0.96rem;
}
.prose__callout--warn {
  border-left-color: var(--cat-service-ink);
  background: var(--cat-service-bg);
  color: var(--cat-service-ink);
}
.prose__callout--warn strong { color: inherit; }

.prose__updated {
  font-size: 0.85rem;
  color: var(--ink-3);
  border-top: 1px solid var(--line);
  padding-top: 1.25rem;
  margin-top: 3rem;
}

/* The contact page's cards. */
/* Six cards, like the feature grid — and for the same reason, counted rather
 * than auto-fit, which lands them as 4 + 2 and leaves a hole. */
.contact-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  margin-top: 2rem;
}
@media (min-width: 620px) { .contact-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .contact-grid { grid-template-columns: repeat(3, 1fr); } }
.contact-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 1.6rem;
  display: grid;
  align-content: start;
  gap: 0.5rem;
}
.contact-card h2 { font-size: var(--step-1); letter-spacing: -0.02em; }
.contact-card p { font-family: var(--font-body); color: var(--ink-2); font-size: 0.94rem; }
.contact-card a { font-weight: 600; word-break: break-word; }
.contact-card__plate {
  width: 2.6rem; height: 2.6rem;
  border-radius: 12px;
  background: var(--accent-wash);
  color: var(--accent-ink);
  display: grid;
  place-items: center;
  margin-bottom: 0.5rem;
}
.contact-card__plate svg { width: 1.35rem; height: 1.35rem; }

/* 404 */
.notfound {
  text-align: center;
  padding-block: clamp(4rem, 3rem + 8vw, 8rem);
}
.notfound__code {
  font-size: clamp(4rem, 2rem + 14vw, 9rem);
  font-weight: 750;
  letter-spacing: -0.05em;
  line-height: 1;
  color: var(--accent-ink);
  opacity: 0.18;
}
.notfound__title { font-size: var(--step-3); margin: -0.4em 0 1rem; }
.notfound__text {
  font-family: var(--font-body);
  color: var(--ink-2);
  max-width: 46ch;
  margin: 0 auto 2rem;
}
.notfound .btn-row { justify-content: center; }


/* 60-motion.css */
/* Motion.
 *
 * Three rules this file keeps to:
 *   1. Nothing moves that a reader has not scrolled to. The reveal is a
 *      one-shot IntersectionObserver class, never a scroll handler.
 *   2. Nothing animates a property that costs layout. Transform, opacity,
 *      filter and stroke-dashoffset only.
 *   3. Every single thing here is off under `prefers-reduced-motion`, and the
 *      page is complete without it — reveals finish in their final state, and
 *      the looping ambience simply does not start.
 */

/* --------------------------------------------------------------------------
   scroll reveal
   -------------------------------------------------------------------------- */

/* The guard: only elements the script has claimed start hidden, so a reader
 * with JavaScript off sees the whole page rather than a blank one. */
.js [data-reveal] {
  opacity: 0;
  translate: 0 18px;
  transition: opacity 0.6s var(--ease), translate 0.6s var(--ease);
}
.js [data-reveal].is-in { opacity: 1; translate: 0 0; }

/* Children revealed one after another — a feature grid, a list of facts. */
.js [data-reveal-stagger] > * {
  opacity: 0;
  translate: 0 18px;
  transition: opacity 0.55s var(--ease), translate 0.55s var(--ease);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.js [data-reveal-stagger].is-in > * { opacity: 1; translate: 0 0; }

/* --------------------------------------------------------------------------
   keyframes
   -------------------------------------------------------------------------- */

@keyframes draw-underline {
  to { stroke-dashoffset: 0; }
}

@keyframes panel-in {
  from { opacity: 0; translate: 0 10px; }
  to { opacity: 1; translate: 0 0; }
}

/* The hero feed scrolling by itself: one card's height, then reset. The list
 * is duplicated in the markup so the loop has no visible seam. */
@keyframes feed-drift {
  from { translate: 0 0; }
  to { translate: 0 -50%; }
}

@keyframes float-soft {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -8px; }
}

@keyframes typing-dot {
  0%, 60%, 100% { opacity: 0.25; translate: 0 0; }
  30% { opacity: 1; translate: 0 -2px; }
}

@keyframes msg-in {
  from { opacity: 0; translate: 0 8px; }
  to { opacity: 1; translate: 0 0; }
}

/* --------------------------------------------------------------------------
   where they are used
   -------------------------------------------------------------------------- */

.hero__float--radius { animation: float-soft 7s ease-in-out infinite; }
.hero__float--chat { animation: float-soft 7s ease-in-out 1.4s infinite; }

/* The feed inside the hero phone drifts only while the hero is on screen —
 * `is-in` is added by the same observer that drives the reveals, so a phone
 * scrolled past is not animating off-screen. */
/* The gap is a margin on each card rather than a flex gap: the drift loops
 * by translating exactly -50%, which only lands on the start of the second
 * copy if every item occupies the same height INCLUDING its spacing. A flex
 * gap is one short — there is none after the last card — and the loop shows a
 * 3px jump every pass. */
.ui-feed__track { display: flex; flex-direction: column; }
.ui-feed__track > * { margin-bottom: 7px; }
/* The delay matters: without it the first thing a visitor sees is a feed
 * already halfway through a scroll, with the top card cut off. */
.js [data-drift].is-in .ui-feed__track {
  animation: feed-drift 30s linear 2.5s infinite;
}
.ui-feed:hover .ui-feed__track { animation-play-state: paused; }

/* The radius diagram's rings and pins are driven by scroll now — see
 * 70-scroll.css, where each one is tied to the paragraph that explains it.
 * The rules that used to live here hid them at opacity 0 and pulsed them on a
 * timer, which would both fight that and, worse, leave them invisible in a
 * browser that cannot scrub. Nothing replaces them: with no scroll-timeline
 * support the diagram is simply drawn, complete, which is the right fallback. */

.ui-typing { display: inline-flex; gap: 2px; align-items: center; }
.ui-typing i {
  width: 3px; height: 3px;
  border-radius: 999px;
  background: currentColor;
  display: block;
  animation: typing-dot 1.4s ease-in-out infinite;
}
.ui-typing i:nth-child(2) { animation-delay: 0.2s; }
.ui-typing i:nth-child(3) { animation-delay: 0.4s; }

/* --------------------------------------------------------------------------
   the opt-out
   -------------------------------------------------------------------------- */
/* Not "shorter": off. A reader who has asked their system for less motion has
 * usually asked for a reason, and a 0.01s version of a parallax is still a
 * parallax. Reveals jump to their finished state so nothing is left invisible. */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .js [data-reveal],
  .js [data-reveal-stagger] > * {
    opacity: 1 !important;
    translate: none !important;
  }

  .hero__title .mark path { stroke-dashoffset: 0; }
}


/* 70-scroll.css */
/* Scroll choreography.
 *
 * The brief was "animation like Apple.com". What that actually means, stripped
 * of the marketing, is four things:
 *
 *   1. Motion is SCRUBBED, not triggered. The animation's progress is the
 *      scroll position, so scrolling back up plays it backwards and stopping
 *      halfway leaves it halfway. A one-shot fade that fires once and is done
 *      — which is what this site had — reads as a web page; a scrubbed one
 *      reads as a surface you are moving through.
 *   2. Something is PINNED while the story moves past it. One visual holds
 *      still and earns several paragraphs of attention instead of scrolling
 *      away after one.
 *   3. The opening is STAGED. Elements arrive in a deliberate order on load,
 *      on a long ease, rather than all at once.
 *   4. There is DEPTH. Layers move at different rates, so leaving a section
 *      feels like passing it rather than scrolling a flat document.
 *
 * All of it is done with native CSS scroll-driven animations — `view()` and
 * named view timelines. No library, no scroll listener, and the work happens
 * off the main thread, which is the only reason this is affordable on a page
 * that already draws three phone mockups.
 *
 * THREE WAYS THIS DEGRADES, all of them to something complete:
 *
 *   * No `animation-timeline` support (Firefox at the time of writing): every
 *     scrubbed rule is inside `@supports`, so none of it applies and the
 *     IntersectionObserver reveals in 20-reveal.js stay in charge. The page
 *     behaves exactly as it did before this file existed.
 *   * No JavaScript: `.js` is never set, nothing is hidden, and the page is
 *     fully readable — the scrubbed rules still run, because they need no
 *     script at all.
 *   * `prefers-reduced-motion: reduce`: the block at the foot of this file
 *     switches every timeline off and pins every element to its finished
 *     state. Pinning is dropped too, because a section that holds still while
 *     you scroll is itself a motion effect.
 */

:root {
  /* A long, decelerating ease. The flat-ish tail is what makes an entrance
   * feel like it settles rather than stops. */
  --ease-out-soft: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ==========================================================================
   1. the opening — a staged load sequence
   ========================================================================== */
/* Not scroll-driven: the hero is already on screen when the page opens, so
 * tying it to scroll would mean "play immediately" and throw away the order.
 * The hero markup carries no [data-reveal] for this reason — CSS owns it. */

@keyframes hero-in {
  from { opacity: 0; translate: 0 22px; }
  to   { opacity: 1; translate: 0 0; }
}

@keyframes hero-stage-in {
  from { opacity: 0; translate: 0 36px; scale: 0.97; }
  to   { opacity: 1; translate: 0 0; scale: 1; }
}

@keyframes float-in {
  from { opacity: 0; translate: 0 14px; scale: 0.94; }
  to   { opacity: 1; translate: 0 0; scale: 1; }
}

@media (prefers-reduced-motion: no-preference) {
  .page-home .hero__badge,
  .page-home .hero__title,
  .page-home .hero__lead,
  .page-home .hero .btn-row,
  .page-home .hero__proof {
    animation: hero-in 0.9s var(--ease-out-soft) both;
  }
  .page-home .hero__badge { animation-delay: 0.05s; }
  .page-home .hero__title { animation-delay: 0.14s; }
  .page-home .hero__lead  { animation-delay: 0.26s; }
  .page-home .hero .btn-row { animation-delay: 0.36s; }
  .page-home .hero__proof { animation-delay: 0.44s; }

  .page-home .hero__stage {
    animation: hero-stage-in 1.15s var(--ease-out-soft) 0.2s both;
  }

  /* The two floating cards arrive last and separately, which is what sells
   * them as objects in front of the phone rather than parts of the picture.
   * Their idle drift (60-motion.css) starts after this. */
  .page-home .hero__float--radius {
    animation:
      float-in 0.7s var(--ease-out-soft) 0.85s both,
      float-soft 7s ease-in-out 1.6s infinite;
  }
  .page-home .hero__float--chat {
    animation:
      float-in 0.7s var(--ease-out-soft) 1.05s both,
      float-soft 7s ease-in-out 3s infinite;
  }

  /* The underline draws itself once the headline it belongs to has landed. */
  .hero__title .mark path { animation-delay: 0.75s; }
}

/* ==========================================================================
   2. scrubbed reveals
   ========================================================================== */

@keyframes scrub-rise {
  from { opacity: 0; translate: 0 34px; }
  to   { opacity: 1; translate: 0 0; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* Ranges are given as LENGTHS, not percentages, on purpose. A percentage
     * of the entry phase is a percentage of the element's own height, so a
     * 1600px feature grid would need 1200px of scrolling to finish fading in
     * while a short card finishes in 200. A fixed 300px band means every
     * element, tall or short, resolves over the same stretch of scroll. */
    .js [data-reveal],
    [data-reveal] {
      animation: scrub-rise linear both;
      animation-timeline: view();
      animation-range: entry 40px entry 340px;
      /* The JS path's transition would otherwise fight the scrub. */
      transition: none;
    }

    /* Each child gets its own timeline, so the stagger comes from their own
     * positions rather than from a delay — which means it reads correctly
     * however fast you scroll, and backwards when you scroll up. */
    .js [data-reveal-stagger] > *,
    [data-reveal-stagger] > * {
      animation: scrub-rise linear both;
      animation-timeline: view();
      animation-range: entry 40px entry 320px;
      transition: none;
    }
  }
}

/* ==========================================================================
   3. depth — the hero parks as you leave it
   ========================================================================== */
/* The copy and the phone exit at different rates. It is a small difference,
 * about 40px over a screen's worth of scroll, and that is the point: enough
 * to read as parallax, not enough to notice as an effect. */

@keyframes park-copy {
  to { opacity: 0.25; translate: 0 -40px; }
}
@keyframes park-stage {
  to { opacity: 0.4; translate: 0 -96px; scale: 0.97; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .page-home .hero__copy {
      animation: park-copy linear both;
      animation-timeline: view();
      animation-range: exit 0% exit 90%;
    }
    .page-home .hero__stage {
      /* Overrides the load animation above once this one applies; the load
       * sequence has finished long before any of this is scrolled to. */
      animation: hero-stage-in 1.15s var(--ease-out-soft) 0.2s both,
                 park-stage linear both;
      animation-timeline: auto, view();
      animation-range: normal, exit 0% exit 90%;
    }
  }
}

/* ==========================================================================
   4. the pinned about sequence
   ========================================================================== */

.about-scroll__inner {
  display: grid;
  gap: clamp(2rem, 1rem + 5vw, 5rem);
  align-items: start;
}

.about-scroll__story {
  display: grid;
  gap: clamp(2.5rem, 1.5rem + 5vw, 5rem);
}

.about-step__km {
  font-size: clamp(2.6rem, 1.8rem + 3.4vw, 4.4rem);
  font-weight: 750;
  letter-spacing: -0.04em;
  line-height: 1;
  color: var(--accent-ink);
  font-variant-numeric: tabular-nums;
  margin-bottom: 0.5rem;
}

.about-step__title {
  font-size: var(--step-2);
  letter-spacing: -0.025em;
  margin-bottom: 0.6rem;
}

.about-step__text {
  font-family: var(--font-body);
  color: var(--ink-2);
  font-size: 1.02rem;
  line-height: 1.7;
  max-width: 44ch;
}

.about-step--list .about__list { margin-top: 0; }

@media (min-width: 900px) {
  .about-scroll__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

  /* The pin itself. `top` centres the square diagram in the viewport. */
  .about-scroll__stage {
    order: 2;
    position: sticky;
    top: max(6rem, calc((100vh - min(36vw, 520px)) / 2 - 2rem));
  }

  /* Each radius is a beat, and a beat has to own the screen: at the first
   * attempt the gap alone left 2 km and 5 km both fully in view, so the
   * diagram was answering two paragraphs at once and the sequence read as a
   * list. A min-height just under the viewport means one beat is centred
   * opposite the map at a time — which is the whole point of pinning it. */
  .about-step--r2,
  .about-step--r5,
  .about-step--r10 {
    min-height: 76vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }

  .about-scroll__story { gap: clamp(2rem, 1rem + 4vh, 4rem); }
  .about-step--list { padding-bottom: 4vh; }
}

/* Each step publishes a timeline that the rings read. `timeline-scope` is what
 * lets a name declared on one subtree be referenced from another — without it,
 * a named view timeline is visible only to that element's own descendants, and
 * the rings live in the other column. */
.about-scroll {
  timeline-scope: --step-r2, --step-r5, --step-r10;
}
.about-step--r2  { view-timeline-name: --step-r2; }
.about-step--r5  { view-timeline-name: --step-r5; }
.about-step--r10 { view-timeline-name: --step-r10; }

@keyframes ring-in {
  from { opacity: 0; scale: 0.55; }
  to   { opacity: 1; scale: 1; }
}
@keyframes label-in {
  from { opacity: 0; translate: 0 6px; }
  to   { opacity: 1; translate: 0 0; }
}
@keyframes pin-in {
  from { opacity: 0; translate: 0 -10px; scale: 0.8; }
  to   { opacity: 1; translate: 0 0; scale: 1; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* SVG children scale about the artwork's centre, not their own box. */
    .radius-art .ring,
    .radius-art .map-pin {
      transform-box: view-box;
      transform-origin: 200px 224px;
    }

    .radius-art .ring,
    .radius-art .ring-label,
    .radius-art .map-pin {
      animation-timing-function: linear;
      animation-fill-mode: both;
    }

    .radius-art .ring--2  { animation-name: ring-in;  animation-timeline: --step-r2;  animation-range: entry 30% cover 35%; }
    .radius-art .ring--5  { animation-name: ring-in;  animation-timeline: --step-r5;  animation-range: entry 30% cover 35%; }
    .radius-art .ring--10 { animation-name: ring-in;  animation-timeline: --step-r10; animation-range: entry 30% cover 35%; }

    .radius-art .ring-label--2  { animation-name: label-in; animation-timeline: --step-r2;  animation-range: entry 40% cover 40%; }
    .radius-art .ring-label--5  { animation-name: label-in; animation-timeline: --step-r5;  animation-range: entry 40% cover 40%; }
    .radius-art .ring-label--10 { animation-name: label-in; animation-timeline: --step-r10; animation-range: entry 40% cover 40%; }

    .radius-art .map-pin--2  { animation-name: pin-in; animation-timeline: --step-r2;  animation-range: entry 45% cover 45%; }
    .radius-art .map-pin--5  { animation-name: pin-in; animation-timeline: --step-r5;  animation-range: entry 45% cover 45%; }
    .radius-art .map-pin--10 { animation-name: pin-in; animation-timeline: --step-r10; animation-range: entry 45% cover 45%; }

    /* The beat's words rise as it arrives. Each child takes its own view()
     * timeline, so the number, the heading and the sentence stagger by their
     * own positions — and run backwards together when you scroll up. */
    .about-step--r2 > *,
    .about-step--r5 > *,
    .about-step--r10 > * {
      animation: scrub-rise linear both;
      animation-timeline: view();
      animation-range: entry 80px entry 420px;
    }

    /* The "you are here" halo breathes while the section is on screen. */
    .radius-art .here-halo {
      animation: here-breathe 3.6s ease-in-out infinite;
    }
  }
}

@keyframes here-breathe {
  0%, 100% { scale: 1; opacity: 0.18; }
  50%      { scale: 1.25; opacity: 0.1; }
}

/* ==========================================================================
   5. the opt-out
   ========================================================================== */
/* Last in the file, so it wins. 60-motion.css already crushes durations, but
 * that does nothing to a scroll-driven animation: its progress comes from the
 * scroll position, not from time, so a 0.001ms duration leaves it scrubbing
 * exactly as before. Each one has to be switched off by name and its subject
 * pinned to the finished state — and the sticky column is released, because a
 * panel that refuses to scroll with the page is itself motion. */

@media (prefers-reduced-motion: reduce) {
  .page-home .hero__badge,
  .page-home .hero__title,
  .page-home .hero__lead,
  .page-home .hero .btn-row,
  .page-home .hero__proof,
  .page-home .hero__stage,
  .page-home .hero__copy,
  .page-home .hero__float--radius,
  .page-home .hero__float--chat,
  .js [data-reveal],
  [data-reveal],
  .js [data-reveal-stagger] > *,
  [data-reveal-stagger] > *,
  .radius-art .ring,
  .radius-art .ring-label,
  .radius-art .map-pin,
  .radius-art .here-halo {
    animation: none !important;
    animation-timeline: none !important;
    opacity: 1 !important;
    translate: none !important;
    scale: none !important;
  }

  .about-scroll__stage { position: static !important; }
  .about-scroll__story { gap: clamp(2.5rem, 1.5rem + 4vw, 4rem) !important; }
}
