/* Korai Studio — product.html only.
   Shared styles (.wrap, .grid, .card, .btn, .discount-badge, ...) live in
   base.css, loaded before this file — see base.html's {% block extra_css %}. */

.product { display: grid; gap: 2.5rem; padding: 2.5rem 0 4rem; }
@media (min-width: 900px) {
  .product { grid-template-columns: 1.15fr 1fr; gap: 4rem; align-items: start; }
  .product-info { position: sticky; top: 6rem; }
}

/* Product gallery — one .gallery-item per image/video, only `.active`
   shown at a time, switched by the thumbnail strip (korai.js). Falls
   back gracefully with a single item and no thumbs at all when a
   product only has one photo (still the case for all 8 seeded products
   today), which is exactly what rendered before this was built out. */
.gallery-main { position: relative; }
.gallery-item { display: none; }
.gallery-item.active { display: block; }
.gallery-item video { width: 100%; aspect-ratio: 3/4; object-fit: cover; background: var(--cream-deep); }

/* Prev/next over the image itself — same translucent-circle treatment
   as .carousel-arrow on the homepage hero (see home.css), so a shopper
   can step through every photo/video without aiming for the thumbnail
   strip. Positioned against .gallery-main (not .gallery-zoom), so they
   stay put at the edge of the frame regardless of which item — image
   or video, own aspect ratio or not — happens to be active. */
.gallery-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 2.5rem; height: 2.5rem; z-index: 2;
  display: grid; place-items: center;
  background: rgba(255,255,255,.85);
  border: 0; border-radius: 999px;
  font-size: 1.1rem; cursor: pointer;
  color: var(--charcoal);
}
.gallery-arrow.prev { left: .75rem; }
.gallery-arrow.next { right: .75rem; }
.gallery-arrow:hover { background: var(--cream); }

/* Hover-zoom: overflow:hidden crops the scaled-up image to the frame;
   korai.js tracks the cursor and sets --zoom-x/--zoom-y so the zoomed
   view follows the pointer instead of always zooming from center. Gated
   to real hover devices — on touch, `:hover` never fires anyway, but
   being explicit here avoids the exact class of bug hit earlier this
   session with hover-only content on mobile (see .story-details). */
.gallery-zoom {
  overflow: hidden; aspect-ratio: 3/4; background: var(--cream-deep);
  --zoom-x: 50%; --zoom-y: 50%;
}
.gallery-zoom img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .2s ease; transform-origin: var(--zoom-x) var(--zoom-y);
  -webkit-user-drag: none; user-select: none; -webkit-touch-callout: none;
}
@media (hover: hover) and (pointer: fine) {
  .gallery-zoom:hover img { transform: scale(2.2); cursor: zoom-in; }
}

/* Left of the main image at every width, mobile included — not below it
   like this used to be. `order: -1` (not a DOM reorder) puts the thumb
   strip first visually while leaving it after .gallery-main in the
   markup, so tab order/screen-reader order still reach the actual photo
   before its own picker. Thumbnails get smaller on a narrow phone
   (below) specifically so the rail doesn't eat into the main image's
   own width on a small screen — at the 68px desktop size on a 375px
   phone, the main photo would be left with barely more room than the
   rail itself. */
.gallery { display: flex; align-items: flex-start; gap: .6rem; }
.gallery-main { flex: 1 1 auto; min-width: 0; }
.gallery-thumbs {
  order: -1; flex: 0 0 auto; display: flex; flex-direction: column;
  gap: .5rem; max-height: 420px; overflow-y: auto;
}
@media (min-width: 420px) { .gallery-thumbs { gap: .6rem; max-height: 500px; } }
@media (min-width: 900px) { .gallery { gap: 1rem; } .gallery-thumbs { max-height: 640px; } }

.gallery-thumb {
  position: relative; width: 44px; aspect-ratio: 3/4; padding: 0; border: 1px solid var(--line);
  background: var(--cream-deep); cursor: pointer; overflow: hidden; opacity: .65;
  transition: opacity .15s ease, border-color .15s ease;
  /* Stops the column layout's flex-shrink from squashing every
     thumbnail short whenever there are enough of them to hit
     .gallery-thumbs' own max-height — genuine overflow (handled by that
     container's overflow-y: auto) is correct there, a shrunk thumbnail
     isn't. */
  flex-shrink: 0;
}
@media (min-width: 420px) { .gallery-thumb { width: 56px; } }
@media (min-width: 900px) { .gallery-thumb { width: 68px; } }
.gallery-thumb img, .gallery-thumb video { width: 100%; height: 100%; object-fit: cover; display: block; }
.gallery-thumb.active, .gallery-thumb:hover { opacity: 1; border-color: var(--charcoal); }
.gallery-thumb .thumb-play {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.25); color: #fff; font-size: .55rem;
}

.product-info h1 { font-size: clamp(2rem, 5vw, 2.9rem); }
.stars { color: var(--gold); letter-spacing: .1em; font-size: 1rem; }
/* Social proof, placed above the price on purpose — see product.html.
   A link (not a plain span) straight to #reviews below. */
.rating-summary {
  display: flex; align-items: center; gap: .45rem; margin-top: .6rem;
  color: var(--charcoal); text-decoration: none;
}
.rating-summary:hover .rating-summary-text { text-decoration: underline; }
.rating-summary-text { font-size: .78rem; color: var(--ink-soft); }
/* No child span here (nothing to compute an average/count from yet) —
   its own hover feedback since the rule above targets a child that
   doesn't exist on this variant. */
.rating-summary-empty { font-size: .78rem; color: var(--ink-soft); }
.rating-summary-empty:hover { text-decoration: underline; }
.product-price { font-size: 1.05rem; margin: 1rem 0 .5rem; }
.product-price s { color: var(--ink-soft); font-size: .85rem; margin-left: .5rem; }
/* Text link, not the card grid's circular photo-overlay treatment —
   this sits in a plain text column here, not over an image. */
.wishlist-toggle {
  display: inline-flex; align-items: center; gap: .4rem;
  background: none; border: 0; padding: 0; margin: 0 0 1rem; cursor: pointer;
  font-size: .8rem; color: var(--ink-soft);
}
.wishlist-toggle:hover { color: var(--charcoal); }
.wishlist-toggle[aria-pressed="true"] { color: var(--charcoal); }
.wishlist-toggle[aria-pressed="true"] svg path { fill: currentColor; }
.free-delivery-note {
  font-size: .8rem; font-weight: 600; color: var(--olive); margin: 0 0 1.25rem;
}
/* Urgency, not a status like free delivery above it — deliberately not
   --olive (that reads as a calm confirmation) or --alert (that reads as
   a warning). --charcoal keeps it matter-of-fact: a plain stated fact
   she can verify, not a manufactured push. */
.recent-purchase-note {
  font-size: .78rem; color: var(--charcoal); margin: 0 0 1.25rem;
}

/* "Does this ship to me" check, ahead of the size/Buy Now decision —
   same /api/pincode lookup checkout's own pincode field already uses
   (see delivery-check.js), just offered earlier so a shopper isn't
   picking a size and reaching checkout before finding out. */
.delivery-check { margin: 0 0 1.75rem; padding: 1rem; background: var(--cream-deep); border: 1px solid var(--line); }
.delivery-check label { display: block; font-size: .72rem; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-soft); margin-bottom: .5rem; }
.delivery-check-row { display: flex; gap: .5rem; }
.delivery-check-row input {
  flex: 1; min-width: 0; padding: .6rem .7rem; border: 1px solid var(--line);
  background: var(--cream); font-family: var(--body); font-size: 1rem; /* 16px floor — see base.css's .qty select comment (iOS Safari zooms on focus below this) */
}
.delivery-check-row input:focus { outline: none; border-color: var(--olive); }
.delivery-check-row button {
  flex: none; padding: .6rem 1.1rem; border: 1px solid var(--charcoal);
  background: var(--charcoal); color: var(--cream); font-family: var(--body);
  font-size: .78rem; letter-spacing: .08em; text-transform: uppercase; cursor: pointer;
}
.delivery-check-row button:disabled { opacity: .5; cursor: default; }
.delivery-check .field-note { margin-top: .6rem; }
.surcharge-note {
  display: block; font-family: var(--body); font-size: .78rem;
  color: var(--ink-soft); margin-top: .3rem;
}
/* Without this, the class's own `display: block` above beats the
   `hidden` attribute's UA-stylesheet `display: none` at equal
   specificity (author rules always win ties over the UA sheet) — so
   toggling `.hidden = true` in product-options.js had zero visual
   effect and the last custom-tailoring note stayed on screen after
   switching back to a regular size, even though the element really was
   `hidden` in the DOM. */
.surcharge-note[hidden] { display: none; }

/* "Size" + the "Size guide" trigger — was riding on .eyebrow (font-size
   .66rem, light --ink-soft), fine for a decorative tag elsewhere on the
   site but too small/low-contrast for what's functionally a form label
   here. Own class instead of touching .eyebrow globally. */
.size-label {
  font-size: .85rem; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--charcoal); margin: 0 0 .5rem;
}
.size-guide-link {
  text-transform: none; letter-spacing: 0; font-weight: 400;
  border: 0; border-bottom: 1px solid var(--olive-deep); margin-left: .6rem;
  background: none; padding: 0; font: inherit; font-size: .8rem;
  color: var(--olive-deep); cursor: pointer;
}
.size-guide-link:hover { color: var(--olive); border-color: var(--olive); }

.sizes { display: flex; flex-wrap: wrap; gap: .5rem; margin: .75rem 0 1.5rem; }
/* Column, not the plain inline <span> this used to be — needed so a
   .size-low-stock note (below) stacks under its own size button
   instead of flowing inline after it and wrapping unpredictably at
   narrow widths. Each .size-opt stays one flex item within .sizes
   either way. */
.size-opt { display: inline-flex; flex-direction: column; align-items: center; gap: .3rem; }
.size-opt input { position: absolute; opacity: 0; }
.size-opt label {
  display: grid; place-items: center;
  min-width: 3.1rem; padding: .65rem .8rem;
  border: 1px solid var(--line);
  font-size: .76rem; letter-spacing: .08em; white-space: nowrap;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.size-opt input:checked + label { border-color: var(--charcoal); background: var(--charcoal); color: var(--cream); }
.size-opt input:focus-visible + label { outline: 2px solid var(--olive); outline-offset: 2px; }
.size-opt input:disabled + label {
  color: var(--ink-soft); cursor: not-allowed;
  background: repeating-linear-gradient(-45deg, transparent 0 5px, var(--line) 5px 6px);
}
/* Real stock, not a fixed "hurry" line — see product.html's own comment
   on why this only ever renders for a size that's genuinely close to
   selling out (settings.low_stock_threshold), never sold out (that size
   is already disabled/hatched above) and never invented. */
.size-low-stock { font-size: .64rem; letter-spacing: .04em; color: var(--alert); white-space: nowrap; }

/* Two ways to leave this form: Add to bag (keep browsing, review at
   /cart) or Buy Now (skip straight to /checkout with just this one item
   — see checkout.py's cart_add, which reads which button was actually
   clicked via the shared `next` field name). Buy Now is the visually
   primary action (solid fill) since it's the fastest path to an order;
   Add to bag stays the ghost/secondary one. Stacked on mobile,
   side-by-side once there's room for two comfortable tap targets. */
.buy-actions { display: flex; flex-direction: column; gap: .6rem; }
@media (min-width: 480px) { .buy-actions { flex-direction: row; } }

/* `display: none` by default, not an off-screen transform — the same
   "a closed/hidden overlay must not be paintable or hit-testable"
   convention base.css's own mobile-nav fix already established (see
   that file's comment on why). sticky-buy-bar.js adds/removes
   .is-visible; nothing here should ever be reachable while it's not
   actually shown. */
.sticky-buy-bar {
  display: none;
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  align-items: center; justify-content: space-between; gap: 1rem;
  background: var(--cream);
  border-top: 1px solid var(--line);
  padding: .75rem var(--gutter);
  padding-bottom: calc(.75rem + env(safe-area-inset-bottom, 0px)); /* clears the home-indicator strip on iOS */
  box-shadow: 0 -2px 12px rgba(0, 0, 0, .08);
}
.sticky-buy-bar.is-visible { display: flex; }
.sticky-buy-bar .btn { flex: none; padding: .75rem 1.75rem; }
.sticky-buy-bar .price-line s { display: none; }  /* the strike-through/badge pair reads fine in the full buy box; too busy at this size — the plain current price is enough */
.sticky-buy-bar .discount-badge { display: none; }
/* Desktop already keeps the real .buy-actions on screen via
   .product-info's own `position: sticky` (top of this file) — this
   would just be a second, redundant copy there. `!important` because
   .is-visible above sets `display: flex` with equal specificity;
   without it, a bar that became visible while narrow would stay visible
   after resizing past 900px (e.g. rotating a tablet) until the next
   scroll event re-ran the observer. */
@media (min-width: 900px) { .sticky-buy-bar { display: none !important; } }

.custom-measurements { margin: -.5rem 0 1.5rem; padding: 1rem; background: var(--cream-deep); }
.custom-fields { display: grid; grid-template-columns: repeat(3, 1fr); gap: .75rem; }
.custom-fields label { display: block; font-size: .68rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft); }
.custom-fields input {
  display: block; width: 100%; margin-top: .35rem; padding: .5rem .6rem;
  font-family: var(--body); font-size: 1rem; border: 1px solid var(--line); background: var(--cream); /* 16px floor, see base.css's .qty select comment */
}
@media (max-width: 480px) { .custom-fields { grid-template-columns: 1fr; } }

.trust-badges {
  list-style: none; margin: 1.75rem 0 0; padding: 1.5rem 0 0; border-top: 1px solid var(--line);
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; text-align: center;
}
.trust-badges li { display: flex; flex-direction: column; align-items: center; gap: .5rem; }
.trust-badges svg { width: 26px; height: 26px; color: var(--charcoal); }
.trust-badges span {
  font-size: .66rem; letter-spacing: .04em; color: var(--ink-soft); line-height: 1.3;
}
@media (max-width: 420px) { .trust-badges { grid-template-columns: repeat(2, 1fr); row-gap: 1.25rem; } }

/* Size guide — native <dialog> rather than a hand-rolled overlay div:
   free backdrop, free Escape-to-close, free focus trapping, and
   .showModal()/.close() in korai.js is the entire JS footprint. Body is
   the scrollable part (max-height + overflow-y), header stays pinned, so
   a long guide never pushes the close button off-screen. */
.size-guide-dialog {
  padding: 0; border: 0; border-radius: 4px; max-width: 480px; width: calc(100% - 2.5rem);
  max-height: 80vh; box-shadow: 0 24px 60px rgba(0,0,0,.25);
}
.size-guide-dialog::backdrop { background: rgba(35,20,15,.55); }
.size-guide-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.1rem 1.4rem; border-bottom: 1px solid var(--line); background: var(--cream);
  position: sticky; top: 0;
}
.size-guide-head h2 { font-size: 1.2rem; margin: 0; }
.size-guide-close {
  background: none; border: 0; font-size: 1.5rem; line-height: 1; cursor: pointer;
  color: var(--ink-soft); padding: .2rem .4rem;
}
.size-guide-close:hover { color: var(--charcoal); }
.size-guide-body { padding: 1.4rem; overflow-y: auto; max-height: calc(80vh - 4rem); }

/* Find-my-size quiz — reuses .size-guide-dialog/-head/-body/-close
   above for the dialog chrome (same trigger-link style too, see
   .size-guide-link), just its own form/result styling below. */
.size-quiz-question { border: 0; padding: 0; margin: 0 0 1.5rem; }
.size-quiz-question legend { font-size: .85rem; font-weight: 600; margin-bottom: .6rem; padding: 0; }
.size-quiz-options { display: flex; flex-wrap: wrap; gap: .5rem; }
.size-quiz-options label {
  display: inline-flex; align-items: center;
  padding: .5rem .85rem; border: 1px solid var(--line);
  font-size: .82rem; cursor: pointer;
}
.size-quiz-options input { margin-right: .4rem; }
.size-quiz-options label:has(input:checked) { border-color: var(--charcoal); background: var(--cream-deep); }
.size-quiz-result-size { font-family: var(--display); font-size: 1.3rem; margin-bottom: .5rem; }
.size-quiz-result-note { font-size: .85rem; color: var(--ink-soft); margin-bottom: 1.5rem; line-height: 1.55; }
.size-quiz-result .btn { margin-bottom: .6rem; }

/* Fabric band — 3-panel strip (photo / olive / rose), same "wide
   editorial band" idea as a reference layout the user shared, but not a
   copy of it: original icons (drawn here, not the reference's), the
   photo panel uses this product's *own* cover image rather than a
   stock/generic texture shot, and the copy correctly says Cotton — this
   catalog has no linen pieces. Stays within .wrap's own content width
   like every other section on this page (Reviews, Style Suggestions,
   Community Styles) rather than bleeding to the true viewport edge —
   the `100vw` full-bleed trick was tried first and caused a real
   horizontal-scroll bug (100vw doesn't account for the scrollbar's own
   width, so it overflows the actual visible viewport by however wide
   the scrollbar is). Not worth that fragility for a decorative band. */
.fabric-band {
  display: grid; grid-template-columns: 1fr 1fr 1fr;
  margin-top: 3rem; border-radius: 4px; overflow: hidden;
}
.fabric-panel { position: relative; min-height: 280px; padding: 2rem; display: flex; flex-direction: column; }
.fabric-panel-photo { padding: 0; }
.fabric-panel-photo img { width: 100%; height: 100%; object-fit: cover; display: block; -webkit-user-drag: none; }
.fabric-panel-label {
  position: absolute; left: 1.5rem; bottom: 1.5rem; color: #fff;
  font-family: var(--display); font-size: 1.5rem; font-weight: 600;
  text-shadow: 0 2px 12px rgba(0,0,0,.45);
}
/* The cotton/eco panels show the real photo up top and the copy in a
   solid color band below it — not text floating directly over the
   photo. A gradient/scrim over the photo can't guarantee contrast for
   arbitrary photo content (the cotton photo's own white fluff sits
   right where a floating heading would, which is exactly what broke
   here first) — a solid band underneath is the only version that's
   legible no matter what the photo looks like. */
.fabric-panel-olive { padding: 0; background: var(--olive); }
.fabric-panel-rose { padding: 0; background: var(--rose); }
.fabric-photo { width: 100%; height: 46%; object-fit: cover; display: block; -webkit-user-drag: none; flex: none; }
.fabric-panel-copy { padding: 1.5rem 1.75rem; }
.fabric-panel-copy h3 { font-size: 1.1rem; margin-bottom: .6rem; }
.fabric-panel-copy p { font-size: .86rem; line-height: 1.55; max-width: 30ch; }
.fabric-panel-olive .fabric-panel-copy h3 { color: var(--cream); }
.fabric-panel-olive .fabric-panel-copy p { color: rgba(255,255,255,.85); }
.fabric-panel-rose .fabric-panel-copy h3, .fabric-panel-rose .fabric-panel-copy p { color: var(--charcoal); }
@media (max-width: 800px) {
  .fabric-band { grid-template-columns: 1fr; }
  .fabric-panel { min-height: 220px; }
}

/* Community reviews — .section-head (base.css) is the same header style
   already used for "The first collection" etc. --gold exists as a
   palette variable but was otherwise unused site-wide (see base.css's
   palette comment) — stars are a fitting, honest use for it rather than
   reaching for --olive and making it do double duty. */
.reviews { padding: 3rem 0; border-top: 1px solid var(--line); margin-top: 3rem; }
.reviews-avg { font-size: .8rem; color: var(--ink-soft); white-space: nowrap; }
.reviews-empty { color: var(--ink-soft); font-size: .88rem; margin-bottom: 2rem; }

.review-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 2rem; margin-bottom: 2.5rem; }
.review-stars { color: var(--gold); letter-spacing: .1em; font-size: 1rem; margin-bottom: .5rem; }
.review-body { font-size: .88rem; line-height: 1.6; margin-bottom: .75rem; color: var(--charcoal); }
.review-media { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: .75rem; }
.review-media img, .review-media video {
  width: 72px; height: 72px; object-fit: cover; border-radius: 4px;
  background: var(--cream-deep); -webkit-user-drag: none;
}
.review-meta { font-size: .7rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: .06em; }

.review-form-guest { background: var(--cream-deep); padding: 1.75rem; text-align: center; max-width: 520px; }
.review-form-guest p { margin-bottom: 1rem; color: var(--ink-soft); font-size: .88rem; }

.review-form { max-width: 520px; }
.review-form h3 { margin-bottom: 1.2rem; font-size: 1.15rem; }
.review-form label {
  display: block; font-size: .7rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-soft); margin-bottom: 1.1rem;
}
.review-form label small { text-transform: none; letter-spacing: 0; }
.review-form select, .review-form textarea, .review-form input[type="file"] {
  display: block; width: 100%; margin-top: .45rem; padding: .6rem .7rem;
  font-family: var(--body); font-size: 1rem; border: 1px solid var(--line); background: var(--cream); /* 16px floor, see base.css's .qty select comment */
}
.review-form textarea { resize: vertical; }

.style-suggestions { padding: 3rem 0; border-top: 1px solid var(--line); }
/* minmax(..., 1fr) with only 1-2 cards stretches each column to fill the
   whole row — a card could end up ~590px wide in a 1180px container.
   Capping the track at 200px (not 1fr) keeps cards a normal thumbnail
   size regardless of count; justify-content lets leftover width become
   margin instead of forcing cards wider. */
.style-list {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 200px));
  justify-content: start; gap: 1.5rem;
}
.style-card { margin: 0; }
.style-card img, .style-card video {
  /* height: auto is load-bearing here, not decorative — the <img> has an
     HTML height="" attribute (the real photo's pixel height), which is a
     genuine style (low-priority, but still wins when nothing else sets
     height). With no CSS height at all, that attribute silently
     determined the box's height and `aspect-ratio` had nothing left to
     compute, so a tall source photo rendered at its full native height
     instead of the intended 3:4 crop. */
  width: 100%; height: auto; aspect-ratio: 3/4; object-fit: cover; border-radius: 4px;
  background: var(--cream-deep); -webkit-user-drag: none;
}
.style-card figcaption { margin-top: .6rem; font-size: .82rem; color: var(--ink-soft); line-height: 1.4; }
.style-card-text {
  aspect-ratio: 3/4; display: flex; align-items: center; justify-content: center;
  padding: 1rem; background: var(--cream-deep); border-radius: 4px;
}
.style-card-text figcaption { margin: 0; text-align: center; font-size: .85rem; }

/* "How our community styles it" — same scroll-snap + horizontal-track
   shape as the homepage's .stories-track (see korai.js's storiesNext for
   the auto-advance this pairs with), independent class names so either
   can change without touching the other. */
.community-styles { padding-top: 2.5rem; }
.community-track {
  display: flex; gap: 1rem; overflow-x: auto; scroll-snap-type: x mandatory;
  padding-bottom: .5rem; -webkit-overflow-scrolling: touch; scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) { .community-track { scroll-behavior: auto; } }
.community-card {
  position: relative; flex: 0 0 auto; width: clamp(130px, 16vw, 180px);
  aspect-ratio: 9/16; border-radius: 8px; overflow: hidden;
  scroll-snap-align: start; background: var(--cream-deep);
}
.community-card img, .community-card video { width: 100%; height: 100%; object-fit: cover; display: block; -webkit-user-drag: none; }

.detail { border-top: 1px solid var(--line); }
.detail summary {
  padding: 1rem 0; cursor: pointer; list-style: none;
  font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
  display: flex; justify-content: space-between;
}
.detail summary::-webkit-details-marker { display: none; }
.detail summary::after { content: "+"; }
.detail[open] summary::after { content: "\2212"; }
.detail p { margin: 0 0 1.25rem; color: var(--ink-soft); font-size: .86rem; }
.detail-content { color: var(--ink-soft); font-size: .86rem; line-height: 1.6; }
.detail-content p { margin: 0 0 1rem; }
.detail-content ul, .detail-content ol { margin: 0 0 1rem 1.5rem; }
.detail-content li { margin: 0 0 0.5rem; }
.detail-content strong { font-weight: 600; color: var(--ink); }
.detail-content em, .detail-content i { font-style: italic; }
.detail-content br { display: block; content: ""; margin: 0.5rem 0; }

/* Floating "picture-in-picture" styling video on the product page —
   bottom-right by default, freely draggable (korai.js), closeable for
   the rest of this page view (no persistence — a refresh/revisit brings
   it back, per how this was scoped). `touch-action: none` stops the
   browser's own scroll/zoom gestures from fighting the drag on touch.
   Chunked delivery for the video itself needs no special handling here
   — it's a plain <video src>, and browsers request those via HTTP Range
   automatically; the server already answers with 206 Partial Content. */
.pip-video {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 200;
  width: 130px; aspect-ratio: 9/16; border-radius: 14px; overflow: hidden;
  box-shadow: 0 12px 32px rgba(0,0,0,.28); background: var(--cream-deep);
  cursor: grab; touch-action: none; -webkit-user-select: none; user-select: none;
}
.pip-video.dragging { cursor: grabbing; }
.pip-video video { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }
.pip-video-close, .pip-video-mute {
  position: absolute; border: 0; border-radius: 50%; background: rgba(0,0,0,.55); color: #fff;
  cursor: pointer; display: flex; align-items: center; justify-content: center; line-height: 1;
}
/* 24px, not the 22px this used to be — WCAG 2.2's pointer-target floor
   is 24x24 CSS px; this is the only control on the page that was under
   it. */
.pip-video-close { top: .35rem; right: .35rem; width: 24px; height: 24px; font-size: .95rem; }
.pip-video-mute { bottom: .35rem; right: .35rem; width: 24px; height: 24px; font-size: .72rem; }
.pip-video-close:hover, .pip-video-mute:hover { background: rgba(0,0,0,.75); }
@media (max-width: 480px) { .pip-video { width: 100px; right: .85rem; bottom: .85rem; } }

/* Form field accessibility improvements */
.field-label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  margin-bottom: 0.5rem;
  color: var(--charcoal);
}
.field-hint {
  display: block;
  font-size: 0.72rem;
  color: var(--ink-soft);
  font-weight: 400;
  margin-top: 0.2rem;
}
