/* ============================================================
   FaceUp — marketing site
   Tokens lifted directly from the app's own client/src/index.css.
   Icons are the app's own Microsoft Fluent Emoji 3D assets
   (attached_assets/, MIT licensed — see credit in the footer),
   self-hosted here as static files, not the OS emoji font.
   ============================================================ */

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("assets/fonts/inter-var.woff2") format("woff2-variations"), url("assets/fonts/inter-var.woff2") format("woff2");
}

:root {
  --bg: #000000;
  /* The app's own pop-up background (BottomSheet.tsx), not a made-up placeholder. */
  --bg-elev: #232328;
  --bg-elev-2: #17181a;
  --border: #2b2b2b;
  --ink: #f5f5f5;
  --ink-dim: #ababab;
  --ink-faint: #6b6b6b;

  --mint: #b5f3c7;
  --lavender: #b79cff;
  --sky: #8ccbff;
  --gold: #f8ca5a;

  --radius-sm: 14px;
  --radius-md: 24px;
  --radius-lg: 32px;
  --radius-pill: 999px;

  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  --container: 1120px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  /* Overshoots past 1 then settles -- the app switch's knob uses it so the slide
     lands with a little give instead of stopping dead on the mark. */
  --ease-spring: cubic-bezier(0.32, 1.45, 0.55, 1);
}

/* Cross-document view transitions: the browser snapshots this page, loads the
   next one, and animates between the two instead of blanking and repainting.
   What it buys us is the app switch at the top of the two landing pages -- the
   knob is on the left on / and on the right on /pairs/, so with both sides
   tagged (see .app-switch-knob below) the browser slides it across *through*
   the navigation, one continuous move, no flash in the middle.
   Browsers without it (Firefox today) ignore the rule and navigate as before;
   script.js animates the knob itself in that case. */
@view-transition {
  navigation: auto;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  overflow-x: hidden;
}

@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;
  }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img,
svg {
  display: block;
  max-width: 100%;
}

a {
  color: inherit;
}

.wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 24px;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin: 0 0 16px;
}

.eyebrow::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--mint), var(--sky));
  flex: none;
}

h1,
h2,
h3 {
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0;
}

h2 {
  font-size: clamp(28px, 4vw, 42px);
}

p {
  color: var(--ink-dim);
  line-height: 1.6;
  margin: 0;
}

.section {
  padding: 108px 0;
  position: relative;
}

.section-head {
  max-width: 620px;
  margin: 0 0 56px;
}

.section-head p {
  margin-top: 14px;
  font-size: 17px;
}

/* ---------- Nav (privacy-policy.html / support.html only) ---------- */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border);
}

.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 72px;
}

/* ---------- Brand ---------- */

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 800;
  font-size: 18px;
  letter-spacing: -0.01em;
  text-decoration: none;
  color: var(--ink);
}

.mark {
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: 8px;
  overflow: hidden;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mark img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: var(--radius-pill);
  padding: 13px 26px;
  font-size: 14px;
  font-weight: 700;
  font-family: var(--font);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: transform 0.2s var(--ease), background 0.2s var(--ease), border-color 0.2s var(--ease);
}

.btn:active {
  transform: scale(0.97);
}

.btn-primary {
  background: var(--ink);
  color: #0d0d0d;
}

.btn-primary:hover {
  background: #fff;
}

.btn-ghost {
  background: transparent;
  border-color: var(--border);
  color: var(--ink);
}

.btn-ghost:hover {
  border-color: var(--ink-dim);
}

.btn[aria-disabled="true"] {
  cursor: default;
  opacity: 0.55;
  pointer-events: none;
}

.btn-sm {
  padding: 9px 16px;
  font-size: 13px;
}

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

.hero {
  position: relative;
  padding: 96px 0 120px;
}

.hero-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
}

/* ---------- Hero top (mark + title + CTA) ---------- */

.hero-top {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.hero-mark {
  position: relative;
  width: 96px;
  height: 96px;
  margin-bottom: 48px;
  transform: scale(0.95);
}

/* Same 45deg six-bar geometry as the app's own boot splash (AppSplash.css),
   measured off the source logo artwork and uniformly scaled down to fit a
   96px mark instead of eyeballing new proportions. Shared with .footer-mark
   and .legal-hero-mark (legal pages' own header, defined inline per-page)
   so every mark on the site stays in sync -- only each container's own
   size/position rules differ. */
.hero-mark span,
.footer-mark span,
.legal-hero-mark span {
  position: absolute;
  display: block;
  width: 5.4px;
  border-radius: 2.7px;
  background: var(--ink);
  transform: rotate(45deg);
}

.hero-mark span:nth-child(1), .footer-mark span:nth-child(1), .legal-hero-mark span:nth-child(1) { height: 25.4px; top: 13.5px; left: 22.2px; }
.hero-mark span:nth-child(2), .footer-mark span:nth-child(2), .legal-hero-mark span:nth-child(2) { height: 51.3px; top: 9.8px;  left: 31.7px; }
.hero-mark span:nth-child(3), .footer-mark span:nth-child(3), .legal-hero-mark span:nth-child(3) { height: 78px;   top: 5.7px;  left: 41px;   }
.hero-mark span:nth-child(4), .footer-mark span:nth-child(4), .legal-hero-mark span:nth-child(4) { height: 72.5px; top: 16.5px; left: 51.9px; }
.hero-mark span:nth-child(5), .footer-mark span:nth-child(5), .legal-hero-mark span:nth-child(5) { height: 47.4px; top: 38px;   left: 60.9px; }
.hero-mark span:nth-child(6), .footer-mark span:nth-child(6), .legal-hero-mark span:nth-child(6) { height: 22.4px; top: 59.3px; left: 69.9px; }

/* ---------- App switch (FaceUp <-> FaceUp Pairs) ----------
   Takes the place of the plain mark at the top of the two landing pages: both
   apps' logos in one pill, with a round knob sitting under whichever app you
   are currently on. Clicking slides the knob across to the other logo and then
   goes to that app's page -- it is a real <a>, so the navigation still happens
   on its own if the script never runs, the knob just doesn't get to move. */

.app-switch {
  position: relative;
  display: flex;
  align-items: center;
  flex: none;
  width: 88px;
  height: 48px;
  padding: 4px;
  margin-bottom: 48px;
  border-radius: var(--radius-pill);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  /* Named so the pill itself is excluded from the page-wide crossfade and stays
     put while everything around it fades -- otherwise the one element you are
     looking at is the one that flickers. */
  view-transition-name: switch-pill;
  transition: transform 0.22s var(--ease);
}

/* Presses down a little further than before, and over 0.22s rather than
   instantly, so the pill answers the finger before anything else moves. */
.app-switch:active {
  transform: scale(0.94);
}

.app-switch-knob {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--ink);
  /* Both pages tag the knob with the same name, so a browser doing cross-document
     view transitions treats the two as one element and tweens between its left
     and right positions across the navigation. */
  view-transition-name: switch-knob;
  transition: transform 0.44s var(--ease-spring);
}

/* 40px, not the knob's own 38px: one slot width plus the 2px gap between the
   two slots, so the knob lands exactly back under the second logo. */
.app-switch[data-active="pairs"] .app-switch-knob {
  transform: translateX(40px);
}

/* Fallback path only (no cross-document view transitions): script.js sets
   data-sliding to the app being moved to, and the knob makes the trip here
   before the navigation fires. It stretches along the direction of travel as it
   leaves and squashes as it lands -- the weight that a plain translate lacks.
   `forwards` holds the end state, which is where data-active puts it anyway. */
/* Deliberately NOT --ease-spring: an animation-timing-function applies to every
   gap between keyframes, so a curve that overshoots would overshoot five times
   over and stall the knob on the mark for the last third of the run. The spring
   lives in the keyframes instead -- they carry the knob past its landing and let
   it settle back -- and the curve between them only has to stay smooth. */
.app-switch[data-sliding="pairs"] .app-switch-knob {
  animation: knob-slide-right 0.46s cubic-bezier(0.4, 0, 0.3, 1) forwards;
}

.app-switch[data-sliding="faceup"] .app-switch-knob {
  animation: knob-slide-left 0.46s cubic-bezier(0.4, 0, 0.3, 1) forwards;
}

/* Stretches along the direction of travel as it leaves, overshoots the target by
   3px, then squashes against it and settles -- the knob reads as having weight
   rather than being teleported 40px sideways. */
@keyframes knob-slide-right {
  0% { transform: translateX(0) scale(1, 1); }
  22% { transform: translateX(8px) scale(1.18, 0.86); }
  55% { transform: translateX(43px) scale(1.05, 0.96); }
  78% { transform: translateX(38.5px) scale(0.95, 1.05); }
  100% { transform: translateX(40px) scale(1, 1); }
}

@keyframes knob-slide-left {
  0% { transform: translateX(40px) scale(1, 1); }
  22% { transform: translateX(32px) scale(1.18, 0.86); }
  55% { transform: translateX(-3px) scale(1.05, 0.96); }
  78% { transform: translateX(1.5px) scale(0.95, 1.05); }
  100% { transform: translateX(0) scale(1, 1); }
}

/* The logo the knob is arriving under gives a small pop as it goes dark, so the
   handover reads as one gesture rather than a slide plus a color change. */
.app-switch[data-sliding="pairs"] .app-switch-slot--pairs,
.app-switch[data-sliding="faceup"] .app-switch-slot--faceup {
  animation: switch-logo-pop 0.46s var(--ease);
}

@keyframes switch-logo-pop {
  0% { transform: scale(1); }
  46% { transform: scale(1.13); }
  100% { transform: scale(1); }
}

.app-switch-slot {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  color: var(--ink-faint);
  transition: color 0.34s var(--ease);
}

/* Named like the knob, and declared after it, so each logo crossfades between
   its grey and its dark state in place -- and paints *above* the sliding knob,
   since groups stack in DOM order and the slots come after it in the markup. */
.app-switch-slot--faceup {
  view-transition-name: switch-logo-faceup;
}

.app-switch-slot--pairs {
  view-transition-name: switch-logo-pairs;
}

.app-switch-slot + .app-switch-slot {
  margin-left: 2px;
}

.app-switch:hover .app-switch-slot {
  color: var(--ink-dim);
}

/* After the :hover rule on purpose -- same specificity, so this one wins and
   the active logo stays dark while hovering. Dark, because the knob underneath
   it is near-white: the same inversion .btn-primary does with its own label. */
.app-switch[data-active="faceup"] .app-switch-slot--faceup,
.app-switch[data-active="pairs"] .app-switch-slot--pairs {
  color: #0d0d0d;
}

/* Both logos have to change color as the knob slides under them -- dark once the
   knob is behind them, grey otherwise -- so neither can be a plain <img>. Each
   is painted as a mask of its own artwork instead: only the file's alpha is
   used, so one flat PNG covers both states and the fill comes from currentColor.
   (This is also why both files have to be the transparent-background exports:
   logo-mark-128.png, the one the nav uses, has a solid white square baked in
   and masks down to a filled blob.)

   The two box sizes differ on purpose: each logo fills a different share of its
   own canvas, and what has to match optically is the two glyphs, not the boxes
   around them. Pairs is wider than the 38px slot for exactly that reason. */
.app-switch-icon {
  display: block;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* The two box sizes come from each file's own ink: the mark covers 80% of its
   128px canvas, the Pairs logo only 56%. 29 x 0.80 and 42 x 0.56 both land on
   ~23px of actual logo, which is what makes the two read as the same size. */
.app-switch-icon--faceup {
  width: 29px;
  height: 29px;
  -webkit-mask-image: url(assets/logo-faceup-mark-128.png);
  mask-image: url(assets/logo-faceup-mark-128.png);
}

.app-switch-icon--pairs {
  width: 42px;
  height: 42px;
  -webkit-mask-image: url(assets/logo-pairs-mark-128.png);
  mask-image: url(assets/logo-pairs-mark-128.png);
}

/* The knob gets the spring and a longer ride than the page's own crossfade, so
   it is still travelling as the rest of the page settles -- that is what carries
   the eye across the navigation. The logos and the pill just need to be told not
   to inherit the default 0.25s, which would finish before the knob arrives. */
::view-transition-group(switch-knob) {
  animation-duration: 0.52s;
  animation-timing-function: var(--ease-spring);
}

::view-transition-group(switch-pill),
::view-transition-group(switch-logo-faceup),
::view-transition-group(switch-logo-pairs) {
  animation-duration: 0.4s;
  animation-timing-function: var(--ease);
}

::view-transition-old(switch-logo-faceup),
::view-transition-new(switch-logo-faceup),
::view-transition-old(switch-logo-pairs),
::view-transition-new(switch-logo-pairs) {
  animation-duration: 0.4s;
}

/* Everything else on the page crossfades, a touch slower than the browser's own
   0.25s but still well inside the knob's trip. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.36s;
  animation-timing-function: var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  .app-switch-knob,
  .app-switch-slot {
    transition: none;
  }

  /* The blanket rule near the top of this file only reaches real elements, not
     these pseudos, so the transition has to be switched off by name: the pages
     swap with no movement at all. */
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

.pill-new {
  display: inline-flex;
  align-items: center;
  padding: 6px 16px;
  margin-bottom: 14px;
  border-radius: var(--radius-pill);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  color: var(--ink);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.02em;
}

.hero-title {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  font-size: clamp(38px, 9vw, 64px);
  line-height: 1.03;
}

.hero-btn {
  margin-top: 32px;
  padding: 18px 36px;
  font-size: 18px;
}

/* Made to look fully live -- overrides .btn[aria-disabled="true"]'s dimmed
   opacity -- even though aria-disabled/pointer-events:none stay on the
   markup itself (it still doesn't link anywhere real yet, on purpose). The
   background is the exact gradient the app's own House mode card uses on
   Home (ModesCarousel.tsx's modeData: "bg-gradient-to-br from-green-200
   via-blue-100 to-gray-100" -- Tailwind's default green-200/blue-100/
   gray-100 hexes, not a made-up palette); .btn-primary's existing #0d0d0d
   text color already reads correctly against it, same as the app's own
   ModeCard uses dark text on this same light gradient. */
a.hero-btn[aria-disabled="true"] {
  opacity: 1;
  background: linear-gradient(135deg, #bbf7d0, #dbeafe, #f3f4f6);
}

.icon {
  width: 22px;
  height: 22px;
  object-fit: contain;
  flex: none;
}

.icon-sm {
  width: 18px;
  height: 18px;
}

.icon-lg {
  width: 34px;
  height: 34px;
}

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

.hero-visual {
  width: 100%;
  max-width: 1180px;
  margin: -70px auto 0;
}

.hero-visual img {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 40px 80px rgba(0, 0, 0, 0.7));
  mask-image: linear-gradient(to bottom, #000 85%, transparent 100%), linear-gradient(to right, #000 88%, transparent 100%);
  mask-composite: intersect;
  -webkit-mask-image: linear-gradient(to bottom, #000 85%, transparent 100%), linear-gradient(to right, #000 88%, transparent 100%);
  -webkit-mask-composite: source-in;
}

@media (max-width: 767px) {
  .hero-visual {
    max-width: none;
    width: calc(100% + 96px);
    margin: -70px -48px 0;
  }
  .hero {
    padding-top: 32px;
  }
}

@media (min-width: 768px) {
  .hero {
    padding-top: 40px;
    padding-bottom: 24px;
  }

  /* Static (not its default relative) so .hero-mark/.hero-btn's absolute
     positioning below resolves against .hero itself -- full viewport width --
     instead of .hero-inner's own box, which is capped at 1120px and centered
     past that width and would otherwise leave them stranded short of the
     real screen edges on a wide monitor. Safe to drop here: the z-index
     stacking .hero-inner's position otherwise exists for (keeping #avatars
     above the hero photo where they overlap) is mobile-only. */
  .hero-inner {
    position: static;
  }

  .hero-mark {
    position: absolute;
    top: 24px;
    left: 24px;
    margin-bottom: 0;
    transform-origin: top left;
    transform: scale(0.8);
    z-index: 50;
  }

  /* Same corner as .hero-mark had, and left at its natural size rather than
     scaled down like the mark: at 48px tall it is the mirror image of
     .hero-btn's own 48px pill sitting in the opposite corner. */
  .app-switch {
    position: absolute;
    top: 24px;
    left: 24px;
    margin-bottom: 0;
    z-index: 50;
  }

  .hero-center {
    max-width: clamp(460px, 40vw, 640px);
    margin: 140px auto 0;
  }

  .pill-new {
    font-size: 15px;
    padding: 7px 18px;
  }

  .hero-title {
    font-size: clamp(64px, 6vw, 108px);
  }

  .hero-btn {
    position: absolute;
    top: 24px;
    right: 24px;
    margin-top: 0;
    height: 48px;
    padding: 0 28px;
    font-size: 15px;
    z-index: 50;
  }

  .hero-visual {
    max-width: clamp(460px, 40vw, 640px);
    margin: 0 auto 0;
  }
}

/* ---------- Shared two-column feature split ---------- */

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
  align-items: center;
}

.split--reverse > :first-child {
  order: 2;
}

.split--visual-only {
  grid-template-columns: 1fr;
  justify-items: center;
}

@media (max-width: 860px) {
  .split {
    grid-template-columns: 1fr;
  }
  .split--reverse > :first-child {
    order: 0;
  }
}

/* ---------- Shared block-panel size (stats sets the reference: 340x360) ---------- */

.stat-panel,
.looks-panel,
.friends-card {
  width: 100%;
  max-width: 340px;
  min-height: 360px;
}

/* ---------- Stats ---------- */

.stat-panel {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 22px;
  display: flex;
  flex-direction: column;
  /* flex-start (not center) so the heading's distance from the top border is the fixed
     22px padding, not a centering offset that shifts with the chart's height -- the
     same reasoning as .avatars-panel below, so the two headings sit at an identical
     gap from their card's top edge regardless of what's rendered underneath. */
  justify-content: flex-start;
  gap: 16px;
}

/* Bleeds past the card's own horizontal padding so the chart runs edge-to-edge, left
   border to right border, instead of floating inset within it. Uses the app's own
   7-stop wave gradient (coinsHistoryShared.ts WAVE_GRADIENT_STOPS) for the line/fill --
   not a made-up palette. */
.stats-chart-frame {
  position: relative;
  height: 165px;
  width: calc(100% + 44px);
  margin: 0 -22px;
  /* Without this, a horizontal drag starting on the chart scrolls the page
     instead of scrubbing it -- the browser claims the gesture for scrolling
     before pointermove events ever reach script.js. */
  touch-action: none;
}

.stats-chart {
  width: 100%;
  height: 100%;
  display: block;
}

.stats-chart-cursor {
  stroke: rgba(255, 255, 255, 0.2);
  stroke-width: 1;
  opacity: 0;
}

.stats-chart-active-dot {
  fill: var(--gold);
  stroke: #000000;
  stroke-width: 2;
  opacity: 0;
}

/* Same look as the app's own chart tooltip (CoinsHistoryChartCanvas.tsx's
   ChartTooltip: rounded bg-[#232328] px-3 py-2 shadow-lg). Follows the
   cursor/dot horizontally, hidden until a pointer actually touches the
   chart. */
.stats-chart-tooltip {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  transform: translate(-50%, -100%);
  background: #232328;
  border-radius: 8px;
  padding: 8px 12px;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s var(--ease);
  white-space: nowrap;
}

.stats-chart-tooltip.is-visible {
  opacity: 1;
}

.stats-chart-tooltip-label {
  display: block;
  font-size: 11px;
  color: var(--ink-faint);
  margin-bottom: 4px;
}

.stats-chart-tooltip-value {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 300;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.stats-chart-tooltip-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
}

/* ---------- Avatars & Emotes panel ---------- */

.looks-panel {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* flex-start, not center: same fixed-gap reasoning as .stat-panel/.avatars-panel --
     the heading always sits 22px from the top border, whatever's below it. */
  justify-content: flex-start;
  gap: 16px;
}

.emotes-square {
  width: 225px;
  height: 225px;
  background: var(--bg-elev-2);
  /* Same corner radius as the card itself, not a smaller/different one. */
  border-radius: var(--radius-lg);
  padding: 20px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 10px;
}

.emotes-square img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.panel-heading {
  width: 100%;
  text-align: center;
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 4px;
}

/* 168px, not the 56px the side slots display at: the hero slot shows this
   same element at 1x (scale(1)), so its rasterized size has to already be
   the LARGEST size it's ever shown at. Sizing it at 56px and scaling *up*
   3x for the hero slot (the previous approach) rendered the bitmap at 56px
   first and stretched that blurry -- side slots now scale *down* from this
   168px box instead, which stays sharp. */
.avatar-img {
  width: 168px;
  height: 168px;
  object-fit: contain;
  flex: none;
}

/* Pulled up to sit right against the hero phone photo, in front of it, so
   the phone reads as tucked in behind the card instead of the two floating
   as separate, far-apart blocks. */
#avatars {
  position: relative;
  z-index: 2;
  margin-top: -350px;
}

/* Tightened at every width now that a real image (not just a short heading)
   sits right below in the final CTA -- pairs with .final-cta's own reduced
   top padding so the two don't add up to a huge gap between blocks. */
#emojis {
  padding-bottom: 24px;
}

@media (max-width: 767px) {
  /* Avatars / Friends / Stats / Emojis packed tight against each other on
     mobile -- ~20px between cards instead of the 216px two adjacent
     .section paddings add up to by default. Each pair splits it 10px/10px;
     avatars' own top spacing (towards the hero photo) is left alone. */
  #avatars {
    margin-top: -200px;
    padding-bottom: 10px;
  }
  #friends {
    padding-top: 10px;
    padding-bottom: 10px;
  }
  #stats {
    padding-top: 10px;
    padding-bottom: 10px;
  }
  #emojis {
    padding-top: 10px;
  }
}


.avatars-heading {
  font-size: 26px;
  margin-bottom: 8px;
}

/* Fixed-size stage: the row's own box never changes size during the
   carousel, only the avatars' `transform` does. Reflowing width/height
   instead (the previous approach) forced the whole page below this block to
   reflow every animation frame, which read as janky/stuttery -- transform is
   compositor-only and stays smooth regardless of what's on the page. */
.avatars-row {
  position: relative;
  width: 100%;
  height: 200px;
}

.avatars-row .avatar-img {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -84px 0 0 -84px;
  opacity: 1;
  /* --ease (cubic-bezier(0.16,1,0.3,1)) is an ease-OUT curve -- near-instant
     velocity right from frame one, which is exactly what read as "brusque"
     at the start of the slide. A proper ease-in-out ramps up gently before
     accelerating, then eases back down, so the whole motion feels smooth
     rather than snapping into place. Slightly longer duration too, so that
     gentler start doesn't just compress the same abruptness into 0.7s. */
  transition: transform 0.9s cubic-bezier(0.65, 0, 0.35, 1), opacity 0.45s cubic-bezier(0.65, 0, 0.35, 1);
}

/* 56/168 -- same final on-screen size as before, now reached by scaling a
   168px-native image down instead of a 56px one up. */
.avatar-slot-left {
  transform: translateX(-130px) scale(0.3333);
}

.avatar-slot-hero {
  transform: translateX(0) scale(1);
  z-index: 1;
}

.avatar-slot-right {
  transform: translateX(130px) scale(0.3333);
}

/* 4th avatar, parked out of sight (behind the hero, scaled to nothing) while
   it waits its turn in the rotation -- the carousel only ever shows 3 at
   once, so with 4 avatars total, one is always sitting here between turns. */
.avatar-slot-hidden {
  transform: translateX(0) scale(0);
  opacity: 0;
  z-index: 0;
}

/* ---------- Friends card (reused in Friends block) ---------- */

.friends-card {
  position: relative;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  /* Matches the shared 360px so all 4 blocks stay the same size. */
  height: 360px;
  overflow: hidden;
  padding: 22px 22px 0;
  display: flex;
  flex-direction: column;
  /* flex-start, not center: same fixed 22px top-gap reasoning as the other 3 blocks. */
  justify-content: flex-start;
  align-items: center;
  gap: 15px;
}

.friends-visual {
  /* Pinned to the card's own bottom edge regardless of the heading above it --
     same height as before (untouched), just anchored by position instead of
     flex flow, so it can't spill past the card the way flex flow did. */
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  height: 300px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  /* Anchors the visible photo to the bottom of its box, so it touches the
     card's bottom edge even where contain leaves letterbox space above it. */
  object-position: center bottom;
}

/* ---------- Trust ---------- */

.trust {
  padding: 64px 0;
}

.trust-box {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 36px;
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 28px;
  align-items: center;
}

.trust-box p {
  font-size: 14px;
}

.age-badge {
  font-size: 28px;
  font-weight: 800;
  border: 2px solid var(--border);
  border-radius: 16px;
  padding: 10px 16px;
  color: var(--ink);
  flex: none;
}

.trust-links {
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 13px;
  font-weight: 600;
}

.trust-links a {
  text-decoration: none;
  color: var(--ink-dim);
}

.trust-links a:hover {
  color: var(--ink);
}

@media (max-width: 760px) {
  .trust-box {
    grid-template-columns: 1fr;
    text-align: left;
  }
}

/* ---------- Final CTA ---------- */

.final-cta {
  text-align: center;
  padding: 48px 0 0;
}

/* Same weight/color as the cards' own .panel-heading above (not the
   global h1-h3 rule's 800 weight + tight letter-spacing) so this reads as
   the same typographic family as the rest of the page, just bigger. */
.final-cta h2 {
  font-size: clamp(30px, 4.4vw, 44px);
  font-weight: 700;
  letter-spacing: normal;
  max-width: 560px;
  margin: 0 auto;
}

.final-cta-sub {
  max-width: 440px;
  margin: 16px auto 0;
  font-size: 18px;
  color: var(--ink);
}

.final-cta-btn {
  margin-top: 32px;
  padding: 18px 36px;
  font-size: 18px;
}

/* Same "looks active" treatment and same House-card gradient as .hero-btn
   above -- kept as two separate rules (rather than sharing one selector)
   since the two buttons live in unrelated parts of the page. */
a.final-cta-btn[aria-disabled="true"] {
  opacity: 1;
  background: linear-gradient(135deg, #bbf7d0, #dbeafe, #f3f4f6);
}

/* Sized and faded like .hero-visual (same max-widths per breakpoint below,
   same bottom fade) instead of its own smaller fixed size, so the two
   full-bleed phone shots on the page read as the same visual weight. Sits
   last with no bottom margin/padding so it runs straight into the footer
   below instead of leaving a gap. */
.final-cta-visual {
  width: 100%;
  max-width: 460px;
  margin: 80px auto 0;
}

.final-cta-visual img {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 40px 80px rgba(0, 0, 0, 0.7));
  mask-image: linear-gradient(to bottom, #000 85%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 85%, transparent 100%);
}

@media (max-width: 767px) {
  .final-cta-visual {
    max-width: none;
    width: calc(100% + 96px);
    margin: 80px -48px 0;
  }
}

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

/* Same background as the avatars/stats/friends/emotes cards above, marking
   where the footer starts by the color changing rather than a drawn line --
   rounded top corners (same --radius-lg the cards themselves use) so that
   change of color curves in from the page's black instead of cutting
   straight across. */
footer {
  padding: 40px 0 0;
  background: var(--bg-elev);
  border-top-left-radius: var(--radius-lg);
  border-top-right-radius: var(--radius-lg);
}

.footer-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 16px;
}

/* Same 6-bar geometry as .hero-mark (see its own comment for where the
   coordinates come from), reused here instead of duplicated so both marks
   stay in sync -- only the container's own size/position differs. */
.footer-mark {
  position: relative;
  display: block;
  width: 96px;
  height: 96px;
  transform: scale(0.62);
}

.footer-email {
  margin-top: -6px;
  margin-bottom: 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-dim);
  text-decoration: none;
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 20px;
}

.footer-links a {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-dim);
  text-decoration: none;
}

.footer-social {
  display: flex;
  gap: 12px;
}

.social-link {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-dim);
  text-decoration: none;
}

.social-link svg {
  width: 20px;
  height: 20px;
}

.social-link[aria-disabled="true"] {
  opacity: 0.55;
  pointer-events: none;
}

.footer-fine {
  font-size: 12.5px;
  color: var(--ink-faint);
}

/* Giant wordmark bleeding out of the footer. The wrapper's height is set in
   em, tied to the same font-size as the text inside it, so the crop ratio
   (top of the letters down to just past their vertical middle) stays
   identical at every viewport width instead of a fixed-px height going
   wrong once the responsive font-size changes. */
.footer-wordmark-clip {
  width: 100%;
  margin-top: 4px;
  overflow: hidden;
  display: flex;
  justify-content: center;
  font-size: clamp(64px, 22vw, 260px);
  height: 0.64em;
  /* Same bottom-fade technique as .hero-visual/.final-cta-visual -- the crop
     line at the bottom of this box now dissolves into the background
     instead of cutting the wordmark off sharply. */
  mask-image: linear-gradient(to bottom, #000 30%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 30%, transparent 100%);
}

.footer-wordmark {
  margin: 0;
  font-size: 1em;
  font-weight: 800;
  line-height: 1;
  color: var(--ink);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

/* ---------- Reveal-on-scroll ---------- */

[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}

[data-reveal].is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* ---------- Focus ---------- */

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--sky);
  outline-offset: 3px;
}

/* ---------- Feature grid (Avatars/Stats/Friends/Emojis, tablet+ only) ----------
   Below 768px these four stay the single stacked column tuned above (including
   #avatars' pull-up under the hero photo) -- phone-only territory. At 768px+
   (iPad portrait and up) they become a 2x2 grid instead, each card filling its
   own column -- bigger and scaling with the viewport (down to the container's
   own max-width) rather than pinned at the stacked layout's fixed 340/410px
   card widths, which is also what was making the avatars card (410px) visibly
   bigger than the other three (340px) on an iPad still hitting that stacked
   layout. */
@media (min-width: 768px) {
  .feature-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 40px;
    max-width: var(--container);
    margin: 0 auto 96px;
    padding: 0 24px;
  }

  .feature-grid .section {
    padding: 0;
  }

  .feature-grid .wrap {
    max-width: none;
    padding: 0;
  }

  #avatars {
    margin-top: 0;
  }

  #emojis {
    padding-bottom: 0;
  }

  .stat-panel,
  .looks-panel,
  .friends-card,
  .avatars-panel {
    max-width: none;
    width: 100%;
  }
}
