/* ==========================================================================
   main.css - Agent 3A
   Public design system for the storefront. Mobile first, dark, glassmorphic.

   Contents
   01. Design tokens
   02. Reset & base
   03. Accessibility helpers
   04. Layout primitives
   05. Surfaces (glass, card)
   06. Site header & navigation
   07. Site footer
   08. Hero
   09. Buttons & spinner
   10. Forms
   11. Badges, tags, price, alerts, empty state
   12. Tables
   13. Breadcrumb & pagination
   14. Stats
   15. Modal
   16. Toasts
   17. Skeletons
   18. Product & variant cards
   19. Checkout summary & gift code
   20. Filter bar
   21. Pagination-free utilities
   21b. Storefront template hooks
   22. Keyframes
   23. Responsive
   24. Motion, fallbacks, print
   ========================================================================== */

/* ==========================================================================
   01. Design tokens - ACHER

   Two layers, on purpose:

     a) --acher-*  is the BRAND layer. It is the single authoritative source of
        truth for the ACHER visual language and the only thing other agents and
        new components should reference by name.

     b) --color-* / --tint-* / --gradient-* / --font-* is the LEGACY layer that
        every pre-existing rule in this file and in admin.css already consumes.
        Each one is re-pointed at an --acher-* value below, so the whole app
        inherits the rebrand with no per-rule edits.

   Never hard-code a hex in a component rule. Add a brand token, point a legacy
   token at it, and the storefront plus the admin panel move together.
   ========================================================================== */

:root {
  /* ---- (a) ACHER brand layer ------------------------------------------- */

  /* Core palette - the eight canonical tokens. */
  --acher-bg: #080808;
  --acher-surface: #0f0f0f;
  --acher-border: #1a1a1a;
  --acher-primary: #00ff41;
  --acher-primary-dim: #00cc33;
  --acher-text: #e8e8e8;
  --acher-muted: #666666;
  --acher-danger: #ff2d2d;
  --acher-warning: #ffaa00;

  /* Derived neighbours. Same family, different jobs. */
  --acher-bg-deep: #050505;          /* below the page: scrollbar track, wells */
  --acher-surface-2: #141414;        /* raised: dropdowns, modals, popovers    */
  --acher-surface-3: #1c1c1c;        /* pressed / hovered raised surface       */
  --acher-border-strong: #2a2a2a;    /* an edge that has to be seen            */
  --acher-primary-soft: #7dff9b;     /* readable green TEXT on a dark surface  */
  --acher-primary-deep: #041a0b;     /* readable TEXT on a bright green fill   */
  --acher-dim: #9a9a9a;              /* de-emphasised copy that must stay legible */
  --acher-danger-soft: #ff8f8f;
  --acher-warning-soft: #ffcc55;

  /* Channel triplets, so alpha can be composed without a second hex. */
  --acher-primary-rgb: 0, 255, 65;
  --acher-danger-rgb: 255, 45, 45;
  --acher-warning-rgb: 255, 170, 0;

  /* Glow ladder. Every neon accent in the system comes from one of these. */
  --acher-glow-sm: 0 0 8px rgba(var(--acher-primary-rgb), 0.28);
  --acher-glow: 0 0 20px rgba(var(--acher-primary-rgb), 0.30);
  --acher-glow-lg: 0 0 38px rgba(var(--acher-primary-rgb), 0.34);
  --acher-glow-text: 0 0 12px rgba(var(--acher-primary-rgb), 0.45);

  /* Fonts. Loaded as one Google Fonts request from templates/base.php. */
  --acher-font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --acher-font-display: "Share Tech Mono", "JetBrains Mono", ui-monospace,
    SFMono-Regular, Menlo, Consolas, monospace;
  --acher-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono",
    Menlo, Consolas, "Liberation Mono", monospace;

  /* ---- (b) legacy layer, re-pointed ------------------------------------ */

  --color-bg: var(--acher-bg);
  --color-primary: var(--acher-primary);
  --color-accent: var(--acher-primary-dim);
  --color-text: var(--acher-text);
  --color-muted: var(--acher-dim);
  --color-glass: rgba(255, 255, 255, 0.028);
  --color-border: var(--acher-border);
  --color-success: var(--acher-primary);
  --color-warn: var(--acher-warning);
  --color-danger: var(--acher-danger);

  /* Derived surfaces */
  --color-bg-soft: #0c0c0c;
  --color-bg-elev: var(--acher-surface-2);
  --color-bg-deep: var(--acher-bg-deep);
  --color-glass-strong: rgba(255, 255, 255, 0.055);
  --color-border-strong: var(--acher-border-strong);
  --color-overlay: rgba(3, 3, 3, 0.82);

  /* Text that sits ON a saturated fill. */
  --color-on-primary: var(--acher-primary-deep);

  /* Tinted washes used for states */
  --tint-primary: rgba(var(--acher-primary-rgb), 0.10);
  --tint-accent: rgba(var(--acher-primary-rgb), 0.08);
  --tint-success: rgba(var(--acher-primary-rgb), 0.10);
  --tint-warn: rgba(var(--acher-warning-rgb), 0.12);
  --tint-danger: rgba(var(--acher-danger-rgb), 0.12);

  /* Shape & motion - ACHER is squarer than what it replaces. */
  --radius: 6px;
  --radius-sm: 4px;
  --radius-lg: 10px;
  --radius-pill: 999px;
  --shadow-glow: var(--acher-glow);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 10px 30px rgba(0, 0, 0, 0.55);
  --shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.65);
  --transition: 0.16s ease;
  --transition-slow: 0.4s cubic-bezier(0.22, 1, 0.36, 1);

  /* Gradients */
  --gradient-primary: linear-gradient(135deg, var(--acher-primary) 0%, var(--acher-primary-dim) 100%);
  --gradient-primary-soft: linear-gradient(135deg, rgba(var(--acher-primary-rgb), 0.85) 0%, rgba(0, 204, 51, 0.85) 100%);
  --gradient-text: linear-gradient(120deg, var(--acher-primary-soft) 0%, var(--acher-primary) 55%, var(--acher-primary-dim) 100%);
  --gradient-hero: linear-gradient(120deg, #080808 0%, #0a1410 26%, #060f09 52%, #0a1410 78%, #080808 100%);

  /* Typography */
  --font-sans: var(--acher-font-body);
  --font-display: var(--acher-font-display);
  --font-mono: var(--acher-font-mono);

  --fs-xs: clamp(0.72rem, 0.69rem + 0.15vw, 0.79rem);
  --fs-sm: clamp(0.82rem, 0.79rem + 0.18vw, 0.9rem);
  --fs-base: clamp(0.94rem, 0.91rem + 0.2vw, 1rem);
  --fs-md: clamp(1.04rem, 0.99rem + 0.3vw, 1.16rem);
  --fs-lg: clamp(1.18rem, 1.08rem + 0.55vw, 1.4rem);
  --fs-xl: clamp(1.42rem, 1.24rem + 0.95vw, 1.95rem);
  --fs-2xl: clamp(1.8rem, 1.45rem + 1.75vw, 2.6rem);
  --fs-3xl: clamp(2.25rem, 1.65rem + 2.95vw, 3.5rem);

  --lh-tight: 1.15;
  --lh-snug: 1.3;
  --lh-base: 1.6;
  --lh-loose: 1.75;

  /* Spacing scale */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-7: 1.75rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;

  /* Layout */
  --container-max: 1200px;
  --container-pad: clamp(1rem, 4vw, 2rem);
  --header-h: 64px;

  /* TASK 2 - the category bar's own height inside the sticky header shell.
     ZERO by default: most of the sticky-offset maths in this file predates the
     bar, and a page without one (no categories yet, or a signed-out visitor
     while the login gate is on) must keep exactly the old numbers. The real
     value is switched on by the :root:has() rule in section 30c, which fires
     only when base.php actually rendered the bar. Kept deliberately constant
     across breakpoints: --shell-h feeds scroll-padding-top, and an offset that
     changed with the viewport would land anchor jumps in the wrong place. */
  --cat-bar-h: 0px;

  /* The FULL height of the sticky unit: header row + category bar. Anything that
     needs to clear the header must use this, not --header-h. */
  --shell-h: calc(var(--header-h) + var(--cat-bar-h));

  /* Z-index ladder */
  --z-header: 100;
  --z-dropdown: 200;
  --z-modal: 900;
  --z-toast: 1000;
}

/* ==========================================================================
   02. Reset & base
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* --shell-h, not --header-h: post TASK 2 the sticky unit is the header row PLUS
     the category bar, so an anchor jump has to clear both or the target lands
     underneath the chips. --cat-bar-h is 0 when there is no bar, which reduces
     this to the value it has always had. */
  scroll-padding-top: calc(var(--shell-h) + var(--space-4));
  color-scheme: dark;
}

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  color: var(--color-text);
  background-color: var(--color-bg);
  /* Two whisper-thin grid layers plus one cold green bloom top-left. The grid
     is what makes the surface read as a terminal rather than as flat black. */
  background-image:
    radial-gradient(760px 420px at 8% -10%, rgba(var(--acher-primary-rgb), 0.055), transparent 62%),
    radial-gradient(900px 620px at 88% 108%, rgba(var(--acher-primary-rgb), 0.035), transparent 68%),
    linear-gradient(rgba(255, 255, 255, 0.014) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.014) 1px, transparent 1px);
  background-size: auto, auto, 44px 44px, 44px 44px;
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Headings are the display face: Share Tech Mono, tracked out, never italic.
   Share Tech Mono has a single weight, so weight is expressed with colour and
   letter-spacing instead of boldness. */
h1, h2, h3, h4, h5, h6 {
  margin: 0 0 var(--space-3);
  font-family: var(--font-display);
  font-weight: 400;
  line-height: var(--lh-tight);
  letter-spacing: 0.01em;
  text-transform: none;
}

h1 { font-size: var(--fs-2xl); letter-spacing: 0.005em; }
h2 { font-size: var(--fs-xl); }
h3 { font-size: var(--fs-lg); }
h4 { font-size: var(--fs-md); }
h5, h6 { font-size: var(--fs-base); }

p {
  margin: 0 0 var(--space-4);
}

p:last-child {
  margin-bottom: 0;
}

a {
  color: var(--color-text);
  text-decoration: none;
  transition: color var(--transition), opacity var(--transition);
}

a:hover {
  color: #7dff9b;
}

ul, ol {
  margin: 0;
  padding: 0;
}

li {
  list-style: none;
}

img, svg, video, canvas {
  display: block;
  max-width: 100%;
  height: auto;
}

button, input, select, textarea {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  background: none;
  border: 0;
}

hr {
  border: 0;
  border-top: 1px solid var(--color-border);
  margin: var(--space-6) 0;
}

code, pre, kbd, samp {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

code {
  padding: 0.12em 0.4em;
  border-radius: var(--radius-sm);
  background: var(--color-glass);
  border: 1px solid var(--color-border);
}

::selection {
  background: rgba(var(--acher-primary-rgb), 0.30);
  color: var(--acher-text);
}

/* Custom scrollbar: a thin green rail on a black track, square like the rest
   of the system. Firefox gets the two-value shorthand, Chromium the pseudos. */
html {
  scrollbar-width: thin;
  scrollbar-color: #2d2d2d var(--acher-bg-deep);
}

::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

::-webkit-scrollbar-track {
  background: var(--acher-bg-deep);
}

::-webkit-scrollbar-corner {
  background: var(--acher-bg-deep);
}

::-webkit-scrollbar-thumb {
  background: #2d2d2d;
  border-radius: 0;
  border: 2px solid var(--acher-bg-deep);
}

::-webkit-scrollbar-thumb:hover {
  background: rgba(var(--acher-primary-rgb), 0.45);
}

::-webkit-scrollbar-thumb:active {
  background: var(--acher-primary-dim);
}

/* ==========================================================================
   03. Accessibility helpers
   ========================================================================== */

/* The focus ring is ALWAYS visible and ALWAYS green. Nothing in this file may
   set `outline: none` on a :focus-visible state - remove the ring and the app
   becomes unusable by keyboard. */
:focus {
  outline: none;
}

:focus-visible {
  outline: 2px solid var(--acher-primary);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--acher-primary);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(var(--acher-primary-rgb), 0.18);
}

.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -100px;
  left: var(--space-4);
  z-index: calc(var(--z-toast) + 1);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-sm);
  background: var(--acher-primary);
  color: var(--color-on-primary);
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: top var(--transition);
}

.skip-link:focus {
  top: var(--space-4);
  color: var(--color-on-primary);
}

.noscript-banner {
  padding: var(--space-3) var(--container-pad);
  background: var(--tint-warn);
  border-bottom: 1px solid rgba(255, 170, 0, 0.4);
  color: #ffd88a;
  font-size: var(--fs-sm);
  text-align: center;
}

/* ==========================================================================
   04. Layout primitives
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

.page {
  display: block;
  min-height: 60vh;
  padding-block: var(--space-8) var(--space-16);
}

.section {
  margin-block: var(--space-12);
}

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}

.section-title {
  margin: 0;
  font-size: var(--fs-xl);
}

.section-subtitle {
  margin: var(--space-1) 0 0;
  color: var(--color-muted);
  font-size: var(--fs-sm);
}

.grid {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fill, minmax(var(--min, 260px), 1fr));
}

.grid-2 { --min: 380px; }
.grid-3 { --min: 300px; }
.grid-4 { --min: 230px; }

.flex {
  display: flex;
  gap: var(--space-3);
}

.flex-col { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
.items-start { align-items: flex-start; }
.items-center { align-items: center; }
.items-end { align-items: flex-end; }
.justify-between { justify-content: space-between; }
.justify-center { justify-content: center; }
.justify-end { justify-content: flex-end; }
.flex-1 { flex: 1 1 auto; min-width: 0; }
.gap-1 { gap: var(--space-1); }
.gap-2 { gap: var(--space-2); }
.gap-3 { gap: var(--space-3); }
.gap-4 { gap: var(--space-4); }
.gap-6 { gap: var(--space-6); }

.stack > * + * {
  margin-top: var(--space-4);
}

.text-center { text-align: center; }
.text-right { text-align: right; }
.text-sm { font-size: var(--fs-sm); }
.text-xs { font-size: var(--fs-xs); }
.text-lg { font-size: var(--fs-lg); }
.font-semibold { font-weight: 600; }
.font-bold { font-weight: 700; }
.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.clamp-3 {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.mt-0 { margin-top: 0; }
.mt-2 { margin-top: var(--space-2); }
.mt-4 { margin-top: var(--space-4); }
.mt-6 { margin-top: var(--space-6); }
.mt-8 { margin-top: var(--space-8); }
.mb-0 { margin-bottom: 0; }
.mb-2 { margin-bottom: var(--space-2); }
.mb-4 { margin-bottom: var(--space-4); }
.mb-6 { margin-bottom: var(--space-6); }
.mb-8 { margin-bottom: var(--space-8); }
.w-full { width: 100%; }
.hidden { display: none !important; }

.divider {
  height: 1px;
  background: var(--color-border);
  margin-block: var(--space-6);
}

/* ==========================================================================
   05. Surfaces
   ========================================================================== */

.glass {
  background: var(--color-glass);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  backdrop-filter: blur(12px) saturate(140%);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--color-glass);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  backdrop-filter: blur(12px) saturate(140%);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition), box-shadow var(--transition),
    border-color var(--transition), background-color var(--transition);
}

.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(140deg, rgba(0, 255, 65, 0.16), rgba(0, 204, 51, 0.08) 55%, transparent 80%);
  transition: opacity var(--transition);
}

.card:hover {
  transform: translateY(-2px);
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow-glow), var(--shadow-md);
}

.card:hover::after {
  opacity: 1;
}

.card:focus-within {
  border-color: rgba(0, 255, 65, 0.55);
}

.card-body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5);
  flex: 1 1 auto;
}

.card-header {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.card-footer {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
}

.card-title {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: 650;
  line-height: var(--lh-snug);
}

.card-text {
  margin: 0;
  color: var(--color-muted);
  font-size: var(--fs-sm);
}

.card-media {
  position: relative;
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: linear-gradient(140deg, #101010, #0a0a0a);
  border-bottom: 1px solid var(--color-border);
}

.card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--transition-slow);
}

.card:hover .card-media img {
  transform: scale(1.04);
}

.card-media-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: rgba(154, 154, 154, 0.55);
  font-size: var(--fs-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.card-link {
  color: inherit;
}

.card-link:hover {
  color: inherit;
}

/* ==========================================================================
   06. Site header & navigation
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: rgba(8, 8, 8, 0.86);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid var(--color-border);
}

/* One hairline of green under the header - the only chrome the shell needs. */
.site-header::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(var(--acher-primary-rgb), 0.35) 22%,
    rgba(var(--acher-primary-rgb), 0.10) 60%,
    transparent 100%
  );
  pointer-events: none;
}

/* THE WRAP RULE HAS TWO HALVES AND BOTH ARE LOAD-BEARING.

   BELOW 900px - wrap:
   .site-nav carries flex-basis:100% so the burger menu drops onto its own
   full-width row under the brand. Without wrap it is forced to share the brand's
   row and collapses into a narrow column on the right. It costs no height while
   the menu is shut, because .site-nav is display:none until #nav-toggle is
   checked - so the phone header is one visible row: lockup + cart + credit, then
   the burger.

   FROM 900px UP - nowrap (section 23, TASK 1):
   the desktop header used to wrap here too, and that was the bug: at 1280px
   .site-header-inner measured 107px against a 72px row because .header-lead
   (359px) + .site-nav's content (777px) + the 16px gap came to 1152px in a
   1136px container - it missed by SIXTEEN pixels and spent a whole extra row on
   it. flex-wrap:nowrap at that breakpoint makes the miss impossible to express:
   there is only ever one line, so an over-full row shrinks its flexible items
   (the credit chip's unit word, the username) instead of dropping one onto a
   second line. TASK 7's search box removal and TASK 1's consolidation of Admin +
   Redeem code into the account menu are what bought the room to make that safe -
   the same row now measures ~826px - but nowrap is the guarantee, not the
   headroom. */
.site-header-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  min-height: var(--header-h);
  padding-block: var(--space-2);
}

/* --------------------------------------------------------------------------
   The ACHER logo lockup.

   static/img/logo.png does not exist yet, so the mark has to survive a 404
   with no broken-image icon and no inline onerror handler (CSP: script-src
   'self'). The construction:

     .brand-logo        relative box, sized by the wordmark inside it
       .brand-wordmark  real text, "ACHER" in Share Tech Mono - ALWAYS rendered
       .brand-logo-img  <img alt="" > absolutely positioned ON TOP of it

   alt="" is load-bearing: per the HTML spec an unavailable image with an empty
   alt "represents nothing", so a missing file paints nothing at all - no icon,
   no alt text - and the wordmark underneath is what you see. When the file does
   land, the image paints over the wordmark and hides it.
   -------------------------------------------------------------------------- */

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 400;
}

.brand:hover {
  color: var(--color-text);
}

/* Fixed width, so the header reserves room for the artwork before it exists
   and a wide logo can never shove the nav sideways. Draw logo.png at roughly
   4:1 (128x32 or 256x64) and it will land exactly in this box. */
.brand-logo {
  position: relative;
  display: inline-flex;
  align-items: center;
  width: 132px;
  height: 32px;
}

.brand-logo-img {
  position: absolute;
  top: 50%;
  left: 0;
  height: 32px;
  width: auto;
  max-width: 100%;
  transform: translateY(-50%);
  object-fit: contain;
  object-position: left center;
  /* Masks the wordmark underneath once real artwork loads, even if the PNG is
     transparent. Safe for the missing-file case: a failed alt="" image has a
     zero-width box, so this background has no area to paint (verified in
     Chromium; the spec says such an image "represents nothing"). */
  background-color: var(--acher-bg);
  /* Neon lift on the supplied artwork. */
  filter: drop-shadow(0 0 6px rgba(var(--acher-primary-rgb), 0.55))
          drop-shadow(0 0 18px rgba(var(--acher-primary-rgb), 0.25));
}

.brand-wordmark {
  font-family: var(--font-display);
  font-size: 1.28rem;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.34em;
  /* The trailing letter-space would otherwise push the lockup off-centre. */
  margin-right: -0.34em;
  color: var(--acher-primary);
  text-shadow: var(--acher-glow-text);
  text-transform: uppercase;
  white-space: nowrap;
}

.brand-logo-img[src=""],
.brand-logo-img:not([src]) {
  display: none;
}

/* Kept for the small square glyph some surfaces still render beside the name. */
.brand-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  color: var(--color-on-primary);
  background: var(--gradient-primary);
  box-shadow: var(--shadow-glow);
}

.brand-name {
  font-family: var(--font-display);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--acher-primary);
  text-shadow: var(--acher-glow-text);
}

.nav-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.nav-burger {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 42px;
  height: 42px;
  margin-left: auto;
  padding: 0 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-glass);
  cursor: pointer;
  transition: border-color var(--transition), background-color var(--transition);
}

.nav-burger:hover {
  border-color: var(--color-border-strong);
  background: var(--color-glass-strong);
}

.nav-burger-bar {
  display: block;
  height: 2px;
  width: 100%;
  border-radius: 2px;
  background: var(--color-text);
  transition: transform var(--transition), opacity var(--transition);
}

.nav-toggle:focus-visible + .nav-burger {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.nav-toggle:checked + .nav-burger .nav-burger-bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle:checked + .nav-burger .nav-burger-bar:nth-child(2) {
  opacity: 0;
}

.nav-toggle:checked + .nav-burger .nav-burger-bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.site-nav {
  display: none;
  flex-basis: 100%;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-4) 0 var(--space-5);
  border-top: 1px solid var(--color-border);
  margin-top: var(--space-2);
}

.nav-toggle:checked ~ .site-nav {
  display: flex;
  animation: fade-slide-down 0.22s ease;
}

.nav-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.nav-cell {
  position: relative;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-muted);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* TASK 1: on a nowrap desktop row an over-full line shrinks its items, and a
     shrunk .nav-item would break "Categories" across two lines and grow the
     header the very way nowrap exists to prevent. The label stays on one line;
     the flexible chips beside it give way instead. */
  white-space: nowrap;
  transition: color var(--transition), background-color var(--transition);
}

.nav-item:hover {
  color: var(--acher-primary);
  background: var(--color-glass);
}

.nav-item.is-active {
  color: var(--acher-primary);
  background: var(--tint-primary);
  box-shadow: inset 2px 0 0 0 var(--acher-primary);
}

.nav-drop {
  width: 100%;
}

.nav-summary {
  cursor: pointer;
  list-style: none;
  justify-content: space-between;
}

.nav-summary::-webkit-details-marker {
  display: none;
}

.nav-summary::marker {
  content: "";
}

.nav-chevron {
  transition: transform var(--transition);
  flex: 0 0 auto;
}

.nav-drop[open] > .nav-summary .nav-chevron {
  transform: rotate(180deg);
}

.nav-dropdown {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: var(--space-1) 0 var(--space-2) var(--space-3);
  padding: var(--space-2);
  border-left: 2px solid var(--color-border);
}

.nav-dropdown-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-muted);
  font-size: var(--fs-sm);
  transition: color var(--transition), background-color var(--transition);
}

.nav-dropdown-item:hover {
  color: var(--color-text);
  background: var(--color-glass);
}

.nav-dropdown-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-sm);
  background: var(--tint-primary);
  font-size: var(--fs-xs);
}

.nav-dropdown-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-dropdown-empty {
  padding: var(--space-2) var(--space-3);
  color: var(--color-muted);
  font-size: var(--fs-sm);
  font-style: italic;
}

.nav-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.user-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  max-width: 200px;
  padding: var(--space-1) var(--space-3) var(--space-1) var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-glass);
  font-size: var(--fs-xs);
  color: var(--color-muted);
}

.user-chip-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--gradient-primary);
  color: var(--color-on-primary);
  font-weight: 700;
  font-size: var(--fs-xs);
}

.user-chip-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.logout-form {
  display: inline-flex;
  margin: 0;
}

/* ==========================================================================
   07. Site footer
   ========================================================================== */

.site-footer {
  margin-top: var(--space-16);
  padding-block: var(--space-12) var(--space-8);
  background: rgba(5, 5, 5, 0.72);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--color-border);
}

.footer-grid {
  display: grid;
  gap: var(--space-8);
  grid-template-columns: 1fr;
}

.footer-brand {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 380px;
}

.brand-footer {
  font-size: var(--fs-base);
}

.footer-tagline {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-loose);
}

.social-list {
  display: flex;
  gap: var(--space-2);
}

.social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-glass);
  color: var(--color-muted);
  transition: color var(--transition), border-color var(--transition),
    transform var(--transition), background-color var(--transition);
}

.social-link:hover {
  color: var(--color-text);
  border-color: rgba(0, 255, 65, 0.5);
  background: var(--tint-primary);
  transform: translateY(-2px);
}

.footer-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.footer-heading {
  margin: 0;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-muted);
}

.footer-links {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.footer-links a {
  color: var(--color-muted);
  font-size: var(--fs-sm);
}

.footer-links a:hover {
  color: var(--color-text);
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-10);
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-border);
  font-size: var(--fs-xs);
}

.footer-bottom p {
  margin: 0;
}

.footer-note {
  opacity: 0.8;
}

/* ==========================================================================
   08. Hero
   ========================================================================== */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: clamp(2.5rem, 6vw, 5rem) clamp(1.25rem, 4vw, 3.5rem);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--gradient-hero);
  background-size: 400% 400%;
  animation: gradient-shift 8s ease infinite;
  box-shadow: var(--shadow-lg);
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(560px 320px at 18% 20%, rgba(0, 255, 65, 0.42), transparent 62%),
    radial-gradient(520px 300px at 82% 12%, rgba(0, 204, 51, 0.32), transparent 64%),
    radial-gradient(700px 420px at 60% 108%, rgba(0, 255, 65, 0.24), transparent 70%);
  pointer-events: none;
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0.35;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px);
  background-size: 46px 46px;
  -webkit-mask-image: radial-gradient(circle at 50% 40%, #000 0%, transparent 72%);
  mask-image: radial-gradient(circle at 50% 40%, #000 0%, transparent 72%);
}

.hero-inner {
  display: grid;
  gap: var(--space-8);
  grid-template-columns: 1fr;
  align-items: center;
}

.hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.06);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #a8ffbf;
}

.hero-title {
  margin: var(--space-4) 0 var(--space-3);
  font-size: var(--fs-3xl);
  font-weight: 800;
  letter-spacing: -0.03em;
}

.hero-title .accent {
  background: var(--gradient-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.hero-lead {
  max-width: 56ch;
  margin: 0 0 var(--space-6);
  color: #c8c8c8;
  font-size: var(--fs-md);
  line-height: var(--lh-loose);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.hero-visual {
  position: relative;
  display: none;
  min-height: 260px;
}

.hero-card {
  position: relative;
  padding: var(--space-5);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.06);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: var(--shadow-lg);
  animation: float 6s ease-in-out infinite;
}

.hero-card + .hero-card {
  margin-top: var(--space-4);
  animation-delay: 1.2s;
}

.hero-stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
  margin-top: var(--space-8);
  padding-top: var(--space-6);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}

/* ==========================================================================
   09. Buttons & spinner
   ========================================================================== */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0.68rem 1.3rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-glass);
  color: var(--color-text);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0.1em;
  text-align: center;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  transition: transform var(--transition), box-shadow var(--transition),
    background-color var(--transition), border-color var(--transition),
    color var(--transition), opacity var(--transition);
}

.btn:hover {
  color: var(--color-text);
  border-color: var(--color-border-strong);
  background: var(--color-glass-strong);
  transform: translateY(-1px);
}

.btn:active {
  transform: translateY(0);
}

.btn:disabled,
.btn.is-disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
  pointer-events: none;
}

.btn-primary {
  border-color: transparent;
  background: var(--gradient-primary);
  color: var(--color-on-primary);
  box-shadow: 0 6px 18px rgba(0, 255, 65, 0.35);
}

.btn-primary:hover {
  color: var(--color-on-primary);
  border-color: transparent;
  background: var(--gradient-primary);
  box-shadow: var(--shadow-glow), 0 10px 26px rgba(0, 255, 65, 0.45);
}

.btn-ghost {
  background: transparent;
  border-color: var(--color-border);
  color: var(--color-muted);
}

.btn-ghost:hover {
  background: var(--color-glass);
  color: var(--color-text);
}

.btn-danger {
  border-color: rgba(255, 45, 45, 0.45);
  background: var(--tint-danger);
  color: #ffb3b3;
}

.btn-danger:hover {
  background: rgba(255, 45, 45, 0.24);
  border-color: rgba(255, 45, 45, 0.7);
  color: #ffffff;
  box-shadow: 0 0 20px rgba(255, 45, 45, 0.28);
}

.btn-success {
  border-color: rgba(0, 255, 65, 0.45);
  background: var(--tint-success);
  color: #a8ffbf;
}

.btn-success:hover {
  background: rgba(0, 255, 65, 0.24);
  color: var(--acher-text);
}

.btn-sm {
  padding: 0.4rem 0.85rem;
  font-size: var(--fs-xs);
  border-radius: var(--radius-sm);
}

.btn-lg {
  padding: 0.9rem 1.8rem;
  font-size: var(--fs-md);
}

.btn-block {
  display: flex;
  width: 100%;
}

.btn-icon {
  padding: 0.5rem;
  width: 36px;
  height: 36px;
}

.btn-group {
  display: inline-flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.spinner {
  display: inline-block;
  width: 1em;
  height: 1em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  vertical-align: -0.125em;
  animation: spin 0.7s linear infinite;
}

.spinner-lg {
  width: 2.2rem;
  height: 2.2rem;
  border-width: 3px;
}

.btn.is-loading {
  color: transparent !important;
  pointer-events: none;
}

.btn.is-loading::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1.1em;
  height: 1.1em;
  margin: -0.55em 0 0 -0.55em;
  border: 2px solid rgba(255, 255, 255, 0.85);
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

/* ==========================================================================
   10. Forms
   ========================================================================== */

.form-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.form-row {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}

.label {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-muted);
}

.label .required {
  color: var(--color-danger);
}

.input,
.select,
.textarea {
  width: 100%;
  padding: 0.68rem 0.9rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.04);
  color: var(--color-text);
  font-size: var(--fs-sm);
  line-height: 1.45;
  transition: border-color var(--transition), box-shadow var(--transition),
    background-color var(--transition);
  -webkit-appearance: none;
  appearance: none;
}

.input::placeholder,
.textarea::placeholder {
  color: rgba(154, 154, 154, 0.7);
}

.input:hover,
.select:hover,
.textarea:hover {
  border-color: var(--color-border-strong);
}

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: rgba(0, 255, 65, 0.75);
  background: rgba(255, 255, 255, 0.07);
  box-shadow: 0 0 0 3px rgba(0, 255, 65, 0.22);
}

.input:disabled,
.select:disabled,
.textarea:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.textarea {
  min-height: 130px;
  resize: vertical;
  line-height: var(--lh-base);
}

.select {
  padding-right: 2.4rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239a9a9a' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.8rem center;
  background-size: 16px 16px;
}

.select option {
  background: var(--color-bg-elev);
  color: var(--color-text);
}

.input.is-invalid,
.select.is-invalid,
.textarea.is-invalid,
.input:user-invalid,
.textarea:user-invalid {
  border-color: rgba(255, 45, 45, 0.75);
  box-shadow: 0 0 0 3px rgba(255, 45, 45, 0.18);
}

.input.is-valid,
.select.is-valid {
  border-color: rgba(0, 255, 65, 0.7);
}

.form-hint {
  font-size: var(--fs-xs);
  color: var(--color-muted);
}

.form-error {
  font-size: var(--fs-xs);
  color: #ff8f8f;
}

.input-group {
  display: flex;
  gap: var(--space-2);
  align-items: stretch;
  flex-wrap: wrap;
}

.input-group .input {
  flex: 1 1 180px;
}

.checkbox,
.radio {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-sm);
  color: var(--color-muted);
  cursor: pointer;
}

.checkbox input,
.radio input {
  width: 18px;
  height: 18px;
  accent-color: var(--color-primary);
  cursor: pointer;
}

.fieldset {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-5);
  margin: 0 0 var(--space-5);
}

.fieldset legend {
  padding-inline: var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-muted);
}

/* ==========================================================================
   11. Badges, tags, price, alerts, empty state
   ========================================================================== */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 0.18rem 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-glass);
  color: var(--color-muted);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
}

.badge-success {
  border-color: rgba(0, 255, 65, 0.42);
  background: var(--tint-success);
  color: #7dff9b;
}

.badge-warn {
  border-color: rgba(255, 170, 0, 0.42);
  background: var(--tint-warn);
  color: #ffcc55;
}

.badge-danger {
  border-color: rgba(255, 45, 45, 0.42);
  background: var(--tint-danger);
  color: #ff8f8f;
}

.badge-primary {
  border-color: rgba(0, 255, 65, 0.45);
  background: var(--tint-primary);
  color: #7dff9b;
}

.badge-accent {
  border-color: rgba(0, 204, 51, 0.45);
  background: var(--tint-accent);
  color: #5cffa0;
}

.badge-dot::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 0.2rem 0.65rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.04);
  color: var(--color-muted);
  font-size: var(--fs-xs);
  letter-spacing: 0.02em;
  transition: color var(--transition), border-color var(--transition),
    background-color var(--transition);
}

a.tag:hover {
  color: var(--color-text);
  border-color: rgba(0, 255, 65, 0.5);
  background: var(--tint-primary);
}

.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.price {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: var(--fs-md);
  color: var(--color-text);
  letter-spacing: -0.01em;
}

.price-lg {
  font-size: var(--fs-xl);
}

.price-old {
  margin-left: var(--space-2);
  color: var(--color-muted);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-decoration: line-through;
}

.muted {
  color: var(--color-muted);
}

.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--color-border);
  border-left-width: 3px;
  border-radius: var(--radius-sm);
  background: var(--color-glass);
  color: var(--color-text);
  font-size: var(--fs-sm);
  line-height: var(--lh-base);
}

.alert p {
  margin: 0;
}

.alert-info {
  border-left-color: var(--color-accent);
  background: var(--tint-accent);
}

.alert-success {
  border-left-color: var(--color-success);
  background: var(--tint-success);
}

.alert-warn {
  border-left-color: var(--color-warn);
  background: var(--tint-warn);
}

.alert-danger {
  border-left-color: var(--color-danger);
  background: var(--tint-danger);
}

.alert-title {
  display: block;
  margin-bottom: var(--space-1);
  font-weight: 700;
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-16) var(--space-6);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.02);
  text-align: center;
}

.empty-state-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: var(--tint-primary);
  color: #7dff9b;
}

.empty-state h2,
.empty-state h3 {
  margin: 0;
  font-size: var(--fs-lg);
}

.empty-state p {
  margin: 0;
  max-width: 46ch;
  color: var(--color-muted);
  font-size: var(--fs-sm);
}

/* ==========================================================================
   12. Tables
   ========================================================================== */

.table-wrap {
  width: 100%;
  overflow-x: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-glass);
  -webkit-overflow-scrolling: touch;
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}

.table caption {
  padding: var(--space-3) var(--space-4);
  color: var(--color-muted);
  font-size: var(--fs-xs);
  text-align: left;
}

.table thead th {
  position: relative;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--color-muted);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: left;
  white-space: nowrap;
}

.table tbody td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  vertical-align: middle;
}

.table tbody tr:last-child td {
  border-bottom: 0;
}

.table tbody tr {
  transition: background-color var(--transition);
}

.table tbody tr:hover {
  background: rgba(255, 255, 255, 0.04);
}

.table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.table .actions {
  display: flex;
  gap: var(--space-2);
  justify-content: flex-end;
}

/* ==========================================================================
   13. Breadcrumb & pagination
   ========================================================================== */

.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
  font-size: var(--fs-xs);
  color: var(--color-muted);
}

.breadcrumb a {
  color: var(--color-muted);
}

.breadcrumb a:hover {
  color: var(--color-text);
}

.breadcrumb li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.breadcrumb li + li::before {
  content: "/";
  opacity: 0.45;
}

.breadcrumb .is-current {
  color: var(--color-text);
  font-weight: 600;
}

.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-10);
}

.pagination a,
.pagination span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  height: 38px;
  padding-inline: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-glass);
  color: var(--color-muted);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  transition: color var(--transition), border-color var(--transition),
    background-color var(--transition), transform var(--transition);
}

.pagination a:hover {
  color: var(--color-text);
  border-color: var(--color-border-strong);
  background: var(--color-glass-strong);
  transform: translateY(-1px);
}

.pagination .is-active {
  border-color: transparent;
  background: var(--gradient-primary);
  color: var(--color-on-primary);
  font-weight: 700;
  box-shadow: 0 4px 14px rgba(0, 255, 65, 0.35);
}

.pagination .is-disabled {
  opacity: 0.4;
  pointer-events: none;
}

.pagination-info {
  width: 100%;
  margin-top: var(--space-2);
  text-align: center;
  color: var(--color-muted);
  font-size: var(--fs-xs);
}

/* ==========================================================================
   14. Stats
   ========================================================================== */

.stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-glass);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  transition: transform var(--transition), box-shadow var(--transition),
    border-color var(--transition);
}

.stat:hover {
  transform: translateY(-2px);
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow-glow);
}

.stat-value {
  font-size: var(--fs-2xl);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  background: var(--gradient-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.stat-label {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-muted);
}

.stat-delta {
  font-size: var(--fs-xs);
  font-weight: 600;
}

.stat-delta.is-up { color: var(--color-success); }
.stat-delta.is-down { color: var(--color-danger); }

/* ==========================================================================
   15. Modal
   ========================================================================== */

.modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--transition), visibility var(--transition);
}

.modal.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: var(--color-overlay);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

.modal-panel {
  position: relative;
  z-index: 1;
  width: min(640px, 100%);
  max-height: min(85vh, 900px);
  overflow-y: auto;
  padding: var(--space-6);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: rgba(15, 15, 15, 0.96);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  box-shadow: var(--shadow-lg);
  transform: scale(0.94) translateY(12px);
  opacity: 0;
  transition: transform var(--transition-slow), opacity var(--transition);
}

.modal.is-open .modal-panel {
  transform: scale(1) translateY(0);
  opacity: 1;
}

.modal-panel-lg {
  width: min(900px, 100%);
}

.modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
}

.modal-title {
  margin: 0;
  font-size: var(--fs-lg);
}

.modal-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: 0 0 auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-glass);
  color: var(--color-muted);
  font-size: 1.1rem;
  line-height: 1;
  transition: color var(--transition), background-color var(--transition);
}

.modal-close:hover {
  color: var(--color-text);
  background: var(--color-glass-strong);
}

.modal-body {
  font-size: var(--fs-sm);
  line-height: var(--lh-base);
}

.modal-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

body.modal-open {
  overflow: hidden;
}

/* ==========================================================================
   16. Toasts
   ========================================================================== */

.toast-container {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: min(360px, calc(100vw - 2 * var(--space-4)));
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-accent);
  border-radius: var(--radius-sm);
  background: rgba(15, 15, 15, 0.96);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  box-shadow: var(--shadow-md);
  color: var(--color-text);
  font-size: var(--fs-sm);
  line-height: 1.45;
  pointer-events: auto;
  animation: toast-in 0.26s cubic-bezier(0.22, 1, 0.36, 1);
}

.toast.is-leaving {
  animation: toast-out 0.22s ease forwards;
}

.toast-info { border-left-color: var(--color-accent); }
.toast-success { border-left-color: var(--color-success); }
.toast-warn,
.toast-warning { border-left-color: var(--color-warn); }
.toast-error,
.toast-danger { border-left-color: var(--color-danger); }

.toast-icon {
  flex: 0 0 auto;
  margin-top: 2px;
}

.toast-info .toast-icon { color: var(--color-accent); }
.toast-success .toast-icon { color: var(--color-success); }
.toast-warn .toast-icon,
.toast-warning .toast-icon { color: var(--color-warn); }
.toast-error .toast-icon,
.toast-danger .toast-icon { color: var(--color-danger); }

.toast-message {
  flex: 1 1 auto;
  min-width: 0;
  word-break: break-word;
}

.toast-close {
  flex: 0 0 auto;
  padding: 0 var(--space-1);
  color: var(--color-muted);
  font-size: 1rem;
  line-height: 1;
}

.toast-close:hover {
  color: var(--color-text);
}

/* ==========================================================================
   17. Skeletons
   ========================================================================== */

.skeleton {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.06);
  color: transparent !important;
  user-select: none;
}

.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.10) 50%,
    transparent 100%
  );
  animation: shimmer 1.4s infinite;
}

.skeleton-text {
  height: 0.85em;
  margin-block: 0.28em;
}

.skeleton-title {
  height: 1.4em;
  width: 60%;
}

.skeleton-media {
  aspect-ratio: 16 / 10;
  width: 100%;
  border-radius: var(--radius);
}

.skeleton-line-sm { width: 40%; }
.skeleton-line-md { width: 70%; }
.skeleton-line-lg { width: 90%; }

/* ==========================================================================
   18. Product & variant cards
   ========================================================================== */

.product-layout {
  display: grid;
  gap: var(--space-8);
  grid-template-columns: 1fr;
  align-items: start;
}

.product-gallery {
  overflow: hidden;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: linear-gradient(140deg, #101010, #0a0a0a);
}

.product-gallery img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.product-title {
  margin-bottom: var(--space-2);
  font-size: var(--fs-2xl);
}

.product-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
  color: var(--color-muted);
  font-size: var(--fs-sm);
}

.product-description {
  color: #c8c8c8;
  font-size: var(--fs-sm);
  line-height: var(--lh-loose);
  white-space: pre-line;
}

.product-purchase {
  position: sticky;
  top: calc(var(--header-h) + var(--space-4));
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-glass);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

#variant-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

.variant-card {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.03);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--transition), background-color var(--transition),
    transform var(--transition), box-shadow var(--transition);
}

.variant-card:hover {
  border-color: var(--color-border-strong);
  background: var(--color-glass);
  transform: translateY(-1px);
}

.variant-card .variant-name {
  display: block;
  font-weight: 650;
  font-size: var(--fs-sm);
}

.variant-card .variant-desc {
  display: block;
  margin-top: var(--space-1);
  color: var(--color-muted);
  font-size: var(--fs-xs);
  line-height: 1.5;
}

.variant-card .variant-price {
  flex: 0 0 auto;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.variant-card .variant-stock {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--fs-xs);
  color: var(--color-muted);
  text-align: right;
}

.variant-card.is-selected {
  border-color: rgba(0, 255, 65, 0.85);
  background: var(--tint-primary);
  box-shadow: var(--shadow-glow);
}

.variant-card.is-selected .variant-name {
  color: var(--acher-primary-soft);
}

.variant-card.is-disabled,
.variant-card[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  filter: grayscale(0.5);
  pointer-events: none;
}

.variant-card.is-disabled:hover {
  transform: none;
  box-shadow: none;
}

.qty-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

#qty-input {
  width: 96px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

#buy-button {
  width: 100%;
}

.stock-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-xs);
  color: var(--color-success);
}

.stock-pill.is-low { color: var(--color-warn); }
.stock-pill.is-out { color: var(--color-danger); }

/* ==========================================================================
   19. Checkout summary & gift code
   ========================================================================== */

.checkout-layout {
  display: grid;
  gap: var(--space-8);
  grid-template-columns: 1fr;
  align-items: start;
}

.summary {
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-glass);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

.summary-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-2);
  font-size: var(--fs-sm);
  color: var(--color-muted);
}

/* display:flex above beats the UA [hidden] rule, so restate it - otherwise the
   discount row is visible before main.js boots and forever without JS. */
.summary-row[hidden] {
  display: none;
}

.summary-row span:last-child {
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
}

#summary-discount-row {
  color: var(--color-success);
}

#summary-discount-row span:last-child {
  color: var(--color-success);
}

.summary-total {
  margin-top: var(--space-3);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--color-text);
}

.summary-total span:last-child {
  font-size: var(--fs-lg);
}

.gift-code-box {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-block: var(--space-4);
  padding: var(--space-4);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.02);
}

.gift-code-row {
  display: flex;
  gap: var(--space-2);
}

#gift-code-input {
  flex: 1 1 auto;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-family: var(--font-mono);
}

#gift-code-feedback {
  min-height: 1.2em;
  font-size: var(--fs-xs);
  color: var(--color-muted);
}

#gift-code-feedback.is-valid { color: var(--color-success); }
#gift-code-feedback.is-invalid { color: var(--color-danger); }

.order-line {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-block: var(--space-3);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.order-line:last-child {
  border-bottom: 0;
}

.order-line-thumb {
  flex: 0 0 auto;
  width: 54px;
  height: 54px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  object-fit: cover;
  background: var(--color-bg-elev);
}

.order-line-body {
  flex: 1 1 auto;
  min-width: 0;
}

.order-line-name {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 600;
}

.order-line-meta {
  display: block;
  color: var(--color-muted);
  font-size: var(--fs-xs);
}

.order-line-price {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-weight: 650;
}

.order-status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

/* ==========================================================================
   20. Filter bar
   ========================================================================== */

#filter-form,
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-glass);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

#filter-form .form-group,
.filter-bar .form-group {
  flex: 1 1 150px;
  min-width: 130px;
  margin-bottom: 0;
}

#filter-form .form-actions,
.filter-bar .form-actions {
  display: flex;
  gap: var(--space-2);
  flex: 0 0 auto;
}

.search-field {
  position: relative;
  flex: 2 1 240px;
}

.search-field .input {
  padding-left: 2.4rem;
}

.search-field-icon {
  position: absolute;
  top: 50%;
  left: 0.8rem;
  transform: translateY(-50%);
  color: var(--color-muted);
  pointer-events: none;
}

.category-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
}

.category-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  background: var(--tint-primary);
  color: #7dff9b;
  font-size: var(--fs-lg);
}

.subcategory-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
}

/* ==========================================================================
   21. Misc utilities
   ========================================================================== */

/* Generic state classes. Components layer their own rules on top
   (.modal.is-open, .variant-card.is-selected, ...); the bare versions below only
   set properties that can never fight a component's own layout mode. */
.is-open {
  visibility: visible;
}

.is-selected {
  border-color: rgba(0, 255, 65, 0.85);
}

.is-disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

.is-hidden { display: none !important; }

.ratio-16-9 {
  aspect-ratio: 16 / 9;
  width: 100%;
}

.scroll-x {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.center-box {
  width: min(460px, 100%);
  margin-inline: auto;
}

.auth-card {
  width: min(430px, 100%);
  margin: var(--space-12) auto;
  padding: var(--space-8);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-glass);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: var(--shadow-md);
}

.auth-card h1 {
  margin-bottom: var(--space-2);
  font-size: var(--fs-xl);
  text-align: center;
}

.auth-card .auth-sub {
  margin-bottom: var(--space-6);
  color: var(--color-muted);
  font-size: var(--fs-sm);
  text-align: center;
}

.error-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  padding-block: var(--space-20);
  text-align: center;
}

.error-code {
  font-size: clamp(4rem, 14vw, 8rem);
  font-weight: 800;
  line-height: 1;
  background: var(--gradient-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

/* ==========================================================================
   21b. Storefront template hooks
   The public templates (templates/index|category|product|checkout.php) emit
   the class names below. Everything reuses the section 01 tokens; grouped by
   page in template order so a markup change is easy to trace back here.
   Pure wrappers that need no rules of their own (.product-hero, .related-strip,
   .stats-band, .qty-group, ...) are deliberately absent.
   ========================================================================== */

/* ---- shared: section subtitles ------------------------------------------ */

.section-sub {
  margin: var(--space-1) 0 0;
  color: var(--color-muted);
  font-size: var(--fs-sm);
}

/* ---- shared: thumbnails -------------------------------------------------- */

/* Fixed-ratio frames: the <img>/placeholder fills its frame, so a late-loading
   image can never reflow the card around it (no layout shift). */
.thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.thumb-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: rgba(154, 154, 154, 0.55);
  background: linear-gradient(140deg, #101010, #0a0a0a);
}

.product-thumb {
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: linear-gradient(140deg, #101010, #0a0a0a);
  border-bottom: 1px solid var(--color-border);
}

.product-thumb img {
  transition: transform var(--transition-slow);
}

.product-card:hover .product-thumb img {
  transform: scale(1.04);
}

/* ---- shared: product cards (home grid, category grid, related strip) ----- */

.product-card-link {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  color: inherit;
}

.product-card-link:hover {
  color: inherit;
}

.product-name {
  margin: 0;
  font-size: var(--fs-md);
  line-height: var(--lh-snug);
}

.product-desc {
  flex: 1 1 auto;
  margin: 0;
  font-size: var(--fs-xs);
  line-height: 1.5;
}

.product-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.product-hover {
  position: absolute;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: 2;
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition: opacity var(--transition), transform var(--transition);
}

.product-card:hover .product-hover,
.product-card:focus-within .product-hover {
  opacity: 1;
  transform: translateY(0);
}

/* Sold-out cards are dimmed but must stay navigable: the generic .is-disabled
   pointer-events lock is for controls, not for a link to a product page. */
.product-card.is-disabled {
  opacity: 0.65;
  pointer-events: auto;
}

/* ---- home: hero ----------------------------------------------------------- */

.hero-glow {
  position: absolute;
  inset: -20%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(36rem 24rem at 20% 25%, rgba(0, 255, 65, 0.35), transparent 62%),
    radial-gradient(30rem 20rem at 80% 20%, rgba(0, 204, 51, 0.25), transparent 64%);
  filter: blur(26px);
}

.hero-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
}

.hero-sub {
  max-width: 56ch;
  margin: 0;
  font-size: var(--fs-md);
  line-height: var(--lh-loose);
}

.hero-title-accent {
  display: block;
  background: var(--gradient-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.hero-points {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--fs-sm);
}

.hero-points li {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.hero-points li::before {
  content: "\2713";
  color: var(--color-accent);
  font-weight: 700;
}

/* The floating product cards; hidden on small screens like .hero-visual. */
.hero-cards {
  display: none;
  flex-direction: column;
  gap: var(--space-4);
}

.hero-cards .card-body {
  flex-direction: row;
  align-items: center;
  gap: var(--space-4);
}

.float {
  animation: float 6s ease-in-out infinite;
  animation-delay: calc(var(--float-index, 0) * 1.2s);
}

.float-thumb {
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  overflow: hidden;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: linear-gradient(140deg, #101010, #0a0a0a);
}

.float-meta {
  min-width: 0;
}

.float-name {
  margin: var(--space-1) 0;
  font-size: var(--fs-sm);
}

/* ---- home: categories, steps, gift-code band ------------------------------ */

.category-card .card-body {
  align-items: flex-start;
}

.category-name {
  margin: 0;
  font-size: var(--fs-md);
}

.category-desc {
  flex: 1 1 auto;
  margin: 0;
  font-size: var(--fs-sm);
}

.step-number {
  font-size: var(--fs-lg);
  font-weight: 800;
  letter-spacing: 0.08em;
  background: var(--gradient-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.step-title {
  margin: 0;
  font-size: var(--fs-md);
}

.giftcode-band-body {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
}

.giftcode-copy {
  flex: 1 1 320px;
  max-width: 62ch;
}

.giftcode-cta {
  flex: 0 0 auto;
}

/* ---- category: hero, subcategory pills, sidebar layout -------------------- */

.hero-compact {
  padding: clamp(1.75rem, 4vw, 3rem) clamp(1.25rem, 4vw, 2.5rem);
}

.category-hero-body {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
}

.category-icon-lg {
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  font-size: var(--fs-xl);
}

.pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-5);
}

.category-layout {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
  align-items: start;
}

/* Section 20 styles a bare #filter-form as a horizontal bar; inside the
   sidebar card the .card column layout must win, hence the id+class override. */
#filter-form.filter-card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 0;
  margin-bottom: 0;
}

#filter-form.filter-card .form-group {
  flex: 0 0 auto;
}

.filter-title {
  margin: 0 0 var(--space-2);
  font-size: var(--fs-md);
}

.filter-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: 0;
}

.category-results {
  min-width: 0;
}

/* category.php marks the current page with .is-selected and renders "…" gaps. */
.pagination .is-selected {
  border-color: transparent;
  background: var(--gradient-primary);
  color: var(--color-on-primary);
  font-weight: 700;
  box-shadow: 0 4px 14px rgba(0, 255, 65, 0.35);
}

.pagination .page-gap {
  min-width: auto;
  padding-inline: var(--space-1);
  border: 0;
  background: none;
}

.breadcrumb-sep {
  opacity: 0.45;
}

/* ---- product page --------------------------------------------------------- */

.product-media {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.product-media-frame {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  background: linear-gradient(140deg, #101010, #0a0a0a);
}

.product-media-glow {
  position: absolute;
  inset: -15%;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(28rem 20rem at 70% 15%, rgba(0, 255, 65, 0.22), transparent 65%);
  filter: blur(18px);
}

.trust-badges {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.trust-badge {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  font-size: var(--fs-sm);
}

.trust-badge-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: var(--radius-sm);
  background: var(--tint-primary);
}

.trust-badge strong {
  display: block;
}

.trust-badge .muted {
  display: block;
  font-size: var(--fs-xs);
}

.product-info {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}

.product-info > .tag {
  align-self: flex-start;
}

.product-headline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.block-title {
  margin: var(--space-2) 0 0;
  font-size: var(--fs-md);
}

.variant-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.variant-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  flex: 0 0 auto;
  text-align: right;
}

.variant-sku {
  margin-top: var(--space-1);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.05em;
}

.giftcode-row {
  display: flex;
  gap: var(--space-2);
}

.giftcode-row .input {
  flex: 1 1 auto;
  min-width: 0;
}

/* State classes set by main.js setFeedback(). */
#gift-code-feedback.is-success { color: var(--color-success); }
#gift-code-feedback.is-error   { color: var(--color-danger); }
#gift-code-feedback.is-muted   { color: var(--color-muted); }

.btn-buy {
  width: 100%;
  padding: 0.9rem 1.5rem;
  font-size: var(--fs-md);
}

.purchase-note {
  margin: var(--space-2) 0 0;
  font-size: var(--fs-xs);
  text-align: center;
}

/* ---- checkout / receipt ---------------------------------------------------- */

.checkout-section .receipt-items,
.checkout-section .receipt-next {
  margin-top: var(--space-6);
}

.receipt-banner-body {
  flex-direction: row;
  align-items: center;
  gap: var(--space-5);
}

.receipt-check {
  flex: 0 0 auto;
  color: var(--color-success);
}

.receipt-title {
  margin: 0 0 var(--space-1);
  font-size: var(--fs-xl);
}

.receipt-meta {
  margin: 0;
  font-size: var(--fs-sm);
}

.receipt-status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-2) 0 0;
  font-size: var(--fs-sm);
}

.receipt-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.receipt-item-thumb {
  display: block;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  overflow: hidden;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: linear-gradient(140deg, #101010, #0a0a0a);
}

.receipt-item-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.receipt-item-name {
  font-weight: 600;
}

.receipt-item-variant {
  font-size: var(--fs-xs);
}

.col-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.receipt-summary {
  margin-top: var(--space-5);
}

.receipt-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-5);
}

.next-steps {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  font-size: var(--fs-sm);
}

.next-steps li strong {
  display: block;
}

.empty-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

/* ---- misc: category.php's inline "in stock only" checkbox row ------------- */

.form-check {
  flex-direction: row;
  align-items: center;
  gap: var(--space-2);
}

.form-check input {
  width: 18px;
  height: 18px;
  accent-color: var(--color-primary);
  cursor: pointer;
}

.form-check .label {
  margin: 0;
  cursor: pointer;
}

/* ---- responsive bindings for this section --------------------------------- */

@media (min-width: 900px) {
  .hero-cards {
    display: flex;
  }

  .category-layout {
    grid-template-columns: 280px minmax(0, 1fr);
  }

  .category-sidebar {
    position: sticky;
    top: calc(var(--header-h) + var(--space-4));
  }
}

/* ==========================================================================
   22. Keyframes
   ========================================================================== */

@keyframes gradient-shift {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

@keyframes float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-12px); }
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

@keyframes shimmer {
  100% { transform: translateX(100%); }
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateX(24px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateX(0) scale(1);
  }
}

@keyframes toast-out {
  from {
    opacity: 1;
    transform: translateX(0) scale(1);
  }
  to {
    opacity: 0;
    transform: translateX(24px) scale(0.96);
  }
}

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

@keyframes fade-in-up {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes pulse-glow {
  0%, 100% { box-shadow: 0 0 0 rgba(0, 255, 65, 0); }
  50% { box-shadow: var(--shadow-glow); }
}

.animate-in {
  animation: fade-in-up 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* ==========================================================================
   23. Responsive
   ========================================================================== */

@media (min-width: 640px) {
  .form-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .footer-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .hero-inner {
    gap: var(--space-10);
  }

  #variant-list {
    gap: var(--space-3);
  }
}

@media (min-width: 900px) {
  :root {
    --header-h: 72px;
  }

  .nav-burger {
    display: none;
  }

  /* TASK 1 - THE ONE-ROW GUARANTEE.

     nowrap is the whole fix. Everything under it is about making the single line
     comfortable rather than merely legal:
       - the row gap drops from 1rem to 0.75rem between 900px and 1199px, where
         the row is tightest, and section "min-width: 1200px" gives it back;
       - .site-nav may shrink below its content width (min-width:0), which is what
         lets the ellipsis backstops on .user-chip-name and .header-balance-unit
         actually engage instead of the row simply overflowing;
       - .nav-actions stops wrapping too. It was the SECOND wrap in the old
         header - a wrapped .nav-actions made .site-nav 80px tall, which pushed
         the whole row over and triggered the outer wrap.
     Verified at 1280px and 1440px: .site-header-inner is 72px, i.e. exactly one
     row, and every in-flow child shares the same getBoundingClientRect().top. */
  .site-header-inner {
    flex-wrap: nowrap;
    gap: var(--space-3);
  }

  .site-nav {
    display: flex;
    flex-basis: auto;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-4);
    flex: 1 1 auto;
    min-width: 0;
    margin-top: 0;
    padding: 0;
    border-top: 0;
    animation: none;
  }

  .nav-toggle:checked ~ .site-nav {
    animation: none;
  }

  .nav-list {
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    gap: var(--space-1);
  }

  /* .nav-actions is NOT unwrapped here - section 30 redeclares it further down
     the file at the same specificity and would win. Its nowrap override lives
     beside that declaration instead. */

  .nav-item {
    padding: var(--space-2) var(--space-3);
  }

  .nav-drop {
    position: relative;
    width: auto;
  }

  .nav-dropdown {
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    z-index: var(--z-dropdown);
    min-width: 240px;
    max-height: 60vh;
    overflow-y: auto;
    margin: 0;
    padding: var(--space-2);
    border: 1px solid var(--color-border);
    border-left-width: 1px;
    border-radius: var(--radius);
    background: rgba(15, 15, 15, 0.97);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    box-shadow: var(--shadow-lg);
    animation: fade-slide-down 0.18s ease;
  }

  .nav-dropdown::before {
    content: "";
    position: absolute;
    top: -10px;
    left: 0;
    right: 0;
    height: 10px;
  }

  .footer-grid {
    grid-template-columns: 1.6fr 1fr 1fr 1fr;
    gap: var(--space-10);
  }

  .product-layout {
    grid-template-columns: minmax(0, 1.4fr) minmax(320px, 0.9fr);
  }

  .checkout-layout {
    grid-template-columns: minmax(0, 1.5fr) minmax(320px, 0.85fr);
  }

  .hero-inner {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  }

  .hero-visual {
    display: block;
  }
}

@media (min-width: 1200px) {
  /* The container has stopped growing at --container-max, so from here on every
     extra pixel of viewport is pure slack. Give the header row back the roomier
     rhythm the 900-1199px band had to borrow from. */
  .site-header-inner {
    gap: var(--space-4);
  }

  .site-nav {
    gap: var(--space-6);
  }

  .page {
    padding-block: var(--space-10) var(--space-20);
  }

  .grid {
    gap: var(--space-6);
  }

  .section {
    margin-block: var(--space-16);
  }
}

@media (max-width: 639px) {
  .toast-container {
    right: var(--space-3);
    left: var(--space-3);
    bottom: var(--space-3);
    width: auto;
  }

  .modal-panel {
    padding: var(--space-5);
    max-height: 90vh;
  }

  .table thead th,
  .table tbody td {
    padding: var(--space-2) var(--space-3);
  }

  .hero {
    border-radius: var(--radius);
  }

  .footer-bottom {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* ==========================================================================
   24. Motion, fallbacks, print
   ========================================================================== */

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .glass,
  .card,
  .stat,
  .summary,
  .product-purchase,
  .filter-bar,
  #filter-form,
  .auth-card {
    background: rgba(15, 15, 15, 0.92);
  }

  .site-header {
    background: rgba(8, 8, 8, 0.97);
  }

  .site-footer {
    background: rgba(5, 5, 5, 0.97);
  }

  .modal-backdrop {
    background: rgba(3, 3, 3, 0.9);
  }

  .modal-panel,
  .toast,
  .nav-dropdown {
    background: #141414;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .hero {
    animation: none;
    background-position: 0% 50%;
  }

  .hero-card {
    animation: none;
  }

  .card:hover,
  .btn:hover,
  .stat:hover,
  .pagination a:hover,
  .social-link:hover,
  .variant-card:hover {
    transform: none;
  }

  .skeleton::after {
    animation: none;
  }
}

@media (prefers-contrast: more) {
  :root {
    --color-border: rgba(255, 255, 255, 0.28);
    --color-border-strong: rgba(255, 255, 255, 0.45);
    --color-muted: #c8c8c8;
  }
}

@media print {
  body {
    background: #ffffff !important;
    color: #000000 !important;
  }

  .site-header,
  .site-footer,
  .toast-container,
  .modal,
  .skip-link,
  .noscript-banner,
  .nav-burger,
  #filter-form,
  .filter-bar,
  .pagination,
  .btn {
    display: none !important;
  }

  .page {
    padding: 0;
  }

  .card,
  .glass,
  .summary,
  .table-wrap {
    border: 1px solid #cccccc !important;
    background: #ffffff !important;
    box-shadow: none !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }

  .price,
  .stat-value,
  .brand-name,
  .hero-title .accent,
  .error-code {
    background: none !important;
    color: #000000 !important;
    -webkit-text-fill-color: #000000 !important;
  }

  a {
    color: #000000 !important;
    text-decoration: underline;
  }

  .muted {
    color: #444444 !important;
  }
}

/* Global Telegram contact: rendered by base.php on every public page. */
.site-tg-contact {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 90;
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  max-width: min(19rem, calc(100vw - 2rem));
  color: #f4f7f8;
  text-decoration: none;
  filter: drop-shadow(0 10px 22px rgba(0, 0, 0, 0.48));
  animation: site-tg-float 3.4s ease-in-out infinite;
}

.site-tg-icon {
  position: relative;
  flex: 0 0 3.25rem;
  width: 3.25rem;
  height: 3.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  background: #229ed9;
  border: 1px solid rgba(255, 255, 255, 0.34);
  border-radius: 50%;
  box-shadow: 0 0 0 0 rgba(34, 158, 217, 0.34);
  transition: transform 0.18s ease, background-color 0.18s ease, box-shadow 0.18s ease;
  animation: site-tg-pulse 2.8s ease-out infinite;
}

.site-tg-icon svg {
  display: block;
  margin-left: -2px;
}

.site-tg-copy {
  display: block;
  padding: 0.55rem 0.72rem;
  color: #dce8ed;
  background: rgba(8, 12, 14, 0.94);
  border: 1px solid rgba(34, 158, 217, 0.42);
  border-radius: 6px;
  font-family: var(--acher-font-mono, monospace);
  font-size: 0.69rem;
  line-height: 1.35;
  letter-spacing: 0;
  white-space: normal;
  transition: color 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}

.site-tg-contact:hover .site-tg-icon,
.site-tg-contact:focus-visible .site-tg-icon {
  transform: translateY(-2px) scale(1.05);
  background: #168bc2;
  box-shadow: 0 7px 24px rgba(34, 158, 217, 0.38);
}

.site-tg-contact:hover .site-tg-copy,
.site-tg-contact:focus-visible .site-tg-copy {
  color: #ffffff;
  border-color: rgba(34, 158, 217, 0.78);
  transform: translateX(-2px);
}

.site-tg-contact:focus-visible {
  outline: 2px solid #7dd3fc;
  outline-offset: 4px;
  border-radius: 6px;
}

@keyframes site-tg-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-5px); }
}

@keyframes site-tg-pulse {
  0%, 45% { box-shadow: 0 0 0 0 rgba(34, 158, 217, 0.34); }
  80%, 100% { box-shadow: 0 0 0 11px rgba(34, 158, 217, 0); }
}

@media (max-width: 520px) {
  .site-tg-contact {
    right: 0.85rem;
    bottom: 0.85rem;
    gap: 0.45rem;
    max-width: calc(100vw - 1.7rem);
  }

  .site-tg-icon {
    flex-basis: 3rem;
    width: 3rem;
    height: 3rem;
  }

  .site-tg-copy {
    max-width: 10.5rem;
    font-size: 0.64rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .site-tg-contact,
  .site-tg-icon {
    animation: none !important;
  }

  .site-tg-contact:hover .site-tg-icon,
  .site-tg-contact:focus-visible .site-tg-icon,
  .site-tg-contact:hover .site-tg-copy,
  .site-tg-contact:focus-visible .site-tg-copy {
    transform: none;
  }
}

@media print {
  .site-tg-contact {
    display: none !important;
  }
}

/* ==========================================================================
   25. ACHER typography assignments

   Three faces, three jobs, no exceptions:

     Share Tech Mono  headings, labels, buttons, nav, anything that acts as
                      chrome or a caption. One weight only - emphasis comes
                      from colour and tracking, never from bold.
     Inter            body copy, descriptions, form values, long text.
     JetBrains Mono   prices, amounts, quantities, SKUs, codes, hashes, ids.
                      Anything a person might compare, copy or read aloud.

   This block lives at the end of the file on purpose: it is the last word on
   font-family, so no earlier rule can quietly reassign a face.
   ========================================================================== */

/* ---- display face: chrome, headings, labels ------------------------------ */

.label,
.footer-heading,
.stat-label,
.hero-eyebrow,
.section-title,
.card-title,
.modal-title,
.filter-title,
.block-title,
.product-title,
.category-name,
.step-title,
.receipt-title,
.auth-title,
.detail-label,
.fieldset legend,
.table thead th,
.breadcrumb,
.error-code,
.empty-state h2,
.empty-state h3,
.alert-title,
.badge,
.acher-label {
  font-family: var(--font-display);
  font-weight: 400;
}

.label,
.footer-heading,
.stat-label,
.detail-label,
.table thead th,
.fieldset legend,
.acher-label {
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* ---- numeric face: money, stock, codes, ids ------------------------------ */

.price,
.price-lg,
.price-old,
.stat-value,
.col-num,
.num,
.table .num,
.variant-price,
.variant-stock,
.order-line-price,
.order-line-meta,
.summary-row span:last-child,
.summary-value,
.detail-value,
.pagination a,
.pagination span,
.stock-pill,
.usage-meter,
.acher-price,
.acher-code,
.variant-box .variant-box-price,
.variant-box .variant-box-stock {
  font-family: var(--acher-font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "zero" 1;
}

.price {
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--acher-text);
}

.price-lg {
  color: var(--acher-primary);
  text-shadow: var(--acher-glow-text);
}

/* A money amount anywhere outside a card's own price slot. */
.acher-price {
  font-weight: 500;
  color: var(--acher-text);
  letter-spacing: -0.01em;
}

.acher-price.is-accent {
  color: var(--acher-primary);
  text-shadow: var(--acher-glow-text);
}

.acher-price.is-struck {
  color: var(--acher-muted);
  text-decoration: line-through;
}

/* A monospaced code / hash / order reference. */
.acher-code {
  padding: 0.1em 0.45em;
  border: 1px solid var(--acher-border);
  border-radius: var(--radius-sm);
  background: var(--acher-bg-deep);
  color: var(--acher-primary-soft);
  font-size: 0.86em;
  letter-spacing: 0.08em;
  word-break: break-all;
}

/* The gradient-clipped numerals the old system used read as a smear at small
   sizes. ACHER states its numbers plainly, in green. */
.stat-value {
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: var(--acher-primary);
  -webkit-text-fill-color: currentColor;
  font-weight: 500;
  letter-spacing: -0.01em;
  text-shadow: var(--acher-glow-text);
}

.step-number,
.hero-title-accent,
.hero-title .accent,
.error-code {
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: var(--acher-primary);
  -webkit-text-fill-color: currentColor;
  text-shadow: var(--acher-glow-text);
}

/* ==========================================================================
   26. ACHER components

   The named set every other agent builds against. Author here, use everywhere;
   nothing downstream should re-style a card or a button from scratch.
   ========================================================================== */

/* ---- .acher-card --------------------------------------------------------- */

.acher-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--space-5);
  border: 1px solid var(--acher-border);
  border-radius: var(--radius);
  background: var(--acher-surface);
  color: var(--acher-text);
  transition: border-color var(--transition), box-shadow var(--transition),
    transform var(--transition), background-color var(--transition);
}

/* Corner bracket, top-left. Drawn with a pseudo-element border so it costs
   nothing to paint and fades in on hover with opacity alone. */
.acher-card::before {
  content: "";
  position: absolute;
  top: -1px;
  left: -1px;
  width: 14px;
  height: 14px;
  border-top: 1px solid var(--acher-primary);
  border-left: 1px solid var(--acher-primary);
  border-top-left-radius: var(--radius);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition);
}

.acher-card::after {
  content: "";
  position: absolute;
  right: -1px;
  bottom: -1px;
  width: 14px;
  height: 14px;
  border-right: 1px solid var(--acher-primary);
  border-bottom: 1px solid var(--acher-primary);
  border-bottom-right-radius: var(--radius);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition);
}

.acher-card:hover,
.acher-card:focus-within {
  border-color: #262626;
  box-shadow: var(--acher-glow-sm);
  transform: translateY(-1px);
}

.acher-card:hover::before,
.acher-card:hover::after,
.acher-card:focus-within::before,
.acher-card:focus-within::after {
  opacity: 0.9;
}

.acher-card.is-flush {
  padding: 0;
  overflow: hidden;
}

.acher-card.is-static:hover {
  transform: none;
  box-shadow: none;
}

.acher-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.acher-card-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 400;
  letter-spacing: 0.06em;
}

/* ---- buttons ------------------------------------------------------------- */

.acher-btn-primary,
.acher-btn-ghost,
.acher-btn-danger {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0.66rem 1.35rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0.12em;
  text-align: center;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  -webkit-appearance: none;
  appearance: none;
  transition: background-color var(--transition), border-color var(--transition),
    color var(--transition), box-shadow var(--transition), transform var(--transition);
}

.acher-btn-primary:disabled,
.acher-btn-ghost:disabled,
.acher-btn-danger:disabled,
.acher-btn-primary.is-disabled,
.acher-btn-ghost.is-disabled,
.acher-btn-danger.is-disabled,
.acher-btn-primary[aria-disabled="true"],
.acher-btn-ghost[aria-disabled="true"],
.acher-btn-danger[aria-disabled="true"] {
  opacity: 0.42;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
  pointer-events: none;
}

.acher-btn-primary {
  border-color: var(--acher-primary);
  background: var(--acher-primary);
  color: var(--acher-primary-deep);
  box-shadow: 0 0 0 rgba(var(--acher-primary-rgb), 0);
}

.acher-btn-primary:hover {
  background: #22ff5c;
  border-color: #22ff5c;
  color: var(--acher-primary-deep);
  box-shadow: var(--acher-glow);
  transform: translateY(-1px);
}

.acher-btn-primary:active {
  background: var(--acher-primary-dim);
  border-color: var(--acher-primary-dim);
  transform: translateY(0);
}

.acher-btn-ghost {
  border-color: var(--acher-border-strong);
  background: transparent;
  color: var(--acher-dim);
}

.acher-btn-ghost:hover {
  border-color: rgba(var(--acher-primary-rgb), 0.55);
  background: rgba(var(--acher-primary-rgb), 0.06);
  color: var(--acher-primary);
}

.acher-btn-ghost:active {
  background: rgba(var(--acher-primary-rgb), 0.12);
}

.acher-btn-danger {
  border-color: rgba(var(--acher-danger-rgb), 0.5);
  background: transparent;
  color: var(--acher-danger-soft);
}

.acher-btn-danger:hover {
  border-color: var(--acher-danger);
  background: rgba(var(--acher-danger-rgb), 0.14);
  color: #ffd0d0;
  box-shadow: 0 0 18px rgba(var(--acher-danger-rgb), 0.24);
  transform: translateY(-1px);
}

.acher-btn-danger:active {
  background: rgba(var(--acher-danger-rgb), 0.22);
  transform: translateY(0);
}

/* Size and width modifiers work on all three. */
.acher-btn-primary.is-sm,
.acher-btn-ghost.is-sm,
.acher-btn-danger.is-sm {
  padding: 0.36rem 0.8rem;
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
}

.acher-btn-primary.is-lg,
.acher-btn-ghost.is-lg,
.acher-btn-danger.is-lg {
  padding: 0.92rem 1.9rem;
  font-size: var(--fs-md);
}

.acher-btn-primary.is-block,
.acher-btn-ghost.is-block,
.acher-btn-danger.is-block {
  display: flex;
  width: 100%;
}

/* Busy state, driven by window.dpsUtil.busyButton() in static/js/main.js. */
.acher-btn-primary.is-loading,
.acher-btn-ghost.is-loading,
.acher-btn-danger.is-loading {
  color: transparent !important;
  pointer-events: none;
}

.acher-btn-primary.is-loading::after,
.acher-btn-ghost.is-loading::after,
.acher-btn-danger.is-loading::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1.05em;
  height: 1.05em;
  margin: -0.525em 0 0 -0.525em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

.acher-btn-primary.is-loading::after {
  border-color: var(--acher-primary-deep);
  border-right-color: transparent;
}

.acher-btn-ghost.is-loading::after,
.acher-btn-danger.is-loading::after {
  border-color: var(--acher-primary);
  border-right-color: transparent;
}

/* ---- .acher-input -------------------------------------------------------- */

.acher-input {
  width: 100%;
  padding: 0.66rem 0.85rem;
  border: 1px solid var(--acher-border);
  border-radius: var(--radius-sm);
  background: var(--acher-bg-deep);
  color: var(--acher-text);
  font-family: var(--acher-font-body);
  font-size: var(--fs-sm);
  line-height: 1.45;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color var(--transition), box-shadow var(--transition),
    background-color var(--transition);
}

.acher-input::placeholder {
  color: var(--acher-muted);
  opacity: 1;
}

.acher-input:hover {
  border-color: var(--acher-border-strong);
}

.acher-input:focus {
  outline: none;
  border-color: var(--acher-primary);
  background: #0a0a0a;
  box-shadow: 0 0 0 3px rgba(var(--acher-primary-rgb), 0.14);
}

.acher-input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.acher-input.is-invalid,
.acher-input:user-invalid {
  border-color: var(--acher-danger);
  box-shadow: 0 0 0 3px rgba(var(--acher-danger-rgb), 0.14);
}

.acher-input.is-valid {
  border-color: rgba(var(--acher-primary-rgb), 0.6);
}

/* Codes and quantities typed by hand read as data, so they get the mono face. */
.acher-input.is-code {
  font-family: var(--acher-font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

textarea.acher-input {
  min-height: 130px;
  line-height: var(--lh-base);
  resize: vertical;
}

select.acher-input {
  padding-right: 2.3rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300ff41' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 15px 15px;
}

/* ---- .acher-badge -------------------------------------------------------- */

.acher-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.16rem 0.55rem;
  border: 1px solid var(--acher-border-strong);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.03);
  color: var(--acher-dim);
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
}

.acher-badge.is-success,
.acher-badge.is-primary {
  border-color: rgba(var(--acher-primary-rgb), 0.45);
  background: rgba(var(--acher-primary-rgb), 0.09);
  color: var(--acher-primary-soft);
}

.acher-badge.is-warning {
  border-color: rgba(var(--acher-warning-rgb), 0.45);
  background: rgba(var(--acher-warning-rgb), 0.10);
  color: var(--acher-warning-soft);
}

.acher-badge.is-danger {
  border-color: rgba(var(--acher-danger-rgb), 0.45);
  background: rgba(var(--acher-danger-rgb), 0.10);
  color: var(--acher-danger-soft);
}

.acher-badge.is-muted {
  border-color: var(--acher-border);
  background: transparent;
  color: var(--acher-muted);
}

.acher-badge.has-dot::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 6px currentColor;
}

/* ---- .acher-tag ---------------------------------------------------------- */

.acher-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.22rem 0.6rem;
  border: 1px solid var(--acher-border);
  border-radius: var(--radius-sm);
  background: var(--acher-surface);
  color: var(--acher-dim);
  font-family: var(--acher-font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.04em;
  text-decoration: none;
  transition: color var(--transition), border-color var(--transition),
    background-color var(--transition);
}

.acher-tag::before {
  content: "#";
  color: var(--acher-muted);
}

.acher-tag.is-plain::before {
  content: none;
}

a.acher-tag:hover,
button.acher-tag:hover {
  border-color: rgba(var(--acher-primary-rgb), 0.5);
  background: rgba(var(--acher-primary-rgb), 0.07);
  color: var(--acher-primary);
}

a.acher-tag:hover::before,
button.acher-tag:hover::before {
  color: var(--acher-primary);
}

.acher-tag.is-active {
  border-color: var(--acher-primary);
  background: rgba(var(--acher-primary-rgb), 0.10);
  color: var(--acher-primary);
}

.acher-tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* ---- .variant-box -------------------------------------------------------- */

.variant-box {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
  padding: var(--space-4);
  border: 1px solid var(--acher-border);
  border-radius: var(--radius-sm);
  background: var(--acher-surface);
  color: var(--acher-text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--transition), background-color var(--transition),
    box-shadow var(--transition), transform var(--transition);
}

.variant-box:hover {
  border-color: var(--acher-border-strong);
  background: var(--acher-surface-3);
  transform: translateY(-1px);
}

.variant-box-main {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}

.variant-box-name {
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  letter-spacing: 0.05em;
}

.variant-box-desc {
  color: var(--acher-muted);
  font-size: var(--fs-xs);
  line-height: 1.5;
}

.variant-box-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.2rem;
  flex: 0 0 auto;
  text-align: right;
}

.variant-box-price {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--acher-text);
}

.variant-box-stock {
  font-size: var(--fs-xs);
  color: var(--acher-muted);
}

/* selected: green edge, a wash of green, and a tick in the top-right corner. */
.variant-box.is-selected {
  border-color: var(--acher-primary);
  background: rgba(var(--acher-primary-rgb), 0.07);
  box-shadow: var(--acher-glow-sm), inset 2px 0 0 0 var(--acher-primary);
}

.variant-box.is-selected .variant-box-name {
  color: var(--acher-primary);
}

.variant-box.is-selected .variant-box-price {
  color: var(--acher-primary);
}

.variant-box.is-selected::after {
  content: "";
  position: absolute;
  top: 8px;
  right: 10px;
  width: 11px;
  height: 6px;
  border-left: 2px solid var(--acher-primary);
  border-bottom: 2px solid var(--acher-primary);
  transform: rotate(-45deg);
  pointer-events: none;
}

/* sold out: still readable, clearly not buyable, and not focusable as a
   control. Templates should ALSO set disabled/aria-disabled on the element. */
.variant-box.is-soldout {
  border-color: var(--acher-border);
  background: #0b0b0b;
  color: var(--acher-muted);
  cursor: not-allowed;
  opacity: 0.55;
  filter: grayscale(0.85);
  pointer-events: none;
}

.variant-box.is-soldout:hover {
  transform: none;
  box-shadow: none;
  background: #0b0b0b;
}

.variant-box.is-soldout .variant-box-price {
  color: var(--acher-muted);
  text-decoration: line-through;
}

.variant-box.is-soldout .variant-box-stock {
  color: var(--acher-danger-soft);
  text-decoration: none;
}

.variant-box-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* ==========================================================================
   27. Search overlay

   DORMANT, NOT DEAD. READ THIS BEFORE DELETING THE SECTION.

   TASK 7 removed the HEADER search box from templates/base.php: both
   button#search-open and the server-rendered div.search-overlay#search-overlay
   scaffold are gone. The .search-trigger / .search-trigger-label /
   .search-trigger-key rules that used to open this section went with them -
   nothing else in the storefront ever used those three classes (admin.css
   declares its own .search-trigger-key and is untouched).

   In the same pass the homepage's mid-page search band (templates/index.php) was
   rewritten by its owner into a plain server-side GET form - ?q=term#home-results,
   results queried and rendered in the page - so it no longer carries the
   #home-search-form / #home-search-input / #home-search-open ids either. With no
   trigger, no overlay and no relay field anywhere in the document,
   static/js/search.js's initSearch() takes its early return on every page and
   the overlay is never built. Nothing on the site renders these rules today.

   THEY STAY ANYWAY, and deliberately:

     - static/js/search.js is NOT owned by this task and still ships
       ensureOverlay(), which builds a full overlay from scratch the moment
       anything calls openSearch(). It uses these exact class names:
         div.search-overlay.is-fallback[hidden] > div.search-panel
           > div.search-head > input#search-input.acher-input + button.search-close
           > div#search-results.search-results
       Deleting the rules would leave that file able to paint an unstyled
       full-screen dialog over the site - a worse failure than some unused CSS.
     - re-introducing live search anywhere (a header trigger, an account-area
       lookup, an admin-side picker) is a markup change only while these hold.

   The .is-fallback block at the end of the section covers the three ways the
   JS-built shape differs from the markup that was deleted: no .search-title, no
   .search-input-wrap caret, no .search-hint footer. Verified working against the
   fallback before index.php's rewrite landed, and kept for the same reason the
   rest of the section is.
   ========================================================================== */

.search-overlay {
  position: fixed;
  inset: 0;
  z-index: 950;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(1rem, 8vh, 6rem) var(--container-pad) var(--space-6);
  background: rgba(4, 4, 4, 0.94);
  -webkit-backdrop-filter: blur(10px) saturate(120%);
  backdrop-filter: blur(10px) saturate(120%);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* display:flex above beats the UA [hidden] rule, so restate it - otherwise the
   overlay covers the whole site before search.js boots, and forever without JS. */
.search-overlay[hidden] {
  display: none;
}

/* Faint scanline wash so the overlay reads as a terminal, not a lightbox. */
.search-overlay::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.5;
  background-image: repeating-linear-gradient(
    to bottom,
    rgba(var(--acher-primary-rgb), 0.035) 0px,
    rgba(var(--acher-primary-rgb), 0.035) 1px,
    transparent 1px,
    transparent 4px
  );
}

.search-panel {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  width: min(720px, 100%);
}

.search-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.search-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  font-weight: 400;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--acher-muted);
}

.search-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  /* Never shrinks: in the JS-built .is-fallback head it shares a flex row with
     the query field, and "Esc" collapsing to an ellipsis would be absurd. */
  flex: 0 0 auto;
  min-height: 40px;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--acher-border-strong);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--acher-dim);
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color var(--transition), border-color var(--transition);
}

.search-close:hover {
  color: var(--acher-primary);
  border-color: rgba(var(--acher-primary-rgb), 0.5);
}

/* The prompt caret sits inside the field's padding, so it can never overlap
   typed text. */
.search-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.search-input-wrap::before {
  content: ">";
  position: absolute;
  left: 1rem;
  font-family: var(--acher-font-mono);
  font-size: 1.1rem;
  line-height: 1;
  color: var(--acher-primary);
  pointer-events: none;
}

#search-input,
.search-overlay .acher-input {
  width: 100%;
  padding: 1rem 1rem 1rem 2.5rem;
  border: 1px solid var(--acher-border-strong);
  border-radius: var(--radius);
  background: var(--acher-surface);
  color: var(--acher-text);
  font-family: var(--acher-font-mono);
  font-size: var(--fs-lg);
  letter-spacing: 0.02em;
}

#search-input::placeholder {
  color: #3d3d3d;
  opacity: 1;
}

#search-input:focus {
  outline: none;
  border-color: var(--acher-primary);
  box-shadow: 0 0 0 3px rgba(var(--acher-primary-rgb), 0.14), var(--acher-glow-sm);
}

.search-hint {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  font-family: var(--acher-font-mono);
  font-size: var(--fs-xs);
  color: var(--acher-muted);
}

#search-results {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-height: 2rem;
}

.search-result {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--acher-border);
  border-radius: var(--radius-sm);
  background: var(--acher-surface);
  color: var(--acher-text);
  text-decoration: none;
  transition: border-color var(--transition), background-color var(--transition);
}

.search-result:hover,
.search-result:focus-visible,
.search-result.is-active {
  border-color: rgba(var(--acher-primary-rgb), 0.55);
  background: rgba(var(--acher-primary-rgb), 0.06);
  color: var(--acher-text);
}

.search-result-thumb {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  overflow: hidden;
  border: 1px solid var(--acher-border);
  border-radius: var(--radius-sm);
  background: var(--acher-bg-deep);
  object-fit: cover;
}

.search-result-body {
  flex: 1 1 auto;
  min-width: 0;
}

.search-result-name {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  letter-spacing: 0.04em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.search-result-meta {
  display: block;
  color: var(--acher-muted);
  font-size: var(--fs-xs);
}

.search-result-price {
  flex: 0 0 auto;
  font-family: var(--acher-font-mono);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--acher-primary);
}

.search-empty,
.search-status {
  padding: var(--space-5) var(--space-3);
  font-family: var(--acher-font-mono);
  font-size: var(--fs-sm);
  color: var(--acher-muted);
  text-align: center;
}

body.search-open {
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   The JS-built overlay (TASK 7). Dormant with the rest of this section - see the
   section header for why it is kept.

   search.js gives its own overlay the extra class .is-fallback, so these rules
   can correct the three structural differences from the deleted server-rendered
   markup WITHOUT touching the shared rules above:

     1. the field sits directly in .search-head beside the close button, instead
        of alone in a .search-input-wrap on its own row. .search-head is already
        a space-between flex row, so the field only needs permission to grow and
        to shrink (min-width:0, or a long value would push the close button out).
     2. there is no .search-input-wrap, so there is no ">" caret in the gutter -
        the 2.5rem left padding #search-input carries for that caret would just
        be a dead indent. It goes back to a normal 1rem.
     3. there is no .search-hint footer, so the panel's own gap is all that
        separates the field from the results.

   Everything else - the backdrop, the scanline wash, the 720px panel, the result
   rows, the skeletons and the empty/error messages - is inherited unchanged, so
   the homepage search looks exactly as it did when base.php rendered the shell.
   -------------------------------------------------------------------------- */

.search-overlay.is-fallback .search-head {
  gap: var(--space-3);
}

.search-overlay.is-fallback #search-input {
  flex: 1 1 auto;
  min-width: 0;
  padding-left: 1rem;
}

/* ==========================================================================
   28. Skeletons - ACHER shimmer
   ========================================================================== */

.skeleton {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: #131313;
  color: transparent !important;
  user-select: none;
}

.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(var(--acher-primary-rgb), 0.05) 45%,
    rgba(var(--acher-primary-rgb), 0.11) 50%,
    rgba(var(--acher-primary-rgb), 0.05) 55%,
    transparent 100%
  );
  animation: acher-shimmer 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
  will-change: transform;
}

/* Transform-only: the shimmer stays on the compositor and never repaints. */
@keyframes acher-shimmer {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}

/* ==========================================================================
   29. Scanlines & cursor glow
   ========================================================================== */

/* .hero-scanlines - for ui:homepage. Put it on any element that already
   establishes a containing block; it paints CRT lines plus a slow sweep over
   the element's own content and swallows no clicks. */
.hero-scanlines {
  position: relative;
  isolation: isolate;
}

.hero-scanlines::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  border-radius: inherit;
  opacity: 0.55;
  background-image:
    repeating-linear-gradient(
      to bottom,
      rgba(0, 0, 0, 0.22) 0px,
      rgba(0, 0, 0, 0.22) 1px,
      transparent 1px,
      transparent 3px
    ),
    linear-gradient(
      to bottom,
      transparent 0%,
      rgba(var(--acher-primary-rgb), 0.055) 48%,
      rgba(var(--acher-primary-rgb), 0.09) 50%,
      rgba(var(--acher-primary-rgb), 0.055) 52%,
      transparent 100%
    );
  background-size: 100% 3px, 100% 220%;
  background-repeat: repeat, no-repeat;
  animation: acher-scan 9s linear infinite;
}

/* Only background-position moves - no layout, no repaint of the content below. */
@keyframes acher-scan {
  from { background-position: 0 0, 0 -110%; }
  to   { background-position: 0 0, 0 210%; }
}

/* --------------------------------------------------------------------------
   Cursor glow.

   CSS cannot read the pointer position, and CSP forbids the JS that would, so
   this is a hover bloom rather than a tracking spotlight: interactive surfaces
   grow a soft green halo under the cursor. Cheap by construction - a single
   pre-composited pseudo-element whose only animated property is opacity, and
   it is scoped to @media (hover: hover) so touch devices never build the extra
   layers at all.
   -------------------------------------------------------------------------- */

@media (hover: hover) and (pointer: fine) {
  .acher-card,
  .acher-btn-primary,
  .acher-btn-ghost,
  .acher-btn-danger,
  .variant-box,
  .search-result,
  .acher-glow {
    /* the halo lives on a stacking context of its own */
    isolation: isolate;
  }

  .acher-btn-ghost::before,
  .acher-btn-danger::before,
  .variant-box::before,
  .acher-glow::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    opacity: 0;
    pointer-events: none;
    background: radial-gradient(
      120% 160% at 50% 130%,
      rgba(var(--acher-primary-rgb), 0.20) 0%,
      transparent 62%
    );
    transition: opacity var(--transition);
  }

  .acher-btn-ghost:hover::before,
  .acher-btn-danger:hover::before,
  .variant-box:hover::before,
  .acher-glow:hover::before {
    opacity: 1;
  }

  .acher-btn-danger::before {
    background: radial-gradient(
      120% 160% at 50% 130%,
      rgba(var(--acher-danger-rgb), 0.22) 0%,
      transparent 62%
    );
  }

  /* .variant-box uses ::after for the selected tick, so its halo must not
     fight the sold-out state. */
  .variant-box.is-soldout::before {
    display: none;
  }
}

/* ==========================================================================
   30. ACHER shell: footer, nav actions, cart
   ========================================================================== */

.site-footer {
  margin-top: var(--space-16);
  padding-block: var(--space-8);
  background: var(--acher-bg-deep);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-top: 1px solid var(--acher-border);
}

.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
}

.footer-brand-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: 44ch;
}

.footer-tagline {
  margin: 0;
  color: var(--acher-muted);
  font-size: var(--fs-xs);
  line-height: 1.7;
}

.footer-links-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
}

.footer-links-row a {
  color: var(--acher-dim);
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.footer-links-row a:hover {
  color: var(--acher-primary);
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--acher-border);
  font-family: var(--acher-font-mono);
  font-size: var(--fs-xs);
  color: var(--acher-muted);
}

.nav-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* TASK 1 - the SECOND wrap, and the one that actually broke the header.

   .nav-actions wrapping made .site-nav two rows tall, which in turn overflowed
   .site-header-inner and triggered the outer wrap. Unwrapping the outer row
   alone would only have moved the problem inwards, so both are pinned.

   This override deliberately sits HERE rather than in section 23 with the rest
   of the 900px header rules: the base declaration above is part of section 30,
   which comes AFTER section 23 in the cascade, so an equally specific
   `flex-wrap: nowrap` up there would simply be overwritten by the `wrap` on the
   line above. Same specificity, later position, later wins. Keep them adjacent.

   Below 900px the wrap stays: down there .nav-actions is a row inside the
   collapsed burger menu and its items are full-width, so wrapping is what
   stacks them. */
@media (min-width: 900px) {
  .nav-actions {
    flex-wrap: nowrap;
  }
}

.nav-cart {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  /* Do not shrink: inside .header-lead the credit chip is the one item that
     gives way, so the cart keeps its icon + label + count whole. */
  flex: 0 0 auto;
  padding: 0.42rem 0.7rem;
  border: 1px solid var(--acher-border);
  border-radius: var(--radius-sm);
  color: var(--acher-dim);
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  transition: border-color var(--transition), color var(--transition),
    background-color var(--transition);
}

.nav-cart:hover {
  border-color: rgba(var(--acher-primary-rgb), 0.5);
  background: rgba(var(--acher-primary-rgb), 0.05);
  color: var(--acher-primary);
}

.nav-cart-count {
  min-width: 1.35em;
  padding: 0 0.3em;
  border-radius: var(--radius-pill);
  background: var(--acher-primary);
  color: var(--acher-primary-deep);
  font-family: var(--acher-font-mono);
  font-size: 0.66rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.nav-cart-count[hidden],
.nav-cart-count:empty {
  display: none;
}

/* The footer lockup is the same construction one step down in size. */
.brand-logo.is-sm {
  width: 106px;
  height: 26px;
}

.brand-logo.is-sm .brand-logo-img {
  height: 26px;
}

.brand-logo.is-sm .brand-wordmark {
  font-size: 1rem;
  letter-spacing: 0.3em;
  margin-right: -0.3em;
}

.user-chip {
  border-radius: var(--radius-sm);
  background: var(--acher-surface);
  font-family: var(--acher-font-mono);
}

.user-chip-avatar {
  border-radius: var(--radius-sm);
  font-family: var(--font-display);
  font-weight: 400;
}

/* ==========================================================================
   30b. Header credit balance

   Numbered 30b, not 32, so it sits BEFORE section 31 - that block is documented
   as the last word in the file and must stay last.

   Rendered by templates/base.php for SIGNED-IN users only. A guest gets the
   header exactly as it was before this section existed - there is no markup to
   style, so there is nothing here to hide.

   DOM contract (deposit.js and the checkout flow refresh it in place):

     <a id="acher-balance" data-balance="1234.50" data-credit-label="credits">
       <span id="acher-balance-value">1,234.50</span>
       <span class="header-balance-unit">credits</span>
     </a>

   CREDITS ARE NOT DOLLARS: the number never carries a currency symbol, the unit
   is the word beside it. --acher-font-mono + tabular-nums so the digits hold
   their column when the value changes under JavaScript.

   POSITION (TASK 4): this chip rides in .header-lead, RIGHT NEXT TO the cart
   (order: lockup, cart, credit). It is therefore always visible - including on
   mobile, where it stays in the top row rather than hiding inside the burger
   menu. The right-hand .nav-actions area now holds the "Add funds" primary CTA
   in the slot this chip used to occupy.

   .header-lead welds the lockup + cart + credit together as ONE flex item at a
   tight gap instead of inheriting .site-header-inner's wider var(--space-4) gap.
   That keeps the load-bearing header behaviour intact: .nav-burger still takes
   margin-left:auto to the right edge and .site-nav still wraps onto its own
   full-width row. The lockup and cart are flex:0 0 auto so the credit chip is
   the only lead item that shrinks - its overflow:hidden + ellipsised unit are
   the backstop that keeps the amount whole and the row off the burger.
   ========================================================================== */

.header-lead {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: 0 1 auto;
  min-width: 0;
}

.header-balance {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex: 0 1 auto;
  min-width: 0;
  padding: 0.3rem 0.55rem;
  border: 1px solid var(--acher-border);
  border-radius: var(--radius-sm);
  background: var(--acher-surface);
  /* The green tick that says "this is money" without spending any width. */
  box-shadow: inset 2px 0 0 0 rgba(var(--acher-primary-rgb), 0.45);
  color: var(--acher-dim);
  font-size: var(--fs-xs);
  line-height: 1;
  white-space: nowrap;
  /* credit_label is admin-editable free text, so nothing inside is allowed to
     escape the chip's own border and land on top of the burger. */
  overflow: hidden;
  transition: border-color var(--transition), background-color var(--transition),
    color var(--transition);
}

.header-balance:hover {
  border-color: rgba(var(--acher-primary-rgb), 0.5);
  background: rgba(var(--acher-primary-rgb), 0.05);
  color: var(--acher-primary);
}

.header-balance-value {
  /* flex-shrink: 0 - the AMOUNT is the one thing in this chip that must never be
     abbreviated. A half-rendered balance is a wrong balance. Everything else in
     here gives way first, and the chip's overflow:hidden is the final backstop. */
  flex: 0 0 auto;
  font-family: var(--acher-font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  color: var(--acher-primary);
  text-shadow: var(--acher-glow-text);
}

.header-balance-unit {
  /* The only shrinkable thing in the chip: when room runs out the WORD gives way
     and ellipsises, and the number beside it stays whole. */
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--font-display);
  font-size: 0.92em;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--acher-muted);
}

.header-balance:hover .header-balance-unit {
  color: var(--acher-primary-dim);
}

/* Below 900px the brand row is shared with .nav-burger, and flex-wrap makes that
   row FRAGILE in a specific way: a flex container decides where to wrap using
   each item's content size BEFORE any shrinking happens, so a wide lead item does
   not squeeze - it pushes the burger onto a second row and doubles the header's
   height. Post TASK 4 the lead holds lockup + CART + CREDIT, so the cap "the lead
   may take everything except the burger and its gap" (58px = 42px burger + 16px
   header gap) is what keeps that three-item row from ever shoving the burger down.
   Scoped below 900px because from there up the burger is display:none and
   .site-nav absorbs the slack. */
@media (max-width: 899px) {
  .header-lead {
    max-width: calc(100% - 58px);
    gap: var(--space-2);
  }

  /* In the collapsed burger menu the Add funds CTA is a call to action, so it
     drops onto its own full-width row with a comfortable 44px touch target
     instead of the compact desktop pill. */
  .nav-add-funds {
    width: 100%;
    min-height: 44px;
  }
}

/* Phones. Three items in the lead (lockup + cart + credit) is the tightest the
   header ever gets, so on phones the two purely decorative words step aside to
   guarantee the row fits beside the burger with no wrap and no clipped amount:
     - the cart drops its "Cart" label and goes icon-only (aria-label="Cart" on
       the link keeps the accessible name; #cart-count is untouched);
     - the credit chip drops its unit WORD (the value stays, and the chip's title
       + aria-label still say "credits", so a screen reader and long-press tooltip
       lose nothing).
   Measured at 375px: 343px container - 58px (burger + gap) = 285px for the lead;
   lockup 132 + cart ~40 (icon-only) + credit ~72 (value-only) + two 8px gaps
   = ~260px, clearing the burger with room to spare. From 481px up there is space
   for the full labels, so they return. */
@media (max-width: 480px) {
  .nav-cart-label {
    display: none;
  }

  .header-balance {
    padding: 0.28rem 0.45rem;
  }

  .header-balance-unit {
    display: none;
  }
}

@media (prefers-contrast: more) {
  .header-balance {
    border-color: var(--acher-border-strong);
  }

  .header-balance-value {
    text-shadow: none;
  }

  .header-balance-unit {
    color: var(--acher-dim);
  }
}

/* ==========================================================================
   30c. Header category bar (TASK 2), account menu (TASK 4), redeem trigger
        (TASK 8)

   Numbered 30c so it stays BEFORE section 31 - that block is documented as the
   last word in the file and must remain last.

   ---------------------------------------------------------------------------
   WHY THESE RULES LIVE HERE AND NOT IN search.css
   ---------------------------------------------------------------------------
   The chip strip used to be rendered by templates/index.php and styled in
   static/css/search.css. base.php loads search.css on EVERY page, so the
   stylesheet is global - but its chip rules are not: every one of them is
   scoped `body.page-home ...`, so they matched on the homepage and nowhere
   else. Moving the bar into the header shell therefore needed the rules
   PORTED here, under the same class names, unscoped, so they apply on all
   pages. templates/index.php + search.css keep the duplicates until
   agent:homepage removes them (reported as a handoff).

   Until that happens both stylesheets describe the same chips on the homepage,
   so every rule below is written at THREE classes or more
   (`.site-header .home-cat-bar.header-cat-bar ...`) - strictly more specific
   than `body.page-home .home-cat-chip` (two). That makes the winner a matter
   of specificity rather than load order, and the bar is pixel-identical on the
   homepage and on every other page. No !important anywhere.

   ---------------------------------------------------------------------------
   ONE STICKY UNIT
   ---------------------------------------------------------------------------
   The bar is a CHILD of <header class="site-header">, which is the single
   position:sticky element in the shell (section 06). So there is exactly one
   sticky box, one z-index and one scrollbar - the header row and the chips can
   never drift apart, which is precisely what a second `position:sticky` sibling
   pinned at top:var(--header-h) would eventually do. It also inherits the
   header's backdrop blur and its `display:none` print rule for free.

   The sticky unit is now taller, so --cat-bar-h (section 01) stops being 0 and
   html{scroll-padding-top} grows with it - see the :root:has() switch below.
   ========================================================================== */

/* --cat-bar-h is 0 in :root and is turned on ONLY when base.php really rendered
   a bar (no categories, or a signed-out visitor under the login gate, and there
   is no bar to clear). :has() keeps that decision in CSS with no body class and
   no JavaScript; a browser without :has() simply keeps the old, slightly small
   offset, which is a cosmetic miss on anchor jumps and nothing more.

   54px is the measured height and is deliberately a constant: 1px top border +
   2 x 0.4rem strip padding + the 40px minimum chip. Nothing in the bar changes
   size across breakpoints, and the strip's scrollbar is suppressed below, so
   this number cannot drift out of step with the rendered box. */
:root:has(.site-header .home-cat-bar.header-cat-bar) {
  --cat-bar-h: 54px;
}

/* The bar's own chrome. A top hairline separates it from the header row; the
   BOTTOM edge is left to .site-header's border + ::after gradient, so the shell
   still ends in exactly one line rather than two stacked ones. */
.site-header .home-cat-bar.header-cat-bar {
  border-top: 1px solid var(--acher-border);
  border-bottom: 0;
  background: linear-gradient(180deg, rgba(var(--acher-primary-rgb), 0.05), transparent);
}

/* THE overflow owner. The strip scrolls sideways; the page never does (body is
   overflow-x:hidden). scroll-snap makes a swipe land on a chip edge.

   The scrollbar is suppressed on purpose and it is a layout decision, not a
   cosmetic one: a classic (non-overlay) horizontal scrollbar is laid out INSIDE
   this box, so on Windows it would silently add ~15px to the sticky unit and put
   --cat-bar-h out of step with reality on exactly the platforms where the offset
   matters. The content stays fully reachable - Tab walks the chips and the
   strip scrolls each one into view, touch swipes, and a trackpad/shift+wheel
   scrolls horizontally. */
.site-header .home-cat-bar.header-cat-bar .home-cat-strip {
  display: flex;
  gap: var(--space-2);
  margin: 0;
  padding: 0.4rem 0;
  list-style: none;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.site-header .home-cat-bar.header-cat-bar .home-cat-strip::-webkit-scrollbar {
  width: 0;
  height: 0;
}

/* display:flex, not the default block: an inline-flex chip inside a block <li>
   sits on a line box and picks up the font's descender, which would make the
   row a couple of unpredictable pixels taller than the 40px chip. A flex item
   has no line box, so the row is exactly the chip's height and --cat-bar-h can
   be a constant. */
.site-header .home-cat-bar.header-cat-bar .home-cat-item {
  display: flex;
  flex: 0 0 auto;
  scroll-snap-align: start;
}

/* The chip, visually identical to the homepage original: pill, hairline border,
   Share Tech Mono, uppercase, >=40px tall for a comfortable tap target at
   375px. */
.site-header .home-cat-bar.header-cat-bar .home-cat-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 40px;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--acher-border-strong);
  border-radius: var(--radius-pill);
  background: var(--acher-surface);
  color: var(--acher-text);
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color var(--transition), color var(--transition),
    box-shadow var(--transition);
}

/* :focus-visible is styled here as well as hovered, but the global green ring
   from section 03 is NOT cancelled - there is no `outline: none` in this file's
   focus states, so a keyboard user always sees where they are. */
.site-header .home-cat-bar.header-cat-bar .home-cat-chip:hover,
.site-header .home-cat-bar.header-cat-bar .home-cat-chip:focus-visible {
  border-color: var(--acher-primary);
  color: var(--acher-primary);
  box-shadow: 0 0 0 2px rgba(var(--acher-primary-rgb), 0.14);
}

.site-header .home-cat-bar.header-cat-bar .home-cat-chip .cat-icon {
  flex: 0 0 auto;
  color: var(--acher-primary);
  font-family: var(--font-display);
  font-size: 1rem;
  font-style: normal;
  line-height: 1;
}

.site-header .home-cat-bar.header-cat-bar .home-cat-chip img.cat-icon-img {
  width: 20px;
  height: 20px;
  object-fit: contain;
}

.site-header .home-cat-bar.header-cat-bar .home-cat-chip-name {
  min-width: 0;
}

@media (prefers-contrast: more) {
  .site-header .home-cat-bar.header-cat-bar {
    background: none;
    border-top-color: var(--acher-border-strong);
  }
}

/* --------------------------------------------------------------------------
   Account menu (TASK 4)

   <details class="account-drop"> whose <summary> IS the .user-chip, so the
   username itself is the control. Native disclosure - no script, works with
   JavaScript off, and the summary is keyboard reachable and shows the global
   green focus ring without any help from here.

   The panel holds Account / Orders / Add funds / Sign out, the last of these
   being the untouched #logout-form / #logout-button that static/js/main.js
   drives; it only changed address, not identity.

   Geometry mirrors .nav-drop exactly (section 06) so the two menus in the
   header behave the same: in the collapsed burger menu the panel is IN FLOW
   under the chip with an indent rule, and from 900px up it becomes an absolute
   card. Right-aligned there, because this is the last cluster in the header and
   a left-aligned panel would hang off the viewport.
   -------------------------------------------------------------------------- */

.account-drop {
  position: relative;
  width: 100%;
  min-width: 0;
}

.account-summary {
  cursor: pointer;
  /* The default disclosure triangle would sit beside our own chevron. */
  list-style: none;
  justify-content: space-between;
  width: 100%;
  max-width: none;
  /* .user-chip is a snug pill; as a menu button it needs a real tap target. */
  min-height: 40px;
  transition: border-color var(--transition), color var(--transition);
}

/* justify-content:space-between on a three-child flex row would centre the name
   between the avatar and the chevron. The avatar and the name are one label:
   keep them together on the left and let the chevron take the far edge. */
.account-summary .user-chip-name {
  margin-right: auto;
}

.account-summary::-webkit-details-marker {
  display: none;
}

.account-summary::marker {
  content: "";
}

.account-summary:hover {
  border-color: rgba(var(--acher-primary-rgb), 0.5);
  color: var(--acher-text);
}

.account-drop[open] > .account-summary {
  border-color: rgba(var(--acher-primary-rgb), 0.5);
  color: var(--acher-text);
}

.account-drop[open] > .account-summary .nav-chevron {
  transform: rotate(180deg);
}

.account-panel {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: var(--space-1) 0 var(--space-2) var(--space-3);
  padding: var(--space-2);
  border-left: 2px solid var(--acher-border);
}

.account-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 40px;
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--acher-dim);
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-align: left;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition: color var(--transition), background-color var(--transition);
}

.account-item:hover {
  background: var(--tint-primary);
  color: var(--acher-primary);
}

/* The Admin row carries page_start()'s `active` state exactly as it did while it
   was a .nav-item in the header row, so an admin browsing /admin still sees
   where they are - the marker just moved from the left edge of a nav cell to the
   left edge of a menu row. */
.account-item.is-active {
  background: var(--tint-primary);
  color: var(--acher-primary);
  box-shadow: inset 2px 0 0 0 var(--acher-primary);
}

.account-item-signout:hover {
  background: rgba(var(--acher-danger-rgb), 0.10);
  color: var(--acher-danger);
}

/* A hairline above the last two rows separates the DESTINATIONS (Account, My
   orders, Add funds, Redeem code) from the ADMINISTRATIVE ones, so Sign out is
   never the row directly under the pointer's travel path. */
.account-item-admin,
.account-logout {
  margin-top: var(--space-1);
  border-top: 1px solid var(--acher-border);
  padding-top: var(--space-1);
}

/* Two consecutive dividers would double the line when an admin sees both rows. */
.account-item-admin + .account-logout {
  margin-top: 0;
  border-top: 0;
  padding-top: 0;
}

/* .logout-form is display:inline-flex (section 06); inside the panel it is one
   full-width row like the links above it. */
.account-logout {
  display: block;
  width: 100%;
  margin: 0;
}

@media (min-width: 900px) {
  .account-drop {
    width: auto;
  }

  .account-summary {
    width: auto;
    max-width: 220px;
  }

  .account-panel {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    z-index: var(--z-dropdown);
    min-width: 220px;
    margin: 0;
    border: 1px solid var(--color-border);
    border-left-width: 1px;
    border-radius: var(--radius);
    background: rgba(15, 15, 15, 0.97);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    box-shadow: var(--shadow-lg);
    animation: fade-slide-down 0.18s ease;
  }

  /* Bridges the 10px gap so the pointer can travel from chip to panel. */
  .account-panel::before {
    content: "";
    position: absolute;
    top: -10px;
    left: 0;
    right: 0;
    height: 10px;
  }
}

/* No blur available -> an opaque raised surface, the same substitution
   .nav-dropdown gets. Scoped to the desktop breakpoint on purpose: below 900px
   the panel is in flow inside the burger menu and has no background at all, so
   an opaque fill there would paint a slab over the menu. */
@media (min-width: 900px) {
  @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .account-panel {
      background: var(--acher-surface-2);
    }
  }
}

/* --------------------------------------------------------------------------
   Redeem trigger (TASK 8, relocated by TASK 1)

   The button only; agent:redeem owns the popup and static/js/redeem.js.

   It used to be a standalone .acher-btn-ghost.is-sm pill sitting in .nav-actions
   between the account chip and Add funds - ~116px of a header row that could not
   afford it. TASK 1 moved it INTO .account-panel, so it is now styled as an
   .account-item like every other row in that menu and this block adds only the
   phone tap target. The id and the data attribute are unchanged; see the comment
   in templates/base.php for why redeem.js does not care where it lives.
   -------------------------------------------------------------------------- */

@media (max-width: 899px) {
  /* In the collapsed burger menu the whole account panel is in flow, so its rows
     get the 44px target the .nav-add-funds CTA beside it already has. The
     Categories dropdown rows sit in the same menu and were measuring 38px, which
     is under the 40px floor - they are levelled up to match rather than left as
     the one cramped list in an otherwise thumb-sized menu. */
  .nav-redeem,
  .account-item,
  .nav-dropdown-item {
    min-height: 44px;
  }

  .nav-redeem {
    width: 100%;
  }

  .account-panel {
    /* Nothing to bridge in flow layout. */
    animation: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .site-header .home-cat-bar.header-cat-bar .home-cat-chip,
  .account-summary,
  .account-item {
    transition: none;
  }

  .account-panel {
    animation: none;
  }
}

/* ==========================================================================
   31. ACHER accessibility & motion guards

   Last block in the file so nothing can undo it.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  /* Kill every ambient loop: shimmer, scanline sweep, glow pulse, float. */
  .skeleton::after,
  .hero-scanlines::after,
  .hero,
  .hero-card,
  .float,
  .animate-in {
    animation: none !important;
  }

  /* The shimmer sits at translateX(-100%) when parked, which would leave the
     skeleton looking empty - park it out of the way with zero opacity instead. */
  .skeleton::after {
    opacity: 0;
  }

  .acher-card:hover,
  .acher-card:focus-within,
  .acher-btn-primary:hover,
  .acher-btn-ghost:hover,
  .acher-btn-danger:hover,
  .variant-box:hover {
    transform: none;
  }

  /* Hover halos are a transition, not a loop - but they still move light
     around, so drop them too. */
  .acher-btn-ghost:hover::before,
  .acher-btn-danger:hover::before,
  .variant-box:hover::before,
  .acher-glow:hover::before {
    opacity: 0;
  }

  /* Glow that was decorative becomes a plain border so state stays legible. */
  .acher-btn-primary:hover {
    box-shadow: none;
    border-color: var(--acher-text);
  }
}

@media (prefers-contrast: more) {
  :root {
    --acher-border: #3a3a3a;
    --acher-border-strong: #565656;
    --acher-muted: #a5a5a5;
    --acher-dim: #d0d0d0;
  }

  .acher-badge,
  .acher-tag,
  .variant-box,
  .acher-card {
    border-color: var(--acher-border-strong);
  }

  .brand-wordmark,
  .price-lg,
  .stat-value {
    text-shadow: none;
  }
}

@media print {
  .search-overlay,
  .nav-cart {
    display: none !important;
  }

  .hero-scanlines::after {
    display: none;
  }

  .acher-card {
    border: 1px solid #cccccc !important;
    background: #ffffff !important;
    box-shadow: none !important;
  }

  .acher-card::before,
  .acher-card::after {
    display: none;
  }

  .brand-wordmark,
  .price-lg,
  .stat-value,
  .step-number,
  .error-code {
    color: #000000 !important;
    -webkit-text-fill-color: #000000 !important;
    text-shadow: none !important;
  }
}
