/* ============================================================
   PATTERN PAGE — presentation layer
   ------------------------------------------------------------
   Every rule is namespaced .pp-* so it cannot collide with
   style.min.css / chic-responsive.css, which keep owning the
   navbar, the footer and the rest of the site.

   Two collisions cost several review rounds while this design
   was built, so they are handled explicitly further down and
   must not be "cleaned up":

   1. style.min.css sets font-family directly on p / li / td.
      A directly targeted rule always beats an inherited one, so
      the page font has to be re-asserted on those elements, and
      the mono/display roles re-asserted again on top.

   2. Grid children default to min-width:auto, so the wide size
      table pushes the whole column past the viewport. Every
      grid child here carries min-width:0.

   Typography roles (approved, to be rolled out site-wide):
      display -> Newsreader     headings
      body    -> Cabin          prose
      data    -> IBM Plex Mono  every measurement and size code
   ============================================================ */

/* ============================================================
   PATTERN PAGE DESIGN TOKENS  (future site-wide reference)
   all page styles are namespaced .pp-* so the site navbar CSS
   above keeps working untouched
   ============================================================ */
:root{
  --pp-paper:        #FAF7F2;
  --pp-paper-alt:    #F2EDE4;
  --pp-raised:       #FFFFFF;
  --pp-ink:          #211D1A;
  --pp-ink-soft:     #5A534C;
  --pp-ink-faint:    #8C837A;
  --pp-line:         #E2D9CC;
  --pp-line-strong:  #C9BCA9;

  --pp-clay:         #B5563A;   /* brand accent */
  --pp-clay-deep:    #8F3F28;
  --pp-clay-tint:    #F6E7E0;
  --pp-black:        #1A1714;   /* CTA resting state */

  --pp-sage:         #5F6B52;   /* technical/data accent */
  --pp-sage-tint:    #E8EBE1;

  --pp-s1:.5rem; --pp-s2:.75rem; --pp-s3:1rem; --pp-s4:1.5rem;
  --pp-s5:2rem;  --pp-s6:3rem;   --pp-s7:4rem;

  --pp-r-s:6px; --pp-r-m:12px; --pp-r-l:18px;
  --pp-shadow:      0 1px 2px rgba(33,29,26,.05), 0 8px 24px -14px rgba(33,29,26,.22);
  --pp-shadow-lift: 0 2px 6px rgba(33,29,26,.06), 0 18px 40px -20px rgba(33,29,26,.30);
  --pp-maxw: 1240px;
  /* the site navbar is position:fixed, so every offset below depends on its
     height — measured at runtime, with a sane fallback for first paint */
  --pp-navh: 85px;
  /* the site stylesheet puts padding-top + a border-top on <html>, so the body
     box starts ~13px lower than the viewport. Every offset below is in viewport
     space, so that difference has to be subtracted from the body padding or the
     anchor bar rests below the navbar and slides up on the first pixels of
     scroll — measured at runtime, 0 when the host adds no offset */
  --pp-hostoff: 0px;

  /* ============================================================
     TYPOGRAPHY — APPROVED, TO BE ROLLED OUT ACROSS THE WHOLE SITE
     Chosen after comparing three options on this page.
       display : Newsreader  — editorial serif built for long-form reading,
                 gives the "instruction manual" register rather than the
                 trendy indie-craft look
       body    : Cabin       — humanist sans, the craft-register body face
       data    : IBM Plex Mono — reserved for every measurement, size code,
                 pattern number and technical label. This is the face that
                 makes the size table read like a real grading chart, and it
                 must not be swapped for the body font.
     These three roles are the site-wide standard from here on: the other
     pages (home, shop, cart, checkout, blog) are to be aligned to them.
     ============================================================ */
  --pp-font-display: 'Newsreader', Georgia, serif;
  --pp-font-body:    'Cabin', -apple-system, Segoe UI, sans-serif;
  --pp-font-data:    'IBM Plex Mono', ui-monospace, monospace;
}
html{scroll-padding-top:calc(var(--pp-navh) + 12px);}

/* ---------- base (mobile first) ---------- */
body.pp-page, .pp-page{
  background:var(--pp-paper); color:var(--pp-ink-soft);
  font-family:var(--pp-font-body);
  font-size:16px; line-height:1.62;
  /* clear the fixed site navbar, and the sticky buy bar at the bottom */
  padding-top:calc(var(--pp-navh) - var(--pp-hostoff)) !important;
  padding-bottom:96px !important;
}
@media (min-width:1024px){ .pp-page{padding-bottom:0 !important;} }
.pp-page *{box-sizing:border-box;}
/* the site stylesheet sets a font-family directly on p/li/td etc., and a
   directly-targeted rule always beats an inherited one — so the page font has
   to be re-asserted on those elements, not just on the body */
.pp-page p, .pp-page li, .pp-page dt, .pp-page dd,
.pp-page td, .pp-page th, .pp-page span, .pp-page div,
.pp-page a, .pp-page button, .pp-page label{
  font-family:var(--pp-font-body);
}
.pp-page h1,.pp-page h2,.pp-page h3,.pp-page h4{
  font-family:var(--pp-font-display); color:var(--pp-ink); margin:0;
  text-wrap:balance; font-weight:600; line-height:1.18;
}
.pp-page img{max-width:100%; display:block;}
.pp-wrap{max-width:var(--pp-maxw); margin:0 auto; padding:0 16px;}

/* visible focus on every interactive control (incl. lightbox) */
.pp-page a:focus-visible,
.pp-page button:focus-visible{
  outline:2px solid var(--pp-clay); outline-offset:3px; border-radius:4px;
}
.pp-lightbox button:focus-visible{outline:2px solid #fff; outline-offset:3px;}

/* ---------- suppress the legacy page furniture ----------
   Site scripts inject their own sticky buy bar and their own back-to-top
   button. On a pattern page both now have a counterpart in this design, so
   without this block the visitor gets two stacked sticky bars (the legacy one
   sits at z-index 1000, on top of ours at 60) and two back-to-top buttons.
   Hidden with CSS rather than by editing the scripts, which other pages
   still rely on. */
.pp-page .mobile-sticky-action-bar,
.pp-page .chic-back-to-top-btn,
.pp-page #back-to-top-btn{display:none !important;}

/* The sticky section bar is gone. With the body folded into four drawers the
   whole page index is already on screen at once, and a bar that scrolled to a
   closed drawer pointed at nothing a visitor could read. */

/* ---------- layout ---------- */
/* min-width:0 is essential: without it the wide size table forces the whole
   grid column past the viewport and every section overflows sideways */
.pp-product{display:grid; grid-template-columns:minmax(0,1fr); gap:var(--pp-s5); padding:var(--pp-s4) 0 var(--pp-s6);}
.pp-buycol, .pp-contentcol{min-width:0;}
.pp-section, .pp-section > *{min-width:0;}

/* ---------- gallery ---------- */
.pp-gallery-main{
  position:relative; background:var(--pp-raised); border:1px solid var(--pp-line);
  border-radius:var(--pp-r-l); overflow:hidden; box-shadow:var(--pp-shadow);
  width:100%; padding:0; display:block;
}
.pp-gallery-open{
  display:block; width:100%; padding:0; margin:0; border:0;
  background:none; cursor:zoom-in; -webkit-appearance:none; appearance:none;
}
.pp-gallery-main img{
  width:100%; aspect-ratio:1/1; max-height:46vh; object-fit:cover; object-position:center 30%;
  transition:transform .5s cubic-bezier(.2,.7,.3,1);
}
.pp-gallery-main:hover img{transform:scale(1.04);}
.pp-zoomhint{
  position:absolute; inset:0; display:grid; place-items:center;
  background:rgba(26,23,20,.16); opacity:0; transition:opacity .25s ease;
  pointer-events:none;
}
.pp-gallery-main:hover .pp-zoomhint,
.pp-gallery-open:focus-visible .pp-zoomhint{opacity:1;}
.pp-zoomhint span{
  width:54px; height:54px; border-radius:50%; background:rgba(255,255,255,.94);
  display:grid; place-items:center; color:var(--pp-ink);
  box-shadow:0 6px 20px rgba(0,0,0,.18); transform:scale(.9);
  transition:transform .25s cubic-bezier(.2,.7,.3,1);
}
.pp-gallery-main:hover .pp-zoomhint span{transform:scale(1);}
@media (hover:none){ .pp-zoomhint{opacity:1; background:transparent;}
  .pp-zoomhint span{width:42px; height:42px; position:absolute; right:12px; bottom:12px;} }

/* prev / next on the main image — shown on mobile and desktop alike, so the
   second view is reachable without scrolling the text column to its end */
.pp-gnav{
  position:absolute; top:50%; z-index:3;
  width:44px; height:44px; padding:0; border-radius:50%;
  display:grid; place-items:center; cursor:pointer;
  border:1px solid rgba(26,23,20,.08); color:var(--pp-ink);
  background:rgba(255,255,255,.88);
  box-shadow:0 4px 16px rgba(26,23,20,.18);
  transform:translateY(-50%);
  transition:background .18s ease, color .18s ease, box-shadow .18s ease;
}
@supports (backdrop-filter:blur(6px)){
  .pp-gnav{background:rgba(255,255,255,.72); backdrop-filter:blur(10px) saturate(120%);}
}
.pp-gnav-prev{left:12px;}
.pp-gnav-next{right:12px;}
.pp-gnav:hover{background:#fff; color:var(--pp-clay); box-shadow:0 6px 20px rgba(26,23,20,.24);}
.pp-gnav:active{transform:translateY(-50%) scale(.93);}
.pp-gnav:focus-visible{outline:2px solid var(--pp-clay); outline-offset:2px;}
/* the zoom overlay must not swallow clicks meant for the arrows */
.pp-gnav svg{pointer-events:none;}

/* position counter, so "1 / 2" tells you a second view exists */
.pp-gcount{
  position:absolute; left:50%; bottom:12px; transform:translateX(-50%);
  margin:0; z-index:3; pointer-events:none;
  font-family:var(--pp-font-data); font-size:.72rem; font-weight:600;
  letter-spacing:.06em; color:#fff;
  background:rgba(26,23,20,.55); border-radius:999px; padding:4px 11px;
}
@supports (backdrop-filter:blur(6px)){
  .pp-gcount{background:rgba(26,23,20,.42); backdrop-filter:blur(8px);}
}

/* ---------- thumbnail rail ----------
   On a phone the rail lies down under the photo and scrolls sideways; from
   1024px up it stands on end beside the photo (see the desktop block near the
   foot of this file), which is what makes the gallery read as a lookbook page
   rather than as a picture with controls bolted underneath. */
.pp-gallery{display:block;}
.pp-rail{display:flex; gap:10px; margin-top:10px; align-items:center;}
.pp-rail-track{
  display:flex; gap:10px; overflow-x:auto; overflow-y:hidden;
  scrollbar-width:none; -webkit-overflow-scrolling:touch; scroll-behavior:smooth;
}
.pp-rail-track::-webkit-scrollbar{display:none;}
.pp-rail-step{
  flex:none; width:32px; height:32px; display:none; place-items:center; cursor:pointer;
  border:1px solid var(--pp-line-strong); border-radius:50%;
  background:var(--pp-raised); color:var(--pp-ink-soft);
  transition:background-color .18s ease, color .18s ease, border-color .18s ease;
}
.pp-rail-step:hover{background:var(--pp-black); color:#fff; border-color:var(--pp-black);}
.pp-rail-step:disabled{opacity:.3; cursor:default; background:var(--pp-raised); color:var(--pp-ink-soft); border-color:var(--pp-line);}
.pp-thumb{
  width:66px; flex:none; padding:0; cursor:pointer; overflow:hidden;
  aspect-ratio:3/4;
  border:1px solid var(--pp-line); border-radius:var(--pp-r-s); background:var(--pp-raised);
  transition:border-color .18s ease, opacity .18s ease;
  opacity:.72;
}
.pp-thumb img{width:100%; height:100%; object-fit:cover; object-position:center 22%;}
/* A landscape photograph - in this catalogue, always a bag - is shown whole
   rather than cropped to the portrait frame, which would cut its handles off
   and leave a vertical strip. It letterboxes on the page's own paper colour so
   the frame still reads as one shape. */
.pp-gallery-main img.is-wide{object-fit:contain; background:var(--pp-paper-alt); object-position:center center;}
.pp-thumb.is-wide img{object-fit:contain; background:var(--pp-paper-alt);}
.pp-thumb:hover{opacity:1;}
.pp-thumb.is-active{border-color:var(--pp-clay); opacity:1;}
@media (prefers-reduced-motion: reduce){
  .pp-rail-track{scroll-behavior:auto;}
  .pp-thumb, .pp-rail-step{transition:none;}
}

/* ---------- image viewer: translucent black over a blurred page ---------- */
.pp-lightbox{
  /* must clear the site navbar, which is position:fixed at z-index 1000 —
     otherwise it renders over the viewer and hides the close button */
  position:fixed; inset:0; z-index:2000; display:none;
  background:rgba(16,13,11,.72);
  -webkit-backdrop-filter:blur(18px) saturate(115%);
          backdrop-filter:blur(18px) saturate(115%);
  opacity:0; transition:opacity .24s ease;
}
/* browsers without backdrop-filter get a solid-enough scrim instead */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .pp-lightbox{background:rgba(16,13,11,.92);}
}
.pp-lightbox.is-open{display:block;}
.pp-lightbox.is-visible{opacity:1;}

.pp-lb-bar{
  position:absolute; top:0; left:0; right:0; height:60px; z-index:3;
  display:flex; align-items:center; justify-content:space-between;
  padding:0 12px 0 20px; background:none; border:0;
}
.pp-lb-count{
  font-family:var(--pp-font-data); font-size:12px; letter-spacing:.08em;
  color:rgba(255,255,255,.82); font-variant-numeric:tabular-nums;
}
.pp-lb-tools{display:flex; align-items:center; gap:6px;}
.pp-lb-tool{
  width:44px; height:44px; display:grid; place-items:center; cursor:pointer;
  border-radius:50%; color:#fff;
  border:1px solid rgba(255,255,255,.26); background:rgba(255,255,255,.12);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  transition:background .16s ease, border-color .16s ease, transform .16s ease;
}
.pp-lb-tool:hover{background:rgba(255,255,255,.26); transform:scale(1.05);}
.pp-lb-tool:disabled{opacity:.32; cursor:default; transform:none;}
/* plain X, sitting apart from the zoom controls */
.pp-lb-tool.is-close{margin-left:10px;}
.pp-lb-tool.is-close span{display:none;}
.pp-lb-tool.is-close:hover{background:#fff; color:#151210; border-color:#fff;}
.pp-lb-zoomval{
  font-family:var(--pp-font-data); font-size:12.5px; color:rgba(255,255,255,.82);
  min-width:46px; text-align:center; font-variant-numeric:tabular-nums;
}

.pp-lb-stage{
  position:absolute; inset:60px 0 0; overflow:hidden;
  display:grid; place-items:center; touch-action:none; background:none;
}
.pp-lb-stage img{
  max-width:min(92vw, 900px); max-height:calc(100vh - 190px);
  width:auto; height:auto; object-fit:contain; border-radius:6px;
  cursor:zoom-in; user-select:none; -webkit-user-drag:none;
  transform-origin:center center;
  transition:transform .26s cubic-bezier(.2,.7,.3,1);
  box-shadow:0 30px 70px -24px rgba(0,0,0,.75);
}
.pp-lb-stage.is-zoomed img{cursor:grab;}
.pp-lb-stage.is-panning img{cursor:grabbing; transition:none;}

.pp-lb-nav{
  position:absolute; top:50%; margin-top:-24px; z-index:2;
  width:48px; height:48px; display:grid; place-items:center; cursor:pointer;
  border-radius:50%; color:#fff;
  border:1px solid rgba(255,255,255,.26); background:rgba(255,255,255,.12);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  transition:background .16s ease, transform .16s ease;
}
.pp-lb-nav:hover{background:rgba(255,255,255,.26); transform:scale(1.05);}
.pp-lb-prev{left:16px;}
.pp-lb-next{right:16px;}

.pp-lb-film{
  position:absolute; left:0; right:0; bottom:0; z-index:3;
  display:flex; gap:10px; justify-content:center;
  padding:14px 14px calc(14px + env(safe-area-inset-bottom));
  background:none; border:0;
}
.pp-lb-filmbtn{
  width:52px; height:52px; padding:0; cursor:pointer; overflow:hidden;
  border:2px solid rgba(255,255,255,.3); border-radius:var(--pp-r-s); background:none;
  opacity:.6; transition:opacity .16s ease, border-color .16s ease;
}
.pp-lb-filmbtn img{width:100%; height:100%; object-fit:cover; object-position:center 22%;}
.pp-lb-filmbtn:hover{opacity:1;}
.pp-lb-filmbtn.is-active{opacity:1; border-color:#fff;}

.pp-lb-hint{
  position:absolute; left:50%; transform:translateX(-50%); bottom:92px; z-index:2;
  font-size:.78rem; color:rgba(255,255,255,.9); background:rgba(255,255,255,.14);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  padding:7px 15px; border-radius:999px; border:1px solid rgba(255,255,255,.22);
  pointer-events:none; transition:opacity .3s ease;
}
body.pp-lb-open{overflow:hidden;}
@media (max-width:600px){
  .pp-lb-nav{width:42px; height:42px;}
  .pp-lb-prev{left:8px;} .pp-lb-next{right:8px;}
  .pp-lb-hint{bottom:88px; font-size:.8rem; padding:6px 12px;}
}
@media (prefers-reduced-motion: reduce){ .pp-lb-stage img{transition:none;} }

/* ---------- buy box ---------- */
.pp-eyebrow{
  font-family:var(--pp-font-data); font-size:12.5px; letter-spacing:.09em;
  text-transform:uppercase; color:var(--pp-clay); display:flex; align-items:center; gap:10px;
}
.pp-eyebrow::after{content:""; flex:1; height:1px; background:var(--pp-line);}
.pp-buybox{margin-top:var(--pp-s4);}
.pp-buybox h1{font-size:1.42rem; margin:10px 0 0; letter-spacing:-.012em;}
.pp-sub{margin:7px 0 0; color:var(--pp-ink-faint); font-size:.85rem; line-height:1.5;}
.pp-pricerow{display:flex; align-items:baseline; gap:12px; margin-top:var(--pp-s3);}
.pp-price{font-family:var(--pp-font-display); font-size:1.55rem; font-weight:700; color:var(--pp-ink); line-height:1;}
.pp-price-note{font-size:.82rem; color:var(--pp-ink-faint);}
/* Named rows in place of the old chips. Each row says what its value is, so
   the values can be set plainly instead of having to carry their meaning in a
   pill colour - which is how the size range and the file count ended up
   looking like two facts of the same kind. */
.pp-meta{margin:var(--pp-s4) 0 0; padding:0;}
.pp-metarow{
  display:grid; grid-template-columns:minmax(96px, 26%) 1fr; gap:16px;
  align-items:baseline; padding:10px 0; border-top:1px solid var(--pp-line);
}
.pp-metarow:last-child{border-bottom:1px solid var(--pp-line);}
.pp-metalabel{
  margin:0; font-size:11.5px; font-weight:500; letter-spacing:.11em;
  text-transform:uppercase; color:var(--pp-ink-faint);
}
.pp-metaval{margin:0; color:var(--pp-ink); font-size:.95rem; line-height:1.45;}
.pp-metaval.is-data{letter-spacing:.02em;}

/* CTA: minimal — black at rest, flat brand colour on hover. No sweep, no lift. */
.pp-btnrow{display:grid; grid-template-columns:1fr; gap:10px; margin-top:var(--pp-s4);}
.pp-btn{
  display:flex; align-items:center; justify-content:center; gap:8px;
  min-height:50px; padding:14px 22px; border-radius:var(--pp-r-m);
  font-family:var(--pp-font-body); font-weight:700; font-size:.98rem;
  text-decoration:none; cursor:pointer; border:1.5px solid transparent;
  transition:background-color .2s ease, color .2s ease, border-color .2s ease;
}
/* colour is repeated on :hover/:focus because the site stylesheet's generic
   a:hover rule would otherwise win on specificity and wash the label out */
.pp-btn-primary,
.pp-btn-primary:link,
.pp-btn-primary:visited{background:var(--pp-black); color:#fff;}
.pp-btn-primary:hover,
.pp-btn-primary:focus{background:var(--pp-clay); color:#fff;}
.pp-btn-ghost{background:transparent; color:var(--pp-ink); border-color:var(--pp-line-strong);}
.pp-btn-ghost:hover,
.pp-btn-ghost:focus{border-color:var(--pp-black); background:var(--pp-black); color:#fff;}
/* pattern.css styles these two by ID (#buy-pattern-single-btn,
   #add-to-cart-btn) with the old 50px pill shape and a solid black fill on
   both. An ID beats a class, so the design above was silently overridden:
   both buttons came out as identical black pills instead of a filled primary
   and an outlined secondary. Re-stated here at ID + page-class specificity,
   which wins, rather than by editing pattern.css - other pages still use it. */
.pp-page #buy-pattern-single-btn,
.pp-page #add-to-cart-btn{
  flex:none; min-width:0;
  min-height:50px; padding:14px 22px;
  border-radius:var(--pp-r-m);
  font-family:var(--pp-font-body); font-weight:700; font-size:.98rem;
  box-shadow:none;
  border:1.5px solid transparent;
}
.pp-page #buy-pattern-single-btn{background:var(--pp-black); color:#fff;}
.pp-page #buy-pattern-single-btn:hover,
.pp-page #buy-pattern-single-btn:focus{background:var(--pp-clay); color:#fff;}
.pp-page #add-to-cart-btn{
  background:transparent; color:var(--pp-ink);
  border:1.5px solid var(--pp-line-strong);
}
.pp-page #add-to-cart-btn:hover,
.pp-page #add-to-cart-btn:focus{
  background:var(--pp-black); color:#fff; border-color:var(--pp-black);
}
@media (prefers-reduced-motion: reduce){ .pp-btn{transition:none;} }

/* ---------- entitlement states (markup injected by pattern.js) ----------
   pattern.js rewrites the CTA container and the three file-card slots once it
   knows whether the visitor owns the pattern. It emits these classes and no
   inline styles, so the look stays owned by this stylesheet. */
.pp-dl{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:44px; padding:11px 20px; border-radius:var(--pp-r-m);
  font-family:var(--pp-font-body); font-weight:700; font-size:.88rem;
  background:var(--pp-black); color:#fff; border:1.5px solid var(--pp-black);
  cursor:pointer; text-decoration:none;
  transition:background-color .2s ease, border-color .2s ease;
}
.pp-dl:hover,
.pp-dl:focus{background:var(--pp-clay); border-color:var(--pp-clay); color:#fff;}
@media (prefers-reduced-motion: reduce){ .pp-dl{transition:none;} }

.pp-included{
  display:inline-block; padding:6px 14px; border-radius:999px;
  font-family:var(--pp-font-data); font-size:.74rem; font-weight:600;
  letter-spacing:.04em; text-transform:uppercase;
  color:var(--pp-sage); background:var(--pp-paper-alt);
  border:1px solid var(--pp-line-strong);
}

.pp-owned{
  border:1px solid var(--pp-sage); border-left:3px solid var(--pp-sage);
  border-radius:var(--pp-r-m); background:var(--pp-paper-alt);
  padding:16px 18px; margin-top:var(--pp-s4);
}
.pp-owned-title{
  display:block; font-family:var(--pp-font-display); font-size:1.06rem;
  font-weight:600; color:var(--pp-ink);
}
.pp-owned-sub{margin:4px 0 0; font-size:.88rem; color:var(--pp-ink-soft);}
.pp-delivery{
  display:flex; align-items:flex-start; gap:10px; margin-top:var(--pp-s3);
  font-size:.84rem; color:var(--pp-ink-faint);
  padding-top:var(--pp-s3); border-top:1px dashed var(--pp-line-strong);
}
.pp-delivery svg{flex:none; margin-top:3px;}

/* ---------- content: one open description, four drawers ---------- */
.pp-section{padding:var(--pp-s5) 0 var(--pp-s4); position:relative;}
.pp-section-open{padding-top:var(--pp-s4);}
/* the label above the description, and the label on a drawer, are the same
   kind of thing and are set identically - the drawer simply adds a chevron */
.pp-page .pp-sec-label{
  margin:0 0 var(--pp-s3);
  font-size:12px; font-weight:600; letter-spacing:.12em;
  text-transform:uppercase; color:var(--pp-clay);
}
/* What you are buying and the closing support note are the small print at
   the foot of the page, not another decision to weigh like Description - the
   user asked for their labels in black rather than the clay used everywhere
   else a section label appears. */
#pp-digital .pp-sec-label,
#pp-support .pp-sec-label{color:var(--pp-ink);}
.pp-section p, .pp-drawer-body p{margin:0 0 var(--pp-s3); max-width:64ch;}
/* The bare category line above the description prose. It is a descriptor, not
   a sentence, so it is set in the display face a step above the body copy and
   given room beneath it rather than a rule - the mono section label directly
   above it is already doing the dividing. */
.pp-page .pp-desc-head{
  margin:2px 0 var(--pp-s3); font-size:1.18rem; letter-spacing:-.006em;
  color:var(--pp-ink);
}
@media (min-width:768px){ .pp-page .pp-desc-head{font-size:1.28rem;} }


.pp-drawer{border-top:1px solid var(--pp-line-strong);}
.pp-drawer:last-of-type{border-bottom:1px solid var(--pp-line-strong);}
.pp-drawer-head{
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:17px 2px; min-height:56px; cursor:pointer;
  list-style:none;               /* Firefox */
}
.pp-drawer-head::-webkit-details-marker{display:none;}   /* Safari */
.pp-drawer-head:focus-visible{outline:2px solid var(--pp-clay); outline-offset:3px; border-radius:var(--pp-r-s);}
.pp-drawer-title{
  margin:0; font-size:12.5px; font-weight:600; letter-spacing:.12em;
  text-transform:uppercase; color:var(--pp-ink);
  transition:color .18s ease;
}
.pp-drawer-head:hover .pp-drawer-title{color:var(--pp-clay);}
.pp-drawer-mark{
  flex:none; display:flex; color:var(--pp-ink-faint);
  transition:transform .22s cubic-bezier(.2,.7,.3,1), color .18s ease;
}
.pp-drawer[open] > .pp-drawer-head .pp-drawer-mark{transform:rotate(90deg); color:var(--pp-clay);}
.pp-drawer-body{padding:2px 0 var(--pp-s5);}
/* a drawer that holds a single sub-section prints no sub-heading, so this only
   ever separates two or more of them */
.pp-page .pp-subsec{
  margin:var(--pp-s5) 0 var(--pp-s3); font-size:1.18rem; letter-spacing:-.008em;
  color:var(--pp-ink);
}
.pp-page .pp-drawer-body > .pp-subsec:first-child{margin-top:0;}
@media (prefers-reduced-motion: reduce){
  .pp-drawer-mark, .pp-drawer-title{transition:none;}
}
.pp-lead{font-size:1.04rem; color:var(--pp-ink);}

/* features */
.pp-features{list-style:none; padding:0; margin:var(--pp-s3) 0 0;}
.pp-features li{display:flex; gap:14px; align-items:flex-start; padding:13px 0; border-bottom:1px solid var(--pp-line);}
.pp-features li:last-child{border-bottom:0;}
.pp-features .pp-mark{
  flex:none; width:24px; height:24px; margin-top:1px; border-radius:50%;
  background:var(--pp-clay-tint); color:var(--pp-clay-deep); display:grid; place-items:center;
}
.pp-features strong{color:var(--pp-ink); font-weight:600; display:block;}
.pp-features span.d{font-size:.92rem;}

/* file cards — proper SVG artwork */
.pp-files{display:grid; gap:12px; margin-top:var(--pp-s3);}
.pp-file{
  display:grid; grid-template-columns:auto 1fr; gap:16px; align-items:center;
  background:var(--pp-raised); border:1px solid var(--pp-line);
  border-radius:var(--pp-r-m); padding:16px; transition:border-color .2s ease, transform .2s ease;
}
.pp-file:hover{border-color:var(--pp-line-strong); transform:translateY(-1px);}
.pp-file-art{width:50px; height:50px; flex:none;}
.pp-file-name{color:var(--pp-ink); font-weight:700; font-size:1rem;}
.pp-file-desc{font-size:.88rem; color:var(--pp-ink-faint); margin-top:2px;}
.pp-file-meta{
  font-family:var(--pp-font-data); font-size:12px; letter-spacing:.05em;
  text-transform:uppercase; color:var(--pp-sage); margin-top:7px; display:inline-block;
  background:var(--pp-sage-tint); padding:4px 8px; border-radius:5px;
}

/* one single size table at every screen size, scrollable sideways on phones */
.pp-tablewrap{
  overflow-x:auto; -webkit-overflow-scrolling:touch; margin-top:var(--pp-s3);
  border:1px solid var(--pp-line); border-radius:var(--pp-r-m); background:var(--pp-raised);
}
.pp-table{border-collapse:collapse; width:100%; min-width:520px;}
.pp-table th,.pp-table td{padding:12px 14px; text-align:left; border-bottom:1px solid var(--pp-line); font-size:.86rem;}
.pp-table thead th{
  font-family:var(--pp-font-data); font-size:12.5px; letter-spacing:.05em;
  text-transform:uppercase; color:var(--pp-ink); background:var(--pp-paper-alt);
  font-weight:600; white-space:nowrap; line-height:1.35;
}
.pp-table thead th span{
  display:block; font-size:12px; letter-spacing:.04em; color:var(--pp-ink-faint);
  font-weight:400; margin-top:2px;
}
.pp-table tbody td{font-family:var(--pp-font-data); font-variant-numeric:tabular-nums; color:var(--pp-ink-soft); white-space:nowrap;}
.pp-table tbody tr:last-child td,
.pp-table tbody tr:last-child th{border-bottom:0;}
.pp-table tbody tr:hover td{background:var(--pp-clay-tint);}
.pp-size-cell{
  font-family:var(--pp-font-data); font-weight:600; color:var(--pp-ink);
  background:var(--pp-paper-alt); text-align:left;
  position:sticky; left:0; z-index:1; box-shadow:1px 0 0 var(--pp-line);
}
.pp-scrollhint{font-size:.8rem; color:var(--pp-ink-faint); margin:8px 0 0;}
@media (min-width: 700px){ .pp-scrollhint{display:none;} }
.pp-note{font-size:.84rem; color:var(--pp-ink-faint); margin-top:10px;}

/* fabric requirement cards — drawn like a cutting layout */
.pp-yardgrid{display:grid; grid-template-columns:1fr; gap:14px; margin-top:var(--pp-s4);}
@media (min-width:560px){ .pp-yardgrid{grid-template-columns:1fr 1fr;} }
.pp-yard{
  position:relative; background:var(--pp-raised); border:1px solid var(--pp-line);
  border-radius:var(--pp-r-l); padding:18px 20px 20px; overflow:hidden;
}
.pp-yard::after{  /* faint fold line, like the fabric folded selvedge to selvedge */
  content:""; position:absolute; top:0; bottom:0; left:26px;
  border-left:1px dashed var(--pp-line); pointer-events:none;
}
.pp-yard-head{
  display:flex; align-items:baseline; justify-content:space-between; gap:10px;
  position:relative; z-index:1;
}
.pp-yard-w{
  font-family:var(--pp-font-data); font-size:12px; letter-spacing:.07em;
  text-transform:uppercase; color:var(--pp-sage); background:var(--pp-sage-tint);
  padding:5px 10px; border-radius:999px;
}
.pp-yard-body{display:flex; align-items:flex-end; gap:16px; margin-top:16px; position:relative; z-index:1;}
.pp-yard-fig{flex:none;}
.pp-yard-nums{min-width:0;}
/* ---------- anatomy ----------
   A short list of the parts the garment is built from. It replaced a full run
   of assembly steps, which was too much for a product page: a buyer wants to
   know the piece has a collar and a lining, not to read the instructions
   before paying for them. Shares the supplies list's dot marker so the two
   short lists on the page read as the same kind of thing. */
.pp-anatomy{list-style:none; padding:0; margin:0; display:grid; gap:10px;}
.pp-anatomy li{display:flex; align-items:flex-start; gap:10px; font-size:.96rem; color:var(--pp-ink);}
@media (min-width:768px){ .pp-anatomy{grid-template-columns:repeat(2,1fr); gap:12px var(--pp-s4);} }

/* ---------- link to the measuring guide ----------
   On its own line with an arrow, because as the tail of a sentence it read as
   punctuation rather than as somewhere to go - and for a buyer who is unsure
   of their size it is the most useful thing in the section. */
.pp-measurelink{margin:0;}
.pp-measurelink a{
  display:inline-flex; align-items:center; gap:7px;
  font-weight:600; color:var(--pp-clay); text-decoration:none;
  border-bottom:1.5px solid currentColor; padding-bottom:1px;
  transition:gap .2s ease, color .2s ease;
}
.pp-measurelink a::after{content:"\2192"; font-size:1.05em; line-height:1;}
.pp-measurelink a:hover{color:var(--pp-clay-deep); gap:10px;}
@media (prefers-reduced-motion: reduce){ .pp-measurelink a{transition:none;} }

/* ---------- inches / centimetres switch ----------
   Both units are in the markup and the switch only changes which is shown, so
   nothing is converted at the click and a reader with no JavaScript - or a
   printer - still gets the inches the page was built with. */
.pp-units{
  display:inline-flex; gap:2px; margin:var(--pp-s3) 0 var(--pp-s2);
  padding:3px; background:var(--pp-paper-alt); border-radius:999px;
}
.pp-unit{
  appearance:none; border:0; cursor:pointer;
  padding:7px 15px; border-radius:999px; background:transparent;
  font-family:var(--pp-font-data); font-size:11.5px; letter-spacing:.05em;
  text-transform:uppercase; color:var(--pp-ink-faint);
  transition:background-color .2s ease, color .2s ease;
}
.pp-unit.is-on{background:var(--pp-raised); color:var(--pp-ink); font-weight:600;}
.pp-unit:hover{color:var(--pp-ink);}
@media (prefers-reduced-motion: reduce){ .pp-unit{transition:none;} }

.pp-sizetable .pp-cm{display:none;}
.pp-sizetable[data-unit="cm"] .pp-in{display:none;}
.pp-sizetable[data-unit="cm"] .pp-cm{display:inline;}

/* ---------- size chart shown as a picture ----------
   On 46 patterns the chart is drawn as vector outlines rather than set as
   text, so nothing can read it and the only faithful way to show it is to
   show it. Rendered straight out of the PDF at the size it is printed, so
   the reader sees the pattern's own chart and not a retyping of it. */
.pp-chartshot{
  margin:var(--pp-s4) 0 0; padding:14px;
  background:var(--pp-raised); border:1px solid var(--pp-line);
  border-radius:var(--pp-r-m); overflow-x:auto;
}
.pp-chartshot img{
  display:block; width:100%; max-width:640px; height:auto; margin:0 auto;
  min-width:340px;
}

/* ---------- skill scale ----------
   Three rungs, with the pattern's own rung marked. "Intermediate" on its own
   is only a word; next to the rung below it and the rung above it, it is a
   position, which is what a buyer is actually asking about.

   Nothing here is carried by colour alone. Every rung is named in text, the
   one that applies is the only one in bold and the only one that says "this
   pattern", and the filled bars are thicker as well as darker - so the scale
   survives a greyscale print, a colour-blind reader and a screen reader
   equally. */
.pp-levels{
  list-style:none; margin:0 0 var(--pp-s4); padding:0;
  display:grid; grid-template-columns:repeat(3,1fr); gap:10px;

  /* green, amber, red - the ordinary traffic reading of "how hard is this".
     Muted to sit inside a paper-and-clay page rather than the pure hues.

     Two shades of each, because a bar and a word are held to different
     standards: a graphical mark needs 3:1 against the page, a line of small
     text needs 4.5:1. The bright amber clears the first and fails the second,
     so the bar keeps it and the label takes the darker one. The colour is
     never the only signal anyway - every rung is named, and only the one that
     applies says "this pattern". */
  --pp-lv1:#4F7A4A;  --pp-lv1-ink:#3F6A3C;
  --pp-lv2:#C2820E;  --pp-lv2-ink:#8F6100;
  --pp-lv3:#B04A32;  --pp-lv3-ink:#9C3F2A;
}
.pp-level-bar{
  display:block; height:4px; border-radius:999px;
  background:var(--pp-line);
}
.pp-level.is-on .pp-level-bar{height:7px;}
.pp-level:nth-child(1).is-on .pp-level-bar{background:var(--pp-lv1);}
.pp-level:nth-child(2).is-on .pp-level-bar{background:var(--pp-lv2);}
.pp-level:nth-child(3).is-on .pp-level-bar{background:var(--pp-lv3);}
.pp-level-name{
  display:block; margin-top:9px;
  font-family:var(--pp-font-data); font-size:11px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--pp-ink-faint);
  line-height:1.35;
}
.pp-level.is-on .pp-level-name{color:var(--pp-ink-soft);}
.pp-level.is-here .pp-level-name{color:var(--pp-ink); font-weight:700;}
.pp-level.is-here .pp-level-name b{
  display:block; font-weight:600; letter-spacing:.04em;
}
.pp-level:nth-child(1).is-here .pp-level-name b{color:var(--pp-lv1-ink);}
.pp-level:nth-child(2).is-here .pp-level-name b{color:var(--pp-lv2-ink);}
.pp-level:nth-child(3).is-here .pp-level-name b{color:var(--pp-lv3-ink);}
.pp-page .pp-level-name{font-family:var(--pp-font-data);}

/* the bars keep their proportions on a phone; only the labels tighten */
@media (max-width:420px){
  .pp-levels{gap:7px;}
  .pp-level-name{font-size:10px; letter-spacing:.03em;}
}

/* ---------- back to the shop ----------
   Two of them, one under the header and one closing the page. A product page
   reached from a search result is otherwise a dead end: the anchor nav is
   desktop-only and the breadcrumb is inside the buy box, below the fold on a
   phone. */
.pp-back{
  display:inline-flex; align-items:center; gap:8px;
  margin:0 0 var(--pp-s3);
  font-size:.92rem; font-weight:600; color:var(--pp-ink-soft);
  text-decoration:none;
  transition:color .2s ease, gap .2s ease;
}
.pp-back:hover{color:var(--pp-clay); gap:11px;}
.pp-back svg{flex:none;}

.pp-relmore{display:flex; justify-content:center; margin-top:var(--pp-s5);}
.pp-relmore a{
  display:inline-flex; align-items:center; gap:8px;
  font-size:.95rem; font-weight:600; color:var(--pp-ink);
  text-decoration:none; padding:10px 4px;
  border-bottom:1.5px solid var(--pp-line-strong);
  transition:color .2s ease, border-color .2s ease, gap .2s ease;
}
.pp-relmore a::after{content:"\2192"; font-size:1.05em; line-height:1;}
.pp-relmore a:hover{color:var(--pp-clay); border-color:var(--pp-clay); gap:11px;}

@media (prefers-reduced-motion: reduce){
  .pp-back, .pp-relmore a{transition:none;}
}

/* ---------- pattern pieces ----------
   The real cutting outlines, lifted out of the A0 plotter artwork. They sit in
   ONE frame as a list - small silhouette, name and measurements beside it -
   rather than as a card each: at card size nine pieces ran down the page and
   took more room than the section they belong to.

   Each outline is normalised into a 100 x 100 box at extraction time and
   centred there, so every row can use the same square viewBox and the column
   of silhouettes lines up whether the shape is a trouser leg or a waistband.

   The outline is stroked, never filled: it is a cutting line, and filling it
   would turn a pattern piece into a silhouette of a garment, which is a
   different and misleading thing. non-scaling-stroke keeps that line one pixel
   wide instead of thickening with the scale factor. */
.pp-pieces{
  list-style:none; margin:var(--pp-s4) 0 0; padding:2px 20px;
  background:var(--pp-raised); border:1px solid var(--pp-line);
  border-radius:var(--pp-r-l);
  display:grid; grid-template-columns:1fr;
}
@media (min-width:640px){
  .pp-pieces{grid-template-columns:1fr 1fr; column-gap:var(--pp-s4);}
}

.pp-piece{
  display:grid; grid-template-columns:46px 1fr; align-items:center; gap:14px;
  padding:11px 0; border-top:1px solid var(--pp-line);
}
/* no rule above the first row of the list - one column, then two */
.pp-piece:first-child{border-top:0;}
@media (min-width:640px){ .pp-piece:nth-child(-n+2){border-top:0;} }

.pp-piece-art{
  display:block; width:46px; height:46px; flex:none;
  color:var(--pp-ink-soft);
}
.pp-piece-art path{
  fill:none; stroke:currentColor; stroke-width:1;
  stroke-linejoin:round; stroke-linecap:round;
  vector-effect:non-scaling-stroke;
}
.pp-piece-text{min-width:0;}
.pp-piece-name{
  display:block; font-size:.94rem; font-weight:600; color:var(--pp-ink);
  line-height:1.3;
}
.pp-piece-meta{
  display:block; margin-top:1px;
  font-family:var(--pp-font-data); font-size:11px; letter-spacing:.03em;
  color:var(--pp-ink-faint);
}
.pp-page .pp-piece-meta{font-family:var(--pp-font-data);}

/* ---------- retired: full assembly step list ----------
   The assembly order, taken from the pattern's own instructions. Numbers come
   from a counter so the markup carries no hard-coded digits, and the rule down
   the left reads as the thread running through the steps. */
.pp-build{list-style:none; counter-reset:ppstep; padding:0; margin:0; display:grid; gap:var(--pp-s4);}
.pp-build-step{
  counter-increment:ppstep;
  position:relative; padding-left:46px;
}
.pp-build-step::before{
  content:counter(ppstep,decimal-leading-zero);
  position:absolute; left:0; top:1px;
  font-family:var(--pp-font-data); font-size:.78rem; font-weight:600;
  color:var(--pp-clay); letter-spacing:.04em;
}
.pp-build-step::after{
  content:""; position:absolute; left:11px; top:22px; bottom:-26px;
  border-left:1px dashed var(--pp-line-strong);
}
.pp-build-step:last-child::after{display:none;}
.pp-build-step h4{font-size:1rem; font-weight:600; color:var(--pp-ink);}
.pp-build-step p{margin:4px 0 0; font-size:.92rem; color:var(--pp-ink-soft);}

/* marks the second half of a merged section (fabrics | yardage) without
   introducing a second numbered heading */
.pp-subhead{
  font-size:1.12rem; font-weight:600; color:var(--pp-ink);
  margin-top:var(--pp-s5) !important; padding-top:var(--pp-s3);
  border-top:1px dashed var(--pp-line-strong);
}
.pp-subhead + p{margin-top:8px;}

.pp-yard-main{
  font-family:var(--pp-font-display); font-size:1.55rem; font-weight:700;
  color:var(--pp-ink); line-height:1; letter-spacing:-.01em;
}
.pp-yard-alt{font-family:var(--pp-font-data); font-size:.9rem; color:var(--pp-ink-soft); margin-top:6px;}
.pp-yard-note{font-size:.84rem; color:var(--pp-ink-faint); margin-top:4px;}

.pp-seamstrip{
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  margin-top:14px; padding:14px 18px;
  background:var(--pp-paper-alt); border-radius:var(--pp-r-m);
}
.pp-seamstrip b{
  font-family:var(--pp-font-data); font-size:.95rem; color:var(--pp-ink);
  font-weight:600;
}
.pp-seamstrip span{font-size:.86rem; color:var(--pp-ink-faint);}

/* fabrics */
.pp-fabrics{display:flex; flex-wrap:wrap; gap:8px; margin-top:var(--pp-s3);}
.pp-fabric{background:var(--pp-raised); border:1px solid var(--pp-line); border-radius:999px; padding:8px 14px; font-size:.86rem; color:var(--pp-ink);}

/* supplies */
.pp-supplies{list-style:none; padding:0; margin:var(--pp-s3) 0 0; display:grid; gap:11px;}
.pp-supplies li{display:flex; gap:12px; align-items:center; font-size:.95rem; flex-wrap:wrap;}
/* shared by the supplies and anatomy lists: two short lists on the same page
   should carry the same marker, or one of them reads as unstyled */
.pp-supplies .pp-dot,
.pp-anatomy .pp-dot{width:6px; height:6px; border-radius:50%; background:var(--pp-clay); flex:none; margin-top:.55em;}
.pp-fromguide{font-family:var(--pp-font-data); font-size:12px; letter-spacing:.04em; text-transform:uppercase; color:var(--pp-sage); background:var(--pp-sage-tint); padding:3px 7px; border-radius:4px;}

/* PDF info: a boxed label/value grid, distinct from the hairline pp-metarow
   rows at the top of the page on purpose - this is reference detail read on
   its own inside a drawer, not the at-a-glance facts under the price. */
.pp-pdfinfo{
  margin-top:var(--pp-s3); border:1px solid var(--pp-line-strong);
  border-radius:var(--pp-r-m); overflow:hidden;
}
.pp-pdfinfo-row{
  display:grid; grid-template-columns:minmax(140px, 42%) 1fr;
  border-bottom:1px solid var(--pp-line-strong);
}
.pp-pdfinfo-row:last-child{border-bottom:0;}
.pp-pdfinfo-row > *{padding:14px 16px; background:var(--pp-paper-alt); font-size:.92rem; line-height:1.45;}
.pp-pdfinfo-label{color:var(--pp-ink); font-weight:500;}
.pp-pdfinfo-value{color:var(--pp-ink-soft); border-left:1px solid var(--pp-line-strong);}
.pp-pdfinfo-value a{color:var(--pp-clay); text-decoration:underline; text-underline-offset:2px;}

/* steps */
.pp-steps{counter-reset:ppstep; margin-top:var(--pp-s3);}
.pp-step{display:grid; grid-template-columns:auto 1fr; gap:14px; padding:15px 0; border-bottom:1px solid var(--pp-line);}
.pp-step:last-child{border-bottom:0;}
.pp-stepn{
  counter-increment:ppstep; width:32px; height:32px; display:grid; place-items:center;
  border:1.5px solid var(--pp-line-strong); border-radius:50%;
  font-family:var(--pp-font-data); font-size:12px; color:var(--pp-ink);
}
.pp-stepn::before{content:counter(ppstep);}
.pp-step h4{font-size:.98rem; margin-bottom:3px;}
.pp-step p{margin:0; font-size:.92rem;}

/* callout */
.pp-callout{background:var(--pp-paper-alt); border-radius:var(--pp-r-l); padding:var(--pp-s4); margin-top:var(--pp-s3);}
.pp-callout h3{font-size:1.15rem; margin-bottom:8px;}
.pp-callout p:last-child{margin-bottom:0;}
.pp-legal{font-size:.85rem; color:var(--pp-ink-faint); max-width:64ch;}

/* related */
.pp-related{background:var(--pp-paper-alt); border-top:1px solid var(--pp-line); padding:var(--pp-s6) 0;}
.pp-related h2{font-size:1.4rem; margin-bottom:var(--pp-s4);}
.pp-relgrid{display:grid; grid-template-columns:repeat(2,1fr); gap:14px;}
.pp-relcard{background:var(--pp-raised); border:1px solid var(--pp-line); border-radius:var(--pp-r-m); overflow:hidden; text-decoration:none; display:block;}
.pp-relcard .ph{aspect-ratio:3/4; background:linear-gradient(160deg,var(--pp-clay-tint),var(--pp-sage-tint));}
.pp-relcard .b{padding:11px 13px;}
.pp-relcard .n{font-family:var(--pp-font-data); font-size:12px; color:var(--pp-ink-faint);}
.pp-relcard .t{color:var(--pp-ink); font-weight:600; font-size:.92rem; margin-top:2px;}
.pp-relcard .p{color:var(--pp-clay); font-weight:700; font-size:.88rem; margin-top:5px;}
/* the .ph box was a flat placeholder in the demo; it now holds the real cover,
   keeping the same 3/4 frame so the grid never reflows while images load */
.pp-relcard .ph img{width:100%; height:100%; object-fit:cover; display:block;}
.pp-relcard{transition:border-color .2s ease, transform .2s ease, box-shadow .2s ease;}
.pp-relcard:hover,
.pp-relcard:focus-visible{
  border-color:var(--pp-line-strong); transform:translateY(-3px);
  box-shadow:var(--pp-shadow-lift);
}
@media (prefers-reduced-motion: reduce){ .pp-relcard{transition:none;} .pp-relcard:hover{transform:none;} }

/* ---------- whole-shop offer: the last thing on the page ----------
   Deliberately the deepest call to action. A visitor this far down has already
   been shown the single pattern twice, so this is the one place the
   alternative is worth stating properly.

   The doubled dashed frame is a stitch line: it is the page's own motif (the
   delivery note and the buy box already use a dashed rule) pushed one step
   further, so the block reads as part of the design rather than a banner
   dropped on top of it. */
.pp-bundle{padding:var(--pp-s6) 0 var(--pp-s7); background:var(--pp-paper);}
.pp-bundle-card{
  position:relative;
  background:var(--pp-clay-tint);
  border:1.5px solid var(--pp-clay);
  border-radius:var(--pp-r-l);
  padding:var(--pp-s5) var(--pp-s4);
}
/* inner stitch line, drawn inside the frame */
.pp-bundle-card::before{
  content:""; position:absolute; inset:7px;
  border:1.5px dashed rgba(181,86,58,.45);
  border-radius:calc(var(--pp-r-l) - 5px);
  pointer-events:none;
}
.pp-bundle-card > *{position:relative;}
.pp-bundle-eyebrow{
  font-family:var(--pp-font-data); font-size:12.5px; font-weight:600;
  letter-spacing:.08em; text-transform:uppercase;
  color:var(--pp-clay-deep); margin:0 0 10px;
}
.pp-bundle-card h2{font-size:1.5rem; max-width:26ch;}
.pp-bundle-sub{margin:10px 0 0; color:var(--pp-ink-soft); max-width:52ch;}

.pp-bundle-points{list-style:none; padding:0; margin:var(--pp-s4) 0 0; display:grid; gap:14px;}
.pp-bundle-points li{
  display:grid; gap:2px;
  padding-left:18px; border-left:2px solid var(--pp-clay);
}
.pp-bundle-points strong{color:var(--pp-ink); font-weight:600; font-size:.96rem;}
.pp-bundle-points span{color:var(--pp-ink-soft); font-size:.9rem;}

.pp-bundle-buy{
  margin-top:var(--pp-s5); padding-top:var(--pp-s4);
  border-top:1.5px dashed rgba(181,86,58,.45);
  display:grid; gap:var(--pp-s3); align-items:center;
}
.pp-bundle-price b{
  display:block; font-family:var(--pp-font-display);
  font-size:2rem; font-weight:600; color:var(--pp-ink); line-height:1.1;
}
.pp-bundle-price span{
  font-family:var(--pp-font-data); font-size:.8rem; color:var(--pp-ink-faint);
}
/* clay on white fails contrast at this size, so the CTA keeps the page's
   near-black fill and only shifts to clay on hover, like every other button */
.pp-bundle-cta{width:100%;}

@media (min-width:768px){
  .pp-bundle-card{padding:var(--pp-s6) var(--pp-s5);}
  .pp-bundle-card h2{font-size:1.9rem;}
  .pp-bundle-points{grid-template-columns:repeat(3,1fr); gap:var(--pp-s4);}
  .pp-bundle-buy{grid-template-columns:auto 1fr; gap:var(--pp-s5);}
  .pp-bundle-cta{width:auto; justify-self:end; min-width:260px;}
}

/* sticky mobile buy bar */
.pp-mobilebar{
  position:fixed; left:0; right:0; bottom:0; z-index:60;
  display:grid; grid-template-columns:auto 1fr; align-items:center; gap:14px;
  background:rgba(250,247,242,.97); backdrop-filter:blur(12px);
  border-top:1px solid var(--pp-line);
  padding:10px 16px calc(10px + env(safe-area-inset-bottom));
  box-shadow:0 -10px 30px -22px rgba(33,29,26,.7);
  transform:translateY(110%); transition:transform .3s cubic-bezier(.2,.7,.3,1);
}
.pp-mobilebar.is-in{transform:translateY(0);}
.pp-mb-price{line-height:1.15;}
.pp-mb-price b{display:block; font-family:var(--pp-font-display); font-size:1.15rem; color:var(--pp-ink);}
.pp-mb-price span{font-size:.78rem; color:var(--pp-clay); font-weight:600;}
.pp-mobilebar .pp-btn{min-height:46px; padding:12px 16px; font-size:.92rem; white-space:nowrap;}

/* ---- back to top ---- */
.pp-totop{
  position:fixed; right:16px; bottom:104px; z-index:55;
  width:50px; height:50px; display:grid; place-items:center; cursor:pointer;
  border-radius:50%; border:1px solid var(--pp-line-strong);
  background:var(--pp-raised); color:var(--pp-ink);
  box-shadow:var(--pp-shadow);
  opacity:0; visibility:hidden; transform:translateY(10px) scale(.94);
  transition:opacity .28s ease, transform .28s cubic-bezier(.2,.7,.3,1),
             visibility .28s, background-color .18s ease, color .18s ease, border-color .18s ease;
}
.pp-totop.is-in{opacity:1; visibility:visible; transform:translateY(0) scale(1);}
.pp-totop:hover{background:var(--pp-black); color:#fff; border-color:var(--pp-black);}
.pp-totop svg{transition:transform .22s cubic-bezier(.2,.7,.3,1);}
.pp-totop:hover svg{transform:translateY(-2px);}
@media (min-width:1024px){ .pp-totop{right:28px; bottom:28px; width:52px; height:52px;} }
@media (prefers-reduced-motion: reduce){
  .pp-totop, .pp-totop svg{transition:opacity .2s ease, visibility .2s;}
  .pp-totop{transform:none;}
  .pp-totop.is-in{transform:none;}
}

/* scroll reveal — visible at rest, JS adds the transition */
.pp-reveal{opacity:1; transform:none;}
.js .pp-reveal{opacity:0; transform:translateY(14px); transition:opacity .45s ease, transform .45s ease;}
.js .pp-reveal.is-in{opacity:1; transform:none;}
@media (prefers-reduced-motion: reduce){
  .js .pp-reveal{opacity:1 !important; transform:none !important; transition:none !important;}
  .pp-gallery-main img, .pp-lb-stage img{transition:none !important;}
  html{scroll-behavior:auto;}
}

/* ============ BREAKPOINTS (mobile-first: 320/375/414 → 768 → 1024 → 1280) ============ */
@media (min-width: 480px){
  .pp-wrap{padding:0 20px;}
  .pp-specs{grid-template-columns:repeat(2,1fr);}
  .pp-btnrow{grid-template-columns:1.4fr 1fr;}
  .pp-buybox h1{font-size:1.55rem;}
}
@media (min-width: 768px){           /* tablet */
  .pp-wrap{padding:0 24px;}
  .pp-product{gap:var(--pp-s6); padding-top:var(--pp-s5);}
  .pp-gallery-main img{aspect-ratio:16/11; object-position:center 24%;}
  .pp-thumb{width:76px;}
  .pp-buybox h1{font-size:1.7rem;}
  .pp-page .pp-subsec{font-size:1.3rem;}
  .pp-specs{grid-template-columns:repeat(3,1fr);}
  .pp-relgrid{grid-template-columns:repeat(3,1fr);}
}
@media (min-width: 1024px){          /* desktop: two columns, sticky buy column */
  /* the photo column took 44% when it held a photo and nothing else. It now
     carries the thumbnail rail as well, so it is given the extra few per
     cent the rail costs - otherwise the garment itself shrinks to pay for
     its own thumbnails. */
  .pp-product{grid-template-columns:minmax(0,49fr) minmax(0,51fr); gap:var(--pp-s6); align-items:start;}
  /* the gallery now owns the sticky column on its own, so it can be sized as a
     real product image instead of being squeezed above the buy box */
  .pp-buycol{position:sticky; top:calc(var(--pp-navh) + 16px);}
  /* the source photos are 598x800 (3:4). Driving the box by HEIGHT at that same
     ratio means nothing is ever cropped — the previous 4:5 box cut ~21% off the
     bottom of the garment. The WIDTH is the fixed px value and the height follows
     from it, so the box never depends on 100vh and never moves after load. */
  .pp-gallery-main{width:min(100%, 460px); margin-inline:auto;}
  .pp-gallery-main img{
    aspect-ratio:3/4; width:100%; height:auto;
    max-height:none;              /* clears the mobile 46vh clamp */
    object-position:center center;
  }
  /* the rail stands on end beside the photo and is exactly as tall as it,
     so a pattern with more views scrolls the rail instead of growing the
     column; flex sizing means it fits whatever width the column happens to be
     at this breakpoint rather than depending on a hand-tuned pixel width */
  .pp-gallery{display:flex; align-items:stretch; gap:14px; justify-content:center;}
  .pp-gallery-main{flex:1 1 auto; min-width:0; max-width:420px; margin-inline:0; width:auto;}
  .pp-rail{flex:0 0 84px; flex-direction:column; gap:10px; margin-top:0; min-width:0;}
  .pp-rail-track{flex:1 1 auto; min-height:0; flex-direction:column; overflow-x:hidden; overflow-y:auto;}
  .pp-rail-step{display:grid;}
  .pp-thumb{width:100%;}
  .pp-buybox{margin-top:0; padding-bottom:26px; border-bottom:1px dashed var(--pp-line-strong);}
  .pp-buybox h1{font-size:2rem;}
  .pp-contentcol .pp-section:first-of-type{padding-top:26px;}
  .pp-mobilebar{display:none;}
  .pp-relgrid{grid-template-columns:repeat(4,1fr);}
  .pp-drawer-head{padding:20px 2px;}
}
@media (min-width: 1280px){
  .pp-wrap{padding:0 32px;}
}

/* A 1920px screen at the Windows 150% display scale reports a ~1280px viewport,
   which is where a large share of this site's visitors actually sit. The desktop
   step at 1024 hands that window the full 1240px shell, so the page ran edge to
   edge on a 24px gutter and every element was then magnified 1.5x on the glass.
   Between 1024 and 1440 the shell and the display sizes step down one notch, so
   the window gets a desktop layout with real margins instead of a blown-up
   tablet one. Redefining the token moves .pp-wrap and the anchor bar together. */
@media (min-width:1024px) and (max-width:1439px){
  :root{--pp-maxw:1080px;}
  .pp-buybox h1{font-size:1.75rem;}
  .pp-page .pp-subsec{font-size:1.22rem;}
  .pp-gallery-main{max-width:360px;}
  .pp-rail{flex-basis:76px;}
}

/* short laptop screens: step the gallery down at fixed breakpoints rather than
   scaling it continuously, so the size stays constant for a given window and
   the sticky column still fits without cutting off the thumbnails */
@media (min-width:1024px) and (max-height:860px){
  .pp-gallery-main{max-width:360px;}
  .pp-rail{flex-basis:74px;}
}
@media (min-width:1024px) and (max-height:760px){
  .pp-gallery-main{max-width:310px;}
  .pp-rail{flex-basis:64px;}
}

/* ---- font-role overrides ----
   the broad p/span/div rule above outranks the component classes, so the
   elements that must stay technical (mono) or editorial (display) are
   re-asserted here with matching specificity */
.pp-page .pp-eyebrow,
.pp-page .pp-sec-label,
.pp-page .pp-drawer-title,
.pp-page .pp-metalabel,
.pp-page .pp-metaval.is-data,
.pp-page .pp-file-meta,
.pp-page .pp-yard-w,
.pp-page .pp-yard-alt,
.pp-page .pp-seamstrip b,
.pp-page .pp-stepn,
.pp-page .pp-scrollhint,
.pp-page .pp-relcard .n,
.pp-page .pp-table thead th,
.pp-page .pp-table tbody td,
.pp-page .pp-size-cell,
.pp-lightbox .pp-lb-count,
.pp-lightbox .pp-lb-zoomval{
  font-family:var(--pp-font-data);
}
.pp-page .pp-price,
.pp-page .pp-yard-main,
.pp-page .pp-mb-price b{
  font-family:var(--pp-font-display);
}

/* Similar patterns (tools/related_patterns.py): the technique tutorials under the cards */
.pp-reltech{margin:var(--pp-s4) 0 0; text-align:center; font-size:.92rem; color:var(--pp-ink-soft,#5C554E); line-height:1.6;}
.pp-reltech a{color:var(--pp-ink,#211D1A); text-decoration:underline; text-underline-offset:2px;}
.pp-reltech a:hover{color:var(--pp-clay);}
