/* ==========================================================================
   static/css/search.css - ui:homepage-search

   Three scopes, one file (this agent owns no other stylesheet):
     A. additions for the live-search overlay (loaded on every public page)
     B. the ACHER landing page (every selector scoped to body.page-home)
     C. the rented ad BANNER BANDS (global - the markup comes from
        includes/ads.php, which any template may call, so these selectors are
        deliberately NOT scoped to one page)

   THE HOME PAGE SEARCH BAND NO LONGER OPENS THE OVERLAY (section B2)
   templates/index.php's mid-page search is now a plain GET that renders its
   results server-side, in the band, because agent:header-nav is deleting the
   header trigger and the #search-overlay scaffold that band used to relay into.
   Section A stays: main.css still owns the overlay chrome and static/js/search.js
   still builds a fallback overlay for any OTHER caller, so removing these rules
   would only break that. B2 gained the .home-results* block for the new panel.

   RELATIONSHIP TO main.css (ui:design-system)
   main.css already owns and fully styles the overlay chrome and the result row
   contract: .search-overlay .search-panel .search-head .search-title
   .search-close .search-input-wrap #search-input .search-hint #search-results
   .search-result .search-result-thumb .search-result-body .search-result-name
   .search-result-meta .search-result-price .search-empty .search-status
   .skeleton .hero-scanlines .acher-card .acher-btn-* .acher-input
   .thumb .thumb-placeholder body.search-open

   So section A only adds what search.js paints and main.css has no rule for
   (grouping, the image-less thumb, skeleton row sizing, the error tint). It
   re-declares NOTHING and overrides NOTHING - one deliberate exception, the
   inset accent bar on .search-result.is-active, which sets a property
   (box-shadow) main.css leaves untouched on that state.

   Section B is scoped to body.page-home throughout, so nothing here can reach
   another page, and every landing-page class name is unique to this file.

   THE CATEGORY BAR IS THE LANDING VIEW (owner rule, do not undo)
   Featured Categories is a compact horizontal CHIP BAR (section B0) rendered as
   the first section under the header, directly above the hero, so it is on
   screen at scroll position 0 with NO script, NO scroll call and NO animation.
   The hero (section B1) is a compact banner below it, not min-height:100vh. Do
   not reintroduce a viewport height on the hero, and do not "fix" the landing
   view with scrollIntoView.

   WHO EMITS THE BAR: templates/base.php, not templates/index.php. The homepage's
   own copy of <nav id="category-bar" class="home-cat-bar"> was removed once
   agent:header-shell moved the bar into the shared layout - two copies rendered
   two stacked bars. The CSS stayed here by agreement. NOTE for whoever owns B0
   next: its selectors are still prefixed body.page-home, so the bar is unstyled
   on every OTHER page until that prefix is dropped - see the handoff.

   DELIVERY TYPES (products.delivery_type) are badged on every product card via
   main.css's .acher-badge.is-success / .is-warning; sections B4/B5 only scale
   them and add the hollow-ring shape cue. The manual window is 4-24 HOURS.

   Load AFTER main.css. Every animation is disabled under prefers-reduced-motion.
   ========================================================================== */

:root {
  /* Local aliases with literal fallbacks. The --acher-* tokens themselves are
     NEVER redeclared here - main.css is their only home. */
  --ahs-bg: var(--acher-bg, #080808);
  --ahs-surface: var(--acher-surface, #0f0f0f);
  --ahs-deep: var(--acher-bg-deep, #050505);
  --ahs-border: var(--acher-border, #1a1a1a);
  --ahs-border-strong: var(--acher-border-strong, #2a2a2a);
  --ahs-primary: var(--acher-primary, #00ff41);
  --ahs-primary-dim: var(--acher-primary-dim, #00cc33);
  --ahs-text: var(--acher-text, #e8e8e8);
  --ahs-muted: var(--acher-muted, #666666);
  --ahs-dim: var(--acher-dim, #9a9a9a);
  --ahs-danger: var(--acher-danger, #ff2d2d);
  --ahs-warning: var(--acher-warning, #ffaa00);
  --ahs-rgb: var(--acher-primary-rgb, 0, 255, 65);

  --ahs-display: var(--acher-font-display, "Share Tech Mono", "JetBrains Mono", ui-monospace, monospace);
  --ahs-mono: var(--acher-font-mono, "JetBrains Mono", ui-monospace, monospace);
  --ahs-body: var(--acher-font-body, "Inter", system-ui, sans-serif);

  --ahs-radius: var(--radius-sm, 4px);
}

/* ==========================================================================
   A. LIVE SEARCH - additions only
   ========================================================================== */

/* #search-results is a flex column in main.css; a group keeps the same rhythm
   so PRODUCTS and CATEGORIES can be labelled without breaking the spacing. */
.search-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.search-group + .search-group {
  margin-top: 0.85rem;
  border-top: 1px solid var(--ahs-border);
  padding-top: 0.85rem;
}

.search-section {
  margin: 0;
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.66rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

/* Keyboard/pointer highlight gets an accent bar on top of the border+wash
   main.css already applies to .is-active. */
.search-result.is-active {
  box-shadow: inset 2px 0 0 var(--ahs-primary);
}

.search-result.is-active .search-result-name {
  color: var(--ahs-primary);
}

/* The row thumbnail is an <img class="search-result-thumb"> when the product
   has one. When it does not, the same box holds a monospace initial - never a
   broken-image icon. */
img.search-result-thumb {
  display: block;
}

.search-result-thumb.is-empty {
  display: flex;
  align-items: center;
  justify-content: center;
}

.search-result-glyph {
  color: var(--ahs-primary-dim);
  font-family: var(--ahs-display);
  font-size: 1.05rem;
  line-height: 1;
}

/* ---- loading rows: .skeleton paints itself (main.css), sizes come from here */
.search-result.is-loading {
  pointer-events: none;
}

.search-skeleton-thumb {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
}

.search-result.is-loading .search-result-body {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.search-skeleton-line {
  display: block;
  height: 0.7rem;
}

.search-skeleton-line.is-wide { width: 62%; }
.search-skeleton-line.is-narrow { width: 32%; }

.search-skeleton-price {
  flex: 0 0 auto;
  display: block;
  width: 3.4rem;
  height: 0.7rem;
}

/* ---- states painted by search.js ---- */
.search-empty {
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

.search-empty::before {
  content: "> ";
  color: var(--ahs-primary-dim);
}

.search-status.is-error {
  color: var(--ahs-danger);
}

/* ==========================================================================
   B. LANDING PAGE - body.page-home only
   ========================================================================== */

/* The hero paints its own top space, so the generic page padding is dropped
   for this one page. */
body.page-home .page {
  padding-top: 0;
}

body.page-home .section-title::before {
  content: "// ";
  color: var(--ahs-primary-dim);
}

body.page-home .section-sub {
  margin: 0.35rem 0 0;
  max-width: 62ch;
  color: var(--ahs-dim);
  font-family: var(--ahs-body);
  font-size: 0.94rem;
  line-height: 1.6;
}

/* --------------------------------------------------------------------------
   B0. Category bar - THE LANDING VIEW. A compact horizontal strip of category
       chips (icon + name) at the very top, under the header and above the hero.
       Single row that SCROLLS on overflow (scroll-snap), never a wrapped
       multi-row grid; the strip owns the overflow so the PAGE never scrolls
       sideways (body is overflow-x:hidden in main.css). Chips are >=40px tall
       for a comfortable tap target at 375px. Icons come from
       acher_home_cat_icon() (emoji <span class="cat-icon">, icon-font <i>, or an
       uploaded <img class="cat-icon-img">) and are sized down for the chip here.
   -------------------------------------------------------------------------- */

body.page-home .home-cat-bar {
  border-bottom: 1px solid var(--ahs-border);
  background: linear-gradient(180deg, rgba(var(--ahs-rgb), 0.05), transparent);
}

body.page-home .home-cat-strip {
  display: flex;
  gap: 0.5rem;
  margin: 0;
  padding: 0.65rem 0;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
}

body.page-home .home-cat-item {
  flex: 0 0 auto;
  scroll-snap-align: start;
}

body.page-home .home-cat-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 40px;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--ahs-border-strong);
  border-radius: var(--radius-pill, 999px);
  background: var(--ahs-surface);
  color: var(--ahs-text);
  font-family: var(--ahs-display);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color 0.16s ease, color 0.16s ease, box-shadow 0.16s ease;
}

body.page-home .home-cat-chip:hover,
body.page-home .home-cat-chip:focus-visible {
  border-color: var(--ahs-primary);
  color: var(--ahs-primary);
  box-shadow: 0 0 0 2px rgba(var(--ahs-rgb), 0.14);
  outline: none;
}

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

body.page-home .home-cat-chip img.cat-icon-img {
  width: 20px;
  height: 20px;
  object-fit: contain;
}

body.page-home .home-cat-chip-name {
  min-width: 0;
}

/* --------------------------------------------------------------------------
   B1. Hero - a COMPACT BANNER, own class so it never inherits the generic .hero
       card. .hero-scanlines (main.css) is applied to this same element.

   The hero is deliberately NOT min-height:100vh. Featured Categories is the
   landing view and is now the CATEGORY BAR (section B0) rendered ABOVE this
   hero, so customers already land on it at scroll position 0 - the hero is a
   content-sized banner underneath, not a full-screen takeover. Nothing animates
   layout and nothing scrolls the viewport on load, so there is no flash, no
   shift, and Back / a #hash / prefers-reduced-motion have nothing to fight. The
   banner shrinks further under the short-viewport media queries below. Anchor
   jumps (the hero scroll cue -> #search) are offset by the global
   html{scroll-padding-top} in main.css; no scroll-margin-top here, it would
   stack.
   -------------------------------------------------------------------------- */

body.page-home .home-hero {
  position: relative;
  display: grid;
  align-items: center;
  /* NO justify-items here: .home-hero-inner is also a .container and must keep
     stretching to its own max-width. The scroll cue centres itself instead. */
  overflow: hidden;
  /* Content-sized, NOT 100vh - see the block comment above. vh-based padding is
     fine (it flexes without ever driving the box to a full screen). */
  padding-block: clamp(1.1rem, 3.4vh, 2.3rem);
  background:
    radial-gradient(1100px 620px at 50% -8%, rgba(var(--ahs-rgb), 0.10), transparent 70%),
    var(--ahs-bg);
}

body.page-home .home-hero-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.45rem, 1.3vw, 0.8rem);
  text-align: center;
}

/* ---- pure-CSS particle field ---------------------------------------------
   Two layered radial-gradient sheets, each moved with a compositor-only
   transform. No canvas, no library, no JS - and gone entirely under
   prefers-reduced-motion. */
body.page-home .home-hero-particles {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

body.page-home .home-hero-particles::before,
body.page-home .home-hero-particles::after {
  content: "";
  position: absolute;
  inset: -60% -20%;
  background-repeat: repeat;
  will-change: transform;
}

body.page-home .home-hero-particles::before {
  background-image:
    radial-gradient(1.6px 1.6px at 12% 18%, rgba(var(--ahs-rgb), 0.55), transparent 60%),
    radial-gradient(1.2px 1.2px at 68% 12%, rgba(var(--ahs-rgb), 0.38), transparent 60%),
    radial-gradient(1.8px 1.8px at 34% 62%, rgba(var(--ahs-rgb), 0.30), transparent 60%),
    radial-gradient(1.1px 1.1px at 84% 74%, rgba(232, 232, 232, 0.20), transparent 60%),
    radial-gradient(1.4px 1.4px at 52% 88%, rgba(var(--ahs-rgb), 0.26), transparent 60%);
  background-size: 320px 320px;
  animation: ahs-drift-a 34s linear infinite;
}

body.page-home .home-hero-particles::after {
  background-image:
    radial-gradient(1px 1px at 22% 44%, rgba(var(--ahs-rgb), 0.30), transparent 60%),
    radial-gradient(1.3px 1.3px at 76% 28%, rgba(var(--ahs-rgb), 0.20), transparent 60%),
    radial-gradient(0.9px 0.9px at 46% 8%, rgba(232, 232, 232, 0.16), transparent 60%),
    radial-gradient(1.1px 1.1px at 8% 82%, rgba(var(--ahs-rgb), 0.22), transparent 60%);
  background-size: 520px 520px;
  opacity: 0.75;
  animation: ahs-drift-b 58s linear infinite;
}

@keyframes ahs-drift-a {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-320px, 320px, 0); }
}

@keyframes ahs-drift-b {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(520px, 520px, 0); }
}

body.page-home .home-hero-eyebrow {
  margin: 0;
  color: var(--ahs-primary-dim);
  font-family: var(--ahs-display);
  font-size: clamp(0.62rem, 2.2vw, 0.76rem);
  letter-spacing: 0.34em;
  text-transform: uppercase;
}

/* ---- logo: the uploaded PNG when it exists, a monospace wordmark when it does
   not (decided server-side, so a broken-image icon is impossible). Both get the
   same neon pulse. The box reserves its height either way, so swapping in a
   real logo later cannot shift the layout. ---- */
/* Scaled DOWN from the old full-screen hero so the category grid reaches the
   fold. min-height on the box and max-height on the image stay in lockstep, so
   swapping in a real logo.png still cannot shift anything. */
body.page-home .home-hero-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: clamp(40px, 9.5vw, 78px);
  margin: 0;
  line-height: 1;
}

body.page-home .home-hero-logo-img {
  width: clamp(140px, 34vw, 260px);
  max-height: clamp(40px, 9.5vw, 78px);
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 0 14px rgba(var(--ahs-rgb), 0.45));
  animation: ahs-glow-img 3.8s ease-in-out infinite alternate;
}

body.page-home .home-hero-wordmark {
  color: var(--ahs-text);
  font-family: var(--ahs-display);
  /* Kept just under .home-hero-logo's min-height at every width so the wordmark
     never grows the banner box. */
  font-size: clamp(2.1rem, 9.5vw, 4.4rem);
  font-weight: 400;
  letter-spacing: 0.14em;
  /* letter-spacing pads the right edge; pull it back so the word stays centred */
  text-indent: 0.14em;
  text-transform: uppercase;
  animation: ahs-glow-text 3.8s ease-in-out infinite alternate;
}

@keyframes ahs-glow-text {
  from {
    text-shadow:
      0 0 5px rgba(var(--ahs-rgb), 0.40),
      0 0 18px rgba(var(--ahs-rgb), 0.22),
      0 0 48px rgba(var(--ahs-rgb), 0.10);
  }
  to {
    text-shadow:
      0 0 8px rgba(var(--ahs-rgb), 0.70),
      0 0 30px rgba(var(--ahs-rgb), 0.45),
      0 0 78px rgba(var(--ahs-rgb), 0.26);
  }
}

@keyframes ahs-glow-img {
  from { filter: drop-shadow(0 0 8px rgba(var(--ahs-rgb), 0.30)); }
  to   { filter: drop-shadow(0 0 22px rgba(var(--ahs-rgb), 0.62)); }
}

/* ---- typewriter tagline: pure CSS steps().
   The tagline is admin-editable (site_settings key home_hero_tagline), so its
   length is NOT hard-coded here any more: templates/index.php measures the
   string and ships the character count in --ahs-tag-ch (an inline style
   attribute - style-src allows those, script-src forbids the JS alternative).
   The 32 in steps() is only how CHUNKY the typing looks and is deliberately
   left as a constant; a mismatch reveals a few characters at a time, it never
   clips. Copy longer than one phone line gets .is-plain from PHP and opts out
   of the animation entirely. ---- */
body.page-home .home-hero-tagline {
  --ahs-tag-ch: 32;
  display: inline-block;
  overflow: hidden;
  width: 0;
  max-width: 100%;
  margin: 0;
  border-right: 2px solid var(--ahs-primary);
  color: var(--ahs-primary);
  font-family: var(--ahs-mono);
  font-size: clamp(0.7rem, 3.05vw, 1.05rem);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
  animation:
    ahs-type 2.6s steps(32, end) 0.45s forwards,
    ahs-caret 900ms step-end infinite;
}

/* Nch is the glyph advance only: letter-spacing adds 0.03em PER character on
   top of it, so the target width has to include it or the last characters are
   clipped. The +2px keeps the caret clear of the final period. The fallback in
   var() keeps the shipped 32-character default working even if the custom
   property never arrives. */
@keyframes ahs-type {
  from { width: 0; }
  to   { width: calc(var(--ahs-tag-ch, 32) * (1ch + 0.03em) + 2px); }
}

/* Long custom tagline: full text, wrapped, no typing, no caret. Width is auto
   from the start so the text can never be stuck at 0 width. */
body.page-home .home-hero-tagline.is-plain {
  width: auto;
  max-width: 48ch;
  border-right: 0;
  white-space: normal;
  animation: none;
}

@keyframes ahs-caret {
  0%, 100% { border-right-color: var(--ahs-primary); }
  50%      { border-right-color: transparent; }
}

/* Narrower and a touch smaller than before: at 375px the shipped copy is four
   lines instead of five, which is ~22px of the fold handed to the grid. The text
   is never clamped or hidden - admin-edited copy always renders in full. */
body.page-home .home-hero-sub {
  max-width: 54ch;
  margin: 0;
  color: var(--ahs-dim);
  font-family: var(--ahs-body);
  font-size: clamp(0.85rem, 2.1vw, 0.96rem);
  line-height: 1.6;
}

body.page-home .home-hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem;
  margin-top: 0.2rem;
}

/* The buttons themselves are .acher-btn-* from main.css and are NOT restyled -
   only the padding is set, now sized for a banner rather than a full screen. */
body.page-home .home-hero-actions .acher-btn-primary,
body.page-home .home-hero-actions .acher-btn-ghost {
  padding: 0.68rem 1.35rem;
}

body.page-home .home-hero-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.2rem 1.1rem;
  margin: 0.1rem 0 0;
  padding: 0;
  list-style: none;
}

body.page-home .home-hero-meta li {
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

body.page-home .home-hero-meta li::before {
  content: "[+] ";
  color: var(--ahs-primary-dim);
}

/* IN-FLOW, not pinned to the bottom of a full screen any more. As a grid item of
   .home-hero it now sits under the banner content and centres itself, so on a
   short viewport it is a real, visible "there is more below" affordance instead
   of being parked off-screen. It links to #search - the section that
   immediately follows the hero (the category bar sits above the hero). */
body.page-home .home-hero-scroll {
  position: static;
  z-index: 1;
  justify-self: center;
  margin-top: clamp(0.35rem, 1.2vh, 0.8rem);
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-decoration: none;
  text-transform: uppercase;
  animation: ahs-nudge 2.4s ease-in-out infinite;
}

body.page-home .home-hero-scroll::after {
  content: " \25BE";
  color: var(--ahs-primary-dim);
}

body.page-home .home-hero-scroll:hover,
body.page-home .home-hero-scroll:focus-visible {
  color: var(--ahs-primary);
}

/* Y only - the -50% half of the old transform belonged to the absolute
   centering the cue no longer uses. Nothing else references this keyframe. */
@keyframes ahs-nudge {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(4px); }
}

/* Short viewports (landscape phones, 1366x600-ish laptops, a browser with three
   toolbars): trim the banner again so the grid still owns the fold. Padding,
   gaps and the logo box only - no copy is ever hidden, because every string on
   this page is admin-editable and an admin must be able to see their edit. */
@media (max-height: 660px) {
  body.page-home .home-hero {
    padding-block: 0.75rem;
  }

  body.page-home .home-hero-inner {
    gap: 0.4rem;
  }

  body.page-home .home-hero-logo {
    min-height: 34px;
  }

  body.page-home .home-hero-logo-img {
    width: clamp(120px, 26vw, 200px);
    max-height: 34px;
  }

  body.page-home .home-hero-wordmark {
    font-size: clamp(1.7rem, 7vw, 2.6rem);
  }

  body.page-home .home-hero-actions .acher-btn-primary,
  body.page-home .home-hero-actions .acher-btn-ghost {
    padding: 0.55rem 1.15rem;
  }
}

/* A landscape phone (813x375 measured) is the one viewport where a banner, a
   section heading AND a whole 226px card cannot all fit - no amount of CSS wins
   that, and the honest answer is not to hide the hero copy for it. What this
   block buys is the part that matters: another ~45px, which lifts the
   "// Featured categories" heading back above the fold, so the landing view
   still ANNOUNCES the grid and the rest is one flick away. The user is never
   trapped either way - the page scrolls normally and the SCROLL cue is on screen
   (verified: cue fully visible at 813x375). */
@media (max-height: 520px) {
  body.page-home .home-hero {
    padding-block: 0.5rem;
  }

  body.page-home .home-hero-inner {
    gap: 0.3rem;
  }

  body.page-home .home-hero-logo {
    min-height: 28px;
  }

  body.page-home .home-hero-logo-img {
    max-height: 28px;
  }

  body.page-home .home-hero-wordmark {
    font-size: clamp(1.5rem, 6vw, 2.1rem);
  }
}

/* --------------------------------------------------------------------------
   B2. Search band - SELF-SUFFICIENT, server-rendered results

   It used to relay into base.php's #search-overlay through static/js/search.js.
   That overlay is being deleted, so templates/index.php now GETs ?q= back to
   itself and prints the matches in .home-results below the field. No script is
   involved in any of it: the panel is ordinary server-rendered markup, so it
   works with JavaScript off and cannot be broken by a change to search.js.
   -------------------------------------------------------------------------- */

body.page-home .home-search-band {
  margin-block: 0;
  padding-block: clamp(1.4rem, 4vw, 2.4rem);
  border-block: 1px solid var(--ahs-border);
  background: linear-gradient(180deg, rgba(var(--ahs-rgb), 0.04), transparent);
}

body.page-home .home-search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: min(760px, 100%);
  margin-inline: auto;
  padding: 0.4rem 0.45rem 0.4rem 0.85rem;
  border: 1px solid var(--ahs-border-strong);
  border-radius: var(--radius, 6px);
  background: var(--ahs-surface);
  transition: border-color 0.16s ease, box-shadow 0.16s ease;
}

body.page-home .home-search:focus-within {
  border-color: var(--ahs-primary);
  box-shadow: 0 0 0 3px rgba(var(--ahs-rgb), 0.14);
}

body.page-home .home-search-prompt {
  color: var(--ahs-primary);
  font-family: var(--ahs-mono);
  font-size: 1.1rem;
  line-height: 1;
}

body.page-home .home-search-input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.7rem 0.2rem;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--ahs-text);
  font-family: var(--ahs-mono);
  /* >=16px so iOS does not zoom the page when the field takes focus */
  font-size: 1rem;
  letter-spacing: 0.02em;
}

body.page-home .home-search-input::placeholder {
  color: var(--ahs-muted);
  letter-spacing: 0.12em;
  opacity: 1;
}

body.page-home .home-search-input:focus,
body.page-home .home-search-input:hover {
  border: 0;
  outline: none;
  box-shadow: none;
}

body.page-home .home-search-note {
  width: min(760px, 100%);
  margin: 0.7rem auto 0;
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-align: center;
  text-transform: uppercase;
}

body.page-home .home-search-note a {
  color: var(--ahs-primary);
}

@media (max-width: 480px) {
  body.page-home .home-search-btn {
    padding-inline: 0.85rem;
  }

  body.page-home .home-search-btn .home-search-btn-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* ---- server-rendered results panel ----------------------------------------
   Same 760px measure as the field above it, so the panel reads as that field's
   output rather than as a new section. It is only in the DOM when ?q= is set;
   an empty search renders nothing here at all.

   The row contract is DELIBERATELY parallel to main.css's .search-result (thumb
   / body / price on one line, 44px thumb), so the results look identical to the
   overlay rows the store has always shown - but the class names are distinct
   (.home-result*), because these rows are NOT in the overlay's listbox and must
   not inherit its role-specific rules. */

body.page-home .home-results {
  width: min(760px, 100%);
  margin: 1.1rem auto 0;
  overflow: hidden;
  border: 1px solid var(--ahs-border-strong);
  border-radius: var(--radius, 6px);
  background: var(--ahs-surface);
}

/* tabindex="-1" jump target: focused by the #home-results fragment, so it must
   not draw a permanent outline, only a keyboard-visible one. */
body.page-home .home-results:focus {
  outline: none;
}

body.page-home .home-results:focus-visible {
  outline: 2px solid var(--ahs-primary);
  outline-offset: 2px;
}

body.page-home .home-results-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 0.75rem;
  padding: 0.7rem clamp(0.75rem, 3vw, 1.05rem);
  border-bottom: 1px solid var(--ahs-border);
  background: linear-gradient(180deg, rgba(var(--ahs-rgb), 0.06), transparent);
}

body.page-home .home-results-title {
  margin: 0;
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.66rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

/* The term is echoed back so the reader can see WHAT was searched; it wraps
   rather than stretching the head, and min-width:0 lets it shrink at 375px. */
body.page-home .home-results-term {
  display: inline-block;
  max-width: 100%;
  overflow-wrap: anywhere;
  color: var(--ahs-primary);
  font-family: var(--ahs-mono);
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  text-transform: none;
}

body.page-home .home-results-count {
  color: var(--ahs-muted);
  font-family: var(--ahs-mono);
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
}

body.page-home .home-results-clear {
  margin-left: auto;
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-decoration: none;
  text-transform: uppercase;
}

body.page-home .home-results-clear:hover,
body.page-home .home-results-clear:focus-visible {
  color: var(--ahs-primary);
}

body.page-home .home-results-note {
  margin: 0;
  padding: clamp(1.1rem, 4vw, 1.8rem) 1rem;
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-align: center;
  text-transform: uppercase;
}

body.page-home .home-results-note.is-error {
  color: var(--ahs-danger);
}

body.page-home .home-results-section {
  margin: 0;
  padding: 0.55rem clamp(0.75rem, 3vw, 1.05rem) 0.25rem;
  border-top: 1px solid var(--ahs-border);
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.6rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

body.page-home .home-results-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

body.page-home .home-result + .home-result {
  border-top: 1px solid var(--ahs-border);
}

body.page-home .home-result-link {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  /* >=44px: these ARE links, so the tap-target floor is not optional */
  min-height: 56px;
  padding: 0.5rem clamp(0.75rem, 3vw, 1.05rem);
  color: inherit;
  text-decoration: none;
}

body.page-home .home-result-link:hover,
body.page-home .home-result-link:focus-visible {
  background: rgba(var(--ahs-rgb), 0.07);
  outline: none;
}

body.page-home .home-result-link:focus-visible {
  box-shadow: inset 2px 0 0 var(--ahs-primary);
}

body.page-home .home-result-link:hover .home-result-name,
body.page-home .home-result-link:focus-visible .home-result-name {
  color: var(--ahs-primary);
}

body.page-home .home-result-thumb {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border: 1px solid var(--ahs-border);
  border-radius: var(--ahs-radius);
  background: var(--ahs-deep);
  object-fit: cover;
}

body.page-home .home-result-thumb.is-empty {
  display: flex;
  align-items: center;
  justify-content: center;
}

body.page-home .home-result-glyph {
  color: var(--ahs-primary-dim);
  font-family: var(--ahs-display);
  font-size: 1.05rem;
  line-height: 1;
}

body.page-home .home-result-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.15rem;
  /* required before text-overflow can work inside a flex item */
  min-width: 0;
}

body.page-home .home-result-name,
body.page-home .home-result-meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

body.page-home .home-result-name {
  color: var(--ahs-text);
  font-family: var(--ahs-body);
  font-size: 0.92rem;
  font-weight: 600;
}

body.page-home .home-result-meta {
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.58rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

body.page-home .home-result-price {
  flex: 0 0 auto;
  color: var(--ahs-primary);
  font-family: var(--ahs-mono);
  font-size: 0.84rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   B3. Stats bar (values are server-rendered; search.js only counts up to them)
   -------------------------------------------------------------------------- */

body.page-home .stats-band {
  margin-block: 0;
  padding-block: clamp(1.75rem, 5vw, 3rem);
  border-bottom: 1px solid var(--ahs-border);
}

body.page-home .stats-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  margin: 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--ahs-border);
  background: var(--ahs-border);
}

/* The bar carries FIVE cells now (…, Orders, Users). On the two-column mobile
   grid five cells leave one on its own row; span that last cell full width so
   the row never shows a hairline-coloured empty gap beside it. Reset the span at
   the desktop tier where all five sit in one clean row. */
body.page-home .stat-cell:last-child {
  grid-column: 1 / -1;
}

@media (min-width: 900px) {
  body.page-home .stats-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  body.page-home .stat-cell:last-child {
    grid-column: auto;
  }
}

body.page-home .stat-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: clamp(0.95rem, 3vw, 1.6rem) 0.7rem;
  background: var(--ahs-surface);
  text-align: center;
}

body.page-home .stat-value {
  color: var(--ahs-primary);
  font-family: var(--ahs-mono);
  font-size: clamp(1.55rem, 6vw, 2.4rem);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  text-shadow: 0 0 18px rgba(var(--ahs-rgb), 0.32);
}

body.page-home .stat-label {
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.6rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   B5. Featured products - masonry-ish grid, DOM order preserved
   -------------------------------------------------------------------------- */

body.page-home .prod-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr));
  gap: clamp(0.85rem, 2vw, 1.3rem);
  align-items: start;
}

body.page-home .prod-card {
  padding: 0;
  overflow: hidden;
}

/* The "masonry-ish" part: alternate cells ride lower on wide screens. Purely
   visual - the reading order is never shuffled. */
@media (min-width: 900px) {
  body.page-home .prod-card:nth-child(even) {
    transform: translateY(1.6rem);
  }

  /* .acher-card:hover lifts by -1px; without this the offset column would snap
     back to 0 and jump 1.6rem on hover. */
  body.page-home .prod-card:nth-child(even):hover,
  body.page-home .prod-card:nth-child(even):focus-within {
    transform: translateY(calc(1.6rem - 1px));
  }
}

body.page-home .prod-link {
  display: flex;
  flex-direction: column;
  height: 100%;
  color: inherit;
  text-decoration: none;
}

body.page-home .prod-thumb {
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-bottom: 1px solid var(--ahs-border);
  background: var(--ahs-deep);
}

body.page-home .prod-thumb .thumb-placeholder {
  color: rgba(var(--ahs-rgb), 0.30);
}

body.page-home .prod-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0.85rem 1rem 0.95rem;
}

/* First row of the card body: category label on the left, DELIVERY TYPE on the
   right. Sharing this row means the badge costs no extra card height, and both
   pieces of metadata land on one scan line. It wraps rather than squeezing when
   a long category name meets the long manual label on a narrow card. */
body.page-home .prod-meta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.3rem 0.5rem;
}

body.page-home .prod-tag {
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* ---- delivery type: instant vs manual ------------------------------------
   Every colour, border and tint comes from main.css's .acher-badge - .is-success
   for instant, .is-warning for the 4-24 hour window - and NOTHING here overrides
   any of them. This block only scales the badge down onto a 240px card so it
   sits level with the tiny uppercase category label beside it.

   The two are separated on THREE axes, so they are still telling apart when
   colour is unavailable (colour-blindness, forced-colours, greyscale print):
     wording  "Instant" vs "Delivered in 4-24h"
     colour   green    vs amber
     shape    a FILLED, glowing dot (main.css .has-dot) vs a HOLLOW ring
   Filled = the goods are sitting in inventory; hollow = a human still has to
   fill it in. */
body.page-home .prod-delivery {
  flex: 0 0 auto;
  padding: 0.13rem 0.4rem;
  font-family: var(--ahs-display);
  font-size: 0.56rem;
  letter-spacing: 0.11em;
  white-space: nowrap;
}

/* Instant gets its dot from .acher-badge.has-dot in main.css - not restated
   here. Manual is NEVER given .has-dot, so these two ::before rules can never
   both apply to the same badge. */
body.page-home .prod-delivery.is-manual::before {
  content: "";
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border: 1px solid currentColor;
  border-radius: 50%;
  background: transparent;
}

body.page-home .prod-name {
  margin: 0;
  color: var(--ahs-text);
  font-family: var(--ahs-body);
  font-size: 0.98rem;
  font-weight: 600;
  line-height: 1.35;
}

body.page-home .prod-desc {
  margin: 0;
  color: var(--ahs-muted);
  font-family: var(--ahs-body);
  font-size: 0.83rem;
  line-height: 1.55;
}

body.page-home .prod-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: auto;
  padding-top: 0.7rem;
  border-top: 1px solid var(--ahs-border);
}

body.page-home .prod-price {
  color: var(--ahs-primary);
  font-family: var(--ahs-mono);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}

body.page-home .prod-price-empty {
  color: var(--ahs-muted);
}

body.page-home .prod-stock {
  padding: 0.18rem 0.45rem;
  border: 1px solid var(--ahs-border-strong);
  border-radius: 3px;
  font-family: var(--ahs-display);
  font-size: 0.56rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
}

body.page-home .prod-stock-in {
  border-color: rgba(var(--ahs-rgb), 0.4);
  color: var(--ahs-primary);
}

body.page-home .prod-stock-low {
  border-color: rgba(255, 170, 0, 0.4);
  color: var(--ahs-warning);
}

body.page-home .prod-stock-out {
  border-color: rgba(255, 45, 45, 0.4);
  color: var(--ahs-danger);
}

body.page-home .prod-card.is-out .prod-thumb {
  filter: grayscale(1) brightness(0.75);
}

/* --------------------------------------------------------------------------
   B6. Top-up / Add Funds - one centred card, one call to action

   Replaces the retired gift-code guide. The old .steps-grid / .step-card /
   .step-num / .step-title / .step-body rules are GONE with the section they
   styled; nothing else on this page referenced them (main.css keeps its own,
   unrelated .step-title / .step-number for other pages, untouched here).
   -------------------------------------------------------------------------- */

body.page-home .topup-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  max-width: 620px;
  margin-inline: auto;
  padding: clamp(1.6rem, 4vw, 2.6rem) clamp(1.2rem, 4vw, 2.4rem);
  text-align: center;
  background:
    radial-gradient(120% 140% at 50% -20%, rgba(var(--ahs-rgb), 0.08), transparent 70%),
    var(--ahs-surface);
}

body.page-home .topup-title {
  margin: 0;
}

body.page-home .topup-body {
  max-width: 52ch;
  margin: 0;
  color: var(--ahs-dim);
  font-family: var(--ahs-body);
  font-size: 0.96rem;
  line-height: 1.6;
}

body.page-home .topup-actions {
  margin-top: 0.35rem;
}

/* .acher-btn-primary from main.css supplies every colour and state; this only
   gives the banner button a roomier hit area. */
body.page-home .topup-cta {
  padding: 0.75rem 1.8rem;
}

/* --------------------------------------------------------------------------
   B6b. Recent-orders feed - the LEDGER under the Top-up section

   Redesigned to be scanned down rather than read across: a labelled column
   strip sits over a card of hairline rows, and the same five tracks carry both.

   WHY THE TRACKS ARE FIXED, NOT auto. Each row is its own grid (a <ul> of <li>,
   not a table - see the template). With `auto` tracks every row sizes itself, so
   "$19.00" and "$1,261.00" produce different column widths and the right-hand
   edge saws up and down the list; that is exactly what stops a feed reading as a
   ledger. Four of the five tracks are therefore fixed rem widths, identical on
   every row, and only the product column flexes. The widths are sized to the
   worst realistic content in the mono face at these sizes:
     --feed-c-user  5.25rem  "Guest***"  (4 chars + the mask, or the guest label)
     --feed-c-qty   2.75rem  "x100"
     --feed-c-amt   5.5rem   "$1,234.56"
     --feed-c-when  4.5rem   "just now" / "365d ago"
   18rem of fixed track plus four 0.85rem gaps is ~21.4rem, so the product cell
   still gets ~830px inside a 1200px container and ~195px at 560px.

   Desktop  [buyer] [product ..........] [qty] [amount] [when]
   <=36rem  [buyer] [when] ......... [amount]
            [product ....................] [qty]
   Nothing overflows and nothing scrolls sideways at 375px; the product name
   truncates with an ellipsis rather than wrapping, so row heights stay equal.
   The column strip is hidden once the layout stacks - a header for columns that
   no longer exist is worse than none.

   NEW-ROW TREATMENT. recent_orders_feed() flags a row under 15 minutes old and
   the template adds .is-fresh. The cue is deliberately quiet and deliberately
   NOT colour-only: a 2px inset rule down the left edge (position), a very faint
   wash, a "New" pill (text), and the timestamp switched to the primary colour.
   Nothing animates and nothing moves, so there is no reduced-motion case.

   The amount keeps main.css's .acher-price and adds tabular-nums, so the digits
   sit in a true column. Colours are tokens only.
   -------------------------------------------------------------------------- */

/* Heading row: title/sub on the left, the row count on the right. */
body.page-home .feed-head {
  align-items: center;
}

/* flex-basis rather than auto: .section-head wraps, and at 375px an auto-sized
   text block pushed the count pill onto a line of its own where it read as a
   stray number. 12rem lets the heading shrink instead, so the count stays
   beside it at every width. */
body.page-home .feed-head-text {
  flex: 1 1 12rem;
  min-width: 0;
}

body.page-home .feed-count {
  flex: 0 0 auto;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--ahs-border-strong);
  border-radius: var(--radius-pill, 999px);
  color: var(--ahs-primary);
  font-family: var(--ahs-mono);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
}

body.page-home .home-feed {
  /* Declared once here and read by BOTH the column strip and every row, so the
     two can never drift out of alignment. */
  --feed-c-user: 5.25rem;
  --feed-c-qty: 2.75rem;
  --feed-c-amt: 5.5rem;
  --feed-c-when: 4.5rem;
  --feed-cols: var(--feed-c-user) minmax(0, 1fr) var(--feed-c-qty) var(--feed-c-amt) var(--feed-c-when);
  --feed-pad-x: clamp(0.75rem, 3vw, 1.15rem);

  margin: 1.4rem 0 0;
  padding: 0;
  overflow: hidden; /* keeps the row hairlines inside the card's radius */
}

body.page-home .feed-cols {
  display: grid;
  grid-template-columns: var(--feed-cols);
  gap: 0.85rem;
  padding: 0.5rem var(--feed-pad-x);
  border-bottom: 1px solid var(--ahs-border);
  background: linear-gradient(180deg, rgba(var(--ahs-rgb), 0.06), transparent);
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.56rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

/* qty / amount / when are right-aligned in the strip because their values are. */
body.page-home .feed-cols span:nth-child(3),
body.page-home .feed-cols span:nth-child(4),
body.page-home .feed-cols span:nth-child(5) {
  text-align: right;
}

body.page-home .feed-list {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}

body.page-home .feed-row {
  display: grid;
  grid-template-columns: var(--feed-cols);
  align-items: center;
  gap: 0.2rem 0.85rem;
  min-height: 44px;
  padding: 0.5rem var(--feed-pad-x);
  font-size: 0.9rem;
}

body.page-home .feed-row + .feed-row {
  border-top: 1px solid var(--ahs-border);
}

body.page-home .feed-row:hover {
  background: rgba(var(--ahs-rgb), 0.035);
}

/* ---- the "just landed" row ---- */
body.page-home .feed-row.is-fresh {
  box-shadow: inset 2px 0 0 var(--ahs-primary);
  background: rgba(var(--ahs-rgb), 0.05);
}

body.page-home .feed-row.is-fresh .feed-ago {
  color: var(--ahs-primary);
}

body.page-home .feed-new {
  flex: 0 0 auto;
  padding: 0.05rem 0.3rem;
  border: 1px solid rgba(var(--ahs-rgb), 0.45);
  border-radius: 3px;
  color: var(--ahs-primary);
  font-family: var(--ahs-display);
  font-size: 0.5rem;
  letter-spacing: 0.14em;
  line-height: 1.5;
  text-transform: uppercase;
}

body.page-home .feed-user {
  display: inline-flex;
  align-items: baseline;
  min-width: 0;
  overflow: hidden;
  color: var(--ahs-primary);
  font-family: var(--ahs-mono);
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

/* The visible proof that the name is deliberately cut to four characters. */
body.page-home .feed-user-mask {
  color: var(--ahs-muted);
  letter-spacing: 0.12em;
}

/* The only flexible track, so it is also the only place the "New" pill can sit
   without widening a fixed column on fresh rows only. */
body.page-home .feed-product {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

body.page-home .feed-product-name {
  min-width: 0; /* required for text-overflow inside a flex item */
  overflow: hidden;
  color: var(--ahs-text);
  font-family: var(--ahs-body);
  text-overflow: ellipsis;
  white-space: nowrap;
}

body.page-home .feed-qty {
  color: var(--ahs-dim);
  font-family: var(--ahs-mono);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

body.page-home .feed-amount {
  font-family: var(--ahs-mono);
  font-size: 0.88rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

body.page-home .feed-ago {
  color: var(--ahs-muted);
  font-family: var(--ahs-mono);
  font-size: 0.72rem;
  text-align: right;
  white-space: nowrap;
}

/* Phones: two lines per row, and the column strip goes away with the columns.
   Line one is who / when / how much, line two is what / how many, so the money
   still lands on the same line as the person and the product keeps a whole line
   to itself before it has to truncate. */
@media (max-width: 36rem) {
  body.page-home .feed-cols {
    display: none;
  }

  body.page-home .feed-row {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "user when amount"
      "prod prod qty";
    gap: 0.2rem 0.6rem;
    padding-block: 0.6rem;
  }

  body.page-home .feed-user    { grid-area: user; }
  body.page-home .feed-ago     { grid-area: when; text-align: left; }
  body.page-home .feed-amount  { grid-area: amount; }
  body.page-home .feed-product { grid-area: prod; }
  body.page-home .feed-qty     { grid-area: qty; }
}

/* --------------------------------------------------------------------------
   B7. Empty states, error alert

   The old .redeem-band / .redeem-copy / .redeem-code-sample rules (and, later,
   the .guide-actions button spacing) are GONE with the sections they styled:
   gift codes are private and the how-it-works guide has been replaced by the
   Top-up section above. Nothing else in the app referenced those classes.
   -------------------------------------------------------------------------- */

body.page-home .home-empty {
  padding: clamp(1.4rem, 5vw, 2.4rem);
  border: 1px dashed var(--ahs-border-strong);
  border-radius: var(--ahs-radius);
  color: var(--ahs-muted);
  font-family: var(--ahs-display);
  font-size: 0.76rem;
  letter-spacing: 0.18em;
  text-align: center;
  text-transform: uppercase;
}

body.page-home .home-alert {
  margin-bottom: 1.5rem;
  padding: 0.85rem 1.05rem;
  border: 1px solid rgba(255, 45, 45, 0.45);
  border-radius: var(--ahs-radius);
  background: rgba(255, 45, 45, 0.08);
  color: var(--ahs-danger);
  font-family: var(--ahs-mono);
  font-size: 0.85rem;
}

/* --------------------------------------------------------------------------
   B9. Sponsored ad rail - DELETED, DO NOT REINSTATE

   A position:fixed 150px rail used to live here, pinned into the right-hand
   gutter above 1560px (.home-ad-rail / .home-ad-label / .home-ad / .home-ad-img
   - all four rules are gone, and templates/index.php no longer emits any of the
   markup). It was replaced because the owner's rule is that the banner and the
   content are BOTH clearly visible and an ad never shrinks or covers content:
   a fixed rail is an overlay by construction, it claims gutter space the layout
   could have used, and it vanished on the phones where most visitors are.
   Home-page advertising is section C below - long horizontal bands in normal
   document flow. Nothing else in the app referenced these four classes.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   B10. Telegram live-chat button - floating, fixed, bottom-right

   A plain <a> (keyboard reachable, no JS), fixed to the bottom-right corner and
   layered above page content. It stays clear of the ad rail (B9 ends 7rem above
   the viewport bottom; this lives in the bottom ~1.5rem) and floats above the
   footer rather than being buried by it. z-index is below the search overlay
   (950) and toasts (1000) so those still cover it when open.
   -------------------------------------------------------------------------- */

body.page-home .home-tg-btn {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  z-index: 90;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.25rem;
  height: 3.25rem;
  color: var(--ahs-bg);
  background: var(--ahs-primary);
  border: 1px solid var(--ahs-primary-dim);
  border-radius: var(--radius-pill, 999px);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.45), 0 0 14px rgba(var(--ahs-rgb), 0.4);
  text-decoration: none;
  transition: transform 0.16s ease, box-shadow 0.16s ease;
}

body.page-home .home-tg-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.5), 0 0 20px rgba(var(--ahs-rgb), 0.55);
}

body.page-home .home-tg-btn:focus-visible {
  outline: 2px solid var(--ahs-primary);
  outline-offset: 3px;
}

body.page-home .home-tg-glyph {
  display: block;
  width: 26px;
  height: 26px;
  /* the paper-plane's mass sits right of centre; nudge it back so it reads
     centred inside the round button */
  margin-left: -2px;
}

/* At 375px keep the button snug in the corner and a touch smaller so it never
   crowds content or the thumb-reach zone. */
@media (max-width: 420px) {
  body.page-home .home-tg-btn {
    right: 1rem;
    bottom: 1rem;
    width: 3rem;
    height: 3rem;
  }
}

/* --------------------------------------------------------------------------
   B8. Reduced motion - every animation above is optional
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  /* The particle field IS the animation, so it goes away entirely. */
  body.page-home .home-hero-particles {
    display: none;
  }

  body.page-home .home-hero-particles::before,
  body.page-home .home-hero-particles::after,
  body.page-home .home-hero-logo-img,
  body.page-home .home-hero-wordmark,
  body.page-home .home-hero-scroll {
    animation: none !important;
  }

  /* Tagline: shown complete, no typing, no caret. */
  body.page-home .home-hero-tagline {
    width: auto;
    border-right: 0;
    animation: none !important;
  }

  body.page-home .home-hero-wordmark {
    text-shadow:
      0 0 6px rgba(var(--ahs-rgb), 0.50),
      0 0 22px rgba(var(--ahs-rgb), 0.30);
  }

  body.page-home .home-hero-logo-img {
    filter: drop-shadow(0 0 14px rgba(var(--ahs-rgb), 0.45));
  }

  /* .home-ad is gone with the rail (B9). The ad BANNER's own reduced-motion
     rule lives in section C, where the class is defined, because that markup is
     not page-home scoped. */
  body.page-home .home-search,
  body.page-home .home-cat-chip,
  body.page-home .prod-card,
  body.page-home .home-tg-btn {
    transition: none;
  }

  body.page-home .prod-card:nth-child(even) {
    transform: none;
  }

  /* The chat button's only motion is a hover lift; drop it too. */
  body.page-home .home-tg-btn:hover {
    transform: none;
  }
}

/* ==========================================================================
   C. RENTED AD BANNERS - includes/ads.php :: ads_render_banner()

   NOT scoped to body.page-home on purpose: the markup comes from a shared
   include and any template may print a band. Every class here is prefixed
   .ads-banner*, which nothing else in the app uses. (The OTHER ad renderer,
   ads_render_band(), still ships its own inline <style> for the login page and
   is untouched by this section - the class names do not overlap.)

   -----------------------------------------------------------------------
   THE BAND NEVER CROWDS THE CONTENT
   -----------------------------------------------------------------------
   .ads-banner is a plain block <section> in normal document flow. It is not
   fixed, not sticky, not absolute, not floated and not a grid/flex column
   beside anything. It takes a full-width horizontal slice of the page and every
   other section keeps 100% of the width it had - the product grid is never
   narrowed and nothing is ever covered. There is no z-index in this section at
   all, which is the simplest possible proof that it cannot overlay content.

   -----------------------------------------------------------------------
   NO LAYOUT SHIFT
   -----------------------------------------------------------------------
   .ads-banner-media declares aspect-ratio, so the box has its final height from
   the first layout pass - before the creative has loaded a byte. object-fit:
   contain letterboxes the artwork into that box, so an advertiser's image is
   never cropped to a ratio they did not buy. (An <img> with a src that 404s
   still occupies the reserved box, so even a broken banner cannot shift the
   page.)

   -----------------------------------------------------------------------
   AUTO-HIDE - THE THRESHOLD IS 48rem (768px) AND HERE IS WHY
   -----------------------------------------------------------------------
   The standard leaderboard creative is 728x90 (8.09:1). .container is
   var(--container-max) wide with var(--container-pad) of side padding, so at a
   768px viewport the inner measure is ~736px and a 728px banner renders at
   essentially 1:1 - 768px is the NARROWEST viewport at which a leaderboard is
   shown at its intended size. Below it the same creative is downscaled: at
   375px the usable width is ~343px, which renders the banner 42px tall and its
   copy illegible. A 42px-tall smear of unreadable text serves neither the
   advertiser (nobody can read the offer) nor the visitor (it is just noise), so
   .ads-banner--lead is display:none there. Phones get .ads-banner--stack
   instead - a 300x250 rectangle, stacked vertically - and that one is
   display:none from 48rem up so the two can never both appear.

   display:none is set on the BAND ITSELF and all of its padding lives on the
   band, so a hidden band is exactly zero pixels tall: no gap, no stray margin,
   no border. A CSS-only switch is also the only kind that works here - the CSP
   forbids inline script and this feature is not worth a JS file.

   HIDE WHEN UNRENTED is enforced upstream: ads_render_banner() returns '' for
   an empty placement, so an unrented store never emits the wrapper at all and
   none of these rules ever match anything.
   ========================================================================== */

.ads-banner {
  display: block;
  width: 100%;
  padding-block: clamp(1rem, 3vw, 1.6rem);
  border-block: 1px solid var(--ahs-border);
  background: linear-gradient(180deg, rgba(var(--ahs-rgb), 0.03), transparent);
}

/* Matches .container (main.css) so the banner's edges line up with every other
   section on the page instead of floating in its own measure. */
.ads-banner-inner {
  width: 100%;
  max-width: var(--container-max, 1200px);
  margin-inline: auto;
  padding-inline: var(--container-pad, 1rem);
}

.ads-banner-label {
  margin: 0 0 0.4rem;
  color: var(--ahs-text);
  font-family: var(--ahs-display);
  font-size: 0.9rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.ads-banner-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ads-banner-item {
  position: relative;
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--ahs-border);
  border-radius: var(--ahs-radius);
  background: var(--ahs-deep);
  transform: translateY(0);
  filter: brightness(1);
  transition: transform 0.18s ease, border-color 0.18s ease,
              box-shadow 0.18s ease, filter 0.18s ease;
}

.ads-banner-item:focus-within {
  z-index: 1;
  transform: translateY(-3px);
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow: 0 9px 24px rgba(0, 0, 0, 0.34),
              inset 0 1px 0 rgba(255, 255, 255, 0.08);
  filter: brightness(1.04);
}

@media (hover: hover) and (pointer: fine) {
  .ads-banner-item:hover {
    z-index: 1;
    transform: translateY(-4px);
    border-color: rgba(255, 255, 255, 0.22);
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.42),
                inset 0 1px 0 rgba(255, 255, 255, 0.1);
    filter: brightness(1.05) contrast(1.02);
  }
}

.ads-banner-link {
  display: block;
  color: inherit;
  text-decoration: none;
}

.ads-banner-link:focus-visible,
.ads-banner-visit:focus-visible {
  outline: 2px solid var(--ahs-primary);
  outline-offset: -2px;
}

/* THE RESERVED BOX. aspect-ratio is set per variant below; everything the two
   share lives here. */
.ads-banner-media {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
  background: var(--ahs-deep);
}

/* A <video> cannot be wrapped in the link and still be playable, so the video
   variant gets this explicit tracked link underneath it instead. */
.ads-banner-visit {
  display: block;
  padding: 0.5rem 0.75rem;
  border-top: 1px solid var(--ahs-border);
  color: var(--ahs-primary);
  font-family: var(--ahs-display);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  /* >=44px tap target */
  min-height: 44px;
  line-height: 2.1;
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
}

.ads-banner-visit:hover {
  background: rgba(var(--ahs-rgb), 0.08);
  text-decoration: underline;
}

/* ---- variant: the wide leaderboard, >= 48rem only ------------------------ */

.ads-banner--lead {
  display: none;
}

.ads-banner--lead .ads-banner-media {
  /* 728x90. Reserved before load; the cap stops an oversized creative eating
     the fold on a very wide monitor (1600px inner measure would otherwise be
     198px tall). */
  aspect-ratio: 728 / 90;
  max-height: 11rem;
}

@media (min-width: 48rem) {
  .ads-banner--lead {
    display: block;
  }
}

/* ---- variant: the stacked phone band, < 48rem only ----------------------- */

.ads-banner--stack .ads-banner-list {
  /* "Vertical/stacked orientation": one rectangle per row, centred, never a
     side-by-side strip that would squeeze both of them to nothing. */
  gap: 0.85rem;
}

.ads-banner--stack .ads-banner-item {
  width: 100%;
  max-width: 300px;
  margin-inline: auto;
}

.ads-banner--stack .ads-banner-media {
  /* 300x250, the standard mobile rectangle. Portrait-ish rather than long, so
     it stays legible on a 343px-wide screen. */
  aspect-ratio: 300 / 250;
}

@media (min-width: 48rem) {
  .ads-banner--stack {
    display: none;
  }
}

/* ---- variant: Partners & Sponsors, two compact banners per row ----------- */

.ads-banner--sponsors .ads-banner-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  gap: 0.65rem 0.75rem;
}

.ads-banner--sponsors .ads-banner-item {
  min-width: 0;
  align-self: start;
}

.ads-banner--sponsors .ads-banner-media {
  /* Sponsor artwork is a horizontal web banner. Let its own dimensions set the
     height: a fixed box either crops it or creates the large black letterbox the
     previous 300/250 rule produced. */
  aspect-ratio: auto;
  height: auto;
  max-height: none;
  object-fit: initial;
}

@media (max-width: 47.99rem) {
  .ads-banner--sponsors .ads-banner-list {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ads-banner-item {
    transition: none;
  }

  .ads-banner-item:hover,
  .ads-banner-item:focus-within {
    transform: none;
    filter: none;
  }
}
