/* =====================================================================
   Roomify — findyouroommate.com

   Every colour, radius and border width below is lifted from the app's
   own theme files (src/theme/themes.ts), so the site is not "on brand"
   by eye — it is literally the same tokens. Change one there, change it
   here, and the two stay honest with each other.

   Structure:
     1. Reset & base
     2. Theme tokens (aurora / paper / neon / soft)
     3. Primitives — type, buttons, fields, reveal
     4. Chrome — header, ambient field, footer
     5. Sections
     6. App mockup (phone)
     7. Responsive & reduced motion
   ===================================================================== */

/* ------------------------------------------------- 1. reset & base -- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The fixed header would otherwise cover the top of any anchored
     section the moment you click a nav link. */
  scroll-padding-top: 88px;
}

body, h1, h2, h3, h4, p, ul, ol, li, figure, blockquote, dl, dd { margin: 0; padding: 0; }
ul, ol { list-style: none; }
img, svg { display: block; max-width: 100%; }
button, input, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

.skip-link {
  position: fixed; top: 12px; left: 12px; z-index: 200;
  transform: translateY(-200%);
  padding: 12px 18px; border-radius: var(--r-pill);
  background: var(--brand); color: var(--on-brand); font-weight: 650;
  transition: transform .2s ease;
}
.skip-link:focus-visible { transform: none; }

:where(a, button, summary, input, [tabindex]):focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}

/* ---------------------------------------------- 2. theme tokens ----- */

:root {
  /* Type. Fluid, and tuned to the app's own scale: the app sets hero at
     -1.2 letter-spacing on 40px, which is -0.03em — kept proportional
     here rather than re-guessed. */
  --font: ui-sans-serif, -apple-system, BlinkMacSystemFont, "SF Pro Display",
          "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* Capped lower than it wants to be. At 4.9rem the headline ran to four
     lines in its column and pushed the signup form below the fold on a
     900px-tall laptop — the one thing on the page that has to be visible
     without scrolling. */
  --t-hero:    clamp(2.35rem, 5.2vw, 4.15rem);
  --t-display: clamp(2rem, 4.1vw, 3.2rem);
  --t-title:   clamp(1.3rem, 2.1vw, 1.72rem);
  --t-lede:    clamp(1.02rem, 1.25vw, 1.16rem);
  --t-body:    1rem;
  --t-caption: .875rem;
  --t-micro:   .715rem;

  /* Spacing, from the app's own scale (4/8/12/16/24/32/48/64). */
  --s-xs: 4px;  --s-sm: 8px;  --s-md: 12px; --s-lg: 16px;
  --s-xl: 24px; --s-2xl: 32px; --s-3xl: 48px; --s-4xl: 64px;

  --shell: 1180px;
  --shell-narrow: 780px;

  /* Motion, from src/theme/tokens.ts. */
  --m-fast: 160ms;
  --m-normal: 260ms;
  --m-slow: 420ms;
  --m-stagger: 55ms;
  --ease: cubic-bezier(.22, .61, .36, 1);
  --ease-spring: cubic-bezier(.34, 1.42, .48, 1);

  /* Re-skinning is a real transition, not a flash. Only colours move —
     never layout, or the whole page would reflow on a theme change. */
  --skin: color var(--m-normal) var(--ease),
          background-color var(--m-normal) var(--ease),
          border-color var(--m-normal) var(--ease);
}

/* NOTE ON --text-3
   The app's own tertiary is #6F6894 / #8E8069 / #556067 / #A19A8E. Those are
   correct on a phone held 30cm from your face; on a web page read at arm's
   length on a large monitor they land at 2.56–3.85:1, under WCAG AA for the
   small sizes this site uses them at (micro labels, form notes, footer
   headings). Each value below is the same hue walked toward --text-2 until it
   clears 4.5:1. The palette is unchanged — only its footing. */

/* --- Aurora: the default. Frosted glass on near-black violet. -------- */
:root, [data-theme="aurora"] {
  --bg: #0A0912;
  --surface: rgba(28, 25, 48, .58);
  --surface-solid: #1C1930;
  --surface-alt: #1C1930;
  --sunken: #272242;

  --brand: #8B7CFF;
  --brand-light: #B4A9FF;
  --brand-tint: #1E1A38;
  --brand-tint-strong: #312A5C;
  --grad-a: #7C6BFF;
  --grad-b: #4F3BD4;
  --on-brand: #FFFFFF;

  --like: #2DD4A7;
  --star: #FFB84D;
  --verified: #4CA9F5;

  --text: #F6F4FE;
  --text-2: #ABA4CC;
  --text-3: #7B749F;
  --border: #2A2442;
  --border-strong: #3A3358;

  --r-xs: 8px; --r-sm: 12px; --r-md: 18px; --r-lg: 24px;
  --r-xl: 32px; --r-2xl: 40px; --r-pill: 999px;
  --bw: 1px;

  --blur: 22px;
  --sheen: rgba(255,255,255,.10);
  --sheen-2: rgba(255,255,255,.03);
  --shadow-card: 0 24px 60px -28px rgba(0,0,0,.85);
  --shadow-glow: 0 18px 46px -18px rgba(124,107,255,.55);
  --orb-alpha: .55;
  --grain: .035;
}

/* --- Paper: editorial print on almond stock. No gradients, no blur. -- */
[data-theme="paper"] {
  --bg: #EDE3D2;
  --surface: #F8F2E7;
  --surface-solid: #F8F2E7;
  --surface-alt: #E4D9C4;
  --sunken: #D6C8AE;

  --brand: #A8542B;
  --brand-light: #C87B4E;
  --brand-tint: #EEDFCF;
  --brand-tint-strong: #E0C8AF;
  --grad-a: #A8542B;
  --grad-b: #A8542B;
  --on-brand: #F8F2E7;

  --like: #3F6B4A;
  --star: #96701C;
  --verified: #33607F;

  --text: #221B12;
  --text-2: #5B4F3F;
  --text-3: #706451;
  --border: #CFC0A6;
  --border-strong: #B8A585;

  --r-xs: 10px; --r-sm: 14px; --r-md: 18px; --r-lg: 24px;
  --r-xl: 30px; --r-2xl: 36px; --r-pill: 999px;
  --bw: 1px;

  --blur: 0px;
  --sheen: rgba(0,0,0,.04);
  --sheen-2: transparent;
  /* Print has no drop shadows. Depth here is rules and ink weight. */
  --shadow-card: 0 0 0 1px #CFC0A6;
  --shadow-glow: 0 0 0 1px #B8A585;
  --orb-alpha: .16;
  --grain: .08;
}

/* --- Neon: glowing wire on pure black. ------------------------------ */
[data-theme="neon"] {
  --bg: #000000;
  --surface: #0A0A0E;
  --surface-solid: #0A0A0E;
  --surface-alt: #101018;
  --sunken: #17171F;

  --brand: #00E5FF;
  --brand-light: #7DF3FF;
  --brand-tint: #06222A;
  --brand-tint-strong: #0B3C49;
  --grad-a: #00E5FF;
  --grad-b: #7B61FF;
  --on-brand: #00131A;

  --like: #39FF9E;
  --star: #FFD166;
  --verified: #7B61FF;

  --text: #EAFBFF;
  --text-2: #8FA3AC;
  --text-3: #69777F;
  --border: #1E2A30;
  --border-strong: #2C3E47;

  --r-xs: 10px; --r-sm: 14px; --r-md: 18px; --r-lg: 24px;
  --r-xl: 30px; --r-2xl: 36px; --r-pill: 999px;
  --bw: 1.5px;

  --blur: 0px;
  --sheen: rgba(0,229,255,.07);
  --sheen-2: transparent;
  --shadow-card: 0 0 0 1.5px #1E2A30, 0 0 34px -12px rgba(0,229,255,.42);
  --shadow-glow: 0 0 40px -10px rgba(0,229,255,.65);
  --orb-alpha: .42;
  --grain: .04;
}

/* --- Soft: pillowy sage on warm white. Zero borders by design. ------- */
[data-theme="soft"] {
  --bg: #F7F5F1;
  --surface: #FFFFFF;
  --surface-solid: #FFFFFF;
  --surface-alt: #F1EEE8;
  --sunken: #E7E2DA;

  --brand: #6B8F71;
  --brand-light: #8FB095;
  --brand-tint: #E9F0EA;
  --brand-tint-strong: #D3E1D6;
  --grad-a: #7FA085;
  --grad-b: #5C7F63;
  --on-brand: #FFFFFF;

  --like: #5B9E7A;
  --star: #D9A86C;
  --verified: #6E8CB0;

  --text: #2E2B26;
  --text-2: #6B655C;
  --text-3: #756F66;
  --border: #EBE7E0;
  --border-strong: #DAD4CA;

  --r-xs: 10px; --r-sm: 16px; --r-md: 22px; --r-lg: 28px;
  --r-xl: 34px; --r-2xl: 42px; --r-pill: 999px;
  /* The app sets borderWidth 0 here: separation comes from shadow only. */
  --bw: 0px;

  --blur: 0px;
  --sheen: rgba(255,255,255,.6);
  --sheen-2: transparent;
  --shadow-card: 0 18px 40px -22px rgba(70,64,54,.35);
  --shadow-glow: 0 16px 34px -14px rgba(107,143,113,.5);
  --orb-alpha: .3;
  --grain: .05;
}

body {
  font-family: var(--font);
  font-size: var(--t-body);
  line-height: 1.62;
  color: var(--text);
  background: var(--bg);
  transition: var(--skin);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* --------------------------------------------- 3. primitives -------- */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: clamp(20px, 5vw, 40px);
}
.shell-narrow { max-width: var(--shell-narrow); }

.eyebrow {
  display: flex; align-items: center; gap: 10px;
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brand);
  margin-bottom: var(--s-lg);
}
.eyebrow-rule {
  width: 22px; height: 2px; border-radius: 2px;
  background: var(--brand);
  flex: none;
}
.eyebrow-center { justify-content: center; }

.section-title {
  font-size: var(--t-display);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1.08;
  text-wrap: balance;
}

.section-lede {
  margin-top: var(--s-lg);
  font-size: var(--t-lede);
  color: var(--text-2);
  max-width: 56ch;
  text-wrap: pretty;
}

.micro {
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* Buttons -------------------------------------------------------------
   The app's Button gives filled actions a gradient plus a top sheen, and
   Paper a flat ink block with two impression rules instead. Same here. */

.btn {
  --btn-h: 54px;
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  gap: 10px;
  height: var(--btn-h);
  padding-inline: var(--s-xl);
  border-radius: var(--r-pill);
  font-size: var(--t-body);
  font-weight: 650;
  letter-spacing: -.01em;
  white-space: nowrap;
  overflow: hidden;
  isolation: isolate;
  transition: transform var(--m-fast) var(--ease),
              box-shadow var(--m-normal) var(--ease),
              var(--skin);
}
.btn-sm { --btn-h: 42px; padding-inline: var(--s-lg); font-size: var(--t-caption); }

.btn-primary {
  color: var(--on-brand);
  background: linear-gradient(135deg, var(--grad-a), var(--grad-b));
  box-shadow: var(--shadow-glow);
}
/* The sheen. Paper overrides it below with impression rules, because a
   gradient wash on printed stock reads as a mistake. */
.btn-primary::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg,
    rgba(255,255,255,.42) 0%, rgba(255,255,255,.18) 6%,
    rgba(255,255,255,.04) 50%, transparent 100%);
}
[data-theme="paper"] .btn-primary::before {
  background:
    linear-gradient(180deg, rgba(255,255,255,.28) 0 1px, transparent 1px),
    linear-gradient(0deg, rgba(0,0,0,.22) 0 1.5px, transparent 1.5px);
}
[data-theme="neon"] .btn-primary::before {
  background: linear-gradient(180deg,
    rgba(255,255,255,.55) 0%, rgba(255,255,255,.22) 5%,
    rgba(255,255,255,.02) 42%, transparent 100%);
}

.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0) scale(.98); }
.btn-primary:hover { box-shadow: var(--shadow-glow), 0 22px 50px -20px rgba(0,0,0,.5); }

.btn-arrow { width: 18px; height: 18px; flex: none; transition: transform var(--m-normal) var(--ease); }
.btn:hover .btn-arrow { transform: translateX(3px); }

.btn[disabled] { opacity: .5; pointer-events: none; }

.link-arrow {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: var(--s-xl);
  /* Padded to a real touch target; the negative margin keeps the optical
     alignment with the paragraph above it. */
  padding-block: 9px;
  margin-bottom: -9px;
  font-weight: 650;
  color: var(--brand);
}
.link-arrow svg { width: 18px; height: 18px; transition: transform var(--m-normal) var(--ease); }
.link-arrow:hover svg { transform: translateX(4px); }

/* Fields --------------------------------------------------------------
   The app animates the focus ring rather than snapping it; 160ms of
   colour is the difference between a form that wakes up and one that
   flickers. */

.field {
  /* Small enough that email, city and the button all fit one row in the
     hero's column. At 220px the button wrapped onto a line of its own. */
  flex: 1 1 165px;
  min-width: 0;
  height: 54px;
  padding-inline: var(--s-xl);
  border-radius: var(--r-pill);
  border: var(--bw) solid var(--border);
  background: var(--surface-alt);
  color: var(--text);
  transition: border-color var(--m-fast) var(--ease),
              background-color var(--m-fast) var(--ease),
              box-shadow var(--m-fast) var(--ease);
}
.field::placeholder { color: var(--text-3); }
.field:focus {
  outline: none;
  border-color: var(--brand);
  background: var(--surface-solid);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand) 18%, transparent);
}
.field-city { flex: 0 1 125px; }
.field[aria-invalid="true"] { border-color: #E5484D; }

.waitlist { margin-top: var(--s-2xl); }
.waitlist-fields { display: flex; flex-wrap: wrap; gap: var(--s-md); }
.waitlist .btn { flex: 0 0 auto; }

.form-note {
  margin-top: var(--s-md);
  font-size: var(--t-caption);
  color: var(--text-3);
  padding-left: var(--s-lg);
  transition: color var(--m-normal) var(--ease);
}
.form-note[data-state="error"] { color: #E5484D; }
.form-note[data-state="ok"] { color: var(--like); font-weight: 600; }

/* Reveal --------------------------------------------------------------
   Mirrors the app's <Reveal>: 18px up, fading in, siblings staggered by
   the same 55ms. Driven by IntersectionObserver in main.js. */

/* Scoped to .js, which an inline script in <head> adds before first paint.
   Without that scope a browser with JavaScript off — or a script that
   fails to load — would hide the entire page behind opacity 0 forever. */
.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--m-slow) var(--ease),
              transform var(--m-slow) var(--ease);
  transition-delay: calc(var(--reveal-i, 0) * var(--m-stagger));
}
.js .reveal.is-in { opacity: 1; transform: none; }

/* --------------------------------------------------- 4. chrome ------ */

/* Ambient field. Four drifting orbs, same colours and roles as the
   app's AmbientBackground — brand, brand-light, like, star. */
.ambient {
  position: fixed; inset: 0;
  z-index: -1;
  overflow: hidden;
  background: var(--bg);
  transition: background-color var(--m-normal) var(--ease);
  pointer-events: none;
}
.orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(10px);
  opacity: var(--orb-alpha);
  transition: opacity var(--m-slow) var(--ease);
  will-change: transform;
}
.orb-1 {
  width: 78vw; height: 78vw; left: -14vw; top: -18vw;
  background: radial-gradient(circle, var(--brand) 0%,
    color-mix(in srgb, var(--brand) 45%, transparent) 55%, transparent 72%);
  animation: drift-1 26s ease-in-out infinite alternate;
}
.orb-2 {
  width: 64vw; height: 64vw; right: -16vw; top: 6vh;
  background: radial-gradient(circle, var(--brand-light) 0%,
    color-mix(in srgb, var(--brand-light) 42%, transparent) 55%, transparent 72%);
  animation: drift-2 31s ease-in-out infinite alternate;
}
.orb-3 {
  width: 56vw; height: 56vw; right: 4vw; bottom: -10vh;
  background: radial-gradient(circle, var(--like) 0%,
    color-mix(in srgb, var(--like) 38%, transparent) 55%, transparent 72%);
  animation: drift-3 37s ease-in-out infinite alternate;
  opacity: calc(var(--orb-alpha) * .6);
}
.orb-4 {
  width: 48vw; height: 48vw; left: -8vw; bottom: -6vh;
  background: radial-gradient(circle, var(--star) 0%,
    color-mix(in srgb, var(--star) 34%, transparent) 55%, transparent 72%);
  animation: drift-4 43s ease-in-out infinite alternate;
  opacity: calc(var(--orb-alpha) * .45);
}

@keyframes drift-1 { to { transform: translate3d(9vw, 7vh, 0) scale(1.28); } }
@keyframes drift-2 { to { transform: translate3d(-10vw, 9vh, 0) scale(1.22); } }
@keyframes drift-3 { to { transform: translate3d(-7vw, -10vh, 0) scale(1.3); } }
@keyframes drift-4 { to { transform: translate3d(11vw, -7vh, 0) scale(1.25); } }

/* A hair of noise over the whole field. Large flat gradients band badly
   on 8-bit displays; grain is what hides the steps. */
.ambient-grain {
  position: absolute; inset: -50%;
  opacity: var(--grain);
  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='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Header. Transparent at rest, frosted once there is content behind it —
   the same rule the app's AppHeader follows. */
.site-header {
  position: fixed; inset: 0 0 auto 0;
  z-index: 100;
  transition: var(--skin), box-shadow var(--m-normal) var(--ease);
}
.site-header::before {
  content: ""; position: absolute; inset: 0;
  opacity: 0;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(var(--blur)) saturate(1.4);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(1.4);
  border-bottom: 1px solid var(--border);
  transition: opacity var(--m-normal) var(--ease);
}
.site-header.is-stuck::before { opacity: 1; }
/* Paper and Soft cannot blur — they get an honest solid instead. */
[data-theme="paper"] .site-header::before,
[data-theme="soft"] .site-header::before,
[data-theme="neon"] .site-header::before {
  background: color-mix(in srgb, var(--bg) 94%, transparent);
}

.header-inner {
  position: relative;
  display: flex; align-items: center; gap: var(--s-xl);
  height: 72px;
}

.brand { display: inline-flex; align-items: center; gap: 10px; flex: none; }
.brand-mark {
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border-radius: var(--r-sm);
  color: var(--on-brand);
  background: linear-gradient(135deg, var(--grad-a), var(--grad-b));
  box-shadow: var(--shadow-glow);
  transition: var(--skin), transform var(--m-normal) var(--ease-spring);
}
.brand:hover .brand-mark { transform: rotate(-6deg) scale(1.06); }
.brand-mark svg { width: 72%; height: 72%; }
.brand-word {
  font-size: 1.16rem; font-weight: 750; letter-spacing: -.03em;
}

.nav {
  display: flex; align-items: center; gap: var(--s-xl);
  margin-left: auto;
  font-size: var(--t-caption);
  font-weight: 550;
  color: var(--text-2);
}
.nav a { position: relative; padding-block: 6px; transition: color var(--m-fast) var(--ease); }
.nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 1.5px; border-radius: 2px;
  background: var(--brand);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--m-normal) var(--ease);
}
.nav a:hover { color: var(--text); }
.nav a:hover::after { transform: scaleX(1); }

.header-actions { display: flex; align-items: center; gap: var(--s-md); flex: none; }

.theme-toggle {
  display: grid; place-items: center;
  width: 40px; height: 40px;
  border-radius: var(--r-pill);
  border: var(--bw) solid var(--border);
  background: var(--surface-alt);
  color: var(--text-2);
  transition: var(--skin), transform var(--m-normal) var(--ease-spring);
}
.theme-toggle:hover { color: var(--brand); transform: rotate(24deg); }
.theme-toggle svg { width: 19px; height: 19px; }

/* Footer -------------------------------------------------------------- */

.site-footer {
  position: relative;
  margin-top: var(--s-4xl);
  padding-top: var(--s-3xl);
  border-top: 1px solid var(--border);
  /* Fades in rather than starting at full strength. A flat 80% --bg began
     abruptly at the footer's first pixel, which put another horizontal
     band across the page. The hairline above stays — that is a divider the
     eye reads as intentional, not a seam. */
  background: linear-gradient(180deg,
    transparent 0%,
    color-mix(in srgb, var(--bg) 55%, transparent) 22%,
    color-mix(in srgb, var(--bg) 85%, transparent) 100%);
  transition: var(--skin);
}
.footer-inner {
  display: flex; flex-wrap: wrap; gap: var(--s-3xl);
  justify-content: space-between;
  padding-bottom: var(--s-2xl);
}
.footer-brand { max-width: 300px; }
.footer-brand p {
  margin-top: var(--s-lg);
  color: var(--text-3);
  font-size: var(--t-caption);
}
.footer-nav { display: flex; flex-wrap: wrap; gap: var(--s-3xl); }
.footer-nav h4 {
  font-size: var(--t-micro); font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: var(--s-lg);
}
.footer-nav a {
  display: block;
  font-size: var(--t-caption);
  color: var(--text-2);
  /* 10px, not 5px: at 5px these rows measured 33px tall, and the footer is
     the one place on a phone where links sit stacked close together. */
  padding-block: 10px;
  transition: color var(--m-fast) var(--ease), transform var(--m-fast) var(--ease);
}
.footer-nav a:hover { color: var(--brand); transform: translateX(3px); }

.footer-base {
  display: flex; flex-wrap: wrap; gap: var(--s-md);
  justify-content: space-between;
  padding-block: var(--s-xl);
  border-top: 1px solid var(--border);
  font-size: var(--t-caption);
  color: var(--text-3);
}
.footer-domain { font-weight: 600; color: var(--text-2); }

/* ------------------------------------------------- 5. sections ------ */

.section { padding-block: clamp(72px, 11vw, 140px); position: relative; }
.section-tight { padding-block: clamp(56px, 8vw, 100px); }

.section-head { margin-bottom: var(--s-3xl); }
.section-head-center {
  text-align: center;
  margin-inline: auto;
  max-width: 660px;
}
.section-head-center .section-lede { margin-inline: auto; }

/* Hero ---------------------------------------------------------------- */

.hero { position: relative; padding-top: clamp(104px, 12vw, 152px); padding-bottom: clamp(48px, 6vw, 84px); }

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}

.hero-title {
  font-size: var(--t-hero);
  font-weight: 820;
  letter-spacing: -.038em;
  line-height: 1.02;
  text-wrap: balance;
}
.hero-title em {
  font-style: normal;
  /* The one gradient word on the page. Anything more and it stops being
     an emphasis and becomes a texture. */
  background: linear-gradient(120deg, var(--brand-light), var(--brand) 55%, var(--grad-b));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
[data-theme="paper"] .hero-title em { color: var(--brand); background: none; }

.lede {
  margin-top: var(--s-lg);
  font-size: var(--t-lede);
  color: var(--text-2);
  max-width: 52ch;
  text-wrap: pretty;
}

.hero .waitlist { margin-top: var(--s-xl); }

.trust {
  display: flex; flex-wrap: wrap; gap: var(--s-lg) var(--s-xl);
  margin-top: var(--s-xl);
  font-size: var(--t-caption);
  color: var(--text-3);
}
.trust li { display: inline-flex; align-items: center; gap: 8px; }
.trust svg { width: 17px; height: 17px; color: var(--brand); flex: none; }

/* Deliberately draws nothing.
   This used to fade the hero's bottom 160px into an opaque --bg. The
   ambient field behind the page is continuous and fixed, so painting the
   background colour over one section and not the next put a hard
   horizontal line across the page at the hero's edge — the page read as
   two stacked slides rather than one document. The element stays in the
   markup as a hook; it simply has nothing to do any more. */
.hero-fade { display: none; }

.hero-stage { position: relative; display: grid; place-items: center; }

.float-chip {
  position: absolute;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px;
  border-radius: var(--r-pill);
  border: var(--bw) solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  box-shadow: var(--shadow-card);
  font-size: var(--t-caption);
  font-weight: 600;
  white-space: nowrap;
  transition: var(--skin);
}
/* Clear of the phone's own text. At -6% the first chip sat straight over
   the "24+ within 50 km" line in the mockup's header. */
.float-chip-a { left: -17%; top: 17%; animation: bob 7s ease-in-out infinite; }
.float-chip-b { right: -13%; bottom: 22%; animation: bob 9s ease-in-out infinite reverse; }
@keyframes bob { 50% { transform: translateY(-10px); } }

.dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.dot-like { background: var(--like); box-shadow: 0 0 12px var(--like); }
.dot-star { background: var(--star); box-shadow: 0 0 12px var(--star); }

/* Statement + stats --------------------------------------------------- */

.statement {
  max-width: 26ch;
  font-size: clamp(1.5rem, 3.4vw, 2.5rem);
  font-weight: 700;
  letter-spacing: -.028em;
  line-height: 1.24;
  max-width: 20ch;
  max-width: 24ch;
}
.statement { max-width: 30ch; }
.statement em { font-style: normal; color: var(--brand); }

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--s-xl);
  margin-top: var(--s-3xl);
  padding-top: var(--s-2xl);
  border-top: 1px solid var(--border);
}
.stat-num {
  display: block;
  font-size: clamp(2.4rem, 4.6vw, 3.4rem);
  font-weight: 800;
  letter-spacing: -.04em;
  line-height: 1;
  color: var(--brand);
  font-variant-numeric: tabular-nums;
}
.stat p {
  margin-top: var(--s-md);
  font-size: var(--t-caption);
  color: var(--text-2);
  max-width: 34ch;
}

/* Steps --------------------------------------------------------------- */

/* Two by two, not auto-fit. There are exactly four steps, and auto-fit
   settled on three columns at desktop widths — which left the fourth step
   sitting alone on a second row looking like an afterthought. */
.steps {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-xl);
}
@media (max-width: 700px) {
  .steps { grid-template-columns: minmax(0, 1fr); }
}
.step {
  position: relative;
  padding: var(--s-xl);
  border-radius: var(--r-xl);
  border: var(--bw) solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: var(--skin), transform var(--m-normal) var(--ease),
              box-shadow var(--m-normal) var(--ease);
}
.step::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--sheen), transparent);
}
.step:hover {
  transform: translateY(-5px);
  box-shadow: var(--shadow-card), var(--shadow-glow);
}
.step-num {
  display: inline-grid; place-items: center;
  width: 42px; height: 42px;
  margin-bottom: var(--s-lg);
  border-radius: var(--r-sm);
  background: var(--brand-tint);
  border: var(--bw) solid color-mix(in srgb, var(--brand) 32%, transparent);
  color: var(--brand);
  font-size: var(--t-caption);
  font-weight: 750;
  letter-spacing: .02em;
}
.step h3 {
  font-size: var(--t-title);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.2;
}
.step p {
  margin-top: var(--s-md);
  font-size: var(--t-caption);
  color: var(--text-2);
}

/* Compatibility ------------------------------------------------------- */

.fit-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}

.weights { display: grid; gap: var(--s-md); margin-top: var(--s-2xl); }
.weights li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 40%;
  align-items: center;
  gap: var(--s-lg);
  font-size: var(--t-caption);
  color: var(--text-2);
}
.bar {
  position: relative;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--surface-alt);
  overflow: hidden;
}
.bar::after {
  content: ""; position: absolute; inset: 0 auto 0 0;
  width: var(--w);
  border-radius: inherit;
  background: linear-gradient(90deg, var(--grad-a), var(--grad-b));
  transform: scaleX(0); transform-origin: left;
  transition: transform 900ms var(--ease);
}
.is-in .bar::after, .reveal.is-in ~ * .bar::after { transform: scaleX(1); }
.weights.is-in .bar::after { transform: scaleX(1); }

.fit-card {
  padding: clamp(24px, 3vw, 36px);
  border-radius: var(--r-2xl);
  border: var(--bw) solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  box-shadow: var(--shadow-card);
  transition: var(--skin);
}

.fit-score { display: flex; align-items: center; gap: var(--s-xl); }

.ring { position: relative; width: 112px; height: 112px; flex: none; }
.ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 9; stroke-linecap: round; }
.ring-track { stroke: var(--surface-alt); }
.ring-fill {
  stroke: var(--brand);
  stroke-dasharray: 326.7;           /* 2πr, r = 52 */
  stroke-dashoffset: 326.7;
  transition: stroke-dashoffset 1400ms var(--ease);
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--brand) 55%, transparent));
}
[data-theme="paper"] .ring-fill { filter: none; }
.ring-label {
  position: absolute; inset: 0;
  display: grid; place-content: center; place-items: baseline;
  grid-auto-flow: column;
}
.ring-num {
  font-size: 2.3rem; font-weight: 800; letter-spacing: -.04em;
  color: var(--brand); font-variant-numeric: tabular-nums;
}
.ring-pct { font-size: 1.1rem; font-weight: 700; color: var(--brand); opacity: .7; }

.fit-headline {
  margin-top: 6px;
  font-size: var(--t-title);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.22;
}

.signals { display: grid; gap: var(--s-sm); margin-top: var(--s-xl); }
.signal {
  display: flex; align-items: center; gap: var(--s-md);
  padding: var(--s-md);
  border-radius: var(--r-md);
  background: var(--surface-alt);
  transition: var(--skin), transform var(--m-fast) var(--ease);
}
.signal:hover { transform: translateX(4px); }
.signal p { font-size: var(--t-caption); color: var(--text); }
.signal-icon {
  display: grid; place-items: center;
  width: 36px; height: 36px; flex: none;
  border-radius: var(--r-sm);
}
.signal-icon svg { width: 18px; height: 18px; }
.signal-good .signal-icon { color: var(--like); background: color-mix(in srgb, var(--like) 15%, transparent); }
.signal-ok .signal-icon   { color: var(--star); background: color-mix(in srgb, var(--star) 15%, transparent); }

.fit-foot {
  margin-top: var(--s-xl);
  padding-top: var(--s-lg);
  border-top: 1px solid var(--border);
  font-size: var(--t-caption);
  color: var(--text-3);
}

/* Verified ------------------------------------------------------------ */

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}
.split-visual { position: relative; }

.company-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-md);
}
.company-card {
  padding: var(--s-lg);
  border-radius: var(--r-lg);
  border: var(--bw) solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  box-shadow: var(--shadow-card);
  transition: var(--skin), transform var(--m-normal) var(--ease);
}
.company-card:hover { transform: translateY(-4px); }
.company-name { margin-top: var(--s-md); font-weight: 650; font-size: var(--t-caption); }
.company-meta { font-size: var(--t-micro); color: var(--text-3); letter-spacing: 0; text-transform: none; font-weight: 500; }

/* A logo tile is always light, in every theme — favicons are mostly dark
   marks on transparent, so a dark chip would erase half of them. Same
   call the app's CompanyLogo makes. */
.logo-tile {
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border-radius: 9px;
  background: #FFFFFF;
  border: 1px solid rgba(17,17,22,.10);
  color: #221B12;
  font-size: .78rem; font-weight: 800;
  flex: none;
}
.logo-lg { width: 42px; height: 42px; border-radius: 12px; font-size: 1rem; }

.follow-btn {
  display: block;
  margin-top: var(--s-md);
  padding-block: 8px;
  border-radius: var(--r-pill);
  border: 1.5px solid var(--border-strong);
  text-align: center;
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-2);
  transition: var(--skin);
}
.follow-btn.is-on {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--on-brand);
}

.verified-badge-demo {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: var(--s-xl);
  padding: 10px 18px;
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--verified) 14%, transparent);
  border: var(--bw) solid color-mix(in srgb, var(--verified) 35%, transparent);
  color: var(--verified);
  font-size: var(--t-caption);
  font-weight: 650;
  transition: var(--skin);
}
.vmark { display: grid; place-items: center; width: 18px; height: 18px; }
.vmark svg { width: 100%; height: 100%; }

/* Safety -------------------------------------------------------------- */

.safety-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--s-xl);
}
.safety-card {
  position: relative;
  padding: var(--s-xl);
  border-radius: var(--r-xl);
  border: var(--bw) solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: var(--skin), transform var(--m-normal) var(--ease),
              border-color var(--m-normal) var(--ease);
}
.safety-card::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 2px;
  background: linear-gradient(90deg, var(--grad-a), var(--grad-b));
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--m-normal) var(--ease);
}
.safety-card:hover { transform: translateY(-5px); }
.safety-card:hover::after { transform: scaleX(1); }
.safety-icon {
  display: grid; place-items: center;
  width: 46px; height: 46px;
  margin-bottom: var(--s-lg);
  border-radius: var(--r-md);
  background: var(--brand-tint);
  color: var(--brand);
}
.safety-icon svg { width: 22px; height: 22px; }
.safety-card h3 {
  font-size: 1.06rem; font-weight: 700; letter-spacing: -.015em; line-height: 1.28;
}
.safety-card p { margin-top: var(--s-md); font-size: var(--t-caption); color: var(--text-2); }

/* Themes -------------------------------------------------------------- */

/* Four across, then two by two. Same reason as the steps: auto-fit landed
   on three columns at tablet widths and left Soft stranded on its own row. */
.theme-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s-xl);
  max-width: 900px;
  margin-inline: auto;
}
@media (max-width: 900px) {
  .theme-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.theme-card {
  display: grid; justify-items: center; gap: 6px;
  padding: var(--s-lg);
  border-radius: var(--r-xl);
  border: var(--bw) solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  text-align: center;
  transition: var(--skin), transform var(--m-normal) var(--ease-spring),
              box-shadow var(--m-normal) var(--ease);
}
.theme-card:hover { transform: translateY(-6px); }
.theme-card[aria-checked="true"] {
  border-color: var(--brand);
  box-shadow: var(--shadow-glow);
}
.theme-name { font-weight: 700; letter-spacing: -.015em; margin-top: var(--s-md); }
.theme-traits { font-size: var(--t-micro); color: var(--text-3); letter-spacing: .04em; text-transform: uppercase; font-weight: 600; }

/* Miniature phones. Built from each theme's own literal values rather
   than the live custom properties — the point is to show a theme that is
   NOT the active one, so they must not inherit. */
.mini {
  display: block;
  width: 92px; height: 164px;
  padding: 4px;
  border-radius: 20px;
  background: #14141A;
  box-shadow: var(--shadow-card);
}
.mini-screen {
  display: block; position: relative;
  width: 100%; height: 100%;
  border-radius: 16px;
  overflow: hidden;
  padding: 9px 8px;
}
.mini-bar  { display: block; height: 7px; border-radius: 4px; width: 58%; }
.mini-card { display: block; height: 34px; border-radius: 10px; margin-top: 8px; }
.mini-card-sm { height: 24px; }
.mini-pill { display: block; position: absolute; left: 12px; right: 12px; bottom: 9px; height: 14px; border-radius: 999px; }

[data-mini="aurora"] .mini-screen { background: #0A0912; }
[data-mini="aurora"] .mini-bar    { background: #8B7CFF; }
[data-mini="aurora"] .mini-card   { background: #1C1930; border: 1px solid #2A2442; }
[data-mini="aurora"] .mini-pill   { background: linear-gradient(135deg,#7C6BFF,#4F3BD4); }

[data-mini="paper"] .mini-screen { background: #EDE3D2; }
[data-mini="paper"] .mini-bar    { background: #A8542B; }
[data-mini="paper"] .mini-card   { background: #F8F2E7; border: 1px solid #CFC0A6; border-radius: 6px; }
[data-mini="paper"] .mini-pill   { background: #A8542B; border-radius: 6px; }

[data-mini="neon"] .mini-screen { background: #000; }
[data-mini="neon"] .mini-bar    { background: #00E5FF; box-shadow: 0 0 8px #00E5FF; }
[data-mini="neon"] .mini-card   { background: #0A0A0E; border: 1.5px solid #1E2A30; border-radius: 8px; }
[data-mini="neon"] .mini-pill   { background: linear-gradient(135deg,#00E5FF,#7B61FF); box-shadow: 0 0 12px rgba(0,229,255,.6); }

[data-mini="soft"] .mini-screen { background: #F7F5F1; }
[data-mini="soft"] .mini-bar    { background: #6B8F71; }
[data-mini="soft"] .mini-card   { background: #fff; border-radius: 12px; box-shadow: 0 4px 10px -4px rgba(70,64,54,.35); }
[data-mini="soft"] .mini-pill   { background: linear-gradient(135deg,#7FA085,#5C7F63); }

/* FAQ ----------------------------------------------------------------- */

.faq { display: grid; gap: var(--s-md); }
.faq-item {
  border-radius: var(--r-lg);
  border: var(--bw) solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  overflow: hidden;
  transition: var(--skin), border-color var(--m-normal) var(--ease);
}
.faq-item[open] { border-color: color-mix(in srgb, var(--brand) 45%, var(--border)); }
.faq-item summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-lg);
  padding: var(--s-lg) var(--s-xl);
  font-weight: 650;
  letter-spacing: -.01em;
  cursor: pointer;
  list-style: none;
  transition: color var(--m-fast) var(--ease);
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary:hover { color: var(--brand); }
.chev {
  position: relative; width: 14px; height: 14px; flex: none;
  transition: transform var(--m-normal) var(--ease);
}
.chev::before, .chev::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 12px; height: 2px; border-radius: 2px;
  background: var(--brand);
  transform: translate(-50%, -50%);
  transition: transform var(--m-normal) var(--ease), opacity var(--m-fast) var(--ease);
}
.chev::after { transform: translate(-50%, -50%) rotate(90deg); }
.faq-item[open] .chev::after { transform: translate(-50%, -50%) rotate(0); opacity: 0; }
.faq-body { padding: 0 var(--s-xl) var(--s-xl); }
.faq-body p { font-size: var(--t-caption); color: var(--text-2); max-width: 62ch; }

/* Join ---------------------------------------------------------------- */

.section-join { padding-bottom: clamp(80px, 12vw, 150px); }
.join-card {
  position: relative;
  padding: clamp(32px, 5vw, 60px);
  border-radius: var(--r-2xl);
  border: var(--bw) solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  box-shadow: var(--shadow-card);
  text-align: center;
  overflow: hidden;
  transition: var(--skin);
}
.join-card::before {
  content: ""; position: absolute; inset: -40% 20% auto 20%; height: 70%;
  background: radial-gradient(ellipse at top,
    color-mix(in srgb, var(--brand) 30%, transparent), transparent 70%);
  pointer-events: none;
}
.join-mark {
  position: relative;
  display: grid; place-items: center;
  width: 66px; height: 66px;
  margin: 0 auto var(--s-xl);
  border-radius: var(--r-lg);
  color: var(--on-brand);
  background: linear-gradient(135deg, var(--grad-a), var(--grad-b));
  box-shadow: var(--shadow-glow);
}
.join-mark svg { width: 72%; height: 72%; }
.join-title {
  position: relative;
  font-size: var(--t-display);
  font-weight: 800; letter-spacing: -.03em; line-height: 1.08;
  text-wrap: balance;
}
.join-lede {
  position: relative;
  margin: var(--s-lg) auto 0;
  max-width: 46ch;
  color: var(--text-2);
  font-size: var(--t-lede);
}
.waitlist-lg { position: relative; max-width: 560px; margin-inline: auto; }
.waitlist-lg .waitlist-fields { justify-content: center; }
.waitlist-lg .form-note { text-align: center; padding-left: 0; }

/* Article pages (privacy, terms) --------------------------------------- */

.article-page { padding-top: clamp(120px, 15vw, 170px); }

.article-head { margin-bottom: var(--s-3xl); }
.article-title {
  font-size: var(--t-display);
  font-weight: 800; letter-spacing: -.03em; line-height: 1.08;
}
.article-intro {
  margin-top: var(--s-lg);
  font-size: var(--t-lede);
  color: var(--text-2);
  max-width: 60ch;
}
.article-updated {
  margin-top: var(--s-md);
  font-size: var(--t-caption);
  color: var(--text-3);
}

.article-notice {
  display: flex; gap: var(--s-md);
  margin: var(--s-xl) 0 var(--s-3xl);
  padding: var(--s-lg) var(--s-xl);
  border-radius: var(--r-lg);
  border: var(--bw) solid color-mix(in srgb, var(--star) 42%, transparent);
  background: color-mix(in srgb, var(--star) 12%, transparent);
  font-size: var(--t-caption);
  color: var(--text);
}
.article-notice strong { color: var(--star); }
.article-notice svg { width: 20px; height: 20px; flex: none; color: var(--star); margin-top: 2px; }

.article-section { margin-bottom: var(--s-2xl); }
.article-section h2 {
  font-size: var(--t-title);
  font-weight: 700; letter-spacing: -.02em; line-height: 1.24;
  margin-bottom: var(--s-md);
}
.article-section p { color: var(--text-2); max-width: 68ch; }
.article-section p + p { margin-top: var(--s-md); }
.article-section ul { margin-top: var(--s-md); display: grid; gap: var(--s-sm); }
.article-section li {
  position: relative;
  padding-left: var(--s-xl);
  color: var(--text-2);
  max-width: 68ch;
}
.article-section li::before {
  content: ""; position: absolute; left: 4px; top: .68em;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--brand);
}

.article-foot {
  margin-top: var(--s-3xl);
  padding-top: var(--s-xl);
  border-top: 1px solid var(--border);
  font-size: var(--t-caption);
  color: var(--text-3);
  max-width: 68ch;
}

.back-link {
  display: inline-flex; align-items: center; gap: 8px;
  margin-bottom: var(--s-xl);
  font-size: var(--t-caption);
  font-weight: 600;
  color: var(--brand);
}
.back-link svg { width: 16px; height: 16px; transition: transform var(--m-fast) var(--ease); }
.back-link:hover svg { transform: translateX(-3px); }

/* ------------------------------------------- 6. app mockup (phone) --- */

.phone {
  position: relative;
  width: min(320px, 78vw);
  aspect-ratio: 320 / 660;
  padding: 9px;
  border-radius: 46px;
  background: linear-gradient(160deg, #2A2A33, #121216 60%);
  box-shadow:
    0 2px 0 rgba(255,255,255,.10) inset,
    0 60px 110px -50px rgba(0,0,0,.9),
    0 30px 60px -40px rgba(0,0,0,.7);
}
.phone::after {
  /* Notch */
  content: ""; position: absolute; top: 20px; left: 50%;
  transform: translateX(-50%);
  width: 92px; height: 22px; border-radius: 999px;
  background: #0B0B0F;
  z-index: 3;
}
.phone-screen {
  position: relative;
  width: 100%; height: 100%;
  border-radius: 38px;
  overflow: hidden;
  background: var(--bg);
  display: flex; flex-direction: column;
  transition: background-color var(--m-normal) var(--ease);
}

.app-header { padding: 46px 18px 10px; }
.app-header-top { display: flex; align-items: center; justify-content: space-between; }
.app-logo { display: block; width: 22px; height: 22px; color: var(--brand); }
.app-filter {
  display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--brand-tint); color: var(--brand);
}
.app-filter svg { width: 15px; height: 15px; }
.app-title { margin-top: 12px; font-size: 1.62rem; font-weight: 800; letter-spacing: -.035em; }
.app-sub { font-size: .68rem; color: var(--text-3); }

.app-scroll {
  flex: 1;
  overflow: hidden;
  padding: 12px 14px 0;
  display: grid;
  gap: 12px;
  align-content: start;
  -webkit-mask-image: linear-gradient(to bottom, #000 78%, transparent);
  mask-image: linear-gradient(to bottom, #000 78%, transparent);
}

.pcard {
  border-radius: var(--r-xl);
  border: var(--bw) solid var(--border);
  background: var(--surface-solid);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  transition: var(--skin);
}
.pcard-peek { opacity: .82; }

.pcard-photo {
  position: relative;
  height: 122px;
  display: flex; align-items: flex-end;
}
/* The photo fills the frame. `object-position` sits above centre because
   these are portrait images cropped into a wide band — a centred crop lands
   on the torso, and a flush-top one lands on the hairline. Same call the
   app's own PersonCard makes with contentPosition. */
.pcard-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  /* `contain` + bottom anchoring, not `cover`. A Memoji-style cut-out is a
     bust on a transparent background: cropping it like a photograph would
     slice the head, whereas standing it on the card's floor is exactly how
     the reference art is composed. A full-bleed photograph still fills the
     frame acceptably this way. */
  object-fit: contain;
  object-position: 50% 100%;
}
/* Empty state, until an avatar PNG is dropped in. The app's own no-photo
   glyph, centred on the tinted frame — restrained on purpose. */
.pcard-empty {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: var(--text-3);
  opacity: .5;
}
.pcard-empty svg {
  width: 42px; height: 42px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Shown whenever the photo is absent — the <img> removes itself on error, so
   this tinted frame is what remains. Never a broken-image icon. */
.pcard-photo {
  background:
    radial-gradient(120% 100% at 30% 0%,
      color-mix(in srgb, var(--brand) 32%, transparent) 0%,
      var(--sunken) 60%, var(--surface-alt) 100%);
}
.pcard-photo::after {
  content: ""; position: absolute; inset: 0;
  /* Starts lower and stays clear for longer than it used to. The old scrim
     began at 30% and put the face itself in shadow, which is fine over a
     gradient and wrong over a person. */
  background: linear-gradient(to bottom,
    transparent 0%, transparent 54%, rgba(8,8,14,.5) 76%, rgba(8,8,14,.93) 100%);
}
.pcard-name {
  position: relative; z-index: 2;
  display: flex; align-items: baseline; gap: 6px;
  padding: 0 12px 10px;
  color: #fff;
}
.pcard-name strong { font-size: .95rem; font-weight: 700; letter-spacing: -.02em; }
.pcard-name span { font-size: .8rem; opacity: .9; }

.pill {
  position: absolute; z-index: 2;
  top: 10px;
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 9px;
  border-radius: 999px;
  background: rgba(10,10,18,.6);
  border: 1px solid rgba(255,255,255,.28);
  color: #fff;
  font-size: .58rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
}
.pill svg { width: 11px; height: 11px; color: var(--like); }
.pill-verified { left: 10px; }
.pill-score { right: 10px; }

.pcard-body { padding: 11px 12px 12px; display: grid; gap: 9px; }
.pcard-work { display: flex; align-items: center; gap: 8px; }
.pcard-role { font-size: .68rem; font-weight: 500; }
.pcard-same { font-size: .6rem; color: var(--brand); font-weight: 650; }
.pcard-rent { display: flex; align-items: baseline; gap: 5px; }
.pcard-rent strong { font-size: .82rem; font-weight: 700; }
.pcard-rent span { font-size: .62rem; color: var(--text-3); }
.pcard-facts { display: flex; flex-wrap: wrap; gap: 5px; }
.fact {
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--surface-alt);
  color: var(--text-2);
  font-size: .58rem;
  font-weight: 600;
}
.app-btn {
  display: block;
  margin-top: 2px;
  padding-block: 9px;
  border-radius: var(--r-pill);
  text-align: center;
  font-size: .72rem;
  font-weight: 700;
  color: var(--on-brand);
  background: linear-gradient(135deg, var(--grad-a), var(--grad-b));
  box-shadow: var(--shadow-glow);
}

/* The floating glass tab bar, cursor and all. */
.app-tabbar {
  position: relative;
  display: flex;
  margin: 0 12px 14px;
  padding: 5px;
  border-radius: 999px;
  border: var(--bw) solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: var(--shadow-card);
}
.app-tab {
  flex: 1;
  display: grid; justify-items: center; gap: 2px;
  padding-block: 5px;
  font-size: .46rem; font-weight: 700; letter-spacing: .04em;
  color: var(--text-3);
  border-radius: 999px;
}
.app-tab svg {
  width: 15px; height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.app-tab.is-on {
  color: var(--brand);
  background: color-mix(in srgb, var(--brand) 22%, transparent);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28);
}
/* The app swaps the outline glyph for its filled twin on the active tab.
   One stroke weight up reads as the same emphasis without shipping ten icons. */
.app-tab.is-on svg { stroke-width: 2.2; }

/* ------------------------------- 7. responsive & reduced motion ------ */

@media (max-width: 980px) {
  .hero-grid, .fit-grid, .split { grid-template-columns: minmax(0, 1fr); }
  .hero-stage { order: -1; margin-bottom: var(--s-lg); }
  .hero-copy { text-align: left; }
  .float-chip-a { left: 0; top: 10%; }
  .float-chip-b { right: 0; bottom: 12%; }
  .nav { display: none; }
  .fit-card { order: 2; }
  .company-grid { max-width: 460px; }
}

@media (max-width: 620px) {
  html { scroll-padding-top: 76px; }
  .header-inner { height: 64px; }
  .brand-word { font-size: 1.06rem; }
  .waitlist-fields { flex-direction: column; }
  .field, .waitlist .btn { width: 100%; flex: 1 1 auto; }
  .float-chip { display: none; }
  .footer-inner { flex-direction: column; gap: var(--s-2xl); }
  .footer-nav { gap: var(--s-xl); }
  .statement { font-size: 1.42rem; }
  .stat-row { gap: var(--s-2xl); }
}

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

/* Print — someone will send this page to a flatmate. Make it legible. */
@media print {
  .ambient, .site-header, .phone, .float-chip, .theme-grid { display: none !important; }
  body { background: #fff; color: #000; }
  .section { padding-block: 24px; }
}

/* ------------------------------------------- who can see you (#choice) --
   The product's own answer to the question every roommate app gets asked,
   so it is built as a demonstration rather than a paragraph: the control on
   the left is the real one from Profile → Discovery, and it really switches.
   ---------------------------------------------------------------------- */

.section-choice { position: relative; }
/* A wash behind this one section, so it reads as the feature it is rather
   than as another row in the stack. */
/* Centred, and fully faded out well before the section's own edges.
   Anchored at `50% 0%` the wash was at full strength exactly on the top
   boundary and absent one pixel above it, which is the same seam the hero
   fade was making. A glow that starts and ends inside the section cannot
   draw a line at its edge. */
.section-choice::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(68% 52% at 50% 50%,
    color-mix(in srgb, var(--brand) 15%, transparent) 0%,
    color-mix(in srgb, var(--brand) 6%, transparent) 42%,
    transparent 78%);
  pointer-events: none;
}

.choice-grid {
  display: grid;
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
  gap: clamp(28px, 4.5vw, 64px);
  align-items: center;
}

.choice-demo { display: grid; gap: var(--s-md); justify-items: center; }

.choice-panel {
  width: 100%;
  padding: clamp(20px, 3vw, 30px);
  border-radius: var(--r-2xl);
  border: var(--bw) solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  box-shadow: var(--shadow-card);
  transition: var(--skin);
}
.choice-panel-title { font-weight: 700; letter-spacing: -.015em; margin-bottom: var(--s-lg); }

/* The app's segmented control: a sunken track, the active cell raised. */
.segmented {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  padding: 4px;
  border-radius: var(--r-md);
  background: var(--sunken);
}
.segment {
  padding: 11px 8px;
  border-radius: var(--r-sm);
  font-size: var(--t-caption);
  font-weight: 600;
  color: var(--text-2);
  transition: var(--skin), box-shadow var(--m-normal) var(--ease),
              transform var(--m-fast) var(--ease);
}
.segment:active { transform: scale(.98); }
.segment.is-on {
  background: var(--surface-solid);
  color: var(--brand);
  box-shadow: var(--shadow-card);
}

.choice-hint {
  margin-top: var(--s-md);
  font-size: var(--t-caption);
  color: var(--text-2);
  min-height: 2.6em;
}

/* The consent block only exists in the "open" state, the same way the app
   only shows its consent sheet on the way in. */
.choice-consent {
  margin-top: var(--s-lg);
  padding-top: var(--s-lg);
  border-top: 1px solid var(--border);
  animation: consent-in var(--m-slow) var(--ease) both;
}
@keyframes consent-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
.choice-consent-head {
  display: flex; align-items: center; gap: 8px;
  font-size: var(--t-caption);
  font-weight: 700;
  color: var(--brand);
  margin-bottom: var(--s-md);
}
.choice-consent-head svg { width: 17px; height: 17px; flex: none; }
.choice-consent-list { display: grid; gap: var(--s-sm); }
.choice-consent-list li {
  position: relative;
  padding-left: 20px;
  font-size: var(--t-caption);
  color: var(--text-2);
}
.choice-consent-list li::before {
  content: ""; position: absolute; left: 4px; top: .62em;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--brand);
}
.choice-consent-foot {
  margin-top: var(--s-md);
  font-size: var(--t-micro);
  letter-spacing: .04em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--text-3);
}
.choice-caption { font-size: var(--t-caption); color: var(--text-3); }

.choice-points { display: grid; gap: var(--s-xl); }
.choice-point { display: flex; gap: var(--s-lg); align-items: flex-start; }
.choice-icon {
  display: grid; place-items: center;
  width: 44px; height: 44px; flex: none;
  border-radius: var(--r-md);
  background: var(--brand-tint);
  border: var(--bw) solid color-mix(in srgb, var(--brand) 28%, transparent);
  color: var(--brand);
}
.choice-icon svg { width: 21px; height: 21px; }
.choice-point h3 {
  font-size: 1.06rem; font-weight: 700; letter-spacing: -.015em; line-height: 1.3;
}
.choice-point p {
  margin-top: 6px;
  font-size: var(--t-caption);
  color: var(--text-2);
  max-width: 48ch;
}

@media (max-width: 980px) {
  .choice-grid { grid-template-columns: minmax(0, 1fr); }
}

/* --------------------------------------------- rotating deck (hero) ----
   The phone cycles through the three states of the gender setting. The
   cards are cross-faded rather than swapped outright, and the caption
   under the phone moves on the same clock, so the words and the pictures
   are never a frame out of step.
   ---------------------------------------------------------------------- */

/* Slot heights are fixed so a swap never reflows the phone. Two people with
   different job titles would otherwise make the whole mockup twitch. */
#deck .pcard {
  transition: opacity 260ms var(--ease), transform 260ms var(--ease);
}
#deck .pcard[data-slot="0"] { min-height: 268px; }
#deck .pcard[data-slot="1"] { min-height: 236px; }

/* Leaving. The second card trails the first by a beat — a deck that turns
   over in sequence reads as considered; both at once reads as a glitch. */
#deck.is-swapping .pcard {
  opacity: 0;
  transform: translateY(7px) scale(.985);
}
#deck.is-swapping .pcard[data-slot="1"] { transition-delay: 70ms; }

/* In flow, not absolutely pinned under the phone. Pinned at a fixed
   negative offset it fell off the bottom of the hero on a laptop, which is
   exactly where the explanation is needed most. hero-stage is a grid, so a
   second child simply takes the row beneath the phone. */
.deck-caption {
  width: min(340px, 86vw);
  margin-top: var(--s-lg);
  text-align: center;
  display: grid;
  gap: 6px;
  justify-items: center;
}
.deck-mode {
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brand);
  transition: opacity 200ms var(--ease), transform 200ms var(--ease);
}
.deck-note {
  font-size: var(--t-caption);
  color: var(--text-2);
  min-height: 2.6em;
  text-wrap: pretty;
  transition: opacity 200ms var(--ease), transform 200ms var(--ease);
}
.deck-caption.is-swapping .deck-mode,
.deck-caption.is-swapping .deck-note {
  opacity: 0;
  transform: translateY(5px);
}

.deck-dots { display: flex; gap: 7px; margin-top: 4px; }
.deck-dot {
  width: 22px; height: 4px;
  border-radius: var(--r-pill);
  background: var(--border-strong);
  padding: 0;
  transition: background-color var(--m-normal) var(--ease),
              width var(--m-normal) var(--ease);
}
/* A generous invisible target over a deliberately small mark. */
.deck-dot::after {
  content: ""; position: absolute;
  inset: -14px -6px;
}
.deck-dot { position: relative; }
.deck-dot.is-on { background: var(--brand); width: 30px; }
.deck-dot:hover { background: var(--brand-light); }

@media (max-width: 980px) {
  .deck-caption { margin-inline: auto; }
}

@media (prefers-reduced-motion: reduce) {
  #deck .pcard, .deck-mode, .deck-note { transition: none; }
}

/* ======================================================================
   HERO DECK v2

   Fixes, in order of how badly they showed:
   1. Two cards now fit the phone whole. The screen grew a little and the
      cards lost some padding; the bottom mask that used to fade the second
      card away is gone, because a card that fades out looks broken rather
      than looks like a list.
   2. The cut-out figures sit in a glow of their own colour with a soft
      floor under them, so they read as lit by the card instead of pasted
      onto it.
   3. Every face is stacked in its slot and cross-faded, so a swap moves
      opacity only — the artwork is already decoded.
   4. The pills shrank. At the old size the two of them were the loudest
      thing on a card whose subject is a person.
   ====================================================================== */

.phone { aspect-ratio: 320 / 700; }

.app-scroll {
  /* No mask. With both cards fitting there is nothing to fade out, and the
     gradient was reading as "the layout is cut off". */
  -webkit-mask-image: none;
  mask-image: none;
  gap: 10px;
  padding: 10px 13px 0;
}

/* One slot per position. Every person who can appear here is stacked
   inside it, absolutely, so swapping never reflows the phone. */
.pcard-slot {
  position: relative;
  height: 240px;
}

.pcard-face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  opacity: 0;
  transform: translateY(6px) scale(.985);
  pointer-events: none;
  transition: opacity 340ms var(--ease), transform 340ms var(--ease);
}
.pcard-face.is-active {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
/* The lower card trails the upper one, so the deck turns over as a
   sequence rather than both at once. */
.pcard-slot[data-slot="1"] .pcard-face { transition-delay: 80ms; }

.pcard-photo {
  height: 104px;
  flex: none;
  overflow: hidden;
  /* Deep, neutral base. The per-person accent is layered over it below, so
     four different people never make four differently-tinted cards. */
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--accent, var(--brand)) 22%, var(--surface-alt)) 0%,
      var(--surface-alt) 78%);
}

/* The light the figure is standing in. Sized and placed to sit behind the
   head, which is what makes the cut-out belong to the card. */
.pcard-glow {
  position: absolute;
  left: 50%;
  top: -12%;
  width: 132%;
  height: 150%;
  transform: translateX(-50%);
  background: radial-gradient(closest-side at 50% 42%,
    color-mix(in srgb, var(--accent, var(--brand)) 55%, transparent) 0%,
    color-mix(in srgb, var(--accent, var(--brand)) 18%, transparent) 46%,
    transparent 72%);
  pointer-events: none;
}

/* A soft contact shadow so the figure has something to stand on rather
   than floating with a hard bottom edge. */
.pcard-floor {
  position: absolute;
  left: 50%;
  bottom: -2px;
  width: 74%;
  height: 26px;
  transform: translateX(-50%);
  background: radial-gradient(closest-side at 50% 100%,
    rgba(0, 0, 0, .55), transparent 78%);
  pointer-events: none;
}

.pcard-img {
  position: absolute;
  left: 50%;
  bottom: 0;
  top: auto;
  width: auto;
  height: 118%;
  transform: translateX(-50%);
  object-fit: contain;
  object-position: bottom center;
  transform-origin: 50% 100%;
}

/* The scrim only has to carry the name now, so it starts far lower and
   never touches the face. */
.pcard-photo::after {
  inset: auto 0 0 0;
  height: 54%;
  background: linear-gradient(to bottom, transparent, rgba(6, 6, 12, .88));
}

.pcard-name { padding: 0 11px 8px; }
.pcard-name strong { font-size: .88rem; }
.pcard-name span { font-size: .74rem; }

/* ---- pills: quieter ---------------------------------------------------
   They are labels on a photograph, not headlines. */
.pill {
  top: 8px;
  gap: 3px;
  padding: 3px 7px;
  font-size: .5rem;
  letter-spacing: .05em;
  border-width: 1px;
}
.pill svg { width: 9px; height: 9px; }
.pill-verified { left: 8px; }
.pill-score { right: 8px; }

/* ---- body: tighter ---------------------------------------------------- */
.pcard-body {
  flex: 1;
  padding: 9px 11px 10px;
  gap: 7px;
  justify-content: space-between;
}
.pcard-work { gap: 7px; }
.logo-tile { width: 26px; height: 26px; border-radius: 8px; font-size: .68rem; }
.pcard-role { font-size: .64rem; }
.pcard-same { font-size: .56rem; }
.pcard-rent strong { font-size: .78rem; }
.pcard-rent span { font-size: .58rem; }
.fact { font-size: .54rem; padding: 2px 7px; }
.app-btn {
  margin-top: 0;
  padding-block: 7px;
  font-size: .68rem;
}

/* ======================================================================
   AVATAR IDLE MOTION

   Four different loops so a deck of four never looks like one asset
   repeated. Each pivots on the bottom of the frame, where the body meets
   the card, so it reads as a person shifting their weight rather than a
   picture being transformed. Amplitudes are deliberately under two
   degrees and three pixels: at this size anything larger stops being alive
   and starts being distracting.
   ====================================================================== */

@keyframes av-sway {
  0%, 100% { transform: translateX(-50%) rotate(-1.1deg); }
  50%      { transform: translateX(-50%) rotate(1.1deg); }
}
@keyframes av-nod {
  0%, 100% { transform: translateX(-50%) translateY(0) rotate(.4deg); }
  50%      { transform: translateX(-50%) translateY(-3px) rotate(-.4deg); }
}
@keyframes av-bob {
  0%, 100% { transform: translateX(-50%) translateY(0) scale(1); }
  50%      { transform: translateX(-50%) translateY(-2px) scale(1.018); }
}
@keyframes av-tilt {
  0%, 100% { transform: translateX(-50%) rotate(1.4deg) translateY(0); }
  50%      { transform: translateX(-50%) rotate(-.7deg) translateY(-2px); }
}

.pcard-img[data-motion="sway"] { animation: av-sway 5.2s ease-in-out infinite; }
.pcard-img[data-motion="nod"]  { animation: av-nod  4.4s ease-in-out infinite; }
.pcard-img[data-motion="bob"]  { animation: av-bob  6.1s ease-in-out infinite; }
.pcard-img[data-motion="tilt"] { animation: av-tilt 5.7s ease-in-out infinite; }

/* Only the card on screen animates. A hidden face looping in the
   background is work nobody can see. */
.pcard-face:not(.is-active) .pcard-img { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) {
  .pcard-img { animation: none !important; }
  .pcard-face { transition: none; }
}

/* ======================================================================
   WAITLIST FIELD v2

   Three separate pills sitting in a row read as a form someone assembled
   out of spare parts. This is one recessed control with two fields and the
   action inside it — the shape says "one thing to fill in", which is what
   it is. It collapses back to stacked full-width controls on a phone,
   where a three-up row would be unusable.
   ====================================================================== */

.waitlist-fields {
  display: flex;
  align-items: center;
  gap: 0;
  padding: 6px;
  border-radius: var(--r-pill);
  border: var(--bw) solid var(--border);
  background: var(--surface-alt);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--sheen) 60%, transparent),
    0 10px 30px -22px rgba(0, 0, 0, .8);
  transition: var(--skin), border-color var(--m-fast) var(--ease),
              box-shadow var(--m-fast) var(--ease);
}
/* The ring lives on the group, not the individual box, so focusing either
   field lights the whole control. */
.waitlist-fields:focus-within {
  border-color: var(--brand);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--sheen) 60%, transparent),
    0 0 0 4px color-mix(in srgb, var(--brand) 16%, transparent),
    0 14px 34px -20px color-mix(in srgb, var(--brand) 60%, transparent);
}

.waitlist-fields .field {
  height: 44px;
  border: 0;
  background: transparent;
  box-shadow: none;
  padding-inline: var(--s-lg);
  border-radius: var(--r-pill);
}
.waitlist-fields .field:focus {
  outline: none;
  background: transparent;
  box-shadow: none;
}
/* A hairline between the two inputs instead of a gap — it separates them
   without breaking the single-control silhouette. */
.waitlist-fields .field-city {
  flex: 0 1 132px;
  border-left: 1px solid var(--border);
  border-radius: 0;
}
.waitlist-fields .btn { height: 44px; flex: none; margin-left: 6px; }

@media (max-width: 620px) {
  .waitlist-fields {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    border-radius: var(--r-lg);
    padding: 8px;
  }
  .waitlist-fields .field {
    width: 100%;
    background: var(--surface);
    border: var(--bw) solid var(--border);
  }
  .waitlist-fields .field-city { border-left: var(--bw) solid var(--border); flex: 1 1 auto; }
  .waitlist-fields .btn { width: 100%; margin-left: 0; }
}

/* ----------------------------------------------------------------------
   DECK FIT

   Measured, not guessed. On the shipped phone the deck gets 458px between
   the header and the tab bar, and two 240px slots plus their gap wanted
   500 — so the lower card's action button was sliding under the tab bar.
   The header gives back ten, and each slot comes down to 216, which puts
   two whole cards inside the space with a little room to spare.
   ---------------------------------------------------------------------- */

.app-header { padding: 40px 16px 8px; }
.app-title { font-size: 1.48rem; }

.pcard-slot { height: 216px; }
.pcard-photo { height: 92px; }

.pcard-body {
  padding: 8px 10px 9px;
  gap: 6px;
}
.logo-tile { width: 24px; height: 24px; border-radius: 7px; font-size: .64rem; }
.pcard-role { font-size: .62rem; }
.pcard-name { padding: 0 10px 7px; }
.pcard-name strong { font-size: .84rem; }
.app-btn { padding-block: 6px; font-size: .66rem; }

/* ----------------------------------------------------------------------
   AVATAR FIT

   The image box was 118% of the frame and anchored to the bottom, so its
   top 18% sat above the frame and `overflow: hidden` sliced the tops of
   people's heads off. `contain` scales the artwork to the box, not to the
   frame — so an oversized box crops rather than enlarges.

   The box now matches the frame exactly and the frame grew instead, which
   is the only way to make the figure bigger without cutting it.
   ---------------------------------------------------------------------- */

.pcard-photo { height: 104px; }

.pcard-img {
  height: 100%;
  /* A hair of scale, from the bottom edge, so the figure fills the frame
     without its crown reaching the top. */
  transform: translateX(-50%) scale(1.04);
  transform-origin: 50% 100%;
}

/* The idle loops have to carry the same scale, or the avatar jumps to a
   different size the moment its animation starts. */
@keyframes av-sway {
  0%, 100% { transform: translateX(-50%) scale(1.04) rotate(-1.1deg); }
  50%      { transform: translateX(-50%) scale(1.04) rotate(1.1deg); }
}
@keyframes av-nod {
  0%, 100% { transform: translateX(-50%) scale(1.04) translateY(0) rotate(.4deg); }
  50%      { transform: translateX(-50%) scale(1.04) translateY(-3px) rotate(-.4deg); }
}
@keyframes av-bob {
  0%, 100% { transform: translateX(-50%) scale(1.04) translateY(0); }
  50%      { transform: translateX(-50%) scale(1.062) translateY(-2px); }
}
@keyframes av-tilt {
  0%, 100% { transform: translateX(-50%) scale(1.04) rotate(1.4deg) translateY(0); }
  50%      { transform: translateX(-50%) scale(1.04) rotate(-.7deg) translateY(-2px); }
}

/* Room for the taller frame: the body gives back what the photo took. */
.pcard-body { padding: 7px 10px 8px; gap: 5px; }
.pcard-rent strong { font-size: .76rem; }
.app-btn { padding-block: 6px; }

/* ======================================================================
   COMPANY MARKS

   Brand-coloured monograms, not the companies' actual logos.

   The app fetches a real favicon for an employer a user has verified
   against — that is a factual statement about that person's job. A
   marketing page is different: these four are invented people, and
   dropping Flipkart's and Zomato's real marks next to invented employees
   reads as those companies endorsing the product. A coloured monogram
   carries the same "which employer" signal without making that claim.
   ====================================================================== */

.logo-tile {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--mark, #6B7280) 92%, #FFFFFF),
    var(--mark, #6B7280));
  border: 0;
  color: #FFFFFF;
  font-weight: 800;
  letter-spacing: -.02em;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .35),
    0 3px 8px -3px color-mix(in srgb, var(--mark, #000) 70%, transparent);
}

/* ======================================================================
   SURFACES

   Every panel on the page was a flat slab of --surface. Each now carries a
   quiet wash of the active theme's brand from its top-left corner, plus a
   one-pixel highlight along the top edge — the same trick the app's Panel
   uses to stop a card reading as a hole cut in the background. It is
   deliberately faint: at 7% you register depth without registering a
   colour.
   ====================================================================== */

.step,
.safety-card,
.faq-item,
.fit-card,
.choice-panel,
.company-card,
.join-card {
  background:
    linear-gradient(158deg,
      color-mix(in srgb, var(--brand) 7%, var(--surface)) 0%,
      var(--surface) 46%,
      color-mix(in srgb, var(--bg) 22%, var(--surface)) 100%);
  position: relative;
}

.step::before,
.safety-card::before,
.faq-item::before,
.fit-card::before,
.choice-panel::before,
.company-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--sheen), transparent);
  pointer-events: none;
}

/* ======================================================================
   LIFT

   The theme cards already rise on hover and it reads well, so every card
   that is a discrete thing now does the same: a small rise, a brand-tinted
   rim, and a shadow that grows with it. Spring easing on the way up,
   because a card that floats up linearly reads as a tooltip.
   ====================================================================== */

.step,
.safety-card,
.faq-item,
.company-card {
  transition:
    transform var(--m-normal) var(--ease-spring),
    box-shadow var(--m-normal) var(--ease),
    border-color var(--m-normal) var(--ease),
    var(--skin);
  will-change: transform;
}

.step:hover,
.safety-card:hover,
.company-card:hover,
.faq-item:hover {
  transform: translateY(-6px);
  border-color: color-mix(in srgb, var(--brand) 42%, var(--border));
  box-shadow:
    var(--shadow-card),
    0 22px 44px -26px color-mix(in srgb, var(--brand) 75%, transparent);
}
/* An open question should sit still — you are reading it, not choosing it. */
.faq-item[open]:hover { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .step, .safety-card, .company-card, .faq-item { transition: none; }
  .step:hover, .safety-card:hover, .company-card:hover, .faq-item:hover { transform: none; }
}

/* ======================================================================
   FAQ

   Was a row of plain bars. Now: more room to breathe, a brand-tinted rail
   down the left of the open one so you can see at a glance which is
   expanded, a chevron that rotates rather than a plus that morphs, and an
   answer that slides in instead of appearing.
   ====================================================================== */

.faq { gap: var(--s-md); }

.faq-item {
  border-radius: var(--r-xl);
  overflow: hidden;
}
.faq-item[open] {
  border-color: color-mix(in srgb, var(--brand) 46%, var(--border));
  box-shadow: var(--shadow-card),
              0 18px 40px -28px color-mix(in srgb, var(--brand) 80%, transparent);
}
/* The rail. Scales from the top on open, so it draws itself down the edge. */
.faq-item::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: linear-gradient(180deg, var(--grad-a), var(--grad-b));
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--m-normal) var(--ease);
  pointer-events: none;
}
.faq-item[open]::after { transform: scaleY(1); }

.faq-item summary {
  padding: var(--s-lg) var(--s-xl);
  font-size: 1.02rem;
  font-weight: 650;
}
.faq-item[open] summary { color: var(--brand); }

.chev {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--surface-alt);
  border: var(--bw) solid var(--border);
  transition: transform var(--m-normal) var(--ease-spring),
              background-color var(--m-fast) var(--ease),
              border-color var(--m-fast) var(--ease);
}
.chev::before, .chev::after { width: 10px; height: 2px; }
.faq-item summary:hover .chev {
  background: var(--brand-tint);
  border-color: color-mix(in srgb, var(--brand) 45%, transparent);
}
.faq-item[open] .chev {
  transform: rotate(180deg);
  background: var(--brand);
  border-color: var(--brand);
}
.faq-item[open] .chev::before,
.faq-item[open] .chev::after { background: var(--on-brand); }

.faq-body { padding: 0 var(--s-xl) var(--s-xl); }
.faq-body p { font-size: .94rem; line-height: 1.62; }
.faq-item[open] .faq-body {
  animation: faq-open var(--m-slow) var(--ease) both;
}
@keyframes faq-open {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .faq-item[open] .faq-body { animation: none; }
}

/* ----------------------------------------------------------------------
   AVATAR FIT, corrected

   `scale()` from a bottom origin grows upward, so a 1.04 scale on a
   full-height image pushed 4-6px of scalp above the frame and the clip
   came back. The artwork is now drawn a little shorter than the frame,
   which leaves headroom the idle motion can move into without ever
   reaching the top edge. Measured: zero clipping on all four.
   ---------------------------------------------------------------------- */

.pcard-img {
  height: 93%;
  transform: translateX(-50%);
}

@keyframes av-sway {
  0%, 100% { transform: translateX(-50%) rotate(-1.1deg); }
  50%      { transform: translateX(-50%) rotate(1.1deg); }
}
@keyframes av-nod {
  0%, 100% { transform: translateX(-50%) translateY(0) rotate(.4deg); }
  50%      { transform: translateX(-50%) translateY(-2.5px) rotate(-.4deg); }
}
@keyframes av-bob {
  0%, 100% { transform: translateX(-50%) translateY(0) scale(1); }
  50%      { transform: translateX(-50%) translateY(-2px) scale(1.015); }
}
@keyframes av-tilt {
  0%, 100% { transform: translateX(-50%) rotate(1.4deg) translateY(0); }
  50%      { transform: translateX(-50%) rotate(-.7deg) translateY(-2px); }
}

/* ======================================================================
   SURFACES v2  — and the reason the lift did nothing

   `.js .reveal.is-in { transform: none }` scores (0,3,0). The hover rules
   were `.step:hover` at (0,2,0), so on every card that is *also* a reveal
   — the steps and the safety cards — the scroll-in rule kept winning and
   the card never moved. FAQ items and company cards are not reveals,
   which is exactly why those two worked and these two did not.

   Everything below is scoped under `.js` to clear that bar, and the wash
   is far stronger than the first attempt: 7% was honestly invisible.
   ====================================================================== */

.js .step,
.js .safety-card,
.js .faq-item,
.js .fit-card,
.js .choice-panel,
.js .company-card,
.js .join-card,
.js .theme-card,
.js .float-chip,
.js .waitlist-fields {
  background:
    /* a bright corner, where the light is coming from */
    radial-gradient(120% 90% at 0% 0%,
      color-mix(in srgb, var(--brand) 24%, transparent) 0%,
      transparent 58%),
    /* a cooler pool opposite it, so the panel has two ends */
    radial-gradient(100% 80% at 100% 100%,
      color-mix(in srgb, var(--brand-light) 13%, transparent) 0%,
      transparent 62%),
    linear-gradient(158deg,
      color-mix(in srgb, var(--brand) 9%, var(--surface)) 0%,
      var(--surface) 52%,
      color-mix(in srgb, var(--bg) 34%, var(--surface)) 100%);
}

/* An inner ring, one pixel inside the border. Two edges instead of one is
   most of what separates a card from a rectangle. */
.js .step::before,
.js .safety-card::before,
.js .faq-item::before,
.js .fit-card::before,
.js .company-card::before,
.js .choice-panel::before {
  content: "";
  position: absolute;
  inset: 0;
  height: auto;
  border-radius: inherit;
  background: none;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #FFFFFF 16%, transparent),
    inset 0 0 0 1px color-mix(in srgb, var(--brand) 10%, transparent);
  pointer-events: none;
}
[data-theme="paper"] .js .step::before { box-shadow: inset 0 0 0 1px rgba(0,0,0,.05); }

/* ---- the lift, at a specificity that actually applies ----------------- */

.js .step,
.js .safety-card,
.js .company-card,
.js .faq-item,
.js .theme-card {
  transition:
    transform var(--m-normal) var(--ease-spring),
    box-shadow var(--m-normal) var(--ease),
    border-color var(--m-normal) var(--ease),
    background-color var(--m-normal) var(--ease);
}

.js .step:hover,
.js .safety-card:hover,
.js .company-card:hover,
.js .faq-item:hover,
.js .step.reveal.is-in:hover,
.js .safety-card.reveal.is-in:hover {
  transform: translateY(-7px) scale(1.012);
  border-color: color-mix(in srgb, var(--brand) 55%, var(--border));
  box-shadow:
    var(--shadow-card),
    0 26px 52px -24px color-mix(in srgb, var(--brand) 85%, transparent);
}
.js .faq-item[open]:hover,
.js .faq-item[open] { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js .step:hover, .js .safety-card:hover,
  .js .company-card:hover, .js .faq-item:hover { transform: none; }
}

/* ======================================================================
   TEXT WEIGHT

   The body copy inside cards was --text-2 at .875rem, which on a tinted
   panel read as greyed-out rather than as secondary. Each theme's
   secondary moves one step toward its primary — lighter on the dark
   themes, darker on the light ones — and card copy goes up a size.
   ====================================================================== */

:root, [data-theme="aurora"] { --text-2: #C6C0E2; --text-3: #8C85AE; }
[data-theme="paper"]        { --text-2: #4A4034; --text-3: #665B4A; }
[data-theme="neon"]         { --text-2: #AABEC7; --text-3: #7C8B93; }
[data-theme="soft"]         { --text-2: #57524A; --text-3: #6B655D; }

.step p,
.safety-card p,
.choice-point p,
.faq-body p,
.section-lede,
.lede {
  font-size: .95rem;
  line-height: 1.62;
}
.step h3, .safety-card h3, .choice-point h3 { font-size: 1.1rem; }

/* ----------------------------------------------------------------------
   EMPLOYER MARKS

   The tile carries a coloured monogram, and a real logo file sits on top
   of it when one exists. A missing file deletes its own <img>, so the
   monogram simply stays — the page is correct either way.

   Real logos go on a white chip, always, in every theme: brand marks are
   drawn for light backgrounds and most of them vanish on near-black.
   ---------------------------------------------------------------------- */

.logo-tile { position: relative; overflow: hidden; }
.logo-letter { position: relative; z-index: 1; }

.logo-img {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  padding: 18%;
  object-fit: contain;
  background: #FFFFFF;
  border-radius: inherit;
}

/* Hidden until it has decoded. Without this, a logo file that is still in
   flight — or one that is about to 404 — paints its white chip over the
   monogram first, and the tile flashes blank. */
.logo-img { opacity: 0; transition: opacity var(--m-fast) var(--ease); }
.logo-img.is-ready { opacity: 1; }

/* ----------------------------------------------------------------------
   ASK TO CONNECT

   The button was not merely large — it was overflowing the card by 2px on
   the shorter profiles and 9px on Ananya's, whose extra "You work there
   too" line pushes everything down. That overhang is what looked cut: it
   was sitting past the card's rounded bottom edge.

   Smaller button, tighter gaps, less body padding — enough to bring the
   tallest card back inside with room to spare.
   ---------------------------------------------------------------------- */

.pcard-body { padding: 6px 10px 7px; gap: 4px; }

.app-btn {
  padding-block: 4px;
  font-size: .6rem;
  letter-spacing: .01em;
  /* Slightly inset, so it reads as sitting inside the card rather than
     spanning it edge to edge. */
  margin-inline: 2px;
}

/* ----------------------------------------------------------------------
   CARD BODY: one column, always full width

   The body was `display: grid` with no explicit columns. An implicit grid
   column is sized to the widest item's max-content, so the column — and
   therefore the full-width button inside it — came out a different width
   on every card: as wide as "Product Designer · Flipkart" on one, as wide
   as "Marketing Lead · Swiggy" on the next. That is why the button kept
   changing length between profiles.

   A flex column stretches its children to the container instead, so the
   button is the same width on all four. `space-between` then does what it
   was always meant to do here — distribute the rows vertically.
   ---------------------------------------------------------------------- */

.pcard-body {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: space-between;
}
/* Keep the work row from stretching its own children vertically. */
.pcard-work { align-items: center; }
.app-btn { width: auto; }

/* ----------------------------------------------------------------------
   HERO SYMMETRY

   The grid centres `.hero-stage`, and the stage is the phone *plus* the
   caption under it. Measured: stage centre 563, copy centre 563 — dead on
   — but the phone's own centre was 502, sitting 61px high, because the
   107px caption and its 16px gap hang below the phone and drag the phone
   up by half of that.

   Taking the caption out of flow above 980px makes the stage exactly as
   tall as the phone, so centring the stage centres the phone. The hero
   gains bottom padding to hold the caption that now overflows it.

   Below 980px the layout is one column and the caption goes back into
   flow, where stacking is what you want anyway.
   ---------------------------------------------------------------------- */

@media (min-width: 981px) {
  .hero-stage { position: relative; }

  .deck-caption {
    position: absolute;
    top: calc(100% + var(--s-lg));
    left: 50%;
    transform: translateX(-50%);
    margin-top: 0;
  }

  /* Room for the caption now that it no longer occupies any. */
  .hero { padding-bottom: clamp(150px, 13vw, 200px); }
}

/* A small optical nudge down.
   Mathematically the text and the phone share a centre line, but the text
   column ends with two light rows of trust items while the phone ends with
   a solid tab bar — so the text reads a touch high even when it measures
   dead centre. Fourteen pixels of relative offset settles it. Kept off the
   single-column layout, where the two stack and there is nothing to
   balance against. */
/* (the 14px nudge was replaced by growing the type — see below) */

/* ----------------------------------------------------------------------
   HERO TYPE

   Rather than nudging the text down to meet the phone, grow it until the
   column is the phone's height and the two centre naturally.

   It also undoes a mistake: when card body copy was bumped to .95rem, the
   `.lede` selector caught the hero's opening paragraph too and shrank it
   from 1.16rem to .95rem. A hero lede is not card copy — it goes back to
   the fluid scale, which both reads better and adds the height needed.
   ---------------------------------------------------------------------- */

.hero-title { font-size: clamp(2.35rem, 5.4vw, 4.5rem); }

.lede {
  font-size: var(--t-lede);
  line-height: 1.66;
}

/* The last 33px, taken as breathing room rather than padding.
   The fourth trust item did not add a row — the list wraps, so it simply
   joined the second one. Loosening the three gaps that structure the hero
   column closes the remaining difference and gives the block a calmer
   rhythm at the same time. Desktop only; the stacked layout does not need
   it. */
@media (min-width: 981px) {
  /* Dialled back from 34/43/43, which overshot by 23px and made the text
     the taller of the two. These land the column within a couple of pixels
     of the phone at 1440. */
  .hero-copy .lede     { margin-top: 26px; }
  .hero-copy .waitlist { margin-top: 35px; }
  .hero-copy .trust    { margin-top: 35px; }
}
