/* ═══════════════════════════════════════════════════════════════════════════
   Qualyx — Welcome / Auth pages
   Reuses the same design tokens as the scorecard app (index.html/app.js),
   so dark/light theming and brand language stay coherent.

   Breakpoint scale (documented; CSS MQs can't consume custom props):
     --bp-sm: 640px   — tablet
     --bp-md: 900px   — small laptop (nav + 2-col layouts)
     --bp-lg: 1024px  — laptop+ (4-col bentos, side-by-side heuristics)
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── Tokens ──────────────────────────────────────────────────────────────── */
:root, [data-theme="dark"] {
  --bg:            oklch(0.10 0.008 130);
  --surface:       oklch(0.13 0.008 130);
  --raised:        oklch(0.17 0.009 130);
  --hover:         oklch(0.20 0.010 130);
  --border:        oklch(0.22 0.010 130);
  --border-strong: oklch(0.32 0.012 130);
  --fg:            oklch(0.96 0.005 130);
  --fg-2:          oklch(0.86 0.008 130);
  --muted:         oklch(0.62 0.010 130);
  --subtle:        oklch(0.55 0.010 130);
  --ink-700:       oklch(0.74 0.010 130);
  --ink-950:       oklch(1.00 0.000 130);

  --accent:        #a8e009;
  --accent-text:   #a8e009;
  --accent-fg:     oklch(0.12 0.008 130);
  --accent-hover:  oklch(0.90 0.22 126);
  --accent-soft:   oklch(0.28 0.09 126);
  --accent-ring:   color-mix(in oklab, var(--accent) 30%, transparent);

  --danger:        oklch(0.70 0.20 28);
  --warn:          oklch(0.78 0.17 80);

  --scrim:         rgba(0, 0, 0, 0.55);
  --shadow-float:  0 16px 40px -16px rgba(0, 0, 0, 0.6);
  --shadow-modal:  0 32px 64px -16px rgba(0, 0, 0, 0.65);
  --card-glow:     0 0 0 1px var(--border), 0 24px 64px -24px rgba(0, 0, 0, 0.55);

  --grid-color:    color-mix(in oklab, var(--fg) 4%, transparent);

  color-scheme: dark;
}

[data-theme="light"] {
  --bg:            oklch(0.98 0.008 130);
  --surface:       oklch(0.96 0.008 130);
  --raised:        oklch(0.93 0.009 130);
  --hover:         oklch(0.90 0.010 130);
  --border:        oklch(0.88 0.010 130);
  --border-strong: oklch(0.78 0.012 130);
  --fg:            oklch(0.12 0.008 130);
  --fg-2:          oklch(0.22 0.008 130);
  --muted:         oklch(0.38 0.010 130);
  --subtle:        oklch(0.42 0.010 130);
  --ink-700:       oklch(0.38 0.010 130);
  --ink-950:       oklch(0.00 0.000 130);

  --accent:        #a8e009;
  --accent-text:   oklch(0.42 0.22 126);
  --accent-fg:     oklch(0.12 0.008 130);
  --accent-hover:  oklch(0.78 0.22 126);
  --accent-soft:   oklch(0.92 0.10 126);
  --accent-ring:   color-mix(in oklab, var(--accent) 45%, transparent);

  --danger:        oklch(0.60 0.20 28);

  --scrim:         rgba(0, 0, 0, 0.35);
  --shadow-float:  0 12px 32px -12px rgba(0, 0, 0, 0.18);
  --shadow-modal:  0 24px 56px -16px rgba(0, 0, 0, 0.22);
  --card-glow:     0 0 0 1px var(--border), 0 20px 48px -24px rgba(0, 0, 0, 0.16);

  --grid-color:    color-mix(in oklab, var(--fg) 5%, transparent);

  color-scheme: light;
}

:root {
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
}

/* ─── Skip-link ──
   Keyboard-only users bypass the nav on every page load. Matches the
   pattern used by the scorecard app's index.html. */
.skip-link {
  position: absolute;
  top: 0; left: 0;
  transform: translateY(-150%);
  padding: 8px 12px;
  background: var(--raised);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
  font-weight: 500;
  z-index: 90;
  transition: transform 180ms var(--ease-out);
}
.skip-link:focus {
  transform: translateY(12px) translateX(12px);
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ─── Reset + base ───────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html {
  background: var(--bg);
  transition: background-color 240ms var(--ease-out);
  scroll-behavior: smooth;
}
body {
  font-family: 'Supreme', system-ui, -apple-system, sans-serif;
  font-feature-settings: 'ss01' on, 'ss02' on, 'cv01' on;
  color: var(--fg);
  background: var(--bg);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  line-height: 1.5;
}
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
input, textarea, select { font-family: inherit; color: inherit; }
::selection { background: var(--accent); color: var(--accent-fg); }

.mono { font-family: 'Chivo Mono', ui-monospace, monospace; font-feature-settings: 'zero' on; }
.eyebrow {
  font-family: 'Chivo Mono', monospace;
  font-size: 10px; font-weight: 500; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted);
  margin: 0;
}
.eyebrow.center { text-align: center; }

.soft { color: var(--muted); }
.dot-accent { color: var(--accent-text); }
.mono-em {
  font-family: 'Chivo Mono', monospace;
  font-style: normal;
  font-size: 0.92em;
  color: var(--fg-2);
}

.sep { color: var(--border-strong); margin: 0 6px; }

/* Focus */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION ICON — 3D squircle in the style of premium iOS icons.
   Dark, grainy, with a rim-lit inner window and backlight glow.
   Uses the Qualyx lime accent in place of the reference's amber,
   for brand consistency.
   ═══════════════════════════════════════════════════════════════════════════ */
.s-icon {
  --icon-size:   108px;
  --icon-radius: 26px;
  position: relative;
  display: block;
  width:  var(--icon-size);
  height: var(--icon-size);
  margin: 0 auto 32px;
  /* Drop the icon: soft black shadow under + warm lime glow below (like sitting on a table) */
  filter:
    drop-shadow(0 14px 22px rgba(0, 0, 0, 0.55))
    drop-shadow(0 10px 28px color-mix(in oklab, var(--accent) 30%, transparent));
  isolation: isolate;
}
@keyframes s-icon-rise {
  0%   { opacity: 0; transform: translateY(12px) scale(0.96); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

.s-icon-hero      { --icon-size: 124px; margin-top: 16px; margin-bottom: 36px; }
.s-icon-section   { --icon-size: 92px;  margin-bottom: 20px; }
.s-icon-showcase  {
  --icon-size: 72px;
  position: absolute;
  top: -36px; left: 50%;
  transform: translateX(-50%);
  margin: 0;
  z-index: 2;
}

/* The squircle shell — outer body of the icon */
.s-icon-shell {
  position: absolute;
  inset: 0;
  border-radius: var(--icon-radius);
  background:
    radial-gradient(120% 80% at 50% -10%, oklch(0.22 0.008 130) 0%, oklch(0.10 0.008 130) 50%, oklch(0.05 0.006 130) 100%);
  box-shadow:
    inset 0  1px 0  rgba(255,255,255,0.06),
    inset 0 -1px 0  rgba(255,255,255,0.02),
    inset 0  0 0 1px rgba(0,0,0,0.55),
    /* the amber/lime edge-light at the bottom that sells the "backlit" look */
    inset 0 -18px 24px -14px color-mix(in oklab, var(--accent) 55%, transparent),
    inset 0  -1px 0    0    color-mix(in oklab, var(--accent) 28%, transparent);
  overflow: hidden;
}

/* Very subtle grain — SVG fractal noise as a CSS mask. Sits between
   surface and light, giving the matte-plastic feel from the reference. */
.s-icon-grain {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.92' numOctaves='2' stitchTiles='stitch' seed='7'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  background-size: 180px 180px;
  mix-blend-mode: overlay;
  opacity: 0.32;
}

/* Embossed inner window — the recessed area that holds the symbol.
   Thin lime rim sells the rim-lit look from the reference. */
.s-icon-inner {
  position: absolute;
  inset: calc(var(--icon-size) * 0.14);
  border-radius: calc(var(--icon-radius) - 8px);
  background:
    radial-gradient(130% 90% at 50% 0%, oklch(0.15 0.008 130) 0%, oklch(0.06 0.006 130) 70%);
  box-shadow:
    inset 0  1px 0 color-mix(in oklab, var(--accent) 45%, transparent),
    inset 0 -1px 0 color-mix(in oklab, var(--accent) 20%, transparent),
    inset  1px 0 0 color-mix(in oklab, var(--accent) 18%, transparent),
    inset -1px 0 0 color-mix(in oklab, var(--accent) 18%, transparent),
    inset 0  0 10px 2px rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

/* Radial rays behind the symbol — the subtle light burst from the reference. */
.s-icon-rays {
  position: absolute;
  inset: -20%;
  border-radius: inherit;
  background:
    radial-gradient(closest-side at 50% 55%,
      color-mix(in oklab, var(--accent) 38%, transparent) 0%,
      color-mix(in oklab, var(--accent) 12%, transparent) 28%,
      transparent 60%),
    conic-gradient(from 210deg at 50% 60%,
      transparent 0deg,
      rgba(255, 255, 255, 0.035) 12deg,
      transparent 24deg,
      transparent 54deg,
      rgba(255, 255, 255, 0.035) 66deg,
      transparent 78deg,
      transparent 102deg,
      rgba(255, 255, 255, 0.045) 114deg,
      transparent 126deg,
      transparent 234deg,
      rgba(255, 255, 255, 0.045) 246deg,
      transparent 258deg,
      transparent 282deg,
      rgba(255, 255, 255, 0.035) 294deg,
      transparent 306deg,
      transparent 336deg,
      rgba(255, 255, 255, 0.035) 348deg,
      transparent 360deg);
  opacity: 0.9;
  pointer-events: none;
  mix-blend-mode: screen;
}

/* The glyph itself — silvered, slightly embossed, centered.
   Color + drop-shadow give the "metallic" feel without a gradient fill. */
.s-icon-inner svg {
  position: relative;
  z-index: 2;
  width: 54%;
  height: 54%;
  color: rgba(226, 226, 226, 0.92);
  filter:
    drop-shadow(0  1px 0 rgba(255, 255, 255, 0.08))
    drop-shadow(0 -1px 0 rgba(0, 0, 0, 0.55))
    drop-shadow(0  0 3px rgba(255, 255, 255, 0.05));
}

/* Light theme: soften the drop shadows so the icon still reads as an "object on a surface". */
[data-theme="light"] .s-icon {
  filter:
    drop-shadow(0 10px 18px rgba(0, 0, 0, 0.18))
    drop-shadow(0  8px 24px color-mix(in oklab, var(--accent) 22%, transparent));
}
[data-theme="light"] .s-icon-shell {
  background:
    radial-gradient(120% 80% at 50% -10%, oklch(0.20 0.010 130) 0%, oklch(0.10 0.008 130) 55%, oklch(0.05 0.006 130) 100%);
}

@media (prefers-reduced-motion: reduce) {
  .s-icon { animation: none; }
}

/* ─── Ambient background (welcome + auth) ────────────────────────────────── */
.ambient {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.ambient-grid {
  position: absolute; inset: -20vh -10vw;
  background-image:
    linear-gradient(to right, var(--grid-color) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-color) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(ellipse at 50% 0%, black 0%, transparent 65%);
  -webkit-mask-image: radial-gradient(ellipse at 50% 0%, black 0%, transparent 65%);
  opacity: 0.7;
}
.ambient-glow {
  position: absolute;
  border-radius: 999px;
  filter: blur(90px);
  opacity: 0.28;
  animation: glowDrift 22s var(--ease-in-out) infinite alternate;
}
[data-theme="light"] .ambient-glow { opacity: 0.20; filter: blur(110px); }
.glow-a {
  width: 520px; height: 520px;
  top: -180px; left: -120px;
  background: radial-gradient(closest-side, var(--accent), transparent 70%);
}
.glow-b {
  width: 460px; height: 460px;
  top: 10vh; right: -160px;
  background: radial-gradient(closest-side, oklch(0.65 0.18 220), transparent 70%);
  animation-duration: 28s; animation-direction: alternate-reverse;
}
.glow-c {
  width: 640px; height: 640px;
  top: 70vh; left: 20vw;
  background: radial-gradient(closest-side, oklch(0.62 0.17 300), transparent 70%);
  animation-duration: 32s;
}
@keyframes glowDrift {
  0%   { transform: translate3d(0, 0, 0)      scale(1); }
  50%  { transform: translate3d(40px, 30px, 0) scale(1.06); }
  100% { transform: translate3d(-30px, 50px, 0) scale(0.96); }
}
@media (prefers-reduced-motion: reduce) {
  .ambient-glow { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   WELCOME PAGE
   ═══════════════════════════════════════════════════════════════════════════ */
.welcome-body {
  position: relative;
  overflow-x: hidden;
}

/* Nav */
.w-nav {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px;
  padding: 16px 28px;
  backdrop-filter: saturate(1.2) blur(18px);
  -webkit-backdrop-filter: saturate(1.2) blur(18px);
  background: color-mix(in oklab, var(--bg) 72%, transparent);
  border-bottom: 1px solid transparent;
  transition: border-color 200ms var(--ease-out), background 200ms var(--ease-out);
}
.w-nav.scrolled { border-bottom-color: var(--border); }
.w-brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-weight: 500; font-size: 14px; letter-spacing: -0.01em;
  color: var(--fg);
}
.brand-q-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  border-radius: 6px;
  background: var(--raised);
  border: 1px solid var(--border);
  transition: transform 220ms var(--ease-out), box-shadow 220ms var(--ease-out);
}
.brand-q-ico.small { width: 18px; height: 18px; border-radius: 5px; }
.brand-q-ico .mono {
  font-size: 13px; font-weight: 600; line-height: 1;
  color: var(--accent-text);
}
.w-brand:hover .brand-q-ico {
  transform: rotate(-3deg);
  box-shadow: 0 0 0 3px var(--accent-ring);
}
.brand-word {
  font-weight: 500;
}

.w-nav-links {
  display: none;
  align-items: center; gap: 28px;
  font-size: 13px; color: var(--fg-2);
}
.w-nav-links a {
  position: relative;
  padding: 4px 0;
  color: var(--fg-2);
  transition: color 160ms var(--ease-out);
}
.w-nav-links a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px;
  height: 1px; background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform 220ms var(--ease-out);
}
.w-nav-links a:hover { color: var(--fg); }
.w-nav-links a:hover::after { transform: scaleX(1); }
@media (min-width: 900px) { .w-nav-links { display: flex; } }

.w-nav-cta {
  display: flex; align-items: center; gap: 14px;
}

/* ─── Language pills (nav) ──
   Ported from the scorecard app so the PT/EN toggle reads identical across
   the marketing surface and the product. */
.pill-group {
  display: inline-flex; padding: 3px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.pill {
  position: relative;
  min-width: 40px; height: 28px; padding: 0 10px;
  font-family: 'Chivo Mono', monospace;
  font-size: 11px; font-weight: 500; letter-spacing: 0.04em;
  color: var(--muted);
  background: transparent; border: 0;
  border-radius: 7px;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: color 160ms var(--ease-out), background 160ms var(--ease-out);
}
.pill:hover { color: var(--fg); }
.pill.active {
  background: var(--raised); color: var(--fg);
  box-shadow: inset 0 0 0 1px var(--border);
}
.pill:active:not(.active) { transform: scale(0.94); transition-duration: 80ms; }
.link-quiet {
  font-size: 13px;
  color: var(--fg-2);
  transition: color 160ms var(--ease-out);
  background: none; border: none; padding: 0;
}
.link-quiet:hover { color: var(--fg); }
.link-accent {
  color: var(--accent-text);
  font-weight: 500;
  transition: opacity 160ms var(--ease-out);
}
.link-accent:hover { opacity: 0.8; }

.auth-nav-hint {
  display: none;
  font-size: 13px; color: var(--muted);
}
@media (min-width: 640px) { .auth-nav-hint { display: inline; } }

/* Buttons */
.btn-primary-sm, .btn-primary-lg, .btn-secondary-sm, .btn-secondary-lg, .btn-social {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 8px;
  font-family: inherit; font-weight: 500;
  border-radius: 10px;
  border: 1px solid transparent;
  transition:
    background 180ms var(--ease-out),
    border-color 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out),
    transform 120ms var(--ease-out),
    color 180ms var(--ease-out);
  cursor: pointer;
  white-space: nowrap;
}
.btn-primary-sm:active, .btn-primary-lg:active,
.btn-secondary-sm:active, .btn-secondary-lg:active,
.btn-social:active {
  transform: scale(0.97);
  transition-duration: 80ms;
}

.btn-primary-sm {
  height: 34px; padding: 0 12px 0 14px;
  font-size: 13px;
  background: var(--accent); color: var(--accent-fg);
  border-color: var(--accent);
}
.btn-primary-sm:hover {
  background: var(--accent-hover);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

.btn-primary-lg {
  height: 48px; padding: 0 22px;
  font-size: 15px; font-weight: 600;
  background: var(--accent); color: var(--accent-fg);
  border-color: var(--accent);
  letter-spacing: -0.005em;
}
/* In-form, the submit button is the destination — break the even form rhythm
   with a wider gap above so it lands as a terminal action. */
.auth-form > .btn-primary-lg { margin-top: 12px; }
.btn-primary-lg:hover {
  background: var(--accent-hover);
  box-shadow: 0 0 0 4px var(--accent-ring);
}
.btn-primary-lg:disabled {
  opacity: 0.4; cursor: not-allowed; box-shadow: none;
}
.btn-primary-lg.full { width: 100%; }

.btn-secondary-sm {
  height: 34px; padding: 0 14px;
  font-size: 13px;
  background: var(--raised); color: var(--fg);
  border-color: var(--border);
}
.btn-secondary-sm:hover {
  background: var(--hover); border-color: var(--border-strong);
}

.btn-secondary-lg {
  height: 48px; padding: 0 22px;
  font-size: 15px;
  background: transparent; color: var(--fg);
  border-color: var(--border-strong);
}
.btn-secondary-lg:hover {
  background: var(--raised); border-color: var(--fg-2);
}

.btn-social {
  height: 44px; padding: 0 16px;
  width: 100%;
  background: var(--raised); color: var(--fg);
  border-color: var(--border);
  font-size: 14px;
  font-weight: 500;
}
.btn-social:hover {
  background: var(--hover); border-color: var(--border-strong);
}

/* KBD hint */
.kbd-hint {
  display: inline-flex; align-items: center;
  padding: 2px 7px;
  margin-left: 4px;
  font-family: 'Chivo Mono', monospace;
  font-size: 10px; font-weight: 500;
  border-radius: 4px;
  background: color-mix(in oklab, var(--fg) 8%, transparent);
  border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
  color: var(--muted);
  letter-spacing: 0.02em;
}
.kbd-hint.on-accent {
  background: color-mix(in oklab, var(--accent-fg) 14%, transparent);
  border-color: color-mix(in oklab, var(--accent-fg) 22%, transparent);
  color: color-mix(in oklab, var(--accent-fg) 85%, transparent);
}

/* Main + hero */
.w-main {
  position: relative;
  z-index: 1;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 28px;
}

.w-hero {
  padding: 72px 0 56px;
  text-align: center;
}
.pill-announce {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 10px 5px 9px;
  font-size: 12px; color: var(--fg-2);
  background: color-mix(in oklab, var(--surface) 80%, transparent);
  border: 1px solid var(--border);
  border-radius: 999px;
  transition: border-color 160ms var(--ease-out), background 160ms var(--ease-out);
}
.pill-announce:hover { border-color: var(--border-strong); background: var(--raised); }
.pill-announce .dot {
  width: 5px; height: 5px; border-radius: 999px;
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 25%, transparent);
  animation: dot-pulse 2.4s ease-in-out infinite;
}
@keyframes dot-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}
.pill-announce svg { color: var(--muted); }

.hero-title {
  margin: 22px 0 18px;
  font-weight: 600;
  font-size: clamp(44px, 8.2vw, 96px);
  line-height: 0.98;
  letter-spacing: -0.035em;
  color: var(--fg);
}
.hero-title .soft { color: var(--muted); }
.hero-title .dot-accent {
  display: inline-block;
  animation: accent-bloom 3.6s ease-in-out infinite;
}
@keyframes accent-bloom {
  0%, 100% { text-shadow: 0 0 0 transparent; }
  50%      { text-shadow: 0 0 24px color-mix(in oklab, var(--accent) 48%, transparent); }
}

.hero-sub {
  max-width: 620px;
  margin: 0 auto 34px;
  color: var(--ink-700);
  font-size: 17px;
  line-height: 1.55;
}

.hero-ctas {
  display: flex; gap: 12px; justify-content: center; flex-wrap: wrap;
  margin-bottom: 22px;
}
.hero-ctas.center { justify-content: center; }

.hero-meta {
  display: inline-flex; flex-wrap: wrap; justify-content: center;
  gap: 2px;
  color: var(--muted);
  font-size: 12px;
  margin: 0;
}

/* ─── Product showcase (mock scorecard) ─── */
.w-showcase {
  position: relative;
  margin: 72px auto 0;
  perspective: 1800px;
}
.showcase-frame {
  position: relative;
  max-width: 1040px;
  margin: 0 auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: var(--card-glow);
  overflow: hidden;
  transform: rotateX(2deg);
  transition: transform 600ms var(--ease-out);
}
.showcase-frame::before {
  content: "";
  position: absolute; inset: 0;
  padding: 1px;
  border-radius: inherit;
  background: radial-gradient(60% 80% at 10% 0%, color-mix(in oklab, var(--accent) 50%, transparent) 0%, transparent 50%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0.5;
  pointer-events: none;
}
.showcase-chrome {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--raised);
}
.showcase-chrome .dot {
  width: 10px; height: 10px; border-radius: 999px;
  background: var(--border-strong);
}
.showcase-chrome .dot.red    { background: #ff5f57; }
.showcase-chrome .dot.amber  { background: #febc2e; }
.showcase-chrome .dot.green  { background: #28c840; }
.chrome-url {
  margin-left: 12px;
  font-size: 11px;
  color: var(--muted);
}

.showcase-body {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
}
@media (min-width: 900px) {
  .showcase-body { grid-template-columns: 1.4fr 1fr; }
}
.sc-col { padding: 24px 26px; }
.sc-col-left { border-bottom: 1px solid var(--border); }
@media (min-width: 900px) {
  .sc-col-left { border-right: 1px solid var(--border); border-bottom: 0; }
}
.sc-title {
  font-size: 20px; font-weight: 600; letter-spacing: -0.02em;
  margin: 6px 0 2px;
}
.sc-sub { color: var(--muted); font-size: 12px; margin: 0 0 20px; }

.sc-heuristics { display: flex; flex-direction: column; gap: 14px; }
.sc-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.sc-row-name { font-size: 13px; color: var(--fg-2); }
.sc-row-pills { display: inline-flex; gap: 3px; padding: 2px; background: var(--bg); border: 1px solid var(--border); border-radius: 8px; }
.sc-pill {
  min-width: 28px; height: 22px; padding: 0 8px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 6px;
  font-family: 'Chivo Mono', monospace; font-size: 11px; font-weight: 500;
  color: var(--muted);
  background: transparent;
}
.sc-pill.on { color: var(--fg); background: var(--raised); box-shadow: inset 0 0 0 1px var(--border); }

.sc-col-right {
  background: var(--bg);
  display: flex; flex-direction: column; gap: 14px;
}
.sc-score {
  display: flex; align-items: baseline; gap: 6px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.sc-score-num {
  font-size: 48px; font-weight: 500;
  color: var(--fg);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.sc-score-denom { font-size: 14px; color: var(--muted); }

.sc-ai-card {
  position: relative;
  padding: 12px 14px;
  background: var(--raised);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.sc-ai-card::before {
  content: "";
  position: absolute; inset: 0; padding: 1px;
  border-radius: inherit;
  background: radial-gradient(100% 55% at 0% 0%, color-mix(in oklab, var(--accent) 60%, transparent) 0%, transparent 35%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0.18;
  pointer-events: none;
}
.sc-ai-head {
  display: inline-flex; align-items: center; gap: 7px;
  color: var(--accent-text);
  font-family: 'Chivo Mono', monospace;
  font-size: 10px; font-weight: 500; letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 6px;
}
.sc-ai-body {
  margin: 0;
  font-size: 13px; line-height: 1.55;
  color: var(--fg-2);
}
.sc-ai-card-alt .sc-ai-head { color: var(--fg-2); letter-spacing: 0.04em; }
.sc-prio {
  background: color-mix(in oklab, var(--accent) 20%, transparent);
  color: var(--accent-text);
  padding: 1px 6px; border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent);
}
.sc-heur { color: var(--muted); text-transform: none; letter-spacing: 0; font-weight: 400; }

/* ─── Features ──
   Asymmetric composition: header is LEFT-aligned + narrow; grid is a bento
   with two wide "hero" cards atop four compact cards. Breaks the monotony
   of six identical tiles and signals hierarchy spatially. */
.w-features {
  padding: 140px 0 72px;
  text-align: left;
}
.w-features .s-icon-section { margin: 0 0 28px; }
.w-features .eyebrow        { text-align: left; }
.w-features .sec-title      { text-align: left; }
.w-features .sec-sub        { text-align: left; max-width: 640px; margin: 0 0 56px; }
.sec-br { display: inline; }

.sec-title {
  margin: 10px 0 14px;
  font-size: clamp(28px, 4.5vw, 48px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.04;
}
.sec-sub {
  max-width: 620px;
  margin: 0 auto 48px;
  color: var(--ink-700);
  font-size: 16px;
  line-height: 1.55;
}

/* Bento grid — 4 columns on desktop; wide cards span 2, compact span 1. */
.feat-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;
}
@media (min-width: 640px) {
  .feat-grid { grid-template-columns: repeat(2, 1fr); gap: 18px; }
  .feat-card.wide    { grid-column: span 2; }
  .feat-card.compact { grid-column: span 1; }
}
@media (min-width: 1024px) {
  .feat-grid { grid-template-columns: repeat(4, 1fr); gap: 20px; }
  .feat-card.wide    { grid-column: span 2; }
  .feat-card.compact { grid-column: span 1; }
}

.feat-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  transition: border-color 180ms var(--ease-out), transform 220ms var(--ease-out);
  overflow: hidden;
  display: flex; flex-direction: column;
}
.feat-card:hover { border-color: var(--border-strong); transform: translateY(-2px); }

/* Wide cards — more space, bigger title, subtle meta caption. */
.feat-card.wide {
  padding: 26px 26px 22px;
}
.feat-card.wide h3 {
  margin: 18px 0 8px;
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.2;
}
.feat-card.wide p {
  margin: 0;
  font-size: 14.5px; line-height: 1.6;
  color: var(--ink-700);
  max-width: 44ch;
}
.feat-card.wide .feat-ico {
  width: 40px; height: 40px;
  border-radius: 10px;
}

/* Meta caption — appears only on wide cards. Tiny, monospace, at the bottom. */
.feat-meta {
  display: inline-block;
  margin-top: auto;
  padding-top: 18px;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Compact cards — denser, no meta. */
.feat-card.compact {
  padding: 20px 20px 22px;
}
.feat-card.compact h3 {
  margin: 14px 0 6px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.005em;
}
.feat-card.compact p {
  margin: 0;
  font-size: 13px; line-height: 1.55;
  color: var(--ink-700);
}
.feat-card.compact .feat-ico {
  width: 28px; height: 28px;
  border-radius: 8px;
}

.feat-ico {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--raised);
  border: 1px solid var(--border);
  color: var(--accent-text);
}

/* Flagship AI card — borrow the AI-block glow from the product, reinforcing the tie. */
.feat-card.feat-ai {
  background:
    radial-gradient(120% 80% at 0% 0%, color-mix(in oklab, var(--accent) 10%, var(--surface)) 0%, var(--surface) 55%);
  border-color: color-mix(in oklab, var(--accent) 28%, var(--border));
}
.feat-card.feat-ai .feat-ico {
  background: color-mix(in oklab, var(--accent) 20%, var(--raised));
  border-color: color-mix(in oklab, var(--accent) 40%, var(--border));
}
.feat-card.feat-ai .feat-meta { color: var(--accent-text); }

/* ─── Heuristics strip ──
   Header moves LEFT on desktop (narrow column) while the 10-item grid sits
   RIGHT (wide column). Breaks the centered stack rhythm without hurting
   density — still see all 10 at a glance. */
.w-heuristics {
  padding: 96px 0 112px;
  text-align: left;
}
.heur-head {
  max-width: 440px;
}
.w-heuristics .eyebrow   { text-align: left; }
.w-heuristics .sec-title { text-align: left; margin: 8px 0 12px; }
.heur-note {
  margin: 0 0 40px;
  color: var(--ink-700);
  font-size: 15px;
  line-height: 1.55;
}
.w-heuristics .s-icon-section { margin: 0 0 24px; }

@media (min-width: 1024px) {
  .w-heuristics {
    display: grid;
    grid-template-columns: minmax(280px, 360px) 1fr;
    column-gap: 72px;
    align-items: start;
  }
  .w-heuristics .heur-head {
    grid-column: 1;
    position: sticky; top: 88px;
  }
  .w-heuristics .s-icon-section,
  .w-heuristics .eyebrow,
  .w-heuristics .sec-title,
  .w-heuristics .heur-head {
    grid-column: 1;
  }
  .w-heuristics .heur-list {
    grid-column: 2;
    margin: 0;
  }
}

.heur-list {
  list-style: none; padding: 0; margin: 40px 0 0;
  display: grid;
  gap: 0;
  grid-template-columns: repeat(1, 1fr);
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface);
  text-align: left;
}
@media (min-width: 640px)  { .heur-list { grid-template-columns: repeat(2, 1fr); } }

.heur-list li {
  display: flex; align-items: center; gap: 14px;
  padding: 18px 22px;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  font-size: 14px; color: var(--fg-2);
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}
.heur-list li:hover { background: var(--raised); color: var(--fg); }
.heur-list li .mono {
  font-size: 11px; color: var(--muted); letter-spacing: 0.08em;
  flex-shrink: 0;
  width: 22px;
}

/* ─── Closing CTA ──
   Horizontal on desktop: icon + headline LEFT, single primary + quiet
   secondary RIGHT. Strong, asymmetric close — not the centered template again. */
.w-cta-final {
  padding: 112px 0 96px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
}
.cta-left, .cta-right {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
}
.cta-left  { flex-direction: column; }
.cta-right { flex-direction: row; justify-content: center; flex-wrap: wrap; gap: 14px; }
.cta-secondary { padding: 0 4px; }

.cta-title {
  margin: 0;
  font-size: clamp(36px, 5.6vw, 64px);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.02;
  text-wrap: balance;
}

@media (min-width: 900px) {
  .w-cta-final {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 48px;
    text-align: left;
    padding: 120px 0 112px;
  }
  .cta-left {
    flex-direction: row;
    align-items: center;
    gap: 28px;
  }
  .cta-left .s-icon { margin: 0; flex-shrink: 0; }
  .cta-title {
    font-size: clamp(32px, 4.2vw, 52px);
    max-width: 540px;
  }
  .cta-right {
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    gap: 20px;
  }
}

/* ─── Footer ─── */
.w-footer {
  position: relative;
  z-index: 1;
  max-width: 1180px;
  margin: 0 auto;
  padding: 32px 28px;
  border-top: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  font-size: 12px;
  color: var(--muted);
  flex-wrap: wrap;
}
.footer-brand { display: inline-flex; align-items: center; gap: 8px; color: var(--fg-2); }
.footer-meta { display: flex; gap: 6px; align-items: center; }
.footer-links { display: flex; align-items: center; gap: 18px; }
.footer-links a, .footer-links button { color: var(--fg-2); }

/* ═══════════════════════════════════════════════════════════════════════════
   AUTH PAGES (login + signup)
   ═══════════════════════════════════════════════════════════════════════════ */
.auth-body {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.auth-nav {
  position: relative;
  z-index: 2;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  padding: 18px 28px;
}
.auth-nav-right {
  display: inline-flex; align-items: center; gap: 14px;
}

.auth-main {
  position: relative;
  z-index: 1;
  flex: 1;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  max-width: 1240px;
  width: 100%;
  margin: 0 auto;
  padding: 48px 28px 80px;
  align-items: center;
}
/* Asymmetric desktop layout — fixed editorial column for the card (optimal
   reading width ~420px), aside takes the rest. Dominance is intentional:
   the card is the task, the aside is context.
   align-items: start — card and aside anchor to the same top line instead of
   centering independently (which leaves the aside floating mid-page). */
@media (min-width: 1024px) {
  .auth-main {
    grid-template-columns: minmax(400px, 440px) minmax(0, 1fr);
    column-gap: clamp(56px, 6vw, 96px);
    padding-top: 72px;
    padding-bottom: 96px;
    align-items: start;
  }
  /* Aside is purely trust content — nudge it down a hair so the quote's
     opening mark aligns roughly with the card's title optical baseline. */
  .auth-aside { padding-top: 8px; }
}

/* Left: card */
.auth-card {
  max-width: 460px;
  width: 100%;
  margin: 0 auto;
  padding: 40px 32px 32px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: var(--card-glow);
  position: relative;
}
@media (min-width: 1024px) { .auth-card { margin: 0; } }

.auth-card::before {
  content: "";
  position: absolute; inset: 0;
  padding: 1px;
  border-radius: inherit;
  background: radial-gradient(80% 60% at 10% 0%, color-mix(in oklab, var(--accent) 55%, transparent) 0%, transparent 55%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0.15;
  pointer-events: none;
}

.auth-eyebrow { margin-bottom: 16px; }
.auth-title {
  margin: 0 0 12px;
  font-size: clamp(30px, 4vw, 40px);
  font-weight: 600;
  line-height: 1.02;
  letter-spacing: -0.028em;
  color: var(--fg);
}
.auth-sub {
  margin: 0;
  font-size: 14px;
  color: var(--ink-700);
}

/* Form uses variable gaps — default is a tight field spacing (12px). Distinct
   groups (social / credentials / submit) break the rhythm with larger margins
   below, creating visual cadence instead of a uniform ladder of inputs. */
.auth-form {
  display: flex; flex-direction: column;
  gap: 12px;
  margin-top: 24px;
}
.field-row { display: flex; gap: 10px; }
/* After the social button, breathe a touch more before the divider separator. */
.auth-form .field-row { margin-bottom: 4px; }

.divider {
  position: relative;
  text-align: center;
  margin: 8px 0 12px;
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.divider::before, .divider::after {
  content: "";
  position: absolute; top: 50%;
  width: calc(50% - 22px);
  height: 1px;
  background: var(--border);
}
.divider::before { left: 0; }
.divider::after  { right: 0; }

.field { display: flex; flex-direction: column; gap: 6px; }
.label-row { display: flex; align-items: center; justify-content: space-between; }
.label {
  font-size: 12px; font-weight: 500;
  color: var(--fg-2);
  letter-spacing: -0.005em;
}

.input-base {
  height: 42px;
  padding: 0 14px;
  font-size: 14px;
  background: var(--raised);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--fg);
  outline: none;
  transition: border-color 160ms var(--ease-out), box-shadow 160ms var(--ease-out), background 160ms var(--ease-out);
  width: 100%;
}
.input-base:hover { border-color: var(--border-strong); }
.input-base:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}
.input-base::placeholder { color: var(--subtle); }

.input-pw-wrap { position: relative; }
.pw-toggle {
  position: absolute; right: 4px; top: 4px; bottom: 4px;
  width: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 0; border-radius: 8px;
  color: var(--muted);
  transition: color 140ms var(--ease-out), background 140ms var(--ease-out);
}
.pw-toggle:hover { color: var(--fg); background: var(--hover); }

/* Password strength */
.pw-strength {
  display: flex; align-items: center; gap: 6px;
  margin-top: 6px;
}
.pw-seg {
  flex: 1;
  height: 3px;
  border-radius: 999px;
  background: var(--border);
  transition: background 220ms var(--ease-out);
}
.pw-seg.on { background: var(--accent); }
.pw-seg.warn { background: var(--warn); }
.pw-strength-label {
  margin-left: 4px;
  font-size: 10px;
  color: var(--muted);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  min-width: 40px;
  text-align: right;
}

/* Checkbox */
.checkbox-row {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 13px;
  color: var(--ink-700);
  cursor: pointer;
  user-select: none;
}
.check {
  appearance: none;
  -webkit-appearance: none;
  width: 16px; height: 16px;
  margin: 2px 0 0;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  background: var(--raised);
  position: relative;
  cursor: pointer;
  transition: background 160ms var(--ease-out), border-color 160ms var(--ease-out);
  flex-shrink: 0;
}
.check:hover { border-color: var(--fg-2); }
.check:checked {
  background: var(--accent);
  border-color: var(--accent);
}
.check:checked::after {
  content: "";
  position: absolute;
  left: 4px; top: 1px;
  width: 5px; height: 9px;
  border: solid var(--accent-fg);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.check:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.auth-status {
  margin: 4px 0 0;
  min-height: 18px;
  font-size: 12px;
  color: var(--muted);
}
.auth-status.error { color: var(--danger); }
.auth-status.ok    { color: var(--accent-text); }

.auth-foot {
  margin: 32px 0 0;
  font-size: 13px;
  color: var(--muted);
  text-align: center;
}

/* Right: aside (trust signal) — editorial, asymmetric, no cards. */
.auth-aside {
  display: none;
  color: var(--fg-2);
  max-width: 520px;
}
@media (min-width: 1024px) { .auth-aside { display: block; } }

/* Quote block: typography-led emphasis — a large monospace open-quote in the
   accent, the blockquote body set generously, attribution in small mono.
   NO side-stripe border (banned). Hierarchy comes from size + weight + color. */
.aside-quote-wrap {
  max-width: 480px;
  margin-bottom: 56px;
  padding: 0;
}
.aside-quote-wrap::before {
  content: "\201C";  /* Big opening curly quote */
  display: block;
  font-family: 'Chivo Mono', monospace;
  font-size: 56px;
  line-height: 0.8;
  color: var(--accent-text);
  margin-bottom: 12px;
}
.aside-quote {
  font-size: clamp(20px, 2.1vw, 26px);
  line-height: 1.28;
  letter-spacing: -0.015em;
  color: var(--fg);
  margin: 0 0 16px;
  font-weight: 500;
  max-width: 22ch;
}
.aside-attrib {
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 0.06em;
  margin: 0;
  text-transform: uppercase;
}

/* Stats: horizontal editorial row (no repeated cards, no backdrop-blur).
   Each stat lives between 1px hairlines — dev-tool, terminal-adjacent.
   The first cell loses its leading hairline; the last loses nothing; the
   hairlines between them give rhythm without boxing. */
.aside-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  max-width: 480px;
  margin-top: 8px;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.aside-stats > div {
  padding: 24px 24px 24px 0;
  position: relative;
}
.aside-stats > div + div {
  padding-left: 24px;
}
/* Vertical hairlines between cells — typographic, not decorative. */
.aside-stats > div + div::before {
  content: "";
  position: absolute;
  left: 0; top: 16px; bottom: 16px;
  width: 1px;
  background: var(--border);
}
.aside-stat-num {
  margin: 0 0 6px;
  font-size: 28px;
  font-weight: 500;
  color: var(--fg);
  letter-spacing: -0.02em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.aside-stat-label {
  margin: 0;
  font-size: 11px;
  color: var(--muted);
  line-height: 1.4;
  letter-spacing: 0.02em;
}

/* ═══════════════════════════════════════════════════════════════════════════
   MOTION LAYER — entrance choreography, scroll reveals, micro-interactions.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── Hero choreography ──
   Signature moment: stagger icon → pill → title → sub → CTAs → meta
   on page load. Each step takes ~720ms with ease-out. */
.w-hero > .s-icon,
.w-hero > .pill-announce,
.w-hero > .hero-title,
.w-hero > .hero-sub,
.w-hero > .hero-ctas,
.w-hero > .hero-meta {
  animation: hero-in 720ms var(--ease-out) both;
}
.w-hero > .s-icon        { animation-duration: 900ms; animation-delay:  60ms; }
.w-hero > .pill-announce { animation-delay: 220ms; }
.w-hero > .hero-title    { animation-duration: 820ms; animation-delay: 320ms; }
.w-hero > .hero-sub      { animation-delay: 460ms; }
.w-hero > .hero-ctas     { animation-delay: 560ms; }
.w-hero > .hero-meta     { animation-delay: 660ms; }

@keyframes hero-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ─── Scroll-reveal primitive ──
   Elements marked .reveal are hidden until IntersectionObserver adds .is-in.
   data-stagger="N" adds cascading delay for sibling groups (cards, list items). */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 640ms var(--ease-out),
    transform 760ms var(--ease-out);
  will-change: opacity, transform;
}
.reveal.is-in { opacity: 1; transform: translateY(0); will-change: auto; }

.reveal[data-stagger="1"].is-in { transition-delay:   0ms; }
.reveal[data-stagger="2"].is-in { transition-delay:  70ms; }
.reveal[data-stagger="3"].is-in { transition-delay: 140ms; }
.reveal[data-stagger="4"].is-in { transition-delay: 210ms; }
.reveal[data-stagger="5"].is-in { transition-delay: 280ms; }
.reveal[data-stagger="6"].is-in { transition-delay: 350ms; }
.reveal[data-stagger="7"].is-in { transition-delay: 420ms; }
.reveal[data-stagger="8"].is-in { transition-delay: 490ms; }
.reveal[data-stagger="9"].is-in { transition-delay: 560ms; }
.reveal[data-stagger="10"].is-in { transition-delay: 630ms; }

/* ─── Showcase: tilt straighten on reveal + sequential pill fill ──
   Mock scorecard enters tilted and scales/rotates to rest position,
   then its pills fill in row-by-row like the real app commits a score. */
.w-showcase .showcase-frame {
  transform: rotateX(9deg) scale(0.965);
  opacity: 0;
  transition:
    transform 980ms var(--ease-out),
    opacity 700ms var(--ease-out);
}
.w-showcase.is-in .showcase-frame {
  transform: rotateX(2deg) scale(1);
  opacity: 1;
}

/* Pills: off state by default; flip to active color when showcase lands. */
.sc-pill.on {
  transition:
    background 320ms var(--ease-out),
    color 320ms var(--ease-out),
    box-shadow 320ms var(--ease-out);
}
.w-showcase:not(.is-in) .sc-pill.on {
  background: transparent;
  color: var(--muted);
  box-shadow: none;
}
.w-showcase.is-in .sc-row:nth-child(1) .sc-pill.on { transition-delay: 480ms; }
.w-showcase.is-in .sc-row:nth-child(2) .sc-pill.on { transition-delay: 560ms; }
.w-showcase.is-in .sc-row:nth-child(3) .sc-pill.on { transition-delay: 640ms; }
.w-showcase.is-in .sc-row:nth-child(4) .sc-pill.on { transition-delay: 720ms; }
.w-showcase.is-in .sc-row:nth-child(5) .sc-pill.on { transition-delay: 800ms; }

/* AI cards + score: slide up after the frame has settled. */
.sc-ai-card, .sc-score {
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 520ms var(--ease-out),
    transform 620ms var(--ease-out);
}
.w-showcase.is-in .sc-score              { opacity: 1; transform: translateY(0); transition-delay: 420ms; }
.w-showcase.is-in .sc-ai-card            { opacity: 1; transform: translateY(0); transition-delay: 700ms; }
.w-showcase.is-in .sc-ai-card + .sc-ai-card { transition-delay: 840ms; }

/* ─── Button arrow nudge on hover ──
   Gives directional buttons a sense of forward momentum. */
.btn-primary-lg svg,
.btn-secondary-lg svg,
.btn-primary-sm svg,
.pill-announce svg {
  transition: transform 220ms var(--ease-out);
}
.btn-primary-lg:hover svg,
.btn-secondary-lg:hover svg,
.btn-primary-sm:hover svg,
.pill-announce:hover svg {
  transform: translateX(3px);
}

/* Re-apply hover lift after reveal lands — raises specificity so the
   translateY(-2px) wins over .reveal.is-in's translateY(0). */
.feat-card.reveal:hover { transform: translateY(-2px); }

/* ─── Feature card: corner-glow halo on hover ──
   Pairs with the existing translate-up lift, adds atmosphere without noise. */
.feat-card::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 260ms var(--ease-out);
  background:
    radial-gradient(80% 60% at 0% 0%, color-mix(in oklab, var(--accent) 22%, transparent), transparent 60%);
}
.feat-card:hover::after { opacity: 1; }

/* Lift the feature icon subtly on card hover — hints at interactivity. */
.feat-card .feat-ico {
  transition:
    transform 240ms var(--ease-out),
    border-color 240ms var(--ease-out),
    background 240ms var(--ease-out);
}
.feat-card:hover .feat-ico {
  transform: translateY(-2px);
  border-color: color-mix(in oklab, var(--accent) 35%, var(--border));
  background: color-mix(in oklab, var(--accent) 6%, var(--raised));
}

/* ─── Heuristic list cell lift ──
   Subtle depth on hover, reinforcing the "inspect this one" affordance. */
.heur-list li {
  transform: translateY(0);
}
.heur-list li .mono {
  transition: color 200ms var(--ease-out);
}
.heur-list li:hover .mono { color: var(--accent-text); }

/* ─── Final CTA title bloom ──
   The accent period on the final CTA echoes the hero's bloom, signaling end-of-page. */
.cta-title .dot-accent {
  animation: accent-bloom 3.6s ease-in-out infinite;
  animation-delay: 1.8s;
}

/* ─── Brand q in nav: gentle breathe when the section is pinned at top ──
   Minimal — just enough to signal "alive". */
@keyframes brand-q-breathe {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent) 0%, transparent); }
  50%      { box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 12%, transparent); }
}
.w-nav.scrolled .brand-q-ico {
  animation: brand-q-breathe 4.8s ease-in-out infinite;
}

/* ═══════════════════════════════════════════════════════════════════════════
   DELIGHT LAYER — restrained sophistication, discoverable touches.
   Match the product's tone: rigorous, sharp, occasional whisper of personality.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── Hero scroll hint ──
   Fades in 2.5s after load, bobs gently, dismisses on first scroll. */
.scroll-hint {
  position: fixed;
  left: 50%; bottom: 18px;
  transform: translateX(-50%) translateY(6px);
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  font-family: 'Chivo Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  background: color-mix(in oklab, var(--surface) 78%, transparent);
  border: 1px solid var(--border);
  border-radius: 999px;
  opacity: 0;
  pointer-events: none;
  z-index: 10;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  animation:
    hint-in 600ms var(--ease-out) 2400ms forwards,
    hint-bob 2.6s ease-in-out 3000ms infinite;
}
.scroll-hint.dismissed {
  opacity: 0 !important;
  animation: none !important;
  transform: translateX(-50%) translateY(6px) !important;
  transition: opacity 400ms var(--ease-out), transform 400ms var(--ease-out);
}
@keyframes hint-in {
  from { opacity: 0; transform: translateX(-50%) translateY(6px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}
@keyframes hint-bob {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(3px); }
}

/* ─── Welcome toast ──
   Shown on ⌘K. Teaches the real product shortcut in context. */
.w-toast {
  position: fixed;
  left: 50%; bottom: 28px;
  transform: translateX(-50%) translateY(12px);
  display: inline-flex; align-items: center; gap: 10px;
  padding: 10px 12px 10px 14px;
  background: color-mix(in oklab, var(--raised) 94%, transparent);
  color: var(--fg);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: var(--shadow-float);
  font-size: 13px;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  opacity: 0;
  pointer-events: none;
  z-index: 30;
  transition:
    opacity 240ms var(--ease-out),
    transform 260ms var(--ease-out);
}
.w-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto; }
.w-toast .kbd-hint { margin: 0; }
.w-toast a.link-accent { font-weight: 500; white-space: nowrap; }

/* ─── Score bloom ──
   Brief lime halo when the showcase count-up lands at 7.5. Echoes the
   real app's total-bloom to reinforce product-brand cohesion. */
@keyframes score-bloom {
  0%, 100% { text-shadow: 0 0 0 transparent; }
  40%      { text-shadow: 0 0 26px color-mix(in oklab, var(--accent) 55%, transparent); }
}
.sc-score-num.bloom { animation: score-bloom 900ms var(--ease-out); }

/* ─── Feature card cursor-follow glow ──
   Makes each card feel like a physical object catching the light.
   Override the static corner-glow with a position-driven gradient. */
.feat-card::after {
  background:
    radial-gradient(140px 110px at var(--mx, 0%) var(--my, 0%),
      color-mix(in oklab, var(--accent) 22%, transparent), transparent 60%);
  transition: opacity 260ms var(--ease-out), background-position 120ms var(--ease-out);
}

/* ─── "qualyx" Konami celebration ──
   Triggered when the user types the brand name anywhere on the page.
   A single lime ring ripples out from center; the brand-q does a clean spin. */
.qx-ripple {
  position: fixed;
  left: 50%; top: 50%;
  width: 10px; height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 50%;
  border: 2px solid var(--accent);
  opacity: 0.9;
  pointer-events: none;
  z-index: 9999;
  animation: qx-ripple 1400ms var(--ease-out) forwards;
}
@keyframes qx-ripple {
  0%   { transform: scale(0.2); opacity: 0.9; }
  80%  { opacity: 0.18; }
  100% { transform: scale(180); opacity: 0; }
}
.brand-q-ico.qx-spin { animation: qx-spin 900ms var(--ease-out); }
@keyframes qx-spin {
  0%   { transform: rotate(0deg)    scale(1); box-shadow: 0 0 0 0   color-mix(in oklab, var(--accent) 0%, transparent); }
  40%  { transform: rotate(-180deg) scale(1.12); box-shadow: 0 0 0 6px color-mix(in oklab, var(--accent) 30%, transparent); }
  100% { transform: rotate(-360deg) scale(1); box-shadow: 0 0 0 0   color-mix(in oklab, var(--accent) 0%, transparent); }
}

/* Delight for reduced-motion users: keep the content, kill the motion. */
@media (prefers-reduced-motion: reduce) {
  .scroll-hint, .qx-ripple, .brand-q-ico.qx-spin,
  .sc-score-num.bloom { animation: none !important; }
  .scroll-hint { display: none; }
}

/* ─── Touch targets for coarse pointers ──
   Desktop density is fine on trackpads/mice, but WCAG 2.5.5 requires 44×44
   for touch. Bumps the compact buttons + password toggle on touch devices
   without disturbing the desktop look. */
@media (pointer: coarse) {
  .btn-primary-sm,
  .btn-secondary-sm {
    min-height: 44px;
    padding-top: 0; padding-bottom: 0;
  }
  .pill-group { padding: 4px; }
  .pill       { min-height: 36px; padding: 0 12px; }
  .pw-toggle { width: 44px; right: 2px; }
  .auth-nav-right .link-quiet,
  .w-nav-cta     .link-quiet {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: 0 6px;
  }
  .cta-secondary {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
}

/* ─── Mobile performance trims ──
   Backdrop-filter is expensive on low-end mobile GPUs; dial down the blur
   radius on narrow viewports where the effect barely reads anyway. */
@media (max-width: 639px) {
  .w-nav        { backdrop-filter: saturate(1.1) blur(10px);
                 -webkit-backdrop-filter: saturate(1.1) blur(10px); }
  .w-toast      { backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
  .scroll-hint  { backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ONBOARDING PAGE — 4-step tour shown right after signup.
   Same dark-first tokens as the auth pages; two-column layout with copy on
   the left and a product-mock "visual" on the right. One primary CTA at the
   bottom center-right; Skip in the top-right. Dots indicate progress.
   ═══════════════════════════════════════════════════════════════════════════ */
.ob-body {
  overflow-x: hidden;
}

.ob-main {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  flex-direction: column;
  max-width: 1180px;
  width: 100%;
  margin: 0 auto;
  padding: 16px 28px 40px;
}

/* Progress: dots on the left, "1/4" counter on the right. Dev-tool meter. */
.ob-progress {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin: 16px 0 40px;
}
.ob-dots {
  display: inline-flex;
  gap: 8px;
}
.ob-dots > .ob-dot {
  width: 28px;
  height: 3px;
  border-radius: 999px;
  background: var(--border);
  transition: background 200ms var(--ease-out), transform 200ms var(--ease-out);
  transform-origin: 0 50%;
}
.ob-dots > .ob-dot.is-current { background: var(--accent); transform: scaleX(1.15); }
.ob-dots > .ob-dot.is-done    { background: var(--border-strong); }

.ob-counter {
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.ob-counter-sep { margin: 0 2px; color: var(--border-strong); }
#obCur { color: var(--fg); }

/* Slides sit in a shared wrapper; only the active one is displayed.
   Anchor slides to the top (not center): consistent entry position
   between slides regardless of their vertical weight. */
.ob-slides {
  flex: 1;
  display: grid;
  align-items: start;
  padding: 40px 0 64px;
}
.ob-slide {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
  align-items: start;
  animation: ob-slide-in 520ms var(--ease-out-quart) both;
}
.ob-slide[hidden] { display: none !important; }
/* Asymmetric desktop layout — copy column fixed to an editorial reading width
   on the left; visual flows on the right. Mirrors the login page's
   card:aside system for cross-surface continuity. */
@media (min-width: 900px) {
  .ob-slide {
    grid-template-columns: minmax(380px, 460px) minmax(0, 1fr);
    column-gap: clamp(56px, 7vw, 112px);
    align-items: start;
  }
  /* Nudge the copy down a hair so its eyebrow aligns roughly with the visual
     baseline, matching the cross-column optical rhythm we set on the login. */
  .ob-copy { padding-top: 4px; }
}
@keyframes ob-slide-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Copy column — editorial, large title, narrow sub. */
.ob-copy { max-width: 520px; }
.ob-copy .eyebrow { margin-bottom: 16px; }
.ob-title {
  margin: 0 0 16px;
  font-size: clamp(32px, 4.4vw, 48px);
  font-weight: 600;
  line-height: 1.04;
  letter-spacing: -0.03em;
  color: var(--fg);
}
.ob-title .soft { color: var(--muted); }
.ob-sub {
  margin: 0;
  max-width: 44ch;
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink-700);
}
.ob-sub .mono { color: var(--fg-2); }
.ob-sub .mono-em { color: var(--fg-2); }

/* Visual column — each slide renders a distinct product-adjacent mock.
   min-height stabilizes vertical weight between slides so the page doesn't
   "jump" when advancing. flex-start + align-items start — visual anchors at
   the top of its cell and the copy carries its own baseline. */
.ob-visual {
  position: relative;
  min-height: 360px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: 12px;
}
@media (min-width: 900px) {
  .ob-visual { align-items: flex-start; }
}

/* Slide 1 — heuristics list, hairline-boxed, hover tint rows. */
.ob-heur-list {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
  max-width: 420px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}
.ob-heur-list li {
  display: flex; align-items: center; gap: 16px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  color: var(--fg-2);
}
.ob-heur-list li:last-child { border-bottom: 0; }
.ob-heur-list li .mono {
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 0.08em;
  width: 22px;
  flex-shrink: 0;
}
.ob-heur-more { color: var(--muted) !important; font-style: italic; }

/* Slide 2 — URL + AI insight mock arranged as a narrative flow.
   A vertical hairline on the left side of the insight card "connects" it to
   the URL above, implying: URL → analysis → insight. */
.ob-mock-url {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  background: var(--raised);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 13px;
  width: 100%; max-width: 460px;
  margin: 0;
  position: relative;
}
/* A 1px rail descends from the URL block into the insight card below —
   reads as "the pipe between input and output". */
.ob-mock-url::after {
  content: "";
  position: absolute;
  left: 24px;
  bottom: -16px;
  width: 1px;
  height: 16px;
  background: var(--border);
}
.ob-mock-scheme { color: var(--muted); }
.ob-mock-host { color: var(--fg-2); flex: 1; }
.ob-mock-analyze {
  font-size: 11px;
  color: var(--accent-text);
  font-family: 'Chivo Mono', monospace;
  letter-spacing: 0.04em;
}
.ob-mock-insight {
  position: relative;
  padding: 16px;
  background: var(--raised);
  border: 1px solid var(--border);
  border-radius: 10px;
  width: 100%; max-width: 460px;
  margin: 16px 0 0;
}
.ob-mock-insight::before {
  content: "";
  position: absolute; inset: 0; padding: 1px;
  border-radius: inherit;
  background: radial-gradient(100% 55% at 0% 0%, color-mix(in oklab, var(--accent) 55%, transparent) 0%, transparent 35%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0.18;
  pointer-events: none;
}
.ob-mock-insight-body {
  margin: 10px 0 12px;
  font-size: 13px; line-height: 1.5;
  color: var(--fg-2);
}
.ob-mock-conf { display: inline-flex; align-items: center; gap: 5px; }
.ob-conf-dot {
  width: 5px; height: 5px; border-radius: 999px;
  background: var(--border-strong);
}
.ob-conf-dot.on { background: var(--accent); }
.ob-conf-label {
  font-size: 10px;
  color: var(--muted);
  letter-spacing: 0.04em;
  margin-left: 6px;
}
.ob-mock-insight .ai-badge { /* tighten spacing */
  padding: 2px 8px 2px 6px;
}

/* Slide 3 — three project cards in a single row. 3-in-a-row gives a clean
   "row of projects" read without the dead-quadrant 2x2 layout creates. */
.ob-project-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  width: 100%;
}
@media (min-width: 720px) {
  .ob-project-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.ob-project-card {
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  min-height: 148px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ob-project-head {
  display: flex; align-items: center; gap: 10px;
}
.ob-project-dot {
  width: 9px; height: 9px; border-radius: 999px;
  flex-shrink: 0;
}
.ob-project-name {
  font-size: 14px; font-weight: 500; color: var(--fg);
}
.ob-project-desc {
  margin: 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--muted);
}
.ob-project-foot {
  margin-top: auto;
  display: flex; align-items: baseline; justify-content: space-between;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.ob-project-meta {
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.ob-project-score {
  font-size: 18px;
  font-weight: 500;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}
.ob-project-ghost {
  align-items: center;
  justify-content: center;
  text-align: center;
  border-style: dashed;
  color: var(--muted);
  font-size: 12px;
}
.ob-project-plus {
  font-size: 22px;
  color: var(--accent-text);
  line-height: 1;
  margin-bottom: 4px;
}

/* Slide 4 — suggestion cards (reuse sg-chip styles from the app). */
.ob-sg-card {
  position: relative;
  padding: 16px;
  background: var(--raised);
  border: 1px solid var(--border);
  border-radius: 10px;
  width: 100%; max-width: 460px;
  margin-bottom: 12px;
}
.ob-sg-card:last-child { margin-bottom: 0; }
.ob-sg-chips {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-bottom: 10px;
}
/* sg-chip already declared near the welcome showcase; ensure shared. */
.sg-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px;
  font-family: 'Chivo Mono', monospace;
  font-size: 10px; font-weight: 500; letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.4;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
}
.sg-chip.prio-high {
  background: color-mix(in oklab, var(--accent) 18%, transparent);
  color: var(--accent-text);
  border-color: color-mix(in oklab, var(--accent) 40%, transparent);
}
.sg-chip.prio-medium {
  background: var(--raised); color: var(--fg-2);
  border-color: var(--border-strong);
}
.sg-chip.heuristic { text-transform: none; letter-spacing: 0; }
.sg-chip.effort { min-width: 18px; justify-content: center; }
.ob-sg-title {
  margin: 0 0 6px;
  font-size: 14px; font-weight: 500;
  color: var(--fg);
  line-height: 1.35;
}
.ob-sg-change {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--fg-2);
}

/* Controls — prev on the left, CTA on the right. On the first slide prev is
   disabled; on the last, next reads "Começar". */
.ob-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}
.ob-prev:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.ob-next {
  min-width: 160px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   ONBOARDING DELIGHT — orchestrated per-slide reveal + one live-demo moment.
   Restraint per briefing: stagger + bloom, no confetti, no cute copy.
   ═══════════════════════════════════════════════════════════════════════════ */

.ob-slide { will-change: opacity, transform; }

/* Inner stagger — when a slide enters, its children ladder in on top of the
   outer .ob-slide fade. Opacity + translateY only (GPU). */
.ob-slide .eyebrow,
.ob-slide .ob-title,
.ob-slide .ob-sub,
.ob-slide .ob-visual > * {
  animation: ob-rise 520ms var(--ease-out-quart) both;
}
.ob-slide .eyebrow      { animation-delay:  40ms; }
.ob-slide .ob-title     { animation-delay: 120ms; animation-duration: 620ms; }
.ob-slide .ob-sub       { animation-delay: 220ms; }
.ob-slide .ob-visual > *:nth-child(1) { animation-delay: 280ms; }
.ob-slide .ob-visual > *:nth-child(2) { animation-delay: 360ms; }
.ob-slide .ob-visual > *:nth-child(3) { animation-delay: 440ms; }
@keyframes ob-rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Slide 2 — "live demo" pulse on the Analisar affordance.
   Runs once, ~420ms after the slide enters, hinting "we ran it for you". */
.ob-slide[data-slide="2"]:not([hidden]) .ob-mock-analyze {
  animation: analyze-pulse 1200ms var(--ease-out-quart) 420ms 1 both;
}
@keyframes analyze-pulse {
  0%   { opacity: 0.5; transform: translateX(0); }
  35%  { opacity: 1;   transform: translateX(2px); }
  60%  { opacity: 1;   transform: translateX(0); }
  100% { opacity: 1;   transform: translateX(0); }
}
/* The connector rail between URL and insight also draws in, reinforcing
   the "analysis flowed through the pipe" reading. */
.ob-slide[data-slide="2"]:not([hidden]) .ob-mock-url::after {
  transform-origin: 0 0;
  animation: rail-draw 420ms var(--ease-out-quart) 620ms both;
}
@keyframes rail-draw {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

/* Progress dots — on transition, the current dot blooms briefly. */
.ob-dots > .ob-dot.is-current {
  animation: dot-bloom 420ms var(--ease-out-quart);
}
@keyframes dot-bloom {
  0%   { transform: scaleX(0.4); opacity: 0.4; }
  60%  { transform: scaleX(1.25); opacity: 1; }
  100% { transform: scaleX(1.15); opacity: 1; }
}
/* "Done" dots settle to a slightly dimmer state than neutral, implying
   progress accumulates. */
.ob-dots > .ob-dot.is-done {
  transition: background 280ms var(--ease-out-quart);
}

/* ─── Easter egg: Don't Make Me Think attribution tooltip ──
   The mono-em text inside slide 2 gets a hover affordance; on hover, a small
   attribution chip appears. Dev-tool whisper — most users won't notice. */
.ob-slide[data-slide="2"] .mono-em {
  position: relative;
  cursor: help;
  border-bottom: 1px dashed color-mix(in oklab, var(--fg) 20%, transparent);
  transition: border-bottom-color 180ms var(--ease-out-quart);
}
.ob-slide[data-slide="2"] .mono-em:hover {
  border-bottom-color: color-mix(in oklab, var(--accent) 50%, transparent);
}
.ob-slide[data-slide="2"] .mono-em::after {
  content: attr(data-attrib);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  padding: 4px 8px;
  background: var(--raised);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-family: 'Chivo Mono', monospace;
  font-style: normal;
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--fg-2);
  white-space: nowrap;
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition:
    opacity 180ms var(--ease-out-quart),
    transform 200ms var(--ease-out-quart);
  z-index: 10;
}
.ob-slide[data-slide="2"] .mono-em:hover::after {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .ob-slide, .ob-slide *, .ob-mock-url::after {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   AUTH PAGE MOTION — one orchestrated reveal on load, restrained micro-feedback.
   Fiel ao briefing ("one well-orchestrated reveal, not micro-interactions on
   every button") do .impeccable.md. Exponential easing; no bounce/elastic.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Shared easing tokens — aliased to the already-declared --ease-out (same
   cubic-bezier) so existing rules keep working while new rules can read
   by semantic intent. */
:root {
  --ease-out-quart: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-out-expo:  cubic-bezier(0.16, 1, 0.3, 1);
}

/* ─── Card entrance choreography ──
   Staggered reveal: eyebrow → title → sub → form (and social button, divider,
   fields, CTA, foot sub-stagger inside the form). Uses opacity + translateY,
   both GPU-accelerated. */
@keyframes auth-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

.auth-card .auth-eyebrow,
.auth-card .auth-title,
.auth-card .auth-sub,
.auth-card .auth-form,
.auth-card .auth-foot {
  animation: auth-rise 680ms var(--ease-out-quart) both;
}
.auth-card .auth-eyebrow { animation-delay:  80ms; animation-duration: 560ms; }
.auth-card .auth-title   { animation-delay: 160ms; animation-duration: 720ms; }
.auth-card .auth-sub     { animation-delay: 260ms; }
.auth-card .auth-form    { animation-delay: 360ms; }
.auth-card .auth-foot    { animation-delay: 560ms; animation-duration: 520ms; }

/* Inner form sub-stagger — the form itself already rises; its children then
   ladder in over ~360ms to sell the cadence without dragging. */
.auth-form > * {
  animation: auth-rise 480ms var(--ease-out-quart) both;
  animation-delay: 440ms;
}
.auth-form > *:nth-child(1) { animation-delay: 440ms; }  /* social */
.auth-form > *:nth-child(2) { animation-delay: 500ms; }  /* divider */
.auth-form > *:nth-child(3) { animation-delay: 540ms; }  /* email */
.auth-form > *:nth-child(4) { animation-delay: 580ms; }  /* senha */
.auth-form > *:nth-child(5) { animation-delay: 620ms; }  /* remember */
.auth-form > *:nth-child(6) { animation-delay: 680ms; }  /* CTA */
.auth-form > *:nth-child(7) { animation-delay: 720ms; }  /* status */

/* The card shell itself also fades up as a container envelope. */
.auth-card {
  animation: auth-card-in 720ms var(--ease-out-expo) both;
}
@keyframes auth-card-in {
  from { opacity: 0; transform: translateY(14px) scale(0.985); }
  to   { opacity: 1; transform: translateY(0)    scale(1); }
}

/* ─── Aside choreography — independent from card; runs in parallel ──
   Big lime quotation mark is the visual anchor. It enters slightly scaled
   and settles — the single "signature moment" of the login page. */
.auth-aside {
  animation: auth-rise 720ms var(--ease-out-quart) 180ms both;
}
.auth-aside .aside-quote-wrap::before {
  display: block;
  animation: quote-land 840ms var(--ease-out-expo) 260ms both;
  transform-origin: 0 50%;
  will-change: transform, opacity;
}
/* Transform + opacity only — GPU-accelerated. Scale from 0.72 sells "arriving"
   without layout shift. No letter-spacing animation (not GPU-friendly). */
@keyframes quote-land {
  0%   { opacity: 0; transform: scale(0.72) translateY(4px); }
  60%  { opacity: 1; }
  100% { opacity: 1; transform: scale(1)    translateY(0); }
}
.auth-aside .aside-quote    { animation: auth-rise 640ms var(--ease-out-quart) 440ms both; }
.auth-aside .aside-attrib   { animation: auth-rise 560ms var(--ease-out-quart) 560ms both; }
.auth-aside .aside-stats    { animation: auth-rise 640ms var(--ease-out-quart) 640ms both; }

/* Top-bar nav fades in on a fast track — it's chrome, not a reveal moment. */
.auth-nav {
  animation: nav-in 420ms var(--ease-out-quart) 60ms both;
}
@keyframes nav-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ─── Feedback layer ──
   Restrained: only where a state change would otherwise be abrupt. */

/* Input focus — field label shifts from muted to full fg when the input is
   focused. Communicates "you are here" without adding a new visual element. */
.field { transition: color 160ms var(--ease-out-quart); }
.field:focus-within .label { color: var(--fg); }
.field:focus-within .link-quiet { color: var(--fg-2); }

/* Checkbox check draw-in — swap the "solid appearing instantly" pattern for a
   tracing animation using a clip-path sweep. Looks like it's being written. */
.check:checked::after {
  animation: check-draw 260ms var(--ease-out-quart) both;
}
@keyframes check-draw {
  from { clip-path: polygon(0 0, 0 0, 0 100%, 0 100%); }
  to   { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); }
}

/* Password toggle — eye icon crossfade when state flips. The JS toggles
   .is-visible on the button; CSS does the rest. */
.pw-toggle svg {
  transition:
    opacity 180ms var(--ease-out-quart),
    transform 200ms var(--ease-out-quart);
}
.pw-toggle svg.eye-off {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 14px; height: 14px;
  opacity: 0;
  transform: scale(0.9);
  pointer-events: none;
}
.pw-toggle.is-visible svg.eye-on  { opacity: 0; transform: scale(0.9); }
.pw-toggle.is-visible svg.eye-off { opacity: 1; transform: scale(1); }
.input-pw-wrap { position: relative; }

/* Auth status — shake micro on error, gentle fade on ok. */
.auth-status {
  transition: color 200ms var(--ease-out-quart);
}
.auth-status.error { animation: status-shake 360ms var(--ease-out-quart); }
@keyframes status-shake {
  0%, 100% { transform: translateX(0); }
  15%      { transform: translateX(-4px); }
  30%      { transform: translateX(4px); }
  45%      { transform: translateX(-3px); }
  60%      { transform: translateX(3px); }
  75%      { transform: translateX(-1px); }
}

/* CTA arrow nudge on hover is already declared; reuse via adjacent rule so
   it applies to auth buttons too (btn-primary-lg covers login CTA). */

/* ─── CTA loading state ──
   During the submit round-trip, swap the arrow for a spinner and update the
   label text via JS. `is-loading` is toggled on the button. */
.btn-primary-lg .btn-icon-spin { display: none; }
.btn-primary-lg.is-loading .btn-icon-go   { display: none; }
.btn-primary-lg.is-loading .btn-icon-spin {
  display: inline-block;
  animation: btn-spin 820ms linear infinite;
  transform-origin: 50% 50%;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* ─── Success check draw-in ──
   When .auth-status.ok arrives, prepend a check that traces in. Pure CSS —
   stroke-dashoffset is GPU-lite and respects reduced motion. */
.auth-status.ok { position: relative; padding-left: 18px; }
.auth-status.ok::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 12px; height: 12px;
  margin-top: -6px;
  background: no-repeat center / contain;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a8e009' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M4 12l5 5L20 6' pathLength='100' stroke-dasharray='100' stroke-dashoffset='100'><animate attributeName='stroke-dashoffset' from='100' to='0' dur='360ms' fill='freeze'/></path></svg>");
}

/* ─── Aside quote hover — discoverable pulse ──
   The big lime opening quote is the login's signature mark. On hover, the
   accent *breathes* — a single 300ms scale + return. Just once, so it
   doesn't become noise; the class is removed after the animation ends. */
.aside-quote-wrap { cursor: default; }
.aside-quote-wrap:hover::before {
  animation: quote-breathe 420ms var(--ease-out-quart);
}
@keyframes quote-breathe {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.08); }
  100% { transform: scale(1); }
}

/* Stats count-up — while waiting for the JS to populate, the number uses
   tabular-nums so digit width doesn't jump during the animation. */
.aside-stat-num {
  font-variant-numeric: tabular-nums;
  transition: color 200ms var(--ease-out-quart);
}
.aside-stat-num.counting { color: var(--accent-text); }

/* ─── Reduced motion ── one authoritative rule for the whole page ─── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  /* Keep the reveal elements visible rather than mid-state. */
  .reveal { opacity: 1; transform: none; }
  .w-showcase .showcase-frame { opacity: 1; transform: rotateX(2deg) scale(1); }
  .sc-ai-card, .sc-score { opacity: 1; transform: none; }
  /* Auth-page motion safe-guards — force final rested state so no element
     flashes in the "from" position when animations are suppressed. */
  .auth-card, .auth-nav, .auth-aside,
  .auth-eyebrow, .auth-title, .auth-sub, .auth-form, .auth-foot,
  .auth-form > *,
  .aside-quote-wrap::before, .aside-quote, .aside-attrib, .aside-stats {
    opacity: 1 !important;
    transform: none !important;
  }
}
