/* ── Reset & Base ─────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --bg-primary: #08080c;
  --bg-secondary: #0c0c12;
  --bg-card: #101017;
  --bg-card-hover: #16161f;
  --bg-elevated: #17171f;
  --bg-modal: #101017;
  --border: #23232c;
  --border-hover: #34343f;
  --text-primary: #f5f5f7;
  --text-secondary: #8888a0;
  --text-muted: #8888a0; /* was #5a5a70 — 2.94:1 failed WCAG AA on ~30 small-text spots incl. checkout fine print */
  --accent: #6366f1;
  --accent-hover: #818cf8;
  --accent-glow: rgba(99, 102, 241, 0.3);
  /* Forge v2: the ONE action colour. Reserved for controls the visitor should
     click — never for decoration, never for text on a light surface. Yellow
     demands dark ink (white on #ffc814 is ~1.7:1); --volt-ink is that ink. */
  --volt: #ffc814;
  --volt-hi: #ffd447;
  --volt-ink: #12100a;
  --hair: rgba(255,255,255,.09);
  --green: #22c55e;
  --orange: #f97316;
  --red: #ef4444;
  --cyan: #06b6d4;
  --pink: #ec4899;
  --radius: 12px;
  --radius-sm: 8px;
  --radius-xs: 6px;
  --shadow: 0 4px 24px rgba(0,0,0,0.4);
  --transition: 0.2s ease;

  /* ── Typography tokens (BitSoul type system 2026-08) ──
     7 sizes · 3 line-heights · 3 weights. Every font decision routes
     through these; if a value isn't here, it isn't part of the system. */
  --font-body: 'Plus Jakarta Sans', 'Jakarta-fb', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-display: var(--font-body); /* same family per brand directive — differentiate by weight+tracking */
  --font-mono: 'JetBrains Mono', Consolas, 'Courier New', monospace;
  --fs-900: clamp(2rem, 1.2rem + 3vw, 3.2rem);
  --fs-800: clamp(1.5rem, 1.15rem + 1.6vw, 2.2rem);
  --fs-700: 1.25rem;
  --fs-600: 1.05rem;
  --fs-500: 1rem;
  --fs-400: .95rem;
  --fs-100: .84rem;
  --lh-tight: 1.15;
  --lh-snug: 1.35;
  --lh-body: 1.6;
  --w-body: 400;
  --w-semi: 600;
  --w-display: 800;
  --track-display: -0.02em;
  --track-caps: 0.08em;
  --measure: 65ch;
}

/* Metric-matched fallback so the system→Jakarta swap doesn't shift layout
   (Jakarta runs ~1-2% wider than Arial at matched size). */
@font-face {
  font-family: 'Jakarta-fb';
  src: local('Arial');
  size-adjust: 98.9%;
  ascent-override: 106%;
  descent-override: 29.7%;
  line-gap-override: 0%;
}

html { font-size: 17px; scroll-behavior: smooth; }
body {
  font-family: var(--font-body);
  background: var(--bg-primary);
  color: var(--text-primary);
  line-height: var(--lh-body);
  min-height: 100vh;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

/* ── Navbar ──────────────────────────────────────────────────────────────── */
.navbar {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(10, 10, 15, 0.85);
  backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--border);
  padding: 0 1.5rem;
}
.nav-inner {
  max-width: 1400px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  height: 64px;
}
.logo {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--fs-700);
  color: var(--text-primary);
  white-space: nowrap;
}
.logo i { font-size: var(--fs-800); color: var(--accent); }
.logo strong { color: var(--accent); }

/* `flex: 1` is `flex: 1 1 0%` — no floor. The nav links squeezed this box down
   to 102px, and once its padding (32), the icon (16), the kbd badge (36) and
   the gaps (16) were subtracted the <input> inside was left 0px wide. The box
   still LOOKED like a search field, so every desktop click landed on this
   wrapper div and nothing focused — the field could not be typed into at all.
   The floor below is what guarantees the input actually has room to exist. */
.search-bar {
  flex: 1 1 220px;
  min-width: 170px;
  max-width: 500px;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.5rem 1rem;
  transition: border var(--transition);
}
.search-bar:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
.search-bar i { color: var(--text-muted); }
.search-bar input {
  flex: 1 1 auto;
  min-width: 0;
  background: none;
  border: none;
  outline: none;
  color: var(--text-primary);
  font-size: var(--fs-400);
}
.search-bar input::placeholder { color: var(--text-muted); }
.search-bar kbd {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.1rem 0.5rem;
  font-size: var(--fs-100);
  color: var(--text-muted);
}

/* `min-width: 0` let this block shrink below the width its buttons actually
   need, and the overflow went somewhere ugly: #navSignedOut got squeezed until
   "Log In" stacked on top of "Join Free", making that one item 84px tall inside
   a 64px bar so the whole row lost its alignment. Nothing in the nav row may
   shrink or wrap — the search box is the only flexible element, which is
   exactly what makes the row keep its shape at every width. */
.nav-actions { display: flex; gap: 0.4rem; margin-left: auto; min-width: auto; flex: 0 0 auto; }
.nav-actions > * { flex: 0 0 auto; }
.nav-actions .btn { white-space: nowrap; padding-left: .7rem; padding-right: .7rem; }
#navSignedOut, #navSignedIn { flex: 0 0 auto; white-space: nowrap; }
#navSignedOut > *, #navSignedIn > * { flex: 0 0 auto; }

/* Nav overflow guard.
   The full link set is ~1550px wide, so on any laptop under that the row ran
   off-screen and took Log In / Join Free with it. Secondary links now drop out
   in priority order (5 = least important) so the auth buttons stay reachable at
   every width. #navSignedOut / #navSignedIn are never hidden here. */
/* ── Mobile menu ───────────────────────────────────────────────────────────
   The .nav-pri-* rules below hide nav links as the viewport narrows so the
   row cannot overflow. Those destinations have to live somewhere, so this
   button holds them. Matches the .menu-panel pattern on the landing page.
   Hidden from 880px up, where the full row fits on its own. */
.mnav-btn {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.04);
  color: var(--text);
  font-size: var(--fs-700);
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease;
}
.mnav-btn:hover { background: rgba(124,106,255,0.14); border-color: var(--accent); }
.mnav-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 200;
  min-width: 244px;
  max-width: calc(100vw - 24px);
  /* 100dvh (not vh) so mobile browser chrome is accounted for, and a 200px
     allowance because the panel sits below the launch banner + navbar — a 90px
     allowance let the last item fall below the fold with no way to scroll to it. */
  max-height: calc(100dvh - 200px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 8px;
  border-radius: 14px;
  background: #12121b;
  border: 1px solid var(--border);
  box-shadow: 0 22px 60px -18px #000, 0 0 0 1px rgba(139,92,246,.12);
  opacity: 0;
  transform: translateY(-8px) scale(.97);
  pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}
.mnav-panel.open { opacity: 1; transform: none; pointer-events: auto; }
/* .mnav-stats is the Stats button, which lives in this menu rather than the
   nav row — it must look and size exactly like the links beside it. */
.mnav-panel a,
.mnav-panel .mnav-stats {
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 44px;
  padding: 12px 14px;
  border-radius: 9px;
  font-size: var(--fs-400);
  font-weight: var(--w-semi);
  color: var(--text);
  text-decoration: none;
}
.mnav-panel .mnav-stats {
  width: 100%;
  background: none;
  border: 0;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
}
.mnav-panel a i,
.mnav-panel .mnav-stats i { font-size: var(--fs-600); color: #818cf8; width: 20px; text-align: center; flex: none; }
.mnav-panel a:hover,
.mnav-panel .mnav-stats:hover { background: rgba(99,102,241,0.13); }
.mnav-panel a.mnav-cta { background: var(--volt); color:var(--volt-ink); margin-top: 2px; }
.mnav-panel a.mnav-cta i { color: #fff; }
.mnav-sep { height: 1px; background: var(--border); margin: 6px 4px; }
@media (max-width: 880px) {
  .mnav-btn { display: inline-flex; }
  /* the nav row becomes the anchor for the absolutely-positioned panel */
  .nav-inner { position: relative; }
  /* .search-bar is flex:1 1 0 with no minimum, so on a phone it was squeezed to
     58px — of which padding and the icon took all of it, leaving the input
     literally 0px wide. Give search its own full-width row instead. */
  .nav-inner { flex-wrap: wrap; row-gap: 8px; padding-bottom: 8px; }
  .navbar { height: auto; min-height: 64px; }
  .logo { order: 1; }
  .nav-actions { order: 2; margin-left: auto; }
  .search-bar { order: 3; flex: 1 0 100%; max-width: none; min-width: 0; }
  /* below 16px iOS zooms the whole page when the field is focused */
  .search-bar input { font-size: 16px; }
  .search-dropdown { left: 0; right: 0; }
}
/* Below 620px the row is: logo + search + Join Free + menu. Pricing and Log In
   move into the menu (which lists both) so the primary CTA and the menu button
   always fit without the page scrolling sideways. */
@media (max-width: 620px) {
  .nav-actions .nav-pri-1,
  #navSignedOut a.btn-ghost { display: none; }
}

/* .nav-inner is max-width:1400px, so the row NEVER gets more than 1400px of
   space no matter how wide the monitor is. Keying pri-5 to a 1680px viewport
   was therefore meaningless: at 1920px the query stopped matching, About and
   Support came back, and the row needed 1527px inside a 1400px container — the
   nav was clipped on every large monitor. pri-5 has no media query now because
   there is no viewport at which those two links fit. Both remain in the footer
   and in the mobile menu, so nothing became unreachable. */
.nav-actions .nav-pri-5 { display: none; }
/* 1500 rather than 1330: .nav-inner tops out at 1400px, so between those two
   widths the row was full and the search box was the thing paying for it.
   The hamburger comes along for the ride: the moment ANY link group is hidden
   there must be a menu holding those destinations. Showing it only at 880px
   left an 881-1500px dead zone on the commonest laptop widths. */
@media (max-width: 1500px) {
  .nav-actions .nav-pri-4 { display: none; }
  .mnav-btn { display: inline-flex; }
}
/* The shortcut badge is decoration; give its ~44px to the input when tight. */
@media (max-width: 1200px) { .search-bar kbd { display: none; } }
@media (max-width: 1120px) { .nav-actions .nav-pri-3 { display: none; } }
/* Raised 940 -> 1075 on 2026-08-09: the type scale went up ~6% for legibility
   and the remaining row stopped fitting at 1024px (nav-actions ran 9px past the
   viewport). Drop pri-2 before that point instead of shrinking the type back. */
@media (max-width: 1075px) { .nav-actions .nav-pri-2 { display: none; } }
/* 621-880px: Pricing collapses to its icon rather than disappearing. Below
   620px it moves into the mobile menu instead (see the rule further up). */
@media (max-width: 880px) {
  .nav-actions .nav-pri-1 { padding-left: .7rem; padding-right: .7rem; }
  .nav-actions .nav-pri-1 span { display: none; }
}

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  padding: 0.55rem 1.1rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font-size: 0.875rem;
  font-weight: var(--w-semi);
  letter-spacing: 0.01em;
  cursor: pointer;
  position: relative;
  -webkit-user-select: none;
  user-select: none;
  transition: transform 0.16s cubic-bezier(.4,0,.2,1), box-shadow 0.16s ease, background 0.16s ease, border-color 0.16s ease, color 0.16s ease, filter 0.16s ease;
  white-space: nowrap;
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(139,92,246,0.55), 0 0 18px -2px rgba(139,92,246,0.6); }
.btn-primary {
  /* Forge v2: the one action colour. Dark ink is mandatory — white on
     #ffc814 is ~1.7:1 and unreadable. No bloom: real products do not glow. */
  background: var(--volt);
  color: var(--volt-ink);
  font-weight: 700;
  border-color: transparent;
  box-shadow: 0 6px 16px -8px rgba(0,0,0,0.85);
}
.btn-primary:hover {
  background: var(--volt-hi);
  border-color: transparent;
  transform: translateY(-1.5px);
  box-shadow: 0 10px 22px -10px rgba(0,0,0,0.9);
}
.btn-primary:active {
  transform: translateY(0);
  box-shadow: inset 0 2px 4px rgba(0,0,0,0.25);
}
.btn-ghost {
  background: transparent;
  color: var(--text-secondary);
  border-color: transparent;
}
.btn-ghost:hover { color: var(--text-primary); background: var(--bg-card); }
.btn-outline {
  background: rgba(255,255,255,0.02);
  color: var(--text-primary);
  border-color: var(--border);
}
.btn-outline:hover { border-color: rgba(167,139,250,0.8); color: var(--accent-hover); transform: translateY(-1px); box-shadow: 0 0 0 1px rgba(139,92,246,0.4), 0 0 18px -4px rgba(139,92,246,0.5); }
.btn-lg { padding: 0.8rem 1.6rem; font-size: var(--fs-500); }
.btn-sm { padding: 0.3rem 0.65rem; font-size: var(--fs-100); }
.btn-full {
  width: 100%;
  justify-content: center;
  /* The base .btn sets `white-space: nowrap`, which is right for a short
     auto-width button and WRONG here: a full-width button already has a known
     box to wrap inside, and nowrap makes its min-content width the entire
     label. Measured consequence in the model modal: the label "Or download it
     with a membership — from $12/mo" needs 424.95px, which dragged the whole
     `1fr` modal column to 467px inside a 388px phone viewport — shearing 58px
     off the Buy button (including its right rounded cap), 38px off this link,
     30px off the trust strip and 57px off the licence line. Wrapping fixes all
     five at once. Do NOT "fix" it with ellipsis: that would hide the price. */
  white-space: normal;
}
.btn-danger { background: linear-gradient(135deg,#f05252,#dc2626); color: #fff; box-shadow: inset 0 1px 0 rgba(255,255,255,0.15), 0 4px 14px -5px rgba(239,68,68,0.5); }
.btn-danger:hover { transform: translateY(-1px); box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), 0 10px 22px -6px rgba(239,68,68,0.6); }
.btn-secondary { background: var(--bg-secondary); color: var(--text-secondary); border: 1px solid var(--border); }
.btn-secondary:hover { border-color: rgba(167,139,250,0.7); color: var(--accent-hover); transform: translateY(-1px); box-shadow: 0 0 0 1px rgba(139,92,246,0.35), 0 0 16px -5px rgba(139,92,246,0.45); }
.btn-secondary.active { background: var(--accent); color: white; border-color: var(--accent); }

/* ── Hero ────────────────────────────────────────────────────────────────── */
.hero {
  background: linear-gradient(135deg, var(--bg-primary) 0%, #0f0f2e 50%, var(--bg-primary) 100%);
  padding: 5rem 1.5rem 3rem;
  text-align: center;
  position: relative;
  overflow: hidden;
}
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 50% 0%, var(--accent-glow) 0%, transparent 60%);
  pointer-events: none;
}
.hero-content { position: relative; max-width: 700px; margin: 0 auto; }
.hero-badge {
  display: inline-block;
  padding: 0.3rem 1rem;
  background: rgba(99, 102, 241, 0.15);
  border: 1px solid rgba(99, 102, 241, 0.3);
  border-radius: 99px;
  font-size: var(--fs-100);
  color: var(--accent-hover);
  margin-bottom: 1.5rem;
  font-weight: var(--w-semi);
}
/* Hero-only ceiling. --fs-900 tops out at 3.2rem which, at the 17px root,
   wrapped the drag-and-drop headline onto four lines and pushed the CTAs
   below the fold. */
.hero h1 { font-size: clamp(1.9rem, 1.05rem + 2.5vw, 2.7rem); font-weight: var(--w-display); line-height: var(--lh-tight); letter-spacing: -.025em; color: #f5f7ff; margin-bottom: 1rem; }
/* Duotone, not a rainbow. The old three-stop indigo->pink->cyan landed a
   DIFFERENT hue on every word (the ampersand went grey), which is the tell of
   an auto-generated page. Two adjacent brand hues read as one deliberate
   material and keep Unity/Unreal/Godot emphasised — they are both the head
   keywords and the buyer's does-this-work-with-my-tool check. */
.gradient-text {color:#fff;text-decoration:underline;text-decoration-color:var(--volt,#ffc814);text-decoration-thickness:.11em;text-underline-offset:.16em;text-decoration-skip-ink:none}
.hero p { color: var(--text-secondary); font-size: var(--fs-600); margin-bottom: 2rem; }
.hero-stats { display: flex; justify-content: center; gap: 3rem; }
.stat { display: flex; flex-direction: column; align-items: center; }
.stat-num { font-size: var(--fs-800); font-weight: var(--w-semi); color: var(--text-primary); }
.stat-label { font-size: var(--fs-100); color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.1em; }

/* ── Filters ─────────────────────────────────────────────────────────────── */
.filters-section {
  position: sticky;
  top: 64px;
  z-index: 90;
  background: rgba(10, 10, 15, 0.9);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  padding: 0.75rem 1.5rem;
}
.filters-inner {
  max-width: 1400px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}
.filter-tabs {
  display: flex;
  gap: 0.25rem;
  overflow-x: auto;
  flex-wrap: nowrap;
  flex: 1;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 6px;
  scrollbar-width: thin;
  scrollbar-color: var(--accent) rgba(99,102,241,0.08);
}
.filter-tabs::-webkit-scrollbar { height: 8px; }
.filter-tabs::-webkit-scrollbar-track {
  background: rgba(99,102,241,0.08);
  border-radius: 99px;
  margin: 0 4px;
}
.filter-tabs::-webkit-scrollbar-thumb {
  background: linear-gradient(90deg, var(--accent), var(--accent-hover));
  border-radius: 99px;
  box-shadow: 0 0 8px rgba(99,102,241,0.45);
}
.filter-tabs::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(90deg, var(--accent-hover), var(--accent));
  box-shadow: 0 0 12px rgba(129,140,248,0.7);
}
.tab {
  padding: 0.4rem 0.9rem;
  border-radius: 99px;
  border: 1px solid transparent;
  background: none;
  color: var(--text-secondary);
  font-size: var(--fs-100);
  cursor: pointer;
  white-space: nowrap;
  transition: all var(--transition);
}
.tab:hover { color: var(--text-primary); background: var(--bg-card); }
/* White on --accent (#6366f1) measures 4.47:1 — just under the 4.5:1 minimum,
   so Lighthouse flags the selected category tab. A hair darker clears it at
   4.88:1 and is visually indistinguishable. Scoped to this one control on
   purpose: --accent itself is the brand token and stays untouched. */
.tab.active { background: #5b5ef0; color: white; border-color: #5b5ef0; }

.filter-right { display: flex; gap: 0.5rem; align-items: center; }
.filter-select {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  color: var(--text-secondary);
  padding: 0.4rem 0.8rem;
  font-size: var(--fs-100);
  cursor: pointer;
}
.filter-select:focus { border-color: var(--accent); outline: none; }

.view-toggle { display: flex; border: 1px solid var(--border); border-radius: var(--radius-xs); overflow: hidden; }
.view-btn {
  padding: 0.4rem 0.6rem;
  border: none;
  background: var(--bg-secondary);
  color: var(--text-muted);
  cursor: pointer;
  transition: all var(--transition);
}
.view-btn.active { background: var(--accent); color: white; }
.view-btn:hover:not(.active) { color: var(--text-primary); }

/* ── Main Content & Grid ─────────────────────────────────────────────────── */
.main-content {
  max-width: 1400px;
  margin: 0 auto;
  padding: 2rem 1.5rem;
  min-height: 60vh;
}
.model-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.25rem;
}
.model-grid.list-view {
  grid-template-columns: 1fr;
}

/* ── Model Card ──────────────────────────────────────────────────────────── */
.model-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  cursor: pointer;
  transition: all var(--transition);
  position: relative;
}
.model-card:hover {
  border-color: var(--border-hover);
  background: var(--bg-card-hover);
  transform: translateY(-2px);
  box-shadow: 0 8px 32px rgba(0,0,0,0.3);
}
.card-thumb {
  position: relative;
  aspect-ratio: 4/3;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Immersive studio backdrop: soft key-light spotlight from upper centre,
     subtle on-brand floor glow, and a wall→floor vertical gradient so the
     transparent-PNG models look like they're standing in real 3D space. */
  background:
    radial-gradient(115% 78% at 50% 14%, rgba(186,190,214,0.20) 0%, rgba(120,124,156,0.07) 30%, rgba(120,124,156,0) 58%),
    radial-gradient(95% 120% at 50% 122%, rgba(99,102,241,0.16) 0%, rgba(99,102,241,0) 55%),
    linear-gradient(180deg, #23242f 0%, #181822 58%, #0e0e16 100%);
}
/* Grounding floor shadow beneath the model — sits behind the image (z below). */
.card-thumb::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 9%;
  width: 60%;
  height: 13%;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0) 72%);
  filter: blur(4px);
  z-index: 1;
  pointer-events: none;
}
.card-thumb img {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 2% 4% 1%;
  transform: scale(1.16);
  filter: drop-shadow(0 12px 16px rgba(0,0,0,0.45));
  transition: transform 0.28s cubic-bezier(.4,0,.2,1);
}
.model-card:hover .card-thumb img {
  transform: scale(1.22) translateY(-3px);
}
.card-thumb .placeholder-icon {
  position: relative;
  z-index: 2;
  font-size: var(--fs-900);
  color: var(--text-muted);
}
/* RETIRED from the markup: this badge was absolutely positioned over the
   top-left of the thumbnail and covered the model itself. The formats now
   render as `.card-meta` inside the card body. The rule is kept only so a
   visitor holding a cached copy of the previous app.js still sees a styled
   badge rather than raw text floating over the artwork; delete it once the
   old bundle has aged out of browser caches. */
.card-format {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 3;
  background: rgba(0,0,0,0.7);
  padding: 0.15rem 0.5rem;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: var(--fs-100);
  font-weight: var(--w-semi);
  text-transform: uppercase;
  letter-spacing: var(--track-caps);
  color: var(--cyan);
}
/* The formats + licence line, in the body where it belongs. One line, clipped
   with an ellipsis rather than wrapping, so every card in the grid keeps the
   same height and the price row never orphans a word. */
.card-meta {
  font-size: var(--fs-100);
  color: var(--text-muted);
  letter-spacing: 0.02em;
  margin: 0.15rem 0 0.45rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.card-featured {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  z-index: 3;
  /* Was white on --orange at 2.8:1 — below the 4.5 AA floor for this size.
     A label is not an action, so it takes the quiet-glass treatment instead of
     a second bright fill. */
  background: rgba(255,255,255,.13);
  color: #fff;
  border: 1px solid rgba(255,255,255,.20);
  padding: 0.1rem 0.4rem;
  border-radius: 4px;
  font-size: var(--fs-100);
  font-weight: var(--w-semi);
}
.card-body { padding: 1rem; }
.card-name {
  font-size: var(--fs-400);
  font-weight: var(--w-semi);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 0.25rem;
}
.card-buy {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 0.5rem;
}
.card-price {
  font-family: var(--font-mono); /* tabular scan across the catalog grid */
  font-size: var(--fs-400);
  font-weight: var(--w-semi);
  color: #a5a8f5;
}
/* Replaces .card-price-old, which drew a strike-through through a $9.99 that
   was never charged. Now used for a factual note beside the price. */
.card-price-note {
  font-size: var(--fs-100);
  font-weight: var(--w-semi);
  color: var(--text-muted);
  margin-left: 0.4rem;
}
.card-buy-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  border: none;
  cursor: pointer;
  font-size: var(--fs-100);
  font-weight: var(--w-semi);
  color:var(--volt-ink);
  background: var(--volt);
  padding: 0.4rem 0.8rem;
  border-radius: 999px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.28),0 6px 16px -8px rgba(0,0,0,.85);
  transition: transform 0.14s cubic-bezier(.4,0,.2,1), box-shadow 0.14s ease, filter 0.14s ease;
}
.card-buy-btn:hover {
  transform: translateY(-1.5px);
  filter: brightness(1.06);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.25), 0 0 0 1px rgba(167,139,250,0.85), 0 0 22px 0 rgba(139,92,246,0.75), 0 7px 18px -4px rgba(99,102,241,0.6);
}
.card-buy-btn:active { transform: translateY(0); box-shadow: inset 0 1px 2px rgba(0,0,0,0.2), 0 0 0 1px rgba(139,92,246,0.6), 0 2px 6px rgba(99,102,241,0.4); }
.price-now { font-weight: var(--w-display); }
/* .price-was (strike-through) removed 2026-08-02 — it displayed a $9.99 that
   was never charged. Do not re-add a strike-through style unless there is a
   genuine, previously-charged price and a real end date behind it. */
.trust-strip {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 1rem;
  margin-top: 0.75rem;
  font-size: var(--fs-100);
  color: var(--text-muted);
}
.trust-strip span {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  white-space: nowrap;
}
.trust-strip i { color: #818cf8; }
.launch-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 0.6rem 1rem;
  background: linear-gradient(90deg, #1b3a4b, #0e2a3a);
  border-bottom: 1px solid rgba(55, 208, 255, 0.3);
  color: #e8f6ff;
  font-size: var(--fs-400);
  text-align: center;
  position: relative;
  z-index: 50;
}
.launch-banner strong { color: #818cf8; }
.launch-banner .launch-was {
  text-decoration: line-through;
  opacity: 0.65;
  font-size: 0.85em;
  color: var(--text-muted);
}
.launch-banner i.ri-fire-fill { color: #ff8a3d; }
.launch-close {
  background: transparent;
  border: none;
  color: #9fc4d8;
  cursor: pointer;
  font-size: var(--fs-600);
  line-height: 1;
  padding: 0.2rem;
  border-radius: 4px;
}
.launch-close:hover { color: #fff; background: rgba(255,255,255,0.1); }
.card-category {
  font-size: var(--fs-100);
  color: var(--accent-hover);
  text-transform: capitalize;
  margin-bottom: 0.5rem;
}
.card-meta {
  display: flex;
  align-items: center;
  gap: 1rem;
  font-size: var(--fs-100);
  color: var(--text-muted);
}
.card-meta span { display: flex; align-items: center; gap: 0.2rem; }

/* List view card */
.list-view .model-card {
  display: flex;
  flex-direction: row;
}
.list-view .card-thumb {
  width: 200px;
  min-width: 200px;
  aspect-ratio: auto;
  height: 140px;
}
.list-view .card-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* ── Empty State ─────────────────────────────────────────────────────────── */
.empty-state {
  text-align: center;
  padding: 4rem 2rem;
  color: var(--text-muted);
}
.empty-state i { font-size: 4rem; margin-bottom: 1rem; }
.empty-state h3 { color: var(--text-secondary); margin-bottom: 0.5rem; }
.empty-state .btn { margin-top: 1.5rem; }

/* ── Loading ─────────────────────────────────────────────────────────────── */
.loading-spinner { text-align: center; padding: 3rem; color: var(--text-muted); }
.spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  margin: 0 auto 1rem;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Pagination ──────────────────────────────────────────────────────────── */
.pagination {
  display: flex;
  justify-content: center;
  gap: 0.25rem;
  margin-top: 2rem;
  flex-wrap: wrap;
}
.page-btn {
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: var(--bg-card);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--fs-400);
  transition: all var(--transition);
}
.page-btn:hover { border-color: rgba(255,200,20,.55); color: var(--text-primary); background: rgba(255,200,20,.08); }
.page-btn.active { background: rgba(255,200,20,.12); color: #fff; border-color: rgba(255,200,20,.6); }
.page-btn:disabled { opacity: 0.3; cursor: not-allowed; }

/* ── Modal ───────────────────────────────────────────────────────────────── */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.8);
  backdrop-filter: blur(4px);
  z-index: 200;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 2rem;
}
.modal-overlay.active { display: flex; }
.modal {
  background: var(--bg-modal);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  max-height: 90vh;
  overflow-y: auto;
  position: relative;
  box-shadow: var(--shadow);
}
.modal-close {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 50%;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  cursor: pointer;
  z-index: 9999;
  transition: all var(--transition);
  pointer-events: auto;
  font-size: var(--fs-800);
  font-weight: bold;
  line-height: 1;
  isolation: isolate;
}
.modal-close:hover { background: var(--red); color: white; border-color: var(--red); }

/* ── Model Detail Modal ──────────────────────────────────────────────────── */
.model-detail-modal { width: 95vw; max-width: 1100px; max-height: 90vh; overflow: hidden; }
/* minmax(0,1fr), not 1fr: a bare `1fr` is `minmax(auto,1fr)`, and that automatic
   minimum is min-content — which is how one un-wrappable button was able to
   widen this whole modal past the viewport. Removing the floor means no future
   label, price string or translation can do it again. */
.model-detail { display: grid; grid-template-columns: minmax(0, 1fr) 380px; height: 80vh; max-height: 80vh; }
.model-viewer-container {
  background: var(--bg-secondary);
  border-right: 1px solid var(--border);
  display: flex;
  align-items: stretch;
  justify-content: stretch;
  position: relative;
  min-height: 400px;
  overflow: hidden;
}
.model-viewer-container model-viewer {
  width: 100%;
  height: 100%;
  min-height: 500px;
  --poster-color: transparent;
  --progress-bar-color: var(--accent);
  --progress-bar-height: 3px;
}
.model-viewer-container .no-preview {
  text-align: center;
  color: var(--text-muted);
  padding: 2rem;
}
.model-viewer-container .no-preview i { font-size: 4rem; display: block; margin-bottom: 1rem; }

/* right padding reserves a gutter for the absolutely-positioned .modal-close;
   without it the tag row and spec values scroll underneath an opaque button. */
.model-info { padding: 1.5rem 3.75rem 1.5rem 1.5rem; overflow-y: auto; }
.model-info h2 { font-size: var(--fs-800); font-weight: var(--w-semi); margin-bottom: 0.25rem; padding-right: 2.5rem; }
.model-info .info-category {
  color: var(--accent-hover);
  text-transform: capitalize;
  font-size: var(--fs-400);
  margin-bottom: 1rem;
}
.model-info .info-description {
  color: var(--text-secondary);
  font-size: var(--fs-400);
  line-height: var(--lh-body);
  margin-bottom: 1.5rem;
}
.model-info .info-tags { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-bottom: 1.5rem; }
.info-tag {
  padding: 0.2rem 0.6rem;
  background: rgba(99, 102, 241, 0.1);
  border: 1px solid rgba(99, 102, 241, 0.2);
  border-radius: 99px;
  font-size: var(--fs-100);
  color: var(--accent-hover);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
a.info-tag:hover {
  background: rgba(99, 102, 241, 0.22);
  border-color: rgba(99, 102, 241, 0.55);
  color: #fff;
  transform: translateY(-1px);
}
.info-meta { margin-bottom: 1.5rem; }
.info-meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-400);
}
.info-meta-row .label { color: var(--text-muted); }
.info-meta-row .value { color: var(--text-primary); font-weight: var(--w-semi); }
.info-actions { display: flex; flex-direction: column; gap: 0.5rem; }
.badge-row { display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap; }
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.2rem 0.6rem;
  border-radius: 4px;
  font-size: var(--fs-100);
  font-weight: var(--w-semi);
}
.badge-green { background: rgba(34,197,94,0.15); color: var(--green); }
.badge-orange { background: rgba(249,115,22,0.15); color: var(--orange); }
.badge-cyan { background: rgba(6,182,212,0.15); color: var(--cyan); }

/* ── Upload Modal ────────────────────────────────────────────────────────── */
.upload-modal { width: 600px; max-width: 95vw; padding: 2rem; }
.upload-modal h2 {
  font-size: var(--fs-700);
  margin-bottom: 1.5rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.upload-form { display: flex; flex-direction: column; gap: 1rem; }
.upload-dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  padding: 2.5rem;
  text-align: center;
  cursor: pointer;
  transition: all var(--transition);
  position: relative;
}
.upload-dropzone:hover, .upload-dropzone.drag-over {
  border-color: var(--accent);
  background: rgba(99, 102, 241, 0.05);
}
.upload-dropzone i { font-size: var(--fs-900); color: var(--text-muted); margin-bottom: 0.5rem; display: block; }
.upload-dropzone p { color: var(--text-secondary); margin-bottom: 0.25rem; }
.upload-dropzone span { font-size: var(--fs-100); color: var(--text-muted); display: block; margin-bottom: 1rem; }
.upload-dropzone input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.upload-file-info {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.upload-file-info i { font-size: var(--fs-800); color: var(--accent); }
.file-name { font-weight: var(--w-semi); display: block; }
.file-size { font-size: var(--fs-100); color: var(--text-muted); }

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.form-group { display: flex; flex-direction: column; gap: 0.3rem; }
.form-group label { font-size: var(--fs-100); color: var(--text-secondary); font-weight: var(--w-semi); }
.form-group input,
.form-group select,
.form-group textarea {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  color: var(--text-primary);
  padding: 0.6rem 0.8rem;
  /* 16px, not 0.9rem: Safari on iPhone AND iPad force-zooms the page whenever a
     focused text field is under 16px. This rule outranks .form-input (one class
     + one type beats one class), so it is the one that actually governs the
     signup/login fields — setting 16px on .form-input alone did nothing here. */
  font-size: 16px;
  font-family: inherit;
  resize: vertical;
  transition: border var(--transition);
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-glow);
}

.upload-progress { margin-top: 0.5rem; }
.progress-bar {
  height: 6px;
  background: var(--bg-secondary);
  border-radius: 99px;
  overflow: hidden;
  margin-bottom: 0.5rem;
}
.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--cyan));
  border-radius: 99px;
  width: 0%;
  transition: width 0.3s ease;
}

/* ── Stats Modal ─────────────────────────────────────────────────────────── */
.stats-modal { width: 600px; max-width: 95vw; padding: 2rem; }
.stats-modal h2 {
  font-size: var(--fs-700);
  margin-bottom: 1.5rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
  margin-bottom: 1.5rem;
}
.stat-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1rem;
  text-align: center;
}
.stat-card .big { font-size: var(--fs-800); font-weight: var(--w-semi); color: var(--text-primary); }
.stat-card .label { font-size: var(--fs-100); color: var(--text-muted); text-transform: uppercase; }
.stats-section { margin-bottom: 1.5rem; }
.stats-section h3 { font-size: var(--fs-500); margin-bottom: 0.75rem; color: var(--text-secondary); }
.stats-bar-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
  font-size: var(--fs-400);
}
.stats-bar-label { width: 100px; color: var(--text-secondary); text-transform: capitalize; }
.stats-bar-track { flex: 1; height: 8px; background: var(--bg-secondary); border-radius: 99px; overflow: hidden; }
.stats-bar-fill { height: 100%; border-radius: 99px; background: var(--accent); }
.stats-bar-count { width: 40px; text-align: right; color: var(--text-muted); font-size: var(--fs-100); }

/* ── Footer ──────────────────────────────────────────────────────────────── */
.footer {
  border-top: 1px solid var(--border);
  padding: 1.5rem;
  margin-top: 2rem;
}
.footer-inner {
  max-width: 1400px;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: var(--fs-100);
  color: var(--text-muted);
}
/* Wraps on narrow screens — unwrapped this row was 401px wide and forced the
   whole page to 503px, which then pushed the nav's auth buttons off-screen. */
.footer-links { display: flex; gap: 1.5rem; flex-wrap: wrap; justify-content: center; }
.footer-links a { color: var(--text-muted); }
.footer-links a:hover { color: var(--accent); }

/* Newsletter signup in footer */
.footer-newsletter {
  max-width: 1400px;
  margin: 0 auto 1.25rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
}
.footer-newsletter .nl-copy {
  flex: 1 1 280px;
  font-size: var(--fs-400);
  color: var(--text-muted);
}
.footer-newsletter .nl-copy strong { color: var(--text); }
.footer-newsletter form {
  display: flex;
  gap: 0.5rem;
  flex: 1 1 320px;
  min-width: 260px;
}
.footer-newsletter input[type="email"] {
  flex: 1;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.55rem 0.75rem;
  font-size: var(--fs-400);
  font-family: inherit;
}
.footer-newsletter input[type="email"]:focus {
  outline: none;
  border-color: var(--accent);
}
.footer-newsletter button {
  background: var(--accent);
  color: #07101f;
  border: 0;
  border-radius: 8px;
  padding: 0.55rem 1.1rem;
  font-weight: var(--w-semi);
  font-size: var(--fs-400);
  cursor: pointer;
  white-space: nowrap;
}
.footer-newsletter button:disabled { opacity: 0.6; cursor: wait; }
.footer-newsletter .nl-msg {
  flex: 1 1 100%;
  font-size: var(--fs-400);
  margin-top: 0.25rem;
  min-height: 1.2em;
}
.footer-newsletter .nl-msg.ok { color: #6cf3a8; }
.footer-newsletter .nl-msg.err { color: #ff9b9b; }
@media (max-width: 640px) {
  .footer-newsletter { flex-direction: column; align-items: stretch; }
  /* flex-basis 280/320px and min-width 260px were wider than a 320px screen,
     forcing the whole page to scroll sideways. */
  .footer-newsletter .nl-copy { flex-basis: auto; }
  .footer-newsletter form { flex-basis: auto; min-width: 0; flex-wrap: wrap; }
  .footer-newsletter input[type="email"] { min-width: 0; }
}

/* ── Responsive ──────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
  .hero h1 { font-size: var(--fs-800); }
  .hero-stats { gap: 1.5rem; }
  .nav-actions .btn span { display: none; }
  .search-bar kbd { display: none; }
  /* The model modal keeps height:80vh from the desktop rule, and this block
     used to only restack the columns. Once stacked, the 3D viewer ate most of
     that fixed box and the info column was left ~212px tall holding ~1145px of
     content — so "Buy & download" sat ~1250px inside a 212px scroller and was
     effectively unreachable on a phone. Let the modal grow and pin the CTA. */
  .modal-overlay { padding: 0; align-items: stretch; }
  .model-detail-modal { width: 100vw; max-width: none; max-height: 100dvh; border-radius: 0; }
  .model-detail { grid-template-columns: minmax(0, 1fr); height: auto; max-height: 100dvh; overflow-y: auto; -webkit-overflow-scrolling: touch; }
  .model-viewer-container { min-height: 0; height: 42dvh; border-right: none; border-bottom: 1px solid var(--border); }
  .model-viewer-container model-viewer { min-height: 0; height: 100%; }
  .model-info { overflow: visible; padding: 1.25rem 1.25rem 1.5rem; }
  .model-info .info-actions {
    position: sticky; bottom: 0; z-index: 2;
    margin: 1rem -1.25rem -1.5rem;
    padding: 0.85rem 1.25rem 1.25rem;
    background: var(--bg-modal);
    box-shadow: 0 -12px 26px -14px #000;
  }
  .form-grid { grid-template-columns: 1fr; }
  .stats-grid { grid-template-columns: repeat(2, 1fr); }
  .filter-right { width: 100%; justify-content: flex-end; }
  .model-grid { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
}

@media (max-width: 480px) {
  .hero h1 { font-size: var(--fs-800); }
  .model-grid { grid-template-columns: 1fr; }
  .hero-stats { flex-direction: column; gap: 0.75rem; }
  /* Reclaim the ~10px that pushed Join Free off a 375px screen. */
  .navbar { padding: 0 0.6rem; }
  .nav-inner { gap: 0.6rem; }
}

/* Small phones: tighten the nav buttons so the Pricing icon, Log In and
   Join Free all fit on one row without the page scrolling sideways. */
@media (max-width: 430px) {
  .nav-actions .btn { padding-left: .65rem; padding-right: .65rem; }
}

/* Phones (<=400px, covers 375/390 and smaller): drop the brand wordmark so the
   search box, Join Free and the menu button all fit on one row. The logo icon
   still links home. */
@media (max-width: 400px) {
  .logo span { display: none; }
}

/* ── Scrollbar ───────────────────────────────────────────────────────────── */
::-webkit-scrollbar { width: 8px; }

/* ── Material Mode Bar ──────────────────────────────────────────────────── */
.material-mode-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.6rem 1rem;
  position: absolute;
  bottom: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  background: rgba(20, 20, 30, 0.85);
  backdrop-filter: blur(12px);
  border-radius: 2rem;
  border: 1px solid rgba(255,255,255,0.08);
}

.mode-sphere {
  position: relative;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 2px solid transparent;
  background: transparent;
  cursor: pointer;
  padding: 3px;
  transition: border-color 0.2s, transform 0.15s, box-shadow 0.2s;
}

.mode-sphere:hover {
  transform: scale(1.15);
  border-color: rgba(255,255,255,0.3);
}

.mode-sphere.active {
  border-color: var(--cyan, #00e5ff);
  box-shadow: 0 0 10px rgba(0,229,255,0.4);
  transform: scale(1.15);
}

.sphere-preview {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  box-shadow: inset -3px -3px 6px rgba(0,0,0,0.5), inset 3px 3px 6px rgba(255,255,255,0.2);
}

.mode-sphere::after {
  content: attr(title);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0,0,0,0.9);
  color: #fff;
  font-size: var(--fs-100);
  padding: 2px 8px;
  border-radius: 4px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s;
}

.mode-sphere:hover::after {
  opacity: 1;
}

/* ── Model Scan FX ───────────────────────────────────────────────────────── */
.model-viewer-container {
  position: relative;
  overflow: hidden;
}
::-webkit-scrollbar-track { background: var(--bg-primary); }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 99px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

/* ── Toast Notifications ─────────────────────────────────────────────────── */
.toast-container {
  position: fixed;
  top: 80px;
  right: 1rem;
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.toast {
  padding: 0.75rem 1.25rem;
  border-radius: var(--radius-sm);
  font-size: var(--fs-400);
  font-weight: var(--w-semi);
  animation: slideIn 0.3s ease;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  max-width: 400px;
}
.toast-success { background: rgba(34,197,94,0.15); border: 1px solid rgba(34,197,94,0.3); color: var(--green); }
.toast-error { background: rgba(239,68,68,0.15); border: 1px solid rgba(239,68,68,0.3); color: var(--red); }
.toast-info { background: rgba(99,102,241,0.15); border: 1px solid rgba(99,102,241,0.3); color: var(--accent-hover); }
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }


/* >>> BEGIN responsive-polish (generated — edit css/responsive-polish.css) */
@supports (height:100dvh){.hero,#hero,.ws-shell,.ws-stage,.modal-overlay,.mnav-panel{max-height:100dvh}}.sc-bubble,.soul-fab,.soul-launcher,#soulFab,.chat-fab,[class*="soul-"][class*="fab"]{bottom:calc(16px + env(safe-area-inset-bottom,0px)) !important;right:calc(16px + env(safe-area-inset-right,0px)) !important}.sc-panel,.soul-panel,.soul-window,#soulPanel{bottom:calc(84px + env(safe-area-inset-bottom,0px)) !important;max-height:calc(100dvh - 120px - env(safe-area-inset-bottom,0px))}.navbar,.gnav{padding-left:max(1.5rem,env(safe-area-inset-left,0px));padding-right:max(1.5rem,env(safe-area-inset-right,0px))}.footer,.site-footer{padding-bottom:calc(2rem + env(safe-area-inset-bottom,0px))}@media (hover:none),(pointer:coarse){.cat-card:hover,.mcard:hover,.model-card:hover,.bundle-card:hover,.bsx-card:hover,.gcard:hover,.hcta:hover,.stage-chip:hover,.fmt-card:hover,.faq-card:hover,.plugin-card:hover{transform:none !important}.bundle-card:hover .imgwrap::after{left:-80% !important}.bsx-wrap:hover .bsx-track{animation-play-state:running !important}}:root{--ar-hero:4 / 3;--ar-card:1 / 1;--ar-wide:16 / 9;--ar-square:1 / 1;--ar-bundle:1.905 / 1}@media (max-width:900px){:root{--ar-hero:4 / 5}}.bundle-card .imgwrap{aspect-ratio:var(--ar-bundle);height:auto !important}.bundle-card img{aspect-ratio:var(--ar-bundle);height:auto !important}.mcard .mthumb,.model-card .thumb-wrap{aspect-ratio:var(--ar-card)}.gcard .gthumb{aspect-ratio:var(--ar-card)}@media (min-width:1700px){.hero-content,.faq-section,.bsx,.fmt-strip,.filters-section,.models-section,.footer-inner{max-width:1600px;margin-left:auto;margin-right:auto}.hero-text p,.bsx>p,.faq-card p{max-width:68ch}}@media (pointer:coarse){.tab,.filter-select,.page-btn,.view-btn,.gnav-btn,.chip,.cat-chip,.nav-actions .btn,.mnav-panel a{min-height:44px}.page-btn{min-width:44px}.tab{padding-top:10px;padding-bottom:10px}.card-buy-btn,.buy-btn,.btn-buy{min-height:44px;padding-top:10px;padding-bottom:10px}input[type="text"],input[type="email"],input[type="search"],input[type="password"],input[type="number"],select,textarea{min-height:44px}.launch-close,.modal-close,.toast-close{min-width:44px;min-height:44px}.view-btn{min-width:44px}.stage-chip{min-height:44px;padding-top:11px;padding-bottom:11px}.gnav-cta,.bt-opt,.hlink{min-height:44px;display:inline-flex;align-items:center}button{min-height:44px}.hero-ctas{gap:10px}.nav-actions{gap:.5rem}}@media (max-height:520px) and (orientation:landscape){.hero{padding-top:12px;padding-bottom:12px}.hero-stage{min-height:260px}.hero h1{font-size:clamp(1.4rem,1rem + 2vw,1.9rem)}.hero-text p{margin-bottom:.5rem}}@media (max-width:380px){.hero-stats{gap:1.1rem;flex-wrap:wrap}.stat-num{font-size:var(--fs-700)}.hero-ctas{flex-wrap:wrap}.hcta,.hcta.engine{width:100%;justify-content:center}}.promo-art{container-type:inline-size}@container (max-width:300px){.promo-art .pa-cap{padding:.8rem .6rem .55rem !important;font-size:var(--fs-100) !important;line-height:1.25 !important;display:-webkit-box !important;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden !important}.promo-art .pa-cap small{font-size:.7rem !important;line-height:1.3 !important;margin-top:2px;display:-webkit-box !important;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.promo-art .pa-ribbon{font-size:.66rem;padding:.2rem .45rem}}@supports not (container-type:inline-size){@media (max-width:640px){.promo-art .pa-cap{padding:.8rem .6rem .55rem;font-size:var(--fs-100);line-height:1.25}.promo-art .pa-cap small{font-size:.7rem}}}@media (min-width:901px){.pricing-grid{align-items:stretch}}p a,li a,small a,td a,dd a,.muted a,.auth-legal a,.sub-detail a,.hero-price-line a,.footer a,.site-footer a,footer a,.hero-detail a,.ptier .tier-value strong,.tier-value strong,.cmp-table strong,.plan-note strong,.vs-singles strong,.meta-cat,.read-more,.section-link,.hero-eyebrow,.post-topbar-links a,.crumbs a,.auth-card a:not(.btn):not(.btn-primary):not(.plan-btn),a[style*="--accent"]{color:#818cf8 !important}@media (max-width:700px){.hero-stats{display:flex !important;flex-direction:row !important;flex-wrap:nowrap !important;gap:1rem !important;justify-content:space-between !important;width:100%}.hero-stats .stat{flex:1 1 0;min-width:0;align-items:center}.hero-stats .stat-num{font-size:1.4rem !important;line-height:1.1}.hero-stats .stat-label{font-size:.68rem !important;letter-spacing:.06em;text-align:center}.hero .hero-text{display:flex;flex-direction:column}.hero .hero-badge{order:1}.hero .hero-text h1{order:2}.hero .hero-lead{order:3}.hero .hero-ctas{order:4;margin-top:1.1rem}.hero .hero-stats{order:5;margin-top:1.2rem}.launch-banner{font-size:.8rem !important;line-height:1.35 !important;padding:9px 40px 9px 12px !important}.hero-ctas .hcta{flex-direction:column !important;align-items:center !important;gap:2px !important;width:100%;text-align:center;padding:12px 18px !important}.hero-ctas .hcta small{font-size:.74rem;opacity:.82}.hero-ctas .hcta.gold small{color:rgba(18,16,10,.75)}}@media (prefers-reduced-transparency:reduce){.stage-chip,.mnav-panel,.search-bar,.glass,[class*="glass"]{backdrop-filter:none !important;background:#14141e !important}}
/* <<< END responsive-polish */
