/* ==========================================================================
   Harashsuq - "neo-souq" design system
   A trading floor rendered as circuitry: obsidian ground, neon violet and
   cyan for the machine, brass gold for the market. Depth comes from a live
   3D canvas behind everything and glass panels floating above it.
   ========================================================================== */

@layer tokens, base, layout, components, motion, utilities;

/* ------------------------------------------------------------------ */
@layer tokens {

:root {
  /* Spectrum */
  --violet-300: #c4b5fd;
  --violet-400: #a78bfa;
  --violet-500: #8b5cf6;
  --violet-600: #7c3aed;
  /* Light-theme link hover only - one step darker than violet-600, so hovering
     still visibly deepens the colour rather than repeating the resting state. */
  --violet-700: #6d28d9;
  --cyan-300:   #67e8f9;
  --cyan-400:   #22d3ee;
  --cyan-500:   #06b6d4;
  --gold-300:   #fcd34d;
  --gold-400:   #fbbf24;
  --gold-500:   #f59e0b;
  --rose-400:   #fb7185;
  --mint-400:   #34d399;

  /* Ground */
  --bg:            #05060c;
  --bg-sunken:     #03040a;
  --bg-elevated:   #0b0d18;
  --surface:       rgba(20, 23, 40, 0.62);
  --surface-solid: #141728;
  --surface-hover: rgba(32, 36, 60, 0.78);
  --border:        rgba(140, 152, 200, 0.14);
  --border-strong: rgba(150, 162, 215, 0.30);

  --text:        #eef0fa;
  --text-muted:  #9aa3c4;
  /* #6a7398 measured 4.36:1 on --bg - just under the 4.5:1 AA floor for the
     small (.tiny/.small) text this is actually used at. Lightened slightly. */
  --text-subtle: #7580a8;

  --accent:          var(--violet-500);
  --accent-hover:    var(--violet-400);
  --accent-contrast: #ffffff;
  --accent-soft:     rgba(139, 92, 246, 0.16);
  --accent-ring:     rgba(139, 92, 246, 0.55);
  --accent-2:        var(--cyan-400);
  --accent-3:        var(--gold-400);

  --success: var(--mint-400);
  --warning: var(--gold-400);
  --danger:  var(--rose-400);
  --info:    var(--cyan-400);

  /* Signature gradients */
  --grad-primary: linear-gradient(135deg, var(--violet-500) 0%, var(--cyan-400) 100%);
  --grad-gold:    linear-gradient(135deg, var(--gold-400) 0%, var(--rose-400) 100%);
  --grad-text:    linear-gradient(100deg, #fff 0%, var(--violet-300) 40%, var(--cyan-300) 70%, #fff 100%);
  /* Text over --grad-primary. Fixed regardless of theme, like the gradient
     itself: white measured as low as 1.81:1 at the gradient's cyan end, and
     darkening the gradient to fit white text would have meant a duller button
     across the whole site. Dark text keeps the gradient exactly as bright as
     it was - #05060c against violet-500 is 4.78:1, against cyan-400 11.2:1. */
  --on-gradient: #05060c;

  /* Glow */
  --glow-accent: 0 0 0 1px rgba(139, 92, 246, 0.35), 0 8px 32px -8px rgba(139, 92, 246, 0.55);
  --glow-cyan:   0 0 0 1px rgba(34, 211, 238, 0.32), 0 8px 30px -10px rgba(34, 211, 238, 0.5);
  --glow-gold:   0 0 0 1px rgba(251, 191, 36, 0.34), 0 8px 30px -10px rgba(251, 191, 36, 0.45);

  --radius-sm: 8px;
  --radius:    12px;
  --radius-lg: 18px;
  --radius-xl: 26px;

  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 72px;

  /* The ink the shadows are cast in, so depth shadows can follow the theme. */
  --shadow-rgb: 0 0 0;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow:    0 10px 30px -12px rgba(0, 0, 0, 0.75);
  --shadow-lg: 0 30px 70px -20px rgba(0, 0, 0, 0.85);

  --glass-blur: 16px;

  --font: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --header-h: 68px;
  --max-w: 1280px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --transition: 200ms var(--ease);

  /* Scrollbars and native controls follow the theme, not the OS. */
  color-scheme: dark;
}

[data-theme="light"] {
  color-scheme: light;

  --bg:            #f4f5fb;
  --bg-sunken:     #eaecf6;
  --bg-elevated:   #ffffff;
  --surface:       rgba(255, 255, 255, 0.78);
  --surface-solid: #ffffff;
  --surface-hover: rgba(255, 255, 255, 0.95);
  --border:        rgba(30, 40, 90, 0.12);
  --border-strong: rgba(30, 40, 90, 0.24);

  --text:        #10121f;
  --text-muted:  #4d5573;
  /* #78809e measured 3.59:1 on this theme's --bg - under the 4.5:1 floor for
     the small (.tiny/.small) text this is actually used at. Darkened. */
  --text-subtle: #606a90;

  /* Default link colour, despite the name (see `a { color: var(--accent-hover) }`
     in the base layer). violet-500 measured 3.89:1 here - under 4.5:1 for
     normal text - so the default state uses violet-600 (5.24:1) instead, and
     the hover state below moves one step darker again, to violet-700, so
     hovering still visibly changes the colour rather than repeating it. */
  --accent:       var(--violet-600);
  --accent-hover: var(--violet-600);
  --accent-soft:  rgba(124, 58, 237, 0.10);

  --success: #059669;
  --warning: #b45309;
  --danger:  #e11d48;
  --info:    #0891b2;

  --grad-text: linear-gradient(100deg, #10121f 0%, var(--violet-600) 45%, var(--cyan-500) 75%, #10121f 100%);
  /* gold-400/rose-400 (the dark-theme stops) measured 1.67:1 and 2.69:1 on
     this theme's white --bg-elevated - both far under 4.5:1. Reuses this
     theme's own --warning/--danger tokens, which were already dark enough:
     5.02:1 and 4.70:1 respectively, checked at the gradient's midpoint too
     (5.09:1) since it is read as continuous gradient-clipped text. */
  --grad-gold: linear-gradient(135deg, var(--warning) 0%, var(--danger) 100%);

  --shadow-rgb: 16 24 60;
  --shadow:    0 10px 30px -14px rgba(16, 24, 60, 0.28);
  --shadow-lg: 0 30px 60px -24px rgba(16, 24, 60, 0.35);
  --glass-blur: 12px;
}

}

/* ------------------------------------------------------------------ */
@layer base {

*, *::before, *::after { box-sizing: border-box; }
/* scroll-padding-top keeps a #fragment target (such as #reviews) out from under
   the sticky header when the page scrolls to it. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: calc(var(--header-h) + var(--space-4)); }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* The live 3D field. Sits behind everything, never intercepts input. */
#bg-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  opacity: 0.9;
}

/* Warm haze so the canvas reads as atmosphere rather than decoration. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(900px 600px at 12% -5%,  rgba(139, 92, 246, 0.16), transparent 65%),
    radial-gradient(800px 500px at 92% 10%,  rgba(34, 211, 238, 0.11),  transparent 65%),
    radial-gradient(700px 500px at 60% 100%, rgba(251, 191, 36, 0.07),  transparent 65%);
}
[data-theme="light"] body::before {
  background:
    radial-gradient(900px 600px at 12% -5%,  rgba(139, 92, 246, 0.14), transparent 65%),
    radial-gradient(800px 500px at 92% 10%,  rgba(34, 211, 238, 0.12), transparent 65%);
}

.site-header, .site-main, .site-footer { position: relative; z-index: 1; }

h1, h2, h3, h4 {
  margin: 0 0 var(--space-3);
  line-height: 1.18;
  font-weight: 680;
  letter-spacing: -0.03em;
}
h1 { font-size: clamp(1.9rem, 1.2rem + 2.6vw, 3.1rem); }
h2 { font-size: clamp(1.35rem, 1.1rem + 1.1vw, 1.85rem); }
h3 { font-size: 1.12rem; }
p  { margin: 0 0 var(--space-3); }

a { color: var(--accent-hover); text-decoration: none; transition: color var(--transition); }
a:hover { color: var(--cyan-300); }
[data-theme="light"] a:hover { color: var(--violet-700); }

img, svg { max-width: 100%; }

:focus-visible {
  outline: 2px solid var(--accent-ring);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

::selection { background: var(--accent-soft); color: var(--text); }

::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--bg-sunken); }
::-webkit-scrollbar-thumb {
  background: linear-gradient(var(--violet-600), var(--cyan-500));
  border-radius: 99px;
  border: 3px solid var(--bg-sunken);
}

/* Present to a screen reader, absent to everyone else.
 *
 * The clip-rect dance rather than display:none or visibility:hidden, both of
 * which remove the element from the accessibility tree too - which would make
 * a live region announce nothing at all. Not width/height 0 either: some
 * engines skip a zero-sized element's text.
 *
 * white-space: nowrap stops a long string collapsing into a 1px column and
 * being reported line by line. */
.visually-hidden {
  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;
  border: 0;
}

/* #main carries tabindex="-1" so a route change can move focus into it, which
   is how a screen reader is told the page changed. That focus is programmatic
   and the ring would appear for a mouse user who clicked a link, so it is
   suppressed here - the skip link and every real control keep theirs. */
.site-main:focus { outline: none; }
.site-main:focus-visible { outline: none; }

.skip-link {
  position: absolute; inset-inline-start: -9999px; top: 0; z-index: 100;
  background: var(--accent); color: #fff;
  padding: var(--space-3) var(--space-4); border-end-end-radius: var(--radius);
}
.skip-link:focus { inset-inline-start: 0; }

.noscript-notice {
  position: fixed; inset: 0; display: grid; place-items: center;
  background: var(--bg); color: var(--text); font-size: 1.1rem; padding: var(--space-6);
}

}

/* ------------------------------------------------------------------ */
@layer layout {

.site-main { flex: 1; width: 100%; }

.container {
  width: 100%;
  max-width: var(--max-w);
  margin-inline: auto;
  padding-inline: var(--space-5);
}
@media (max-width: 640px) { .container { padding-inline: var(--space-4); } }

.section { padding-block: var(--space-8); }
.section-tight { padding-block: var(--space-6); }

.stack    { display: flex; flex-direction: column; gap: var(--space-4); }
.row      { display: flex; align-items: center; gap: var(--space-3); }
.row-wrap { flex-wrap: wrap; }
.spread   { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); }
.grow     { flex: 1; min-width: 0; }

.grid { display: grid; gap: var(--space-4); }
.grid-assets { grid-template-columns: repeat(auto-fill, minmax(276px, 1fr)); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }

.split-sidebar { display: grid; grid-template-columns: 268px 1fr; gap: var(--space-6); align-items: start; }
@media (max-width: 900px) { .split-sidebar { grid-template-columns: 1fr; } }

.detail-layout { display: grid; grid-template-columns: minmax(0, 1fr) 350px; gap: var(--space-6); align-items: start; }
@media (max-width: 940px) { .detail-layout { grid-template-columns: 1fr; } }

.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-4); margin-bottom: var(--space-5);
}
.section-head h2 { margin: 0; }

}

/* ------------------------------------------------------------------ */
@layer components {

/* ---------- Header ---------- */

.site-header {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(var(--glass-blur)) saturate(150%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(150%);
  border-bottom: 1px solid var(--border);
}
/* Hairline of light along the header edge. */
.site-header::after {
  content: '';
  position: absolute; inset-inline: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg, transparent, var(--violet-500), var(--cyan-400), transparent);
  opacity: 0.55;
}

.header-inner {
  height: var(--header-h);
  display: flex; align-items: center; gap: var(--space-4);
  max-width: var(--max-w); margin-inline: auto; padding-inline: var(--space-5);
}
@media (max-width: 640px) { .header-inner { padding-inline: var(--space-4); gap: var(--space-2); } }

.brand {
  display: inline-flex; align-items: center; gap: var(--space-3);
  font-weight: 750; font-size: 1.08rem; color: var(--text);
  letter-spacing: -0.035em; flex-shrink: 0;
}
.brand:hover { color: var(--text); }

.brand-mark {
  position: relative;
  width: 36px; height: 36px; flex-shrink: 0;
  display: grid; place-items: center;
  font-weight: 800; font-size: 16px; color: #fff;
  background: var(--grad-primary);
  /* Octagram silhouette - the khatam star of a souq lattice. */
  clip-path: polygon(50% 0%, 65% 18%, 88% 12%, 82% 35%, 100% 50%, 82% 65%, 88% 88%,
                     65% 82%, 50% 100%, 35% 82%, 12% 88%, 18% 65%, 0% 50%, 18% 35%, 12% 12%, 35% 18%);
  box-shadow: 0 0 22px -4px rgba(139, 92, 246, 0.85);
  animation: markSpin 18s linear infinite;
}
@keyframes markSpin {
  from { filter: hue-rotate(0deg); }
  to   { filter: hue-rotate(360deg); }
}

.brand-text {
  white-space: nowrap;
  background: var(--grad-text);
  background-size: 220% 100%;
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  animation: sheen 7s linear infinite;
}
@keyframes sheen {
  to { background-position: -220% 0; }
}
@media (max-width: 520px) { .brand-text { display: none; } }

.header-search { flex: 1; max-width: 480px; position: relative; }
.header-search input { padding-inline-start: 40px; }
.header-search .search-icon {
  position: absolute; inset-inline-start: 13px; top: 50%; transform: translateY(-50%);
  color: var(--text-subtle); pointer-events: none; display: flex;
  transition: color var(--transition);
}
.header-search:focus-within .search-icon { color: var(--accent-hover); }

.header-nav { display: flex; align-items: center; gap: var(--space-1); margin-inline-start: auto; }

.nav-link {
  position: relative;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  color: var(--text-muted); font-weight: 550; font-size: 0.9rem; white-space: nowrap;
}
.nav-link::after {
  content: '';
  position: absolute; left: 50%; bottom: 4px;
  width: 0; height: 2px; border-radius: 2px;
  background: var(--grad-primary);
  transform: translateX(-50%);
  transition: width var(--transition);
}
.nav-link:hover { color: var(--text); }
.nav-link:hover::after, .nav-link.active::after { width: 56%; }
.nav-link.active { color: var(--text); }
@media (max-width: 860px) { .nav-link.hide-sm { display: none; } }

/* ---------- Mobile navigation drawer ---------- */

/* The mirror of .hide-sm: shown only where the links it replaces are hidden.
   Same 860px breakpoint, deliberately - one of the two is always present and
   there is no width at which both or neither appear. */
.show-sm { display: none; }
@media (max-width: 860px) { .show-sm { display: revert; } }

.drawer { position: relative; }
/* A <details> marker is a triangle in every engine and a different one in
   each. The icon is the affordance. */
.drawer__toggle { list-style: none; }
.drawer__toggle::-webkit-details-marker { display: none; }
.drawer__toggle {
  display: inline-grid; place-items: center;
  width: 40px; height: 40px; border-radius: var(--radius);
  color: var(--text-muted); cursor: pointer;
  border: 1px solid transparent; transition: var(--transition);
}
.drawer__toggle:hover { background: var(--surface-hover); color: var(--text); border-color: var(--border); }
.drawer[open] .drawer__toggle { background: var(--accent-soft); color: var(--text); border-color: var(--border); }

/* inset-inline-end rather than right: this panel is one of the few places
   the RTL work would otherwise have to come back and fix, and the logical
   property costs nothing today. */
.drawer__panel {
  position: absolute; inset-inline-end: 0; top: calc(100% + 10px);
  min-width: 232px; z-index: 60;
  display: flex; flex-direction: column;
  /* Opaque, unlike the avatar menu it is otherwise styled after.
     That one opens over page content and the translucency reads as depth.
     This one opens over the hero, whose animated canvas shows straight
     through a glass panel and turns the navigation into unreadable text on
     top of unreadable text - and it is the ONLY navigation a phone has, so it
     is the last thing in the interface that should be hard to read. The blur
     stays for where it does land. */
  background: var(--bg-elevated);
  backdrop-filter: blur(var(--glass-blur)) saturate(160%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(160%);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  padding: var(--space-2);
  animation: menuIn 200ms var(--ease);
}
.drawer__link {
  padding: 10px var(--space-3); border-radius: var(--radius);
  color: var(--text); font-size: 0.94rem; font-weight: 550; white-space: nowrap;
}
.drawer__link:hover { background: var(--accent-soft); color: var(--text); }
@media (prefers-reduced-motion: reduce) { .drawer__panel { animation: none; } }

.icon-btn {
  position: relative; display: inline-grid; place-items: center;
  width: 40px; height: 40px; border-radius: var(--radius);
  background: transparent; border: 1px solid transparent; color: var(--text-muted);
  cursor: pointer; transition: var(--transition);
}
.icon-btn:hover {
  background: var(--surface-hover); color: var(--text);
  border-color: var(--border); transform: translateY(-1px);
}

.badge-count {
  position: absolute; top: 1px; inset-inline-end: 1px; min-width: 18px; height: 18px;
  padding: 0 5px; border-radius: 9px;
  background: var(--grad-gold); color: #2a1a02;
  font-size: 10px; font-weight: 800; display: grid; place-items: center;
  border: 2px solid var(--bg); line-height: 1;
  box-shadow: 0 0 12px -2px var(--gold-400);
}

/* ---------- Avatar & menu ---------- */

.avatar {
  border-radius: 30%; display: grid; place-items: center; flex-shrink: 0;
  font-weight: 700; color: #fff; letter-spacing: -0.02em;
  background: linear-gradient(140deg, hsl(var(--hue, 260) 85% 62%), hsl(calc(var(--hue, 260) + 55) 80% 48%));
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 4px 14px -6px hsl(var(--hue, 260) 85% 50%);
}
.avatar-sm { width: 30px; height: 30px; font-size: 11px; }
.avatar-md { width: 40px; height: 40px; font-size: 14px; }
.avatar-lg { width: 78px; height: 78px; font-size: 27px; border-radius: 26%; }

.menu-wrap { position: relative; }
.menu {
  position: absolute; inset-inline-end: 0; top: calc(100% + 10px); min-width: 244px; z-index: 50;
  background: color-mix(in srgb, var(--bg-elevated) 88%, transparent);
  backdrop-filter: blur(var(--glass-blur)) saturate(160%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(160%);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  padding: var(--space-2);
  transform-origin: top right;
  animation: menuIn 220ms var(--ease);
}
@keyframes menuIn {
  from { opacity: 0; transform: translateY(-8px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}

.menu-item {
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  padding: 9px var(--space-3); border-radius: var(--radius);
  color: var(--text); background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 0.9rem; text-align: start;
  transition: var(--transition);
}
.menu-item:hover {
  background: var(--accent-soft); color: var(--text);
  transform: translateX(3px);
}
.menu-item.danger { color: var(--danger); }
.menu-header { padding: var(--space-3); border-bottom: 1px solid var(--border); margin-bottom: var(--space-2); }
.menu-sep { height: 1px; background: var(--border); margin: var(--space-2) 0; }

/* ---------- Buttons ---------- */

.btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  padding: 10px var(--space-4); border-radius: var(--radius);
  font: inherit; font-size: 0.9rem; font-weight: 640; line-height: 1.2;
  border: 1px solid transparent; cursor: pointer; white-space: nowrap;
  text-decoration: none; overflow: hidden;
  transition: transform var(--transition), box-shadow var(--transition),
              background var(--transition), border-color var(--transition), color var(--transition);
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn:not(:disabled):hover { transform: translateY(-2px); }
.btn:not(:disabled):active { transform: translateY(0); }

/* Light sweeps across on hover. */
.btn::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 20%, rgba(255, 255, 255, 0.26) 50%, transparent 80%);
  transform: translateX(-120%);
  transition: transform 620ms var(--ease);
}
.btn:not(:disabled):hover::before { transform: translateX(120%); }

.btn-primary {
  background: var(--grad-primary); color: var(--on-gradient);
  box-shadow: 0 6px 22px -10px rgba(139, 92, 246, 0.9);
}
.btn-primary:not(:disabled):hover { box-shadow: 0 12px 30px -10px rgba(139, 92, 246, 1); color: var(--on-gradient); }

.btn-secondary {
  background: var(--surface); color: var(--text); border-color: var(--border-strong);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.btn-secondary:not(:disabled):hover { border-color: var(--accent); color: var(--text); box-shadow: var(--glow-accent); }

.btn-ghost { background: transparent; color: var(--text-muted); }
.btn-ghost:not(:disabled):hover { background: var(--surface-hover); color: var(--text); }

.btn-danger { background: transparent; color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.btn-danger:not(:disabled):hover {
  background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger);
  box-shadow: 0 6px 22px -10px var(--danger);
}

/*
 * Sign in with Google. Google's branding terms require their own mark on a
 * plain white or plain dark surface, so this one button opts out of the
 * gradient treatment the others share - including the hover sweep, which would
 * wash over the four-colour mark.
 */
/* Dark is the default here, as everywhere else in this file. */
.btn-google {
  background: #131314; color: #e3e3e3; border-color: #8e918f;
  font-weight: 600;
}
.btn-google::before { content: none; }
.btn-google:not(:disabled):hover { background: #1e1f20; border-color: #a2a6a4; color: #e3e3e3; }
.btn-google .google-mark { flex: none; }
[data-theme="light"] .btn-google { background: #fff; color: #1f1f1f; border-color: #dadce0; }
[data-theme="light"] .btn-google:not(:disabled):hover { background: #f7f8f8; border-color: #d2d5d9; color: #1f1f1f; }

/*
 * Sign in with Apple. Apple's guidelines are stricter than Google's: black on
 * light, white on dark, the mark in the same colour as the label, and nothing
 * layered over either - so this button opts out of the sweep for the same
 * reason the Google one does.
 */
.btn-apple {
  background: #fff; color: #000; border-color: #fff;
  font-weight: 600;
}
.btn-apple::before { content: none; }
.btn-apple:not(:disabled):hover { background: #e6e6e6; border-color: #e6e6e6; color: #000; }
/* The mark is a silhouette, so it takes the label's colour in both themes. */
.btn-apple .apple-mark { flex: none; fill: currentColor; }
[data-theme="light"] .btn-apple { background: #000; color: #fff; border-color: #000; }
[data-theme="light"] .btn-apple:not(:disabled):hover { background: #1a1a1a; border-color: #1a1a1a; color: #fff; }

/* Stacked provider buttons share one gap, then one rule down to the form. */
.auth-providers { display: grid; gap: var(--space-3); }

/* "or" rule between the provider buttons and the email form. */
.auth-divider {
  display: flex; align-items: center; gap: var(--space-3);
  margin: var(--space-4) 0;
  color: var(--text-subtle); font-size: 0.8rem;
}
.auth-divider::before, .auth-divider::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}

/* ---------- The lamp over sign-in and sign-up ----------

   Opt-in rather than built into authShell: pages/account.js asks for it on
   /login and /register only, so the screens an emailed link lands on - reset,
   verify, welcome, support, wallet-confirm - stay plain. Someone following a
   password-reset link is mid-errand, not arriving.

   Three layers sit behind the card: the haze where the light source would be,
   the cone itself, and the lit seam the cone leaves along the top edge. All of
   it is decorative, so the wrapper is aria-hidden and none of it is focusable.

   Deliberately its own box rather than a pseudo-element on .card: ::before
   there is already the top-edge light and .depth::before is the pointer
   highlight, so both are spoken for.

   Every colour is mixed from a token that already exists, so the theme stays
   the single source and test/contrast.test.js has no new value to parse.

   Centred with inset-inline plus margin-inline:auto rather than a translateX,
   so it needs no [dir="rtl"] counterpart - a centred cone is the same cone in
   either direction.

   The reduced-motion block near the end of this file flattens every animation
   to 0.01ms, and all three layers animate `forwards`, so anyone asking for less
   motion gets the lamp already lit and completely still - never an unlit page,
   which is what `animation: none` would have left behind. */

.auth-stage {
  position: relative;
  /* Headroom for the cone above the card. Floors at 48px on a short phone and
     stops growing at 132px, so the card is never pushed off a laptop screen. */
  padding-block-start: clamp(var(--space-7), 14vh, 152px);
}

.auth-lamp {
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 300px;
  /* Behind the card, in front of the canvas. .auth-stage is positioned but sets
     no z-index, so this stays inside .site-main's stacking context - which also
     leaves the card's backdrop-filter the lamp to blur. */
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  /* How bright the lamp settles. The light theme is ink on paper - the same call
     background.js makes for the canvas - so the cone is held well back there
     rather than bleaching the page. */
  --lamp-lit: 1;
}
[data-theme="light"] .auth-lamp { --lamp-lit: 0.42; }

.auth-lamp__haze, .auth-lamp__cone, .auth-lamp__seam {
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  margin-inline: auto;
}

/* The source itself, most of it clipped away above the top edge. */
.auth-lamp__haze {
  width: min(330px, 70vw); height: 128px;
  margin-block-start: -64px;
  border-radius: 50%;
  background: radial-gradient(closest-side,
    color-mix(in srgb, var(--accent-2) 46%, transparent),
    color-mix(in srgb, var(--accent) 18%, transparent),
    transparent);
  filter: blur(18px);
  opacity: 0;
  transform: scaleX(0.4);
  animation: lampOn 900ms 120ms var(--ease) forwards;
}

.auth-lamp__cone {
  width: min(760px, 96vw); height: 340px;
  /* A conic wedge, not a clipped triangle. clip-path is applied after filter,
     so blurring a triangle still leaves hard diagonal edges and a flat top -
     a cut-out rather than a beam. Angles run clockwise from straight up, which
     puts the centre line of the beam at 180deg. */
  background: conic-gradient(from 0deg at 50% 0%,
    transparent 118deg,
    color-mix(in srgb, var(--accent) 20%, transparent) 140deg,
    color-mix(in srgb, var(--accent) 52%, transparent) 164deg,
    color-mix(in srgb, var(--accent-2) 78%, transparent) 180deg,
    color-mix(in srgb, var(--accent) 52%, transparent) 196deg,
    color-mix(in srgb, var(--accent) 20%, transparent) 220deg,
    transparent 242deg);
  /* Light falls off with distance. The wedge alone would reach the bottom edge
     at full strength and read as a painted shape rather than a beam. It has to
     carry over the 3D canvas, which is busiest exactly where the cone lands, so
     the core stays strong well past halfway before it goes. */
  -webkit-mask-image: linear-gradient(to bottom, #000, rgba(0, 0, 0, 0.55) 48%, transparent 86%);
  mask-image: linear-gradient(to bottom, #000, rgba(0, 0, 0, 0.55) 48%, transparent 86%);
  filter: blur(14px);
  opacity: 0;
  transform: scaleX(0.3);
  animation: lampOn 900ms 120ms var(--ease) forwards;
}

.auth-lamp__seam {
  width: min(480px, 76vw); height: 2px;
  background: linear-gradient(90deg, transparent,
    var(--accent) 22%, var(--accent-2) 50%, var(--accent) 78%, transparent);
  transform: scaleX(0);
  animation: lampSeam 820ms var(--ease) forwards;
}

@keyframes lampOn   { to { opacity: var(--lamp-lit); transform: scaleX(1); } }
@keyframes lampSeam { to { transform: scaleX(1); } }

.btn-lg { padding: 13px var(--space-5); font-size: 1rem; border-radius: var(--radius-lg); }
.btn-sm { padding: 6px var(--space-3); font-size: 0.82rem; }
.btn-block { width: 100%; }

.btn-spinner {
  width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0;
  border: 2px solid currentColor; border-top-color: transparent;
  animation: spin 0.6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Forms ---------- */

.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--space-4); }
.field-label { font-size: 0.85rem; font-weight: 640; color: var(--text); }
.field-hint  { font-size: 0.8rem; color: var(--text-subtle); }
.field-error { font-size: 0.8rem; color: var(--danger); }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
@media (max-width: 560px) { .field-row { grid-template-columns: 1fr; } }

input[type="text"], input[type="email"], input[type="password"], input[type="search"],
input[type="number"], textarea, select {
  width: 100%; padding: 11px var(--space-3);
  background: color-mix(in srgb, var(--bg-sunken) 70%, transparent);
  color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  font: inherit; font-size: 0.9rem;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  transition: border-color var(--transition), box-shadow var(--transition), background var(--transition);
}
textarea { resize: vertical; min-height: 110px; line-height: 1.65; }
select {
  cursor: pointer; appearance: none; padding-inline-end: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239aa3c4' stroke-width='3'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 13px center;
}

input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft), 0 0 22px -8px var(--accent);
}
input::placeholder, textarea::placeholder { color: var(--text-subtle); }
input[aria-invalid="true"], textarea[aria-invalid="true"] { border-color: var(--danger); }

.checkbox { display: flex; align-items: flex-start; gap: var(--space-3); cursor: pointer; font-size: 0.9rem; }
.checkbox input { width: 17px; height: 17px; margin-top: 3px; accent-color: var(--accent); flex-shrink: 0; }

.input-prefix { position: relative; }
.input-prefix span {
  position: absolute; inset-inline-start: 13px; top: 50%; transform: translateY(-50%);
  color: var(--text-subtle); font-size: 0.9rem; pointer-events: none;
}
.input-prefix input { padding-inline-start: 27px; }

.dropzone {
  position: relative;
  border: 1.5px dashed var(--border-strong); border-radius: var(--radius-lg);
  padding: var(--space-7) var(--space-5); text-align: center; cursor: pointer;
  background: color-mix(in srgb, var(--bg-sunken) 55%, transparent);
  transition: var(--transition);
}
.dropzone:hover, .dropzone.dragging {
  border-color: var(--accent); background: var(--accent-soft);
  box-shadow: var(--glow-accent); transform: translateY(-2px);
}
.dropzone input { display: none; }
.dropzone-file { display: flex; align-items: center; gap: var(--space-3); text-align: start; }

/* A large file going up in parts, on the Sell page. */
.upload-progress { margin-bottom: var(--space-5); }
.upload-progress__bar {
  height: 8px; border-radius: 999px; overflow: hidden;
  background: color-mix(in srgb, var(--bg-sunken) 70%, transparent);
  border: 1px solid var(--border);
}
.upload-progress__bar span {
  display: block; height: 100%; width: 0;
  background: var(--grad-primary);
  transition: width 0.3s ease;
}
@media (prefers-reduced-motion: reduce) { .upload-progress__bar span { transition: none; } }

/* One release in the version history. */
.version-row { padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.version-row:last-child { border-bottom: 0; }
.version-row__head {
  display: flex; align-items: center; gap: var(--space-3);
  flex-wrap: wrap; margin-bottom: 4px;
}

/* The cover a listing already has, in the replace dialog. */
.cover-current {
  width: 100%; max-width: 320px; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: var(--radius); border: 1px solid var(--border); display: block;
}

/* A value in a form that is shown but not edited. Styled like an input so the
   row does not go ragged, but plainly not one - no border highlight, no caret,
   muted text. */
.input-static {
  padding: 10px var(--space-3);
  border: 1px dashed var(--border); border-radius: var(--radius);
  background: var(--surface); color: var(--text-muted);
  font-size: 0.94rem; min-height: 42px; display: flex; align-items: center;
}

/* The chosen cover, at card proportions so the seller sees the crop the grid
   will apply rather than the shape of their file. */
.cover-preview {
  width: 96px; height: 54px; flex-shrink: 0;
  object-fit: cover; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--surface);
}

.tag-input {
  display: flex; flex-wrap: wrap; gap: 6px; padding: 8px;
  background: color-mix(in srgb, var(--bg-sunken) 70%, transparent);
  border: 1px solid var(--border-strong); border-radius: var(--radius);
}
.tag-input:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.tag-input input { border: 0; background: none; padding: 3px; flex: 1; min-width: 120px; box-shadow: none !important; }

.tag-chip {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px;
  background: var(--accent-soft); color: var(--violet-300);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  border-radius: var(--radius-sm); font-size: 0.8rem; font-weight: 550;
}
[data-theme="light"] .tag-chip { color: var(--violet-600); }
.tag-chip button { background: none; border: 0; color: inherit; cursor: pointer; padding: 0; line-height: 1; font-size: 15px; }

/* ---------- Glass surfaces ---------- */

.card, .panel {
  position: relative;
  background: var(--surface);
  backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.card { padding: var(--space-5); }
.card-tight { padding: var(--space-4); }
.card-flush { padding: 0; overflow: hidden; }
.panel { overflow: hidden; }

/* Top-edge light on every glass surface. */
.card::before, .panel::before {
  content: '';
  position: absolute; top: 0; inset-inline: 12%; height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-strong), transparent);
}

.panel-head {
  padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
}
.panel-body { padding: var(--space-5); }
.panel-body-flush { padding: 0; }

/* ---------- Asset card ---------- */

/* A glass card with a border lit in its category's hue, and a cover drawn as a
   small code editor: illustration for the category, never the listing's own
   file - see CATEGORY_ART in components.js. The cover stays dark in both
   themes, as an editor does. */
.asset-card {
  --accent: hsl(var(--hue, 260) 85% 64%);
  position: relative;
  display: flex; flex-direction: column;
  border: 1px solid transparent;
  border-radius: 20px; overflow: hidden;
  background:
    linear-gradient(var(--surface), var(--surface)) padding-box,
    linear-gradient(160deg, hsl(var(--hue, 260) 80% 65% / 0.45), var(--border) 40%, hsl(var(--hue, 260) 80% 65% / 0.25)) border-box;
  backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  box-shadow: 0 26px 60px -32px rgb(var(--shadow-rgb) / 0.8);
  transform-style: preserve-3d;
  transition: transform 260ms var(--ease), box-shadow 260ms var(--ease);
}
[data-theme="light"] .asset-card {
  --accent: hsl(var(--hue, 260) 70% 46%);
  background:
    linear-gradient(var(--surface-solid), var(--surface-solid)) padding-box,
    linear-gradient(160deg, hsl(var(--hue, 260) 75% 55% / 0.45), var(--border) 40%, hsl(var(--hue, 260) 75% 55% / 0.25)) border-box;
}
.asset-card:hover {
  box-shadow: 0 26px 60px -30px rgb(var(--shadow-rgb) / 0.8), 0 0 0 1px hsl(var(--hue, 260) 90% 65% / 0.5),
              0 24px 60px -22px hsl(var(--hue, 260) 90% 55% / 0.55);
}

.asset-card__thumb {
  height: 176px; position: relative; display: grid; place-items: center;
  color: #fff;
  background:
    radial-gradient(260px 160px at 85% 10%, hsl(var(--hue, 260) 90% 55% / 0.55), transparent 70%),
    radial-gradient(240px 160px at 0% 100%, hsl(calc(var(--hue, 260) + 50) 90% 50% / 0.35), transparent 70%),
    hsl(var(--hue, 260) 45% 9%);
  overflow: hidden;
}
[data-theme="light"] .asset-card__thumb {
  background:
    radial-gradient(260px 160px at 85% 10%, hsl(var(--hue, 260) 90% 60% / 0.55), transparent 70%),
    radial-gradient(240px 160px at 0% 100%, hsl(calc(var(--hue, 260) + 50) 90% 55% / 0.35), transparent 70%),
    hsl(var(--hue, 260) 40% 15%);
}
.asset-card > .asset-card__thumb { margin: 8px 8px 0; border-radius: 14px; }
/* A dot lattice and faint scan lines over the cover. */
.asset-card__thumb::after {
  content: '';
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    radial-gradient(rgb(255 255 255 / 0.12) 1px, transparent 1.2px),
    repeating-linear-gradient(0deg, rgb(255 255 255 / 0.025) 0 1px, transparent 1px 3px);
  background-size: 14px 14px, auto;
  mask-image: linear-gradient(180deg, #000, transparent 90%);
}
/* A listing's own cover, when it has one. z-index sits it above the lattice
   ::after overlay, which is texture for the generated cover and noise on top
   of somebody's actual artwork. object-fit crops rather than distorts:
   uploads are not going to arrive at 16:9 and a squashed screenshot looks
   worse than a cropped one. */
.asset-card__image {
  position: relative; z-index: 1;
  width: 100%; height: 100%; object-fit: cover; display: block;
}

.asset-card__glyph {
  position: absolute; z-index: 1; right: -14px; bottom: -18px;
  width: 118px; height: 118px;
  color: hsl(var(--hue, 260) 95% 75% / 0.35);
  filter: drop-shadow(0 0 18px hsl(var(--hue, 260) 95% 60% / 0.7));
  transition: transform 400ms var(--ease);
}
.asset-card__glyph svg { width: 100%; height: 100%; }
.asset-card:hover .asset-card__glyph { transform: translateY(-4px) scale(1.06) rotate(-4deg); }

.asset-card__code {
  position: absolute; z-index: 1; left: 14px; right: 14px; top: 42px;
  display: flex; flex-direction: column;
  font: 0.75rem/1.7 var(--font-mono); color: #d9ddf8; text-align: left;
}
.asset-card__code .code-k { color: hsl(var(--hue, 260) 95% 80%); }
.asset-card__code .code-s { color: #86efac; }
.asset-card__code .code-c { color: rgb(217 221 248 / 0.45); }
.asset-card__diagram { width: 210px; max-width: 100%; height: auto; color: hsl(var(--hue, 260) 95% 75%); }

/* The category's id, as a file tab would name it, and the price on a glass pill. */
.asset-card__kind {
  position: absolute; z-index: 2; top: 11px; left: 12px;
  font: 500 0.66rem var(--font-mono); letter-spacing: 0.04em;
  color: hsl(var(--hue, 260) 95% 85%);
  padding: 3px 7px; border-radius: 6px;
  background: rgb(0 0 0 / 0.35); border: 1px solid hsl(var(--hue, 260) 90% 70% / 0.35);
}
.asset-card__price {
  position: absolute; z-index: 2; top: 10px; right: 11px;
  font-weight: 750; font-size: 0.86rem; color: #fff;
  padding: 5px 11px; border-radius: 999px;
  background: rgb(10 12 25 / 0.45); border: 1px solid rgb(255 255 255 / 0.22);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.asset-card__thumb .ribbon { top: auto; bottom: 10px; inset-inline-start: 12px; }

.asset-card__body { padding: 14px 16px 16px; display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.asset-card__chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 9px; border-radius: 999px;
  font-size: 0.74rem; font-weight: 650;
  color: hsl(var(--hue, 260) 90% 80%);
  background: hsl(var(--hue, 260) 80% 55% / 0.14);
  border: 1px solid hsl(var(--hue, 260) 80% 65% / 0.3);
}
[data-theme="light"] .asset-card__chip { color: hsl(var(--hue, 260) 70% 32%); background: hsl(var(--hue, 260) 80% 55% / 0.09); }
.asset-card__title {
  font-weight: 660; font-size: 1rem; line-height: 1.35; color: var(--text);
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.asset-card__summary {
  font-size: 0.85rem; color: var(--text-muted); line-height: 1.55;
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.asset-card__foot {
  margin-top: auto; padding-top: var(--space-3); border-top: 1px dashed var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
}
.asset-card__seller {
  position: relative; z-index: 2; min-width: 0;
  display: flex; align-items: center; gap: 7px;
  font-size: 0.8rem; color: var(--text-muted);
}
.asset-card__seller:hover { color: var(--text); }
.asset-card__seller .avatar { width: 24px; height: 24px; font-size: 10px; flex: none; }
.asset-card__seller span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The title is the link, so the listing's name is its anchor text - what a search
   engine reads to learn what the address is. Its ::after stretches the link over
   the whole card, as the empty overlay anchor used to, and takes the focus ring
   with it. */
.asset-card__link, .asset-card__link:hover { color: inherit; }
.asset-card__link::after { content: ''; position: absolute; inset: 0; z-index: 1; }
.asset-card__link:focus-visible { outline: none; }
.asset-card__link:focus-visible::after {
  outline: 2px solid var(--accent-ring); outline-offset: -2px; border-radius: var(--radius-lg);
}
.asset-card__foot .btn { position: relative; z-index: 2; }

.ribbon {
  position: absolute; top: var(--space-3); inset-inline-start: var(--space-3); z-index: 2;
  padding: 4px 10px; border-radius: 999px;
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase;
  background: var(--grad-gold); color: #2a1a02;
  box-shadow: 0 4px 16px -4px var(--gold-400);
}

/* ---------- Badges & pills ---------- */

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border-radius: 999px;
  font-size: 0.74rem; font-weight: 650; letter-spacing: 0.015em;
  background: color-mix(in srgb, var(--surface-solid) 70%, transparent);
  color: var(--text-muted); border: 1px solid var(--border);
}
.badge-accent  { background: var(--accent-soft); color: var(--violet-300); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
.badge-success { background: color-mix(in srgb, var(--success) 16%, transparent); color: var(--success); border-color: color-mix(in srgb, var(--success) 40%, transparent); }
.badge-warning { background: color-mix(in srgb, var(--warning) 16%, transparent); color: var(--warning); border-color: color-mix(in srgb, var(--warning) 40%, transparent); }
.badge-danger  { background: color-mix(in srgb, var(--danger) 16%, transparent);  color: var(--danger);  border-color: color-mix(in srgb, var(--danger) 40%, transparent); }
.badge-info    { background: color-mix(in srgb, var(--info) 16%, transparent);    color: var(--info);    border-color: color-mix(in srgb, var(--info) 40%, transparent); }
[data-theme="light"] .badge-accent { color: var(--violet-600); }

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 13px; border-radius: 999px; font-size: 0.83rem; font-weight: 550;
  background: var(--surface); border: 1px solid var(--border); color: var(--text-muted);
  cursor: pointer; text-decoration: none;
  transition: var(--transition);
}
.pill:hover {
  border-color: var(--accent); color: var(--text);
  transform: translateY(-2px); box-shadow: var(--glow-accent);
}
.pill.active { background: var(--grad-primary); border-color: transparent; color: var(--on-gradient); }

.chip-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* ---------- Stars ---------- */

.stars { display: inline-flex; align-items: center; gap: 1px; color: var(--gold-400); }
.stars svg { display: block; filter: drop-shadow(0 0 5px rgba(251, 191, 36, 0.45)); }
.star-empty { color: var(--border-strong); filter: none; }
.rating-line { display: inline-flex; align-items: center; gap: 6px; font-size: 0.84rem; color: var(--text-muted); }

.star-picker { display: inline-flex; gap: 3px; }
.star-picker button {
  background: none; border: 0; cursor: pointer; padding: 2px;
  color: var(--border-strong); transition: var(--transition);
}
.star-picker button.on { color: var(--gold-400); transform: scale(1.12); }

.rating-bar { display: grid; grid-template-columns: 46px 1fr 34px; gap: var(--space-2); align-items: center; font-size: 0.8rem; color: var(--text-muted); }
.rating-bar__track { height: 7px; background: var(--bg-sunken); border-radius: 4px; overflow: hidden; }
.rating-bar__fill { height: 100%; background: var(--grad-gold); border-radius: 4px; transition: width 700ms var(--ease); }

/* ---------- Hero ---------- */

.hero {
  position: relative; overflow: hidden;
  border-bottom: 1px solid var(--border);
}
.hero-inner { padding-block: var(--space-8); max-width: 820px; position: relative; z-index: 1; }
.hero h1 { margin-bottom: var(--space-4); }
/* The headline reads as lit glass. */
.hero h1 {
  background: var(--grad-text);
  background-size: 200% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: sheen 9s linear infinite;
}
.hero-lede { font-size: 1.14rem; color: var(--text-muted); margin-bottom: var(--space-5); max-width: 62ch; }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-6); }
.hero-stats { display: flex; flex-wrap: wrap; gap: var(--space-7); padding-top: var(--space-5); border-top: 1px solid var(--border); }
.hero-stat__value {
  font-size: 1.7rem; font-weight: 760; letter-spacing: -0.035em;
  background: var(--grad-primary);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero-stat__label { font-size: 0.8rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; }
.hero-stat__note { font-size: 0.76rem; color: var(--text-subtle); margin-top: 2px; }
.hero-stat { min-width: 148px; }

/* ---------- Category tiles: a bento grid ---------- */

.eyebrow-code { font-family: var(--font-mono); font-size: 0.78rem; letter-spacing: 0.04em; color: var(--cyan-400); margin-bottom: 4px; }
[data-theme="light"] .eyebrow-code { color: #0e7490; }

.bento {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: minmax(178px, auto); grid-auto-flow: dense; gap: var(--space-4);
}
.cat-tile--lead { grid-column: span 2; grid-row: span 2; }
.cat-tile--wide { grid-column: span 2; }
@media (max-width: 1020px) {
  .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cat-tile--lead { grid-row: auto; }
}
@media (max-width: 560px) {
  .bento { grid-template-columns: minmax(0, 1fr); }
  .cat-tile--lead, .cat-tile--wide { grid-column: auto; }
}

/* Each tile in its category's hue (--h, set per tile): a lit border, light
   pooled in the top corner, a dot lattice like a circuit board and a large
   faint icon in the corner. */
.cat-tile {
  --accent: hsl(var(--h, 265) 85% 64%);
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-5); border-radius: 20px;
  border: 1px solid transparent;
  background:
    radial-gradient(420px 220px at 100% 0%, hsl(var(--h, 265) 90% 60% / 0.22), transparent 70%) padding-box,
    radial-gradient(hsl(var(--h, 265) 80% 70% / 0.13) 1px, transparent 1.3px) 0 0 / 16px 16px padding-box,
    linear-gradient(var(--surface), var(--surface)) padding-box,
    linear-gradient(140deg, hsl(var(--h, 265) 90% 66% / 0.75), hsl(calc(var(--h, 265) + 60) 90% 60% / 0.12) 45%, hsl(var(--h, 265) 90% 66% / 0.45)) border-box;
  backdrop-filter: blur(var(--glass-blur)); -webkit-backdrop-filter: blur(var(--glass-blur));
  box-shadow: 0 30px 70px -34px rgb(var(--shadow-rgb) / 0.85);
  color: var(--text);
  transition: transform 260ms var(--ease), box-shadow 260ms var(--ease);
}
[data-theme="light"] .cat-tile {
  --accent: hsl(var(--h, 265) 70% 45%);
  background:
    radial-gradient(420px 220px at 100% 0%, hsl(var(--h, 265) 90% 60% / 0.14), transparent 70%) padding-box,
    radial-gradient(hsl(var(--h, 265) 70% 40% / 0.14) 1px, transparent 1.3px) 0 0 / 16px 16px padding-box,
    linear-gradient(var(--surface-solid), var(--surface-solid)) padding-box,
    linear-gradient(140deg, hsl(var(--h, 265) 80% 55% / 0.65), hsl(calc(var(--h, 265) + 60) 80% 50% / 0.1) 45%, hsl(var(--h, 265) 80% 55% / 0.4)) border-box;
}
.cat-tile::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(135deg, hsl(var(--h, 265) 85% 64%), hsl(calc(var(--h, 265) + 50) 85% 60%));
  opacity: 0; transition: opacity 260ms var(--ease);
  mask-image: radial-gradient(circle at 80% 0%, #000, transparent 70%);
}
.cat-tile:hover {
  color: var(--text); transform: translateY(-5px);
  box-shadow: 0 30px 70px -30px rgb(var(--shadow-rgb) / 0.85), 0 0 34px -12px var(--accent);
}
.cat-tile:hover::after { opacity: 0.13; }
.cat-tile > * { position: relative; z-index: 1; }
.cat-tile > .cat-tile__ghost {
  position: absolute; z-index: 0; inset-inline-end: -18px; bottom: -26px;
  width: 150px; height: 150px; pointer-events: none;
  color: hsl(var(--h, 265) 90% 70% / 0.13); transform: rotate(-12deg);
}
[data-theme="light"] .cat-tile > .cat-tile__ghost { color: hsl(var(--h, 265) 70% 45% / 0.1); }
.cat-tile__ghost svg { width: 100%; height: 100%; }
.cat-tile > .cat-tile__tag {
  position: absolute; top: 26px; inset-inline-end: 28px;
  font: 500 0.7rem var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase;
  color: hsl(var(--h, 265) 90% 78%);
}
[data-theme="light"] .cat-tile > .cat-tile__tag { color: hsl(var(--h, 265) 70% 36%); }
.cat-tile__top { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.cat-tile__icon {
  width: 44px; height: 44px; border-radius: 13px; display: grid; place-items: center; flex: none;
  color: hsl(var(--h, 265) 95% 80%);
  background: hsl(var(--h, 265) 80% 55% / 0.16);
  border: 1px solid hsl(var(--h, 265) 80% 65% / 0.45);
  box-shadow: 0 0 24px -6px hsl(var(--h, 265) 90% 60% / 0.8);
  transition: var(--transition);
}
[data-theme="light"] .cat-tile__icon {
  color: hsl(var(--h, 265) 75% 36%); background: hsl(var(--h, 265) 80% 55% / 0.1);
  box-shadow: 0 8px 18px -10px hsl(var(--h, 265) 80% 45% / 0.7);
}
.cat-tile:hover .cat-tile__icon { background: linear-gradient(135deg, hsl(var(--h, 265) 85% 64%), hsl(calc(var(--h, 265) + 50) 85% 60%)); color: var(--on-gradient); transform: rotate(-8deg) scale(1.06); }
.cat-tile__name { font-weight: 680; font-size: 1.05rem; letter-spacing: -0.015em; margin-top: var(--space-2); }
.cat-tile__meta { font-size: 0.84rem; color: var(--text-muted); line-height: 1.5; max-width: 38ch; }
.cat-tile__count {
  font: 500 0.72rem var(--font-mono); white-space: nowrap;
  padding: 4px 9px; border-radius: 999px;
  color: hsl(var(--h, 265) 90% 80%);
  background: hsl(var(--h, 265) 80% 50% / 0.14);
  border: 1px solid hsl(var(--h, 265) 80% 60% / 0.3);
}
[data-theme="light"] .cat-tile__count { color: hsl(var(--h, 265) 70% 32%); background: hsl(var(--h, 265) 80% 50% / 0.08); }
.cat-tile__foot { margin-top: auto; padding-top: var(--space-2); display: flex; align-items: center; gap: var(--space-2); }
.cat-tile__code {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font: 0.75rem/1.4 var(--font-mono); color: hsl(var(--h, 265) 85% 76%);
}
[data-theme="light"] .cat-tile__code { color: hsl(var(--h, 265) 70% 32%); }
.cat-tile__code b { color: var(--text-subtle); font-weight: 400; }
.cat-tile__go {
  margin-inline-start: auto; flex: none;
  width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  border: 1px solid var(--border); color: var(--text-muted);
  transition: var(--transition);
}
.cat-tile:hover .cat-tile__go { color: var(--text); border-color: var(--accent); }

.cat-tile--lead { padding: var(--space-6); }
.cat-tile--lead .cat-tile__icon { width: 56px; height: 56px; border-radius: 16px; }
.cat-tile--lead .cat-tile__name { font-size: 1.5rem; letter-spacing: -0.025em; margin-top: var(--space-4); }
.cat-tile--lead .cat-tile__meta { font-size: 0.92rem; max-width: 46ch; }
.cat-tile--lead > .cat-tile__ghost { width: 280px; height: 280px; inset-inline-end: -40px; bottom: -60px; }
/* The lead tile's preview: an editor window with its three dots. */
.cat-tile__preview {
  margin-top: var(--space-4); max-width: 440px;
  display: flex; flex-direction: column;
  padding: 12px 14px; border-radius: 12px;
  border: 1px solid hsl(var(--h, 265) 70% 60% / 0.25);
  background: rgb(3 4 10 / 0.55);
  font: 0.8rem/1.75 var(--font-mono); color: #cfd5f5; text-align: left;
}
[data-theme="light"] .cat-tile__preview { background: #0f1222; color: #dfe3fb; }
.cat-tile__dots { display: flex; gap: 6px; margin-bottom: 8px; }
.cat-tile__dots i { width: 9px; height: 9px; border-radius: 50%; background: #ff5f57; }
.cat-tile__dots i:nth-child(2) { background: #febc2e; }
.cat-tile__dots i:nth-child(3) { background: #28c840; }

/* Code drawn as decoration, line by line. */
.code-line { display: block; white-space: pre; overflow: hidden; text-overflow: ellipsis; }
.code-k { color: #c4b5fd; }
.code-s { color: #67e8f9; }
.code-c { color: #6b7393; }

/* ---------- Tables ---------- */

.table-wrap { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
table.data th, table.data td { padding: var(--space-3) var(--space-4); text-align: start; }
table.data th {
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--text-subtle); font-weight: 700; border-bottom: 1px solid var(--border); white-space: nowrap;
}
table.data td { border-bottom: 1px solid var(--border); vertical-align: middle; }
table.data tbody tr { transition: background var(--transition); }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data tbody tr:hover { background: var(--accent-soft); }
.num { text-align: end; font-variant-numeric: tabular-nums; }
.mono { font-family: var(--font-mono); font-size: 0.85em; }

/* ---------- Stats ---------- */

.stat {
  position: relative; overflow: hidden;
  padding: var(--space-5); border-radius: var(--radius-lg);
  background: var(--surface);
  backdrop-filter: blur(var(--glass-blur)); -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--border);
  transition: var(--transition);
}
.stat:hover { border-color: var(--border-strong); transform: translateY(-3px); box-shadow: var(--shadow); }
.stat::after {
  content: '';
  position: absolute; inset-inline-start: 0; top: 0; width: 3px; height: 100%;
  background: var(--grad-primary); opacity: 0.85;
}
.stat__label { font-size: 0.74rem; color: var(--text-subtle); text-transform: uppercase; letter-spacing: 0.09em; font-weight: 700; }
.stat__value { font-size: 1.75rem; font-weight: 760; letter-spacing: -0.035em; margin-top: 3px; font-variant-numeric: tabular-nums; }
.stat__note { font-size: 0.8rem; color: var(--text-muted); }

.spark { display: block; width: 100%; height: 60px; }
.spark path { fill: none; stroke: url(#sparkGrad, var(--accent)); stroke: var(--accent); stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; filter: drop-shadow(0 0 6px var(--accent-ring)); }
.spark .area { fill: var(--accent-soft); stroke: none; filter: none; }

/* ---------- Asset detail ---------- */

.asset-hero { padding-block: var(--space-7) var(--space-6); border-bottom: 1px solid var(--border); }
.breadcrumbs { font-size: 0.83rem; color: var(--text-subtle); margin-bottom: var(--space-3); }
.breadcrumbs a { color: var(--text-muted); }

.buy-box { position: sticky; top: calc(var(--header-h) + var(--space-4)); }

/* Sticky needs somewhere to travel. `align-items: start` on the grid sizes the
   sidebar column to the summary itself, so the containing block and the sticky
   box were exactly the same height and the box never stuck to anything - it
   just scrolled away like static content. Stretching only the aside gives it
   the full row height to move within, while the items panel keeps its own
   height rather than growing into an empty tail. */
.detail-layout > aside { align-self: stretch; min-width: 0; }

/* When the summary is taller than the space beneath the header, pinning its top
   would park the checkout button below the fold and keep it there for as long
   as the box stays pinned. Better to let it scroll with the page: everything
   stays reachable. Toggled from cart.js, which is the only place that knows the
   rendered height. Deliberately not `overflow-y: auto` - the coin panel is an
   absolutely positioned child, and any scroll container here would clip it. */
.buy-box.is-unpinned { position: static; }

/* The seller's cover image, at the top of the buy box on the listing page. */
.buy-box__cover {
  width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; display: block;
  border-radius: var(--radius); border: 1px solid var(--border); margin-bottom: var(--space-4);
}

/* A compact select for an inline control, such as sorting reviews. */
select.input-sm { width: auto; padding-block: 6px; padding-inline-start: var(--space-3); font-size: 0.82rem; }

/* The search row above an admin table. */
.admin-search { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.admin-search input[type="search"] { flex: 1 1 280px; width: auto; padding-block: 8px; }

/* ---------- The administration console ----------

   The admin screens were the one part of the site with no treatment of their
   own: .panel and .stat lent them glass and nothing after that did anything,
   which left the densest and most-used screens in the product looking like the
   least considered ones. Everything below is scoped to .admin-console - set by
   pages/admin.js and pages/member.js on their page container - so none of it
   can reach the buyer-facing pages that share .panel, .stat, .tabs and
   table.data.

   Every colour is mixed from a token that already exists, so both themes follow
   along unaided and no new value enters the palette. */

.admin-console .grid-4 { gap: var(--space-3); }

/* Tighter than a marketing stat: four of these are read together, as one row. */
.admin-console .stat { padding: var(--space-4); border-radius: var(--radius); }
.admin-console .stat__value { font-size: 1.5rem; }
/* The top-edge light every other glass surface carries. .stat spends its
   ::after on the gradient spine down the leading edge, so this is ::before. */
.admin-console .stat::before {
  content: '';
  position: absolute; inset-block-start: 0; inset-inline: 10%; height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-strong), transparent);
}

/* The tab row becomes a segmented control. A console switches between views of
   one thing, where an underline says "you have gone somewhere else" - which is
   not what pressing Orders does. */
.admin-console .tabs {
  gap: 2px;
  padding: var(--space-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
}
.admin-console .tabs .tab {
  margin-bottom: 0;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
}
.admin-console .tabs .tab:hover { background: var(--surface-hover); }
.admin-console .tabs .tab.active { background: var(--accent-soft); color: var(--accent-hover); }
/* The sliding underline belongs to the other presentation. */
.admin-console .tabs .tab::after { content: none; }

/* Records read in bulk: a header strip that holds its own above the body,
   alternating rows so the eye keeps its line across a wide table, and tabular
   figures so money and counts line up down their columns. */
.admin-console table.data th {
  background: color-mix(in srgb, var(--bg-sunken) 70%, transparent);
  border-bottom: 1px solid var(--border-strong);
}
.admin-console table.data td {
  padding-block: var(--space-2);
  font-variant-numeric: tabular-nums;
}
.admin-console table.data tbody tr:nth-child(even) {
  background: color-mix(in srgb, var(--text) 3%, transparent);
}
.admin-console table.data tbody tr:hover { background: var(--accent-soft); }

/* A panel head reads as the label on a drawer, not a first line of body copy. */
.admin-console .panel-head {
  background: color-mix(in srgb, var(--bg-sunken) 55%, transparent);
  border-bottom: 1px solid var(--border-strong);
}

/* The search row sits on the same glass as the table it filters. */
.admin-console .admin-search {
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

/* A toggle button that is on - a helpful vote the reader has cast. */
.btn.is-pressed { color: var(--success); background: color-mix(in srgb, var(--success) 12%, transparent); }
.buy-box__price {
  font-size: 2.35rem; font-weight: 780; letter-spacing: -0.04em;
  background: var(--grad-gold);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

.spec-list { display: flex; flex-direction: column; font-size: 0.87rem; }
.spec-row { display: flex; justify-content: space-between; gap: var(--space-3); padding: 10px 0; border-bottom: 1px solid var(--border); }
.spec-row:last-child { border-bottom: 0; }
.spec-row dt { color: var(--text-subtle); }
.spec-row dd { margin: 0; color: var(--text); text-align: end; font-weight: 550; word-break: break-word; }

/* ------------------------------------------------------------------ */
/* Coin picker                                                         */
/*                                                                     */
/* A searchable listbox rather than a <select>: the provider returns   */
/* over two hundred tickers, which no native dropdown makes scannable. */
/* ------------------------------------------------------------------ */

.coin-picker { position: relative; }

.coin-picker__trigger {
  width: 100%; display: flex; align-items: center; gap: var(--space-3);
  padding: 11px var(--space-4);
  background: var(--bg-elevated); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius);
  font: inherit; cursor: pointer; text-align: start;
  transition: border-color var(--transition), background var(--transition);
}
.coin-picker__trigger:hover { border-color: var(--border-strong); }
.coin-picker__trigger:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }
.coin-picker__sel { display: flex; align-items: baseline; gap: var(--space-2); flex: 1; min-width: 0; }
.coin-picker__chev { flex: none; color: var(--text-subtle); }
.coin-picker__trigger[aria-expanded="true"] .coin-picker__chev { transform: rotate(180deg); }

/* Height is bounded by the viewport, not by a guessed pixel count: the buy box
   is sticky, so the panel can open anywhere down the page. Search and chips keep
   their natural height and the list takes what is left, so the list is the only
   thing that ever scrolls. */
.coin-picker__panel {
  position: absolute; z-index: 40; inset-inline: 0; top: calc(100% + 6px);
  display: flex; flex-direction: column;
  max-height: min(62dvh, 420px); /* replaced by a measured value on open */
  background: var(--surface-solid);
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.coin-picker__searchbar {
  display: flex; align-items: center; gap: var(--space-2); flex: none;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border);
}
.coin-picker__searchicon { flex: none; color: var(--text-subtle); }
.coin-picker__search {
  flex: 1; min-width: 0; padding: 6px 0;
  background: none; border: 0; color: var(--text); font: inherit;
}
.coin-picker__search:focus { outline: none; }
.coin-picker__search::placeholder { color: var(--text-subtle); }

/* min-height:0 is what lets a flex child actually shrink and scroll. */
.coin-picker__list {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: var(--space-2);
  /* Two hundred-odd rows in a 270px window put the thumb at about 3% of the
     track - a few pixels of default grey on a dark panel, which read as a
     rendering fault rather than a control. Thin but coloured is findable. */
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
  /* Without this, scrolling past either end of the list carries on into the
     page - which moves the sticky buy box, and takes the trigger out from
     under the panel while it is still open. */
  overscroll-behavior: contain;
  /* Keeps a row clear of the sticky group heading when the arrow keys land on
     the first entry under one. */
  scroll-padding-block: 30px var(--space-2);
}
.coin-picker__list::-webkit-scrollbar { width: 10px; }
.coin-picker__list::-webkit-scrollbar-track { background: transparent; }
.coin-picker__list::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: 999px;
  border: 3px solid transparent; background-clip: content-box;
}
.coin-picker__list::-webkit-scrollbar-thumb:hover { background: var(--text-subtle); background-clip: content-box; }

/* Sticky, because "Popular" and "All coins" are the only things telling you
   where you are once the list is a few hundred rows deep. */
.coin-picker__group {
  position: sticky; top: 0; z-index: 1;
  padding: var(--space-2) var(--space-2) var(--space-1);
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text-subtle);
  background: var(--surface-solid);
}

.coin-opt {
  width: 100%; display: flex; align-items: center; gap: var(--space-3);
  padding: 9px var(--space-3);
  background: none; border: 0; border-radius: var(--radius-sm);
  color: var(--text); font: inherit; text-align: start; cursor: pointer;
}
.coin-opt:hover:not(:disabled) { background: var(--surface-hover); }
.coin-opt:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: -2px; }
.coin-opt__main { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: var(--space-2); }
.coin-opt__name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Within Popular nearly every row says "Tether USD" or "USD Coin"; the network
   is what actually tells them apart, so it is a tag rather than an afterthought. */
.coin-opt__net {
  flex: none;
  font-size: 0.68rem; font-weight: 600; line-height: 1.6;
  padding: 0 7px; border-radius: 999px; white-space: nowrap;
  color: var(--text-muted);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
}
.coin-opt__ticker {
  flex: none; font-family: var(--font-mono); font-size: 0.72rem;
  color: var(--text-subtle); letter-spacing: 0.02em;
}


/* The tick marks the current choice; it holds its space so rows do not shift. */
.coin-opt__tick { flex: none; width: 15px; color: var(--accent); visibility: hidden; }
.coin-opt[aria-selected="true"] .coin-opt__tick { visibility: visible; }
.coin-opt[aria-selected="true"] { background: var(--accent-soft); }


/* Network chips: "the USDT on Tron" is really a network question, so make
   that one tap instead of a scroll. */
.coin-picker__chips {
  display: flex; gap: 6px; flex: none;
  /* One scrolling line rather than wrapping: on a narrow screen these wrapped to
     three rows and pushed the coins themselves off the bottom. */
  flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border);
  overscroll-behavior-x: contain;
}
.coin-picker__chips::-webkit-scrollbar { display: none; }
.coin-chip { flex: none; }
.coin-chip {
  padding: 3px 10px; border-radius: 999px;
  background: none; border: 1px solid var(--border);
  color: var(--text-muted); font: inherit; font-size: 0.74rem; cursor: pointer;
  white-space: nowrap;
}
.coin-chip:hover { border-color: var(--border-strong); color: var(--text); }
.coin-chip:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 1px; }
.coin-chip.is-on {
  background: var(--accent-soft); border-color: var(--accent);
  color: var(--accent-hover); font-weight: 600;
}

/* Phones: the row has four things competing for ~320px, so the name gives up
   its width first and the ticker - the least readable part - drops out entirely.
   The network tag stays: it is the one that disambiguates. */
/* Opens upward when there is more room above than below - set by place(). */
.coin-picker__panel.is-above { top: auto; bottom: calc(100% + 6px); }

@media (max-width: 480px) {
  .coin-opt { gap: var(--space-2); padding: 10px var(--space-2); }
  .coin-opt__ticker { display: none; }
  .coin-picker__trigger { padding: 11px var(--space-3); }
  .coin-picker__trigger .coin-opt__ticker { display: inline; font-size: 0.68rem; }
}

.coin-picker__empty {
  padding: var(--space-4); margin: 0;
  text-align: center; font-size: 0.85rem; color: var(--text-subtle);
}

@media (prefers-reduced-motion: reduce) {
  .coin-picker__trigger { transition: none; }
}

/* Long-form legal copy: one measured column, not the full grid width. */
.legal-doc { max-width: 72ch; margin: 0 auto; }
.legal-doc .prose h2 {
  font-size: 1.06rem; letter-spacing: -0.01em;
  margin-top: var(--space-7); margin-bottom: var(--space-2);
}
.legal-doc .prose h2:first-child { margin-top: 0; }
.legal-foot {
  margin-top: var(--space-7); padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}
/* The English original beneath a translated document: the text that applies,
   one click away rather than a second full document in the way. */
.legal-original {
  margin-top: var(--space-7); padding: var(--space-4) var(--space-5);
  border: 1px solid var(--border); border-radius: var(--radius);
}
.legal-original > summary { cursor: pointer; font-weight: 600; color: var(--text-muted); }
.legal-original[open] > summary { margin-bottom: var(--space-5); }
/* Footer legal links sit inline with the commission note. */
.footer-legal { display: inline-flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }

.prose { font-size: 0.97rem; line-height: 1.78; color: var(--text); }
.prose h1, .prose h2, .prose h3 { margin-top: var(--space-6); }
.prose p { margin-bottom: var(--space-4); }
.prose ul, .prose ol { margin: 0 0 var(--space-4); padding-inline-start: var(--space-5); }
.prose li { margin-bottom: var(--space-2); }
.prose li::marker { color: var(--accent-hover); }
.prose code {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--violet-300);
  padding: 2px 7px; border-radius: var(--radius-sm);
  font-family: var(--font-mono); font-size: 0.86em;
  border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
}
[data-theme="light"] .prose code { color: var(--violet-600); }
.prose pre {
  background: color-mix(in srgb, var(--bg-sunken) 85%, transparent);
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-4); overflow-x: auto; margin-bottom: var(--space-4);
}
.prose pre code { background: none; border: 0; padding: 0; font-size: 0.85rem; color: var(--cyan-300); }
[data-theme="light"] .prose pre code { color: var(--cyan-500); }
.prose table { width: 100%; border-collapse: collapse; margin-bottom: var(--space-4); font-size: 0.88rem; }
.prose th, .prose td { border: 1px solid var(--border); padding: var(--space-2) var(--space-3); text-align: start; }
.prose th { background: color-mix(in srgb, var(--accent) 10%, transparent); font-weight: 680; }
.prose strong { font-weight: 680; color: var(--text); }
.prose blockquote {
  margin: 0 0 var(--space-4); padding: var(--space-2) var(--space-4);
  border-inline-start: 3px solid var(--accent); color: var(--text-muted);
  background: var(--accent-soft); border-start-end-radius: var(--radius); border-end-end-radius: var(--radius);
}

.review { padding: var(--space-5) 0; border-bottom: 1px solid var(--border); }
.review:last-child { border-bottom: 0; }
.review__head { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-2); }
.review__body { color: var(--text-muted); font-size: 0.9rem; margin: 0; white-space: pre-wrap; }

/* ---------- Cart & library ---------- */

.line-item {
  display: grid; grid-template-columns: 60px 1fr auto; gap: var(--space-4);
  align-items: center; padding: var(--space-4); border-bottom: 1px solid var(--border);
  transition: background var(--transition);
}
.line-item:last-child { border-bottom: 0; }
.line-item:hover { background: var(--accent-soft); }
.line-item__thumb {
  width: 60px; height: 60px; border-radius: var(--radius); display: grid; place-items: center;
  color: #fff;
  background: linear-gradient(150deg, hsl(var(--hue, 260) 60% 24%), hsl(calc(var(--hue, 260) + 55) 65% 14%));
  border: 1px solid var(--border);
}
[data-theme="light"] .line-item__thumb {
  background: linear-gradient(150deg, hsl(var(--hue,260) 75% 88%), hsl(calc(var(--hue,260) + 55) 70% 80%));
  color: hsl(var(--hue, 260) 60% 30%);
}
@media (max-width: 560px) {
  .line-item { grid-template-columns: 46px 1fr; }
  .line-item__actions { grid-column: 1 / -1; justify-content: flex-end; display: flex; gap: var(--space-2); }
}
/* A row with no thumbnail: a title and a figure. The three-column grid above would put the title in the thumbnail's column. */
.line-item.line-item--plain { grid-template-columns: minmax(0, 1fr) auto; }

.summary-row { display: flex; justify-content: space-between; gap: var(--space-3); padding: 8px 0; font-size: 0.9rem; }
.summary-row.total {
  border-top: 1px solid var(--border); margin-top: var(--space-2); padding-top: var(--space-3);
  font-weight: 750; font-size: 1.12rem;
}

/* The per-item lines above the subtotal. Named rows rather than a bare count,
   because "Items (3)  $27.00" tells the buyer nothing about which three. */
.summary-lines {
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-2); padding-bottom: var(--space-1);
  max-height: 172px; overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent;
  overscroll-behavior: contain;
}
.summary-row.sub { padding: 5px 0; font-size: 0.83rem; color: var(--text-muted); }
.summary-row.sub .truncate { min-width: 0; }

/* The facts that are true of the payment rather than the price. Set apart so
   they do not read as further charges on the total. */
.summary-meta {
  border-top: 1px dashed var(--border);
  margin-top: var(--space-2); padding-top: var(--space-2);
}
.summary-meta .summary-row { padding: 4px 0; }
.summary-meta .summary-row > span:last-child { text-align: end; }

.license-key {
  font-family: var(--font-mono); font-size: 0.82rem; letter-spacing: 0.05em;
  background: color-mix(in srgb, var(--cyan-400) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--cyan-400) 30%, transparent);
  color: var(--cyan-300);
  padding: 5px 10px; border-radius: var(--radius-sm);
  display: inline-flex; align-items: center; gap: var(--space-2); cursor: pointer;
  transition: var(--transition);
}
.license-key:hover { box-shadow: var(--glow-cyan); }
[data-theme="light"] .license-key { color: var(--cyan-500); }

/* ---------- Filters ---------- */

/* A sidebar that follows the page - but only where it is a sidebar. Its own
   scroll (max-height + overflow) keeps every group reachable when the panel is
   taller than the window, which the pinned, unscrollable version was not.

   At the .split-sidebar break the layout is one column, the panel sits ABOVE the
   results, and a pinned box taller than the screen stays glued over them for the
   whole page - so there it is an ordinary block, and a collapsed one (below). */
.filters {
  position: sticky; top: calc(var(--header-h) + var(--space-4));
  max-height: calc(100vh - var(--header-h) - var(--space-5));
  overflow-y: auto; overscroll-behavior: contain;
}
@media (max-width: 900px) {
  .filters { position: static; max-height: none; overflow: visible; }
}

/* The disclosure that holds the filters. A phone sees the summary and, opened, the
   panel; a wide screen sees the panel only (pages/browse.js opens it there). */
.filters__toggle {
  list-style: none;
  display: flex; align-items: center; gap: var(--space-3);
  min-height: 44px; padding: var(--space-2) var(--space-4);
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
  font-weight: 640; cursor: pointer;
}
.filters__toggle::-webkit-details-marker { display: none; }
.filters__toggle > span:first-child { flex: 1; }
.filters__toggle::after {
  content: ''; flex-shrink: 0;
  width: 8px; height: 8px; margin-block-end: 3px;
  border-inline-end: 2px solid currentColor; border-block-end: 2px solid currentColor;
  transform: rotate(45deg); transition: transform var(--transition);
}
.filters__panel[open] > .filters__toggle::after { transform: rotate(-135deg); margin-block-end: -3px; }
.filters__panel[open] > .card { margin-top: var(--space-3); }
.filters__count {
  min-width: 22px; padding: 0 7px; border-radius: 999px; text-align: center;
  font-size: 0.76rem; font-weight: 750; line-height: 22px;
  background: var(--accent-soft); color: var(--violet-300);
}
[data-theme="light"] .filters__count { color: var(--violet-600); }
@media (min-width: 901px) {
  .filters__toggle { display: none; }
  /* Newer engines hide a closed <details> body through this part; the script sets
     `open` for the rest. */
  .filters__panel::details-content { content-visibility: visible; }
}
@media (prefers-reduced-motion: reduce) { .filters__toggle::after { transition: none; } }
.filter-group { padding-bottom: var(--space-4); margin-bottom: var(--space-4); border-bottom: 1px solid var(--border); }
.filter-group:last-child { border-bottom: 0; margin-bottom: 0; padding-bottom: 0; }
.filter-title { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--text-subtle); font-weight: 700; margin-bottom: var(--space-3); }
.filter-option {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  padding: 6px 8px; font-size: 0.88rem; color: var(--text-muted); cursor: pointer;
  background: none; border: 0; width: 100%; text-align: start; font-family: inherit;
  border-radius: var(--radius-sm); transition: var(--transition); text-decoration: none;
}
.filter-option:hover { color: var(--text); background: var(--surface-hover); transform: translateX(3px); }
.filter-option.active { color: var(--violet-300); background: var(--accent-soft); font-weight: 640; }
[data-theme="light"] .filter-option.active { color: var(--violet-600); }
.filter-option__count { font-size: 0.76rem; color: var(--text-subtle); }

/* ---------- Tabs ---------- */

.tabs { display: flex; gap: var(--space-1); border-bottom: 1px solid var(--border); margin-bottom: var(--space-5); overflow-x: auto; }
.tab {
  position: relative;
  padding: var(--space-3) var(--space-4); background: none; border: 0;
  color: var(--text-muted); font: inherit; font-size: 0.9rem; font-weight: 580;
  cursor: pointer; white-space: nowrap; margin-bottom: -1px;
  transition: color var(--transition);
}
.tab::after {
  content: '';
  position: absolute; inset-inline: 12%; bottom: 0; height: 2px;
  background: var(--grad-primary); border-radius: 2px;
  transform: scaleX(0); transform-origin: center;
  transition: transform 260ms var(--ease);
}
.tab:hover { color: var(--text); }
.tab.active { color: var(--text); }
.tab.active::after { transform: scaleX(1); }

/* ---------- Toasts & modal ---------- */

.toast-stack {
  position: fixed; bottom: var(--space-5); inset-inline-end: var(--space-5); z-index: 90;
  display: flex; flex-direction: column; gap: var(--space-2);
  max-width: min(400px, calc(100vw - 32px));
}
.toast {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-3) var(--space-4); border-radius: var(--radius);
  background: color-mix(in srgb, var(--bg-elevated) 90%, transparent);
  backdrop-filter: blur(var(--glass-blur)); -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-lg); font-size: 0.88rem;
  animation: toastIn 320ms var(--ease);
  cursor: pointer;
}
@keyframes toastIn {
  from { opacity: 0; transform: translateX(24px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
.toast.leaving { opacity: 0; transform: translateX(24px); transition: var(--transition); }
.toast__icon { flex-shrink: 0; margin-top: 1px; }
.toast-success { border-color: color-mix(in srgb, var(--success) 45%, transparent); }
.toast-success .toast__icon { color: var(--success); }
.toast-error   { border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.toast-error   .toast__icon { color: var(--danger); }
.toast-info    .toast__icon { color: var(--info); }

.modal-backdrop {
  position: fixed; inset: 0; z-index: 80; display: grid; place-items: center;
  background: rgba(3, 4, 10, 0.72); backdrop-filter: blur(6px);
  padding: var(--space-4);
  animation: fade 200ms var(--ease);
}
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.modal {
  width: 100%; max-width: 540px; max-height: 88vh; overflow-y: auto;
  background: color-mix(in srgb, var(--bg-elevated) 94%, transparent);
  backdrop-filter: blur(var(--glass-blur)) saturate(150%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(150%);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-xl); box-shadow: var(--shadow-lg);
  animation: modalIn 320ms var(--ease);
}
@keyframes modalIn {
  from { opacity: 0; transform: translateY(22px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
.modal-head { padding: var(--space-5) var(--space-5) 0; display: flex; justify-content: space-between; gap: var(--space-3); }
.modal-body { padding: var(--space-4) var(--space-5); }
.modal-foot { padding: 0 var(--space-5) var(--space-5); display: flex; justify-content: flex-end; gap: var(--space-3); }

/* ---------- Feedback ---------- */

.empty { text-align: center; padding: var(--space-8) var(--space-4); color: var(--text-muted); }
.empty__icon { color: var(--text-subtle); margin-bottom: var(--space-4); opacity: 0.7; animation: float 5s ease-in-out infinite; }
.empty__title { font-size: 1.12rem; font-weight: 680; color: var(--text); margin-bottom: var(--space-2); }
@keyframes float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-9px); }
}

.alert {
  display: flex; gap: var(--space-3); padding: var(--space-4);
  border-radius: var(--radius); font-size: 0.88rem; border: 1px solid;
}
.alert-info    { background: color-mix(in srgb, var(--info) 11%, transparent);    border-color: color-mix(in srgb, var(--info) 32%, transparent);    color: var(--text); }
.alert-warning { background: color-mix(in srgb, var(--warning) 11%, transparent); border-color: color-mix(in srgb, var(--warning) 32%, transparent); color: var(--text); }
.alert-danger  { background: color-mix(in srgb, var(--danger) 11%, transparent);  border-color: color-mix(in srgb, var(--danger) 32%, transparent);  color: var(--text); }
.alert-success { background: color-mix(in srgb, var(--success) 11%, transparent); border-color: color-mix(in srgb, var(--success) 32%, transparent); color: var(--text); }
.alert__icon { flex-shrink: 0; margin-top: 2px; }

.skeleton {
  background: linear-gradient(100deg,
    color-mix(in srgb, var(--surface-solid) 60%, transparent) 25%,
    color-mix(in srgb, var(--accent) 12%, transparent) 50%,
    color-mix(in srgb, var(--surface-solid) 60%, transparent) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite linear;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
}
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.skeleton-card { height: 300px; }
.skeleton-line { height: 12px; margin-bottom: 8px; border-radius: var(--radius-sm); }

.pagination { display: flex; align-items: center; justify-content: center; gap: var(--space-2); margin-top: var(--space-7); }
.page-btn {
  min-width: 40px; height: 40px; padding: 0 var(--space-3); border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--border); color: var(--text-muted);
  font: inherit; font-size: 0.88rem; cursor: pointer; transition: var(--transition);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.page-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--text); transform: translateY(-2px); }
.page-btn.active { background: var(--grad-primary); border-color: transparent; color: var(--on-gradient); font-weight: 700; }
.page-btn:disabled { opacity: 0.35; cursor: not-allowed; }

/* ---------- Footer ---------- */

.site-footer {
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg-sunken) 75%, transparent);
  backdrop-filter: blur(var(--glass-blur)); -webkit-backdrop-filter: blur(var(--glass-blur));
  margin-top: var(--space-8);
}
.footer-inner { padding-block: var(--space-7); display: grid; grid-template-columns: 2fr 1fr 1fr 1fr 1fr; gap: var(--space-5); }
@media (max-width: 1024px) { .footer-inner { grid-template-columns: 1fr 1fr 1fr; } }
@media (max-width: 760px) { .footer-inner { grid-template-columns: 1fr 1fr; } }
.footer-col h4 { font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--text-subtle); margin-bottom: var(--space-3); font-weight: 700; }
.footer-col a { display: block; color: var(--text-muted); font-size: 0.88rem; padding: 4px 0; transition: var(--transition); }
.footer-col a:hover { color: var(--accent-hover); transform: translateX(4px); }
.footer-bottom {
  border-top: 1px solid var(--border); padding-block: var(--space-4);
  display: flex; flex-wrap: wrap; gap: var(--space-3); justify-content: space-between;
  font-size: 0.82rem; color: var(--text-subtle);
}

/* ---------- Age confirmation ---------- */

/* The layer pages/age.js puts over the page until the visitor has answered:
   above the header (40), below modals (80) and toasts (90).

   Frosted rather than solid, so the site reads as still being there - it is;
   the page is drawn underneath, out of reach - and the panel, which is nearly
   opaque, is what carries the text. Flex with an auto-margined panel rather
   than place-items: centre, because centring a box taller than its container
   that way pushes the top of it out of reach of a scroll, and a phone held
   sideways is exactly that. */
.age-gate {
  position: fixed; inset: 0; z-index: 70;
  display: flex; padding: var(--space-4);
  overflow-y: auto; overscroll-behavior: contain;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  /* On this element, not the panel: it restarts only when the layer comes back
     from display: none, so drawing the "No" screen or a new language inside it
     does not make the panel blink out and fade in again. */
  animation: fade 240ms var(--ease);
}
/* Nothing drawn: not there at all, so it cannot swallow a click. */
.age-gate:empty { display: none; }
/* Nothing behind it scrolls while it is up (set on <body> by syncAgeGate). */
.age-gated { overflow: hidden; }

.age-gate__panel {
  width: 100%; max-width: 460px; margin: auto;
  padding: var(--space-6) var(--space-5);
  text-align: center;
  background: color-mix(in srgb, var(--bg-elevated) 94%, transparent);
  border-color: var(--border-strong);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}
/* Focus is put on the panel so a screen reader reads the question first; a ring
   round the whole card would only be noise, and every control inside keeps its own. */
.age-gate__panel:focus { outline: none; }

.age-gate__brand { margin-bottom: var(--space-5); }
/* The name is dropped from the header's brand on a phone, to make room. There is room here. */
.age-gate__brand .brand-text { display: inline; }

/* The mark everybody recognises for this question. Decorative: the heading says it in words. */
.age-gate__badge {
  width: 88px; height: 88px; margin: 0 auto var(--space-5);
  display: grid; place-items: center;
  border: 2px solid transparent; border-radius: 50%;
  background: linear-gradient(var(--bg-elevated), var(--bg-elevated)) padding-box, var(--grad-primary) border-box;
  box-shadow: var(--glow-accent);
  font-size: 1.85rem; font-weight: 800; line-height: 1; letter-spacing: -0.03em;
}

.age-gate__title { margin-bottom: var(--space-3); }

.age-gate__actions { display: grid; gap: var(--space-3); margin-top: var(--space-5); }
/* Buttons do not wrap anywhere else; here a long translation on a very narrow phone must. */
.age-gate__actions .btn { white-space: normal; text-align: center; }

.age-gate__fine { margin: var(--space-4) 0 0; }
.age-gate__lang { margin-top: var(--space-4); }

}

/* ------------------------------------------------------------------ */
@layer motion {

/* Elements enter as they scroll into view. `is-in` is added by motion.js.
   Without JS everything stays visible, so content is never trapped. */
/* The reveal slides with the individual `translate` property, not `transform`.
   `transform` belongs to the depth layer below: when both used it, the reveal's
   `transform: none` (higher specificity than the old tilt rule) silently
   cancelled every hover transform on a revealed element. The other properties
   are listed so a revealed element keeps its own hover transitions - a
   `transition` here replaces the component's, it does not add to it. */
.reveal {
  opacity: 0;
  translate: 0 26px;
  transition: opacity 620ms var(--ease), translate 620ms var(--ease),
              transform 260ms var(--ease), border-color 260ms var(--ease),
              box-shadow 260ms var(--ease), background-color 200ms var(--ease);
  will-change: opacity, translate;
}
.reveal.is-in { opacity: 1; translate: none; will-change: auto; }

/* Staggered children inside a revealed grid. The delay belongs to the entrance
   only, not to hover. */
.reveal-stagger > * {
  opacity: 0;
  translate: 0 22px;
  transition: opacity 560ms var(--ease) calc(var(--i, 0) * 55ms),
              translate 560ms var(--ease) calc(var(--i, 0) * 55ms),
              transform 260ms var(--ease), border-color 260ms var(--ease),
              box-shadow 260ms var(--ease), background-color 200ms var(--ease);
}
.reveal-stagger.is-in > * { opacity: 1; translate: none; }

/* The escape hatch. motion.js adds this when a reveal has not completed in
   time - including the case where transitions never advance at all. It skips
   the animation rather than waiting on it, so content cannot stay hidden. */
.motion-off,
.motion-off > * {
  opacity: 1 !important;
  translate: none !important;
  transform: none !important;
  transition: none !important;
}

/* ---------- Depth ----------
   motion.js springs --px/--py (pointer, -1..1), --mx/--my (pointer, %),
   --lift and --press (0..1) on the element under the pointer and adds
   .depth / .depth-btn / .depth-fld only while it moves. This file turns those
   numbers into a tilt, a highlight and a shadow, so an element at rest carries
   no transform, no layer and no extra paint. Rotation is capped at 4deg. */

.depth {
  --px: 0; --py: 0; --mx: 50%; --my: 50%; --lift: 0; --press: 0;
  transform: perspective(900px)
             rotateX(calc(var(--py) * -4deg)) rotateY(calc(var(--px) * 4deg))
             translate3d(0, calc(var(--lift) * -5px), 0)
             scale(calc(1 + var(--lift) * 0.01));
  will-change: transform;
  /* The springs do the easing; a CSS transition on top would only lag them. */
  transition: none;
  /* The light sits where the pointer is, so the shadow falls away from it. */
  box-shadow:
    calc(var(--px) * var(--lift) * -14px) calc(var(--lift) * (14px - var(--py) * 8px)) calc(var(--lift) * 44px) -12px rgb(var(--shadow-rgb) / calc(var(--lift) * 0.7)),
    0 0 calc(var(--lift) * 34px) -14px var(--accent);
  border-color: color-mix(in srgb, var(--accent) calc(var(--lift) * 55%), var(--border));
}

/* Cast in the theme's own ink, a little lighter on white. */
[data-theme="light"] .depth {
  box-shadow:
    calc(var(--px) * var(--lift) * -14px) calc(var(--lift) * (14px - var(--py) * 8px)) calc(var(--lift) * 44px) -14px rgb(var(--shadow-rgb) / calc(var(--lift) * 0.4)),
    0 0 calc(var(--lift) * 30px) -16px var(--accent);
}

/* A highlight that follows the pointer across the glass. */
.depth::before {
  content: '';
  position: absolute; inset: 0; z-index: 2;
  border-radius: inherit; pointer-events: none;
  background: radial-gradient(240px circle at var(--mx) var(--my),
              rgb(255 255 255 / 0.09), color-mix(in srgb, var(--accent) 7%, transparent) 42%, transparent 72%);
  opacity: var(--lift);
}
[data-theme="light"] .depth::before {
  background: radial-gradient(240px circle at var(--mx) var(--my),
              color-mix(in srgb, var(--accent) 9%, transparent), transparent 70%);
}

/* Layers inside a surface sit at different depths. Two-dimensional on purpose:
   these surfaces clip their content (overflow: hidden), which flattens 3D. */
.cat-tile.depth::after { mask-image: radial-gradient(circle at var(--mx) var(--my), #000, transparent 70%); opacity: calc(var(--lift) * 0.13); }
.cat-tile.depth .cat-tile__icon {
  transform: translate3d(calc(var(--px) * 8px), calc(var(--py) * 8px), 0)
             rotate(calc(var(--lift) * -8deg)) scale(calc(1 + var(--lift) * 0.06));
  background: linear-gradient(135deg,
              color-mix(in srgb, hsl(var(--h, 265) 85% 64%) calc(var(--lift) * 100%), transparent),
              color-mix(in srgb, hsl(calc(var(--h, 265) + 50) 85% 60%) calc(var(--lift) * 100%), transparent)),
              hsl(var(--h, 265) 80% 55% / 0.16);
  color: color-mix(in srgb, var(--on-gradient) calc(var(--lift) * 100%), hsl(var(--h, 265) 95% 80%));
  transition: none;
}
[data-theme="light"] .cat-tile.depth .cat-tile__icon {
  color: color-mix(in srgb, var(--on-gradient) calc(var(--lift) * 100%), hsl(var(--h, 265) 75% 36%));
}
.cat-tile.depth .cat-tile__name { transform: translate3d(calc(var(--px) * 4px), calc(var(--py) * 4px), 0); }
.cat-tile.depth .cat-tile__meta { transform: translate3d(calc(var(--px) * 2px), calc(var(--py) * 2px), 0); }

.asset-card.depth .asset-card__image {
  transform: translate3d(calc(var(--px) * -7px), calc(var(--py) * -6px), 0) scale(1.05);
}
.asset-card.depth .asset-card__glyph {
  transform: translate3d(calc(var(--px) * -9px), calc(var(--py) * -8px - var(--lift) * 4px), 0)
             rotate(calc(var(--lift) * -4deg)) scale(calc(1 + var(--lift) * 0.09));
  transition: none;
}
.asset-card.depth .asset-card__body { transform: translate3d(calc(var(--px) * 2px), calc(var(--py) * 2px), 0); }

.stat.depth { transform: perspective(900px) rotateX(calc(var(--py) * -3deg)) rotateY(calc(var(--px) * 3deg)) translate3d(0, calc(var(--lift) * -3px), 0); }

/* Buttons keep their look and respond like a physical key: lean toward the
   pointer as it nears, lift on hover, compress on press, spring back. */
.btn.depth-btn:not(:disabled) {
  --px: 0; --py: 0; --lift: 0; --press: 0;
  transform: perspective(500px)
             rotateX(calc(var(--py) * -5deg)) rotateY(calc(var(--px) * 5deg))
             translate3d(calc(var(--px) * 1.5px), calc(var(--lift) * -3px + var(--press) * 1.5px), 0)
             scale(calc(1 + var(--lift) * 0.012 - var(--press) * 0.035));
  will-change: transform;
  transition: box-shadow 260ms var(--ease), background var(--transition), border-color var(--transition), color var(--transition);
}
.btn-primary.depth-btn:not(:disabled) {
  box-shadow: calc(var(--px) * -6px) calc(6px + var(--lift) * 7px - var(--press) * 4px) calc(22px + var(--lift) * 10px) -10px rgba(139, 92, 246, 1);
}
.btn-secondary.depth-btn:not(:disabled):hover { box-shadow: var(--glow-accent), 0 calc(var(--lift) * 6px) 18px -10px rgb(var(--shadow-rgb) / 0.6); }

/* Keyboard: the same lift and a clear ring, without any pointer light. */
.btn:not(:disabled):focus-visible { outline-offset: 4px; }
.btn:not(:disabled):focus-visible:not(.depth-btn) { transform: translateY(-2px); }
.btn:not(:disabled):focus-visible:not(.depth-btn):active { transform: translateY(0) scale(0.97); }

/* Fields: lift a hair on focus and catch the light under the pointer. */
input[type="text"], input[type="email"], input[type="password"], input[type="search"],
input[type="number"], textarea, select { --lift: 0; --mx: 50%; --my: 50%; }
.depth-fld:not(select) {
  background-image: radial-gradient(200px circle at var(--mx) var(--my),
                    color-mix(in srgb, var(--accent) calc(var(--lift) * 13%), transparent), transparent 72%);
}
.depth-fld:not(:focus):not([aria-invalid="true"]) {
  border-color: color-mix(in srgb, var(--accent) calc(var(--lift) * 38%), var(--border-strong));
}
input[type="text"]:focus, input[type="email"]:focus, input[type="password"]:focus,
input[type="search"]:focus, input[type="number"]:focus, textarea:focus, select:focus {
  translate: 0 -1px;
  box-shadow: 0 0 0 3px var(--accent-soft), 0 0 22px -8px var(--accent), 0 10px 22px -14px rgb(var(--shadow-rgb) / 0.8);
}
input[aria-invalid="true"], textarea[aria-invalid="true"] {
  animation: fieldNudge 320ms var(--ease);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 18%, transparent);
}
@keyframes fieldNudge { 20% { translate: -3px 0; } 45% { translate: 3px 0; } 70% { translate: -1.5px 0; } }

/* Sections: the hero drifts a little slower than the page. */
.hero-inner { transform: translate3d(0, calc(var(--scroll-d, 0) * -20px), 0); }

/* Touch has no hover to follow: a press compresses, nothing else moves. */
@media (hover: none) {
  .btn:not(:disabled):active { transform: scale(0.97); }
  .asset-card:active, .cat-tile:active { transform: scale(0.985); }
}

}

/* ------------------------------------------------------------------ */
@layer utilities {

.muted    { color: var(--text-muted); }
.subtle   { color: var(--text-subtle); }
.small    { font-size: 0.85rem; }
.tiny     { font-size: 0.78rem; }
.strong   { font-weight: 680; }
.center   { text-align: center; }
.right    { text-align: end; }
.nowrap   { white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The attribute, not only the class. The browser's own [hidden] rule is the
   weakest thing in the cascade, so any class that sets a display - .coin-opt is
   flex, .alert is flex - silently beat it, and `el.hidden = true` set the
   attribute while the element carried on painting. That is not a small thing:
   the coin picker's search hid 230 rows that all stayed on screen, so searching
   appeared to do nothing while the matches piled up at the bottom of a
   ten-thousand-pixel list. Anything toggled by `.hidden` in JS goes through
   here, so it is fixed once rather than per component. */
/* The `until-found` carve-out matches what the browser's own rule does. Nothing
   uses it yet, but `display: none !important` would make it permanently
   unimplementable: find-in-page reveal needs the element laid out, and the
   !important would block any override. */
.hidden, [hidden]:not([hidden="until-found"]) { display: none !important; }

.mt-0 { margin-top: 0; } .mt-1 { margin-top: var(--space-1); } .mt-2 { margin-top: var(--space-2); } .mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); } .mt-5 { margin-top: var(--space-5); } .mt-6 { margin-top: var(--space-6); }
.mb-0 { margin-bottom: 0; } .mb-2 { margin-bottom: var(--space-2); } .mb-3 { margin-bottom: var(--space-3); }
.mb-4 { margin-bottom: var(--space-4); } .mb-5 { margin-bottom: var(--space-5); }
.gap-2 { gap: var(--space-2); } .gap-3 { gap: var(--space-3); } .gap-4 { gap: var(--space-4); } .gap-5 { gap: var(--space-5); }

/* A heading that should read as a section title, whatever element it is. */
.h5 { font-size: 1.08rem; letter-spacing: -0.02em; }

}

/* ------------------------------------------------------------------ */
/* Anyone who asks for less motion gets a still, flat page.            */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .reveal, .reveal-stagger > * { opacity: 1 !important; transform: none !important; translate: none !important; }
  .depth, .depth-btn, .hero-inner { transform: none !important; }
  .depth::before { display: none; }
  input:focus, textarea:focus, select:focus { translate: none; }
  #bg-canvas { display: none; }
}

/* ==========================================================================
   Right-to-left
   ==========================================================================

   Everything that CAN be logical already is - inset-inline, padding-inline,
   text-align: start. What is left here is the short list of properties CSS
   gives no start/end spelling for, so they have to be restated once for the
   mirrored direction:

     transform: translateX(...)   a nudge toward one physical side
     transform-origin             no logical keywords exist
     background-position          same

   Driven by dir="rtl" on <html>, which setLocale() in store.js sets from the
   active locale. A rule here is a rule that could not be written logically -
   if something can be expressed with an inline property, it belongs above
   rather than in this block, because a rule up there is one that cannot fall
   out of step with its LTR counterpart. */

/* Hover nudges point inward from the reading edge, so they invert. */
[dir="rtl"] .menu-item:hover            { transform: translateX(-3px); }
[dir="rtl"] .filter-option:hover        { transform: translateX(-3px); }
[dir="rtl"] .footer-col a:hover         { transform: translateX(-4px); }

/* The sheen that sweeps across a button sweeps the other way. */
[dir="rtl"] .btn::before                        { transform: translateX(120%); }
[dir="rtl"] .btn:not(:disabled):hover::before   { transform: translateX(-120%); }

/* Menus and drawers hang off the trailing edge, so they grow from it. */
[dir="rtl"] .menu { transform-origin: top left; }

/* Toasts slide in from the edge they sit on. */
[dir="rtl"] .toast.leaving { transform: translateX(-24px); }
@keyframes toastInRtl {
  from { opacity: 0; transform: translateX(-24px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
[dir="rtl"] .toast { animation-name: toastInRtl; }

/* Latin digits inside an Arabic page. Prices, order references and licence
   keys are identifiers and amounts that people copy, read aloud to support and
   compare against a block explorer - they must read identically in every
   locale. Intl would otherwise render them in Arabic-Indic numerals for ar,
   which is correct typography and the wrong thing for a string somebody is
   about to paste into a wallet. */
[dir="rtl"] .mono,
[dir="rtl"] code,
[dir="rtl"] .num { direction: ltr; unicode-bidi: embed; text-align: end; }

/* A receipt prints as a document: no site chrome, no background canvas, no
   buttons. Anything that only makes sense on screen carries .no-print. */
@media print {
  #site-header, #site-footer, #bg-canvas, #toasts, .no-print { display: none !important; }
  body { background: #fff !important; color: #000 !important; }
  .panel { background: #fff !important; box-shadow: none !important; border-color: #bbb !important; }
  .receipt a { color: #000 !important; text-decoration: none !important; }
}

/* The language switch: a button styled as the link beside it, in the header,
   the drawer and the footer.
   In the components layer with the links it sits among. Unlayered, its display
   beat the layered .nav-link.hide-sm rule whatever the specificity - an
   unlayered style outranks every layer - so the header switch stayed on screen
   on a phone, beside the same switch in the drawer. */
@layer components {
  .lang-switch {
    display: inline-flex; align-items: center; gap: 6px;
    background: none; border: 0; cursor: pointer; font: inherit;
  }
  .lang-switch svg { flex: none; opacity: 0.8; }
  button.drawer__link { text-align: start; width: 100%; }
  .footer-lang { color: var(--text-subtle); padding: 0; }
  .footer-lang:hover { color: var(--accent-hover); }
}

/* Arabic.
   Inter has no Arabic letters, so without this every Arabic glyph falls back,
   one at a time, to whatever the system happens to have - naming good Arabic
   faces first gives one coherent face instead. Letter-spacing is removed
   everywhere: Arabic letters join, and any tracking - positive on the
   uppercase labels or negative on the headings - pulls the joins apart. */
:root[lang="ar"] {
  --font: "Segoe UI", "SF Arabic", "Noto Sans Arabic", "Geeza Pro", Tahoma, "Inter", ui-sans-serif, system-ui, sans-serif;
}
:root[lang="ar"] body,
:root[lang="ar"] body * { letter-spacing: normal !important; }
:root[lang="ar"] .prose { line-height: 1.9; }

/* ==========================================================================
   Wallets and payments: the pay screen, the wallet page, the seller notice.
   Logical properties throughout (inline-start / inline-end), so the Arabic
   layout mirrors without a second set of rules.
   ========================================================================== */

/* A notice that applies wherever the signed-in person is. */
.site-notice {
  background: color-mix(in srgb, var(--warning) 14%, var(--bg-elevated));
  border-bottom: 1px solid color-mix(in srgb, var(--warning) 34%, transparent);
}
.site-notice:empty { display: none; }
.site-notice__inner {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  padding-block: var(--space-2); flex-wrap: wrap;
}
.site-notice__text { display: inline-flex; align-items: center; gap: var(--space-2); font-size: 0.9rem; }

/* The pay screen. */
.pay-card { max-width: 560px; margin-inline: auto; }
.pay-items { list-style: none; margin: var(--space-3) 0 0; padding: 0; }
.pay-items li {
  display: flex; justify-content: space-between; gap: var(--space-3);
  padding: 6px 0; font-size: 0.9rem; color: var(--text-muted);
  border-bottom: 1px solid var(--border);
}
.pay-items li:last-child { border-bottom: 0; }
.pay-items .truncate { min-width: 0; }

/* USDT | USDC */
.pay-token {
  display: inline-flex; margin-top: var(--space-4); padding: 3px; gap: 3px;
  background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius);
}
.pay-token__btn {
  appearance: none; border: 0; background: transparent; color: var(--text-muted);
  font: inherit; font-weight: 600; letter-spacing: 0.02em; cursor: pointer;
  padding: 8px 18px; border-radius: calc(var(--radius) - 3px);
}
.pay-token__btn:hover:not(:disabled) { color: var(--text); }
.pay-token__btn.is-on { background: var(--accent); color: var(--accent-contrast); }
.pay-token__btn:disabled { cursor: default; opacity: 0.6; }
.pay-token__btn:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }

/* Which wallet is paying. */
.pay-wallet {
  padding: var(--space-4); border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.wallet-chip {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: 6px 12px; border-radius: 999px; font-size: 0.85rem;
  background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
}
.wallet-chip.is-ok {
  background: color-mix(in srgb, var(--success) 14%, transparent);
  border-color: color-mix(in srgb, var(--success) 40%, transparent);
}
.wallet-chip code { font-size: 0.85em; }

/* "1 Approve exact amount / 2 Pay" - and the wallet page's three steps. */
.pay-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.pay-step { display: flex; gap: var(--space-3); align-items: flex-start; color: var(--text-subtle); }
.pay-step__n {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.8rem; font-weight: 700;
  border: 1px solid var(--border-strong); color: var(--text-muted); background: var(--bg-sunken);
}
.pay-step strong { color: inherit; }
.pay-step.is-active { color: var(--text); }
.pay-step.is-active .pay-step__n { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
.pay-step.is-done { color: var(--text-muted); }
.pay-step.is-done .pay-step__n {
  background: color-mix(in srgb, var(--success) 18%, transparent);
  border-color: color-mix(in srgb, var(--success) 50%, transparent); color: var(--success);
}

/* A dot that breathes while something is being waited for. */
.pulse-dot {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent); margin-inline-end: 6px; vertical-align: middle;
  animation: pulse-dot 1.4s ease-in-out infinite;
}
@keyframes pulse-dot { 0%, 100% { opacity: 0.35; transform: scale(0.85); } 50% { opacity: 1; transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .pulse-dot { animation: none; } }

/* "Paying from a Binance exchange account?" */
.help-panel { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.help-panel > summary {
  cursor: pointer; list-style: none; padding: var(--space-3) var(--space-4);
  display: flex; align-items: center; gap: var(--space-2); font-weight: 600;
}
.help-panel > summary::-webkit-details-marker { display: none; }
.help-panel[open] > summary { border-bottom: 1px solid var(--border); }
.help-panel__body { padding: var(--space-4); }
.help-panel__body ol { margin: 0 0 var(--space-3); padding-inline-start: 20px; }
.help-panel__body li { margin-bottom: 4px; }

/* What a seller will be paid, before anything is signed. */
.payout-preview {
  padding: var(--space-3) var(--space-4); border-radius: var(--radius);
  background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  font-size: 0.9rem; line-height: 1.7;
}
