/* ═══════════════════════════════════════════════════════════════════════════════════════════════════
   SINGLE PRODUCT PAGE — brief of 23 Sep 2026, mockup `product-page-mockup.html`
   Tokens come from css/header-footer-global.css. The mockup declares its own (--pt-ink-mute,
   --pt-line-strong, --pt-sunk, --pt-grey); they map to --pt-ink-3, --pt-border-strong,
   --pt-fill-control and --pt-grey-dot here. Nothing is re-declared.
   ═══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* 🔴 FULL WIDTH. `.site-content` is display:flex, so a negative margin alone cannot full-bleed a child —
   it needs a flex basis as well. This is the same fix the shop grid needed on 22 Sep; without it the
   page sits in GeneratePress's narrow left-aligned box with white space down the right (§H9). */
.pt-pp{flex:0 0 100vw;max-width:100vw;margin-left:calc(50% - 50vw);background:var(--pt-surface-dim);color:var(--pt-ink)}
.pt-pp .pp-wrap{max-width:1320px;margin:0 auto;padding:0 32px}

.pt-pp .pp-crumb{font-size:13px;color:var(--pt-ink-3);padding:20px 0 18px}
.pt-pp .pp-crumb a{color:inherit}
.pt-pp .pp-crumb a:hover{color:var(--pt-ink)}
.pt-pp .pp-crumb span{color:var(--pt-border-strong);margin:0 6px}

/* ── TOP: gallery + a panel that stays with you ─────────────────────────────── */
.pt-pp .pp-top{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);gap:48px;align-items:start;padding:0 0 56px}

.pt-pp .pp-gallery{display:grid;grid-template-columns:72px minmax(0,1fr);gap:12px}
/* 🔴 ONE COLUMN when there are no thumbnails. `:only-child` never matched — the gallery has the buy
   panel beside it — so a single-photo product kept the 72px thumb column, the main image became the
   first grid item and landed IN it, and the photo rendered 72x54. The class comes from the template,
   which is the only thing that knows how many photos there are. */
.pt-pp .pp-gallery.is-single{grid-template-columns:minmax(0,1fr)}
.pt-pp .pp-thumbs{display:flex;flex-direction:column;gap:8px}
.pt-pp .pp-thumb{aspect-ratio:1;border:1px solid var(--pt-border);background:var(--pt-fill-control);padding:0;cursor:pointer;overflow:hidden;border-radius:0}
.pt-pp .pp-thumb img{width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply}
.pt-pp .pp-thumb.is-on{border-color:var(--pt-ink)}
.pt-pp .pp-main{position:relative;aspect-ratio:4/3;background:var(--pt-fill-control);border:1px solid var(--pt-border);overflow:hidden}
/* `multiply` so a cut-out photographed on white melts into the panel instead of drawing a second box
   inside the first. The 11% inset stops the product touching the border. */
/* Fills the frame (Leon, 23 Sep). It was inset to 78% for a "product on paper" look, which on a
   4:3 frame left a band of empty grey down every side and made the photo the smallest thing in
   the column. `contain` still means nothing is cropped. */
.pt-pp .pp-main .pp-photo{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply}
.pt-pp .pp-noimg{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}
.pt-pp .pp-tag{position:absolute;top:12px;left:12px;z-index:2;background:var(--pt-brand);color:#fff;font-size:12px;font-weight:600;padding:4px 9px}
.pt-pp .pp-count{position:absolute;right:12px;bottom:12px;z-index:2;background:rgba(26,26,26,.72);color:#fff;font-size:11.5px;padding:3px 7px}
/* 🔴 STATE THE COLOUR ON EVERY LIGHT CONTROL (23 Sep — third one today, after the review-photo "×"
   and the quantity buttons below). GeneratePress styles `button` with white text. Any control we
   give a light background and no `color` inherits that, and an icon drawn with `currentColor` then
   strokes white on white — it renders, it is clickable, and it looks like nothing is there.
   Leon reported this one as "blank like the quantity control icons". */
.pt-pp .pp-zoom{position:absolute;right:12px;top:12px;z-index:2;width:32px;height:32px;display:flex;align-items:center;justify-content:center;background:var(--pt-surface);color:var(--pt-ink);border:1px solid var(--pt-border);cursor:pointer;border-radius:0;padding:0}
.pt-pp .pp-zoom svg{width:15px;height:15px}
.pt-pp .pp-zoom:hover{background:var(--pt-ink);color:var(--pt-surface);border-color:var(--pt-ink)}

/* THE ONE THING THAT MOVES THE NUMBERS on a product page: the price and the button stay with the reader
   through the whole description. */
.pt-pp .pp-buy{position:sticky;top:calc(var(--pt-header-h,64px) + 16px)}
.pt-pp .pp-brand{margin:0 0 8px;font-size:12.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--pt-ink-3)}
.pt-pp .pp-brand a{color:inherit;border-bottom:1px solid var(--pt-border-strong)}
.pt-pp .pp-h1{margin:0 0 10px;font-size:32px;font-weight:700;letter-spacing:-.02em;line-height:1.15}
/* 🔴 THE WHOLE RATING IS ONE LINK (Leon, 23 Sep). It is an inline-flex <a>, not a block, so it is
   exactly as wide as the stars and the numbers — wrapping the row would have swallowed the price. */
.pt-pp .pp-rating{display:inline-flex;align-items:center;gap:6px;margin:0 0 20px;font-size:13px;color:var(--pt-ink-3);text-decoration:none}
.pt-pp .pp-stars{display:flex;gap:2px}
.pt-pp .pp-stars svg{width:14px;height:14px;fill:var(--pt-border-strong)}
.pt-pp .pp-stars svg.on{fill:var(--pt-ink)}
.pt-pp .pp-dot{color:var(--pt-border-strong)}
.pt-pp .pp-score{font-weight:700;color:var(--pt-ink)}
/* The count rides beside the score in brackets, quieter than it — it is context, not the headline. */
.pt-pp .pp-rcount{color:var(--pt-ink-3)}
/* Underline on hover only, and the SCORE never recolours: the number is a fact, not a link label. */
.pt-pp a.pp-rating:hover .pp-rcount,.pt-pp a.pp-rating:focus-visible .pp-rcount{text-decoration:underline;color:var(--pt-ink)}
.pt-pp a.pp-rating:hover,.pt-pp a.pp-rating:focus-visible{color:var(--pt-ink-3)}
.pt-pp a.pp-rating:focus-visible{outline:2px solid var(--pt-ink);outline-offset:3px}

/* Price left, Save hard right, sharing the rule above them (Leon, 23 Sep). `align-items:baseline`
   would drop the heart below the 30px figure, so the row centres and the price keeps its own baseline. */
.pt-pp .pp-priceline{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;padding:16px 0 0;border-top:1px solid var(--pt-ink)}
.pt-pp .pp-priceline .pp-pricerow{padding:0;border-top:0;flex:1 1 auto;min-width:0}
.pt-pp .pp-priceline .pp-save{flex:0 0 auto;margin-left:auto;padding-bottom:4px}
.pt-pp .pp-pricerow{padding:16px 0 0;border-top:1px solid var(--pt-ink);font-family:var(--pt-mono);font-variant-numeric:tabular-nums;font-size:30px;font-weight:600;letter-spacing:-.01em;line-height:1.2}
.pt-pp .pp-pricerow .price{font:inherit;color:inherit;margin:0;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.pt-pp .pp-pricerow del{font-size:15px;color:var(--pt-ink-3);text-decoration:line-through;font-weight:400}
.pt-pp .pp-pricerow ins{text-decoration:none}
.pt-pp .pp-tax{margin:6px 0 0;font-size:12.5px;color:var(--pt-ink-3)}

/* Always rendered, so picking a size never nudges the button down the page. */
.pt-pp .pp-stock{display:flex;align-items:center;gap:8px;min-height:20px;margin:14px 0 0;font-size:13.5px}
.pt-pp .pp-sdot{width:7px;height:7px;border-radius:50%;flex:0 0 auto}
.pt-pp .pp-stock.is-in{color:var(--pt-green-text)}   .pt-pp .pp-stock.is-in  .pp-sdot{background:var(--pt-green-dot)}
.pt-pp .pp-stock.is-low{color:var(--pt-amber-text)}  .pt-pp .pp-stock.is-low .pp-sdot{background:var(--pt-amber-dot)}
.pt-pp .pp-stock.is-out{color:var(--pt-ink-3)}       .pt-pp .pp-stock.is-out .pp-sdot{background:var(--pt-grey-dot)}
.pt-pp .pp-stock:empty,.pt-pp .pp-stock span:empty+span:empty{min-height:20px}

/* ── WooCommerce's own form, restyled ──────────────────────────────────────── */
.pt-pp .pp-form{margin:22px 0 0}
.pt-pp .pp-form .variations{width:100%;border:0;margin:0 0 4px;display:block}
.pt-pp .pp-form .variations tbody,.pt-pp .pp-form .variations tr,.pt-pp .pp-form .variations td,.pt-pp .pp-form .variations th{display:block;border:0;padding:0;width:auto}
.pt-pp .pp-form .variations tr{margin:0 0 18px}
.pt-pp .pp-form .variations label{display:block;font-size:13.5px;font-weight:600;margin:0 0 8px}
/* 🔴 THE WHOLE TABLE GOES, not just the <select>. WooCommerce prints a <th><label>Colour</label></th>
   beside every dropdown; hiding only the select left that label on screen next to the one the chip row
   draws, so every attribute named itself twice with an empty cell between. The markup stays in the form
   — the selects still submit and still hold the state — it just stops being seen.
   With JavaScript off, `has-chips` is never added and the real dropdowns are the control. */
.pt-pp .pp-form.has-chips table.variations,
.pt-pp .pp-form.has-chips .reset_variations{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

.pt-pp .pp-opts{margin:22px 0 0}
.pt-pp .pp-optgrp + .pp-optgrp{margin-top:22px}
.pt-pp .pp-optlabel{display:flex;justify-content:space-between;align-items:baseline;gap:12px;font-size:13.5px;font-weight:600;margin:0 0 8px}
.pt-pp .pp-optlabel em{font-style:normal;font-weight:400;color:var(--pt-ink-3);font-size:12.5px}
.pt-pp .pp-chips{display:flex;gap:6px;flex-wrap:wrap}
.pt-pp .pp-chip{min-width:48px;text-align:center;padding:9px 12px;border:1px solid var(--pt-border-strong);background:var(--pt-surface);color:var(--pt-ink);font:inherit;font-size:13.5px;cursor:pointer;border-radius:0;line-height:1.2}
.pt-pp .pp-chip:hover{background:var(--pt-fill-control)}
.pt-pp .pp-chip.is-on{background:var(--pt-ink);border-color:var(--pt-ink);color:#fff}
/* Out of stock STAYS VISIBLE — people need to see the size exists and has gone. */
.pt-pp .pp-chip[aria-disabled="true"]{color:var(--pt-border-strong);border-color:var(--pt-border-strong);text-decoration:line-through;cursor:not-allowed}
.pt-pp .pp-chip[aria-disabled="true"]:hover{background:var(--pt-surface)}
.pt-pp .pp-chip:focus-visible{outline:2px solid var(--pt-accent);outline-offset:2px}
/* 44px colour squares, per the mockup — only when every value in the group is a colour the browser
   actually understands. A group of half swatches and half words reads as a rendering fault. */
.pt-pp .pp-sw{width:44px;min-width:44px;height:44px;padding:3px}
.pt-pp .pp-sw i{display:block;width:100%;height:100%}
.pt-pp .pp-sw.is-on{border-color:var(--pt-ink);border-width:2px;padding:2px;background:var(--pt-surface)}
/* A struck-through line means nothing on a square of colour, so a gone swatch is dimmed and crossed. */
.pt-pp .pp-sw[aria-disabled="true"]{text-decoration:none;position:relative;opacity:.45}
.pt-pp .pp-sw[aria-disabled="true"]::after{content:"";position:absolute;inset:0;background:linear-gradient(to top right,transparent calc(50% - 1px),var(--pt-ink-3) 50%,transparent calc(50% + 1px))}

.pt-pp .pp-form form.cart{display:grid;grid-template-columns:118px minmax(0,1fr);gap:10px;margin:22px 0 0;align-items:start}
.pt-pp .pp-form form.cart.variations_form{display:block}
.pt-pp .pp-form .woocommerce-variation-add-to-cart{display:grid;grid-template-columns:118px minmax(0,1fr);gap:10px;margin:22px 0 0}
/* 🔴 FOUR CHILDREN IN A THREE-COLUMN GRID (Leon, 24 Sep).
   WooCommerce puts a `<label class="screen-reader-text">` between the minus button and the input, and
   a grid counts it as an item — so minus took column 1, the LABEL took column 2, the input took
   column 3, and `+` wrapped onto a second row at the left. That is exactly what the screenshot shows.
   Two fixes, because either alone is fragile: the label is taken out of flow (it is for screen
   readers, it should never occupy layout), and each control is placed EXPLICITLY, so the layout
   survives WooCommerce adding another node in a future release. */
/* 🔴 THE BOX MUST FIT ITS TRACK. `form.cart` above gives column 1 a FIXED 118px. This was
   `44px minmax(44px,1fr) 44px` with `min-width:132px`, which cannot fit in 118px — so the box
   rendered 132px wide, overflowed the track by 14px, ate the whole 10px gap and overlapped the Add
   button by 4px. Measured in headless Chrome, not guessed: gap was -4px. 36+46+36 = 118 exactly,
   which is the mockup's own split. minmax(0,1fr) on the middle track, never plain 1fr, or the
   input's min-content width pushes the box wide again. [[reference-grid-minmax-zero]]

   🔴 ONE ROW, AND STRAY CHILDREN CANNOT MAKE A SECOND (24 Sep 2026, second pass).
   Leon: correct on first paint, then "margin at the bottom" once JS had run. A bottom-only gap in a
   FIXED-height grid has one classic cause — a child with no explicit placement auto-places into row
   2, and the two rows then share the 50px, so row 1 (the −, the input, the +) gets shorter and the
   space lands underneath. Only `.pt-minus`, `input` and `.pt-plus` are pinned to `grid-row:1`, so
   ANY node injected into `.quantity` by WooCommerce, the theme or a plugin does exactly that.
   `grid-template-rows:minmax(0,1fr)` fixes the real row at full height and `grid-auto-rows:0`
   flattens every implicit one, so a stray child can no longer steal height whatever puts it there.
   `overflow:hidden` keeps it from painting outside the box.
   ⚠️ This is a fix for the SYMPTOM, arrived at because the fault could not be reproduced logged
   out — measured geometry is correct for a guest, before and after the input's type flip. If the gap
   ever returns, the next step is to list `.quantity`'s children AFTER a click in Leon's own browser
   and find what is being appended. */
.pt-pp .pp-form .quantity{display:grid;grid-template-columns:36px minmax(0,1fr) 36px;
    grid-template-rows:minmax(0,1fr);grid-auto-rows:0;align-items:stretch;align-content:stretch;
    height:52px;overflow:hidden;border:1px solid var(--pt-border-strong);background:var(--pt-surface)}
.pt-pp .pp-form .quantity > label.screen-reader-text{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}
.pt-pp .pp-form .quantity .pt-minus{grid-column:1;grid-row:1}
.pt-pp .pp-form .quantity input{grid-column:2;grid-row:1}
.pt-pp .pp-form .quantity .pt-plus{grid-column:3;grid-row:1}
.pt-pp .pp-form .quantity input{border:0;background:transparent;text-align:center;width:100%;height:100%;font-family:var(--pt-mono);font-size:15px;-moz-appearance:textfield}
.pt-pp .pp-form .quantity input::-webkit-outer-spin-button,.pt-pp .pp-form .quantity input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
/* Same fault as `.pp-zoom` above: transparent background, no colour, white glyph.
   🔴 FULL-BLEED, EXPLICITLY. The glyph is centred by flex, but the BUTTON must fill its whole
   grid cell or its hover paints as a floating block with a margin round it — which is what Leon saw.
   `align-self:stretch` + `height:100%` + zeroed margin/min-height say so outright rather than relying
   on `align-items:stretch` surviving whatever the theme adds; GeneratePress styles bare `button`
   (see `button:focus{background:#333}`) and those rules are NOT stripped for logged-in users the way
   the optimiser strips them for guests, so a rule that loses in a logged-out test can still win in
   Leon's browser. State it here and neither can reach it. [[reference-css-specificity-theme-override]] */
.pt-pp .pp-form .pt-minus,.pt-pp .pp-form .pt-plus{display:flex;align-items:center;justify-content:center;
    align-self:stretch;height:100%;min-height:0;margin:0;padding:0;box-sizing:border-box;
    border:0;border-radius:0;background:transparent;color:var(--pt-ink);font-size:18px;font-weight:600;line-height:1;cursor:pointer;
    transition:background .12s ease,color .12s ease}
/* ⚠️ ALL FOUR STATES NAMED — BUT `:focus` IS NOT A HOVER (corrected 25 Sep 2026).
   The theme's `button:focus{background:#333}` has to be beaten, so `:focus` must be named. It was
   named with the HOVER fill, which meant a click left the button filled grey until you clicked
   somewhere else — Leon: "the hover colour sticks post click". A stepper gets clicked repeatedly, so
   every press left a mark behind it.
   `:focus` therefore resets to TRANSPARENT (it only exists to beat the theme, not to style anything)
   and `:active` shows the fill for the instant the mouse is down, which is the press. Keyboard users
   still get a real ring from `:focus-visible`, which a mouse click does not set. */
.pt-pp .pp-form .pt-minus:focus,.pt-pp .pp-form .pt-plus:focus{background:transparent;color:var(--pt-ink)}
.pt-pp .pp-form .pt-minus:hover,.pt-pp .pp-form .pt-plus:hover,
.pt-pp .pp-form .pt-minus:active,.pt-pp .pp-form .pt-plus:active{background:var(--pt-fill-control);color:var(--pt-ink)}
.pt-pp .pp-form .pt-minus:focus-visible,.pt-pp .pp-form .pt-plus:focus-visible{background:var(--pt-fill-control);outline:2px solid var(--pt-accent);outline-offset:-2px}
/* A DIM, NOT AN INVERSION. These rest white, so they dim to the control fill — the same hover the
   shop cards' Add to cart uses (`.pt-shop .sg-add:hover`) and the same one chips use. Flipping a
   white control to solid black on hover is a recolour, not a dim. The hover itself is declared with
   :active above, so it is not repeated here. [[feedback-button-hover-noir]] */
.pt-pp .pp-form .pt-minus:disabled,.pt-pp .pp-form .pt-plus:disabled{color:var(--pt-border-strong);background:transparent;cursor:default}
/* INK, like every other primary button on this site. The purple one appeared nowhere else. */
.pt-pp .pp-form button.single_add_to_cart_button{height:52px;width:100%;background:var(--pt-ink);color:var(--pt-surface-dim);border:1px solid var(--pt-ink);font-size:15px;font-weight:600;cursor:pointer;border-radius:0;padding:0}
/* A DIM YOU CAN ACTUALLY SEE. This was #1f1f1f — five points off #1A1A1A, which no eye resolves, so
   the primary action on the page had no hover feedback at all. #2E2E2E still reads unmistakably as
   the black primary button; it does not flip to a light fill, because inverting a primary control on
   hover reads as the button switching off. The white controls beside it (the −/+ stepper) dim the
   other way, to --pt-fill-control, matching the shop cards. Both are dims; neither is a recolour.
   ⚠️ The site-wide standard in [[feedback-button-hover-noir]] still says black→#1f1f1f. Leon
   approved this one on 24 Sep 2026 after seeing that #1f1f1f is invisible. If the rest of the site
   moves, move it here too. */
.pt-pp .pp-form button.single_add_to_cart_button:hover{background:#2E2E2E;border-color:#2E2E2E}
.pt-pp .pp-form button.single_add_to_cart_button.disabled,
.pt-pp .pp-form button.single_add_to_cart_button[disabled]{background:var(--pt-fill-control);border-color:var(--pt-border-strong);color:var(--pt-ink-3);cursor:not-allowed}
.pt-pp .pp-form .woocommerce-variation-price{display:none}   /* the real price row above already says it */
.pt-pp .pp-form .woocommerce-variation-availability{display:none}  /* the stock line above says it */
.pt-pp .pp-form .stock{display:none}

.pt-pp .pp-save{margin-left:auto;flex:0 0 auto;display:inline-flex;gap:7px;align-items:center;background:none;border:0;padding:0;color:var(--pt-ink);font:inherit;font-size:13.5px;cursor:pointer}
.pt-pp .pp-save svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.8}
.pt-pp .pp-save.is-on svg{fill:currentColor}

.pt-pp .pp-facts{margin:24px 0 0;border-top:1px solid var(--pt-border)}
.pt-pp .pp-fact{display:flex;gap:10px;padding:11px 0;border-bottom:1px solid var(--pt-border);font-size:13.5px;color:var(--pt-ink-2)}
.pt-pp .pp-fact b{font-weight:600;color:var(--pt-ink)}
.pt-pp .pp-fact a{color:var(--pt-accent)}
.pt-pp .pp-fact::before{content:"";width:16px;height:16px;flex:0 0 auto;margin-top:2px;background:var(--pt-ink);
    -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}
.pt-pp .pp-fact--van::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='black' stroke-width='1.6'%3E%3Cpath d='M1 5h10v7H1zM11 8h3l3 3v1h-6z'/%3E%3Ccircle cx='4.5' cy='14' r='1.5'/%3E%3Ccircle cx='13.5' cy='14' r='1.5'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='black' stroke-width='1.6'%3E%3Cpath d='M1 5h10v7H1zM11 8h3l3 3v1h-6z'/%3E%3Ccircle cx='4.5' cy='14' r='1.5'/%3E%3Ccircle cx='13.5' cy='14' r='1.5'/%3E%3C/svg%3E")}
.pt-pp .pp-fact--return::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='black' stroke-width='1.6'%3E%3Cpath d='M3 9a6 6 0 1 1 2 4.5'/%3E%3Cpath d='M3 5v4h4'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='black' stroke-width='1.6'%3E%3Cpath d='M3 9a6 6 0 1 1 2 4.5'/%3E%3Cpath d='M3 5v4h4'/%3E%3C/svg%3E")}
.pt-pp .pp-fact--lock::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='black' stroke-width='1.6'%3E%3Crect x='3' y='7.5' width='12' height='8'/%3E%3Cpath d='M6 7.5V5a3 3 0 016 0v2.5'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='black' stroke-width='1.6'%3E%3Crect x='3' y='7.5' width='12' height='8'/%3E%3Cpath d='M6 7.5V5a3 3 0 016 0v2.5'/%3E%3C/svg%3E")}
.pt-pp .pp-fact--shield::before{-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='black' stroke-width='1.6'%3E%3Cpath d='M9 1l7 2.5v5C16 13 12.5 16 9 17 5.5 16 2 13 2 8.5v-5z'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none' stroke='black' stroke-width='1.6'%3E%3Cpath d='M9 1l7 2.5v5C16 13 12.5 16 9 17 5.5 16 2 13 2 8.5v-5z'/%3E%3C/svg%3E")}

/* ── SECTIONS — open, never accordions ─────────────────────────────────────── */
.pt-pp .pp-sections{border-top:1px solid var(--pt-ink)}
.pt-pp .pp-secnav{display:flex;gap:26px;padding:14px 0;border-bottom:1px solid var(--pt-border);position:sticky;top:var(--pt-header-h,64px);background:var(--pt-surface-dim);z-index:3;font-size:14px;font-weight:600}
.pt-pp .pp-secnav a{color:var(--pt-ink-3)}
.pt-pp .pp-secnav a.is-on{color:var(--pt-ink);box-shadow:inset 0 -2px 0 var(--pt-ink)}
.pt-pp .pp-sec{display:grid;grid-template-columns:200px minmax(0,1fr);gap:40px;padding:40px 0;border-bottom:1px solid var(--pt-border);scroll-margin-top:calc(var(--pt-header-h,64px) + 60px)}
.pt-pp .pp-sec:last-child{border-bottom:0}
/* 🔴 DIRECT CHILD. As a descendant selector this also caught every <h2> inside the prose — the
   Delivery section pulls in a real page with its own headings, and all six of them turned into mono
   11.5px uppercase labels. The section's label is the section's own h2, not every h2 beneath it. */
.pt-pp .pp-sec > h2{margin:2px 0 0;font-family:var(--pt-mono);font-size:11.5px;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--pt-ink-3)}
/* Headings inside the prose are ordinary headings. */
.pt-pp .pp-prose h2{margin:22px 0 8px;font-size:17px;font-weight:700;letter-spacing:-.01em;color:var(--pt-ink)}
.pt-pp .pp-prose h2:first-child{margin-top:0}
.pt-pp .pp-prose h3{margin:18px 0 6px;font-size:15px;font-weight:700}
.pt-pp .pp-prose a{color:var(--pt-accent)}
.pt-pp .pp-prose ul,.pt-pp .pp-prose ol{margin:0 0 14px;padding-left:20px}
.pt-pp .pp-prose{max-width:760px;font-size:16px;line-height:1.65}
.pt-pp .pp-prose p{margin:0 0 14px}
.pt-pp .pp-prose p:last-child{margin-bottom:0}
.pt-pp .pp-todo{font-size:12.5px;color:var(--pt-ink-3);border-left:2px solid var(--pt-border-strong);padding-left:10px}

/* 🔴 HORIZONTAL RULES ONLY (Leon, 23 Sep). The theme draws a border on every `th` and `td`, which turns
   this into a gridded spreadsheet. The rule belongs to the ROW — it separates one fact from the next —
   and a cell needs no box around it. Cell borders are zeroed explicitly rather than hoped away. */
.pt-pp .pp-spec{width:100%;max-width:760px;border-collapse:collapse;border:0}
.pt-pp .pp-spec tr{border:0;border-bottom:1px solid var(--pt-border)}
.pt-pp .pp-spec tr:first-child{border-top:1px solid var(--pt-border)}
.pt-pp .pp-spec th,
.pt-pp .pp-spec td{border:0;background:none}
.pt-pp .pp-spec th{width:220px;text-align:left;font-weight:500;color:var(--pt-ink-3);font-size:13.5px;padding:13px 16px 13px 0}
.pt-pp .pp-spec td{padding:13px 0;font-size:14px;font-family:var(--pt-mono);color:var(--pt-ink)}
/* Nothing stripes the rows either — an alternating fill is a second separator doing the same job. */
.pt-pp .pp-spec tr:nth-child(even) th,
.pt-pp .pp-spec tr:nth-child(even) td{background:none}

.pt-pp .pp-rev-empty{display:flex;gap:24px;align-items:center;justify-content:space-between;max-width:760px;padding:20px 22px;background:var(--pt-surface);border:1px solid var(--pt-border)}
.pt-pp .pp-rev-empty b{display:block;font-size:15px}
.pt-pp .pp-rev-empty span{font-size:13.5px;color:var(--pt-ink-3)}
.pt-pp .pp-btn-out{display:inline-flex;align-items:center;justify-content:center;height:44px;padding:0 18px;border:1px solid var(--pt-ink);background:transparent;color:var(--pt-ink);font-size:14px;font-weight:600;cursor:pointer;flex:0 0 auto;border-radius:0}
.pt-pp .pp-btn-out:hover{background:var(--pt-fill-control)}
.pt-pp .pp-more{margin:18px 0 0}

/* ── RAILS — the same card as everywhere else ──────────────────────────────── */
.pt-pp .pp-rail{padding:44px 0 0}
.pt-pp .pp-railhead{display:flex;justify-content:space-between;align-items:flex-end;border-bottom:1px solid var(--pt-ink);padding-bottom:14px;margin:0 0 20px}
.pt-pp .pp-railhead h2{margin:0;font-size:26px;font-weight:800;letter-spacing:-.02em}
/* FREE SCROLL, no snap (Leon, 22 Sep — every rail we own). */
/* 4.5 cards on desktop (Leon, 23 Sep) — same as the homepage rails. The half card is the point:
   a row that ends flush looks finished, and nobody scrolls a finished row. 4 gaps, not 3.5,
   because only four gaps are actually visible across the 4.5 columns. */
.pt-pp .pp-track{display:grid;grid-auto-flow:column;grid-auto-columns:calc((100% - 4*16px)/4.5);gap:16px;overflow-x:auto;scrollbar-width:none;scroll-snap-type:none;padding-bottom:4px}
.pt-pp .pp-track::-webkit-scrollbar{display:none}

.pt-pp .pp-xlink{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:22px;align-items:center;background:var(--pt-surface);border:1px solid var(--pt-border);padding:24px 28px;margin:44px 0 56px}
.pt-pp .pp-k{font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--pt-ink-3)}
.pt-pp .pp-xlink b{display:block;font-size:19px;font-weight:800;letter-spacing:-.01em}
.pt-pp .pp-xlink p{margin:4px 0 0;font-size:14px;color:var(--pt-ink-2)}

/* ── LIGHTBOX ──────────────────────────────────────────────────────────────── */
.pt-pp-lb{position:fixed;inset:0;z-index:1000;background:rgba(26,26,26,.9);display:flex;align-items:center;justify-content:center}
.pt-pp-lb[hidden]{display:none}
.pt-pp-lb img{max-width:92vw;max-height:86vh;object-fit:contain}
.pt-pp-lb button{position:absolute;background:var(--pt-surface);border:1px solid var(--pt-border);width:40px;height:40px;cursor:pointer;font-size:20px;line-height:1;padding:0;border-radius:0}
.pt-pp-lb .lb-x{top:18px;right:18px}
.pt-pp-lb .lb-p{left:18px;top:50%;transform:translateY(-50%)}
.pt-pp-lb .lb-n{right:18px;top:50%;transform:translateY(-50%)}

/* ── PHONE ─────────────────────────────────────────────────────────────────── */
.pt-pp .pp-stickybar{position:fixed;left:0;right:0;bottom:0;z-index:20;display:grid;grid-template-columns:auto minmax(0,1fr);gap:12px;align-items:center;
    padding:10px 16px calc(10px + env(safe-area-inset-bottom));background:var(--pt-surface);border-top:1px solid var(--pt-border)}
.pt-pp .pp-stickybar[hidden]{display:none}
.pt-pp .pp-sb-price{font-size:17px;font-weight:600}
.pt-pp .pp-sb-price del{font-size:13px;color:var(--pt-ink-3);font-weight:400}
.pt-pp .pp-sb-cta{height:46px;background:var(--pt-ink);color:var(--pt-surface-dim);border:1px solid var(--pt-ink);font:inherit;font-size:15px;font-weight:600;cursor:pointer;border-radius:0}

@media (max-width:1000px){
    .pt-pp .pp-top{grid-template-columns:1fr;gap:28px;padding-bottom:36px}
    .pt-pp .pp-buy{position:static}
    .pt-pp .pp-sec{grid-template-columns:1fr;gap:12px}
    .pt-pp .pp-track{grid-auto-columns:calc((100% - 32px)/3)}
}
@media (max-width:640px){
    .pt-pp .pp-wrap{padding:0 16px}
    .pt-pp .pp-gallery{grid-template-columns:1fr;gap:8px}
    .pt-pp .pp-thumbs{flex-direction:row;order:2;overflow-x:auto;scrollbar-width:none}
    .pt-pp .pp-thumbs::-webkit-scrollbar{display:none}
    .pt-pp .pp-thumb{width:56px;flex:0 0 56px}
    .pt-pp .pp-h1{font-size:24px}
    .pt-pp .pp-pricerow{font-size:26px}
    .pt-pp .pp-track{grid-auto-columns:72%;gap:10px}
    .pt-pp .pp-railhead h2{font-size:21px}
    .pt-pp .pp-xlink{grid-template-columns:1fr;gap:14px;margin-bottom:24px}
    .pt-pp .pp-k{display:none}
    .pt-pp .pp-secnav{gap:16px;overflow-x:auto;white-space:nowrap;scrollbar-width:none}
    .pt-pp .pp-secnav::-webkit-scrollbar{display:none}
    /* Only the two that matter on a phone (§F). */
    /* Only the two that matter on a phone (§F): delivery and returns. */
    .pt-pp .pp-fact--lock,.pt-pp .pp-fact--shield{display:none}
    /* Room for the sticky bar so it never covers the last thing on the page. */
    .pt-pp{padding-bottom:72px}
}

/* ── Delivery and returns: two short blocks and one link ─────────────────────
   Brief of 23 Sep. The section used to carry ~450 words of policy on every product. */
.pt-pp .pp-dr{max-width:640px}
.pt-pp .pp-dr h3{margin:0 0 4px;font-size:13.5px;font-weight:600;color:var(--pt-ink)}
.pt-pp .pp-dr h3 + p{margin:0 0 18px;font-size:15px;line-height:1.6;color:var(--pt-ink-2)}
.pt-pp .pp-dr p:last-of-type{margin-bottom:0}
/* The exception, when there is one, is the first thing read and the only thing in full ink. */
.pt-pp .pp-dr__note{margin:0 0 18px;font-size:15px;line-height:1.6;font-weight:600;color:var(--pt-ink)}
.pt-pp .pp-dr__link{margin:18px 0 0;font-size:15px;color:var(--pt-ink-2)}
.pt-pp .pp-dr__link a{color:var(--pt-accent)}

/* The reviews section's styling lives in `css/reviews.css` — the same partials draw this page and the
   /reviews/ hub, so the CSS is shared for the same reason the markup is. Loaded by both. */

/* 🔴 RAIL CARD TITLES WERE RED. `.sg-title` is an <a>, and inside the product template it was picking up
   the theme's link colour instead of the card's own — the shop grid never showed it because that page
   sets a link colour of its own. A card title is a title, not a link, whatever element it happens to be.
   (Leon, 23 Sep.) */
.pt-pp .pp-rail .sg-title,
.pt-pp .pp-rail .sg-title:visited{color:var(--pt-ink)}
.pt-pp .pp-rail .sg-title:hover{color:var(--pt-ink);text-decoration:underline}
.pt-pp .pp-rail .sg-brand{color:var(--pt-ink-3)}
