/* ============================================================================
   SmartObjector — design system  ·  Precision Dark (v6)
   ----------------------------------------------------------------------------
   Solid charcoal/slate grounds · subtle glass panels · crisp 1px borders.
   Functional blue accent only on CTAs, active nav, and progress.
   No neon, no glow backdrops, no diffuse card shadows.

   • Per-category accent injection via shell.js (--accent on <body>).
   • Legacy class names preserved so existing tool pages keep working.
   ============================================================================ */
/* fonts are loaded at runtime via a <link> in index.html (served by Flask at /static) */

:root{
  /* ── surfaces (solid charcoal → slate) ─────────────────────────────────── */
  --bg:#0B0D10;
  --bg-2:#111418; --bg-3:#161A20;
  --panel:rgba(22,26,32,.72); --panel-2:rgba(26,31,39,.78); --raise:#1A1F27;
  --glass:rgba(255,255,255,.03); --glass-2:rgba(255,255,255,.05); --glass-3:rgba(255,255,255,.08);
  --line:rgba(255,255,255,.12); --line-2:rgba(255,255,255,.16); --line-3:rgba(255,255,255,.22);
  /* ── text ──────────────────────────────────────────────────────────────── */
  --text:#E8ECF2; --muted:#9AA3B2; --faint:#6B7380;
  /* ── functional blue (sparse accent) ───────────────────────────────────── */
  --accent:#3B82F6; --accent-2:#60A5FA; --accent-ink:#ffffff;
  --accent-weak:rgba(59,130,246,.12); --accent-line:rgba(59,130,246,.45);
  --grad:var(--accent);
  --cat-convert:#3B82F6; --cat-textures:#3B82F6; --cat-create:#3B82F6;
  --cat-world:#3B82F6;   --cat-weapons:#3B82F6; --cat-account:#3B82F6;
  --brand:#3B82F6; --brand-2:#60A5FA; --brand-3:#2563EB;
  --brand-grad:var(--accent);
  --brand-soft:rgba(59,130,246,.12);
  /* ── semantic ───────────────────────────────────────────────────────────── */
  --discord:#5865F2; --ok:#22C55E; --warn:#D97706; --err:#DC2626; --info:#3B82F6;
  --ok-weak:rgba(34,197,94,.12); --warn-weak:rgba(217,119,6,.12);
  --err-weak:rgba(220,38,38,.12); --info-weak:rgba(59,130,246,.12);
  /* ── shape — sharp 1px borders + restrained layered elevation ──────────── */
  color-scheme:dark;
  --r-sm:8px; --r:10px; --r-lg:12px; --r-xl:14px; --r-pill:999px;
  --sh:0 1px 2px rgba(0,0,0,.35);
  --sh-md:0 6px 20px -6px rgba(0,0,0,.45);
  --sh-lg:0 24px 64px -16px rgba(0,0,0,.65);
  --sh-glow:0 0 0 1px var(--accent-line);
  --ring:0 0 0 3px var(--accent-weak);
  --blur:blur(10px);
  --ease:cubic-bezier(.22,1,.36,1); --ease-out:cubic-bezier(.16,1,.3,1); --spring:cubic-bezier(.34,1.45,.64,1);
  /* 240px left "SmartObjector" itself right at the edge of fitting next to the
     logo + collapse button (120px logo/gaps/button + ~125-130px for the bold
     13-char wordmark ≈ 250-255px needed) — it was clipping/ellipsizing on
     essentially every page since the sidebar renders everywhere. */
  --sb-w:260px; --sb-w-min:72px;
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px; --s7:48px; --s8:64px;
}

*{box-sizing:border-box}
html{scroll-behavior:smooth;background:var(--bg)}
html,body{margin:0}
body{
  --grad:var(--accent);
  font-family:'Plus Jakarta Sans',system-ui,sans-serif;
  background-color:var(--bg);
  background-image:none;
  color:var(--text);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
  letter-spacing:-.011em; line-height:1.6; min-height:100vh;
}
body::before{display:none}
body>*{position:relative;z-index:1}
a{color:inherit;text-decoration:none}
::selection{background:var(--accent);color:var(--accent-ink)}
/* Consistent heading rhythm everywhere — :where() keeps zero specificity so any
   page-level heading rule still wins untouched. */
:where(h1,h2,h3){letter-spacing:-.02em;line-height:1.2}
:where(h4,h5,h6){letter-spacing:-.01em;line-height:1.3}
/* Keyboard-accessibility: every focusable control gets a visible accent ring.
   Components that style their own :focus-visible override this (higher specificity). */
:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;border-radius:4px}
.display{font-family:'Outfit','Plus Jakarta Sans',sans-serif;letter-spacing:-.035em}
.mono{font-family:'IBM Plex Mono',ui-monospace,monospace}
.container{max-width:1180px;margin:0 auto;padding:0 32px}

/* shared stroke icons (icons.js → ORI.ico) */
.ori-ico{width:1.15em;height:1.15em;display:inline-block;vertical-align:-.2em;stroke:currentColor;stroke-width:1.8;fill:none;flex:0 0 auto;overflow:visible}
.ori-ico.lg{width:1.45em;height:1.45em}
.ori-ico.xl{width:2em;height:2em}
.btn .ori-ico,.primary .ori-ico,.ghost .ori-ico{width:17px;height:17px;vertical-align:middle}
.btn-lg .ori-ico{width:18px;height:18px}
.big>.ori-ico,.empty .ori-ico,.big .ori-ico{width:48px;height:48px;stroke-width:1.35;vertical-align:middle}
.sb-burger .ori-ico,.sb-collapse .ori-ico{width:18px;height:18px}
.chip .ori-ico,.spt .ori-ico,.copt .ico .ori-ico,.abil .ico .ori-ico{width:16px;height:16px}
.badge .ori-ico{width:12px;height:12px;margin-right:3px;vertical-align:-.1em}
.vref .ori-ico{width:14px;height:14px;margin-right:4px}

select{color:var(--text);background-color:var(--bg-2)}
option{background-color:#000;color:#fff}
option:disabled{color:#666}
option:checked,option:hover{
  background:#c5c5c5 linear-gradient(0deg,#c5c5c5 0%,#c5c5c5 100%);
  color:#000;
}
optgroup{background-color:#0a0a0a;color:var(--muted);font-weight:700}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(255,255,255,.1);border-radius:99px;border:2px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:rgba(59,130,246,.35);background-clip:content-box}

/* aura disabled — keep class for markup compatibility, no visual effect */
.aura{display:none}

/* ============================================================== BORDER CHASE */
.so-chase{position:relative;isolation:isolate}
.so-chase::after{
  content:"";position:absolute;inset:0;border-radius:inherit;padding:1px;
  background:conic-gradient(from var(--so-chase-a,0deg),var(--accent) 0deg,transparent 110deg,transparent 360deg);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;
  opacity:0;pointer-events:none;z-index:2;transition:opacity .18s var(--ease);
}
.so-chase:hover::after,.so-chase.is-active::after,.so-chase.is-loading::after{
  opacity:1;animation:so-chase-spin 1.2s linear infinite;
}
.so-chase.is-active{border-color:var(--border-strong,var(--line-2));background:var(--raise)}
.so-chase.is-ok::after{background:conic-gradient(from var(--so-chase-a,0deg),var(--ok) 0deg,transparent 110deg,transparent 360deg);animation:none;opacity:1}
@keyframes so-chase-spin{to{--so-chase-a:360deg}}
@property --so-chase-a{
  syntax:"<angle>";inherits:false;initial-value:0deg;
}

/* ============================================================== SIDEBAR */
.sidebar{position:fixed;left:0;top:0;bottom:0;width:var(--sb-w);z-index:80;display:flex;flex-direction:column;
  background:var(--panel);
  backdrop-filter:var(--blur);
  -webkit-backdrop-filter:var(--blur);
  border-right:1px solid var(--line);
  transition:width .28s var(--ease)}
.sidebar::before,.sidebar::after{display:none}
/* content gutter: keep every page a comfortable distance from the sidebar edge.
   The padding transition only arms once shell.js stamps sb-ready (post-first-layout),
   so pages never slide in from padding 0 on load. */
body.has-sidebar{padding-left:calc(var(--sb-w) + var(--content-gap,22px));
  padding-right:var(--content-gap,22px)}
body.sb-ready{transition:padding-left .3s var(--ease)}
body.sb-collapsed{padding-left:calc(var(--sb-w-min) + var(--content-gap,22px))}
body.sb-collapsed .sidebar{width:var(--sb-w-min)}
body.has-sidebar .nav{display:none}

.sb-top{display:flex;align-items:center;gap:11px;padding:18px 16px 14px;position:relative;flex-wrap:nowrap}
/* In-app software update banner */
#soUpdateBar{position:fixed;left:0;right:0;top:0;z-index:80;pointer-events:none;
  padding:10px 14px;display:flex;justify-content:center}
#soUpdateBar .so-upd-inner{pointer-events:auto;display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  max-width:min(720px,100%);padding:10px 14px;border-radius:var(--r);
  background:var(--panel-2);border:1px solid var(--accent-line);box-shadow:var(--sh-md);
  backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);
  color:var(--text);font-size:13px;font-weight:550;
  animation:soUpdIn .3s var(--ease-out) both}
@keyframes soUpdIn{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
#soUpdateBar b{color:var(--text);font-weight:750}
#soUpdateBar .so-upd-cur{color:var(--muted);font-weight:500}
#soUpdateBar .so-upd-btn{border:1px solid transparent;cursor:pointer;border-radius:var(--r-sm);padding:8px 14px;
  font:inherit;font-weight:700;font-size:13px;color:var(--accent-ink);
  background:var(--accent)}
#soUpdateBar .so-upd-btn:hover{background:var(--accent-2)}
#soUpdateBar .so-upd-btn:disabled{opacity:.65;cursor:wait}
#soUpdateBar .so-upd-x{border:0;background:transparent;color:var(--muted);cursor:pointer;
  font-size:18px;line-height:1;padding:4px 6px;border-radius:var(--r-sm)}
#soUpdateBar .so-upd-x:hover{color:var(--text);background:var(--glass-2)}
body.has-sidebar #soUpdateBar{padding-left:calc(var(--sb-w, 240px) + 14px)}
body.has-sidebar.sb-collapsed #soUpdateBar{padding-left:calc(var(--sb-w-min, 72px) + 14px)}

.sb-brand{display:flex;align-items:center;gap:11px;font-weight:700;font-size:16.5px;letter-spacing:-.025em;
  min-width:0;flex:1 1 auto;overflow:hidden}
.sb-logo{width:36px;height:36px;border-radius:50%;background:var(--bg-2);display:grid;place-items:center;
  color:#fff;font-size:15px;font-weight:800;flex:0 0 auto;overflow:hidden;
  border:1px solid var(--line)}
.sb-logo img{width:100%;height:100%;object-fit:cover;display:block}
.sb-word{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.sb-word b{font-weight:400;font-family:'Alfa Slab One','Outfit',sans-serif;letter-spacing:-.01em}
/* Shell chrome lives on every page, so it must be immune to page-level CSS.
   Tool pages style their own controls with a bare `button{padding:13px;…}`
   rule, which used to win on any property this class left undeclared —
   padding was the one that mattered: it pushed the arrow glyph ~8px down and
   right, out of its own 30px box (Fix Props, Texture Studio, Extract
   Textures, 3D Text, Flying Car), and weapon.html's `padding:12px 16px` even
   stretched the button to 34px. Declaring the full box here (a class beats a
   bare element selector) is what keeps the arrow put. Same reasoning applies
   to .sb-burger below — don't trim these back to "what looks needed". */
.sb-collapse{margin:0 0 0 auto;padding:0;width:30px;height:30px;min-width:30px;max-width:30px;
  min-height:30px;max-height:30px;box-sizing:border-box;
  border-radius:var(--r-sm);border:1px solid var(--line);background:var(--glass);
  color:var(--muted);cursor:pointer;display:grid;place-items:center;font-size:13px;line-height:1;
  font-family:inherit;font-weight:600;appearance:none;-webkit-appearance:none;
  flex:0 0 30px;transition:color .15s,background .15s,border-color .15s}
.sb-collapse:hover{color:var(--text);background:var(--glass-2);border-color:var(--line-2)}
.sb-collapse:active{transform:scale(.94)}

.sb-nav{flex:1;overflow-y:auto;padding:6px 10px 14px;display:flex;flex-direction:column;gap:2px}
.sb-group{margin-top:13px}
.sb-label{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);font-weight:700;padding:5px 10px 7px;
  display:flex;align-items:center;gap:8px}
.sb-label::after{content:"";flex:1;height:1px;background:var(--line)}
.sb-item{position:relative;display:flex;align-items:center;gap:12px;padding:9px 11px;border-radius:var(--r);
  border:1px solid transparent;color:var(--muted);
  font-size:13.5px;font-weight:550;transition:color .16s,background .16s,border-color .16s;white-space:nowrap;overflow:hidden}
.sb-item svg{width:18px;height:18px;flex:0 0 auto;stroke:currentColor;stroke-width:1.6;fill:none;
  transition:transform .18s var(--ease)}
.sb-item:hover{color:var(--text);background:var(--glass);border-color:var(--line)}
.sb-item:hover svg{transform:translateX(1px) scale(1.06)}
.sb-item.is-active{color:var(--text);background:var(--accent-weak);border-color:transparent}
.sb-item.is-active::before{content:"";position:absolute;left:0;top:8px;bottom:8px;width:2px;border-radius:0 2px 2px 0;
  background:var(--accent)}
.sb-item.is-active svg{color:var(--accent-2)}
.sb-item .sb-x{margin-left:auto;font-size:9.5px;font-weight:800;letter-spacing:.06em;color:var(--accent-ink);
  background:var(--accent);padding:2px 7px;border-radius:6px}

.sb-foot{margin-top:auto;padding:12px 12px 14px;display:flex;flex-direction:column;gap:0;
  border-top:none;position:relative}
.sb-foot::before{content:"";position:absolute;left:14px;right:14px;top:0;height:1px;
  background:var(--line)}
.sb-acct{display:flex;align-items:center;gap:12px;margin-top:12px;padding:10px 10px 10px 11px;
  border:1px solid var(--line);border-radius:var(--r-lg);
  background:var(--bg-2);position:relative;overflow:hidden;
  transition:background .2s var(--ease),border-color .2s var(--ease)}
.sb-acct::before{display:none}
.sb-acct:hover{background:var(--raise);border-color:var(--line-2)}
.sb-av{width:36px;height:36px;border-radius:50%;background:var(--accent);
  display:grid;place-items:center;color:#fff;font-size:13px;font-weight:800;font-family:'Outfit',sans-serif;
  flex:0 0 auto;overflow:hidden;letter-spacing:-.02em;text-decoration:none;
  border:1px solid var(--line-2);position:relative;z-index:1}
.sb-av img{width:100%;height:100%;object-fit:cover;display:block}
.sb-acct .who{min-width:0;flex:1;overflow:hidden;position:relative;z-index:1;
  display:flex;flex-direction:column;gap:3px;justify-content:center;text-decoration:none;color:inherit}
.sb-acct .nm{display:block;font-size:13px;font-weight:650;color:var(--text);line-height:1.2;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;letter-spacing:-.015em}
.sb-acct .tk{display:inline-flex;align-items:center;gap:5px;font-size:11px;color:var(--muted);
  font-weight:600;line-height:1;margin:0}
.sb-acct .tk svg{width:12px;height:12px;stroke:var(--accent-2);stroke-width:1.9;fill:none;flex:0 0 auto}
.sb-acct .tk b{color:var(--accent-2);font-weight:750;font-variant-numeric:tabular-nums}
.sb-logout{width:32px;height:32px;border-radius:12px;display:grid;place-items:center;color:var(--faint);
  border:none;background:transparent;flex:0 0 auto;transition:color .18s,background .18s;position:relative;z-index:1}
.sb-logout svg{width:16px;height:16px;stroke:currentColor;stroke-width:1.8;fill:none}
.sb-logout:hover{color:var(--err);background:var(--err-weak)}

body.sb-collapsed .sb-word,body.sb-collapsed .sb-label,body.sb-collapsed .sb-item span:not(.sb-x),
body.sb-collapsed .sb-acct .who,body.sb-collapsed .sb-item .sb-x{display:none}
body.sb-collapsed .sb-top{flex-direction:column;justify-content:center;gap:10px;padding:16px 0 14px}
body.sb-collapsed .sb-collapse{margin:0}
/* overflow must be visible here or the hover tooltip (::after, positioned past the
   item's right edge) is clipped by the base .sb-item{overflow:hidden} */
body.sb-collapsed .sb-item{justify-content:center;padding:11px 0;overflow:visible}
body.sb-collapsed .sb-group{margin-top:10px}
body.sb-collapsed .sb-label{padding:5px 0;justify-content:center}
body.sb-collapsed .sb-label::after{display:none}
body.sb-collapsed .sb-foot{padding:10px 0 14px;align-items:center}
body.sb-collapsed .sb-foot::before{left:18%;right:18%}
body.sb-collapsed .sb-acct{justify-content:center;padding:8px;margin-top:10px;width:auto;border-radius:14px}
body.sb-collapsed .sb-logout{display:none}
body.sb-collapsed .sb-item::after{content:attr(data-label);position:absolute;left:calc(100% + 10px);top:50%;transform:translateY(-50%) scale(.96);
  background:var(--raise);border:1px solid var(--line-2);color:var(--text);font-size:12.5px;font-weight:600;box-shadow:var(--sh-md);
  padding:6px 11px;border-radius:var(--r);white-space:nowrap;pointer-events:none;opacity:0;transition:.14s var(--ease);z-index:5}
body.sb-collapsed .sb-item:hover::after{opacity:1;transform:translateY(-50%) scale(1)}

.sb-burger{position:fixed;top:14px;left:14px;z-index:90;width:42px;height:42px;min-width:42px;max-width:42px;
  min-height:42px;max-height:42px;border-radius:14px;display:none;margin:0;padding:0;box-sizing:border-box;
  align-items:center;justify-content:center;border:1px solid var(--line-2);background:rgba(10,10,10,.92);
  color:var(--text);cursor:pointer;font-size:17px;font-family:inherit;line-height:1;
  appearance:none;-webkit-appearance:none}
.sb-scrim{position:fixed;inset:0;z-index:79;background:rgba(0,0,0,.6);opacity:0;pointer-events:none;transition:opacity .25s}
@media(max-width:900px){
  body.has-sidebar{padding-left:14px;padding-right:14px}
  /* fully hide the off-canvas sidebar so badges/pills can't peek past the edge */
  .sidebar{transform:translateX(-100%);visibility:hidden;
    transition:transform .3s var(--ease),visibility 0s .3s}
  body.sb-open .sidebar{transform:none;visibility:visible;
    transition:transform .3s var(--ease)}
  body.sb-open .sb-scrim{opacity:1;pointer-events:auto}
  .sb-burger{display:flex}
  /* Once the sidebar slides in, its own brand row sits right under this
     fixed-position button (both start near 14-16px from the corner) — left
     visible, the two visually collide into what looks like a second,
     misplaced arrow floating over the SmartObjector logo. The scrim (tap
     anywhere outside the sidebar) already closes it, so the burger doesn't
     need to stay up while open. */
  body.sb-open .sb-burger{display:none}
  body.sb-collapsed .sidebar{width:var(--sb-w)}
  body.sb-collapsed .sb-word,body.sb-collapsed .sb-label,body.sb-collapsed .sb-item span:not(.sb-x){display:inline}
  body.sb-collapsed .sb-top{flex-direction:row;padding:18px 16px 14px}
  body.sb-collapsed .sb-item::after{display:none}
  .sb-collapse{display:none}
}

/* ---------------------------------------------------------------- top nav */
.nav{position:sticky;top:0;z-index:60;
  background:rgba(5,5,5,.7);border-bottom:1px solid var(--line)}
.nav .container{display:flex;align-items:center;gap:8px;height:68px}
.brand{display:flex;align-items:center;gap:11px;font-weight:700;font-size:17.5px;letter-spacing:-.025em;font-family:'Outfit',sans-serif}
.brand .logo{width:34px;height:34px;border-radius:50%;background:var(--bg-2);display:grid;place-items:center;
  border:1px solid var(--line);
  color:var(--accent-ink);font-size:15px;font-weight:800;overflow:hidden}
.brand .logo img{width:100%;height:100%;object-fit:cover;display:block}
.brand b{font-weight:400;font-family:'Alfa Slab One','Outfit',sans-serif;letter-spacing:-.01em}
.nav .spacer{flex:1}
.nav a.link{position:relative;color:var(--muted);font-size:14px;font-weight:550;padding:8px 13px;border-radius:12px;transition:color .15s}
.nav a.link:hover{color:var(--text)}
.nav a.link.is-active{color:var(--text)}
.nav a.link.is-active::after{content:"";position:absolute;left:13px;right:13px;bottom:1px;height:2px;border-radius:2px;background:var(--accent)}

/* ============================================================== BUTTONS */
.btn{display:inline-flex;align-items:center;gap:9px;justify-content:center;border:1px solid transparent;
  border-radius:var(--r-sm);padding:10px 16px;font-size:14px;font-weight:650;cursor:pointer;font-family:inherit;
  transition:background .18s,border-color .18s,color .18s,transform .12s var(--ease),box-shadow .18s;
  white-space:nowrap;-webkit-tap-highlight-color:transparent;min-height:38px}
.btn svg{width:17px;height:17px;stroke:currentColor;stroke-width:1.9;fill:none;flex:0 0 auto}
.btn:hover{transform:translateY(-1px)}
.btn:active{transform:translateY(0) scale(.985)}
.btn:focus-visible{outline:none;border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
.btn:disabled,.btn[aria-disabled=true]{opacity:.4;cursor:not-allowed;pointer-events:none}
.btn-primary{background:var(--accent);color:var(--accent-ink);border-color:var(--brand-3);box-shadow:var(--sh)}
.btn-primary:hover{background:var(--accent-2);border-color:var(--accent);box-shadow:var(--sh-md)}
.btn-glass{background:var(--glass-2);color:var(--text);border-color:var(--line-2)}
.btn-glass:hover{background:var(--raise);border-color:var(--line-3)}
.btn-ghost{background:transparent;color:var(--muted);border-color:transparent}
.btn-ghost:hover{background:var(--glass);color:var(--text);border-color:var(--line)}
.btn-outline{background:transparent;color:var(--accent-2);border-color:var(--accent-line)}
.btn-outline:hover{background:var(--accent-weak);border-color:var(--accent)}
.btn-danger{background:var(--err-weak);color:var(--err);border-color:rgba(220,38,38,.35)}
.btn-danger:hover{background:rgba(220,38,38,.2)}
.btn-discord{background:var(--discord);color:#fff;border-color:transparent}
.btn-discord:hover{filter:brightness(1.06)}
.btn-sm{padding:7px 12px;font-size:13px;min-height:32px;border-radius:var(--r-sm)}
.btn-lg{padding:12px 20px;font-size:15px;min-height:42px;border-radius:var(--r)}
.btn-block{width:100%}
.btn-icon{padding:0;width:38px;height:38px;min-height:38px;border-radius:var(--r-sm)}

/* ============================================================== CARDS */
.glass{background:var(--panel);
  border:1px solid var(--line);border-radius:var(--r-lg);
  backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);
  box-shadow:var(--sh)}
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--sh);position:relative;
  backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur)}
.card-pad{padding:20px}
.card-hover{transition:border-color .2s,background .2s,transform .18s var(--ease),box-shadow .2s}
.card-hover:hover{border-color:var(--line-2);background:var(--panel-2);transform:translateY(-2px);box-shadow:var(--sh-md)}
.card-accent:hover{border-color:var(--accent-line)}
.card-head{display:flex;align-items:center;gap:11px;padding:14px 16px;border-bottom:1px solid var(--line)}
.card-head .t{font-weight:700;font-size:14.5px;letter-spacing:-.01em}
.card-head .ico{width:32px;height:32px;border-radius:var(--r-sm);display:grid;place-items:center;background:var(--bg-2);border:1px solid var(--line);color:var(--accent-2);flex:0 0 auto}
.card-head .ico svg{width:16px;height:16px;stroke:currentColor;stroke-width:1.8;fill:none}

.tile{padding:16px;border-radius:var(--r-lg);background:var(--panel);border:1px solid var(--line);
  display:flex;flex-direction:column;gap:8px;transition:border-color .2s,background .2s,transform .18s var(--ease)}
.tile:hover{border-color:var(--line-2);background:var(--panel-2);transform:translateY(-1px)}
.tile .k{color:var(--muted);font-size:12px;font-weight:500}
.tile .v{font-family:'Outfit',sans-serif;font-size:24px;font-weight:700;letter-spacing:-.02em;line-height:1.3;
  font-variant-numeric:tabular-nums}

/* ============================================================== PILLS */
.pill{display:inline-flex;gap:9px;align-items:center;font-size:12.5px;color:var(--muted);font-weight:550;
  background:var(--glass);border:1px solid var(--line);padding:7px 14px;border-radius:var(--r-pill);
  transition:border-color .18s,color .18s,background .18s}
.pill:hover{border-color:var(--line-2);color:var(--text);background:var(--glass-2)}
.pill .dot{width:6px;height:6px;border-radius:50%;background:var(--ok)}
.eyebrow{color:var(--accent-2);font-weight:650;font-size:12px;letter-spacing:.18em;text-transform:uppercase}
.tag{font-size:9.5px;font-weight:800;letter-spacing:.06em;color:var(--accent-ink);background:var(--accent);padding:2px 8px;border-radius:99px}

/* ============================================================== INPUTS */
.field{display:block;margin-bottom:14px}
.field>.lbl,label.lbl{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--muted);margin-bottom:7px;font-weight:650;letter-spacing:.01em}
.field .req{color:var(--accent-2)}
.input,.select,.textarea{width:100%;padding:11px 13px;background:var(--raise);border:1px solid var(--line);
  border-radius:var(--r-sm);color:var(--text);font-size:14px;font-family:inherit;transition:border-color .15s,background .15s}
.input::placeholder,.textarea::placeholder{color:var(--faint)}
.input:hover,.select:hover,.textarea:hover{border-color:var(--line-2)}
.input:focus,.select:focus,.textarea:focus{outline:none;border-color:var(--accent);background:var(--bg-3);box-shadow:var(--ring)}
.input.is-error,.select.is-error,.textarea.is-error{border-color:var(--err);box-shadow:0 0 0 3px var(--err-weak)}
.textarea{resize:vertical;min-height:90px;line-height:1.5}
.select{appearance:none;-webkit-appearance:none;-moz-appearance:none;
  background-color:var(--bg-2);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239a9a9a' stroke-width='2.2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;padding-right:36px}
.select option{background-color:#000;color:#fff}
.select option:checked,.select option:hover{
  background:#c5c5c5 linear-gradient(0deg,#c5c5c5 0%,#c5c5c5 100%);
  color:#000;
}
.help{font-size:11.5px;color:var(--faint);line-height:1.5;margin-top:6px}
.err-text{font-size:11.5px;color:var(--err);line-height:1.5;margin-top:6px;display:flex;align-items:center;gap:6px}
input[type=range]{accent-color:var(--accent)}
input[type=checkbox],input[type=radio]{accent-color:var(--accent)}

.toggle{position:relative;display:inline-flex;align-items:center;gap:10px;cursor:pointer;font-size:13.5px;color:var(--text);user-select:none}
.toggle input{position:absolute;opacity:0;width:0;height:0}
.toggle .track{width:42px;height:24px;border-radius:99px;background:var(--glass-3);border:1px solid var(--line-2);transition:.2s var(--ease);flex:0 0 auto;position:relative}
.toggle .track::after{content:"";position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:#cfcfcf;transition:.22s var(--spring);box-shadow:0 2px 4px rgba(0,0,0,.35)}
.toggle input:checked+.track{background:var(--accent);border-color:transparent}
.toggle input:checked+.track::after{transform:translateX(18px);background:#fff}
.toggle input:focus-visible+.track{box-shadow:0 0 0 3px var(--accent-weak)}

.seg{display:inline-flex;gap:4px;background:var(--bg-2);border:1px solid var(--line);border-radius:14px;padding:4px}
.seg-item{padding:9px 14px;border-radius:12px;background:transparent;color:var(--muted);font-size:13.5px;font-weight:600;
  cursor:pointer;border:none;font-family:inherit;display:inline-flex;align-items:center;gap:8px;transition:.15s}
.seg-item svg{width:16px;height:16px;stroke:currentColor;stroke-width:1.8;fill:none}
.seg-item:hover{color:var(--text)}
.seg-item:focus-visible{outline:none;box-shadow:var(--ring)}
.seg-item.is-active,.seg-item.active{background:var(--accent-weak);color:var(--accent-2);box-shadow:inset 0 0 0 1px var(--accent-line)}

/* ============================================================== DROPZONE */
.dropzone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;
  min-height:240px;padding:36px;text-align:center;border-radius:var(--r-lg);cursor:pointer;
  background:var(--bg-workspace,var(--bg-2));border:1px dashed var(--line-2);transition:border-color .2s,background .2s;overflow:hidden}
.dropzone::before{display:none}
.dropzone:hover{border-color:var(--accent-line);background:var(--bg-3)}
.dropzone.is-drag{border-color:var(--accent);border-style:solid;background:var(--accent-weak)}
.dropzone .dz-ico{width:56px;height:56px;border-radius:var(--r);display:grid;place-items:center;background:var(--raise);
  border:1px solid var(--line);color:var(--accent-2);transition:transform .2s var(--ease),border-color .2s}
.dropzone:hover .dz-ico{border-color:var(--line-2);transform:translateY(-2px)}
.dropzone.is-drag .dz-ico{transform:scale(1.06)}
.dropzone .dz-ico svg{width:28px;height:28px;stroke:currentColor;stroke-width:1.5;fill:none}
.dropzone .dz-title{font-size:16px;font-weight:700;letter-spacing:-.01em}
.dropzone .dz-sub{font-size:13px;color:var(--muted)}
.dropzone .dz-formats{display:flex;flex-wrap:wrap;gap:6px;justify-content:center;margin-top:4px}
.dropzone .dz-formats span{font-size:10.5px;font-weight:700;letter-spacing:.04em;color:var(--muted);
  background:var(--glass);border:1px solid var(--line);padding:3px 8px;border-radius:6px}

/* ============================================================== PROGRESS */
.steps{display:flex;flex-direction:column;gap:2px}
.step{display:flex;align-items:center;gap:13px;padding:11px 4px;position:relative}
.step .dot{width:26px;height:26px;border-radius:50%;flex:0 0 auto;display:grid;place-items:center;font-size:12px;font-weight:700;
  background:var(--bg-3);border:1px solid var(--line-2);color:var(--faint);transition:.25s var(--ease);position:relative;z-index:1}
.step .dot svg{width:14px;height:14px;stroke:currentColor;stroke-width:3;fill:none}
.step.step-err .dot{background:var(--err);border-color:transparent;color:#fff;animation:none}
.step.step-err .lbl{color:var(--err)}
.step:not(:last-child) .dot::after{content:"";position:absolute;top:100%;left:50%;transform:translateX(-50%);width:2px;height:13px;background:var(--line-2);transition:background .3s}
.step .lbl{font-size:13.5px;font-weight:600;color:var(--muted);transition:color .25s}
.step .sub{font-size:11.5px;color:var(--faint)}
.step.is-done .dot{background:var(--ok);border-color:transparent;color:#04130d}
.step.is-done:not(:last-child) .dot::after{background:var(--ok)}
.step.is-done .lbl{color:var(--text)}
.step.is-active .dot{background:var(--accent);border-color:transparent;color:var(--accent-ink);animation:none;
  box-shadow:0 0 0 4px var(--accent-weak)}
.step.is-active .lbl{color:var(--text)}
.step .spin{width:13px;height:13px;border:2px solid rgba(255,255,255,.35);border-top-color:currentColor;border-radius:50%;animation:spin .7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

.bar{height:4px;border-radius:2px;background:var(--bg-3);overflow:hidden;border:1px solid var(--line)}
.bar>i{display:block;height:100%;border-radius:1px;width:0;transition:width .4s var(--ease);
  background:linear-gradient(90deg,var(--accent),var(--accent-2));position:relative;overflow:hidden}
.bar>i::after{content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.22),transparent);
  transform:translateX(-100%);animation:barSheen 1.8s var(--ease) infinite}
@keyframes barSheen{to{transform:translateX(100%)}}

/* ============================================================== STATUS */
.status{display:inline-flex;align-items:center;gap:7px;padding:4px 11px;border-radius:var(--r-pill);font-size:11.5px;font-weight:700;letter-spacing:.01em;border:1px solid transparent}
.status .d{width:6px;height:6px;border-radius:50%;background:currentColor}
.status-ok{background:var(--ok-weak);color:var(--ok);border-color:rgba(52,211,153,.24)}
.status-warn{background:var(--warn-weak);color:var(--warn);border-color:rgba(251,191,36,.24)}
.status-err{background:var(--err-weak);color:var(--err);border-color:rgba(248,113,113,.24)}
.status-info{background:var(--info-weak);color:var(--info);border-color:rgba(96,165,250,.24)}
.status-busy{background:var(--accent-weak);color:var(--accent-2);border-color:var(--accent-line)}
.status-busy .d{animation:blink 1s ease-in-out infinite}
@keyframes blink{50%{opacity:.3}}
.status-idle{background:var(--glass-2);color:var(--muted);border-color:var(--line)}

/* ============================================================== EMPTY */
.empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;text-align:center;padding:56px 32px;color:var(--muted)}
.empty .e-ico{width:74px;height:74px;border-radius:22px;display:grid;place-items:center;color:var(--faint);
  background:var(--glass-2);border:1px solid var(--line);position:relative}
.empty .e-ico svg{width:34px;height:34px;stroke:currentColor;stroke-width:1.4;fill:none}
.empty .e-ico::after{display:none}
.empty .e-title{font-size:16px;font-weight:700;color:var(--text);letter-spacing:-.01em}
.empty .e-sub{font-size:13.5px;max-width:380px;line-height:1.6}

/* ============================================================== MODAL */
.modal{position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;padding:24px;
  background:rgba(0,0,0,.72);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  animation:modalIn .2s var(--ease)}
.modal-card{background:var(--panel-2);border:1px solid var(--line-2);border-radius:var(--r-lg);box-shadow:var(--sh-lg);
  max-width:min(560px,94vw);max-height:92vh;overflow:hidden;display:flex;flex-direction:column;animation:cardIn .22s var(--ease-out)}
.modal-card.lg{max-width:min(860px,94vw)}
.modal-head{display:flex;align-items:center;gap:11px;padding:18px 20px;border-bottom:1px solid var(--line)}
.modal-head .t{font-weight:700;font-size:16px;letter-spacing:-.01em;flex:1}
.modal-x{width:32px;height:32px;border-radius:12px;border:1px solid var(--line);background:var(--glass);color:var(--muted);cursor:pointer;display:grid;place-items:center;font-size:16px;transition:color .15s,background .15s,border-color .15s,transform .12s}
.modal-x:hover{color:var(--text);background:var(--glass-2);border-color:var(--line-2)}
.modal-x:active{transform:scale(.9)}
.modal-body{padding:20px;overflow:auto}
.modal-foot{display:flex;gap:10px;justify-content:flex-end;padding:16px 20px;border-top:1px solid var(--line)}
@keyframes modalIn{from{opacity:0}to{opacity:1}}
@keyframes cardIn{from{opacity:0;transform:translateY(14px) scale(.97)}to{opacity:1;transform:none}}

/* ============================================================== TOOLTIP */
[data-tip]{position:relative}
[data-tip]::after{content:attr(data-tip);position:absolute;bottom:calc(100% + 9px);left:50%;transform:translateX(-50%) translateY(4px);
  background:var(--raise);border:1px solid var(--line-2);color:var(--text);font-size:11.5px;font-weight:600;line-height:1.3;box-shadow:var(--sh-md);
  padding:6px 10px;border-radius:var(--r-sm);white-space:nowrap;pointer-events:none;opacity:0;transition:.16s var(--ease);z-index:50}
[data-tip]::before{content:"";position:absolute;bottom:calc(100% + 4px);left:50%;transform:translateX(-50%);
  border:5px solid transparent;border-top-color:var(--line-2);opacity:0;transition:.16s var(--ease);z-index:50}
[data-tip]:hover::after{opacity:1;transform:translateX(-50%) translateY(0)}
[data-tip]:hover::before{opacity:1}

/* ============================================================== CODE */
.code{border:1px solid var(--line-2);border-radius:var(--r);overflow:hidden;background:var(--bg-2)}
.code-head{display:flex;align-items:center;gap:8px;padding:9px 13px;border-bottom:1px solid var(--line);background:var(--glass);font-size:11.5px;color:var(--muted);font-weight:600}
.code-head .lang{margin-left:auto;font-family:'IBM Plex Mono',monospace;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--faint)}
.code-copy{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border-radius:10px;border:1px solid var(--line-2);background:var(--glass-2);color:var(--muted);font-size:11px;font-weight:600;cursor:pointer;transition:.15s;font-family:inherit}
.code-copy:hover{color:var(--text);border-color:var(--line-3)}
.code-copy.copied{color:var(--ok);border-color:rgba(52,211,153,.4)}
.code pre{margin:0;padding:14px 15px;font-family:'IBM Plex Mono',monospace;font-size:12px;line-height:1.65;color:#c7c7c7;
  max-height:340px;overflow:auto;white-space:pre;tab-size:2}
.code pre .tag{color:#7ba3ff;background:none;padding:0;font:inherit}

/* ============================================================== TOOL LAYOUT */
.tool{display:flex;flex-direction:column}
.tool-main{flex:1;min-width:0;display:flex;flex-direction:column;overflow:hidden;position:relative}
.tool-aside{flex:0 0 384px;width:384px;background:var(--bg-2);
  border-left:1px solid var(--line);display:flex;flex-direction:column;overflow:hidden}
.tool-aside .aside-scroll{overflow-y:auto;padding:20px;display:flex;flex-direction:column;gap:16px;flex:1}
@media(max-width:980px){.tool{height:auto;flex-direction:column}.tool-aside{flex:none;width:100%;border-left:none;border-top:1px solid var(--line)}}

body.has-sidebar .container{max-width:none;width:100%;padding:0 30px}
body.has-sidebar .tool{max-width:none;margin-left:0;margin-right:0;width:auto}

.split{display:grid;grid-template-columns:minmax(0,1fr) var(--aside,400px);gap:20px;align-items:start}
.split>.ws-side{display:flex;flex-direction:column;gap:16px;min-width:0}
.split>.ws-main{display:flex;flex-direction:column;gap:16px;min-width:0}
.split>.viewer,.split>.ws-main .viewer{min-height:60vh}
.split>.ws-main>.drop:only-child{min-height:56vh;justify-content:center}

@media(min-width:1081px){
  body.has-sidebar:has(.split){overflow:hidden}
  body.has-sidebar .tool:has(.split){height:100vh;padding-top:22px;padding-bottom:22px;gap:16px}
  .tool>.split{flex:1 1 auto;min-height:0;align-items:stretch}
  .split>.viewer{height:100%;min-height:0}
  .split>.ws-main{height:100%;min-height:0}
  .split>.ws-main .viewer{flex:1;min-height:0}
  .split>.ws-main>.drop:only-child{flex:1;min-height:0}
  .split>.ws-side{height:100%;overflow-y:auto;overscroll-behavior:contain;padding-right:6px;
    scrollbar-gutter:stable}
}
@media(max-width:1080px){
  .split{grid-template-columns:1fr}
  .split>.viewer,.split>.ws-main .viewer{min-height:340px}
}

.tool-head{display:flex;align-items:center;gap:14px;row-gap:10px;padding:16px 22px;border-bottom:1px solid var(--line);
  background:var(--bg-2);min-height:64px;flex-wrap:wrap}
.tool-head .th-actions{flex-wrap:wrap}
.tool-head .th-ico{width:40px;height:40px;border-radius:14px;display:grid;place-items:center;background:var(--accent-weak);color:var(--accent-2);flex:0 0 auto;box-shadow:inset 0 0 0 1px var(--accent-line)}
.tool-head .th-ico svg{width:20px;height:20px;stroke:currentColor;stroke-width:1.8;fill:none}
.tool-head .th-txt{min-width:0}
.tool-head h1{font-size:17px;font-weight:800;letter-spacing:-.02em;margin:0;line-height:1.2;font-family:'Sora','Outfit',sans-serif}
.tool-head .th-sub{font-size:12.5px;color:var(--muted);margin:0}
.tool-head .th-actions{margin-left:auto;display:flex;align-items:center;gap:10px}

/* Tool page titles ("Fix Props", "3D Text", …). Each of the 22 tool pages
   declares its own `.wz-tt h1{font-family:'Outfit'…}` in a page-local \3c style>
   that loads after this file, so an equal-specificity rule here would lose.
   Qualifying with the parent (.wz-head .wz-tt h1) outranks it and keeps all
   22 titles on one font without editing — and re-editing — 22 files.
   Sora at 800 reads heavier and more technical than Outfit's rounder 700. */
.wz-head .wz-tt h1,.mb-top h1{
  font-family:'Sora','Outfit','Plus Jakarta Sans',sans-serif;
  font-weight:800;letter-spacing:-.022em;line-height:1.15;
}

.crumb{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--faint);font-weight:500}
.crumb a{color:var(--muted)}.crumb a:hover{color:var(--text)}
.crumb .sep{opacity:.5}
.crumb .cur{color:var(--accent-2)}

.result-card{border:1px solid var(--accent-line);border-radius:var(--r-lg);background:var(--accent-weak);overflow:hidden}
.result-card .rc-top{display:flex;align-items:center;gap:11px;padding:16px 18px;border-bottom:1px solid var(--line)}
.result-card .rc-check{width:34px;height:34px;border-radius:50%;background:var(--ok);display:grid;place-items:center;flex:0 0 auto;color:#04130d}
.result-card .rc-check svg{width:18px;height:18px;stroke:currentColor;stroke-width:3;fill:none;stroke-dasharray:24;stroke-dashoffset:24;animation:check .5s .15s var(--ease-out) forwards}
@keyframes check{to{stroke-dashoffset:0}}
.result-card .rc-body{padding:16px 18px;display:flex;flex-direction:column;gap:10px}

/* ============================================================== ENTITLEMENTS
   Locked sidebar tools + the full-screen access gate (no plan / Discord not linked). */
.sb-item.is-locked{opacity:.45;cursor:not-allowed}
.sb-item.is-locked:hover{background:transparent;border-color:transparent;color:var(--muted)}
.sb-item .sb-lock{margin-left:auto;opacity:.85;flex:0 0 auto;display:inline-flex}
.sb-item .sb-lock svg{width:13px;height:13px}

#soAccessGate{
  position:fixed;inset:0;z-index:100000;display:flex;align-items:center;justify-content:center;
  padding:24px;background:rgba(5,6,8,.86);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  animation:modalIn .2s var(--ease)}
.so-gate-card{max-width:440px;width:100%;padding:36px 32px;border-radius:var(--r-xl);text-align:center;
  background:var(--panel-2);border:1px solid var(--line-2);box-shadow:var(--sh-lg);
  animation:cardIn .24s var(--ease-out)}
.so-gate-icon{width:60px;height:60px;border-radius:50%;margin:0 auto 18px;display:grid;place-items:center;
  color:var(--accent-2);background:var(--accent-weak);box-shadow:inset 0 0 0 1px var(--accent-line)}
.so-gate-icon svg{width:26px;height:26px}
.so-gate-icon-err{color:var(--err);background:var(--err-weak);box-shadow:inset 0 0 0 1px rgba(220,38,38,.35)}
.so-gate-card h2{margin:0 0 10px;font-size:19px;font-weight:800;letter-spacing:-.02em;font-family:'Outfit',sans-serif}
.so-gate-card p{margin:0 0 20px;color:var(--muted);font-size:13.5px;line-height:1.6}
.so-gate-card .btn{width:100%}
.so-gate-hint{margin:14px 0 0!important;font-size:12px!important;color:var(--faint)!important}

/* ============================================================== TOASTS (global)
   Every page keeps its local `.toast` element + show/hide JS untouched; this
   higher-specificity block (body .toast beats each page's bare .toast) re-homes
   all of them to the TOP-center with a premium glass treatment and a springy
   drop-in / lift-out animation. */
body .toast{
  position:fixed;top:20px;bottom:auto;left:50%;
  transform:translateX(-50%) translateY(-16px) scale(.96);
  background:var(--panel-2);border:1px solid var(--line-2);color:var(--text);
  padding:12px 22px;border-radius:var(--r-xl);font-size:13px;font-weight:600;
  letter-spacing:-.005em;line-height:1.45;text-align:center;
  max-width:min(92vw,480px);
  box-shadow:var(--sh-lg),inset 0 1px 0 rgba(255,255,255,.06);
  backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);
  opacity:0;pointer-events:none;z-index:99999;
  transition:opacity .26s var(--ease),transform .34s var(--spring)}
body .toast::before{
  content:"";position:absolute;left:16px;right:16px;top:-1px;height:2px;
  border-radius:0 0 2px 2px;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--accent),transparent)}
body .toast.show{opacity:1;transform:translateX(-50%) translateY(0) scale(1);pointer-events:auto}

/* ============================================================== FOOTER */
.footer{border-top:1px solid var(--line);padding:34px 0;color:var(--faint);font-size:13px}
.footer .container{display:flex;flex-wrap:wrap;gap:14px;align-items:center;justify-content:space-between}
.footer a{color:var(--muted)}.footer a:hover{color:var(--text)}
.footer .fbrand{display:flex;align-items:center;gap:9px;color:var(--muted);font-weight:650;font-family:'Outfit',sans-serif}
.footer .fbrand .logo{width:24px;height:24px;border-radius:50%;background:var(--bg-2);display:grid;place-items:center;color:var(--accent-ink);font-size:11px;font-weight:800;overflow:hidden;border:1px solid var(--line)}
.footer .fbrand .logo img{width:100%;height:100%;object-fit:cover;display:block}

.reveal{opacity:0;transform:translateY(16px);transition:opacity .7s var(--ease),transform .7s var(--ease)}
.reveal.in{opacity:1;transform:none}

/* ============================================================== PAGE TRANSITIONS (sidebar nav)
   Primary mechanism: the browser's native cross-document View Transition (below) —
   it snapshots the outgoing/incoming page and crossfades them in one compositor-driven
   animation, so it's immune to the JS timing races that make hand-rolled fades feel
   glitchy. shell.js only falls back to the manual ori-nav-* class fade further down for
   browsers that don't support it at all. */
@supports (view-transition-name: none){
  @view-transition{navigation:auto}
  ::view-transition-group(root){
    animation-duration:.36s;
    animation-timing-function:var(--ease);
  }
  ::view-transition-old(root){
    animation:oriVtOut .2s var(--ease-out) both;
  }
  ::view-transition-new(root){
    animation:oriVtIn .36s var(--ease) both;
  }
  @keyframes oriVtOut{
    to{opacity:0;transform:scale(.985)}
  }
  @keyframes oriVtIn{
    from{opacity:0;transform:translateY(10px) scale(.992)}
    to{opacity:1;transform:none}
  }
  /* the fallback path below must never also run once the browser is doing this natively */
  body.ori-nav-out,body.ori-nav-ready{animation:none!important;opacity:1!important;transform:none!important}
}

/* Pre-paint nav guard (fallback path only — set synchronously by an inline <script> at
   the very top of <head>, before first paint, gated on the browser lacking native view
   transitions). Without this, the incoming page would flash fully-visible for a frame
   before shell.js mounts the sidebar and starts the manual fade-in, then visibly "reset"
   back to invisible to animate — the exact glitch this whole mechanism exists to avoid. */
html.ori-pre-nav body{opacity:0}

#oriNavProgress{
  position:fixed;top:0;left:0;right:0;height:2px;z-index:99990;pointer-events:none;
  background:transparent;opacity:0;transition:opacity .15s;
}
#oriNavProgress.on{opacity:1}
#oriNavProgress > i{
  display:block;height:100%;width:0;border-radius:0;
  background:var(--accent);
  transition:width .35s var(--ease);
}
body.ori-nav-out #oriNavProgress > i{width:72%}
body.ori-nav-busy #oriNavProgress > i{width:92%;transition:width 1.2s linear}

/* Animate page chrome (not the fixed sidebar) on section switch */
body.has-sidebar.ori-nav-ready > *:not(.sidebar):not(.sb-burger):not(.sb-scrim):not(#oriDlgRoot):not(#oriDlToast):not(#oriNavProgress){
  animation:oriPageIn .34s var(--ease) both;
  will-change:opacity,transform;
}
body.has-sidebar.ori-nav-out > *:not(.sidebar):not(.sb-burger):not(.sb-scrim):not(#oriDlgRoot):not(#oriDlToast):not(#oriNavProgress){
  animation:none;
  opacity:0;
  transform:translateY(12px);
  transition:opacity .18s var(--ease-out),transform .18s var(--ease-out);
  pointer-events:none;
  will-change:opacity,transform;
}
@keyframes oriPageIn{
  from{opacity:0;transform:translateY(14px)}
  to{opacity:1;transform:none}
}

.sb-item.is-pending{color:#fff;background:var(--accent-weak)}
.sb-item.is-pending::before{content:"";position:absolute;left:0;top:10px;bottom:10px;width:3px;border-radius:0 3px 3px 0;background:var(--accent)}
.sb-item.is-pending svg{color:var(--accent-2)}

@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
  .reveal{opacity:1;transform:none}
  .so-chase::after{animation:none!important;opacity:0!important}
  .so-chase:hover,.so-chase.is-active{border-color:var(--line-2)}
  body.has-sidebar.ori-nav-ready > *:not(.sidebar):not(.sb-burger):not(.sb-scrim):not(#oriDlgRoot):not(#oriDlToast):not(#oriNavProgress),
  body.has-sidebar.ori-nav-out > *:not(.sidebar):not(.sb-burger):not(.sb-scrim):not(#oriDlgRoot):not(#oriDlToast):not(#oriNavProgress){
    opacity:1!important;transform:none!important
  }
  #oriNavProgress{display:none}
}
@media(max-width:760px){
  .container{padding:0 20px}
  .nav .container{height:60px}
  .nav a.link{padding:8px 9px;font-size:13.5px}
}
/* ============================================================
   SmartObjector — unified design system (uses theme.css vars)
   ============================================================ */
* { box-sizing: border-box; }
html, body, #root { height: 100%; margin: 0; }
body {
  background:
    radial-gradient(1200px 600px at 80% -10%, rgba(59,130,246,.10), transparent 60%),
    radial-gradient(900px 500px at -10% 10%, rgba(139,92,246,.08), transparent 55%),
    var(--bg, #0B0D10);
  color: var(--ink, #e7ebf0);
  font-family: 'Inter', 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: rgba(255,255,255,.09); border-radius: 8px; border: 2px solid transparent; background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.16); background-clip: padding-box; }

/* ---- App layout ----
   One header spanning the full width, sidebar underneath it, content beside.
   The brand block is exactly as wide as the sidebar so the header reads as a
   single continuous row and the vertical rule runs unbroken from the very top. */
.layout {
  display: grid;
  grid-template-columns: 264px 1fr;
  grid-template-rows: auto 1fr;
  grid-template-areas: "top top" "side main";
  height: 100vh;
}
.layout > .topbar { grid-area: top; }
.layout > .sidebar { grid-area: side; }
.layout > .main { grid-area: main; min-width: 0; }

/* The React app is the whole site now; the new layout is a CSS grid, so the
   sidebar must be an in-flow grid item. The legacy theme.css sets
   `.sidebar{position:fixed}`, which would pull it out of the grid and let
   .main collapse behind it (blank content). Override with higher specificity. */
.layout > .sidebar {
  position: relative; left: auto; top: auto; bottom: auto; right: auto;
  width: auto; height: auto; max-width: none; z-index: auto; transform: none;
}

.sidebar {
  background: linear-gradient(180deg, rgba(18,22,28,.92), rgba(12,15,19,.92));
  border-right: 1px solid var(--line, rgba(255,255,255,.08));
  overflow-y: auto; padding: 14px 12px 8px; display: flex; flex-direction: column; gap: 1px;
  backdrop-filter: blur(8px);
}
.sidebar > div:first-child .sb-cat { padding-top: 6px; }
.sb-cat { color: var(--faint, #6b7280); font-size: 10.5px; font-weight: 800; letter-spacing: .12em; padding: 16px 12px 7px; text-transform: uppercase; }
.sb-item {
  display: flex; align-items: center; gap: 11px; padding: 8.5px 12px; border-radius: 10px;
  color: var(--muted, #98a2b3); text-decoration: none; font-size: 13.5px; font-weight: 500; cursor: pointer;
  border: 1px solid transparent; transition: background .14s, color .14s, border-color .14s;
}
.sb-item:hover { background: rgba(255,255,255,.045); color: var(--ink, #e7ebf0); }
.sb-item.active {
  background: linear-gradient(90deg, rgba(59,130,246,.18), rgba(59,130,246,.06));
  color: #fff; border-color: rgba(59,130,246,.35);
  box-shadow: inset 0 0 0 1px rgba(59,130,246,.10);
}
.sb-item svg { width: 18px; height: 18px; flex: 0 0 auto; opacity: .9; }
.sb-item.active svg { color: var(--accent-2, #60A5FA); opacity: 1; }
.sb-badge { margin-left: auto; font-size: 9px; font-weight: 800; color: var(--accent-2, #60A5FA); background: rgba(59,130,246,.14); padding: 2px 7px; border-radius: 999px; letter-spacing: .04em; }

.main { overflow-y: auto; }
/* Top bar — same furniture as the public site header (brand, the same three
   links, an account cluster) so the app doesn't look like a different product
   once you sign in. Spans the whole window, brand included. */
.topbar {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: stretch; gap: 0;
  height: 60px; padding: 0 26px 0 0;
  border-bottom: 1px solid var(--line, rgba(255,255,255,.07));
  background: rgba(11,13,16,.82); backdrop-filter: blur(10px);
}
.tb-brand {
  display: flex; align-items: center; gap: 10px; flex: 0 0 264px;
  padding: 0 16px 0 24px; box-sizing: border-box;
  font-weight: 800; font-size: 16.5px; letter-spacing: -.02em;
  color: var(--ink, #e7ebf0); text-decoration: none;
  /* continues the sidebar's edge, so the rule is unbroken top to bottom */
  border-right: 1px solid var(--line, rgba(255,255,255,.08));
  transition: background .14s;
}
.tb-brand:hover { background: rgba(255,255,255,.03); }
.tb-brand span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-logo { width: 26px; height: 26px; border-radius: 7px; flex: 0 0 auto; }

.tb-links { display: flex; align-items: center; gap: 22px; margin-right: auto; padding-left: 26px; }
.tb-links a { color: var(--muted, #98a2b3); text-decoration: none; font-size: 13.5px; font-weight: 500;
  padding: 4px 0; border-bottom: 1.5px solid transparent; transition: color .14s, border-color .14s; }
.tb-links a:hover { color: var(--ink, #e7ebf0); border-bottom-color: var(--accent, #3B82F6); }

.tb-right { display: flex; align-items: center; gap: 12px; flex: 0 0 auto; }
.tb-links a, .tb-right > * { align-self: center; }
.tb-plan { font-size: 11px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
  color: var(--accent-2, #60A5FA); background: rgba(59,130,246,.14);
  border: 1px solid var(--accent-line, rgba(59,130,246,.3)); padding: 4px 10px; border-radius: 999px; }
.tb-credits { font-size: 13px; color: var(--muted, #98a2b3); white-space: nowrap; }
.tb-credits b { color: var(--ink, #e7ebf0); font-size: 15px; font-variant-numeric: tabular-nums; }

.tb-user { display: inline-flex; align-items: center; gap: 8px; text-decoration: none; color: var(--ink, #e7ebf0);
  padding: 5px 11px 5px 5px; border-radius: 999px; border: 1px solid var(--line, rgba(255,255,255,.1));
  background: rgba(255,255,255,.04); transition: background .14s, border-color .14s; }
.tb-user:hover { background: rgba(255,255,255,.09); border-color: var(--line-2, rgba(255,255,255,.18)); }
.tb-avatar { width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center;
  font-size: 11.5px; font-weight: 800; color: #fff; flex: 0 0 auto; object-fit: cover;
  background: linear-gradient(180deg, var(--accent-2, #60A5FA), var(--accent, #3B82F6)); }
img.tb-avatar { background: rgba(255,255,255,.06); }
.tb-name { font-size: 13px; font-weight: 600; max-width: 150px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-out { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 9px;
  color: var(--muted, #98a2b3); border: 1px solid var(--line, rgba(255,255,255,.1));
  background: rgba(255,255,255,.04); transition: .14s; flex: 0 0 auto; }
.tb-out:hover { color: #f87171; border-color: rgba(239,68,68,.35); background: rgba(239,68,68,.1); }

/* sidebar footer links */
.sb-foot { margin-top: auto; padding: 12px; display: flex; flex-direction: column; gap: 6px; }
.sb-foot a { color: var(--muted, #aeb6c2); text-decoration: none; font-size: 12px; }
.sb-foot a:hover { color: var(--ink, #e7ebf0); }
.content { padding: 30px 34px 60px; max-width: 1400px; margin: 0 auto; }

.tool-h { font-size: 27px; font-weight: 800; letter-spacing: -.025em; margin: 0 0 6px; }
.tool-sub { color: var(--muted, #98a2b3); font-size: 14.5px; margin: 0 0 24px; }

/* ---- Cards ---- */
.card {
  background: linear-gradient(180deg, rgba(26,31,39,.55), rgba(20,24,30,.55));
  border: 1px solid var(--line, rgba(255,255,255,.09));
  border-radius: 16px; padding: 22px;
  box-shadow: 0 1px 0 rgba(255,255,255,.03) inset, 0 12px 32px -18px rgba(0,0,0,.7);
}

/* ---- Buttons ---- */
.btn {
  display: inline-flex; align-items: center; gap: 8px; justify-content: center;
  background: linear-gradient(180deg, var(--accent-2, #60A5FA), var(--accent, #3B82F6));
  color: #fff; border: 0; border-radius: 11px; padding: 11px 18px;
  font-weight: 700; font-size: 14px; cursor: pointer; text-decoration: none;
  box-shadow: 0 8px 20px -10px rgba(59,130,246,.8); transition: transform .1s, box-shadow .15s, filter .15s;
}
.btn:hover { filter: brightness(1.06); box-shadow: 0 10px 26px -10px rgba(59,130,246,.9); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .55; cursor: default; box-shadow: none; filter: none; }
.btn.ghost { background: rgba(255,255,255,.06); color: var(--ink, #e7ebf0); border: 1px solid var(--line, rgba(255,255,255,.12)); box-shadow: none; }
.btn.ghost:hover { background: rgba(255,255,255,.1); filter: none; }
.btn.big { padding: 14px 26px; font-size: 15px; border-radius: 13px; }

/* ---- Fields ---- */
.field { display: block; margin: 14px 0; }
.field label { display: block; font-size: 12.5px; color: var(--muted, #98a2b3); margin-bottom: 7px; font-weight: 600; }
.input, select.input {
  width: 100%; background: rgba(0,0,0,.28); border: 1px solid var(--line, rgba(255,255,255,.12));
  border-radius: 10px; padding: 11px 13px; color: var(--ink, #e7ebf0); font-size: 14px; transition: border-color .15s, box-shadow .15s;
}
.input:focus, select.input:focus { outline: none; border-color: var(--accent-line, rgba(59,130,246,.55)); box-shadow: 0 0 0 3px rgba(59,130,246,.14); }
input[type=color].input { padding: 4px; height: 42px; }

.dropzone {
  border: 1.5px dashed var(--line-2, rgba(255,255,255,.16)); border-radius: 14px; padding: 42px 20px;
  text-align: center; color: var(--muted, #98a2b3); cursor: pointer; font-size: 14px; transition: border-color .15s, background .15s;
}
.dropzone:hover, .dropzone.drag { border-color: var(--accent-line, rgba(59,130,246,.55)); background: rgba(59,130,246,.06); color: var(--ink, #e7ebf0); }

.viewer { position: relative; height: 400px; border-radius: 14px; overflow: hidden; border: 1px solid var(--line, rgba(255,255,255,.09));
  background: radial-gradient(70% 70% at 50% 35%, rgba(19,16,30,.5), rgba(5,6,9,.85) 82%); }
.viewer canvas { display: block; width: 100%; height: 100%; }
/* Centred overlay message inside a viewer (loading / unavailable), above the canvas. */
.viewer-over { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 0 18px; color: var(--muted, #98a2b3); font-size: 13px; pointer-events: none; }
.viewer-hint { position: absolute; top: 11px; right: 13px; font-size: 11px; color: var(--faint, #6b7280);
  background: rgba(0,0,0,.45); border: 1px solid var(--line, rgba(255,255,255,.09)); padding: 4px 10px; border-radius: 999px; }

/* ---- Badges / status ---- */
/* NAME COLLISION with theme.css, which styles `.status` as a small inline-flex
   PILL for the legacy UI. In the React app `.status` is the block container that
   holds the result badge, the file list and the download button — as an
   inline-flex it shrink-wrapped to max-content (873px inside a 382px card), laid
   its children out in a row and spilled them outside the panel. Reset it back to
   a plain block; app.css is imported after theme.css so this wins. */
.status {
  display: block; width: 100%; min-width: 0; margin-top: 16px;
  padding: 0; border: 0; border-radius: 0; font-size: inherit; font-weight: inherit; letter-spacing: normal;
}
/* max-width + wrapping: a badge carrying a long prop name ("Done:
   tamir_irondome_missile") must not stretch its container. */
.badge { display: inline-flex; align-items: center; gap: 7px; padding: 6px 12px; border-radius: 999px;
  font-size: 12.5px; font-weight: 700; max-width: 100%; overflow-wrap: break-word; text-align: left; }
.badge.ok { background: rgba(34,197,94,.14); color: #4ade80; border: 1px solid rgba(34,197,94,.25); }
.badge.err { background: rgba(239,68,68,.14); color: #f87171; border: 1px solid rgba(239,68,68,.25); }
.spinner { width: 14px; height: 14px; border: 2px solid rgba(255,255,255,.2); border-top-color: currentColor; border-radius: 50%; display: inline-block; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.center-msg { display: grid; place-items: center; height: 100vh; color: var(--muted, #98a2b3); }

/* ---- Tables ---- */
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th { text-align: left; padding: 10px 12px; color: var(--muted, #98a2b3); font-weight: 600; border-bottom: 1px solid var(--line, rgba(255,255,255,.1)); }
td { padding: 10px 12px; border-bottom: 1px solid rgba(255,255,255,.05); }

/* ============================================================
   Public (logged-out) pages
   ------------------------------------------------------------
   The `.pub-*` rules that used to live here were from the old server-rendered
   public site. The React public site uses the SAME class names and owns them
   in src/public/public.css, so these did not sit harmlessly beside it — they
   leaked in. `.pub-nav { display:flex }` in particular made the header a flex
   row, which collapsed the mobile menu to zero width. Removed; the remaining
   rules below are not in the .pub-* namespace.
   ============================================================ */

.hero { text-align: center; padding: 80px 24px 56px; max-width: 860px; margin: 0 auto; }
.hero-logo { width: 74px; height: 74px; border-radius: 20px; margin-bottom: 26px; box-shadow: 0 20px 50px -18px rgba(59,130,246,.7); }
.hero-badge { display: inline-block; font-size: 12px; color: var(--accent-2, #60A5FA); background: rgba(59,130,246,.1); border: 1px solid rgba(59,130,246,.3); padding: 6px 14px; border-radius: 999px; margin-bottom: 26px; }
.hero h1 { font-size: 56px; font-weight: 800; letter-spacing: -.035em; line-height: 1.03; margin: 0 0 20px;
  background: linear-gradient(180deg, #fff, #b9c2d0); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.hero p { color: var(--muted, #98a2b3); font-size: 17.5px; line-height: 1.6; max-width: 620px; margin: 0 auto 32px; }
.hero-cta { display: flex; gap: 12px; justify-content: center; }

.tool-grid { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; }
.tool-chip { background: rgba(255,255,255,.03); border: 1px solid var(--line, rgba(255,255,255,.09)); border-radius: 12px; padding: 14px 22px; font-weight: 600; font-size: 14px; transition: transform .12s, border-color .15s; }
.tool-chip:hover { transform: translateY(-2px); border-color: var(--accent-line, rgba(59,130,246,.4)); }
.tool-chip.more { color: var(--accent-2, #60A5FA); }

.price-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-top: 32px; text-align: left; }
.price-card { background: linear-gradient(180deg, rgba(26,31,39,.6), rgba(18,22,28,.6)); border: 1px solid var(--line, rgba(255,255,255,.09)); border-radius: 18px; padding: 28px; position: relative; }
.price-card.popular { border-color: rgba(59,130,246,.45); box-shadow: 0 24px 50px -24px rgba(59,130,246,.5); }
.price-pop { position: absolute; top: -12px; left: 28px; background: linear-gradient(180deg, var(--accent-2, #60A5FA), var(--accent, #3B82F6)); color: #fff; font-size: 11px; font-weight: 700; padding: 4px 13px; border-radius: 999px; }
.price-name { font-size: 15px; color: var(--muted, #98a2b3); font-weight: 700; }
.price-amt { font-size: 40px; font-weight: 800; margin: 6px 0; letter-spacing: -.02em; }
.price-amt span { font-size: 15px; color: var(--muted, #98a2b3); font-weight: 500; }
.price-credits { color: var(--accent-2, #60A5FA); font-size: 13px; margin-bottom: 18px; }
.price-card ul { list-style: none; padding: 0; margin: 0 0 22px; }
.price-card li { padding: 8px 0; font-size: 14px; color: var(--muted, #cbd3df); border-bottom: 1px solid var(--line, rgba(255,255,255,.06)); }

/* ---- Auth (login/signup): PublicNav on top + centered card ---- */
.auth-wrap { flex: 1; display: flex; align-items: center; justify-content: center; padding: 48px 20px; }
.auth-card { max-width: 410px; width: 100%; text-align: center;
  background: linear-gradient(180deg, rgba(26,31,39,.7), rgba(18,22,28,.7)); border: 1px solid var(--line, rgba(255,255,255,.1));
  border-radius: 20px; padding: 36px 34px; box-shadow: 0 30px 70px -30px rgba(0,0,0,.8); }
.auth-card-logo { width: 56px; height: 56px; border-radius: 16px; margin: 0 auto 16px; display: block;
  box-shadow: 0 18px 44px -18px rgba(59,130,246,.7); }
.auth-card h1 { font-size: 25px; font-weight: 800; margin: 0 0 6px; letter-spacing: -.02em; }
.auth-card-sub { color: var(--muted, #98a2b3); font-size: 14px; margin: 0 0 22px; }
/* form controls inside the card read left-to-right even though the card is centered */
.auth-card form, .auth-card .field, .auth-card .badge { text-align: left; }

@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; grid-template-areas: "top" "main"; }
  .sidebar { display: none; }
  .price-grid { grid-template-columns: 1fr; }
  .hero h1 { font-size: 40px; }
  /* No sidebar to line up with — the brand shrinks to its content. */
  .tb-brand { flex: 0 0 auto; border-right: none; padding: 0 0 0 16px; }
  .tb-links { gap: 16px; margin-right: 0; padding-left: 20px; }
  .content { padding: 22px 18px 48px; }
}
@media (max-width: 700px) {
  .topbar { height: auto; padding: 12px 16px; gap: 10px; flex-wrap: wrap; align-items: center; }
  .tb-brand { padding-left: 0; }
  .tb-links { order: 3; width: 100%; padding-left: 0; }
  .tb-right { margin-left: auto; }
  .tb-name, .tb-plan { display: none; }   /* keep the avatar + credits, drop the words */
}

/* ---- ToolForm extras (segmented, hints, progress, file list) ---- */
.tf-hint { font-size: 12px; color: var(--faint,#6b7280); margin-top: 6px; line-height: 1.5; }
.seg { display: inline-flex; gap: 4px; background: rgba(0,0,0,.28); border: 1px solid var(--line-2,rgba(255,255,255,.12)); border-radius: 10px; padding: 4px; flex-wrap: wrap; }
.seg-btn { padding: 7px 13px; border-radius: 7px; font-size: 13px; font-weight: 600; cursor: pointer; border: none; background: transparent; color: var(--muted,#98a2b3); }
.seg-btn.on { background: var(--accent-weak,rgba(59,130,246,.16)); color: var(--accent-2,#60A5FA); }
.tf-prog { height: 6px; border-radius: 4px; background: rgba(255,255,255,.08); overflow: hidden; margin-top: 12px; }
.tf-prog > i { display: block; height: 100%; background: linear-gradient(90deg,var(--accent-2,#60A5FA),var(--accent,#3B82F6)); transition: width .3s; }
.tf-files { font-size: 12.5px; border: 1px solid var(--line,rgba(255,255,255,.1)); border-radius: 9px; overflow: hidden; margin-top: 12px; }
.tf-files div { display: flex; justify-content: space-between; gap: 12px; padding: 8px 12px; border-bottom: 1px solid var(--line,rgba(255,255,255,.07)); }
.tf-files div:last-child { border-bottom: none; }
/* A resource path like stream/tamir_irondome_missile.ydr is one unbreakable
   monospace token. Without min-width:0 the flex row refuses to shrink below it
   and pushes the whole result panel outside its card. Let the name wrap and
   pin the size column. */
/* flex:1 1 auto so the name TAKES the free space; overflow-wrap:break-word (not
   `anywhere`) so a long path still breaks when it has to, without reporting a
   one-character min-content width — `anywhere` let flexbox shrink this column to
   a single glyph and stacked the filename vertically. */
.tf-files div span:first-child { font-family: 'JetBrains Mono', monospace; color: var(--ink,#e7ebf0);
  flex: 1 1 auto; min-width: 0; overflow-wrap: break-word; }
.tf-files div span:last-child { flex: 0 0 auto; white-space: nowrap; color: var(--muted,#98a2b3); }
textarea.input { resize: vertical; font-family: inherit; }

/* ---- Grid overflow guard -------------------------------------------------
   Grid and flex items default to min-width:auto, so ONE unbreakable child (a
   long resource path, a wide table) silently widens its track past the declared
   column size and the card spills out of the layout. Every tool panel opts out. */
.cv-grid > *, .wp-grid > *, .fc-grid > *, .pl-grid > *, .ar-grid > *,
.pm-board-wrap > *, .grid2 > *, .cv-side > *, .wp-side > *, .fc-side > *, .pl-side > * { min-width: 0; }
.card { min-width: 0; }
/* ============================================================
   Clean dark mode — applied to the WHOLE product, not just the
   marketing page.

     · black and greys carry every surface
     · blue only on primary buttons, active nav, focus rings and
       small icons — never as a background wash
     · prominent rounded corners everywhere
     · no glow, no gradient decoration, no textured backdrops
     · depth = 1px border + one surface step

   Loaded after theme.css/app.css so it wins, and written with the
   same class names those files already use.
   ============================================================ */

:root {
  --bg:        #08090A;
  --surface:   #121316;
  --surface-2: #191B1F;
  --surface-3: #202329;
  --line:      #24262B;
  --line-soft: #1B1D21;
  --ink:       #F4F5F7;
  --muted:     #A2A8B2;
  --faint:     #6E747E;
  --accent:      #2E6BE6;
  --accent-2:    #7FA9F5;
  --accent-line: #2E6BE6;
  --accent-weak: rgba(46,107,230,.14);

  --r-lg: 22px;   /* cards / panels */
  --r-md: 14px;   /* buttons / inputs */
  --r-sm: 10px;   /* chips / small tiles */
}

html, body { background: var(--bg); color: var(--ink); }
body {
  background-image: none;                 /* drop the old radial washes */
  -webkit-font-smoothing: antialiased;
}

/* ---------- surfaces ---------- */
.card, .panel, .tf-card {
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
  box-shadow: none;
}

/* ---------- buttons ---------- */
.btn {
  border-radius: var(--r-md); font-weight: 600; letter-spacing: -.01em;
  border: 1px solid var(--accent); background: var(--accent); color: #fff;
  box-shadow: none; transition: background .15s, border-color .15s, transform .12s;
}
.btn:hover:not(:disabled) { background: #2760D2; border-color: #2760D2; transform: translateY(-1px); }
.btn:active:not(:disabled) { transform: translateY(0); }
.btn.ghost, .btn.secondary {
  background: var(--surface-2); color: var(--ink); border-color: var(--line);
}
.btn.ghost:hover:not(:disabled), .btn.secondary:hover:not(:disabled) {
  background: var(--surface-3); border-color: #2E3138;
}
.btn.danger { background: #C5453B; border-color: #C5453B; }
.btn.danger:hover:not(:disabled) { background: #B03B32; border-color: #B03B32; }
.btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }

/* ---------- inputs ---------- */
.input, input[type=text], input[type=email], input[type=password],
input[type=number], input[type=search], select, textarea {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-md); color: var(--ink);
}
.input:focus, input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(46,107,230,.18);
}
.field label { color: var(--muted); }

/* The burger exists only on small screens — declared before the media query
   below so the query can turn it on. */
.tb-burger { display: none; border: none; background: none; padding: 0; }
.sb-scrim { display: none; }

/* ---------- app chrome ---------- */
.topbar { background: rgba(8,9,10,.9); border-bottom: 1px solid var(--line-soft); }
.sidebar { background: var(--bg); border-right: 1px solid var(--line-soft); backdrop-filter: none; }
.tb-brand { border-right: 1px solid var(--line-soft); }
.sb-item { border-radius: var(--r-md); }
.sb-item.active {
  background: var(--surface-2); color: var(--ink);
  border-color: var(--line); box-shadow: none;
}
.sb-item.active svg { color: var(--accent-2); }
/* ---------- topbar account cluster ----------
   These four sat at four different heights (chip 24, credits as bare text,
   user pill 34, logout 32) and two different radii (999px and 9px), so the
   row read as four unrelated widgets that happened to be next to each other.
   One height, one radius, one surface step — the rule this theme already
   states — and they read as a set. */
/* ---------- open-tool tabs (Windows 11 Explorer shape) ----------
   A rounded RECTANGLE, not a pill: the active tab reads as a card that the
   content below belongs to, which is what makes a tab strip say "these are
   separate windows" instead of "these are buttons". Inactive tabs stay flat
   and quiet so the active one is unmistakable at a glance. */
.tb-tabs {
  display: flex; align-items: flex-end; gap: 2px;
  margin-right: auto; padding: 0 8px 0 12px;
  min-width: 0; overflow-x: auto; scrollbar-width: none;
  align-self: stretch;
}
.tb-tabs::-webkit-scrollbar { display: none; }
.tb-tab {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  height: 38px; padding: 0 6px 0 12px;
  min-width: 132px; max-width: 220px;
  border-radius: 9px 9px 0 0;
  border: 1px solid transparent; border-bottom: none;
  color: var(--muted); text-decoration: none;
  font-size: 12.5px; font-weight: 500; white-space: nowrap;
  transition: background .13s, color .13s, border-color .13s;
}
.tb-tab > span:first-of-type { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.tb-tab svg { flex: 0 0 auto; opacity: .85; }
.tb-tab:hover { background: var(--surface-2); color: var(--ink); }

/* The active tab is filled and joined to the page: its bottom border is
   painted over by the strip itself, so the card and the content read as one
   surface — exactly what Explorer does. */
.tb-tab.on {
  background: var(--surface-2);
  border-color: var(--line);
  color: var(--ink); font-weight: 600;
}
.tb-tab.on::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -1px;
  height: 2px; background: var(--surface-2);
}
.tb-tab.on svg { opacity: 1; color: var(--accent-2); }

.tb-tab-x {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 22px; height: 22px; border-radius: 6px;
  font-size: 15px; line-height: 1; color: var(--faint); cursor: pointer;
  opacity: 0; transition: opacity .12s, background .12s, color .12s;
}
/* Explorer only shows the close affordance where it is reachable — on the tab
   you are on, or the one under the cursor. Showing every × at once turns the
   strip into a row of buttons. */
.tb-tab:hover .tb-tab-x, .tb-tab.on .tb-tab-x { opacity: 1; }
.tb-tab-x:hover { background: rgba(197,69,59,.18); color: #F0928A; }
.tb-tab-x:focus-visible { opacity: 1; outline: 2px solid var(--accent); outline-offset: 1px; }

/* a tab with work still running */
.tb-tab.busy { color: var(--ink); }
.tb-tab-spin {
  width: 13px; height: 13px; flex: 0 0 auto; border-radius: 50%;
  border: 2px solid var(--line); border-top-color: var(--accent-2);
  animation: tb-spin .7s linear infinite;
}
@keyframes tb-spin { to { transform: rotate(360deg); } }

/* ---------- background-job notifications ---------- */
.tb-notes {
  position: fixed; right: 18px; bottom: 18px; z-index: 1200;
  display: flex; flex-direction: column-reverse; gap: 8px;
  max-width: min(360px, calc(100vw - 36px));
}
.tb-note {
  display: flex; align-items: stretch; gap: 0;
  background: var(--surface-2); border: 1px solid var(--line);
  border-left: 3px solid #4ADE80; border-radius: var(--r-md);
  box-shadow: 0 10px 30px rgba(0,0,0,.45);
  animation: tb-note-in .18s ease-out;
}
.tb-note.err { border-left-color: #E5484D; }
@keyframes tb-note-in { from { opacity: 0; transform: translateY(8px); } }
.tb-note-main {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px;
  padding: 11px 12px; text-align: left; cursor: pointer;
  background: none; border: none; color: var(--ink); font: inherit; border-radius: var(--r-md) 0 0 var(--r-md);
}
.tb-note-main:hover { background: var(--surface-3); }
.tb-note-main b { font-size: 13px; font-weight: 600; }
.tb-note-main span { font-size: 12px; color: var(--muted); }
.tb-note-x {
  flex: 0 0 auto; width: 34px; background: none; border: none;
  color: var(--faint); font-size: 16px; cursor: pointer; border-radius: 0 var(--r-md) var(--r-md) 0;
}
.tb-note-x:hover { background: var(--surface-3); color: var(--ink); }

/* The account cluster is a different kind of thing from the tabs beside it —
   one is what you are working on, the other is who you are. A rule between
   them says so without adding another box. */
.tb-right {
  gap: 8px;
  margin-left: 10px; padding-left: 14px;
  border-left: 1px solid var(--line);
  align-self: stretch;
}

.tb-plan,
.tb-credits,
.tb-user,
.tb-out {
  height: 34px;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  box-shadow: none;
  transition: background .15s, border-color .15s, color .15s;
}

.tb-plan {
  padding: 0 12px;
  font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--accent-2);
  background: var(--accent-weak);
  border-color: var(--accent-line);
}

/* Was a bare text node between two chips, which is why it looked unanchored. */
.tb-credits { padding: 0 13px; gap: 5px; font-size: 12.5px; color: var(--muted); white-space: nowrap; }
.tb-credits b {
  color: var(--ink); font-size: 14px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;   /* the number must not jitter as it counts down */
}

.tb-user { gap: 8px; padding: 0 13px 0 4px; text-decoration: none; color: var(--ink); }
.tb-name { font-size: 13px; font-weight: 600; }
.tb-avatar { width: 26px; height: 26px; border-radius: 50%; font-size: 12px; background: var(--accent); }
img.tb-avatar { background: var(--surface-3); }

.tb-out { width: 34px; justify-content: center; color: var(--muted); }

.tb-user:hover { background: var(--surface-3); border-color: var(--line); }
.tb-out:hover  { background: rgba(197,69,59,.12); border-color: rgba(197,69,59,.42); color: #F0928A; }

/* The whole cluster is links — keyboard users need to see where they are. */
.tb-user:focus-visible, .tb-out:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

/* ---------- badges / chips ---------- */
.badge { border-radius: 999px; }
.badge.ok  { background: rgba(34,197,94,.12);  border-color: rgba(34,197,94,.28);  color: #7BD9A0; }
.badge.err { background: rgba(197,69,59,.12);  border-color: rgba(197,69,59,.32);  color: #F0928A; }
.seg { border-radius: var(--r-md); background: var(--surface-2); border-color: var(--line); }
.seg-btn { border-radius: var(--r-sm); }
.seg-btn.on { background: var(--accent-weak); color: var(--accent-2); }

/* ============================================================
   RESPONSIVE — four stages: desktop, tablet, phone, small phone.
   ============================================================ */

/* Nothing may push the document wider than the viewport. `clip` rather than
   `hidden` so the sticky header keeps working. */
html, body { overflow-x: clip; max-width: 100%; }
img, svg, video, canvas { max-width: 100%; }
/* Grid/flex children default to min-width:auto, so a single long unbroken
   string (a file name, a hash, a URL) can stretch its track past the screen. */
.db-stats > *, .db-tools > *, .ad-tiles > *, .ad-two > *, .ad-assets > *,
.split > *, .tf-actions > * { min-width: 0; }
.tool-h, .tool-sub, .card p, .card li { overflow-wrap: break-word; }
/* Long values (paths, IDs, log lines) scroll their own box instead of the page. */
pre, code, .tf-log, .db-row-v { overflow-x: auto; max-width: 100%; }

/* ---- tablet / small laptop: the fixed 264px rail costs too much width ---- */
@media (min-width: 901px) and (max-width: 1200px) {
  .layout { grid-template-columns: 216px 1fr; }
  .sidebar { width: auto; }
  .tb-brand { width: 216px; }
  .content { padding: 24px 24px 52px; }
  .db-tools { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .ad-two, .ad-assets { grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); }
  .split { grid-template-columns: minmax(0, 1fr) var(--aside, 320px); }
}

/* ---- tablet portrait: one column of content, drawer navigation ---- */
@media (max-width: 900px) {
  /* --- the sidebar becomes a drawer instead of disappearing --- */
  .layout > .sidebar {
    display: flex;                       /* app.css hides it below 900px */
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 60;
    width: 282px; max-width: 86vw;
    padding: 14px 12px calc(14px + env(safe-area-inset-bottom));
    border-right: 1px solid var(--line);
    transform: translateX(-102%);
    transition: transform .26s cubic-bezier(.22,.61,.36,1);
    overflow-y: auto; overscroll-behavior: contain;
  }
  .layout.menu-open > .sidebar { transform: none; }

  .sb-scrim {
    display: block;
    position: fixed; inset: 0; z-index: 55; background: rgba(0,0,0,.6);
    opacity: 0; visibility: hidden; transition: opacity .22s, visibility .22s;
  }
  .layout.menu-open .sb-scrim { opacity: 1; visibility: visible; }

  .tb-burger {
    display: inline-grid; place-items: center; gap: 4px;
    width: 40px; height: 40px; flex: 0 0 auto; margin-left: 14px;
    border-radius: var(--r-md); cursor: pointer;
    background: var(--surface-2); border: 1px solid var(--line);
  }
  .tb-burger span { display: block; width: 16px; height: 2px; border-radius: 2px; background: var(--ink); }

  .topbar { height: auto; min-height: 58px; padding: 10px 14px 10px 0; gap: 10px; }
  .tb-brand { border-right: none; flex: 0 0 auto; padding: 0 0 0 10px; font-size: 15px; }
  .tb-logo { width: 22px; height: 22px; }
  .tb-links { display: none; }                /* they live in the drawer */
  .tb-right { margin-left: auto; gap: 8px; }

  .content { padding: 18px 16px calc(56px + env(safe-area-inset-bottom)); }

  /* Side-by-side editor panes stack; a 400px aside beside a 3D view leaves
     neither usable at this width. */
  .split { grid-template-columns: 1fr; }
  .db-stats { grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr)); }
  .ad-two, .ad-assets { grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); }
}

@media (max-width: 620px) {
  /* keep the header to one tidy row: avatar + menu, nothing else */
  .tb-name, .tb-plan, .tb-credits { display: none; }
  .tb-brand span { display: none; }           /* mark only */
  /* Both grow to a comfortable touch target, and stay equal to each other —
     sizing only one of them is what left them mismatched before. */
  .tb-out, .tb-user { width: 38px; height: 38px; padding: 0; justify-content: center; }

  .content { padding: 16px 14px calc(52px + env(safe-area-inset-bottom)); }
  .tool-h { font-size: 22px; }
  .tool-sub { font-size: 13.5px; margin-bottom: 18px; }
  .card, .panel { padding: 18px; border-radius: 18px; }

  /* every multi-column grid in the product collapses to one column */
  .db-stats, .db-tools, .ad-tiles, .ad-two, .ad-assets,
  .price-grid, .tg-grid, .why-grid, .steps, .foot-grid {
    grid-template-columns: 1fr !important;
  }

  /* tables scroll inside their own card rather than stretching the page */
  .ad-scroll, .tf-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .ad-table { min-width: 560px; }

  /* forms and actions go full width so they are thumb-sized */
  .btn { padding: 11px 16px; }
  .tf-actions, .pe-toolbar, .ad-head-act { flex-wrap: wrap; gap: 8px; }
  .tf-actions .btn, .ad-head-act .btn { flex: 1 1 auto; justify-content: center; }

  /* 3D viewports need a sane height on a short screen */
  .pe-view, .cv-view, .vw-view { min-height: 240px; }

  /* modals become sheets */
  .pe-modal, .pe-studio, .lg-card {
    width: calc(100vw - 24px); max-width: none; border-radius: 20px;
  }
}

@media (max-width: 420px) {
  .content { padding: 14px 12px 48px; }
  .card, .panel { padding: 16px; }
  .tool-h { font-size: 20px; }
}

/* Touch: no sticky hover states after a tap. */
@media (hover: none) {
  .btn:hover, .card:hover, .sb-item:hover { transform: none; }
}


/* ---------- navigation stays usable while a tool is loading ----------
   LoadingGate is a fixed full-screen scrim at z-index 95; the topbar sat at 5
   and the sidebar below that, so a pack that takes a minute to build also took
   the tab strip hostage — the panes were alive the whole time and there was no
   way to reach them. The gate should block the TOOL it belongs to, not the app
   around it. Lifting the chrome above the scrim is enough: the work keeps
   running in its own (hidden) pane and the gate is still there when you come
   back to it. */
.topbar  { z-index: 120; }
.sidebar { z-index: 110; }
.sb-scrim { z-index: 105; }


/* ============================================================================
   Dropdowns
   ----------------------------------------------------------------------------
   The tools' selects carry class="input", so they only ever picked up the text
   -field styling: dark box, native arrow, and an option list drawn by Windows
   in its own light theme — a white popup with a blue Windows highlight in the
   middle of a black app.

   Two layers here, on purpose:

   1. Every browser. `color-scheme: dark` is what makes the NATIVE popup dark
      (it follows the element's colour scheme, not its background), plus explicit
      option colours for the engines that honour them, and our own chevron since
      the native one goes with appearance:none.

   2. Chrome 135+ / anything with the customisable-select API. `base-select`
      hands us the popup itself, so it can be a real panel — rounded, hairline
      border, our blue on the selected row. Wrapped in @supports, so a browser
      without it simply keeps layer 1.
   ============================================================================ */
select, select.input, .select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  color-scheme: dark;
  cursor: pointer;
  padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%238b93a1' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
select:hover, select.input:hover, .select:hover { border-color: var(--line-2, rgba(255,255,255,.16)); }
select option, select.input option, .select option {
  background-color: #14161b;
  color: var(--ink, #e8ecf2);
}
select option:checked, select.input option:checked, .select option:checked {
  background-color: #2f6fed;
  color: #fff;
}

@supports (appearance: base-select) {
  select, select.input, .select {
    appearance: base-select;
    background-image: none;          /* ::picker-icon draws the arrow now */
    padding-right: 34px;
    display: flex; align-items: center; gap: 8px;
  }
  select::picker-icon {
    margin-left: auto;
    color: var(--faint, #8b93a1);
    transition: transform .18s ease, color .18s ease;
  }
  select:hover::picker-icon { color: var(--ink, #e8ecf2); }
  select:open::picker-icon { transform: rotate(180deg); }

  select::picker(select) {
    appearance: base-select;
    box-sizing: border-box;
    width: anchor-size(width);       /* line the panel up with the field */
    margin-top: 6px;
    padding: 6px;
    border: 1px solid var(--line-2, rgba(255,255,255,.14));
    border-radius: 14px;
    background: #14161b;
    box-shadow: 0 20px 44px rgba(0, 0, 0, .6);
    max-height: 320px;
    overflow-y: auto;
  }
  select option {
    display: flex; align-items: center; gap: 10px;
    padding: 9px 11px;
    border-radius: 9px;
    font-size: 13.5px;
    color: var(--muted, #aab2c0);
    background: transparent;
    cursor: pointer;
    transition: background .12s ease, color .12s ease;
  }
  select option:hover, select option:focus {
    background: rgba(255, 255, 255, .06);
    color: var(--ink, #e8ecf2);
    outline: none;
  }
  /* In base-select the BUTTON renders the selected option, so the layer-1
     highlight (blue fill, white text) leaks onto the field itself. Reset it on
     the control, then paint it only inside the picker. */
  select option:checked {
    background: transparent;
    color: var(--ink, #e8ecf2);
    font-weight: 600;
  }
  select::picker(select) option:checked {
    background: rgba(47, 111, 237, .9);
    color: #fff;
  }
  /* The tick the API adds sits before the label; keep it, tint it, and stop it
     shifting the text of the rows that do not have one. */
  select option::checkmark {
    order: 1; margin-left: auto;
    color: var(--accent-2, #7fa9f5);
  }
  select option:not(:checked)::checkmark { visibility: hidden; }
}
/* The credits panel.
 *
 * Anchored under the header chip rather than shown as a modal: it is a detail
 * view of a thing that is already on screen, and covering the whole app to show
 * a balance would be out of proportion to the question being asked.
 *
 * Colours come from the app's own custom properties where they exist, with
 * literal fallbacks so the panel still reads correctly if it is ever mounted
 * somewhere those are not defined.
 */

.cr-wrap { position: relative; display: inline-flex; }

/* ---- the header chip ---------------------------------------------------- */
.cr-chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px 5px 8px;
  font: inherit; font-size: 12px; line-height: 1;
  color: var(--muted, #9aa3b2);
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 999px;
  cursor: pointer;
  transition: background .16s ease, border-color .16s ease, color .16s ease;
}
.cr-chip:hover { color: #fff; background: rgba(255, 255, 255, .08); border-color: rgba(255, 255, 255, .16); }
.cr-chip.cr-open { color: #fff; background: rgba(59, 130, 246, .16); border-color: rgba(59, 130, 246, .5); }
.cr-chip b { font-size: 13px; font-weight: 650; color: var(--ink, #fff); font-variant-numeric: tabular-nums; }

/* A dot instead of a sentence: the chip has no room to explain itself, and the
   colour is the same one the ring uses, so the two agree at a glance. */
.cr-dot { width: 7px; height: 7px; border-radius: 50%; background: #22c55e; flex: none; }
.cr-chip.cr-low .cr-dot { background: #f0ad4e; }
.cr-chip.cr-out .cr-dot { background: #ef4444; }
.cr-chip.cr-idle .cr-dot { box-shadow: 0 0 0 3px rgba(34, 197, 94, .18); }
/* Only pulses while a refill is actually pending — a full balance is at rest
   and should look it. */
.cr-chip.cr-ticking .cr-dot { animation: cr-pulse 2s ease-in-out infinite; }
@keyframes cr-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(240, 173, 78, .45); }
  50%      { box-shadow: 0 0 0 5px rgba(240, 173, 78, 0); }
}
.cr-chip-clock { font-variant-numeric: tabular-nums; opacity: .8; font-size: 11px; }

/* ---- the panel ---------------------------------------------------------- */
.cr-pop {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 1200;
  width: min(390px, calc(100vw - 24px));
  max-height: min(76vh, 720px); overflow: auto; overscroll-behavior: contain;
  padding: 16px;
  color: var(--ink, #e8ecf3);
  background: color-mix(in srgb, var(--panel, #10141c) 96%, #000);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 16px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .55), 0 2px 8px rgba(0, 0, 0, .4);
  animation: cr-in .16s cubic-bezier(.2, .8, .3, 1);
}
@keyframes cr-in { from { opacity: 0; transform: translateY(-6px) scale(.985); } }
@media (prefers-reduced-motion: reduce) {
  .cr-pop { animation: none; }
  .cr-chip.cr-ticking .cr-dot { animation: none; }
}

.cr-pop::-webkit-scrollbar { width: 10px; }
.cr-pop::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .12); border-radius: 8px;
  border: 3px solid transparent; background-clip: content-box;
}

.cr-loading, .cr-empty { padding: 22px 4px; text-align: center; font-size: 12.5px; color: var(--faint, #6b7280); }
.cr-err { padding: 12px; font-size: 12.5px; color: #fca5a5; background: rgba(239, 68, 68, .08);
          border: 1px solid rgba(239, 68, 68, .28); border-radius: 10px; }
.cr-err button { margin-left: 8px; font: inherit; color: #fff; background: none;
                 border: 0; text-decoration: underline; cursor: pointer; }

.cr-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.cr-eyebrow { display: block; font-size: 10px; letter-spacing: .09em; text-transform: uppercase;
              color: var(--faint, #6b7280); }
.cr-head h3 { margin: 3px 0 0; font-size: 17px; font-weight: 680; letter-spacing: -.01em; }
.cr-head h3 em { margin-left: 7px; font-style: normal; font-size: 12px; font-weight: 500;
                 color: var(--faint, #6b7280); }
.cr-upgrade {
  flex: none; padding: 5px 11px; font-size: 11.5px; font-weight: 600; text-decoration: none;
  color: var(--muted, #9aa3b2); border: 1px solid rgba(255, 255, 255, .12); border-radius: 8px;
  transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.cr-upgrade:hover { color: #fff; background: rgba(255, 255, 255, .06); border-color: rgba(255, 255, 255, .22); }

/* ---- balance ------------------------------------------------------------ */
.cr-hero { display: flex; align-items: center; gap: 16px; margin: 16px 0 12px; }
.cr-ring { position: relative; flex: none; }
.cr-ring svg { display: block; }
.cr-ring-bg { stroke: rgba(255, 255, 255, .07); }
.cr-ring-fg { stroke: #22c55e; transition: stroke-dashoffset .5s cubic-bezier(.2, .8, .3, 1), stroke .3s ease; }
.cr-low .cr-ring-fg { stroke: #f0ad4e; }
.cr-out .cr-ring-fg { stroke: #ef4444; }
.cr-ring-mid {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 1px;
}
.cr-ring-mid b { font-size: 30px; font-weight: 700; letter-spacing: -.02em;
                 font-variant-numeric: tabular-nums; line-height: 1; }
.cr-ring-mid i { font-style: normal; font-size: 11px; color: var(--faint, #6b7280); }

.cr-hero-txt { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.cr-label { font-size: 10px; letter-spacing: .09em; text-transform: uppercase; color: var(--faint, #6b7280); }
.cr-clock { font-size: 24px; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.cr-clock.cr-idle { color: #22c55e; }
.cr-sub { font-size: 11.5px; line-height: 1.5; color: var(--muted, #9aa3b2); }

.cr-bar { height: 5px; border-radius: 99px; background: rgba(255, 255, 255, .07); overflow: hidden; }
.cr-bar span {
  display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, #3b82f6, #22c55e);
  transition: width .5s cubic-bezier(.2, .8, .3, 1);
}

/* ---- numbers ------------------------------------------------------------ */
.cr-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 14px 0 4px; }
.cr-stat {
  min-width: 0; padding: 10px 9px; text-align: center;
  background: rgba(255, 255, 255, .03); border: 1px solid rgba(255, 255, 255, .06); border-radius: 11px;
}
.cr-stat b { display: block; font-size: 17px; font-weight: 680; font-variant-numeric: tabular-nums; }
.cr-stat span {
  display: block; margin-top: 2px; font-size: 10.5px; line-height: 1.35; color: var(--faint, #6b7280);
  /* A tool name can be long; clip it rather than let one card grow taller than
     the two beside it. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.cr-block { margin-top: 16px; }
.cr-block-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 8px; font-size: 10px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--faint, #6b7280);
}
.cr-refresh { font: inherit; font-size: 10px; letter-spacing: .06em; color: var(--muted, #9aa3b2);
              background: none; border: 0; cursor: pointer; text-transform: uppercase; }
.cr-refresh:hover:not(:disabled) { color: #fff; }
.cr-refresh:disabled { opacity: .5; cursor: default; }

.cr-tools { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.cr-tools li { display: grid; grid-template-columns: minmax(0, 1fr) 68px auto; align-items: center; gap: 9px; }
.cr-tool-name { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cr-tool-bar { height: 4px; border-radius: 99px; background: rgba(255, 255, 255, .07); overflow: hidden; }
.cr-tool-bar i { display: block; height: 100%; background: #3b82f6; border-radius: 99px; }
.cr-tool-n { font-size: 12px; font-weight: 620; font-variant-numeric: tabular-nums; text-align: right; }
.cr-tool-n i { display: block; font-style: normal; font-size: 10px; font-weight: 400; color: var(--faint, #6b7280); }

/* ---- ledger ------------------------------------------------------------- */
.cr-log { list-style: none; margin: 0; padding: 0; }
.cr-log li {
  display: grid; grid-template-columns: 8px minmax(0, 1fr) auto auto;
  align-items: center; gap: 9px; padding: 7px 0;
  border-bottom: 1px solid rgba(255, 255, 255, .05);
  font-size: 12px;
}
.cr-log li:last-child { border-bottom: 0; }
.cr-log-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--faint, #6b7280); }
.cr-log-charge .cr-log-dot { background: #ef4444; }
.cr-log-refill .cr-log-dot { background: #22c55e; }
.cr-log-refund .cr-log-dot { background: #3b82f6; }
.cr-log-what { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cr-log-when { font-size: 10.5px; color: var(--faint, #6b7280); white-space: nowrap; }
.cr-log-amt { font-weight: 640; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cr-log-charge .cr-log-amt { color: #fca5a5; }
.cr-log-refill .cr-log-amt, .cr-log-refund .cr-log-amt { color: #86efac; }

/* ---- phones ------------------------------------------------------------- */
@media (max-width: 560px) {
  /* Anchoring to a chip that is now near the screen edge would push the panel
     off it, so below this width it becomes a sheet pinned to the viewport. */
  .cr-pop {
    position: fixed; top: auto; bottom: 0; left: 0; right: 0;
    width: auto; max-height: 82vh;
    border-radius: 18px 18px 0 0;
    animation: cr-up .2s cubic-bezier(.2, .8, .3, 1);
  }
  @keyframes cr-up { from { transform: translateY(14px); opacity: 0; } }
  .cr-hero { gap: 14px; }
  .cr-stats { grid-template-columns: 1fr 1fr; }
  .cr-stat:last-child { grid-column: 1 / -1; }
}

/* Renewal / cancellation date under the balance. */
.cr-renews { margin: 8px 0 10px; font-size: 11.5px; color: var(--faint, #6b7280); }
/* .cr-upgrade is a <button> as well as an <a> now — reset the button chrome so
   the two are indistinguishable. */
button.cr-upgrade { font: inherit; cursor: pointer; background: none; }
button.cr-upgrade:disabled { opacity: .6; cursor: default; }
/* Account home. Everything is a real class on an auto-fitting grid — the old
   fixed 3-column layout with inline styles couldn't reflow and squashed on any
   narrow window. */

.db-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.db-head .tool-sub { margin-bottom: 18px; }
.db-head-act { display: flex; gap: 8px; flex: 0 0 auto; }

/* ---- stat row ---- */
.db-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }
.db-stat { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.db-k { font-size: 10.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--faint, #6b7280); }
.db-v { font-size: 28px; font-weight: 800; letter-spacing: -.03em; line-height: 1.1;
  font-variant-numeric: tabular-nums; }
.db-v.sm { font-size: 19px; letter-spacing: -.015em; }
.db-v small { font-size: 14px; font-weight: 600; color: var(--muted, #98a2b3); margin-left: 2px; }
.db-meter { height: 6px; border-radius: 4px; background: rgba(255,255,255,.08); overflow: hidden; margin-top: 2px; }
.db-meter > i { display: block; height: 100%; border-radius: 4px;
  background: linear-gradient(90deg, var(--accent-2, #60A5FA), var(--accent, #3B82F6)); transition: width .4s; }
.db-note { font-size: 12px; color: var(--muted, #98a2b3); margin-top: auto; }
.db-link { font-size: 12.5px; font-weight: 600; color: var(--accent-2, #60A5FA); text-decoration: none; }
.db-link:hover { text-decoration: underline; }

/* ---- sections ---- */
.db-sec { margin-top: 28px; }
.db-sec-h { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.db-sec-h h2 { font-size: 16px; font-weight: 800; letter-spacing: -.015em; margin: 0; }
.db-sec-h span { font-size: 12.5px; color: var(--muted, #98a2b3); }

/* ---- tool shortcuts ---- */
.db-tools { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: 10px; }
.db-tool { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 12px;
  text-decoration: none; color: var(--ink, #e7ebf0); min-width: 0;
  background: linear-gradient(180deg, rgba(26,31,39,.55), rgba(20,24,30,.55));
  border: 1px solid var(--line, rgba(255,255,255,.09));
  transition: transform .12s, border-color .14s, background .14s; }
.db-tool:hover { transform: translateY(-2px); border-color: var(--accent-line, rgba(59,130,246,.45));
  background: linear-gradient(180deg, rgba(59,130,246,.12), rgba(20,24,30,.6)); }
.db-tool-ico { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 9px; flex: 0 0 auto;
  background: var(--accent-weak, rgba(59,130,246,.14)); color: var(--accent-2, #60A5FA); }
.db-tool-n { font-size: 13px; font-weight: 600; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.db-empty { font-size: 13.5px; color: var(--muted, #98a2b3); }
.db-empty a { color: var(--accent-2, #60A5FA); }

/* ---- account rows ---- */
.db-row { display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 10px 0; border-bottom: 1px solid var(--line, rgba(255,255,255,.08)); }
.db-row:last-child { border-bottom: none; }
.db-row-k { color: var(--muted, #98a2b3); font-size: 13px; flex: 0 0 auto; }
.db-row-v { font-weight: 600; font-size: 13px; min-width: 0; text-align: right;
  overflow: hidden; text-overflow: ellipsis; }

/* ---- no subscription: the one thing on the page that matters ---- */
.db-locked { display: flex; align-items: center; gap: 18px; margin-bottom: 20px; }
.db-locked-ic { display: grid; place-items: center; width: 46px; height: 46px; flex: 0 0 auto;
  border-radius: 14px; background: var(--surface-3, rgba(255,255,255,.06));
  border: 1px solid var(--line, rgba(255,255,255,.1)); color: var(--accent-2, #7FA9F5); }
.db-locked-txt { flex: 1 1 auto; min-width: 0; }
.db-locked-txt h2 { font-size: 16px; font-weight: 700; letter-spacing: -.015em; margin: 0 0 5px; }
.db-locked-txt p { margin: 0; font-size: 13px; line-height: 1.6;
  color: var(--muted, #98a2b3); max-width: 62ch; text-wrap: pretty; }
.db-locked .btn { flex: 0 0 auto; }

/* ---- credit ledger ---- */
.db-ledger { padding-block: 4px; }
.db-le { display: grid; align-items: center; gap: 4px 14px;
  grid-template-columns: minmax(0, 1fr) auto auto auto;
  padding: 11px 0; border-bottom: 1px solid var(--line-soft, rgba(255,255,255,.06));
  font-size: 13px; }
.db-le:last-child { border-bottom: none; }
.db-le-k { min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.db-le-k em { font-style: normal; font-weight: 500; color: var(--muted, #98a2b3); margin-left: 8px; }
.db-le-a { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--muted, #98a2b3); }
.db-le-a.out { color: #F0928A; }
.db-le-a.in { color: #7BD9A0; }
.db-le-b { font-variant-numeric: tabular-nums; font-size: 12.5px; color: var(--muted, #98a2b3); }
.db-le-t { font-size: 12px; color: var(--faint, #6b7280); text-align: right; min-width: 62px; }
.db-ledger-empty { font-size: 13px; color: var(--muted, #98a2b3); padding: 8px 0; }

/* ---- phone ---- */
@media (max-width: 620px) {
  .db-head-act { width: 100%; }
  .db-head-act .btn { flex: 1 1 auto; justify-content: center; }

  /* the banner stacks so the headline is never squeezed into two words a line */
  .db-locked { flex-direction: column; align-items: flex-start; gap: 14px; }
  .db-locked .btn { width: 100%; justify-content: center; }

  /* the ledger drops to two rows per entry instead of four cramped columns */
  .db-le { grid-template-columns: minmax(0, 1fr) auto; }
  .db-le-k { white-space: normal; }
  .db-le-b { grid-column: 1; font-size: 12px; }
  .db-le-t { grid-column: 2; }
}
/* Security settings. Reuses the app's card/button/field primitives; everything
   here is the layout and the state colours those primitives don't cover. */

/* Full width of the shell (.content already caps at 1400px and centres). The
   page used to cap itself at 880px on top of that, which left roughly a third
   of a wide screen empty while the cards inside were still cramped. Width is
   only worth having if the layout uses it, so the sections below become
   columns rather than one long stretched stack. */
.sec { width: 100%; }
/* Prose still wraps at a readable measure — a 1300px-wide sentence is worse
   than a narrow one, even when the space is there. */
.sec .tool-sub { max-width: 78ch; text-wrap: pretty; }

/* ---- the two-column body ---- */
.sec-grid { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 16px; align-items: start; }
.sec-col { display: flex; flex-direction: column; min-width: 0; }
.sec-col > .sec-card:last-child { margin-bottom: 16px; }
@media (max-width: 1080px) { .sec-grid { grid-template-columns: minmax(0, 1fr); gap: 0; } }

/* ---- flash messages ---- */
.sec-flash { display: flex; align-items: flex-start; gap: 9px; padding: 11px 14px; border-radius: 11px;
  font-size: 13.5px; font-weight: 600; line-height: 1.5; margin-bottom: 18px; }
.sec-flash svg { flex: 0 0 auto; margin-top: 1px; }
.sec-flash.ok { background: rgba(34,197,94,.12); color: #6ee7a0; border: 1px solid rgba(34,197,94,.26); }
.sec-flash.err { background: rgba(239,68,68,.12); color: #f89a94; border: 1px solid rgba(239,68,68,.26); }
.sec-err { color: #f89a94; font-size: 14px; }

/* ---- status strip ---- */
.sec-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 14px; margin-bottom: 18px; }
.sec-tile { display: flex; align-items: flex-start; gap: 13px; padding: 16px 18px; min-width: 0; }
.sec-tile-ic { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 10px;
  flex: 0 0 auto; background: rgba(255,255,255,.06); color: var(--faint, #8b93a1);
  border: 1px solid var(--line, rgba(255,255,255,.09)); }
.sec-tile.on .sec-tile-ic { background: rgba(34,197,94,.13); color: #6ee7a0; border-color: rgba(34,197,94,.28); }
.sec-tile-b { min-width: 0; }
.sec-tile-k { font-size: 10.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--faint, #6b7280); }
.sec-tile-v { font-size: 16px; font-weight: 700; letter-spacing: -.015em; margin-top: 3px; }
.sec-tile-n { font-size: 11.5px; color: var(--muted, #98a2b3); margin-top: 4px; line-height: 1.45; }

/* ---- section cards ---- */
.sec-card { margin-bottom: 16px; padding: 20px 22px; }
.sec-h { display: flex; align-items: flex-start; gap: 13px; margin-bottom: 16px; }
.sec-h > div { flex: 1 1 auto; min-width: 0; }
.sec-h h2 { font-size: 16px; font-weight: 800; letter-spacing: -.015em; margin: 0 0 4px; }
.sec-h p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--muted, #98a2b3);
  max-width: 64ch; text-wrap: pretty; }
.sec-h-ic { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 10px;
  flex: 0 0 auto; background: var(--accent-weak, rgba(59,130,246,.14));
  color: var(--accent-2, #60A5FA); border: 1px solid var(--accent-line, rgba(59,130,246,.24)); }

.sec-pill { flex: 0 0 auto; font-size: 11px; font-weight: 800; letter-spacing: .04em;
  padding: 5px 11px; border-radius: 999px; text-transform: uppercase;
  background: rgba(255,255,255,.07); color: var(--muted, #98a2b3);
  border: 1px solid var(--line, rgba(255,255,255,.11)); }
.sec-pill.on { background: rgba(34,197,94,.13); color: #6ee7a0; border-color: rgba(34,197,94,.3); }

.sec-lead { font-size: 13.5px; line-height: 1.6; color: var(--muted, #98a2b3);
  margin: 0 0 16px; max-width: 66ch; text-wrap: pretty; }

/* ---- method rows (both a chosen state and a pickable button) ---- */
.sec-methods { display: grid; gap: 10px; }

/* A method is a row with a switch, not a button that starts doing something
   the moment it is pressed. The icon column matches .sec-method so both
   layouts line up while the old one is still used elsewhere. */
.sec-method-row { align-items: flex-start; gap: 13px; }
/* the base row is space-between for a two-child layout; this one has three,
   so the text block has to claim the middle */
.sec-method-row > div { flex: 1 1 auto; }
.sec-method-row .sec-method-ic { margin-top: 1px; }
.sec-method-row.is-on { border-color: rgba(34, 197, 94, .34); background: rgba(34, 197, 94, .05); }
.sec-method-row.is-on .sec-method-ic { background: rgba(34, 197, 94, .14); color: #6ee7a0; }
.sec-method-note {
  margin-top: 5px; font-size: 11.5px; font-weight: 600;
  letter-spacing: .02em; color: #6ee7a0 !important;
}
.sec-methods-foot {
  margin: 2px 0 0; font-size: 12px; line-height: 1.5;
  color: var(--faint, #6b7380);
}
.sec-method { display: flex; align-items: center; gap: 13px; width: 100%; text-align: left;
  padding: 14px 16px; border-radius: 12px; color: inherit; font: inherit;
  background: rgba(255,255,255,.035); border: 1px solid var(--line, rgba(255,255,255,.09)); }
.sec-method.pick { cursor: pointer; transition: border-color .14s, background .14s, transform .12s; }
.sec-method.pick:hover:not(:disabled) { border-color: var(--accent-line, rgba(59,130,246,.5));
  background: rgba(59,130,246,.09); transform: translateY(-1px); }
.sec-method.pick:disabled { opacity: .5; cursor: not-allowed; }
.sec-method.active { background: rgba(34,197,94,.07); border-color: rgba(34,197,94,.26); }
.sec-method-ic { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 10px;
  flex: 0 0 auto; background: rgba(255,255,255,.06); color: var(--accent-2, #60A5FA);
  border: 1px solid var(--line, rgba(255,255,255,.09)); }
.sec-method.active .sec-method-ic { background: rgba(34,197,94,.14); color: #6ee7a0;
  border-color: rgba(34,197,94,.28); }
.sec-method-b { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.sec-method-b b { font-size: 14px; font-weight: 700; }
.sec-method-b span { font-size: 12.5px; line-height: 1.5; color: var(--muted, #98a2b3);
  text-wrap: pretty; }
.sec-method-go { flex: 0 0 auto; font-size: 12.5px; font-weight: 700;
  color: var(--accent-2, #60A5FA); white-space: nowrap; }
.sec-method-tick { display: grid; place-items: center; width: 26px; height: 26px; flex: 0 0 auto;
  border-radius: 999px; background: rgba(34,197,94,.16); color: #6ee7a0; }
.sec-avatar { width: 36px; height: 36px; border-radius: 999px; flex: 0 0 auto;
  border: 1px solid var(--line, rgba(255,255,255,.14)); object-fit: cover; }

/* ---- actions ---- */
.sec-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 9px; margin-top: 16px; }
.sec-card .btn.danger { background: rgba(239,68,68,.14); color: #f89a94;
  border: 1px solid rgba(239,68,68,.3); box-shadow: none; }
.sec-card .btn.danger:hover:not(:disabled) { background: rgba(239,68,68,.22); filter: none; }
.sec-card .btn.sm { padding: 7px 13px; font-size: 12.5px; border-radius: 9px; }
.sec-linkbtn { background: none; border: 0; padding: 0; cursor: pointer; font: inherit;
  display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 600;
  color: var(--accent-2, #60A5FA); }
.sec-linkbtn:hover:not(:disabled) { text-decoration: underline; }
.sec-linkbtn:disabled { opacity: .5; cursor: default; }

/* ---- enrollment ---- */
.sec-flow { margin-top: 4px; }
.sec-steps { margin: 0 0 16px; padding-left: 20px; display: grid; gap: 6px;
  font-size: 13.5px; line-height: 1.55; color: var(--muted, #98a2b3); }
.sec-steps li::marker { color: var(--accent-2, #60A5FA); font-weight: 700; }

.sec-enroll { display: flex; align-items: center; gap: 22px; flex-wrap: wrap;
  padding: 18px; border-radius: 13px; background: rgba(0,0,0,.22);
  border: 1px solid var(--line, rgba(255,255,255,.08)); }
.sec-qr { width: 186px; height: 186px; flex: 0 0 auto; border-radius: 10px;
  background: #fff; padding: 6px; }
.sec-qr.placeholder { display: grid; place-items: center; background: rgba(255,255,255,.05);
  color: var(--muted, #98a2b3); font-size: 12px; text-align: center; padding: 12px; }
.sec-enroll-b { flex: 1 1 220px; min-width: 0; display: flex; flex-direction: column;
  align-items: flex-start; gap: 9px; }
.sec-k { font-size: 10.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--faint, #6b7280); }
.sec-secret { display: block; width: 100%; font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13.5px; letter-spacing: .09em; word-break: break-all; line-height: 1.6;
  color: var(--ink, #e7ebf0); background: rgba(0,0,0,.3); padding: 10px 12px; border-radius: 9px;
  border: 1px solid var(--line, rgba(255,255,255,.1)); }

.sec-code-f { max-width: 220px; }
.sec-code { font-size: 21px; font-weight: 700; letter-spacing: .32em; text-align: center;
  font-variant-numeric: tabular-nums; padding-left: 13px; }

.sec-warn { display: flex; align-items: flex-start; gap: 10px; padding: 13px 15px; border-radius: 11px;
  background: rgba(245,158,11,.1); border: 1px solid rgba(245,158,11,.28);
  color: #e5b567; font-size: 13px; line-height: 1.55; margin-bottom: 4px; }
.sec-warn svg { flex: 0 0 auto; margin-top: 1px; }

/* ---- toggle ---- */
.sec-toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 14px 16px; border-radius: 12px; background: rgba(255,255,255,.035);
  border: 1px solid var(--line, rgba(255,255,255,.09)); }
.sec-toggle-row > div { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.sec-toggle-row b { font-size: 14px; font-weight: 700; }
.sec-toggle-row span { font-size: 12.5px; line-height: 1.5; color: var(--muted, #98a2b3);
  text-wrap: pretty; }
.sec-switch { flex: 0 0 auto; width: 46px; height: 26px; border-radius: 999px; cursor: pointer;
  padding: 0; background: rgba(255,255,255,.12); border: 1px solid var(--line, rgba(255,255,255,.14));
  transition: background .16s, border-color .16s; position: relative; }
.sec-switch > span { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px;
  border-radius: 999px; background: #cfd6e0; transition: transform .16s, background .16s; }
.sec-switch.on { background: rgba(34,197,94,.35); border-color: rgba(34,197,94,.5); }
.sec-switch.on > span { transform: translateX(20px); background: #6ee7a0; }
.sec-switch:disabled { opacity: .45; cursor: not-allowed; }

/* ---- sign-in log ----
   A real table now that it has the width: device, location, IP and time each
   get a column instead of being crushed onto one line under the event. */
/* A container query, not a viewport one: this table's real width depends on the
   sidebar and the page padding as much as the window, so keying its columns to
   the viewport dropped the IP address on a 1240px window that still had 900px
   of table to play with. It now responds to the space it actually has. */
.sec-log { display: grid; container-type: inline-size; }
.sec-log-head, .sec-log-r { display: grid; align-items: center; gap: 14px;
  grid-template-columns: 24px minmax(120px, 0.9fr) minmax(0, 1.4fr) minmax(0, 1fr) 130px 92px; }
.sec-log-head { padding: 0 0 8px; font-size: 10px; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--faint, #6b7280);
  border-bottom: 1px solid var(--line, rgba(255,255,255,.09)); }
.sec-log-r { padding: 11px 0; font-size: 13px;
  border-bottom: 1px solid var(--line-soft, rgba(255,255,255,.06)); }
.sec-log-r:last-child { border-bottom: none; }
.sec-log-d { display: grid; place-items: center; width: 22px; height: 22px; border-radius: 999px; }
.sec-log-d.ok { background: rgba(34,197,94,.15); color: #6ee7a0; }
.sec-log-d.bad { background: rgba(239,68,68,.15); color: #f89a94; }
.sec-log-e { font-weight: 700; white-space: nowrap; }
.sec-log-v { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sec-log-v.muted { color: var(--muted, #98a2b3); }
.sec-log-ip { font-size: 12px; color: var(--muted, #98a2b3); font-variant-numeric: tabular-nums;
  white-space: nowrap; }
.sec-log-t { font-size: 12px; color: var(--faint, #6b7280); text-align: right; white-space: nowrap; }

/* Drop columns as the table's own space runs out, least useful first. The
   outcome, the device and the time are the last three to go — those answer
   "was this me?" on their own. */
@container (max-width: 760px) {
  .sec-log-head, .sec-log-r { grid-template-columns: 24px minmax(110px, 0.9fr) minmax(0, 1.4fr) minmax(0, 1fr) 92px; }
  .sec-log-head > :nth-child(5), .sec-log-r > .sec-log-ip { display: none; }
}
@container (max-width: 560px) {
  .sec-log-head, .sec-log-r { grid-template-columns: 24px minmax(0, 1fr) minmax(0, 1.2fr) 84px; }
  .sec-log-head > :nth-child(4), .sec-log-r > .sec-log-v.muted { display: none; }
}
@container (max-width: 380px) {
  .sec-log-head { display: none; }
  .sec-log-r { grid-template-columns: 24px minmax(0, 1fr) auto; }
  .sec-log-r > .sec-log-e { display: none; }
}

@media (max-width: 620px) {
  .sec-h { flex-wrap: wrap; }
  .sec-pill { order: 3; }
  .sec-enroll { justify-content: center; }
}
/* ============================================================================
   Account settings.
   ----------------------------------------------------------------------------
   One column, one measure. The first pass laid the three blocks out in a
   two-column grid, which produced two faults at once: the cards ended at
   different heights and left a ragged hole, and the full-width block below
   stretched its password fields to about 1280px — a text box six times wider
   than anything anyone types into it.

   A settings page is a form, so it is built like one: a single column capped
   at a readable measure, every control capped again at the width its content
   actually needs, and each rule stated under the field it governs rather than
   discovered by having the server reject you.

   Namespaced `st-` so it cannot collide with security.css or dashboard.css.
   ============================================================================ */

.st {
  /* The page fills the pane. Two earlier attempts failed the same way: a wide
     card split into "description | controls" puts the two halves at opposite
     ends and opens a hole between them, and capping the column instead just
     moves the emptiness to the sides. The fix is to stop stretching ONE card
     and let several share the width — each card is a self-contained panel, so
     the width is spent on content rather than on gaps.
     --st-card is the narrowest a panel may get before the grid drops a column. */
  --st-card: 420px;

  /* ── premium dark, scoped to this page ────────────────────────────────────
     The app runs on theme.css: a blue-tinted ground (#0B0D10), blue-grey text
     and the old #3B82F6 accent at 10-16px radii, which is why this page read
     as dated next to the landing site. These override the same token NAMES on
     .st only, so the whole page shifts without touching the shared theme. */
  --bg:     #0A0A0B;                    /* the well an input sits in */
  --bg-2:   #131315;                    /* card surface */
  --line:   rgba(255, 255, 255, .08);
  --line-2: rgba(255, 255, 255, .14);
  --text:   #FFFFFF;
  --muted:  #A9A9AF;                    /* neutral, not blue-grey */
  --faint:  #8B8B92;
  --info:   #4DA3FF;                    /* accent ON dark: links, icons */
  /* Accent BEHIND white text needs to be darker: white on #0A84FF measures
     3.68:1, under the 4.5:1 floor. #0060DF measures 5.62:1. */
  --st-fill: #0060DF;
  --st-fill-hover: #0A6FE8;

  padding: 4px 0 56px;
}

/* ── header ───────────────────────────────────────────────────────────────── */
.st-top { margin-bottom: 32px; }
/* the intro still reads as prose, so it keeps a measure even though the grid
   below it does not */
.st-top p { max-width: 78ch; }
.st-top h1 {
  margin: 0 0 8px; font-size: 26px; font-weight: 800;
  letter-spacing: -.02em; line-height: 1.2; color: var(--text);
}
.st-top p { margin: 0; font-size: 14.5px; line-height: 1.65; color: var(--muted); }
.st-top a { color: var(--info); font-weight: 600; text-decoration: none; }
.st-top a:hover { text-decoration: underline; }

/* ── the stack ────────────────────────────────────────────────────────────── */
.st-grid {
  display: grid; gap: 16px;
  grid-template-columns: minmax(0, 1fr);
  /* Equal heights across a row. The earlier worry — that stretching would put
     the empty space back inside the shorter card — only holds if the content
     stays at the top. The action is pinned to the card floor instead, so the
     slack goes above the button and the buttons line up across the row. */
  align-items: stretch;
}

/* auto-fit was the obvious choice here and it is wrong: it only collapses a
   track that is empty in EVERY row, so three cards in two columns still left
   the bottom-right cell blank — the same dead corner, one row lower. The
   column count is pinned instead, and in the two-column case the last card is
   told to span, so every row is full at every width. */
@media (min-width: 820px) {
  .st-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* The odd card out spans the row so no cell is left blank — but a spanning
     card is ~930px wide, and stacked that gives it a 880px password field. It
     has the width for two columns, so it uses them: description left, controls
     right, and the space goes to content instead of to one enormous input. */
  .st-grid > .st-card:last-child:nth-child(odd) {
    grid-column: 1 / -1;
    display: grid; grid-template-columns: 320px minmax(0, 1fr);
    gap: 36px; align-items: start;
  }
  .st-grid > .st-card:last-child:nth-child(odd) .st-form {
    margin-top: 0; padding-top: 0; border-top: 0;
  }
}
@media (min-width: 1400px) {
  .st-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* three across: nothing spans, so the card goes back to a plain panel */
  .st-grid > .st-card:last-child:nth-child(odd) {
    grid-column: auto; display: flex; flex-direction: column;
  }
  .st-grid > .st-card:last-child:nth-child(odd) .st-form {
    margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--line);
  }
}

.st-card {
  display: flex; flex-direction: column;
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: 24px; padding: 26px;
  transition: border-color .18s ease;
}
/* the card you are actually typing in lifts a little out of the stack */
.st-card:focus-within { border-color: var(--line-2); }

.st-head { display: flex; align-items: flex-start; gap: 13px; }
.st-ico {
  width: 40px; height: 40px; flex: 0 0 auto; border-radius: 14px;
  display: grid; place-items: center;
  background: rgba(10, 132, 255, .12); border: 1px solid rgba(10, 132, 255, .3);
  color: var(--info);
}
.st-head h2 {
  margin: 0 0 3px; font-size: 16px; font-weight: 700;
  letter-spacing: -.012em; color: var(--text);
}
.st-head p { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--muted);
  max-width: 54ch; text-wrap: pretty; }

/* Stacked on a phone, a rule separates "what this is" from "change it".
   From 820px the card splits into two columns and the rule is redundant —
   see the breakpoint at the bottom of this file. */
.st-form {
  display: flex; flex-direction: column; gap: 14px;
  flex: 1 1 auto;
  margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--line);
}
/* pushes the button to the bottom of the card, which is what lets a row of
   cards share one action baseline however tall each one's content is */
.st-form .st-btn { margin-top: auto; }

.st-field { display: flex; flex-direction: column; gap: 6px; }
/* the label, not the hint — the hint is a <span> in the same box, and a
   `> span` rule here would out-specify .st-hint and restyle it */
.st-field > label { font-size: 13px; font-weight: 600; color: #C9C9CF; letter-spacing: -.005em; }
.st-input {
  width: 100%;
  min-height: 48px; padding: 0 15px; border-radius: 14px;
  background: var(--bg); border: 1px solid var(--line-2); color: var(--text);
  font-family: inherit;
  /* 16px keeps iOS from zooming the page when a field takes focus */
  font-size: 16px;
  transition: border-color .16s ease, box-shadow .16s ease;
}
.st-input::placeholder { color: var(--faint); }
.st-input:hover:not(:disabled):not(:focus) { border-color: rgba(255, 255, 255, .22); }
.st-input:focus {
  outline: none; border-color: var(--info);
  box-shadow: 0 0 0 3px rgba(10, 132, 255, .20);
}
.st-input:disabled { opacity: .5; cursor: not-allowed; }

/* the rule for a field, stated under the field */
.st-hint {
  font-size: 12.5px; line-height: 1.45; color: var(--faint);
}
.st-hint.is-bad { color: #FCA5A5; }

/* two short controls side by side, still inside the measure */
.st-pair { display: grid; gap: 16px; grid-template-columns: repeat(2, minmax(0, 1fr)); }

.st-btn {
  align-self: flex-start; min-height: 46px; padding: 0 24px; border-radius: 999px;
  border: 0; cursor: pointer; font-family: inherit; font-size: 14px; font-weight: 600;
  background: var(--st-fill); color: #fff; white-space: nowrap;
  transition: background .16s ease, opacity .16s ease;
}
.st-btn:hover:not(:disabled) { background: var(--st-fill-hover); }
/* Disabled until something actually changed — a button that saves nothing is
   worse than no button, because it makes you doubt the save worked. */
.st-btn:disabled { opacity: .4; cursor: not-allowed; }

.st-note {
  display: flex; align-items: flex-start; gap: 9px; padding: 11px 13px;
  border-radius: 16px; font-size: 13.5px; line-height: 1.5;
}
.st-note svg { flex: 0 0 auto; margin-top: 2px; }
.st-note.is-err { background: rgba(220, 38, 38, .1); border: 1px solid rgba(220, 38, 38, .32); color: #FCA5A5; }
.st-note.is-ok  { background: rgba(34, 197, 94, .1); border: 1px solid rgba(34, 197, 94, .32); color: #86EFAC; }

/* ── panels ───────────────────────────────────────────────────────────────────
   Each card now stacks: what the setting IS on top, the controls under it. The
   two-column split this replaced only made sense while a card owned the whole
   pane; inside a ~430px panel there is no width to split, and stacking is what
   keeps the controls full-bleed so no gap can open beside them. */
/* Admin panel — real tables and cards instead of raw JSON in a <pre>. */

.ad-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.ad-head .tool-sub { margin-bottom: 18px; }
.ad-head-act { display: flex; gap: 8px; flex: 0 0 auto; }

/* ---- stat tiles ---- */
.ad-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; margin-bottom: 18px; }
.ad-tile { position: relative; display: flex; flex-direction: column; gap: 5px; min-width: 0;
  padding: 18px 20px; overflow: hidden; transition: border-color .16s, transform .16s; }
/* a hairline of colour along the top edge — enough to give the row a rhythm
   without turning the panel into a set of traffic lights */
.ad-tile::before { content: ''; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(90deg, var(--accent, #3B82F6), transparent 70%); opacity: .55; }
.ad-tile:hover { border-color: var(--accent-line, rgba(59,130,246,.32)); transform: translateY(-1px); }
.ad-k { font-size: 10.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--faint, #6b7280); }
.ad-v { font-size: 28px; font-weight: 800; letter-spacing: -.03em; line-height: 1.1;
  font-variant-numeric: tabular-nums; }
.ad-v.ok { color: #4ade80; }
.ad-v.bad { color: #f87171; }
.ad-note { font-size: 11.5px; color: var(--muted, #98a2b3); margin-top: auto; }

.ad-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; align-items: start; }
.ad-two > * { min-width: 0; }
.ad-h3 { font-size: 13px; font-weight: 800; margin: 0 0 14px; letter-spacing: .02em;
  text-transform: uppercase; color: var(--muted, #98a2b3);
  padding-bottom: 10px; border-bottom: 1px solid var(--line, rgba(255,255,255,.07)); }

.ad-kv { display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 8px 0; border-bottom: 1px solid var(--line, rgba(255,255,255,.07)); font-size: 13px; }
.ad-kv:last-of-type { border-bottom: none; }
.ad-kv span { color: var(--muted, #98a2b3); flex: 0 0 auto; }
.ad-kv b { min-width: 0; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; }

/* ---- tables ---- */
.ad-scroll { overflow-x: auto; margin: 0 -4px; }
.ad-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.ad-table th { text-align: left; font-weight: 700; font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--faint, #6b7280); padding: 9px 12px; border-bottom: 1px solid var(--line-2, rgba(255,255,255,.12));
  white-space: nowrap; position: sticky; top: 0; background: #14181f; }
.ad-table td { padding: 11px 12px; border-bottom: 1px solid var(--line, rgba(255,255,255,.06)); vertical-align: middle; }
.ad-table tr:last-child td { border-bottom: none; }
.ad-table tbody tr { transition: background .12s; }
.ad-table tbody tr:hover { background: rgba(59,130,246,.06); }
/* first column carries the identity — give it a little more weight */
.ad-table tbody td:first-child { font-weight: 600; color: var(--ink, #e7ebf0); }
.ad-table td.mono { font-family: 'JetBrains Mono', monospace; font-size: 11.5px; color: var(--muted, #98a2b3); }
.ad-table td.right { text-align: right; white-space: nowrap; }
.ad-detail { max-width: 280px; color: var(--muted, #98a2b3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.ad-pill { display: inline-block; font-size: 10.5px; font-weight: 700; padding: 2px 8px; border-radius: 999px;
  background: rgba(255,255,255,.07); color: var(--muted, #98a2b3); white-space: nowrap; }
.ad-pill.ok { background: rgba(34,197,94,.15); color: #4ade80; }
.ad-pill.bad { background: rgba(239,68,68,.15); color: #f87171; }
.ad-pill.accent { background: rgba(59,130,246,.16); color: var(--accent-2, #60A5FA); }

.ad-btn { display: inline-block; padding: 5px 11px; border-radius: 8px; font-size: 11.5px; font-weight: 700;
  cursor: pointer; font-family: inherit; text-decoration: none; color: var(--ink, #e7ebf0);
  border: 1px solid var(--line-2, rgba(255,255,255,.12)); background: rgba(255,255,255,.04); }
.ad-btn:hover { background: rgba(255,255,255,.09); }
.ad-btn:disabled { opacity: .45; cursor: not-allowed; }
.ad-btn.danger { color: #f87171; border-color: rgba(239,68,68,.3); }
.ad-btn.danger:hover { background: rgba(239,68,68,.12); }

/* ---- filters ---- */
.ad-filter { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.ad-filter input[type=search] { flex: 1; min-width: 180px; background: rgba(0,0,0,.28);
  border: 1px solid var(--line-2, rgba(255,255,255,.12)); border-radius: 9px; padding: 9px 12px;
  color: var(--ink, #e7ebf0); font-size: 13px; }

/* ---- assets ----
   Every job is the same tile whether it produced 2 files or 233: picture, what
   it was, who ran it, what came out. The per-bucket file lists live in the
   detail panel — inline they made each card a different height, left the short
   ones with a hole in the middle, and still could not show a 233-file pack. */
.ad-chips { display: flex; flex-wrap: wrap; gap: 7px; margin: 0 0 14px; }
.ad-chip { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; font-family: inherit;
  padding: 6px 12px; border-radius: 999px; font-size: 12px; font-weight: 600;
  color: var(--muted, #98a2b3); background: rgba(255,255,255,.04);
  border: 1px solid var(--line, rgba(255,255,255,.09)); transition: color .15s, background .15s, border-color .15s; }
.ad-chip:hover { color: var(--ink, #e7ebf0); }
.ad-chip.on { color: #fff; background: var(--accent, #3B82F6); border-color: var(--accent, #3B82F6); }
.ad-chip i { font-style: normal; font-size: 10.5px; opacity: .75; }

.ad-assets { display: grid; grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); gap: 12px; }
.ad-asset { display: flex; flex-direction: column; min-width: 0; overflow: hidden;
  border-radius: 14px; background: var(--panel, rgba(22,26,32,.72));
  border: 1px solid var(--line, rgba(255,255,255,.09));
  transition: border-color .16s, transform .16s; }
.ad-asset:hover { border-color: var(--accent-line, rgba(59,130,246,.32)); transform: translateY(-2px); }

/* the picture: one fixed 16:10 window, so a portrait texture and a wide render
   line up in the same grid instead of each setting its own height */
.ad-asset-shot { position: relative; display: block; width: 100%; aspect-ratio: 16 / 10;
  padding: 0; border: 0; cursor: pointer; overflow: hidden; background: rgba(0,0,0,.4);
  border-bottom: 1px solid var(--line, rgba(255,255,255,.09)); }
.ad-asset-shot img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .3s var(--ease, ease); }
.ad-asset:hover .ad-asset-shot img { transform: scale(1.03); }
.ad-asset-none { display: grid; place-items: center; width: 100%; height: 100%;
  font-size: 30px; font-weight: 800; color: var(--faint, #6b7280); }
.ad-asset-count { position: absolute; right: 8px; bottom: 8px; font-size: 10.5px; font-weight: 700;
  color: #fff; background: rgba(0,0,0,.66); border: 1px solid rgba(255,255,255,.16);
  padding: 3px 8px; border-radius: 999px; backdrop-filter: blur(4px); }

.ad-asset-body { display: flex; flex-direction: column; gap: 7px; padding: 13px 14px; min-width: 0; }
.ad-asset-h { display: flex; align-items: center; gap: 8px; justify-content: space-between; }
.ad-asset-h b { font-size: 13.5px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ad-asset-m { display: flex; flex-wrap: wrap; gap: 3px 10px; font-size: 11.5px; color: var(--muted, #98a2b3); }
.ad-asset-m > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ad-asset-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 2px; }
.ad-tag { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px; font-weight: 600;
  color: var(--muted, #98a2b3); background: rgba(255,255,255,.05); border-radius: 999px; padding: 3px 8px; }
.ad-asset-act { margin-top: auto; display: flex; gap: 8px; padding: 0 14px 13px; }
.ad-asset-act .ad-btn { flex: 1; text-align: center; }

/* ---- asset detail ---- */
.ad-modal { position: fixed; inset: 0; z-index: 300; display: grid; place-items: center;
  padding: 24px; background: rgba(0,0,0,.72); backdrop-filter: blur(4px); }
.ad-modal-box { width: min(1080px, 100%); max-height: 90vh; display: flex; flex-direction: column;
  border-radius: 16px; background: var(--bg-2, #111418);
  border: 1px solid var(--line-2, rgba(255,255,255,.14)); box-shadow: 0 40px 90px rgba(0,0,0,.7); }
.ad-modal-head { display: flex; align-items: center; gap: 12px; padding: 16px 18px;
  border-bottom: 1px solid var(--line, rgba(255,255,255,.09)); }
.ad-modal-t { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 3px; }
.ad-modal-t b { font-size: 15px; }
.ad-modal-t span { font-size: 11.5px; color: var(--muted, #98a2b3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ad-modal-body { padding: 18px; overflow-y: auto; display: flex; flex-direction: column; gap: 22px; }
.ad-sec > h4 { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; font-size: 12px;
  font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--muted, #98a2b3); }
.ad-sec > h4 i { font-style: normal; font-size: 10.5px; letter-spacing: 0; color: var(--faint, #6b7280);
  background: rgba(255,255,255,.07); padding: 1px 8px; border-radius: 999px; }
.ad-kv { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px; }
.ad-kv > div { padding: 9px 12px; border-radius: 10px; background: rgba(0,0,0,.22);
  border: 1px solid var(--line, rgba(255,255,255,.07)); min-width: 0; }
.ad-kv span { display: block; font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--faint, #6b7280); }
.ad-kv b { display: block; font-size: 12.5px; margin-top: 2px; overflow-wrap: anywhere; }

.ad-gal { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.ad-gal-i { padding: 0; border: 1px solid var(--line, rgba(255,255,255,.09)); border-radius: 12px;
  background: rgba(0,0,0,.3); cursor: pointer; overflow: hidden; display: flex; flex-direction: column;
  transition: border-color .16s; }
.ad-gal-i:hover { border-color: var(--accent, #3B82F6); }
.ad-gal-i img { width: 100%; aspect-ratio: 1 / 1; object-fit: contain; display: block;
  background: repeating-conic-gradient(rgba(255,255,255,.045) 0% 25%, transparent 0% 50%) 50% / 16px 16px; }
.ad-gal-i span { padding: 7px 9px; font-size: 10.5px; color: var(--muted, #98a2b3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-top: 1px solid var(--line, rgba(255,255,255,.07)); }

.ad-zoom { position: fixed; inset: 0; z-index: 310; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 12px; padding: 28px;
  background: rgba(0,0,0,.9); cursor: zoom-out; }
.ad-zoom img { max-width: 100%; max-height: 82vh; object-fit: contain; border-radius: 10px; }
.ad-zoom span { font-size: 12px; color: var(--muted, #98a2b3); }
.ad-zoom a { color: var(--accent-2, #60A5FA); }

@media (max-width: 700px) {
  .ad-modal { padding: 0; }
  .ad-modal-box { max-height: 100vh; height: 100%; border-radius: 0; border: 0; }
  .ad-modal-head { flex-wrap: wrap; }
}

/* one collapsible section per bucket (renders / game files / config) */
.ad-group { border: 1px solid var(--line, rgba(255,255,255,.07)); border-radius: 10px;
  background: rgba(0,0,0,.16); overflow: hidden; }
.ad-group > summary { display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  padding: 8px 11px; font-size: 12px; font-weight: 700; user-select: none; }
.ad-group > summary::-webkit-details-marker { display: none; }
.ad-group > summary:hover { background: rgba(255,255,255,.04); }
.ad-group > summary i { margin-left: auto; font-style: normal; font-size: 10.5px; font-weight: 700;
  color: var(--muted, #98a2b3); background: rgba(255,255,255,.07); padding: 1px 7px; border-radius: 999px; }
.ad-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--faint, #6b7280); }
.ad-dot.preview { background: #4ade80; }
.ad-dot.stream { background: var(--accent-2, #60A5FA); }
.ad-dot.data { background: #fbbf24; }
.ad-dot.archive { background: #c084fc; }

.ad-group + .ad-group { margin-top: 8px; }
.ad-files { list-style: none; margin: 0; padding: 4px 11px 10px; display: grid; gap: 4px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  max-height: 320px; overflow-y: auto; }
.ad-files li { font-size: 11.5px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ad-files a { color: var(--accent-2, #60A5FA); text-decoration: none; }
.ad-files a:hover { text-decoration: underline; }

.ad-empty { padding: 22px 4px; text-align: center; color: var(--muted, #98a2b3); font-size: 13px; }

/* ---- plan picker in the users table ----
   Narrow, quiet until you touch it: it sits in every row, so a full-strength
   form control would turn the table into a wall of boxes. It inherits the
   app's dropdown styling (theme-clean.css), which is what makes the option
   list dark instead of a white Windows popup. */
.ad-plan {
  min-width: 118px; padding: 6px 30px 6px 10px; font-size: 12px;
  border-radius: 8px; color: var(--ink, #e7ebf0);
  background-color: rgba(255, 255, 255, .04);
  border: 1px solid var(--line, rgba(255,255,255,.10));
  background-position: right 9px center;
}
.ad-plan:hover { border-color: var(--line-2, rgba(255,255,255,.18)); }
.ad-plan:disabled { opacity: .5; cursor: not-allowed; }
/* An account with no plan reads as inactive, so the control does too. */
.ad-plan:has(option[value=""]:checked) { color: var(--muted, #98a2b3); }

/* ── plan and how long it runs ───────────────────────────────────────────
   The two dropdowns are one decision, so they sit in one cell and share a
   column: the length is meaningless without the plan beside it. */
.ad-plan-cell { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; }
.ad-plan-cell .ad-plan { width: 100%; }
.ad-days { font-size: 11px; opacity: .9; }
.ad-until {
  font-size: 10.5px; letter-spacing: .01em; color: #8b96a5;
  padding: 1px 6px; border-radius: 999px; background: rgba(255, 255, 255, .05);
}
.ad-until.dim { opacity: .6; }
.ad-until.bad { color: #fca5a5; background: rgba(239, 68, 68, .14); }

/* ── the activity feed ───────────────────────────────────────────────────── */
.ad-who { display: flex; flex-direction: column; line-height: 1.25; }
.ad-who b { font-weight: 650; }
.ad-who i { font-style: normal; font-size: 10.5px; opacity: .6; }
.ad-dim { opacity: .6; font-size: 11px; margin-left: 6px; }
.ad-btn.accent { color: #bfe0ff; border-color: rgba(59, 130, 246, .5); background: rgba(59, 130, 246, .16); }

/* ── the live toggle ─────────────────────────────────────────────────────
   A pulsing dot rather than a word, because the question it answers — "is this
   still updating?" — should be answerable without reading. */
.ad-btn.live { color: #86efac; border-color: rgba(34, 197, 94, .45); background: rgba(34, 197, 94, .12); }
.ad-btn .ad-live-dot {
  display: inline-block; width: 7px; height: 7px; margin-right: 7px;
  border-radius: 50%; background: currentColor; opacity: .35; vertical-align: middle;
}
.ad-btn.live .ad-live-dot { opacity: 1; animation: ad-pulse 1.8s ease-in-out infinite; }
@keyframes ad-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
  .ad-btn.live .ad-live-dot { animation: none; }
}

/* The desktop log is a footnote to this page, not a section of it. */
.ad-more { margin-top: 14px; }
.ad-more > .ad-btn { font-size: 12px; }
/* Shared task-progress bar — stage, percentage and approximate time left.
   Used by every tool action so a long operation always shows where it is. */
.tp { margin-top: 14px; }
.tp-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.tp-stage { display: inline-flex; align-items: center; gap: 9px; font-size: 13px; font-weight: 600;
  color: var(--ink, #e7ebf0); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tp-pct { font-size: 15px; font-weight: 800; color: var(--accent-2, #60A5FA);
  font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.tp-bar { height: 8px; border-radius: 5px; background: rgba(255,255,255,.08); overflow: hidden; margin: 9px 0 7px; }
.tp-bar > i { display: block; height: 100%; border-radius: 5px;
  background: linear-gradient(90deg, var(--accent-2, #60A5FA), var(--accent, #3B82F6));
  /* Smooth, not steppy: the driver updates every frame, this just softens jumps
     when a real server percentage arrives and overrides the curve. */
  transition: width .25s cubic-bezier(.4, 0, .2, 1); }
.tp-foot { font-size: 11.5px; color: var(--faint, #6b7280); font-variant-numeric: tabular-nums; }
/* Ped Editor — scoped styles (.pe-*), using the shared theme.css tokens.
 *
 * Interaction states are defined ONCE, at the top, and every clickable thing in
 * the editor opts into them. Before this each control invented its own (or, more
 * often, none): the category chips, the ◀ ▶ arrows, the variant tabs and the
 * queue buttons had no hover, no focus ring and no pressed state at all, so half
 * the editor felt dead under the cursor while the other half responded. */

.pe-wrap {
  --pe-accent: var(--accent, #3B82F6);
  --pe-accent-2: var(--accent-2, #60A5FA);
  --pe-line: var(--line-2, rgba(255,255,255,.12));
  --pe-surface: rgba(255,255,255,.04);
  --pe-surface-hi: rgba(255,255,255,.09);
  --pe-ease: cubic-bezier(.2, .7, .35, 1);
  --pe-t: .16s var(--pe-ease);
}

/* ---- the shared interaction layer -------------------------------------- */
.pe-wrap button,
.pe-wrap .pe-chip,
.pe-wrap .pe-ocat,
.pe-wrap .pe-vtab {
  font-family: inherit;
  transition: background var(--pe-t), border-color var(--pe-t), color var(--pe-t),
              transform var(--pe-t), box-shadow var(--pe-t), opacity var(--pe-t);
}
.pe-wrap button:not(:disabled) { cursor: pointer; }
.pe-wrap button:disabled { opacity: .42; cursor: not-allowed; }
/* Keyboard focus gets a real ring; mouse clicks do not (:focus-visible). */
.pe-wrap :focus-visible {
  outline: 2px solid var(--pe-accent-2);
  outline-offset: 2px;
  border-radius: 8px;
}
/* A pressed control should move. Excluded where a nudge would jitter a
   scrolling list or a full-width bar. */
.pe-wrap button:not(:disabled):active { transform: translateY(1px); }

@media (prefers-reduced-motion: reduce) {
  .pe-wrap *, .pe-wrap *::before, .pe-wrap *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
  }
  .pe-wrap button:not(:disabled):active { transform: none; }
}

/* ---- header ------------------------------------------------------------ */
.pe-head { display:flex; align-items:center; gap:14px; margin-bottom:16px; }
.pe-head .pe-ico { width:46px; height:46px; border-radius:13px; display:grid; place-items:center;
  background:var(--accent-weak, rgba(59,130,246,.14)); color:var(--pe-accent-2);
  box-shadow:inset 0 0 0 1px var(--accent-line, rgba(59,130,246,.35)); flex:0 0 auto; }
.pe-head .pe-ico svg { width:24px; height:24px; }
.pe-head h1 { margin:0; font-size:24px; font-weight:800; letter-spacing:-.02em; }
.pe-head p { margin:2px 0 0; color:var(--muted,#98a2b3); font-size:13.5px; }

/* upload card */
.pe-upload { display:flex; flex-direction:column; gap:12px; }

/* ---- toolbar ----------------------------------------------------------- */
.pe-toolbar { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:14px; }
.pe-toolbar .pe-info { color:var(--muted,#98a2b3); font-size:13px; margin-right:auto; }

.pe-btn { display:inline-flex; align-items:center; justify-content:center; gap:7px;
  padding:9px 14px; border-radius:10px; font-size:13px; font-weight:700; white-space:nowrap;
  border:1px solid var(--pe-line); background:var(--pe-surface); color:var(--ink,#e7ebf0); }
.pe-btn:not(:disabled):hover { background:var(--pe-surface-hi); border-color:var(--line-3,rgba(255,255,255,.2)); }
.pe-btn svg { width:15px; height:15px; flex:0 0 auto; }
.pe-btn.accent { border-color:var(--accent-line,rgba(59,130,246,.4)); color:var(--pe-accent-2);
  background:var(--accent-weak,rgba(59,130,246,.12)); }
.pe-btn.accent:not(:disabled):hover { background:rgba(59,130,246,.2); }
.pe-btn.primary { background:linear-gradient(180deg,var(--pe-accent-2),var(--pe-accent)); color:#fff;
  border-color:transparent; box-shadow:0 8px 20px -10px rgba(59,130,246,.8); }
.pe-btn.primary:not(:disabled):hover { filter:brightness(1.07); box-shadow:0 10px 24px -10px rgba(59,130,246,.95); }
.pe-btn.danger { color:#f87171; border-color:rgba(239,68,68,.3); }
.pe-btn.danger:not(:disabled):hover { background:rgba(239,68,68,.14); border-color:rgba(239,68,68,.5); }

/* ---- board layout ------------------------------------------------------
   Three columns on a wide screen, two when the queue no longer fits, one on a
   phone. The old rule dropped straight from 3 to 2 at 1200px and never went to
   1, so the ped panel and the grid fought over a narrow viewport. */
.pe-board { display:grid; grid-template-columns:340px minmax(0,1fr) 260px; gap:16px; align-items:start; }
@media (max-width:1280px){ .pe-board { grid-template-columns:320px minmax(0,1fr); } .pe-pending { display:none; } }
@media (max-width:860px){
  .pe-board { grid-template-columns:minmax(0,1fr); }
  .pe-ped { position:static; }
}

/* ---- ped panel --------------------------------------------------------- */
.pe-ped { position:sticky; top:78px; }
/* Base rule, NOT scoped to .pe-ped. The texture studio uses .pe-view too, and
   while this only existed as `.pe-ped .pe-view` the studio's copy got no
   `position:relative` — so its `.pe-over` child (position:absolute; inset:0)
   anchored to `.pe-studio-bg` instead and stretched its caption across the
   whole overlay. That is the "there is no CSS for editing" symptom: the panel
   had no frame and its label floated loose in the middle of the modal. */
.pe-view { position:relative; border-radius:12px; overflow:hidden;
  border:1px solid var(--line,rgba(255,255,255,.09));
  background:radial-gradient(70% 70% at 50% 30%, #171a22, #0a0c11 85%); }
.pe-ped .pe-view { height:360px; }
.pe-view canvas { display:block; width:100%; height:100%; }
.pe-over { position:absolute; inset:0; display:grid; place-items:center; text-align:center;
  color:var(--muted,#98a2b3); font-size:13px; padding:20px; pointer-events:none; }
.pe-name-line { font-size:12.5px; color:var(--muted,#98a2b3); margin:10px 2px 0; }
.pe-name-line b { color:var(--ink,#e7ebf0); }

.pe-outfit { margin-top:12px; display:flex; flex-direction:column; gap:10px; }

/* Category chips. A tidy wrapped row — every chip the same height, so a
   two-line wrap reads as a grid rather than a ragged pile. */
.pe-ocats { display:flex; flex-wrap:wrap; gap:6px; }
.pe-ocat { display:inline-flex; align-items:center; height:28px; padding:0 11px; border-radius:999px;
  font-size:11.5px; font-weight:700; white-space:nowrap;
  border:1px solid var(--pe-line); background:rgba(255,255,255,.03); color:var(--muted,#98a2b3); }
.pe-ocat:not(:disabled):hover { background:var(--pe-surface-hi); color:var(--ink,#e7ebf0); }
.pe-ocat.on { background:var(--accent-weak,rgba(59,130,246,.16)); color:var(--pe-accent-2);
  border-color:var(--accent-line,rgba(59,130,246,.4)); }
.pe-ocat.on:hover { background:rgba(59,130,246,.24); }

/* Stepper rows: ◀ [ slider ] ▶ */
.pe-nav { display:flex; align-items:center; gap:8px; }
.pe-nav input[type=range] { flex:1; min-width:0; accent-color:var(--pe-accent); cursor:pointer; }
.pe-nav .pe-arrow { width:32px; height:30px; flex:0 0 auto; border-radius:8px; display:grid; place-items:center;
  font-size:11px; line-height:1; border:1px solid var(--pe-line); background:var(--pe-surface);
  color:var(--ink,#e7ebf0); }
.pe-nav .pe-arrow:not(:disabled):hover { background:var(--pe-surface-hi); color:var(--pe-accent-2);
  border-color:var(--accent-line,rgba(59,130,246,.4)); }
.pe-olabel { font-size:12.5px; color:var(--muted,#98a2b3); text-align:center; }
.pe-olabel b { color:var(--ink,#e7ebf0); }

.pe-preload { height:5px; border-radius:3px; background:rgba(255,255,255,.08); overflow:hidden; }
.pe-preload > i { display:block; height:100%; width:0;
  background:linear-gradient(90deg,var(--pe-accent-2),var(--pe-accent)); transition:width .3s var(--pe-ease); }
.pe-preload-text { font-size:11px; color:var(--faint,#6b7280); text-align:center; }

/* Ped actions. A grid, not a 3-way flex: equal columns with nowrap labels kept
   "Clear outfit" from wrapping to two lines and leaving the row uneven. Falls
   to two columns before it would squash. */
.pe-ped-actions { display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:8px; margin-top:12px; }
.pe-ped-actions .pe-btn { width:100%; padding-inline:8px; font-size:12.5px; }
@media (max-width:1360px) and (min-width:1281px){
  .pe-ped-actions { grid-template-columns:repeat(2, minmax(0,1fr)); }
  .pe-ped-actions .pe-btn:last-child { grid-column:1 / -1; }
}
.pe-foot { font-size:11.5px; color:var(--faint,#6b7280); margin-top:8px; text-align:center; }

/* ---- piece grid -------------------------------------------------------- */
.pe-filter { display:flex; align-items:center; gap:10px; margin-bottom:12px; flex-wrap:wrap; }
.pe-filter input[type=search] { flex:1; min-width:160px; background:rgba(0,0,0,.28);
  border:1px solid var(--pe-line); border-radius:9px; padding:9px 12px; color:var(--ink,#e7ebf0);
  font-size:13px; transition:border-color var(--pe-t), box-shadow var(--pe-t); }
.pe-filter input[type=search]:focus { outline:none; border-color:var(--accent-line,rgba(59,130,246,.55));
  box-shadow:0 0 0 3px rgba(59,130,246,.14); }

.pe-chips { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:14px; }
.pe-chip { display:inline-flex; align-items:center; height:28px; padding:0 11px; border-radius:999px;
  font-size:12px; font-weight:700; white-space:nowrap;
  border:1px solid var(--pe-line); background:rgba(255,255,255,.03); color:var(--muted,#98a2b3); }
.pe-chip:not(:disabled):hover { background:var(--pe-surface-hi); color:var(--ink,#e7ebf0); }
.pe-chip.on { background:var(--accent-weak,rgba(59,130,246,.16)); color:var(--pe-accent-2);
  border-color:var(--accent-line,rgba(59,130,246,.4)); }
.pe-chip.on:hover { background:rgba(59,130,246,.24); }

.pe-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:12px; }
.pe-card { border:1px solid var(--line,rgba(255,255,255,.09)); border-radius:13px; overflow:hidden;
  background:linear-gradient(180deg,rgba(26,31,39,.5),rgba(18,22,28,.5));
  display:flex; flex-direction:column; min-width:0;
  transition:transform var(--pe-t), border-color var(--pe-t), box-shadow var(--pe-t); }
.pe-card:hover { transform:translateY(-2px); border-color:var(--accent-line,rgba(59,130,246,.42));
  box-shadow:0 14px 30px -18px rgba(0,0,0,.9); }
.pe-card.del { opacity:.5; }
.pe-card.del:hover { transform:none; }
.pe-card .pe-t { position:relative; aspect-ratio:1;
  background:radial-gradient(70% 70% at 50% 35%,#171a22,#0a0c11 85%); display:grid; place-items:center; }
.pe-card .pe-t img { width:100%; height:100%; object-fit:contain; }
.pe-card .pe-ph { color:var(--faint,#6b7280); font-size:11px; }
.pe-card .pe-meta { padding:9px 10px; display:flex; flex-direction:column; gap:6px; flex:1; }
.pe-card .pe-n { font-size:12.5px; font-weight:600; word-break:break-all; line-height:1.25; }
.pe-card .pe-bd { display:flex; flex-wrap:wrap; gap:4px; }

/* The editor stays mounted while a pack loads (the 3D viewport needs a real
   size to build into) but shows nothing until it is finished. visibility keeps
   the layout — and therefore the canvas dimensions — unlike display:none. */
.pe-stage.loading { visibility:hidden; pointer-events:none; opacity:0; }
.pe-stage.ready { visibility:visible; opacity:1; transition:opacity .22s ease-out; }

/* swap-in notice on the viewport — small, bottom-left, never covers the model */
.pe-swap { position:absolute; left:10px; bottom:10px; display:flex; align-items:center; gap:8px;
  padding:6px 11px; border-radius:999px; font-size:11.5px; font-weight:600;
  background:rgba(8,10,14,.82); border:1px solid var(--line,rgba(255,255,255,.12));
  color:var(--muted,#98a2b3); pointer-events:none; }

/* card whose render is still queued — a quiet shimmer, not a broken-image icon */
.pe-shim { width:100%; height:100%; border-radius:8px;
  background:linear-gradient(100deg, rgba(255,255,255,.03) 30%, rgba(255,255,255,.08) 50%, rgba(255,255,255,.03) 70%);
  background-size:220% 100%; animation:pe-shim 1.3s linear infinite; }
@keyframes pe-shim { from { background-position:120% 0 } to { background-position:-20% 0 } }

.pe-tag { font-size:9.5px; font-weight:700; padding:2px 6px; border-radius:5px;
  background:rgba(255,255,255,.06); color:var(--muted,#98a2b3); white-space:nowrap; }
.pe-tag.edit { background:rgba(234,179,8,.16); color:#facc15; }

/* Card actions: an even row that never squashes one button to fit another. */
.pe-acts { display:grid; grid-auto-flow:column; grid-auto-columns:1fr; gap:5px; margin-top:auto; padding-top:2px; }
.pe-acts button { padding:6px 4px; border-radius:7px; font-size:10.5px; font-weight:700; white-space:nowrap;
  border:1px solid var(--pe-line); background:var(--pe-surface); color:var(--ink,#e7ebf0); }
.pe-acts button:not(:disabled):hover { background:var(--pe-surface-hi); border-color:var(--line-3,rgba(255,255,255,.2)); }
.pe-acts button.danger { color:#f87171; }
.pe-acts button.danger:not(:disabled):hover { background:rgba(239,68,68,.14); border-color:rgba(239,68,68,.45); }
.pe-acts button.accent { color:var(--pe-accent-2); }
.pe-acts button.accent:not(:disabled):hover { background:rgba(59,130,246,.16); border-color:var(--accent-line,rgba(59,130,246,.45)); }

/* ---- pending / queue panel --------------------------------------------- */
.pe-pending { position:sticky; top:78px; }
.pe-pending .pe-pcount { margin-left:auto; font-size:10px; font-weight:800; color:var(--pe-accent-2);
  background:var(--accent-weak,rgba(59,130,246,.14)); padding:2px 8px; border-radius:999px; }
.pe-pending .pe-pcount.empty { color:var(--faint,#6b7280); background:rgba(255,255,255,.05); }
.pe-prow { display:flex; align-items:center; gap:8px; padding:8px 0;
  border-bottom:1px solid var(--line,rgba(255,255,255,.07)); font-size:12px; }
.pe-prow:last-child { border-bottom:none; }
.pe-prow .pe-pn { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pe-prow button { font-size:10.5px; padding:4px 8px; border-radius:6px; font-weight:700; white-space:nowrap;
  border:1px solid var(--pe-line); background:var(--pe-surface); color:var(--ink,#e7ebf0); }
.pe-prow button:not(:disabled):hover { background:var(--pe-surface-hi); color:var(--pe-accent-2);
  border-color:var(--accent-line,rgba(59,130,246,.4)); }

/* ---- modal ------------------------------------------------------------- */
.pe-modal-bg { position:fixed; inset:0; z-index:1000; background:rgba(0,0,0,.62); backdrop-filter:blur(3px);
  display:flex; align-items:center; justify-content:center; padding:24px; animation:pe-fade .16s var(--pe-ease); }
.pe-modal { width:100%; max-width:520px; max-height:88vh; overflow:auto;
  background:linear-gradient(180deg,#151922,#0f131b); border:1px solid var(--line,rgba(255,255,255,.1));
  border-radius:18px; padding:24px; box-shadow:0 40px 90px -30px #000;
  animation:pe-pop .18s var(--pe-ease); }
@keyframes pe-fade { from { opacity:0 } to { opacity:1 } }
@keyframes pe-pop { from { opacity:0; transform:translateY(8px) scale(.985) } to { opacity:1; transform:none } }
.pe-modal h2 { margin:0 0 4px; font-size:19px; font-weight:800; }
.pe-modal .pe-msub { color:var(--muted,#98a2b3); font-size:13px; margin:0 0 18px; }
.pe-modal-x { float:right; width:30px; height:30px; border-radius:8px; display:grid; place-items:center;
  color:var(--muted,#98a2b3); background:none; border:1px solid transparent; font-size:20px; line-height:1; }
.pe-modal-x:hover { background:var(--pe-surface-hi); color:var(--ink,#e7ebf0); border-color:var(--pe-line); }

.pe-drop { border:1.5px dashed var(--line-3,rgba(255,255,255,.16)); border-radius:12px; padding:26px 16px;
  text-align:center; color:var(--muted,#98a2b3); cursor:pointer; font-size:13px;
  transition:border-color var(--pe-t), background var(--pe-t), color var(--pe-t); }
.pe-drop:hover, .pe-drop.over { border-color:var(--accent-line,rgba(59,130,246,.5));
  background:var(--accent-weak,rgba(59,130,246,.07)); color:var(--ink,#e7ebf0); }
.pe-drop .fn { color:var(--pe-accent-2); font-weight:700; margin-top:6px; word-break:break-all; }

.pe-field { margin:12px 0; }
.pe-field label { display:block; font-size:12px; color:var(--muted,#98a2b3); margin-bottom:6px; font-weight:600; }
.pe-select, .pe-input { width:100%; background:rgba(0,0,0,.28); border:1px solid var(--pe-line);
  border-radius:9px; padding:10px 12px; color:var(--ink,#e7ebf0); font-size:13.5px;
  transition:border-color var(--pe-t), box-shadow var(--pe-t); }
.pe-select:focus, .pe-input:focus { outline:none; border-color:var(--accent-line,rgba(59,130,246,.55));
  box-shadow:0 0 0 3px rgba(59,130,246,.14); }
.pe-divider { text-align:center; color:var(--faint,#6b7280); font-size:11px; margin:14px 0;
  text-transform:uppercase; letter-spacing:.1em; }

/* ---- texture studio (split overlay) ------------------------------------ */
.pe-studio-bg { position:fixed; inset:0; z-index:1100; background:rgba(6,8,12,.82); backdrop-filter:blur(4px);
  display:flex; animation:pe-fade .16s var(--pe-ease); }
.pe-studio { margin:auto; width:min(1180px,96vw); height:min(760px,92vh);
  display:grid; grid-template-columns:380px minmax(0,1fr);
  background:linear-gradient(180deg,#141822,#0e121a); border:1px solid var(--line,rgba(255,255,255,.1));
  border-radius:18px; overflow:hidden; animation:pe-pop .2s var(--pe-ease); }
@media (max-width:820px){
  .pe-studio { grid-template-columns:minmax(0,1fr); grid-template-rows:auto minmax(0,1fr); }
  .pe-studio-left { border-right:none; border-bottom:1px solid var(--line,rgba(255,255,255,.08)); max-height:38vh; }
}
.pe-studio-left { border-right:1px solid var(--line,rgba(255,255,255,.08)); padding:16px; overflow:auto; }
.pe-studio-right { display:flex; flex-direction:column; min-height:0; min-width:0; }
.pe-studio-head { display:flex; align-items:center; gap:10px; padding:16px 18px;
  border-bottom:1px solid var(--line,rgba(255,255,255,.08)); }
.pe-studio-head h2 { margin:0; font-size:17px; font-weight:800; }
.pe-studio-head .pe-msub2 { font-size:12px; color:var(--muted,#98a2b3); }
.pe-studio-body { padding:16px 18px; overflow:auto; flex:1; }

.pe-vtabs { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:14px; }
.pe-vtab { display:inline-flex; align-items:center; height:28px; padding:0 11px; border-radius:8px;
  font-size:12px; font-weight:700; white-space:nowrap;
  border:1px solid var(--pe-line); background:rgba(255,255,255,.03); color:var(--muted,#98a2b3); }
.pe-vtab:not(:disabled):hover { background:var(--pe-surface-hi); color:var(--ink,#e7ebf0); }
.pe-vtab.on { background:var(--accent-weak,rgba(59,130,246,.16)); color:var(--pe-accent-2);
  border-color:var(--accent-line,rgba(59,130,246,.4)); }
.pe-vtab.on:hover { background:rgba(59,130,246,.24); }

.pe-gallery { display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:12px; }
.pe-tex { border:1px solid var(--line,rgba(255,255,255,.09)); border-radius:11px; overflow:hidden;
  background:rgba(0,0,0,.2); display:flex; flex-direction:column; min-width:0;
  transition:border-color var(--pe-t), box-shadow var(--pe-t); }
.pe-tex:hover { border-color:var(--accent-line,rgba(59,130,246,.35)); box-shadow:0 10px 26px -18px #000; }
.pe-tex .pe-teximg { aspect-ratio:1;
  background:repeating-conic-gradient(#1b1f27 0% 25%, #141821 0% 50%) 50% / 20px 20px;
  display:grid; place-items:center; }
.pe-tex .pe-teximg img { width:100%; height:100%; object-fit:contain; }
.pe-tex .pe-texmeta { padding:8px 10px; font-size:11px; color:var(--muted,#98a2b3); }
.pe-tex .pe-texmeta b { color:var(--ink,#e7ebf0); display:block; word-break:break-all;
  font-size:11.5px; margin-bottom:2px; }

/* Texture actions: Upload + Photopea side by side, Save on its own row under
   them. A 2-column grid instead of wrapping flex, so the two top buttons are
   always exactly equal and the third always spans — no ragged middle state. */
.pe-texbtns { display:grid; grid-template-columns:1fr 1fr; gap:5px; padding:0 8px 8px;
  margin-top:auto; }
.pe-texbtns .pe-texchg.dl { grid-column:1 / -1; }
.pe-texchg { width:100%; padding:7px 6px; border-radius:7px; font-size:11px; font-weight:700;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  border:1px solid var(--pe-line); background:var(--pe-surface); color:var(--pe-accent-2); }
.pe-texchg:not(:disabled):hover { background:rgba(59,130,246,.16);
  border-color:var(--accent-line,rgba(59,130,246,.45)); }
.pe-texchg.alt { color:var(--pe-accent-2); border-color:var(--accent-line,rgba(59,130,246,.4)); }
.pe-texchg.dl { color:var(--muted,#98a2b3); }
.pe-texchg.dl:not(:disabled):hover { color:var(--ink,#e7ebf0); background:var(--pe-surface-hi);
  border-color:var(--line-3,rgba(255,255,255,.2)); }

/* ---- toast ------------------------------------------------------------- */
.pe-toast { position:fixed; bottom:24px; left:50%; transform:translateX(-50%); z-index:1200;
  padding:10px 18px; border-radius:10px; background:#1b2130;
  border:1px solid var(--line,rgba(255,255,255,.12)); font-size:13px;
  box-shadow:0 20px 50px -20px #000; animation:pe-toast-in .2s var(--pe-ease); }
@keyframes pe-toast-in { from { opacity:0; transform:translate(-50%, 10px) } to { opacity:1; transform:translate(-50%, 0) } }

/* The pack loading window now lives in the shared LoadingGate component. */

/* ---- "reopen your last pack" offer on the upload screen ----------------
   A reload should not silently drag you back into the previous ped. */
.pe-resume { display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-top:14px;
  padding:12px 14px; border-radius:12px; background:rgba(59,130,246,.08);
  border:1px solid var(--accent-line, rgba(59,130,246,.3)); }
.pe-resume > div:first-child { display:flex; flex-direction:column; gap:2px; min-width:0; flex:1; }
.pe-resume b { font-size:13px; }
.pe-resume span { font-size:12px; color:var(--muted,#98a2b3); }
.pe-resume-act { display:flex; gap:8px; flex:0 0 auto; }

/* ---- live debug feed under the preview -------------------------------- */
.pe-dbg { margin-top:10px; border:1px solid var(--pe-line,rgba(255,255,255,.1)); border-radius:10px;
  background:rgba(0,0,0,.28); overflow:hidden; }
.pe-dbg-h { width:100%; display:flex; align-items:center; gap:8px; padding:8px 10px; cursor:pointer;
  background:none; border:none; color:var(--ink,#e7ebf0); font:inherit; text-align:left; }
.pe-dbg-h b { font-size:11px; letter-spacing:.08em; text-transform:uppercase; color:var(--muted,#98a2b3); }
.pe-dbg-h span { flex:1; min-width:0; font-size:11.5px; color:var(--faint,#6b7280);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pe-dbg-h i { font-style:normal; color:var(--faint,#6b7280); }
.pe-dbg-b { max-height:210px; overflow:auto; border-top:1px solid var(--pe-line,rgba(255,255,255,.08)); }
.pe-dbg-e { display:flex; gap:8px; padding:5px 10px; font-size:11px; line-height:1.45;
  font-family:ui-monospace,Consolas,monospace; border-bottom:1px solid rgba(255,255,255,.04); }
.pe-dbg-t { color:var(--faint,#6b7280); flex:0 0 auto; }
.pe-dbg-e b { flex:0 0 auto; color:#7FA9F5; font-weight:600; }
.pe-dbg-e b.bad { color:#F0928A; }
.pe-dbg-d { color:var(--muted,#98a2b3); word-break:break-all; }
.pe-dbg-copy { margin:8px 10px; padding:5px 10px; font-size:11px; cursor:pointer;
  background:rgba(255,255,255,.05); border:1px solid var(--pe-line,rgba(255,255,255,.12));
  border-radius:7px; color:var(--ink,#e7ebf0); }

/* ---- category listbox (replaces a native <select>) --------------------- */
.pe-sel { position:relative; }
.pe-sel-btn { width:100%; display:flex; align-items:center; gap:8px; padding:9px 12px;
  border-radius:10px; border:1px solid var(--pe-line); background:rgba(0,0,0,.28);
  color:var(--ink,#e7ebf0); font:inherit; font-size:13px; text-align:left; }
.pe-sel-btn:hover { border-color:var(--accent-line,rgba(59,130,246,.4)); }
.pe-sel-btn > span { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pe-sel-btn i { font-style:normal; color:var(--faint,#6b7280); }
/* (the "new slot" badge is gone — the category list is a flat list of names) */
.pe-sel-scrim { position:fixed; inset:0; z-index:40; }
.pe-sel-list { position:absolute; z-index:41; top:calc(100% + 6px); left:0; right:0;
  max-height:280px; overflow:auto; padding:5px; border-radius:12px;
  border:1px solid var(--pe-line); background:#141822;
  box-shadow:0 18px 44px rgba(0,0,0,.6); }
.pe-sel-o { width:100%; display:flex; align-items:center; gap:8px; padding:8px 10px;
  border-radius:8px; border:none; background:none; color:var(--muted,#98a2b3);
  font:inherit; font-size:13px; text-align:left; }
.pe-sel-o > span { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pe-sel-o:hover { background:var(--pe-surface-hi); color:var(--ink,#e7ebf0); }
.pe-sel-o.on { background:var(--accent-weak,rgba(59,130,246,.16)); color:var(--pe-accent-2); }

/* ---- in-page load panel (replaces the full-screen gate) ---------------- */
.pe-loading { padding:18px 20px; margin-bottom:16px; }
.pe-loading-h { display:flex; align-items:center; gap:12px; margin-bottom:14px; }
.pe-loading-h > div { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.pe-loading-h b { font-size:15px; font-weight:700; }
.pe-loading-h span { font-size:12.5px; color:var(--muted,#98a2b3); }
.pe-loading-spin { width:20px; height:20px; flex:0 0 auto; border-radius:50%;
  border:2px solid var(--pe-line); border-top-color:var(--pe-accent-2); animation:pe-ldsp .7s linear infinite; }
@keyframes pe-ldsp { to { transform:rotate(360deg); } }
.pe-loading-bar { height:7px; border-radius:4px; background:rgba(255,255,255,.07); overflow:hidden; }
.pe-loading-bar > i { display:block; height:100%; border-radius:4px;
  background:linear-gradient(90deg,var(--pe-accent-2),var(--pe-accent)); transition:width .35s var(--pe-ease); }
.pe-loading-f { display:flex; align-items:center; gap:12px; margin-top:9px; font-size:12px; }
.pe-loading-f span { flex:1; min-width:0; color:var(--muted,#98a2b3);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pe-loading-f b { flex:0 0 auto; font-variant-numeric:tabular-nums; color:var(--ink,#e7ebf0); }
.pe-loading-err { margin-top:10px; padding:9px 11px; border-radius:9px; font-size:12.5px;
  color:#F0928A; background:rgba(197,69,59,.12); border:1px solid rgba(197,69,59,.3); }

/* spinner inside a button that is doing work */
.pe-btn-spin { width:13px; height:13px; flex:0 0 auto; border-radius:50%;
  border:2px solid rgba(255,255,255,.35); border-top-color:#fff;
  animation:pe-btnsp .7s linear infinite; }
@keyframes pe-btnsp { to { transform:rotate(360deg); } }

/* The piece being edited, beside its textures. Same well as .pe-view, but it
   holds a picture rather than a canvas — the card already rendered off this
   model, so the panel shows the thing you are painting instead of a caption in
   an empty box. */
.pe-studio-shot { position:relative; border-radius:12px; overflow:hidden;
  border:1px solid var(--line,rgba(255,255,255,.09));
  background:radial-gradient(70% 70% at 50% 30%, #171a22, #0a0c11 85%); }
.pe-studio-shot img { width:100%; height:100%; object-fit:contain; display:block; }
.pe-studio-shot .pe-ph { position:absolute; inset:0; display:grid; place-items:center; }
/* The caption drops to the foot so it never sits across the model. */
.pe-studio-shot .pe-over { inset:auto 0 0 0; padding:10px 14px 12px; font-size:12px;
  background:linear-gradient(to top, rgba(8,10,14,.92), rgba(8,10,14,0)); }
/* ============================================================================
   SmartObjector — public site. Built from scratch.
   ----------------------------------------------------------------------------
   Everything is namespaced `.pub` / `pub-*`, so nothing here can reach the
   signed-in app's stylesheets and nothing there can reach this.

   The brief: rounded, soft, clean, animated, and correct on a phone first.
   Nothing on this site has a square corner. Depth comes from soft shadow and
   a light rim rather than hard 1px boxes, and every interactive thing moves.

   Type: Sora for display, Plus Jakarta Sans for prose, IBM Plex Mono for data.
   All three are already self-hosted by the app — no external font request.
   ============================================================================ */

.pub {
  /* ── ground ─────────────────────────────────────────────────────────────── */
  --bg:     #000000;
  --bg-2:   #0A0A0B;
  --s1:     #131315;
  --s2:     #1B1B1E;
  --s3:     #26262A;

  /* Borders are white at low alpha rather than a fixed grey, so they stay
     correct on top of any surface in the ladder. */
  --line:   rgba(255, 255, 255, .07);
  --line-2: rgba(255, 255, 255, .13);

  --text:   #FFFFFF;
  --text-2: #A9A9AF;
  /* --text-3 carries the smallest labels on the page (mono captions, hints,
     footer meta). At #6D7889 on #08090D it measured about 3.9:1 — under the
     4.5:1 AA floor for normal text, and these are BELOW normal size. Lifted
     to clear it with room to spare rather than sit on the line. */
  --text-3: #8B8B92;

  /* ── accent: blue, and only blue ─────────────────────────────────────────
     The gradient runs deep blue to light blue rather than blue to violet —
     it reads as one colour with depth instead of two colours competing, and
     it matches the brand mark, which is blue on navy with no second hue. */
  --a1:     #0A84FF;
  --a2:     #4DA3FF;
  --a-deep: #0060DF;
  /* flat, not a gradient — kept as a token so every `background: var(--grad)`
     on the page flattens to the one accent without touching those rules */
  --grad:   #0060DF;
  --a-soft: rgba(10, 132, 255, .12);
  --a-line: rgba(10, 132, 255, .34);

  /* ── Object Forge ──────────────────────────────────────────────────────────
     The page had one blue doing every job at once, which is what made it read
     as a generic dark SaaS template. Three colours with three jobs instead:

       blueprint  structure, axes, measurements, anything technical
       forge      the brand moment — the CTA, and nothing else
       ready      a state that is genuinely finished ("ready to ensure")

     Blue stays primary because the brand mark is blue on navy. Forge orange is
     rationed to one element per screen; lime never decorates, it only reports
     a real state. */
  --forge:      #0A84FF;
  --forge-deep: #0060DF;
  --forge-soft: rgba(10, 132, 255, .12);
  --forge-line: rgba(10, 132, 255, .34);
  --blueprint:  #0A84FF;
  --ready:      #4DA3FF;
  --ready-soft: rgba(10, 132, 255, .11);
  --ready-line: rgba(10, 132, 255, .34);
  --bone:       #F5F5F7;

  --ok:     #34D399;
  --ok-soft: rgba(52, 211, 153, .12);
  --ok-line: rgba(52, 211, 153, .30);
  --bad:    #FB7185;
  --bad-soft: rgba(251, 113, 133, .11);
  --bad-line: rgba(251, 113, 133, .30);

  /* ── generous radii: nothing here is square ─────────────────────────────── */
  --r-xs:  12px;
  --r-sm:  18px;
  --r:     24px;
  --r-lg:  30px;
  --r-xl:  38px;
  --pill:  999px;

  /* ── soft elevation ─────────────────────────────────────────────────────── */
  --sh-1: 0 1px 3px rgba(0, 0, 0, .55);
  --sh-2: 0 10px 30px -16px rgba(0, 0, 0, .85);
  --sh-3: 0 20px 48px -20px rgba(0, 0, 0, .92);
  /* kept only so existing `box-shadow: var(--glow)` rules stay valid — it is
     now an ordinary neutral shadow, not a coloured halo */
  --glow: 0 8px 22px -12px rgba(0, 0, 0, .8);
  --rim:  inset 0 1px 0 rgba(255, 255, 255, .04);

  --display: 'Sora', 'Plus Jakarta Sans', system-ui, sans-serif;
  --body: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
  --ease: cubic-bezier(.22, .61, .36, 1);
  --spring: cubic-bezier(.34, 1.42, .64, 1);

  background: var(--bg);
  /* The app-wide shell paints #08090D from index.css. This site is true black,
     so the wrapper must cover the full viewport or that lighter ground shows
     through on short pages and on overscroll. Scoped here rather than changing
     the shared token, which the signed-in app also uses. */
  min-height: 100dvh;
  /* Column layout so the footer sits at the bottom of a short page instead of
     floating mid-screen. This used to come from a stale .pub rule in app.css,
     which is exactly the kind of accident that made the header a flex row. */
  display: flex; flex-direction: column;
  color: var(--text-2);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  overflow-x: clip;
  padding-bottom: env(safe-area-inset-bottom);
}

.pub *, .pub *::before, .pub *::after { box-sizing: border-box; }
.pub p, .pub h1, .pub h2, .pub h3, .pub li { overflow-wrap: break-word; }
.pub ::selection { background: var(--a1); color: #fff; }
.pub :where(a, button, input, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--a2); outline-offset: 3px; border-radius: var(--r-xs);
}

/* first stop in the tab order; off-canvas until it takes focus */
.pub-skip {
  position: absolute; left: 12px; top: -100px; z-index: 200;
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 18px;
  border-radius: var(--pill); background: var(--a1); color: #fff;
  font-size: 14px; font-weight: 600; text-decoration: none;
  transition: top .16s var(--ease);
}
.pub-skip:focus { top: 12px; }

/* ── layout ───────────────────────────────────────────────────────────────── */
.pub-wrap { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 20px; }
/* the mark is the real logo file, already circular with its own dark disc */
.pub-mark { display: block; flex: 0 0 auto; border-radius: 50%; }
/* Phone spacing is tighter: at 72/96px, section padding alone accounted for
   roughly 1,500px of the scroll. The desktop values are restored at 900px. */
.pub-sec { padding: 52px 0; }
.pub-sec-lg { padding: 60px 0; }
/* the two strips that sit directly under the hero and belong to it */
.pub-sec-tight { padding: 28px 0; }

/* ── type ─────────────────────────────────────────────────────────────────── */
.pub h1, .pub h2, .pub h3 { margin: 0; color: var(--text); font-family: var(--display); }
.pub h1 {
  font-size: clamp(34px, 6.4vw, 62px); font-weight: 700; line-height: 1.08;
  letter-spacing: -.03em; text-wrap: balance;
}
.pub h2 {
  font-size: clamp(27px, 4.4vw, 40px); font-weight: 700; line-height: 1.16;
  letter-spacing: -.025em; text-wrap: balance;
}
.pub h3 { font-size: 18px; font-weight: 600; letter-spacing: -.015em; line-height: 1.4; }
.pub p { margin: 0; }

.pub-lede { font-size: 17px; line-height: 1.7; color: var(--text-2); max-width: 58ch; }
.pub-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  /* Solid, not gradient-clipped. Gradient text was one of the tells that made
     this read as a generic template, and it never survives a copy-paste or a
     forced-colours mode intact. */
  color: var(--blueprint);
}
.pub-head { display: flex; flex-direction: column; gap: 14px; margin-bottom: 40px; max-width: 620px; }
.pub-head-mid { margin-inline: auto; text-align: center; align-items: center; }
.pub code {
  font-family: var(--mono); font-size: .86em; padding: 3px 8px; border-radius: var(--r-xs);
  background: var(--s2); border: 1px solid var(--line); color: var(--text);
}
/* was gradient-filled text; a single solid accent reads cleaner and keeps the
   blue rationed to things you can act on */
.pub-grad { color: var(--a2); }

/* ── buttons: pills, with a shine that sweeps on hover ────────────────────── */
.pub-btn {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 52px; padding: 0 26px; border-radius: var(--pill);
  white-space: nowrap;
  border: 1px solid transparent; font-family: var(--body); font-size: 15px;
  font-weight: 600; letter-spacing: -.01em; text-decoration: none; cursor: pointer;
  transition: transform .14s var(--ease), box-shadow .14s var(--ease),
              background .14s var(--ease), border-color .14s var(--ease);
}
/* the sweeping highlight was the most "template" thing on the page; a premium
   dark UI changes surface on hover, it does not shine */
.pub-btn-primary { background: var(--a-deep); color: #fff; box-shadow: var(--sh-1); }
.pub-btn-primary:hover { background: #0A6FE8; box-shadow: var(--sh-2); }
/* The one forge-orange element on the page. Flat, not gradient: the gradient
   buttons were a large part of why the page read as a template. */
/* the single primary action on the page — the one place the accent is filled */
.pub-btn-forge {
  background: var(--a-deep); color: #fff;
  box-shadow: var(--sh-1);
}
.pub-btn-forge:hover {
  background: #0A6FE8; color: #fff;
  box-shadow: var(--sh-2);
}
.pub-btn-ghost {
  background: var(--s2); color: var(--text); border-color: var(--line-2);
  box-shadow: var(--rim);
}
.pub-btn-ghost:hover { background: var(--s3); transform: translateY(-1px); }
.pub-btn-block { width: 100%; }
.pub-btn:active { transform: translateY(0) scale(.99); transition-duration: .08s; }
.pub-btn:disabled { opacity: .5; pointer-events: none; }
.pub-btn-sm { min-height: 42px; padding: 0 18px; font-size: 14px; }

/* Discord's own brand blurple — the one button on the page allowed to break
   from the accent palette, since it has to read as "Discord" at a glance. */
.pub-btn-discord {
  min-height: 44px; font-size: 14px;
  background: #4E5BE8; color: #fff; border-color: rgba(148, 155, 255, .4);
}
.pub-btn-discord:hover { background: #5865F2; }

.pub-divider {
  display: flex; align-items: center; gap: 12px;
  color: var(--text-3); font-size: 12px; margin: 22px 0;
}
.pub-divider::before, .pub-divider::after { content: ""; flex: 1; height: 1px; background: var(--line-2); }

.pub-link { color: var(--a2); font-weight: 600; text-decoration: none; }
.pub-link:hover { text-decoration: underline; }
/* a link that stands alone as a call to action needs a real tap target —
   inline it measured 21px tall, half the 44px minimum */
.pub-link-lg {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
  padding: 0 4px;
}
.pub-linkish {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  color: var(--a2); font-weight: 600;
}
.pub-linkish:disabled { opacity: .5; cursor: not-allowed; }

/* ── surfaces ─────────────────────────────────────────────────────────────── */
.pub-card {
  border-radius: var(--r-lg); background: var(--s1); border: 1px solid var(--line);
  box-shadow: var(--rim), var(--sh-1); padding: 26px;
  transition: transform .24s var(--ease), border-color .24s var(--ease),
              box-shadow .24s var(--ease), background .24s var(--ease);
}
.pub-card:hover {
  transform: translateY(-4px); background: var(--s2);
  border-color: var(--line-2); box-shadow: var(--rim), var(--sh-2);
}
.pub-ico {
  width: 46px; height: 46px; border-radius: var(--r-sm); display: grid; place-items: center;
  background: var(--a-soft); border: 1px solid var(--a-line); color: var(--a2);
  flex: 0 0 auto; transition: transform .3s var(--spring), background .24s var(--ease);
}
.pub-card:hover .pub-ico { transform: scale(1.08) rotate(-4deg); }
.pub-chip {
  display: inline-flex; align-items: center; gap: 9px; padding: 8px 16px;
  border-radius: var(--pill); background: rgba(22, 26, 35, .72);
  border: 1px solid var(--line-2); backdrop-filter: blur(10px);
  font-size: 13.5px; color: var(--text-2); box-shadow: var(--rim);
}
.pub-chip i {
  width: 7px; height: 7px; border-radius: 50%; background: var(--a2);
  box-shadow: 0 0 0 4px rgba(96, 165, 250, .18);
  animation: pub-pulse 2.4s var(--ease) infinite;
}
@keyframes pub-pulse {
  0%, 100% { box-shadow: 0 0 0 4px rgba(96, 165, 250, .18); }
  50%      { box-shadow: 0 0 0 8px rgba(96, 165, 250, .04); }
}
.pub-tag {
  display: inline-block; font-family: var(--mono); font-size: 11px;
  letter-spacing: .06em; padding: 5px 12px; border-radius: var(--pill);
  color: var(--text-3); background: var(--s2); border: 1px solid var(--line);
}
/* "Free to run" was the one green pill left; the palette is black, grey and
   one blue. Error/success notes on the auth pages keep red and green, where
   the colour carries meaning rather than decoration. */
.pub-tag.is-free { color: var(--a2); background: var(--a-soft); border-color: var(--a-line); }

/* ── ambient light ────────────────────────────────────────────────────────────
   Soft drifting colour behind the hero. Written as a background gradient that
   reaches full transparency on its own — an absolutely-positioned blurred blob
   inside an overflow-hidden box still carries opacity where the box ends, and
   the box edge then shows up as a hard line across the page. */
.pub-glow { position: relative; }
.pub-glow::before {
  /* The drifting blue blobs are gone. The brief is a clean, high-end dark UI:
     the ground is flat black and hierarchy comes from surface, spacing and
     rounding — not from a lit backdrop. Kept as an empty rule so the z-index
     contract below (and .pub-glow > *) stays intact. */
  content: none;
}
.pub-glow > * { position: relative; z-index: 1; }
@keyframes pub-drift {
  from { transform: translate3d(0, 0, 0) scale(1); opacity: .9; }
  to   { transform: translate3d(-2%, 2%, 0) scale(1.06); opacity: 1; }
}

/* ── entrance + scroll reveal ─────────────────────────────────────────────────
   CONTENT IS VISIBLE BY DEFAULT. The reveal only hides an element once script
   has confirmed it can show it again: `.pub-js` is set on the root by the
   Reveal component itself, so if the bundle fails, IntersectionObserver is
   missing, or JS is off entirely, every section renders at full opacity
   instead of leaving the pricing and proof invisible on a blank page.

   The hidden state is also gated on `prefers-reduced-motion: no-preference`,
   so a reduced-motion visitor never has content animated in at all. */
.pub-rv { opacity: 1; transform: none; }

@media (prefers-reduced-motion: no-preference) {
  .pub-js .pub-rv {
    opacity: 0; transform: translateY(16px);
    transition: opacity .38s var(--ease), transform .38s var(--ease);
  }
  .pub-js .pub-rv.is-in { opacity: 1; transform: none; }
}

@keyframes pub-in {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}
/* Same rule as the scroll reveal: the hero's headline and CTA start VISIBLE,
   and only animate when script and the motion preference both allow it. The
   whole entrance lands in ~440ms with a 45ms stagger. */
@media (prefers-reduced-motion: no-preference) {
  .pub-js .pub-enter > * { opacity: 0; animation: pub-in .44s var(--ease) forwards; }
  .pub-js .pub-enter > *:nth-child(1) { animation-delay: .04s; }
  .pub-js .pub-enter > *:nth-child(2) { animation-delay: .085s; }
  .pub-js .pub-enter > *:nth-child(3) { animation-delay: .13s; }
  .pub-js .pub-enter > *:nth-child(4) { animation-delay: .175s; }
  .pub-js .pub-enter > *:nth-child(5) { animation-delay: .22s; }
}

/* ============================================================== header ===== */
/* With .pub as a column, the main region takes the slack so the footer is
   pushed to the bottom of a short page rather than sitting under the fold. */
.pub > main { flex: 1 0 auto; }

/* The header stacks its bar and its mobile sheet. Stated explicitly: a stray
   `display:flex` from another stylesheet turned this into a row, which pushed
   the sheet to width:0 and squeezed the bar to 291px on a 390px phone. */
.pub-nav {
  display: block;
  position: sticky; top: 0; z-index: 60; padding-top: env(safe-area-inset-top);
  background: transparent; backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent; transition: border-color .3s var(--ease), background .3s var(--ease);
}
.pub-nav.is-stuck { border-bottom-color: var(--line); background: rgba(0, 0, 0, .82); }
/* The bar spans the whole window: brand hard left, actions hard right. It is
   the one element on the page that is deliberately NOT held to the content
   measure — a header boxed into 1200px on a 1900px screen leaves the logo
   floating in the middle of nowhere with dead space either side of it. */
.pub-nav-in {
  height: 68px; display: flex; align-items: center; gap: 14px;
  width: 100%; max-width: none; margin: 0; padding: 0 20px;
}
.pub-brand {
  display: inline-flex; align-items: center; gap: 11px; text-decoration: none;
  color: var(--text); font-family: var(--display); font-size: 17px; font-weight: 700;
  letter-spacing: -.02em;
}
.pub-brand svg { flex: 0 0 auto; transition: transform .4s var(--spring); }
.pub-brand:hover svg { transform: rotate(-12deg) scale(1.06); }
.pub-nav-links { display: none; }
.pub-nav-right { margin-left: auto; display: flex; align-items: center; gap: 9px; flex: 0 0 auto; }
.pub-brand { min-width: 0; flex: 0 1 auto; }
.pub-brand-word { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pub-burger {
  display: inline-grid; place-items: center; width: 44px; height: 44px; flex: 0 0 auto;
  border-radius: var(--pill); background: var(--s2); border: 1px solid var(--line);
  color: var(--text); cursor: pointer; transition: background .18s var(--ease);
}
.pub-burger:hover { background: var(--s3); }
.pub-sheet {
  overflow: hidden; max-height: 0; border-bottom: 1px solid transparent;
  background: var(--bg-2); transition: max-height .34s var(--ease), border-color .34s var(--ease);
}
.pub-sheet.is-open { max-height: 420px; border-bottom-color: var(--line); }
.pub-sheet-in { padding: 8px 20px 22px; display: flex; flex-direction: column; }
.pub-sheet a {
  display: flex; align-items: center; min-height: 52px; font-size: 16px; font-weight: 500;
  color: var(--text-2); text-decoration: none; border-bottom: 1px solid var(--line);
}
.pub-sheet a:last-of-type { border-bottom: 0; }
.pub-sheet .pub-btn { margin-top: 14px; }
.pub-avatar {
  width: 24px; height: 24px; flex: none; display: inline-flex; align-items: center;
  justify-content: center; font-size: 11px; font-weight: 700; line-height: 1; color: #fff;
  background: rgba(255, 255, 255, .22); border-radius: 50%; overflow: hidden;
}
.pub-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pub-nav-hold { display: inline-block; width: 92px; height: 36px; }
/* Below the desktop breakpoint the burger is present, and a signed-in
   username alongside it pushed the whole right-hand group past the edge of a
   375px screen — the burger ended up 26px off-canvas and unreachable. The
   avatar alone identifies the session at that width. */
.pub-nav-name { display: none; }
.pub-nav-right .pub-btn-sm { padding: 0 12px; }

/* ── narrow phones ────────────────────────────────────────────────────────────
   At 320px the header carried a wordmark, TWO buttons and the menu button, and
   the menu button ended up 32px past the right edge — present in the DOM,
   impossible to press. The header keeps a compact logo, ONE call to action and
   the menu, which is all it needs; "Sign in" is still in the menu itself. */
@media (max-width: 479px) {
  .pub-nav-2nd { display: none; }
  .pub-nav-in { gap: 8px; padding: 0 14px; }
  .pub-nav-right { gap: 6px; }
  .pub-nav-right .pub-btn-sm { padding: 0 13px; font-size: 13.5px; }
  .pub-brand { font-size: 15px; gap: 8px; }
  /* the text is the first thing to go — the mark alone still identifies us */
  .pub-brand-word { max-width: 42vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}
@media (max-width: 359px) {
  .pub-brand-word { display: none; }
}

/* ============================================================== hero ======= */
/* One centred column of copy, then the transformation across the full width.
   The old hero put a 62px headline in a narrow left column beside dead space,
   which pushed the only meaningful visual below the fold. Copy is centred and
   capped so the headline lands in two lines on a laptop and the strip starts
   inside the first screen. */
.pub-hero { padding: 30px 0 8px; }
.pub-hero-lead { max-width: 940px; margin-inline: auto; text-align: center; }
.pub-hero-lead > * { margin-inline: auto; }
.pub-hero h1 {
  margin-top: 16px;
  font-size: clamp(31px, 4.6vw, 53px);
  line-height: 1.06; letter-spacing: -.015em;
  text-wrap: balance;                 /* keeps the last line from orphaning */
}
/* "FiveM-ready" is one idea; balanced wrapping was splitting it at the hyphen */
.pub-nb { white-space: nowrap; }
.pub-hero .pub-lede { margin-top: 16px; max-width: 60ch; }
.pub-hero-cta {
  display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px;
  justify-content: center;
}
/* ── the conversion strip: source → preview → in game ────────────────────────
   The hero's job is to show the transformation, not describe it. Three real
   stages of one real job (pony_cartoon.glb), using the customer's own
   screenshots. Every figure shown — GLB, 3.8 MB, 2.89 × 1.34 × 3.43 m — is
   read off those screenshots, so nothing here is a claim we cannot back.

   No processing time is shown anywhere: we have not measured one. */
.pub-hero-pipe { margin-top: 40px; }
.pub-pipe { display: grid; gap: 14px; }

.pub-stage {
  position: relative; display: flex; flex-direction: column; min-width: 0;
  border-radius: var(--r); overflow: hidden;
  background: var(--s1); border: 1px solid var(--line-2);
  box-shadow: var(--rim), var(--sh-2);
}
/* stage 2 is the product itself, so it carries a little more weight */
.pub-stage.is-lead { border-color: var(--a-line); box-shadow: var(--rim), var(--sh-3); }

/* the workbench cue: a ruled header strip carrying the step and its label */
.pub-stage-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 13px; border-bottom: 1px solid var(--line);
  background: var(--bg-2);
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--text-3);
}
.pub-stage-n { color: var(--blueprint); font-weight: 600; }
.pub-stage-label { color: var(--text-2); }
.pub-stage-bar b {
  margin-left: auto; font-weight: 500; color: var(--text-3);
  letter-spacing: .06em; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

/* Every stage frames to the same 16:10 window so the three read as one strip.
   The in-game capture is 465px wide, so the strip is capped near that width —
   scaled past it, it visibly softens. */
.pub-stage-body { position: relative; background: var(--bg-2); aspect-ratio: 16 / 10; }
.pub-stage img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}

/* stage 1 has no screenshot — it is the file itself, drawn as the app draws it */
.pub-file {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  flex-direction: column; text-align: center; gap: 11px;
  padding: 18px 14px;
}
.pub-file-ic {
  width: 44px; height: 44px; display: grid; place-items: center;
  border-radius: var(--r-xs);
  background: var(--a-soft); border: 1px solid var(--a-line); color: var(--a2);
}
.pub-file-name {
  font-family: var(--mono); font-size: 13.5px; color: var(--text);
  overflow-wrap: anywhere; line-height: 1.4; max-width: 100%;
}
.pub-file-meta {
  font-family: var(--mono); font-size: 11px; color: var(--text-3);
  display: flex; flex-wrap: wrap; gap: 4px 8px; justify-content: center;
}
.pub-file-meta span {
  padding: 2px 7px; border-radius: 999px;
  border: 1px solid var(--line-2); background: var(--bg-2);
}

/* the readout under each stage — mono, because it is data */
.pub-stage-foot {
  padding: 11px 13px; border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 11px; line-height: 1.55; color: var(--text-3);
  flex: 1 0 auto;
}
.pub-stage-foot code { font-size: 10.5px; }
.pub-stage-foot .is-ready { color: var(--ready); }

/* Between stages. A caret pointing down while stacked, along the row once the
   strip goes horizontal. Hidden from assistive tech: the numbered steps
   already carry the order. */
.pub-pipe-arrow {
  display: grid; place-items: center; color: var(--blueprint);
  min-height: 26px;
}
.pub-pipe-arrow svg { width: 22px; height: 22px; transform: rotate(90deg); }

@media (min-width: 920px) {
  .pub-pipe {
    /* the preview is the product, so it gets the extra pixels */
    grid-template-columns: 1fr auto 1.3fr auto 1fr;
    align-items: stretch; gap: 0;
    max-width: 1180px; margin-inline: auto;
  }
  .pub-pipe-arrow { min-height: 0; padding: 0 14px; }
  .pub-pipe-arrow svg { transform: none; }
  /* the lead column is wider, so a shared 16:10 would make it taller than its
     neighbours and the row would read ragged — fix the band height instead */
  .pub-stage-body { aspect-ratio: auto; height: clamp(168px, 17.5vw, 226px); }
}

/* ── marquee of formats ───────────────────────────────────────────────────── */
.pub-marquee {
  display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.pub-marquee::-webkit-scrollbar { display: none; }
.pub-marquee span {
  flex: 0 0 auto; font-family: var(--mono); font-size: 13px; color: var(--text-2);
  padding: 9px 16px; border-radius: var(--pill);
  background: var(--s1); border: 1px solid var(--line);
  transition: transform .22s var(--spring), border-color .22s var(--ease), color .22s var(--ease);
}
.pub-marquee span:hover { transform: translateY(-3px); border-color: var(--a-line); color: var(--a2); }

/* ── stats ────────────────────────────────────────────────────────────────── */
.pub-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.pub-stat {
  border-radius: var(--r); background: var(--s1); border: 1px solid var(--line);
  box-shadow: var(--rim); padding: 22px;
  transition: transform .24s var(--ease), border-color .24s var(--ease);
}
.pub-stat:hover { transform: translateY(-3px); border-color: var(--a-line); }
.pub-stat b {
  display: block; font-family: var(--display); font-size: 30px; font-weight: 700;
  letter-spacing: -.03em; line-height: 1; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.pub-stat span {
  display: block; margin-top: 8px; font-family: var(--mono); font-size: 11px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--text-3);
}

/* ── steps ────────────────────────────────────────────────────────────────── */
.pub-steps { display: grid; gap: 16px; }
/* On a phone these are rows — icon or number in a first column, copy in the
   second. Stacked as tall cards, the three-up grids (steps, support) alone
   pushed the page past 9,700px, which is twelve screenfuls of scrolling on a
   812px phone. As rows they read the same and cost about half the height. */
.pub-step, .pub-feature {
  position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: 16px; align-items: start;
}
.pub-step-n {
  display: inline-grid; place-items: center; width: 40px; height: 40px;
  border-radius: var(--pill); background: var(--grad); color: #fff;
  font-family: var(--mono); font-size: 14px; font-weight: 600;
  box-shadow: var(--glow); flex: 0 0 auto;
}
.pub-step p, .pub-feature p {
  margin-top: 8px; font-size: 15px; line-height: 1.65; color: var(--text-2);
}

/* From tablet up they go back to being proper cards, stacked vertically. */
@media (min-width: 560px) {
  .pub-step, .pub-feature { display: block; }
  .pub-step-n, .pub-feature .pub-ico { margin-bottom: 18px; }
}

/* ── before / after ───────────────────────────────────────────────────────── */
.pub-ba { display: grid; gap: 18px; }
.pub-ba-item { padding: 16px; }
.pub-ba-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
/* each shot is a button — the whole thumbnail is the tap target */
.pub-ba-shot {
  margin: 0; padding: 0; position: relative; display: block; width: 100%;
  border: 0; border-radius: var(--r); overflow: hidden; background: var(--bg-2);
  cursor: zoom-in; -webkit-tap-highlight-color: transparent;
}
/* `contain`, not `cover`: the pairs mix a wide tool screenshot with a portrait
   in-game shot, and cropping either to a common box hides the very thing the
   comparison exists to show. Letterboxing against the ground is the honest
   presentation here. */
.pub-ba-pair img {
  display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: contain;
  background: var(--bg); transition: transform .5s var(--ease);
}
.pub-ba-shot:hover img { transform: scale(1.03); }
.pub-ba-shot .pub-ba-tag { position: absolute; top: 10px; left: 10px; }
/* the magnifier only appears on hover — on touch the whole tile is tappable
   and a permanent badge would just cover the picture */
.pub-ba-zoom {
  position: absolute; right: 10px; bottom: 10px; width: 32px; height: 32px;
  display: grid; place-items: center; border-radius: var(--pill);
  background: rgba(0, 0, 0, .82); border: 1px solid var(--line-2); color: var(--text);
  backdrop-filter: blur(6px); opacity: 0; transform: scale(.85);
  transition: opacity .2s var(--ease), transform .24s var(--spring);
}
.pub-ba-shot:hover .pub-ba-zoom, .pub-ba-shot:focus-visible .pub-ba-zoom {
  opacity: 1; transform: scale(1);
}
.pub-ba-tag {
  display: inline-block; padding: 4px 11px; border-radius: var(--pill);
  font-family: var(--mono); font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  background: rgba(0, 0, 0, .80); border: 1px solid var(--line-2); color: var(--text-2);
  backdrop-filter: blur(6px);
}
.pub-ba-tag.is-after { background: var(--grad); border-color: transparent; color: #fff; }
.pub-ba-txt { padding: 18px 8px 6px; }
.pub-ba-txt h3 { margin: 12px 0 8px; }
.pub-ba-txt p { font-size: 14.5px; line-height: 1.65; color: var(--text-2); }

/* Two up from tablet. With four pairs that fills two clean rows — a third
   column would leave the last one stranded on a row of its own. */
@media (min-width: 900px) { .pub-ba { grid-template-columns: repeat(2, 1fr); } }

/* ── lightbox ─────────────────────────────────────────────────────────────── */
.pub-lb {
  position: fixed; inset: 0; z-index: 140; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 14px;
  padding: 16px calc(16px + env(safe-area-inset-right)) calc(16px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-left));
  background: rgba(4, 5, 8, .90); backdrop-filter: blur(8px);
  animation: pub-fade .18s var(--ease);
}
.pub-lb-fig {
  margin: 0; display: flex; flex-direction: column; align-items: center; gap: 12px;
  max-width: 100%; max-height: 100%; animation: pub-rise .26s var(--spring);
}
.pub-lb-fig img {
  display: block; max-width: 100%; max-height: calc(100vh - 130px);
  width: auto; height: auto; object-fit: contain;
  border-radius: var(--r); border: 1px solid var(--line-2); box-shadow: var(--sh-3);
  background: var(--bg);
}
.pub-lb-fig figcaption { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; justify-content: center; }
.pub-lb-cap { font-family: var(--mono); font-size: 12px; color: var(--text-2); }
.pub-lb-x {
  position: absolute; top: calc(14px + env(safe-area-inset-top)); right: 14px;
  width: 44px; height: 44px; border-radius: var(--pill); cursor: pointer;
  background: var(--s2); border: 1px solid var(--line-2); color: var(--text);
  display: grid; place-items: center;
  transition: background .18s var(--ease), transform .24s var(--spring);
}
.pub-lb-x:hover { background: var(--s3); transform: rotate(90deg); }

/* ── tools ────────────────────────────────────────────────────────────────── */
.pub-tabs {
  display: flex; gap: 9px; overflow-x: auto; padding-bottom: 6px; margin-bottom: 22px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.pub-tabs::-webkit-scrollbar { display: none; }
.pub-tab {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 9px; cursor: pointer;
  min-height: 46px; padding: 0 20px; border-radius: var(--pill);
  background: var(--s1); border: 1px solid var(--line); color: var(--text-2);
  font-family: var(--body); font-size: 14.5px; font-weight: 600; white-space: nowrap;
  transition: background .2s var(--ease), color .2s var(--ease),
              border-color .2s var(--ease), transform .2s var(--spring);
}
.pub-tab:hover { transform: translateY(-2px); color: var(--text); }
.pub-tab.is-on { background: var(--grad); border-color: transparent; color: #fff; box-shadow: var(--glow); }
.pub-tab b { font-family: var(--mono); font-size: 11px; font-weight: 500; opacity: .7; }

.pub-tools { display: grid; gap: 14px; }
.pub-tool { display: flex; align-items: flex-start; gap: 16px; }
.pub-tool-txt { min-width: 0; flex: 1; }
.pub-tool-txt b { display: block; font-family: var(--display); font-size: 16px; font-weight: 600; color: var(--text); }
.pub-tool-txt p { margin-top: 6px; font-size: 14px; line-height: 1.6; color: var(--text-2); }
.pub-tool-meta { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }

/* ── pricing ──────────────────────────────────────────────────────────────── */
.pub-plans { display: grid; gap: 18px; align-items: stretch; }
.pub-plan {
  position: relative; display: flex; flex-direction: column; padding: 30px 26px;
  border-radius: var(--r-xl); background: var(--s1); border: 1px solid var(--line);
  box-shadow: var(--rim), var(--sh-1);
  transition: transform .26s var(--ease), border-color .26s var(--ease), box-shadow .26s var(--ease);
}
.pub-plan:hover { transform: translateY(-5px); border-color: var(--line-2); box-shadow: var(--rim), var(--sh-2); }
/* the popular plan gets a gradient rim drawn with a mask, so the border itself
   carries the site's gradient without a wrapper element */
.pub-plan-best { background: var(--s2); border-color: transparent; box-shadow: var(--rim), var(--glow); }
.pub-plan-best::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px;
  background: var(--grad);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  pointer-events: none;
}
.pub-plan-top { display: flex; align-items: center; gap: 10px; }
.pub-plan-top b { font-family: var(--display); font-size: 17px; font-weight: 600; color: var(--text); }
.pub-badge {
  margin-left: auto; font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; padding: 6px 12px; border-radius: var(--pill);
  background: var(--grad); color: #fff;
}
.pub-price { display: flex; align-items: baseline; gap: 8px; margin: 18px 0 4px; }
.pub-price b {
  font-family: var(--display); font-size: 46px; font-weight: 700; line-height: 1;
  letter-spacing: -.04em; color: var(--text);
}
.pub-plan-best .pub-price b { background: var(--grad); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.pub-price span { font-size: 14px; color: var(--text-3); }
.pub-plan-meta { font-family: var(--mono); font-size: 12px; color: var(--text-2); }
.pub-plan > p { margin: 16px 0 22px; font-size: 14.5px; line-height: 1.65; color: var(--text-2); }
.pub-feats {
  list-style: none; margin: 24px 0 0; padding: 24px 0 0; border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 12px; flex: 1;
}
.pub-feats li { display: flex; gap: 11px; font-size: 14px; line-height: 1.55; color: var(--text-2); }
.pub-feats svg { color: var(--a2); flex: 0 0 auto; margin-top: 3px; }
/* "Visa · Bit · Crypto" on every plan — the question "can I even pay you?"
   answered on the card, not two clicks later inside the checkout modal. */
.pub-pays {
  display: flex; flex-wrap: wrap; gap: 7px; margin-top: 20px;
  padding-top: 18px; border-top: 1px solid var(--line);
}
.pub-pay-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 11px;
  border-radius: var(--pill); font-family: var(--mono); font-size: 11px;
  color: var(--text-2); background: var(--s2); border: 1px solid var(--line);
  transition: border-color .18s var(--ease), color .18s var(--ease);
}
.pub-plan:hover .pub-pay-chip { border-color: var(--line-2); color: var(--text); }
.pub-pay-chip svg { color: var(--a2); flex: 0 0 auto; }
.pub-plan-note {
  margin-top: 16px; font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-3);
}

/* ── faq ──────────────────────────────────────────────────────────────────── */
.pub-faq { display: grid; gap: 12px; align-items: start; }
.pub-faq details {
  border-radius: var(--r); background: var(--s1); border: 1px solid var(--line);
  box-shadow: var(--rim); overflow: hidden;
  transition: background .22s var(--ease), border-color .22s var(--ease);
}
.pub-faq details[open] { background: var(--s2); border-color: var(--line-2); }
.pub-faq summary {
  list-style: none; cursor: pointer; padding: 19px 22px; display: flex; align-items: center;
  gap: 14px; font-size: 15.5px; font-weight: 600; color: var(--text);
}
.pub-faq summary::-webkit-details-marker { display: none; }
.pub-faq summary::after {
  content: '+'; margin-left: auto; font-family: var(--mono); font-size: 20px; line-height: 1;
  color: var(--text-3); transition: transform .28s var(--spring), color .22s var(--ease);
}
.pub-faq details[open] summary::after { transform: rotate(135deg); color: var(--a2); }
/* a real height transition, not a snap */
.pub-faq-a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .3s var(--ease); }
.pub-faq details[open] .pub-faq-a { grid-template-rows: 1fr; }
.pub-faq-a > div { overflow: hidden; }
.pub-faq-a p { padding: 0 22px 22px; font-size: 14.5px; line-height: 1.75; color: var(--text-2); }

/* ── closing band ─────────────────────────────────────────────────────────── */
.pub-close {
  position: relative; overflow: hidden; text-align: center;
  padding: 60px 26px; border-radius: var(--r-xl);
  background: var(--s1); border: 1px solid var(--line); box-shadow: var(--rim), var(--sh-2);
}
.pub-close::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: none;
}
.pub-close > * { position: relative; z-index: 1; }
.pub-close p { margin: 16px auto 30px; max-width: 50ch; color: var(--text-2); }
.pub-close .pub-hero-cta { margin: 0; justify-content: center; }

/* ============================================================== legal ====== */
.pub-legal { max-width: 68ch; }
.pub-legal h1 { font-size: clamp(30px, 5vw, 44px); }
.pub-legal h2 {
  font-size: 19px; margin: 36px 0 10px; letter-spacing: -.015em;
  text-transform: none;
}
.pub-legal p { margin-bottom: 14px; line-height: 1.75; }
.pub-legal-meta { font-family: var(--mono); font-size: 12.5px; color: var(--text-3); }
.pub-legal-banner {
  margin: 22px 0 8px; padding: 16px 18px; border-radius: var(--r);
  background: rgba(251, 191, 36, .08); border: 1px solid rgba(251, 191, 36, .3);
  color: #FCD34D; font-size: 14px; line-height: 1.65;
}
.pub-legal-banner strong { color: #FDE68A; }
/* an unanswered point, shown as one — never quietly filled with plausible text */
.pub-legal-todo {
  padding: 12px 15px; border-radius: var(--r-sm);
  background: var(--s2); border: 1px dashed var(--line-2);
  font-size: 14px; color: var(--text-2);
}
.pub-legal-todo strong { color: var(--a2); }

/* ============================================================== footer ===== */
.pub-foot { border-top: 1px solid var(--line); padding: 44px 0 30px; }
/* two columns even on the narrowest phone: four stacked link lists made the
   footer 883px tall on its own */
.pub-foot-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 26px 20px; }
.pub-foot-brand { grid-column: 1 / -1; }
.pub-foot-brand p { margin-top: 14px; font-size: 14px; line-height: 1.7; color: var(--text-3); max-width: 320px; }
.pub-foot h4 {
  margin: 0 0 12px; font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase; color: var(--text-3);
}
.pub-foot-col { display: flex; flex-direction: column; }
.pub-foot-col a {
  /* 44px, not 40 — these are the smallest tap targets on the site and they sit
     in a two-column grid where a mis-tap opens the wrong page. */
  display: flex; align-items: center; min-height: 44px; font-size: 14.5px;
  color: var(--text-2); text-decoration: none; transition: color .18s var(--ease), transform .18s var(--ease);
}
.pub-foot-col a:hover { color: var(--a2); transform: translateX(3px); }
.pub-foot-base {
  margin-top: 36px; padding-top: 24px; border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 8px; font-size: 13px; color: var(--text-3);
}

/* ============================================================== auth ======= */
.pub-auth { padding: 28px 0 56px; }
.pub-auth-box {
  width: 100%; max-width: 412px; margin: 0 auto; padding: 28px 24px;
  border-radius: var(--r-xl); background: var(--s1); border: 1px solid var(--line);
  box-shadow: var(--rim), var(--sh-2);
  animation: pub-in .6s var(--ease) both;
}
.pub-auth-box h1 { font-size: 25px; line-height: 1.2; }
.pub-auth-box > .pub-lede { margin-top: 9px; font-size: 14.5px; }
.pub-form { margin-top: 22px; display: flex; flex-direction: column; gap: 15px; }
.pub-field { display: flex; flex-direction: column; gap: 7px; }
/* sentence case, matching every other label on the site — the old reset page
   set these in spaced uppercase, which is part of why it read as a different
   product sitting on the same domain */
.pub-field label { font-size: 13px; font-weight: 600; color: var(--text-2); }
.pub-input {
  width: 100%; min-height: 48px; padding: 0 16px; border-radius: var(--r-sm);
  background: var(--bg-2); border: 1px solid var(--line-2); color: var(--text);
  font-family: var(--body); font-size: 16px; /* 16px avoids the iOS zoom-on-focus */
  transition: border-color .18s var(--ease), background .18s var(--ease), box-shadow .18s var(--ease);
}
.pub-input::placeholder { color: var(--text-3); }
.pub-input:focus {
  outline: none; border-color: var(--a1); background: var(--s1);
  box-shadow: 0 0 0 4px var(--a-soft);
}
.pub-input-code {
  font-family: var(--mono); font-size: 21px; letter-spacing: .32em;
  text-align: center; padding: 0 10px;
}
.pub-note {
  display: flex; gap: 11px; align-items: flex-start; padding: 14px 16px;
  border-radius: var(--r-sm); font-size: 14px; line-height: 1.55; margin-top: 20px;
}
.pub-note svg { flex: 0 0 auto; margin-top: 3px; }
.pub-note-err { background: var(--bad-soft); border: 1px solid var(--bad-line); color: #FDA4AF; }
.pub-note-ok { background: var(--ok-soft); border: 1px solid var(--ok-line); color: var(--ok); }
.pub-auth-alt { margin-top: 22px; font-size: 14px; color: var(--text-3); text-align: center; }
.pub-spin {
  width: 17px; height: 17px; border-radius: 50%; display: inline-block;
  border: 2px solid rgba(255, 255, 255, .32); border-top-color: #fff;
  animation: pub-spin .7s linear infinite;
}
@keyframes pub-spin { to { transform: rotate(360deg); } }

/* ============================================================== modal ====== */
.pub-modal-wrap {
  position: fixed; inset: 0; z-index: 120; display: flex; align-items: flex-end;
  justify-content: center; background: rgba(3, 4, 6, .72); backdrop-filter: blur(4px);
  animation: pub-fade .18s var(--ease);
}
@keyframes pub-fade { from { opacity: 0; } to { opacity: 1; } }
.pub-modal {
  position: relative; width: 100%; max-width: 460px; max-height: 90vh; overflow-y: auto;
  background: var(--s1); border: 1px solid var(--line-2);
  border-radius: var(--r-xl) var(--r-xl) 0 0; box-shadow: var(--sh-3);
  padding: 28px 22px calc(28px + env(safe-area-inset-bottom));
  animation: pub-rise .28s var(--spring);
}
@keyframes pub-rise { from { transform: translateY(26px); opacity: 0; } to { transform: none; opacity: 1; } }
.pub-modal-x {
  position: absolute; top: 18px; right: 18px; width: 38px; height: 38px;
  border-radius: var(--pill); background: var(--s2); border: 1px solid var(--line);
  color: var(--text-2); display: grid; place-items: center; cursor: pointer;
  transition: background .18s var(--ease), transform .24s var(--spring);
}
.pub-modal-x:hover { background: var(--s3); color: var(--text); transform: rotate(90deg); }
.pub-modal h3 { font-size: 22px; margin-top: 8px; }
.pub-modal-head { padding-right: 46px; margin-bottom: 22px; }
.pub-modal-head .pub-lede { margin-top: 8px; font-size: 14.5px; }
.pub-pay { display: flex; flex-direction: column; gap: 11px; }
.pub-pay-row {
  display: flex; align-items: center; gap: 14px; width: 100%; text-align: left;
  padding: 16px; border-radius: var(--r); background: var(--s2);
  border: 1px solid var(--line); cursor: pointer;
  transition: background .18s var(--ease), border-color .18s var(--ease), transform .2s var(--spring);
}
.pub-pay-row:hover { background: var(--s3); border-color: var(--a-line); transform: translateX(3px); }
.pub-pay-row:disabled { opacity: .5; pointer-events: none; }
.pub-pay-txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.pub-pay-txt b { font-size: 15px; font-weight: 600; color: var(--text); }
.pub-pay-txt span { font-size: 12.5px; color: var(--text-2); line-height: 1.45; }
.pub-pay-row > svg:last-child { color: var(--text-3); flex: 0 0 auto; }
.pub-ticket {
  display: flex; align-items: center; gap: 14px; margin-top: 20px; padding: 16px;
  border-radius: var(--r); background: var(--a-soft); border: 1px solid var(--a-line);
}
.pub-ticket .pub-btn { flex: 0 0 auto; }

/* ============================================================ breakpoints == */
@media (min-width: 560px) {
  .pub-wrap { padding: 0 28px; }
  .pub-stats { grid-template-columns: repeat(4, 1fr); }
  .pub-steps { grid-template-columns: repeat(3, 1fr); }
  .pub-foot-grid { grid-template-columns: repeat(3, 1fr); }
  .pub-foot-brand { grid-column: 1 / -1; }
  .pub-foot-base { flex-direction: row; flex-wrap: wrap; gap: 8px 26px; }
  .pub-auth-box { padding: 34px 30px; }
  .pub-modal-wrap { align-items: center; padding: 24px; }
  .pub-modal { border-radius: var(--r-xl); }
}

@media (min-width: 900px) {
  .pub-wrap { padding: 0 36px; }
  .pub-sec { padding: 68px 0; }
  .pub-sec-lg { padding: 80px 0; }
  .pub-sec-tight { padding: 40px 0; }
  .pub-tools { grid-template-columns: repeat(2, 1fr); }
  .pub-plans { grid-template-columns: repeat(3, 1fr); }
  .pub-plan { height: 100%; }
  .pub-faq { grid-template-columns: repeat(2, 1fr); }
  .pub-auth { padding: 48px 0 76px; }
}

@media (min-width: 1080px) {
  .pub-nav-links { display: flex; align-items: center; gap: 4px; margin-left: 22px; }
  .pub-nav-links a {
    position: relative; padding: 10px 15px; border-radius: var(--pill);
    font-size: 14.5px; font-weight: 500; color: var(--text-2); text-decoration: none;
    transition: color .18s var(--ease), background .18s var(--ease);
  }
  .pub-nav-links a:hover { color: var(--text); background: var(--s2); }
  .pub-burger { display: none; }
  .pub-sheet { display: none; }
  .pub-nav-name { display: inline; }
  .pub-nav-right .pub-btn-sm { padding: 0 18px; }
  .pub-hero { padding: 40px 0 20px; }
  .pub-tools { grid-template-columns: repeat(3, 1fr); }
  .pub-foot-grid { grid-template-columns: 1.5fr repeat(3, 1fr); }
  .pub-foot-brand { grid-column: auto; }
}

/* ---- large desktop: use the screen ----------------------------------------
   At 1200px the page left ~350px of dead black down each side of a 1900px
   monitor, which made the whole design look small and marooned in the middle.
   The measure grows with the window instead. */
@media (min-width: 1400px) {
  .pub-wrap { max-width: 1340px; padding-inline: 44px; }
  .pub-nav-in { padding: 0 44px; }
  .pub-hero { padding: 48px 0 24px; }
}

@media (min-width: 1700px) {
  .pub-wrap { max-width: 1520px; }
  .pub-nav-in { padding: 0 56px; }
  .pub-sec { padding: 80px 0; }
  .pub-sec-lg { padding: 96px 0; }
}

@media (prefers-reduced-motion: reduce) {
  .pub *, .pub *::before, .pub *::after { animation: none !important; transition: none !important; }
  .pub-rv { opacity: 1; transform: none; }
  .pub-enter > * { opacity: 1; }
}

/* visually hidden, still announced — used for the lightbox description */
.pub-sr {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
/* The work-in-progress notice.
 *
 * Deliberately calm: this is not an error, and dressing it as one would make a
 * planned pause look like something broke. One card, centred, no red.
 */
.uc {
  display: flex; align-items: center; justify-content: center;
  min-height: min(70vh, 640px); padding: 28px 18px;
}

.uc-card {
  width: 100%; max-width: 520px; padding: 34px 30px 30px; text-align: center;
  background:
    radial-gradient(120% 90% at 50% -10%, rgba(59, 130, 246, .10), transparent 62%),
    rgba(255, 255, 255, .02);
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 18px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .35);
}

.uc-badge {
  display: inline-block; margin-bottom: 20px;
  padding: 5px 12px;
  font-size: 10.5px; font-weight: 650; letter-spacing: .11em; text-transform: uppercase;
  color: #f0ad4e;
  background: rgba(240, 173, 78, .10);
  border: 1px solid rgba(240, 173, 78, .32);
  border-radius: 999px;
}

/* Six bricks that settle into place and start over — a build in progress,
   which is what the page is actually saying. */
.uc-art {
  display: grid; grid-template-columns: repeat(3, 26px); gap: 7px;
  justify-content: center; margin: 0 auto 24px;
}
.uc-brick {
  height: 12px; border-radius: 3px;
  background: rgba(255, 255, 255, .10);
  animation: uc-lay 2.6s ease-in-out infinite;
}
.uc-brick:nth-child(1) { animation-delay: 0s; }
.uc-brick:nth-child(2) { animation-delay: .13s; }
.uc-brick:nth-child(3) { animation-delay: .26s; }
.uc-brick:nth-child(4) { animation-delay: .39s; }
.uc-brick:nth-child(5) { animation-delay: .52s; }
.uc-brick:nth-child(6) { animation-delay: .65s; }
@keyframes uc-lay {
  0%, 70%, 100% { background: rgba(255, 255, 255, .10); transform: translateY(0); }
  18%, 52%      { background: rgba(240, 173, 78, .55); transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) {
  .uc-brick { animation: none; }
}

.uc-card h1 {
  margin: 0 0 10px; font-size: 21px; font-weight: 680; letter-spacing: -.015em;
  color: var(--ink, #eef2f8);
}
.uc-lede { margin: 0 0 16px; font-size: 13.5px; line-height: 1.6; color: var(--muted, #9aa3b2); }
.uc-note {
  margin: 0 0 22px; padding: 11px 13px;
  font-size: 12px; line-height: 1.6; text-align: left;
  color: var(--muted, #9aa3b2);
  background: rgba(255, 255, 255, .03);
  border-left: 2px solid rgba(255, 255, 255, .14);
  border-radius: 8px;
}

.uc-actions { display: flex; flex-wrap: wrap; gap: 9px; justify-content: center; }
.uc-btn {
  padding: 9px 16px; font-size: 12.5px; font-weight: 600; text-decoration: none;
  color: var(--muted, #9aa3b2);
  border: 1px solid rgba(255, 255, 255, .12); border-radius: 10px;
  transition: color .15s ease, background .15s ease, border-color .15s ease;
}
.uc-btn:hover { color: #fff; background: rgba(255, 255, 255, .06); border-color: rgba(255, 255, 255, .22); }
.uc-btn-primary {
  color: #fff; background: var(--accent, #3b82f6); border-color: transparent;
}
.uc-btn-primary:hover { background: #2f74e0; border-color: transparent; }

/* The sidebar tag next to a switched-off tool. */
.sb-badge.sb-wip { color: #f0ad4e; background: rgba(240, 173, 78, .12); }

@media (max-width: 520px) {
  .uc-card { padding: 28px 20px 24px; }
  .uc-actions .uc-btn { flex: 1 1 100%; }
}
