/* ============================================================
   TECP Single Product — full-screen layouts (Phase 2)
   Glass info panel consumes popups.css tokens (--tecp-pop-*) so it
   follows the global glass/white switch. SKELETON — visual polish later.
   ============================================================ */

.tecp-sp { font-family: Verdana, Geneva, sans-serif; }

/* --- stage (image area) --- */
.tecp-sp-stage {
    position: relative;
    width: 100%;
    height: var(--tecp-sp-img-h, 580px);
    overflow: hidden;
    background: #0c0a08;
}

/* landscape main image */
.tecp-sp-main {
    position: absolute;
    inset: 0;
    z-index: 0;
    background-size: cover;
    background-position: center;
}
/* crossfade overlay: new image fades/slides in over the old → no black flash */
.tecp-sp-fx {
    z-index: 1;
    opacity: 0;
    pointer-events: none;
}

/* portrait: blurred bg + centred image */
.tecp-sp-port-bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    background-size: cover;
    background-position: center;
    filter: blur(40px);
    transform: scale(1.3);
    opacity: 0.4;
}
.tecp-sp-main-port {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: var(--tecp-sp-port-w, 38%);
    z-index: 1;
    background-size: cover;
    background-position: center;
}

/* --- slider arrows --- */
/* --- shared filled chevron (slider arrows + panel toggle) --- */
.tecp-sp-chevron { display: block; }
.tecp-sp-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 6;
    color: rgba(255, 255, 255, 0.55);
    cursor: pointer;
    transition: color 0.25s;
    user-select: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
}
.tecp-sp-arrow:hover { color: #fff; }
.tecp-sp-prev { left: 16px; }
.tecp-sp-next { right: 16px; }
.tecp-sp-prev .tecp-sp-chevron { transform: rotate(180deg); }  /* points left */

/* --- thumbnail strips --- */
/* landscape: strip BELOW the image (not overlaid). 6 thumbs across, full width. */
.tecp-sp-thumbs-h {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 8px;
    margin-top: 8px;   /* gap from hero = gap between thumbs */
    padding: 0;
    background: none;
}
.tecp-sp-thumbs-h .tecp-sp-thumb {
    width: 100%;
    aspect-ratio: 16 / 9;   /* match the 16:9 photos → contain fills, no letterbox
                               (so visual gap from hero == gap between thumbs) */
}
.tecp-sp-thumbs-v {
    position: absolute;
    left: 24px; top: 28px; bottom: 28px;
    z-index: 4;
    display: flex;
    flex-direction: column;
    gap: 8px;
    justify-content: center;
}
.tecp-sp-thumbs-v .tecp-sp-thumb {
    width: var(--tecp-sp-thumb-w, 50px);
    aspect-ratio: 3 / 4;
}
.tecp-sp-thumb {
    background-size: contain;         /* full thumbnail, no zoom/crop */
    background-repeat: no-repeat;
    background-position: center;
    border: none;                    /* no frame, no dim — thumbnails stay clean */
    cursor: pointer;
}

/* --- glass info panel (tokens → glass/white switch) --- */
.tecp-sp-panel {
    position: absolute;
    right: 5rem;    /* 5rem gap from the image right edge (panel keeps its 28% width → shifts left) */
    top: 5rem;
    z-index: 5;
    width: var(--tecp-sp-panel-w, 28%);
    /* base colour — settings: Product page → "Panel colour" + opacity (default ≈ #FFFFFF21) */
    background: var(--tecp-sp-panel-bg, #FFFFFF21);
    /* backdrop blur — settings control, default 0 (site standard keeps blur for
       pop-ups only, §3 — this control is a deliberate owner-managed exception) */
    -webkit-backdrop-filter: blur(var(--tecp-sp-panel-blur, 0px));
    backdrop-filter: blur(var(--tecp-sp-panel-blur, 0px));
    padding: 3.5rem;   /* uniform inner margins (content higher again) */
    overflow-y: auto;
    display: flex;
    flex-direction: column;
}
/* Elementor-style background overlay: a tinted layer ABOVE the panel background but
   BELOW the content — lifts the panel off bright photos without darkening the text.
   Colour/opacity from settings (--tecp-sp-panel-ov; alpha 0 = off). */
.tecp-sp-panel::before {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--tecp-sp-panel-ov, transparent);
    pointer-events: none;
    z-index: 0;
}
/* SECOND glass sheet (owner 2026-07-05, layering experiment): an extra independently
   styled pane under the whole panel — its own colour/opacity/blur on top of the panel
   knobs. A pseudo-element SHARES the panel's box (inset:0), so it is pixel-locked to
   the panel through every animation (collapse/expand/resize) by definition — separate
   sibling elements would drift. Stack: photo → panel bg → THIS sheet → tint(::before)
   → content. Its backdrop-filter still samples the photo (the flat panel bg above it
   in paint order blurs to itself). alpha 0 = off. */
.tecp-sp-panel::after {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--tecp-sp-panel-under, transparent);
    -webkit-backdrop-filter: blur(var(--tecp-sp-panel-under-blur, 0px));
    backdrop-filter: blur(var(--tecp-sp-panel-under-blur, 0px));
    pointer-events: none;
    z-index: -1;
}
.tecp-sp-panel > * { position: relative; z-index: 1; }
.tecp-sp-landscape .tecp-sp-panel { bottom: 5rem; }
.tecp-sp-portrait  .tecp-sp-panel { bottom: 5rem; }
/* collapse: cubic-bezier for snappier feel; overflow controlled by JS during expand */
.tecp-sp-panel { transition: max-height 0.45s cubic-bezier(0.4, 0, 0.2, 1), padding 0.45s ease; }
.tecp-sp-panel.collapsed { padding-top: 0 !important; padding-bottom: 0 !important; overflow: hidden !important; }

/* ════════════ PANEL STYLE PRESETS — settings: Product page → "Panel style" ════════════
   `current` (no preset class effect) stays knob-driven via --tecp-sp-panel-* vars.
   The four presets below are self-contained comparison looks: each sets its own
   background/overlay/blur with direct values (selector specificity 0,2,0 beats the
   var-based `.tecp-sp-panel` rule 0,1,0), so the colour/opacity/overlay/blur knobs
   are intentionally ignored while a preset is active. Owner-managed exception to the
   blur-on-pop-ups-only rule (§3). To tune a preset, edit its values here. */

/* A · GLASS — white frosted glass + a subtle dark tint (keeps the light glass feel,
   but the frost + tint lift it off bright photos). Light text (unchanged tokens). */
.tecp-sp-pstyle-glass .tecp-sp-panel {
    background: rgba(255, 255, 255, 0.10);
    -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
}
.tecp-sp-pstyle-glass .tecp-sp-panel::before { background: rgba(0, 0, 0, 0.22); }

/* B · DARK — dark translucent card. White text already contrasts → no token flip.
   Reads on ANY photo (bright or dark). Owner's favourite. */
.tecp-sp-pstyle-dark .tecp-sp-panel {
    background: rgba(14, 11, 9, 0.58);
    -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
}
.tecp-sp-pstyle-dark .tecp-sp-panel::before { background: transparent; }

/* D · MINIMAL — near-invisible panel; readability comes from a bottom gradient scrim
   (::before) + a soft text shadow on all panel text. Lightest look, closest to Melani. */
.tecp-sp-pstyle-minimal .tecp-sp-panel {
    background: transparent;
    -webkit-backdrop-filter: none; backdrop-filter: none;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}
.tecp-sp-pstyle-minimal .tecp-sp-panel::before {
    background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.10) 35%, rgba(0, 0, 0, 0.42) 100%);
}

/* ── E / F / G — UNIFORM FAMILY ──────────────────────────────────────────────
   F and G hardcode a solid #FFFFFF21 panel — their chips / glow are the point, so the
   base stays fixed. E is the FULLY EDITABLE one: it does NOT override bg / blur /
   overlay, so it falls through to the var-driven base `.tecp-sp-panel` rule and every
   control drives it (Panel colour, opacity, Backdrop blur, Overlay colour/opacity) —
   plus the Text shadow control added below. Default knob values = #FFFFFF / 13% / 0 blur
   / 0 overlay, so E still looks like the uniform #FFFFFF21 panel until you change them. */
.tecp-sp-pstyle-backing .tecp-sp-panel,
.tecp-sp-pstyle-glow .tecp-sp-panel {
    background: rgba(255, 255, 255, 0.13);   /* = #FFFFFF21 */
    -webkit-backdrop-filter: none; backdrop-filter: none;
}
/* F/G keep the overlay layer OFF so it doesn't muddy the chips / glow. */
.tecp-sp-pstyle-backing .tecp-sp-panel::before,
.tecp-sp-pstyle-glow .tecp-sp-panel::before { background: transparent; }
/* E text shadow — soft dark halo on the panel text (offset/blur fixed like D, alpha
   driven by the "Text shadow (%)" control → var --tecp-sp-text-shadow-a). alpha 0 = off. */
.tecp-sp-pstyle-uniform .tecp-sp-panel { text-shadow: 0 1px 6px rgba(0, 0, 0, var(--tecp-sp-text-shadow-a, 0)); }

/* E · dark text test — flip the panel content tokens (--tecp-pop-*) to a dark scheme so
   you can compare dark-on-light vs the default light text. Driven by the "Panel text"
   control. Dark text also kills the text shadow (a dark halo under dark text is muddy).
   Buttons keep their own styling for now — these tokens only drive the text elements. */
.tecp-sp-pstyle-uniform.tecp-sp-ptext-darkgrey .tecp-sp-panel {
    --tecp-pop-text: #2b2b2b;
    --tecp-pop-text-muted: rgba(43, 43, 43, 0.72);
    --tecp-pop-text-faint: rgba(43, 43, 43, 0.5);
    --tecp-pop-sep: rgba(0, 0, 0, 0.18);
}
.tecp-sp-pstyle-uniform.tecp-sp-ptext-black .tecp-sp-panel {
    --tecp-pop-text: #111111;
    --tecp-pop-text-muted: rgba(17, 17, 17, 0.72);
    --tecp-pop-text-faint: rgba(17, 17, 17, 0.5);
    --tecp-pop-sep: rgba(0, 0, 0, 0.22);
}
.tecp-sp-pstyle-uniform.tecp-sp-ptext-darkgrey .tecp-sp-panel,
.tecp-sp-pstyle-uniform.tecp-sp-ptext-black .tecp-sp-panel { text-shadow: none; }


/* F · BACKING — a dark chip hugging each text block (width:fit-content keeps the chip
   tight to the text, not the full panel). White text on the dark chip reads on ANY
   photo; the trade-off is dark patches inside the light panel. Tune: chip alpha 0.34. */
.tecp-sp-pstyle-backing .tecp-sp-name,
.tecp-sp-pstyle-backing .tecp-sp-price,
.tecp-sp-pstyle-backing .tecp-sp-stock,
.tecp-sp-pstyle-backing .tecp-sp-label,
.tecp-sp-pstyle-backing .tecp-sp-desc {
    background: rgba(0, 0, 0, 0.34);
    width: -moz-fit-content;
    width: fit-content;
    max-width: 100%;
    padding: 2px 7px;
}

/* G · GLOW — a dark halo on the letters themselves (text-shadow inherits to all panel
   text). The panel stays clean and light; readability comes purely from the glow.
   Subtler than F, but weaker on very bright / busy photos. Tune: the two shadows. */
.tecp-sp-pstyle-glow .tecp-sp-panel {
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.75), 0 0 2px rgba(0, 0, 0, 0.55);
}

/* C · AUTO — JS samples the photo behind the panel and toggles .tecp-panel-on-light.
   dark photo → dark panel + light text (default); light photo → light panel + dark text
   (content tokens flipped). transition softens the swap between slides. */
.tecp-sp-pstyle-auto .tecp-sp-panel {
    background: rgba(14, 11, 9, 0.55);
    -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
    transition: background 0.4s ease;
}
.tecp-sp-pstyle-auto .tecp-sp-panel::before { background: transparent; }
.tecp-sp-pstyle-auto .tecp-sp-panel.tecp-panel-on-light {
    background: rgba(255, 255, 255, 0.64);
    --tecp-pop-text: #1a1714;
    --tecp-pop-text-muted: rgba(20, 18, 16, 0.66);
    --tecp-pop-text-faint: rgba(20, 18, 16, 0.46);
    --tecp-pop-sep: rgba(0, 0, 0, 0.16);
}

/* panel toggle — in the STAGE (stays put when the panel collapses), placed
   where the × close used to be: top-right corner of the panel. */
.tecp-sp-panel-toggle {
    position: absolute;
    top: calc(5rem + 18px);                  /* 18px below the panel top — same line as player controls */
    right: calc(5rem + 18px);                /* 18px inside the panel top-right corner (asymmetric: stays in the corner) */
    z-index: 7;
    background: none; border: none;
    color: rgba(255, 255, 255, 0.55);
    cursor: pointer;
    padding: 6px;
    display: flex;
    transition: color 0.25s;
}
.tecp-sp-panel-toggle:hover { color: #fff; }
/* open → chevron up (▲ = collapse); collapsed → down (▼ = expand) */
.tecp-sp-panel-toggle .tecp-sp-chevron { transform: rotate(-90deg); transition: transform 0.3s; }
.tecp-sp-panel-toggle.is-collapsed .tecp-sp-chevron { transform: rotate(90deg); }

/* ── slideshow controls — panel top-left, level with the collapse chevron ── */
.tecp-sp-autoplay-controls {
    position: absolute;
    top: 18px;                  /* higher again (previous value) */
    left: calc(3.5rem - 5px);   /* glyph left edge = content left edge — stays aligned left */
    z-index: 7;
    display: flex;
    align-items: center;
    gap: 2px;
}
.tecp-sp-ac-btn {
    background: none; border: none; padding: 5px; cursor: pointer;
    color: rgba(255, 255, 255, 0.55);
    display: flex; align-items: center; justify-content: center;
    transition: color 0.25s;
}
.tecp-sp-ac-btn:hover { color: #fff; }
.tecp-sp-ac-prev .tecp-sp-chevron { transform: rotate(180deg); }   /* point left */
/* play/pause icon swap (data-playing on the wrapper) */
.tecp-sp-autoplay-controls[data-playing="false"] .tecp-sp-ac-pause,
.tecp-sp-autoplay-controls[data-playing="true"]  .tecp-sp-ac-play { display: none; }
.tecp-sp-autoplay-controls[data-playing="false"] .tecp-sp-ac-play,
.tecp-sp-autoplay-controls[data-playing="true"]  .tecp-sp-ac-pause { display: block; }
/* highlight the active running direction — follows the contrast (light photo →
   dark highlight, dark photo → light highlight), so it switches with the others. */
.tecp-sp-autoplay-controls[data-direction="left"][data-playing="true"]  .tecp-sp-ac-prev,
.tecp-sp-autoplay-controls[data-direction="right"][data-playing="true"] .tecp-sp-ac-next { color: #fff; }
.tecp-sp-autoplay-controls.tecp-on-light[data-direction="left"][data-playing="true"]  .tecp-sp-ac-prev,
.tecp-sp-autoplay-controls.tecp-on-light[data-direction="right"][data-playing="true"] .tecp-sp-ac-next { color: rgba(0, 0, 0, 0.85); }

/* ── two-colour auto-contrast over the photo (set by JS luminance sampling per
   image — NOT mix-blend, which produced infinite computed greys). Default = light
   (on dark photos); .tecp-on-light = dark (on light photos). Each keeps a hover.
   Exactly one light tone on dark, one dark tone on light. ---------------------- */
.tecp-sp-arrow.tecp-on-light,
.tecp-sp-panel-toggle.tecp-on-light { color: rgba(0, 0, 0, 0.55); }
.tecp-sp-arrow.tecp-on-light:hover,
.tecp-sp-panel-toggle.tecp-on-light:hover { color: rgba(0, 0, 0, 0.85); }
.tecp-sp-autoplay-controls.tecp-on-light .tecp-sp-ac-btn { color: rgba(0, 0, 0, 0.55); }
.tecp-sp-autoplay-controls.tecp-on-light .tecp-sp-ac-btn:hover { color: rgba(0, 0, 0, 0.85); }

/* ── separators inside the panel ── */
.tecp-sp-sep {
    width: 100%;
    height: 1px;
    background: var(--tecp-pop-sep);
    margin: 20px 0;   /* = widget separator standard (1.25rem, 20px both sides — cart/checkout product items) */
    flex-shrink: 0;
}

/* name → page-title typography (.tecp-w-title standard, §3): Verdana 20px / weight 400 /
   letter-spacing 5.5px / lowercase / line-height 1.5. Colour left as-is (tuned later). */
.tecp-sp-name {
    font-family: Verdana, Geneva, sans-serif;
    font-size: 18px;
    font-weight: 400;
    letter-spacing: 1.5px;
    text-transform: none;   /* natural product-name casing (capitalised as stored) */
    line-height: 1.5;
    color: var(--tecp-pop-text);
    margin-bottom: 4px;
}
/* price → section-header typography (.tecp-w-label standard): Verdana 13px / 2px. */
.tecp-sp-price {
    font-family: Verdana, Geneva, sans-serif;
    font-size: 13px;
    letter-spacing: 2px;
    color: var(--tecp-pop-text-muted);   /* #FFFFFF80 (0.5) */
    margin-bottom: 0;
}
/* "price including tax" suffix — WC wraps it in <small> (browser default ~10.8px,
   inherits the price's 2px). Pinned to an explicit 11px/1px so it's deterministic.
   Colour inherits #FFFFFF80 from .tecp-sp-price. */
.tecp-sp-price .woocommerce-price-suffix {
    font-size: 11px;
    letter-spacing: 1px;
}
.tecp-sp-price .woocommerce-Price-amount {
    font-size: 13px;   /* "£65.00" amount = 13px (same as collection); suffix "price including tax" stays 11px (2026-06-19) */
}
.tecp-sp-group { margin-bottom: 12px; }
/* low-stock notice ("only N left") */
.tecp-sp-stock {
    font-size: 11px;
    letter-spacing: 1px;
    color: var(--tecp-pop-text-muted);   /* #FFFFFF80 (0.5) */
    margin-bottom: 12px;
    text-transform: lowercase;
}
.tecp-sp-label {
    font-size: 13px;   /* section-header style (like site .tecp-w-label) — distinct from 11px disclaimers ("only N left") */
    color: var(--tecp-pop-text-muted);   /* #FFFFFF80 (0.5) — unified (was faint 0.4) */
    margin-bottom: 6px;
    letter-spacing: 2px;
}
/* selected colour/size annotation on the 13px header — 11px, like the price suffix (2026-06-19) */
.tecp-sp-label-value {
    font-size: 11px;
    letter-spacing: 1px;
}
/* sizes: natural left-aligned flow, exact 16px gaps, first button on the start line. */
.tecp-sp-sizes { display: flex; gap: 16px; flex-wrap: wrap; }
.tecp-sp-size {
    padding: 0;
    background: none;                 /* no boxes — plain text sizes */
    color: var(--tecp-pop-text-muted);   /* #FFFFFF80 (0.5) */
    font-size: 12px;
    letter-spacing: 1px;
    border: none;
    cursor: pointer;
    transition: color 0.2s;
    -webkit-appearance: none; appearance: none;
}
.tecp-sp-size:hover { color: var(--tecp-pop-text); }
.tecp-sp-size.active {
    color: var(--tecp-pop-text);
    text-decoration: underline;
    text-underline-offset: 5px;
    text-decoration-thickness: 1px;
}
/* OOS sizes ARE selectable (→ waitlist), so keep the interactive pointer like any
   other size — never not-allowed (a "blocked" cursor stops users from clicking to
   discover the waitlist). Line-through + dim still signals it's out of stock. */
.tecp-sp-size.oos { opacity: 0.4; text-decoration: line-through; cursor: pointer; }
.tecp-sp-size.oos:hover { opacity: 0.6; }

/* swatches start flush at the top of their box, while the size text sits ~3px lower in
   its line-box (line-height leading). Push the swatches down by that leading so the gap
   below the "colour" label visually matches the gap below "size". padding-top (NOT
   margin-top — that would collapse into the label's margin-bottom and do nothing). */
.tecp-sp-colours { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; padding-top: 4px; }
.tecp-sp-colour {
    width: 11px; height: 11px;             /* minimal, Melani-like */
    border: none;   /* solid single-colour fill — ring only on selection (.active outline) */
    border-radius: 50%;
    cursor: pointer;
    background-size: cover; background-position: center;
    display: inline-block;
    transition: box-shadow 0.2s, transform 0.2s;
}
.tecp-sp-colour:hover { transform: scale(1.15); }
/* selected swatch — white ring set a few px OFF the swatch (outline-offset makes a true
   gap that shows the photo/panel behind, since the panel is translucent — unlike the
   gallery, which fakes the gap with a white ring on its solid white card). */
/* SAME ring as gallery/filter — colours inverted for the dark panel: 2px dark gap +
   1px white ring → 17px outer, perfectly centred (box-shadow). Replaces the outline
   (read as thin/off-centre vs the box-shadow rings elsewhere). */
.tecp-sp-colour.active { box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.65), 0 0 0 3px #fff; outline: none; }

/* short description — ALWAYS OPEN (owner decision 2026-06-20): no toggle, no +/−. It's the LAST
   panel element; flex:1 fills from 25px below wishlist/sizes down to the panel's 3.5rem bottom
   padding (= "3.5rem from the panel bottom"). Overflow scrolls INSIDE the box. When express
   expands, the flex re-layout SHRINKS this box automatically (the only transformation) — pure CSS,
   no JS height math. */
.tecp-sp-desc-wrap {
    margin-bottom: 0;
    flex: 1 1 auto;        /* fill the remaining panel height */
    min-height: 0;         /* allow shrinking below content → the BOX scrolls, not the panel */
    display: flex;
    flex-direction: column;
}
.tecp-sp-desc {
    font-size: 12px;
    letter-spacing: 1px;
    color: var(--tecp-pop-text-muted);   /* #FFFFFF80 (0.5) */
    line-height: 1.6;
    margin: 0;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;        /* keep the wheel INSIDE the description — don't chain to the panel */
    text-wrap: pretty;                   /* fewer widows/orphans (Chrome 117+/FF 121+; harmless fallback) */
    scrollbar-width: thin;               /* Firefox */
    scrollbar-color: rgba(255,255,255,0.25) transparent;
}
.tecp-sp-desc p { margin: 0 0 0.8em; }   /* paragraph spacing (wpautop) */
.tecp-sp-desc p:last-child { margin-bottom: 0; }
.tecp-sp-desc::-webkit-scrollbar { width: 4px; }
.tecp-sp-desc::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.25); }
.tecp-sp-desc::-webkit-scrollbar-track { background: transparent; }

/* 2026-06-19: qty +/- stepper removed — premium PDP buys 1, adjust in the (mini-)cart.
   add-to-cart now fills the row full-width. */
.tecp-sp-cart-row { display: flex; gap: 8px; margin-bottom: 25px; align-items: center; }   /* 2026-06-19: trust section removed → cart-row → sep#2 25px (button box → separator). ⚠️ verify live */
.tecp-sp-addcart {
    flex: 1;
    height: 44px;
    text-align: center;
    background: #FFFFFF21;   /* shared grey — match panel surface, card badge */
    color: rgba(255, 255, 255, 0.5);
    font-family: Verdana, Geneva, sans-serif;
    font-size: 13px;
    letter-spacing: 2px;   /* site button standard — 13px/2px (matches .tecp-w-contact-submit) */
    cursor: pointer;
    transition: all 0.3s;
    border: none; -webkit-appearance: none; appearance: none;
}
.tecp-sp-addcart:hover { background: rgba(255, 255, 255, 0.25); color: #fff; }
.tecp-sp-addcart.disabled { opacity: 0.4; pointer-events: none; }

/* ── Express checkout buttons — EXACT MIRROR of cart (.tecp-w-express-inner) ───
   PPCP product-page output (display_paypal_button_product_page):
     .ppcp-button-container
        > #ppcp_product                       (PayPal — .paypal-buttons inside)
        + .google-pay-container.product       (GPay)
        + .apple-pay-container.product        (Apple Pay — Safari only)
   Same treatment as cart: container display:contents → the 3 children join the
   flex row directly; #ppcp_product stays a flex item (NOT contents) and the
   .paypal-buttons inside it is forced to 100%×44px. */
.tecp-sp-express {
    width: 100%;
    /* CURTAIN model (owner spec): the wrap animates ONLY the buttons. The 25px gap ABOVE the buttons
       is static on the toggle (outside the wrap) so it's never an animated empty band. The 25px gap
       BELOW the buttons lives here (margin-bottom, inside the wrap) → revealed LAST, after the
       buttons, so the buttons still appear first. zoid adds ~10px bottom slack → 15 gives 25px ink. */
    margin: -10.5px 0 15px;   /* margin-top -10.5 CLIPS PayPal's ~10.5px empty space ABOVE the visible button
                                 (it sits above the wrap-top → clipped) so the button itself rises to the wrap top
                                 = exactly where the separator descends to. Open text→buttons 35.5 → 25. No mask.
                                 margin-bottom 15 → below-gap 25 (15 + ~10 bottom slack). */
}

/* ── express reveal — CURTAIN (owner spec 2026-06-20) ────────────────────────
   Collapsed: toggle, 25px static gap (toggle margin-bottom), then the 0-height wrap sits right at
   sep#3. Click → ONLY the wrap (buttons + below-gap) animates 0→full; sep#3 descends like a curtain
   (69px = 44 buttons + 25 below-gap). The above-gap never moves → no "mask", no collapse desync. */
.tecp-sp-express-reveal {
    margin-top: 25px;       /* sep#2 → "express checkout" text (owner: 22→25) */
    margin-bottom: 0;       /* sep#3 sits directly after the wrap — gaps live on toggle (above) + express (below) */
}
.tecp-sp-express-toggle {
    display: block; width: 100%; text-align: center;
    background: none; border: none; padding: 0; cursor: pointer;
    font-family: Verdana, Geneva, sans-serif;
    font-size: 13px; letter-spacing: 2px; text-transform: lowercase;
    color: var(--tecp-pop-text-muted);   /* #FFFFFF80 */
    margin-bottom: 25px;    /* STATIC above-gap (owner: 14→25). Always present (collapsed + open), NOT animated
                               → never an empty band, never desyncs. */
    transition: color 0.25s;
}
.tecp-sp-express-toggle:hover { color: #ffffff; }              /* #FFFFFFFF — interactive cue without an arrow */
.tecp-sp-express-wrap {
    max-height: 0; overflow: hidden;
    transition: max-height 0.45s cubic-bezier(0.4, 0, 0.2, 1);   /* match the glass-panel collapse speed/easing */
}
/* Open height driven by JS inline max-height, mirroring the panel-collapse pattern EXACTLY:
   set explicit FROM px → reflow → TO px, then 'none'. (Earlier stall was CSS-value→inline; the
   panel works with this same transition because it animates inline→inline.) */

/* The .ppcp-button-container IS the flex row (order-pay pattern). NOT display:contents
   — woocommerce_after_add_to_cart_form has more hooks than the cart's
   woocommerce_proceed_to_checkout, so sibling elements would otherwise join the flex
   and starve the 3 buttons (collapsed them to 22px). Scoping flex to the container
   guarantees the 3 buttons get the full width regardless of what else is hooked. */
.tecp-sp-express .ppcp-button-container {
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    gap: 6px !important;
    align-items: center !important;   /* centre the 44px buttons in the ~54px flex line
                                         (PayPal zoid makes the line taller). Do NOT pin
                                         the row to 44px+overflow:hidden — that clips the
                                         line from the top and shifts logos up 5px. */
    width: 100% !important;
}

/* All 3 equal width, sharp clip */
.tecp-sp-express .ppcp-button-container .google-pay-container,
.tecp-sp-express .ppcp-button-container .apple-pay-container,
.tecp-sp-express .ppcp-button-container #ppcp_product {
    flex: 1 1 0% !important;
    min-width: 0 !important;
    height: 44px !important;
    display: block !important;
    border-radius: 0 !important;
    overflow: hidden !important;
    clip-path: inset(0 round 0px) !important;
}

/* Order: GPay(1) Apple(2) PayPal(3) */
.tecp-sp-express .ppcp-button-container .google-pay-container { order: 1 !important; }
.tecp-sp-express .ppcp-button-container .apple-pay-container  { order: 2 !important; }
.tecp-sp-express .ppcp-button-container #ppcp_product         { order: 3 !important; }

/* Force iframes/buttons inside to fill containers */
.tecp-sp-express .ppcp-button-container #ppcp_product iframe,
.tecp-sp-express .ppcp-button-container .google-pay-container iframe,
.tecp-sp-express .ppcp-button-container .apple-pay-container iframe,
.tecp-sp-express .ppcp-button-container #ppcp_product .paypal-buttons {
    width: 100% !important;
    height: 44px !important;
    min-height: 44px !important;
    border-radius: 0 !important;
    margin: 0 !important;   /* kill PayPal SDK inline margin-left centering */
}

/* Google Pay: sharp corners on native button + neutralize SDK hover */
.tecp-sp-express .ppcp-button-container .google-pay-container .gpay-card-info-container,
.tecp-sp-express .ppcp-button-container .google-pay-container .gpay-button,
.tecp-sp-express .ppcp-button-container .google-pay-container button.gpay-button,
.tecp-sp-express .ppcp-button-container .google-pay-container button[class*="gpay"] {
    width: 100% !important;
    height: 44px !important;
    min-height: 44px !important;
    border-radius: 0 !important;
    -webkit-border-radius: 0 !important;
    box-shadow: none !important;
    border: none !important;
    outline: none !important;
}
.tecp-sp-express .ppcp-button-container .google-pay-container button::after,
.tecp-sp-express .ppcp-button-container .google-pay-container button::before {
    display: none !important;
    content: none !important;
}
.tecp-sp-express .ppcp-button-container .google-pay-container .gpay-button:hover,
.tecp-sp-express .ppcp-button-container .google-pay-container button.gpay-button:hover,
.tecp-sp-express .ppcp-button-container .google-pay-container button[class*="gpay"]:hover {
    background-color: #000000 !important;
    box-shadow: none !important;
}

/* Apple Pay: sharp corners via CSS custom property (shadow DOM) + direct style.
   apple-pay-button is inline-block by default → force block/100% so it fills. */
.tecp-sp-express .ppcp-button-container .apple-pay-container { background-color: #000 !important; }
.tecp-sp-express .ppcp-button-container .apple-pay-container apple-pay-button {
    --apple-pay-button-border-radius: 0px;
    display: block !important;
    width: 100% !important;
    height: 44px !important;
    min-height: 44px !important;
    max-height: 44px !important;
    border-radius: 0 !important;
    -webkit-border-radius: 0 !important;
    box-shadow: none !important;
    border: none !important;
}

/* PayPal: force the .paypal-buttons wrapper to fill 44px, clip its rounded
   iframe corners, and lay it on brand yellow (hides transparent corners).
   Mirrors the working order-pay treatment. */
.tecp-sp-express .ppcp-button-container #ppcp_product .paypal-buttons {
    height: 44px !important;
    max-height: 44px !important;
    overflow: hidden !important;
    clip-path: inset(0px) !important;
    background-color: #FFC439 !important;
}

/* Hide "Or" separator if PPCP injects one */
.tecp-sp-express .ppcp-proceed-to-checkout-button-separator { display: none !important; }

/* Hide the duplicate Stripe express GPay (we use PPCP GPay) — same as cart */
.tecp-sp-express #wc-stripe-express-checkout-element { display: none !important; }
.tecp-sp-express #wc-stripe-express-checkout-button-separator { display: none !important; }

/* Transparency + hover: all 3 containers */
.tecp-sp-express .ppcp-button-container #ppcp_product,
.tecp-sp-express .ppcp-button-container .google-pay-container,
.tecp-sp-express .ppcp-button-container .apple-pay-container {
    opacity: 0.55 !important;   /* lowered from 0.72 — calm the brand colours so they don't out-shout add-to-cart; bigger gap to hover makes the lift visible */
    transition: opacity 0.3s ease !important;
    border: none !important;
    box-shadow: none !important;
    outline: none !important;
}
.tecp-sp-express .ppcp-button-container #ppcp_product:hover,
.tecp-sp-express .ppcp-button-container .google-pay-container:hover,
.tecp-sp-express .ppcp-button-container .apple-pay-container:hover {
    opacity: 0.9 !important;   /* was 1 — clear hover feedback now that base is 0.5 */
}

/* ── OOS / waitlist state ─────────────────────────────────────────────────
   panel.is-oos (per-size via JS, or simple-OOS server-side):
   hide qty + add-to-cart + express → show "out of order" status + waitlist. */
.tecp-sp-oos-status {
    display: none;
    flex: 1;
    height: 44px;
    align-items: center;
    font-size: 11px;
    letter-spacing: 1px;
    color: var(--tecp-pop-text-muted);
    text-transform: lowercase;
}
/* 2026-06-19 restructure: waitlist now sits AFTER sep#2 (where express was). margin-top
   bridges sep#2 → "sold out!" (express is hidden in OOS so it contributes nothing). */
.tecp-sp-waitlist { display: none; margin-top: 22px; margin-bottom: 25px; }   /* sep#2 → "sold out!" 25px ink (box 22 + ~3 title leading); waitlist btn → sep#3 25px. ink-verified OOS 2026-06-19 */

/* OOS: the "out of stock" notice lives in .tecp-sp-stock (under the sizes, where "only N left"
   sits). Hide the action row (add-to-cart) and express; show the waitlist after sep#2. */
.tecp-sp-panel.is-oos .tecp-sp-cart-row,
.tecp-sp-panel.is-oos .tecp-sp-express-reveal { display: none !important; }
.tecp-sp-panel.is-oos .tecp-sp-waitlist { display: block; }
/* OOS: cart-row hidden → stock ("out of stock") sits directly above sep#2. Its default
   margin-bottom (21.8px → 25px ink to the separator) is exactly what we want, so no override. */

/* Blocksy waitlist form markup (.ct-product-waitlist) — styled to the panel.
   State toggling done here (Blocksy's own CSS isn't enqueued on our template). */
.tecp-sp-waitlist .ct-waitlist-subscribed-state { display: none; }
.tecp-sp-waitlist .ct-product-waitlist[data-state="subscribed"] .ct-waitlist-initial-state { display: none; }
.tecp-sp-waitlist .ct-product-waitlist[data-state="subscribed"] .ct-waitlist-subscribed-state { display: block; }
/* loading (blc_waitlist_sync in flight): hide BOTH states so the "enter your e-mail" form
   doesn't flash for ~1s before "subscribed" resolves when switching to an already-subscribed size. */
.tecp-sp-waitlist .ct-product-waitlist[data-state="loading"] .ct-waitlist-initial-state,
.tecp-sp-waitlist .ct-product-waitlist[data-state="loading"] .ct-waitlist-subscribed-state { display: none; }
/* Subscribed state: the "Great! …" message → unsubscribe gap. The shared .ct-waitlist-message
   margin (16.9px) is tuned for the email-input (a block); unsubscribe is 11px text with extra
   top leading, so trim to keep "Great!…" → unsubscribe at 20px ink. */
.tecp-sp-waitlist .ct-product-waitlist[data-state="subscribed"] .ct-waitlist-message { margin-bottom: 17.3px; }   /* "Great!…" → unsubscribe 25px ink (was 20) */
/* subscribed: unsubscribe (text) → bottom separator 20px — trim vs the in-stock 44px submit button */
.tecp-sp-waitlist:has(.ct-product-waitlist[data-state="subscribed"]) { margin-bottom: 23.8px; }   /* unsubscribe → separator 25px (was 20) */
.tecp-sp-waitlist .ct-waitlist-title {
    font-size: 12px; letter-spacing: 1px; color: var(--tecp-pop-text);
    margin: 0 0 3.4px; font-weight: 400;   /* "sold out!" → "No worries" 10px ink (tuned 2026-06-19) */
}
.tecp-sp-waitlist .ct-waitlist-message {
    font-size: 12px; letter-spacing: 1px; line-height: 1.6; color: var(--tecp-pop-text-muted); margin: 0 0 21.9px;   /* → email field 25px ink (was 20) */
    text-wrap: pretty;   /* wdowy (samotne "stock") — warstwa 1, Chrome; warstwa 2 (FF) = nbsp przez gettext w pliku glownym (2026-07-27) */
}
.tecp-sp-waitlist .ct-product-waitlist-form { display: flex; flex-direction: column; gap: 6px; }   /* email field → button 6px */
.tecp-sp-waitlist .ct-product-waitlist-form input[type="email"] {
    height: 44px; box-sizing: border-box; padding: 12px 16px;
    background: rgba(255,255,255,0.08); border: none; color: #fff;
    font-family: Verdana, Geneva, sans-serif; font-size: 12px; border-radius: 0;
}
.tecp-sp-waitlist .ct-product-waitlist-form input[type="email"]:focus {
    background: rgba(255,255,255,0.15); outline: none;
}
.tecp-sp-waitlist .ct-product-waitlist-form .ct-button {
    height: 44px; display: flex; align-items: center; justify-content: center;
    background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.5);
    border: none; cursor: pointer; border-radius: 0;
    font-family: Verdana, Geneva, sans-serif; font-size: 13px; letter-spacing: 2px;   /* site button standard — 13px/2px */
    text-transform: lowercase;   /* site is all-lowercase (matches "add to cart") */
    transition: all 0.3s;
}
.tecp-sp-waitlist .ct-product-waitlist-form .ct-button:hover {
    background: rgba(255,255,255,0.25); color: #fff;
}
/* Unsubscribe (subscribed state) — transparent text-style button, EÏNN look:
   no fill, lowercase, muted → white on hover. */
.tecp-sp-waitlist .ct-button.unsubscribe {
    display: inline-flex; align-items: center; gap: 6px;
    background: none; border: none; padding: 0; min-height: 0; height: auto; cursor: pointer;   /* kill Blocksy's 40px min-height — it centered the text in a tall box → fake double gaps */
    color: rgba(255,255,255,0.5);
    font-family: Verdana, Geneva, sans-serif; font-size: 11px; letter-spacing: 1px;
    text-transform: lowercase;
    transition: color 0.25s;
}
.tecp-sp-waitlist .ct-button.unsubscribe:hover { color: #fff; }
.tecp-sp-waitlist-error { font-size: 11px; color: rgba(255,120,120,0.9); margin: 8px 0 0; }

.tecp-sp-links { display: flex; gap: 14px; margin-bottom: 0; align-items: center; }   /* center; wraps are flex (below) so no inline strut — wishlist/sizes text tops align (2026-06-19) */
.tecp-sp-link {
    font-size: 11px;
    color: var(--tecp-pop-text-muted);   /* #FFFFFF80 (0.5) — unified */
    cursor: pointer;
}
.tecp-sp-link:hover { color: #ffffff; }
/* Make the wishlist/sizes wraps flex so the embedded inline-flex buttons don't add a
   line-box strut below — otherwise the heart makes the wishlist wrap ~3px taller and
   "sizes" drops below the "wishlist" text. Flex wrap height == button height → text tops align. */
/* wishlist + size guide — OUR OWN controls (Blocksy's output helpers don't exist on the custom
   template; JS wires them to Blocksy's AJAX). Button reset → text-link look (§26.5/§27.4).
   Wraps are inline-flex so the heart adds no line-box strut → wishlist/sizes stay level. */
.tecp-sp-wishlist, .tecp-sp-sizeguide {
    display: inline-flex; align-items: center;
    background: none; border: none; padding: 0; margin: 0; line-height: 1;
    font-family: Verdana, Geneva, sans-serif; font-size: 11px; letter-spacing: 1px; text-transform: lowercase;
    color: var(--tecp-pop-text-muted);   /* #FFFFFF80 (0.5) — unified */
    cursor: pointer; transition: color 0.25s;
}
.tecp-sp-wishlist:hover, .tecp-sp-sizeguide:hover { color: #ffffff; }
.tecp-sp-wishlist { gap: 6px; }
.tecp-sp-heart { width: 14px; height: 14px; display: block; flex-shrink: 0; }   /* EXACT gallery/collection heart (Blocksy 15×15, two paths) */
.tecp-sp-heart path { fill: currentColor; }                                     /* outline + fill follow the link colour */
.tecp-sp-heart .ct-heart-fill { opacity: 0; transition: opacity 0.2s ease; }    /* inner solid heart hidden until added */
.tecp-sp-wishlist.tecp-wished .tecp-sp-heart .ct-heart-fill { opacity: 1; }     /* heart fills when in wishlist (like the gallery) */
.tecp-sp-wishlist.tecp-wished { color: #ffffff; }                               /* added → heart + label BOTH white (like the gallery) */

/* ── size guide modal (our own glass pop-up — §3/§5 pop-up standard) ── */
.tecp-sg-overlay {
    position: fixed; inset: 0; z-index: 100000;
    display: flex; align-items: center; justify-content: center;
    padding: 24px;
    /* entrance like the drawers: dim fades via BACKGROUND-COLOR (not opacity!) —
       parent opacity wraps the blurred modal in a composite group, so the glass
       only "loaded" after the slide finished (owner 2026-07-03: staged look) */
    background-color: rgba(19, 19, 19, 0);
    visibility: hidden; pointer-events: none;
    transition: background-color 0.3s ease, visibility 0s linear 0.3s;
}
.tecp-sg-overlay.open {
    background-color: var(--tecp-pop-overlay-bg);   /* screen dim — settings-driven */
    visibility: visible; pointer-events: auto;
    transition: background-color 0.3s ease;
}
/* SYMMETRIC slide + fade of the WHOLE modal (owner 2026-07-03: the exit fade read
   nicer than the slide-only entrance → entrance now mirrors it). Safe: opacity sits
   on the MODAL itself, not on the overlay parent — the parent-opacity composite
   group was what made the glass "load" after arrival (v3.3.749 lesson). */
.tecp-sg-modal {
    transform: translateY(26px);
    opacity: 0;
    transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
}
.tecp-sg-overlay.open .tecp-sg-modal {
    transform: translateY(0);
    opacity: 1;
}
.tecp-sg-modal {
    position: relative;
    width: 100%; max-width: min(1240px, 94vw); max-height: 85vh; overflow-y: auto;   /* roomy: two equal no-wrap tables + 5rem gap, tables fill so right margin = 5rem */
    /* glass colour + optional filter/tint + blur — same --tecp-pop-* tokens as filter / mini-cart */
    background-color: var(--tecp-pop-panel-bg);
    background-image: linear-gradient(var(--tecp-pop-panel-overlay, transparent), var(--tecp-pop-panel-overlay, transparent));
    -webkit-backdrop-filter: blur(var(--tecp-pop-panel-blur)); backdrop-filter: blur(var(--tecp-pop-panel-blur));
    /* no edge ring / no drop shadow — matches every other pop-up (owner 2026-07-05:
       the old 1px glass edge made sizes the ONLY outlined window) */
    padding: 3.5rem 5rem;   /* large-container margins (like login panel §3) */
    color: #fff;
    font-family: Verdana, Geneva, sans-serif;
}
.tecp-sg-close {
    position: absolute; top: 18px; right: 22px;
    background: none; border: none; cursor: pointer; padding: 0; line-height: 1;
    font-size: 21px; color: var(--tecp-pop-icon);
    transition: color 0.2s ease, transform 0.2s ease;
}
.tecp-sg-close:hover { color: var(--tecp-pop-icon-hover); transform: rotate(90deg); }
.tecp-sg-loading, .tecp-sg-empty { color: rgba(255,255,255,0.6); font-size: 12px; }
.tecp-sg-body .ct-panel-heading { display: none !important; }   /* Blocksy chrome - we render the editor content */
/* readable light text on the dark glass (paragraphs styled separately below) */
.tecp-sg-body, .tecp-sg-body td, .tecp-sg-body th, .tecp-sg-body span, .tecp-sg-body li { color: rgba(255,255,255,0.5) !important; }   /* muted table text (#FFFFFF80) — heading keeps its own white below */
/* light outer frame — !important overrides WP block's has-black-border-color (which is !important). base = light everywhere */
.tecp-sg-body table { border-collapse: collapse; font-size: 12px; border: 1px solid rgba(255,255,255,0.12) !important; }
/* editorial: NO vertical grid (categorically removed), only thin UNIFORM light horizontal rules, airy padding.
   !important so the black WP grid never shows through, regardless of cache/specificity. */
.tecp-sg-body th, .tecp-sg-body td {
    border: none !important;
    border-bottom: 1px solid rgba(255,255,255,0.12) !important;
    padding: 11px 10px; text-align: center; font-weight: 400;
    white-space: nowrap;   /* dense table's text stays on one line; the modal widens to fit */
}
.tecp-sg-body tr:last-child th, .tecp-sg-body tr:last-child td { border-bottom: none !important; }
/* header ROW ONLY: spaced + light glassmorphism bg (NOT the data rows).
   text-transform NONE — respect authored case: "size"/"bust"/"waist"/"hips" lowercase, country codes (UK/US/FR/DE/IT/JP) UPPERCASE. */
.tecp-sg-body thead th {
    text-transform: none; font-size: 11px; letter-spacing: 1.5px;
    background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.5);
}
/* first column (size labels): left-aligned (no glass bg — only the header row has it); colour inherits base #FFFFFF80 */
.tecp-sg-body td:first-child, .tecp-sg-body th:first-child {
    text-align: left; letter-spacing: 1px;
}
/* subtle row highlight on hover (data rows only) */
.tecp-sg-body tbody tr:hover td { background: rgba(255,255,255,0.05); }

/* Multiple tables in one size guide (WP-editor .entry-content): heading + intro full-width on top,
   then the two tables side by side with a 5rem gap. Wraps to stack on narrow screens. */
.tecp-sg-body .entry-content {
    display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: flex-start;
    gap: 0 5rem;                                  /* 5rem between the two tables */
}
.tecp-sg-body .entry-content > p { flex: 1 1 100%; margin: 0; text-align: left; }
.tecp-sg-body .entry-content > p:empty { display: none; }
/* main heading (1st paragraph): white 12px / 1px */
.tecp-sg-body .entry-content > p:first-of-type {
    color: #fff !important; font-size: 12px; letter-spacing: 1px; margin: 0 0 14px;
}
/* longer intro text: #FFFFFF80 11px / 1px. COPY TO BE REDACTED LATER with the other UI texts
   (after the pop-ups; see memory project-language-style). */
.tecp-sg-body .entry-content > p:not(:first-of-type) {
    color: rgba(255,255,255,0.5) !important; font-size: 11px; letter-spacing: 1px; line-height: 1.6; margin: 0 0 28px;
}
/* both tables EQUAL width, filling the row (so the right margin = 5rem, not double).
   width + table-layout forced over WP's has-fixed-layout so the table grows to fill the figure. */
.tecp-sg-body .entry-content > figure.wp-block-table { flex: 1 1 calc(50% - 2.5rem); min-width: 0; margin: 0; }   /* each = half the row minus half the 5rem gap → fills exactly */
.tecp-sg-body .entry-content > figure.wp-block-table > table { width: 100% !important; table-layout: auto !important; }

/* Trust section (.tecp-sp-safe / .tecp-sp-safe-label / .tecp-sp-badges + payment badges)
   REMOVED from the PDP 2026-06-19 — platform/CRO trope, off-brand for a designer store.
   Cart-row now sits directly above sep#2; OOS waitlist directly after sep#2. */

/* collapsed-panel reopen tab */
.tecp-sp-reopen {
    position: absolute;
    right: 0; top: 28px;
    z-index: 5;
    background: var(--tecp-pop-panel-bg);
    -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
    color: var(--tecp-pop-text);
    padding: 10px 8px;
    cursor: pointer;
    font-size: 11px;
    letter-spacing: 1px;
    writing-mode: vertical-rl;
    display: none;
}
.tecp-sp-reopen.visible { display: block; }

/* --- below-fold --- */
/* full width with the gallery's outer margins; description stays narrow for
   readability, the related grid spans full width like the gallery. */
.tecp-sp-below {
    padding: 2.5rem 31px;        /* outer margins ≈ gallery */
    max-width: none;
    margin: 0;
}
.tecp-sp-below-label {
    font-size: 11px;
    letter-spacing: 2px;
    color: #7a7a7a;
    margin-bottom: 12px;
}
/* recently-viewed label sits below the related grid — same section rhythm (2rem) */
.tecp-sp-recent-label { margin-top: 2rem; }
.tecp-sp-below-desc {
    font-size: 13px;
    color: #333;
    line-height: 1.8;
    margin-bottom: 2rem;
    max-width: none;             /* full-width description (2026-06-19) */
}
/* related grid mirrors the gallery: 4 columns, same gaps */
.tecp-sp-related {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 35px 8px;
}
@media (max-width: 1024px) { .tecp-sp-related { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px)  { .tecp-sp-related { grid-template-columns: repeat(2, 1fr); } }
.tecp-sp-related-item { text-decoration: none; }
/* relative wrapper so the hover image can overlay the primary (3:4 cropped card) */
.tecp-sp-related-img { position: relative; aspect-ratio: 3/4; margin-bottom: 8px; overflow: hidden; }
.tecp-sp-related-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* hover-flip: 2nd image fades in over the primary on hover (like gallery cards) */
.tecp-sp-related-img .tecp-sp-related-hover {
    position: absolute; inset: 0;
    opacity: 0;
    transition: opacity 0.35s ease;
}
/* flip only when hovering the IMAGE — hovering the caption/dots must not swap the photo */
.tecp-sp-related-img:hover .tecp-sp-related-hover { opacity: 1; }
/* caption sizes+rhythm (owner 2026-07-02): name 13, gap +6px, price 12,
   suffix EXPLICIT 11px — it's a <small> tag (browser default ~0.8em ≈ 9px
   without a rule; the collection sets it explicitly — that's why they differed) */
.tecp-sp-related-name { font-size: 13px; color: #333; }
.tecp-sp-related-price { font-size: 12px; color: #7a7a7a; margin-top: 3px; }   /* ~4px visible (owner 2026-07-02) */
.tecp-sp-related-price .woocommerce-price-suffix { font-size: 11px; }
/* meta row: texts LEFT, sibling colour dots RIGHT — dots vertically centered
   against the two text lines (owner 2026-07-02). Dots = the gallery swatches
   (11px, no ring at rest, own colour .active double-ring — white-bg variant).
   They are BUTTONS (in-place colour swap like the collection) → full reset.
   ⚠ The whole card is an <a> — the EMPTY strip between the texts and the dots
   must NOT be clickable (owner). pointer-events:none on a CHILD doesn't punch
   a hole in the parent link (the click falls through to the <a> itself) →
   donut pattern: none on the <a>, auto back on image/text/dots. Clicks on the
   re-enabled children bubble to the link as normal. */
.tecp-sp-related-item { pointer-events: none; }
/* dots: ONLY the buttons live — the container's 11px gaps would bubble clicks to the
   card link. ::after pads each dot's hit-area to its full 17px visual ring. */
.tecp-sp-related-img { pointer-events: auto; }
.tecp-sp-related-sw { pointer-events: auto; position: relative; }
.tecp-sp-related-sw::after { content: ''; position: absolute; inset: -3px; }
/* only the TEXT itself is interactive (inline spans hug the glyphs) — a short
   name above a longer price line must not leave a clickable strip in the block */
.tecp-sp-related-name > span, .tecp-sp-related-price > span { pointer-events: auto; }
.tecp-sp-related-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.tecp-sp-related-text { min-width: 0; }
.tecp-sp-related-swatches { display: flex; align-items: center; gap: 14px; flex-shrink: 0; padding-right: 4px; }
.tecp-sp-related-sw {
    width: 11px; height: 11px; border-radius: 50%;
    border: none; padding: 0; margin: 0; cursor: pointer;
    -webkit-appearance: none; appearance: none; outline: none;
    background-size: cover; background-position: center;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.tecp-sp-related-sw:hover { transform: scale(1.12); }
.tecp-sp-related-sw.active { box-shadow: 0 0 0 2px #fff, 0 0 0 3px rgba(0, 0, 0, 0.65); }

/* hover GLASS SIZE PANEL — copied 1:1 from gallery.css (.tecp-loop-size-panel;
   gallery.css does NOT load on single product, hence the scoped copy) */
.tecp-sp-related-img .tecp-loop-size-panel {
    position: absolute; left: 0; right: 0; bottom: 0;
    height: 10%;
    display: flex; justify-content: center; align-items: center; gap: 16px;
    padding: 0 10px;
    background: #FFFFFF21;
    -webkit-backdrop-filter: blur(1.3px); backdrop-filter: blur(1.3px);
    opacity: 0; transform: translateY(100%);
    transition: opacity 0.25s ease, transform 0.25s ease;
    pointer-events: none; z-index: 2;
}
/* size panel only on IMAGE hover (like the flip) — dots/caption must not trigger it */
.tecp-sp-related-img:hover .tecp-loop-size-panel { opacity: 1; transform: translateY(0); }
.tecp-sp-related-img .tecp-loop-size {
    font-family: Verdana, Geneva, sans-serif;
    font-size: 12px; letter-spacing: 1px; text-transform: uppercase;
    color: #ffffff; line-height: 1;
}
.tecp-sp-related-img .tecp-loop-size.oos { color: rgba(255, 255, 255, 0.35); text-decoration: line-through; }

/* ════════ PANEL SPACING — unified VISIBLE gaps (owner spec, 2026-06-15) ════════
   Targets: header→content = 10px, element/section→section = 20px — measured LETTER-to-
   letter, not box-to-box. Panel is flex (no margin collapse) so each gap = one explicit
   margin. Each value = target − (upper bottom line-height leading + lower top leading),
   from measured Verdana leadings (name 2.9/7.1, price 0.8/3.6, label 2.5/3.3-3.6,
   size-btn 3.1/3.4, stock 0.4/3.2, desc 2.7/4.3, wishlist 2.5/3.3; circles/buttons/
   separators = 0). ⚠️ express→wishlist is zoid-estimated (≈5px PayPal slack) — verify all
   with the measurement snippet and fine-tune. Placed last so it overrides the base rules. */
/* ⚠️ 2026-06-19 RESTRUCTURE — new order: name→price→sep→colour→size→stock→cart-row→
   safe(badges)→sep→express→sep→links→desc(clamped). All gaps 25 except header→content 10.
   Values below are starting ink estimates — VERIFY LIVE (in-stock + OOS) and fine-tune. */
.tecp-sp-name { margin-bottom: 3.1px; }                                          /* → price 10px */
.tecp-sp-price { margin-bottom: 23.7px; }                                        /* → separator 25px */
.tecp-sp-sep { margin: 0; }
.tecp-sp-sep-bottom { margin-bottom: 22.4px; }                                    /* sep#3 → wishlist TEXT 25px */
.tecp-sp-price + .tecp-sp-sep { margin-bottom: 21.7px; }                          /* sep#1 → colour 25px */
.tecp-sp-group { margin-bottom: 0; }
.tecp-sp-group:has(.tecp-sp-colours) { margin-bottom: 21.4px; }                  /* swatches → size 25px */
.tecp-sp-group:has(.tecp-sp-sizes)   { margin-bottom: 22.1px; }                  /* size buttons → "only N left" 25px */
/* Well-stocked → "only N left" hidden, so sizes sit directly above the cart-row (boxes).
   Fires ONLY when the stock line is empty. ⚠️ verify live. */
.tecp-sp-group:has(.tecp-sp-sizes):has(+ .tecp-sp-stock:empty) { margin-bottom: 22.5px; }   /* size → cart-row 25px */
.tecp-sp-group:has(.tecp-sp-colours) .tecp-sp-label { margin-bottom: 9.4px; }    /* colour → swatches 10px */
.tecp-sp-group:has(.tecp-sp-sizes)   .tecp-sp-label { margin-bottom: 6.1px; }    /* size → buttons 10px */
.tecp-sp-colours { padding-top: 0; }
.tecp-sp-stock { margin-bottom: 21.8px; }                                        /* stock → cart-row 25px (now under stock, was → desc) */
.tecp-sp-links { margin-bottom: 0; }
.tecp-sp-links:has(+ .tecp-sp-desc-wrap) { margin-bottom: 19px; }                 /* wishlist/sizes → description 25px (now last, relocated) */
/* cart-row → sep#2 lives on .tecp-sp-cart-row margin-bottom (25px). OOS: cart-row + express
   hidden → stock → sep#2 (default stock mb) & sep#2 → waitlist (.tecp-sp-waitlist margin-top). */
