/*
 * Wholesale theme — generated bundle. DO NOT EDIT.
 * Edit the files in src/ and re-run build.sh.
 * Order: fonts tokens base atmosphere chrome components product hero module-compat legacy-ie
 */

/* ===== src/fonts.css ===== */
/* ==========================================================================
   Wholesale — self-hosted faces

   No CDN: the site runs under a CSP that only allows same-origin resources,
   and a font that silently falls back to Helvetica is what makes a technical
   catalogue read as unstyled.

   Latin subsets only — the storefront ships a single English locale. Add the
   cyrillic cuts from themes/default/assets/fonts/ if another locale is
   enabled.
   ========================================================================== */

@font-face {
    font-family: Inter;
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url(../fonts/inter-400-latin.woff2) format("woff2");
}

@font-face {
    font-family: Inter;
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url(../fonts/inter-500-latin.woff2) format("woff2");
}

@font-face {
    font-family: Inter;
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url(../fonts/inter-600-latin.woff2) format("woff2");
}

@font-face {
    font-family: Inter;
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url(../fonts/inter-700-latin.woff2) format("woff2");
}

@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url(../fonts/jetbrains-mono-400-latin.woff2) format("woff2");
}

@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url(../fonts/jetbrains-mono-500-latin.woff2) format("woff2");
}

/* ===== src/tokens.css ===== */
/* ==========================================================================
   Wholesale — design tokens

   Dark only, by decision rather than omission. The catalogue is an instrument
   panel: a lit readout on a dark chassis. There is no light scheme and no
   toggle, so every token below is the one and only value.

   Direction: measuring instrument, not shop. The subject is metric threads,
   DIN standards and tolerances, so the page is built like a spec sheet —
   hairline rules, tabular figures, monospace as the voice of data. Depth comes
   from an atmospheric mesh behind translucent surfaces (see atmosphere.css),
   never from drop shadows.

   Neutrals carry a blue bias: zinc-plated steel reads blue-white, and a pure
   grey reads as unconsidered.
   ========================================================================== */

:root {
    color-scheme: dark;

    /* ── Steel ramp ────────────────────────────────────────────────────── */
    --wh-steel-950: #05070a;
    --wh-steel-900: #090c11;
    --wh-steel-850: #0d1117;
    --wh-steel-800: #131820;
    --wh-steel-700: #1c232d;
    --wh-steel-600: #2b3542;
    --wh-steel-500: #4a5666;
    --wh-steel-400: #7b899b;
    --wh-steel-300: #8f9cad;
    --wh-steel-200: #b3becc;
    --wh-steel-100: #d3dae4;
    --wh-white:     #ffffff;

    /* ── Circuit cyan ──────────────────────────────────────────────────────
       Sampled from the hero photography, where it is the glow along the board
       traces. It is the primary accent and the brightest thing on the page. */
    --wh-cyan-500: #06b6d4;
    --wh-cyan-400: #22d3ee;
    --wh-cyan-300: #67e8f9;
    --wh-cyan-glow: rgba(34, 211, 238, 0.3);

    /* ── Blueprint ─────────────────────────────────────────────────────── */
    --wh-blue-600: #2557d6;
    --wh-blue-500: #3d6ee8;
    --wh-blue-400: #6b93f5;
    --wh-blue-300: #9dbaff;

    /* Deep indigo — the third mesh stop. Never used for text or borders; it
       exists to keep the atmosphere from reading as a two-colour ramp. */
    --wh-indigo-600: #4338ca;

    /* ── Semantic (state only — never decoration) ──────────────────────── */
    --wh-ok-400:   #34d399;
    --wh-warn-400: #fbbf24;

    /* ── Surfaces ──────────────────────────────────────────────────────────
       Translucent so the atmospheric mesh reads through them. `--wh-surface`
       is the card ground; anything that must stay legible over imagery uses
       `--wh-surface-solid`. */
    --wh-bg:            var(--wh-steel-950);
    --wh-bg-subtle:     rgba(255, 255, 255, 0.022);
    --wh-bg-sunken:     rgba(0, 0, 0, 0.32);
    --wh-surface:       rgba(255, 255, 255, 0.028);
    --wh-surface-hover: rgba(255, 255, 255, 0.055);
    --wh-surface-solid: var(--wh-steel-900);

    --wh-text:           #e9eef5;
    --wh-text-secondary: var(--wh-steel-300);
    /* Lifted until small monospace text (article numbers, facet counts) clears
       WCAG AA 4.5:1 on the page ground — at the previous value it measured
       4.49 and technically failed. */
    --wh-text-muted:     var(--wh-steel-400);
    --wh-text-inverse:   var(--wh-steel-950);

    /* Borders are light-on-dark at low alpha: a solid grey line on a lit mesh
       reads as a seam, an alpha line reads as an edge. */
    --wh-border:        rgba(255, 255, 255, 0.1);
    --wh-border-strong: rgba(255, 255, 255, 0.2);
    --wh-border-subtle: rgba(255, 255, 255, 0.06);
    --wh-rule:          rgba(255, 255, 255, 0.075);

    --wh-accent:       var(--wh-cyan-400);
    --wh-accent-hover: var(--wh-cyan-300);
    --wh-accent-soft:  rgba(34, 211, 238, 0.14);
    --wh-on-accent:    #032027;

    --wh-ok:      var(--wh-ok-400);
    --wh-ok-soft: rgba(52, 211, 153, 0.14);

    --wh-focus: var(--wh-cyan-400);

    /* ── Type ──────────────────────────────────────────────────────────── */
    --wh-font-sans: Inter, ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif;
    /* Monospace is the voice of the catalogue: article numbers, threads,
       lengths, pack sizes and counts all read as measured values. */
    --wh-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

    /* Slashed zero and tabular figures are not styling: an article number has
       to distinguish 0 from O, and spec columns have to align. */
    --wh-numeric: "tnum" 1, "zero" 1;

    --wh-text-2xs:  0.6875rem;
    --wh-text-xs:   0.75rem;
    --wh-text-sm:   0.8125rem;
    --wh-text-base: 0.9375rem;
    --wh-text-lg:   1.0625rem;
    --wh-text-xl:   1.375rem;
    --wh-text-2xl:  1.75rem;
    --wh-text-3xl:  2.25rem;
    --wh-text-4xl:  3rem;
    --wh-text-5xl:  4rem;

    --wh-leading-tight: 1.1;
    --wh-leading-snug:  1.35;
    --wh-leading-base:  1.6;

    /* ── Space — 4px baseline ──────────────────────────────────────────── */
    --wh-space-1:  0.25rem;
    --wh-space-2:  0.5rem;
    --wh-space-3:  0.75rem;
    --wh-space-4:  1rem;
    --wh-space-5:  1.25rem;
    --wh-space-6:  1.5rem;
    --wh-space-8:  2rem;
    --wh-space-10: 2.5rem;
    --wh-space-12: 3rem;
    --wh-space-16: 4rem;
    --wh-space-20: 5rem;
    --wh-space-24: 6rem;

    /* ── Shape ─────────────────────────────────────────────────────────── */
    /* Square by default. Structure comes from rules and alignment, not from
       rounded cards — a spec sheet has no rounded corners. */
    --wh-radius:    0px;
    --wh-radius-sm: 0px;
    --wh-border-width: 1px;

    --wh-container: 1320px;
    --wh-container-narrow: 760px;

    --wh-transition: 140ms cubic-bezier(0.2, 0, 0.13, 1);

    /* ── Glass ─────────────────────────────────────────────────────────────
       One blur value, used sparingly. Backdrop filters are expensive, so only
       surfaces that actually sit over the mesh get one. */
    --wh-glass-blur: 14px;

    /* ── Dark band ─────────────────────────────────────────────────────────
       Kept as aliases so band components need no rewrite now that the whole
       page is dark. They resolve to the page tokens. */
    --wh-band-bg:        transparent;
    --wh-band-text:      var(--wh-text);
    --wh-band-secondary: var(--wh-text-secondary);
    --wh-band-muted:     var(--wh-text-muted);
    --wh-band-rule:      var(--wh-rule);
    --wh-band-accent:    var(--wh-accent);
}

/* ===== src/base.css ===== */
/* ==========================================================================
   Wholesale — reset, typography, layout primitives
   ========================================================================== */

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

* { margin: 0; }

/* The layout hides modals, the mega menu and the mobile drawer with the
   `hidden` attribute. Old document modes carry no UA rule for it, and a
   stylesheet that sets `display` on those elements outranks it in any case —
   either way the hidden panels drop into the page flow. */
[hidden] { display: none !important; }

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
}

@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;
    }
}

/* Legacy safety net — see docs/ie-legacy-support-plan.md.
   Browsers without custom properties (IE10/11) discard every declaration that
   reads a token, which leaves the page black-on-white in Times New Roman. The
   literal declarations below are what those browsers land on; anything that
   understands var() overrides them on the very next line. Kept to the handful
   of properties that decide whether the page reads as designed-but-degraded
   rather than as broken — the full treatment is the legacy build (G.1). */
body {
    font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    font-family: Inter, ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif; font-family: var(--wh-font-sans);
    font-size: 0.9375rem;
    font-size: 0.9375rem; font-size: var(--wh-text-base);
    line-height: 1.6;
    line-height: 1.6; line-height: var(--wh-leading-base);
    color: #e9eef5;
    color: #e9eef5; color: var(--wh-text);
    background: #05070a;
    background: #05070a; background: var(--wh-bg);
    /* Slashed zero and tabular figures everywhere: this page is mostly
       measured values, and 0/O ambiguity in an article number is a real
       ordering error. */
    font-feature-settings: var(--wh-numeric);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

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

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

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

a { color: inherit; text-decoration: none; }

ul, ol { list-style: none; padding: 0; }

table { border-collapse: collapse; width: 100%; }

h1, h2, h3, h4 {
    font-weight: 600;
    line-height: 1.1; line-height: var(--wh-leading-tight);
    /* Tighter tracking at display sizes — Inter is drawn loose for UI. */
    letter-spacing: -0.022em;
    text-wrap: balance;
}

p { text-wrap: pretty; }

:focus-visible {
    outline: 2px solid #22d3ee; outline: 2px solid var(--wh-focus);
    outline-offset: 2px;
}

::selection {
    background: #22d3ee; background: var(--wh-accent);
    color: #032027; color: var(--wh-on-accent);
}

/* ── Shell ─────────────────────────────────────────────────────────────── */

.wh-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.wh-main { flex: 1 0 auto; }

.wh-container {
    width: 100%;
    max-width: 1320px; max-width: var(--wh-container);
    margin-left: auto; margin-right: auto; margin-inline: auto;
    padding-left: 1.25rem; padding-right: 1.25rem; padding-inline: var(--wh-space-5);
}

@media (min-width: 768px) {
    .wh-container { padding-left: 2rem; padding-right: 2rem; padding-inline: var(--wh-space-8); }
}

.wh-container--narrow { max-width: 760px; max-width: var(--wh-container-narrow); }

.wh-section { padding-top: 4rem; padding-bottom: 4rem; padding-block: var(--wh-space-16); }

@media (min-width: 768px) {
    .wh-section { padding-top: 5rem; padding-bottom: 5rem; padding-block: var(--wh-space-20); }
}

.wh-section--tight { padding-top: 3rem; padding-bottom: 3rem; padding-block: var(--wh-space-12); }

/*
   Section boundaries are full-bleed hairlines rather than boxed cards — the
   page reads as one continuous sheet with ruled divisions, the way a parts
   catalogue does.
*/
.wh-section--ruled { border-top: 1px solid rgba(255, 255, 255, 0.075); border-top: var(--wh-border-width) solid var(--wh-rule); }

.wh-skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    padding: 0.75rem 1rem; padding: var(--wh-space-3) var(--wh-space-4);
    background: #22d3ee; background: var(--wh-accent);
    color: #032027; color: var(--wh-on-accent);
    font-weight: 600;
}

.wh-skip-link:focus { left: 0; }

/* ── Type utilities ────────────────────────────────────────────────────── */

/*
   The monospace face is the voice of measured data: article numbers, threads,
   lengths, pack sizes, counts. Everything a buyer compares between two rows
   is set in it, so the columns align optically as well as numerically.
*/
.wh-mono {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-feature-settings: var(--wh-numeric);
    font-size: 0.92em;
    letter-spacing: -0.02em;
}

.wh-eyebrow {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

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

/* ===== src/atmosphere.css ===== */
/* ==========================================================================
   Wholesale — atmosphere: mesh gradient, aurora, glass

   The page ground is not flat black. A mesh of soft colour fields sits behind
   everything, and the surfaces above it are translucent so the colour reads
   through them rather than being painted on top.

   Two rules keep this from becoming decoration:

   1. The hues are the ones in the product photography — circuit cyan and
      blueprint blue, with one deep indigo to stop the ramp reading as two
      colours. No purple-pink; the subject is instrumentation, not a launch
      page.
   2. The mesh never touches text contrast. Every field is under 0.3 alpha and
      sits behind a surface, so body copy always resolves against a near-black
      ground.
   ========================================================================== */

/*
   Fixed, not scrolled: the mesh behaves like the light in the room rather than
   like a pattern printed on the page. It also means one paint for the whole
   document instead of one per section.
*/
.wh-shell::before {
    content: "";
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
    z-index: -2;
    pointer-events: none;
    background:
        radial-gradient(58% 44% at 12% -4%,  rgba(37, 87, 214, 0.26), transparent 72%),
        radial-gradient(46% 38% at 88% 4%,   rgba(34, 211, 238, 0.16), transparent 70%),
        radial-gradient(52% 42% at 78% 62%,  rgba(67, 56, 202, 0.18), transparent 74%),
        radial-gradient(44% 36% at 8% 88%,   rgba(6, 182, 212, 0.12), transparent 72%);
    background-color: #05070a; background-color: var(--wh-bg);
}

/*
   Aurora: three slow-drifting blobs over the static mesh. They are what make
   the ground feel lit rather than printed. Kept to three because each one is a
   large blurred layer and the compositor pays for every extra.
*/
.wh-aurora {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
    /* Screen keeps the blobs additive over the mesh instead of muddying it. */
    mix-blend-mode: screen;
    opacity: 0.55;
}

.wh-aurora__blob {
    position: absolute;
    border-radius: 50%;
    /* A large blur is what turns a circle into a field. */
    filter: blur(90px);
    will-change: transform;
}

.wh-aurora__blob--1 {
    width: 46vw;
    height: 46vw;
    top: -14vw;
    left: -8vw;
    background: radial-gradient(circle, rgba(37, 87, 214, 0.5), transparent 68%);
    animation: wh-drift-a 34s ease-in-out infinite alternate;
}

.wh-aurora__blob--2 {
    width: 38vw;
    height: 38vw;
    top: 6vw;
    right: -10vw;
    background: radial-gradient(circle, rgba(34, 211, 238, 0.36), transparent 68%);
    animation: wh-drift-b 28s ease-in-out infinite alternate;
}

.wh-aurora__blob--3 {
    width: 42vw;
    height: 42vw;
    bottom: -16vw;
    left: 34%;
    background: radial-gradient(circle, rgba(67, 56, 202, 0.4), transparent 70%);
    animation: wh-drift-c 40s ease-in-out infinite alternate;
}

/* Transform-only keyframes so the animation stays on the compositor. */
@keyframes wh-drift-a {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to   { transform: translate3d(6vw, 8vh, 0) scale(1.18); }
}

@keyframes wh-drift-b {
    from { transform: translate3d(0, 0, 0) scale(1.1); }
    to   { transform: translate3d(-7vw, 10vh, 0) scale(0.92); }
}

@keyframes wh-drift-c {
    from { transform: translate3d(0, 0, 0) scale(0.95); }
    to   { transform: translate3d(-5vw, -9vh, 0) scale(1.15); }
}

/* Ambient drift is exactly the kind of motion reduced-motion users ask not to
   see. The mesh stays; only the movement stops. */
@media (prefers-reduced-motion: reduce) {
    .wh-aurora__blob { animation: none; }
}

/*
   Below a certain width the blobs cost more than they give: the viewport is
   small, the blur radius is proportionally huge, and mobile GPUs pay for it on
   every scroll. The static mesh alone carries the look there.
*/
@media (max-width: 700px) {
    .wh-aurora { display: none; }
}

/* ── Glass surfaces ────────────────────────────────────────────────────── */

/*
   Applied only where a surface genuinely overlaps the mesh and needs to stay
   legible. Each backdrop-filter is a separate compositing pass, so this is a
   short list on purpose — the product grid uses plain alpha instead.
*/
.wh-glass {
    background: rgba(255, 255, 255, 0.028); background: var(--wh-surface);
    backdrop-filter: blur(var(--wh-glass-blur)) saturate(130%);
    -webkit-backdrop-filter: blur(var(--wh-glass-blur)) saturate(130%);
    border: 1px solid rgba(255, 255, 255, 0.1); border: var(--wh-border-width) solid var(--wh-border);
}

/*
   A one-pixel highlight along the top edge. On a dark translucent panel this
   is what separates "a lit surface" from "a grey box" — it reads as the sheen
   on an anodised face.
*/
.wh-glass--lit { position: relative; }

.wh-glass--lit::before {
    content: "";
    position: absolute;
    left: 0; right: 0; inset-inline: 0;
    top: 0;
    height: 1px;
    background: linear-gradient(
        90deg,
        transparent,
        rgba(255, 255, 255, 0.22) 22%,
        rgba(255, 255, 255, 0.22) 78%,
        transparent
    );
    pointer-events: none;
}

/* ===== src/chrome.css ===== */
/* ==========================================================================
   Wholesale — header, navigation, breadcrumbs, footer, modals
   ========================================================================== */

/* ── Header ────────────────────────────────────────────────────────────── */

.wh-header {
    position: sticky;
    top: 0;
    z-index: 40;
    background: rgba(5, 7, 10, 0.72);
    backdrop-filter: blur(var(--wh-glass-blur)) saturate(140%);
    -webkit-backdrop-filter: blur(var(--wh-glass-blur)) saturate(140%);
    border-bottom: 1px solid rgba(255, 255, 255, 0.075); border-bottom: var(--wh-border-width) solid var(--wh-rule);
}

.wh-header__inner {
    display: flex;
    align-items: center;
    gap: var(--wh-space-8);
    min-height: 56px;
}

.wh-header__brand { flex-shrink: 0; }

.wh-header__logo { max-height: 32px; width: auto; }

.wh-header__wordmark {
    font-weight: 600;
    font-size: 0.9375rem; font-size: var(--wh-text-base);
    letter-spacing: -0.03em;
}

.wh-header__aside {
    display: flex;
    align-items: center;
    gap: var(--wh-space-3);
    margin-left: auto;
}

.wh-header__phone {
    display: none;
    flex-direction: column;
    line-height: 1.25;
    text-align: right;
}

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

.wh-header__phone-label {
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-header__phone-value {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-feature-settings: var(--wh-numeric);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    font-weight: 500;
}

.wh-nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 1px solid rgba(255, 255, 255, 0.1); border: var(--wh-border-width) solid var(--wh-border);
    border-radius: 0px; border-radius: var(--wh-radius);
    color: #8f9cad; color: var(--wh-text-secondary);
    transition: color 140ms cubic-bezier(0.2, 0, 0.13, 1), border-color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: color var(--wh-transition), border-color var(--wh-transition);
}

.wh-nav-toggle:hover {
    color: #e9eef5; color: var(--wh-text);
    border-color: rgba(255, 255, 255, 0.2); border-color: var(--wh-border-strong);
}

.wh-nav-toggle { flex-direction: column; gap: 3px; }
.wh-nav-toggle span {
    display: block;
    width: 15px;
    height: 1.5px;
    background: currentColor;
}

@media (min-width: 900px) {
    .wh-nav-toggle { display: none; }
}

/* ── Primary navigation ────────────────────────────────────────────────── */

.wh-nav { display: none; }

@media (min-width: 900px) {
    /* Flex, not block: the catalogue trigger and the menu list are siblings
       and a block container would stack them on two lines. */
    .wh-nav {
        display: flex;
        align-items: center;
        gap: var(--wh-space-5);
    }
}

.wh-nav__list {
    display: flex;
    align-items: center;
    gap: var(--wh-space-5);
}

.wh-nav__item { position: relative; }

.wh-nav__link {
    display: block;
    padding-top: 0.5rem; padding-bottom: 0.5rem; padding-block: var(--wh-space-2);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    font-weight: 450;
    letter-spacing: -0.008em;
    color: #8f9cad; color: var(--wh-text-secondary);
    border-bottom: 1px solid transparent;
    transition: color 140ms cubic-bezier(0.2, 0, 0.13, 1), border-color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: color var(--wh-transition), border-color var(--wh-transition);
}

.wh-nav__link:hover { color: #e9eef5; color: var(--wh-text); }

.wh-nav__link.is-active {
    color: #e9eef5; color: var(--wh-text);
    border-bottom-color: #22d3ee; border-bottom-color: var(--wh-accent);
}

/* Second level: a flat dropdown. Category trees are two deep by contract,
   so no recursive flyout is needed. */
.wh-nav__sub {
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 200px;
    padding: 0.5rem 0; padding: var(--wh-space-2) 0;
    background: #090c11; background: var(--wh-surface-solid);
    border: 1px solid rgba(255, 255, 255, 0.1); border: var(--wh-border-width) solid var(--wh-border);
    border-radius: 0px; border-radius: var(--wh-radius);
    opacity: 0;
    visibility: hidden;
    transition: opacity 140ms cubic-bezier(0.2, 0, 0.13, 1), visibility 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: opacity var(--wh-transition), visibility var(--wh-transition);
}

.wh-nav__item:hover > .wh-nav__sub,
.wh-nav__item:focus-within > .wh-nav__sub {
    opacity: 1;
    visibility: visible;
}

.wh-nav__sub .wh-nav__link {
    padding: 0.5rem 1rem; padding: var(--wh-space-2) var(--wh-space-4);
    border-bottom: 0;
    white-space: nowrap;
}

.wh-nav__sub .wh-nav__link:hover { background: rgba(255, 255, 255, 0.055); background: var(--wh-surface-hover); }

/* ── Mobile navigation ─────────────────────────────────────────────────── */

.wh-mobile-nav {
    border-top: 1px solid rgba(255, 255, 255, 0.1); border-top: var(--wh-border-width) solid var(--wh-border);
    background: #090c11; background: var(--wh-surface-solid);
    padding: 0.5rem 1rem 1rem; padding: var(--wh-space-2) var(--wh-space-4) var(--wh-space-4);
}

@media (min-width: 900px) {
    .wh-mobile-nav { display: none; }
}

.wh-mobile-nav__link {
    display: block;
    padding: 0.75rem 0; padding: var(--wh-space-3) 0;
    font-size: 0.9375rem; font-size: var(--wh-text-base);
    font-weight: 500;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06); border-bottom: var(--wh-border-width) solid var(--wh-border-subtle);
}

.wh-mobile-nav__link.is-active { color: #22d3ee; color: var(--wh-accent); }

.wh-mobile-nav__sub { padding-left: 1rem; padding-left: var(--wh-space-4); }

/* ── Breadcrumbs ───────────────────────────────────────────────────────── */

.wh-breadcrumbs {
    border-bottom: 1px solid rgba(255, 255, 255, 0.075); border-bottom: var(--wh-border-width) solid var(--wh-rule);
}

.wh-breadcrumbs__list {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--wh-space-2);
    padding-top: 0.75rem; padding-bottom: 0.75rem; padding-block: var(--wh-space-3);
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    letter-spacing: 0.02em;
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-breadcrumbs__item { display: flex; align-items: center; gap: var(--wh-space-2); }

.wh-breadcrumbs__item + .wh-breadcrumbs__item::before {
    content: "/";
    color: rgba(255, 255, 255, 0.2); color: var(--wh-border-strong);
}

.wh-breadcrumbs__link:hover { color: #e9eef5; color: var(--wh-text); }

.wh-breadcrumbs__current { color: #e9eef5; color: var(--wh-text); font-weight: 500; }

/* ── Footer ────────────────────────────────────────────────────────────── */

.wh-footer {
    margin-top: 5rem; margin-top: var(--wh-space-20);
    border-top: 1px solid rgba(255, 255, 255, 0.2); border-top: var(--wh-border-width) solid var(--wh-border-strong);
    padding-top: 3rem; padding-bottom: 1.5rem; padding-block: var(--wh-space-12) var(--wh-space-6);
}

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

@media (min-width: 700px) {
    .wh-footer__grid { grid-template-columns: repeat(3, 1fr); }
}

.wh-footer__brand {
    font-weight: 600;
    letter-spacing: -0.02em;
    margin-bottom: 0.5rem; margin-bottom: var(--wh-space-2);
}

.wh-footer__note {
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    color: #8f9cad; color: var(--wh-text-secondary);
    margin-bottom: 0.75rem; margin-bottom: var(--wh-space-3);
}

.wh-footer__terms {
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    font-weight: 600;
    color: #22d3ee; color: var(--wh-accent);
}

.wh-footer__terms:hover { text-decoration: underline; }

.wh-footer__heading {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: #7b899b; color: var(--wh-text-muted);
    margin-bottom: 0.75rem; margin-bottom: var(--wh-space-3);
}

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

.wh-footer__link,
.wh-footer__address {
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    color: #8f9cad; color: var(--wh-text-secondary);
}

.wh-footer__link:hover { color: #e9eef5; color: var(--wh-text); }

.wh-footer__bar {
    margin-top: 2.5rem; margin-top: var(--wh-space-10);
    padding-top: 1.25rem; padding-top: var(--wh-space-5);
    border-top: 1px solid rgba(255, 255, 255, 0.1); border-top: var(--wh-border-width) solid var(--wh-border);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #7b899b; color: var(--wh-text-muted);
}

/* ── Modals ────────────────────────────────────────────────────────────── */

.wh-modal {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
    z-index: 90;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 1.5rem 1rem; padding: var(--wh-space-6) var(--wh-space-4);
    background: rgba(3, 5, 8, 0.78);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    overflow-y: auto;
}

.wh-modal[hidden] { display: none; }

.wh-modal__panel {
    position: relative;
    width: 100%;
    max-width: 560px;
    margin-top: auto; margin-bottom: auto; margin-block: auto;
    padding: 2rem; padding: var(--wh-space-8);
    background: #090c11; background: var(--wh-surface-solid);
    border: 1px solid rgba(255, 255, 255, 0.1); border: var(--wh-border-width) solid var(--wh-border);
    border-radius: 0px; border-radius: var(--wh-radius);
}

.wh-modal__close {
    position: absolute;
    top: 0.75rem; top: var(--wh-space-3);
    right: 0.75rem; right: var(--wh-space-3);
    width: 30px;
    height: 30px;
    font-size: 1.4rem;
    line-height: 1;
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-modal__close:hover { color: #e9eef5; color: var(--wh-text); }

/* ── Error pages ───────────────────────────────────────────────────────── */

.wh-error__inner { max-width: 760px; max-width: var(--wh-container-narrow); text-align: center; }

.wh-error__code {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 3rem; font-size: var(--wh-text-4xl);
    font-weight: 700;
    color: #22d3ee; color: var(--wh-accent);
}

.wh-error__title { font-size: 1.75rem; font-size: var(--wh-text-2xl); margin-top: 0.75rem; margin-bottom: 0.75rem; margin-block: var(--wh-space-3); }

.wh-error__text {
    color: #8f9cad; color: var(--wh-text-secondary);
    margin-bottom: 1.5rem; margin-bottom: var(--wh-space-6);
}

.wh-footer__legal {
    display: block;
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #e9eef5; color: var(--wh-text);
    margin-bottom: 0.25rem; margin-bottom: var(--wh-space-1);
}

/* ── Mega menu ─────────────────────────────────────────────────────────── */

.wh-nav__trigger {
    display: inline-flex;
    align-items: center;
    gap: var(--wh-space-2);
    font-family: inherit;
}

.wh-nav__trigger svg { transition: transform 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: transform var(--wh-transition); }
.wh-nav__trigger[aria-expanded="true"] { color: #e9eef5; color: var(--wh-text); }
.wh-nav__trigger[aria-expanded="true"] svg { transform: rotate(180deg); }

.wh-mega {
    position: absolute;
    left: 0; right: 0; inset-inline: 0;
    top: 100%;
    z-index: 45;
    background: rgba(5, 7, 10, 0.985);
    backdrop-filter: blur(calc(var(--wh-glass-blur) * 1.6)) saturate(140%);
    -webkit-backdrop-filter: blur(var(--wh-glass-blur)) saturate(140%);
    border-bottom: 1px solid rgba(255, 255, 255, 0.1); border-bottom: var(--wh-border-width) solid var(--wh-border);
    box-shadow: 0 24px 48px -24px rgba(0, 0, 0, 0.8);
}

.wh-mega[hidden] { display: none; }

@media (max-width: 899px) {
    /* The rail-and-panel layout needs width; below the nav breakpoint the
       mobile drawer carries navigation instead. */
    .wh-mega { display: none; }
}

.wh-mega__inner {
    display: grid;
    grid-template-columns: 264px minmax(0, 1fr);
    gap: 0;
    padding-top: 1.5rem; padding-bottom: 2rem; padding-block: var(--wh-space-6) var(--wh-space-8);
    max-height: min(72vh, 640px);
}

.wh-mega__rail {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding-right: 1.5rem; padding-right: var(--wh-space-6);
    border-right: 1px solid rgba(255, 255, 255, 0.075); border-right: var(--wh-border-width) solid var(--wh-rule);
    overflow-y: auto;
    scrollbar-width: thin;
}

.wh-mega__root {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--wh-space-3);
    padding: 0.5rem 0.75rem; padding: var(--wh-space-2) var(--wh-space-3);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    color: #8f9cad; color: var(--wh-text-secondary);
    border-left: 2px solid transparent;
    transition: background 140ms cubic-bezier(0.2, 0, 0.13, 1), color 140ms cubic-bezier(0.2, 0, 0.13, 1), border-color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: background var(--wh-transition), color var(--wh-transition), border-color var(--wh-transition);
}

.wh-mega__root:hover,
.wh-mega__root.is-active {
    background: rgba(255, 255, 255, 0.028); background: var(--wh-surface);
    color: #e9eef5; color: var(--wh-text);
    border-left-color: #22d3ee; border-left-color: var(--wh-accent);
}

.wh-mega__count {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-feature-settings: var(--wh-numeric);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-mega__panels {
    padding-left: 2rem; padding-left: var(--wh-space-8);
    overflow-y: auto;
    scrollbar-width: thin;
}

.wh-mega__panel { display: none; }
.wh-mega__panel.is-active { display: block; }

.wh-mega__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: var(--wh-space-5) var(--wh-space-6);
    align-items: start;
}

.wh-mega__link {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--wh-space-2);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    font-weight: 500;
    color: #e9eef5; color: var(--wh-text);
    padding-bottom: 0.5rem; padding-bottom: var(--wh-space-2);
    border-bottom: 1px solid rgba(255, 255, 255, 0.075); border-bottom: var(--wh-border-width) solid var(--wh-rule);
}

.wh-mega__link:hover { color: #22d3ee; color: var(--wh-accent); }

/* Third level: a nested list rather than another column, so the hierarchy
   stays readable without a second level of interaction. */
.wh-mega__sub {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: 0.5rem; margin-top: var(--wh-space-2);
    padding-left: 0.75rem; padding-left: var(--wh-space-3);
    border-left: 1px solid rgba(255, 255, 255, 0.075); border-left: var(--wh-border-width) solid var(--wh-rule);
}

.wh-mega__sub-link {
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #7b899b; color: var(--wh-text-muted);
    padding-top: 1px; padding-bottom: 1px; padding-block: 1px;
}

.wh-mega__sub-link:hover { color: #e9eef5; color: var(--wh-text); }

/* ==========================================================================
   Legacy-browser notice

   Shown only to IE (server-side UA check in the layout). Written in literal
   values rather than tokens on purpose: the browsers that see this banner are
   precisely the ones that discard custom properties, and a notice explaining
   that the page may look wrong must not itself look wrong. It also predates
   the generated fallbacks in the cascade, so it stays correct even if that
   build step is ever skipped.
   ========================================================================== */

.wh-legacy-notice {
    padding: 12px 20px;
    background: #fbbf24;
    color: #0d1117;
    font-size: 14px;
    line-height: 1.5;
    text-align: center;
}

.wh-legacy-notice a {
    color: #0d1117;
    text-decoration: underline;
    font-weight: 600;
    margin-left: 8px;
}

/* ===== src/components.css ===== */
/* ==========================================================================
   Wholesale — controls, specimen cards, facets, ruled grids
   ========================================================================== */

/* ── Buttons ───────────────────────────────────────────────────────────── */

.wh-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--wh-space-2);
    padding: 0.75rem 1.25rem; padding: var(--wh-space-3) var(--wh-space-5);
    border: 1px solid rgba(255, 255, 255, 0.2); border: var(--wh-border-width) solid var(--wh-border-strong);
    border-radius: 0px; border-radius: var(--wh-radius);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    font-weight: 500;
    letter-spacing: -0.005em;
    color: #e9eef5; color: var(--wh-text);
    background: transparent;
    transition: background 140ms cubic-bezier(0.2, 0, 0.13, 1), border-color 140ms cubic-bezier(0.2, 0, 0.13, 1), color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: background var(--wh-transition), border-color var(--wh-transition), color var(--wh-transition);
}

.wh-btn:hover { border-color: #e9eef5; border-color: var(--wh-text); }

.wh-btn--primary {
    background: #22d3ee; background: var(--wh-accent);
    border-color: #22d3ee; border-color: var(--wh-accent);
    color: #032027; color: var(--wh-on-accent);
    font-weight: 600;
    /* The accent is the brightest thing on the page; a soft bloom makes it
       read as lit rather than as a flat swatch. */
    box-shadow: 0 0 24px -6px rgba(34, 211, 238, 0.3); box-shadow: 0 0 24px -6px var(--wh-cyan-glow);
}

.wh-btn--primary:hover {
    background: #67e8f9; background: var(--wh-accent-hover);
    border-color: #67e8f9; border-color: var(--wh-accent-hover);
}

.wh-btn--sm { padding: 0.5rem 0.75rem; padding: var(--wh-space-2) var(--wh-space-3); font-size: 0.75rem; font-size: var(--wh-text-xs); }
.wh-btn--block { width: 100%; }

/* ── Form controls ─────────────────────────────────────────────────────── */

.wh-field {
    width: 100%;
    padding: 0.5rem 0.75rem; padding: var(--wh-space-2) var(--wh-space-3);
    background: rgba(0, 0, 0, 0.32); background: var(--wh-bg-sunken);
    border: 1px solid rgba(255, 255, 255, 0.1); border: var(--wh-border-width) solid var(--wh-border);
    border-radius: 0px; border-radius: var(--wh-radius);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    color: #e9eef5; color: var(--wh-text);
    transition: border-color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: border-color var(--wh-transition);
}

.wh-field:focus { border-color: #22d3ee; border-color: var(--wh-accent); outline: none; }
.wh-field::placeholder { color: #7b899b; color: var(--wh-text-muted); }

.wh-label {
    display: block;
    margin-bottom: 0.5rem; margin-bottom: var(--wh-space-2);
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: #7b899b; color: var(--wh-text-muted);
}

/* ── Badges ────────────────────────────────────────────────────────────── */

.wh-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--wh-space-1);
    padding: 2px 0.5rem; padding: 2px var(--wh-space-2);
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* State is encoded in form as well as colour: a leading dot reads at a glance
   and survives a monochrome print or a colour-blind viewer. */
.wh-badge::before {
    content: "";
    width: 5px;
    height: 5px;
    background: currentColor;
}

.wh-badge--stock   { background: rgba(52, 211, 153, 0.14); background: var(--wh-ok-soft); color: #34d399; color: var(--wh-ok); }
.wh-badge--request { background: rgba(0, 0, 0, 0.32); background: var(--wh-bg-sunken); color: #8f9cad; color: var(--wh-text-secondary); }

/* ── Listing header ────────────────────────────────────────────────────── */

.wh-listing__head {
    padding-top: 3rem; padding-bottom: 1.5rem; padding-block: var(--wh-space-12) var(--wh-space-6);
}

.wh-listing__title {
    font-size: 2.25rem; font-size: var(--wh-text-3xl);
    letter-spacing: -0.03em;
}

/*
   The wholesale disclaimer. This is the only signal on a listing page that
   retail ordering is not offered, so it sits directly under the H1 as a ruled
   meta strip — never collapsed into a tooltip or hidden behind an icon.
*/
.wh-listing__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--wh-space-3);
    margin-top: 1.25rem; margin-top: var(--wh-space-5);
    padding-top: 0.75rem; padding-top: var(--wh-space-3);
    border-top: 1px solid rgba(255, 255, 255, 0.075); border-top: var(--wh-border-width) solid var(--wh-rule);
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    letter-spacing: 0.02em;
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-listing__meta-sep { color: rgba(255, 255, 255, 0.2); color: var(--wh-border-strong); }

.wh-listing__notice {
    color: #22d3ee; color: var(--wh-accent);
    text-transform: uppercase;
    letter-spacing: 0.1em;
}

.wh-listing__description {
    max-width: 68ch;
    margin-top: 1rem; margin-top: var(--wh-space-4);
    color: #8f9cad; color: var(--wh-text-secondary);
}

/* ── Listing layout ────────────────────────────────────────────────────── */

.wh-listing__body {
    display: grid;
    gap: 0;
    grid-template-columns: 1fr;
    border-top: 1px solid rgba(255, 255, 255, 0.075); border-top: var(--wh-border-width) solid var(--wh-rule);
}

@media (min-width: 1000px) {
    .wh-listing__body { grid-template-columns: 232px minmax(0, 1fr); }

    /* The sidebar is separated by a rule, not a gap — the grid line itself is
       the structure. */
    .wh-listing__results {
        border-left: 1px solid rgba(255, 255, 255, 0.075); border-left: var(--wh-border-width) solid var(--wh-rule);
        padding-left: 2rem; padding-left: var(--wh-space-8);
        margin-left: -1px;
    }
}

.wh-listing__sidebar {
    min-width: 0;
    padding-top: 1.5rem; padding-bottom: 1.5rem; padding-block: var(--wh-space-6);
    padding-right: 1.5rem; padding-right: var(--wh-space-6);
}

@media (min-width: 1000px) {
    .wh-listing__sidebar {
        position: sticky;
        top: 64px;
        align-self: start;
        max-height: calc(100vh - 88px);
        overflow-y: auto;
        scrollbar-width: thin;
    }
}

/* ── Collapsible facets on narrow screens ─────────────────────────────────
   A listing can carry fifty facets. On a phone that pushes the products a
   couple of screens down, so the sidebar collapses behind a button below
   1000px — the same breakpoint at which the two-column grid appears.

   Both the button and the collapse are driven by JS adding `is-collapsible`
   to the sidebar. Without JS nothing matches and the sidebar stays open, as
   it always was.
   ------------------------------------------------------------------------ */

.wh-listing__filter-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--wh-space-2);
    align-self: start;
    margin-top: 1.25rem; margin-bottom: 0; margin-block: var(--wh-space-5) 0;
    padding: 0.75rem 1rem; padding: var(--wh-space-3) var(--wh-space-4);
    border: 1px solid rgba(255, 255, 255, 0.2); border: var(--wh-border-width) solid var(--wh-border-strong);
    border-radius: 0px; border-radius: var(--wh-radius);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    font-weight: 500;
    color: #e9eef5; color: var(--wh-text);
    background: transparent;
    cursor: pointer;
    transition: border-color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: border-color var(--wh-transition);
}

.wh-listing__filter-toggle:hover { border-color: #e9eef5; border-color: var(--wh-text); }

.wh-listing__filter-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding-left: 6px; padding-right: 6px; padding-inline: 6px;
    border-radius: 999px;
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: rgba(255, 255, 255, 0.028); color: var(--wh-surface);
    background: #22d3ee; background: var(--wh-accent);
}

/* Desktop keeps the sidebar permanently open, whatever JS decided earlier. */
@media (min-width: 1000px) {
    .wh-listing__filter-toggle,
    .wh-facets__done {
        display: none !important;
    }
}

@media (max-width: 999px) {
    .wh-listing__sidebar.is-collapsible.is-collapsed {
        display: none;
    }

    /* Open, the panel is the page — the rule that separates it from the
       results below would otherwise read as a second, empty section. */
    .wh-listing__sidebar.is-collapsible:not(.is-collapsed) {
        border-bottom: 1px solid rgba(255, 255, 255, 0.075); border-bottom: var(--wh-border-width) solid var(--wh-rule);
    }

    .wh-facets__done {
        display: block;
        width: 100%;
        margin-top: 1.5rem; margin-top: var(--wh-space-6);
        padding: 0.75rem 1.25rem; padding: var(--wh-space-3) var(--wh-space-5);
        border: none;
        border-radius: 0px; border-radius: var(--wh-radius);
        font-size: 0.8125rem; font-size: var(--wh-text-sm);
        font-weight: 500;
        color: rgba(255, 255, 255, 0.028); color: var(--wh-surface);
        background: #22d3ee; background: var(--wh-accent);
        cursor: pointer;
    }
}

.wh-listing__results { padding-top: 1.5rem; padding-bottom: 1.5rem; padding-block: var(--wh-space-6); min-width: 0; }

.wh-listing__toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--wh-space-3);
    margin-bottom: 1.5rem; margin-bottom: var(--wh-space-6);
}

.wh-listing__count {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-listing__empty {
    padding: 4rem 1rem; padding: var(--wh-space-16) var(--wh-space-4);
    text-align: center;
    color: #7b899b; color: var(--wh-text-muted);
    border: 1px dashed rgba(255, 255, 255, 0.1); border: var(--wh-border-width) dashed var(--wh-border);
}

/* ── Specimen grid ─────────────────────────────────────────────────────── */

/*
   Cards have no border of their own. They sit inside a ruled grid: one shared
   hairline between neighbours, drawn with a background so the rules stay
   continuous and never double up at the seams.
*/
.wh-grid {
    display: grid;
    grid-template-columns: repeat(1, minmax(0, 1fr));
    gap: var(--wh-border-width);
    /* Transparent container: on a lit ground a filled gap layer reads as a
       slab. The hairlines come from the cells' own alpha borders instead. */
    background: rgba(255, 255, 255, 0.075); background: var(--wh-rule);
    border: 1px solid rgba(255, 255, 255, 0.075); border: var(--wh-border-width) solid var(--wh-rule);
    backdrop-filter: blur(var(--wh-glass-blur)) saturate(125%);
    -webkit-backdrop-filter: blur(var(--wh-glass-blur)) saturate(125%);
}

@media (min-width: 520px)  { .wh-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 820px)  { .wh-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 820px)  { .wh-grid--4 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1240px) { .wh-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 820px)  { .wh-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ── Specimen card ─────────────────────────────────────────────────────── */

.wh-card {
    display: flex;
    flex-direction: column;
    background: rgba(255, 255, 255, 0.028); background: var(--wh-surface);
    transition: background 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: background var(--wh-transition);
    position: relative;
}

.wh-card:hover { background: rgba(255, 255, 255, 0.055); background: var(--wh-surface-hover); }

/* The lit top edge that separates a panel from a grey box. */
.wh-card::before {
    content: "";
    position: absolute;
    left: 0; right: 0; inset-inline: 0;
    top: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,0.14) 30%, rgba(255,255,255,0.14) 70%, transparent);
    opacity: 0;
    transition: opacity 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: opacity var(--wh-transition);
    pointer-events: none;
}

.wh-card:hover::before { opacity: 1; }

/* A hairline in the accent slides in on hover — the only motion on the grid,
   and it reads as a cursor on an instrument rather than a decorative lift. */
.wh-card::after {
    content: "";
    position: absolute;
    left: 0; right: 0; inset-inline: 0;
    top: 0;
    height: 2px;
    background: #22d3ee; background: var(--wh-accent);
    box-shadow: 0 0 12px rgba(34, 211, 238, 0.3); box-shadow: 0 0 12px var(--wh-cyan-glow);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: transform var(--wh-transition);
}

.wh-card:hover::after,
.wh-card:focus-within::after { transform: scaleX(1); }

.wh-card__media {
    position: relative;
    aspect-ratio: 4 / 3;
    /* White plate, same reasoning as the detail gallery: the shots are cut out
       on white, so `contain` leaves no visible letterbox. */
    background: rgb(255 255 255);
    overflow: hidden;
}

/* `contain`, not `cover`: a fastener photographed end-on loses its head to a
   4:3 crop. The box keeps its ratio, the shot fills whichever axis binds first
   and the remainder is white on white. `background-size` cannot do this — the
   picture is an <img>, so the fit lives on `object-fit`. */
.wh-card__media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: center;
    padding: 0.5rem; padding: var(--wh-space-2);
}

/*
   A catalogue of fasteners is mostly photograph-less. Reserving a full 4:3
   block for grid paper would push real data below the fold, so an image-less
   card gets a short specimen strip instead and the listing stays dense.
*/
.wh-card__media:has(.wh-card__placeholder) { aspect-ratio: 5 / 2; }

/* No photograph: show the article number as the specimen marking instead of
   an empty grey rectangle. */
.wh-card__placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    letter-spacing: 0.08em;
    color: #4a5666; color: var(--wh-steel-500);
    background-image:
        linear-gradient(rgba(255,255,255,0.045) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255,255,255,0.045) 1px, transparent 1px);
    background-size: 16px 16px;
}

.wh-card__body {
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: var(--wh-space-2);
    padding: 1rem; padding: var(--wh-space-4);
}

.wh-card__title {
    font-size: 0.9375rem; font-size: var(--wh-text-base);
    font-weight: 500;
    line-height: 1.35; line-height: var(--wh-leading-snug);
    letter-spacing: -0.015em;
}

.wh-card__title a::after {
    content: "";
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
}

.wh-card__sku {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-card__excerpt {
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    color: #8f9cad; color: var(--wh-text-secondary);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.wh-card__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--wh-space-2);
    margin-top: auto;
    padding-top: 0.75rem; padding-top: var(--wh-space-3);
    border-top: 1px solid rgba(255, 255, 255, 0.075); border-top: var(--wh-border-width) solid var(--wh-rule);
}

/*
   Occupies the slot where a retail card would show a price. Saying "trade
   price on request" beats leaving the row empty: blank space reads as an
   unfinished site, this reads as a deliberate policy.
*/
.wh-card__price-note {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    letter-spacing: 0.01em;
    color: #8f9cad; color: var(--wh-text-secondary);
}

/* ── List variant ──────────────────────────────────────────────────────── */

.wh-grid--list { grid-template-columns: 1fr; }
.wh-grid--list .wh-card { flex-direction: row; }

.wh-grid--list .wh-card__media {
    flex: 0 0 160px;
    aspect-ratio: 1;
}

@media (max-width: 600px) {
    .wh-grid--list .wh-card { flex-direction: column; }
    .wh-grid--list .wh-card__media { flex: none; aspect-ratio: 4 / 3; }
}

/* ── Facet sidebar ─────────────────────────────────────────────────────── */

.wh-facets__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--wh-space-2);
    padding-bottom: 0.75rem; padding-bottom: var(--wh-space-3);
    margin-bottom: 1.25rem; margin-bottom: var(--wh-space-5);
    border-bottom: 1px solid rgba(255, 255, 255, 0.075); border-bottom: var(--wh-border-width) solid var(--wh-rule);
}

.wh-facets__title {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-facets__clear {
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #22d3ee; color: var(--wh-accent);
}

.wh-facets__clear:hover { text-decoration: underline; }

.wh-facets__search { margin-bottom: 1.5rem; margin-bottom: var(--wh-space-6); }

.wh-facet-group + .wh-facet-group { margin-top: 1.5rem; margin-top: var(--wh-space-6); }

.wh-facet-group__label {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: #7b899b; color: var(--wh-text-muted);
    padding-bottom: 0.5rem; padding-bottom: var(--wh-space-2);
    margin-bottom: 0.75rem; margin-bottom: var(--wh-space-3);
    border-bottom: 1px solid rgba(255, 255, 255, 0.075); border-bottom: var(--wh-border-width) solid var(--wh-rule);
}

.wh-facet + .wh-facet { margin-top: 1rem; margin-top: var(--wh-space-4); }

.wh-facet__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    gap: var(--wh-space-2);
    margin-bottom: 0.5rem; margin-bottom: var(--wh-space-2);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    font-weight: 500;
    color: #e9eef5; color: var(--wh-text);
}

.wh-facet__chevron {
    color: #7b899b; color: var(--wh-text-muted);
    transition: transform 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: transform var(--wh-transition);
}

.wh-facet.is-collapsed .wh-facet__chevron { transform: rotate(-90deg); }
.wh-facet.is-collapsed .wh-facet__values { display: none; }

.wh-facet__values { display: flex; flex-direction: column; }

/*
   Each value is a link, not a checkbox: the sidebar navigates rather than
   submits, which keeps a filtered listing shareable and crawlable and lets
   the page work without JavaScript.
*/
.wh-facet__value {
    display: flex;
    align-items: center;
    gap: var(--wh-space-2);
    padding: 5px 0.5rem; padding: 5px var(--wh-space-2);
    margin-left: calc(0.5rem * -1); margin-right: calc(0.5rem * -1); margin-inline: calc(var(--wh-space-2) * -1);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    color: #8f9cad; color: var(--wh-text-secondary);
    transition: background 140ms cubic-bezier(0.2, 0, 0.13, 1), color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: background var(--wh-transition), color var(--wh-transition);
}

.wh-facet__value:hover { background: rgba(255, 255, 255, 0.022); background: var(--wh-bg-subtle); color: #e9eef5; color: var(--wh-text); }

.wh-facet__box {
    flex-shrink: 0;
    width: 13px;
    height: 13px;
    border: 1px solid rgba(255, 255, 255, 0.2); border: var(--wh-border-width) solid var(--wh-border-strong);
    position: relative;
}

.wh-facet__value.is-active { color: #e9eef5; color: var(--wh-text); font-weight: 500; }

.wh-facet__value.is-active .wh-facet__box {
    background: #22d3ee; background: var(--wh-accent);
    border-color: #22d3ee; border-color: var(--wh-accent);
}

.wh-facet__value.is-active .wh-facet__box::after {
    content: "";
    position: absolute;
    left: 4px;
    top: 1px;
    width: 3px;
    height: 7px;
    border: solid #032027; border: solid var(--wh-on-accent);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

.wh-facet__name { flex: 1; min-width: 0; }

.wh-facet__count {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    color: #7b899b; color: var(--wh-text-muted);
}

/* A zero-count option stays visible but inert — hiding it would make the
   facet list jump as the visitor filters. */
.wh-facet__value.is-empty { opacity: 0.28; pointer-events: none; }

.wh-facets__empty { font-size: 0.8125rem; font-size: var(--wh-text-sm); color: #7b899b; color: var(--wh-text-muted); }

/* ── Active filter chips ───────────────────────────────────────────────── */

.wh-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--wh-space-2);
    margin-bottom: 1.25rem; margin-bottom: var(--wh-space-5);
}

.wh-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--wh-space-2);
    padding: 3px 0.5rem; padding: 3px var(--wh-space-2);
    background: rgba(34, 211, 238, 0.14); background: var(--wh-accent-soft);
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    color: #e9eef5; color: var(--wh-text);
    transition: background 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: background var(--wh-transition);
}

.wh-chip:hover { background: rgba(0, 0, 0, 0.32); background: var(--wh-bg-sunken); }
.wh-chip__remove { color: #22d3ee; color: var(--wh-accent); font-weight: 700; }

/* ── Pagination ────────────────────────────────────────────────────────── */

.wh-pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--wh-space-3);
    margin-top: 2.5rem; margin-top: var(--wh-space-10);
    padding-top: 1.25rem; padding-top: var(--wh-space-5);
    border-top: 1px solid rgba(255, 255, 255, 0.075); border-top: var(--wh-border-width) solid var(--wh-rule);
}

.wh-pagination__list { display: flex; align-items: center; gap: var(--wh-space-1); }

.wh-pagination__page,
.wh-pagination__step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    height: 32px;
    padding-left: 0.5rem; padding-right: 0.5rem; padding-inline: var(--wh-space-2);
    border: 1px solid transparent; border: var(--wh-border-width) solid transparent;
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #8f9cad; color: var(--wh-text-secondary);
    transition: border-color 140ms cubic-bezier(0.2, 0, 0.13, 1), color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: border-color var(--wh-transition), color var(--wh-transition);
}

.wh-pagination__step { font-family: Inter, ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif; font-family: var(--wh-font-sans); }

.wh-pagination__page:hover,
.wh-pagination__step:hover { border-color: rgba(255, 255, 255, 0.2); border-color: var(--wh-border-strong); color: #e9eef5; color: var(--wh-text); }

.wh-pagination__page.is-current {
    background: #22d3ee; background: var(--wh-accent);
    border-color: #22d3ee; border-color: var(--wh-accent);
    color: #032027; color: var(--wh-on-accent);
}

.wh-pagination__step.is-disabled { opacity: 0.35; pointer-events: none; }
.wh-pagination__gap { color: #7b899b; color: var(--wh-text-muted); padding-left: 0.25rem; padding-right: 0.25rem; padding-inline: var(--wh-space-1); }

/* ── Spec table ────────────────────────────────────────────────────────── */

.wh-specs + .wh-specs { margin-top: 2rem; margin-top: var(--wh-space-8); }

.wh-specs__group {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: #7b899b; color: var(--wh-text-muted);
    padding-bottom: 0.5rem; padding-bottom: var(--wh-space-2);
    border-bottom: 1px solid rgba(255, 255, 255, 0.2); border-bottom: var(--wh-border-width) solid var(--wh-border-strong);
}

.wh-specs__table { font-size: 0.8125rem; font-size: var(--wh-text-sm); }

.wh-specs__table th,
.wh-specs__table td {
    padding: 0.75rem 0; padding: var(--wh-space-3) 0;
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid rgba(255, 255, 255, 0.075); border-bottom: var(--wh-border-width) solid var(--wh-rule);
}

.wh-specs__table th {
    width: 42%;
    font-weight: 400;
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-specs__table td {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #e9eef5; color: var(--wh-text);
}

/* Icecat ships values like "USB Type-C 3.2 Gen 2 (3.1 Gen 2)" — long enough to
   push the mono column out of a half-width layout without a break opportunity. */
.wh-specs__table td { overflow-wrap: anywhere; }

/*
   Desktop: the groups run in two columns instead of one tall ladder. An Icecat
   record arrives as a dozen-odd small groups — Design, Security, Software,
   Sustainability, most of them one or two lines — so a single column is mostly
   group headings and pushes the description and the enquiry panel a screen and
   a half down.

   Multicol rather than a two-track grid: the browser balances the column
   heights itself, which a grid cannot do when the groups differ in length —
   grid rows would size to the tallest group in each pair and leave gaps.

   `break-inside: avoid` keeps a group whole, so a heading never ends up in one
   column with its rows in the other. Below the breakpoint nothing applies and
   the list is a plain single column again.
*/
@media (min-width: 900px) {
    .wh-specs-grid {
        columns: 2;
        column-gap: var(--wh-space-10);
    }

    .wh-specs-grid .wh-specs {
        break-inside: avoid;
        /* The stacked spacing is a top margin, which would push the first group
           of the second column down and unlevel the two columns. Carry the same
           gap underneath instead. */
        margin-top: 0;
        margin-bottom: 2rem; margin-bottom: var(--wh-space-8);
    }

    .wh-specs-grid .wh-specs:last-child { margin-bottom: 0; }
}

/* ── Icons ─────────────────────────────────────────────────────────────── */

/*
   One stroke weight across the set. Icons inherit `currentColor`, so a link
   hover recolours the glyph with its label rather than leaving it behind.
*/
.wh-mega__icon svg,
.wh-cat-tile__icon svg,
.wh-listing__icon svg,
.wh-contacts__icon svg,
.wh-card__glyph svg {
    width: 100%;
    height: 100%;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    stroke-linecap: square;
    stroke-linejoin: miter;
}

.wh-mega__icon {
    display: block;
    flex-shrink: 0;
    width: 17px;
    height: 17px;
    color: #7b899b; color: var(--wh-text-muted);
    transition: color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: color var(--wh-transition);
}

.wh-mega__icon--sm { width: 14px; height: 14px; }

.wh-mega__label { flex: 1; min-width: 0; }

.wh-mega__root:hover .wh-mega__icon,
.wh-mega__root.is-active .wh-mega__icon { color: #22d3ee; color: var(--wh-accent); }

.wh-mega__link:hover .wh-mega__icon { color: #22d3ee; color: var(--wh-accent); }

.wh-mega__link { align-items: center; }

.wh-cat-tile__icon {
    display: block;
    width: 26px;
    height: 26px;
    color: #7b899b; color: var(--wh-text-muted);
    transition: color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: color var(--wh-transition);
}

.wh-cat-tile:hover .wh-cat-tile__icon { color: #22d3ee; color: var(--wh-accent); }

.wh-listing__title {
    display: flex;
    align-items: center;
    gap: var(--wh-space-4);
}

.wh-listing__icon {
    display: block;
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    color: #22d3ee; color: var(--wh-accent);
}

.wh-contacts__row dt {
    display: flex;
    align-items: center;
    gap: var(--wh-space-2);
}

.wh-contacts__icon {
    display: block;
    width: 13px;
    height: 13px;
    color: #7b899b; color: var(--wh-text-muted);
}

/*
   The image-less card. The icon says what kind of thing this is; the article
   number stays as the marking underneath. Both are dim by default and lift on
   hover so a grid of 24 does not read as 24 competing glyphs.
*/
.wh-card__glyph {
    display: block;
    width: 32px;
    height: 32px;
    /* Dim enough that a grid of 24 does not read as 24 competing glyphs, but
       still legible — at steel-600 the shape disappeared entirely. */
    color: #4a5666; color: var(--wh-steel-500);
    transition: color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: color var(--wh-transition);
}

.wh-card:hover .wh-card__glyph { color: #22d3ee; color: var(--wh-accent); }

.wh-card__marking {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    letter-spacing: 0.08em;
    color: #4a5666; color: var(--wh-steel-500);
}

.wh-card__placeholder { flex-direction: column; gap: var(--wh-space-2); }

/* ── Forms ─────────────────────────────────────────────────────────────── */

.wh-form-block { max-width: 34rem; }

.wh-form__heading {
    font-size: 1.0625rem; font-size: var(--wh-text-lg);
    letter-spacing: -0.02em;
    padding-bottom: 0.75rem; padding-bottom: var(--wh-space-3);
    margin-bottom: 1rem; margin-bottom: var(--wh-space-4);
    border-bottom: 1px solid rgba(255, 255, 255, 0.2); border-bottom: var(--wh-border-width) solid var(--wh-border-strong);
}

.wh-form__description {
    margin-bottom: 1.5rem; margin-bottom: var(--wh-space-6);
    color: #8f9cad; color: var(--wh-text-secondary);
}

.wh-form {
    display: flex;
    flex-direction: column;
    gap: var(--wh-space-5);
}

.wh-form__row { display: flex; flex-direction: column; }

.wh-form__required {
    margin-left: 3px;
    color: #22d3ee; color: var(--wh-accent);
}

.wh-field--area {
    resize: vertical;
    min-height: 8rem;
    line-height: 1.6; line-height: var(--wh-leading-base);
}

.wh-form__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--wh-space-4);
    padding-top: 0.5rem; padding-top: var(--wh-space-2);
}

[data-wh-form-submit].is-busy {
    opacity: 0.55;
    cursor: progress;
}

.wh-form__legal {
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    color: #7b899b; color: var(--wh-text-muted);
    max-width: 24rem;
}

/*
   The honeypot. Off-screen rather than `display: none` — some bots skip
   hidden inputs but happily fill a positioned one, which is the whole point.
   `aria-hidden` plus `tabindex="-1"` on the input keeps it away from anyone
   using a keyboard or a screen reader.
*/
.wh-form__trap {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.wh-form__note {
    padding: 0.75rem 1rem; padding: var(--wh-space-3) var(--wh-space-4);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    border-left: 2px solid currentColor;
}

.wh-form__note[hidden] { display: none; }

.wh-form__note--ok {
    color: #34d399; color: var(--wh-ok);
    background: rgba(52, 211, 153, 0.14); background: var(--wh-ok-soft);
}

.wh-form__note--error {
    color: #fca5a5;
    background: rgba(248, 113, 113, 0.12);
}

/* ===== src/product.css ===== */
/* ==========================================================================
   Wholesale — hero, category overview, product detail, prose
   ========================================================================== */

/* ── Section heading ───────────────────────────────────────────────────── */

.wh-section__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--wh-space-3);
    padding-bottom: 1rem; padding-bottom: var(--wh-space-4);
    margin-bottom: 1.5rem; margin-bottom: var(--wh-space-6);
    border-bottom: 1px solid rgba(255, 255, 255, 0.2); border-bottom: var(--wh-border-width) solid var(--wh-border-strong);
}

.wh-section__title {
    font-size: 1.375rem; font-size: var(--wh-text-xl);
    letter-spacing: -0.025em;
}

/* ── Category tiles ────────────────────────────────────────────────────── */

.wh-cat-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--wh-border-width);
    background: rgba(255, 255, 255, 0.075); background: var(--wh-rule);
    border: 1px solid rgba(255, 255, 255, 0.075); border: var(--wh-border-width) solid var(--wh-rule);
    backdrop-filter: blur(var(--wh-glass-blur)) saturate(125%);
    -webkit-backdrop-filter: blur(var(--wh-glass-blur)) saturate(125%);
}

.wh-cat-tile {
    display: flex;
    flex-direction: column;
    gap: var(--wh-space-3);
    padding: 1.25rem; padding: var(--wh-space-5);
    min-height: 140px;
    background: rgba(255, 255, 255, 0.028); background: var(--wh-surface);
    transition: background 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: background var(--wh-transition);
}

.wh-cat-tile:hover { background: rgba(255, 255, 255, 0.055); background: var(--wh-surface-hover); }

.wh-cat-tile:hover .wh-cat-tile__title { color: #22d3ee; color: var(--wh-accent); }

.wh-cat-tile__title {
    font-size: 0.9375rem; font-size: var(--wh-text-base);
    font-weight: 500;
    letter-spacing: -0.015em;
}

/* Subsections carry the information a buyer navigates by, so they get real
   room rather than a truncated caption. */
.wh-cat-tile__children {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: auto;
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-cat-tile__child { display: flex; gap: var(--wh-space-2); }

.wh-cat-tile__child::before {
    content: "";
    flex-shrink: 0;
    width: 8px;
    height: 1px;
    margin-top: 0.62em;
    background: rgba(255, 255, 255, 0.2); background: var(--wh-border-strong);
}

.wh-cat-tile__count {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    color: #7b899b; color: var(--wh-text-muted);
}

/* ── Category overview (catalog root) ──────────────────────────────────── */

.wh-cat-section + .wh-cat-section { margin-top: 4rem; margin-top: var(--wh-space-16); }

.wh-cat-section__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--wh-space-3);
    padding-bottom: 1rem; padding-bottom: var(--wh-space-4);
    margin-bottom: 1.5rem; margin-bottom: var(--wh-space-6);
    border-bottom: 1px solid rgba(255, 255, 255, 0.2); border-bottom: var(--wh-border-width) solid var(--wh-border-strong);
}

.wh-cat-section__title { font-size: 1.375rem; font-size: var(--wh-text-xl); letter-spacing: -0.025em; }

.wh-cat-section__all {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #22d3ee; color: var(--wh-accent);
}

.wh-cat-section__all:hover { text-decoration: underline; }

.wh-cat-section__description {
    max-width: 68ch;
    margin-top: 0.5rem; margin-top: var(--wh-space-2);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    color: #8f9cad; color: var(--wh-text-secondary);
}

/* ── Product detail ────────────────────────────────────────────────────── */

.wh-product {
    display: grid;
    gap: var(--wh-space-10);
    grid-template-columns: 1fr;
    padding-top: 2.5rem; padding-bottom: 2.5rem; padding-block: var(--wh-space-10);
}

@media (min-width: 900px) {
    .wh-product {
        grid-template-columns: minmax(0, 5fr) minmax(0, 4fr);
        gap: var(--wh-space-16);
    }
}

.wh-gallery__main {
    aspect-ratio: 4 / 3;
    /* Near-white rather than the subtle surface tint: catalogue photography is
       shot on white, so the letterboxing left by `contain` has to disappear
       into the plate instead of framing it. */
    background: rgb(253 253 253);
    border: 1px solid rgba(255, 255, 255, 0.075); border: var(--wh-border-width) solid var(--wh-rule);
    overflow: hidden;
}

.wh-gallery__main img { width: 100%; height: 100%; object-fit: contain; }

/* Until the script marks the gallery live the shots stay stacked in flow, so a
   JS-less visitor can still see all of them. Once `is-live` lands they overlay
   and only the current one shows. */
.wh-gallery.is-live .wh-gallery__main { position: relative; }

.wh-gallery.is-live .wh-gallery__shot {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
    opacity: 0;
    visibility: hidden;
    transition: opacity 140ms linear;
}

.wh-gallery.is-live .wh-gallery__shot.is-current {
    opacity: 1;
    visibility: visible;
}

/* Same reasoning as the listing card: without a photograph there is nothing to
   look at, so the block collapses to a specimen strip rather than holding a
   screenful of grid paper above the specification. */
.wh-gallery__main:has(.wh-card__placeholder) { aspect-ratio: 16 / 6; }

/* Flex rather than a filled grid: an auto-fill grid reserves a track for every
   column that fits, so a three-shot gallery painted the remaining ten tracks as
   an empty rule-coloured band across the page. */
.wh-gallery__thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--wh-border-width);
    margin-top: 1px; margin-top: var(--wh-border-width);
}

/* The thumb is a <button>, so the UA's own border, padding and background have
   to go before the grid gap can read as the hairline rule it is elsewhere. */
.wh-gallery__thumb {
    flex: 0 0 auto;
    width: 72px;
    aspect-ratio: 1;
    background: rgba(255, 255, 255, 0.022); background: var(--wh-bg-subtle);
    overflow: hidden;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.075); border: var(--wh-border-width) solid var(--wh-rule);
    cursor: pointer;
    position: relative;
}

.wh-gallery__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0.55;
    transition: opacity 120ms linear;
}

.wh-gallery__thumb:hover img,
.wh-gallery__thumb:focus-visible img,
.wh-gallery__thumb.is-current img { opacity: 1; }

/* Inset rather than a border: a real border would resize the cell and shift
   every sibling as the selection moves. */
.wh-gallery__thumb.is-current::after {
    content: "";
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
    box-shadow: inset 0 0 0 2px #22d3ee; box-shadow: inset 0 0 0 2px var(--wh-accent);
    pointer-events: none;
}

.wh-gallery__thumb:focus-visible {
    outline: 2px solid #22d3ee; outline: 2px solid var(--wh-accent);
    outline-offset: -2px;
}

.wh-product__title {
    font-size: 1.75rem; font-size: var(--wh-text-2xl);
    letter-spacing: -0.03em;
}

@media (min-width: 768px) {
    .wh-product__title { font-size: 2.25rem; font-size: var(--wh-text-3xl); }
}

.wh-product__ident {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--wh-space-3);
    margin-top: 1rem; margin-top: var(--wh-space-4);
}

.wh-product__sku {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    color: #8f9cad; color: var(--wh-text-secondary);
}

.wh-product__excerpt {
    margin-top: 1.25rem; margin-top: var(--wh-space-5);
    color: #8f9cad; color: var(--wh-text-secondary);
}

/*
   The commercial panel. It sits exactly where a retail shop would put the
   price and the add-to-cart button, and carries the whole "wholesale only"
   message on the product page: no price, no quantity, no cart — one link to
   the terms instead. The accent rule on the leading edge marks it as the
   page's decision point.
*/
.wh-offer {
    position: relative;
    margin-top: 2rem; margin-top: var(--wh-space-8);
    padding: 1.5rem; padding: var(--wh-space-6);
    background: rgba(255, 255, 255, 0.028); background: var(--wh-surface);
    backdrop-filter: blur(var(--wh-glass-blur)) saturate(130%);
    -webkit-backdrop-filter: blur(var(--wh-glass-blur)) saturate(130%);
    border: 1px solid rgba(255, 255, 255, 0.1); border: var(--wh-border-width) solid var(--wh-border);
    border-left: 2px solid #22d3ee; border-left: 2px solid var(--wh-accent);
    box-shadow: -12px 0 32px -20px rgba(34, 211, 238, 0.3); box-shadow: -12px 0 32px -20px var(--wh-cyan-glow);
}

.wh-offer__price {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 1.0625rem; font-size: var(--wh-text-lg);
    font-weight: 500;
    letter-spacing: -0.02em;
}

.wh-offer__note {
    margin-top: 0.5rem; margin-top: var(--wh-space-2);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    color: #8f9cad; color: var(--wh-text-secondary);
}

.wh-offer__actions { margin-top: 1.5rem; margin-top: var(--wh-space-6); }

.wh-product__section { margin-top: 4rem; margin-top: var(--wh-space-16); }

.wh-product__section-title {
    font-size: 1.0625rem; font-size: var(--wh-text-lg);
    letter-spacing: -0.02em;
    padding-bottom: 0.75rem; padding-bottom: var(--wh-space-3);
    margin-bottom: 1.25rem; margin-bottom: var(--wh-space-5);
    border-bottom: 1px solid rgba(255, 255, 255, 0.2); border-bottom: var(--wh-border-width) solid var(--wh-border-strong);
}

/* ── Static pages ──────────────────────────────────────────────────────── */

.wh-page__header {
    padding-top: 4rem; padding-bottom: 2rem; padding-block: var(--wh-space-16) var(--wh-space-8);
    border-bottom: 1px solid rgba(255, 255, 255, 0.075); border-bottom: var(--wh-border-width) solid var(--wh-rule);
}

.wh-page__title {
    font-size: 2.25rem; font-size: var(--wh-text-3xl);
    letter-spacing: -0.03em;
}

/* ── Prose ─────────────────────────────────────────────────────────────── */

.wh-prose {
    color: #8f9cad; color: var(--wh-text-secondary);
    line-height: 1.65;
}

.wh-prose > * + * { margin-top: 1rem; margin-top: var(--wh-space-4); }

.wh-prose h2 {
    font-size: 1.0625rem; font-size: var(--wh-text-lg);
    color: #e9eef5; color: var(--wh-text);
    letter-spacing: -0.02em;
    margin-top: 3rem; margin-top: var(--wh-space-12);
    padding-bottom: 0.5rem; padding-bottom: var(--wh-space-2);
    border-bottom: 1px solid rgba(255, 255, 255, 0.075); border-bottom: var(--wh-border-width) solid var(--wh-rule);
}

.wh-prose h2:first-child { margin-top: 0; }

.wh-prose h3 {
    font-size: 0.9375rem; font-size: var(--wh-text-base);
    color: #e9eef5; color: var(--wh-text);
    margin-top: 2rem; margin-top: var(--wh-space-8);
}

.wh-prose ul, .wh-prose ol { padding-left: 1.25rem; padding-left: var(--wh-space-5); }
.wh-prose ul { list-style: square; }
.wh-prose ol { list-style: decimal; }
.wh-prose li + li { margin-top: 0.5rem; margin-top: var(--wh-space-2); }
.wh-prose li::marker { color: #7b899b; color: var(--wh-text-muted); }

.wh-prose a { color: #22d3ee; color: var(--wh-accent); text-decoration: underline; text-underline-offset: 2px; }
.wh-prose strong { color: #e9eef5; color: var(--wh-text); font-weight: 600; }

.wh-prose table {
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    border: 1px solid rgba(255, 255, 255, 0.075); border: var(--wh-border-width) solid var(--wh-rule);
}

.wh-prose th, .wh-prose td {
    padding: 0.75rem; padding: var(--wh-space-3);
    text-align: left;
    border: 1px solid rgba(255, 255, 255, 0.075); border: var(--wh-border-width) solid var(--wh-rule);
}

.wh-prose th { background: rgba(255, 255, 255, 0.022); background: var(--wh-bg-subtle); font-weight: 600; color: #e9eef5; color: var(--wh-text); }

.wh-prose blockquote {
    padding-left: 1rem; padding-left: var(--wh-space-4);
    border-left: 2px solid #22d3ee; border-left: 2px solid var(--wh-accent);
    color: #e9eef5; color: var(--wh-text);
}

/* ── Error pages ───────────────────────────────────────────────────────── */

.wh-error__inner { max-width: 760px; max-width: var(--wh-container-narrow); }

.wh-error__code {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 3rem; font-size: var(--wh-text-4xl);
    font-weight: 500;
    letter-spacing: -0.04em;
    color: #22d3ee; color: var(--wh-accent);
}

.wh-error__title { font-size: 1.75rem; font-size: var(--wh-text-2xl); margin-top: 0.75rem; margin-bottom: 0.75rem; margin-block: var(--wh-space-3); }
.wh-error__text { color: #8f9cad; color: var(--wh-text-secondary); margin-bottom: 2rem; margin-bottom: var(--wh-space-8); }

/* ── Contacts ──────────────────────────────────────────────────────────── */

.wh-contacts {
    display: grid;
    gap: var(--wh-space-12);
    grid-template-columns: 1fr;
}

@media (min-width: 900px) {
    .wh-contacts {
        grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
        gap: var(--wh-space-16);
        align-items: start;
    }
}

/*
   A registration card, not a "get in touch" panel. A trade buyer raising a
   purchase order copies the legal name and registered address verbatim, so
   both are set in the monospace face and left unwrapped where possible.
*/
.wh-contacts__card {
    padding: 1.5rem; padding: var(--wh-space-6);
    border: 1px solid rgba(255, 255, 255, 0.1); border: var(--wh-border-width) solid var(--wh-border);
    background: rgba(255, 255, 255, 0.028); background: var(--wh-surface);
    backdrop-filter: blur(var(--wh-glass-blur)) saturate(130%);
    -webkit-backdrop-filter: blur(var(--wh-glass-blur)) saturate(130%);
}

.wh-contacts__legal {
    margin-top: 0.5rem; margin-top: var(--wh-space-2);
    font-size: 1.0625rem; font-size: var(--wh-text-lg);
    font-weight: 600;
    letter-spacing: -0.02em;
    color: #e9eef5; color: var(--wh-text);
}

.wh-contacts__rows {
    display: flex;
    flex-direction: column;
    margin-top: 1.25rem; margin-top: var(--wh-space-5);
    border-top: 1px solid rgba(255, 255, 255, 0.1); border-top: var(--wh-border-width) solid var(--wh-border);
}

.wh-contacts__row {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--wh-space-1);
    padding-top: 1rem; padding-bottom: 1rem; padding-block: var(--wh-space-4);
    border-bottom: 1px solid rgba(255, 255, 255, 0.075); border-bottom: var(--wh-border-width) solid var(--wh-rule);
}

.wh-contacts__row dt {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: #7b899b; color: var(--wh-text-muted);
}

.wh-contacts__value {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-feature-settings: var(--wh-numeric);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    color: #e9eef5; color: var(--wh-text);
}

a.wh-contacts__value:hover { color: #22d3ee; color: var(--wh-accent); text-decoration: underline; }

.wh-contacts__address { line-height: 1.65; }

.wh-contacts__body > * + * { margin-top: 2rem; margin-top: var(--wh-space-8); }

.wh-contacts__map {
    margin-top: 3rem; margin-top: var(--wh-space-12);
    border-top: 1px solid rgba(255, 255, 255, 0.075); border-top: var(--wh-border-width) solid var(--wh-rule);
}

.wh-contacts__map iframe { display: block; width: 100%; min-height: 380px; border: 0; }

/* ===== src/hero.css ===== */
/* ==========================================================================
   Wholesale — dark bands and the hero slider

   The catalogue itself is a light, dense, ruled document. These are the few
   places that go dark on purpose: they break the sheet into chapters and give
   the product photography somewhere to live. The photography carries a cyan
   circuit glow, so cyan is the accent inside a band — and only there.
   ========================================================================== */

:root {
    /* Concrete ink for scrims. The `--wh-band-*` tokens are transparent
       aliases now that the whole page is dark, and a gradient built on a
       transparent stop renders as nothing. */
    --wh-scrim-ink: #05070a;
}

.wh-band {
    position: relative;
    background: transparent;
    color: #e9eef5; color: var(--wh-band-text);
    overflow: hidden;
    isolation: isolate;
}

.wh-band a { color: inherit; }

/* ── Hero slider ───────────────────────────────────────────────────────── */

.wh-hero {
    position: relative;
    background: #05070a; background: var(--wh-scrim-ink);
    color: #e9eef5; color: var(--wh-text);
    overflow: hidden;
    isolation: isolate;
}

.wh-hero__stage {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
    z-index: -2;
}

.wh-hero__slide {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
    background-position: right center;
    background-size: cover;
    background-repeat: no-repeat;
    opacity: 0;
    /* A slow drift keeps the still frames from reading as a static banner;
       the movement is small enough that it never competes with the copy. */
    transform: scale(1.04);
    transition: opacity 900ms ease, transform 7000ms linear;
    will-change: opacity, transform;
}

.wh-hero__slide.is-active {
    opacity: 1;
    transform: scale(1);
}

/*
   Scrim. Every supplied frame places its subject on the right against empty
   dark space on the left, so the gradient only has to deepen what is already
   there for the copy to hold contrast.
*/
.wh-hero__scrim {
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
    z-index: -1;
    background: /* Horizontal: opens the right side where the subject sits. */
        linear-gradient(
            100deg,
            #05070a 0%,
            rgba(5, 7, 10, 0.94) 32%,
            rgba(5, 7, 10, 0.55) 54%,
            rgba(5, 7, 10, 0.12) 76%
        ),
        /* Vertical: seats the figures row against the bottom edge so the
           monospace values never fight the photograph behind them. */
        linear-gradient(
            to bottom,
            transparent 45%,
            rgba(5, 7, 10, 0.55) 74%,
            rgba(5, 7, 10, 0.92) 100%
        ); background:
        /* Horizontal: opens the right side where the subject sits. */
        linear-gradient(
            100deg,
            var(--wh-scrim-ink) 0%,
            rgba(5, 7, 10, 0.94) 32%,
            rgba(5, 7, 10, 0.55) 54%,
            rgba(5, 7, 10, 0.12) 76%
        ),
        /* Vertical: seats the figures row against the bottom edge so the
           monospace values never fight the photograph behind them. */
        linear-gradient(
            to bottom,
            transparent 45%,
            rgba(5, 7, 10, 0.55) 74%,
            rgba(5, 7, 10, 0.92) 100%
        );
}

@media (max-width: 860px) {
    /* On narrow screens the subject and the copy would overlap, so the scrim
       becomes a vertical one and the frame sits behind the text. */
    .wh-hero__scrim {
        background: linear-gradient(
            to bottom,
            rgba(5, 7, 10, 0.7) 0%,
            rgba(5, 7, 10, 0.93) 55%,
            #05070a 100%
        ); background: linear-gradient(
            to bottom,
            rgba(5, 7, 10, 0.7) 0%,
            rgba(5, 7, 10, 0.93) 55%,
            var(--wh-scrim-ink) 100%
        );
    }
}

.wh-hero__inner {
    position: relative;
    padding-top: 5rem; padding-bottom: 4rem; padding-block: var(--wh-space-20) var(--wh-space-16);
    min-height: 480px;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

@media (min-width: 1000px) {
    .wh-hero__inner { min-height: 560px; }
}

.wh-hero__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: var(--wh-space-2);
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: #22d3ee; color: var(--wh-band-accent);
}

/* A short lit rule before the eyebrow — the one place the circuit glow is
   quoted literally. */
.wh-hero__eyebrow::before {
    content: "";
    width: 28px;
    height: 1px;
    background: #22d3ee; background: var(--wh-band-accent);
    box-shadow: 0 0 8px rgba(34, 211, 238, 0.3); box-shadow: 0 0 8px var(--wh-cyan-glow);
}

.wh-hero__title {
    max-width: 16ch;
    margin-top: 1.25rem; margin-bottom: 1.25rem; margin-block: var(--wh-space-5) var(--wh-space-5);
    font-size: clamp(2.1rem, 4.6vw, 3.6rem);
    font-weight: 600;
    letter-spacing: -0.04em;
    line-height: 1.04;
    color: #e9eef5; color: var(--wh-band-text);
}

.wh-hero__lead {
    max-width: 46ch;
    font-size: 1.0625rem; font-size: var(--wh-text-lg);
    line-height: 1.55;
    color: #8f9cad; color: var(--wh-band-secondary);
}

.wh-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--wh-space-3);
    margin-top: 2rem; margin-top: var(--wh-space-8);
}

/* Buttons on a band need their own pair — the page tokens assume light ground. */
.wh-btn--band {
    background: #22d3ee; background: var(--wh-band-accent);
    border-color: #22d3ee; border-color: var(--wh-band-accent);
    color: #04252c;
    font-weight: 600;
}

.wh-btn--band:hover {
    background: #67e8f9; background: var(--wh-cyan-300);
    border-color: #67e8f9; border-color: var(--wh-cyan-300);
}

.wh-btn--band-ghost {
    background: transparent;
    border-color: rgba(255, 255, 255, 0.28);
    color: #e9eef5; color: var(--wh-band-text);
}

.wh-btn--band-ghost:hover { border-color: #e9eef5; border-color: var(--wh-band-text); }

/* ── Slider controls ───────────────────────────────────────────────────── */

.wh-hero__controls {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--wh-space-3);
    margin-top: 2.5rem; margin-top: var(--wh-space-10);
}

.wh-hero__dot {
    position: relative;
    width: 34px;
    height: 2px;
    background: rgba(255, 255, 255, 0.22);
    transition: background 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: background var(--wh-transition);
}

.wh-hero__dot:hover { background: rgba(255, 255, 255, 0.45); }

.wh-hero__dot.is-active { background: #22d3ee; background: var(--wh-band-accent); }

/* The active dot doubles as the autoplay progress bar, so the interval is
   visible rather than a surprise. */
.wh-hero__dot.is-active::after {
    content: "";
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
    background: #67e8f9; background: var(--wh-cyan-300);
    transform-origin: left;
    animation: wh-hero-progress 6s linear forwards; animation: wh-hero-progress var(--wh-hero-interval, 6s) linear forwards;
}

.wh-hero.is-paused .wh-hero__dot.is-active::after { animation-play-state: paused; }

@keyframes wh-hero-progress {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
}

/* Kept beside the dots rather than pushed to the far edge: the right of the
   frame is where the photograph is brightest, and a muted mono counter has no
   contrast there. */
.wh-hero__counter {
    margin-left: 0.75rem; margin-left: var(--wh-space-3);
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-feature-settings: var(--wh-numeric);
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    letter-spacing: 0.1em;
    color: #7b899b; color: var(--wh-band-muted);
}

@media (prefers-reduced-motion: reduce) {
    .wh-hero__slide { transition: opacity 1ms; transform: none; }
    .wh-hero__dot.is-active::after { animation: none; transform: scaleX(1); }
}

/* ── Figures inside the band ───────────────────────────────────────────── */

.wh-hero__facts {
    position: relative;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--wh-border-width);
    margin-top: 3rem; margin-top: var(--wh-space-12);
    background: rgba(255, 255, 255, 0.075); background: var(--wh-rule);
    border-top: 1px solid rgba(255, 255, 255, 0.075); border-top: var(--wh-border-width) solid var(--wh-rule);
}

.wh-fact {
    background: rgba(5, 7, 10, 0.66);
    backdrop-filter: blur(var(--wh-glass-blur)) saturate(130%);
    -webkit-backdrop-filter: blur(var(--wh-glass-blur)) saturate(130%);
    padding: 1.25rem 1.25rem 1rem; padding: var(--wh-space-5) var(--wh-space-5) var(--wh-space-4);
}

.wh-fact__value {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-feature-settings: var(--wh-numeric);
    font-size: 1.75rem; font-size: var(--wh-text-2xl);
    font-weight: 500;
    letter-spacing: -0.04em;
    color: #22d3ee; color: var(--wh-band-accent);
}

.wh-fact__label {
    margin-top: 0.25rem; margin-top: var(--wh-space-1);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #7b899b; color: var(--wh-band-muted);
}

/* ── Terms band ────────────────────────────────────────────────────────── */

/*
   Sits immediately above the footer and restates the one thing the site needs
   every visitor to leave knowing. Dark so it reads as a closing statement
   rather than another section of the catalogue.
*/
.wh-terms-band__inner {
    display: grid;
    gap: var(--wh-space-8);
    grid-template-columns: 1fr;
    padding-top: 4rem; padding-bottom: 4rem; padding-block: var(--wh-space-16);
}

@media (min-width: 860px) {
    .wh-terms-band__inner {
        grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
        align-items: center;
        gap: var(--wh-space-16);
    }
}

.wh-terms-band__title {
    font-size: 1.75rem; font-size: var(--wh-text-2xl);
    letter-spacing: -0.03em;
    margin-top: 1rem; margin-top: var(--wh-space-4);
    color: #e9eef5; color: var(--wh-band-text);
}

.wh-terms-band__text {
    margin-top: 1rem; margin-top: var(--wh-space-4);
    color: #8f9cad; color: var(--wh-band-secondary);
    max-width: 52ch;
}

.wh-terms-band__points {
    display: flex;
    flex-direction: column;
    gap: var(--wh-border-width);
    background: rgba(255, 255, 255, 0.075); background: var(--wh-band-rule);
    border: 1px solid rgba(255, 255, 255, 0.075); border: var(--wh-border-width) solid var(--wh-band-rule);
}

.wh-terms-band__point {
    display: flex;
    align-items: baseline;
    gap: var(--wh-space-4);
    padding: 1rem 1.25rem; padding: var(--wh-space-4) var(--wh-space-5);
    background: rgba(5, 7, 10, 0.6);
    backdrop-filter: blur(var(--wh-glass-blur));
    -webkit-backdrop-filter: blur(var(--wh-glass-blur));
}

.wh-terms-band__key {
    flex-shrink: 0;
    width: 5.5rem;
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-family: var(--wh-font-mono);
    font-feature-settings: var(--wh-numeric);
    font-size: 0.75rem; font-size: var(--wh-text-xs);
    color: #22d3ee; color: var(--wh-band-accent);
}

.wh-terms-band__desc { font-size: 0.8125rem; font-size: var(--wh-text-sm); color: #8f9cad; color: var(--wh-band-secondary); }

.wh-terms-band__actions { margin-top: 2rem; margin-top: var(--wh-space-8); }

/* ===== src/module-compat.css ===== */
/* ==========================================================================
   Wholesale — compatibility layer for module-provided block views

   Some block views live in modules (`modules/{slug}/views/blocks/*.php`) and
   hard-code the class vocabulary of the default theme. Rather than fork those
   views into this theme — which would duplicate real logic such as the CTA's
   ~85-line entity-URL resolution and leave two copies to drift — this file
   maps the vocabulary they use onto this theme's tokens.

   Forking is still the right call when a module view's *markup* is wrong for
   the design (see themes/wholesale/blocks/catalog_featured.php). This layer
   handles the common case where only the styling differs.
   ========================================================================== */

/* ── Buttons (pages: cta) ──────────────────────────────────────────────── */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--wh-space-2);
    padding: 0.75rem 1.25rem; padding: var(--wh-space-3) var(--wh-space-5);
    border: 1px solid rgba(255, 255, 255, 0.2); border: var(--wh-border-width) solid var(--wh-border-strong);
    border-radius: 0px; border-radius: var(--wh-radius);
    font-size: 0.8125rem; font-size: var(--wh-text-sm);
    font-weight: 600;
    color: #e9eef5; color: var(--wh-text);
    background: rgba(255, 255, 255, 0.028); background: var(--wh-surface);
    transition: background 140ms cubic-bezier(0.2, 0, 0.13, 1), border-color 140ms cubic-bezier(0.2, 0, 0.13, 1); transition: background var(--wh-transition), border-color var(--wh-transition);
}

.btn:hover { background: rgba(255, 255, 255, 0.055); background: var(--wh-surface-hover); border-color: #7b899b; border-color: var(--wh-text-muted); }

.btn-primary {
    background: #22d3ee; background: var(--wh-accent);
    border-color: #22d3ee; border-color: var(--wh-accent);
    color: #032027; color: var(--wh-on-accent);
}

.btn-primary:hover { background: #67e8f9; background: var(--wh-accent-hover); border-color: #67e8f9; border-color: var(--wh-accent-hover); }

.btn-secondary { background: rgba(0, 0, 0, 0.32); background: var(--wh-bg-sunken); }

.btn-ghost { background: transparent; border-color: rgba(255, 255, 255, 0.1); border-color: var(--wh-border); }

.btn-lg { padding: 0.75rem 1.5rem; padding: var(--wh-space-3) var(--wh-space-6); }
.btn-sm { padding: 0.5rem 0.75rem; padding: var(--wh-space-2) var(--wh-space-3); font-size: 0.75rem; font-size: var(--wh-text-xs); }

/* ── Layout vocabulary ─────────────────────────────────────────────────── */

.site-container {
    width: 100%;
    max-width: 1320px; max-width: var(--wh-container);
    margin-left: auto; margin-right: auto; margin-inline: auto;
    padding-left: 1rem; padding-right: 1rem; padding-inline: var(--wh-space-4);
}

@media (min-width: 768px) {
    .site-container { padding-left: 1.5rem; padding-right: 1.5rem; padding-inline: var(--wh-space-6); }
}

.site-section { padding-top: 3rem; padding-bottom: 3rem; padding-block: var(--wh-space-12); }

/* ── Typography vocabulary ─────────────────────────────────────────────── */

.h-display {
    font-size: 2.25rem; font-size: var(--wh-text-3xl);
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.1; line-height: var(--wh-leading-tight);
}

.eyebrow {
    display: inline-flex;
    font-size: 0.6875rem; font-size: var(--wh-text-2xs);
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: #7b899b; color: var(--wh-text-muted);
}

.text-content { color: #8f9cad; color: var(--wh-text-secondary); }
.text-secondary-token { color: #8f9cad; color: var(--wh-text-secondary); }
.text-muted-token { color: #7b899b; color: var(--wh-text-muted); }

/* `prose` is emitted by the html/wysiwyg blocks; reuse the theme's own
   long-form styling rather than maintaining a second set of rules. */
.prose { max-width: 72ch; color: #8f9cad; color: var(--wh-text-secondary); }
.prose > * + * { margin-top: 1rem; margin-top: var(--wh-space-4); }
.prose h2 { font-size: 1.375rem; font-size: var(--wh-text-xl); color: #e9eef5; color: var(--wh-text); margin-top: 2rem; margin-top: var(--wh-space-8); }
.prose h3 { font-size: 1.0625rem; font-size: var(--wh-text-lg); color: #e9eef5; color: var(--wh-text); margin-top: 1.5rem; margin-top: var(--wh-space-6); }
.prose ul { list-style: square; padding-left: 1.25rem; padding-left: var(--wh-space-5); }
.prose ol { list-style: decimal; padding-left: 1.25rem; padding-left: var(--wh-space-5); }
.prose li + li { margin-top: 0.5rem; margin-top: var(--wh-space-2); }
.prose a { color: #22d3ee; color: var(--wh-accent); text-decoration: underline; }
.prose strong { color: #e9eef5; color: var(--wh-text); font-weight: 600; }
.prose img { border-radius: 0px; border-radius: var(--wh-radius); }

/* ── Utility escape hatches used inline by module views ────────────────── */

.mt-6 { margin-top: 1.5rem; margin-top: var(--wh-space-6); }
.mb-6 { margin-bottom: 1.5rem; margin-bottom: var(--wh-space-6); }
.text-center { text-align: center; }
.leading-relaxed { line-height: 1.6; line-height: var(--wh-leading-base); }
.whitespace-pre-line { white-space: pre-line; }
.text-base { font-size: 0.9375rem; font-size: var(--wh-text-base); }
.text-sm { font-size: 0.8125rem; font-size: var(--wh-text-sm); }
.text-lg { font-size: 1.0625rem; font-size: var(--wh-text-lg); }

/* ===== src/legacy-ie.css ===== */
/* ==========================================================================
   Wholesale — Internet Explorer 10/11 layout fallbacks

   Every rule here sits inside a media query that only IE10 and IE11 match, so
   no modern browser parses a line of it. That is what makes it safe to write
   layout rules that would be wrong anywhere else.

   The generated token fallbacks (legacy-fallbacks.php) already hand IE the
   colours, type and spacing. What it still cannot do is lay the page out:
   `grid` and `gap` are both absent, so every grid collapses into one
   full-width column and every flex gap closes up — one product per screen,
   menu items running together. That is what BrowserStack showed on
   2026-08-17.

   Values are literal rather than tokens on purpose: this is the one file whose
   audience is defined by not understanding custom properties.

   Column counts below were measured against the real grid rendering at
   1366px rather than read off the source, since several of these grids use
   auto-fill and resolve to more columns than the template suggests.
   ========================================================================== */

/* ── Applies at any width ─────────────────────────────────────────────────
   Gaps and the image box, neither of which depends on having room for
   columns. */

@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {

    /* Header — gaps become margins. */
    .wh-header__brand { margin-right: 2rem; }
    .wh-nav__trigger { margin-right: 1.25rem; }
    .wh-nav__item { margin-right: 1.25rem; }
    .wh-nav__item:last-child { margin-right: 0; }
    .wh-header__phone { margin-right: 0.75rem; }

    /* Product card image.
       `aspect-ratio` is unsupported, so the media box has no height of its own
       and the picture grows to whatever it likes — the worst artefact in the
       capture. A fixed box with a centred, unscaled image reproduces
       `object-fit: contain` closely enough. */
    .wh-card__media { height: 240px; }

    .wh-card__media img {
        position: absolute;
        top: 50%;
        left: 50%;
        -ms-transform: translate(-50%, -50%);
        transform: translate(-50%, -50%);
        width: auto;
        height: auto;
        max-width: 100%;
        max-height: 100%;
        padding: 0.5rem;
    }

    .wh-card__body > * { margin-bottom: 0.5rem; }

    /* Vertical flex gaps inside tiles and panels. */
    .wh-cat-tile > * { margin-bottom: 0.75rem; }
    .wh-cat-tile > *:last-child { margin-bottom: 0; }

    /* Without the gap the 8px rule drawn by ::before collides with its label
       and reads as a stray mark above the text. */
    .wh-cat-tile__child::before { margin-right: 0.5rem; }

    /* Hero slides — why the slider renders as empty space.

       `.wh-hero` establishes its stacking context with `isolation: isolate`,
       which IE does not implement, and `position: relative` alone does not
       create one. The slide layer at `z-index: -2` therefore escapes into the
       root stacking context and is painted behind the opaque `body`
       background: the photographs load, they are just underneath the page.

       Fixed by giving `.wh-hero` a context IE does recognise — `position:
       relative` plus an explicit `z-index` — and rebuilding the same order out
       of non-negative values. */
    .wh-hero { z-index: 0; }
    .wh-hero__stage { z-index: 0; }
    .wh-hero__scrim { z-index: 1; }
    .wh-hero__inner { z-index: 2; }

    /* The ambient blobs are circles that only become a field through
       `filter: blur(90px)`. Unblurred they are three hard discs, so the layer
       is better off absent. It is invisible in IE today only because it too
       sits at a negative z-index; this makes that intentional. */
    .wh-aurora { display: none; }

    /* Single-column-by-default grids only need their gaps back. */
    .wh-product > * { margin-bottom: 2.5rem; }
    .wh-contacts > * { margin-bottom: 3rem; }
    .wh-terms-band__inner > * { margin-bottom: 2rem; }
}

/* ── Columns — only where there is room for them ──────────────────────────
   Below this width the stacked layout is the mobile design rather than a
   defect, and narrow floats would be worse than no floats.

   Floats, not inline-block: no whitespace gaps to fight. Cards are uneven in
   height, so each row's first cell clears — without that a tall card snags the
   next one and the grid staircases. */

@media all and (-ms-high-contrast: none) and (min-width: 820px),
       (-ms-high-contrast: active) and (min-width: 820px) {

    .wh-grid,
    .wh-cat-tiles,
    .wh-hero__facts,
    .wh-listing__body,
    .wh-mega__inner,
    .wh-mega__grid,
    .wh-footer__grid { display: block; }

    .wh-grid::after,
    .wh-cat-tiles::after,
    .wh-hero__facts::after,
    .wh-listing__body::after,
    .wh-mega__inner::after,
    .wh-mega__grid::after,
    .wh-footer__grid::after {
        content: "";
        display: block;
        clear: both;
    }

    /* Product grid. The hairlines normally come from the container showing
       through the gap; without gap they have to be the cells' own borders. */
    .wh-grid > * {
        float: left;
        width: 50%;
        min-height: 380px;
        border-right: 1px solid rgba(255, 255, 255, 0.075);
        border-bottom: 1px solid rgba(255, 255, 255, 0.075);
    }

    .wh-grid > *:nth-child(2n+1) { clear: left; }

    /* The `:nth-child(n)` on the resets is not decoration: the two-column
       `clear` above is a class plus a pseudo-class, so a plain `.wh-grid--4 > *`
       loses to it on specificity and every third card would still break the
       row. */
    .wh-grid--3 > * { width: 33.333%; }
    .wh-grid--3 > *:nth-child(n) { clear: none; }
    .wh-grid--3 > *:nth-child(3n+1) { clear: left; }

    .wh-grid--4 > * { width: 25%; }
    .wh-grid--4 > *:nth-child(n) { clear: none; }
    .wh-grid--4 > *:nth-child(4n+1) { clear: left; }

    /* The list layout is a single column in every browser by design. */
    .wh-grid--list > * { float: none; width: auto; min-height: 0; }
    .wh-grid--list > *:nth-child(n) { clear: none; }

    /* Category tiles resolve to five auto-filled columns at 1366px. Four is
       the deliberate choice here: it holds up from 1024px — the width these
       machines actually run at — without squeezing long category names. */
    .wh-cat-tiles > * {
        float: left;
        width: 25%;
        min-height: 240px;
        border-right: 1px solid rgba(255, 255, 255, 0.075);
        border-bottom: 1px solid rgba(255, 255, 255, 0.075);
    }

    .wh-cat-tiles > *:nth-child(4n+1) { clear: left; }

    /* Hero facts — three of them, one row. */
    .wh-hero__facts > * {
        float: left;
        width: 33.333%;
        border-right: 1px solid rgba(255, 255, 255, 0.075);
    }

    /* Catalogue listing — facets beside the results, not stacked above them. */
    .wh-listing__sidebar {
        float: left;
        width: 232px;
        padding-right: 1.25rem;
    }

    .wh-listing__results { margin-left: 232px; }

    /* Mega menu. */
    .wh-mega__rail { float: left; width: 264px; }
    .wh-mega__panels { margin-left: 264px; }

    .wh-mega__grid > * {
        float: left;
        width: 33.333%;
        padding-right: 1.5rem;
        margin-bottom: 1.25rem;
    }

    .wh-mega__grid > *:nth-child(3n+1) { clear: left; }

    /* Footer. */
    .wh-footer__grid > * {
        float: left;
        width: 33.333%;
        padding-right: 2rem;
    }

    .wh-footer__grid > *:nth-child(3n+1) { clear: left; }
}

