/* ===== DESIGN TOKENS =====
 * shadcn/ui preset `b2oqVQdgO`, theme layer only (the equivalent of
 * `shadcn apply --preset b2oqVQdgO --only theme`). The preset code decodes to:
 *   base: base · style: maia · baseColor: olive · theme: green · chartColor: green
 *   radius: default (0.625rem) · menuAccent: subtle · menuColor: default
 *   font: inter / fontHeading: inherit  ← NOT applied: `--only theme` excludes the font
 *   layer, and the site is Georgian-first, so 'Noto Sans Georgian' is kept.
 * Values below are copied verbatim from the resolved registry item (`base-maia-theme`,
 * light set). This project is vanilla CSS with no Tailwind/npm, so the tokens live here as
 * plain custom properties instead of an `@theme` block — same names, same values.
 * Only the light set is defined (dark mode intentionally out of scope).
 */
:root {
  --background: oklch(1 0 0);
  --foreground: oklch(0.153 0.006 107.1);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.153 0.006 107.1);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.153 0.006 107.1);
  --primary: oklch(0.527 0.154 150.069);
  --primary-foreground: oklch(0.982 0.018 155.826);
  --secondary: oklch(0.967 0.001 286.375);
  --secondary-foreground: oklch(0.21 0.006 285.885);
  --muted: oklch(0.966 0.005 106.5);
  --muted-foreground: oklch(0.58 0.031 107.3);
  --accent: oklch(0.966 0.005 106.5);
  --accent-foreground: oklch(0.228 0.013 107.4);
  --destructive: oklch(0.577 0.245 27.325);
  --border: oklch(0.93 0.007 106.5);
  --input: oklch(0.93 0.007 106.5);
  --ring: oklch(0.737 0.021 106.9);
  --chart-1: oklch(0.871 0.15 154.449);
  --chart-2: oklch(0.723 0.219 149.579);
  --chart-3: oklch(0.627 0.194 149.214);
  --chart-4: oklch(0.527 0.154 150.069);
  --chart-5: oklch(0.448 0.119 151.328);
  --radius: 0.625rem;

  /* ===== DERIVED TOKENS =====
   * Not part of the preset — a few extra steps the site needs that a shadcn component
   * library would normally get from Tailwind utilities (hover shades, tinted surfaces,
   * status colors). All expressed in the preset's own hues so they stay on-palette. */
  --primary-hover:  oklch(0.448 0.119 151.328);  /* = chart-5, one step darker than primary */
  --primary-subtle: oklch(0.962 0.031 152);      /* primary at ~4% — pill/hover backgrounds */
  --primary-ring:   oklch(0.527 0.154 150.069 / 0.35);
  --border-strong:  oklch(0.87 0.011 106.7);
  --overlay:        oklch(0.153 0.006 107.1 / 0.55);
  /* Scrim laid over the wood-species card photos so the white label/pills stay readable on
     any image. Single knob — raise/lower the alpha here and both cards follow. Kept inside
     the requested 35–45% band. */
  --species-card-overlay: oklch(0.153 0.006 107.1 / 0.42);
  /* Scrim over the photo-backed tiles in the "choose by category" grid (#uses). Flat, because
     the labels sit centred — a vertical ramp would put its dark end where no text is. Each tile
     overrides this with its own value (see the --use-tile-scrim lines further down) rather than
     sharing one: the three photos differ a lot in brightness, so a single number either lets the
     palest (facade) fall under the contrast floor or needlessly muddies the darkest (ceiling).
     This is only the fallback for a tile that doesn't set its own. */
  --use-tile-scrim: oklch(0.153 0.006 107.1 / 0.45);

  /* Status */
  --in-stock:    oklch(0.527 0.154 150.069);
  --low-stock:   oklch(0.62 0.145 62);
  --special-order: oklch(0.55 0.09 255);
  /* `--whatsapp: #25D366;` (WhatsApp brand green — a fixed brand colour, deliberately not themed)
     was here. Removed with the last thing that used it, the mobile bar's `.mbar-btn.wa` button.
     To restore, uncomment the line below and put `.mbar-btn.wa` back in the MOBILE STICKY BAR
     block near the end of this file, where it is recorded the same way. */
  /* --whatsapp:    #25D366; */

  /* Shadows — neutral (olive-black), matching shadcn's subtle elevation scale */
  --shadow-xs:   0 1px 2px 0 oklch(0.153 0.006 107.1 / 0.05);
  --shadow-sm:   0 1px 3px 0 oklch(0.153 0.006 107.1 / 0.07), 0 1px 2px -1px oklch(0.153 0.006 107.1 / 0.05);
  --shadow-md:   0 4px 8px -2px oklch(0.153 0.006 107.1 / 0.08), 0 2px 4px -2px oklch(0.153 0.006 107.1 / 0.05);
  --shadow-lg:   0 12px 20px -6px oklch(0.153 0.006 107.1 / 0.11), 0 4px 8px -4px oklch(0.153 0.006 107.1 / 0.06);

  --r:    var(--radius);                 /* 10px */
  --r-sm: calc(var(--radius) - 2px);     /*  8px */
  --r-lg: calc(var(--radius) + 4px);     /* 14px */
  --font: 'Noto Sans Georgian', system-ui, -apple-system, sans-serif;

  /* ===== LEGACY ALIASES =====
   * The site was built on a warm cream/wood palette whose variable names are referenced by
   * several hundred rules across style.css / product.css / about.css. Rather than renaming
   * every call site, each old name is remapped onto the preset token that plays the same
   * role — so the whole site re-skins from the block above, and any rule not explicitly
   * restyled still lands on-palette. Prefer the preset names for NEW rules. */
  --green-dark:  var(--primary-hover);
  --green-mid:   var(--primary);
  --green-light: var(--chart-3);
  --green-pale:  var(--primary-subtle);

  --wood-dark:   var(--foreground);        /* headings / strongest text */
  --wood-rich:   var(--accent-foreground);
  --wood-mid:    var(--muted-foreground);
  --wood-light:  var(--border-strong);
  --wood-pale:   var(--muted);

  --cream:       var(--background);
  --warm-bg:     var(--muted);
  --white:       var(--card);

  --text:        var(--foreground);
  --text-mid:    oklch(0.42 0.019 107.3);
  --text-muted:  var(--muted-foreground);

  --border-light: oklch(0.955 0.005 106.5);

  /* Sticky header's actual rendered height, kept in sync by script.js (via ResizeObserver —
     see "HEADER HEIGHT" there) since it changes across breakpoints (wraps to multiple rows on
     mobile). 64px here is just the desktop fallback for the instant before that first runs. Used
     by `scroll-margin-top` below so in-page anchor links/scrollIntoView() land with their target
     fully visible under the sticky header instead of partly hidden behind it. */
  --header-h: 64px;
}

/* ===== RESET ===== */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
/* Users who ask the OS for reduced motion get instant jumps instead of the smooth scroll
   above and no transitions/animations anywhere — previously `scroll-behavior: smooth` and
   every component transition applied unconditionally. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
body {
  font-family: var(--font);
  color: var(--foreground);
  background: var(--background);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
a { color: inherit; text-decoration: none; }
ul { list-style: none; }
button { cursor: pointer; border: none; background: none; font-family: var(--font); color: inherit; }
input, select, textarea { font-family: var(--font); }
img { max-width: 100%; display: block; }
::selection { background: var(--primary-subtle); color: var(--primary-hover); }

/* Site-wide keyboard focus ring (shadcn convention: a `--ring`-colored halo, never an
   outline on mouse click). Previously nothing on this site had ANY visible focus state —
   `.search-input:focus` cleared its outline outright — making it unusable via keyboard. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* ===== LAYOUT ===== */
.container { max-width: 1200px; margin: 0 auto; padding: 0 20px; }
.section { padding: 64px 0; }
.section-alt { background: var(--muted); border-block: 1px solid var(--border); }
.section-alt + .section-alt { border-top: none; }
.section-dark { background: var(--foreground); color: var(--background); }
.hidden { display: none !important; }

/* ===== TYPOGRAPHY ===== */
.section-title {
  font-size: clamp(1.4rem, 3vw, 1.9rem);
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--foreground);
  margin-bottom: 28px;
  line-height: 1.25;
}
.section-title.light { color: var(--background); }
.section-title.has-subtitle { margin-bottom: 6px; }
.section-subtitle { font-size: 0.92rem; color: var(--muted-foreground); margin-bottom: 28px; }

/* ===== BUTTONS =====
 * shadcn button anatomy: every variant carries the SAME 1px border (transparent on solid
 * variants) so a solid and an outline button sitting side by side are pixel-identical in
 * height. Previously `.btn-primary` had no border while `.btn-outline` had a 2px one, which
 * made outline buttons 4px taller than the solid button next to them everywhere they were
 * paired (hero, B2B block, product card actions, contact card, About CTA). */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 20px;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font-weight: 600;
  font-size: 0.94rem;
  line-height: 1.4;
  font-family: var(--font);
  transition: background-color 0.16s ease, color 0.16s ease, border-color 0.16s ease, box-shadow 0.16s ease;
  text-align: center;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  user-select: none;
}
.btn-lg { padding: 13px 26px; font-size: 1rem; border-radius: var(--r); }
.btn-sm { padding: 7px 12px; font-size: 0.8rem; }
.btn-full { width: 100%; justify-content: center; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; pointer-events: none; }

.btn-primary { background: var(--primary); color: var(--primary-foreground); box-shadow: var(--shadow-xs); }
.btn-primary:hover { background: var(--primary-hover); }

.btn-outline { border-color: var(--border); background: var(--background); color: var(--foreground); box-shadow: var(--shadow-xs); }
.btn-outline:hover { background: var(--accent); color: var(--accent-foreground); border-color: var(--border-strong); }

.btn-secondary { background: var(--muted); color: var(--accent-foreground); }
.btn-secondary:hover { background: var(--border); }

.btn-ghost { color: var(--muted-foreground); }
.btn-ghost:hover { background: var(--accent); color: var(--accent-foreground); }

.btn-outline-light { border-color: oklch(1 0 0 / 0.35); color: oklch(1 0 0); }
.btn-outline-light:hover { background: oklch(1 0 0 / 0.12); border-color: oklch(1 0 0 / 0.55); }

/* `.btn-whatsapp` was here and is gone with the "WhatsApp — საპროექტო ფასი" button in the #b2b
   section of index.html, its only call site (see the note there). If that button is ever restored,
   the rules were:
   .btn-whatsapp { background: var(--whatsapp); color: #fff; box-shadow: var(--shadow-xs); }
   .btn-whatsapp:hover { background: #1ebe59; }
   The `--whatsapp` token is gone too: `.mbar-btn.wa` (mobile bar) was its last user and has now
   been removed as well, so the token sits commented out in `:root` at the spot it occupied. */

/* ===== HEADER ===== */
#header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: oklch(1 0 0 / 0.85);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--border);
}
/* Fallback for browsers without backdrop-filter — otherwise the header would be
   semi-transparent with no blur and content would show through while scrolling. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  #header { background: var(--background); }
}

/* Every section actually targeted by an in-page anchor link (nav "მთავარი"/logo → #hero,
   "კონტაქტი" → #footer, nav-dropdown/footer species links → #products/#species). Without this,
   the sticky header (position: sticky, always pinned at top:0) ends up rendered on top of the
   target's own top edge after the browser scrolls it to y:0, hiding exactly that much of its
   content — which is the reported "lands slightly above the section, first thing visible is
   whatever's below the header's height" bug. `scroll-margin-top` shifts the browser's own anchor
   landing point (and any scrollIntoView() call, e.g. the ones in script.js's filter functions) so
   the target's top lands just below the header instead of underneath it. */
#hero, #uses, #species, #popular, #products, #b2b, #footer {
  scroll-margin-top: calc(var(--header-h) + 12px);
}
/* `#header.scrolled` replaces the inline `style.boxShadow` script.js used to assign on every
   scroll event — same effect, but the value is a design token instead of a hardcoded rgba()
   string living in JS, and the header no longer gets an inline style written to it ~60×/sec. */
#header.scrolled { box-shadow: var(--shadow-md); }

.header-inner {
  display: flex;
  align-items: center;
  gap: 10px;
  /* `min-height`, was a fixed `height: 64px` — same 64px bar, it just can't clip the contact block
     if a line is ever added to it.
     Explicitly NOT `flex-wrap: wrap`: that was tried here and is exactly what jumbled this bar.
     Measured at 1450px, the row's contents are ~15px wider than the 1160px container and always
     have been — harmlessly, because the excess only eats into the container's own 20px padding
     and never reaches the viewport edge (the page has no horizontal scrollbar at any width). With
     wrapping switched on, though, that 15px was enough to throw `.header-contact` onto a second
     row and turn a 64px bar into a jumbled 105px one. Overflowing by a hair looks like nothing;
     wrapping looks broken. Below 1300px the media queries below wrap the bar deliberately, which
     is a different thing entirely. */
  min-height: 64px;
}
.logo {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 1.25rem;
  font-weight: 800;
  color: var(--foreground);
  flex-shrink: 0;
  letter-spacing: -0.02em;
}
.logo-icon { color: var(--primary); flex-shrink: 0; }
.logo-text { font-weight: 800; }
.logo-ge { font-weight: 400; color: var(--muted-foreground); font-size: 0.78em; letter-spacing: 0; }

/* ===== MAIN NAV ===== */
.main-nav { flex-shrink: 0; }
.nav-list {
  display: flex;
  align-items: center;
  gap: 2px;
}
.nav-item { position: relative; }
.nav-link {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted-foreground);
  white-space: nowrap;
  transition: background-color 0.15s, color 0.15s;
}
/* menuAccent: subtle — hovered/active menu items use the neutral `accent` surface, not a
   tinted primary one; the primary color only marks the ACTIVE item's text. */
.nav-link:hover { background: var(--accent); color: var(--accent-foreground); }
.nav-link.active { color: var(--primary); background: var(--primary-subtle); }
.nav-caret { font-size: 0.6rem; line-height: 1; transition: transform 0.2s ease; }

.dropdown-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 240px;
  background: var(--popover);
  color: var(--popover-foreground);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: var(--shadow-lg);
  padding: 5px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.98);
  transform-origin: top left;
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
  z-index: 300;
}
.dropdown-menu li a {
  display: block;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--muted-foreground);
  transition: background-color 0.12s, color 0.12s;
}
.dropdown-menu li a:hover { background: var(--accent); color: var(--accent-foreground); }

@media (min-width: 901px) {
  .nav-item.has-dropdown:hover .dropdown-menu,
  .nav-item.has-dropdown:focus-within .dropdown-menu {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
  }
  .nav-item.has-dropdown:hover .nav-caret,
  .nav-item.has-dropdown:focus-within .nav-caret { transform: rotate(180deg); }
}

.hamburger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: var(--r-sm);
  transition: background 0.15s;
}
.hamburger:hover { background: var(--accent); }
.hamburger span {
  display: block;
  width: 20px;
  height: 2px;
  margin: 0 auto;
  background: var(--foreground);
  border-radius: 2px;
  transition: transform 0.25s ease, opacity 0.2s ease;
}
.hamburger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.hamburger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.hamburger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.header-search {
  width: 260px;
  position: relative;
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
/* Fired briefly by script.js while it re-parents .header-search between the hero and this
   slot, so the move reads as a fade/slide instead of an instant jump. */
.header-search.search-box-transition { opacity: 0; transform: translateY(-6px); }

/* Docking slot inside the sticky header — empty (zero-size) until the hero scrolls out of
   view, at which point script.js moves the single, shared .header-search box in here. Owns
   the right-alignment margin itself so header-contact/lang-toggle stay pinned to the right
   edge whether or not the search box is currently docked here. */
.header-search-slot {
  margin-left: auto;
  flex-shrink: 0;
}

/* Docking slot inside the hero — holds the search box by default on page load. */
.hero-search-slot { width: 100%; }
.hero-search-slot .header-search {
  width: 100%;
  margin: 0;
}
.hero-search-slot .search-input {
  padding: 18px 26px 18px 54px;
  font-size: 1.05rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--background);
  box-shadow: var(--shadow-md);
}
.hero-search-slot .search-input:focus { box-shadow: var(--shadow-md), 0 0 0 3px var(--primary-ring); }
.hero-search-slot .search-svg-icon { left: 22px; width: 20px; height: 20px; }
.hero-search-slot .search-clear { right: 18px; }

.search-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  min-width: 300px;
  background: var(--popover);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: var(--shadow-lg);
  /* Above everything else on the page: the highest z-index anywhere else in this file is the
     sticky #header's 100. The dropdown does not sit in a stacking context of its own making —
     its nearest positioned ancestors (.header-search, .hero-compact > .container, .hero-compact)
     are all `position: relative; z-index: auto`, which does NOT create a stacking context — so
     this 500 is compared at the root level against the sections that follow the hero (#uses and
     friends are unpositioned, i.e. z-index auto), and wins. Do not add a z-index to .hero-compact
     or its .container: that would create a stacking context and trap this value inside it. */
  z-index: 500;
  /* Grows downward with its content and starts scrolling instead of running off the viewport
     once there are more than ~7 rows. `overflow-y: auto` replaces a blanket `overflow: hidden`,
     which was only doing one useful job — clipping the first/last row's square corners to the
     rounded border — and any non-`visible` overflow value keeps doing that. `overflow-x` is
     pinned to hidden explicitly because a lone `overflow-y: auto` would compute the untouched
     `visible` axis to `auto` and could add a stray horizontal scrollbar. */
  max-height: min(58vh, 420px);
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;   /* scrolling past the last row must not scroll the page */
}
.search-result {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 12px;
  cursor: pointer;
  border-bottom: 1px solid var(--border-light);
  transition: background-color 0.12s;
  text-align: left;
  width: 100%;
}
.search-result:last-child { border-bottom: none; }
.search-result:hover, .search-result:focus-visible { background: var(--accent); }
/* `display: block` on the inner elements: search results are rendered as <button> with <span>
   children (they used to be <div onclick>, which was not keyboard-reachable), and spans are
   inline by default — without this the swatch would collapse to zero size and the name/category
   lines would run together on one line. */
.sr-swatch { display: block; width: 34px; height: 34px; border-radius: var(--r-sm); border: 1px solid var(--border); flex-shrink: 0; }
.sr-info { display: block; flex: 1; min-width: 0; }
.sr-name { display: block; font-size: 0.82rem; font-weight: 700; color: var(--foreground); }
.sr-dims { display: block; font-size: 0.68rem; color: var(--muted-foreground); margin-top: 1px; }
.sr-price { font-size: 0.8rem; font-weight: 700; color: var(--foreground); white-space: nowrap; }
.search-no-results { padding: 16px 14px; font-size: 0.82rem; color: var(--muted-foreground); text-align: center; }
.search-dropdown-footer {
  padding: 9px 14px;
  width: 100%;
  background: var(--muted);
  border-top: 1px solid var(--border);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted-foreground);
  text-align: center;
  cursor: pointer;
  transition: background-color 0.12s, color 0.12s;
}
.search-dropdown-footer:hover { background: var(--border); color: var(--foreground); }
.header-search .search-input {
  padding: 8px 36px 8px 38px;
  font-size: 0.84rem;
  border-radius: var(--r-sm);
}
.header-search .search-svg-icon { left: 12px; }
.header-search .search-clear { right: 9px; width: 20px; height: 20px; font-size: 0.55rem; }

.header-contact {
  display: flex;
  flex-direction: column;
  /* `flex-start`, was `flex-end`. Right-aligning three lines of different length is what made this
     block look ragged once it held two numbers: each row ended flush with the page margin, so
     because "ხის მასალები" and "ძაღლის სახლი" are not the same width, the two numbers — and all
     three icons — each began at a different x. Starting the rows from the same edge instead lines
     the columns up: icon under icon, number under number, label under label. Paired with the
     `tabular-nums` on the numbers below, which is what makes the two of them measure exactly the
     same and so keeps the label column straight too.
     Only the desktop column layout is affected: the ≤900px rule further down re-declares
     `align-items: center` for the horizontal, centred mobile row. */
  align-items: flex-start;
  justify-content: center;
  gap: 4px;
  flex-shrink: 0;
  white-space: nowrap;
}
.contact-item {
  display: flex;
  align-items: center;
  gap: 6px;
  line-height: 1.2;
}
.contact-icon { color: var(--primary); flex-shrink: 0; }
.header-phone { font-weight: 700; color: var(--foreground); font-size: 0.9rem; }
.header-phone:hover { color: var(--primary); }
/* The number itself (the only child here that isn't the icon or the label). `tabular-nums` gives
   every digit the same advance width, so the two numbers — same shape, different digits — come out
   exactly the same length and the label column beside them stays straight. Without it the header
   is at the mercy of whichever digits the numbers happen to contain. Same treatment the size
   columns on the product cards already get (`.card-size-dims`). */
.header-phone > span:not(.phone-label) { font-variant-numeric: tabular-nums; }
/* Which line a number belongs to (ხის მასალები / ძაღლის სახლი) — the header and the footer both
   list two numbers now, and an unlabelled pair is just ambiguous. Quieter and smaller than the
   number itself so the number stays the thing you read first. The footer overrides the colour to
   its own palette (see `.footer-col .phone-label`); size is reduced rather than the contrast,
   which stays on the AA-checked `--footer-fg-soft` token down there. */
.phone-label { font-size: 0.7rem; font-weight: 500; color: var(--muted-foreground); }
.header-hours { font-weight: 500; color: var(--muted-foreground); font-size: 0.75rem; }

/* Segmented control (shadcn Tabs shape): one recessed track, the active item lifted out of it. */
.lang-toggle {
  display: flex;
  gap: 2px;
  flex-shrink: 0;
  padding: 3px;
  background: var(--muted);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
.lang-btn {
  padding: 3px 9px;
  border-radius: calc(var(--r-sm) - 3px);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted-foreground);
  transition: background-color 0.15s, color 0.15s, box-shadow 0.15s;
}
.lang-btn.active { background: var(--background); color: var(--foreground); box-shadow: var(--shadow-xs); }
.lang-btn:hover:not(.active) { color: var(--foreground); }

/* ===== HERO (compact e-commerce search hero) =====
 * ---------------------------------------------------------------------------------------
 * ROUND 2 — quieter headline block. Everything below the `.hero-search-*` rules is scoped to
 * the title/description/CTA stack; the search box and its docking behaviour are deliberately
 * untouched (same markup, same ids, same `.hero-search-slot` sizing), so script.js's hero⇄header
 * docking works exactly as before.
 *
 * What changed and why: the block read as a consumer landing page, not a timber merchant —
 * a 40px/800 headline over a 50px filled button is a lot of voice for two short lines that
 * are really just a positioning statement. The copy is unchanged; only its weight is. Type
 * went 40px/800 -> 27px/700 and the description 17px -> 15px, which restores an actual size
 * ratio between them (1.8x, was 2.35x but at a shouting scale); the CTA dropped from `btn-lg`
 * to the default `btn`; the decorative radial wash is gone, leaving one flat muted band with
 * a hairline bottom border. Net: hero 300px -> ~200px.
 *
 * ROUND 3 — compaction pass, spacing only. The strapline lost "მიტანა მთელ საქართველოში" and
 * now reads just "2000 წლიდან", so the block is four short elements; at Round 2's padding it
 * still ate ~263px of a desktop viewport. Nothing here touches type sizes, the search box, or
 * the CTA — those three are ~158px of fixed content and are the floor. All that changed is the
 * ~105px of padding/gap around them, cut to ~51px: hero ~263px -> ~209px (-20%). Anything more
 * would have to come out of the search box or the button, which is why it stops at 20% and not
 * 30%. Paired with `.hero-compact + .section` below, which pulls the next section's 64px top
 * padding up to 40px so the freed space doesn't just reappear as a gap under the hero.
 *
 * TO REVERT: restore the numbers marked "was ..." below (each carries its full history), drop
 * the `.hero-compact + .section` rule, and restore the mobile block in the @media at the
 * bottom of this file. Round 2's revert notes still apply on top of that: re-add the
 * `.hero-compact::before` wash and put `btn-lg` back on `.hero-main-cta` in index.html.
 * --------------------------------------------------------------------------------------- */
.hero-compact {
  position: relative;
  background: var(--muted);
  border-bottom: 1px solid var(--border);
  padding: 10px 0 14px;          /* was 26px 0 30px, was 28px 0 36px */
  /* was `overflow: hidden`. That clip is what buried the hero search autocomplete: #searchDropdown
     is absolutely positioned inside .header-search, which lives in this section, so every part of
     it below the hero's bottom edge was cut away — leaving only the couple of rows that happened
     to fit — and it appeared to sit *under* the "შეარჩიე კატეგორიის მიხედვით" section. No z-index
     can escape an ancestor's overflow clip; the clip itself had to go. It was left over from the
     Round 2 `.hero-compact::before` radial wash, which no longer exists, and nothing else in the
     hero overflows this box (the inner stack is a centred flex column, .hero-main is capped at
     620px), so making it explicit changes no geometry: padding, height and spacing are untouched. */
  overflow: visible;
}
.hero-compact > .container { position: relative; }
.hero-compact-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;                     /* was 18px, was 16px */
}
.hero-search-block {
  width: 100%;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.hero-main {
  width: 100%;
  max-width: 620px;              /* was 760px — a shorter measure suits the smaller type */
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;                      /* was 8px, was 16px — title and strapline are one unit */
  text-align: center;
  padding: 0 20px;               /* was 2px 20px 0, was 20px 20px 6px */
}
.hero-main-title {
  font-size: clamp(22px, 2.3vw, 27px);   /* was clamp(28px, 4vw, 40px) */
  font-weight: 700;                      /* was 800 */
  letter-spacing: -0.02em;               /* was -0.025em; less tracking suits the smaller size */
  color: var(--foreground);
  line-height: 1.2;
}
.hero-main-desc {
  font-size: 0.94rem;            /* was clamp(15px, 1.6vw, 17px) */
  color: var(--muted-foreground);
  line-height: 1.5;
}
.hero-main-cta { margin-top: 4px; }      /* was 12px, was 4px. Round 2 gave the button its own
                                            air; with the 6px flex gap on top that reads as
                                            10px, which is still a visible step down from the
                                            title/strapline pair. */

/* Requirement of the compaction pass: the space taken out of the hero must not come straight
   back as a gap underneath it. #uses is the only `.section` that ever follows `.hero-compact`
   (home page only — category.html/about.html have no hero, so this selector never matches
   there and every other `.section` keeps the standard 64px). */
.hero-compact + .section { padding-top: 40px; }   /* was 64px, from `.section` */

/* ===== SPECIES GRID ===== */
.species-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(155px, 1fr));
  gap: 16px;
}
.species-tile {
  border: 2px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
  background: var(--white);
  transition: all 0.2s;
  text-align: left;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
}
.species-tile:hover { border-color: var(--green-mid); box-shadow: var(--shadow-md); transform: translateY(-2px); }
.species-tile.active { border-color: var(--green-mid); border-width: 2.5px; box-shadow: var(--shadow-md); }

.tile-img { height: 100px; width: 100%; }
.tile-all    { background: linear-gradient(135deg, #7A4A28, #3B6B22); }
.tile-spruce      { background: linear-gradient(135deg, #C8B420, #887A10); }
.tile-pine        { background: linear-gradient(135deg, #D4A520, #8B6200); }
.tile-pine-spruce { background: linear-gradient(135deg, #C8B420, #8B6200); }
.tile-oak    { background: linear-gradient(135deg, #9C6A20, #5C3810); }
.tile-larch  { background: linear-gradient(135deg, #C04C2A, #7A2A10); }
.tile-birch  { background: linear-gradient(135deg, #D8D0B8, #8A8264); }
.tile-linden { background: linear-gradient(135deg, #A8B840, #6A7820); }
.tile-walnut { background: linear-gradient(135deg, #6B3A20, #3A1C0C); }

.tile-label { padding: 10px 14px; }
.tile-label strong { display: block; font-size: 0.9rem; font-weight: 700; color: var(--text); }
.tile-label span { font-size: 0.72rem; color: var(--text-muted); }

/* ===== USE GRID ===== */
.use-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 14px;
}
.use-tile {
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 22px 12px;
  background: var(--card);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  cursor: pointer;
  transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
  box-shadow: var(--shadow-xs);
}
.use-tile:hover { border-color: var(--primary); box-shadow: var(--shadow-md); transform: translateY(-2px); }
.use-tile.active { border-color: var(--primary); background: var(--primary-subtle); }
.use-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: var(--r-sm);
  background: var(--muted);
  font-size: 1.5rem;
  line-height: 1;
  color: var(--muted-foreground);
  transition: background-color 0.18s ease, color 0.18s ease;
}
.use-tile:hover .use-icon,
.use-tile.active .use-icon { background: var(--primary-subtle); color: var(--primary); }
.use-tile strong { font-size: 0.8rem; font-weight: 600; color: var(--foreground); line-height: 1.35; }

/* Holds the #uses row at the height it had when every tile still carried an icon. The row was
   sized by "ჭერისა და კედლის მასალები" — the only two-line label — so icon(46) + gap(10) +
   2 lines(34.6) + padding(44) = 136px, and every tile stretched to that. Now that this tile is
   a photo card with no icon, the tallest remaining tile is a one-line icon tile at ~118.7px,
   which would have shrunk all six. A floor, not a fixed height: content can still push a tile
   taller (it does at narrow widths, where labels wrap more), so nothing can clip. Scoped to
   #uses — category.html's sidebar tiles are a different shape and must not pick this up. */
#uses .use-tile { min-height: 136px; }

/* ===== Photo-backed tiles in the #uses grid =====
 * Opt-in per tile via `.use-tile-photo` + a `--use-tile-photo` url. Three tiles use it today
 * ("ფასადის მასალები", "ჭერისა და კედლის მასალები", "დახერხილი ფიცარი"); the rest keep the flat
 * --card surface. To add another: drop the tile's `.use-icon` from index.html, add
 * `use-tile-photo` to its class list, and give it `--use-tile-photo` + `--use-tile-scrim` lines
 * below. Measure the new photo before picking its scrim — see the note on those lines.
 *
 * Built like the wood-species cards further down: the dark scrim is an extra `background-image`
 * LAYER rather than a pseudo-element or an overlay <div>. That keeps the DOM, the padding box
 * and the `.use-tile:hover` transition untouched, and the background is clipped to the existing
 * `border-radius: var(--r)` for free. Layer order is TOP-first: the scrim is listed before the
 * photo, so it paints over it. `background-color` under both layers is a dark fallback that
 * keeps the white label readable if a photo ever 404s.
 *
 * The selector is deliberately `#uses`-scoped and id-weighted, for two reasons: (1) it can
 * only ever match homepage tiles, never category.html's sidebar `.use-tile` buttons; and
 * (2) an id (1,1,0) outranks `.use-tile.active` (0,2,0), whose `background` SHORTHAND would
 * otherwise reset background-image back to none. Homepage tiles are plain <a> links and
 * never receive `.active` today (see script.js "TILE CLICK WIRING"), but this stays correct
 * if that ever changes.
 *
 * These tiles carry no `.use-icon` (removed from the markup), so the label is their only child.
 * Two things follow, and they are the ONLY declarations here besides the background:
 *   - `color: oklch(1 0 0)` on the label — `--foreground` is near-black and unreadable over
 *     a scrimmed photo. Font size/weight/family are untouched.
 *   - `justify-content: center` — the base rule is `flex-start`, written for an icon-then-label
 *     stack; with the icon gone that pins the title to the top edge and leaves the rest of the
 *     photo empty. Centring only redistributes the free space the removed icon left behind:
 *     `padding` (22px 12px), `gap`, `border-radius`, the card's width/height and the responsive
 *     overrides are all still exactly as the other tiles' have them.
 * Card height itself needs no help — `#uses .use-tile` carries a min-height (see above), so
 * these tiles stay the size they were when every tile still had an icon.
 *
 * The scrim is a flat fill — `linear-gradient(<color>, <color>)` with two identical stops — not
 * a ramp, because a centred label wants its darkest area in the middle, which is exactly where a
 * top-to-bottom ramp is average. Each tile sets its own alpha; see those lines below.
 *
 * The two unsplash photos are stored DOWNSCALED to 1000px wide; the multi-megapixel originals
 * live in `../product photos/`. Letting the browser scale a 5000–6000px file into a ~182px box
 * moirés fine detail (plank lines, panel grooves) badly, so they were resampled offline in
 * halving steps instead — which also took 5.2MB -> 187KB and 2.6MB -> 120KB. Keep that up for
 * any photo added here: export at ~1000px, don't drop in the raw download. */
#uses .use-tile-photo {
  background-color: oklch(0.153 0.006 107.1);
  background-image:
    linear-gradient(var(--use-tile-scrim), var(--use-tile-scrim)),
    var(--use-tile-photo);
  background-size: cover;
  background-position: var(--use-tile-photo-pos, center);
  background-repeat: no-repeat;
  justify-content: center;
}
#uses .use-tile-photo strong { color: oklch(1 0 0); }

/* Per-photo scrim alpha. These are not taste values — each is the lowest alpha that still puts
   the white label at >= 5:1 contrast against the BRIGHTEST 8x8 patch of that photo behind the
   text (measured on the rendered card; WCAG AA for this text size is 4.5:1). So every photo is
   left as bright as it can be and no brighter. Re-measure if a photo is swapped: the facade shot
   needs nearly twice the ceiling one because a pale grey diagonal runs right under its label. */
#uses .use-tile-facade {                        /* 5.18:1 */
  --use-tile-photo: url('images/uses/khara-woods-B4HszZLE5-g-unsplash.jpg');
  --use-tile-scrim: oklch(0.153 0.006 107.1 / 0.56);
}
#uses .use-tile-ceiling {                       /* 5.04:1 — darkest photo, needs the least */
  --use-tile-photo: url('images/uses/nikola-a3wBIi1I1kY-unsplash.jpg');
  --use-tile-scrim: oklch(0.153 0.006 107.1 / 0.31);
}
/* This one is already web-sized at 688x344 / 16KB, so unlike the two above it is used as-is —
   `cover` scales it DOWN (0.4x here, 0.79x on a 2x display), never up. Its 2:1 crop is wider
   than the card, so the sides are trimmed. */
#uses .use-tile-sawn {                          /* 5.10:1 */
  --use-tile-photo: url('images/uses/f0cc2a7a41f06aa2b62b6431231a57ae.webp');
  --use-tile-scrim: oklch(0.153 0.006 107.1 / 0.43);
}
/* The only PORTRAIT source here (784x1358, stored at 600x1039) and the only one that overrides
   `background-position`. The card is landscape, so `cover` matches the card's WIDTH and 179px of
   the 315px-tall rendered image falls outside the box — 57% of the picture is cropped, and which
   57% is entirely up to the position. Centred, the visible band was the stairs and the white
   wall behind them: pale, off-message for a flooring category, and the brightest part of the
   frame sat right under the label. `72%` keeps the boards as the subject but leaves a thin strip
   of the wall along the top edge, which gives the shot some depth instead of reading as a flat
   swatch. The wall only starts entering the frame below ~75% — 78% and 100% look identical —
   and by ~60% the stairs are back and the card turns pale again, so the usable window is narrow.
   Mean luminance 0.184 centred -> 0.149 here, which also brings this tile nearer the other three
   (0.076–0.099) instead of reading as the one pale card in the row. */
#uses .use-tile-floor {                         /* 5.00:1 */
  --use-tile-photo: url('images/uses/Gemini_Generated_Image_4410xa4410xa4410.jpg');
  --use-tile-photo-pos: center 72%;
  --use-tile-scrim: oklch(0.153 0.006 107.1 / 0.43);
}
/* The only PRE-CROPPED source. The original (1200x1600, kept in `../product photos/` as .jfif)
   is a yard shot: the doghouse sits on a car's roof rack, with a second car and lumber stacks
   behind it. No `background-position` can hide that — every framing that keeps the house whole
   also keeps some of the car — so the crop was baked into the file instead: x170 y520 740x554 of
   the original, already at the card's 1.34 aspect so `cover` has nothing left to trim. The
   trade-off is the roof apex: the gable line runs diagonally, so any rectangle holding the full
   roof also holds sky and lumber in the top corners. Cutting just above the bone plaque keeps
   the house's shape readable and drops both cars entirely. Re-crop from the original rather than
   nudging position here — this file has no spare margin. */
#uses .use-tile-doghouse {                      /* 5.02:1 */
  --use-tile-photo: url('images/uses/acbb42f9-fb7e-47ea-bf59-d5625885258a.jpg');
  --use-tile-scrim: oklch(0.153 0.006 107.1 / 0.50);
}

/* ===== POPULAR PRODUCTS ===== */
.popular-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
}
/* Vertical card layout (image on top) — the base .product-card row layout
 * (fixed 110px image + flexible body) is too cramped at 5-per-row widths. */
.popular-grid .product-card { flex-direction: column; }
.popular-grid .card-img { width: 100%; height: 150px; min-height: 150px; }
.popular-grid .card-body { padding: 16px; }
.popular-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 8px; }
.popular-tag {
  font-size: 0.66rem;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--primary-subtle);
  color: var(--primary-hover);
}
.popular-tag.alt { background: var(--muted); color: var(--muted-foreground); border: 1px solid var(--border); }
/* Unused since Popular Products stopped showing view counts (see popularCardHTML() in script.js).
 * Kept in place so restoring that line needs no CSS work. */
.popular-views {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 0.74rem;
  color: var(--muted-foreground);
  margin-bottom: 10px;
}
.popular-views svg { flex-shrink: 0; color: var(--muted-foreground); }
.popular-view-all { text-align: center; margin-top: 32px; }

@media (max-width: 1100px) {
  .popular-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 768px) {
  .popular-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .popular-grid { grid-template-columns: 1fr; }
}

/* ===== PRODUCTS ===== */
.products-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 24px;
}
.products-header .section-title { margin-bottom: 0; }
.products-count { font-size: 0.85rem; color: var(--text-muted); }

/* ===== PRODUCT SEARCH ===== */
.products-search { margin-bottom: 22px; }
.search-wrap {
  position: relative;
  display: flex;
  align-items: center;
}
.search-svg-icon {
  position: absolute;
  left: 14px;
  color: var(--muted-foreground);
  pointer-events: none;
  flex-shrink: 0;
}
.search-input {
  width: 100%;
  padding: 10px 42px 10px 40px;
  border: 1px solid var(--input);
  border-radius: var(--r-sm);
  background: var(--background);
  font-size: 0.88rem;
  font-family: var(--font);
  color: var(--foreground);
  transition: border-color 0.15s, box-shadow 0.15s;
}
.search-input:focus,
.search-input:focus-visible {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-ring);
}
.search-input::placeholder { color: var(--muted-foreground); opacity: 0.75; }
.search-clear {
  position: absolute;
  right: 10px;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--muted);
  color: var(--muted-foreground);
  font-size: 0.6rem;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.12s, color 0.12s;
}
.search-clear:hover { background: var(--border); color: var(--foreground); }

.products-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
}
.products-empty {
  text-align: center;
  padding: 56px 24px;
  color: var(--muted-foreground);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r);
  background: var(--muted);
}
.products-empty p { margin-bottom: 16px; }

.products-group { margin-bottom: 48px; }
.products-group:last-child { margin-bottom: 0; }
.products-group-title {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--foreground);
  margin-bottom: 18px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.products-subgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 20px;
}

/* ===== FEATURED COLLECTIONS ===== */
.collections-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
.collection-card {
  border-radius: var(--r);
  height: 152px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  padding: 28px 30px;
  cursor: pointer;
  overflow: hidden;
  position: relative;
  transition: transform 0.2s, box-shadow 0.2s;
}
.collection-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.collection-card:hover .coll-arrow { transform: translateX(5px); opacity: 1; }
.coll-conifer {
  background:
    linear-gradient(135deg, rgba(18,10,4,0.65) 0%, rgba(18,10,4,0.18) 65%, transparent 100%),
    linear-gradient(145deg, #284F14 0%, #4A7A28 45%, #7AB050 100%);
}
.coll-deciduous {
  background:
    linear-gradient(135deg, rgba(18,10,4,0.65) 0%, rgba(18,10,4,0.18) 65%, transparent 100%),
    linear-gradient(145deg, #6B3A18 0%, #9C6420 45%, #C48840 100%);
}
.coll-body { display: flex; flex-direction: column; gap: 3px; }
.coll-en {
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.42);
}
.coll-ka {
  font-size: 1.12rem;
  font-weight: 700;
  color: var(--white);
  line-height: 1.2;
}
.coll-list { font-size: 0.74rem; color: rgba(255,255,255,0.58); margin-top: 2px; }
.coll-arrow {
  font-size: 1.3rem;
  color: rgba(255,255,255,0.42);
  opacity: 0.7;
  transition: transform 0.2s, opacity 0.2s;
  align-self: flex-end;
  padding-bottom: 2px;
  flex-shrink: 0;
}

/* ===== WOOD SPECIES — compact editorial split card (Concept D) =====
   Merges the old flat species-tile grid + coniferous/deciduous collection cards (still kept,
   untouched, inside an HTML comment in index.html for a one-step revert) into one component.
   Sized ~35% shorter than the comparison-preview version of this concept: tighter padding,
   smaller type/pills, no separate CTA row (the whole card + an arrow glyph is the click
   target instead). */
.species-split-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}
.species-split-header .section-title { margin-bottom: 0; }
.species-split-all {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--foreground);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 6px 15px;
  background: var(--card);
  box-shadow: var(--shadow-xs);
  transition: background-color 0.16s, border-color 0.16s, color 0.16s;
  flex-shrink: 0;
}
.species-split-all:hover { background: var(--accent); border-color: var(--border-strong); }
.species-split-all.active { background: var(--primary); border-color: var(--primary); color: var(--primary-foreground); }
.species-split-count {
  font-size: 0.7rem;
  font-weight: 700;
  background: var(--muted);
  color: var(--muted-foreground);
  border-radius: 999px;
  padding: 1px 8px;
}
.species-split-all.active .species-split-count { background: oklch(1 0 0 / 0.22); color: var(--primary-foreground); }

/* ===== Species split cards =====
 * Photographic cards: each half is backed by its own photo (`images/species/`) with a flat
 * dark scrim on top, so the labels read as white-on-image. The scrim is layered as an extra
 * `background-image` LAYER rather than a pseudo-element, because `::before` is already taken
 * by the accent rail below — a `linear-gradient(<color>, <color>)` with two identical stops
 * is a flat fill, and `background-size/position/repeat` (set once on `.species-split-half`)
 * apply to every layer, so the photo gets exactly the requested `cover` / `center` /
 * `no-repeat` treatment while the scrim just fills the box.
 *
 * Layer order in `background-image` is TOP-first: the scrim is listed before the photo, so
 * it paints over it. `background-color` underneath is a dark fallback, which keeps the white
 * text readable even if a photo 404s.
 *
 * URLs are percent-encoded because the two filenames are Georgian and must not be renamed;
 * encoding them removes any dependence on how this stylesheet's character encoding is
 * detected (there is no @charset here or BOM). Readable names are in the comments below.
 * The paths are relative to THIS FILE, not to the document, so the single declaration is
 * correct from every page depth — no `ROOT` prefix needed as in the JS-generated markup.
 *
 * Card geometry (min-height, padding, gap, radius), typography (sizes/weights/spacing), the
 * accent rail, hover/active behavior, click targets and the responsive rules are all
 * unchanged from the flat-surface version — only paint and text/border colors moved, which
 * they had to: the surface is now dark. Previous flat version: see git tag
 * `checkpoint-before-species-bg-images`. */
.species-split-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.species-split-half {
  border-radius: var(--r);
  border: 1px solid oklch(1 0 0 / 0.14);
  /* Fallback under the photo — dark, so white text stays legible if the image can't load. */
  background-color: var(--accent-foreground);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  /* 128px -> 144px (+12.5%), to let more of the photo show. `min-height` is the ONLY
     dimension touched: it is what actually sets the rendered height here (the content —
     ~56px of label + pills plus 44px of vertical padding — never reaches it), so padding,
     typography and the grid stay exactly as they were. And because the card is
     `align-items: flex-end`, the extra 16px opens up ABOVE the text: the label keeps its
     22px distance from the bottom edge and nothing inside the card shifts. Width and the
     16px column gap come from `.species-split-grid` and are untouched; the ≤600px override
     further down keeps its own 150px, so mobile renders identically to before. */
  min-height: 144px;
  padding: 22px 24px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  cursor: pointer;
  overflow: hidden;
  position: relative;
  box-shadow: var(--shadow-xs);
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
/* images/species/წიწვოვანი.PNG */
.species-split-conifer {
  background-image:
    linear-gradient(var(--species-card-overlay), var(--species-card-overlay)),
    url('images/species/%E1%83%AC%E1%83%98%E1%83%AC%E1%83%95%E1%83%9D%E1%83%95%E1%83%90%E1%83%9C%E1%83%98.PNG');
}
/* images/species/ფოთლოვანი.jpg */
.species-split-deciduous {
  background-image:
    linear-gradient(var(--species-card-overlay), var(--species-card-overlay)),
    url('images/species/%E1%83%A4%E1%83%9D%E1%83%97%E1%83%9A%E1%83%9D%E1%83%95%E1%83%90%E1%83%9C%E1%83%98.jpg');
}
/* Accent rail — sits above the photo + scrim (it is a positioned pseudo-element, they are
   backgrounds of the element itself), and clear of the 24px content padding. */
.species-split-half::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 4px;
  background: var(--primary);
  opacity: 0.9;
}
.species-split-deciduous::before { background: var(--chart-2); }
.species-split-half:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); border-color: oklch(1 0 0 / 0.32); }
.species-split-half:hover .species-split-arrow { transform: translateX(4px); opacity: 1; }
.species-split-half.active { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-ring), var(--shadow-md); }
.species-split-body { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.species-split-body strong { font-size: 1.05rem; font-weight: 700; color: oklch(1 0 0); line-height: 1.25; letter-spacing: -0.01em; }
.species-split-pills { display: flex; flex-wrap: wrap; gap: 6px; }
/* NOTE: `.species-split-pill` is reused by category.html's sidebar, where it must stay a
   plain dark-on-light list item. That page's `.category-sidebar .species-split-pill` rules
   are both more specific AND later in this file, so they keep overriding the on-photo colors
   below — same arrangement as before this change, just different values being overridden. */
.species-split-pill {
  font-size: 0.72rem;
  font-weight: 600;
  color: oklch(1 0 0 / 0.92);
  background: oklch(1 0 0 / 0.15);
  border: 1px solid oklch(1 0 0 / 0.3);
  border-radius: 999px;
  padding: 4px 11px;
  transition: background-color 0.15s, color 0.15s, border-color 0.15s;
}
.species-split-pill:hover { background: oklch(1 0 0 / 0.28); color: oklch(1 0 0); border-color: oklch(1 0 0 / 0.45); }
.species-split-pill.active { background: var(--primary); color: var(--primary-foreground); border-color: var(--primary); }
.species-split-arrow {
  font-size: 1.15rem;
  color: oklch(1 0 0 / 0.75);
  opacity: 0.7;
  transition: transform 0.2s, opacity 0.2s;
  align-self: flex-end;
  flex-shrink: 0;
}

/* Product Card — horizontal layout */
.product-card {
  display: flex;
  flex-direction: row;
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--shadow-xs);
  transition: box-shadow 0.18s ease, transform 0.18s ease, border-color 0.18s ease;
}
.product-card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--border-strong);
  transform: translateY(-2px);
}
.card-img {
  width: 110px;
  flex-shrink: 0;
  position: relative;
  min-height: 110px;
  background-color: var(--muted);
}
.card-stock-badge {
  position: absolute;
  top: 8px;
  left: 8px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 0.6rem;
  font-weight: 700;
  line-height: 1.5;
  color: #fff;
  box-shadow: var(--shadow-xs);
}
.badge-in  { background: var(--in-stock); }
.badge-low { background: var(--low-stock); }
/* `stock: 'special-order'` products (ბლოკჰაუსი) used to fall through to `.badge-low`, so
   "შეკვეთით" was painted in the amber "low stock" color and read as a stock warning. */
.badge-order { background: var(--special-order); }

.card-body {
  flex: 1;
  padding: 13px 15px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-width: 0;
}
.card-header-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 6px;
  margin-bottom: 3px;
}
.card-name { font-size: 0.92rem; font-weight: 700; color: var(--foreground); line-height: 1.3; letter-spacing: -0.005em; }
.card-dims { font-size: 0.72rem; color: var(--muted-foreground); font-variant-numeric: tabular-nums; margin-bottom: 2px; }
.card-cat  { font-size: 0.76rem; color: var(--muted-foreground); margin-bottom: 2px; }
.card-use-badge {
  display: inline-block;
  align-self: flex-start;
  font-size: 0.63rem;
  font-weight: 600;
  color: var(--muted-foreground);
  background: var(--muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 1px 8px;
  margin-bottom: 6px;
}

/* Multi-size cards - easy to revert: purely additive, only rendered when a product has
 * `variants`/`sizeOptions` (see cardHTML() in script.js). To restore the previous card layout for
 * these products, remove the `.card-sizes*` block below from cardHTML()'s output — nothing here
 * needs to change, these rules simply won't be used anymore. */
.card-sizes { margin-bottom: 2px; }
.card-sizes-label { font-size: 0.72rem; font-weight: 700; color: var(--text-muted); margin-bottom: 3px; }
.card-sizes-list { list-style: none; display: flex; flex-direction: column; gap: 2px; }
.card-sizes-list li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: 0.7rem;
  line-height: 1.35;
}
.card-size-dims { color: var(--muted-foreground); font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.card-size-price { color: var(--foreground); font-weight: 700; white-space: nowrap; flex-shrink: 0; }
/* Card price unit - easy to revert: companion to the `unit` param added to cardSizesHTML()
 * (script.js) — shows the measurement unit (მ²/მ³) next to each size row's price, muted/smaller
 * than the price itself, same relationship .card-price-unit has to .card-price. To revert, delete
 * this rule (harmless on its own; pair with the script.js revert to fully remove the feature). */
.card-size-unit { font-size: 0.62rem; font-weight: 600; color: var(--text-muted); }
.card-sizes-more { font-size: 0.68rem; color: var(--text-muted); font-style: italic; margin-top: 1px; }
.card-footer-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}
.card-price {
  font-size: 1.1rem;
  font-weight: 800;
  color: var(--foreground);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.card-price-unit { font-size: 0.67rem; font-weight: 600; color: var(--muted-foreground); vertical-align: middle; }
.q-badge {
  background: var(--muted);
  border: 1px solid var(--border);
  color: var(--foreground);
  border-radius: 999px;
  padding: 2px 8px;
  font-size: 0.64rem;
  font-weight: 700;
  white-space: nowrap;
  flex-shrink: 0;
}
.card-actions { display: flex; gap: 6px; align-items: center; }
.card-actions .btn { padding: 7px 12px; font-size: 0.76rem; }
/* `.card-actions .card-actions-call { padding: 7px 10px; }` was here, and went with the small
   phone button beside "დეტალურად" that was its only user (see the notes on cardHTML() in script.js
   and relatedCardHTML() in build-products.js). */

/* Product card layout (main catalog grid) - easy to revert: purely additive overrides, scoped to
 * `.products-grid .product-card` / `.products-grid .card-img`, so the base horizontal layout above
 * (110px image + flexible body, `flex-direction: row` — still used wherever `.product-card` markup
 * appears outside a `.products-grid` container, if any) is completely untouched. `.popular-grid` has
 * its own separate rule set (`.popular-grid .card-img { width: 100%; height: 150px; min-height:
 * 150px; }`, unchanged) and is unaffected either way.
 * History (5 rounds of tuning on this block; each round only changed values here, never the HTML/JS):
 *   1. flex-direction:column + `width:100%; aspect-ratio:4/3` (image on top, full-bleed) — too large.
 *   2. `width:auto; margin:14px 14px 0; aspect-ratio:16/10` (image on top, inset/framed) — still large.
 *   3. `width:auto; margin:12px 12px 0; height:125px` (image on top, full-width short band) — looked
 *      like a banner, not a thumbnail.
 *   4. image on top, fixed 150×150px square, centered via `margin:auto` — square looked right in
 *      isolation, but the overall vertical (image-over-text) card shape was no longer wanted.
 *   5. (current) back to a HORIZONTAL layout (`flex-direction: row`, image LEFT / info RIGHT — same
 *      orientation as the untouched base rule above, and as the ORIGINAL pre-redesign card), but with
 *      round 4's 150×150px square + `contain` image instead of the original 110px + `cover` crop, and
 *      `align-items: center` so the info column is vertically centered next to the image regardless
 *      of which one (image vs. text content) ends up taller for a given product.
 * `background-size: contain !important` + `background-color: var(--wood-pale) !important` override
 * just those two components of the inline `background: url(...) center/cover no-repeat` set in
 * cardHTML() (untouched) — `!important` is required because an inline style otherwise always wins
 * over an external stylesheet, and this is a CSS-only change per the request. `contain` shows the
 * ENTIRE photo without cropping, scaled down to fit inside the square; the inline shorthand's
 * `center` position (untouched) centers it both horizontally AND vertically inside that square; any
 * leftover letterboxed space is filled with the neutral `--wood-pale` tone instead of a rendering
 * gap. CSS gradient placeholder photos (products with no real `images[]` yet) are unaffected either
 * way — generated gradients have no intrinsic size/ratio, so per spec `background-size: contain`
 * renders them at 100%×100% of the box regardless, same as before.
 * CSS Grid's default `align-items: stretch` on `.products-grid` still equalizes `.product-card`
 * height within each row (unchanged since round 1); the `align-items: center` added below is a
 * separate, inner flex alignment (image vs. info column within that already-equal card height).
 * A dedicated mobile override (see `@media (max-width: 600px)` → "Products" further down, alongside
 * the existing `.products-grid { grid-template-columns: 1fr; }` rule) switches back to a stacked
 * column layout (image above info) on narrow screens, matching the requested responsive behavior.
 * NOTE: the "related products" grid on every product-detail page (build-products.js,
 * `relatedCardHTML()`) reuses this exact same `.products-grid`/`.product-card` markup, so it picks
 * up the same treatment automatically for visual consistency across the site.
 * To revert to round 4 (image on top, centered square):
 *   .products-grid .product-card { flex-direction: column; }
 *   .products-grid .card-img { width: 150px; height: 150px; margin: 14px auto 0; border-radius:
 *   var(--r-sm); background-color: var(--wood-pale) !important; background-size: contain !important; }
 *   (and remove the mobile override mentioned above, or leave it — harmless once already column)
 * To revert to round 3 (full-width short band, ~125px tall):
 *   .products-grid .card-img { width: auto; margin: 12px 12px 0; height: 125px; border-radius:
 *   var(--r-sm); background-color: var(--wood-pale) !important; background-size: contain !important; }
 * To revert to round 2 (inset/framed, larger box):
 *   .products-grid .card-img { width: auto; margin: 14px 14px 0; aspect-ratio: 16 / 10; height: auto;
 *   min-height: 0; border-radius: var(--r-sm); background-color: var(--wood-pale) !important;
 *   background-size: contain !important; }
 * To revert to round 1 (full-bleed, largest):
 *   .products-grid .product-card { flex-direction: column; }
 *   .products-grid .card-img { width: 100%; aspect-ratio: 4 / 3; height: auto; min-height: 0; }
 * To revert all the way to the ORIGINAL horizontal 110px-thumbnail layout, delete this whole block
 * (including its mobile-override companion further down) — `.card-img { width: 110px; flex-shrink: 0;
 * position: relative; min-height: 110px; }` and `.product-card { flex-direction: row; }` (both still
 * defined, untouched, above) take over again exactly as they were.
 * Either way, nothing outside this CSS file needs to change. */
.products-grid .product-card { flex-direction: row; align-items: flex-start; }
.products-grid .card-img {
  width: 150px;
  height: 150px;
  flex-shrink: 0;
  margin: 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background-color: var(--muted) !important;
  background-size: contain !important;
}
.products-grid .card-body { padding: 14px 18px; }
/* Button alignment fix - the "დეტალურად" button stopped at a different height in every card, so a
 * row of cards had its buttons scattered. CSS Grid stretches each `.product-card` in a row to the
 * same height, but `align-items: flex-start` on the card (above — it is there on purpose, see the
 * note below) leaves `.card-body` only as tall as its own content, so the footer row, and the
 * button inside it, simply ended wherever that content ended. Measured on the homepage grid before
 * this fix: within a single row one card's button sat 15px above the card's bottom edge while its
 * partner's sat 51px, 71px, even 88px above it.
 * Stretching just the BODY to the card's full height, and letting the footer's auto top margin eat
 * the slack, pins the button to the bottom of every card while the text stays anchored to the top:
 * an auto margin consumes free space before `justify-content` is applied, so the `space-between`
 * already on `.card-body` quietly becomes a no-op instead of spreading the title/sizes apart.
 * `padding-top` replaces the footer's previous `margin-top: 10px`, keeping the same minimum gap
 * above it. Verified after: every row has both buttons 15px above the card bottom AND both
 * category badges 15px below the card top. The related-products grid on product-detail pages
 * reuses this markup, so it is fixed too. To revert, delete these two rules. */
.products-grid .card-body { align-self: stretch; }
.products-grid .card-footer-row { margin-top: auto; padding-top: 10px; }
/* Card alignment fix - easy to revert: `align-items: center` (above, for 6 rounds) vertically
 * centered the image+info column as two independent blocks within the row's shared height (CSS
 * Grid's `align-items: stretch` on `.products-grid` equalizes every card's height with its row
 * partner). That's invisible for most product pairings, where both cards' body content is a
 * similar height — but for a product with drastically shorter content than its row partner (e.g.
 * a `priceDisplay` flat-price product with no dims/size list, paired with a multi-size product
 * whose size list + note fills much more vertical space), centering made its title/category/price
 * start noticeably lower than the neighboring card's — reported for "ლარტყა" (id 18). Changed to
 * `flex-start` so both the image and the info column anchor to the top of the card, exactly like
 * every other card, regardless of how much shorter one card's content is than its row partner's.
 * Verified: before this change, "ლარტყა"'s title sat 65.7px from the card top vs. its sibling's
 * 37.9px (both cards sharing the same 197.7px stretched row height) — a ~28px gap. To revert,
 * change `align-items: flex-start` back to `align-items: center` on the `.product-card` rule above
 * — nothing else needs to change. */

/* ===== QUOTE FORM ===== */
.quote-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  align-items: start;
}
.quote-desc { color: rgba(255,255,255,0.78); margin-bottom: 28px; line-height: 1.7; font-size: 1.02rem; }
.quote-perks { margin-bottom: 32px; }
.perk { color: rgba(255,255,255,0.88); padding: 5px 0; font-size: 0.95rem; }
.quote-direct { }
.quote-direct p { color: rgba(255,255,255,0.6); font-size: 0.85rem; margin-bottom: 10px; }
.quote-direct-btns { display: flex; flex-wrap: wrap; gap: 10px; }

.quote-form {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 32px;
  box-shadow: var(--shadow-lg);
}
.form-group { margin-bottom: 18px; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
label { display: block; font-size: 0.83rem; font-weight: 600; color: var(--foreground); margin-bottom: 5px; }
.label-opt { font-weight: 400; color: var(--muted-foreground); }
input, select, textarea {
  width: 100%;
  padding: 10px 13px;
  border: 1px solid var(--input);
  border-radius: var(--r-sm);
  font-size: 0.95rem;
  color: var(--foreground);
  background: var(--background);
  transition: border-color 0.15s, box-shadow 0.15s;
  outline: none;
  appearance: none;
  -webkit-appearance: none;
}
input:focus, select:focus, textarea:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-ring);
}
input.error, select.error { border-color: var(--destructive); }
select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23777' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; padding-right: 36px; }
textarea { resize: vertical; min-height: 80px; }
.form-privacy { font-size: 0.73rem; color: var(--muted-foreground); text-align: center; margin-top: 10px; }

/* ===== B2B SECTION ===== */
.b2b-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 40px 48px;
  display: flex;
  gap: 48px;
  align-items: center;
  box-shadow: var(--shadow-sm);
  position: relative;
  overflow: hidden;
}
.b2b-card::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 4px;
  background: var(--primary);
}
.b2b-badge {
  display: inline-block;
  background: var(--primary-subtle);
  color: var(--primary-hover);
  padding: 3px 12px;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  margin-bottom: 12px;
}
.b2b-content h2 { font-size: 1.45rem; font-weight: 700; letter-spacing: -0.015em; color: var(--foreground); margin-bottom: 8px; }
.b2b-content p { color: var(--muted-foreground); margin-bottom: 16px; }
.b2b-list li { padding: 5px 0; color: var(--foreground); font-size: 0.93rem; }
.b2b-cta-block { flex-shrink: 0; display: flex; flex-direction: column; gap: 12px; min-width: 230px; }

/* ===== DELIVERY ===== */
.delivery-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 18px;
  margin-bottom: 20px;
}
.delivery-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 24px 20px;
  text-align: center;
  box-shadow: var(--shadow-xs);
}
.delivery-card.delivery-featured { border-color: var(--primary); }
.delivery-icon { font-size: 1.8rem; margin-bottom: 8px; }
.delivery-card h3 { font-size: 1rem; font-weight: 700; margin-bottom: 8px; color: var(--foreground); }
.delivery-price { font-size: 1.35rem; font-weight: 800; color: var(--foreground); margin-bottom: 8px; }
.delivery-price.green { color: var(--primary); }
.delivery-card p { font-size: 0.82rem; color: var(--muted-foreground); margin-bottom: 4px; }
.delivery-note-sm { font-size: 0.72rem; color: var(--muted-foreground); }
.delivery-disclaimer { font-size: 0.82rem; color: var(--muted-foreground); text-align: center; }

/* ===== DELIVERY SIMPLE ===== */
.delivery-simple {
  text-align: center;
  padding: 16px 0 8px;
}
.ds-heading {
  font-size: clamp(1.2rem, 2.5vw, 1.6rem);
  font-weight: 700;
  color: var(--foreground);
  margin-bottom: 8px;
}
.ds-sub {
  font-size: 0.95rem;
  color: var(--muted-foreground);
  margin-bottom: 28px;
}

/* ===== FOOTER =====
 * ---------------------------------------------------------------------------------------
 * THEME: "Charred Oak" (Option A). Every colour in this whole block comes from the seven
 * `--footer-*` custom properties declared on `#footer` below — no rule here hard-codes a
 * colour. Switching the footer's entire visual theme is therefore swapping those seven
 * lines and nothing else; two alternates (B "Kiln Paper", C "Deep Forest") are kept
 * ready-to-paste in the comment block further down.
 *
 * Why it replaced the old treatment, in one line each:
 *   - The old ground was `--foreground` (#0C0C09) — chroma 0.006, i.e. flat near-black. On a
 *     site selling facade cladding, the largest surface on the page had no material
 *     association at all. Charred cedar (shou sugi ban) is both a real timber product and a
 *     premium architectural one, so the ground is now a warm brown-black.
 *   - The old hierarchy was built from `opacity` (0.5/0.65/0.75/0.45). Opacity over black can
 *     only ever produce neutral grey, which is why the old hover had NO colour — it was an
 *     opacity bump to 1. Every tier is now an explicit `color`, which is what lets the brand
 *     green land on `:hover`.
 *   - `--footer-hover` is `--chart-2`'s value. That token was already in the file but its only
 *     call site (`.footer-logo .logo-icon`) referenced an element deleted back in 6e2b735,
 *     so it rendered nowhere. The dead rule is gone and the colour finally appears.
 *   - The old `.footer-bottom-inner p` sat at 4.4:1, under the 4.5:1 WCAG AA floor for 12.5px
 *     text. Every tier below now passes AA; see the ratios noted per line.
 *
 * LIGHTNESS: the ground was tuned across four steps and settled on the third. If it ever needs
 * to move again, `--footer-bg`, `--footer-dim` and `--footer-rule` must move TOGETHER — the dim
 * tier is the binding constraint and drops under AA within one step if left behind:
 *     #1A1613 / #8A8177 / #2E2822   (darkest — original charred)
 *     #241E19 / #948B80 / #382F27
 *     #2C2520 / #9C9287 / #423830   ← active
 *     #352D26 / #A69C90 / #4C4138   (ceiling — past this the secondary tier fails AA and the
 *                                    footer reads neither dark nor light, just muddy)
 *
 * TO REVERT WHOLESALE: `git checkout footer-restyle-checkpoint -- style.css`.
 * --------------------------------------------------------------------------------------- */
#footer {
  /* -- Option A · "Charred Oak" — ACTIVE -- */
  --footer-bg:      #2C2520;   /* warm brown-black; was var(--foreground) #0C0C09 */
  --footer-fg:      #F5F1EB;   /* paper cream   — 13.4:1 AAA */
  --footer-fg-soft: #A8A096;   /* warm taupe    —  5.8:1 AA  (tagline, links, contact lines) */
  --footer-dim:     #9C9287;   /* dim taupe     —  4.9:1 AA  (column heads, ©, .ge suffix) */
  --footer-hover:   #00C951;   /* emerald       —  6.8:1 AAA (= --chart-2) */
  --footer-rule:    #423830;   /* divider */
  --footer-pill:    #221C18;   /* badge chip — deliberately DARKER than the ground. A lighter
                                  pill would put --footer-fg-soft at 4.4:1 and fail AA; inset
                                  reads as debossed here anyway. Text on it: 6.5:1 AA. */

  background: var(--footer-bg);
  color: var(--footer-fg);
}
.footer-inner {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1.5fr;
  gap: 40px;
  padding: 48px 20px;
}
/* `color` must be reset here: `.footer-logo` also carries the `.logo` class, whose base rule
   sets the dark `--foreground` — on the dark footer that renders the wordmark invisible. */
.footer-logo { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; color: var(--footer-fg); }
.footer-logo .logo-text { font-size: 1.1rem; font-weight: 800; color: inherit; }
.footer-logo .logo-ge { color: var(--footer-dim); }
.footer-tagline { font-size: 0.82rem; color: var(--footer-fg-soft); line-height: 1.5; }

.footer-col h4 {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--footer-dim);
  margin-bottom: 14px;
}
.footer-col ul li { margin-bottom: 7px; }
/* `transition` is on `color`, not `opacity`: the hover is now a hue change (taupe -> emerald),
   which is the only place the brand colour appears in the footer at all. */
.footer-col ul li a, .footer-col a { font-size: 0.88rem; color: var(--footer-fg-soft); transition: color 0.15s ease; }
.footer-col ul li a:hover, .footer-col a:hover,
.footer-col ul li a:focus-visible, .footer-col a:focus-visible { color: var(--footer-hover); }
.footer-col p { font-size: 0.88rem; color: var(--footer-fg-soft); margin-bottom: 7px; }
/* The contact column's phone links must not break across lines: the phone number is
   printed spaced — "+995 595 51 86 55", see DEFAULT_PHONE in products-data.js — and a wrap inside
   it would split the `tel:` link's tap target into two boxes on a narrow screen. The address and
   opening-hours paragraphs carry no link and still wrap normally. */
.footer-col p a { white-space: nowrap; }
/* Same job as `.phone-label` in the header, recoloured for the dark footer. Kept on the
   AA-checked `--footer-fg-soft` token (5.8:1) rather than dimmed further — the size step down
   from the number is what separates them, so the contrast budget documented on the footer
   palette above is untouched. */
.footer-col .phone-label { font-size: 0.78rem; color: var(--footer-fg-soft); }

.footer-bottom { border-top: 1px solid var(--footer-rule); }
.footer-bottom-inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  padding: 16px 0;
}
/* was `opacity: 0.45`, which computed to 4.4:1 — under the 4.5:1 AA floor for 12.5px text. */
.footer-bottom-inner p { font-size: 0.78rem; color: var(--footer-dim); }
.footer-badges { display: flex; gap: 8px; flex-wrap: wrap; }
.f-badge {
  background: var(--footer-pill);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--footer-fg-soft);
}

/* ===== FOOTER — ALTERNATE THEMES (inactive) ==============================================
 * Both were designed against this exact markup and carry contrast ratios verified the same
 * way as the active theme. To switch: replace the seven `--footer-*` lines inside `#footer`
 * near the top of this block with one of the two below. Nothing else in this file changes,
 * no markup changes, and `node build-products.js` does NOT need re-running — the footer's
 * four copies of markup (index/about/category/build-products.js) are colour-agnostic.
 *
 * ---- Option B · "Kiln Paper" — light warm footer -----------------------------------------
 * The inversion: the footer stops being dark and becomes the deepest tint in the page's own
 * paper stack (sections already alternate white <-> --muted #F4F4F0, so #EDE8DF is the next
 * rung rather than a cliff). For a seller of unfinished material, keeping the whole page
 * inside the wood's tonal family is the more honest read. Note the hover MUST be the dark
 * green — #00C951 is illegible on a light ground.
 *
 *     --footer-bg:      #EDE8DF;    warm oatmeal
 *     --footer-fg:      #231F1A;    dark warm brown  — 13.4:1 AAA
 *     --footer-fg-soft: #6B6355;    warm stone       —  4.9:1 AA
 *     --footer-dim:     #6B6355;    same tier; #EDE8DF has no room for a third step
 *     --footer-hover:   #026630;    forest green     —  5.8:1 AA  (= --primary-hover)
 *     --footer-rule:    #D8D0C3;    sand rule
 *     --footer-pill:    #DFD8CB;    sand chip        —  4.9:1 AA
 *
 *   B ALSO REQUIRES one extra declaration on `#footer`, or the page appears to just stop
 *   rather than end — a light footer has no tonal break to separate it from the last section:
 *     border-top: 1px solid #D8D0C3;
 *
 * ---- Option C · "Deep Forest" — brand green owns the footer -------------------------------
 * The strongest identity statement of the three: the sign-off carries the brand colour instead
 * of borrowing a neutral. The inversion is the point — ground is green, hover is oak, so the
 * two halves of the brand trade places. Kept very dark and low-chroma deliberately; a brighter
 * green slides straight into generic health-food. Note this is a TONE, not a claim, so it stays
 * clear of the project's FSC/origin constraint (see CLAUDE.md).
 *
 *     --footer-bg:      #12261B;    deep forest
 *     --footer-fg:      #F2F6F1;    green-tinted white — 14.6:1 AAA
 *     --footer-fg-soft: #9DAE9F;    sage               —  6.8:1 AAA
 *     --footer-dim:     #8A9C8D;    deeper sage        —  5.4:1 AA
 *     --footer-hover:   #E8DCC4;    light oak          — 11.7:1 AAA
 *     --footer-rule:    #26402D;    moss rule
 *     --footer-pill:    #26402D;    moss chip
 *
 *   C's one caveat: it is the only theme whose ground competes with the `--primary` buttons
 *   sitting directly above it in #b2b. Worth a look at that seam before committing to it.
 * ========================================================================================= */


/* ===== MOBILE STICKY BAR ===== */
.mobile-bar {
  display: none;
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 99;
  background: var(--background);
  border-top: 1px solid var(--border);
  box-shadow: 0 -3px 12px oklch(0.153 0.006 107.1 / 0.08);
  padding-bottom: env(safe-area-inset-bottom);
}
.mbar-btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 10px 4px;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--text-mid);
  text-decoration: none;
  transition: background 0.15s;
}
.mbar-btn span:first-child { font-size: 1.15rem; }
.mbar-btn.primary { background: var(--primary); color: var(--primary-foreground); }
/* `.mbar-btn.wa` was here and is gone with the mobile bar's WhatsApp button (removed on request;
   the markup is recorded at the spot it occupied in all four copies of the bar — index.html,
   about.html, category.html, and footerHTML() in build-products.js). The rule was:
   .mbar-btn.wa { background: var(--whatsapp); color: #fff; }
   and the `--whatsapp` token it read is likewise commented out in `:root` above — restore both
   together. The `:not(.wa)` in the hover rule below is deliberately left in place: it matches
   nothing now, costs nothing, and means restoring the button needs no edit here beyond
   uncommenting the rule. */
.mbar-btn:not(.primary):not(.wa):hover { background: var(--accent); }

/* ===== MODAL ===== */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: var(--overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
  padding: 20px;
}
.modal {
  background: var(--popover);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 40px 36px;
  max-width: 360px;
  width: 100%;
  text-align: center;
  box-shadow: var(--shadow-lg);
}
.modal-icon { font-size: 3rem; margin-bottom: 14px; }
.modal h3 { font-size: 1.3rem; font-weight: 700; margin-bottom: 8px; }
.modal p { color: var(--muted-foreground); margin-bottom: 24px; line-height: 1.6; }

/* ===== RESPONSIVE — NAV (≤1300px) ===== */
@media (max-width: 1300px) {
  .header-inner { flex-wrap: wrap; row-gap: 8px; height: auto; padding: 10px 0; gap: 8px; }
  .nav-link { padding: 8px 7px; font-size: 0.8rem; }
  .header-contact { margin-left: auto; }
  .header-search-slot {
    order: 5;
    flex: 1 0 100%;
    width: 100%;
    max-width: 100%;
    margin-left: 0;
  }
  .header-search-slot .header-search { width: 100%; max-width: 100%; margin-left: 0; }
}

/* ===== RESPONSIVE — NAV (≤900px) ===== */
@media (max-width: 900px) {
  .header-inner { flex-wrap: wrap; row-gap: 8px; height: auto; padding: 10px 0; }
  .hamburger { display: flex; order: 3; margin-left: auto; }
  .lang-toggle { order: 2; }
  .header-contact {
    order: 4;
    flex: 1 0 100%;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 8px 18px;
    margin-left: 0;
    padding: 10px 0;
    border-top: 1px solid var(--border-light);
    border-bottom: 1px solid var(--border-light);
  }
  .header-contact .contact-item { font-size: 0.84rem; }
  .header-search-slot {
    order: 6;
    flex: 1 1 100%;
    width: 100%;
    max-width: 100%;
    margin-left: 0;
  }
  .header-search-slot .header-search { width: 100%; max-width: 100%; margin-left: 0; }

  .main-nav {
    order: 10;
    flex: 1 0 100%;
    max-height: 0;
    overflow: hidden;
  }
  /* The max-height transition lives on .open only, so the menu still animates open (a transition
     runs with the rules of the state being entered) but collapses instantly. Bug fix (mobile
     "კონტაქტი"): the menu sits in-flow inside the sticky header, and a link tap closes it at
     the same moment the browser starts the smooth anchor scroll — so the #footer target was
     measured against the still-open menu and the page shrank by the menu's height
     mid-animation, which cut the scroll off around the category tiles on iPhone. Closing
     instantly means the anchor target is computed after the menu is gone. To revert: move the
     transition line back onto .main-nav above. */
  .main-nav.open { max-height: 70vh; overflow-y: auto; transition: max-height 0.3s ease; }

  .nav-list { flex-direction: column; align-items: stretch; gap: 0; padding-top: 6px; }
  .nav-item { width: 100%; border-top: 1px solid var(--border-light); }
  .nav-link {
    width: 100%;
    justify-content: space-between;
    padding: 13px 4px;
    border-radius: 0;
  }
  .nav-toggle { width: 100%; text-align: left; }
  .nav-item.open .nav-caret { transform: rotate(180deg); }

  .dropdown-menu {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    box-shadow: none;
    border: none;
    padding: 0 0 0 14px;
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.25s ease;
  }
  .nav-item.open .dropdown-menu { max-height: 400px; }
}

/* ===== RESPONSIVE — MOBILE STICKY HEADER: ONE COMPACT ROW WHILE SCROLLED (≤900px) =====
   Mobile only, and only while the page is scrolled. `#header.scrolled` is the class script.js
   already toggles at scrollY > 8 for the header shadow — nothing was added to the JS, this just
   gives that state a layout. Below 900px the header normally wraps to three rows
   ([logo … hamburger] / [phones + hours] / [search]) and, being sticky, stayed that tall for the
   whole scroll — most of a phone screen was header. Once scrolled it now collapses to ONE row:

       [logo]  [search ─── fills whatever width is left ───]  [hamburger]

   - `.header-contact` (both phone numbers + opening hours) leaves the flow entirely. Both numbers
     are still one scroll-to-top away, and the footer carries them on every page.
   - `.header-search-slot` moves from its own full-width row (order 6 in the ≤900px block above)
     to order 1 — between the logo (order 0) and the hamburger (order 3) — and flexes into the
     remaining width. It is the same single `.header-search` node as always: on index.html
     script.js docks it in here once the hero leaves the viewport (the slot just sits empty, and
     invisible, until then), on every other page it already lives here. No second input.
   - The results panel (`.search-dropdown`) is `left: 0; right: 0; min-width: 300px` relative to
     `.header-search`. With the box now roughly half the screen wide that would spill past the
     right edge — and a results list that narrow is unreadable anyway — so the box is
     un-positioned here (`position: static` AND `transform: none`: the base rule's
     `translateY(0)` is a transform value other than `none` and would otherwise keep the box
     as the containing block) and the panel anchors to the sticky `#header` itself, spanning the
     container width and hanging just under the bar. The docking fade-in still runs; only its 6px
     slide is dropped in this state.
   Everything is scoped to `#header.scrolled` inside this breakpoint, so at the top of the page
   (scrollY ≤ 8) and at every width above 900px the header is exactly what it was. Nothing in
   the ≤600px block needs a companion rule: its `.header-search-slot` line only resets max-width
   and margin, which the rule below re-declares at higher specificity.
   The switch is an instant one at the 8px threshold — the collapsing row is `display: none`,
   not animated — so the content under the header moves up by the row's height at that point.
   To revert: delete this block, or
   `git checkout checkpoint-before-mobile-sticky-header -- style.css`. */
@media (max-width: 900px) {
  #header.scrolled .header-contact { display: none; }
  #header.scrolled .header-search-slot {
    order: 1;
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    max-width: none;
    margin: 0;
  }
  #header.scrolled .header-search-slot .header-search {
    min-width: 0;
    position: static;
    transform: none;
  }
  #header.scrolled .header-search-slot .search-dropdown {
    /* A small inset rather than edge-to-edge: the bar's own side padding is already 0 at this
       width (`.header-inner { padding: 10px 0 }` in the ≤1300px block), so 0 would put the
       panel flush against the screen edges. */
    left: 12px;
    right: 12px;
    min-width: 0;
  }
}

/* ===== RESPONSIVE — TABLET (≤960px) ===== */
@media (max-width: 960px) {
  .species-grid { grid-template-columns: repeat(4, 1fr); }
  .use-grid { grid-template-columns: repeat(3, 1fr); }
  .footer-inner { grid-template-columns: 1fr 1fr; }
  .b2b-card { flex-direction: column; gap: 28px; padding: 32px; }
  .b2b-cta-block { flex-direction: row; min-width: unset; }
}

/* ===== RESPONSIVE — MOBILE (≤600px) ===== */
@media (max-width: 600px) {
  body { padding-bottom: 62px; }
  .section { padding: 40px 0; }

  /* Header */
  .header-contact { gap: 6px 14px; }
  .header-contact .contact-item { font-size: 0.78rem; }
  .header-search-slot { max-width: unset; margin: 0; }
  .header-search-slot .header-search { max-width: unset; margin: 0; }

  /* Hero — kept in step with the smaller desktop headline block. These were written for the
     old 40px/800 title: at 24px/17px the mobile title was barely below the new desktop size
     and the description was actually LARGER here than on desktop, which inverted the ramp.
     Only the padding moves in the compaction pass, and only to keep the ramp pointing the
     right way: at the desktop rule's new 10px/14px, mobile's 20px/22px would have been MORE
     padding on the smaller screen. Everything else the pass changed (`.hero-compact-inner`
     gap, `.hero-main-cta` margin) is unscoped and inherits down here already, so it is not
     repeated. Breakpoints, stacking order and the type ramp are untouched. */
  .hero-compact { padding: 8px 0 12px; }    /* was 20px 0 22px, was 18px 0 20px */
  .hero-main { padding: 0 12px; gap: 6px; } /* was 16px 12px 4px / 12px */
  .hero-main-title { font-size: 21px; }     /* was 24px */
  .hero-main-desc { font-size: 0.875rem; }  /* was 17px */
  .hero-compact + .section { padding-top: 26px; }  /* was 40px above, 40px from `.section` */

  /* Collections (legacy backup only) */
  .collections-grid { grid-template-columns: 1fr; }
  .collection-card { height: 120px; padding: 22px 24px; }

  /* Wood species split card */
  .species-split-header { gap: 12px; }
  .species-split-grid { grid-template-columns: 1fr; }
  .species-split-half { min-height: 150px; padding: 18px 20px; }

  /* Grids */
  .species-grid { grid-template-columns: repeat(3, 1fr); }
  .use-grid { grid-template-columns: repeat(3, 1fr); }
  .use-tile { padding: 16px 8px; }
  /* Same floor as the desktop rule near ".use-tile strong", minus the 12px of vertical padding
     this block drops (136 -> 124), so the row keeps the height it had when the ceiling/wall tile
     still had an icon here too. Needs the #uses prefix to outweigh that rule's specificity. */
  #uses .use-tile { min-height: 124px; }

  /* Products */
  .products-grid { grid-template-columns: 1fr; gap: 10px; }
  /* Product card layout - easy to revert: companion to the "Product card layout (main catalog
   * grid)" block earlier in this file (round 5) — stacks image-above-info on narrow screens instead
   * of the desktop/tablet horizontal (image-left) layout. Delete these 2 lines to keep the row
   * layout at every width, or delete the whole round-5 block (see that comment) to remove the
   * feature entirely. */
  .products-grid .product-card { flex-direction: column; align-items: stretch; }
  .products-grid .card-img { margin: 14px auto 0; }

  /* B2B */
  .b2b-cta-block { flex-direction: column; }
  .b2b-card { padding: 24px 20px; }

  /* Footer */
  .footer-inner { grid-template-columns: 1fr; gap: 28px; padding: 32px 20px; }

  /* Mobile bar - hidden on request. The bar's markup and its `.mobile-bar` / `.mbar-btn` rules are
     all still in place; this one line is what used to reveal it below 768px, and `.mobile-bar`
     defaults to `display: none` further up. Nothing else compensated for its height, so removing
     it leaves no gap. Click-to-call is still one scroll away: the sticky #header carries both
     phone numbers at the top of every page (below 900px they hide while the page is scrolled -
     see the "MOBILE STICKY HEADER: ONE COMPACT ROW" block above), and the footer lists them too.
     To restore, uncomment the line below — that is the whole change.
  .mobile-bar { display: flex; } */
}

@media (max-width: 400px) {
  .products-grid { grid-template-columns: 1fr; }
  .delivery-grid { grid-template-columns: 1fr; }
  .use-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ===== CATEGORY / BROWSE PAGE (category.html) =====
 * Left sidebar (category, wood-species, price filters) + the same product grid/cards used on the
 * homepage (reuses cardHTML()/renderProducts() from script.js as-is via the shared #productsGrid/
 * #productsEmpty ids — no new rendering code). Sidebar filter buttons reuse the existing
 * .use-tile / .species-split-all / .species-split-pill classes (so script.js's existing click
 * wiring + active-state toggling just works) but are restyled here into a plain vertical list —
 * scoped under .category-sidebar so these overrides can't leak into the homepage's own tile/pill
 * components, which keep their original look. */
.category-page-header { padding: 22px 0 4px; }
.category-page-title { font-size: clamp(1.5rem, 3vw, 2.1rem); font-weight: 800; letter-spacing: -0.02em; color: var(--foreground); margin-top: 8px; }

.category-layout {
  display: flex;
  align-items: flex-start;
  gap: 32px;
  margin-top: 8px;
}
.category-sidebar { width: 250px; flex-shrink: 0; }
.category-main { flex: 1; min-width: 0; }

.filter-group { margin-bottom: 28px; }
.filter-group:last-child { margin-bottom: 0; }
.filter-title {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
  margin-bottom: 10px;
}
.filter-list { display: flex; flex-direction: column; gap: 2px; }

.category-sidebar .use-tile,
.category-sidebar .species-split-all,
.category-sidebar .species-split-pill {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 12px;
  border-radius: var(--r-sm);
  border: none;
  background: transparent;
  box-shadow: none;
  color: var(--muted-foreground);
  font-size: 0.86rem;
  font-weight: 500;
  transition: background-color 0.15s, color 0.15s;
}
/* menuAccent: subtle — neutral `accent` hover, primary reserved for the selected row. */
.category-sidebar .use-tile:hover,
.category-sidebar .species-split-all:hover,
.category-sidebar .species-split-pill:hover { background: var(--accent); color: var(--accent-foreground); transform: none; }
.category-sidebar .use-tile.active,
.category-sidebar .species-split-all.active,
.category-sidebar .species-split-pill.active {
  background: var(--primary-subtle);
  color: var(--primary-hover);
  font-weight: 600;
  box-shadow: inset 2px 0 0 var(--primary);
}

@media (max-width: 900px) {
  .category-layout { flex-direction: column; }
  .category-sidebar { width: 100%; }
  .filter-group { margin-bottom: 18px; }
  .filter-list { flex-direction: row; flex-wrap: wrap; gap: 6px; }
  .category-sidebar .use-tile,
  .category-sidebar .species-split-all,
  .category-sidebar .species-split-pill { width: auto; border: 1px solid var(--border); border-radius: 999px; padding: 7px 14px; }
  .category-sidebar .use-tile.active,
  .category-sidebar .species-split-all.active,
  .category-sidebar .species-split-pill.active { border-color: var(--primary); box-shadow: none; }
}
