/* WDK single-product (PDP) — loads ONLY on is_product() via inc/wdk-single.php.
 *
 * CW-parity pass over Porto's PDP markup. The buy ladder (.cw-vl*, snippets
 * 115/116) styles itself and is NOT restyled here; this sheet owns the frame
 * around it: title voice, subtitle, meta cleanup, the assurance band, the
 * reviews area (WP comment form inside Porto's #tab-reviews) and the related
 * slider heading. Every selector is scoped to body.wdk-pdp-page.
 * Tokens are namespaced --wdks-* and the sheet is self-sufficient.
 */

:root{
  --wdks-jade:#3EB785;
  --wdks-deep:#1F8A5F;
  --wdks-jadetext:#177A52;
  --wdks-cta:#177A52;
  --wdks-cta-hover:#0F6342;
  --wdks-mint:#F1F9F5;
  --wdks-ink:#151917;
  --wdks-mut:#6C7570;
  --wdks-paper:#F7F8F7;
  --wdks-card:#FFFFFF;
  --wdks-line:#E9EDEA;
  --wdks-line-2:#D9E0DB;
  --wdks-display:'Archivo Black','Arial Black',Impact,sans-serif;
  --wdks-ui:'Open Sans',-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --wdks-r:10px;
  --wdks-r-sm:6px;
}

/* ============================================================
   0. GALLERY COLUMN — bigger main image, and it rides the scroll
   (owner, 2026-08-18: "make the main image 30% bigger and sticky").

   Porto splits the PDP into .summary-before.col-md-5 (gallery) and
   .summary.col-md-7 (buy ladder). The main image has no width of
   its own — it fills the column — so the 30% comes from the column:
   41.6667% (5/12) x 1.3 = 54.1667% (6.5/12), with the summary taking
   the remaining 45.8333%. Measured on staging that moves the image
   from 613px to ~806px at a 1600px viewport.

   Porto already sets position:sticky/top:20px on the column, but it
   is a stretch-by-default flex child: any rule that gives the column
   a full-height box silently kills the stick. align-self:flex-start
   pins that down, and the offset is restated here so this sheet owns
   it. Sticky releases at the bottom of .row, which is the intent —
   the image travels the length of the ladder, then scrolls away with
   the assurance band. Only >=992px: below that the columns stack and
   a wider gallery would squeeze the ladder.
   ============================================================ */
@media (min-width:992px){
  body.wdk-pdp-page .product-summary-wrap > .row > .summary-before.col-md-5{
    flex:0 0 54.1667%;max-width:54.1667%;
    align-self:flex-start;
    position:sticky;top:20px;
  }
  body.wdk-pdp-page .product-summary-wrap > .row > .summary.entry-summary.col-md-7{
    flex:0 0 45.8333%;max-width:45.8333%;
  }
  /* A tall image on a short viewport would otherwise hang off the
     bottom while stuck. Cap the stuck box and let it scroll inside. */
  @media (max-height:900px){
    body.wdk-pdp-page .product-summary-wrap > .row > .summary-before.col-md-5{
      max-height:calc(100vh - 40px);overflow-y:auto;scrollbar-width:none;
    }
    body.wdk-pdp-page .product-summary-wrap > .row > .summary-before.col-md-5::-webkit-scrollbar{
      width:0;height:0;
    }
  }
}

/* ============================================================
   1. SUMMARY — the CW voice on Porto's markup.
   ============================================================ */
body.wdk-pdp-page h2.product_title.entry-title{
  font-family:var(--wdks-display)!important;font-weight:400!important;
  text-transform:uppercase;letter-spacing:-0.01em;
  font-size:clamp(26px,3vw,38px)!important;line-height:1.06!important;
  color:var(--wdks-ink)!important;margin:0 0 8px!important;
}
/* "AAA Hybrid<br>THC 18-22%" — one quiet jade eyebrow block under the title. */
body.wdk-pdp-page .product-subtitle{
  font:800 12.5px/1.7 var(--wdks-ui)!important;letter-spacing:.12em;text-transform:uppercase;
  color:var(--wdks-jadetext)!important;margin:0 0 10px!important;
}
/* Star row OFF (owner, 2026-08-18: the grey "★★★★★ (There are no reviews
   yet.)" strip). Hidden outright, not just when empty — the review count the
   shop cards show and the What-people-say card below carry the social proof. */
body.wdk-pdp-page .summary .woocommerce-product-rating{display:none!important}
/* SKU / categories row: CW's PDP does not show catalogue plumbing. */
body.wdk-pdp-page .summary .product_meta{display:none!important}
body.wdk-pdp-page .summary .description,
body.wdk-pdp-page .summary .woocommerce-product-details__short-description{
  font:400 14.5px/1.75 var(--wdks-ui);color:var(--wdks-ink);
}
/* No "Add to wishlist" on the product page (owner, 2026-08-18). Hidden rather
   than unhooked: YITH prints the block through a `wishlist-fragment` that it
   re-renders over AJAX, so a removed hook comes back the moment a fragment
   refresh lands. The rest of the plugin — the wishlist page, the account tab —
   is untouched, and this rule is scoped to the PDP summary only. */
body.wdk-pdp-page .summary .yith-wcwl-add-to-wishlist{display:none!important}

/* ============================================================
   1b. BUY LADDER + EXPANDER TYPE (snippet 115's subtree).
   The snippet ships NO font-family — on CW, Woodmart supplied it;
   Porto's typography never reaches this markup, so every row and
   the whole details expander computed Times New Roman. The wrap
   gets the site's UI face (inheritance dresses everything the
   snippet left bare) and the key elements get bigger sizes
   (owner, 2026-08-18: "change these fonts and make them bigger").
   Snippet 115 itself is untouched.
   ============================================================ */
body.wdk-pdp-page .cw-vlist-wrap{font-family:var(--wdks-ui)}
/* Ladder type joined the sitewide Figtree money/variation voice (owner,
   2026-08-18); 800->600 — the weight the picker settled on. */
body.wdk-pdp-page .cw-vl-name{
  font:600 19px/1.25 'Figtree',var(--wdks-ui);letter-spacing:.01em;color:var(--wdks-ink);
}
body.wdk-pdp-page .cw-vl-price{font:600 17px/1.3 'Figtree',var(--wdks-ui);color:var(--wdks-jadetext)}
body.wdk-pdp-page .cw-vl-price del{
  font-weight:600;font-size:14px;color:var(--wdks-mut);margin-right:6px;
}
/* Description intro, the Show/Hide Product Details toggle, and the spec block. */
body.wdk-pdp-page .cw-desc-intro p{font:400 16px/1.75 var(--wdks-ui);color:var(--wdks-ink)}
body.wdk-pdp-page .cw-desc-toggle{
  font:800 12.5px/1.2 var(--wdks-ui);letter-spacing:.1em;text-transform:uppercase;
  color:var(--wdks-jadetext);
}
body.wdk-pdp-page .cw-desc-details h2{
  font-family:var(--wdks-display);font-weight:400;font-size:19px;line-height:1.2;
  text-transform:uppercase;color:var(--wdks-ink);
}
body.wdk-pdp-page .cw-desc-details li{font:400 15px/1.75 var(--wdks-ui);color:var(--wdks-ink)}
/* 600, not 800 (owner, 2026-08-19: "for the product details section reduce the
   boldness on the bolded text"). The list body is 400, so 600 still reads as a
   label without the spec bullets shouting over the copy above them. */
body.wdk-pdp-page .cw-desc-details li strong,
body.wdk-pdp-page .cw-desc-details li b{font-weight:600}

/* ============================================================
   2. ASSURANCE BAND (markup from inc/wdk-single.php).
   CW's: hairline-topped row of four, square jade bullet, caps
   title, quiet sub.
   ============================================================ */
body.wdk-pdp-page .wdk-pdp-assure{
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:0;
  border-top:1px solid var(--wdks-line-2);border-bottom:1px solid var(--wdks-line-2);
  margin:34px 0 8px;padding:18px 0;
}
body.wdk-pdp-page .wdk-pdp-assure-i{
  display:flex;flex-direction:column;gap:4px;position:relative;
  padding:2px 18px;min-width:0;
}
body.wdk-pdp-page .wdk-pdp-assure-i + .wdk-pdp-assure-i{border-left:1px solid var(--wdks-line)}
body.wdk-pdp-page .wdk-pdp-assure-t{
  font:800 11.5px/1.3 var(--wdks-ui);letter-spacing:.12em;text-transform:uppercase;
  color:var(--wdks-ink);padding-left:16px;position:relative;
}
body.wdk-pdp-page .wdk-pdp-assure-t::before{
  content:"";position:absolute;left:0;top:3px;width:8px;height:8px;
  background:var(--wdks-jade);border-radius:2px;
}
body.wdk-pdp-page .wdk-pdp-assure-s{
  font:400 12px/1.5 var(--wdks-ui);color:var(--wdks-mut);padding-left:16px;
}
@media (max-width:900px){
  body.wdk-pdp-page .wdk-pdp-assure{grid-template-columns:repeat(2,minmax(0,1fr));row-gap:14px}
  body.wdk-pdp-page .wdk-pdp-assure-i:nth-child(3){border-left:0}
}
@media (max-width:480px){
  body.wdk-pdp-page .wdk-pdp-assure{grid-template-columns:minmax(0,1fr)}
  body.wdk-pdp-page .wdk-pdp-assure-i{border-left:0!important;padding:2px 4px}
}

/* ============================================================
   3. REVIEWS — the WP comment form inside Porto's #tab-reviews
   (PDP reviews ARE comments here; the tab headers are hidden and
   the form used to render bare). White card + the checkout pass's
   field language. The title/submit strings are renamed in PHP.
   ============================================================ */
body.wdk-pdp-page #product-tab #tab-reviews{
  background:var(--wdks-card);border:1px solid var(--wdks-line);border-radius:var(--wdks-r);
  box-shadow:0 1px 4px rgba(21,25,23,.05);
  padding:clamp(18px,2.6vw,28px);margin:26px 0 0;
}
body.wdk-pdp-page #tab-reviews #reply-title{
  display:block;font-family:var(--wdks-display)!important;font-weight:400!important;
  text-transform:uppercase;letter-spacing:.01em;
  font-size:clamp(18px,2.2vw,24px)!important;line-height:1.15!important;
  color:var(--wdks-ink)!important;margin:0 0 6px!important;padding:0 0 12px;
  border-bottom:1px solid var(--wdks-line);position:relative;
}
body.wdk-pdp-page #tab-reviews #reply-title small{
  display:inline-block;margin-left:12px;font:700 12px/1.4 var(--wdks-ui);letter-spacing:0;text-transform:none;
}
body.wdk-pdp-page #tab-reviews #reply-title small a{color:var(--wdks-jadetext)}
body.wdk-pdp-page #tab-reviews p.comment-notes{
  font:400 12.5px/1.6 var(--wdks-ui);color:var(--wdks-mut);margin:10px 0 16px;
}
/* Field rows: eyebrow labels + paper-filled controls (checkout's language). */
body.wdk-pdp-page #tab-reviews .comment-form > p{margin:0 0 16px}
body.wdk-pdp-page #tab-reviews .comment-form label{
  display:block;margin:0 0 6px;
  font:800 10.5px/1.4 var(--wdks-ui);letter-spacing:.11em;text-transform:uppercase;
  color:var(--wdks-mut);
}
body.wdk-pdp-page #tab-reviews .comment-form input[type=text],
body.wdk-pdp-page #tab-reviews .comment-form input[type=email],
body.wdk-pdp-page #tab-reviews .comment-form input[type=url],
body.wdk-pdp-page #tab-reviews .comment-form textarea{
  width:100%;box-sizing:border-box;min-height:46px;
  padding:11px 13px;border:1.5px solid transparent;border-radius:var(--wdks-r-sm);
  background:var(--wdks-paper);color:var(--wdks-ink);
  font:400 14.5px/1.4 var(--wdks-ui);box-shadow:none;
  transition:border-color .15s ease,background-color .15s ease;
}
body.wdk-pdp-page #tab-reviews .comment-form textarea{min-height:120px;resize:vertical}
body.wdk-pdp-page #tab-reviews .comment-form input:focus,
body.wdk-pdp-page #tab-reviews .comment-form textarea:focus{
  border-color:var(--wdks-jade);background:var(--wdks-card);outline:none;
}
/* Author + email side by side at desktop. */
@media (min-width:700px){
  body.wdk-pdp-page #tab-reviews .comment-form{
    display:grid;grid-template-columns:repeat(2,minmax(0,1fr));column-gap:16px;
  }
  body.wdk-pdp-page #tab-reviews .comment-form > *{grid-column:1 / -1}
  body.wdk-pdp-page #tab-reviews .comment-form > p.comment-form-author{grid-column:1}
  body.wdk-pdp-page #tab-reviews .comment-form > p.comment-form-email{grid-column:2}
}
/* The Website field is blog plumbing — a review does not need a URL. The field
   stays in the DOM (optional, nothing breaks); it is just not offered. */
body.wdk-pdp-page #tab-reviews .comment-form p.comment-form-url{display:none!important}
body.wdk-pdp-page #tab-reviews p.comment-form-cookies-consent{
  display:flex;align-items:flex-start;gap:9px;
}
body.wdk-pdp-page #tab-reviews p.comment-form-cookies-consent input[type=checkbox]{
  width:18px;height:18px;flex:0 0 auto;accent-color:var(--wdks-deep);margin:1px 0 0;
}
body.wdk-pdp-page #tab-reviews p.comment-form-cookies-consent label{
  display:inline;margin:0;font:400 12.5px/1.6 var(--wdks-ui);letter-spacing:0;text-transform:none;
  color:var(--wdks-mut);
}
body.wdk-pdp-page #tab-reviews .g-recaptcha{margin:0 0 16px}
body.wdk-pdp-page #tab-reviews p.form-submit{margin:0}
body.wdk-pdp-page #tab-reviews p.form-submit input.submit{
  appearance:none;cursor:pointer;min-height:48px;padding:12px 30px;
  background:var(--wdks-cta);border:1.5px solid var(--wdks-cta);border-radius:999px;
  color:#fff;font:800 12.5px/1.2 var(--wdks-ui);letter-spacing:.12em;text-transform:uppercase;
  transition:background-color .15s ease;
}
body.wdk-pdp-page #tab-reviews p.form-submit input.submit:hover{
  background:var(--wdks-cta-hover);border-color:var(--wdks-cta-hover);
}

/* Existing reviews, when they arrive: quiet cards above the form. */
body.wdk-pdp-page #tab-reviews ol.commentlist{list-style:none;margin:0 0 22px;padding:0}
body.wdk-pdp-page #tab-reviews ol.commentlist > li{
  list-style:none;margin:0 0 12px;padding:14px 16px;
  background:var(--wdks-paper);border:1px solid var(--wdks-line);border-radius:var(--wdks-r-sm);
  font:400 13.5px/1.65 var(--wdks-ui);color:var(--wdks-ink);
}
body.wdk-pdp-page #tab-reviews ol.commentlist .comment-author,
body.wdk-pdp-page #tab-reviews ol.commentlist .meta,
body.wdk-pdp-page #tab-reviews ol.commentlist cite{
  font:700 13px/1.4 var(--wdks-ui);font-style:normal;color:var(--wdks-ink);
}
body.wdk-pdp-page #tab-reviews ol.commentlist .comment-metadata,
body.wdk-pdp-page #tab-reviews ol.commentlist time{
  font:400 11.5px/1.4 var(--wdks-ui);color:var(--wdks-mut);
}
body.wdk-pdp-page #tab-reviews ol.commentlist img.avatar{border-radius:50%}

/* The reviews that actually arrived (owner, 2026-08-21).

   Until inc/wdk-reviews.php landed, #tab-reviews rendered porto/comments.php
   — a blog comment thread, no stars and no "(verified owner)" — because
   ReviewX nulls the comments_template path whenever it is not connected to
   its SaaS and WordPress then falls through to the parent theme's generic
   template. The rules above were written against THAT markup (.comment-author,
   .comment-metadata, cite) and still apply to it.

   WooCommerce's own single-product-reviews.php nests differently:

       li > .comment_container > .img-thumbnail + .comment-text > p.meta

   and Porto dresses that shell for a PDP with no card around it, so three of
   its rules fight this one:

     .comment_container  #f5f5f5 fill + 10/10/15 padding — a second, offset
                         card drawn inside this card
     .comment-text       #f5f5f5 fill + min-height:90px — dead space under
                         every review shorter than the avatar
     .img-thumbnail      position:absolute pinned to the li's top-left corner
                         at 80px, which put the gravatar half outside this
                         card's 14/16 padding and under its corner radius: a
                         clipped grey blob on every row

   Strip all three back to nothing and give the avatar a real 40px slot inside
   the padding, with padding-left on the li opening the gutter it sits in. The
   li is already position:relative — that is what the absolute avatar measures
   from, so top/left here are card-padding coordinates, not page ones. */
body.wdk-pdp-page #tab-reviews ol.commentlist > li{padding-left:70px}
body.wdk-pdp-page #tab-reviews ol.commentlist .comment_container{
  background:none;border:0;padding:0;margin:0;min-height:0;
}
body.wdk-pdp-page #tab-reviews ol.commentlist .comment-text{
  background:none;border:0;padding:0;margin:0;min-height:0;
}
body.wdk-pdp-page #tab-reviews ol.commentlist .img-thumbnail{
  position:absolute;top:14px;left:16px;width:40px;height:40px;
  padding:0;border:0;background:none;box-shadow:none;
}
body.wdk-pdp-page #tab-reviews ol.commentlist img.avatar{
  position:static;display:block;width:40px;height:40px;
  padding:0;border:0;background:none;box-shadow:none;border-radius:50%;
}
body.wdk-pdp-page #tab-reviews ol.commentlist .comment-text .description p:last-child{
  margin-bottom:0;
}
/* p.meta carries the author, the badge and the date on one line and inherits
   the 700/13px rule above; the date and dash step back down to the muted
   size the old .comment-metadata rule gave them, and the badge picks up the
   jade the rest of the PDP uses for anything affirmative. */
body.wdk-pdp-page #tab-reviews ol.commentlist .woocommerce-review__verified{
  font-style:normal;font-weight:700;color:var(--wdks-jadetext);
}
body.wdk-pdp-page #tab-reviews ol.commentlist .woocommerce-review__dash,
body.wdk-pdp-page #tab-reviews ol.commentlist .woocommerce-review__published-date{
  font:400 11.5px/1.4 var(--wdks-ui);color:var(--wdks-mut);
}
/* "5 reviews for <product>" is WooCommerce's own h2 and had no rule at all,
   so it rendered as a bare Poppins heading above a card whose other heading
   (#reply-title) is display-face uppercase. Same treatment, same rule. */
body.wdk-pdp-page #tab-reviews .woocommerce-Reviews-title{
  display:block;font-family:var(--wdks-display)!important;font-weight:400!important;
  text-transform:uppercase;letter-spacing:.01em;
  font-size:clamp(18px,2.2vw,24px)!important;line-height:1.15!important;
  color:var(--wdks-ink)!important;margin:0 0 18px!important;padding:0 0 12px;
  border-bottom:1px solid var(--wdks-line);
}
body.wdk-pdp-page #tab-reviews .woocommerce-Reviews-title span{font:inherit;color:inherit}


/* Porto's mobile tab-accordion headers (ADDITIONAL INFORMATION / REVIEWS (0)).
   CW's PDP has neither: specs live in the summary expander (snippet 115) and
   the review card is always open — which is exactly the state the panes are
   in when the headers are simply not shown. Desktop already hides them. */
body.wdk-pdp-page #product-tab h2.resp-accordion{display:none!important}

/* ============================================================
   4. THE FOUR-COLUMN PRODUCTS WIDGET BAND (Featured / Best
   Selling / Latest / Top Rated) — Porto block-widget furniture
   with no CW counterpart. Off, on the PDP only.
   ============================================================ */
body.wdk-pdp-page .wp-block-columns:has(.widget_products){display:none!important}

/* ============================================================
   5. RELATED ("Also on this shelf" — renamed in PHP).
   Cards are the shop grid's own language; this owns the heading
   and the slider chrome only.
   ============================================================ */
/* The related section prints outside the summary's measure and ran flush to
   the viewport edge; CW keeps its shelf inside the page gutters. */
body.wdk-pdp-page .related.products{
  padding-left:clamp(16px,3vw,40px);padding-right:clamp(16px,3vw,40px);
  max-width:1610px;margin-left:auto;margin-right:auto;box-sizing:border-box;
}
body.wdk-pdp-page .related.products > h2.slider-title,
body.wdk-pdp-page .related.products h2.slider-title{
  font-family:var(--wdks-display)!important;font-weight:400!important;
  text-transform:uppercase;letter-spacing:-0.01em;
  font-size:clamp(20px,2.4vw,26px)!important;line-height:1.1!important;
  color:var(--wdks-ink)!important;margin:30px 0 18px!important;
}
body.wdk-pdp-page .related.products .owl-dot span{background:var(--wdks-line-2)}
body.wdk-pdp-page .related.products .owl-dot.active span{background:var(--wdks-jade)}
body.wdk-pdp-page .related.products .owl-nav button{color:var(--wdks-ink)}

/* ============================================================
   6. QUANTITY STEPPER (owner, 2026-08-18: "give product page the
   same qty selectors" — the cart's pill). Same declarations as
   wdk-cart.css §stepper, same markup underneath (Woo qty input +
   Porto's .minus/.plus buttons), so the two render identically.
   Scoped to the summary's add-to-cart form; the buy-ladder rows
   (snippets 115/116) carry their own steppers and are untouched.
   ============================================================ */
body.wdk-pdp-page .summary form.cart div.quantity{
  display:inline-flex!important;align-items:center;border:1px solid var(--wdks-line);
  border-radius:99px;overflow:hidden;background:var(--wdks-card);height:38px;
  float:none!important;margin:0 14px 0 0!important;
}
body.wdk-pdp-page .summary form.cart div.quantity .minus,
body.wdk-pdp-page .summary form.cart div.quantity .plus{
  appearance:none;-webkit-appearance:none;border:0;background:none;
  width:36px;height:36px;cursor:pointer;color:var(--wdks-ink);
  font:400 17px/1 var(--wdks-ui);display:flex;align-items:center;justify-content:center;
  transition:background .14s,color .14s;padding:0;border-radius:0;
}
body.wdk-pdp-page .summary form.cart div.quantity .minus:hover,
body.wdk-pdp-page .summary form.cart div.quantity .plus:hover{
  background:var(--wdks-mint);color:var(--wdks-cta);
}
body.wdk-pdp-page .summary form.cart div.quantity input.qty{
  width:44px!important;height:36px;border:0!important;background:none!important;
  text-align:center;font:600 14px/1 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-variant-numeric:tabular-nums;color:var(--wdks-ink);
  box-shadow:none!important;padding:0!important;-moz-appearance:textfield;min-height:0;
}
body.wdk-pdp-page .summary form.cart div.quantity input.qty::-webkit-outer-spin-button,
body.wdk-pdp-page .summary form.cart div.quantity input.qty::-webkit-inner-spin-button{
  -webkit-appearance:none;margin:0;
}

/* ============================================================
   7. REVIEWS, the line the card missed: "Logged in as …" is
   p.logged-in-as, which none of the §3 rules reached, so it fell
   through to a serif default (owner, 2026-08-18: "change font
   here to match our font").
   ============================================================ */
body.wdk-pdp-page #tab-reviews{font-family:var(--wdks-ui)}
body.wdk-pdp-page #tab-reviews p.logged-in-as{
  font:400 13px/1.6 var(--wdks-ui)!important;color:var(--wdks-mut);margin:10px 0 16px;
}
body.wdk-pdp-page #tab-reviews p.logged-in-as a{
  color:var(--wdks-jadetext);text-decoration:underline;text-underline-offset:3px;
}

/* ============================================================
   8. "ALSO ON THIS SHELF": the card's SELECT dropdown was clipped
   at the carousel's bottom edge (owner, 2026-08-18) — Owl's
   .owl-stage-outer is overflow:hidden, which is also what hides
   the off-screen slides. Split the axes: clip X (slides stay
   hidden), free Y (the options panel can extend past the row).
   `clip` rather than `hidden` on purpose — hidden would make the
   other axis scrollable instead of visible per css-overflow-3.
   The open card then needs to stack above the reviews card below.
   ============================================================ */
body.wdk-pdp-page .related.products .owl-stage-outer{
  overflow-x:clip!important;overflow-y:visible!important;
}
body.wdk-pdp-page .related.products{position:relative;z-index:5}
body.wdk-pdp-page .related.products .cw-card.open{position:relative;z-index:10}

/* ============================================================
   9. ULTIMATE BUNDLE PDPs (owner, 2026-08-18: "match our theme,
   remove the truck image, move the description below" — the move
   is PHP, wdk_single_bundle_desc_below in inc/wdk-single.php).
   Scope: .product-type-ultimate_bundle, the class Woo puts on the
   product div (not on body).
   ============================================================ */

/* The truck: every bundle excerpt embeds delivery-truck-product-*.jpg. Hidden
   by src, not by position, so it dies wherever the excerpt renders — and on
   any other product that pasted the same banner. Content is untouched. */
body.wdk-pdp-page .summary img[src*="delivery-truck"]{display:none!important}

/* Price line: bundles show Woo's del/ins pair (no ladder). The active price
   gets the display face; the struck one steps back. */
body.wdk-pdp-page .product-type-ultimate_bundle .summary > p.price{
  display:flex;align-items:baseline;gap:12px;margin:2px 0 14px;
}
body.wdk-pdp-page .product-type-ultimate_bundle .summary > p.price ins{
  text-decoration:none;font-family:var(--cw-money,'Figtree',sans-serif);font-weight:600;
  font-size:32px;line-height:1;color:var(--wdks-ink);
}
body.wdk-pdp-page .product-type-ultimate_bundle .summary > p.price del{
  font:600 15px/1 'Figtree',var(--wdks-ui);color:var(--wdks-mut);
}

/* Included items — the plugin's list restyled as a theme card: white ground,
   hairline rows, UI face, jade FREE badge (the plugin inlines its own green,
   hence the !important pair). */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-items-wrap{
  background:var(--wdks-card);border:1px solid var(--wdks-line);border-radius:var(--wdks-r);
  box-shadow:0 1px 4px rgba(21,25,23,.05);padding:16px 18px;margin:0 0 18px;
  font-family:var(--wdks-ui);
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-items-title{
  font:800 11.5px/1.4 var(--wdks-ui);letter-spacing:.12em;text-transform:uppercase;
  color:var(--wdks-mut);margin:0 0 10px;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-items-list{
  list-style:none;margin:0;padding:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-item{
  display:flex;align-items:center;gap:14px;margin:0;padding:11px 0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-item + .ub-bundle-item{
  border-top:1px solid var(--wdks-line);
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-thumb-wrap{flex:none;line-height:0}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-thumb{
  width:54px;height:54px;border-radius:8px;object-fit:cover;border:1px solid var(--wdks-line);
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-details{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-qty{
  font:700 12px/1 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:var(--wdks-mut);
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-name{
  font:800 14px/1.35 var(--wdks-ui);color:var(--wdks-ink)!important;text-decoration:none;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-name:hover{color:var(--wdks-jadetext)!important}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-line-price,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-line-price .amount{
  font:600 12.5px/1 var(--wdks-ui);color:var(--wdks-mut);
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-badge{
  background:var(--wdks-jade)!important;color:#fff!important;
  font:800 10px/1 var(--wdks-ui);letter-spacing:.1em;text-transform:uppercase;
  padding:4px 8px;border-radius:99px;
}

/* The relocated description (now after the form): quiet body copy with a
   hairline above, so it reads as the footnote of the buy block. */
body.wdk-pdp-page .product-type-ultimate_bundle .summary > .description,
body.wdk-pdp-page .product-type-ultimate_bundle .summary > .woocommerce-product-details__short-description{
  border-top:1px solid var(--wdks-line);margin-top:18px;padding-top:16px;
}

/* Bundle price $ steps down like every large figure (owner, 2026-08-18);
   the struck one keeps a full-size mark, same as everywhere else. */
body.wdk-pdp-page .product-type-ultimate_bundle .summary > p.price ins .woocommerce-Price-currencySymbol{
  font-size:.6em}

/* ============================================================
   LADDER STEPPERS — the cart's selector, unshaded (owner,
   2026-08-18: "use this selector for the product pages" /
   "remove the shading"). Overrides snippet 115's grey capsule:
   white field, hairline border, flat - / +, Figtree count.
   ============================================================ */
body.wdk-pdp-page .cw-vl-qty{
  background:#fff;border:1.5px solid var(--wdks-line-2);
  border-radius:var(--wdks-r-sm);overflow:hidden}
body.wdk-pdp-page .cw-vl-qty .cw-vl-minus,
body.wdk-pdp-page .cw-vl-qty .cw-vl-plus{
  background:transparent;border:0;color:var(--wdks-ink)}
body.wdk-pdp-page .cw-vl-qty .cw-vl-minus:hover,
body.wdk-pdp-page .cw-vl-qty .cw-vl-plus:hover{color:var(--wdks-jadetext)}
body.wdk-pdp-page .cw-vl-qty input.cw-vl-input[type="text"]{
  background:#fff;border:0;
  font-family:'Figtree',var(--wdks-ui);font-weight:600}

/* ============================================================
   GALLERY: THUMBNAIL RAIL ON THE LEFT  (owner, 2026-08-19:
   "image gallery should go on the left side of the main image")

   Porto ships the thumbs UNDER the main image. It does have a
   vertical-thumb variant, but only inside the whole 'transparent'
   product layout — switching to that would redraw the entire PDP,
   so the rail is rebuilt here instead.

   .woocommerce-product-gallery__wrapper holds exactly two children:
   .product-images (the main Owl slider) and .product-thumbnails.
   Turning the wrapper into a flex row and ordering the thumbs first
   is the whole move. The thumbs are themselves an Owl carousel with
   an inline stage width, a translate3d transform and per-item widths
   and margins — every one of those is overridden with !important,
   which beats an inline style, so the stage can be a plain column
   and Owl's re-measures on resize can never claw it back.

   Desktop only: at =<991px the rail would eat a third of the screen,
   so the thumbs stay beneath the image exactly as Porto draws them.
   assets/wdk-single.js refreshes the MAIN slider afterwards — it had
   measured itself against the full-width container before the rail
   took its share.
   ============================================================ */
@media (min-width:992px){
  body.wdk-pdp-page .woocommerce-product-gallery__wrapper{
    display:flex;flex-direction:row;align-items:flex-start;gap:14px;
  }
  body.wdk-pdp-page .woocommerce-product-gallery__wrapper > .product-images{
    order:2;flex:1 1 auto;min-width:0;margin:0;
  }
  body.wdk-pdp-page .woocommerce-product-gallery__wrapper > .product-thumbnails{
    order:1;flex:0 0 96px;width:96px;margin:0;
  }
  /* the rail: Owl's horizontal stage becomes a plain column */
  body.wdk-pdp-page .product-thumbnails .owl-stage-outer{overflow:visible!important;width:auto!important}
  body.wdk-pdp-page .product-thumbnails .owl-stage{
    width:auto!important;transform:none!important;transition:none!important;
    display:flex!important;flex-direction:column!important;gap:10px!important;
    padding:0!important;margin:0!important;
  }
  body.wdk-pdp-page .product-thumbnails .owl-item{
    width:96px!important;max-width:96px!important;margin:0!important;float:none!important;
  }
  body.wdk-pdp-page .product-thumbnails .owl-item .img-thumbnail{margin:0}
  body.wdk-pdp-page .product-thumbnails .owl-item img{
    width:100%;height:auto;display:block;border-radius:8px;
  }
  /* a carousel that no longer scrolls has no use for its controls */
  body.wdk-pdp-page .product-thumbnails .owl-nav,
  body.wdk-pdp-page .product-thumbnails .owl-dots{display:none!important}
  /* the selected thumb reads as selected */
  body.wdk-pdp-page .product-thumbnails .owl-item img{
    border:1px solid var(--wdks-line);transition:border-color .16s;
  }
  body.wdk-pdp-page .product-thumbnails .owl-item.selected img,
  body.wdk-pdp-page .product-thumbnails .owl-item img:hover{
    border-color:var(--wdks-jade);
  }
}


/* ============================================================
   ROUND 25 (owner, 2026-08-19): NO GREY FRAMES IN THE GALLERY
   "there is a grey border around the images remove it."

   Two Porto/Bootstrap frames were drawing them, both on the
   `.img-thumbnail` DIV that wraps every gallery image:
     .img-thumbnail                                   1px #DEE2E6 + 4px radius
                                                      + .25rem padding + white bg
     .product-thumbs-slider … .img-thumbnail          1px var(--porto-gray-1)
     … .owl-item.selected .img-thumbnail              2px var(--porto-heading-color)
   The last one was ALSO Porto's selected-thumb affordance, so it cannot just be
   deleted: the jade indicator below takes the job over, and it moves OUT of the
   =<992px rail block so it works at every width (the rail itself is still
   desktop-only).

   The thumb's own border stays at 1px but goes TRANSPARENT rather than away, so
   the jade state costs no layout shift.
   ============================================================ */
body.wdk-pdp-page .woocommerce-product-gallery__wrapper .img-thumbnail{
  border:0!important;padding:0!important;border-radius:0!important;
  background:transparent!important;
}
body.wdk-pdp-page .product-thumbnails .owl-item img{
  border:1px solid transparent;border-radius:8px;transition:border-color .16s;
}
body.wdk-pdp-page .product-thumbnails .owl-item.selected img,
body.wdk-pdp-page .product-thumbnails .owl-item img:hover{
  border-color:var(--wdks-jade);
}

/* ============================================================
   ROUND 25b (owner, 2026-08-19)
   ============================================================ */

/* --- no zoom "+" over the gallery ------------------------------------
   "remove plus sign in product page images." It is Porto's lightbox
   affordance: `span.zoom` (absolute, z-index 1000, bottom-right of the main
   image) wrapping `<i class="porto-icon-plus">`, an icon-font glyph. Hiding
   the span takes the icon with it and leaves the drag/swipe carousel exactly
   as it was — the image itself was never the zoom trigger. */
body.wdk-pdp-page .woocommerce-product-gallery__wrapper .zoom,
body.wdk-pdp-page .product-images .zoom{display:none!important}

/* --- the product title speaks in the card's voice ---------------------
   Owner picked "cards UI-800 everywhere" (2026-08-19) after asking whether
   the cart/checkout titles matched the shop and category cards. They did not:
   the card is `.cw-nm` = 800 var(--cw-ui) uppercase +.05em, while this ladder
   name was Figtree 600 sentence case and the cart/checkout were Archivo Black
   400. `--cw-ui` (not --wdks-ui) is deliberate — it is the token the CARD
   reads, and it carries NO 'Open Sans', so anything else would land a
   near-match instead of the same face. Size stays per-surface. */
body.wdk-pdp-page .cw-vl-name{
  font-family:var(--cw-ui);font-weight:800;
  text-transform:uppercase;letter-spacing:.05em;
}

/* ============================================================
   9b. BUNDLE STEPPERS + the duplicate form qty (owner,
   2026-08-19: "the mnm pages needs to look like our product
   pages, same qty selector … remove the qty selector beside the
   add to cart button").

   The plugin ships a plain −/[input]/+ trio (.ub-item-qty-wrap,
   assets/css/bundle-frontend.css) that reads as a raw form
   control. It is restyled to the CART/CHECKOUT stepper (owner,
   2026-08-19, second pass: 44px tall, 6px radius, 1.5px line-2
   border, 38px jade-text glyphs, 18px cw-money count) — the same
   declarations as wdk-checkout.css § tr.cart_item .quantity, so
   the control a shopper drives on the PDP is the one they meet
   again in the cart. The plugin's own sizes are overridden, not
   its markup — no plugin file is touched, so a nukeleus
   auto-update cannot revert this.

   The form-level quantity is dropped because on a pick-N bundle
   it means "how many whole boxes", which nobody reads it as when
   every row above already has its own stepper. It stays in the
   DOM (display:none still submits) at value 1, so one bundle is
   added per click exactly as before.
   ============================================================ */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-qty-wrap{
  display:inline-flex!important;align-items:stretch!important;gap:0!important;
  height:44px;width:auto;overflow:hidden;flex:none;
  margin:0!important;padding:0!important;
  background:var(--wdks-card);
  border:1.5px solid var(--wdks-line-2);
  border-radius:var(--wdks-r-sm);
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-qty-wrap .ub-qty-btn{
  appearance:none;-webkit-appearance:none;
  display:flex!important;align-items:center!important;justify-content:center!important;
  width:38px!important;flex:0 0 38px!important;height:auto!important;min-height:0!important;
  padding:0!important;margin:0!important;cursor:pointer;
  border:0!important;border-radius:0!important;background:transparent!important;
  box-shadow:none!important;text-decoration:none!important;
  font:700 17px/1 var(--wdks-ui)!important;letter-spacing:0!important;
  text-transform:none!important;color:var(--wdks-jadetext)!important;
  transition:background-color .15s ease,color .15s ease;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-qty-wrap .ub-qty-btn:hover,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-qty-wrap .ub-qty-btn:active{
  background:var(--wdks-jade)!important;color:#fff!important;
}
body.wdk-pdp-page .product-type-ultimate_bundle input.ub-item-qty-input{
  width:36px!important;min-width:36px!important;max-width:36px!important;
  height:100%!important;min-height:0!important;box-sizing:border-box!important;
  margin:0!important;padding:0 4px!important;
  border:0!important;border-radius:0!important;background:transparent!important;
  box-shadow:none!important;text-align:center!important;
  font-family:var(--cw-money,'Figtree',sans-serif)!important;font-weight:600!important;
  font-size:18px!important;line-height:1!important;color:var(--wdks-ink)!important;
  -moz-appearance:textfield;appearance:textfield;
}
body.wdk-pdp-page .product-type-ultimate_bundle input.ub-item-qty-input:focus{outline-offset:-2px}
body.wdk-pdp-page .product-type-ultimate_bundle input.ub-item-qty-input::-webkit-outer-spin-button,
body.wdk-pdp-page .product-type-ultimate_bundle input.ub-item-qty-input::-webkit-inner-spin-button{
  -webkit-appearance:none;appearance:none;margin:0;
}

/* Per-row stepper is the only qty control on a bundle PDP. */
body.wdk-pdp-page .product-type-ultimate_bundle .summary form.cart div.quantity{
  display:none!important;
}

/* The free-delivery banner that used to sit in these excerpts is removed from
   the content itself now (owner, 2026-08-19), not hidden — this rule stays as
   a safety net for any product whose excerpt still embeds one. */
body.wdk-pdp-page .summary img[src*="free-delivery"]{display:none!important}

/* ============================================================
   9c. SALE BADGE ON THE PRICE LINE (owner, 2026-08-19: "remove
   the badge … the badge should be like the category pages next
   to the prices" / "should show sale price then reg price then
   the sale badge").

   Porto's corner flash (div.onsale, "-71%") is dropped, and the
   grid card's SAVE pill takes its place beside the price — same
   declarations as .cw-salerow .off in wdk-shop.css, same label
   from cw_save_label(), so a PDP badge and a grid badge are one
   thing in two places. The sale-before-regular order is done in
   PHP (wdk_single_price_save_badge, inc/wdk-single.php).
   ============================================================ */
body.wdk-pdp-page .onsale{display:none!important}

body.wdk-pdp-page .summary .wdk-pdp-save{
  display:inline-block;align-self:center;
  font:800 10.5px/1 var(--wdks-ui);
  background:var(--cw-badge,#FF9800);color:var(--cw-badge-ink,#fff);
  letter-spacing:.05em;padding:5px 7px;border-radius:3px;
  font-variant-numeric:tabular-nums;vertical-align:middle;white-space:nowrap;
}
/* Spacing is margins, not the flex gap §9 gave bundles, so the same rhythm
   holds on every product type — bundle price lines are flex, simple ones are
   plain inline flow, and a variable range (no badge) is untouched either way. */
body.wdk-pdp-page .product-type-ultimate_bundle .summary > p.price{gap:0}
body.wdk-pdp-page .summary > p.price del{margin-left:12px}
body.wdk-pdp-page .summary > p.price .wdk-pdp-save{margin-left:12px}


/* ============================================================
   9d. BUNDLE PDP — "THE SHELF" (owner, 2026-08-19: "bundle pages
   needs a redesign to match our theme … two different looking
   free badges, fonts are all different"; direction picked from
   the two mock-ups, plus "make Pick your free gift a bit bigger"
   and "make the choose 1 color green").

   The block stops being the plugin's grey widget and becomes the
   same shelf the buy ladder draws on every other PDP: no card,
   flush hairline rows, the card face on names, Figtree on every
   figure, and ONE free treatment — the word FREE in jade caps
   sitting over the struck retail price in a right-hand money
   column. It replaces BOTH badges the page used to show (the
   plugin's inline .ub-badge pill and its green square
   .ub-free-choice-free-label).

   Layout mechanism: .ub-item-details / .ub-free-choice-details
   are flat flex rows in the plugin, so the money column is built
   with explicit grid placement of the plugin's own children —
   no markup is changed and no plugin file is touched.
     col 1  qty ("1 x")        row 1
     col 2  name               row 1   |  sold-out chip row 2
     col 3  FREE badge         row 1   |  price / stepper row 2
     rows   variation selects  row 3, spanning cols 1-2
   A row with no FREE badge lifts its price to span rows 1-2 so it
   stays optically centred; that is the only :has() in the block
   and its absence degrades to a slightly low price, never to an
   overlap.

   This section supersedes §9's card treatment of
   .ub-bundle-items-wrap and its .ub-badge pill. §9b (the stepper)
   and §9c (the price line + SAVE pill) are deliberately untouched.
   ============================================================ */

/* The one token this section needs that §0 did not declare. */
:root{--wdks-warn:#A52016}

/* --- the container: no card, no shadow, no padding ---------------- */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-items-wrap{
  background:none;border:0;border-radius:0;box-shadow:none;
  padding:0;margin:4px 0 0;font-family:var(--wdks-ui);
}

/* --- section headings: eyebrow + trailing hairline ---------------- */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-items-title,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-title{
  display:flex;align-items:center;gap:10px;
  font:800 11.5px/1.4 var(--wdks-ui);letter-spacing:.12em;text-transform:uppercase;
  color:var(--wdks-mut);margin:0 0 4px;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-items-title::after,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-title::after{
  content:"";flex:1;height:1px;background:var(--wdks-line);
}
/* The gift heading is the one line in the block that asks the shopper to
   decide, so it reads a size up on the contents heading (owner). */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-title{
  font-size:13.5px;letter-spacing:.1em;color:var(--wdks-ink);
}
/* Chips injected by inc/wdk-single.php: the contents count, and the green
   "Choose 1" the gift heading carries (owner: green, not the orange
   required-state). The hairline keeps the two chips apart at a glance. */
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-chip{
  flex:0 0 auto;
  font:800 10px/1 var(--wdks-ui);letter-spacing:.08em;text-transform:uppercase;
  color:var(--wdks-jadetext);background:var(--wdks-mint);
  border:1px solid transparent;border-radius:99px;padding:4px 8px;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-chip.is-pick{
  font-size:10.5px;color:var(--wdks-deep);border-color:#BFE3D2;padding:4px 9px;
}

/* --- rows: hairlines only, the ladder's rhythm -------------------- */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-items-list{
  list-style:none;margin:0;padding:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-item{
  display:flex;align-items:center;gap:16px;margin:0;padding:16px 0;
  border-bottom:1px solid var(--wdks-line);border-top:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-item:last-child{
  border-bottom:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-thumb-wrap{
  flex:0 0 auto;line-height:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-thumb{
  width:84px;height:84px;border-radius:8px;object-fit:cover;display:block;
  background:var(--wdks-paper);border:1px solid var(--wdks-line);
}

/* --- the three-column grid the money column hangs off ------------- */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-details,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-details{
  display:grid;flex:1 1 auto;min-width:0;
  grid-template-columns:auto minmax(0,1fr) auto;
  column-gap:8px;row-gap:2px;align-items:center;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-qty{
  grid-column:1;grid-row:1;
  font:600 12.5px/1.4 var(--cw-money,'Figtree',sans-serif);color:var(--wdks-mut);
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-name{
  grid-column:2;grid-row:1;min-width:0;
  font:800 14.5px/1.3 var(--cw-ui,var(--wdks-ui));letter-spacing:.045em;text-transform:uppercase;
  color:var(--wdks-ink)!important;text-decoration:none;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-name:hover{
  color:var(--wdks-jadetext)!important;
}

/* --- ONE free treatment: jade caps over the struck price ---------- */
/* The plugin inlines a per-item background colour on this badge, so the
   reset has to carry !important; the pill it used to draw is gone. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-badge.ub-badge-start{
  grid-column:3;grid-row:1;justify-self:end;align-self:end;
  background:none!important;color:var(--wdks-jadetext)!important;
  font:800 11px/1 var(--wdks-ui);letter-spacing:.1em;text-transform:uppercase;
  padding:0;border-radius:0;white-space:nowrap;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-line-price,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-line-price .amount{
  font:600 15px/1.45 var(--cw-money,'Figtree',sans-serif);color:var(--wdks-mut);
  font-variant-numeric:tabular-nums;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-line-price{
  grid-column:3;grid-row:2;justify-self:end;align-self:start;
  white-space:nowrap;margin:0;
}
/* No FREE badge on this row: the price is the only thing in the column, so
   it centres across both rows instead of sitting under an empty cell. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-item:not(:has(.ub-badge-start)) .ub-item-line-price{
  grid-row:1 / 3;align-self:center;
}
/* Woo's del/ins wrapping inside the line price. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-line-price del{
  text-decoration:line-through;color:var(--wdks-mut);
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-line-price .woocommerce-Price-currencySymbol{
  font-size:.72em;
}

/* --- sold-out component: a chip under the name ------------------- */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-badge.ub-badge-soldout{
  grid-column:2;grid-row:2;justify-self:start;
  background:#FCF3F2!important;color:var(--wdks-warn,#A52016)!important;
  border:1px solid #E7C9C6;border-radius:3px;padding:4px 6px;
  font:800 9.5px/1 var(--wdks-ui);letter-spacing:.08em;text-transform:uppercase;
}

/* --- the qty stepper on editable bundles keeps §9b's look, and just
       takes the money column's place ------------------------------ */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-qty-wrap{
  grid-column:3;grid-row:1 / 3;justify-self:end;align-self:center;
  margin:0!important;
}

/* Pick-any-N bundles list up to 15 rows (mix-match-hash-14g), where an 84px
   thumb turns the picker into a scroll. Those are exactly the bundles that
   hide prices, so the shape is addressable: same design, tighter rhythm. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-prices-hidden .ub-bundle-item{
  padding:11px 0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-prices-hidden .ub-item-thumb{
  width:64px;height:64px;
}

/* --- variation selects: the cart/checkout field ------------------- */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-variation-selects{
  grid-column:1 / 3;grid-row:3;
  display:flex;flex-direction:column;gap:8px;width:auto;margin:8px 0 0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-variation-row{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-variation-label{
  font:800 10px/1 var(--wdks-ui);letter-spacing:.12em;text-transform:uppercase;
  color:var(--wdks-mut);white-space:nowrap;margin:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle select.ub-variation-select{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  min-width:190px;max-width:100%;height:44px;min-height:44px;
  padding:0 34px 0 13px;margin:0;
  border:1.5px solid var(--wdks-line-2);border-radius:var(--wdks-r-sm);
  background-color:var(--wdks-card);color:var(--wdks-ink);
  font:600 14px/1 var(--cw-money,'Figtree',sans-serif);cursor:pointer;box-shadow:none;
  background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23177A52' stroke-width='2'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;background-size:12px 8px;
}
body.wdk-pdp-page .product-type-ultimate_bundle select.ub-variation-select:focus{
  border-color:var(--wdks-jade);outline:2.5px solid var(--wdks-jade);outline-offset:2px;
}
/* The plugin's own not-yet-chosen / sold-out states, in the theme's red. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-variation-missing select.ub-variation-select,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-variation-oos select.ub-variation-select{
  border-color:var(--wdks-warn,#A52016);
}
/* bundle-frontend.js appends this AFTER .ub-variation-selects when the chosen
   combination is sold out. It is a grid child like any other, so it is placed
   explicitly — auto-placement would drop it into the first free cell (under
   the qty) instead of under the dropdown it belongs to. Its colour and margin
   are inline, hence the !important pair. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-variation-soldout{
  grid-column:1 / 4;grid-row:4;justify-self:start;
  margin:6px 0 0!important;
  font:800 10px/1.4 var(--wdks-ui)!important;letter-spacing:.08em;text-transform:uppercase;
  color:var(--wdks-warn,#A52016)!important;
}

/* --- the gift picker -------------------------------------------- */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-wrap{
  border-top:0;margin:26px 0 0;padding:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-list{
  list-style:none;margin:0;padding:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-item{
  border-bottom:1px solid var(--wdks-line);padding:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-item:last-child{
  border-bottom:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-label{
  display:flex;align-items:center;gap:14px;cursor:pointer;font-weight:400;
  margin:3px -12px;padding:13px 12px;border-radius:8px;
  border:1.5px solid transparent;background:var(--wdks-card);
  transition:background-color .14s ease,border-color .14s ease;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-label:hover{
  background:var(--wdks-mint);
}
/* Selected row. The plugin sets no class on check, so the state is read off
   the input itself; without :has() the row simply stays white and the jade
   box still marks the choice. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-label:has(.ub-free-choice-radio:checked){
  background:var(--wdks-mint);border-color:var(--wdks-jade);
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-label:focus-within{
  outline:2.5px solid var(--wdks-jade);outline-offset:2px;
}
/* The picker control: a jade check box, the shape the store uses for a
   made choice (cart/checkout), not the plugin's grey square. */
body.wdk-pdp-page .product-type-ultimate_bundle input.ub-free-choice-radio{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  flex:0 0 auto;width:24px;height:24px;margin:0;position:relative;cursor:pointer;
  border:2px solid var(--wdks-line-2);border-radius:6px;background:var(--wdks-card);
  transition:background-color .14s ease,border-color .14s ease;
}
body.wdk-pdp-page .product-type-ultimate_bundle input.ub-free-choice-radio:checked{
  background:var(--wdks-deep);border-color:var(--wdks-deep);
}
body.wdk-pdp-page .product-type-ultimate_bundle input.ub-free-choice-radio:checked::after{
  content:"";position:absolute;left:7px;top:3px;width:6px;height:12px;
  border:solid #fff;border-width:0 2.5px 2.5px 0;transform:rotate(45deg);
}
body.wdk-pdp-page .product-type-ultimate_bundle input.ub-free-choice-radio:disabled{
  cursor:not-allowed;background:var(--wdks-paper);border-color:var(--wdks-line);
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-item.ub-out-of-stock{
  opacity:.55;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-item.ub-out-of-stock .ub-free-choice-label{
  cursor:not-allowed;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-item.ub-out-of-stock .ub-free-choice-label:hover{
  background:var(--wdks-card);
}
/* Gift thumbs sit a size down on the contents above them. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-label .ub-item-thumb{
  width:64px;height:64px;
}
/* The green square badge is gone: FREE joins the money column, exactly as it
   does on the contents rows above. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-free-label{
  grid-column:3;grid-row:1;justify-self:end;align-self:end;
  display:block;background:none;color:var(--wdks-jadetext);
  font:800 11px/1 var(--wdks-ui);letter-spacing:.1em;text-transform:uppercase;
  padding:0;border-radius:0;white-space:nowrap;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-original-price,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-original-price .amount{
  font:600 15px/1.45 var(--cw-money,'Figtree',sans-serif);color:var(--wdks-mut);
  font-variant-numeric:tabular-nums;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-original-price{
  grid-column:3;grid-row:2;justify-self:end;align-self:start;white-space:nowrap;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-original-price .woocommerce-Price-currencySymbol{
  font-size:.72em;
}

/* --- TOTAL + saving (markup from inc/wdk-single.php) -------------- */
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-total{
  display:flex;align-items:baseline;gap:12px;
  margin:22px 0 0;padding-top:18px;border-top:1px solid var(--wdks-line-2);
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-total-l{
  font:800 11.5px/1 var(--wdks-ui);letter-spacing:.12em;text-transform:uppercase;
  color:var(--wdks-mut);margin-right:auto;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-total-was,
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-total-was .amount{
  font:600 16px/1 var(--cw-money,'Figtree',sans-serif);color:var(--wdks-mut);
  text-decoration:line-through;font-variant-numeric:tabular-nums;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-total-amt,
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-total-amt .amount{
  font:800 26px/1 var(--cw-money,'Figtree',sans-serif);color:var(--wdks-jadetext);
  font-variant-numeric:tabular-nums;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-total-amt .woocommerce-Price-currencySymbol{
  font-size:.6em;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-saved{
  margin:8px 0 0;text-align:right;
  font:600 12.5px/1.4 var(--wdks-ui);color:var(--wdks-jadetext);
}

/* --- ADD TO CART: the buy ladder's button ------------------------ */
/* A normal WDK PDP never shows this button — snippet 115 draws its own CTA —
   so the bundle page is the one place the stock one surfaced, and it was
   wearing the Customizer's orange (#wp-custom-css `.button{background-color:
   #F7941D}`). Three things have to be beaten, hence the !important run:
     #wp-custom-css .product-summary-wrap .single_add_to_cart_button
                                             {border-radius:3px!important}
     Porto  .single_add_to_cart_button        {height:3rem!important}
     Porto  .single_add_to_cart_button:before {content:"\e8ba"}  (icon font)
   #wp-custom-css is an inline <style> AFTER the combined sheet, so source
   order cannot win it — only specificity above (0,2,0) plus !important.
   Scoped through `.summary` on purpose: Porto's mobile sticky bar carries a
   second .single_add_to_cart_button outside the summary, and it must keep
   Porto's own look. Same declarations as .cw-vl-addall (snippet 115), with
   the bag glyph as a masked ::before so no markup changes. */
body.wdk-pdp-page .product-type-ultimate_bundle .summary form.cart{
  margin:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .summary form.cart button.single_add_to_cart_button{
  display:flex!important;align-items:center;justify-content:center;gap:10px;
  width:100%;float:none;margin:14px 0 0;padding:15px 28px;
  height:auto!important;min-height:0;
  border:0!important;border-radius:10px!important;
  background:linear-gradient(180deg,var(--wdks-jade) 0%,var(--wdks-deep) 100%)!important;
  color:#fff!important;
  font:800 17px/1 var(--wdks-ui)!important;letter-spacing:0!important;text-transform:none!important;
  box-shadow:0 3px 8px rgba(62,183,133,.35);cursor:pointer;
  transition:filter .12s ease,transform .08s ease;
}
body.wdk-pdp-page .product-type-ultimate_bundle .summary form.cart button.single_add_to_cart_button::before{
  content:"";width:20px;height:20px;flex:0 0 20px;display:block;
  background-color:#fff;
  -webkit-mask:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z'/%3E%3Cpath d='M3 6h18'/%3E%3Cpath d='M16 10a4 4 0 0 1-8 0'/%3E%3C/svg%3E") center/20px 20px no-repeat;
  mask:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z'/%3E%3Cpath d='M3 6h18'/%3E%3Cpath d='M16 10a4 4 0 0 1-8 0'/%3E%3C/svg%3E") center/20px 20px no-repeat;
}
body.wdk-pdp-page .product-type-ultimate_bundle .summary form.cart button.single_add_to_cart_button:hover{
  filter:brightness(1.06);
}
body.wdk-pdp-page .product-type-ultimate_bundle .summary form.cart button.single_add_to_cart_button:active{
  transform:scale(.99);
}
body.wdk-pdp-page .product-type-ultimate_bundle .summary form.cart button.single_add_to_cart_button:focus-visible{
  outline:2.5px solid var(--wdks-deep);outline-offset:3px;
}
/* The plugin's own "you still have a choice to make" state — it keeps the
   button unclickable; it should read as waiting, not as broken. */
body.wdk-pdp-page .product-type-ultimate_bundle .summary form.cart button.single_add_to_cart_button.ub-disabled{
  filter:saturate(.3);opacity:.65;box-shadow:none;
}

/* --- calculated-mode safety net ----------------------------------
   No WDK bundle uses `calculated` pricing today (all 60 are `fixed`), so the
   plugin's own live total never renders — but it is one admin dropdown away.
   Given the voice of the TOTAL row above so it cannot ship raw. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-total{
  margin:0 0 10px;font-size:inherit;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-total-price,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-total-price .amount{
  font:800 26px/1 var(--cw-money,'Figtree',sans-serif);color:var(--wdks-jadetext);
  font-variant-numeric:tabular-nums;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-total-qty{
  font:600 12.5px/1 var(--wdks-ui);color:var(--wdks-mut);margin-left:8px;
}

/* --- the plugin's runtime messages, in the block's voice ---------- */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-min-qty-msg,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-max-qty-msg{
  margin:10px 0 0;font:600 12.5px/1.5 var(--wdks-ui);color:var(--wdks-mut);
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-min-qty-msg,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-max-qty-msg.ub-max-reached{
  color:var(--wdks-warn,#A52016);
}
body.wdk-pdp-page .product-type-ultimate_bundle p.ub-bundle-soldout{
  margin:16px 0 0;font:800 12.5px/1.3 var(--wdks-ui);letter-spacing:.1em;
  text-transform:uppercase;color:var(--wdks-warn,#A52016);
}

/* --- narrow screens ---------------------------------------------- */
@media (max-width:520px){
  body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-item{gap:12px}
  body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-thumb{width:64px;height:64px}
  body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-label .ub-item-thumb{
    width:54px;height:54px;
  }
  body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-name{font-size:13px}
  body.wdk-pdp-page .product-type-ultimate_bundle select.ub-variation-select{min-width:0;width:100%}
  body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-label{gap:10px}
  body.wdk-pdp-page .product-type-ultimate_bundle .summary form.cart button.single_add_to_cart_button{
    font-size:16px!important;padding:14px 20px;
  }
}

/* ============================================================
   9e. BUNDLE VARIATION DROPDOWN (owner, 2026-08-19: "the drop
   down menu goes up and not down").

   A native <select> popup is painted by the browser in the top
   layer — CSS cannot tell it which way to open, and with 20
   flavours Chrome flips it up over the product title. The store
   already owns a dropdown that always opens downward: the shop
   card's .cw-dd panel (wdk-shop.css). The bundle select gets the
   same one, drawn by assets/wdk-single.js over the native
   element, which stays in the DOM and stays authoritative.

   The button is the field §9d already styled, so a shopper sees
   no change until it opens.
   ============================================================ */
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd{
  position:relative;display:inline-block;min-width:190px;max-width:100%;
}
/* The native control stays for the plugin's JS to read and write; it is taken
   out of the paint, not out of the DOM. */
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd select.ub-variation-select{
  position:absolute;inset:0;width:100%;height:100%;
  opacity:0;pointer-events:none;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-btn{
  appearance:none;-webkit-appearance:none;
  display:flex;align-items:center;gap:10px;width:100%;
  height:44px;min-height:44px;padding:0 34px 0 13px;margin:0;cursor:pointer;
  border:1.5px solid var(--wdks-line-2);border-radius:var(--wdks-r-sm);
  background-color:var(--wdks-card);color:var(--wdks-ink);
  font:600 14px/1 var(--cw-money,'Figtree',sans-serif);text-align:left;
  box-shadow:none;text-transform:none;letter-spacing:0;
  background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23177A52' stroke-width='2'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;background-size:12px 8px;
  transition:border-color .14s ease;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-btn:hover{
  border-color:var(--wdks-jade);
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-btn:focus-visible{
  outline:2.5px solid var(--wdks-jade);outline-offset:2px;border-color:var(--wdks-jade);
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd.is-placeholder .wdk-ubdd-btn{
  color:var(--wdks-mut);
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-lab{
  flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* The plugin's "you have not chosen yet" / "that one is sold out" states have
   to reach the button now that it is what the shopper sees. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-variation-missing .wdk-ubdd-btn,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-variation-oos .wdk-ubdd-btn{
  border-color:var(--wdks-warn,#A52016);
}

/* The panel: the card picker's language (wdk-shop.css .cw-dd). Downward by
   default — `top:calc(100% + 6px)` — and .opens-up is only added by the script
   when there is genuinely no room below. */
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-pop{
  display:none;position:absolute;left:0;right:0;top:calc(100% + 6px);z-index:40;
  background:var(--wdks-card);border:1.5px solid var(--wdks-ink);border-radius:var(--wdks-r-sm);
  box-shadow:0 14px 34px rgba(17,17,16,.22);
  overflow-y:auto;overscroll-behavior:contain;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd.is-open .wdk-ubdd-pop{
  display:block;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd.opens-up .wdk-ubdd-pop{
  top:auto;bottom:calc(100% + 6px);
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-opt{
  appearance:none;-webkit-appearance:none;
  display:block;width:100%;margin:0;padding:11px 12px;cursor:pointer;
  border:0;border-bottom:1px solid var(--wdks-line);border-radius:0;
  background:none;text-align:left;text-transform:none;letter-spacing:0;
  font:600 13px/1.3 var(--cw-money,'Figtree',sans-serif);color:var(--wdks-ink);
  min-height:0;height:auto;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-opt:last-child{border-bottom:0}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-opt:hover,
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-opt:focus-visible{
  background:var(--wdks-mint);color:var(--wdks-jadetext);outline:none;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-opt.is-on{
  background:var(--wdks-mint);color:var(--wdks-jadetext);
}
/* bundle-frontend.js disables options whose variation is out of stock and
   appends " — Sold Out" to their label. */
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-opt.is-off{
  color:var(--wdks-mut);cursor:not-allowed;text-decoration:line-through;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd-opt.is-off:hover{
  background:none;color:var(--wdks-mut);
}

/* ============================================================
   9f. BREATHING ROOM UNDER THE HEADER (owner, 2026-08-19: "all
   the products pages are too close to the header, move it down
   a bit").

   Porto gives .main-content a flat padding-top:20px, so on a PDP
   the product title and the gallery start 20px under the sticky
   header + promo ticker — the tightest gap anywhere on the site.
   Raised here on product pages only (body.wdk-pdp-page), which
   leaves the shop grid, cart and checkout exactly as they are.
   ============================================================ */
body.wdk-pdp-page .main-content{padding-top:34px}
@media (min-width:992px){
  body.wdk-pdp-page .main-content{padding-top:70px}
}

/* ============================================================
   9g. THE DOUBLE HAIRLINE (found by the post-deploy audit).

   §9 line 417 draws the row separator as a border-TOP on
   `.ub-bundle-item + .ub-bundle-item` — specificity (0,4,1).
   §9d redraws the shelf with a border-BOTTOM on
   `.ub-bundle-item` — (0,3,1) — and its `border-top:0` loses the
   tie by one class, so every pair of rows was separated by BOTH
   lines: a 2px rule between rows 1-2 and 2-3, and 1px at the
   ends. Measured on all three shapes before this fix.

   Matched here at the same (0,4,1) and later in the file, rather
   than by editing §9: that section still owns the pre-Shelf
   layout and this sheet has always superseded by appending.
   ============================================================ */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-item + .ub-bundle-item{
  border-top:0;
}

/* Narrow screens: the enhanced dropdown is the tap target now, so it takes the
   row's full width the way the native field did (§9d's rule only reached the
   hidden <select>). */
@media (max-width:520px){
  body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ubdd{min-width:0;width:100%}
  body.wdk-pdp-page .product-type-ultimate_bundle .ub-variation-row{gap:6px}
}

/* ============================================================
   9i. STEPPER AND LINE PRICE IN THE SAME CELL (post-deploy audit).

   §9d places the line price at column 3 / row 2 and the qty
   stepper at column 3 / rows 1-3, so a bundle that is BOTH
   qty-editable AND shows prices would stack them on top of each
   other. No WDK bundle is in that state today — all 11 editable
   ones hide prices — but it is two admin dropdowns away, and an
   overlap is not a failure anyone would read as a setting.

   Prices hidden: the stepper is alone in the money column and
   stays centred across it. Prices shown: the column becomes
   FREE / stepper / price, and the variation selects drop a row.
   ============================================================ */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-prices-hidden .ub-item-qty-wrap{
  grid-row:1 / 3;align-self:center;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-items-wrap:not(.ub-prices-hidden) .ub-item-qty-wrap{
  grid-row:2;align-self:center;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-items-wrap:not(.ub-prices-hidden) .ub-bundle-item:has(.ub-item-qty-wrap) .ub-item-line-price{
  grid-row:3;align-self:start;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-bundle-items-wrap:not(.ub-prices-hidden) .ub-bundle-item:has(.ub-item-qty-wrap) .ub-variation-selects{
  grid-row:4;
}

/* ============================================================
   9j. AUDIT ROUND (post-deploy review, 2026-08-19).

   Three things the review caught that a shopper would see.
   ============================================================ */

/* (a) A variable gift ships its radio DISABLED until a flavour is chosen —
   that is "pending", not "unavailable", but §9d painted both the same grey.
   On free-choice-bundle-test every gift is variable, so the whole picker read
   as dead under a chip promising "Choose 1". The grey is now reserved for rows
   the plugin actually marked out of stock. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-item:not(.ub-out-of-stock) input.ub-free-choice-radio:disabled{
  background:var(--wdks-card);border-color:var(--wdks-line-2);cursor:pointer;
}

/* (b) Porto puts margin-right:.5rem on the add-to-cart pseudo icon, which the
   flex `gap:10px` then added to — an 18px gap where 10 was specified. */
body.wdk-pdp-page .product-type-ultimate_bundle .summary form.cart button.single_add_to_cart_button::before{
  margin:0;
}

/* (c) The grid's 8px column gap rendered even where column 1 is empty — gift
   rows (the theme strips their "1 x") and every prices-hidden row — so those
   names sat 8px right of the contents names above them. The gap now travels
   with the elements that need it instead of with the track. */
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-details,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-details{
  column-gap:0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-qty{margin-right:8px}
body.wdk-pdp-page .product-type-ultimate_bundle .ub-badge.ub-badge-start,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-line-price,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-free-label,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-free-choice-original-price,
body.wdk-pdp-page .product-type-ultimate_bundle .ub-item-qty-wrap{
  margin-left:12px;
}

/* ============================================================
   9k. THE PRODUCT-DETAILS EXPANDER ON BUNDLES (owner, 2026-08-19).

   Markup from inc/wdk-single.php; the toggle's own look, the
   chevron rotation and `display:none` on the panel all come from
   snippet 115's inline CSS, which prints on every product page.
   Only the spacing is ours: on a regular PDP the toggle hangs off
   `.cw-desc`, which carries the hairline and the top padding, and
   the bundle block ends with the excerpt instead.
   ============================================================ */
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-desc{
  margin:14px 0 0;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-desc .cw-desc-details{
  font-family:var(--wdks-ui);
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-desc .cw-desc-details h2,
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-desc .cw-desc-details h3,
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-desc .cw-desc-details h4{
  font:800 12px/1.3 var(--wdks-ui)!important;letter-spacing:.1em;text-transform:uppercase;
  color:var(--wdks-ink);margin:16px 0 8px!important;
}
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-desc .cw-desc-details p,
body.wdk-pdp-page .product-type-ultimate_bundle .wdk-ub-desc .cw-desc-details li{
  font:400 14.5px/1.7 var(--wdks-ui);color:var(--wdks-ink);
}


/* ============================================================
   10. LOYALTY REWARD POINTS BADGE (owner, 2026-08-20: "this needs
   to match our theme").

   The markup is WooRewards' and is NOT ours to rename. WooRewards
   Pro prints the store's own snippet on the
   woocommerce_single_product_summary hook (wp-admin options
   lws_woorewards_product_preview_regular / _variable):

     .loyalty-single-container
       > .loyalty-read-more    "Loyalty Reward Points read more..."
       > .loyalty-earn-points  "Earn up to <strong><span
          class='loyalty-points'>900 Points</span></strong> with purchase"

   It used to be a #30ec79 mint pill with WHITE text - 1.9:1, so the
   figure was the least readable thing on it - set in Poppins, a face
   this PDP uses nowhere else. Those rules lived in the Customizer's
   Additional CSS; they are deleted there and replaced here, so the
   badge now speaks the same chip language as the bundle chips in
   9d (mint field, jadetext, 99px, Open Sans), one size up because
   this chip carries a sentence rather than a word.

   PDP-only sheet, PDP-only badge: the archive preview position is
   'none' in wp-admin, so nothing outside is_product() ever emits
   these classes.
   ============================================================ */
body.wdk-pdp-page .loyalty-single-container{
  width:100%;margin:12px 0 20px;font-family:var(--wdks-ui);
}
/* The first line is a label, not a sentence - it joins the uppercase
   micro-type every other meta line on this page is set in. */
body.wdk-pdp-page .loyalty-single-container .loyalty-read-more{
  font:700 10.5px/1.5 var(--wdks-ui);letter-spacing:.09em;text-transform:uppercase;
  color:var(--wdks-mut);margin:0 0 8px;
}
body.wdk-pdp-page .loyalty-single-container .loyalty-read-more a{
  color:var(--wdks-jadetext);font-weight:800;
  text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px;
}
body.wdk-pdp-page .loyalty-single-container .loyalty-read-more a:hover{
  color:var(--wdks-cta-hover);
}
/* inline-block, not inline-flex: the chip is one run of text with a
   <strong> in the middle of it, and flex would wrap each run in an
   anonymous item and add a gap on top of the spaces already there. */
body.wdk-pdp-page .loyalty-single-container .loyalty-earn-points{
  display:inline-block;width:fit-content;max-width:100%;
  font:600 12.5px/1.35 var(--wdks-ui);
  color:var(--wdks-jadetext);background:var(--wdks-mint);
  border:1px solid #BFE3D2;border-radius:99px;padding:8px 15px;
}
/* The figure is the point of the chip, so it is the one thing in it
   that is not the chip's own weight. The underline it used to carry
   read as a link on something that is not one. */
body.wdk-pdp-page .loyalty-single-container .loyalty-earn-points strong{font-weight:inherit}
body.wdk-pdp-page .loyalty-single-container .loyalty-points{
  font:800 13.5px/1.35 var(--wdks-ui);color:var(--wdks-deep);
  text-decoration:none;font-variant-numeric:tabular-nums;
}
@media (max-width:575px){
  body.wdk-pdp-page .loyalty-single-container{margin:10px 0 16px}
  body.wdk-pdp-page .loyalty-single-container .loyalty-earn-points{font-size:12px;padding:7px 13px}
  body.wdk-pdp-page .loyalty-single-container .loyalty-points{font-size:13px}
}


/* ============================================================
   11. STRAIN + THC CHIPS UNDER THE NAME (owner, 2026-08-21:
   "the products pages on wdk need to show the thc and indica,
   sativa, hybrid badges below the name").

   Markup from inc/wdk-single.php; the words come from
   cw_strain_meta(), the same reader behind the grid card's
   .cw-tag line, so a card and its product page can never quote
   a different strain or a different potency.

   The card sets the strain word as coloured TEXT because it is
   one line in a dense column. Here the row sits alone under a
   38px Archivo Black title with nothing competing, so it is
   chips: readable at a glance in a way 10px letter-spaced text
   is not. Strain colours are the card's own
   (--cw-indica #7a4fd0 / --cw-sativa #c98514 / --cw-hybrid
   #1F8A5F) DARKENED for the tint they now sit on — #7a4fd0 on
   #F3EEFC is 4.0:1, under AA for an 11px face.

   Potency and grade keep the plain outline chip: they are
   reference data, and only the strain earns a colour code.
   ============================================================ */
body.wdk-pdp-page .wdk-pdp-tags{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0 0 14px;
}
body.wdk-pdp-page .wdk-pdp-tag{
  display:inline-flex;align-items:center;
  font:800 11px/1 var(--wdks-ui);letter-spacing:.1em;text-transform:uppercase;
  padding:7px 11px;border:1px solid var(--wdks-line-2);border-radius:99px;
  color:var(--wdks-mut);background:var(--wdks-card);
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
body.wdk-pdp-page .wdk-pdp-tag.is-indica{color:#4A2C8F;background:#F3EEFC;border-color:#DCCFF4}
body.wdk-pdp-page .wdk-pdp-tag.is-sativa{color:#8A5A00;background:#FDF5E6;border-color:#F0DDB4}
body.wdk-pdp-page .wdk-pdp-tag.is-hybrid{color:var(--wdks-jadetext);background:var(--wdks-mint);border-color:#BFE3D2}
/* The jade eyebrow line said the same thing in words; the class is set in PHP
   only when the chips repeat all of it. Scoped through .summary because the
   related-products slider below prints .product-subtitle on its own cards, and
   those keep theirs. */
body.wdk-pdp-page.wdk-tags-cover-sub .summary .product-subtitle{display:none!important}
@media (max-width:575px){
  body.wdk-pdp-page .wdk-pdp-tags{gap:6px;margin:0 0 12px}
  body.wdk-pdp-page .wdk-pdp-tag{font-size:10.5px;padding:6px 9px;letter-spacing:.08em}
}

/* ============================================================
   12. LOYALTY CHIP UNDER THE BUY BUTTON (owner, 2026-08-21:
   "lets move this to below the add to cart button").

   Section 10 still owns how that chip LOOKS; this is only where
   it now sits. inc/wdk-single.php re-hooks WooRewards onto
   woocommerce_after_add_to_cart_button, and on a variable
   product snippet 144 wraps that output in .cw-vl-extras, which
   already carries margin-top:14px — so the wrapper drops its
   own margin there rather than stacking two.
   ============================================================ */
body.wdk-pdp-page .wdk-pdp-loyalty{margin:16px 0 0}
body.wdk-pdp-page .cw-vl-extras .wdk-pdp-loyalty{margin:0}
body.wdk-pdp-page .wdk-pdp-loyalty .loyalty-single-container{margin:0}

/* ============================================================
   13. THE $ IN THE LADDER'S STRUCK TOTAL (owner, 2026-08-21:
   "the $ isnt crossed out when the total price shows in the
   product pages").

   The running total is rewritten in JS on every keystroke by
   snippet 144's fmtHtml(), which prints the mark as its own
   <span class="cw-cur">$</span>. wdk-shop.css steps every
   .cw-cur down to .6em, and a line-through is drawn once at the
   DECORATING box's metrics — 18px here — so the rule struck
   "40.00" cleanly and passed over the top of a 10.8px $.

   CW carries the fix as "THE $ IN A STRUCK PRICE KEEPS FULL
   SIZE"; wdk-shop.css ported that rule but trimmed .cw-vl-* out
   of its selector list (the note is still there), which left
   this one case behind. Restored PDP-scoped rather than
   reopening that list, so nothing outside the ladder moves.
   ============================================================ */
body.wdk-pdp-page .cw-vl-total-retail .cw-cur,
body.wdk-pdp-page .cw-vl-total-retail .woocommerce-Price-currencySymbol,
body.wdk-pdp-page .cw-vl-retail .cw-cur,
body.wdk-pdp-page .cw-vl-retail .woocommerce-Price-currencySymbol{
  font-size:inherit!important;vertical-align:baseline!important;margin-right:0!important;
}
