/* Design tokens — palette is the existing cream/navy/orange (kept per
   DESIGN_ELEMENTS.md direction), formalized into named tokens per the
   2026-08-24 design review rather than scattered hard-coded hex values.
   Typography stays system-font for now (fast, no license/loading concerns);
   a licensed display webfont for headings is an explicit P2/optional item,
   not done here. */

:root {
    --color-bg: #F4F1EC;
    --color-surface: #FFFFFF;
    --color-text: #333333;
    --color-text-muted: #6B6B6B;
    --color-heading: #1B2A4A;
    --color-accent: #F5821F;
    --color-accent-hover: #D96F19;
    --color-link: #1B2A4A;
    --color-link-hover: #F5821F;
    --color-border: #EEEEEE;
    --color-outofstock: #999999;
    --color-success: #2E9E7C;
    --color-success-bg: #E7F5F0;
    --color-error: #B3261E;
    --color-error-bg: #FBEAE9;

    --font-sans: -apple-system, "Helvetica Neue", Arial, sans-serif;
    --text-xs: 13px;
    --text-sm: 14px;
    --text-base: 16px;
    --text-lg: 20px;
    --text-xl: 28px;
    --text-2xl: 36px;
    --font-weight-body: 400;
    --font-weight-medium: 500;
    --font-weight-bold: 700;

    --space-1: 4px;
    --space-2: 8px;
    --space-3: 16px;
    --space-4: 24px;
    --space-5: 32px;
    --space-6: 48px;
    --space-7: 64px;

    --radius-sm: 8px;
    --radius-md: 16px;
    --shadow-card: 0 6px 24px rgba(0,0,0,0.08);
    --shadow-card-hover: 0 10px 32px rgba(0,0,0,0.12);
}

* { box-sizing: border-box; }

/* Global img reset — WooCommerce description/short_description HTML embeds
   raw <img width="300" height="300"> tags (WordPress's own convention).
   Without this, an unstyled image with only an HTML width attribute keeps
   that literal pixel size regardless of viewport, which blows out any
   grid/flex ancestor whose track sizing defaults to minmax(auto, 1fr) —
   the actual cause of the mobile horizontal-scroll bug on product pages. */
img { max-width: 100%; height: auto; display: block; }

body {
    margin: 0;
    font-family: var(--font-sans);
    font-size: var(--text-base);
    background: var(--color-bg);
    color: var(--color-text);
}

/* Links — override browser defaults site-wide. Was previously unstyled
   (#0000EE, underlined, purple-once-visited) everywhere text sat inside an
   <a>, which is why product titles/nav read as plain hyperlinks. */
a {
    color: var(--color-link);
    text-decoration: none;
}
a:hover { color: var(--color-link-hover); }
a:visited { color: var(--color-link); }

:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

.site-footer-inner {
    max-width: 1200px;
    margin: 0 auto;
    padding: var(--space-3) var(--space-4);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    justify-content: space-between;
}

.site-header {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}

.site-header-logo-row {
    max-width: 1200px;
    margin: 0 auto;
    padding: var(--space-3) var(--space-4) var(--space-2);
}

.logo-link { display: inline-block; }
.site-logo { height: 90px; width: auto; display: block; }

.site-header-nav-row {
    max-width: 1200px;
    margin: 0 auto;
    padding: var(--space-2) var(--space-4) var(--space-3);
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-top: 1px solid var(--color-border);
}

.main-nav { display: flex; align-items: center; gap: var(--space-4); }
.main-nav a, .header-actions a {
    color: var(--color-heading);
    font-weight: var(--font-weight-medium);
}
.main-nav a:hover { color: var(--color-accent); }

/* Category dropdown — click/tap-toggle (via a small script), not
   hover-only, so it actually works on touch devices. Hover still opens it
   on desktop for convenience. */
.nav-dropdown { position: relative; }
.nav-dropdown-toggle {
    background: none;
    border: none;
    font: inherit;
    color: var(--color-heading);
    font-weight: var(--font-weight-medium);
    cursor: pointer;
    padding: 0;
}
.nav-dropdown-toggle:hover { color: var(--color-accent); }
.nav-dropdown-menu {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    background: var(--color-surface);
    box-shadow: var(--shadow-card);
    border-radius: var(--radius-sm);
    padding: var(--space-2) 0;
    min-width: 200px;
    z-index: 10;
}
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown.open .nav-dropdown-menu { display: block; }
.nav-dropdown-menu a {
    display: block;
    padding: var(--space-2) var(--space-3);
    font-weight: var(--font-weight-body);
    white-space: nowrap;
}
.nav-dropdown-menu a:hover { background: var(--color-bg); }

.header-actions { display: flex; align-items: center; gap: var(--space-3); }
.header-admin-link {
    font-size: var(--text-sm);
    color: var(--color-text-muted) !important;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 4px 10px;
    white-space: nowrap;
}
.header-admin-link:hover { color: var(--color-heading) !important; border-color: var(--color-heading); }

.cart-badge {
    display: inline-block;
    background: var(--color-accent);
    color: #fff;
    border-radius: 999px;
    padding: 0 var(--space-2);
    font-size: var(--text-xs);
}

.page-content {
    max-width: 1200px;
    margin: 0 auto;
    padding: var(--space-4);
}

/* ===== Hero — full-bleed artwork collage (design brief §A) ================ */
.hero {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    min-height: 480px;
    padding: var(--space-6) var(--space-3);
    overflow: hidden;
    color: #fff;
}

/* Full-bleed trick: break out of .page-content's centered max-width while
   staying inside normal document flow. */
.hero-collage {
    position: absolute;
    inset: 0;
    width: 100vw;
    left: 50%;
    transform: translateX(-50%);
    overflow: hidden;
}

.hero-collage-item {
    position: absolute;
    overflow: hidden;
    will-change: transform;
}
.hero-collage-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
    /* Permanent oversize crop so short-travel parallax never exposes an
       edge; this also holds on mobile where the scroll-linked JS travel
       is disabled outright, so the collage still reads as intentional. */
    transform: scale(1.12);
}
/* Item 4's source (Shiva Family) is a portrait photo in a landscape tile
   — default center cropping was cutting into the figures' heads at the
   top and, less importantly, their feet at the bottom. Biasing upward
   keeps the faces (the actual focal point) fully in frame. Flagged
   2026-08-26 alongside the "images feel randomly cropped" note. */
.hero-collage-item-4 img { object-position: center 15%; }

/* A faint shared navy wash across every tile, 2026-08-26 — the five
   source images (a painted dragon, a dark product-box photo, a gold
   religious icon, a teal family portrait, a pastel heart pattern) have
   no common palette on their own, which is a real part of why the
   collage read as "randomly" assembled rather than one composed piece.
   This doesn't fix that by picking new images — it nudges all five
   toward the same brand-navy undertone so they sit together more
   comfortably, without hiding any of the artwork underneath. */
.hero-collage-item::after {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(27, 42, 74, 0.10);
    mix-blend-mode: multiply;
    pointer-events: none;
}

/* Loose editorial mosaic — five asymmetric tiles, not a uniform grid.
   Bug found 2026-08-26 (later): despite looking hand-tiled, these five
   boxes never actually met edge-to-edge — item-2 stops at y:42%, but
   item-5 didn't start until y:58%, leaving a real untiled gap (x:46-66%,
   y:42-58%, no tile covers it at all) sitting almost exactly behind the
   hero paragraph text. It was invisible under the original heavy scrim
   (58-74% opacity) and only became a visible grey patch once that scrim
   was lightened earlier the same day — reported directly as "the grey
   block has returned." Fixed by extending item-5 (a portrait-oriented
   image already, so a taller box suits its own crop too) up to meet
   item-2's edge exactly, closing the gap with no other tiles touched. */
.hero-collage-item-1 { top: 0;    left: 0;   width: 46%; height: 58%; }
.hero-collage-item-2 { top: 0;    left: 46%; width: 54%; height: 42%; }
.hero-collage-item-3 { top: 42%;  left: 66%; width: 34%; height: 58%; }
.hero-collage-item-4 { top: 58%;  left: 0;   width: 30%; height: 42%; }
.hero-collage-item-5 { top: 42%;  left: 30%; width: 36%; height: 58%; }

.hero-scrim {
    /* Lightened 2026-08-26 — flagged directly against the live preview as
       reading like a visible dark overlay glitch, not a subtle readability
       aid. It technically was intentional (see git history), but at
       58-74% opacity across the *entire* hero, not just behind the text,
       it was doing far more darkening than legibility needed. Dropped to
       a much lighter gradient and added a text-shadow on the heading/copy
       below instead — real legibility insurance that doesn't require
       muting the artwork underneath. */
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(27,42,74,0.18) 0%, rgba(27,42,74,0.32) 55%, rgba(27,42,74,0.18) 100%);
}

.hero-content {
    position: relative;
    z-index: 1;
    max-width: 640px;
}
.hero-content h1 { color: #fff; margin: 0 0 var(--space-3); text-shadow: 0 2px 12px rgba(0,0,0,0.45); }
.hero-content p { font-size: var(--text-lg); margin: 0 0 var(--space-4); text-shadow: 0 1px 8px rgba(0,0,0,0.45); }

/* ===== Mission band — editorial type over a single full-width artwork
   (design brief §C), copy lifted from product-page descriptions ========== */
.mission-band {
    position: relative;
    width: 100vw;
    left: 50%;
    transform: translateX(-50%);
    margin: var(--space-6) 0;
    min-height: 420px;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: #fff;
    overflow: hidden;
}
.mission-band-media {
    position: absolute;
    inset: 0;
}
.mission-band-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.mission-band-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(27,42,74,0.72) 0%, rgba(27,42,74,0.8) 100%);
}
.mission-band-content {
    position: relative;
    z-index: 1;
    max-width: 720px;
    padding: var(--space-5) var(--space-4);
}
.mission-band h2 { color: #fff; font-size: var(--text-2xl); margin: 0 0 var(--space-4); }
.mission-band-body { font-size: var(--text-lg); line-height: 1.5; margin: 0 0 var(--space-3); }
.mission-band-cause { color: rgba(255,255,255,0.85); font-size: var(--text-base); margin: 0; }

/* Buttons */
.btn-primary, .hero-cta, .checkout-cta, .add-to-cart-button {
    display: inline-block;
    background: var(--color-accent);
    color: #fff;
    padding: 12px 24px;
    border-radius: var(--radius-sm);
    text-decoration: none;
    border: none;
    cursor: pointer;
    font-size: var(--text-base);
    font-weight: var(--font-weight-medium);
    transition: background 0.15s ease, transform 0.1s ease;
}
.btn-primary:hover, .hero-cta:hover, .checkout-cta:hover, .add-to-cart-button:hover {
    background: var(--color-accent-hover);
}
.btn-primary:active, .add-to-cart-button:active { transform: scale(0.98); }

.btn-secondary {
    display: inline-block;
    background: transparent;
    color: var(--color-heading);
    border: 1px solid var(--color-heading);
    border-radius: var(--radius-sm);
    padding: 12px 24px;
    text-decoration: none;
}

.featured-products { margin: var(--space-6) 0; }
.featured-products h2 { color: var(--color-heading); margin: 0 0 var(--space-4); }

.purpose-products-intro { color: var(--color-text-muted); margin: 0 0 var(--space-4); font-size: var(--text-lg); }

/* "Puzzles with Purpose" founder's note */
.founder-note-section { margin: var(--space-6) 0; display: flex; justify-content: center; }
.founder-note {
    max-width: 720px;
    margin: 0;
    padding: var(--space-5) var(--space-6);
    border-left: 4px solid var(--color-heading);
    background: var(--color-surface);
    border-radius: 0 12px 12px 0;
    box-shadow: 0 6px 24px rgba(0,0,0,0.06);
}
.founder-note p { font-size: var(--text-lg); line-height: 1.6; color: var(--color-text); margin: 0 0 var(--space-3); font-style: italic; }
.founder-note-signature { font-style: normal; font-weight: 600; color: var(--color-heading); }

/* Product grid + cards */
.product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--space-4);
}

.product-card {
    background: var(--color-surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card);
    padding: var(--space-3);
    display: flex;
    flex-direction: column;
    height: 100%;
    transition: box-shadow 0.15s ease;
}
.product-card:hover { box-shadow: var(--shadow-card-hover); }

.product-card > a {
    display: flex;
    flex-direction: column;
    flex: 1;
    text-decoration: none;
    color: inherit;
}

.product-card-image, .product-detail-gallery-main img {
    max-width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: var(--radius-sm);
}

/* Card image micro-zoom while in view (design brief §B) — wrapper clips
   the scale so it never nudges layout; the scale itself only progresses
   while data-zoom-in-view is intersecting (see scroll-effects.js) and
   reverses on its own via the transition when it scrolls back out. */
.product-card-image-wrap {
    overflow: hidden;
    border-radius: var(--radius-sm);
}
.product-card-image-wrap .product-card-image {
    width: 100%;
    height: 100%;
    transition: transform 1.1s ease;
}
.product-card-image-wrap.is-in-view .product-card-image {
    transform: scale(1.04);
}

.product-card-name {
    color: var(--color-heading);
    font-weight: var(--font-weight-medium);
    font-size: var(--text-base);
    line-height: 1.35;
    margin: var(--space-2) 0 0;
    min-height: calc(1.35em * 2);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.product-card-name:hover { color: var(--color-link-hover); }

/* Always rendered (possibly empty) so cards without an extractable piece
   count still reserve the same vertical slot — otherwise price/button rows
   drift out of alignment against neighboring cards in the same grid row
   that do have a piece count. */
.product-card-pieces { color: var(--color-text-muted); font-size: var(--text-sm); min-height: 1.2em; }
.product-card-price { color: var(--color-heading); font-weight: var(--font-weight-bold); margin-top: var(--space-2); }

.add-to-cart-form { margin-top: auto; padding-top: var(--space-3); }

/* Was completely unstyled — the only feedback on "Add to Basket" was the
   cart badge count ticking up, easy to miss. A small success pill under
   the button gives an actual visible confirmation. */
.add-to-cart-confirmation {
    margin-top: var(--space-2);
    padding: 6px 12px;
    background: var(--color-success-bg);
    color: var(--color-success);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    font-weight: var(--font-weight-medium);
    text-align: center;
    animation: add-to-cart-fade-in 250ms ease;
}
@keyframes add-to-cart-fade-in {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: translateY(0); }
}

.out-of-stock-badge {
    margin-top: auto;
    padding-top: var(--space-3);
}
.out-of-stock-badge span {
    display: block;
    color: var(--color-outofstock);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 12px 24px;
    text-align: center;
}

/* Catalogue layout / filters */
.catalogue-layout {
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: var(--space-5);
}

.filters summary {
    font-size: var(--text-lg);
    color: var(--color-heading);
    font-weight: var(--font-weight-bold);
    cursor: pointer;
    margin: var(--space-3) 0 var(--space-2);
}
.filters details:first-of-type summary { margin-top: 0; }
.filters ul { list-style: none; padding: 0; margin: 0 0 var(--space-4); }
.filters li { padding: var(--space-1) 0; }
.filters a { color: var(--color-text); }
.filters a.active {
    color: var(--color-accent);
    font-weight: var(--font-weight-bold);
}
.filters li.zero-count { opacity: 0.4; pointer-events: none; }
.filters-clear { display: inline-block; margin-top: var(--space-2); font-size: var(--text-sm); }

.filters-toggle-button { display: none; }

/* Product detail page */
.product-detail {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-5);
}

.product-detail-gallery-main img {
    width: 100%;
    display: block;
}
.product-detail-gallery-thumbs {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-2);
    flex-wrap: wrap;
}
.product-detail-gallery-thumbs img {
    width: 72px;
    height: 72px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    cursor: pointer;
    border: 2px solid transparent;
}
.product-detail-gallery-thumbs img.active { border-color: var(--color-accent); }

.product-detail-price { font-size: var(--text-xl); color: var(--color-heading); font-weight: var(--font-weight-bold); }

.purchase-panel {
    box-shadow: var(--shadow-card);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    margin-top: var(--space-3);
    background: var(--color-surface);
}

/* Product metadata sections (specs, description, key line, whimsies) — was
   entirely unstyled, so the <dl>/<dt>/<dd> spec list fell back to the
   browser default definition-list layout (indented, stacked) and the whole
   block sat auto-placed into just the gallery column of .product-detail's
   2-column grid instead of spanning full width underneath it. */
.product-metadata-sections {
    grid-column: 1 / -1;
    margin-top: var(--space-5);
    border-top: 1px solid var(--color-border);
    padding-top: var(--space-5);
}
.product-metadata-section { margin-bottom: var(--space-5); }
.product-metadata-section:last-child { margin-bottom: 0; }
.product-metadata-section h2 {
    color: var(--color-heading);
    font-size: var(--text-lg);
    margin: 0 0 var(--space-3);
}

.product-specs dl {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: var(--space-4);
    row-gap: var(--space-2);
    max-width: 420px;
    margin: 0;
}
.product-specs dt { color: var(--color-text-muted); font-weight: var(--font-weight-medium); }
.product-specs dd { margin: 0; color: var(--color-text); }

/* Cart */
.cart-line {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-border);
}
.cart-line-image { width: 60px; border-radius: var(--radius-sm); }
.cart-line-info { flex: 1; }

.cart-error {
    background: var(--color-error-bg);
    color: var(--color-error);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
    margin: var(--space-2) 0;
}

.out-of-stock { color: var(--color-outofstock); font-style: italic; }

.site-footer {
    margin-top: var(--space-6);
    background: var(--color-heading);
    color: rgba(255,255,255,0.75);
}
.site-footer h3 { color: #fff; font-size: var(--text-sm); margin: 0 0 var(--space-2); }
.site-footer-inner { align-items: center; }
.site-footer-mission { max-width: 560px; }
.site-footer-mission-tagline {
    color: #fff;
    font-weight: var(--font-weight-bold);
    font-size: var(--text-lg);
    margin: 0 0 var(--space-1);
}
.site-footer-mission-line { margin: 0; line-height: 1.5; }
.site-footer-meta {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-2);
    flex-shrink: 0;
}
.site-footer-copyright { margin: 0; font-size: var(--text-sm); }
.site-footer-admin-link {
    margin-left: var(--space-2);
    color: rgba(255,255,255,0.45);
    font-size: var(--text-xs);
    text-decoration: none;
    border-left: 1px solid rgba(255,255,255,0.25);
    padding-left: var(--space-2);
}
.site-footer-admin-link:hover { color: rgba(255,255,255,0.85); }
.social-links { display: flex; gap: var(--space-3); }
.social-links a { color: rgba(255,255,255,0.85); }
.social-links a:hover { color: #fff; }

@media (max-width: 600px) {
    .site-footer-inner { flex-direction: column; align-items: flex-start; }
    .site-footer-meta { align-items: flex-start; }
}

.htmx-indicator { display: none; }
.htmx-request .htmx-indicator { display: inline; }

/* ===== Scroll-reveal + lazy-image fade utility (used across sections) ===== */
[data-reveal] {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 480ms cubic-bezier(0.22, 1, 0.36, 1), transform 480ms cubic-bezier(0.22, 1, 0.36, 1);
    transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal].is-revealed { opacity: 1; transform: translateY(0); }

img[loading="lazy"] { opacity: 0; transition: opacity 320ms ease; }
img[loading="lazy"].is-loaded { opacity: 1; }

/* ===== Category storytelling strip (design brief §D) ====================== */
.category-strip { margin: var(--space-6) 0; }
.category-strip h2 { color: var(--color-heading); margin: 0 0 var(--space-4); }
.category-strip-track {
    display: flex;
    gap: var(--space-4);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    padding-bottom: var(--space-2);
    -webkit-overflow-scrolling: touch;
}
.category-tile {
    position: relative;
    flex: 0 0 240px;
    aspect-ratio: 3 / 4;
    border-radius: var(--radius-md);
    overflow: hidden;
    scroll-snap-align: start;
    display: block;
}
.category-tile img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 1.1s ease, opacity 320ms ease;
}
.category-tile.is-in-view img,
.category-tile:hover img { transform: scale(1.05); }
.category-tile-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(27,42,74,0) 45%, rgba(27,42,74,0.8) 100%);
}
.category-tile-name {
    position: absolute;
    left: var(--space-3);
    right: var(--space-3);
    bottom: var(--space-3);
    z-index: 1;
    color: #fff;
    font-weight: var(--font-weight-bold);
    font-size: var(--text-lg);
}

/* ===== Connective background flow layer (design brief §4 + §E) ============
   One low-opacity, page-level watermark of puzzle-piece/dog-silhouette
   shapes, mounted once on the homepage (templates/partials/bg_flow_layer.html)
   and given a single continuous scroll-linked drift by scroll-effects.js —
   this is what makes the hero/grid/mission/category sections read as one
   continuous space instead of a stack of separately-styled blocks. */
.bg-flow-layer {
    /* Disabled 2026-08-26: reported as a visible "overlay issue" (stray
       gray shapes) on the live preview, by more than one person looking
       at it independently. Confirmed via direct DOM inspection this was
       genuinely rendering at its coded opacity (0.06), not a bug in the
       opacity itself — the puzzle-piece silhouette's scalloped edges just
       created enough local contrast against the light background to read
       as a visible artifact rather than a subtle watermark, especially in
       a screenshot/photo. Rather than keep tuning a number that already
       failed once, retiring the whole effect — same call already made for
       viewports under 768px (see the media query below), now applied
       everywhere. Markup/JS (templates/partials/bg_flow_layer.html,
       static/js/scroll-effects.js's flow-layer block) left in place but
       inert; safe to delete outright next time this file is touched. */
    display: none;
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
    will-change: transform;
}
.bg-flow-shape {
    position: absolute;
    color: var(--color-heading);
    opacity: 0.06;
}
.bg-flow-shape svg { width: 100%; height: 100%; display: block; }
.bg-flow-shape-piece { width: 90px; height: 90px; }
.bg-flow-shape-dog { width: 130px; height: 130px; }

.bg-flow-pos-1 { top: 4%;  left: 8%;  transform: rotate(-12deg); }
.bg-flow-pos-2 { top: 16%; left: 78%; transform: rotate(8deg); }
.bg-flow-pos-3 { top: 32%; left: 42%; transform: rotate(20deg); }
.bg-flow-pos-4 { top: 50%; left: 12%; transform: rotate(-6deg); }
.bg-flow-pos-5 { top: 58%; left: 68%; transform: rotate(-15deg); }
.bg-flow-pos-6 { top: 74%; left: 30%; transform: rotate(10deg); }
.bg-flow-pos-7 { top: 86%; left: 82%; transform: rotate(-20deg); }
.bg-flow-pos-8 { top: 96%; left: 4%;  transform: rotate(14deg); }

/* Responsive */
.mobile-menu-toggle { display: none; }

@media (max-width: 900px) {
    .product-grid { grid-template-columns: repeat(2, 1fr); }
    .catalogue-layout { grid-template-columns: 1fr; }
    .product-detail { grid-template-columns: 1fr; }

    /* Bug found 2026-08-26 via a real tablet-width (768px) check: this is
       also where .catalogue-layout above goes single-column, stacking the
       filter sidebar ABOVE the product grid instead of beside it. The
       collapsible filters-behind-a-button treatment below used to only
       kick in at 600px, so from 601-900px a shopper got the full,
       uncollapsed Piece Count + Category filter list (dozens of items)
       sitting on top of the grid — measured at ~2 full screen-heights of
       scrolling before the first product appeared. Moved here so the
       toggle covers the whole single-column range, not just phone width. */
    .filters { display: none; }
    .filters.open {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 50;
        background: var(--color-bg);
        overflow-y: auto;
        padding: var(--space-4);
    }
    .filters-toggle-button {
        display: block;
        width: 100%;
        margin-bottom: var(--space-3);
        background: var(--color-surface);
        border: 1px solid var(--color-border);
        border-radius: var(--radius-sm);
        padding: var(--space-2) var(--space-3);
        font-weight: var(--font-weight-medium);
    }
}

/* Mobile gets less, not the same amount tuned down: the background flow
   layer and hero/category-strip parallax travel are dropped entirely
   below this width (scroll-effects.js also gates its own listeners on the
   same ~768px breakpoint) rather than just scaled down — phones scroll
   fast and jittery parallax reads as broken there, not elegant. */
@media (max-width: 768px) {
    .bg-flow-layer { display: none; }
    .hero { min-height: 380px; }
    .mission-band { min-height: 320px; }
    .category-tile { flex-basis: 180px; }
}

@media (max-width: 600px) {
    .product-grid { grid-template-columns: 1fr 1fr; gap: var(--space-3); }
    .site-header-nav-row { flex-wrap: wrap; gap: var(--space-2); }
    .main-nav { display: none; gap: var(--space-3); flex-direction: column; align-items: flex-start; width: 100%; }
    .main-nav.open { display: flex; }
    .mobile-menu-toggle { display: block; background: none; border: none; font-size: var(--text-lg); cursor: pointer; }
}

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; }
}

/* ---------------------------------------------------------------------
   Tranche 1 (2026-09-03) — front-end audit remediation.
   --------------------------------------------------------------------- */

/* Screen-reader-only labels. Used by the cart quantity input and the 404
   page's search box, both of which are visually self-evident but were
   unlabelled for assistive tech. */
.visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* Products this storefront can't sell itself (Mix-and-Match bundles).
   Deliberately styled as a secondary action so it reads as a different
   kind of step from "Add to Basket", not a broken version of it. */
.enquire-button {
    background: transparent;
    border: 1px solid currentColor;
    text-decoration: none;
    display: inline-block;
    text-align: center;
}
.enquire-note {
    font-size: 0.9rem;
    opacity: 0.85;
    margin: 0 0 0.5rem;
}

/* "Price on request" — for the gift vouchers, the free catalogue and the
   bundles, which have no price in WooCommerce and used to render R0.00. */
.product-card-price-on-request {
    font-style: italic;
    opacity: 0.75;
}

/* Search field: a magnifying glass so a bare input reads as a search box
   before you click into it. */
.search-input-wrap { position: relative; display: block; }
.search-input-wrap .search-input-icon {
    position: absolute;
    left: 0.75rem;
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
    opacity: 0.6;
    font-size: 0.95rem;
}
.search-input-wrap input[type="search"] { padding-left: 2.4rem; width: 100%; }

/* 404 / 500 page. */
.error-page { max-width: 40rem; margin: 3rem auto; text-align: center; padding: 0 1rem; }
.error-page-message { opacity: 0.85; margin-bottom: 1.75rem; }
.error-page-search { display: flex; gap: 0.5rem; margin-bottom: 1.75rem; }
.error-page-search input { flex: 1; }
.error-page-links { display: flex; flex-wrap: wrap; gap: 1.25rem; justify-content: center; }

/* Footer: the WordPress-hosted content and policy pages. */
.site-footer-links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1.5rem;
    justify-content: center;
    margin-bottom: 1rem;
    font-size: 0.9rem;
}

/* Ratings — render only when a product actually has a review, so these
   rules sit unused until the first one lands. */
.product-card-rating, .product-detail-rating { display: flex; align-items: center; gap: 0.4rem; }
.product-card-rating { justify-content: center; font-size: 0.85rem; }
.stars { letter-spacing: 0.05em; color: #c9a227; }
.rating-count { opacity: 0.7; font-size: 0.85rem; }

/* Cross-sell strip on the product page. */
.related-products { margin: 3rem auto 0; max-width: 1200px; padding: 0 1rem; }
.related-products h2 { margin-bottom: 1.25rem; }

/* Puzzle Club signup in the footer. */
.site-footer-newsletter { text-align: center; margin-bottom: 1.5rem; }
.site-footer-newsletter-title { font-weight: 600; margin: 0 0 0.25rem; }
.site-footer-newsletter-blurb { margin: 0 0 0.75rem; opacity: 0.8; font-size: 0.9rem; }
.newsletter-form { display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap; }
.newsletter-form input[type="email"] { min-width: 15rem; }

/* Reviews — display and submission. Honeypot must be genuinely invisible
   but NOT display:none, which some bots skip. */
.product-reviews { margin: 3rem auto 0; max-width: 1200px; padding: 0 1rem; }
.review-list { list-style: none; padding: 0; margin: 0 0 1.5rem; }
.review { padding: 1rem 0; border-bottom: 1px solid rgba(0,0,0,0.08); }
.review-head { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 0.35rem; }
.review-author { font-weight: 600; }
.review-verified {
    font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em;
    background: #d8efdc; color: #1c5b2c; padding: 0.1rem 0.4rem; border-radius: 3px;
}
.review-date { opacity: 0.6; font-size: 0.85rem; margin-left: auto; }
.review-body { line-height: 1.6; }
.review-empty { opacity: 0.75; }
.review-form-wrap summary { cursor: pointer; font-weight: 600; padding: 0.5rem 0; }
.review-form { display: flex; flex-direction: column; gap: 0.35rem; max-width: 32rem; margin-top: 0.75rem; }
.review-form label { font-weight: 600; margin-top: 0.5rem; }
.review-form .field-hint { font-size: 0.85rem; opacity: 0.7; margin: 0; }
.review-form button { margin-top: 0.75rem; align-self: flex-start; }
.review-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.review-thanks { margin-top: 0.75rem; padding: 0.75rem 1rem; background: #d8efdc; color: #1c5b2c; border-radius: 4px; }
.review-error { margin-top: 0.75rem; }
