/* ==========================================================================
   product-polish.css — the product page's craft layer. Loaded ONLY on a single
   product view, ONLY by inc/product-polish.php, after ostugrupp-woocommerce.

   WHAT THIS FILE IS. Yesterday's design pass finished the cart
   (assets/css/cart-polish.css) and the checkout (assets/css/checkout-polish.css)
   and never reached the one page where shoppers actually spend their time. The
   product page is not broken — it is simply speaking an OLDER dialect than the
   two pages next to it in the funnel. This file adds NO content and NO feature.
   It is surfaces, rhythm, hierarchy and state, translated into the language the
   cart and the checkout now speak:

     card            = --surface + 1px --border + --radius-16 + --shadow-card
     nested corners  = 16px panel -> 12px control -> 8px chip (step down, never equal)
     label / value   = 14/400 --text-muted  vs  14/600 --text
     numbers         = font-variant-numeric: tabular-nums
     quiet band      = --surface-muted
     brand tint      = --brand-a1 hover, --brand-a2 press
     selected        = a FULL-COLOUR ring, never an alpha one (see §2)

   ---------------------------------------------------------------------
   1 · SCOPE
   ---------------------------------------------------------------------
   Everything below is anchored on `.single-product.woocommerce` plus a second
   structural class. Two fences matter more than the rest:

     (a) THE PRICE IS NOT TOUCHED, ANYWHERE. woocommerce.css:653-687 records
         what it cost to get the main price to 32px in the theme's ink and
         scoped to `.summary`: an earlier unscoped repair blew every
         related-product price up to 32px too. No rule in this file names
         `.price`, `ins` or `del`.
     (b) `.summary` IS THE FENCE FOR THE BUY COLUMN. WooCommerce renders the
         related and upsell rails INSIDE the same `div.product` wrapper, so a
         `div.product` selector reaches every recommended product card. Every
         buy-column rule here carries `.summary`; the only rules that leave it
         are §1/§2 (the gallery, a sibling column), §6 (the spec table, which
         lives in `.woocommerce-tabs`) and §7, which uses a CHILD combinator on
         the rail container itself and never descends into a card.

   ---------------------------------------------------------------------
   2 · CLAUDE.md TRAP 1 — SPECIFICITY IS STATED, NOT ASSUMED
   ---------------------------------------------------------------------
   This page is where Trap 1 has bitten twice. A plugin ships
     .woocommerce div.product div.images.woocommerce-product-gallery{position:relative}
   at (0,4,2) and silently beat the theme's sticky rule at (0,3,0) — while
   `top:96px` still applied, so the rule LOOKED live in DevTools. And WooCommerce
   core ships
     .woocommerce:where(body:not(.woocommerce-uses-block-theme)) div.product p.price
   at (0,3,2), which beat the theme's price rule at (0,2,0) for months.
   So: every block below states the specificity of its selector AND the
   specificity of the rule it has to beat. Where the number is a tie, that is
   said out loud rather than left to source order.

   ---------------------------------------------------------------------
   3 · CLAUDE.md TRAP 9 — the `woocommerce-page` cascade
   ---------------------------------------------------------------------
   Core ships `.woocommerce img, .woocommerce-page img { height:auto;
   max-width:100% }` at (0,1,1), which beats any single-class theme rule on this
   template. NOTHING in this file sets width, height, max-width or max-height on
   an image. §1 and §2 are paint-only for exactly that reason: woocommerce.css
   sizes the gallery thumbnails at 64px (0,3,2) on phones and re-sizes them to a
   6-column grid at (0,3,2) from 900px, and a single unfenced size rule here
   would beat BOTH and put the desktop size on a phone.

   ---------------------------------------------------------------------
   4 · CLAUDE.md TRAP 11 — no `display` on a th or a td. Anywhere.
   ---------------------------------------------------------------------
   §6 restyles `table.shop_attributes`, which IS a real table on desktop. Not
   one declaration below sets `display` on a th or a td: everything is either
   paint (background, color, font, letter-spacing) or a property that cannot
   generate an anonymous cell. product-sections.css already converts the WHOLE
   table — table, tbody, tr, th, td — to blocks under 768px, which is the safe
   half of Trap 11's fix pattern; §6 is fenced to `min-width: 769px` so it can
   never reach into that conversion and half-undo it.

   ---------------------------------------------------------------------
   5 · WHAT IS NOT IN THIS FILE, ON PURPOSE
   ---------------------------------------------------------------------
   · transitions and animations — assets/css/motion.css owns the shop's single
     motion rhythm and is enqueued last (inc/motion.php, priority 99). It
     already lists `.single_add_to_cart_button`,
     `.woocommerce-product-gallery__trigger` and `.flex-control-thumbs img`.
     A duration here would fork it. STATE styles (:hover, :active, :disabled)
     ARE here — they are appearance, not motion.
   · focus rings — a11y.css:33-47 already draws every ring. This file's only
     involvement is §4, which stops one wrapper from clipping it.
   · the main price, the sale colour, the gallery pre-init guard
     (woocommerce.css:488-517) and the sticky-gallery rule
     (woocommerce.css:607-628). All three are load-bearing and all three are
     left exactly as they are.
   · the CTA's green glow. `--shadow-green` (main.css:101) is built on
     rgba(5,150,105,…) — the #059669 that tokens.css:10 records as deleted —
     but it is a SHARED token used by every primary button in the shop.
     Correcting it on this one page would create the fork this pass exists to
     remove. It belongs in main.css, in one edit, and is written up in the
     handover instead.
   · the buy-box's own lift. `.ostu-buybox` carries a bespoke two-layer shadow
     (single.css:66) rather than a named recipe. It is the one panel on the page
     that is meant to sit higher than everything else, the values are within a
     hair of main.css's --shadow-card-hover, and re-cutting it would be a taste
     change with owner-visible risk and no consistency gain. Its PADDING and
     MARGIN are normalised in §3; its shadow is not.

   ---------------------------------------------------------------------
   6 · TOKENS
   ---------------------------------------------------------------------
   Every var() carries its literal as a fallback, and the literal is the value
   that resolves TODAY — read out of assets/css/tokens.css and, for the two
   names declared twice, out of main.css. --shadow-card and --font-display exist
   in BOTH tokens.css and main.css, and inc/enqueue.php:105-113 makes main.css
   load after tokens.css, so main.css wins: --shadow-card is
   `0 1px 2px rgba(15,23,42,.04), 0 1px 3px rgba(15,23,42,.06)`.
   The fallbacks are not decoration. This theme deploys as a hand-built zip, the
   live site at v1.2.85 did not load tokens.css at all, and a custom property
   that cannot resolve does not fall back to an older value — it becomes the
   guaranteed-invalid value and takes its whole declaration down with it.
   Every spacing number is on the pack's 4px ladder (tokens.css section A4).
   The page's off-ladder legacy values — 22, 18, 14, 13.5, 15.5, 10 — are the
   thing §3 exists to retire.

   ---------------------------------------------------------------------
   7 · WHAT WAS NOT VERIFIED
   ---------------------------------------------------------------------
   There is no browser in this session. The specificity arithmetic below is
   arithmetic, not a measured computed value — Trap 1 exists precisely because a
   rule can look live in DevTools and still not apply. Nothing here has been
   seen rendered. Three things need one real look before anyone calls them done:
   the gallery frame shadow at >=900px (§1), the quantity stepper on a variable
   and on a grouped product (§4), and the spec table at 769-900px (§6).
   ========================================================================== */


/* ==========================================================================
   §1 · THE GALLERY FRAME — give both columns the same physics
   ==========================================================================
   On desktop the summary column is a lifted white card and the gallery beside
   it is a flat bordered box. Two adjacent surfaces obeying two different rules
   is the same "unfinished" signal cart-polish.css §1 was written to remove, and
   here it is the first thing on the page.

   WHERE THE SHADOW GOES, AND WHY IT IS TWO SELECTORS. Once FlexSlider builds,
   the visible frame is `.flex-viewport` — a window with `overflow:hidden` — and
   the `__image` slides live INSIDE it, so a shadow on a slide is clipped away
   and never seen. Before FlexSlider builds (measured live: 694 ms) there is no
   viewport at all and `__image` IS the frame. Painting both means there is no
   pop at 694 ms and no dependence on the `:has()` guard. The radius on the
   viewport is the same 16px the slide already carries, so rounding the window
   clips nothing that was not already round.

   FENCED TO >=900px on purpose. That is the breakpoint where the two columns
   sit side by side (woocommerce.css:448). Below it the gallery is stacked and
   full-bleed, `.woocommerce-product-gallery` carries `overflow:hidden`
   (woocommerce.css:1619), and a soft shadow would only be clipped at the
   container edge for no gain.

   SPECIFICITY
     .single-product.woocommerce div.product .woocommerce-product-gallery .flex-viewport
       = (0,5,1) — beats FlexSlider's `.flex-viewport` (0,1,0) outright, and is
         built on the same structure as the sticky rule that had to reach (0,5,2)
         to beat the plugin.
     .single-product.woocommerce div.product .woocommerce-product-gallery__image
       = (0,4,1) — beats the theme's own (0,2,0) at woocommerce.css:521.
   Paint only: no width, no height, no display, no position. The pre-init guard
   and the sticky rule are untouched. */

@media (min-width: 900px) {
  .single-product.woocommerce div.product .woocommerce-product-gallery .flex-viewport,
  .single-product.woocommerce div.product .woocommerce-product-gallery__image {
    border-radius: var(--radius-16, 16px);
    box-shadow: var(--shadow-card, 0 1px 2px rgba(15, 23, 42, .04), 0 1px 3px rgba(15, 23, 42, .06));
  }
}


/* ==========================================================================
   §2 · THE THUMBNAIL STRIP — a selected state you can actually see
   ==========================================================================
   Two problems, both measured off the shipped stylesheet.

   1. THE TILES ARE FLAT. The cart's product thumbnail is a white tile with a
      hairline, a 12px corner and the faintest lift (cart-polish.css §4). The
      gallery thumbnails are the same object, one funnel step earlier, with the
      hairline and the corner but no lift. One declaration closes that.

   2. THE SELECTED TILE IS MARKED IN A COLOUR THAT NO LONGER EXISTS.
      woocommerce.css:605 rings the active thumb with
      `0 0 0 2px rgb(4 120 87 / .22)` — #059669, which tokens.css:10 records as
      deleted from the system — at 22% alpha. tokens.css:242-245 already settled
      this exact argument for the focus ring: an alpha ring composites on white
      to roughly 1,6:1 and fails WCAG 1.4.11's 3:1 for a non-text indicator, so
      a visible ring must be FULL colour. A selection ring is the same kind of
      object as a focus ring — it answers "which one am I on" — and on a phone
      it is the only answer there is. --brand at full strength, 5,00:1 on white.

   The `border-color: var(--green) !important` at woocommerce.css:605 stays; the
   ring sits outside it, so the selected tile reads as 1px brand border + 2px
   brand ring. Nothing here is clipped: the strip is `overflow: visible
   !important` (woocommerce.css:561).

   SPECIFICITY
     resting  .single-product.woocommerce .woocommerce-product-gallery .flex-control-thumbs img
                = (0,4,1) vs the theme's (0,3,2) at woocommerce.css:594 — four
                  classes beat three, whatever the element count.
     selected same chain + .flex-active = (0,5,1) vs the theme's (0,3,1).
   NO SIZE PROPERTIES — see the Trap 9 note in the header. */

.single-product.woocommerce .woocommerce-product-gallery .flex-control-thumbs img {
  box-shadow: 0 1px 2px var(--ink-a1, rgba(15, 23, 42, .04));
}

.single-product.woocommerce .woocommerce-product-gallery .flex-control-thumbs img.flex-active,
.single-product.woocommerce .woocommerce-product-gallery .flex-control-thumbs .flex-active img,
.single-product.woocommerce .woocommerce-product-gallery .flex-control-thumbs li.flex-active img {
  box-shadow: 0 0 0 2px var(--brand, #047857);
}


/* ==========================================================================
   §3 · THE SUMMARY COLUMN — one rhythm instead of eleven numbers
   ==========================================================================
   The column already has the right ARCHITECTURE: title -> rating -> price ->
   savings -> stock -> add-to-cart -> trust -> accordions, with the buy block
   wrapped in one card (inc/single-product.php:110). What it does not have is a
   rhythm. Read off single.css and woocommerce.css, the vertical gaps down this
   column today are 14, 16, 18, 20, 22, 24, 28 — seven values, four of them off
   the 4px ladder, none of them expressing a rule. The eye cannot group what has
   no rule, which is why the column reads as stacked parts rather than as a
   panel with sections.

   ONE RULE, stated so the next person can keep it:
     24px  BETWEEN blocks   (title/short description -> buy-box -> accordion -> meta)
     16px  INSIDE a block   (the buy-box's own padding rhythm, trust separator)
     12px  BETWEEN SIBLINGS that belong together (status row, rating, price)
   Nothing moves by more than 6px. This is not a redesign; it is the same layout
   with its spacing snapped onto the ladder.

   SPECIFICITY. single.css owns these margins at (0,3,0)
   (`.single-product .summary .ostu-buybox`) and (0,1,0)–(0,2,0) for the rest.
   Adding `.woocommerce` to the anchor takes every rule below to (0,4,0) or
   (0,5,0), which wins on class count alone and does NOT depend on this file
   printing after single.css. It does print after (inc/product-polish.php uses
   priority 21 for exactly that reason) — that is the belt, not the mechanism. */

/* The card itself: even 24px padding, 24px off the block above it. Was
   `padding: 22px 24px 24px` and `margin: 22px 0 0` — 22 is not on the ladder,
   and an uneven top/bottom padding on a bordered card is visible as a tilt.
   The SHADOW is deliberately not touched — see the header, section 5. */
.single-product.woocommerce .summary .ostu-buybox {
  margin-top: var(--space-24, 24px);
  padding: var(--space-24, 24px);
}

/* Rating -> price. 18px pushed the stars away from the number they qualify;
   12px groups them with the status row above (which is already 12px). */
.single-product.woocommerce .summary .ostu-buybox .woocommerce-product-rating {
  margin: 0 0 var(--space-12, 12px);
}

/* The trust row closes the card. Its separator was 18px above the rule
   (woocommerce.css:726) and 20px below the button — an asymmetry with no
   reason. 20px of air, then the rule, then 16px. */
.single-product.woocommerce .summary .ostu-buybox .product-trust {
  margin-top: var(--space-20, 20px);
  padding-top: var(--space-16, 16px);
}

/* Key specs inside the buy-box: the SAME label/value hierarchy the cart totals
   and the spec sheet in §6 use, so the shopper meets one convention three
   times instead of three conventions once each. 13,5px is not a type step;
   14px is. The values are things like "48.82 x 7.67 x 1240 mm" and "3 500 W",
   so they get tabular figures — proportional digits make a stack of numbers
   ripple sideways.
   (0,4,0) / (0,4,1) against single.css's (0,2,0), which also wins the
   `max-width: 600px` block there — intended: on a phone the row stacks label
   over value, and a 14px label over a 14px semibold value is more readable
   than 12,5 over 14. */
.single-product.woocommerce .summary .ostu-keyspecs__dt {
  font-size: var(--fs-sm, 14px);
  font-weight: var(--fw-regular, 400);
  color: var(--text-muted, #475569);
}
.single-product.woocommerce .summary .ostu-keyspecs__dd {
  font-size: var(--fs-sm, 14px);
  font-weight: var(--fw-semibold, 600);
  color: var(--text, #0f172a);
  font-variant-numeric: tabular-nums;
}

/* The short description is intro copy, read in full paragraphs. 15,5px/1.75 is
   off the scale in both axes; 16px/28px is --fs-md over --lh-lg and is the same
   measure the rest of the shop reads at. 16px is also the phone floor.
   The colour is restated only to name the ROLE — --slate-600 already resolves
   to the same #475569 as --text-muted, so nothing changes on screen. */
.single-product.woocommerce .summary .woocommerce-product-details__short-description {
  font-size: var(--fs-md, 16px);
  line-height: var(--lh-lg, 28px);
  color: var(--text-muted, #475569);
}

/* Accordion card and meta block join the 24px between-blocks rule. */
.single-product.woocommerce .summary .ostu-info-accordion {
  margin: var(--space-24, 24px) 0 0;
}
.single-product.woocommerce .summary .product_meta {
  margin-top: var(--space-24, 24px);
  padding-top: var(--space-16, 16px);
}


/* ==========================================================================
   §4 · THE QUANTITY STEPPER — the cart's control, on the page it is met first
   ==========================================================================
   assets/js/interactions.js:189 wraps EVERY `.quantity > input.qty` in the shop
   — cart and product page alike — and injects the − / + buttons. So the control
   the cart page just had rebuilt into a white segmented control
   (cart-polish.css §5) is the identical control here, still wearing
   cart-widget.css:254-271: a --muted grey brick that fills SOLID GREEN on
   hover, fades to `opacity:.4` when disabled, and has no pressed state at all.

   That last point is the whole argument. 73% of this shop is phones, where
   :hover is not a state a finger can produce. On a phone this button today gives
   no feedback whatsoever — and it is the second-most-tapped control on the page,
   right beside the one that spends money. The press state is not decoration
   here; it is the only feedback that exists.

   Rebuilt to match the cart exactly: white segmented frame on --border-strong,
   glyphs in --text-muted, --brand-a1 tint on hover, the deeper --brand-a2 on
   press, and a disabled state that keeps its shape instead of dissolving.

   ⚠ `overflow: hidden` is REMOVED from the wrapper, deliberately and for the
   same reason as in the cart: a11y.css:33-47 draws the keyboard ring as
   `outline` (3px) plus a `box-shadow` out to 6px, and an ancestor's
   overflow:hidden clips BOTH — so today the ring around − and + is cut off on
   all four sides. Losing the clip means the buttons must round their own outer
   corners: 11px = the wrapper's 12px minus its 1px border, so the tint lands
   exactly inside the frame.

   Only `.quantity.qty-stepper` is reframed, never a bare `.quantity`: if
   interactions.js does not run there are no buttons, and a frame drawn around a
   still-bordered input would double the border.

   SCOPED TO `.summary`, not to `form.cart`. A grouped product puts one stepper
   per child row inside a table, and a variable product puts its stepper inside
   `.woocommerce-variation-add-to-cart`; both are inside `.summary`, so one
   anchor covers all three product types. Nothing outside the summary column has
   a quantity input on this template.

   SPECIFICITY. cart-widget.css owns this control at (0,1,0) `.qty-stepper` and
   (0,2,0) `.qty-stepper .qty-stepper__btn`; woocommerce.css:713 owns the input
   at (0,3,1). The chains below are (0,5,0) to (0,7,0) and (0,5,1), so every one
   wins on class count. The three `!important` declarations cart-widget.css:275
   puts on the input's borders are deliberately left in place — they are what
   makes the input read as the middle segment. */

.single-product.woocommerce .summary .quantity.qty-stepper {
  border: 1px solid var(--border-strong, #cbd5e1);
  border-radius: var(--radius-12, 12px);
  background: var(--surface, #ffffff);
  overflow: visible;
}

.single-product.woocommerce .summary .qty-stepper .qty-stepper__btn {
  background: var(--surface, #ffffff);
  color: var(--text-muted, #475569);
  font-size: var(--fs-lg, 18px);
  font-weight: var(--fw-semibold, 600);
  line-height: var(--lh-flat, 1);
}
.single-product.woocommerce .summary .qty-stepper .qty-stepper__minus {
  border-radius: 11px 0 0 11px;
}
.single-product.woocommerce .summary .qty-stepper .qty-stepper__plus {
  border-radius: 0 11px 11px 0;
}

/* Behind (hover: hover) because a :hover that latches after a tap is worse than
   no hover at all — and on this control the latched state used to be a solid
   green fill that looked like the button was stuck down. */
@media (hover: hover) {
  .single-product.woocommerce .summary .qty-stepper .qty-stepper__btn:hover:not(:disabled) {
    background: var(--brand-a1, rgba(4, 120, 87, .06));
    color: var(--brand, #047857);
  }
}
/* The press. On a phone this is the only feedback that exists. --brand-a2 is
   deeper than the hover tint on purpose: a press must read as MORE than hover,
   or it disappears the moment a latched hover is also on the element. */
.single-product.woocommerce .summary .qty-stepper .qty-stepper__btn:active:not(:disabled) {
  background: var(--brand-a2, rgba(4, 120, 87, .12));
  color: var(--brand-active, #024430);
}
/* Disabled is the RESTING state of the minus button at quantity 1, i.e. what
   most shoppers see first, so it has to look deliberate. `opacity: .4` fades the
   glyph AND the frame into a smudge; a flat quiet ink keeps the shape.
   `:disabled:hover` is named because cart-widget.css:271 names it. */
.single-product.woocommerce .summary .qty-stepper .qty-stepper__btn:disabled,
.single-product.woocommerce .summary .qty-stepper .qty-stepper__btn:disabled:hover {
  opacity: 1;
  background: var(--surface, #ffffff);
  color: var(--border-strong, #cbd5e1);
  cursor: default;
}

/* The number itself. 16px is a floor, not a preference: below 16px iOS Safari
   zooms the page in when the field is focused, which on a product page throws
   the buy button off screen. Weight drops 700 -> 600 to match the cart, where
   the same number sits in the same control. */
.single-product.woocommerce .summary .qty-stepper input.qty {
  background: none;
  color: var(--text, #0f172a);
  font-size: var(--fs-md, 16px);
  font-weight: var(--fw-semibold, 600);
  font-variant-numeric: tabular-nums;
}


/* ==========================================================================
   §5 · THE INFO ACCORDION — three rows that read as one card
   ==========================================================================
   Tarne / Tagastus / Garantii is the block that answers the questions that stop
   a purchase, and it is styled at (0,1,0) — the weakest selector on a template
   whose body carries `woocommerce-page`, i.e. exactly the cascade CLAUDE.md
   Trap 1 is about. Re-anchoring it is half the value of this section; the other
   half is four small things:

     · the head is 15px, which is not a step on the scale (14 and 16 are), and
       drops to 14,5px on phones — a third value for one control;
     · the icon inherits the title's ink, so the row reads as three equally
       dark objects (icon, title, chevron) with no lead;
     · the hover fill latches on touch, and there is no pressed state;
     · the bullet ticks are the TEXT glyph "✓" while the identical ticks 200px
       above them, in the trust row, are the pack's SVG check
       (woocommerce.css:730). Yesterday's pass unified forty icons onto one
       drawing; this is the same job, two characters wide.

   The tick below is byte-for-byte the trust row's data URI. A data URI cannot
   resolve a var(), so the `%23047857` inside it is --brand written out — if that
   token ever moves, this string moves with it. Same constraint, same note, as
   the select chevron in checkout-fields.css.

   BODY INDENT. 20px head padding + 20px icon + 12px gap = 52px, so the copy
   starts exactly under the title. Below 600px that indent is given up and the
   body aligns to the head's own left padding instead: on a 360px screen a 52px
   gutter costs a seventh of the line, and there is no second column for the eye
   to align to anyway.

   SPECIFICITY. single.css owns all of this at (0,1,0) and (0,1,2); the chains
   below are (0,4,0), (0,4,2), (0,5,0) and (0,7,0). The mobile blocks in
   single.css (`max-width: 768px` and `max-width: 480px`) are also (0,1,0) — a
   media query adds no specificity — so the values below win at every width.
   That is intended: one control, one set of numbers. */

.single-product.woocommerce .summary .ostu-acc__head {
  gap: var(--space-12, 12px);
  min-height: var(--tap-min, 44px);
  box-sizing: border-box;
  padding: var(--space-16, 16px) var(--space-20, 20px);
  font-size: var(--fs-md, 16px);
  font-weight: var(--fw-semibold, 600);
  color: var(--text, #0f172a);
}

/* The icon leads the row. It is a 20px inline SVG stroked in currentColor
   (inc/icons.php), so a colour is all it takes; `inline-flex` centres it against
   the title's line box, which `font-size` on a span could never do. */
.single-product.woocommerce .summary .ostu-acc__icon {
  display: inline-flex;
  align-items: center;
  color: var(--brand, #047857);
}

/* Open state: the chevron picks up the brand, so an open row is identifiable
   from the head alone without a second background tone. */
.single-product.woocommerce .summary .ostu-acc[open] > .ostu-acc__head .ostu-acc__chevron {
  border-right-color: var(--brand, #047857);
  border-bottom-color: var(--brand, #047857);
}

/* States. The press is the point: on a phone the head is a 44px tap target that
   currently acknowledges nothing, while its :hover fill (single.css:262) latches
   after the tap and stays lit on a row the shopper has already left. */
.single-product.woocommerce .summary .ostu-acc__head:active {
  background: var(--surface-muted, #f1f5f9);
}
@media (hover: none) {
  .single-product.woocommerce .summary .ostu-acc__head:hover {
    background: transparent;
  }
}

.single-product.woocommerce .summary .ostu-acc__body {
  padding: 0 var(--space-20, 20px) var(--space-20, 20px) 52px;
  font-size: var(--fs-sm, 14px);
  line-height: var(--lh-md, 24px);
  color: var(--text-muted, #475569);
}
@media (max-width: 600px) {
  .single-product.woocommerce .summary .ostu-acc__body {
    padding-left: var(--space-20, 20px);
  }
}

/* The tick. 14px glyph on a 24px line box -> top: 5px centres it on the first
   line, which is why the body's line-height above is a token and not a ratio. */
.single-product.woocommerce .summary .ostu-acc__list li {
  padding-left: var(--space-24, 24px);
}
.single-product.woocommerce .summary .ostu-acc__list li::before {
  content: "";
  top: 5px;
  width: 14px;
  height: 14px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23047857' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5L20 7'/%3E%3C/svg%3E") center/contain no-repeat;
}


/* ==========================================================================
   §6 · THE SPECIFICATION SHEET — the most-read table on the page
   ==========================================================================
   "Täielik spetsifikatsioon" is the block this shop's customers actually came
   for: inc/product-sections.php:60-64 records that the tabs were opened out
   precisely because people were e-mailing to ask for data that was already on
   the page. It is styled as a plain table, and it carries one real defect.

   THE DEFECT. product-sections.css:129-131 paints even rows #fbfdfe — a
   near-white that exists in no palette — at (0,4,3), and the label column
   --muted at (0,3,2). The zebra therefore WINS on even rows, so the label column
   alternates between two different greys down the table. Nobody would draw that
   on purpose; it is two rules meeting at the wrong specificity.

   THE FIX is the cart's three-step hierarchy, which is the same shape of
   problem: a quiet label column, a strong value column, and figures that hold
   still. `font-variant-numeric: tabular-nums` matters more here than anywhere
   else on the page — a spec sheet is forty numbers stacked vertically, and
   proportional digits make that column ripple.

   VALUES STAY LEFT-ALIGNED. The cart right-aligns its columns because money is
   compared by decimal point. A specification is read as text ("Roostevabast
   terasest otsikud", "IPX4"), and right-aligning prose puts a ragged left edge
   on the one column people scan. Do not "unify" this later.

   ⚠ FENCED TO min-width: 769px, AND THE FENCE IS LOAD-BEARING (Trap 11).
   product-sections.css:144-158 converts the ENTIRE table — table, tbody, tr, th,
   td — to blocks under 768px, which is the safe half of Trap 11's fix pattern:
   with no table-display ancestor left, no anonymous cell can be generated. Those
   rules run at (0,3,2)–(0,4,2). Everything below is (0,5,x) or (0,6,x), so an
   unfenced rule here would beat them and repaint the phone's stacked cards with
   desktop table values. 769px is the exact complement of their 768px.

   ROOTS. `.woocommerce-tabs` is kept whether the sections module is on or off:
   inc/product-sections.php:111 renders `<div class="woocommerce-tabs
   ostu-psec-wrap">`, and with the toggle off WooCommerce prints the same wrapper
   itself. One selector therefore covers both modes, which is also why the theme
   scoped its base table styling there in the first place.
   `tbody tr th` is used rather than a bare `th` so background reaches (0,5,4)
   and beats the zebra's (0,4,3); the implicit <tbody> the HTML parser inserts is
   always present, whether or not the template writes one.
   NO `display` ON ANY th OR td. Grep it. */

.single-product.woocommerce .woocommerce-tabs .panel table.shop_attributes td {
  font-variant-numeric: tabular-nums;
}

@media (min-width: 769px) {
  /* Label column: quiet, one grey, on the type scale. Restating the background
     here is what retires the alternating-grey defect. */
  .single-product.woocommerce .woocommerce-tabs .panel table.shop_attributes tbody tr th {
    background: var(--surface-muted, #f1f5f9);
    font-size: var(--fs-sm, 14px);
    font-weight: var(--fw-regular, 400);
    color: var(--text-muted, #475569);
  }
  /* Value column: the thing being read. Ink, semibold, on the shop's own
     surface — no zebra, because the tinted label column already gives the eye
     its rail and two banding systems in one table cancel each other out. */
  .single-product.woocommerce .woocommerce-tabs .panel table.shop_attributes tbody tr td {
    background: var(--surface, #ffffff);
    font-size: var(--fs-sm, 14px);
    font-weight: var(--fw-semibold, 600);
    color: var(--text, #0f172a);
  }
}


/* ==========================================================================
   §7 · THE RELATED RAIL — a real end to the product
   ==========================================================================
   The rail is separated from the product by a 1px --border hairline with 48px
   under it (single.css:360-364). The trouble is that it is the FIFTH identical
   hairline in a row: every `.ostu-psec` section draws the same 1px --border at
   the same 34px rhythm (product-sections.css:62-66). A divider that looks like
   the four dividers above it does not divide — it continues. So the page ends by
   sliding from "this product" into "other products" with no seam, and the
   shopper's eye keeps reading the same page.

   Two changes, no new ideas: MORE AIR than the section rhythm (24px above the
   rule where a section gets none, 56px below it where a section gets 34), and a
   HEAVIER rule (--border-strong, the token whose stated role is "eraldaja
   rõhuga" — a separator with emphasis). Together they read as a chapter break
   rather than another paragraph.

   The eyebrow moves onto the shop's one label recipe. It is 12px/700 at .14em
   today; --label-sm is 12px/600 at .06em, and .06em is what `.ostu-share__label`
   already uses. Three different trackings for one editorial role is the same
   fragmentation this pass exists to remove. The brand green STAYS — it is an
   established accent and changing it would be taste, not consistency.

   SPECIFICITY. `.related.products` and `.upsells.products` are (0,2,0) in both
   woocommerce.css:771 and single.css:360/386. The child combinator below reaches
   (0,5,1) — and, just as importantly, `>` guarantees the rules touch the RAIL
   CONTAINER only and can never descend into a product card, which is how the
   price incident of woocommerce.css:671-677 happened. */

.single-product.woocommerce div.product > .related.products,
.single-product.woocommerce div.product > .upsells.products {
  margin-top: var(--space-24, 24px);
  padding-top: var(--space-56, 56px);
  border-top: 1px solid var(--border-strong, #cbd5e1);
}

.single-product.woocommerce div.product > .related.products::before {
  font-size: var(--fs-2xs, 12px);
  font-weight: var(--fw-semibold, 600);
  letter-spacing: var(--label-sm-tracking, .06em);
  margin-bottom: var(--space-8, 8px);
}

/* Phones: same rule, tighter. single.css:472 sets 36px here at (0,2,0); the
   chain above is (0,5,1) and would otherwise carry the desktop 56px onto a
   375px screen, where it is a screenful of nothing. */
@media (max-width: 768px) {
  .single-product.woocommerce div.product > .related.products,
  .single-product.woocommerce div.product > .upsells.products {
    margin-top: var(--space-16, 16px);
    padding-top: var(--space-40, 40px);
  }
}
