/* ===========================================================================
   Pzorion Design System — complete token + component stylesheet.
   All values derive from the DS token files in css/ds/*.css.
   =========================================================================== */

/* ── Tokens: Colors ── */
:root {
  --brand-500: #10b981;
  --brand-400: #34d399;
  --brand-600: #059669;
  --brand-700: #047857;
  --brand-300: #6ee7b7;
  --brand-100: #d1fae5;
  --brand-900: #064e3b;

  --neutral-0:   #ffffff;
  --neutral-50:  #fafafa;
  --neutral-100: #f4f4f5;
  --neutral-200: #e4e4e7;
  --neutral-300: #d4d4d8;
  --neutral-400: #a1a1aa;
  --neutral-500: #71717a;
  --neutral-600: #52525b;
  --neutral-700: #3f3f46;
  --neutral-800: #27272a;
  --neutral-850: #1c1c1f;
  --neutral-900: #111118;
  --neutral-950: #0a0a0f;

  --color-success: #10b981;
  --color-warning: #f59e0b;
  --color-error:   #ef4444;
  --color-info:    #3b82f6;
}

/* Light mode */
:root, [data-theme="light"] {
  --bg-base:       var(--neutral-50);
  --bg-subtle:     var(--neutral-100);
  --bg-muted:      var(--neutral-200);
  --bg-card:       var(--neutral-0);
  --bg-overlay:    rgba(0,0,0,0.5);

  --fg-1:          #09090b;
  --fg-2:          #18181b;
  --fg-3:          var(--neutral-600);
  --fg-muted:      var(--neutral-400);
  --fg-on-brand:   #ffffff;

  --border-default: var(--neutral-200);
  --border-muted:   var(--neutral-100);
  --border-strong:  var(--neutral-300);

  --accent:        var(--brand-500);
  --accent-hover:  var(--brand-600);
  --accent-subtle: var(--brand-100);
  --accent-fg:     var(--brand-700);
  --accent-rgb:    16, 185, 129;

  /* Filled-button surface, separate from --accent on purpose.
     --accent doubles as a tint for rings, icons and hover text, where a
     vivid mid-green is exactly right. As a BUTTON background under a white
     label it measured 2.54:1 (and 3.77:1 on hover) - under WCAG AA's 4.5:1,
     on the site's main calls to action. Splitting the token fixes the
     buttons without repainting every accent in the theme.
     Light: a dark surface with a white label, the classic CTA look. */
  --btn-bg:        var(--brand-700);   /* #047857 + #fff = 5.48:1 */
  --btn-bg-hover:  #065f46;            /*           + #fff = 7.68:1 */
  --btn-fg:        #ffffff;

  --shadow-sm: 0 1px 2px rgba(0,0,0,0.06);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.08);
  --shadow-lg: 0 8px 32px rgba(0,0,0,0.10);
}

/* Dark mode */
[data-theme="dark"], .dark {
  --bg-base:       var(--neutral-950);
  --bg-subtle:     var(--neutral-900);
  --bg-muted:      var(--neutral-850);
  --bg-card:       var(--neutral-900);
  --bg-overlay:    rgba(0,0,0,0.7);

  --fg-1:          var(--neutral-50);
  --fg-2:          var(--neutral-100);
  --fg-3:          var(--neutral-400);
  /* Was neutral-600 (#52525b) - only 2.43:1 against --bg-card
     (#111118, what the footer sits on), well under WCAG AA's 4.5:1 for
     normal text. #7f7f89 clears 4.5:1 with a little headroom while staying
     one step dimmer than --fg-3, so "muted" still reads as muted. */
  --fg-muted:      #7f7f89;
  --fg-on-brand:   #ffffff;

  --border-default: var(--neutral-800);
  --border-muted:   var(--neutral-850);
  --border-strong:  var(--neutral-700);

  --accent:        var(--brand-400);
  --accent-hover:  var(--brand-300);
  --accent-subtle: rgba(16,185,129,0.12);
  --accent-fg:     var(--brand-300);
  --accent-rgb:    52, 211, 153;

  /* Dark theme goes the other way round: the surface stays the bright mint
     the palette needs against a dark page, and the LABEL goes dark. White on
     #34d399 was 1.92:1, the worst reading on the site; a dark-green ink on
     the same surface is 8.58:1 and keeps the button just as prominent. */
  --btn-bg:        var(--brand-400);   /* #34d399 + #04241b = 8.58:1  */
  --btn-bg-hover:  var(--brand-300);   /* #6ee7b7 + #04241b = 10.82:1 */
  --btn-fg:        #04241b;

  --shadow-sm: 0 1px 2px rgba(0,0,0,0.3);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.4);
  --shadow-lg: 0 8px 32px rgba(0,0,0,0.5);
}

/* Telegram Mini App theme bridge */
.tg-app {
  --bg-base:       var(--tg-theme-bg-color, var(--bg-base));
  --bg-card:       var(--tg-theme-secondary-bg-color, var(--bg-card));
  --fg-1:          var(--tg-theme-text-color, var(--fg-1));
  --fg-3:          var(--tg-theme-hint-color, var(--fg-3));
  --accent:        var(--tg-theme-button-color, var(--accent));
  --fg-on-brand:   var(--tg-theme-button-text-color, var(--fg-on-brand));
  /* Inside Telegram the client dictates the button pair, and it guarantees
     they contrast with each other - so defer to it and fall back to our own
     accessible pair outside the app. */
  --btn-bg:        var(--tg-theme-button-color, var(--btn-bg));
  --btn-bg-hover:  var(--tg-theme-button-color, var(--btn-bg-hover));
  --btn-fg:        var(--tg-theme-button-text-color, var(--btn-fg));
  --border-default: var(--tg-theme-section-separator-color, var(--border-default));
}

/* ── Tokens: Typography ── */
:root {
  --font-sans:  Vazirmatn, 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
  --font-mono:  'JetBrains Mono', 'Fira Code', monospace;

  --text-xs:   0.75rem;
  --text-sm:   0.875rem;
  --text-base: 1rem;
  --text-lg:   1.125rem;
  --text-xl:   1.25rem;
  --text-2xl:  1.5rem;
  --text-3xl:  1.875rem;
  --text-4xl:  2.25rem;
  --text-5xl:  3rem;
  --text-6xl:  3.75rem;

  --weight-light:    300;
  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;
  --weight-extrabold: 800;

  --leading-tight:  1.2;
  --leading-snug:   1.35;
  --leading-normal: 1.5;
  --leading-relaxed: 1.625;

  --tracking-tight:  -0.025em;
  --tracking-normal:  0em;
  --tracking-wide:    0.025em;
  --tracking-wider:   0.05em;
}

/* ── Tokens: Spacing (4px grid) ── */
:root {
  --space-0:  0;
  --space-px: 1px;
  --space-0-5: 0.125rem;
  --space-1:  0.25rem;
  --space-1-5: 0.375rem;
  --space-2:  0.5rem;
  --space-2-5: 0.625rem;
  --space-3:  0.75rem;
  --space-4:  1rem;
  --space-5:  1.25rem;
  --space-6:  1.5rem;
  --space-7:  1.75rem;
  --space-8:  2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;

  --gap-xs:   var(--space-1);
  --gap-sm:   var(--space-2);
  --gap-md:   var(--space-4);
  --gap-lg:   var(--space-6);
  --gap-xl:   var(--space-8);
  --gap-2xl:  var(--space-12);

  --padding-card-sm: var(--space-4) var(--space-4);
  --padding-card-md: var(--space-5) var(--space-6);
  --padding-card-lg: var(--space-8) var(--space-8);

  --padding-btn-sm:  var(--space-1-5) var(--space-3);
  --padding-btn-md:  var(--space-2-5) var(--space-5);
  --padding-btn-lg:  var(--space-3) var(--space-6);

  --radius-sm:   4px;
  --radius-md:   8px;
  --radius-lg:   12px;
  --radius-xl:   16px;
  --radius-2xl:  24px;
  --radius-full: 9999px;

  --container-sm:  640px;
  --container-md:  768px;
  --container-lg:  1024px;
  --container-xl:  1280px;
}

/* ── Tokens: Animation ── */
:root {
  --duration-instant: 80ms;
  --duration-fast:    150ms;
  --duration-normal:  250ms;
  --duration-slow:    400ms;
  --duration-slower:  600ms;

  --ease-out:   cubic-bezier(0.0, 0, 0.2, 1);
  --ease-in:    cubic-bezier(0.4, 0, 1, 1);
  --ease-inout: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  --transition-fast:   var(--duration-fast) var(--ease-out);
  --transition-normal: var(--duration-normal) var(--ease-out);
  --transition-spring: var(--duration-slow) var(--ease-spring);
}

/* ── Legacy bridge (old var names → DS tokens) ── */
:root {
  --accent-2: var(--brand-500);
  --accent-3: var(--brand-300);
  --bg: var(--bg-base);
  --text: var(--fg-1);
  --text-dim: var(--fg-3);
  --danger: var(--color-error);
  --ok: var(--color-success);
  --radius: var(--radius-xl);
  --shadow: var(--shadow-md);
  --nav-h: 64px;
  --tabbar-h: 60px;
  color-scheme: dark;
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;
    --accent-2: var(--brand-600);
    --accent-3: var(--brand-400);
  }
}
:root[data-theme="light"] {
  color-scheme: light;
  --accent-2: var(--brand-600);
  --accent-3: var(--brand-400);
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --accent-2: var(--brand-500);
  --accent-3: var(--brand-300);
}


/* Inline SVG masks for pseudo-element marks (see .check-list / details). */
:root {
  --ic-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 13 4.5 4.5L19 7'/%3E%3C/svg%3E");
  --ic-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}

/* ── end tokens ── */

/* ── Fonts ── */
@font-face {
  font-family: "Vazirmatn";
  src: url("/assets/fonts/Vazirmatn-Regular.woff2") format("woff2");
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: "Vazirmatn";
  src: url("/assets/fonts/Vazirmatn-Medium.woff2") format("woff2");
  font-weight: 500 600; font-display: swap;
}
@font-face {
  font-family: "Vazirmatn";
  src: url("/assets/fonts/Vazirmatn-Bold.woff2") format("woff2");
  font-weight: 700 900; font-display: swap;
}

/* ══════════════════════════════════════════════════════════════════════════
   BASE RESET
   ══════════════════════════════════════════════════════════════════════════ */
*, *::before, *::after { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body {
  margin: 0; padding: 0;
  background: var(--bg-base);
  color: var(--fg-1);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--weight-regular);
  line-height: var(--leading-relaxed);
  overflow-x: hidden;
}
body {
  min-height: 100vh;
  display: flex; flex-direction: column; align-items: center;
  padding: calc(var(--nav-h) + var(--space-6)) var(--space-4) calc(var(--tabbar-h) + var(--space-5));
  position: relative;
  transition: background var(--transition-normal), color var(--transition-normal);
}
a { color: inherit; }

/* ── Ambient background ── */
.blob { position: fixed; border-radius: 50%; filter: blur(90px); opacity: .18; z-index: 0; pointer-events: none; }
.blob-1 { width: 420px; height: 420px; background: radial-gradient(circle, var(--accent), transparent 70%); top: -160px; right: -120px; animation: float1 18s var(--ease-inout) infinite; }
.blob-2 { width: 360px; height: 360px; background: radial-gradient(circle, var(--accent-2), transparent 70%); bottom: -140px; left: -120px; animation: float2 22s var(--ease-inout) infinite; }
.blob-3 { width: 280px; height: 280px; background: radial-gradient(circle, var(--accent-3), transparent 70%); top: 40%; left: 50%; opacity: .10; animation: float3 26s var(--ease-inout) infinite; }
@keyframes float1 { 0%,100% { transform: translate(0,0); } 50% { transform: translate(-30px, 40px); } }
@keyframes float2 { 0%,100% { transform: translate(0,0); } 50% { transform: translate(30px, -30px); } }
@keyframes float3 { 0%,100% { transform: translate(-50%,-50%) scale(1); } 50% { transform: translate(-50%,-50%) scale(1.15); } }

/* ── Layout containers ──
   Widened to the DS container scale. The old site capped at 640/980px, which
   left most of a desktop viewport empty and forced every grid into narrow
   columns. */
.wrap { width: 100%; max-width: 560px; position: relative; z-index: 1; }
.wrap-wide { max-width: 100%; }
@media (min-width: 860px) {
  .wrap { max-width: var(--container-md); }
  .wrap-wide { max-width: var(--container-lg); }
}
@media (min-width: 1200px) {
  .wrap-wide { max-width: var(--container-xl); }
}

.grid-3 { display: grid; grid-template-columns: 1fr; gap: var(--gap-md); }
@media (min-width: 700px) { .grid-3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .grid-3 { grid-template-columns: repeat(3, 1fr); } }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-md); }
/* Four peers (the service line-up) - 1 up on phones, 2 up on tablets, 4 up
   on desktop so the set never breaks into an orphaned last card. */
.grid-4 { display: grid; grid-template-columns: 1fr; gap: var(--gap-md); }
@media (min-width: 620px)  { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .grid-4 { grid-template-columns: repeat(4, 1fr); } }

/* Five cards. Tops out at THREE columns, not five: in a four-column grid the
   fifth card sits alone on its own row, and five 190px columns at 1000px are
   too narrow for a title plus two lines plus a button. Three columns give
   3+2, which reads as a deliberate block. */
.grid-5 { display: grid; grid-template-columns: 1fr; gap: var(--gap-md); }
@media (min-width: 620px)  { .grid-5 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .grid-5 { grid-template-columns: repeat(3, 1fr); } }
.service-card { display: flex; flex-direction: column; }

/* ══════════════════════════════════════════════════════════════════════════
   TOP NAV
   ══════════════════════════════════════════════════════════════════════════ */
.topnav {
  position: fixed; top: 0; right: 0; left: 0; height: var(--nav-h); z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--space-5);
  background: var(--bg-card);
  border-bottom: 1px solid var(--border-default);
  transition: background var(--transition-normal);
}
.topnav .brand {
  display: flex; align-items: center; gap: var(--gap-sm);
  font-weight: var(--weight-extrabold); font-size: var(--text-base);
  text-decoration: none; color: var(--fg-1);
}
.topnav .brand .ic { width: 24px; height: 24px; object-fit: contain; }
.topnav .links { display: none; align-items: center; gap: var(--space-1); }
.topnav .links a {
  text-decoration: none; color: var(--fg-3);
  font-size: var(--text-sm); font-weight: var(--weight-semibold);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-md);
  transition: background var(--transition-fast), color var(--transition-fast);
}
.topnav .links a:hover { background: var(--bg-subtle); color: var(--fg-1); }
.topnav .links a.active { background: var(--accent-subtle); color: var(--accent-fg); }
.topnav .right { display: flex; align-items: center; gap: var(--gap-sm); }

.theme-toggle {
  /* 44px, not 40: the recommended minimum comfortable touch target
     (reported 2026-09-21). */
  width: 44px; height: 44px; border-radius: var(--radius-md);
  border: 1px solid var(--border-default); background: var(--bg-subtle);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; font-size: var(--text-base); color: var(--fg-1);
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.theme-toggle:hover { background: var(--bg-muted); }

.hamburger {
  width: 44px; height: 44px; border-radius: var(--radius-md);
  border: 1px solid var(--border-default); background: var(--bg-subtle);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; font-size: var(--text-lg);
  transition: background var(--transition-fast);
}
.hamburger:hover { background: var(--bg-muted); }
.nav-pro-btn {
  display: none;
  /* .btn-sm's own padding measured ~32px tall (reported 2026-09-21) - fixed
     here rather than in .btn-sm itself, which many compact in-list buttons
     share and don't need to grow. */
  min-height: 44px;
}

@media (min-width: 860px) {
  .topnav .links { display: flex; }
  .hamburger { display: none; }
  .nav-pro-btn { display: inline-flex; }
}

/* ── Mobile drawer ── */
.drawer-backdrop {
  position: fixed; inset: 0; background: var(--bg-overlay); z-index: 90;
  opacity: 0; pointer-events: none; transition: opacity var(--transition-normal);
}
.drawer-backdrop.open { opacity: 1; pointer-events: auto; }
.drawer {
  position: fixed; top: 0; bottom: 0; right: -300px; width: 280px; z-index: 91;
  background: var(--bg-card);
  border-left: 1px solid var(--border-default);
  padding: var(--space-5) var(--space-4);
  transition: right var(--transition-normal);
}
.drawer.open { right: 0; }
.drawer a {
  display: block; padding: var(--space-3) var(--space-3);
  border-radius: var(--radius-md); text-decoration: none;
  color: var(--fg-1); font-size: var(--text-sm); font-weight: var(--weight-semibold);
  transition: background var(--transition-fast);
}
.drawer a { display: flex; align-items: center; gap: var(--space-2-5); }
.drawer a:hover { background: var(--bg-subtle); }
.drawer a.active { background: var(--accent-subtle); color: var(--accent-fg); }
.drawer .close-drawer {
  width: 36px; height: 36px; border-radius: var(--radius-md);
  border: 1px solid var(--border-default); background: var(--bg-subtle);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: var(--space-4); cursor: pointer;
  transition: background var(--transition-fast);
}
.drawer .close-drawer:hover { background: var(--bg-muted); }

/* ── Bottom tab bar (mobile) ── */
.tabbar {
  position: fixed; bottom: 0; right: 0; left: 0; height: var(--tabbar-h); z-index: 50;
  display: flex; background: var(--bg-card);
  border-top: 1px solid var(--border-default);
  transition: background var(--transition-normal);
}
.tabbar a {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; text-decoration: none; color: var(--fg-muted);
  font-size: var(--text-xs); font-weight: var(--weight-bold);
  transition: color var(--transition-fast);
}
/* Wrapper is .tab-ic, not .ic: the icon inside is itself an svg.ic, and
   nesting the same sizing class would apply the em box twice. */
.tabbar a .tab-ic { display: flex; align-items: center; justify-content: center; }
.tabbar a .tab-ic svg.ic { width: 20px; height: 20px; vertical-align: 0; }
.tabbar a:hover { color: var(--fg-3); }
.tabbar a.active { color: var(--accent); }
@media (min-width: 860px) { .tabbar { display: none; } body { padding-bottom: var(--space-8); } }

/* ══════════════════════════════════════════════════════════════════════════
   GENERIC COMPONENTS
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Card ── */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xl);
  padding: var(--padding-card-md);
  box-shadow: var(--shadow-sm);
  margin-bottom: var(--gap-md);
  position: relative; overflow: hidden;
  transition: box-shadow var(--transition-normal), border-color var(--transition-normal), background var(--transition-normal);
}
.card:hover { box-shadow: var(--shadow-md); }

/* ── Button ── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--gap-sm);
  padding: var(--padding-btn-md);
  border-radius: var(--radius-lg); border: none;
  font-weight: var(--weight-bold); font-size: var(--text-sm);
  cursor: pointer;
  background: var(--btn-bg);
  color: var(--btn-fg);
  text-decoration: none;
  box-shadow: 0 2px 8px -2px rgba(var(--accent-rgb), .35);
  transition: transform var(--transition-fast), box-shadow var(--transition-fast), background var(--transition-fast);
  font-family: inherit;
}
.btn:hover { background: var(--btn-bg-hover); box-shadow: 0 4px 14px -4px rgba(var(--accent-rgb), .5); }
.btn:active { transform: scale(.97); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-block { display: flex; width: 100%; text-align: center; }
/* The variants repeat the base box because several call sites write
   class="btn-ghost btn-sm" with no .btn - without this they render as bare
   bordered text with no padding (this is what made /account's buttons look
   like empty input boxes). */
.btn-ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--gap-sm);
  padding: var(--padding-btn-md); border-radius: var(--radius-lg);
  font-family: inherit; font-weight: var(--weight-bold); font-size: var(--text-sm);
  cursor: pointer; text-decoration: none;
  background: var(--bg-subtle); border: 1px solid var(--border-default);
  color: var(--fg-1); box-shadow: none;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.btn-ghost:hover { background: var(--bg-muted); border-color: var(--border-strong); }
.btn-green { background: #22c55e; box-shadow: 0 2px 8px -2px rgba(34,197,94,.4); }
.btn-green:hover { background: #16a34a; }
.btn-danger { background: var(--color-error); box-shadow: 0 2px 8px -2px rgba(239,68,68,.4); }
.btn-danger:hover { background: #dc2626; }
.btn-sm { padding: var(--padding-btn-sm); font-size: var(--text-xs); border-radius: var(--radius-md); }

/* ── Section title ── */
.section-title {
  font-size: var(--text-xs); font-weight: var(--weight-bold);
  color: var(--fg-3); text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  margin: 0 0 var(--gap-md);
  display: flex; align-items: center; gap: var(--gap-sm);
}

/* ── Error message ── */
.err { color: var(--color-error); font-size: var(--text-sm); margin-top: var(--space-3); display: none; }
.err.show { display: block; }

/* ── Form fields ── */
.field { margin-bottom: var(--gap-md); }
.field label {
  display: block; font-size: var(--text-xs); color: var(--fg-3);
  margin-bottom: var(--space-1-5); font-weight: var(--weight-semibold);
}
.field input[type=text], .field input[type=password], .field input[type=number],
.field input[type=email], .field select, .field textarea {
  width: 100%; background: var(--bg-subtle);
  border: 1px solid var(--border-default); border-radius: var(--radius-lg);
  padding: var(--space-2-5) var(--space-3);
  color: var(--fg-1); font-family: inherit; font-size: var(--text-sm);
  outline: none;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.field textarea { resize: vertical; min-height: 90px; }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), .15);
}
.hint-sm { font-size: var(--text-xs); color: var(--fg-3); margin-top: var(--space-1); }

/* ── Tabs ── */
.tabs {
  display: flex; gap: var(--space-1);
  background: var(--bg-subtle); border: 1px solid var(--border-default);
  border-radius: var(--radius-xl); padding: var(--space-1);
  margin-bottom: var(--gap-md);
}
.tabs button {
  flex: 1; border: none; background: none;
  padding: var(--space-2-5) var(--space-2); border-radius: var(--radius-lg);
  font-family: inherit; font-weight: var(--weight-bold);
  font-size: var(--text-xs); color: var(--fg-3);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast);
}
.tabs button:hover { background: var(--bg-muted); }
.tabs button.active {
  background: var(--bg-card); color: var(--fg-1);
  box-shadow: var(--shadow-sm);
}
.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* ── Advanced settings (collapsible) ── */
.adv-toggle {
  display: flex; align-items: center; justify-content: space-between;
  cursor: pointer; padding: var(--space-3) var(--space-1);
  font-size: var(--text-xs); font-weight: var(--weight-bold); color: var(--fg-3);
  transition: color var(--transition-fast);
}
.adv-toggle:hover { color: var(--fg-1); }
.adv-toggle .chev { transition: transform var(--transition-normal); }
.adv-toggle.open .chev { transform: rotate(180deg); }
.adv-body { display: none; padding-top: var(--space-2); }
.adv-body.open { display: block; animation: fadeSlideIn var(--duration-normal) var(--ease-out); }

@keyframes fadeSlideIn {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ── Progress bar ── */
.progress-wrap {
  margin-top: var(--space-4); height: 6px; border-radius: var(--radius-full);
  background: var(--bg-muted); overflow: hidden; display: none;
}
.progress-bar {
  height: 100%; width: 0%; border-radius: var(--radius-full);
  background: var(--accent);
  transition: width var(--transition-fast);
}
.progress-meta {
  display: flex; justify-content: space-between;
  font-size: var(--text-xs); color: var(--fg-3); margin-top: var(--space-1-5);
}

/* ── Result card ── */
/* .show is added by JS (downloader.js, stream.js) on a successful job -
   without this rule the panel stayed display:none forever, so a successful
   download/stream silently produced no visible link and no error. F2Link's
   own upload.js dodges this by setting style.display directly instead of a
   class, which is why that flow looked fine while these two did not. */
.result { display: none; }
.result.show { display: block; }
.result .row {
  display: flex; gap: var(--gap-sm); align-items: center;
  background: var(--bg-subtle); border: 1px solid var(--border-default);
  border-radius: var(--radius-lg); padding: var(--space-2-5) var(--space-3);
  margin-top: var(--space-3);
}
.result .row input {
  flex: 1; min-width: 0; background: none; border: none; color: var(--fg-1);
  font-size: var(--text-xs); direction: ltr; text-align: left;
  outline: none; font-family: inherit;
  /* A signed S3/Parspack URL runs a couple thousand px past the card's
     width with nothing to say so - min-width:0 lets it actually shrink
     inside the flex row instead of pushing the copy/open buttons off, and
     the ellipsis at least shows it's truncated instead of just stopping
     mid-token. The copy button (added 2026-09-21 to downloader.html to
     match f2link/stream) is the real way to get the full link out. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.result .meta { color: var(--fg-3); font-size: var(--text-xs); margin-top: var(--space-2); }
.share-row { display: flex; gap: var(--gap-sm); margin-top: var(--space-3); flex-wrap: wrap; }
.share-row .btn { flex: 1; font-size: var(--text-xs); padding: var(--padding-btn-sm); min-width: 90px; }

/* ── Dropzone ── */
.dropzone {
  border: 2px dashed var(--border-strong); border-radius: var(--radius-xl);
  padding: var(--space-10) var(--space-4); text-align: center;
  cursor: pointer;
  transition: border-color var(--transition-normal), background var(--transition-normal), transform var(--transition-fast);
}
.dropzone:hover { transform: translateY(-2px); border-color: var(--fg-muted); }
.dropzone.drag { border-color: var(--accent); background: rgba(var(--accent-rgb), .06); }
.dropzone .ic {
  font-size: var(--text-4xl); margin-bottom: var(--space-3);
  display: flex; justify-content: center; color: var(--fg-3);
}
.dropzone .hint { color: var(--fg-3); font-size: var(--text-xs); margin-top: var(--space-2); }
input[type=file] { display: none; }

/* ── Badges ── */
.badges { display: flex; justify-content: center; gap: var(--gap-sm); margin: var(--space-1) 0 var(--space-5); flex-wrap: wrap; }
/* In a hero the chips follow the CTA row, so they need real separation. */
.hero .badges { margin-top: var(--space-8); }
.badge {
  display: flex; align-items: center; gap: var(--space-1-5);
  font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--fg-3);
  background: var(--bg-subtle); border: 1px solid var(--border-default);
  padding: var(--space-1-5) var(--space-3); border-radius: var(--radius-full);
  transition: background var(--transition-fast);
}

/* ── Toast ── */
.toast-host {
  position: fixed; bottom: calc(var(--tabbar-h) + var(--space-4)); left: 50%; transform: translateX(-50%);
  z-index: 200; display: flex; flex-direction: column; gap: var(--gap-sm);
  align-items: center; width: 100%; padding: 0 var(--space-4);
}
.toast {
  background: var(--bg-card); border: 1px solid var(--border-default);
  padding: var(--space-3) var(--space-4); border-radius: var(--radius-lg);
  font-size: var(--text-xs); font-weight: var(--weight-semibold);
  box-shadow: var(--shadow-lg); max-width: 420px;
  animation: toast-in var(--duration-normal) var(--ease-spring);
}
@keyframes toast-in { from { opacity: 0; transform: translateY(12px) scale(.96); } to { opacity: 1; transform: translateY(0) scale(1); } }
@media (min-width: 860px) { .toast-host { bottom: var(--space-6); } }

/* ── Modal ── */
.modal-backdrop {
  position: fixed; inset: 0; background: var(--bg-overlay); z-index: 150;
  display: none; align-items: center; justify-content: center;
  padding: var(--space-4);
}
.modal-backdrop.open { display: flex; }
.modal {
  width: 100%; max-width: 400px; background: var(--bg-card);
  border: 1px solid var(--border-default); border-radius: var(--radius-2xl);
  padding: var(--padding-card-lg); box-shadow: var(--shadow-lg);
  animation: modalIn var(--duration-normal) var(--ease-spring);
}
@keyframes modalIn { from { opacity: 0; transform: scale(.95) translateY(8px); } to { opacity: 1; transform: scale(1) translateY(0); } }
.modal h3 { margin: 0 0 var(--space-4); font-size: var(--text-lg); font-weight: var(--weight-bold); }
.modal .modal-actions { display: flex; gap: var(--gap-sm); margin-top: var(--space-4); }
.modal .qr-img { display: block; margin: 0 auto; border-radius: var(--radius-lg); background: #fff; padding: var(--space-3); }

/* ── Skeleton loader ── */
.skel {
  background: linear-gradient(90deg, var(--bg-subtle) 25%, var(--bg-muted) 37%, var(--bg-subtle) 63%);
  background-size: 400% 100%;
  animation: skel 1.4s var(--ease-inout) infinite;
  border-radius: var(--radius-md);
}
@keyframes skel { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ── Chip ── */
.chip {
  display: inline-flex; align-items: center; gap: var(--space-1-5);
  font-size: var(--text-xs); font-weight: var(--weight-bold);
  padding: var(--space-1) var(--space-3); border-radius: var(--radius-full);
  background: var(--bg-subtle); border: 1px solid var(--border-default); color: var(--fg-3);
}
.chip.warn { color: var(--color-warning); border-color: rgba(245,158,11,.35); }

/* ══════════════════════════════════════════════════════════════════════════
   ICONS
   Replaced the emoji that used to sit in headings, buttons and nav. Emoji
   rendered differently on every OS, ignored the theme, and sat on the text
   baseline wrong; these inherit currentColor and align properly.
   ══════════════════════════════════════════════════════════════════════════ */
/* Scoped to svg on purpose. Several pages predate this class and use
   <div class="ic"> / <span class="ic"> as a plain "icon slot" wrapper; an
   unscoped rule shrank those wrappers to 1.15em, which is what knocked the
   dropzone's cloud out of centre. */
svg.ic {
  width: 1.15em; height: 1.15em;
  flex-shrink: 0;
  vertical-align: -0.18em;
  stroke: currentColor; fill: none;
}
svg.ic-lg { width: 1.5em; height: 1.5em; }
svg.ic-xl { width: 2.25em; height: 2.25em; }
.ic-accent { color: var(--accent); }
.ic-ok { color: var(--color-success); }
.ic-warn { color: var(--color-warning); }
.ic-danger { color: var(--color-error); }
.ic-dim { color: var(--fg-3); }

/* Feature/empty-state art: a larger mark in a tinted tile. */
.ic-tile {
  width: 48px; height: 48px; border-radius: var(--radius-lg);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent-subtle); color: var(--accent-fg);
  margin-bottom: var(--space-3);
}
.ic-tile svg.ic { width: 24px; height: 24px; }

/* ══════════════════════════════════════════════════════════════════════════
   DASHBOARD PRIMITIVES
   Section headers, list rows and standalone inputs. Before these existed,
   /account built every row out of a .card plus a long inline flex style,
   which is why its titles and buttons sat at opposite ends of an empty bar.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Page header for inner pages (smaller than a landing .hero) ── */
.page-head { text-align: center; margin: var(--space-4) 0 var(--space-8); }
.page-head h1 {
  font-size: var(--text-2xl); font-weight: var(--weight-extrabold);
  margin: 0 0 var(--space-2); letter-spacing: var(--tracking-tight);
}
.page-head p { color: var(--fg-3); font-size: var(--text-sm); margin: 0; }
@media (min-width: 860px) { .page-head h1 { font-size: var(--text-3xl); } }

/* ── Section header: title on one side, its action right beside it ── */
.sec-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-md); flex-wrap: wrap;
  margin: var(--space-8) 0 var(--space-3);
}
.sec-head:first-child { margin-top: 0; }
.sec-head h2 {
  font-size: var(--text-lg); font-weight: var(--weight-bold);
  margin: 0; display: flex; align-items: center; gap: var(--gap-sm);
}
.sec-head .sec-sub {
  width: 100%; margin: 0; color: var(--fg-3); font-size: var(--text-xs);
}

/* ── Standalone input (outside a .field wrapper) ── */
.input {
  background: var(--bg-subtle);
  border: 1px solid var(--border-default); border-radius: var(--radius-lg);
  padding: var(--space-2) var(--space-3);
  color: var(--fg-1); font-family: inherit; font-size: var(--text-sm);
  outline: none;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.input::placeholder { color: var(--fg-muted); }
.input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), .15);
}
.input-sm { padding: var(--space-1-5) var(--space-2-5); font-size: var(--text-xs); max-width: 200px; }

/* ── List row: one record, its metadata, and its actions ── */
.list-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-md);
  background: var(--bg-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-4);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.list-row + .list-row { margin-top: var(--space-2); }
.list-row:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.list-row .row-main { min-width: 0; flex: 1; }
.list-row .row-title {
  display: block; font-weight: var(--weight-semibold); font-size: var(--text-sm);
  color: var(--fg-1); text-decoration: none;
  /* One line, clipped. Titles here are uploaded filenames, and a full
     release name ("Culpa.Mia.2023.720p.WEBRip.x264.AAC-HardSub.[@Filmseven]
     .mp4") used to wrap to a second line, so that card stood taller than
     every other row in the list. The full name stays available through the
     title attribute the renderers set. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color var(--transition-fast);
}
a.row-title:hover { color: var(--accent); }
.list-row .row-meta {
  color: var(--fg-3); font-size: var(--text-xs); margin-top: 2px;
  word-break: break-word;
}
.list-row .row-amount { font-weight: var(--weight-bold); font-size: var(--text-sm); white-space: nowrap; }
.list-row .row-actions { display: flex; gap: var(--space-2); flex-shrink: 0; }
@media (max-width: 520px) {
  .list-row { flex-direction: column; align-items: stretch; }
  .list-row .row-actions { justify-content: flex-end; }
}

/* ── Wallet summary ── */
.wallet-card {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: var(--gap-md);
}
.wallet-label { font-size: var(--text-xs); color: var(--fg-3); margin-top: 2px; }
.wallet-name { font-weight: var(--weight-bold); font-size: var(--text-base); }
.wallet-amount {
  font-size: var(--text-3xl); font-weight: var(--weight-extrabold);
  color: var(--accent); line-height: var(--leading-tight);
}

/* ── Compact empty state for a list that has no records yet ── */
.empty-slim {
  text-align: center; color: var(--fg-3); font-size: var(--text-sm);
  padding: var(--space-8) var(--space-4);
  background: var(--bg-card);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
}

/* ── Purchasable plan/bundle tile ── */
.offer-card {
  background: var(--bg-card); border: 1px solid var(--border-default);
  border-radius: var(--radius-lg); padding: var(--space-4);
  display: flex; flex-direction: column; gap: var(--space-2);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.offer-card:hover { border-color: var(--accent); box-shadow: var(--shadow-sm); }
.offer-card .offer-title { font-weight: var(--weight-bold); font-size: var(--text-base); }
.offer-card .offer-desc { color: var(--fg-3); font-size: var(--text-xs); flex: 1; }
.offer-card .offer-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-sm); margin-top: var(--space-1);
}
.offer-card .offer-price { font-weight: var(--weight-extrabold); font-size: var(--text-base); }

/* ── Empty / error states ── */
.empty-state { text-align: center; padding: var(--space-10) var(--space-4); color: var(--fg-3); }
.empty-state .ic {
  font-size: 48px; margin-bottom: var(--space-3);
  display: flex; justify-content: center;
}
.empty-state h3 { color: var(--fg-1); font-size: var(--text-lg); margin: 0 0 var(--space-2); }
.empty-state p { font-size: var(--text-xs); margin: 0; }

/* ── Prose ── */
.prose h2 { font-size: var(--text-lg); margin: var(--space-5) 0 var(--space-3); font-weight: var(--weight-semibold); }
.prose p, .prose li { color: var(--fg-3); font-size: var(--text-sm); line-height: var(--leading-relaxed); }
.prose ul { padding: 0 var(--space-5) 0 0; }

/* ── Footer ──
   A distinct surface at the end of the page rather than a run of centred
   text: brand block plus labelled link columns, with the legal/copyright
   line split off into its own bottom bar. */
.site-footer {
  margin-top: var(--space-16);
  background: var(--bg-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-2xl);
  /* Bottom padding matches the bottom bar's own top padding, so the card
     closes symmetrically instead of leaving the slab of empty space the
     seal's arrival exposed. */
  padding: var(--space-8) var(--space-6) var(--space-5);
  color: var(--fg-3);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  text-align: right;
  position: relative;
  overflow: hidden;
}
/* Brand-coloured hairline along the top edge. */
.site-footer::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: .5;
}

.footer-main {
  display: grid; grid-template-columns: 1fr; gap: var(--space-8);
  padding-bottom: var(--space-6);
}
/* Single-column (phone): centre everything. Stacked right-aligned columns
   read as three ragged blocks against the edge; centred they sit as one tidy
   run down the middle, which is also where the seal and bottom bar are. */
@media (max-width: 639px) {
  /* Brand block stays full width and centred; the three link columns share a
     two-column grid below it.
     Stacked in ONE column they came to 950px on a 844px screen - and that is
     before the coarse-pointer touch targets, which push it past 1200px. The
     footer then filled the whole phone screen with a long ladder of links
     (reported from a real device). Two columns halves that without shrinking
     a single tap target. */
  .footer-main {
    text-align: center;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-5) var(--space-3);
  }
  .footer-brand { grid-column: 1 / -1; }
  .footer-brand, .footer-col { align-items: center; }
  .footer-social { justify-content: center; }
}
@media (min-width: 640px) { .footer-main { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 940px) { .footer-main { grid-template-columns: 1.6fr repeat(3, 1fr); gap: var(--space-6); } }

.footer-brand { display: flex; flex-direction: column; gap: var(--space-3); }
.footer-logo {
  display: flex; align-items: center; gap: var(--gap-sm);
  font-weight: var(--weight-extrabold); font-size: var(--text-lg);
  color: var(--fg-1); text-decoration: none;
}
.footer-logo img { width: 26px; height: 26px; object-fit: contain; }
.footer-tag { margin: 0; font-size: var(--text-sm); color: var(--fg-3); max-width: 32ch; }
.footer-social { display: flex; flex-wrap: wrap; gap: var(--gap-sm); margin-top: var(--space-1); }
.footer-social a {
  display: inline-flex; align-items: center; gap: var(--space-1-5);
  font-size: var(--text-xs); font-weight: var(--weight-semibold);
  padding: var(--space-1-5) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--bg-subtle); border: 1px solid var(--border-default);
  color: var(--fg-3); text-decoration: none;
  transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}
.footer-social a:hover { background: var(--accent-subtle); color: var(--accent-fg); border-color: var(--accent); }

.footer-col { display: flex; flex-direction: column; gap: var(--space-2-5); }
.footer-col-title {
  font-size: var(--text-xs); font-weight: var(--weight-bold);
  color: var(--fg-1); text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  margin-bottom: var(--space-1);
}
.footer-col a {
  color: var(--fg-3); text-decoration: none; font-size: var(--text-sm);
  width: fit-content;
  transition: color var(--transition-fast), transform var(--transition-fast);
}
.footer-col a:hover { color: var(--accent); transform: translateX(-3px); }

/* Touch devices: grow the HIT AREA to the 44px accessibility floor.
   These links measured 21px tall with a 10px gap, so on a phone the target
   was half the recommended size and its neighbour was 10px away - a mistap
   opened the wrong page. Only padding changes; the type stays --text-sm, and
   the column gap shrinks to absorb the extra height so the footer does not
   suddenly stretch.

   Scoped to `pointer: coarse` rather than a width breakpoint: it is the
   input device that decides whether a 21px target is a problem, and a narrow
   desktop window is still driven by a mouse. Pointer-precise devices keep
   the tighter footer they already had. */
@media (pointer: coarse) {
  .footer-col { gap: var(--space-0-5); }
  .footer-col a {
    /* 14px x 1.5 = 21px of text, + 2 x 12px = 45px total. */
    padding-block: var(--space-3);
  }
}

/* Bottom bar: copyright, the Enamad seal, and the legal links, on one line
   and vertically centred. Mobile stacks them; the order below is the stacking
   order, which is why the seal sits between the two text rows. */
/* Bottom bar: copyright and the legal links, one row, vertically centred.
   (The Enamad seal used to live here; it now sits under the contact links in
   the brand column, so this row is back to two items.) */
.footer-bottom {
  display: flex; flex-direction: column;
  align-items: center; justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-muted);
  font-size: var(--text-xs); color: var(--fg-muted);
  text-align: center;
}
.footer-copy { min-width: 0; }

.footer-legal { display: flex; gap: var(--space-4); flex: 0 0 auto; }
.footer-legal a { color: var(--fg-muted); text-decoration: none; transition: color var(--transition-fast); }
.footer-legal a:hover { color: var(--accent); }

/* نماد اعتماد الکترونیکی (اینماد), under the contact links in the brand
   column.
   Enamad requires the seal's own aspect ratio to be preserved, so the IMAGE
   is never given a width, height, transform or object-fit - only a ceiling,
   which `width: auto` follows on both axes. Everything else here is spacing
   and the backing panel.
   Never add display:none or lazy-loading: the seal has to be present and
   visible for the checker. */
.enamad-seal {
  align-self: flex-start;      /* RTL: the column's start edge, under the links */
  margin-top: var(--space-1);
  line-height: 0;
  /* No backing panel. There used to be a white one so the artwork would not
     look muddy on the dark theme, but trustseal.enamad.ir is slow or
     unreachable often enough that the image frequently has no size at all -
     and then the panel collapsed to its own padding and rendered as a stray
     12x12 white dot in the middle of the footer (seen on a real phone).
     With nothing behind it, a logo that has not arrived simply shows
     nothing. */
}
.enamad-seal a { display: block; line-height: 0; }
.enamad-seal img {
  max-height: 86px; width: auto; max-width: 100%;
  display: block;
}

/* The brand column centres on a phone, so the seal follows it instead of
   staying pinned to the start edge. This has to sit AFTER the base rule
   above: equal specificity means the later declaration wins, and while this
   lived up in the earlier mobile block the base `flex-start` overrode it and
   the seal stayed off to one side. */
@media (max-width: 639px) {
  .enamad-seal { align-self: center; }
}

@media (min-width: 640px) {
  .footer-bottom { flex-direction: row; text-align: right; gap: var(--space-5); }
}

/* Pages that still render a plain <footer> keep a sane default. */
footer:not(.site-footer) {
  text-align: center; color: var(--fg-3);
  font-size: var(--text-xs); margin-top: var(--space-8);
  line-height: var(--leading-relaxed);
}
footer:not(.site-footer) a { color: var(--fg-3); transition: color var(--transition-fast); }
footer:not(.site-footer) a:hover { color: var(--accent); }

@media (max-width: 380px) {
  .card { padding: var(--padding-card-sm); }
}

/* ══════════════════════════════════════════════════════════════════════════
   SCROLL REVEAL
   Elements enter as they cross into view. The hidden state is gated on
   .has-reveal, which common.js sets on <html> the moment it parses - so if
   JS never runs, nothing is ever left invisible.
   ══════════════════════════════════════════════════════════════════════════ */
.has-reveal .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity var(--duration-slower) var(--ease-out),
    transform var(--duration-slower) var(--ease-out);
  will-change: opacity, transform;
}
.has-reveal .reveal.in-view { opacity: 1; transform: none; will-change: auto; }

/* Directional variants - set by common.js so alternating sections drift in
   from opposite sides instead of everything sliding the same way. */
.has-reveal .reveal-right { transform: translateX(36px) translateY(12px); }
.has-reveal .reveal-left  { transform: translateX(-36px) translateY(12px); }
.has-reveal .reveal-scale { transform: scale(.96) translateY(16px); }
.has-reveal .reveal-fade  { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .has-reveal .reveal,
  .has-reveal .reveal-right,
  .has-reveal .reveal-left,
  .has-reveal .reveal-scale {
    opacity: 1; transform: none; transition: none;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   SCROLL ORB - progress ring + back-to-top, expands to the wordmark at the
   end of the page.
   ══════════════════════════════════════════════════════════════════════════ */
.scroll-orb {
  position: fixed;
  /* Bottom-right at EVERY width - third time this element was reported for
     covering content, so it is no longer top-anchored anywhere.
       2026-09-16: left:50% + translateX(-50%) put it on the gutter line of
         every 2-column grid, and the .complete pill grew into both columns.
         Re-anchored right, which fixed the columns.
       2026-09-23: on phones the top position sat on section headings.
         Moved to the bottom corner below 520px only.
       2026-09-28: still overlapped on desktop. The premise of the two fixes
         above - "the page is narrower than the viewport, so the orb sits in
         the empty right margin" - is simply false: .wrap-wide is 100% below
         860px and --container-lg/xl above it, so the content column reaches
         the 16px body padding on every viewport up to ~1580px. There is no
         empty right margin to sit in, at any realistic desktop width.
     Bottom-right is also where a back-to-top control is expected, and it
     only ever floats over the end of the page rather than mid-content.
     `bottom` clears the tab bar where one exists; --tabbar-h is defined for
     every page, and pages without a tab bar just get a slightly higher orb,
     which is harmless. */
  top: auto;
  bottom: calc(var(--tabbar-h) + var(--space-4) + env(safe-area-inset-bottom, 0px));
  /* Right-anchored matches .orb-mark/.orb-label's own layout, which assumes
     the mark leads on the right (RTL) and the label grows to its left, so
     the .complete pill only ever grows inward along the bottom edge. */
  right: var(--space-4);
  transform: translateY(-8px);
  z-index: 45;
  height: 46px; width: 46px;
  padding: 0;
  /* flex-start (= right, RTL) so the mark stays locked under the ring, which
     is anchored to that same edge. Centring instead would drift the logo off
     the ring's centre as soon as the label claimed width. */
  display: inline-flex; align-items: center; justify-content: flex-start;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-full);
  background: var(--bg-card);
  box-shadow: var(--shadow-md);
  cursor: pointer;
  overflow: hidden;
  opacity: 0; pointer-events: none;
  transition:
    width var(--duration-slow) var(--ease-spring),
    opacity var(--transition-normal),
    transform var(--transition-normal),
    background var(--transition-normal);
}
/* Appears once there is actually something to scroll back up from. */
.scroll-orb.visible { opacity: 1; pointer-events: auto; transform: translateY(0); }
.scroll-orb:hover { background: var(--bg-subtle); }
.scroll-orb:active { transform: scale(.94); }

/* Pinned to a fixed 46px square over the logo, NOT inset:0. Stretching it to
   the pill's width made the 48-unit viewBox re-centre itself in a 132px box
   when .complete expanded the orb, so the ring detached from the mark and cut
   through the wordmark. Anchored right because the logo leads in RTL. */
/* No rotation: the polygon's point list already starts at the top vertex and
   runs clockwise, so progress fills from 12 o'clock the way the circle did. */
.orb-ring {
  position: absolute; top: 0; right: 0;
  width: 46px; height: 46px;
  pointer-events: none;
}
.orb-track {
  fill: none; stroke: var(--border-default); stroke-width: 1.5;
  stroke-linejoin: round;
}
.orb-fill {
  fill: none; stroke: var(--accent); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  /* A regular hexagon's side equals its circumradius, so with r = 18.5 the
     perimeter is exactly 6 x 18.5 = 111 - no approximation. JS drives offset. */
  stroke-dasharray: 111;
  stroke-dashoffset: 111;
  transition: stroke-dashoffset 120ms linear;
}
/* Same 46px box as the ring, so the two stay concentric in both states. */
.orb-mark {
  width: 46px; height: 46px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
/* Smaller than the ring it sits inside, so the logo's own hexagon and the
   progress hexagon stay visually separate instead of fusing. */
.orb-mark img { width: 19px; height: 19px; object-fit: contain; display: block; }
.orb-label {
  font-weight: var(--weight-bold); font-size: var(--text-sm);
  letter-spacing: var(--tracking-tight);
  color: var(--fg-1); white-space: nowrap;
  max-width: 0; opacity: 0; overflow: hidden;
  transition: max-width var(--duration-slow) var(--ease-spring),
              opacity var(--transition-fast),
              padding var(--duration-slow) var(--ease-spring);
}
/* At the bottom of the page the ring is full, so it gives way to the name. */
/* Page is RTL, so the mark leads on the right and the label runs to its left:
   padding-left keeps the wordmark off the pill's left edge, padding-right sets
   the gap to the mark. */
.scroll-orb.complete { width: 134px; }
.scroll-orb.complete .orb-label {
  max-width: 100px; opacity: 1;
  padding-left: 18px; padding-right: 2px;
}
.scroll-orb.complete .orb-track { stroke: transparent; }

@media (max-width: 520px) {
  /* Size only - the position is the same bottom-right corner at every width
     now (see the base rule). A phone gives up proportionally more of its
     screen to the orb, so it shrinks a little here. */
  .scroll-orb { height: 42px; width: 42px; }
  .orb-ring, .orb-mark { width: 42px; height: 42px; }
  .orb-mark img { width: 17px; height: 17px; }
  .scroll-orb.complete { width: 122px; }
  .scroll-orb.complete .orb-label { padding-left: 14px; }
}
/* The watch room owns the whole viewport - no page scroll to report. */
body.in-room .scroll-orb { display: none; }
@media (prefers-reduced-motion: reduce) {
  .scroll-orb { transition: opacity var(--transition-fast); }
  .orb-fill { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   LANDING PAGE: Hero + Features
   ══════════════════════════════════════════════════════════════════════════ */
.hero { text-align: center; padding: var(--space-12) 0 var(--space-6); }
.hero-icon {
  font-size: 64px; margin-bottom: var(--space-5);
  filter: drop-shadow(0 8px 24px rgba(var(--accent-rgb), .3));
  animation: hero-float 5s var(--ease-inout) infinite;
}
.hero-logo { width: 80px; height: auto; display: block; margin: 0 auto var(--space-5); }
@keyframes hero-float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
.hero h1 {
  font-size: var(--text-4xl); margin: 0 0 var(--space-4);
  font-weight: var(--weight-extrabold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
}
.hero p {
  color: var(--fg-3); font-size: var(--text-lg);
  max-width: 640px; margin: 0 auto var(--space-8);
  line-height: var(--leading-relaxed);
}
.hero-cta { display: flex; gap: var(--gap-sm); justify-content: center; flex-wrap: wrap; margin-bottom: var(--space-2); }
.hero-cta .btn { padding: var(--padding-btn-lg); font-size: var(--text-base); }

/* Stats read as a bordered band rather than floating text - gives the hero a
   definite bottom edge and separates it from the sections below. */
.stat-row {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
  margin: var(--space-10) auto var(--space-2);
  max-width: 560px;
  padding: var(--space-6) var(--space-4);
  background: var(--bg-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-2xl);
}
.stat-row .stat { text-align: center; }
.stat-row .stat .num {
  font-size: var(--text-3xl); font-weight: var(--weight-extrabold);
  color: var(--accent); line-height: var(--leading-tight);
}
.stat-row .stat .lbl { font-size: var(--text-xs); color: var(--fg-3); margin-top: var(--space-1); }

@media (min-width: 1000px) {
  .hero { padding: var(--space-20) 0 var(--space-8); }
  .hero-logo { width: 96px; }
}

.section-heading { text-align: center; margin: var(--space-12) 0 var(--space-8); }
.section-heading h2 { font-size: var(--text-2xl); font-weight: var(--weight-extrabold); margin: 0 0 var(--space-2); }
.section-heading p { color: var(--fg-3); font-size: var(--text-sm); margin: 0; }

/* Service cards sit in a grid instead of stacking as full-width alternating
   rows - on a wide screen the old pattern left one half of every row empty. */
.feature-grid {
  display: grid; grid-template-columns: 1fr; gap: var(--gap-lg);
  margin-bottom: var(--space-8);
}
@media (min-width: 1000px) { .feature-grid { grid-template-columns: repeat(2, 1fr); } }

.feature-row {
  display: flex; flex-direction: column; gap: var(--space-5); align-items: center;
  background: var(--bg-card); border: 1px solid var(--border-default);
  border-radius: var(--radius-2xl); box-shadow: var(--shadow-sm);
  padding: var(--padding-card-lg); margin-bottom: 0;
  position: relative; overflow: hidden;
  transition: box-shadow var(--transition-normal), transform var(--transition-normal), border-color var(--transition-normal);
}
/* Accent rail along the card's inline-start edge - reads as a designed
   surface rather than a plain bordered box, and picks up the brand hue. */
.feature-row::before {
  content: ""; position: absolute; inset-block: 0; inset-inline-start: 0; width: 3px;
  background: var(--accent); opacity: 0;
  transition: opacity var(--transition-normal);
}
.feature-row:hover::before { opacity: 1; }
.feature-row:hover {
  box-shadow: var(--shadow-md); transform: translateY(-3px);
  border-color: var(--border-strong);
}
.feature-visual {
  width: 100%; max-width: 160px; aspect-ratio: 1; border-radius: var(--radius-2xl);
  display: flex; align-items: center; justify-content: center;
  font-size: 72px; flex-shrink: 0;
}
.feature-text { flex: 1; min-width: 0; text-align: center; }
.feature-text .kicker {
  font-size: var(--text-xs); font-weight: var(--weight-bold); color: var(--accent);
  margin-bottom: var(--space-1-5); letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
.feature-text h3 { font-size: var(--text-xl); font-weight: var(--weight-extrabold); margin: 0 0 var(--space-3); }
.feature-text .desc {
  color: var(--fg-3); font-size: var(--text-sm);
  line-height: var(--leading-relaxed); margin: 0 0 var(--space-4);
}
.check-list { list-style: none; margin: 0 0 var(--space-5); padding: 0; text-align: right; display: inline-block; }
.check-list li {
  display: flex; align-items: flex-start; gap: var(--gap-sm);
  font-size: var(--text-sm); color: var(--fg-3);
  margin-bottom: var(--space-2-5); line-height: var(--leading-normal);
}
.check-list li::before {
  /* Drawn as an SVG mask rather than a "✓" glyph: the character rendered at a
     different weight and baseline on every platform. currentColor still
     applies because it is a mask, not an image. */
  content: ""; flex-shrink: 0;
  width: 1.05em; height: 1.05em; margin-top: .18em;
  background: var(--color-success);
  -webkit-mask: var(--ic-check) center / contain no-repeat;
  mask: var(--ic-check) center / contain no-repeat;
}
.feature-cta { display: flex; gap: var(--gap-sm); justify-content: center; flex-wrap: wrap; }

/* Between the phone layout and the 2-up grid there is a band where a single
   card is wide enough to read as a side-by-side row. Above 1000px the cards
   pair up, so each one goes back to a vertical stack. */
@media (min-width: 700px) and (max-width: 999px) {
  .feature-row { flex-direction: row; text-align: right; padding: var(--space-8); gap: var(--space-8); }
  .feature-row.reverse { flex-direction: row-reverse; }
  .feature-text { text-align: right; }
  .feature-text .desc { margin-inline: 0; }
  .check-list { text-align: right; }
  .feature-cta { justify-content: flex-start; }
  .feature-visual { max-width: 200px; font-size: 88px; }
}
@media (min-width: 1000px) {
  .hero h1 { font-size: var(--text-5xl); }
  .feature-row { align-items: flex-start; text-align: right; }
  .feature-visual { margin-inline: auto; }
  .feature-text { text-align: right; width: 100%; }
  .check-list { text-align: right; display: block; }
  .feature-cta { justify-content: flex-start; }
}

/* ══════════════════════════════════════════════════════════════════════════
   HOW-IT-WORKS + FAQ
   ══════════════════════════════════════════════════════════════════════════ */
.how-it-works {
  list-style: none; counter-reset: step;
  display: flex; flex-direction: column; gap: var(--gap-sm);
  max-width: 480px; margin: 0 auto var(--space-5); padding: 0;
}
.how-it-works li {
  counter-increment: step; position: relative;
  padding: var(--space-3) var(--space-4) var(--space-3) var(--space-4);
  padding-inline-start: 48px;
  background: var(--bg-card); border: 1px solid var(--border-default);
  border-radius: var(--radius-xl); font-size: var(--text-sm); color: var(--fg-1);
  text-align: right;
  transition: box-shadow var(--transition-fast), transform var(--transition-fast);
}
.how-it-works li:hover { box-shadow: var(--shadow-sm); transform: translateY(-1px); }
.how-it-works li::before {
  content: counter(step); position: absolute; inset-inline-start: var(--space-3); top: 50%;
  transform: translateY(-50%); width: 26px; height: 26px; border-radius: var(--radius-full);
  background: var(--accent); color: var(--fg-on-brand);
  font-size: var(--text-xs); font-weight: var(--weight-extrabold);
  display: flex; align-items: center; justify-content: center;
}
@media (min-width: 860px) { .how-it-works { flex-direction: row; max-width: none; } .how-it-works li { flex: 1; } }

.card details { border-bottom: 1px solid var(--border-muted); padding: var(--space-3) var(--space-1); }
.card details:last-of-type { border-bottom: none; }
.card details summary {
  cursor: pointer; font-weight: var(--weight-bold); font-size: var(--text-sm);
  list-style: none; display: flex; justify-content: space-between; align-items: center;
  transition: color var(--transition-fast);
}
.card details summary:hover { color: var(--accent); }
.card details summary::-webkit-details-marker { display: none; }
.card details summary::after {
  content: ""; width: 1em; height: 1em; flex-shrink: 0;
  background: var(--fg-muted);
  -webkit-mask: var(--ic-chevron) center / contain no-repeat;
  mask: var(--ic-chevron) center / contain no-repeat;
  transition: transform var(--transition-normal);
}
.card details[open] summary::after { transform: rotate(180deg); }
.card details p { color: var(--fg-3); font-size: var(--text-xs); line-height: var(--leading-relaxed); margin: var(--space-2) 0 0; }

.compare-table { width: 100%; border-collapse: collapse; font-size: var(--text-xs); }
.compare-table th, .compare-table td {
  padding: var(--space-3) var(--space-2); text-align: right;
  border-top: 1px solid var(--border-muted);
}
.compare-table thead th { color: var(--fg-3); font-weight: var(--weight-bold); border-top: none; }

/* ── Service icons: light/dark ── */
.svc-ico { display: block; }
.svc-ico .dark-art { display: none; }
.svc-ico .light-art { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .svc-ico .dark-art { display: block; }
  :root:not([data-theme="light"]) .svc-ico .light-art { display: none; }
}
:root[data-theme="dark"] .svc-ico .dark-art { display: block; }
:root[data-theme="dark"] .svc-ico .light-art { display: none; }
:root[data-theme="light"] .svc-ico .dark-art { display: none; }
:root[data-theme="light"] .svc-ico .light-art { display: block; }
.svc-ico img { width: 100%; height: 100%; object-fit: contain; }

/* ── Glass compat (for inline styles referencing glass vars) ── */
:root {
  --glass: var(--bg-subtle);
  --glass-strong: var(--bg-card);
  --glass-border: var(--border-default);
  --glass-highlight: var(--border-muted);
}
