/* ═══════════════════════════════════════════════════════════════════
   Page renderer — used by the builder canvas AND the public page.
   Every colour comes from a --pb-* token the theme sets, so a palette
   swap repaints everything and no section hard-codes a brand colour.
   ═══════════════════════════════════════════════════════════════════ */
/* The page declares itself a container so every breakpoint below measures the
   page, not the window — one set of rules for real phones and for the
   builder's device preview. */
.pb-page,.bd-canvas,.bd-prev-page{container-type:inline-size;container-name:pb}
.pb-page,.bd-prev-page{margin:0;background:var(--pb-surface,#fff);color:var(--pb-ink,#111);font-family:var(--pb-font-body,'Inter'),system-ui,sans-serif;font-size:16px;line-height:1.6;-webkit-font-smoothing:antialiased}
.pb-page *{box-sizing:border-box}
.pb-page img{max-width:100%;display:block}
/* Prose links take the colour of the text around them. A button is not a
   link in a sentence: it carries its own ink, and `.pb-page a` — one class and
   one type — outranked `.pb-btn`, so every solid button on every built page
   was rendering its label in the page's dark ink on the accent it sits on.
   Black on black, which is what a creator saw and could not explain. */
.pb-page a{text-decoration:none}
/* Links take the page's ink; the things that are buttons do not.
   `.sw-pop-btn` is the popup's call to action and lives inside .pb-page,
   so without that exception this rule (0,2,0) beat its own colour (0,1,0)
   and painted the label in the body ink — dark on the accent.
   `.sw-community` is the floating community button and is the same case
   again: an <a> inside .pb-page carrying its own accent ink. */
.pb-page a:not(.pb-btn):not(.sw-pop-btn):not(.sw-community){color:inherit}

/* ── section shell ───────────────────────────────────────────────── */
.pb-section{position:relative;background:var(--pb-surface,#fff);color:var(--pb-ink,#111)}
.pb-bg-card{background:var(--pb-card,#f6f6f6)}
.pb-bg-muted{background:color-mix(in srgb,var(--pb-card,#f6f6f6) 60%,var(--pb-surface,#fff))}
.pb-bg-accent{background:var(--pb-accent,#111);color:var(--pb-accent-ink,#fff)}
.pb-bg-dark{background:var(--pb-dark,#111);color:var(--pb-dark-ink,#fff)}
.pb-bg-image{background-image:var(--pb-bg-image);background-size:cover;background-position:center;color:#fff}
.pb-bg-image::before{content:"";position:absolute;inset:0;background:#000;opacity:var(--pb-overlay,.4)}
.pb-bg-image>*{position:relative;z-index:1}
.pb-tone-light,.pb-tone-light .pb-lead{color:#fff}
.pb-tone-dark,.pb-tone-dark .pb-lead{color:var(--pb-ink,#111)}
.pb-divider{border-bottom:1px solid var(--pb-line,#e4e4e4)}
.pb-hidden{display:none}

/* Every gap multiplied by the theme's own `space` token, so "roomy" moves the
   whole page together rather than asking somebody to raise five sections one at
   a time. The per-section choice still decides the proportion; the theme
   decides the scale. */
.pb-space-top-none{padding-top:0}.pb-space-top-sm{padding-top:calc(24px * var(--pb-space,1))}.pb-space-top-md{padding-top:calc(48px * var(--pb-space,1))}.pb-space-top-lg{padding-top:calc(80px * var(--pb-space,1))}.pb-space-top-xl{padding-top:calc(120px * var(--pb-space,1))}
.pb-space-bottom-none{padding-bottom:0}.pb-space-bottom-sm{padding-bottom:calc(24px * var(--pb-space,1))}.pb-space-bottom-md{padding-bottom:calc(48px * var(--pb-space,1))}.pb-space-bottom-lg{padding-bottom:calc(80px * var(--pb-space,1))}.pb-space-bottom-xl{padding-bottom:calc(120px * var(--pb-space,1))}

.pb-wrap{margin:0 auto;padding:0 24px;width:100%}
.pb-w-narrow{max-width:680px}.pb-w-boxed{max-width:1080px}.pb-w-wide{max-width:1320px}.pb-w-full{max-width:none}
.pb-align-left{text-align:left}.pb-align-center{text-align:center}.pb-align-right{text-align:right}
.pb-align-center .pb-actions,.pb-align-center .pb-form{justify-content:center}
.pb-align-center .pb-lead{margin-left:auto;margin-right:auto}

/* ── type ────────────────────────────────────────────────────────── */
/* Sizes are a scale multiplied into a clamp(), never a fixed pixel value —
   that is what keeps "Display" readable on a 375px phone. */
.pb-page,.bd-prev-page{overflow-wrap:break-word}
.pb-h1,.pb-h2,.pb-h3{overflow-wrap:normal;word-break:normal;hyphens:none;font-family:var(--pb-font-heading,'Plus Jakarta Sans'),sans-serif;letter-spacing:var(--pb-h-track,-.03em);line-height:1.12;margin:0;font-weight:var(--pb-h-weight,700)}
.pb-h1{font-size:clamp(1.75rem,calc(3.7cqw * var(--pb-h-scale,1) + .7rem),calc(2.95rem * var(--pb-h-scale,1)))}
.pb-h2{font-size:clamp(1.32rem,calc(2.5cqw * var(--pb-h-scale,1) + .62rem),calc(2rem * var(--pb-h-scale,1)))}
.pb-h3{font-size:calc(1.16rem * var(--pb-h-scale,1))}
.pb-section{font-size:calc(1rem * var(--pb-body-scale,1));font-weight:var(--pb-body-weight,400);line-height:var(--pb-leading,1.6)}
.pb-lead{font-size:calc(1.05rem * var(--pb-body-scale,1));color:color-mix(in srgb,currentColor 72%,transparent);max-width:62ch;margin:0}
.pb-case-upper .pb-h1,.pb-case-upper .pb-h2,.pb-case-upper .pb-h3{text-transform:uppercase}
.pb-case-lower .pb-h1,.pb-case-lower .pb-h2,.pb-case-lower .pb-h3{text-transform:lowercase}
.pb-case-title .pb-h1,.pb-case-title .pb-h2,.pb-case-title .pb-h3{text-transform:capitalize}
.pb-eyebrow{font-size:.76rem;letter-spacing:.14em;text-transform:uppercase;font-weight:700;color:var(--pb-accent,#111)}
.pb-bg-accent .pb-eyebrow,.pb-bg-dark .pb-eyebrow,.pb-bg-image .pb-eyebrow{color:inherit;opacity:.75}
.pb-note{font-size:.82rem;opacity:.7}
.pb-stack{display:flex;flex-direction:column;gap:18px}
.pb-align-center .pb-stack{align-items:center}
.pb-align-right .pb-stack{align-items:flex-end}

/* ── buttons ─────────────────────────────────────────────────────── */
.pb-actions{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
/* Its own ink, not the palette's on-accent colour: those are different jobs,
   and conflating them is how you end up with amber text on a black button. */
.pb-btn{display:inline-flex;align-items:center;gap:8px;background:var(--pb-accent,#111);color:var(--pb-btn-ink,#fff);padding:.82rem 1.5rem;border-radius:var(--pb-radius,14px);font-weight:600;font-size:.95rem;border:0;cursor:pointer;transition:transform .18s,filter .18s}
.pb-btn:hover{transform:translateY(-1px);background:var(--pb-accent-hover,var(--pb-accent,#111))}
.pb-btn-sm{padding:.5rem 1rem;font-size:.86rem}
.pb-btn-ghost{background:transparent;color:inherit;border:1px solid color-mix(in srgb,currentColor 22%,transparent)}

.pb-btnsize-sm .pb-btn{padding:.58rem 1.1rem;font-size:.88rem}
.pb-btnsize-lg .pb-btn{padding:1rem 1.9rem;font-size:1.02rem}
.pb-btnshape-square .pb-btn{border-radius:4px}
.pb-btnshape-pill .pb-btn{border-radius:999px}
.pb-btn-outline .pb-btn{background:transparent;color:var(--pb-accent,#111);border:1.5px solid currentColor}
.pb-btn-soft .pb-btn{background:color-mix(in srgb,var(--pb-accent,#111) 14%,transparent);color:var(--pb-accent,#111)}
.pb-btn-link .pb-btn{background:transparent;color:var(--pb-accent,#111);padding-left:0;padding-right:0;text-decoration:underline;text-underline-offset:5px}

/* On a dark or photographic band the accent may be invisible, so the
   non-solid styles switch to plain white there. */
.pb-bg-dark.pb-btn-outline .pb-btn,.pb-bg-accent.pb-btn-outline .pb-btn,.pb-bg-image.pb-btn-outline .pb-btn,
.pb-bg-dark.pb-btn-link .pb-btn,.pb-bg-accent.pb-btn-link .pb-btn,.pb-bg-image.pb-btn-link .pb-btn,
.pb-tone-light .pb-btn:where(.pb-btn-outline *,.pb-btn-link *){color:#fff}
.pb-bg-dark.pb-btn-soft .pb-btn,.pb-bg-accent.pb-btn-soft .pb-btn,.pb-bg-image.pb-btn-soft .pb-btn{background:rgba(255,255,255,.18);color:#fff}
.pb-bg-accent .pb-btn{background:var(--pb-surface,#fff);color:var(--pb-ink,#111)}

/* A hover for every button style, not only the solid one.

   The solid button's own rule is above; these four exist because each variant
   sets its own background at a specificity the generic hover cannot reach, so
   without them an outlined or soft button did nothing at all under the
   pointer. A control that does not answer reads as a control that is broken. */
.pb-btn-outline .pb-btn:hover{background:color-mix(in srgb,var(--pb-accent,#111) 12%,transparent)}
.pb-btn-soft .pb-btn:hover{background:color-mix(in srgb,var(--pb-accent,#111) 24%,transparent)}
.pb-btn-link .pb-btn:hover{transform:none;text-decoration-thickness:2px}
.pb-bg-accent .pb-btn:hover{background:color-mix(in srgb,var(--pb-ink,#111) 8%,var(--pb-surface,#fff))}
.pb-bg-dark.pb-btn-outline .pb-btn:hover,.pb-bg-accent.pb-btn-outline .pb-btn:hover,
.pb-bg-image.pb-btn-outline .pb-btn:hover,.pb-bg-dark.pb-btn-soft .pb-btn:hover,
.pb-bg-accent.pb-btn-soft .pb-btn:hover,.pb-bg-image.pb-btn-soft .pb-btn:hover{background:rgba(255,255,255,.28)}

/* Keyboard users get the same affordance the pointer does. */
.pb-btn:focus-visible{outline:3px solid color-mix(in srgb,currentColor 55%,transparent);outline-offset:2px}

/* ── layout helpers ──────────────────────────────────────────────── */
/* auto-fit with a minimum keeps three cards from becoming three slivers: below
   the floor the grid drops a column instead of crushing the text. */
.pb-grid{display:grid;gap:var(--pb-gap,20px);grid-template-columns:repeat(auto-fit,minmax(min(210px,100%),1fr));width:100%;text-align:left}
.pb-cols-1 .pb-grid{grid-template-columns:minmax(0,1fr)}
.pb-gap-sm{--pb-gap:12px}
.pb-gap-md{--pb-gap:20px}
.pb-gap-lg{--pb-gap:32px}
.pb-hide-desktop{display:none}
.pb-split{display:grid;grid-template-columns:1fr 1fr;gap:44px;align-items:center;text-align:left;width:100%}
.pb-split.is-flipped .pb-split-media{order:-1}
.pb-media{width:100%;border-radius:var(--pb-radius,14px);object-fit:fill;aspect-ratio:4/3}
.pb-round{border-radius:999px;aspect-ratio:1;max-width:280px}
.pb-card{background:var(--pb-elevated,var(--pb-surface,#fff));border:1px solid var(--pb-line,#e4e4e4);border-radius:var(--pb-radius,14px);padding:22px;display:flex;flex-direction:column;gap:10px}
.pb-bg-card .pb-card,.pb-bg-muted .pb-card{background:var(--pb-elevated-2,var(--pb-surface,#fff))}
.pb-bg-dark .pb-card,.pb-bg-accent .pb-card,.pb-bg-image .pb-card{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.16)}
.pb-icon{width:42px;height:42px;border-radius:12px;display:grid;place-items:center;background:var(--pb-card,#f6f6f6);color:var(--pb-accent,#111);font-size:19px}
.pb-img-empty{width:100%;aspect-ratio:4/3;border-radius:var(--pb-radius,14px);background:color-mix(in srgb,currentColor 8%,transparent);display:grid;place-items:center;font-size:26px;opacity:.4}

/* ── individual sections ─────────────────────────────────────────── */
/* 18px, not 24. The bar has more in it than it did — a menu, a search, the
   buyer's own link and the creator's button — and six gaps at 24px is 144px
   spent on nothing. */
.pb-nav{display:flex;align-items:center;gap:18px;width:100%}
.pb-nav-toggle{display:none;margin-left:auto;width:38px;height:38px;border-radius:10px;border:1px solid color-mix(in srgb,currentColor 18%,transparent);background:none;color:inherit;cursor:pointer;font-size:17px;align-items:center;justify-content:center;flex:none}
.pb-nav.is-sticky{position:sticky;top:0;z-index:30;backdrop-filter:blur(14px)}
/* What actually sticks: the box around the bar. The bar alone could not — its
   parent was exactly its own height, so it had nowhere to stay while the page
   moved. See builder/partials/section.blade.php and storefront chrome. */
.pb-section.pb-section-sticky,
.pb-chrome-header.is-sticky{position:sticky;top:0;z-index:40}
.pb-t-nav-constrained,.pb-t-nav-fullwidth{position:relative;z-index:30}
.pb-nav-brand{display:flex;align-items:center;gap:9px;font-weight:700;font-family:var(--pb-font-heading,'Plus Jakarta Sans')}
.pb-nav-logo{height:28px;width:auto}
/* `flex-shrink:0` is the one that stops a menu breaking in half.
   Without it the links row is squeezable, and a squeezed row that is allowed
   to wrap does exactly that — five items became four and a lonely fifth on a
   second line the moment anything else in the bar wanted room. Now the row
   keeps the width its own links need and the squeeze lands on the search box,
   which is built to take it. `wrap` stays for the menu that genuinely cannot
   fit on one line at any width. */
.pb-nav-links{display:flex;gap:18px;flex-wrap:wrap;flex-shrink:0;font-size:.9rem}
.pb-nav-brand+.pb-nav-links,.pb-nav-links:first-child:not(:empty){margin-left:auto}
.pb-nav-links:empty{display:none}
.pb-nav-brand{order:-1}
.pb-v-split .pb-nav-brand{order:0}
.pb-nav-links a:hover{opacity:.65}
/* The bar's call to action is chrome, not a hero button.
   It sat inside the section's own button size, so any design that asked for
   large buttons got a nav button nearly the height of the bar itself. A nav
   button is a fixed, compact size in every real store, whatever the page
   below it does. */
.pb-nav .pb-btn{
  margin-left:6px;padding:.48rem .95rem;font-size:.82rem;
  line-height:1.3;white-space:nowrap
}

/* The search box in a nav — M2.6. Sized off the bar's own type so it belongs
   to the theme rather than sitting on top of it, and it shrinks before the
   links do: a box you cannot read is worse than a narrow one. */
/* An icon until it is asked for.

   The open box was 240px of a bar that also carries a brand, a menu, the
   buyer's own link and the creator's button — and a shop with five or six menu
   items simply does not have 240px spare. Everything overlapped. So the
   magnifier is the control and the box is what it opens; see
   `builder/partials/nav-search.blade.php` and the toggle in sellwares-page.js.

   `is-ready` is added by that script. Without it — script blocked, or still
   loading — the rules below never narrow anything and the box stays the open,
   working, no-JavaScript form it has always been. Nothing can end up collapsed
   with no way to open it. */
.pb-nav-search{display:flex;align-items:center;gap:7px;flex:0 4 240px;min-width:132px;
  margin-left:auto;padding:.36rem .62rem;
  border:1px solid color-mix(in srgb,currentColor 16%,transparent);
  border-radius:999px;background:color-mix(in srgb,currentColor 5%,transparent);
  transition:flex-basis .18s ease,padding .18s ease,background .18s ease}

/* Closed: the button, and nothing else. No border and no fill either — a lone
   round outline sitting between two links reads as an empty input somebody
   forgot to finish. */
.pb-nav-search.is-ready:not(.is-open){
  flex:none;min-width:0;padding:0;border-color:transparent;background:none}
.pb-nav-search.is-ready:not(.is-open) input{width:0;padding:0;opacity:0;pointer-events:none}
.pb-nav-search.is-ready.is-open{flex:0 4 240px;min-width:132px}

/* The magnifier itself. Sized off the bar's own type so it matches the links
   beside it rather than the button at the end. */
.pb-nav-searchbtn{
  display:inline-flex;align-items:center;justify-content:center;flex:none;
  width:30px;height:30px;padding:0;border:0;border-radius:999px;
  background:none;color:inherit;cursor:pointer;font-size:.95rem;
  transition:background .18s,opacity .18s}
.pb-nav-searchbtn:hover{background:color-mix(in srgb,currentColor 9%,transparent)}
.pb-nav-searchbtn:focus-visible{outline:3px solid color-mix(in srgb,currentColor 45%,transparent);outline-offset:2px}
.pb-nav-search.is-ready:not(.is-open) .pb-nav-searchbtn{margin:0}

.pb-nav-search i{flex:none;opacity:.55;font-size:.9rem}
.pb-nav-searchbtn i{opacity:.75;font-size:1rem}
.pb-nav-search input{flex:1;min-width:0;border:0;background:none;color:inherit;
  font:inherit;font-size:.9rem;padding:0;transition:width .18s ease,opacity .18s ease}
.pb-nav-search input:focus{outline:none}
.pb-nav-search:focus-within{border-color:color-mix(in srgb,currentColor 36%,transparent)}
/* ── the buyer's own door ─────────────────────────────────────────
   "My purchases", drawn by the bar itself and not by the creator's menu —
   see builder/partials/nav-purchases.blade.php for why it is not theirs to
   remove.

   Drawn as a link and not as a button, and that is the second attempt. A
   bordered pill next to the creator's own call to action put two things that
   look pressable side by side, and it cost about 150px of a bar that only has
   1080 of them — enough to push a five-item menu onto a second line. A link
   with an icon says the same thing in a third of the room and lets the
   creator's button stay the only button. */
.pb-nav-purchases{
  display:inline-flex;align-items:center;gap:6px;flex:none;
  padding:0;border:0;border-radius:999px;
  font-size:.85rem;font-weight:600;line-height:1.3;white-space:nowrap;
  transition:opacity .18s
}
.pb-nav-purchases:hover{opacity:.65}
.pb-nav-purchases i{font-size:1rem;opacity:.7}
.pb-nav-purchases:focus-visible{outline:3px solid color-mix(in srgb,currentColor 45%,transparent);outline-offset:2px}


/* A search box takes the auto margin, so the links stop taking it and the
   bar does not end up with two things fighting for the same gap. */
.pb-nav-search~.pb-nav-links,.pb-nav-links:has(~.pb-nav-search){margin-left:0}
.pb-hero-shot{width:100%;margin-top:14px}
.pb-stats{display:flex;gap:36px;flex-wrap:wrap}
.pb-stat b{display:block;font-family:var(--pb-font-heading,'Plus Jakarta Sans');font-size:2rem;line-height:1}
.pb-stat span{font-size:.86rem;opacity:.65}
.pb-checklist{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:14px;text-align:left}
.pb-checklist li{display:flex;gap:12px;align-items:flex-start}
.pb-checklist i{color:var(--pb-accent,#111);margin-top:3px}
.pb-checklist b{display:block}
.pb-checklist span{opacity:.72;font-size:.95rem}
.pb-checklist-sm li{gap:9px}
.pb-stepno{width:30px;height:30px;border-radius:10px;background:var(--pb-accent,#111);color:var(--pb-accent-ink,#fff);display:grid;place-items:center;font-weight:700;font-size:.9rem}
.pb-product{transition:transform .2s,box-shadow .2s}
.pb-product:hover{transform:translateY(-3px);box-shadow:0 18px 40px -26px rgba(0,0,0,.5)}
/* Out to the card's edges, the way a post card's cover already is.

   `.pb-card` carries 22px of padding, so the picture sat in a frame of card
   colour on all four sides — a band left, right and above every product in
   the grid. That is right for words and wrong for the one thing on the card
   that is supposed to be looked at. Pulled out by the same 22px and rounded
   only where it meets the corner it is now sitting in. */
.pb-product-shot{width:100%;aspect-ratio:4/3;object-fit:fill;
  margin:-22px -22px 3px;
  border-radius:calc(var(--pb-radius,14px) - 1px) calc(var(--pb-radius,14px) - 1px) 0 0}
.pb-price{font-weight:700;font-family:var(--pb-font-heading,'Plus Jakarta Sans')}
.pb-price-lg{font-size:1.9rem}
.pb-pricerow{display:flex;align-items:baseline;gap:10px}
.pb-pricerow s{opacity:.45}
.pb-plan.is-featured{border-color:var(--pb-accent,#111);box-shadow:0 0 0 2px var(--pb-accent,#111) inset}
.pb-tag{align-self:flex-start;background:var(--pb-accent,#111);color:var(--pb-accent-ink,#fff);font-size:.7rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;padding:4px 9px;border-radius:999px}
.pb-plan .pb-btn{margin-top:auto}
.pb-gallery figure{margin:0}
.pb-gallery figcaption{font-size:.82rem;opacity:.65;margin-top:7px}
.pb-logobar{display:flex;gap:34px;flex-wrap:wrap;align-items:center;justify-content:inherit;opacity:.72}
.pb-logo{height:30px;width:auto}
.pb-logo-text{font-family:var(--pb-font-heading,'Plus Jakarta Sans');font-weight:700;font-size:1.1rem}
.pb-stars{color:#F5A524}
.pb-person{display:flex;align-items:center;gap:11px;margin-top:auto}
.pb-person-center{justify-content:center}
.pb-avatar{width:40px;height:40px;border-radius:999px;object-fit:cover;flex:none}
.pb-person b{display:block;font-size:.92rem}
.pb-person span{font-size:.82rem;opacity:.65}
.pb-quote-mark{font-size:2.4rem;opacity:.25}
.pb-faq{width:100%;display:flex;flex-direction:column;gap:10px;text-align:left}
.pb-faq details{border:1px solid var(--pb-line,#e4e4e4);border-radius:var(--pb-radius,14px);padding:16px 18px;background:var(--pb-surface,#fff)}
.pb-faq summary{cursor:pointer;font-weight:600;display:flex;align-items:center;justify-content:space-between;gap:12px;list-style:none}
.pb-faq summary::-webkit-details-marker{display:none}
.pb-faq details[open] summary i{transform:rotate(180deg)}
.pb-faq summary i{transition:transform .2s}
.pb-faq p{margin:12px 0 0;opacity:.75}
.pb-tabs{width:100%;text-align:left}
.pb-tabbar{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:16px}
.pb-tabbar button{background:var(--pb-card,#f6f6f6);border:0;padding:.6rem 1.1rem;border-radius:999px;cursor:pointer;font:inherit;font-size:.9rem}
.pb-tabbar button.on{background:var(--pb-accent,#111);color:var(--pb-accent-ink,#fff)}
.pb-tabpane{display:none}.pb-tabpane.on{display:block}
.pb-form{display:flex;gap:10px;flex-wrap:wrap;width:100%;max-width:520px}
.pb-form input{flex:1;min-width:220px;padding:.82rem 1rem;border-radius:var(--pb-radius,14px);border:1px solid var(--pb-line,#e4e4e4);font:inherit;background:var(--pb-surface,#fff);color:var(--pb-ink,#111)}
.pb-said{display:inline-flex;align-items:center;gap:7px;font-size:.92rem;font-weight:600;color:var(--pb-accent,#111)}
.pb-said-bad{color:#C4483C;font-weight:500}
.pb-bg-dark .pb-said,.pb-bg-accent .pb-said,.pb-bg-image .pb-said{color:inherit}
.pb-links{width:100%;max-width:540px;gap:11px}
.pb-linkrow{display:flex;align-items:center;gap:13px;width:100%;padding:1rem 1.15rem;border:1px solid var(--pb-line,#e4e4e4);border-radius:var(--pb-radius,14px);background:var(--pb-surface,#fff);font-weight:600;transition:transform .18s}
.pb-linkrow:hover{transform:translateY(-2px)}
.pb-linkrow span{flex:1}
/* Four equal cells rather than wrapping flex: "00 SECS" dropping onto its own
   line under three others looked broken, and it did it at every width. */
.pb-clock{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;width:100%;max-width:440px}
.pb-align-center .pb-clock{margin-left:auto;margin-right:auto}
.pb-clock span{background:color-mix(in srgb,currentColor 8%,transparent);border-radius:var(--pb-radius,14px);padding:14px 8px;text-align:center;min-width:0}
.pb-clock b{display:block;font-family:var(--pb-font-heading,'Plus Jakarta Sans');font-size:1.9rem;line-height:1}
.pb-clock small{font-size:.72rem;opacity:.65;letter-spacing:.08em;text-transform:uppercase}
.pb-footer{display:flex;align-items:center;gap:20px;flex-wrap:wrap;width:100%;font-size:.9rem}
.pb-footer small{opacity:.6;margin-left:auto}
.pb-socials{display:flex;gap:14px;font-size:1.2rem}

/* ═══════════════ variants ═══════════════
   Each look is a modifier on the same markup, so a creator can switch
   arrangement without losing a single word of their content. */

/* navigation */
.pb-v-center .pb-nav{justify-content:center}
.pb-v-center .pb-nav-links{margin-left:0}
.pb-v-split .pb-nav{display:grid;grid-template-columns:1fr auto 1fr;align-items:center}
.pb-v-split .pb-nav-brand{order:2;justify-content:center}
.pb-v-split .pb-nav-links{margin-left:0}
.pb-v-split .pb-nav-links:last-of-type{justify-content:flex-end}
.pb-v-card .pb-nav{background:var(--pb-surface,#fff);border:1px solid var(--pb-line,#e4e4e4);border-radius:999px;padding:.5rem .5rem .5rem 1.2rem;box-shadow:0 10px 30px -22px rgba(0,0,0,.5)}
.pb-v-minimal .pb-nav{border:0}
.pb-t-nav-fullwidth.pb-v-classic .pb-wrap,.pb-t-nav-fullwidth.pb-v-dark .pb-wrap{padding-left:32px;padding-right:32px}

/* hero */
.pb-v-badge .pb-eyebrow{background:color-mix(in srgb,currentColor 12%,transparent);padding:.32rem .85rem;border-radius:999px}
.pb-v-boxed .pb-hero,.pb-t-hero-centered.pb-v-boxed .pb-wrap>*{background:var(--pb-surface,#fff);border-radius:var(--pb-radius,14px);padding:44px 34px;box-shadow:0 30px 60px -46px rgba(0,0,0,.5)}
.pb-v-offset .pb-split{grid-template-columns:1.25fr .95fr}
.pb-v-splitcard .pb-split-media{background:var(--pb-surface,#fff);padding:16px;border-radius:calc(var(--pb-radius,14px) + 6px);box-shadow:0 26px 50px -40px rgba(0,0,0,.6)}
.pb-v-stacked .pb-split{grid-template-columns:1fr;text-align:center}
.pb-v-stacked .pb-split-copy{align-items:center}
.pb-v-compact .pb-h1{font-size:clamp(1.6rem,3.4vw,2.4rem)}

/* about */
.pb-v-stacked .pb-about{grid-template-columns:1fr;justify-items:center;text-align:center}
.pb-v-wide .pb-about{grid-template-columns:.8fr 1.2fr}
.pb-v-card .pb-about{background:var(--pb-surface,#fff);border-radius:var(--pb-radius,14px);padding:30px;box-shadow:0 26px 54px -44px rgba(0,0,0,.5)}
.pb-v-card .pb-stats .pb-stat,.pb-t-about-stats.pb-v-card .pb-stat{background:var(--pb-surface,#fff);border:1px solid var(--pb-line,#e4e4e4);border-radius:var(--pb-radius,14px);padding:18px 22px}
.pb-t-about-stats.pb-v-inline .pb-stat b{font-size:1.3rem;display:inline;margin-right:6px}
.pb-t-about-stats.pb-v-inline .pb-stats{gap:20px}

/* feature and content grids */
.pb-v-minimal .pb-card,.pb-v-plain .pb-card{background:none;border:0;padding:0}
.pb-v-bordered .pb-card{background:none;box-shadow:none}
.pb-v-numbered .pb-card{counter-increment:pbnum;position:relative;padding-top:30px}
.pb-v-numbered .pb-card::before{content:counter(pbnum,decimal-leading-zero);position:absolute;top:16px;right:20px;font-family:var(--pb-font-heading,'Plus Jakarta Sans');font-size:1.6rem;font-weight:800;opacity:.16}
.pb-v-numbered .pb-grid{counter-reset:pbnum}
.pb-v-iconleft .pb-card{flex-direction:row;align-items:flex-start;gap:14px;background:none;border:0;padding:0}
.pb-v-iconleft .pb-icon{flex:none}
.pb-v-timeline .pb-grid{grid-template-columns:1fr;gap:0}
.pb-v-timeline .pb-card{border:0;border-left:2px solid var(--pb-line,#e4e4e4);border-radius:0;margin-left:14px;padding-left:26px;padding-bottom:26px;position:relative;background:none}
.pb-v-timeline .pb-stepno{position:absolute;left:-16px;top:0}
.pb-v-row .pb-card{background:none;border:0;align-items:center;text-align:center}

/* shop */
.pb-v-minimal .pb-product p{display:none}
.pb-v-overlay .pb-product{position:relative;--pb-bleed:0px;padding:0;overflow:hidden;border:0}
.pb-v-overlay .pb-product-shot{aspect-ratio:3/4}
.pb-v-overlay .pb-product .pb-h3,.pb-v-overlay .pb-product .pb-price{position:relative;z-index:2;color:#fff;padding:0 16px}
.pb-v-overlay .pb-product .pb-h3{margin-top:-64px}
.pb-v-overlay .pb-product .pb-price{padding-bottom:16px}
.pb-v-overlay .pb-product p{display:none}
.pb-v-overlay .pb-product::after{content:"";position:absolute;inset:auto 0 0;height:60%;background:linear-gradient(transparent,rgba(0,0,0,.78));z-index:1}
.pb-v-list .pb-product{--pb-bleed:0px;flex-direction:row;align-items:center;gap:20px}
/* The list variant puts the picture beside the words rather than over them,
   so it keeps its own box and its own rounding — the bleed above would drag
   it out through the side of the card. */
.pb-v-list .pb-product-shot{width:150px;flex:none;aspect-ratio:1;margin:0;
  border-radius:calc(var(--pb-radius,14px) - 6px)}
.pb-v-list .pb-price{margin-left:auto}
.pb-v-flipped .pb-featured .pb-split-media{order:2}
.pb-v-card .pb-featured{background:var(--pb-surface,#fff);border-radius:var(--pb-radius,14px);padding:26px;box-shadow:0 26px 54px -44px rgba(0,0,0,.5)}
.pb-v-bordered .pb-plan{background:none}
.pb-v-compact .pb-plan{padding:16px}
.pb-v-compact .pb-price-lg{font-size:1.45rem}

/* gallery */
.pb-v-masonry .pb-grid{display:block;columns:var(--pb-cols,3);column-gap:var(--pb-gap,20px)}
.pb-v-masonry .pb-grid figure{break-inside:avoid;margin-bottom:var(--pb-gap,20px)}
.pb-v-masonry .pb-media{aspect-ratio:auto}
.pb-v-carousel .pb-grid{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:10px;-webkit-overflow-scrolling:touch}
.pb-v-carousel .pb-grid>*{flex:0 0 min(78%,320px);scroll-snap-align:start}
.pb-v-wide .pb-wrap{padding-left:0;padding-right:0}
.pb-v-wide .pb-media{border-radius:0}
.pb-v-band .pb-logobar{justify-content:center}

/* testimonials and team */
.pb-v-plain .pb-quote{background:none;border:0;padding:0}
.pb-v-square .pb-member .pb-round{border-radius:var(--pb-radius,14px);aspect-ratio:4/5;max-width:none}
.pb-v-card .pb-quote-big{background:var(--pb-surface,#fff);border-radius:var(--pb-radius,14px);padding:34px;box-shadow:0 26px 54px -44px rgba(0,0,0,.5)}

/* faq and tabs */
.pb-v-minimal .pb-faq details{border:0;border-bottom:1px solid var(--pb-line,#e4e4e4);border-radius:0;padding:14px 0}
.pb-v-twocol .pb-faq{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.pb-v-minimal .pb-tabbar button{background:none;border-radius:0;border-bottom:2px solid transparent;padding:.55rem .2rem;margin-right:18px}
.pb-v-minimal .pb-tabbar button.on{background:none;color:inherit;border-bottom-color:var(--pb-accent,#111);font-weight:700}

/* lead capture and cta */
.pb-v-inline .pb-capture,.pb-v-inline .pb-cta{display:grid;grid-template-columns:1fr auto;align-items:center;gap:26px;text-align:left}
.pb-v-inline .pb-capture .pb-form{max-width:420px}
.pb-v-card .pb-capture{background:var(--pb-surface,#fff);border-radius:var(--pb-radius,14px);padding:34px;box-shadow:0 26px 54px -44px rgba(0,0,0,.5)}
.pb-v-plain .pb-linkrow{border:0;border-bottom:1px solid var(--pb-line,#e4e4e4);border-radius:0;padding:.9rem .2rem}
.pb-v-button .pb-linkrow{justify-content:center;background:var(--pb-accent,#111);color:var(--pb-accent-ink,#fff);border:0}
.pb-v-button .pb-linkrow span{flex:none}

/* countdown and footer */
.pb-v-minimal .pb-clock span{background:none;padding:6px 0;min-width:64px}
.pb-v-stacked .pb-footer{flex-direction:column;text-align:center;gap:12px}
.pb-v-stacked .pb-footer small{margin-left:0}

.pb-previewbar{background:#111;color:#fff;padding:9px 18px;font-size:.86rem;display:flex;gap:10px;align-items:center;justify-content:center}
.pb-previewbar a{text-decoration:underline;opacity:.85}

/* ── tablet ──────────────────────────────────────────────────────── */
/* Above the floor, the creator's chosen column count wins. */
@container pb (min-width:1025px){
  .pb-grid{grid-template-columns:repeat(var(--pb-cols,3),minmax(0,1fr))}
}

@container pb (max-width:1024px){
  .pb-grid{grid-template-columns:repeat(var(--pb-cols-t,2),minmax(0,1fr))}
  .pb-v-masonry .pb-grid{columns:var(--pb-cols-t,2)}
  .pb-v-offset .pb-split{grid-template-columns:1fr 1fr}
  .pb-v-twocol .pb-faq{grid-template-columns:1fr}
}

/* ── mobile ──────────────────────────────────────────────────────── */
@container pb (max-width:768px){
  .pb-grid{grid-template-columns:repeat(var(--pb-cols-m,1),minmax(0,1fr))}
  .pb-v-masonry .pb-grid{columns:var(--pb-cols-m,1)}
  .pb-split,.pb-v-offset .pb-split{grid-template-columns:1fr;gap:26px}
  .pb-split-media{max-width:520px;width:100%}
  .pb-align-center .pb-split-media{margin-left:auto;margin-right:auto}
  .pb-split.is-flipped .pb-split-media,.pb-v-flipped .pb-featured .pb-split-media{order:0}
  .pb-v-inline .pb-capture,.pb-v-inline .pb-cta{grid-template-columns:1fr;text-align:inherit}
  .pb-v-list .pb-product{flex-direction:column;align-items:stretch}
  .pb-v-list .pb-product-shot{width:100%;aspect-ratio:16/9}
  .pb-v-list .pb-price{margin-left:0}
  .pb-v-split .pb-nav{grid-template-columns:1fr}
  /* The bar keeps the brand and a toggle; everything else folds away until
     asked for. A wrapped row of links pretending to be a menu is worse than
     no menu at all. */
  .pb-nav{flex-wrap:wrap;gap:12px}
  .pb-nav-toggle{display:inline-flex}
  .pb-nav-links{display:none;order:3;width:100%;flex-direction:column;gap:2px;margin-left:0;padding-top:6px;border-top:1px solid color-mix(in srgb,currentColor 12%,transparent)}
  .pb-nav.is-open .pb-nav-links{display:flex}
  .pb-nav-links a{padding:.6rem 0}
  /* On a phone the box is the thing under your thumb, not three taps away
     behind the menu button — but only once it is asked for. Closed it is the
     icon beside the bag; opened it takes the whole width, which is the only
     width worth typing into on a phone. */
  .pb-nav-search{order:2;flex:1 1 100%;margin-left:0}
  .pb-nav-search.is-ready:not(.is-open){order:1;flex:none;margin-left:0}
  .pb-nav-search.is-ready.is-open{order:2;flex:1 1 100%;min-width:0}
  .pb-nav .pb-btn{order:4;margin-left:0;width:100%;justify-content:center;display:none}
  .pb-nav.is-open .pb-btn{display:inline-flex}
  /* The one link that does not fold away.
     Everything else in the bar is the shop talking; this is a buyer coming
     back for what they already paid for, and making them open a menu to find
     it is how they end up emailing the creator for a download link instead.
     Just the bag on a narrow bar — the label is what does not fit, not the
     door. */
  .pb-nav-purchases{order:1;margin-left:auto;padding:.5rem .6rem}
  .pb-nav-purchases span{display:none}
  .pb-nav-purchases i{font-size:1.05rem;opacity:1}
  .pb-v-split .pb-nav-brand{order:0}
  .pb-footer{flex-wrap:wrap;gap:14px}
  .pb-footer small{margin-left:0;width:100%}
  .pb-stats{gap:22px}
  .pb-clock{grid-template-columns:repeat(4,minmax(0,1fr));gap:7px}
  .pb-clock span{padding:10px 4px}
  .pb-clock b{font-size:1.32rem}
  .pb-clock small{font-size:.62rem;letter-spacing:.04em}
  .pb-card{padding:18px}
  .pb-round{max-width:190px}
  .pb-product-shot{aspect-ratio:16/10}
  .pb-form{flex-direction:column}
  .pb-form input,.pb-form .pb-btn{width:100%}
  .pb-wrap{padding-left:18px;padding-right:18px}
  .pb-hide-mobile{display:none}
  .pb-hide-desktop{display:block}

  /* Mobile alignment override, when the creator asks for one. */
  .pb-malign-center{text-align:center}
  .pb-malign-center .pb-stack{align-items:center}
  .pb-malign-center .pb-actions,.pb-malign-center .pb-form{justify-content:center}
  .pb-malign-left{text-align:left}
  .pb-malign-left .pb-stack{align-items:flex-start}
  .pb-malign-left .pb-actions{justify-content:flex-start}

  /* Mobile scale falls back to the desktop one unless the creator set it, and
     is capped either way so a Display heading cannot overflow a phone. */
  .pb-section{font-size:calc(1rem * var(--pb-body-scale-m,var(--pb-body-scale,1)))}
  .pb-lead{font-size:calc(1.02rem * var(--pb-body-scale-m,var(--pb-body-scale,1)))}
  .pb-h1{font-size:clamp(1.75rem,calc(7cqw * min(var(--pb-h-scale-m,var(--pb-h-scale,1)),1.2)),2.6rem)}
  .pb-h2{font-size:clamp(1.35rem,calc(5.4cqw * min(var(--pb-h-scale-m,var(--pb-h-scale,1)),1.2)),2rem)}
  .pb-h3{font-size:calc(1.08rem * min(var(--pb-h-scale-m,var(--pb-h-scale,1)),1.2))}

  .pb-space-top-lg{padding-top:52px}.pb-space-bottom-lg{padding-bottom:52px}
  .pb-space-top-xl{padding-top:60px}.pb-space-bottom-xl{padding-bottom:60px}
}

@container pb (max-width:420px){
  .pb-wrap{padding-left:15px;padding-right:15px}
  .pb-clock{gap:6px}
  .pb-clock span{padding:9px 2px}
  .pb-clock b{font-size:1.15rem}
  .pb-h1{font-size:clamp(1.6rem,8vw,2.1rem)}
  .pb-stats{gap:16px}
  .pb-stat b{font-size:1.6rem}
}
@media (prefers-reduced-motion:reduce){.pb-page *{transition:none!important}}


/* ═══════════════ form block ═══════════════ */
.pb-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;width:100%;text-align:left}
.pb-field{display:flex;flex-direction:column;gap:6px;min-width:0}
.pb-field.is-wide{grid-column:1 / -1}
.pb-fieldlabel{font-size:.88rem;font-weight:600}
.pb-fieldlabel i{color:#C4483C;font-style:normal;margin-left:2px}
.pb-fields input[type=text],.pb-fields input[type=email],.pb-fields input[type=tel],
.pb-fields input[type=number],.pb-fields input[type=date],.pb-fields select,.pb-fields textarea{
  width:100%;padding:.72rem .9rem;border:1px solid var(--pb-line,#e4e4e4);
  border-radius:var(--pb-radius,14px);font:inherit;font-size:.95rem;
  background:var(--pb-elevated,var(--pb-surface,#fff));color:var(--pb-ink,#111)}
.pb-fields textarea{resize:vertical;min-height:110px}
.pb-fields input:focus,.pb-fields select:focus,.pb-fields textarea:focus{
  outline:2px solid var(--pb-accent,#111);outline-offset:1px;border-color:transparent}
.pb-tick{display:flex;align-items:center;gap:8px;font-size:.95rem}
.pb-tick input{width:18px;height:18px;accent-color:var(--pb-accent,#111)}
.pb-formblock .pb-said-bad{font-size:.82rem;color:#C4483C}
/* The send button fills the row, so its label has to be told to sit in the
   middle — .pb-btn is inline-flex and would otherwise hug the left edge. */
.pb-fields .pb-btn{justify-content:center;text-align:center}
.pb-said{display:inline-flex;align-items:center;gap:7px;font-size:.95rem;font-weight:600;color:var(--pb-accent,#111)}

/* Dark and photographic bands need their own field colours, or the inputs
   vanish into the background. */
.pb-bg-dark .pb-fields input,.pb-bg-dark .pb-fields textarea,.pb-bg-dark .pb-fields select,
.pb-bg-accent .pb-fields input,.pb-bg-accent .pb-fields textarea,.pb-bg-accent .pb-fields select,
.pb-bg-image .pb-fields input,.pb-bg-image .pb-fields textarea,.pb-bg-image .pb-fields select{
  background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.26);color:inherit}
.pb-bg-dark .pb-said,.pb-bg-accent .pb-said,.pb-bg-image .pb-said{color:inherit}

.pb-v-split .pb-formblock{display:grid;grid-template-columns:1fr 1.15fr;gap:36px;align-items:start}
.pb-v-split .pb-formblock .pb-fields{grid-column:2;grid-row:1 / span 4}

@container pb (max-width:768px){
  .pb-fields{grid-template-columns:1fr}
  .pb-v-split .pb-formblock{grid-template-columns:1fr;gap:20px}
  .pb-v-split .pb-formblock .pb-fields{grid-column:1;grid-row:auto}
}

/* ══════════ THE BLOCKS ADDED IN 2.1 ══════════ */

/* ── layout ────────────────────────────────────────────────────────────────
   Nothing but room, and the line between two things. Both were missing, and a
   creator's only way to make a gap was an empty heading — which a screen
   reader announces and a search engine indexes. */
.pb-spacer{height:var(--h,64px)}
@container pb (max-width:640px){.pb-spacer{height:var(--hm,var(--h,64px))}}

.pb-divider{border:0;border-top:var(--w,2px) var(--style,solid) color-mix(in srgb,currentColor 18%,transparent);margin:0;width:100%}
.pb-divider-labelled{display:flex;align-items:center;gap:14px;border:0}
.pb-divider-labelled span{flex:1;height:0;border-top:var(--w,2px) var(--style,solid) color-mix(in srgb,currentColor 18%,transparent)}
.pb-divider-labelled em{font-style:normal;font-size:.82rem;letter-spacing:.08em;text-transform:uppercase;opacity:.62}

/* ── commerce ─────────────────────────────────────────────────────────────── */
.pb-buy-price{opacity:.72;font-weight:500}
.pb-tip-amounts{display:flex;gap:10px;flex-wrap:wrap;justify-content:inherit}

/* ── testimonial carousel ──────────────────────────────────────────────────
   A scroll container, not a slider. It swipes on a phone, scrolls with a
   trackpad and tabs with a keyboard, without a line of script — scroll-snap is
   what makes it stop on a card. */
.pb-carousel{display:flex;gap:16px;overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:8px;scrollbar-width:none}
.pb-carousel::-webkit-scrollbar{display:none}
.pb-carousel>*{flex:0 0 min(360px,84%);scroll-snap-align:start}
.pb-carousel:focus-visible{outline:2px solid var(--pb-accent,#111);outline-offset:4px;border-radius:12px}

/* ── star rating ──────────────────────────────────────────────────────────── */
.pb-stars{display:inline-flex;gap:3px;font-size:1.15rem;color:#F5A524}
.pb-stars .bi-star{opacity:.28}
.pb-rating-score{display:flex;align-items:baseline;gap:9px;justify-content:inherit}
.pb-rating-score b{font-size:1.5rem}
.pb-rating-score span{opacity:.68;font-size:.9rem}

/* ── urgency ──────────────────────────────────────────────────────────────── */
.pb-stock-line{display:inline-flex;align-items:center;gap:8px;font-weight:600;font-size:.95rem}

/* Fixed on a live page, in the flow inside the editor — a bar sitting over the
   canvas hides the section somebody is trying to edit. */
.pb-sticky{position:fixed;left:0;right:0;z-index:60;display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  padding:12px 18px;background:var(--pb-accent,#111);color:var(--pb-btn-ink,#fff);
  box-shadow:0 -8px 30px -18px rgba(0,0,0,.6)}
.pb-sticky-top{top:0}
.pb-sticky-bottom{bottom:0}
.pb-sticky.is-inline{position:static;border-radius:var(--pb-radius,14px)}
.pb-sticky p{margin:0;font-weight:600;flex:1;min-width:180px}
.pb-sticky .pb-btn{background:var(--pb-btn-ink,#fff);color:var(--pb-accent,#111)}
.pb-sticky-x{background:none;border:0;color:inherit;opacity:.7;cursor:pointer;padding:6px;line-height:1}
.pb-sticky-x:hover{opacity:1}
.pb-sticky[hidden]{display:none}

/* ── lead magnet card ─────────────────────────────────────────────────────── */
.pb-magnet{display:grid;grid-template-columns:1fr;gap:22px;align-items:center}
@container pb (min-width:820px){.pb-magnet{grid-template-columns:minmax(0,260px) minmax(0,1fr)}}
.pb-magnet-cover img{width:100%;border-radius:var(--pb-radius,14px);display:block}
.pb-magnet-body{display:flex;flex-direction:column;gap:12px}
.pb-ticks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:7px}
.pb-ticks li{display:flex;align-items:flex-start;gap:9px;font-size:.94rem}
.pb-ticks i{color:var(--pb-accent,#111);margin-top:2px;flex:none}

/* ── social links ─────────────────────────────────────────────────────────── */
.pb-social{display:flex;gap:12px;flex-wrap:wrap;justify-content:inherit}
.pb-social a{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  width:44px;height:44px;border-radius:999px;
  border:1px solid color-mix(in srgb,currentColor 20%,transparent);color:inherit;text-decoration:none;
  transition:transform .18s,background .18s}
.pb-social a:hover{transform:translateY(-2px);background:color-mix(in srgb,currentColor 8%,transparent)}
.pb-social i{font-size:1.1rem}
/* The name is there for a screen reader and hidden from the eye — until the
   labelled variant asks for it. */
.pb-social span{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}
.pb-social-sm a{width:38px;height:38px}
.pb-social-sm i{font-size:.98rem}
.pb-social-lg a{width:52px;height:52px}
.pb-social-lg i{font-size:1.3rem}

/* ── embed ────────────────────────────────────────────────────────────────
   The box holds its own height from the ratio, so the page does not jump when
   the iframe arrives — rule four of the five every block has to keep. */
.pb-embed{position:relative;width:100%;border-radius:var(--pb-radius,14px);overflow:hidden;background:color-mix(in srgb,currentColor 6%,transparent)}
.pb-embed::before{content:"";display:block;padding-top:var(--ratio,56.25%)}
.pb-embed iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.pb-embed-16-9{--ratio:56.25%}
.pb-embed-4-3{--ratio:75%}
.pb-embed-1-1{--ratio:100%}
.pb-embed-tall{--ratio:125%}
/* The labelled variant shows the name it was already carrying for a screen
   reader, rather than a second copy of it in the markup. */
.pb-v-labelled .pb-social a{width:auto;height:auto;padding:.6rem 1rem;border-radius:999px}
.pb-v-labelled .pb-social span{position:static;width:auto;height:auto;margin:0;clip:auto;overflow:visible;font-size:.9rem;font-weight:600}
.pb-v-square .pb-social a{border-radius:var(--pb-radius,12px)}
/* A carousel drawn plainly: no card, just the words. */
.pb-v-quiet .pb-carousel .pb-quote{background:none;border:0;padding:0}
/* The big score. */
.pb-v-big .pb-rating-score b{font-size:2.6rem}
.pb-v-big .pb-stars{font-size:1.5rem}

/* ── the theme's shadow, and the change itself ─────────────────────────────
   Cards, media and the raised things wear the theme's own shadow rather than
   one baked in here, so a flat theme is flat everywhere and a dramatic one is
   dramatic everywhere. */
.pb-card,.pb-quote,.pb-linkrow,.pb-faq details{box-shadow:var(--pb-shadow,none)}
.pb-media,.pb-product-shot,.pb-magnet-cover img{box-shadow:var(--pb-shadow,none)}

/* Swapping a palette repaints the whole page at once. Without this it snaps —
   nine colours and a corner radius changing in one frame reads as a flicker
   rather than as a choice being applied. */
.pb-section,.pb-card,.pb-btn,.pb-quote,.pb-linkrow,.pb-media,.pb-faq details,.pb-form input{
  transition:background-color .34s cubic-bezier(.22,1,.36,1),
             color .34s cubic-bezier(.22,1,.36,1),
             border-color .34s cubic-bezier(.22,1,.36,1),
             box-shadow .34s cubic-bezier(.22,1,.36,1),
             border-radius .34s cubic-bezier(.22,1,.36,1),
             padding .34s cubic-bezier(.22,1,.36,1);
}
@media (prefers-reduced-motion:reduce){
  .pb-section,.pb-card,.pb-btn,.pb-quote,.pb-linkrow,.pb-media,.pb-faq details,.pb-form input{transition:none}
}

/* ── the plain pieces — §M2.2 ─────────────────────────────────────────
   Layout: Section, Columns. Content: Heading, Text, Image, Video, Button.
   Everything else in this file dresses a ready-made arrangement; these are
   for the page that does not fit one. */

/* Words typed into a box, shown the way they were typed. `pre-line` keeps the
   blank lines a creator put there without asking them to learn any markup. */
.pb-prose{white-space:pre-line;margin:0;line-height:var(--pb-leading,1.6);
          font-size:calc(1rem * var(--pb-body-scale,1));font-weight:var(--pb-body-weight,400)}

/* Widths a block can be asked to take. `readable` is a measure rather than a
   number somebody liked: past about 70 characters the eye loses the line. */
.pb-w-readable{max-width:64ch;margin-left:auto;margin-right:auto}
.pb-w-normal{max-width:900px;margin-left:auto;margin-right:auto}

.pb-band{width:100%}

.pb-cols{display:grid;gap:var(--pb-gap,22px);align-items:start}
.pb-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}
.pb-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}
.pb-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}
.pb-col{display:flex;flex-direction:column;gap:8px;min-width:0}

.pb-image{display:block;width:100%;height:auto;border-radius:var(--pb-radius,14px)}
.pb-caption{margin:0;font-size:.86rem;color:var(--pb-muted,#5F7A70)}

/* A full-width button, for a phone where a small target is a missed sale. */
.pb-btn-block{display:flex;width:100%;justify-content:center}

/* Only ever drawn inside the editor. `[data-uid]` is added while editing and
   never on a public page, so this cannot leak advice to a visitor. */
.pb-hint{display:none;margin:0;font-size:.86rem;color:var(--pb-muted,#5F7A70)}
[data-uid] .pb-hint{display:block}

/* `@container`, not `@media`, like every other breakpoint in this file.

   These three were the last rules measuring the browser window rather than
   the page, and the page is not always the window: in the builder it is a
   frame the creator resizes with the Desktop / Tablet / Mobile buttons. So a
   four-column band stayed four columns however narrow the preview got — the
   creator checked their phone layout, saw four columns that would never
   appear on a phone, and had no way to tell which of the two was lying. */
@container pb (max-width:900px){
  /* Four columns on a phone is four unreadable columns. Three and four both
     fall to two, then to one, rather than shrinking to nothing. */
  .pb-cols-3,.pb-cols-4{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@container pb (max-width:620px){
  .pb-cols-2,.pb-cols-3,.pb-cols-4{grid-template-columns:minmax(0,1fr)}
}

/* ═══════════════ the product & course card ═══════════════
   A shelf of things to buy, laid out the way every marketplace a buyer has
   already used lays one out: picture, name, who made it, what it scored,
   what it costs. The order is the order they are read in, and the price is
   pinned to the bottom so a row of cards lines its prices up whatever the
   titles do.

   Only .pb-product is touched. Every other .pb-card on a page — a feature, a
   plan, a testimonial — keeps the card it had, and the .pb-v-* variants keep
   restyling the box itself without fighting anything here. */
.pb-product{--pb-bleed:22px;gap:7px;overflow:hidden}

/* Edge to edge across the top of the card, by pulling back out through the
   card's own padding. The width has to grow by the same amount it is pulled
   out by: `width:100%` is 100% of the *content* box, so a picture with
   -22px margins and no extra width started at the card's left edge and
   stopped 44px short of its right one — the empty strip down the side.

   The variants below zero the bleed, so they get the inset picture instead:
   a negative margin against no padding hangs the image off the card, and
   against .pb-v-timeline it would cross the rule. */
.pb-product-shot{aspect-ratio:16/10;
  width:calc(100% + var(--pb-bleed,22px) * 2);
  margin:calc(var(--pb-bleed,22px) * -1) calc(var(--pb-bleed,22px) * -1) 5px;
  border-radius:calc(var(--pb-radius,14px) - 1px) calc(var(--pb-radius,14px) - 1px) 0 0}

/* The width above is worthless without this. `.pb-page img{max-width:100%}`
   near the top of the file outranks a single-class rule, so it clamped the
   extra width straight back off and the picture stopped short of the card's
   right edge — the whole bug. Two classes to outrank it; the width itself
   stays on the rule above, so .pb-v-list keeps its own 150px picture. */
.pb-product .pb-product-shot{max-width:none}

.pb-v-minimal .pb-product-shot,
.pb-v-plain .pb-product-shot,
.pb-v-iconleft .pb-product-shot,
.pb-v-timeline .pb-product-shot{--pb-bleed:0px;border-radius:calc(var(--pb-radius,14px) - 6px)}

/* Two lines, then an ellipsis — and two lines of room whether or not the
   title uses them, so the byline and everything under it starts at the same
   place on every card in the row. A marketplace title runs long, and a grid
   whose cards all start their text somewhere different reads as broken. */
.pb-product-name{font-size:calc(1.02rem * var(--pb-h-scale,1));line-height:1.3;
  min-height:2.6em;
  display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

.pb-product-by{margin:0;font-size:.8rem;line-height:1.35;opacity:.62}
.pb-product-facts{margin:0;font-size:.76rem;opacity:.55}

.pb-product-meta{display:flex;align-items:center;flex-wrap:wrap;gap:8px}
.pb-product-tag{align-self:center;font-size:.66rem;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;padding:3px 8px;border-radius:6px;
  background:var(--pb-card,#f6f6f6);color:inherit;white-space:nowrap}

.pb-product-rating{display:inline-flex;align-items:center;gap:5px;font-size:.8rem;line-height:1}
/* Not the star's own yellow: #F5A524 is a fill colour and fails as small text
   on white. This is the same hue carried down to something readable. */
.pb-product-rating b{color:#8A5A00;font-weight:800;font-size:.86rem}
.pb-stars-sm{font-size:.78rem;gap:1px}
.pb-product-votes{opacity:.55;white-space:nowrap}

/* Pinned low as one block — the badge, the score and the price together —
   so all three line up across a row however much a card carries above them.
   The auto margin has to sit on the first of the three: two auto margins in
   one column split the free space and prise the rating off the price. */
.pb-product-meta{margin-top:auto}
.pb-product .pb-price{padding-top:3px;font-size:1.06rem}

/* The list variant lays a card out sideways, where "push it to the bottom"
   means dropping the badges below the title's baseline for no reason. */
.pb-v-list .pb-product-meta{margin-top:0}

/* On a dark or a photographic band the two borrowed colours stop working:
   a near-black chip disappears and #8A5A00 goes muddy. */
.pb-bg-dark .pb-product-tag,.pb-bg-accent .pb-product-tag,.pb-bg-image .pb-product-tag{
  background:rgba(255,255,255,.15)}
.pb-bg-dark .pb-product-rating b,.pb-bg-accent .pb-product-rating b,.pb-bg-image .pb-product-rating b{
  color:#F5C56B}

/* .pb-card drops to 18px of padding on a phone; the bleed follows it, or the
   picture overhangs by the 4px difference. After the rules above on purpose:
   the shared 768px block sits higher up the file and would lose to them. */
@container pb (max-width:768px){.pb-product{--pb-bleed:18px}}

/* ── the blog blocks ──────────────────────────────────────────────────
   Article, post header, post cards, author card.

   Everything above dresses a block whose text a creator typed into one field.
   An article is different in kind: the markup comes out of the Markdown
   converter, so these rules style *elements* — h2, p, ul, blockquote — rather
   than classes nobody can put there. Scoped under .pb-article so they cannot
   reach the rest of the page. */

.pb-article{line-height:var(--pb-leading,1.7);
  font-size:calc(1rem * var(--pb-body-scale,1));font-weight:var(--pb-body-weight,400)}

/* Vertical rhythm as one rule rather than a margin on every element: the
   converter decides what elements exist, and a list of them here would be a
   list that goes out of date the first time a creator uses a table. */
.pb-article>*+*{margin-top:1.05em}
.pb-article>*:first-child{margin-top:0}

.pb-article h2,.pb-article h3,.pb-article h4{
  font-family:var(--pb-font-heading,'Plus Jakarta Sans'),sans-serif;
  letter-spacing:var(--pb-h-track,-.03em);font-weight:var(--pb-h-weight,700);
  line-height:1.22;margin-top:1.9em;margin-bottom:-.25em;
  /* Scroll to a subheading and it lands under a sticky nav otherwise. */
  scroll-margin-top:80px}
.pb-article h2{font-size:calc(1.5rem * var(--pb-h-scale,1))}
.pb-article h3{font-size:calc(1.2rem * var(--pb-h-scale,1))}
.pb-article h4{font-size:calc(1.05rem * var(--pb-h-scale,1))}

/* The permalink anchor the converter inserts. It exists to carry the id and
   draws nothing — see App\Builder\Markdown. */
.pb-article .heading-permalink{display:inline-block;width:0;overflow:hidden}

.pb-article a{color:var(--pb-accent,#0F766E);text-underline-offset:2px}
.pb-article ul,.pb-article ol{padding-left:1.35em}
.pb-article li+li{margin-top:.4em}
.pb-article img{display:block;max-width:100%;height:auto;border-radius:var(--pb-radius,14px)}

.pb-article blockquote{margin-left:0;margin-right:0;padding:2px 0 2px 1.1em;
  border-left:3px solid var(--pb-accent,#0F766E);font-style:italic;opacity:.88}

.pb-article code{font-size:.9em;padding:.15em .38em;border-radius:5px;
  background:var(--pb-card,#f4f4f4)}
.pb-article pre{padding:14px 16px;border-radius:var(--pb-radius,14px);
  background:var(--pb-card,#f4f4f4);overflow-x:auto}
.pb-article pre code{padding:0;background:none}

/* A table in a post is the one thing that will not fit a phone, so it scrolls
   inside itself rather than pushing the whole page sideways. */
.pb-article table{width:100%;border-collapse:collapse;display:block;overflow-x:auto}
.pb-article th,.pb-article td{padding:8px 10px;border-bottom:1px solid var(--pb-line,#e5e5e5);text-align:left}

/* ── the things in a post that are not sentences ──

   A video, a product card, a button, a callout, a gallery, an email box. The
   markup comes out of App\Builder\PostBlocks, which is why these are class
   names rather than elements — and why the same names appear in
   sellwares-dashboard.css, where the editor's preview styles them off its own
   tokens. Two stylesheets and one set of names, so what a creator approves in
   the preview is what a reader gets. */

.pb-article .pa-embed{position:relative;aspect-ratio:16/9;overflow:hidden;
  border-radius:var(--pb-radius,14px);background:var(--pb-card,#f4f4f4)}
.pb-article .pa-embed iframe{position:absolute;inset:0;width:100%;height:100%;border:0}

.pb-article .pa-prod{display:flex;align-items:center;gap:14px;padding:14px 16px;
  border:1px solid var(--pb-line,#e5e5e5);border-radius:var(--pb-radius,14px);
  background:var(--pb-card,#fafafa)}
.pb-article .pa-prod-ic{display:grid;place-items:center;width:44px;height:44px;flex:none;
  border-radius:11px;background:var(--pb-surface,#fff);color:var(--pb-accent,#0F766E);font-size:19px}
.pb-article .pa-prod-t{flex:1;min-width:0}
.pb-article .pa-prod-t b{display:block;font-size:1.02rem;line-height:1.3}
.pb-article .pa-prod-t span{font-size:.85rem;opacity:.7}
.pb-article .pa-prod-go{flex:none;padding:10px 18px;border-radius:10px;text-decoration:none;
  background:var(--pb-accent,#0F766E);color:#fff;font-size:.9rem;font-weight:700}

.pb-article .pa-cta-go{display:inline-block;padding:13px 24px;border-radius:11px;text-decoration:none;
  background:var(--pb-accent,#0F766E);color:#fff;font-size:1rem;font-weight:700}

/* Not a blockquote: that is somebody else talking, this is the writer stepping
   out to say "here is the part that matters". */
.pb-article .pa-note{padding:16px 20px;border-left:3px solid var(--pb-accent,#0F766E);
  border-radius:0 var(--pb-radius,14px) var(--pb-radius,14px) 0;background:var(--pb-card,#f6f6f6)}
.pb-article .pa-note>*{margin-top:0}
.pb-article .pa-note>*+*{margin-top:.7em}

.pb-article .pa-gallery{display:grid;gap:10px}
.pb-article .pa-gallery-2{grid-template-columns:repeat(2,1fr)}
.pb-article .pa-gallery-3{grid-template-columns:repeat(3,1fr)}
.pb-article .pa-gallery-4{grid-template-columns:repeat(2,1fr)}
.pb-article .pa-gallery img{width:100%;height:100%;object-fit:cover;aspect-ratio:4/3}
@media (max-width:640px){
  .pb-article .pa-gallery-3{grid-template-columns:repeat(2,1fr)}
}

.pb-article .pa-signup{padding:20px;border:1px solid var(--pb-line,#e5e5e5);
  border-radius:var(--pb-radius,14px);background:var(--pb-card,#fafafa)}
.pb-article .pa-signup b{display:block;margin-bottom:12px;
  font-family:var(--pb-font-heading,'Plus Jakarta Sans'),sans-serif;font-size:1.15rem}
.pb-article .pa-signup-f{display:flex;gap:9px;flex-wrap:wrap}
.pb-article .pa-signup-f input{flex:1;min-width:170px;padding:12px 14px;border-radius:10px;
  border:1px solid var(--pb-line,#e5e5e5);background:var(--pb-surface,#fff);font:inherit;font-size:.95rem}
.pb-article .pa-signup-f button{padding:12px 22px;border:0;border-radius:10px;cursor:pointer;
  background:var(--pb-accent,#0F766E);color:#fff;font:inherit;font-size:.95rem;font-weight:700}

/* Contents list. Off by default — a 300-word post with one of these looks
   lost — so these rules only ever run where a creator asked for it. */
.pb-toc{margin-bottom:26px;padding:14px 16px;border-radius:var(--pb-radius,14px);
  background:var(--pb-card,#f6f6f6);font-size:.92rem}
.pb-toc-t{display:block;margin-bottom:7px;font-size:.72rem;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase;opacity:.6}
.pb-toc ol{margin:0;padding-left:1.1em}
.pb-toc li+li{margin-top:.3em}
.pb-toc-3{padding-left:1em;opacity:.8}

/* ── post header ── */
.pb-posthead{display:flex;flex-direction:column;gap:12px;width:100%}
.pb-posthead-cover{width:100%;height:auto;aspect-ratio:16/8;object-fit:cover;
  border-radius:var(--pb-radius,14px)}
.pb-posthead-cats{display:flex;flex-wrap:wrap;gap:7px}
.pb-cat{font-size:.72rem;font-weight:700;letter-spacing:.03em;padding:4px 9px;
  border-radius:999px;background:var(--pb-card,#f4f4f4);color:inherit;text-decoration:none}
.pb-cat:hover{background:var(--pb-accent,#0F766E);color:var(--pb-accent-ink,#fff)}
.pb-posthead-title{margin:0}
.pb-posthead-blurb{margin:0;font-size:calc(1.08rem * var(--pb-body-scale,1));
  line-height:1.5;opacity:.78}

/* The meta row. A middot between the parts, drawn in CSS so the markup does
   not have to know which of the three the creator switched off. */
.pb-posthead-meta{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;
  font-size:.86rem;color:var(--pb-muted,#5F7A70)}
.pb-posthead-meta>*+*::before{content:'·';margin-right:10px;opacity:.6}
.pb-meta-author{font-weight:600;color:inherit}

/* `display` beats the `hidden` attribute, and every one of these three sets
   one — so the cards held back for "Show more" were drawn anyway, the bar
   meant to appear only with scripting was always there, and "Show less" sat
   beside "Show more" from the start. The attribute is the state; this is what
   lets it be. Same trap the community's replies fell into.

   Not a blanket `[hidden]{display:none}`: this stylesheet is loaded over pages
   whose own rules may rely on `hidden` meaning nothing until a script says
   otherwise, and a global override is a change to every one of them. */
.pb-post[hidden],
.pb-morebar[hidden],
.pb-morebar .pb-btn[hidden]{display:none}

/* The two buttons under a Latest posts block. Centred, because the grid above
   them is centred and a control hanging off the left of three cards reads as
   part of the last one. */
.pb-morebar{display:flex;justify-content:center;gap:10px;flex-wrap:wrap;margin-top:18px}

/* ── post cards ── */
/* `height:100%` so three cards in a row are one height whatever their titles
   do — a grid stretches its items, but a flex column inside one only fills the
   track when it is told to. */
.pb-post{display:flex;flex-direction:column;gap:10px;text-decoration:none;color:inherit;
  min-width:0;height:100%;overflow:hidden}
/* The words take the room the picture does not, so every card's title sits on
   the same line as its neighbours'. */
.pb-post .pb-post-body{flex:1}
.pb-post-cover{display:block;aspect-ratio:16/10;margin:-22px -22px 3px;overflow:hidden;
  border-radius:calc(var(--pb-radius,14px) - 1px) calc(var(--pb-radius,14px) - 1px) 0 0}
/* `fill`, not `cover`.

   Cover keeps the picture's shape and cuts whatever does not fit, which is
   the better-looking answer and not the one asked for: a creator who sizes a
   cover to the card wants the whole of it on the card. Fill stretches it to
   the box exactly — the picture is distorted when its shape does not match,
   and every card in the row is the same size, which is the point. */
.pb-post-cover img{width:100%;height:100%;object-fit:fill;display:block}
/* Keeps the grid square when one post has a picture and the next does not. */
.pb-post-cover-none{background:var(--pb-card,#f1f1f1)}
.pb-post-body{display:flex;flex-direction:column;gap:6px;min-width:0}
.pb-post-when{font-size:.78rem;color:var(--pb-muted,#5F7A70)}
.pb-post-title{font-family:var(--pb-font-heading,'Plus Jakarta Sans'),sans-serif;
  font-size:calc(1.02rem * var(--pb-h-scale,1));line-height:1.3;
  display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.pb-post-blurb{font-size:.9rem;line-height:1.5;opacity:.75;
  display:-webkit-box;-webkit-line-clamp:3;line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}

/* The list variant: a row per post, no card, no picture frame. */
.pb-v-list .pb-post{flex-direction:row;align-items:center;gap:14px}
.pb-v-list .pb-post-cover{flex:0 0 116px;aspect-ratio:4/3;margin:0;
  border-radius:calc(var(--pb-radius,14px) - 6px)}

/* ── the four card designs ──

   The markup is identical in all four; only this class changes. A creator can
   switch between them as often as they like and lose nothing, and the block
   stores one word.

   `plain` is the default drawn above and has no rules of its own. */

/* Words on the picture. One card, not two halves — so the cover fills it and
   the text sits on a gradient dark enough to read against a white photograph
   and a black one alike. No picture means no overlay to sit on, so those
   cards fall back to the ordinary arrangement rather than printing pale text
   on nothing. */
.pb-posts-overlay .pb-post{position:relative;padding:0;min-height:240px;justify-content:flex-end}
.pb-posts-overlay .pb-post-cover{position:absolute;inset:0;margin:0;aspect-ratio:auto;
  border-radius:inherit}
.pb-posts-overlay .pb-post-body{position:relative;z-index:1;padding:18px;gap:5px;flex:0}
.pb-posts-overlay .pb-post:has(.pb-post-cover img)::after{content:'';position:absolute;inset:0;
  border-radius:inherit;
  background:linear-gradient(180deg,rgba(0,0,0,0) 30%,rgba(0,0,0,.72) 100%)}
.pb-posts-overlay .pb-post:has(.pb-post-cover img) .pb-post-title,
.pb-posts-overlay .pb-post:has(.pb-post-cover img) .pb-post-blurb,
.pb-posts-overlay .pb-post:has(.pb-post-cover img) .pb-post-when,
.pb-posts-overlay .pb-post:has(.pb-post-cover img) .pb-post-meta{color:#fff}
.pb-posts-overlay .pb-post:has(.pb-post-cover img) .pb-post-blurb{opacity:.85}

/* Picture beside the words. For a column too narrow to give a cover the full
   width — a sidebar, or a two-up grid on a page that is mostly text. Stacks
   back to the ordinary card when the card itself gets narrow, because a 96px
   thumbnail beside two words is neither. */
.pb-posts-side .pb-post{flex-direction:row;align-items:flex-start;gap:14px}
.pb-posts-side .pb-post-cover{flex:0 0 104px;aspect-ratio:1;margin:0;
  border-radius:calc(var(--pb-radius,14px) - 6px)}
.pb-posts-side .pb-post-body{flex:1}
.pb-posts-side .pb-post-title{-webkit-line-clamp:3;line-clamp:3}

/* Words only, with a rule between. What an index of essays wants: no boxes,
   no thumbnails, nothing competing with the titles. The rule is on the top of
   each card rather than the bottom, so the last one does not leave a line
   hanging under the block. */
/* One column, whatever the block's column setting says. Three columns of
   rules reads as a table header, not an index — and an index is the whole
   reason to take the pictures away. */
.pb-posts-text{grid-template-columns:1fr;gap:0}
.pb-posts-text .pb-post{padding:16px 0;border-radius:0;background:none;border:0;
  box-shadow:none;gap:6px}
.pb-posts-text .pb-post+.pb-post,
.pb-posts-text .pb-post:first-child{border-top:1px solid var(--pb-line,#e4e4e4)}
.pb-posts-text .pb-post-title{font-size:calc(1.14rem * var(--pb-h-scale,1));-webkit-line-clamp:3;line-clamp:3}

@container (max-width:520px){
  .pb-posts-side .pb-post{flex-direction:column}
  .pb-posts-side .pb-post-cover{flex-basis:auto;width:100%;aspect-ratio:16/10;
    margin:-22px -22px 3px;
    border-radius:calc(var(--pb-radius,14px) - 1px) calc(var(--pb-radius,14px) - 1px) 0 0}
  .pb-posts-overlay .pb-post{min-height:200px}
}

/* ── author card ── */
.pb-author{display:flex;gap:16px;align-items:flex-start;width:100%;text-align:left}
.pb-author-photo{flex:0 0 64px;width:64px;height:64px;border-radius:50%;object-fit:cover}
.pb-author-body{display:flex;flex-direction:column;gap:5px;min-width:0}
.pb-author-name{font-family:var(--pb-font-heading,'Plus Jakarta Sans'),sans-serif;
  font-size:calc(1.05rem * var(--pb-h-scale,1))}
.pb-author-role{font-size:.82rem;color:var(--pb-muted,#5F7A70)}
.pb-author-link{font-size:.88rem;font-weight:600;color:var(--pb-accent,#0F766E)}
.pb-v-plain .pb-author{gap:14px}

/* Said only inside the editor, like .pb-hint above: a visitor is not the
   person who can fix an empty blog. */
.pb-empty{display:none;margin:0;font-size:.9rem;color:var(--pb-muted,#5F7A70)}
[data-uid] .pb-empty{display:block}

@container (max-width:640px){
  .pb-posthead-cover{aspect-ratio:16/10}
  .pb-v-list .pb-post-cover{flex-basis:88px}
  .pb-author{gap:12px}
  .pb-author-photo{flex-basis:52px;width:52px;height:52px}
}

/* ═══════════════════════════════════════════════════════════ blog — M3.3

   Typography first, decoration second. A blog is words, and the four things
   that decide whether it reads well are measure, leading, heading scale and
   the space between elements — all four of which are theme tokens, so every
   preset gets the same structure in its own voice. Nothing below hardcodes a
   colour that is not a fallback for a token.

   Mobile first: every rule here is the phone layout, and the two media queries
   at the end are what widens it. Most blog traffic arrives on a phone, and a
   desktop layout narrowed down is not the same thing as a phone layout. */

/* ── the post, in pieces ─────────────────────────────────────────────── */

.pb-post-title-block{margin:0}

.pb-post-excerpt{margin:0;line-height:1.55;color:var(--pb-muted,#5F7A70)}
.pb-post-excerpt.pb-lead{font-size:calc(1.1rem * var(--pb-body-scale,1));line-height:1.5}

.pb-post-cover-block{display:block;width:100%;height:auto;object-fit:cover}
.pb-post-cover-block.is-rounded{border-radius:var(--pb-radius,14px)}

/* One line, dot-separated. The separator is a pseudo-element rather than a
   character in the markup, so a screen reader reads "Maya, 6 March, 4 min read"
   and not "Maya dot 6 March dot". */
.pb-post-metarow{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;
  font-size:.85rem;color:var(--pb-muted,#5F7A70)}
.pb-post-metarow>*+*:not(.pb-post-metacats)::before{content:'·';margin-right:10px;opacity:.6}
.pb-post-metarow .pb-meta-author{font-weight:600;color:var(--pb-ink,#12211C)}
.pb-post-metacats{display:inline-flex;flex-wrap:wrap;gap:6px}

/* ── the card grid's meta row ────────────────────────────────────────── */

.pb-post-meta{display:flex;flex-wrap:wrap;gap:4px 8px;font-size:.78rem;
  color:var(--pb-muted,#5F7A70)}
.pb-post-meta>*+*::before{content:'·';margin-right:8px;opacity:.6}

/* ── the list ────────────────────────────────────────────────────────── */

.pb-postlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}

/* A rule between rows rather than a card around each: a list of eight boxes is
   eight borders competing with the words inside them. The last one has none —
   a line under the final row is a line under nothing. */
.pb-postrow{border-bottom:1px solid var(--pb-line,rgba(0,0,0,.09))}
.pb-postrow:last-child{border-bottom:0}

.pb-postrow-link{display:flex;gap:14px;align-items:flex-start;
  padding:18px 0;text-decoration:none;color:inherit}
.pb-postrow-link:hover .pb-postrow-title{color:var(--pb-accent,#0F766E)}
.pb-postrow-link:focus-visible{outline:2px solid var(--pb-accent,#0F766E);
  outline-offset:3px;border-radius:var(--pb-radius,14px)}

.pb-postrow-thumb{flex:0 0 88px;display:block;aspect-ratio:4/3;overflow:hidden;
  border-radius:calc(var(--pb-radius,14px) * .6);background:var(--pb-card,#f1f1f1)}
.pb-postrow-thumb img{width:100%;height:100%;object-fit:cover;display:block}

.pb-postrow-body{display:flex;flex-direction:column;gap:6px;min-width:0}

/* The headline carries the heading font and the preset's own scale, so it moves
   with the theme instead of being a size somebody picked once. */
.pb-postrow-title{font-family:var(--pb-font-heading,'Plus Jakarta Sans'),sans-serif;
  font-weight:var(--pb-h-weight,700);letter-spacing:var(--pb-h-track,-.01em);
  font-size:calc(1.06rem * var(--pb-h-scale-m,var(--pb-h-scale,1)));
  line-height:1.3;transition:color .12s ease}

/* Two lines, then it stops. A four-line headline in a list is a headline that
   has become a paragraph, and the rhythm of the list is what makes it
   scannable. */
.pb-postrow-blurb{font-size:.9rem;line-height:1.55;color:var(--pb-muted,#5F7A70);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

.pb-postrow-meta{display:flex;flex-wrap:wrap;gap:4px 8px;font-size:.78rem;
  color:var(--pb-muted,#5F7A70)}
.pb-postrow-meta>*+*::before{content:'·';margin-right:8px;opacity:.6}

/* ── the testimonial marquee ──────────────────────────────────────────
   A track that animates rather than a strip that scrolls. There is no
   scrollbar to hide because there is no overflow to scroll: the row is one
   flex track wider than the box, moved with a transform.

   The track carries the quotes twice, so travelling half its own width lands
   on a copy of the start and the loop has no seam. Half the gap comes off as
   well — `-50%` alone stops one gap short and the whole row jumps once a
   cycle, which is the thing that makes a marquee look broken. */
.pb-marquee{
  width:100%;overflow:hidden;
  /* The ends fade rather than cut, so a card leaving the frame does not look
     like a card that was clipped by a bug. */
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent)
}
.pb-marquee-track{
  display:flex;gap:var(--pb-gap,20px);width:max-content;
  animation:pb-marquee var(--pb-marquee,64s) linear infinite;
  will-change:transform
}
@keyframes pb-marquee{
  from{transform:translate3d(0,0,0)}
  to{transform:translate3d(calc(-50% - (var(--pb-gap,20px) / 2)),0,0)}
}
/* Stoppable by anybody who wants to read one. */
.pb-marquee:hover .pb-marquee-track,
.pb-marquee:focus-within .pb-marquee-track{animation-play-state:paused}

.pb-marquee .pb-quote-card{flex:0 0 min(392px,82vw)}

/* A quote that looks like a card somebody designed.
   Ranged left whatever the section is ranged, because a quote is read as a
   paragraph and a centred paragraph with a name under it reads as an epitaph.
   The heading above it still follows the section. */
.pb-quote-card{
  display:flex;flex-direction:column;gap:14px;text-align:left;
  padding:26px 26px 22px;border-radius:var(--pb-radius,16px);
  background:var(--pb-card,#fff);
  border:var(--pb-border-width,1px) solid var(--pb-line,#e8e8e8);
  box-shadow:var(--pb-shadow,0 1px 2px rgba(16,24,40,.04))
}
.pb-quote-card .pb-person{justify-content:flex-start;text-align:left}
.pb-quote-card .pb-quote-mark{
  font-size:1.7rem;line-height:1;opacity:.22;color:var(--pb-accent,#111)
}
.pb-quote-card blockquote{
  margin:0;font-size:1.02rem;line-height:1.62;flex:1 1 auto
}
.pb-quote-card .pb-stars{color:#F5A524;font-size:.86rem;letter-spacing:1px;line-height:1}

/* Initials instead of an empty circle. Six tones so a row of them reads as a
   set rather than as one colour repeated. */
.pb-avatar-text{
  display:grid;place-items:center;width:38px;height:38px;border-radius:999px;
  flex:none;font-size:.8rem;font-weight:700;letter-spacing:.02em;
  background:#4B5563;
  /* Important because the section sets a text colour on everything inside it,
     and on a light theme that repainted the initials in the body ink — grey on
     grey, which looked like a disc that had failed to render. */
  color:#fff!important
}
.pb-avatar-text[data-tone="0"]{background:#1F7A5A}
.pb-avatar-text[data-tone="1"]{background:#4A3AFF}
.pb-avatar-text[data-tone="2"]{background:#C2410C}
.pb-avatar-text[data-tone="3"]{background:#0EA5E9}
.pb-avatar-text[data-tone="4"]{background:#9333EA}
.pb-avatar-text[data-tone="5"]{background:#E11D48}

.pb-verified{margin-left:auto;color:#0EA5E9;font-size:1rem;line-height:1}

/* Quiet: the same row without the card around it. */
.pb-v-quiet .pb-quote-card{background:none;border:0;box-shadow:none;padding:6px 2px}

@media (prefers-reduced-motion: reduce){
  /* Stopped, and then made scrollable again — a reader who turned motion off
     still needs a way to reach the quotes that are off the right edge. */
  .pb-marquee-track{animation:none}
  .pb-marquee{overflow-x:auto;scrollbar-width:none;-webkit-mask-image:none;mask-image:none}
  .pb-marquee::-webkit-scrollbar{display:none}
}

/* ── the carousel ────────────────────────────────────────────────────── */

/* Native overflow with scroll-snap. No script, so it is a usable row of cards
   from the first paint rather than a blank strip waiting for JavaScript — and
   it is the widest block on a page, which would make that the biggest layout
   shift on it. */
.pb-carousel{display:flex;gap:var(--pb-gap,20px);overflow-x:auto;
  scroll-snap-type:x mandatory;scroll-padding-left:2px;
  padding-bottom:6px;-webkit-overflow-scrolling:touch;
  scrollbar-width:thin}
.pb-carousel:focus-visible{outline:2px solid var(--pb-accent,#0F766E);outline-offset:4px;
  border-radius:var(--pb-radius,14px)}
.pb-carousel-item{scroll-snap-align:start;flex:0 0 78%;max-width:78%}
.pb-carousel-sm .pb-carousel-item{flex-basis:62%;max-width:62%}
.pb-carousel-lg .pb-carousel-item{flex-basis:88%;max-width:88%}

/* ── the category list ───────────────────────────────────────────────── */

.pb-cats{list-style:none;margin:0;padding:0}
.pb-cats-chips{display:flex;flex-wrap:wrap;gap:8px}
.pb-cats-list{display:flex;flex-direction:column}

.pb-cats-list li{border-bottom:1px solid var(--pb-line,rgba(0,0,0,.09))}
.pb-cats-list li:last-child{border-bottom:0}
.pb-cats-link{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:11px 0;text-decoration:none;color:inherit;font-weight:600}
.pb-cats-link:hover{color:var(--pb-accent,#0F766E)}

/* Indented, not a second list. One level of nesting reads as a menu; a nested
   list element would need its own spacing rules to say the same thing. */
.pb-cats-child .pb-cats-link{padding-left:16px;font-weight:500}
.pb-cats-chips .pb-cats-child .pb-cat{opacity:.85}

.pb-cats-count{font-size:.75rem;font-weight:700;opacity:.6;font-variant-numeric:tabular-nums}
.pb-cat .pb-cats-count{margin-left:5px}

/* ── archive pagination ──────────────────────────────────────────────── */

.pb-pages{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:6px;margin-top:26px}
.pb-pages-nums{display:flex;flex-wrap:wrap;align-items:center;gap:4px}

/* 40px minimum, which is the smallest a thumb hits reliably. Pagination is the
   one control on an archive, and one that misses is one that sends a reader
   back to the top of the page. */
.pb-pages-num,.pb-pages-step{min-width:40px;min-height:40px;
  display:inline-flex;align-items:center;justify-content:center;
  padding:0 12px;border-radius:calc(var(--pb-radius,14px) * .55);
  font-size:.88rem;font-weight:600;text-decoration:none;color:inherit}
.pb-pages-num:hover,.pb-pages-step:hover{background:var(--pb-card,rgba(0,0,0,.05))}
.pb-pages-num:focus-visible,.pb-pages-step:focus-visible{
  outline:2px solid var(--pb-accent,#0F766E);outline-offset:2px}
.pb-pages-num.is-here{background:var(--pb-accent,#0F766E);color:var(--pb-accent-ink,#fff)}
.pb-pages-step.is-off{opacity:.35;pointer-events:none}
.pb-pages-gap{padding:0 2px;opacity:.5}

/* ── wider than a phone ──────────────────────────────────────────────── */

@media (min-width:700px){
  .pb-postrow-link{gap:20px;padding:22px 0}
  .pb-postrow-thumb{flex-basis:168px}
  .pb-postrow-title{font-size:calc(1.28rem * var(--pb-h-scale,1))}
  .pb-postrow-blurb{font-size:.95rem;-webkit-line-clamp:3}
  .pb-carousel-item{flex-basis:46%;max-width:46%}
  .pb-carousel-sm .pb-carousel-item{flex-basis:32%;max-width:32%}
  .pb-carousel-lg .pb-carousel-item{flex-basis:58%;max-width:58%}
}

@media (min-width:1000px){
  .pb-postrow-title{font-size:calc(1.4rem * var(--pb-h-scale,1))}
  .pb-carousel-item{flex-basis:31.5%;max-width:31.5%}
  .pb-carousel-sm .pb-carousel-item{flex-basis:23%;max-width:23%}
  .pb-carousel-lg .pb-carousel-item{flex-basis:42%;max-width:42%}
}

/* Somebody who has asked their machine to stop moving things means it. */
@media (prefers-reduced-motion:reduce){
  .pb-carousel{scroll-behavior:auto}
  .pb-postrow-title{transition:none}
}


/* ═══════════════ motion — Page Builder v2, Part E ═══════════════
   Every duration and distance comes from a theme token, so one control on the
   theme screen sets how much the whole store moves. A block never decides for
   itself how fast the site feels.

   CSS only. There is no animation library on the storefront and the whole
   JavaScript runtime for this is one shared IntersectionObserver that adds
   `.in-view` — see sellwares-page.js. */

/* Scroll reveal. The element is present and laid out from the first paint —
   only its opacity and transform change — so nothing here can shift the page
   or cost a byte of CLS. */
.pb-reveal{
  opacity:0;
  transform:translateY(var(--pb-rise,8px));
  transition:opacity var(--pb-reveal,250ms) var(--pb-ease,ease),
             transform var(--pb-reveal,250ms) var(--pb-ease,ease);
  will-change:opacity,transform;
}
.pb-reveal.in-view{opacity:1;transform:none;will-change:auto}

/* Stagger, capped at six. Past that a visitor is watching a list load rather
   than reading it, and the last row of a twelve-item grid would arrive most of
   a second after the first. */
.pb-reveal.in-view:nth-child(2){transition-delay:60ms}
.pb-reveal.in-view:nth-child(3){transition-delay:120ms}
.pb-reveal.in-view:nth-child(4){transition-delay:180ms}
.pb-reveal.in-view:nth-child(5){transition-delay:240ms}
.pb-reveal.in-view:nth-child(n+6){transition-delay:300ms}

/* Nothing above the fold animates in. Animating the hero is exactly what breaks
   LCP: the largest element on the page would start at opacity 0, so the metric
   would measure when the animation finished rather than when the page did. */
.pb-page > .pb-section:first-child .pb-reveal,
.pb-hero .pb-reveal{opacity:1;transform:none;transition:none}

/* Hover, at the token's speed. `transform` and `opacity` only — never a
   layout property, so a hover can never move anything around it. */
.pb-motion-lively .pb-card:hover,
.pb-motion-lively .pb-media:hover{transform:translateY(-3px) scale(1.006)}
.pb-motion-subtle .pb-card:hover{transform:translateY(-2px)}
.pb-motion-none .pb-card:hover{transform:none}

/* The setting wins over the theme, with no exception and no way for a template
   to opt out. For some readers motion is nausea, not decoration. */
@media (prefers-reduced-motion:reduce){
  .pb-reveal,.pb-reveal.in-view{opacity:1!important;transform:none!important;transition:none!important}
  .pb-page *,.pb-page *::before,.pb-page *::after{
    animation-duration:.001ms!important;
    animation-iteration-count:1!important;
    transition-duration:.001ms!important;
    scroll-behavior:auto!important;
  }
}


/* ═══════════════ nav search suggest — Page Builder v2, B2 ═══════════════
   Absolutely positioned over the page, never in the flow: opening the dropdown
   must not reflow the nav or move anything under it. That is the brief's rule
   and it is also the whole of how this stays at zero CLS. */
.pb-nav-search{position:relative}

.pb-nav-suggest{
  position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:60;
  max-height:min(60vh,420px);overflow-y:auto;
  background:var(--pb-surface,#fff);
  border:var(--pb-border-width,1px) solid var(--pb-line,#e4e4e4);
  border-radius:var(--pb-radius,14px);
  box-shadow:var(--pb-shadow,0 8px 30px -12px rgba(0,0,0,.22));
  padding:6px;
}
@media (max-width:640px){
  /* On a phone the nav is narrow and the dropdown is not: it spans the screen
     rather than the box, or the product names are three words a line. */
  .pb-nav-suggest{left:0;right:0;width:100%;min-width:min(92vw,340px)}
}

.pb-suggest-row{
  display:flex;align-items:center;gap:10px;
  padding:8px 9px;border-radius:calc(var(--pb-radius,14px) - 5px);
  color:inherit;text-decoration:none;
}
/* Hover and keyboard highlight are the same state, deliberately: a keyboard
   user should see exactly what a mouse user sees. */
.pb-suggest-row:hover,.pb-suggest-row.on{background:var(--pb-card,#f4f4f4)}
.pb-suggest-row:focus-visible{outline:2px solid var(--pb-accent,#0F766E);outline-offset:-2px}

/* Fixed size whether or not there is a picture, so a product without one does
   not make its row shorter than the one above — the list must not reflow as
   results arrive. */
.pb-suggest-thumb{
  flex:0 0 38px;width:38px;height:38px;border-radius:8px;
  background:var(--pb-card,#f4f4f4) center/cover no-repeat;
}
.pb-suggest-row.is-collection .pb-suggest-thumb{display:none}

.pb-suggest-name{flex:1;min-width:0;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pb-suggest-price{font-size:.82rem;color:var(--pb-muted,#6b6b6b);font-variant-numeric:tabular-nums}

.pb-suggest-row.is-collection .pb-suggest-name::before{
  content:"";display:inline-block;width:6px;height:6px;border-radius:50%;
  background:var(--pb-accent,#0F766E);margin-right:8px;vertical-align:middle;
}

.pb-suggest-more{
  display:block;padding:9px;text-align:center;font-size:.84rem;font-weight:600;
  color:var(--pb-accent,#0F766E);text-decoration:none;
  border-top:1px solid var(--pb-line,#e4e4e4);margin-top:4px;
}
.pb-suggest-more:hover,.pb-suggest-more.on{background:var(--pb-card,#f4f4f4)}


/* ═══════════════ nav variants — Page Builder v2, B3 ═══════════════
   Seven shapes over one markup. Every variant renders the same elements in the
   same order, so there is one tab order and one screen-reader reading rather
   than seven — the differences are all layout. */

/* ── the announcement strip ── */
.pb-nav-announce{
  background:var(--pb-dark,#111);color:var(--pb-dark-ink,#fff);
  text-align:center;font-size:.82rem;padding:7px 14px;
}
.pb-nav-announce a{color:inherit;text-decoration:underline}

/* ── logo only: everything behind the button ── */
.pb-nav-minimal .pb-nav-links{display:none}
.pb-nav-minimal .pb-nav-toggle{display:inline-flex}
.pb-nav-minimal.is-open .pb-nav-links{
  display:flex;flex-direction:column;align-items:stretch;
  position:absolute;top:100%;left:0;right:0;
  background:var(--pb-surface,#fff);
  border:var(--pb-border-width,1px) solid var(--pb-line,#e4e4e4);
  border-radius:var(--pb-radius,14px);padding:8px;gap:2px;
  box-shadow:var(--pb-shadow,0 8px 30px -12px rgba(0,0,0,.22));
}

/* ── mega: one wide panel rather than a dropdown per link ── */
.pb-nav-drop{position:relative}
.pb-nav-droptrigger{
  display:inline-flex;align-items:center;gap:5px;
  background:none;border:0;padding:0;font:inherit;color:inherit;cursor:pointer;
}
.pb-nav-dropmenu{
  position:absolute;top:calc(100% + 8px);left:0;z-index:55;min-width:190px;
  display:flex;flex-direction:column;gap:2px;padding:8px;
  background:var(--pb-surface,#fff);
  border:var(--pb-border-width,1px) solid var(--pb-line,#e4e4e4);
  border-radius:var(--pb-radius,14px);
  box-shadow:var(--pb-shadow,0 8px 30px -12px rgba(0,0,0,.22));
}
.pb-nav-dropmenu a{padding:7px 9px;border-radius:8px;text-decoration:none;color:inherit}
.pb-nav-dropmenu a:hover{background:var(--pb-card,#f4f4f4)}

.pb-nav-mega .pb-nav-dropmenu{
  /* Full width of the bar, in columns. The whole point of a mega menu is that
     a shop with twenty collections shows them in one readable panel rather
     than in a list somebody scrolls. */
  left:0;right:0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:4px 18px;
  padding:16px;
}

/* ── floating pill ── */
.pb-nav-card{
  margin:12px auto;width:calc(100% - 24px);max-width:var(--pb-max-width,1080px);
  border-radius:999px;padding-left:20px;padding-right:14px;
  border:var(--pb-border-width,1px) solid var(--pb-line,#e4e4e4);
  background:color-mix(in srgb,var(--pb-surface,#fff) 82%,transparent);
}
/* The glass only once there is something behind it to blur. `backdrop-filter`
   on a bar over plain background costs a compositor layer for nothing. */
@supports (backdrop-filter:blur(1px)){
  .pb-nav-card.is-sticky.is-stuck{backdrop-filter:saturate(1.4) blur(12px)}
}

/* ── over the hero ── */
.pb-nav.is-transparent{
  background:transparent;border-color:transparent;
  transition:background var(--pb-hover,150ms) var(--pb-ease,ease),
             border-color var(--pb-hover,150ms) var(--pb-ease,ease);
}
/* Solid the moment the page moves: white-on-photograph stops being readable
   as soon as the photograph does. */
.pb-nav.is-transparent.is-stuck{
  background:var(--pb-surface,#fff);
  border-color:var(--pb-line,#e4e4e4);
}

/* ── shrink on scroll ── */
.pb-nav.can-shrink{transition:padding var(--pb-hover,150ms) var(--pb-ease,ease)}
.pb-nav.can-shrink.is-stuck{padding-top:6px;padding-bottom:6px}
.pb-nav.can-shrink.is-stuck .pb-nav-logo{max-height:26px}

@media (prefers-reduced-motion:reduce){
  .pb-nav,.pb-nav.can-shrink,.pb-nav.is-transparent{transition:none}
}


/* ═══════════════ the variants Page Builder v2 added ═══════════════
   Layout only. Every colour, radius, shadow and gap still comes from the theme
   tokens, so a variant is a *shape* and the eight art directions can each wear
   any of them. A variant that hardcoded a colour would be a ninth direction
   nobody chose. */

/* ── product grid: one large, the rest small ──
   The launch layout. First child spans two columns and two rows; the rest fall
   in around it. `grid-auto-flow: dense` so a gap left by the feature is filled
   rather than left as a hole. */
.pb-v-feature .pb-grid{grid-auto-flow:dense}
@media (min-width:760px){
  /* `align-self:stretch` undoes the grid's own `align-items:start` for this one
     card. Without it the featured card claimed two rows and filled one, which
     left a card-sized hole under it that looked like a layout that had failed
     rather than one that had been asked for. */
  .pb-v-feature .pb-grid > :first-child{
    grid-column:span 2;grid-row:span 2;align-self:stretch;
    display:flex;flex-direction:column
  }
  .pb-v-feature .pb-grid > :first-child .pb-media{aspect-ratio:4/3}
  /* The shot is capped for ordinary cards; the featured one is the exception,
     and it takes whatever height the two rows leave it. */
  .pb-v-feature .pb-grid > :first-child .pb-product-shot{
    max-height:none;flex:1 1 auto;min-height:0;object-fit:cover
  }
  /* The name earns more room at that size — it is the thing being featured. */
  .pb-v-feature .pb-grid > :first-child h3{font-size:calc(1.3rem * var(--pb-scale,1))}
}

/* ── pricing: side by side, as rows ──
   Cards become a table when the question is "which of these has the export".
   `overflow-x` on the wrapper rather than the page, so three wide plans scroll
   inside their own box and never make the whole page slide sideways. */
.pb-v-table .pb-prices{
  display:block;overflow-x:auto;
  border:var(--pb-border-width,1px) solid var(--pb-line,#e4e4e4);
  border-radius:var(--pb-radius,14px);
}
.pb-v-table .pb-price{
  display:flex;align-items:baseline;gap:16px;flex-wrap:wrap;
  border:0;border-bottom:1px solid var(--pb-line,#e4e4e4);
  border-radius:0;box-shadow:none;background:none;
  padding:16px 18px;margin:0;
}
.pb-v-table .pb-price:last-child{border-bottom:0}
.pb-v-table .pb-price h3{flex:0 0 auto;min-width:150px;margin:0}
.pb-v-table .pb-price-amount{flex:0 0 auto;font-variant-numeric:tabular-nums}
.pb-v-table .pb-price ul{flex:1 1 260px;margin:0}
/* Zebra, from the theme's own card colour rather than an invented grey. */
.pb-v-table .pb-price:nth-child(odd){background:var(--pb-card,#f6f6f6)}

/* ── footer: in columns ──
   `auto-fit` rather than a fixed count: a store with two groups gets two, one
   with five gets five, and neither needs a setting.

   Aimed at the link groups, not at the footer itself. It used to make
   `.pb-footer` the grid, which turned its two children — the main block and
   the sign-off rule under it — into two columns side by side: the copyright
   ended up level with the brand, and the link groups were squeezed into
   150px so "All products" wrapped onto two lines. The footer's own stacked
   grid is right; only the columns inside it needed widening. */
.pb-v-columns .pb-foot-main{grid-template-columns:minmax(0,1.1fr) minmax(0,1.4fr)}
.pb-v-columns .pb-foot-cols{
  grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
  gap:var(--pb-block-gap,18px) 32px;align-items:start;text-align:left
}

/* ── footer: big sign-off ──
   The footer as the last thing somebody reads rather than the small print. The
   brand mark is large and the links go quiet underneath it. */
.pb-v-big .pb-footer{display:flex;flex-direction:column;align-items:center;gap:18px;text-align:center}
.pb-v-big .pb-footer-brand{
  font-family:var(--pb-font-heading,'Plus Jakarta Sans'),sans-serif;
  font-size:clamp(2rem,7vw,4.2rem);
  font-weight:var(--pb-heading-weight,700);
  letter-spacing:var(--pb-letter-spacing,-.02em);
  line-height:1;margin:0;
}
.pb-v-big .pb-footer-links{
  display:flex;flex-wrap:wrap;justify-content:center;gap:8px 20px;
  font-size:.88rem;opacity:.72;
}

/* ── product list: rules, and big image left ── */
.pb-v-bare .pb-product{background:none;border:0;border-radius:0;box-shadow:none;padding:14px 0}
.pb-v-bare .pb-product + .pb-product{border-top:1px solid var(--pb-line,#e4e4e4)}

@media (min-width:680px){
  .pb-v-wide .pb-product{display:grid;grid-template-columns:minmax(0,1fr) 2fr;gap:20px;align-items:center}
  .pb-v-wide .pb-media{aspect-ratio:4/3;margin:0}
}


/* ═══════════════ art direction signatures — Page Builder v2, D3 ═══════════════
   The part tokens cannot say. Colour, type and spacing are all tokens, and a
   direction built from those alone would be a recolour — which the brief rules
   out by name. This is the rest of each one: the blur, the perspective, the
   offsets.

   Scoped under `.pb-dir-*` so a direction's expensive rules cost nothing on a
   page not using it, and so adding a ninth is a token set plus a block here
   rather than an edit to sixty-two section partials. */

/* ── Glass ──
   Translucent over a luminous ground. The gradient is on the page, the blur is
   on the card, and the whole thing is behind @supports: a browser without
   backdrop-filter gets a solid surface rather than an unreadable one. */
.pb-dir-glass{
  background:
    radial-gradient(1100px 620px at 12% -10%, color-mix(in srgb,var(--pb-accent) 24%,transparent), transparent 62%),
    radial-gradient(900px 560px at 92% 8%, color-mix(in srgb,var(--pb-accent) 16%,transparent), transparent 58%),
    var(--pb-surface,#f4f4ff);
  background-attachment:fixed;
}
@supports (backdrop-filter:blur(1px)){
  .pb-dir-glass .pb-card,
  .pb-dir-glass .pb-product,
  .pb-dir-glass .pb-price{
    background:color-mix(in srgb,var(--pb-card,#fff) 62%,transparent);
    backdrop-filter:blur(14px) saturate(1.3);
    border:1px solid color-mix(in srgb,#fff 55%,transparent);
  }
}
/* `background-attachment: fixed` is expensive to repaint while scrolling on
   mobile, and a phone gets the flat ground instead. The direction still reads
   as itself — the blur is the signature, not the parallax. */
@media (max-width:760px){
  .pb-dir-glass{background-attachment:scroll}
}

/* ── Depth ──
   CSS 3D, which is perspective and transform and nothing else. No WebGL, no
   library. The tilt is `transform` only, so it composites and can never move
   anything around it. */
.pb-dir-depth .pb-grid,
.pb-dir-depth .pb-prices{perspective:1200px}
.pb-dir-depth .pb-card,
.pb-dir-depth .pb-product,
.pb-dir-depth .pb-price{
  transform-style:preserve-3d;
  transition:transform var(--pb-hover,150ms) var(--pb-ease,ease),
             box-shadow var(--pb-hover,150ms) var(--pb-ease,ease);
}
.pb-dir-depth .pb-card:hover,
.pb-dir-depth .pb-product:hover,
.pb-dir-depth .pb-price:hover{
  transform:translateY(-4px) rotateX(3deg) rotateY(-2deg);
  box-shadow:0 30px 60px -24px rgba(15,23,42,.45), 0 8px 18px -10px rgba(15,23,42,.3);
}
/* Layered rather than one shadow: two at different spreads is what reads as a
   thing above a surface rather than a thing with a grey edge. */
.pb-dir-depth .pb-section{position:relative}

/* ── Playful ──
   Colour blocking, chunky outlines, and a bit of spring. The offset shadow is
   a solid colour rather than a blur — that is the sticker look, and a blurred
   one is just a soft shadow in a bright palette. */
.pb-dir-playful .pb-card,
.pb-dir-playful .pb-product,
.pb-dir-playful .pb-price{
  border:2px solid var(--pb-ink,#1b1235);
  box-shadow:5px 5px 0 var(--pb-ink,#1b1235);
  transition:transform var(--pb-hover,150ms) var(--pb-ease,ease),
             box-shadow var(--pb-hover,150ms) var(--pb-ease,ease);
}
.pb-dir-playful .pb-card:hover,
.pb-dir-playful .pb-product:hover{
  transform:translate(-2px,-2px);
  box-shadow:8px 8px 0 var(--pb-ink,#1b1235);
}
.pb-dir-playful .pb-btn{border:2px solid var(--pb-ink,#1b1235);box-shadow:3px 3px 0 var(--pb-ink,#1b1235)}
.pb-dir-playful .pb-btn:active{transform:translate(3px,3px);box-shadow:none}

/* ── Brutal Minimal ──
   Structure and nothing else. Rules rather than cards, and the rules are the
   design. Everything soft is switched off explicitly rather than left to the
   tokens, because a stray shadow is the one thing that breaks this. */
.pb-dir-brutal .pb-card,
.pb-dir-brutal .pb-product,
.pb-dir-brutal .pb-price{box-shadow:none;border-radius:0}
.pb-dir-brutal .pb-section + .pb-section{border-top:2px solid var(--pb-line,#000)}
.pb-dir-brutal h1,.pb-dir-brutal h2,.pb-dir-brutal h3{text-transform:uppercase}
.pb-dir-brutal .pb-btn{border:2px solid currentColor;box-shadow:none}

/* ── Dark Premium ──
   One accent on near-black, and a hairline that catches the light. The border
   is a gradient rather than a colour, which is what reads as metal. */
.pb-dir-premium .pb-card,
.pb-dir-premium .pb-product,
.pb-dir-premium .pb-price{
  border:1px solid transparent;
  background:
    linear-gradient(var(--pb-card,#141418),var(--pb-card,#141418)) padding-box,
    linear-gradient(160deg, color-mix(in srgb,var(--pb-accent) 55%,transparent), transparent 42%) border-box;
}
.pb-dir-premium .pb-btn-primary{
  box-shadow:0 0 0 1px color-mix(in srgb,var(--pb-accent) 45%,transparent),
             0 8px 30px -14px var(--pb-accent);
}

/* ── Bold Editorial ──
   The rule under a heading is the magazine tell, and the asymmetry is a grid
   offset rather than absolute positioning — which would break the server
   render and the budget both. */
.pb-dir-editorial .pb-section > h2{
  border-bottom:2px solid var(--pb-ink,#0b0b0b);
  padding-bottom:.35em;margin-bottom:.8em;
}
@media (min-width:900px){
  .pb-dir-editorial .pb-grid > :nth-child(3n+2){transform:translateY(28px)}
}

/* ── Soft Studio ──
   Two shadows at different spreads, which is what "soft and layered" means and
   what one shadow cannot do. */
.pb-dir-studio .pb-card,
.pb-dir-studio .pb-product{
  box-shadow:0 1px 2px rgba(46,39,36,.04), 0 14px 34px -18px rgba(46,39,36,.22);
  transition:transform var(--pb-hover,150ms) var(--pb-ease,ease),
             box-shadow var(--pb-hover,150ms) var(--pb-ease,ease);
}
.pb-dir-studio .pb-card:hover,.pb-dir-studio .pb-product:hover{
  transform:translateY(-3px);
  box-shadow:0 2px 4px rgba(46,39,36,.05), 0 26px 50px -22px rgba(46,39,36,.28);
}

/* ── Clean Commerce ──
   Near-invisible chrome: the card is the photograph and the line only appears
   when somebody points at it. */
.pb-dir-clean .pb-product{border-color:transparent;transition:border-color var(--pb-hover,150ms) var(--pb-ease,ease)}
.pb-dir-clean .pb-product:hover{border-color:var(--pb-line,#eaebed)}

/* Every direction's motion goes when the reader asks for none. The rule above
   is not enough on its own: these set `transform` on hover, and hover is not a
   transition somebody can opt out of by not scrolling. */
@media (prefers-reduced-motion:reduce){
  .pb-dir-depth .pb-card:hover,.pb-dir-depth .pb-product:hover,.pb-dir-depth .pb-price:hover,
  .pb-dir-playful .pb-card:hover,.pb-dir-playful .pb-product:hover,
  .pb-dir-studio .pb-card:hover,.pb-dir-studio .pb-product:hover,
  .pb-dir-editorial .pb-grid > :nth-child(3n+2){transform:none}
}

/* ═══════════════════════════════════════════════════════════════════
   The product template — Page Builder v2.

   The blocks that read the product they are handed rather than naming
   one, so a shop with forty products lays out a page once. Sized here
   because they were not sized anywhere: an empty cover with an
   aspect-ratio and no width is a 1,100px hole that pushes the price
   below the fold.
   ═══════════════════════════════════════════════════════════════════ */

.pb-product-cover-block{
  display:block;width:100%;max-width:520px;margin-inline:auto;
  object-fit:cover;background:var(--pb-card,#f6f6f6)
}
.pb-product-cover-block.is-rounded{border-radius:var(--pb-radius,14px)}
/* A product with no picture yet. A tinted panel rather than a gap, so the
   template still shows the creator where the image goes. */
.pb-product-cover-block.is-empty{
  border:1px dashed var(--pb-line,#e4e4e4);
  background:color-mix(in srgb, var(--pb-accent,#111) 5%, var(--pb-card,#f6f6f6))
}
.pb-align-left .pb-product-cover-block{margin-inline:0}

.pb-product-title-block{margin:0}

.pb-product-price-block{
  display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin:0;
  font-family:var(--pb-font-heading,inherit);font-weight:700;line-height:1.1
}
.pb-align-center .pb-product-price-block{justify-content:center}
.pb-align-right .pb-product-price-block{justify-content:flex-end}
.pb-product-price-block.is-md{font-size:clamp(1.15rem,1rem + .6vw,1.5rem)}
.pb-product-price-block.is-lg{font-size:clamp(1.6rem,1.2rem + 1.4vw,2.4rem)}
.pb-product-price-block.is-xl{font-size:clamp(2rem,1.4rem + 2.4vw,3.4rem)}
.pb-price-was{
  font-weight:400;font-size:.5em;color:var(--pb-muted,#6b6b6b);
  text-decoration-thickness:1px
}

.pb-product-summary{margin:0;color:var(--pb-muted,#6b6b6b)}

/* The buy block in the builder, where there is no product to buy. It has to
   read as the button it will be without being pressable. */
.pb-btn.is-placeholder{opacity:.55;cursor:default;pointer-events:none}

/* ═══════════════════════════════════════════════════════════════════
   Motion — Part E.

   Every duration comes off the theme's own `motion` token, so a store set
   to "none" is still, one set to "lively" moves more, and no block decides
   for itself. No JavaScript: §13.3 says this page renders without it, and
   a reveal that depends on a script is a shop with invisible products the
   moment the script fails.
   ═══════════════════════════════════════════════════════════════════ */

.pb-product-cover-block,
.pb-card,
.pb-btn{transition:transform var(--pb-hover,150ms) var(--pb-ease,ease),
        box-shadow var(--pb-hover,150ms) var(--pb-ease,ease),
        border-color var(--pb-hover,150ms) var(--pb-ease,ease)}

.pb-card:hover{transform:translateY(calc(var(--pb-rise,8px) * -.375))}
.pb-btn:hover{transform:translateY(calc(var(--pb-rise,8px) * -.25))}

/* The arrival. `view()` drives the keyframe off the element's own position
   in the scrollport, which is the whole reveal in two declarations and no
   observer. Browsers without it never start the animation and simply show
   the section, which is the correct fallback rather than a hidden one. */
@keyframes pb-rise{
  from{transform:translateY(var(--pb-rise,8px))}
  to{transform:none}
}

/* Slides, never fades.
   
   This used to fade as well, and `both` fill meant a section that had not yet
   entered its range sat at the first keyframe — `opacity: 0`. Below the fold
   that is invisible, and a shop whose products are invisible until somebody
   scrolls exactly right is a shop that loses the sale. It is also what a
   full-page render produced: two whole sections blank.
   
   So the default reveal moves and nothing more. A creator who wants a fade
   picks a variant that fades — that is a choice, and it applies to a section
   they chose it for. */
@keyframes pb-nudge{from{transform:translateY(var(--pb-rise,8px))}to{transform:none}}

/* The arrival every section makes, in every theme.

   Eight pixels in a quarter of a second was the old one and it read as
   nothing: by the time an eye reached a section it had already finished. This
   travels far enough to be seen and takes long enough to be felt, which is the
   difference between a page that animates and a page that twitches.

   It fades as well as moves, and that is only safe inside the @supports guard
   below. `both` fill means an element outside its range sits at the first
   keyframe — so in a browser with no scroll timeline, opacity:0 would be
   permanent and whole sections would never appear. The guard is what makes the
   fade a progressive enhancement rather than a blank shop. */
@keyframes pb-arrive{
  from{opacity:0;transform:translateY(26px)}
  to{opacity:1;transform:none}
}

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference){
    .pb-section{
      animation:pb-arrive var(--pb-reveal,560ms) var(--pb-ease,cubic-bezier(.22,.68,.3,1)) both;
      animation-timeline:view();
      animation-range:entry 0% cover 26%
    }

    /* The first thing on the page has already entered by the time it paints,
       so it would jump rather than arrive. The bar and the footer are chrome:
       furniture that slides in on every page reads as a page still loading,
       and the borrowed chrome on a checkout sits outside the scroll container
       these timelines are measured against. */
    .pb-section:first-child,
    .pb-chrome .pb-section,
    .pb-t-nav-constrained,
    .pb-t-nav-fullwidth,
    .pb-t-footer-simple{animation:none}

    /* And the things inside a section, one after another.
       No delay is set anywhere: `view()` gives every element its own timeline,
       so a row of cards staggers because the cards reach the viewport at
       slightly different moments. The stagger is the layout's own doing. */
    .pb-section .pb-grid > *,
    .pb-section .pb-steps > *,
    .pb-section .pb-faq > *,
    .pb-section .pb-prices > *,
    .pb-section .pb-stats > *{
      animation:pb-arrive var(--pb-reveal,560ms) var(--pb-ease,cubic-bezier(.22,.68,.3,1)) both;
      animation-timeline:view();
      animation-range:entry 2% cover 32%
    }

    /* The marquee runs on its own clock and its cards must not also arrive —
       one would fight the other and the row would jitter as it travelled. */
    .pb-marquee *{animation-timeline:auto}
  }
}

/* Smooth rather than instant, everywhere something moves under a pointer. */
.pb-card,.pb-btn,.pb-product,.pb-quote-card{
  transition:transform .22s var(--pb-ease,cubic-bezier(.22,.68,.3,1)),
             box-shadow .22s var(--pb-ease,cubic-bezier(.22,.68,.3,1)),
             border-color .22s ease
}

@media (prefers-reduced-motion: reduce){
  .pb-section{animation:none!important}
  .pb-product-cover-block,.pb-card,.pb-btn,.pb-quote-card{transition:none}
  .pb-card:hover,.pb-btn:hover{transform:none}
}

/* ── the product header ─────────────────────────────────────────────
   Picture on one side, the buy box on the other. Collapses to one
   column on a phone, where two columns of half a product each is
   worse than a long page.                                            */

.pb-prodhero{
  display:grid;grid-template-columns:1fr 1fr;gap:clamp(24px,4vw,56px);
  align-items:start;text-align:left
}
.pb-prodhero-shot img,
.pb-prodhero-shot .is-empty{
  display:block;width:100%;object-fit:cover;
  border-radius:var(--pb-radius,14px);background:var(--pb-card,#f6f6f6)
}
.pb-prodhero-shot .is-empty{
  border:1px dashed var(--pb-line,#e4e4e4);
  background:color-mix(in srgb, var(--pb-accent,#111) 5%, var(--pb-card,#f6f6f6))
}

/* The buy box sticks while the description scrolls past it — the one piece
   of behaviour a product page is expected to have. */
.pb-prodhero-buy{position:sticky;top:24px;display:grid;gap:14px;justify-items:start}
.pb-prodhero-buy .pb-h1{margin:0}
.pb-prodhero-summary{margin:0;color:var(--pb-muted,#6b6b6b)}

.pb-prodhero-price{
  display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin:0;
  font-family:var(--pb-font-heading,inherit);font-weight:700;line-height:1.1;
  font-size:clamp(1.6rem,1.2rem + 1.4vw,2.4rem)
}
.pb-prodhero-price s{font-weight:400;font-size:.5em;color:var(--pb-muted,#6b6b6b)}
.pb-prodhero .pb-actions{margin:0}
.pb-prodhero .pb-btn{min-width:min(280px,100%);justify-content:center}
.pb-prodhero .pb-note{margin:0;font-size:.88rem;color:var(--pb-muted,#6b6b6b)}

/* Picture right. */
.pb-v-flipped .pb-prodhero-shot{order:2}

/* The buy box as a panel, for the designs that want one. */
.pb-v-card .pb-prodhero-buy{
  padding:clamp(20px,2.4vw,30px);border-radius:var(--pb-radius,14px);
  background:var(--pb-surface,#fff);border:1px solid var(--pb-line,#e4e4e4);
  box-shadow:var(--pb-shadow,none);justify-items:stretch
}

/* Picture on top, everything centred under it. */
.pb-v-stacked .pb-prodhero{grid-template-columns:1fr;text-align:center;max-width:720px;margin-inline:auto}
.pb-v-stacked .pb-prodhero-buy{position:static;justify-items:center}
.pb-v-stacked .pb-prodhero-price{justify-content:center}

@media (max-width:860px){
  .pb-prodhero{grid-template-columns:1fr}
  .pb-prodhero-shot{order:0}
  .pb-v-flipped .pb-prodhero-shot{order:0}
  .pb-prodhero-buy{position:static}
}

/* A product with no picture. The two-column shape only makes sense when there
   is something in the first column; without it the buy box would sit in the
   right half of the page with nothing beside it. */
.pb-prodhero.is-noshot{grid-template-columns:1fr;max-width:720px;margin-inline:auto}
.pb-prodhero.is-noshot .pb-prodhero-buy{position:static}

/* Visible to a screen reader and to nothing else.

   The nav search puts its label and its submit button in this class — the icon
   and the field are the visible interface, and the other two are there for a
   keyboard and for a browser that will not submit on Enter. The rule was in
   the dashboard's stylesheet and never in this one, so on a storefront both of
   them printed: a bar that read "Search 🔍 [Search products] Search". */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0
}
/* Except when it is focused, so a keyboard user can see where they are. */
.sr-only:focus-visible{
  position:static;width:auto;height:auto;margin:0;overflow:visible;
  clip:auto;clip-path:none;white-space:normal
}

/* ── the centred-logo bar, with a search on it ──────────────────────
   The variant splits the menu in two and puts the brand between them, so
   the bar holds: links, brand, links, search, button.

   The brand sits *between* the two groups rather than pinned to the middle
   of the bar. Pinned it looked right on a wide nav and collided with the
   search on a narrow one — and a brand name printed on top of a search box
   is worse than one a few pixels off centre. Flow, not absolutes: nothing
   here can overlap whatever else the creator puts on the bar. */
/* The base bar centres its contents; this variant spans them instead, so
   the first group hugs the left edge and the search and button hug the
   right, with the brand taking the space between. */
.pb-v-split .pb-nav{display:flex;align-items:center;justify-content:flex-start;gap:14px;flex-wrap:wrap}
/* `order` is reset here on purpose: an earlier rule in this file put the
   brand at order 2 for the grid version of this variant, which in flex
   moves it past every default-order item and lands it at the far right. */
.pb-v-split .pb-nav-brand{order:0;margin-inline:auto;white-space:nowrap;flex:0 0 auto}
.pb-v-split .pb-nav-links{margin:0;flex:0 1 auto}
.pb-v-split .pb-nav-links:last-of-type{margin-left:0}
.pb-v-split .pb-nav-search{flex:0 1 200px;min-width:0;margin-left:auto}
.pb-v-split .pb-nav .pb-btn{margin-left:10px;flex:none}

@media (max-width:820px){
  .pb-v-split .pb-nav-brand{margin:0 auto 0 0}
  .pb-v-split .pb-nav-search{flex-basis:100%;margin-left:0}
}

/* A section whose optional picture was never uploaded runs as one column
   rather than leaving half the page empty beside the words. */
.pb-split.is-nophoto{grid-template-columns:1fr;max-width:64ch}
.pb-align-center .pb-split.is-nophoto{margin-inline:auto}

/* ── the borrowed bar on a page it was not built for ────────────────
   Checkout, the receipt and the library run in a narrow reading column
   (`.store` is 680px). The bar and the footer are page-width furniture,
   so inside that column they arrive squeezed — the menu collapses and
   the button loses its label.

   Break them out to the full width of the window, then let the section's
   own `--pb-max-width` decide how wide the contents run. Nothing about
   the sections themselves changes, which is the point: it is the same
   bar the shop front draws. */
/* `100vw` was the scrollbar.
|
| It counts the scrollbar's width as part of the viewport, so on any page long
| enough to scroll — every product page — the bar came out about fifteen pixels
| wider than the window and put a horizontal scrollbar under the whole shop.
|
| The negative margins were solving a different problem: the chrome used to be
| drawn inside the storefront's reading column, 680px on most pages, and had to
| break out of it. It is emitted outside <main> now, where the body is already
| the full width, so there is nothing left to break out of. `100%` is the honest
| number and it cannot exceed the window.
|
| `clip` rather than `hidden`: `hidden` on an ancestor breaks the nav's own
| sticky positioning, and a sticky bar that stops sticking is the next bug. */
.pb-chrome{
  width:100%;
  max-width:100%;
  margin-inline:0;
  overflow-x:clip
}
.pb-chrome>*{max-width:100%}
.pb-chrome-header{margin-bottom:clamp(18px,3vw,34px)}
.pb-chrome-footer{margin-top:clamp(28px,5vw,64px)}

/* The reading column's own font size must not shrink the bar's type. */
.pb-chrome .pb-section{font-size:1rem}

/* ── one picture must not set the height of the whole row ───────────
   A grid row is as tall as its tallest card, and a 4:3 image in a wide
   column is 400px of it. With one product photographed and the rest not,
   that left two cards with their price stranded at the bottom of a
   mostly empty box.

   So the picture is capped, and the cards stop stretching to match each
   other — a card is as tall as what is in it.

   Product cards take that stretch back, just below. The cap above already
   settles the picture, so nothing is left that can blow a row up; what was
   left was a shelf whose cards each stopped wherever their own text ran
   out, which reads as broken rather than as varied. */
.pb-grid{align-items:start}
.pb-product-shot{max-height:clamp(160px,22vw,260px)}

/* A shelf of products is a row of equal boxes: the same width from the grid,
   the same height from here. A course carrying a lesson count and a one-line
   download end up the same card, and the price sits on the same line across
   the row rather than wherever each card happened to finish. */
.pb-product{align-self:stretch}

/* A card with no picture at all closes the gap the picture would have
   left, rather than keeping the space warm for one that never comes. */
.pb-product > .pb-h3:first-child{margin-top:0}

/* ═══════════════════════════════════════════════════════════════════
   Motion as a look, not a setting — Part E, second pass.

   A creator picking "Centred" and a creator picking "Centred, arriving on
   scroll" are choosing two different things, so they are two variants
   rather than one variant and a switch somewhere else.

   Every one below is driven by `animation-timeline: view()`, which ties
   the keyframe to the element's own position in the scrollport. No
   observer, no script, and nothing that can fail half-way and leave a
   section invisible: a browser without it simply never starts the
   animation and shows the finished state, which is the correct fallback.

   Durations come from the theme's own `--pb-reveal` and `--pb-ease`, so a
   store set to "no motion" gets 0ms here too and everything is still.
   ═══════════════════════════════════════════════════════════════════ */

@keyframes pb-drift{from{transform:translateY(var(--pb-drift,34px))}to{transform:translateY(calc(var(--pb-drift,34px) * -1))}}
/* Opens from just under full size. No opacity: see pb-nudge — a picture
   that is not there yet is worse than one that does not fade. */
@keyframes pb-expand{from{transform:scale(.9)}to{transform:none}}

@supports (animation-timeline: view()){

  /* ── Centred, arriving on scroll ──────────────────────────────────
     The eyebrow, the heading, the line of copy and the buttons come in
     one after another rather than as a block. `view()` gives each child
     its own timeline, so the stagger is the layout's own doing. */
  .pb-v-reveal .pb-stack > *{
    animation:pb-rise var(--pb-reveal,250ms) var(--pb-ease,ease) both;
    animation-timeline:view();
    animation-range:entry 4% cover 26%
  }

  /* ── Parallax ─────────────────────────────────────────────────────
     The picture moves against the page as it passes. `cover` runs the
     whole time the element is on screen, which is what makes it read as
     depth rather than as a jolt on arrival. */
  .pb-v-parallax :is(img,.pb-media),
  .pb-v-drift .pb-gal-item :is(img,.pb-media){
    animation:pb-drift linear both;
    animation-timeline:view();
    animation-range:cover;
    will-change:transform
  }
  /* Nothing may drift out of its own frame. */
  .pb-v-parallax :is(.pb-media,.pb-hero-media),
  .pb-v-drift .pb-gal-item{overflow:hidden}

  /* ── Scroll-expanding image ───────────────────────────────────────
     Opens from just under full size. Small on purpose: a picture that
     starts at half size and grows reads as a slideshow. */
  .pb-v-expand :is(img,.pb-media){
    animation:pb-expand var(--pb-reveal,250ms) var(--pb-ease,ease) both;
    animation-timeline:view();
    animation-range:entry 0% cover 34%;
    transform-origin:center
  }

  /* ── Cards that arrive one by one ─────────────────────────────────
     Each card is its own timeline, so the order comes from where the
     cards are rather than from an nth-child delay that guesses. */
  .pb-v-stagger .pb-grid > *{
    animation:pb-rise var(--pb-reveal,250ms) var(--pb-ease,ease) both;
    animation-timeline:view();
    animation-range:entry 0% cover 22%
  }

  /* The section's own arrival would fight its children's. */
  .pb-v-reveal,.pb-v-stagger,.pb-v-expand{animation:none}
}

/* Decoration, all of it. A reader who asked their system for less movement
   loses nothing by having every one of these switched off. */
@media (prefers-reduced-motion: reduce){
  .pb-v-reveal .pb-stack > *,
  .pb-v-parallax :is(img,.pb-media),
  .pb-v-drift .pb-gal-item :is(img,.pb-media),
  .pb-v-expand :is(img,.pb-media),
  .pb-v-stagger .pb-grid > *{animation:none!important}
}

/* ═══════════════════════════════════════════════════════════════════
   The footer.

   One markup, seven arrangements. Everything is optional and every block
   removes itself when empty, so the shapes below are about where the
   filled-in parts sit rather than about which parts exist.
   ═══════════════════════════════════════════════════════════════════ */

.pb-footer{display:grid;gap:clamp(20px,3vw,34px);width:100%}

.pb-foot-main{
  display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);
  gap:clamp(24px,4vw,64px);align-items:start
}
/* The brand column ranges left because it is a column, whatever the section
   is ranged. It inherited the section's centring, so the address and the
   contact line sat centred inside a left-hand column while the name above them
   did not — the commonest thing wrong with these footers. */
.pb-foot-brand{display:grid;gap:10px;justify-items:start;text-align:left}

/* One group of links and nothing to put beside them: a row, not a column.
   This is the shape the default footer takes, so it has to be the one that
   looks deliberate. */
.pb-foot-row{display:flex;flex-wrap:wrap;align-items:center;gap:10px 20px}
.pb-foot-row a{color:inherit;text-decoration:none}
.pb-foot-row a:hover{text-decoration:underline;text-underline-offset:3px}
.pb-foot-name{font-family:var(--pb-font-heading,inherit);font-size:1.05rem;font-weight:700}
.pb-foot-blurb{margin:0;color:var(--pb-muted,#6b6b6b);max-width:46ch}

/* Address and contact. The label sits above its value in the small, quiet
   type a footer uses for the things nobody reads until they need them. */
.pb-foot-line{display:grid;gap:2px;margin:0;font-size:.9rem;color:var(--pb-muted,#6b6b6b)}
.pb-foot-line span{font-weight:600;color:var(--pb-ink,#111);font-size:.82rem}
.pb-foot-line a{display:block;color:inherit;text-decoration:underline;text-underline-offset:3px}

.pb-foot-socials{display:flex;gap:12px;margin-top:4px;font-size:1.05rem}
/* On a dark ground the quiet parts have to give up the theme's ink.
   `--pb-ink` and `--pb-muted` are the palette's dark greys, which is right on
   a white page and invisible on a dark footer — the "Email" label above the
   address disappeared entirely, and the blurb was a shade off the background.
   White at two opacities instead: it works on every dark the designs use. */
.pb-tone-light :is(.pb-foot-blurb,.pb-foot-line,.pb-foot-col b,.pb-foot-base){color:rgba(255,255,255,.62)}
.pb-tone-light .pb-foot-line span{color:rgba(255,255,255,.9)}
.pb-tone-light .pb-foot-base{border-top-color:rgba(255,255,255,.16)}
.pb-tone-light .pb-foot-col a:hover{color:#fff}


.pb-foot-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));gap:clamp(20px,3vw,48px)}
.pb-foot-col{display:grid;gap:9px;align-content:start;font-size:.92rem}
.pb-foot-col b{font-size:.82rem;letter-spacing:.04em;text-transform:uppercase;color:var(--pb-muted,#6b6b6b)}
.pb-foot-col a{color:inherit}
.pb-foot-col a:hover{color:var(--pb-accent,#111)}

/* The rule and the sign-off under it. */
.pb-foot-base{
  display:flex;flex-wrap:wrap;align-items:center;gap:12px 22px;
  padding-top:clamp(14px,2vw,22px);border-top:1px solid var(--pb-line,#e4e4e4);
  font-size:.87rem;color:var(--pb-muted,#6b6b6b)
}
.pb-foot-base small{font-size:inherit}
.pb-foot-legal{display:flex;flex-wrap:wrap;gap:16px;margin-left:auto}
.pb-foot-legal a{color:inherit;text-decoration:underline;text-underline-offset:3px}

/* ── the shapes ────────────────────────────────────────────────────── */

/* Inside a card, lifted off the page. */
.pb-v-card .pb-footer{
  padding:clamp(24px,3.4vw,40px);
  background:var(--pb-surface,#fff);
  border:1px solid var(--pb-line,#e4e4e4);
  border-radius:calc(var(--pb-radius,14px) + 4px);
  box-shadow:var(--pb-shadow,none)
}

/* Everything down the middle. */
.pb-v-centred .pb-foot-main{grid-template-columns:1fr;justify-items:center;text-align:center}
.pb-v-centred .pb-foot-brand{justify-items:center;text-align:center}
.pb-v-centred .pb-foot-row{justify-content:center}
.pb-v-centred .pb-foot-cols{grid-template-columns:repeat(auto-fit,minmax(120px,auto));justify-content:center;text-align:center}
.pb-v-centred .pb-foot-col{justify-items:center}
.pb-v-centred .pb-foot-base{justify-content:center;text-align:center}
.pb-v-centred .pb-foot-legal{margin:0}

/* A line and a rule, nothing else. */
.pb-v-minimal .pb-foot-main{display:none}
.pb-v-minimal .pb-foot-base{justify-content:center;border-top:0}
.pb-v-minimal .pb-foot-legal{margin:0}

/* The old one-liners keep behaving as they did. */
.pb-v-classic .pb-foot-base,.pb-v-stacked .pb-foot-base,.pb-v-dark .pb-foot-base{border-top:0}
.pb-v-stacked .pb-foot-base{flex-direction:column;justify-content:center;text-align:center}
.pb-v-stacked .pb-foot-legal{margin:0}

@media (max-width:760px){
  .pb-foot-main{grid-template-columns:1fr}
  .pb-foot-legal{margin-left:0}
}

/* ── proof, laid out the way a proof section is ─────────────────────
   An eyebrow, a heading and a line under it, then the quotes. The two
   shapes below are the ones a store actually uses: three across and
   centred, or two across and ranged left. */
.pb-quotes .pb-eyebrow{display:block}
.pb-quotes .pb-lead{margin:0 0 4px}

.pb-quote{display:grid;gap:12px;align-content:start}
.pb-quote p{margin:0}
.pb-quote .pb-stars{color:#F5A524;font-size:.9rem;letter-spacing:1px}

/* The person, under the quote and always at the bottom of the card so a
   row of quotes of different lengths still lines its faces up. */
.pb-person{display:flex;align-items:center;gap:10px;margin-top:auto}
.pb-person .pb-avatar{width:38px;height:38px;border-radius:999px;object-fit:cover;flex:none}
.pb-person b{display:block;font-size:.94rem;line-height:1.25}
.pb-person span{display:block;font-size:.84rem;color:var(--pb-muted,#6b6b6b)}

/* Centred, three across. */
.pb-v-triple .pb-quotes{text-align:center}
.pb-v-triple .pb-quote{justify-items:center;text-align:center}
.pb-v-triple .pb-person{flex-direction:column;gap:7px;text-align:center}

/* Left-ranged, two across — the wider quote, for longer stories. */
.pb-v-double .pb-quotes{text-align:left}
.pb-v-double .pb-quote{text-align:left}

/* ── the heading beside the quotes ──────────────────────────────────
   The shape a long-form proof section wants: what this is, on the left,
   and the quotes stacked down the right. It reads as a conversation
   rather than as a wall. */
.pb-quotes-head{display:grid;gap:10px}

.pb-v-aside .pb-quotes{
  display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
  gap:clamp(28px,5vw,72px);align-items:start;text-align:left
}
.pb-v-aside .pb-quotes-head{position:sticky;top:24px}
.pb-v-aside .pb-grid{grid-template-columns:1fr;gap:14px}
.pb-v-aside .pb-quote{text-align:left}

/* ── the floating slider ────────────────────────────────────────────
   A row you push sideways. Scroll snapping and `overflow-x` only —
   no carousel script, so it works on a phone the way a phone already
   works and cannot break when JavaScript does. */
.pb-v-slider .pb-grid{
  display:flex;gap:16px;overflow-x:auto;scroll-snap-type:x mandatory;
  padding-bottom:10px;margin-bottom:-10px;
  scrollbar-width:thin
}
.pb-v-slider .pb-quote{
  flex:0 0 min(88%,340px);scroll-snap-align:center;
  box-shadow:var(--pb-shadow,0 14px 34px -22px rgba(0,0,0,.35))
}
/* The card lifts as it settles under the pointer, which is the whole of
   "floating" — the rest is the shadow it already carries. */
.pb-v-slider .pb-quote{transition:transform var(--pb-hover,150ms) var(--pb-ease,ease)}
.pb-v-slider .pb-quote:hover{transform:translateY(-3px)}

@media (max-width:760px){
  .pb-v-aside .pb-quotes{grid-template-columns:1fr}
  .pb-v-aside .pb-quotes-head{position:static}
}

@media (prefers-reduced-motion: reduce){
  .pb-v-slider .pb-quote{transition:none}
  .pb-v-slider .pb-quote:hover{transform:none}
}

/* ── the plans ──────────────────────────────────────────────────────
   Read top to bottom: what it is called, what it costs, who it is for,
   what is in it, and then the button that answers all of that. The
   button is pinned to the bottom so a row of plans with different
   numbers of features still lines its buttons up. */
.pb-pricing-head{display:grid;gap:10px;justify-items:center;text-align:center;max-width:60ch;margin-inline:auto}
.pb-align-left .pb-pricing-head{justify-items:start;text-align:left;margin-inline:0}

.pb-plan{display:grid;gap:12px;align-content:start;position:relative}
.pb-plan .pb-h3{margin:0}
.pb-plan-note{margin:-6px 0 0;font-size:.84rem;color:var(--pb-muted,#6b6b6b)}
.pb-plan-blurb{margin:0;font-size:.94rem;color:var(--pb-muted,#6b6b6b)}
.pb-plan .pb-checklist{margin:4px 0 0}
.pb-plan .pb-btn{margin-top:auto;justify-content:center;width:100%}

/* The struck-through price sits beside the live one, never above it. */
.pb-pricerow s{font-size:.5em;font-weight:400;color:var(--pb-muted,#6b6b6b)}

/* The badge belongs to the plan, so it sits on its edge rather than in
   the flow pushing the name down. */
.pb-plan-badge{position:absolute;top:14px;right:14px;margin:0}

/* ── three plans, the middle one raised ─────────────────────────────
   The shape a pricing table is usually in. The highlighted plan is
   raised rather than recoloured: a plan that is a different colour
   reads as a different product. */
.pb-v-three .pb-grid{align-items:center}
.pb-v-three .pb-plan{padding-block:clamp(22px,2.6vw,30px)}
.pb-v-three .pb-plan.is-featured{
  transform:scale(1.04);
  box-shadow:var(--pb-shadow,0 22px 48px -26px rgba(0,0,0,.4));
  z-index:1
}

@media (max-width:760px){
  .pb-v-three .pb-plan.is-featured{transform:none}
}
@media (prefers-reduced-motion: reduce){
  .pb-v-three .pb-plan.is-featured{transform:none}
}

/* ── kept through the theme merge ──────────────────────────────────
   The archive's stylesheet predates these two and would have dropped
   them: `.pb-guarantee` is the reassurance line under a buy button,
   and `.pb-nav-lib` is the buyer's own door in a nav otherwise built
   entirely by the creator. Both are still used by the sections, so
   losing the rules would have left live markup unstyled. */
.pb-guarantee{text-align:center;border:1px solid var(--pb-line,#e6e6e6);
  border-radius:var(--pb-radius,14px);padding:22px 20px;display:grid;gap:8px;justify-items:center}
.pb-guarantee i{font-size:30px;color:var(--pb-accent,#111);line-height:1}
.pb-guarantee h3{margin:0;font-size:19px;line-height:1.25}
.pb-guarantee p{margin:0;max-width:52ch;color:var(--pb-muted,#667);font-size:14.5px;line-height:1.6}
/* ── the duplicate that used to sit here ───────────────────────────
   The first 135 lines of this file were appended to the end of it again
   during the builder/theme merge, and CSS gives the last declaration the
   win. So eighty-five selectors were declared twice and eight of them
   *differed* — every refinement made between here and the top was being
   silently reverted by an older copy of itself sitting underneath.

   What that cost, in the order it was noticed: `.pb-h1` and `.pb-h2` came
   back at the louder scale the quiet one had replaced, `.pb-divider` lost
   its token-driven weight and style for a flat 1px line, `.pb-btn` and its
   hover lost the motion tokens and went back to a hardcoded 150ms and a
   1px lift, `.pb-v-split .pb-nav-brand` lost its centring, and `.pb-grid`
   and `.pb-page a` were re-declared over.

   Every selector in the removed block was already declared earlier in the
   file — checked before deleting, not assumed — so nothing here is lost.
   The two rules below it are NOT duplicates and stay: see the note above
   `.pb-guarantee`. */

/* The buyer's own door, in a nav otherwise built entirely by the creator.
   Reads as one of the links because it is one; the icon is what separates
   "where my things are" from "another page of this shop". */
.pb-nav-lib{display:inline-flex;align-items:center;gap:7px}
.pb-nav-lib i{font-size:1.02em;opacity:.75}

/* ══════════════════════════════════════════════════════════════════════
   Form controls on a published page.

   `.pb-form input` dressed the one text box a capture block has, and nothing
   else. Every other control a creator can put on a page — the dropdown on a
   contact form, its tick boxes, a date field, a file upload — was drawn by
   the browser: square corners, a system arrow and system blue, in the middle
   of a page carrying the creator's own fonts and colours.

   Every value below is a `--pb-*` token, so these move with the preset like
   everything else on the page rather than needing a second stylesheet.
   ══════════════════════════════════════════════════════════════════════ */

/* One `:not()` with a list inside it, not seven chained.
   Each `:not()` adds its argument's weight, so the chained version carried
   eight classes' worth of specificity — heavy enough that the nav search's
   own opt-out below could not beat it, which put a bordered white box inside
   the search pill. A list counts once. */
.pb-page textarea,
.pb-page select,
.pb-page input:not([type=checkbox],[type=radio],[type=file],[type=range],[type=submit],[type=button],[type=hidden]){
  width:100%;padding:.82rem 1rem;font:inherit;font-size:1rem;line-height:1.45;
  color:var(--pb-ink,#111);background:var(--pb-surface,#fff);
  border:1px solid var(--pb-line,#e4e4e4);border-radius:var(--pb-radius,14px);
}
.pb-page textarea{min-height:120px;resize:vertical}

.pb-page textarea:focus,
.pb-page select:focus,
.pb-page input:focus{
  outline:none;border-color:var(--pb-accent,#111);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--pb-accent,#111) 20%,transparent);
}

.pb-page ::placeholder{color:var(--pb-muted,#5F7A70);opacity:1}

/* The nav's search box dresses itself — it is a pill inside a bar, not a
   field on a page — so it opts out of the rule above.

   Written into the same selector rather than beside it. Every `:not()` above
   adds its argument's weight, so that rule carries eight classes' worth of
   specificity and a plain `.pb-nav-search input` lost to it — which put a
   white box with its own border inside the pill, a pill inside a pill. A
   later rule does not beat a heavier one; only being heavier does. */
.pb-page .pb-nav-search input,
.pb-page .pb-nav-search input:focus,
.pb-nav-search input{
  width:auto;padding:0;border:0;border-radius:0;background:none;box-shadow:none;
}

/* Ours, because the system arrow is the one part of a styled select that
   still looks like a system dialog. Everything else stays the browser's:
   the keyboard, the mobile picker, the form semantics. */
.pb-page select{
  appearance:none;-webkit-appearance:none;
  padding-right:2.4rem;cursor:pointer;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 16 16' fill='none' stroke='%23888' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right .9rem center;
}
.pb-page select[multiple]{appearance:auto;background-image:none;padding-right:1rem;cursor:auto}

/* `accent-color` keeps the browser's own focus ring, keyboard handling and
   indeterminate state. The colour was the only thing wrong with these. */
.pb-page input[type=checkbox],
.pb-page input[type=radio]{
  accent-color:var(--pb-accent,#111);
  width:17px;height:17px;margin:0;flex:none;cursor:pointer;
}
.pb-page label:has(> input[type=checkbox]),
.pb-page label:has(> input[type=radio]){
  display:inline-flex;align-items:flex-start;gap:9px;cursor:pointer;line-height:1.45;
}

.pb-page input[type=range]{accent-color:var(--pb-accent,#111)}

.pb-page input[type=date],
.pb-page input[type=time],
.pb-page input[type=datetime-local]{accent-color:var(--pb-accent,#111);color-scheme:light}
.pb-page input[type=date]::-webkit-calendar-picker-indicator,
.pb-page input[type=time]::-webkit-calendar-picker-indicator,
.pb-page input[type=datetime-local]::-webkit-calendar-picker-indicator{
  filter:grayscale(1) opacity(.55);cursor:pointer;
}
.pb-page input[type=date]:hover::-webkit-calendar-picker-indicator{filter:none;opacity:1}

.pb-page input[type=file]{font:inherit;font-size:.95rem;color:var(--pb-muted,#5F7A70)}
.pb-page input[type=file]::file-selector-button{
  margin-right:11px;padding:.5rem 1rem;
  border:1px solid var(--pb-line,#e4e4e4);border-radius:999px;
  background:var(--pb-surface,#fff);color:var(--pb-ink,#111);
  font:inherit;font-size:.9rem;font-weight:600;cursor:pointer;
}
.pb-page input[type=file]::file-selector-button:hover{border-color:var(--pb-accent,#111)}

/* ═══════════════ book a time ═══════════════
   The way into the booking page, from the shop itself. Everything
   behind it shipped with no front door: the only route to a creator's
   own booking page was to know the address and paste it into a button.

   A card here is three facts and an answer — how long, where, how much,
   and the button. The facts sit on one line with a dot between them
   rather than stacked, because three one-word paragraphs read as three
   times as much to get through. */
.pb-booking-head{display:grid;gap:10px;max-width:60ch}
.pb-align-center .pb-booking-head{justify-items:center;text-align:center;margin-inline:auto}

/* Cards the same height, so a row of them lines its buttons up. The
   page-wide `.pb-grid{align-items:start}` is right for a gallery and
   wrong here: three cards with different amounts of blurb were three
   heights with three buttons at three heights. Taken back on the card,
   the way the product shelf already does it. */
.pb-booking-card{
  align-self:stretch;
  display:flex;flex-direction:column;gap:14px;align-items:stretch;text-align:left
}
/* `align-content:start` because the body is a grid inside a card that
   stretches: without it the three rows share out the card's spare
   height and a one-line heading sits in an eighty-pixel box. */
.pb-booking-body{display:grid;gap:8px;align-content:start}
.pb-booking-card .pb-h3{margin:0}

/* The middle dot is drawn rather than typed, so a fact that is switched
   off does not leave a separator hanging with nothing after it. */
.pb-booking-facts{
  display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;
  margin:0;font-size:.86rem;font-weight:600;color:var(--pb-muted,#6b6b6b)
}
.pb-booking-facts span+span::before{content:"·";margin-right:10px;opacity:.6}

.pb-booking-blurb{margin:0;font-size:.94rem;line-height:1.6;color:var(--pb-muted,#6b6b6b)}

/* The button pinned to the bottom, so a row of cards with different
   amounts of blurb still lines its buttons up. */
.pb-booking-foot{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:auto
}
.pb-booking-card .pb-price{font-size:1.15rem}
.pb-booking-pwyw{font-size:.95rem;font-weight:600}
.pb-booking-foot .pb-btn{margin-left:auto}

/* A button with nothing beside it fills the foot instead of hiding in
   the right-hand corner. With a price there it sits opposite the price,
   which is the pairing a price list already teaches. */
.pb-booking-foot .pb-btn:only-child{width:100%;justify-content:center;margin-left:0}

.pb-booking-empty{
  margin:0;padding:18px;border-radius:var(--pb-radius,14px);
  border:1px dashed var(--pb-line,#e4e4e4);
  font-size:.92rem;color:var(--pb-muted,#6b6b6b)
}

/* ── a list, one per row ───────────────────────────────────────────
   For the coach with six kinds of session: read down rather than
   across, with the button on the right where a price list keeps it. */
.pb-v-rows .pb-grid{grid-template-columns:1fr}
.pb-v-rows .pb-booking-card{
  flex-direction:row;align-items:center;gap:18px;flex-wrap:wrap
}
.pb-v-rows .pb-booking-body{flex:1 1 260px}
.pb-v-rows .pb-booking-foot{margin-top:0;flex:0 0 auto}
.pb-v-rows .pb-booking-foot .pb-btn,
.pb-v-rows .pb-booking-foot .pb-btn:only-child{margin-left:0;width:auto}

/* ── one, large ────────────────────────────────────────────────────
   A grid of one card is a card with an accident either side of it. The
   shop with a single intro call gets that call, full width, bigger. */
.pb-v-single .pb-grid{grid-template-columns:1fr}
.pb-v-single .pb-booking-card{padding-block:clamp(22px,2.6vw,30px);gap:18px}
.pb-v-single .pb-booking-card .pb-h3{font-size:clamp(1.3rem,2.4vw,1.75rem)}
/* Wide, not full width. A button the whole width of a large card stops
   reading as a button and starts reading as a bar. */
.pb-v-single .pb-booking-foot .pb-btn,
.pb-v-single .pb-booking-foot .pb-btn:only-child{
  width:auto;min-width:220px;margin-left:0;justify-content:center
}

/* ── no boxes ──────────────────────────────────────────────────────
   A rule between instead of a border around. On a page that is already
   a stack of cards, four more cards is furniture. */
.pb-v-plain .pb-booking-card{
  background:none;border:0;box-shadow:none;padding:0 0 20px;
  border-bottom:1px solid var(--pb-line,#e4e4e4);border-radius:0
}

/* And the button is a button again rather than a slab. A full-width
   solid bar under every entry puts the boxes back that this look took
   away. */
.pb-v-plain .pb-booking-foot .pb-btn,
.pb-v-plain .pb-booking-foot .pb-btn:only-child{width:auto;margin-left:0}

@media (max-width:640px){
  .pb-v-rows .pb-booking-card{flex-direction:column;align-items:stretch}

  /* The row's `flex:1 1 260px` is a *width* while the card is a row, and
     turns into a 260-pixel **height** the moment it becomes a column —
     which is how a card holding three short lines ended up nearly four
     hundred pixels tall on a phone, with its button stranded at the
     bottom of the empty half. */
  .pb-v-rows .pb-booking-body{flex:0 1 auto}
  .pb-v-rows .pb-booking-foot{width:100%}
  .pb-v-rows .pb-booking-foot .pb-btn{margin-left:auto}
}

/* ── the clock a one-click offer is already running on ─────────────────────
   Not invented urgency: Upsells refuses an offer more than
   OFFER_WINDOW_MINUTES after the purchase, and this counts down to that same
   deadline. The buyer was never told it existed, so they closed the tab to
   think about it and came back to a receipt. */
.offer-clock{display:block;margin-top:16px;padding:11px 14px;border-radius:var(--radius);
  border:1px solid var(--line);background:var(--bg)}
.offer-clock b{display:block;font-size:14.5px;line-height:1.35}
.offer-clock span{display:block;margin-top:3px;color:var(--muted);font-size:13px;line-height:1.5}
.offer-clock[data-expired] b{color:var(--danger,#C4483C)}

/* ══════ the ten blog layouts — §11.2 item 15 ══════

   Four switches, two of them about the archive and two about the article, and
   every one of the ten is a combination of them. The archive carries all four;
   a post carries only `bl-read-*` and `bl-type-*`, because the other two would
   be dead classes on it.

   ## Why the measure is a switch and not a theme

   The blog already has twenty themes and they carry the typefaces and the
   palette. What a theme cannot say is how wide a line of text is allowed to
   run — and a 60-character measure is the single largest thing anybody can do
   to make long text readable. No amount of choosing a nicer face fixes a line
   that runs to 140 characters.

   `ch` rather than px, deliberately: the measure is a count of characters, so
   it has to be expressed in the width of one. A 680px column is a different
   measure in every face the twenty themes offer.

   See App\Domain\Blog\BlogTemplates. */

/* ── the measure ──
   On the text, not on the page: a cover picture and a code block want the
   width they are given, and only the reading wants to be held back. */
.bl-read-narrow .pb-rich > *,
.bl-read-narrow .bl-post > p,
.bl-read-narrow .bl-post > h2,
.bl-read-narrow .bl-post > h3,
.bl-read-narrow .bl-post > ul,
.bl-read-narrow .bl-post > ol,
.bl-read-narrow .bl-post > blockquote{max-width:58ch;margin-inline:auto}

.bl-read-normal .pb-rich > *,
.bl-read-normal .bl-post > p,
.bl-read-normal .bl-post > h2,
.bl-read-normal .bl-post > h3,
.bl-read-normal .bl-post > ul,
.bl-read-normal .bl-post > ol,
.bl-read-normal .bl-post > blockquote{max-width:72ch;margin-inline:auto}

/* Wide is the absence of a cap, not a bigger one. A rule setting `none` would
   still beat a narrower rule further down the sheet, which is how a "wide"
   layout ends up unable to be narrowed by anything. */
.bl-read-wide .pb-rich > *{max-width:none}

/* ── how the type is set ──
   Serif for the body, or serif headings over a sans body — the two
   arrangements a theme's two faces can make that a theme itself does not
   choose between. `--pb-font-*` are the tokens the themes already define, so
   nothing here names a typeface. */
.bl-type-serif{font-family:var(--pb-font-heading,Georgia,'Times New Roman',serif)}
.bl-type-serif .bl-post p,
.bl-type-serif .pb-rich p{line-height:1.78;font-size:1.06em}

.bl-type-mixed h1,.bl-type-mixed h2,.bl-type-mixed h3,
.bl-type-mixed .bl-title{font-family:var(--pb-font-heading,Georgia,serif)}
.bl-type-mixed p,.bl-type-mixed li{font-family:var(--pb-font-body,inherit)}

/* ── the newest post, drawn large ──
   `:first-child` rather than a flag on the record: which post is newest is
   already decided by the order the archive is queried in, and a second answer
   to it in the markup is a second thing that can disagree.

   Only from the width where a two-column row is a row. Below it the rule would
   make the first card taller than the rest for no reason. */
@media (min-width:760px){
  .bl-feat-on .pb-posts > *:first-child,
  .bl-feat-on .pb-grid > *:first-child{grid-column:1 / -1}
  .bl-feat-on .pb-posts > *:first-child img,
  .bl-feat-on .pb-grid > *:first-child img{aspect-ratio:21 / 9;object-fit:cover;width:100%}
  .bl-feat-on .pb-posts > *:first-child h2,
  .bl-feat-on .pb-posts > *:first-child h3,
  .bl-feat-on .pb-grid > *:first-child h2,
  .bl-feat-on .pb-grid > *:first-child h3{font-size:1.6em;line-height:1.2}
}

/* ── the archive's own shape ──
   `bl-ix-list` and `bl-ix-grid` agree with what `BlogLayout::isGrid()` already
   tells the template to render, and are here so the shape is legible in the
   markup — a preview or a test can read which layout a page is on without
   re-deriving it from a column count. */
.bl-ix-list .pb-posts{display:block}
.bl-ix-list .pb-posts > * + *{margin-top:22px}
