/* ---- Fonts (self-hosted, latin subset) ---- */
/* IBM Plex Sans latin is served by Google as a single variable file that
   covers 400-700, so all four weights point to it. */
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/ibm-plex-sans-var.b2c9031d9fd6.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-400.79936b18df9f.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-500.b1c8a895f5fd.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-600.5a2ce7798732.woff2") format("woff2");
}

/* ---- Light theme tokens (:root) ---- */
:root {
  color-scheme: light;
  --bg: #efece6;
  --surface: #fbfaf7;
  --surface2: #f3f0ea;
  --border: #d8d2c8;
  /* 3:1 against the input fill (--surface2), WCAG 1.4.11. */
  --border-input: #8c8579;
  --line: #e9e5de;
  --text: #1c1a17;
  --dim: #5d5951;
  --faint: #6d6760;
  --brand: #1667cf;
  --brandBg: #e6effd;
  --amber: #8f6410;
  --amberBg: color-mix(in srgb, var(--amber) 8%, var(--surface));
  --amberBorder: color-mix(in srgb, var(--amber) 26%, var(--surface));
  --btn: #0f6fe0;
  --btnInk: #ffffff;
  --rowHi: #eef4ff;
  --shadow: 0 1px 2px rgba(50, 40, 25, 0.06), 0 6px 18px rgba(50, 40, 25, 0.07);
  /* Ink used for scroll shades and other inward shadows painted over a surface. */
  --shadow-ink: rgba(50, 40, 25, 0.12);

  /* Meaning hues: green = paid/active/matched, red = failed/disputed,
     orange = refunded. Amber above stays pending/attention. Other ended states
     (canceled, expired) stay grey. --info (violet) is the informational hue on the
     landing and buyer pages only; in the dashboard violet means a paid plan, so
     informational marks there take the brand blue. */
  --ok: #1b7a3e;
  --okBg: color-mix(in srgb, var(--ok) 9%, var(--surface));
  --bad: #b8281f;
  --badBg: color-mix(in srgb, var(--bad) 9%, var(--surface));
  --orange: #c2520c;
  --orangeBg: color-mix(in srgb, var(--orange) 9%, var(--surface));
  --info: #6a3fc2;
  --infoBg: color-mix(in srgb, var(--info) 8%, var(--surface));
  /* Violet means "on a paid plan" and nothing else: plan tags, locked zones. */
  --plan: #6a3fc2;
  --planBg: color-mix(in srgb, var(--plan) 8%, transparent);
  /* Select chevron, stroked in --faint (4.9:1 on the input fill). */
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5l3 3 3-3' fill='none' stroke='%236d6760' stroke-width='1.5'/%3E%3C/svg%3E");
  /* Padlock, used as a CSS mask so it takes the plan colour. */
  --icon-lock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.8'%3E%3Crect x='3' y='7' width='10' height='7' rx='1.5'/%3E%3Cpath d='M5.5 7V5a2.5 2.5 0 0 1 5 0v2'/%3E%3C/svg%3E");

  /* Brand-mark hues for the two AI tiles (green, terracotta). */
  --chart-a: #0fa47f;
  --chart-b: #d97757;

  --glass-bg: rgba(241, 246, 255, 0.55);
  --glass-blur: blur(18px) saturate(180%);
  --glass-shadow:
    0 14px 40px rgba(20, 40, 80, 0.14),
    0 3px 10px rgba(20, 40, 80, 0.07),
    inset 0 1px 1px rgba(255, 255, 255, 0.8),
    inset 0 -10px 26px rgba(255, 255, 255, 0.14);
  --glass-rim: linear-gradient(140deg,
    rgba(255, 255, 255, 0.98) 0%, rgba(255, 255, 255, 0.35) 20%,
    rgba(255, 255, 255, 0) 40%, rgba(255, 255, 255, 0) 60%,
    rgba(255, 255, 255, 0.55) 100%);
  --glass-hi: rgba(255, 255, 255, 0.5);
  --atmos:
    radial-gradient(1100px 720px at 10% -10%, rgba(90, 169, 255, 0.34), transparent 60%),
    radial-gradient(900px 620px at 94% 6%, rgba(96, 148, 240, 0.2), transparent 58%),
    radial-gradient(1000px 820px at 72% 110%, rgba(70, 175, 225, 0.16), transparent 60%);
  --sheen: rgba(255, 255, 255, 0.5);

  --font-sans: "IBM Plex Sans", system-ui, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, monospace;

  /* ---- Shape + motion tokens ---- */
  --radius-pill: 999px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-control: 10px;
  --radius-lg: 14px;
  --radius-card: 18px;
  --icon-size-sm: 15px;
  --icon-size-md: 18px;
  --transition-fast: 120ms ease;

  /* ---- Spacing scale ---- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;

  /* ---- Type scale ---- */
  --fs-2xs: 10px;
  --fs-xs: 11px;
  --fs-sm: 12px;
  --fs-base: 13px;
  --fs-md: 14px;
  --fs-lg: 16px;
  --fs-xl: 23px;
  --fs-2xl: 32px;
}

/* ---- Dark theme tokens ---- */
html[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0f131c;
  --surface: #171c28;
  --surface2: #202736;
  --border: #2b3446;
  --border-input: #66738c;
  --line: #232b3a;
  --text: #ece8e1;
  --dim: #a9aeb9;
  --faint: #8f96a3;
  --brand: #75b6f6;
  --brandBg: #1a2a45;
  --amber: #dbb35e;
  --amberBg: color-mix(in srgb, var(--amber) 9%, var(--surface));
  --amberBorder: color-mix(in srgb, var(--amber) 24%, var(--surface));
  --btn: #0f6fe0;
  --btnInk: #ffffff;
  --rowHi: #1b2436;
  --shadow:
    0 1px 2px rgba(0, 0, 0, 0.5),
    0 8px 24px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(190, 215, 255, 0.06);
  --shadow-ink: rgba(0, 0, 0, 0.45);

  --ok: #66cc8c;
  --okBg: color-mix(in srgb, var(--ok) 14%, var(--surface));
  --bad: #f8958c;
  --badBg: color-mix(in srgb, var(--bad) 10%, var(--surface));
  --orange: #f7a049;
  --orangeBg: color-mix(in srgb, var(--orange) 12%, var(--surface));
  --info: #cbb5fa;
  --infoBg: color-mix(in srgb, var(--info) 14%, var(--surface));
  --plan: #cbb5fa;
  --planBg: color-mix(in srgb, var(--plan) 10%, transparent);
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5l3 3 3-3' fill='none' stroke='%238f96a3' stroke-width='1.5'/%3E%3C/svg%3E");

  --chart-a: #3fb89a;
  --chart-b: #d4866b;

  --glass-bg: rgba(24, 34, 56, 0.55);
  --glass-blur: blur(18px) saturate(180%);
  --glass-shadow:
    0 16px 44px rgba(0, 0, 0, 0.55),
    0 3px 10px rgba(0, 0, 0, 0.4),
    inset 0 1px 1px rgba(190, 215, 255, 0.2),
    inset 0 -10px 26px rgba(120, 160, 240, 0.07);
  --glass-rim: linear-gradient(140deg,
    rgba(200, 222, 255, 0.6) 0%, rgba(200, 222, 255, 0.16) 20%,
    rgba(200, 222, 255, 0) 40%, rgba(200, 222, 255, 0) 60%,
    rgba(200, 222, 255, 0.32) 100%);
  --glass-hi: rgba(190, 215, 255, 0.16);
  --atmos:
    radial-gradient(1100px 720px at 10% -10%, rgba(50, 110, 230, 0.3), transparent 60%),
    radial-gradient(900px 620px at 94% 6%, rgba(58, 120, 220, 0.2), transparent 58%),
    radial-gradient(1000px 820px at 72% 110%, rgba(35, 135, 200, 0.16), transparent 60%);
  --sheen: rgba(150, 195, 255, 0.09);
}

/* ---- Base elements ---- */
* {
  box-sizing: border-box;
}
body {
  margin: 0;
  background: var(--atmos), var(--bg);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: 1.5;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(118deg, transparent 22%, var(--sheen) 39%, transparent 55%),
    linear-gradient(123deg, transparent 62%, var(--sheen) 73%, transparent 83%);
  -webkit-mask-image: radial-gradient(150% 130% at 50% 0%, #000 38%, transparent 100%);
  mask-image: radial-gradient(150% 130% at 50% 0%, #000 38%, transparent 100%);
}
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.35;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='grain'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23grain)' opacity='0.5'/%3E%3C/svg%3E");
}
.app,
.plain-shell,
.lp {
  position: relative;
  z-index: 1;
}
h1, h2, h3, h4 {
  letter-spacing: -0.01em;
  color: var(--text);
  margin: 0;
}
h1 {
  letter-spacing: -0.02em;
}
a {
  color: var(--text);
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}
.link {
  color: var(--brand);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Global focus ring on interactive controls. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* ---- Eyebrow / section labels ---- */
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--dim);
}
.field > label,
.field > .field-label {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--dim);
}
/* Checkbox and radio rows: the label text is the choice itself, so it keeps the
   text color; the hint under it stays on the hint tier. */
.field > label:has(input[type="checkbox"], input[type="radio"]) {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--text);
}
.field input[type="checkbox"],
.field > label > input[type="radio"] {
  accent-color: var(--brand);
  width: 15px;
  height: 15px;
  margin: 0;
}

/* Read by screen readers, not shown. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- Cards ---- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow);
  padding: 18px var(--sp-5);
}

.card-hint {
  color: var(--dim);
  font-size: var(--fs-base);
  margin: 6px 0 0;
  max-width: 68ch;
}

/* ---- KPI cards ---- */
.kpi {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 15px var(--sp-4);
}
.kpi-value {
  display: block;
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

/* ---- Buttons ---- */
.btn,
.btn-ghost,
.btn-discord,
.btn-danger,
.btn-plan {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: 600;
  padding: 7px var(--sp-3);
  border-radius: var(--radius-control);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.btn {
  background: var(--btn);
  color: var(--btnInk);
  border: 1px solid var(--btn);
}
.btn:hover {
  background: color-mix(in srgb, var(--btn) 90%, black);
  border-color: color-mix(in srgb, var(--btn) 90%, black);
}
.btn-ghost {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
}
.btn-ghost:hover {
  background: var(--surface2);
}
.btn-discord {
  background: #5865f2;
  color: var(--btnInk);
  border: 1px solid #5865f2;
}
.btn-discord:hover {
  background: #4752c4;
  border-color: #4752c4;
}
.discord-mark {
  flex: none;
}
/* Outline buttons: a destructive action, and the way to a paid plan. Both also
   work combined with .btn ("btn btn-plan"), so the hover resets the border too. */
.btn-danger,
.btn-plan {
  background: transparent;
}
.btn-danger,
.btn-danger:hover {
  color: var(--bad);
  border: 1px solid color-mix(in srgb, var(--bad) 45%, transparent);
}
.btn-danger:hover {
  background: var(--badBg);
}
.btn-plan,
.btn-plan:hover {
  color: var(--plan);
  border: 1px solid color-mix(in srgb, var(--plan) 45%, transparent);
}
.btn-plan:hover {
  background: var(--planBg);
}
.btn[disabled],
.btn-ghost[disabled],
.btn-danger[disabled],
.btn-plan[disabled],
.btn[aria-disabled="true"],
.btn-ghost[aria-disabled="true"],
.btn-danger[aria-disabled="true"],
.btn-plan[aria-disabled="true"] {
  opacity: 0.55;
  pointer-events: none;
  cursor: default;
}

/* ---- Status pills ---- */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-xs);
  font-weight: 600;
  padding: 3px var(--sp-2);
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  white-space: nowrap;
}
.pill::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background: currentColor;
  flex: none;
}
a.pill {
  text-decoration: none;
}
.deadline-past { color: var(--bad); }
.pill-ok {
  color: var(--ok);
  background: var(--okBg);
}
.pill-bad {
  color: var(--bad);
  background: var(--badBg);
}
.pill-info {
  color: var(--info);
  background: var(--infoBg);
}
.pill-amber {
  color: var(--amber);
  background: var(--amberBg);
}
.pill-orange {
  color: var(--orange);
  background: var(--orangeBg);
}
.pill-muted {
  color: var(--faint);
  background: transparent;
  border-color: var(--border);
}
.app .pill-info {
  color: var(--brand);
  background: var(--brandBg);
}

/* ---- Usage rows (plan page limit list) ---- */
.usage-list {
  list-style: none;
  margin: var(--sp-2) 0;
  padding: 0;
}
.usage-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-1) 0;
}
.usage-value {
  color: var(--faint);
  white-space: nowrap;
}

/* ---- Inputs ---- */
.input,
.select {
  background-color: var(--surface2);
  color: var(--text);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-control);
  font-family: var(--font-sans);
  font-size: 13.5px;
  padding: var(--sp-2) var(--sp-3);
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.input:not(textarea, summary, select[size], select[multiple], [type="file"]),
.select {
  height: 36px;
}
summary.input {
  min-height: 36px;
}
/* One chevron for every single-line select, whichever class it carries. */
select.input:not([size], [multiple]),
.select {
  appearance: none;
  padding-right: 32px;
  background-image: var(--chevron);
  background-repeat: no-repeat;
  background-position: right 11px center;
}
/* IDs, keys and hex values keep the code font. */
.input-mono {
  font-family: var(--font-mono);
  font-size: 12.5px;
}
.input::placeholder {
  color: var(--faint);
}
/* Focus draws one ring: the accent border plus a soft halo, so the global
   offset outline is turned off here to avoid a doubled edge. */
.input:focus,
.select:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 28%, transparent);
}
.input:focus-visible,
.select:focus-visible {
  outline: none;
}
/* A control switched off by another choice on the form (not a plan lock, which the
   locked zone below styles): flat, faint and not clickable. */
.input:disabled,
.select:disabled {
  background-color: transparent;
  border-color: var(--border);
  color: var(--faint);
  cursor: not-allowed;
}
.input::file-selector-button {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-1) 10px;
  margin-right: 10px;
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.input::file-selector-button:hover {
  background: var(--surface2);
}
/* Listbox selects (size/multiple): the .input padding otherwise half-clips the
   option row at the bottom edge. */
select.input[size],
select.input[multiple] {
  padding: var(--sp-1);
  height: auto;
}
select.input[size] option,
select.input[multiple] option {
  padding: 5px var(--sp-2);
  border-radius: var(--radius-sm);
}

/* ---- Nav dot marker (house style) ---- */
.dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  flex: none;
}
/* fill comes from the parent nav item's active state */
.nav-item .dot {
  background: transparent;
  border: 1.5px solid var(--border);
}
.nav-item.active .dot {
  background: var(--brand);
  border-color: transparent;
}

/* ---- Table panel primitives ---- */
.table-panel {
  /* Scroll-shadow stack over the surface: an inward shade appears at either
     edge only while more columns hide beyond it, so sideways scroll is
     discoverable on phones. The covers scroll with the content (local) and
     hide the static shades once that edge is fully in view. */
  background:
    linear-gradient(to right, var(--surface) 40%, transparent) left / 48px 100%,
    linear-gradient(to left, var(--surface) 40%, transparent) right / 48px 100%,
    radial-gradient(farthest-side at 0 50%, var(--shadow-ink), transparent) left / 16px 100%,
    radial-gradient(farthest-side at 100% 50%, var(--shadow-ink), transparent) right / 16px 100%,
    var(--surface);
  background-repeat: no-repeat;
  background-attachment: local, local, scroll, scroll;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow-x: auto;
  overflow-y: hidden;
}
.table-panel .row {
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line);
  transition: background var(--transition-fast);
}
.table-panel .row:hover {
  background: var(--surface2);
}
.table-panel .row-hi {
  background: var(--rowHi);
}

/* ---- Icon theme toggle (quiet ghost button) ---- */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex: none;
  padding: 0;
  color: var(--dim);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.theme-toggle:hover {
  background: var(--surface2);
}
.theme-toggle .icon-moon {
  display: none;
}
html[data-theme="dark"] .theme-toggle .icon-sun {
  display: none;
}
html[data-theme="dark"] .theme-toggle .icon-moon {
  display: inline;
}

/* ---- App shell (sidebar + main) ---- */
.app {
  display: flex;
  min-height: 100vh;
}
.sidebar {
  width: 222px;
  flex: none;
  border-right: 1px solid var(--border);
  padding: var(--sp-4) var(--sp-3);
  display: flex;
  flex-direction: column;
}
.main {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
}

/* Brand */
.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 2px var(--sp-1) 14px;
}
.brand:hover {
  text-decoration: none;
}
.brand-mark {
  width: 18px;
  height: 18px;
  background: url("../img/favicon.415e4e371a6b.svg") center / contain no-repeat;
  flex: none;
}
.brand-name {
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
}

/* Storefront switcher */
.sf-switch {
  position: relative;
  margin-bottom: var(--sp-4);
}
.sf-card {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--sp-2) 10px;
}
.sf-avatar {
  width: 26px;
  height: 26px;
  border-radius: var(--radius-sm);
  background: var(--brand);
  color: var(--btnInk);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  flex: none;
  object-fit: cover;
}
.sf-avatar-round {
  border-radius: var(--radius-pill);
}
.sf-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.sf-name {
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sf-badge {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--brand);
  background: var(--brandBg);
  border-radius: var(--radius-sm);
  padding: 1px 5px;
}
.text-center {
  text-align: center;
}
.sf-caret {
  margin-left: auto;
  color: var(--dim);
  font-size: var(--fs-2xs);
  flex: none;
}
.sf-switch select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  border: 0;
}
/* The overlay select is invisible, so its focus ring must land on the card. */
.sf-switch:focus-within .sf-card {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}
.sf-new {
  margin: -10px 0 14px;
  font-size: var(--fs-sm);
}

/* Nav */
.nav {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.nav-eyebrow {
  margin: 14px var(--sp-1) 6px;
}
.nav-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 7px var(--sp-2);
  border-radius: var(--radius-sm);
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--dim);
  transition: background var(--transition-fast);
}
.nav-item:hover {
  background: color-mix(in srgb, var(--brand) 8%, transparent);
  text-decoration: none;
}
.nav-item.active {
  color: var(--brand);
  background: var(--brandBg);
  font-weight: 600;
}

/* Sidebar footer */
.sidebar-footer {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
}
.footer-name {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.footer-sub {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--dim);
}
.footer-logout {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--dim);
  flex: none;
}
.footer-logout-btn {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font: inherit;
  color: inherit;
}
.footer-logout-btn[aria-disabled="true"] {
  opacity: 0.55;
  pointer-events: none;
}

/* Topbar */
.topbar {
  height: 62px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-3);
  padding: 0 var(--sp-6);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.topbar-search .input {
  width: 220px;
  max-width: 40vw;
}

/* Scroll area. --scroll-gap is the space between page blocks; sections stacked in
   the page cancel it (see .set), so both read the one value. */
.scroll {
  --scroll-gap: var(--sp-6);
  padding: 26px 28px 40px;
  display: flex;
  flex-direction: column;
  gap: var(--scroll-gap);
  flex: 1 1 auto;
  min-width: 0;
}

/* Plain shell (marketing / auth / no-access pages) */
.plain-shell {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--sp-5) var(--sp-6) 48px;
}
.plain-col {
  width: 100%;
  max-width: 1120px;
}
.plain-toggle {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 1;
}
.plain-shell .messages {
  width: 100%;
  max-width: 420px;
  margin: 0 auto var(--sp-4);
}
.card-narrow {
  max-width: 460px;
  margin: 12vh auto 0;
}

/* Legal pages (Terms, Privacy): narrow reading measure, plain prose */
.legal {
  max-width: 68ch;
  margin: 0 auto;
  color: var(--text);
  line-height: 1.65;
  font-size: 15px;
}
.legal-title {
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 var(--sp-1);
}
.legal-updated {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--dim);
  margin: 0 0 var(--sp-6);
}
.legal-summary {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--sp-4) var(--sp-5);
  margin: 0 0 32px;
  box-shadow: var(--shadow);
}
.legal-summary ul {
  margin: var(--sp-2) 0 0;
  padding-left: var(--sp-5);
}
.legal-summary li {
  margin: 6px 0;
}
.legal-h2 {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 32px 0 var(--sp-2);
}
.legal p {
  margin: 0 0 var(--sp-3);
}
.legal-list {
  margin: 0 0 var(--sp-3);
  padding-left: var(--sp-5);
}
.legal-list li {
  margin: 6px 0;
}
.legal a:not(.btn):not(.btn-ghost) {
  color: var(--text);
  text-decoration: underline;
}

/* "Ask AI to explain" card on legal pages (Terms, Privacy) */
.ai-explain {
  border-radius: var(--radius-card);
  margin: 0 0 32px;
}
.ai-explain-head {
  margin: 0 0 14px;
}
.ai-explain-title {
  font-size: var(--fs-lg);
  font-weight: 700;
  margin: 0 0 var(--sp-1);
}
.ai-explain-sub {
  color: var(--dim);
  font-size: var(--fs-base);
  margin: 0;
}
.ai-explain-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
.ai-explain-tile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: var(--sp-3) 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  background: var(--surface2);
  text-decoration: none;
  transition: border-color var(--transition-fast);
}
.ai-explain-tile:hover {
  border-color: var(--faint);
  text-decoration: none;
}
.ai-explain-tile-left {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.ai-explain-tile-icon {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-control);
  border: 1px solid var(--border);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.ai-explain-tile-icon svg {
  width: 20px;
  height: 20px;
  display: block;
}
.ai-explain-tile-icon-chatgpt {
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--chart-a) 10%, transparent),
    color-mix(in srgb, var(--chart-a) 20%, transparent));
}
.ai-explain-tile-icon-claude {
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--chart-b) 10%, transparent),
    color-mix(in srgb, var(--chart-b) 20%, transparent));
}
.ai-explain-tile-name {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
}
.ai-explain-tile-arrow {
  width: 16px;
  height: 16px;
  color: var(--faint);
  flex: none;
}
.ai-explain-tile:hover .ai-explain-tile-arrow {
  color: var(--text);
}

/* Quiet legal footer on the buyer-facing storefront */
.store-legal {
  display: flex;
  justify-content: center;
  gap: var(--sp-2);
  font-size: var(--fs-sm);
  margin: var(--sp-2) 0 0;
}
.store-legal a {
  color: var(--dim);
  text-decoration: none;
}
.store-legal span {
  color: var(--faint);
}

/* Messages as toasts under the topbar */
.messages {
  list-style: none;
  margin: 0 0 var(--sp-3);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.toast {
  background: var(--amberBg);
  border: 1px solid var(--amberBorder);
  border-radius: var(--radius-control);
  padding: var(--sp-2) var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--fs-base);
  text-align: center;
  color: var(--amber);
}
.toast-success {
  background: var(--okBg);
  border-color: color-mix(in srgb, var(--ok) 35%, var(--okBg));
  color: var(--ok);
}

/* ---- Page-level layout ---- */

/* Generic vertical stack for stacked cards / sections */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}
.section-head {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
}
.section-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.link-row {
  display: flex;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}
.link-row .input {
  flex: 1;
  min-width: 0;
}

/* ---- Dashboard page anatomy: page header, flat sections, save bar ---- */

/* Page header: title and one line on the left, the page's own buttons on the right. */
.dash-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: 14px;
}
.dash-head-text {
  min-width: 0;
}
.dash-head h1 {
  font-size: 20px;
  font-weight: 600;
  margin: 0;
  overflow-wrap: anywhere;
}
.dash-head p {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--dim);
}
.dash-head p:empty,
.dash-head-actions:empty {
  display: none;
}
.dash-head-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

/* Flat section: heading and one line on the left, fields on the right, a hairline
   between sections. The first section on a page (or in the form right under the
   header) drops the line. */
.set {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  gap: 16px 40px;
  padding-block: 30px;
  border-top: 1px solid var(--line);
  min-width: 0;
}
.set:first-child,
.dash-head + .set,
.dash-head + form > .set:first-of-type {
  border-top: 0;
  padding-top: 6px;
}
/* A later section that opens its own form keeps its line, whatever the form holds
   before it (a CSRF input or nothing). */
:not(.dash-head) + form > .set:first-of-type {
  border-top: 1px solid var(--line);
  padding-top: 30px;
}
/* A back link or page note under the header belongs to it, so the section after it
   is still first. */
.dash-head + :is(p:has(> .backlink), .list-note) + .set,
.dash-head + :is(p:has(> .backlink), .list-note) + form > .set:first-of-type {
  border-top: 0;
  padding-top: 6px;
}
.dash-head + :is(p:has(> .backlink), .list-note) {
  margin: 0;
}
/* Sections stacked straight in the page space themselves with their padding and
   hairline, so they cancel the page's own gap between blocks. */
.scroll > :is(.set, form) + :is(.set, form:has(> .set)) {
  margin-top: calc(-1 * var(--scroll-gap));
}
/* A form holding only hidden inputs (one that buttons elsewhere submit through
   form=, or a CSRF-only reset form) draws nothing, so it takes no gap either. */
.scroll > form:not(:has(> :not(input[type="hidden"]))) {
  display: contents;
}
.set-head {
  min-width: 0;
}
.set-head h2 {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  font-size: 15px;
  font-weight: 600;
  margin: 0;
}
.set-head p {
  margin: 3px 0 0;
  font-size: 13px;
  color: var(--dim);
}
.set-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
  align-content: start;
  max-width: 600px;
  min-width: 0;
}
/* A .form-grid inside a section body is one full-width column on the body's rhythm. */
.set-body .form-grid {
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
  margin: 0;
}
.set-body .form-grid .field-wide {
  max-width: none;
}
/* A table needs more than a form column: it takes the whole right-hand side. */
.set-body:has(> .table-panel > table) {
  max-width: none;
}
.set-body:has(> .table-panel > table) > :not(.table-panel) {
  max-width: 600px;
}
.set-body > :is(p, .linked-list, .linked-empty, .connect-tips, .usage-list) {
  margin: 0;
}
/* Price fields inside a section read as one column, like every other field. */
.set-body .price-row {
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
}
/* A walkthrough (the connect steps) needs the full width: heading on top, body below. */
.set.is-stacked {
  grid-template-columns: minmax(0, 1fr);
}
.set.is-stacked > .set-body {
  max-width: none;
}
/* A stacked section has one column, so its foot sits in it too. */
.set.is-stacked > .set-foot {
  grid-column: 1;
}
/* Wide content that takes the whole right-hand side, like a table: a raw payload
   (wide JSON) and the plan fee calculator (a little wider than a form). */
.set-body:has(> details > .raw-pre) {
  max-width: none;
}
.set-body:has(> .calc) {
  max-width: 760px;
}
/* The role-sync result box takes no room in its section until it has something to say. */
.set-body .sync-status:not(:has(*)) {
  display: none;
}
/* In the Plans section the toggle, tier cards and fee calculator follow the
   section's own spacing instead of the landing page's margins. */
.app .set-body > .plan-cycle {
  margin: 0;
  justify-self: start;
}
.app .set-body > :is(.lp-tiers, .calc) {
  margin: 0;
}
/* A read-only value with its Copy button (a new API key) fills the row. */
.form-row > .input[readonly] {
  flex: 1 1 240px;
  min-width: 0;
}
/* Text and buttons stacked in a field: no browser margins, no full-width stretch. */
.set-body .field > p:not(.field-error),
.set-body .field > div > p:not(.field-error) {
  margin: 0;
}
.set-body .field > :is(button, .btn, .btn-ghost, .btn-danger, .btn-plan) {
  align-self: flex-start;
}
/* A button placed straight in a one-column grid keeps its own width. */
:is(.set-body, .field-group:disabled) > :is(button, .btn, .btn-ghost, .btn-danger, .btn-plan, .btn-discord) {
  justify-self: start;
}
.set-foot {
  grid-column: 2;
  max-width: 600px;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--sp-2);
}
.set.is-danger h2 {
  color: var(--bad);
}
/* .option-row is the same row with a plain edge: one of a few choices, or one notice,
   each with its button. */
.danger-row,
.option-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 12px 16px;
  padding: 14px 16px;
  border: 1px solid color-mix(in srgb, var(--bad) 40%, transparent);
  border-radius: var(--radius-md);
}
.option-row {
  border-color: var(--border);
}
:is(.danger-row, .option-row) > div {
  flex: 1 1 260px;
  min-width: 0;
}
:is(.danger-row, .option-row) strong {
  font-size: 13.5px;
  font-weight: 600;
}
:is(.danger-row, .option-row) p {
  margin: 2px 0 0;
  font-size: 12.5px;
  color: var(--dim);
}
.danger-row form {
  margin: 0;
}
@media (max-width: 900px) {
  .set {
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
  }
  .set-foot {
    grid-column: 1;
  }
}

/* Save bar for form[data-unsaved-guard]: stays in view at the bottom of the form.
   ui.js adds .is-dirty to the form once something is edited, which reveals the
   message and the Discard (type="reset") button. */
.savebar {
  position: sticky;
  bottom: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  padding: 12px 0;
  background: var(--bg);
  border-top: 1px solid var(--line);
}
.savebar-msg,
.savebar [type="reset"] {
  display: none;
}
.is-dirty .savebar-msg {
  display: inline;
  margin-right: auto;
  font-size: 13px;
  font-weight: 600;
}
.is-dirty .savebar [type="reset"] {
  display: inline-flex;
}
/* Beside the section grid (240px heading column, 40px gap, 600px fields) the bar's
   message and buttons end where the fields end. */
@media (min-width: 901px) {
  .savebar {
    padding-right: max(0px, calc(100% - 880px));
  }
}
/* The page itself scrolls: keep a focused field clear of the sticky bar (61px tall,
   69px with the phone's 44px buttons, plus a margin). */
html:has(form[data-unsaved-guard] .savebar) {
  scroll-padding-bottom: 76px;
}
@media (max-width: 820px) {
  html:has(form[data-unsaved-guard] .savebar) {
    scroll-padding-bottom: 84px;
  }
}

/* ---- Plan-locked controls ----
   Shown so merchants see what a plan adds, but not usable: the fieldset is
   disabled and the server refuses the values anyway. Enabled, the fieldset is
   display: contents and leaves no trace. Disabled, it becomes a hatched zone with
   a lock note first and a lock mark on every label. */
.field-group {
  display: contents;
}
.field-group:disabled {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
  grid-column: 1 / -1;
  min-width: 0;
  margin: 0;
  padding: 14px;
  border: 1px dashed color-mix(in srgb, var(--plan) 55%, transparent);
  border-radius: 12px;
  background: repeating-linear-gradient(135deg, var(--planBg) 0 7px, transparent 7px 14px);
}
.field-group:disabled :is(.input, .select) {
  background-color: transparent;
  border-style: dashed;
  border-color: var(--border);
  color: var(--faint);
}
.field-group:disabled .field > label {
  color: var(--dim);
}
/* The lock note explains a locked zone, so field hints (upload sizes and the like)
   are left out and the zone packs tighter than an open form. Saved values stay.
   .field-hint-keep marks a line that explains what a locked card is for, which stays. */
.field-group:disabled {
  gap: 14px;
}
.field-group:disabled .field-hint:not(.field-hint-keep) {
  display: none;
}
.field-group:disabled :is(button, .btn, .btn-ghost, .btn-danger, .accent-swatch, .color-swatch):not(.btn-plan),
.field-group:disabled .input::file-selector-button {
  opacity: 0.45;
  pointer-events: none;
}
.lock-note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 10px 12px;
  border-radius: 9px;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--plan) 35%, transparent);
}
.lock-note-icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background: var(--planBg);
  border: 1px solid color-mix(in srgb, var(--plan) 30%, transparent);
}
.lock-note-text {
  flex: 1 1 220px;
  min-width: 0;
}
.lock-note-text strong {
  font-size: 13.5px;
  font-weight: 600;
}
.lock-note-text p {
  margin: 2px 0 0;
  font-size: 12.5px;
  color: var(--dim);
}
/* Plan tag: the tier name beside a locked section's heading. */
.plan-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: normal;
  white-space: nowrap;
  color: var(--plan);
  background: var(--planBg);
  border: 1px solid color-mix(in srgb, var(--plan) 35%, transparent);
  border-radius: var(--radius-pill);
  padding: 1px 8px 1px 6px;
}
/* The padlock mark: masked, so it paints in the plan colour. */
.plan-tag::before,
.lock-note-icon::before,
.field-group:disabled .field > label::before {
  content: "";
  flex: none;
  width: 11px;
  height: 11px;
  background: var(--plan);
  -webkit-mask: var(--icon-lock) center / contain no-repeat;
  mask: var(--icon-lock) center / contain no-repeat;
}
.lock-note-icon::before {
  width: 15px;
  height: 15px;
}
.field-group:disabled .field > label::before {
  display: inline-block;
  margin-right: 6px;
  vertical-align: -1px;
}
/* Checkbox labels are flex rows; their gap already spaces the mark. */
.field-group:disabled .field > label:has(input[type="checkbox"])::before {
  margin-right: 0;
}

/* ---- Dashboard overrides (.app only) ----
   The dashboard reads flat: one quiet frame per real object, no shadows or glass
   on content. Buyer, auth, legal and landing pages sit outside .app and keep
   their look. */
.app .card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.app .card::after {
  display: none;
}
/* The current plan's card keeps its edge over the flat card above. */
.app .card.lp-tier-popular {
  border-color: var(--brand);
}
.app .table-panel {
  border-radius: 12px;
  box-shadow: none;
}
.app .table-panel thead th {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  color: var(--faint);
}
.app .filter-bar {
  gap: var(--sp-2);
}
.app .tab:is(a, button):hover {
  background: none;
  color: var(--text);
}
.app .tab.active {
  color: var(--text);
  border-bottom-color: currentColor;
}
/* KPI strip: one frame, cells split by hairlines. Each cell draws its line on its
   right and bottom edge; the frame's overflow clips the ones on the outer edge.
   Full rows above a short last row still draw a full-width line under them, and
   the last cell of a short row closes it off, at any column or cell count. */
.app .kpi-grid {
  gap: 0;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
}
/* Each headline tile carries its own hue (a top edge, a faint wash, the label)
   so the four read apart at a glance. */
.app .kpi {
  --kpi-hue: var(--brand);
  background: linear-gradient(color-mix(in srgb, var(--kpi-hue) 13%, transparent), transparent 80%);
  border: 0;
  border-radius: 0;
  box-shadow: inset 0 2px 0 var(--kpi-hue), 1px 0 0 var(--line), 0 1px 0 var(--line);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.app .kpi .eyebrow {
  color: color-mix(in srgb, var(--kpi-hue) 75%, var(--text));
}
.app .kpi-customers {
  --kpi-hue: var(--info);
}
.app .kpi-subs {
  --kpi-hue: var(--ok);
}
.app .kpi-cancels {
  --kpi-hue: var(--amber);
}
.app .kpi::after {
  display: none;
}
.app .callout-danger,
.app .attention {
  margin: 0;
  padding: 10px 14px;
  border-radius: 8px;
  font-size: var(--fs-base);
}
/* An overview alert reads as one row: its label, the message, then the action. */
.app .callout-danger:has(> .callout-head) {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
}
.app .callout-danger:has(> .callout-head) > *,
.app .callout-danger:has(> .callout-head) p {
  margin: 0;
}
.app .callout-danger:has(> .callout-head) > div:not(.callout-head) {
  flex: 1 1 280px;
  min-width: 0;
}
.app .callout-danger:has(> .callout-head) p + p {
  margin-top: 2px;
}

/* List pages: tabs straight under the page header, a plain filter row, one table
   frame, then the row count and pager on one line under it. */
.tab-row.page-tabs {
  gap: 22px;
  flex-wrap: nowrap;
  overflow-x: auto;
  box-shadow: inset 0 -1px 0 var(--line);
}
.page-tabs .tab {
  padding: 8px 0 10px;
  margin: 0;
  font-size: 13.5px;
  white-space: nowrap;
}
.page-tabs .tab-count {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.app .page-tabs .tab.active .tab-count:not(.tab-count-amber) {
  color: var(--faint);
}
.app .filter-bar label {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
}
.app .filter-bar .input {
  min-width: 0;
}
/* The search box takes the spare width. Its 320px basis makes a long filter row
   (subscriptions) wrap before the date pair instead of between the two dates. */
.filter-grow {
  flex: 1 1 320px;
}
.filter-grow .input {
  flex: 1 1 auto;
}
.list-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
}
.list-foot:not(:has(*)) {
  display: none;
}
.app :is(.pager, .pager-count) {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
}
.list-note {
  max-width: 72ch;
}
/* The blocks of one list sit closer than separate page blocks. */
.scroll > :is(.page-tabs, .list-note, .filter-bar, .table-panel) + :is(.filter-bar, .table-panel, .list-foot, .list-note) {
  margin-top: calc(14px - var(--scroll-gap));
}

/* Sparkline chart cards */
.chart-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.chart-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-3);
}
.chart-value {
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin-top: 6px;
  flex-wrap: wrap;
}
.chart-delta {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
}
.delta-up {
  color: var(--ok);
}
.delta-down {
  color: var(--bad);
}
.chart-note {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--faint);
  flex: none;
}
.spark {
  width: 100%;
  height: 56px;
  display: block;
}
.spark-lg {
  height: 120px;
}
.spark-line {
  fill: none;
  stroke: var(--brand);
  stroke-width: 1.2;
  vector-effect: non-scaling-stroke;
}
.spark-fill {
  fill: var(--brandBg);
  stroke: none;
}
.chart-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-3);
}
@media (max-width: 900px) {
  .chart-grid {
    grid-template-columns: 1fr;
  }
  .kpi-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Overview date range: the preset tabs and the custom dates each draw their own
   hairline and both grow, so on one row the two lines meet as one rule under the whole
   row, and if the row wraps the tabs keep their line, so the active tab's underline
   always sits on one. The tabs sit at the bottom of the row so their underline meets
   the line. On phones the tabs take their own line and the dates follow below
   without one, in the same order as the keyboard reaches them. The first chart sits
   close under it, like a list's table under its tabs. */
.range-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 0;
}
.range-bar > .page-tabs {
  flex: 1 1 auto;
  align-items: flex-end;
}
.range-bar > .range-form {
  flex: 1 1 auto;
  justify-content: flex-end;
  margin: 0;
  padding: 0 0 6px 16px;
  box-shadow: inset 0 -1px 0 var(--line);
}
@media (max-width: 900px) {
  .range-bar > .page-tabs {
    flex-basis: 100%;
  }
  .range-bar > .range-form {
    justify-content: flex-start;
    padding: 0;
    box-shadow: none;
  }
}
.scroll > .range-bar + .chart-card {
  margin-top: calc(14px - var(--scroll-gap));
}
/* Custom date-range form beside the range tabs */
.range-form {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.input-date {
  width: auto;
  padding: 5px var(--sp-2);
  font-size: var(--fs-sm);
  cursor: pointer;
}
.range-auto .range-apply {
  display: none;
}
.range-sep {
  font-size: var(--fs-sm);
  color: var(--faint);
}

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--sp-1) 14px;
  /* Must be able to shrink next to the big chart value or it widens the page
     on phones. */
  flex: 0 1 auto;
  min-width: 0;
}
.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--faint);
}
.legend-swatch {
  width: 14px;
  height: 0;
  border-top-width: 2px;
  border-top-style: solid;
}
.legend-current {
  border-top-color: var(--brand);
}
.legend-prior {
  border-top-color: var(--faint);
  border-top-style: dashed;
}
.spark-prior {
  fill: none;
  stroke: var(--faint);
  stroke-width: 1;
  stroke-dasharray: 3 2;
  vector-effect: non-scaling-stroke;
}
.spark-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.spark-pt {
  position: absolute;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: var(--brand);
  border: 1px solid var(--surface);
  cursor: pointer;
  pointer-events: auto;
}
/* Invisible halo so the 7px dot is tappable on touch screens. */
.spark-pt::after {
  content: "";
  position: absolute;
  inset: -14px;
}
.spark-pt:hover,
.spark-pt:focus {
  width: 11px;
  height: 11px;
}
.chart-plot {
  position: relative;
}
.chart-axis {
  position: relative;
  height: 18px;
  margin-top: var(--sp-1);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--faint);
}
.axis-tick {
  position: absolute;
  top: 0;
  width: 1px;
  height: 4px;
  background: var(--border);
}
.axis-label {
  position: absolute;
  top: 6px;
  transform: translateX(-50%);
  white-space: nowrap;
}
.axis-label-start {
  transform: none;
}
.axis-label-end {
  transform: translateX(-100%);
}
.chart-tooltip {
  position: absolute;
  bottom: calc(100% + 4px);
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: var(--sp-2) 10px;
  min-width: 150px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow);
  font-size: var(--fs-sm);
  pointer-events: none;
  z-index: 5;
}
.chart-tooltip[hidden] {
  display: none;
}
.tt-date {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--dim);
}
.tt-row {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* KPI card grid */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-3);
}
.kpi .eyebrow {
  display: block;
  margin-bottom: var(--sp-2);
}
.kpi-delta,
.kpi-caption {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  margin-top: 6px;
}
.kpi-caption {
  color: var(--dim);
}
.kpi-primary .kpi-value {
  font-size: var(--fs-2xl);
}

/* Needs-attention row under the KPI grid: the label, then the items on one line */
.attention {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 18px;
  border-left: 3px solid var(--amber);
  background: var(--amberBg);
}
.attention-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) 18px;
  font-size: var(--fs-base);
}
.attention-count {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--amber);
}
/* Generic data table living inside a .table-panel */
.table-panel table {
  width: 100%;
  border-collapse: collapse;
}
.table-panel thead th {
  text-align: left;
  padding: var(--sp-2) var(--sp-4);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--dim);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.table-panel thead:has(+ tbody > tr:only-child > td.empty) {
  display: none;
}
.table-panel tbody td {
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-base);
  vertical-align: middle;
}
.table-panel tbody tr:last-child td {
  border-bottom: none;
}
.table-panel tbody tr:hover {
  background: var(--surface2);
}
.table-panel tbody tr.row-hi {
  background: var(--rowHi);
}
/* Panel toolbar: title / tabs left, actions right */
.panel-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  padding: 7px var(--sp-4);
}
.panel-title {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* Filter tab row */
.tab-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
.tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px var(--sp-2);
  margin-right: var(--sp-1);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--dim);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.tab:is(a, button):hover {
  background: var(--brandBg);
  text-decoration: none;
}
.tab.active {
  color: var(--brand);
  border-bottom-color: var(--brand);
}
.tab.active .tab-count:not(.tab-count-amber) {
  color: inherit;
}
.tab-count {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--faint);
}
.tab-count-amber {
  color: var(--amber);
  background: var(--amberBg);
  border-radius: var(--radius-sm);
  padding: 0 5px;
}
.nav-count {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: 16px;
  color: var(--amber);
  background: var(--amberBg);
  border-radius: var(--radius-pill);
  padding: 0 6px;
}

/* Two-line payment cell */
.pay-cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pay-ref {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--dim);
}
.pay-amount {
  font-size: var(--fs-md);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.cell-mono {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--dim);
  /* Unbroken tokens wrap rather than widening the column. */
  overflow-wrap: anywhere;
}
.cell-faint {
  color: var(--faint);
}
.table-panel th.num,
.table-panel td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.nowrap {
  white-space: nowrap;
}
.price-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
}

/* Avatar image + name cell (customer lists and detail heads) */
.avatar-cell {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
}
.avatar-img {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
  background: var(--surface2);
}
.avatar-img-lg {
  width: 48px;
  height: 48px;
}

/* Row action menu (ui.js opens and closes it) */
.row-menu {
  position: relative;
  display: inline-block;
}
.row-menu > summary {
  list-style: none;
  cursor: pointer;
}
.row-menu > summary::-webkit-details-marker {
  display: none;
}
.row-menu-panel {
  /* Fixed so the panel escapes the table-panel's overflow clipping; ui.js
     anchors it to the "..." button on open and closes it on scroll. */
  position: fixed;
  z-index: 40;
  min-width: 190px;
  max-width: calc(100vw - 16px);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow);
  text-align: left;
}
.row-menu-panel form {
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
.row-menu-panel .btn-ghost,
.row-menu-panel .btn-danger {
  width: 100%;
  justify-content: flex-start;
}
.row-menu-divider {
  border-top: 1px solid var(--line);
  margin: var(--sp-1) 0;
}
/* Flex row inside a table-panel (non-tabular lists) */
.row-flex {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.push-right {
  margin-left: auto;
}

/* Inline action clusters (hand-link forms) */
.form-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  align-items: center;
}
.form-row + .field {
  margin-top: 14px;
}
/* Stacked form layout (plan form, settings) */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 320px));
  gap: var(--sp-3) 18px;
  align-items: start;
  margin: 14px 0;
}
.form-grid .field-wide {
  grid-column: 1 / -1;
  max-width: 660px;
}
.field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.color-field {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}
.color-swatch {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  padding: 2px;
  border: 1px solid var(--border-input);
  border-radius: var(--radius-control);
  background: var(--surface2);
  cursor: pointer;
}
.price-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 320px));
  gap: var(--sp-3) 18px;
  align-items: start;
}
.form-grid > .price-row,
#price-rows > .price-row {
  grid-column: 1 / -1;
}
#price-rows > .price-row + .price-row {
  border-top: 1px solid var(--border);
  padding-top: 14px;
  margin-top: var(--sp-1);
}
.field-hint {
  font-size: var(--fs-sm);
  color: var(--faint);
  margin: 0;
}

/* ui.js swaps a preview that fails to load for this note. */
.img-unavailable {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 160px;
  height: 48px;
  margin-bottom: var(--sp-2);
  border: 1px dashed var(--border);
  border-radius: var(--radius-control);
  color: var(--faint);
  font-size: var(--fs-sm);
}
.form-image-preview {
  display: block;
  max-width: 160px;
  max-height: 96px;
  width: auto;
  height: auto;
  border-radius: var(--radius-control);
  border: 1px solid var(--line);
  margin-bottom: var(--sp-2);
}

/* display: block above outranks the hidden attribute ui.js sets on a broken preview. */
.form-image-preview[hidden] {
  display: none;
}

.accent-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 6px 0;
}
.accent-swatch {
  width: 22px;
  height: 22px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  cursor: pointer;
}

.field-error {
  color: var(--bad);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  margin: 0 0 6px;
}

.input[aria-invalid="true"] {
  border-color: var(--bad);
}

/* Detail pages: label and value rows with a hairline between them. Mono is only for
   IDs (dd.cell-mono), and those read at full strength, not dimmed like a table cell. */
.data-list .num {
  font-variant-numeric: tabular-nums;
}
.data-list {
  display: grid;
  grid-template-columns: minmax(120px, 190px) minmax(0, 1fr);
  margin: 0;
}
/* The label's right padding is the column gap, so the hairline runs unbroken. */
.data-list > dt {
  font-size: 12.5px;
  line-height: 20px;
  color: var(--faint);
  padding: 9px var(--sp-4) 9px 0;
  border-bottom: 1px solid var(--line);
}
.data-list > dd {
  margin: 0;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
  font-size: 13.5px;
  line-height: 20px;
  min-width: 0;
  overflow-wrap: anywhere;
}
.data-list > dd.cell-mono {
  font-size: 12.5px;
  color: var(--text);
}
.data-list > dt:last-of-type,
.data-list > dd:last-of-type {
  border-bottom: none;
}

/* Mono callout (raw API key, one-time secret) */
.callout-mono {
  background: var(--surface2);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-md);
  padding: var(--sp-3) 14px;
  font-family: var(--font-mono);
  font-size: var(--fs-base);
  color: var(--text);
  /* Long unbroken tokens (keys, URLs) break as needed; prose wraps at spaces. */
  overflow-wrap: anywhere;
}

/* Danger callout (a payment account that cannot take payments) */
.callout-danger {
  background: var(--badBg);
  border: 1px solid color-mix(in srgb, var(--bad) 30%, var(--badBg));
  border-radius: var(--radius-md);
  padding: var(--sp-3) 14px;
  font-size: var(--fs-base);
  color: var(--bad);
  margin: 0 0 var(--sp-4);
}
.callout-danger .eyebrow,
.callout-danger a:not(.btn, .btn-ghost, .btn-danger, .btn-plan, .btn-discord) {
  color: var(--bad);
}
.callout-danger a:not(.btn, .btn-ghost, .btn-danger, .btn-plan, .btn-discord) {
  font-weight: 600;
  text-decoration: underline;
}
.callout-danger form {
  display: inline;
}
.callout-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-1);
}
.callout-head .eyebrow {
  margin: 0;
}
/* Stacked dashboard alerts sit close together instead of taking the page gap. */
.alert-stack {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.alert-stack > * {
  margin: 0;
}
.callout-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.callout-dismiss {
  margin-left: auto;
  flex: none;
}
.callout-dismiss-btn {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--bad);
  text-decoration: underline;
}

/* Back link above a detail page */
.backlink {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--dim);
}

/* Raw payload block */
.raw-pre {
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--sp-3) 14px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  overflow-x: auto;
  margin: var(--sp-2) 0 0;
}
.empty {
  color: var(--faint);
  font-size: var(--fs-base);
}
/* Empty-state rows live inside tables that scroll sideways; pin the message to
   the visible edge of the panel so it never clips mid-sentence off-screen. */
.table-panel td.empty {
  position: sticky;
  left: 12px;
  display: inline-block;
  max-width: min(60ch, calc(100vw - 72px));
  white-space: normal;
  border-bottom: none;
  padding: 28px var(--sp-3);
}
.empty-title {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
}
.empty-body {
  margin: var(--sp-1) 0 0;
}
.empty-title + .btn,
.empty-body + .btn {
  margin-top: var(--sp-3);
}
.btn-sm {
  font-size: var(--fs-sm);
  padding: 5px var(--sp-3);
}

/* Filter bar (ledger) */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}
.filter-bar label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--dim);
}
.filter-bar .input {
  min-width: 32ch;
}
.pager {
  display: flex;
  gap: var(--sp-3);
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--dim);
}
.pager-count {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--dim);
  white-space: nowrap;
}

/* ---- Marketing landing page ---- */
.lp {
  min-height: 100vh;
}

/* Hero background canvas, painted by static/js/landing.js */
.lp-hero-bg {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: clamp(560px, 92vh, 860px);
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 68%, transparent);
  mask-image: linear-gradient(to bottom, #000 68%, transparent);
}
#gradient-canvas {
  display: block;
  width: 100%;
  height: 100%;
  --gradient-color-1: #e8f1ff;
  --gradient-color-2: #bcd6f8;
  --gradient-color-3: #8fbcf3;
  --gradient-color-4: #5fa2f0;
  /* Static fallback shown when WebGL/JS is unavailable or reduced motion is set;
     the shader paints over this once it boots. */
  background: linear-gradient(150deg, #e8f1ff, #bcd6f8 40%, #8fbcf3 72%, #5fa2f0);
}
html[data-theme="dark"] #gradient-canvas {
  --gradient-color-1: #0a1626;
  --gradient-color-2: #122a4d;
  --gradient-color-3: #1c4a86;
  --gradient-color-4: #2b6bc4;
  background: linear-gradient(150deg, #0a1626, #122a4d 40%, #1c4a86 72%, #2b6bc4);
}
/* Contrast scrim: keeps the left-side hero copy legible over the brightest blobs,
   fading to clear on the right so the proof card sits over the full gradient. */
.lp-hero-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    rgba(247, 250, 255, 0.72),
    rgba(247, 250, 255, 0.3) 46%,
    transparent 66%
  );
}
html[data-theme="dark"] .lp-hero-bg::after {
  background: linear-gradient(
    90deg,
    rgba(8, 12, 21, 0.82),
    rgba(8, 12, 21, 0.45) 46%,
    transparent 68%
  );
}

.lp-section {
  max-width: 1120px;
  margin: 0 auto;
  padding: 72px 32px;
  border-bottom: 1px solid var(--border);
}
.lp-center {
  text-align: center;
}
.lp-h1 {
  font-size: clamp(30px, 6vw, 46px);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin: 14px 0;
  text-wrap: balance;
}
.lp-h2 {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 6px 0 0;
}
.lp-sub {
  color: var(--dim);
  font-size: 15px;
  line-height: 1.6;
  max-width: 46ch;
  margin: 14px 0;
}
.lp-sub.lp-center {
  margin-left: auto;
  margin-right: auto;
}

/* Nav (sticky, translucent, blur backdrop) */
.lp-nav {
  position: sticky;
  top: 0;
  z-index: 20;
  border-bottom: 1px solid var(--border);
}
.lp-nav-inner {
  max-width: 1120px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 12px 32px;
}
.lp-nav .brand {
  padding: 0;
}
.lp-nav-links {
  display: flex;
  gap: 20px;
  margin-left: 12px;
}
.lp-nav-links a {
  font-size: 13px;
  color: var(--dim);
}
.lp-nav-links a:hover {
  color: var(--text);
  text-decoration: none;
}
.lp-nav-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Hero */
.lp-hero {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 40px;
  align-items: center;
  padding-top: 78px;
  padding-bottom: 78px;
}
.lp-cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 22px 0 16px;
}
.lp-btn-lg {
  font-size: 14px;
  padding: 11px 20px;
}
.lp-reassure {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--dim);
  margin: 0;
}
/* Brand marks keep their own colors, so the tiles stay white in both themes */
.lp-pay {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  list-style: none;
  padding: 0;
  margin: 18px 0 0;
}
.lp-pay li {
  display: grid;
  place-items: center;
  width: 54px;
  height: 34px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.lp-pay svg {
  width: 42px;
  height: 24px;
}

.lp-hero-card {
  padding: 16px 18px;
}
.wp-name {
  font-size: 13px;
  font-weight: 600;
}

.icon {
  width: var(--icon-size-md);
  height: var(--icon-size-md);
  display: block;
  flex: none;
}
.hero-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 600;
  padding: 8px 16px 8px 8px;
  border-radius: var(--radius-pill);
  background: var(--brandBg);
  color: var(--brand);
  margin-bottom: 20px;
}
.hero-pill-icon {
  width: 22px;
  height: 22px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.hero-pill-icon .icon {
  width: var(--icon-size-sm);
  height: var(--icon-size-sm);
}
.hero-cta-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  /* Darkened against --brand so the white label clears AA contrast in light theme. */
  background: color-mix(in srgb, var(--brand) 86%, black);
  color: var(--btnInk);
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 700;
  padding: 14px 24px;
  border-radius: var(--radius-control);
  border: none;
  cursor: pointer;
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.08);
  transition: background var(--transition-fast);
}
html[data-theme="dark"] .hero-cta-primary {
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.45);
}
.hero-cta-primary:hover {
  background: color-mix(in srgb, var(--brand) 74%, black);
}
.hero-cta-secondary {
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  color: var(--dim);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.hero-cta-secondary:hover {
  color: var(--text);
}
.hero-proof-card {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.hero-stat-label {
  font-size: 12.5px;
  color: var(--dim);
  margin: 0;
}
.hero-stat-value {
  font-size: 36px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 2px 0 0;
}
.hero-stat-value small {
  font-size: 14px;
  font-weight: 600;
  color: var(--dim);
}
.hero-divider {
  height: 1px;
  background: var(--line);
}
.hero-role-row {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--surface2);
  border-radius: var(--radius-control);
  padding: 12px 14px;
}
.hero-role-avatar {
  width: 34px;
  height: 34px;
  border-radius: var(--radius-pill);
  background: var(--brandBg);
  color: var(--brand);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.hero-role-text {
  flex: 1;
  min-width: 0;
  font-size: 13px;
}
.hero-role-text b {
  display: block;
}
.hero-role-text span {
  color: var(--dim);
  font-size: 12px;
}
@media (prefers-reduced-motion: no-preference) {
  .hero-role-row {
    animation: hero-role-in 120ms ease-out;
  }
  @keyframes hero-role-in {
    from {
      opacity: 0;
      transform: translateY(3px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }
}

/* How it works */
.lp-steps {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px 32px;
  margin-top: 28px;
}
.lp-step-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--brand);
  color: var(--brand);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
}
.lp-step-title {
  font-size: 16px;
  font-weight: 600;
  margin: 12px 0 6px;
}
.lp-step-body {
  color: var(--dim);
  font-size: 13.5px;
  line-height: 1.6;
  margin: 0;
}

/* Why section */
.lp-why {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  align-items: center;
}
.lp-bullets {
  list-style: none;
  margin: 18px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.lp-bullets li {
  /* Block flow, not flex: an inline link inside the sentence must stay inline. */
  position: relative;
  padding-left: 17px;
  font-size: 14px;
  color: var(--text);
}
.lp-bullets li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 7px;
  width: 7px;
  height: 7px;
  border-radius: var(--radius-pill);
  background: var(--brand);
}
.lp-why-visual {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.lp-chain {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
}
.lp-chain-node {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  padding: 8px 14px;
  box-shadow: var(--shadow);
}
.lp-chain-arrow {
  color: var(--brand);
  font-size: 14px;
}
.lp-ledger td {
  padding: 11px 16px;
}

/* Pricing / CTA */
.lp-pricing {
  text-align: center;
}
.lp-pricing .lp-btn-lg {
  margin-top: 10px;
}
.lp-lead {
  color: var(--text);
  font-weight: 600;
}
.lp-tiers {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
  margin: 28px 0;
  text-align: left;
}
.lp-tier {
  display: flex;
  flex-direction: column;
  padding: 20px;
}
.lp-tier .lp-bullets {
  flex: 1;
  margin: 0 0 18px;
}
.lp-tier .lp-bullets li {
  font-size: 13.5px;
}
.lp-tier .btn {
  justify-content: center;
}
.lp-tier-popular {
  border-color: var(--brand);
}
.lp-tier-name {
  font-size: 16px;
  font-weight: 600;
  margin: 0;
}
.lp-tier-price {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 6px 0 14px;
}
.lp-tier-price span:not(.price-monthly, .price-annual) {
  font-size: 13px;
  font-weight: 500;
  color: var(--dim);
}
.lp-tier-annual {
  margin: -10px 0 14px;
  font-size: 12px;
  color: var(--dim);
}
.lp-tier-soon {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--dim);
  text-align: center;
  padding: 7px 13px;
  border: 1px dashed var(--border);
  border-radius: var(--radius-control);
}

/* FAQ (details/summary accordion) */
.lp-faq-item {
  max-width: 720px;
  margin: 0 auto;
  border-bottom: 1px solid var(--border);
  transition: border-color var(--transition-fast);
}
.lp-faq-item:first-of-type {
  margin-top: 24px;
}
.lp-faq-item:hover {
  border-bottom-color: var(--text);
}
.lp-faq-item > summary {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.lp-faq-item > summary::-webkit-details-marker {
  display: none;
}
.lp-faq-item > summary::after {
  content: "+";
  color: var(--dim);
}
.lp-faq-item[open] > summary::after {
  content: "\2212";
}
.lp-faq-item > p {
  color: var(--dim);
  font-size: 14px;
  line-height: 1.6;
  margin: 0 0 14px;
}

/* Fee calculator, landing page and plan tab (rows rendered by static/js/fee-calc.js) */
.calc {
  /* The dashboard content column is flex; auto margins there shrink-wrap to the
     table's min-width and push the page sideways on phones. */
  width: 100%;
  max-width: 760px;
  margin: 24px auto 0;
}
.calc-inputs {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-bottom: 14px;
}
.calc-note {
  color: var(--dim);
  font-size: 12px;
  line-height: 1.6;
  margin: 12px 0 0;
}
.calc-ours td {
  font-weight: 600;
  color: var(--brand);
}

/* Product screenshots */
.lp-shots-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
  margin-top: 28px;
}
.lp-shot-wide {
  grid-column: 1 / -1;
}
.lp-shot {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 12px;
}
.lp-shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
}
.lp-shot figcaption {
  color: var(--dim);
  font-size: 13px;
  line-height: 1.6;
  margin-top: auto;
  padding-top: 10px;
}

/* Footer */
.lp-footer {
  max-width: 1120px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr 1fr;
  gap: 32px;
  padding: 48px 32px;
}
.lp-footer-blurb {
  color: var(--dim);
  font-size: 13px;
  line-height: 1.6;
  max-width: 34ch;
  margin: 12px 0 0;
}
.lp-footer-col {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.lp-footer-col a {
  font-size: 13px;
  color: var(--dim);
}
.lp-footer-col a:hover {
  color: var(--text);
  text-decoration: none;
}
.lp-copy {
  grid-column: 1 / -1;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--faint);
  margin: 12px 0 0;
}

@media (max-width: 1100px) {
  .lp-tiers {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 860px) {
  .lp-hero,
  .lp-why {
    grid-template-columns: 1fr;
  }
  .lp-steps,
  .lp-tiers {
    grid-template-columns: 1fr;
    gap: 20px;
  }
  .lp-footer {
    grid-template-columns: 1fr;
  }
  .lp-nav-links {
    display: none;
  }
}

/* ---- Buyer + auth surfaces ---- */

.store {
  max-width: 560px;
  margin: 0 auto;
}
.store-banner {
  display: block;
  /* Shown at the image's own ratio, never cropped: the merchant controls the
     shape of their banner. */
  width: 100%;
  height: auto;
  border-radius: var(--radius-lg);
}
.store-head {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--sp-2) 14px;
  margin: 14px 0 var(--sp-5);
}
.store-banner + .store-head {
  margin-top: 6px;
}
.store-banner + .store-head .store-logo,
.store-banner + .store-head .store-avatar {
  margin-top: -46px;
  border: 3px solid var(--bg);
}
.store-head-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.store-logo {
  width: 80px;
  height: 80px;
  border-radius: var(--radius-pill);
  object-fit: cover;
  flex: none;
}
.store-tagline {
  color: var(--dim);
  font-size: var(--fs-base);
  margin: 0;
}
.store-desc {
  color: var(--dim);
  font-size: var(--fs-md);
  line-height: 1.6;
  margin: 0 0 var(--sp-6);
}
.store-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--sp-2);
  margin-left: auto;
}
.store-link {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 5px var(--sp-3);
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.store-link:hover {
  background: var(--surface2);
}
/* Merchant accent: only applied when a validated #rrggbb hex is set inline as
   --accent on the .store root, so the buy button and link chips adopt it. */
.sf-accent .store-avatar {
  background: var(--accent);
  /* White fallback, then a luminance-picked ink (black on light accents,
     white on dark ones) where relative color syntax is supported. */
  color: var(--btnInk);
  color: lch(from var(--accent) calc((49.44 - l) * infinity) 0 0);
}
.sf-accent .plan-buy,
.sf-accent .store-cta {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--btnInk);
  color: lch(from var(--accent) calc((49.44 - l) * infinity) 0 0);
}
.sf-accent .store-link:hover {
  border-color: var(--accent);
}
.p-accent .plan-buy {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--btnInk);
  color: lch(from var(--accent) calc((49.44 - l) * infinity) 0 0);
}
.store-avatar {
  width: 80px;
  height: 80px;
  border-radius: var(--radius-pill);
  background: var(--brand);
  color: var(--btnInk);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: var(--fs-2xl);
  font-weight: 600;
  flex: none;
}
.store-title {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.02em;
}
/* The title and logo link back to the storefront page without reading as links:
   display:contents keeps the logo anchor out of the header's flex layout. */
.store-title a {
  color: inherit;
  text-decoration: none;
}
.store-head-link {
  display: contents;
}
.store-url {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--dim);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
}
.store-note {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--dim);
  text-align: center;
  margin: var(--sp-5) 0 0;
}
.store-terms {
  max-width: 560px;
  margin: var(--sp-4) auto 0;
  font-size: var(--fs-base);
  line-height: 1.6;
  color: var(--dim);
}
.store-terms summary {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  text-align: center;
}
.store-cta {
  display: flex;
  width: 100%;
  justify-content: center;
  font-size: var(--fs-md);
  padding: var(--sp-3) var(--sp-5);
  margin-bottom: var(--sp-5);
}
.store-plans {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
@media (min-width: 880px) {
  .store {
    max-width: 960px;
  }
  .store-desc,
  .store .callout-mono {
    max-width: 720px;
    margin-left: auto;
    margin-right: auto;
  }
  .store-cta {
    max-width: 560px;
    margin: 0 auto var(--sp-5);
  }
  .store-plans {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    align-items: stretch;
  }
  .store-plans .plan-card {
    flex: 1 1 260px;
    max-width: 340px;
  }
  .store-plans-list {
    flex-direction: column;
  }
  .store-plans-list .plan-card {
    max-width: 560px;
    width: 100%;
    margin-left: auto;
    margin-right: auto;
  }
}
.plan-card {
  padding: 18px var(--sp-5);
  display: flex;
  flex-direction: column;
}
.plan-image {
  display: block;
  width: calc(100% + 40px);
  height: auto;
  margin: -18px -20px 14px;
  /* Match the card's outer radius minus its 1px border so the corners meet
     without a seam. */
  border-radius: calc(var(--radius-card) - 1px) calc(var(--radius-card) - 1px) 0 0;
}
.plan-image + .plan-head {
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 2px;
}
.plan-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
}
.plan-name {
  font-size: var(--fs-lg);
  font-weight: 700;
}
.plan-price {
  display: flex;
  align-items: baseline;
  gap: var(--sp-1);
  flex: none;
  text-align: right;
}
.plan-amount {
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.02em;
}
.plan-amount-prose {
  font-size: 15px;
  font-weight: 500;
  color: var(--text);
}
.plan-suffix {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--dim);
}
.plan-desc {
  color: var(--dim);
  font-size: var(--fs-md);
  line-height: 1.6;
  margin: 10px 0 0;
}
.plan-card form {
  margin-top: var(--sp-4);
}
.plan-buy-block {
  margin-top: auto;
}
.plan-options {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}
.plan-option {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  padding: 7px 10px;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  transition: border-color var(--transition-fast);
}
/* Landing-page fields sit directly on the page ground, where the surface fill is
   only a shade off the ground and the field stops reading as a field. The same
   partial is rendered inside a dashboard card, where white would disappear, so
   this stays scoped to the landing sections. */
html:not([data-theme="dark"]) .lp-section .input {
  background: var(--surface);
}
label.plan-option {
  cursor: pointer;
}
.plan-option:has(input:checked) {
  border-color: var(--accent, var(--brand));
}
.plan-option input {
  accent-color: var(--accent, var(--brand));
}
.plan-options + .plan-buy {
  margin-top: var(--sp-4);
}
.plan-option .plan-price {
  margin-left: auto;
}
.plan-option .plan-amount {
  font-size: var(--fs-md);
  font-weight: 600;
}
.plan-option .plan-amount-prose {
  font-size: var(--fs-base);
}
/* The plan-picker popup a multi-price card's buy button opens, and the dashboard's
   own small dialogs (.modal), which want the same surface. */
.plan-dialog,
.modal {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 18px var(--sp-5);
  width: min(92vw, 400px);
}
.plan-dialog::backdrop,
.modal::backdrop {
  background: rgba(0, 0, 0, 0.55);
}
.modal .field,
.modal .form-row {
  margin-top: var(--sp-3);
}
.plan-dialog form {
  margin-top: var(--sp-3);
}
.plan-dialog .plan-buy {
  margin-top: var(--sp-4);
}
.plan-amount-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: var(--sp-3);
}
/* display: flex above outranks the hidden attribute; the plan picker hides the
   fields of every plan except the chosen one, so hidden must win here. */
.plan-amount-field[hidden] {
  display: none;
}
.plan-amount-label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--dim);
}
.plan-amount-field .input {
  width: 100%;
}
.plan-buy {
  width: 100%;
  justify-content: center;
  font-size: var(--fs-md);
  padding: 10px var(--sp-4);
}
/* Two rails: one buy button per payment option, stacked. */
.plan-rails {
  display: grid;
  gap: var(--sp-2);
}

/* Checkout result + auth: single narrow centered card */
.result,
.auth {
  max-width: 420px;
  margin: 0 auto;
}
.result-card,
.auth-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-4);
  text-align: center;
  padding: 28px var(--sp-6);
}
.result-msg {
  font-size: var(--fs-md);
  color: var(--text);
  margin: 0;
}
/* Delivered license keys inside the result card */
.result-keys {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 100%;
}
.result-card .btn-ghost {
  justify-content: center;
}
.auth-brand {
  padding: 0;
  margin-bottom: var(--sp-1);
}
.auth-heading {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
  color: var(--text);
}
.auth-providers {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
}
.auth-btn {
  width: 100%;
  justify-content: center;
  font-size: var(--fs-md);
  padding: var(--sp-3) var(--sp-5);
}
.auth-reassure {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--dim);
  margin: 0;
}
.auth-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  width: 100%;
  text-align: left;
}
.auth-links {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-3);
  width: 100%;
  font-size: var(--fs-base);
  margin: 0;
}
/* Prose variant: running text with an inline link, not a row of links. Flex would
   split the text nodes into columns and wrap the link mid-word. */
.auth-links.auth-links-text {
  display: block;
  text-align: center;
}
.auth-or {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  color: var(--dim);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
}
.auth-or::before,
.auth-or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

/* Merchant accent, extended. Every rule below is scoped to .sf-accent, so a
   storefront with no validated accent hex renders exactly as it did before. */

/* A wash of the accent over the page ground. It is a fixed layer rather than a
   background on .store because .store is a narrow centred column and the tint has
   to reach the page edges; the negative z-index keeps it under every storefront
   surface, so the fan-facing cards still paint white over it. */
.store.sf-accent::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
/* Ring around the store mark. box-shadow, not border, so the banner overlap rule's
   3px --bg border survives and the ring sits outside it. The lettermark is already
   filled with the accent, so it needs a --bg gap first or the ring cannot be seen. */
.sf-accent .store-logo {
  box-shadow: 0 0 0 2px var(--accent);
}
.sf-accent .store-avatar {
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);
}
/* Accent-coloured text sitting on the page ground. A merchant hex can be any
   lightness, so the raw accent is never used: the color-mix pulls it toward the
   text colour, and where relative colour syntax is supported the lightness is
   clamped into a readable band instead, which holds the same contrast floor
   without draining the hue. */
.sf-accent .store-title a:hover,
.sf-accent .store-url .pill {
  color: color-mix(in srgb, var(--accent) 35%, var(--text));
  color: lch(from var(--accent) min(l, 32) min(c, 70) h);
}
html[data-theme="dark"] .sf-accent .store-title a:hover,
html[data-theme="dark"] .sf-accent .store-url .pill {
  color: color-mix(in srgb, var(--accent) 35%, var(--text));
  color: lch(from var(--accent) max(l, 74) c h);
}
/* The platform pill is the only pill inside .store-url, so it is matched by
   position rather than by whichever status class it currently carries. */
.sf-accent .store-url .pill {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* ---- Dashboard Plan page: monthly/annual cycle toggle ---- */
.plan-cycle-radio {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.plan-cycle {
  display: inline-flex;
  gap: var(--sp-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 3px;
  margin-bottom: var(--sp-4);
  align-self: flex-start;
}
.plan-cycle label {
  padding: 5px 14px;
  border-radius: var(--radius-pill);
  font-size: var(--fs-base);
  cursor: pointer;
  color: var(--dim);
  transition: background var(--transition-fast);
}
.plan-cycle label:hover {
  background: var(--brandBg);
}
#plan-cycle-monthly:checked ~ .plan-cycle label[for="plan-cycle-monthly"],
#plan-cycle-annual:checked ~ .plan-cycle label[for="plan-cycle-annual"] {
  background: var(--brandBg);
  color: var(--brand);
  font-weight: 600;
}
/* The radios are visually hidden but keyboard-focusable, so the ring must land
   on the visible label (same treatment as .sf-switch:focus-within). */
#plan-cycle-monthly:focus-visible ~ .plan-cycle label[for="plan-cycle-monthly"],
#plan-cycle-annual:focus-visible ~ .plan-cycle label[for="plan-cycle-annual"] {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}
.price-annual,
.cycle-annual {
  display: none;
}
#plan-cycle-annual:checked ~ .lp-tiers .price-monthly {
  display: none;
}
#plan-cycle-annual:checked ~ .lp-tiers .price-annual {
  display: inline;
}
#plan-cycle-annual:checked ~ .lp-tiers .cycle-monthly {
  display: none;
}
#plan-cycle-annual:checked ~ .lp-tiers .cycle-annual {
  display: block;
}

/* ---- Linked (social) accounts ---- */
.linked-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin: var(--sp-3) 0;
}
.linked-account {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 10px var(--sp-3);
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
}
.linked-avatar {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-pill);
  object-fit: cover;
  flex: none;
}
.linked-badge {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, #5865f2 16%, var(--surface));
  color: #5865f2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
html[data-theme="dark"] .linked-badge {
  color: #8b96f8;
}
.linked-name {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
}
.linked-tag {
  color: var(--dim);
  font-weight: 500;
}
.linked-status {
  margin-left: auto;
}
.linked-account .push-right {
  margin-left: 0;
}
.linked-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sp-2);
  padding: var(--sp-6) var(--sp-4);
  margin: var(--sp-3) 0;
  border: 1px dashed var(--border);
  border-radius: var(--radius-control);
}
.linked-empty .card-hint {
  margin: 0;
}
.linked-empty-title {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
  margin: 0;
}

/* ---- Accessibility ---- */

/* Skip link: visually hidden until keyboard-focused. */
.skip-link {
  position: absolute;
  left: -9999px;
  z-index: 100;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  padding: var(--sp-2) 14px;
  font-size: var(--fs-base);
}
.skip-link:focus {
  left: 12px;
  top: 12px;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
  html {
    scroll-behavior: auto !important;
  }
}

/* ---- Mobile shell ---- */

.nav-toggle {
  display: none;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  color: var(--text);
  font-size: var(--fs-lg);
  line-height: 1;
  padding: var(--sp-2) var(--sp-3);
  cursor: pointer;
  flex: none;
  margin-right: auto;
}
.nav-scrim {
  display: none;
}

@media (max-width: 820px) {
  body {
    /* Mobile browsers paint fixed-attachment backgrounds per viewport, so the
       atmosphere blobs sit still while the page scrolls; let them scroll. */
    background-attachment: scroll;
  }

  /* Off-canvas sidebar */
  .sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(280px, 84vw);
    z-index: 50;
    transform: translateX(-100%);
    transition: transform var(--transition-fast);
    overflow-y: auto;
  }
  body.nav-open .sidebar {
    transform: translateX(0);
    box-shadow: 0 0 40px rgba(0, 0, 0, 0.25);
  }
  body.nav-open .nav-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 40;
    background: rgba(0, 0, 0, 0.35);
    border: none;
    padding: 0;
  }
  .nav-toggle {
    display: inline-flex;
  }
  body.nav-open {
    overflow: hidden;
  }

  .topbar {
    padding: 0 14px;
    gap: 10px;
  }
  .topbar-search .input {
    width: 120px;
    max-width: 32vw;
  }
  .topbar-search .input:focus {
    width: 55vw;
    max-width: 55vw;
  }
  .scroll {
    --scroll-gap: 14px;
    padding: 14px;
  }

  /* Comfortable tap targets */
  .btn,
  .btn-ghost,
  .btn-danger,
  .btn-plan {
    min-height: 44px;
  }
  .nav-item {
    padding: var(--sp-3) var(--sp-2);
  }

  /* 16px stops iOS Safari from zooming the page on focus. */
  .input,
  .select {
    font-size: var(--fs-lg);
  }
  .form-row .input {
    flex: 1 1 160px;
    min-width: 0;
  }

  .table-panel table {
    min-width: 560px;
  }
  /* A small table (a few short columns) fits the phone and wraps its cells; the
     first column (an email or a link) may break anywhere, the short ones never. */
  .table-panel.is-fit table {
    min-width: 0;
  }
  .table-panel.is-fit :is(td, th) {
    white-space: normal;
  }
  .table-panel.is-fit td:first-child {
    overflow-wrap: anywhere;
  }
  .lp-ledger table {
    min-width: 0;
  }

  /* Grid/flex children may not shrink below content width by default. */
  .lp-hero > *,
  .lp-why > * {
    min-width: 0;
  }

  .data-list {
    grid-template-columns: 1fr;
  }
  .data-list > dt {
    border-bottom: none;
    padding-bottom: 0;
  }
  .data-list > dd {
    padding-top: 2px;
  }

  .lp-shots-grid {
    grid-template-columns: 1fr;
  }

  .lp-section {
    padding: 44px var(--sp-5);
  }
  .lp-nav-inner {
    padding: 10px var(--sp-4);
  }
  .lp-footer {
    padding: 40px var(--sp-5);
  }
}

@media (max-width: 560px) {
  /* Landing nav: brand plus both auth buttons must fit a phone-width row, so
     drop the beta badge and tighten spacing instead of clipping the CTA. */
  .lp-nav-inner {
    gap: var(--sp-3);
  }
  .lp-nav-right {
    gap: 6px;
  }
  .lp-nav-right .btn,
  .lp-nav-right .btn-ghost {
    padding: 7px 10px;
  }
  .lp-nav .sf-badge {
    display: none;
  }
  .kpi-grid {
    grid-template-columns: 1fr;
  }
  .plan-head {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-1);
  }
  .plan-price {
    text-align: left;
  }
  .plain-shell {
    /* Clear the absolutely-positioned theme toggle so it never overlaps the
       auth card on phones. */
    padding: 60px var(--sp-4) var(--sp-6);
  }
  .filter-bar label {
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-1);
  }
  .filter-bar .select,
  .filter-bar .input {
    flex: 1 1 auto;
    min-width: 0;
  }

  .compare-stack table,
  .compare-stack thead,
  .compare-stack tbody {
    display: block;
    min-width: 0;
  }
  .compare-stack thead tr,
  .compare-stack tbody tr {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
  .compare-stack th:first-child {
    display: none;
  }
  .compare-stack tbody td:first-child {
    grid-column: 1 / -1;
    font-weight: 600;
    border-bottom: none;
    padding-bottom: 2px;
  }
}

.glass,
.kpi,
.chart-card,
.hero-proof-card,
.lp-tier {
  position: relative;
  background: var(--glass-bg);
  border: 1px solid transparent;
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
}
.glass::after,
.kpi::after,
.chart-card::after,
.hero-proof-card::after,
.lp-tier::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.2px;
  background: var(--glass-rim);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
}
.lp-tier-popular {
  border-color: var(--brand);
}

.sidebar,
.topbar {
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: inset 0 1px 0 var(--glass-hi);
}

.lp-nav {
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
}

@supports (backdrop-filter: url("#glass-distort")) or (-webkit-backdrop-filter: url("#glass-distort")) {
  .lp-nav,
  .hero-proof-card,
  .lp-tier-popular {
    -webkit-backdrop-filter: url(#glass-distort) blur(5px) saturate(1.85);
    backdrop-filter: url(#glass-distort) blur(5px) saturate(1.85);
  }
}

@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .glass,
  .kpi,
  .chart-card,
  .hero-proof-card,
  .lp-tier,
  .sidebar,
  .topbar,
  .lp-nav {
    background: var(--surface);
    border-color: var(--border);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .glass::after,
  .kpi::after,
  .chart-card::after,
  .hero-proof-card::after,
  .lp-tier::after {
    display: none;
  }
  .lp-tier-popular {
    border-color: var(--brand);
  }
  body {
    background: var(--bg);
  }
  body::before,
  body::after {
    display: none;
  }
}

/* Capability fallback: where backdrop-filter is unsupported or GPU-disabled the
   panels would otherwise be bare translucent fills over the atmosphere (and the
   sidebar/topbar lost their solid background in the glass restyle). Give them an
   opaque surface + solid rim so text stays legible without the blur. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass,
  .kpi,
  .chart-card,
  .hero-proof-card,
  .lp-tier,
  .sidebar,
  .topbar,
  .lp-nav {
    background: var(--surface);
    border-color: var(--border);
  }
  .glass::after,
  .kpi::after,
  .chart-card::after,
  .hero-proof-card::after,
  .lp-tier::after {
    display: none;
  }
  .lp-tier-popular {
    border-color: var(--brand);
  }
}

/* ---- Setup checklist (dashboard overview) ---- */
.checklist-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
}
.checklist-progress {
  color: var(--dim);
  font-size: var(--fs-base);
  margin: 0;
}
.checklist-steps {
  list-style: none;
  margin: var(--sp-3) 0;
  padding: 0;
  display: grid;
  gap: var(--sp-3);
}
.checklist-step {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
}
.checklist-step.is-current {
  border-left: 2px solid var(--brand);
  padding-left: 10px;
}
.checklist-step.is-done .checklist-title {
  color: var(--dim);
  text-decoration: line-through;
}
.checklist-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  color: var(--dim);
  font-size: var(--fs-sm);
}
.checklist-step.is-done .checklist-mark {
  border-color: var(--ok);
  color: var(--ok);
}
.checklist-body {
  min-width: 0;
}
.checklist-title {
  margin: 0;
}
.checklist-blurb {
  color: var(--dim);
  font-size: var(--fs-base);
  margin: 2px 0 6px;
}
.checklist-dismiss {
  font-size: var(--fs-base);
}

/* ---- Connect Stripe / PayPal: numbered steps, each beside a small drawing of the
   provider's screen with the thing to click outlined ---- */
.connect-lede {
  font-size: var(--fs-lg);
  margin: 0;
}
.connect-lede span {
  display: block;
  color: var(--dim);
  font-size: var(--fs-base);
}
.connected-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.connected-mark {
  display: grid;
  place-items: center;
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--ok);
  background: var(--okBg);
}
/* .field's flex display would otherwise beat the hidden attribute */
.field[hidden] {
  display: none;
}
.connect-tips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: var(--sp-3) 0 var(--sp-6);
}
.tip {
  position: relative;
}
.tip > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-sm);
  color: var(--dim);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 3px 10px 3px 4px;
  transition: border-color var(--transition-fast);
}
.tip > summary::-webkit-details-marker {
  display: none;
}
.tip > summary::before {
  content: "?";
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  font: 600 var(--fs-xs) var(--font-mono);
  background: var(--surface2);
  border: 1px solid var(--border-input);
}
.tip[open] > summary {
  border-color: var(--brand);
  color: var(--text);
}
.tip-body {
  position: absolute;
  z-index: 5;
  left: 0;
  top: calc(100% + 6px);
  width: min(340px, 80vw);
  background: var(--surface);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
  padding: 10px var(--sp-3);
  font-size: var(--fs-base);
}
.connect-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 28px;
}
.connect-step {
  display: grid;
  /* capped text column keeps each drawing beside its step on wide screens */
  grid-template-columns: 28px minmax(0, 460px) auto;
  gap: var(--sp-3) var(--sp-6);
  align-items: start;
}
.step-num {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  font: 600 var(--fs-base) var(--font-mono);
  color: var(--brand);
  background: var(--brandBg);
}
.step-body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding-top: 3px;
  min-width: 0;
}
.step-body > .input {
  width: 100%;
}
.step-do {
  font-size: 15px;
  font-weight: 600;
  margin: 0;
}
.step-help {
  color: var(--dim);
  font-size: var(--fs-base);
  margin: 0;
  max-width: 60ch;
}
.step-more > summary {
  cursor: pointer;
  font-size: var(--fs-sm);
  color: var(--brand);
}
.step-more > p {
  color: var(--dim);
  font-size: var(--fs-base);
  margin: var(--sp-1) 0 0;
  padding-left: 10px;
  border-left: 2px solid var(--line);
}
.ext-link::after {
  content: "\2197";
  font-weight: 400;
}
.key-check {
  font-size: var(--fs-sm);
  font-weight: 500;
  margin: 0;
}
.key-check.is-ok { color: var(--ok); }
.key-check.is-info { color: var(--brand); }
.key-check.is-bad { color: var(--bad); }
.key-check.is-warn { color: var(--amber); }
.env-choice {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.env-choice label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-base);
  border: 1px solid var(--border-input);
  background: var(--surface2);
  border-radius: var(--radius-pill);
  padding: 4px var(--sp-3);
  cursor: pointer;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.env-choice label:has(input:checked) {
  border-color: var(--brand);
  background: var(--brandBg);
}
.env-choice input {
  accent-color: var(--brand);
  margin: 0;
}
/* The drawings copy the provider's own light dashboard (colors sampled from it), so
   they look the same in both of our themes. Stripe is the default palette,
   .is-paypal swaps it. .shot-mark outlines the one thing to click. */
.shot {
  --shot-bg: #ffffff;
  --shot-side-bg: #ffffff;
  --shot-head-bg: transparent;
  --shot-text: #1a1b25;
  --shot-dim: #414552;
  --shot-line: #ebeef1;
  --shot-accent: #533afd;
  --shot-accent-bg: #f5f3ff;
  --shot-link: #533afd;
  --shot-icon: #545d68;
  --shot-mark: #e8590c;
  --shot-bad: #c0262d;
  color-scheme: light;
  width: 320px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: var(--sp-3);
  background: var(--shot-bg);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
  font-family: -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  font-size: var(--fs-sm);
  color: var(--shot-dim);
}
.shot.is-paypal {
  --shot-side-bg: #f5f7fa;
  --shot-head-bg: #faf8f5;
  --shot-text: #001435;
  --shot-dim: #001435;
  --shot-line: #e6e0d9;
  --shot-accent: #002991;
  --shot-accent-bg: #b0d0fb;
  --shot-link: #0070e0;
}
.shot-head,
.shot-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
}
.shot-head {
  color: var(--shot-text);
  font-weight: 700;
}
.shot-row {
  border: 1px solid var(--shot-line);
  border-radius: var(--radius-sm);
  padding: 6px var(--sp-2);
}
.shot .is-dim {
  opacity: 0.55;
}
.shot-key {
  display: block;
  font-family: Menlo, Consolas, monospace;
  color: #273951;
}
.shot-btn {
  flex: none;
  font-weight: 600;
  color: #353a44;
  background: #ffffff;
  border: 1px solid #d8dee4;
  border-radius: var(--radius-sm);
  padding: 1px var(--sp-2);
}
.shot-btn.is-primary {
  color: #ffffff;
  background: #000000;
  border-color: #000000;
  border-radius: var(--radius-pill);
  padding: 2px var(--sp-3);
}
.shot-brand {
  color: #000000;
  font-weight: 800;
  font-size: var(--fs-lg);
}
.shot-side {
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--shot-side-bg);
  border: 1px solid var(--shot-line);
  border-radius: var(--radius-sm);
  padding: 6px;
  color: var(--shot-text);
}
.shot-side > span {
  padding: 2px 6px;
}
.shot-side > .is-current {
  color: var(--shot-accent);
  background: var(--shot-accent-bg);
  border-radius: var(--radius-sm);
  font-weight: 600;
}
.shot-side > .shot-toggle {
  padding: 0;
  margin: 2px 0 4px;
}
.shot-toggle {
  display: inline-flex;
  align-self: flex-start;
  padding: 2px;
  background: #ffffff;
  border: 1px solid #adb3be;
  border-radius: var(--radius-pill);
  color: #696969;
}
.shot-toggle > span {
  padding: 1px 10px;
  border-radius: var(--radius-pill);
}
.shot-toggle > .is-on {
  color: #ffffff;
  background: #000000;
  font-weight: 700;
}
/* PayPal's app list: App name / Client ID / Secret columns */
.shot-grid {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  border: 1px solid var(--shot-line);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.shot-grid > span {
  padding: 5px 6px;
}
.shot-th {
  font-weight: 700;
  color: var(--shot-text);
  background: var(--shot-head-bg);
}
.shot-app {
  color: var(--shot-link);
  font-weight: 700;
}
.shot-cell {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--shot-text);
}
.shot-grid > .shot-cell {
  margin: 3px;
  padding: 2px 4px;
}
.shot-cell svg {
  flex: none;
  width: 13px;
  height: 13px;
  color: var(--shot-icon);
}
.shot-account {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--shot-text);
  font-weight: 600;
}
.shot-account small {
  display: block;
  font-weight: 400;
  color: var(--shot-dim);
}
.shot-account b {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: var(--radius-sm);
  background: #f4f7fa;
  border: 1px solid var(--shot-line);
  font-size: var(--fs-xs);
}
.shot-tabs {
  display: flex;
  gap: var(--sp-3);
  border-bottom: 1px solid var(--shot-line);
  color: #3c4f69;
}
.shot-tabs > span {
  padding-bottom: 3px;
}
.shot-tabs > .is-current {
  color: var(--shot-accent);
  font-weight: 600;
  border-bottom: 2px solid var(--shot-accent);
}
.shot-mark {
  outline: 2px solid var(--shot-mark);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.shot-note {
  color: var(--shot-mark);
  font-weight: 700;
  margin: 0;
}
.shot-note.is-bad {
  color: var(--shot-bad);
}
@media (max-width: 760px) {
  .connect-step {
    grid-template-columns: 28px minmax(0, 1fr);
  }
  .shot {
    grid-column: 2;
    width: 100%;
    max-width: 360px;
  }
}

/* Drag-to-reorder rows on the Products table (static/js/product-reorder.js).
   The move up/down buttons stay in the markup as the no-JS and keyboard path and
   are only hidden once the script has taken over. */
.drag-grip {
  cursor: grab;
  color: var(--faint);
  user-select: none;
}
tr.is-dragging {
  opacity: 0.5;
}
tr.is-drop-target > td {
  border-top: 2px solid var(--brand);
}
.reorder-on .move-btn {
  display: none;
}

/* Discord role picker: a scrollable list of radio rows, each showing the role's
   icon (or emoji, or a colored dot) and its name in the role color. */
.role-picker {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  max-height: 260px;
  overflow-y: auto;
  padding: 6px;
  background: var(--surface2);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-control);
  margin-bottom: var(--sp-3);
}
label.role-option {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 5px var(--sp-2);
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.role-option:hover {
  background: var(--surface);
}
.role-option:has(input:checked) {
  border-color: var(--brand);
  background: var(--surface);
}
.role-option input {
  accent-color: var(--brand);
}
/* Collapsed form of the picker: the summary shows the chosen role (ui.js copies it in)
   and the list opens below it. */
.role-select {
  margin-bottom: var(--sp-3);
}
.role-select > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  list-style: none;
  cursor: pointer;
}
.role-select > summary::-webkit-details-marker {
  display: none;
}
.role-select > summary::after {
  content: "";
  flex: none;
  width: 12px;
  height: 12px;
  background: var(--chevron) center / contain no-repeat;
}
.role-select .role-picker {
  margin: var(--sp-1) 0 0;
}
.role-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.role-icon {
  width: 16px;
  height: 16px;
  line-height: 16px;
  font-size: var(--fs-md);
  text-align: center;
}
.role-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--faint);
}
