/* ── Design tokens ──────────────────────────────────────────────────────── */
:root {
  --bg: #fafafa;
  --surface: #ffffff;
  --surface-warm: #fff4cc;
  --fg: #0d1117;
  --fg-2: #374151;
  --muted: #6b7280;
  --border: #e5e7eb;
  --border-soft: #f3f4f6;
  --accent: #ffd21e;
  --accent-on: #0d1117;
  --accent-hover: #f59e0b;
  /* The one blue in the system: a link or a file-format hint inside a
     component. Separate from the category accents below, which mean "this is
     a SaaS directory", not "this is actionable". */
  --link: #2563eb;
  --success: #16a34a;
  --danger: #dc2626;
  --font-display: "Roboto", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: var(--font-body);
  --text-xs: 12px; --text-sm: 13px; --text-base: 15px; --text-lg: 18px;
  --text-xl: 24px; --text-2xl: 32px; --text-3xl: 40px;
  --leading-body: 1.55; --leading-tight: 1.1; --tracking-display: -0.01em;
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px;
  --space-6: 24px; --space-8: 32px; --space-12: 48px;
  --section-y-desktop: 80px; --section-y-tablet: 48px; --section-y-phone: 32px;
  --radius-sm: 4px; --radius-md: 6px; --radius-lg: 8px; --radius-pill: 9999px;
  --elev-raised: 0 2px 8px color-mix(in oklab, var(--fg), transparent 90%);
  --focus-ring: 0 0 0 3px rgba(13, 17, 23, 0.1);
  --motion-fast: 120ms; --motion-base: 200ms; --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --container-max: 1280px; --container-gutter-desktop: 24px;
  --container-gutter-tablet: 16px; --container-gutter-phone: 12px;

  /* directory category accents */
  --cat-saas: #2563eb;      --cat-saas-bg: #dbeafe;
  --cat-product: #16a34a;   --cat-product-bg: #dcfce7;
  --cat-dev: #9333ea;       --cat-dev-bg: #f3e8ff;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
body {
  margin: 0; background: var(--bg); color: var(--fg);
  font-family: var(--font-body); font-size: var(--text-base);
  line-height: var(--leading-body); -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 600; margin: 0; line-height: var(--leading-tight); }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
[id] { scroll-margin-top: 76px; }
:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }
[hidden] { display: none !important; }

.container { max-width: var(--container-max); margin: 0 auto; padding: 0 var(--container-gutter-desktop); }
.eyebrow {
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted);
  display: inline-flex; align-items: center; gap: var(--space-2);
}
.eyebrow::before { content: ""; width: 18px; height: 2px; background: var(--accent); display: inline-block; }
.lead { font-size: var(--text-lg); color: var(--fg-2); line-height: 1.55; }
.mono { font-family: var(--font-mono); }
.tnum { font-variant-numeric: tabular-nums; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--fg); color: #fff; padding: 10px 16px;
  border-radius: var(--radius-sm); font-family: var(--font-mono); font-size: var(--text-sm);
}
.skip-link:focus { left: var(--space-4); top: var(--space-4); }

/* ── Buttons ────────────────────────────────────────────────────────────── */
.btn {
  font-family: var(--font-display); font-size: var(--text-sm); font-weight: 500;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  padding: 10px 16px; border-radius: var(--radius-md); border: 1px solid transparent;
  cursor: pointer; transition: background var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard), color var(--motion-fast); white-space: nowrap;
  min-height: 44px;
}
.btn-primary { background: var(--fg); color: #fff; }
.btn-primary:hover { background: var(--fg-2); }
.btn-accent { background: var(--accent); color: var(--accent-on); }
.btn-accent:hover { background: var(--accent-hover); }
.btn-outline { background: var(--surface); color: var(--fg); border-color: var(--border); }
.btn-outline:hover { background: var(--border-soft); border-color: #d1d5db; }
.btn-ghost { background: transparent; color: var(--fg-2); }
.btn-ghost:hover { background: var(--border-soft); color: var(--fg); }
.btn-lg { padding: 13px 22px; font-size: var(--text-base); }
/* Inline glyph inside a button (e.g. the "Looks good →" arrow). Never shrinks,
   and glides forward on hover/focus to hint at the direction of travel — with a
   slightly deeper push on press. Motion is opted out under reduced-motion. */
.btn-icon { flex: none; transition: transform var(--motion-base) var(--ease-standard); }
.btn:hover .btn-icon,
.btn:focus-visible .btn-icon { transform: translateX(4px); }
.btn:active .btn-icon { transform: translateX(6px); }
@media (prefers-reduced-motion: reduce) {
  .btn-icon { transition: none; }
  .btn:hover .btn-icon,
  .btn:focus-visible .btn-icon,
  .btn:active .btn-icon { transform: none; }
}
/* Keyboard focus (and while pressed) draws an offset ring: a bg-coloured gap
   then a solid --fg ring, so it reads on the dark primary and the light
   ghost/outline variants alike. Overrides the faint global --focus-ring, which
   vanishes on a dark button. */
.btn:focus-visible,
.btn:focus-visible:active { box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--fg); border-radius: var(--radius-md); }
.btn-block { width: 100%; }

/* ── Tags / chips ───────────────────────────────────────────────────────── */
.tag {
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: 500;
  letter-spacing: 0.02em; padding: 2px 8px; border-radius: var(--radius-sm);
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
}
.tag-saas { background: var(--cat-saas-bg); color: var(--cat-saas); }
.tag-product { background: var(--cat-product-bg); color: var(--cat-product); }
.tag-dev { background: var(--cat-dev-bg); color: var(--cat-dev); }

.pill {
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: 500;
  padding: 3px 10px; border-radius: var(--radius-pill); display: inline-flex; align-items: center; gap: 6px;
}
.pill-ok { background: var(--cat-product-bg); color: var(--success); }
.dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* ── Nav ────────────────────────────────────────────────────────────────── */
header.nav {
  position: sticky; top: 0; z-index: 50; background: color-mix(in oklab, var(--bg), transparent 15%);
  backdrop-filter: saturate(180%) blur(8px); border-bottom: 1px solid var(--border);
}
.nav-inner { display: flex; align-items: center; gap: var(--space-6); height: 60px; }
.brand { display: flex; align-items: center; gap: var(--space-2); font-family: var(--font-display); font-weight: 600; font-size: var(--text-base); flex: none; }
.brand .mark {
  width: 26px; height: 26px; border-radius: var(--radius-sm); background: var(--accent);
  color: var(--accent-on); display: grid; place-items: center; font-size: 14px; font-weight: 600;
  border: 1px solid color-mix(in oklab, var(--accent-hover), black 5%); flex: none;
}
.brand small { color: var(--muted); font-weight: 400; }
.nav-menu { display: flex; align-items: center; gap: var(--space-6); flex: 1; }
.nav-links { display: flex; align-items: center; gap: var(--space-5); }
.nav-links a { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--fg-2); padding: 8px 0; }
.nav-links a:hover { color: var(--fg); }
.nav-actions { display: flex; align-items: center; gap: var(--space-3); margin-left: auto; }
.nav-actions .signin { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--fg-2); padding: 8px 4px; }
.nav-actions .signin:hover { color: var(--fg); }
.nav-toggle {
  display: none; width: 44px; height: 44px; place-items: center; margin-left: auto; flex: none;
  background: var(--surface); color: var(--fg); border: 1px solid var(--border);
  border-radius: var(--radius-md); cursor: pointer; padding: 0;
}
.nav-toggle .bars { display: grid; gap: 4px; }
.nav-toggle .bars i { width: 16px; height: 2px; background: currentColor; border-radius: 1px; }

/* ── Signed-in user menu ──────────────────────────────────────────────────── */
.user-menu { position: relative; }
.user-chip {
  display: flex; align-items: center; gap: var(--space-2); padding: 4px 10px 4px 4px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-pill);
  cursor: pointer; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--fg);
  transition: border-color var(--motion-fast) var(--ease-standard);
}
.user-chip:hover { border-color: color-mix(in oklab, var(--fg), transparent 70%); }
.user-avatar { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex: none; }
.user-avatar-fallback {
  display: grid; place-items: center; background: var(--accent); color: var(--accent-on);
  font-weight: 600; font-size: 13px;
}
.user-name { max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-dropdown {
  position: absolute; top: calc(100% + 8px); right: 0; min-width: 200px; z-index: 60;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--elev-raised); padding: var(--space-2); display: grid; gap: 4px;
}
.user-dropdown[hidden] { display: none; }
.user-email { font-size: var(--text-xs); color: var(--muted); padding: 8px 10px; word-break: break-all; }
.user-logout {
  text-align: left; background: none; border: 0; border-radius: var(--radius-md); cursor: pointer;
  padding: 8px 10px; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--fg);
}
.user-logout:hover { background: var(--border-soft); }

/* ── Auth modal (Google Sign-In popup) ────────────────────────────────────── */
.auth-overlay {
  position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center;
  padding: 16px; background: color-mix(in oklab, var(--fg), transparent 45%); backdrop-filter: blur(3px);
}
.auth-overlay[hidden] { display: none; }
.auth-card {
  position: relative; width: min(400px, 100%); max-height: calc(100vh - 32px); overflow: auto;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--elev-raised); padding: 40px 36px 30px; text-align: center;
}
@media (max-width: 480px) { .auth-card { padding: 32px 22px 24px; } }
.auth-x {
  position: absolute; top: 12px; right: 12px; width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: var(--border-soft); color: var(--muted); font-size: 16px; line-height: 1; cursor: pointer;
  display: grid; place-items: center; transition: background var(--motion-fast) var(--ease-standard);
}
.auth-x:hover { background: var(--border); color: var(--fg); }
.auth-mark { width: 40px; height: 40px; font-size: 18px; margin: 0 auto var(--space-4); }
.auth-card h2 { font-size: var(--text-xl); letter-spacing: var(--tracking-display); margin-bottom: var(--space-2); }
.auth-fine { font-size: var(--text-sm); color: var(--fg-2); line-height: var(--leading-body); margin-bottom: var(--space-6); }
.auth-gsi { display: flex; justify-content: center; min-height: 44px; }
.auth-note { font-size: var(--text-sm); color: var(--muted); background: var(--surface-warm); border-radius: var(--radius-md); padding: 12px; }
.auth-note code { font-family: ui-monospace, monospace; font-size: 12px; }
.auth-err { margin-top: var(--space-4); font-size: var(--text-sm); font-weight: 500; color: var(--danger); }
.auth-legal { margin-top: var(--space-5); font-size: var(--text-xs); color: var(--muted); }

/* ── Get-started auth gate ("step zero") ─────────────────────────────────────
   The signed-out screen shown in place of the wizard (templates/partials/
   get-started-auth.php). Reuses the page palette: a centered card like the sign-
   in popup, the same GSI button, and a disabled magic-link row (coming soon). */
/* Full-width flex item of .ob-main; margin-block:auto centers it vertically the
   same way .ob-wizard does. The card itself centers horizontally via
   margin-inline:auto (block centering — .ob-step.show forces display:block, so a
   flex/justify-content approach here would lose on specificity). */
.gs-auth { width: 100%; margin-block: auto; }
.gs-auth-card {
  width: min(420px, 100%); margin-inline: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--elev-raised);
  padding: 40px 36px 30px; text-align: center;
}
@media (max-width: 480px) { .gs-auth-card { padding: 32px 22px 24px; } }
.gs-auth-mark { width: 40px; height: 40px; font-size: 18px; margin: 0 auto var(--space-4); }
.gs-auth-card .eyebrow { justify-content: center; }
.gs-auth-card h1 { font-size: var(--text-xl); letter-spacing: var(--tracking-display); margin: var(--space-3) 0 var(--space-2); }
.gs-auth-card .ob-pane-lead { margin: 0 auto var(--space-6); max-width: 42ch; }
.gs-auth-err {
  margin: 0 0 var(--space-5); font-size: var(--text-sm); font-weight: 500; color: var(--danger);
  background: color-mix(in oklab, var(--danger), transparent 90%);
  border-radius: var(--radius-md); padding: 10px 12px;
}
.gs-auth-google { margin-bottom: var(--space-5); }
/* "or" divider */
.gs-or { display: flex; align-items: center; gap: var(--space-3); color: var(--muted);
  font-family: var(--font-mono); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.08em; }
.gs-or::before, .gs-or::after { content: ""; flex: 1; height: 1px; background: var(--border); }
/* magic-link row (disabled until email delivery ships) */
.gs-magic { margin-top: var(--space-5); display: flex; flex-direction: column; gap: var(--space-3); }
.gs-email {
  width: 100%; padding: 11px 14px; border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--surface); color: var(--fg); font-size: var(--text-base);
}
.gs-email::placeholder { color: var(--muted); }
.gs-magic[aria-describedby] .gs-email:disabled,
.gs-magic .btn:disabled { opacity: 0.55; cursor: not-allowed; }
.gs-soon { margin: 0; font-size: var(--text-xs); color: var(--muted); }
.gs-auth-fine { margin-top: var(--space-6); font-size: var(--text-sm); color: var(--fg-2); }
.gs-auth-legal { margin-top: var(--space-3); font-size: var(--text-xs); color: var(--muted); }
.gs-auth-legal a { color: var(--fg-2); text-decoration: underline; }
.gs-auth-legal a:hover { color: var(--fg); }

/* ── Sections ───────────────────────────────────────────────────────────── */
section { padding: var(--section-y-desktop) 0; }
.band { background: var(--surface); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.section-head { max-width: 640px; margin-bottom: var(--space-8); }
.section-head h2 { font-size: var(--text-2xl); margin: var(--space-3) 0 var(--space-3); letter-spacing: var(--tracking-display); }
.section-head p { color: var(--fg-2); font-size: var(--text-lg); }

/* ── Hero ───────────────────────────────────────────────────────────────── */
.hero { padding-top: 64px; padding-bottom: 64px; }
.hero-grid { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: var(--space-12); align-items: center; }
.hero h1 { font-size: clamp(30px, 4.4vw, 48px); letter-spacing: var(--tracking-display); }
.hero h1 .hl { background: linear-gradient(transparent 62%, var(--accent) 62%); padding: 0 2px; }
.hero .lead { margin-top: var(--space-5); max-width: 46ch; }
.hero-cta { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-8); }
.hero-cta .btn { flex: 0 0 auto; }
.hero-cta-note { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); margin-top: var(--space-4); }

.trust { display: flex; flex-wrap: wrap; gap: var(--space-5); margin: var(--space-6) 0 0; padding: 0; list-style: none; }
.trust li { display: inline-flex; align-items: center; gap: 7px; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--fg-2); }
.trust .ck { color: var(--success); }

/* ── Live analyze panel (hero right) ────────────────────────────────────── */
.panel {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--elev-raised); overflow: hidden;
}
.panel-bar { height: 4px; background: var(--accent); }
.panel-top { display: flex; align-items: center; gap: var(--space-2); padding: 12px 16px; border-bottom: 1px solid var(--border-soft); font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); }
.panel-top .dots { display: flex; gap: 5px; }
.panel-top .dots i { width: 9px; height: 9px; border-radius: 50%; background: var(--border); display: inline-block; }
.panel-top .u { margin-left: auto; color: var(--fg-2); }
.panel-body { padding: var(--space-5); }

.panel-idle .eyebrow { margin-bottom: 14px; }
.panel-idle p { font-size: var(--text-sm); color: var(--fg-2); margin-bottom: 16px; }

.scan-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.scan-list li { display: flex; align-items: center; gap: 10px; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--muted); }
/* A circle, so a pending item reads as an empty ○ and a landed one as a filled
   ✓ — the checkmark is in the markup but transparent until .done. */
.scan-list li .box {
  width: 18px; height: 18px; border-radius: 50%; border: 1px solid var(--border);
  display: grid; place-items: center; font-size: 11px; color: transparent; flex: none;
  transition: background var(--motion-base) var(--ease-standard), border-color var(--motion-base) var(--ease-standard), color var(--motion-base) var(--ease-standard);
}
.scan-list li.done { color: var(--fg-2); }
.scan-list li.done .box { background: var(--cat-product-bg); border-color: var(--cat-product-bg); color: var(--success); }
/* The item in flight is marked by weight and a darker ring. It deliberately
   gets no spinner of its own: with one already turning in the step's head, a
   second animation off to the right read as two separate processes running. */
.scan-list li.active { color: var(--fg); font-weight: 500; }
.scan-list li.active .box { border-color: var(--fg); }
@keyframes spin { to { transform: rotate(360deg); } }

.found-head { display: flex; align-items: center; gap: var(--space-3); }
.found-head .pill { margin-left: auto; }
.found-logo { width: 44px; height: 44px; border-radius: var(--radius-md); background: var(--surface-warm); border: 1px solid var(--border); display: grid; place-items: center; font-family: var(--font-display); font-weight: 600; font-size: var(--text-lg); }
.found-name { font-size: var(--text-lg); }
.found-head .dom { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); }
.found-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: var(--space-4) 0; }
.found-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; margin-top: var(--space-4); }
.found-metrics div { background: var(--surface); padding: 12px 14px; }
.found-metrics .n { font-family: var(--font-mono); font-size: var(--text-xl); font-weight: 600; }
.found-metrics .l { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); }
.found-cta { display: flex; gap: var(--space-2); margin-top: var(--space-5); }
.found-cta .btn { flex: 1; }

/* ── Loop / how it works ────────────────────────────────────────────────── */
.loop-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; list-style: none; margin: 0; padding: 0; }
.loop-step { background: var(--surface); padding: var(--space-6); position: relative; }
.loop-step .idx { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); }
.loop-step .ico { width: 40px; height: 40px; border-radius: var(--radius-md); background: var(--surface-warm); border: 1px solid color-mix(in oklab, var(--accent), var(--border) 55%); display: grid; place-items: center; margin: var(--space-4) 0 var(--space-4); }
.loop-step h3 { font-size: var(--text-lg); margin-bottom: var(--space-2); }
.loop-step p { font-size: var(--text-sm); color: var(--fg-2); }
.loop-step:not(:last-child)::after { content: "→"; position: absolute; right: -11px; top: calc(var(--space-6) + 52px); font-family: var(--font-mono); color: var(--muted); background: var(--surface); width: 22px; height: 22px; display: grid; place-items: center; z-index: 2; }

/* ── Extension bridge ───────────────────────────────────────────────────── */
.ext { background: var(--fg); color: #e6edf3; }
.ext-grid { display: grid; grid-template-columns: 1fr 0.9fr; gap: var(--space-12); align-items: center; }
.ext .eyebrow { color: #9ca3af; }
.ext h2 { color: #f9fafb; font-size: var(--text-2xl); letter-spacing: var(--tracking-display); margin: var(--space-3) 0 var(--space-4); }
.ext p.lead { color: #c9d1d9; }
.ext-steps { list-style: none; margin: var(--space-6) 0 0; padding: 0; display: grid; gap: var(--space-3); }
.ext-steps li { display: flex; gap: var(--space-3); align-items: flex-start; font-size: var(--text-sm); color: #c9d1d9; }
.ext-steps li .n { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--accent); border: 1px solid #30363d; border-radius: var(--radius-sm); width: 22px; height: 22px; display: grid; place-items: center; flex: none; }
.ext-card { background: #161b22; border: 1px solid #30363d; border-radius: var(--radius-lg); overflow: hidden; }
.ext-card .cbar { height: 4px; background: var(--accent); }
.ext-card .chd { display: flex; align-items: center; gap: 10px; padding: 14px 18px; border-bottom: 1px solid #21262d; }
.ext-card .chd .fav { width: 30px; height: 30px; border-radius: var(--radius-sm); background: #21262d; display: grid; place-items: center; font-family: var(--font-display); font-weight: 600; font-size: var(--text-xs); color: #e6edf3; }
.ext-card .chd .nm { font-family: var(--font-display); font-weight: 500; color: #f0f6fc; font-size: var(--text-base); }
.ext-card .chd .supp { margin-left: auto; }
.ext-card .cbd { padding: 18px; }
.ext-fields { display: grid; gap: 10px; margin-bottom: var(--space-5); }
.ext-fields .fr { display: flex; align-items: center; gap: 10px; font-family: var(--font-mono); font-size: var(--text-xs); }
.ext-fields .fr .lbl { color: #8b949e; width: 130px; flex: none; }
.ext-fields .fr .val { color: #e6edf3; background: #21262d; border: 1px solid #30363d; border-radius: var(--radius-sm); padding: 5px 9px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ext-fields .fr.filled .val { border-color: color-mix(in oklab, var(--success), transparent 40%); }
.ext-fields .fr .ck { color: var(--success); }
.ext-count { font-family: var(--font-mono); font-size: var(--text-xs); color: #8b949e; margin-bottom: var(--space-4); }
.ext-count b { color: #f0f6fc; }

/* ── Stats band ─────────────────────────────────────────────────────────── */
.stats { background: var(--surface-warm); border-top: 1px solid color-mix(in oklab, var(--accent), var(--border) 40%); border-bottom: 1px solid color-mix(in oklab, var(--accent), var(--border) 40%); }
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-8); }
.stat .n { font-family: var(--font-mono); font-size: var(--text-3xl); font-weight: 600; letter-spacing: -0.02em; }
.stat .l { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--fg-2); margin-top: var(--space-1); }

/* ── Final CTA ──────────────────────────────────────────────────────────── */
.cta-final { text-align: center; }
.cta-final .inner { max-width: 640px; margin: 0 auto; }
.cta-final .eyebrow { justify-content: center; }
.cta-final h2 { font-size: clamp(26px, 3.4vw, 40px); letter-spacing: var(--tracking-display); }
.cta-final .lead { margin: var(--space-4) auto 0; }
.cta-actions { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); margin-top: var(--space-8); }
.cta-actions .hint { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); margin: 0; }
.cta-final .trust { justify-content: center; }

/* ── Footer ─────────────────────────────────────────────────────────────── */
footer.ft { background: var(--surface); border-top: 1px solid var(--border); padding: var(--space-12) 0 var(--space-8); }
.ft-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr; gap: var(--space-8); }
.ft-brand p { color: var(--muted); font-size: var(--text-sm); margin-top: var(--space-3); max-width: 30ch; }
.ft-col h4 { font-family: var(--font-mono); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 500; margin-bottom: var(--space-4); }
.ft-col a { display: block; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--fg-2); padding: 4px 0; }
.ft-col a:hover { color: var(--fg); }
.ft-bottom { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); margin-top: var(--space-12); padding-top: var(--space-6); border-top: 1px solid var(--border-soft); font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); flex-wrap: wrap; }

/* ── Responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 1024px) {
  .hero-grid { grid-template-columns: 1fr; gap: var(--space-8); }
  .hero-panel { max-width: 520px; }
  .ext-grid { grid-template-columns: 1fr; gap: var(--space-8); }
  .loop-step:not(:last-child)::after { display: none; }
}
@media (max-width: 860px) {
  section { padding: var(--section-y-tablet) 0; }
  .nav-toggle { display: inline-grid; }
  .nav-menu { display: none; }
  .nav.nav-open .nav-menu {
    display: flex; flex-direction: column; align-items: stretch;
    position: absolute; top: 60px; left: 0; right: 0; margin: 0;
    max-height: calc(100dvh - 60px); overflow-y: auto;
    background: var(--surface); border-bottom: 1px solid var(--border);
    box-shadow: var(--elev-raised); padding: var(--space-4) var(--container-gutter-tablet) var(--space-5);
    gap: var(--space-2);
  }
  .nav.nav-open .nav-links { flex-direction: column; align-items: stretch; gap: 0; }
  .nav.nav-open .nav-links a { padding: 12px 0; width: 100%; border-bottom: 1px solid var(--border-soft); }
  .nav.nav-open .nav-actions {
    flex-direction: column; align-items: stretch; gap: var(--space-3);
    margin-left: 0; margin-top: var(--space-3);
  }
  .nav.nav-open .nav-actions .signin { padding: 10px 0; }
  .nav.nav-open .nav-actions .btn { width: 100%; }
  .loop-grid { grid-template-columns: 1fr 1fr; }
  .stats-grid { grid-template-columns: 1fr 1fr; gap: var(--space-6); }
  .ft-grid { grid-template-columns: 1fr 1fr; gap: var(--space-6); }
}
@media (max-width: 560px) {
  .container { padding: 0 var(--container-gutter-phone); }
  section { padding: var(--section-y-phone) 0; }
  .hero { padding-top: 40px; padding-bottom: 40px; }
  .section-head h2 { font-size: var(--text-xl); }
  .section-head p, .hero .lead, .ext p.lead, .cta-final .lead { font-size: var(--text-base); }
  .hero-cta { flex-direction: column; }
  .hero-cta .btn { width: 100%; }
  .loop-grid { grid-template-columns: 1fr; }
  .stats-grid { grid-template-columns: 1fr 1fr; gap: var(--space-5); }
  .stat .n { font-size: var(--text-2xl); }
  .ft-grid { grid-template-columns: 1fr; }
  .ft-bottom { flex-direction: column; align-items: flex-start; gap: var(--space-2); }
  .found-metrics { grid-template-columns: 1fr 1fr; }
  .found-cta { flex-direction: column; }
  .ext-fields .fr { flex-direction: column; align-items: flex-start; gap: 4px; }
  .ext-fields .fr .lbl { width: auto; }
  .ext-fields .fr .val { width: 100%; }
}

@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }

/* ── Getting-started onboarding wizard (/get-started) ────────────────────── */
/* A focused, single-column funnel. justify-content:center + margin-block:auto
   centers the card when it fits and top-aligns it (scrollable, never clipped)
   when a step is taller than the viewport — paired with min-height (not
   height:100%) so a tall Step 3 can grow and scroll on small screens. */
/* Percentage-sized radials (relative to the viewport-tall .ob-body) let the
   brand glow wash across the whole screen instead of clustering at the top: a
   broad accent halo up top plus a softer counter-tint anchored bottom-right, so
   the funnel reads on a full-bleed gradient rather than a flat slab. */
.ob-body {
  --topbar-h: 60px;
  display: flex; flex-direction: column; min-height: 100dvh;
  background:
    radial-gradient(120% 90% at 50% -10%, color-mix(in oklab, var(--accent), transparent 86%), transparent 60%),
    radial-gradient(90% 70% at 100% 110%, color-mix(in oklab, var(--accent), transparent 90%), transparent 65%),
    var(--bg);
  background-attachment: fixed;
}
.ob-topbar { position: sticky; top: 0; z-index: 50; min-height: var(--topbar-h); display: flex; align-items: center; gap: var(--space-4); padding: 0 clamp(16px, 4vw, 24px); }
/* The minimal funnel keeps a bare bar; once the editor is revealed the bar gains
   a blurred backdrop + border so the completeness meter and Save stay legible. */
.ob-topbar.editing { background: color-mix(in oklab, var(--bg), transparent 12%); backdrop-filter: saturate(180%) blur(8px); border-bottom: 1px solid var(--border); }
.ob-crumb { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ob-crumb b { color: var(--fg-2); font-weight: 500; }
.ob-top-right { margin-left: auto; display: flex; align-items: center; gap: var(--space-3); }
.ob-mini-pct { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); display: inline-flex; align-items: center; gap: 8px; }
.ob-mini-pct .bar { width: 64px; height: 6px; border-radius: var(--radius-pill); background: var(--border-soft); overflow: hidden; border: 1px solid var(--border); }
.ob-mini-pct .bar i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--accent-hover), var(--accent)); transition: width var(--motion-base) var(--ease-standard); }
.ob-mini-pct b { color: var(--fg); }
/* Give the bare (non-editing) bar the brand on the left, nothing else. */
.ob-topbar:not(.editing) .brand { margin-right: auto; }

.ob-main { flex: 1; display: flex; justify-content: center; padding: clamp(20px, 5vh, 48px) clamp(16px, 4vw, 24px) 56px; }
.ob-wizard { width: 100%; max-width: 560px; margin-block: auto; }
/* The page-level `section` rule gives homepage bands 80px of block padding. A
   <section> in this funnel is a wizard step, a flow pane or a review card, not
   a band — without this reset each one carries 80px of phantom space. */
.ob-main section { padding: 0; }

/* Step panels — no card. These screens share the flow panes' plain
   eyebrow → heading → lead rhythm so the funnel reads as one surface from
   step 01 through the review screens. Their heading picks up .ob-pane h1
   sizing below; the lead uses .ob-pane-lead. */
.ob-step { display: none; }
.ob-step.show { display: block; }
@media (prefers-reduced-motion: no-preference) {
  .ob-step.show { animation: obFade var(--motion-base) var(--ease-standard); }
}
@keyframes obFade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* URL step */
.ob-field-label { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 500; color: var(--fg); display: block; margin: var(--space-6) 0 var(--space-2); }

/* The funnel's one input. The `https://` prefix is a real affix — tinted and
   divided off — so it reads as part of the field's chrome rather than as
   placeholder text the visitor is expected to type around. Stretch-aligned
   children make the divider run the field's full height, and the whole row
   (never the bare input) owns the hover / focus / error treatment, so there is
   only ever one box on screen. */
.url-row {
  display: flex; align-items: stretch; overflow: hidden;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: border-color var(--motion-fast) var(--ease-standard), box-shadow var(--motion-fast) var(--ease-standard);
}
.url-row:hover { border-color: #d1d5db; }
.url-row:focus-within { border-color: var(--fg); box-shadow: var(--focus-ring); }
/* Set alongside aria-invalid on the input when validation fails. */
.url-row.err { border-color: var(--danger); }
.url-row.err:focus-within { box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.12); }
.url-row .lead-ico {
  display: grid; place-items: center; padding: 0 12px;
  background: var(--border-soft); border-right: 1px solid var(--border);
  color: var(--muted); font-size: var(--text-sm); white-space: nowrap; user-select: none;
}
.url-row input {
  flex: 1; min-width: 0; border: 0; background: transparent; color: var(--fg);
  /* 16px on purpose, not --text-base (15px): iOS zooms the viewport when a
     focused field's text is under 16px, which would jerk the funnel's first
     interaction sideways. */
  font-size: 16px; padding: 13px 14px;
}
.url-row input:focus { outline: none; }
.url-row input::placeholder { color: #9ca3af; }

/* The hint under the field doubles as the validation message — .err turns it
   red, and the reserved height keeps the CTA from jumping when it appears. */
.ob-step .hint { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); margin-top: var(--space-3); min-height: 16px; }
.ob-step .hint.err { color: var(--danger); }
.ob-actions { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-6); }
.ob-actions .btn-primary, .ob-actions .btn-accent { flex: 1 1 auto; }
.ob-actions .btn-ghost { flex: 0 0 auto; }
/* The line under the URL step's CTA — it takes the separated, quiet slot the
   reassurance chips used to occupy, as a single sentence instead of a row. */
.ob-note { margin-top: var(--space-6); padding-top: var(--space-5); border-top: 1px solid var(--border-soft); font-size: var(--text-sm); color: var(--fg-2); }

/* Step 3a — analyzing */
.ob-analyze-head { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-5); }
.ob-analyze-h2 { margin: 6px 0 0; }
.ob-spinner { width: 26px; height: 26px; border: 3px solid var(--border); border-top-color: var(--fg); border-radius: 50%; animation: spin .7s linear infinite; flex: none; }
.ob-scan { margin-top: var(--space-5); gap: 12px; }
.ob-scan-count { color: var(--fg-2); font-variant-numeric: tabular-nums; }
.ob-analyze-note { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); margin-top: var(--space-6); }

/* ── Profile ready — full-width editable profile editor ─────────────────── */
/* min-width:0 matters: as a flex item of .ob-main this would otherwise size to
   its widest content — the step bar — and push the whole page sideways instead
   of letting that bar scroll inside itself on a phone. */
.ob-editor { width: 100%; max-width: 720px; min-width: 0; margin: 0 auto; }
@media (prefers-reduced-motion: no-preference) { .ob-editor:not([hidden]) { animation: obFade var(--motion-base) var(--ease-standard); } }
/* ── The profile flow (one screen per decision) ─────────────────────────────
   Replaces the single-page editor's sidebar + stacked groups. A narrow column
   for focus, and one pane visible at a time. */
.ob-flow { max-width: 680px; }

/* Identity anchor — whose profile this is, on every screen. */
.ob-ident {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  padding-bottom: var(--space-5); margin-bottom: var(--space-6); border-bottom: 1px solid var(--border-soft);
}
.ob-ident .logo { width: 40px; height: 40px; border-radius: var(--radius-md); background: var(--surface-warm); border: 1px solid var(--border); display: grid; place-items: center; font-family: var(--font-display); font-weight: 700; font-size: var(--text-base); flex: none; }
.ob-ident .logo.has-img { background: none; border: none; padding: 0; overflow: hidden; }
.ob-ident .logo img { display: block; }
.ob-ident .logo.is-fallback { color: var(--muted); }
.ob-ident .logo .wsico { display: grid; place-items: center; width: 100%; height: 100%; }
.ob-ident .logo .wsico svg { width: 60%; height: 60%; }
.ob-ident .who { min-width: 0; }
.ob-ident h3 { font-size: var(--text-base); }
.ob-ident .dom { font-size: 11px; color: var(--muted); word-break: break-all; }
.ob-ident .tagline { font-size: var(--text-sm); color: var(--muted); margin-left: auto; max-width: 38ch; text-align: right; }
@media (max-width: 700px) { .ob-ident .tagline { margin-left: 0; text-align: left; flex-basis: 100%; } }

/* Panes */
.ob-pane { display: none; }
.ob-pane.show { display: grid; gap: var(--space-5); }
.ob-pane h1, .ob-step h1 { font-size: clamp(24px, 5.5vw, 30px); margin: var(--space-3) 0 0; letter-spacing: var(--tracking-display); }
.ob-pane-lead { color: var(--fg-2); font-size: var(--text-base); max-width: 62ch; margin: 0; }
/* The panes lay eyebrow → h1 → lead out on a grid, so their gaps come free.
   The URL / analyzing / error steps are block-flow, so restore the same
   rhythm with explicit margins. */
.ob-step .ob-pane-lead { margin-top: var(--space-4); }

/* A subsection inside a screen (Pricing, Company, Brand assets). */
.ob-sub { display: grid; gap: var(--space-5); padding-top: var(--space-5); border-top: 1px solid var(--border-soft); }
.ob-sub > h2 { font-size: var(--text-lg); margin: 0; }
.ob-sub > h2 + .ob-sub-lead { margin-top: calc(-1 * var(--space-4)); }
.ob-sub-lead { color: var(--fg-2); font-size: var(--text-sm); margin: 0; }

/* Looks good / Back — ordinary buttons at their own width, flush left with the
   fields above them. A full-bleed confirm read as the end of the funnel; it
   isn't, it's one of six screens. */
.ob-pane-actions { display: flex; gap: var(--space-3); align-items: center; justify-content: flex-start; margin-top: var(--space-6); padding-top: var(--space-5); border-top: 1px solid var(--border-soft); }
.ob-pane-actions .btn { flex: 0 0 auto; }

/* Radio list — the pricing question, where the answer changes the form. */
.ob-radios { display: grid; gap: 8px; }
.ob-radio {
  display: flex; align-items: flex-start; gap: 10px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-md); padding: 11px 13px;
  transition: border-color var(--motion-fast), background var(--motion-fast);
}
.ob-radio:hover { border-color: #d1d5db; }
/* Selected reads like the primary CTA: dark fill, white text — the dot and
   labels invert so they stay legible on it. */
.ob-radio.on { border-color: var(--fg); background: var(--fg); }
.ob-radio input { position: absolute; opacity: 0; width: 0; height: 0; }
.ob-radio .rb { width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--border); flex: none; margin-top: 2px; display: grid; place-items: center; }
.ob-radio.on .rb { border-color: #fff; }
.ob-radio.on .rb::after { content: ""; width: 8px; height: 8px; border-radius: 50%; background: #fff; }
.ob-radio input:focus-visible + .rb { box-shadow: var(--focus-ring); }
.ob-radio .rt { display: grid; gap: 1px; }
.ob-radio .rt b { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 500; color: var(--fg); }
.ob-radio .rt i { font-style: normal; font-size: var(--text-xs); color: var(--muted); }
.ob-radio.on .rt b { color: #fff; }
.ob-radio.on .rt i { color: rgba(255, 255, 255, 0.7); }
.ob-price-note { font-size: var(--text-sm); color: var(--fg-2); background: var(--surface-warm); border: 1px solid color-mix(in oklab, var(--accent), var(--border) 40%); border-radius: var(--radius-md); padding: 11px 13px; margin: 0; }

/* Checkbox chips — "also useful for". */
.ob-checks { display: flex; flex-wrap: wrap; gap: 8px; }
.ob-check {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-pill); padding: 7px 13px 7px 10px;
  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--fg-2);
  transition: border-color var(--motion-fast), background var(--motion-fast), color var(--motion-fast);
}
.ob-check:hover { border-color: #d1d5db; }
/* Selected reads like the primary CTA: dark fill, white text — the tick box
   inverts to a white square with a dark check so it stays legible. */
.ob-check.on { border-color: var(--fg); background: var(--fg); color: #fff; }
.ob-check input { position: absolute; opacity: 0; width: 0; height: 0; }
.ob-check .cb { width: 14px; height: 14px; border-radius: var(--radius-sm); border: 1px solid var(--border); flex: none; display: grid; place-items: center; font-size: 10px; color: transparent; }
.ob-check.on .cb { background: #fff; border-color: #fff; }
.ob-check.on .cb::after { content: "✓"; color: var(--fg); }
.ob-check input:focus-visible + .cb { box-shadow: var(--focus-ring); }

/* Review screen */
.ob-review { display: grid; gap: var(--space-5); }
.ob-rev-group { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); overflow: hidden; }
.ob-rev-group > header { display: flex; align-items: center; gap: var(--space-3); padding: 12px var(--space-5); border-bottom: 1px solid var(--border-soft); }
.ob-rev-group > header h2 { font-size: var(--text-base); margin: 0; }
.ob-rev-group > header .btn-mini { margin-left: auto; }
.ob-rev-row { display: flex; gap: var(--space-4); padding: 10px var(--space-5); border-top: 1px solid var(--border-soft); font-size: var(--text-sm); }
.ob-rev-row:first-of-type { border-top: 0; }
.ob-rev-row .k { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); flex: 0 0 34%; padding-top: 2px; }
.ob-rev-row .v { color: var(--fg); min-width: 0; overflow-wrap: anywhere; white-space: pre-wrap; }
.ob-rev-row.missing .v { color: var(--muted); font-style: italic; }
.ob-ready-cta { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-3); }


.ob-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-5); }

.ob-field { display: grid; gap: 6px; min-width: 0; }
.ob-field .ftop { display: flex; align-items: center; gap: var(--space-2); }
.ob-field label { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 500; color: var(--fg); }
.ob-field .fstat { margin-left: auto; font-family: var(--font-mono); font-size: 11px; color: var(--muted); white-space: nowrap; }
.ob-field.is-filled .fstat { color: var(--success); }
.inp, .ta, .sel { width: 100%; font-family: var(--font-body); font-size: var(--text-base); color: var(--fg); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 10px 12px; transition: border-color var(--motion-fast), box-shadow var(--motion-fast); }
.inp.mono, .ta.mono { font-family: var(--font-mono); font-size: var(--text-sm); }
.inp:focus, .ta:focus, .sel:focus { outline: none; border-color: var(--fg); box-shadow: var(--focus-ring); }
.inp::placeholder, .ta::placeholder { color: #9ca3af; }
.ta { resize: vertical; min-height: 84px; line-height: 1.6; }
/* The description fields grow with their text (see .ta-grow in the funnel JS),
   so the scrollbar is dead weight and only makes the box look full. */
.ta-grow { overflow-y: hidden; }
/* The main description is prose, not a field: enough room to see a couple of
   paragraphs at once, and measure/leading tuned for reading them. */
.ta-lg { min-height: 220px; line-height: 1.7; padding: 14px 16px; }
.sel { appearance: none; -webkit-appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%); background-position: calc(100% - 18px) 51%, calc(100% - 13px) 51%; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; padding-right: 36px; cursor: pointer; }
.ob-field .help { font-size: var(--text-xs); color: var(--muted); }
.ob-field .prefix-row { display: flex; align-items: stretch; border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; transition: border-color var(--motion-fast), box-shadow var(--motion-fast); }
.ob-field .prefix-row:focus-within { border-color: var(--fg); box-shadow: var(--focus-ring); }
.ob-field .prefix-row .pre { display: grid; place-items: center; padding: 0 10px; background: var(--border-soft); border-right: 1px solid var(--border); font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); white-space: nowrap; }
.ob-field .prefix-row input { border: 0; box-shadow: none; border-radius: 0; }

/* Social-link fields carry a small brand glyph next to the label and validate
   the pasted URL live (see the funnel JS). An invalid URL turns the border and
   the field status red; the status slot doubles as the error message. */
.link-ico { display: inline-grid; place-items: center; width: 15px; height: 15px; color: var(--muted); flex: none; }
.link-ico svg { width: 100%; height: 100%; display: block; }
.ob-field.is-invalid .inp { border-color: var(--danger); box-shadow: none; }
.ob-field.is-invalid .inp:focus { box-shadow: 0 0 0 3px rgba(220, 38, 38, .16); }
.ob-field.is-invalid .fstat { color: var(--danger); }
.ob-grid-2 > .ob-span-2 { grid-column: 1 / -1; }

/* ── Multi-select combobox (reusable) ────────────────────────────────────────
   A search field that collects several options as pills. The chosen values are
   mirrored into a hidden <input> so the surrounding form reads them like any
   other field; the wrapping .ob-field's data-state drives completeness. Written
   standalone (no category specifics) so it drops in wherever a bounded
   multi-pick is needed — wired up by createMultiCombobox() in the funnel JS. */
.combobox { position: relative; }
.combo-control {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  min-height: 44px; padding: 6px 8px 6px 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md);
  cursor: text; transition: border-color var(--motion-fast), box-shadow var(--motion-fast);
}
.combobox.open .combo-control,
.combo-control:focus-within { border-color: var(--fg); box-shadow: var(--focus-ring); }
.combo-search-ico { display: inline-flex; color: var(--muted); flex: none; }
.combobox.has-chips .combo-search-ico { display: none; }
.combo-input {
  flex: 1 1 90px; min-width: 90px; border: 0; outline: none; background: transparent;
  font-family: var(--font-body); font-size: var(--text-base); color: var(--fg); padding: 4px 2px;
}
.combo-input::placeholder { color: #9ca3af; }
.combo-caret {
  flex: none; margin-left: auto; display: grid; place-items: center; width: 24px; height: 24px;
  border: 0; background: transparent; color: var(--muted); cursor: pointer;
  transition: transform var(--motion-fast) var(--ease-standard);
}
.combobox.open .combo-caret { transform: rotate(180deg); }
.combo-caret svg { display: block; }

/* A chosen value — a solid dark pill with an inline remove. */
.combo-chip {
  display: inline-flex; align-items: center; gap: 4px; flex: none; max-width: 100%;
  background: var(--fg); color: #fff; border-radius: var(--radius-pill);
  padding: 4px 4px 4px 12px; font-size: var(--text-sm); line-height: 1.3;
}
.combo-chip-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.combo-chip-x {
  flex: none; width: 18px; height: 18px; display: grid; place-items: center; border: 0; border-radius: 50%;
  background: transparent; color: rgba(255, 255, 255, 0.65); font-size: 15px; line-height: 1; cursor: pointer;
  transition: background var(--motion-fast), color var(--motion-fast);
}
.combo-chip-x:hover { background: rgba(255, 255, 255, 0.18); color: #fff; }

/* Dropdown of options. */
.combo-menu {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 20;
  max-height: 264px; overflow-y: auto; padding: 6px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md);
  box-shadow: var(--elev-raised);
}
.combo-opt {
  display: flex; align-items: center; gap: 12px; padding: 9px 10px; border-radius: var(--radius-sm);
  cursor: pointer; font-size: var(--text-base); color: var(--fg);
}
.combo-opt:hover, .combo-opt.active { background: var(--border-soft); }
.combo-opt .combo-box {
  width: 18px; height: 18px; border-radius: var(--radius-sm); border: 1.5px solid var(--border); flex: none;
  display: grid; place-items: center; color: transparent; transition: background var(--motion-fast), border-color var(--motion-fast);
}
.combo-opt.on .combo-box { background: var(--fg); border-color: var(--fg); }
.combo-opt.on .combo-box::after { content: "✓"; color: #fff; font-size: 12px; }
.combo-opt.disabled { opacity: 0.4; cursor: not-allowed; }
.combo-opt.disabled:hover { background: transparent; }
.combo-empty { padding: 12px 10px; font-size: var(--text-sm); color: var(--muted); }
.combo-count { color: var(--muted); white-space: nowrap; }

/* ── Brand assets: logo, screenshots, demo video ─────────────────────────
   The only step that takes files. Each asset is a bordered card — a preview on
   the left, its controls in the middle, and (for the logo) a recommendation
   aside on the right. Screenshots are a gallery whose last cell is always the
   "add more" invitation, so new shots stack ahead of it. */
.ob-brand { gap: var(--space-4); }
.ob-asset { display: grid; gap: var(--space-3); }

/* Card shell shared by the logo and demo-video assets. */
.asset-card {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--space-4); align-items: start;
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface); padding: var(--space-4);
}
.ob-asset.over .asset-card,
.ob-asset.over .shot-gallery { border-color: var(--fg); box-shadow: var(--focus-ring); }

/* Preview slot — square for the logo, 16:9 for the video poster. */
.asset-media {
  position: relative; width: 104px; height: 104px; flex: none;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--border-soft); display: grid; place-items: center; overflow: hidden;
}
.asset-media.has-media { background: var(--surface); }
.asset-media img { width: 100%; height: 100%; object-fit: contain; }
.asset-media-empty { color: var(--fg-2); opacity: 0.65; }
.asset-media-empty svg { width: 30px; height: 30px; }
.asset-media-video { width: 200px; height: 116px; }
.asset-media-video img { padding: 0; object-fit: cover; }

/* Product logo — a plain row (no card chrome) so it sits in line with the rest
   of the flow. The preview reveals a dashed "Upload" drop zone on hover or when
   a file is dragged over it; there's no delete affordance, since a logo can only
   ever be replaced, never removed. */
.logo-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-4); align-items: center;
}
.logo-shell { position: relative; width: 104px; height: 104px; flex: none; }
.logo-shell .asset-media { width: 100%; height: 100%; }
.logo-info { min-width: 0; display: grid; gap: 6px; align-content: center; }
.logo-dropzone {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  border: 1.5px dashed var(--border); border-radius: var(--radius-md);
  background: color-mix(in oklab, var(--surface), transparent 12%);
  color: var(--fg-2); font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600;
  cursor: pointer; opacity: 0; pointer-events: none; transition: opacity var(--motion-fast);
}
.logo-dropzone svg { width: 22px; height: 22px; }
.logo-shell:hover .logo-dropzone,
.ob-logo.over .logo-dropzone { opacity: 1; pointer-events: auto; }

/* Busy: a spinner rides the preview while an upload is in flight. */
.ob-asset.is-busy .asset-media::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 22px; height: 22px; border-radius: 50%;
  border: 2px solid rgba(13, 17, 23, 0.15); border-top-color: var(--fg);
  animation: spin .7s linear infinite;
}

/* Play glyph over the video poster (and its empty state). */
.play-badge {
  position: absolute; inset: 0; margin: auto; width: 40px; height: 40px;
  border-radius: 50%; background: rgba(13, 17, 23, 0.62); color: #fff;
  display: grid; place-items: center; pointer-events: none;
}
.play-badge svg { width: 18px; height: 18px; margin-left: 2px; }
.asset-media:not(.has-media) .play-badge { background: var(--fg); opacity: 0.85; }

.asset-main { min-width: 0; display: grid; gap: 8px; align-content: start; }
.asset-head { display: flex; align-items: center; gap: 8px; }
.asset-title { font-size: var(--text-lg); font-weight: 600; color: var(--fg); }
.asset-desc { margin: 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }
.asset-detected {
  display: inline-flex; align-items: center; gap: 6px; margin: 0;
  color: var(--success); font-size: var(--text-sm); font-weight: 500;
}
.asset-detected svg { width: 15px; height: 15px; }

/* Status badges on each asset head. */
.badge {
  font-family: var(--font-mono); font-size: 11px; font-weight: 600; line-height: 1;
  letter-spacing: 0.01em; padding: 4px 9px; border-radius: var(--radius-pill); flex: none;
}
.badge-req { background: #dcfce7; color: #15803d; }
.badge-rec { background: #fef3c7; color: #b45309; }
.badge-opt { background: var(--border-soft); color: var(--muted); border: 1px solid var(--border); }

.asset-cta { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px; }
.btn-asset {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600;
  padding: 8px 14px; min-height: 38px; border-radius: var(--radius-md);
  border: 1px solid var(--border); background: var(--surface); color: var(--fg);
  cursor: pointer; transition: background var(--motion-fast), border-color var(--motion-fast);
}
.btn-asset svg { width: 15px; height: 15px; }
.btn-asset:hover { background: var(--border-soft); border-color: #d1d5db; }
.btn-asset.ghost { border-color: transparent; background: none; color: var(--muted); }
.btn-asset.ghost.danger:hover { color: var(--danger); background: none; }

.asset-link { min-width: 0; }
.asset-note {
  width: 150px; flex: none; align-self: start;
  padding-left: var(--space-4); border-left: 1px solid var(--border-soft);
  color: var(--muted); font-size: var(--text-xs); line-height: 1.5;
}

/* Demo-video URL field with a leading link glyph. */
.asset-input { position: relative; display: flex; align-items: center; }
.asset-input-ico { position: absolute; left: 12px; color: var(--fg-2); display: grid; place-items: center; pointer-events: none; }
.asset-input-ico svg { width: 16px; height: 16px; }
.asset-input .inp { padding-left: 38px; }
.asset-hint { margin: 0; color: var(--muted); font-family: var(--font-mono); font-size: var(--text-xs); }

.dz-err { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--danger); }

/* Live URL of the stored logo. */
.dz-link { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.dz-link .u { font-size: 11px; color: var(--link); text-decoration: underline; text-underline-offset: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dz-link .btn-mini { min-height: 26px; padding: 3px 9px; flex: none; }

/* Screenshot gallery — four across, wrapping, the first tile is the cover. The
   dashed "add more" cell is always the last child, so shots stack ahead of it. */
.shot-gallery { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-3); }
.shot { position: relative; margin: 0; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--border-soft); overflow: hidden; }
.shot img { width: 100%; height: auto; aspect-ratio: 16 / 10; object-fit: contain; display: block; }
/* The image is a lightbox trigger (Featherlight): it stays in flow so the tile
   keeps the image's height, shows a zoom cursor, and reveals a magnifier on
   hover/focus so it reads as clickable, like a product image viewer. */
.shot .shot-zoom { display: block; cursor: zoom-in; }
.shot .shot-zoom picture { display: block; }
.shot .shot-zoom-ico {
  position: absolute; right: 6px; bottom: 40px; width: 26px; height: 26px; display: grid; place-items: center;
  border-radius: 50%; background: rgba(13, 17, 23, 0.62); color: #fff; opacity: 0; transition: opacity 0.12s ease; pointer-events: none;
}
.shot:hover .shot-zoom-ico, .shot .shot-zoom:focus-visible ~ .shot-zoom-ico, .shot .shot-zoom:focus-visible .shot-zoom-ico { opacity: 1; }
.shot .shot-zoom-ico svg { width: 15px; height: 15px; }
.shot figcaption { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); font-family: var(--font-mono); font-size: 11px; color: var(--muted); padding: 4px 4px 4px 8px; background: var(--surface); border-top: 1px solid var(--border-soft); }
.shot figcaption a { color: var(--link); }
/* Dragging: the tile lifts, and a rule marks the edge it would land against. */
.shot[draggable="true"] { cursor: grab; }
.shot.dragging { opacity: 0.45; cursor: grabbing; }
.shot.drop-before::before, .shot.drop-after::before {
  content: ""; position: absolute; top: 0; bottom: 0; width: 3px; z-index: 1;
  border-radius: 2px; background: var(--fg);
}
/* Inside the tile, since it clips its overflow to keep the image rounded. */
.shot.drop-before::before { left: 0; }
.shot.drop-after::before { right: 0; }
/* Position chip top-left; the first tile also carries a COVER pill above the
   caption bar (whose height is fixed so the pill clears it). */
.shot .num {
  position: absolute; top: 6px; left: 6px; width: 20px; height: 20px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.92); border: 1px solid var(--border); color: var(--fg);
  font-family: var(--font-mono); font-size: 10px; font-weight: 700; display: grid; place-items: center;
}
.shot .cover { position: absolute; left: 6px; bottom: 38px; font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; background: var(--fg); color: #fff; border-radius: var(--radius-sm); padding: 2px 6px; }
/* Auto-captured pill: a shot the funnel grabbed off the site, not uploaded. Sits
   to the right of the position chip, clear of the remove (top-right) button. */
.shot .auto { position: absolute; top: 8px; left: 32px; font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; background: var(--accent); color: var(--accent-on); border-radius: var(--radius-sm); padding: 2px 6px; }
.shot .x { position: absolute; top: 6px; right: 6px; width: 24px; height: 24px; border-radius: 50%; border: 1px solid var(--border); background: rgba(255, 255, 255, 0.92); color: var(--fg-2); font-size: 11px; line-height: 1; cursor: pointer; display: grid; place-items: center; }
.shot .x:hover { background: var(--danger); border-color: var(--danger); color: #fff; }
.shot.is-pending { display: grid; place-items: center; aspect-ratio: 16 / 10; }
.shot.is-pending figcaption { position: absolute; bottom: 0; left: 0; right: 0; justify-content: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* First cell spans the full width — the cover screenshot, or the upload hero
   while the gallery is empty. Every other shot flows into the row beneath it. */
.shot-hero { grid-column: 1 / -1; }
.shot.shot-hero img { aspect-ratio: 16 / 8; }
.shot-add.shot-hero {
  aspect-ratio: auto; min-height: 190px; gap: 8px;
}
.shot-hero-ico { color: var(--fg-2); }
.shot-hero-ico svg { width: 40px; height: 40px; }
.shot-add.shot-hero .shot-add-t { font-size: var(--text-base); }

/* The trailing invitation cell — matches a real tile's footprint. It stretches
   to the height of the screenshot tile beside it (image + caption bar), rather
   than a bare 16/10 image box, so the two line up; the min-height is only the
   floor for when it starts a fresh grid row on its own. */
.shot-add {
  display: grid; place-content: center; justify-items: center; gap: 3px;
  align-self: stretch; min-height: 96px; text-align: center; padding: var(--space-2);
  border: 1px dashed var(--border); border-radius: var(--radius-md);
  background: var(--surface); color: var(--fg-2); cursor: pointer;
  transition: border-color var(--motion-fast), background var(--motion-fast), color var(--motion-fast);
}
.shot-add:hover { border-color: #d1d5db; background: var(--border-soft); color: var(--fg); }
.shot-add:focus-visible { outline: none; border-color: var(--fg); box-shadow: var(--focus-ring); }
.shot-add-ico { font-size: 22px; line-height: 1; font-weight: 300; }
.shot-add-t { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600; }
.shot-add-s { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); }

/* Constraints footer under the gallery — the empty hero states them itself. */
.shot-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; margin: 2px 0 0; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); }
#ob-brand-shots[data-state="empty"] .shot-foot { display: none; }

/* ── Screenshot lightbox (Featherlight) ─────────────────────────────────────
   A chromeless viewer: the image sits directly on the dimmed backdrop — no
   white padded frame, no corner ✕ (click the backdrop or press Esc to close).
   The gallery add-on injects the prev/next controls but we don't load its
   stylesheet, so paging is styled here too: a full-height click zone pinned to
   each side of the screen with a large chevron centered in it. */
.featherlight .featherlight-content {
  padding: 0; border: 0; background: transparent; border-radius: 0;
  max-width: 92vw; max-height: 92vh; overflow: visible;
}
.featherlight .featherlight-content .featherlight-image {
  display: block; width: auto; max-width: 92vw; max-height: 92vh;
  border-radius: var(--radius-md); box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
}
/* No close control in the corner. */
.featherlight .featherlight-close-icon { display: none; }
/* Side navigation: only the circular chevron is clickable — a compact button
   pinned to each screen edge, vertically centered. Everything else around the
   image stays backdrop, so a click off the image closes (paging happens on the
   arrows alone, never by clicking beside the picture). */
.featherlight .featherlight-previous,
.featherlight .featherlight-next {
  position: fixed; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 52px; height: 52px; margin: 0; padding: 0;
  display: grid; place-items: center; cursor: pointer; color: #fff;
  border-radius: 50%; background: rgba(13, 17, 23, 0.55);
  font-size: 30px; line-height: 1;
  opacity: 0.85; transition: opacity 0.12s ease, background 0.12s ease;
}
.featherlight .featherlight-previous { left: clamp(8px, 3vw, 36px); }
.featherlight .featherlight-next { right: clamp(8px, 3vw, 36px); }
.featherlight .featherlight-previous > span,
.featherlight .featherlight-next > span { display: block; }
.featherlight .featherlight-previous:hover,
.featherlight .featherlight-next:hover { opacity: 1; background: rgba(13, 17, 23, 0.82); }

@media (max-width: 640px) {
  .asset-card { grid-template-columns: auto minmax(0, 1fr); }
  .asset-note { grid-column: 1 / -1; width: auto; border-left: 0; border-top: 1px solid var(--border-soft); padding: var(--space-3) 0 0; }
  .shot-gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .asset-media-video { width: 140px; height: 82px; }
}

.btn-mini { font-family: var(--font-mono); font-size: var(--text-xs); padding: 6px 12px; border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--surface); color: var(--fg-2); cursor: pointer; min-height: 32px; white-space: nowrap; }
.btn-mini:hover { background: var(--border-soft); }

/* Plans editor — one row per pricing tier (name / amount / period / per-unit) */
.ob-plans { display: grid; gap: var(--space-3); }
.ob-plans:empty { display: none; }
.ob-plan { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 0.9fr) minmax(0, 1fr) minmax(0, 1fr) auto; gap: var(--space-2); align-items: center; }
.ob-plan .inp, .ob-plan .sel { padding: 8px 10px; font-size: var(--text-sm); }
.ob-plan .sel { padding-right: 30px; }
/* Remove plan reads like the primary CTA: dark fill, white glyph. */
.ob-plan-del { min-height: 36px; padding: 6px 10px; background: var(--fg); border-color: var(--fg); color: #fff; }
.ob-plan-del:hover { background: var(--fg-2); border-color: var(--fg-2); color: #fff; }
#f-plan-add { justify-self: start; }
@media (max-width: 560px) { .ob-plan { grid-template-columns: 1fr 1fr; } .ob-plan .ob-plan-name { grid-column: 1 / -1; } .ob-plan-del { grid-column: 2; justify-self: end; } }


/* Step 3 — error */
.ob-error { text-align: center; }
.ob-error-mark { width: 52px; height: 52px; border-radius: 50%; background: #fee2e2; color: var(--danger); display: grid; place-items: center; margin: 0 auto var(--space-4); font-family: var(--font-display); font-weight: 700; font-size: var(--text-2xl); }
.ob-error .ob-actions { justify-content: center; }

/* ── Editor responsive ──────────────────────────────────────────────────── */
/* Below the sidebar breakpoint the summary collapses (completeness now lives in
   the sticky topbar) and the section nav becomes a horizontal scroller. */
@media (max-width: 860px) {
}
@media (max-width: 620px) { .ob-crumb { display: none; } }
@media (max-width: 560px) { .ob-grid-2 { grid-template-columns: 1fr; } }
/* On a phone the editing bar carries the brand and the meter, which together
   don't fit: drop the meter's bar, then its "complete" label, then the
   wordmark. */
@media (max-width: 420px) { .ob-mini-pct .bar { display: none; } }
@media (max-width: 480px) {
  .ob-topbar.editing .brand span:not(.mark) { display: none; }
  .ob-topbar.editing .ob-mini-pct { font-size: 0; gap: 0; }
  .ob-topbar.editing .ob-mini-pct b { font-size: var(--text-xs); }
}

/* Narrow phones — stack the wizard's Continue action full-width and keep the
   analyze header readable when the spinner + heading can't share a line. */
@media (max-width: 420px) {
  .ob-actions { flex-direction: column; align-items: stretch; }
  .ob-actions .btn { width: 100%; }
  .ob-analyze-head { align-items: flex-start; }
}

