/* ============================================================
   Impastro — brand website
   Built on the Impastro Design System tokens (tokens/*.css).
   Almost-monochrome gallery aesthetic; Cormorant Garamond display
   + DM Sans UI; coral reserved for star ratings only.
   ============================================================ */

*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{
  font-family:var(--font-body);
  background:var(--surface-page);
  color:var(--text-body);
  line-height:var(--lh-body);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button{font:inherit}
::selection{background:var(--ink-950);color:var(--white)}

.display{font-family:var(--font-display)}
.section{max-width:var(--container-max);margin:0 auto;padding:var(--space-9) var(--space-6);text-align:center}

/* ---------- scroll progress ---------- */
.progress{position:fixed;inset:0 0 auto 0;height:2px;z-index:60;background:transparent;pointer-events:none}
.progress span{display:block;height:100%;width:0;background:var(--ink-950);transition:width .1s linear}

/* ---------- fixed bottom edge blur ---------- */
/* Thin frosted strip pinned to the viewport bottom, blurring whatever page
   content happens to be scrolled underneath it. Backdrop-filter is the only
   option here (unlike the device mockup, the content behind is arbitrary and
   scrolls, so there's no static image to pre-blur and cross-fade). A single
   masked backdrop-filter layer tends to show a faint seam right where the
   mask reaches zero -- its blur sampling is clipped at the element's own box
   edge instead of tapering off. Stacking a few soft, overlapping layers of
   increasing blur (the standard "progressive blur" trick) spreads that
   falloff across several gentle transitions instead of one hard one. */
.edge-blur{position:fixed;left:0;right:0;bottom:0;height:180px;z-index:55;pointer-events:none}
.edge-blur span{position:absolute;inset:0;display:block}
.edge-blur span:nth-child(1){
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 0%,rgba(0,0,0,.5) 55%,rgba(0,0,0,.9) 100%);
  mask-image:linear-gradient(to bottom,transparent 0%,rgba(0,0,0,.5) 55%,rgba(0,0,0,.9) 100%);
}
.edge-blur span:nth-child(2){
  -webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 35%,rgba(0,0,0,.45) 70%,rgba(0,0,0,.85) 100%);
  mask-image:linear-gradient(to bottom,transparent 35%,rgba(0,0,0,.45) 70%,rgba(0,0,0,.85) 100%);
}
.edge-blur span:nth-child(3){
  -webkit-backdrop-filter:blur(13px);backdrop-filter:blur(13px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 60%,rgba(0,0,0,.4) 82%,rgba(0,0,0,.8) 100%);
  mask-image:linear-gradient(to bottom,transparent 60%,rgba(0,0,0,.4) 82%,rgba(0,0,0,.8) 100%);
}

/* ---------- custom cursor dot ---------- */
/* Rides alongside the native pointer (doesn't hide it), trailing toward a
   point offset to the pointer's top-right (not the pointer's own xy, so it
   never converges onto/overlaps the real cursor) -- position is fully
   JS-driven (translate3d, updated every rAF frame with a delayed/eased
   follow) so it's set here as inline style each frame; this block only owns
   size/color, which transition smoothly on their own without fighting the
   per-frame transform writes. Fine-pointer devices only; touch and
   prefers-reduced-motion never get one (see site.js). */
.cursor-dot{
  position:fixed;top:0;left:0;width:14px;height:14px;border-radius:50%;
  background:var(--ink-950);pointer-events:none;z-index:70;opacity:0;
  display:flex;align-items:center;justify-content:center;
  transition:width .22s cubic-bezier(.2,.7,.2,1),height .22s cubic-bezier(.2,.7,.2,1),
    background .22s ease,border-color .22s ease,border-width .22s ease,
    opacity .25s ease,box-shadow .22s ease;
  will-change:transform;
}
.cursor-dot.is-visible{opacity:1}
.cursor-dot.is-down{width:9px;height:9px}
.cursor-dot.is-hover{width:34px;height:34px;background:transparent;border:1.5px solid var(--ink-950)}
.cursor-dot.is-hover.is-down{width:26px;height:26px}

/* over a product card: a solid white "add to cart" bubble with a black
   glyph -- opaque, not blend-mode-based, so it stays readable over any
   product photo or paint-gradient placeholder behind it */
.cursor-dot__icon{
  width:20px;height:20px;background:var(--ink-950);opacity:0;
  transition:opacity .18s ease;
  -webkit-mask:url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTMgNGgybDIuNCAxMi40YTEgMSAwIDAgMCAxIC44aDguNGExIDEgMCAwIDAgMS0uOEwyMCA4SDYiIHN0cm9rZT0iYmxhY2siIHN0cm9rZS13aWR0aD0iMS43IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48Y2lyY2xlIGN4PSI5LjUiIGN5PSIyMCIgcj0iMS4zIiBmaWxsPSJibGFjayIvPjxjaXJjbGUgY3g9IjE3IiBjeT0iMjAiIHI9IjEuMyIgZmlsbD0iYmxhY2siLz48L3N2Zz4=) center/contain no-repeat;
  mask:url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTMgNGgybDIuNCAxMi40YTEgMSAwIDAgMCAxIC44aDguNGExIDEgMCAwIDAgMS0uOEwyMCA4SDYiIHN0cm9rZT0iYmxhY2siIHN0cm9rZS13aWR0aD0iMS43IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48Y2lyY2xlIGN4PSI5LjUiIGN5PSIyMCIgcj0iMS4zIiBmaWxsPSJibGFjayIvPjxjaXJjbGUgY3g9IjE3IiBjeT0iMjAiIHI9IjEuMyIgZmlsbD0iYmxhY2siLz48L3N2Zz4=) center/contain no-repeat;
}
.cursor-dot.is-cart{
  width:58px;height:58px;background:var(--white);border:none;
  box-shadow:0 6px 24px rgba(22,23,22,.3);
}
.cursor-dot.is-cart .cursor-dot__icon{opacity:1;background:var(--ink-950)}
.cursor-dot.is-cart.is-down{width:48px;height:48px}

/* ---------- navbar ---------- */
.nav{position:sticky;top:0;z-index:50;background:var(--paper-0);border-bottom:1px solid var(--line);transition:box-shadow .35s ease}
.nav.scrolled{box-shadow:0 1px 0 rgba(22,23,22,.03),0 14px 34px -22px rgba(22,23,22,.35)}
.nav__inner{position:relative;max-width:var(--container-max);margin:0 auto;display:flex;align-items:center;justify-content:space-between;padding:var(--space-5) var(--space-6)}
.nav__brand{display:inline-flex;align-items:center;gap:12px;font-family:var(--font-display);font-size:21px;font-weight:600;color:var(--ink-950)}
.nav__brand img{width:46px;height:46px;transition:transform .6s cubic-bezier(.2,.7,.2,1)}
.nav__brand:hover img{transform:rotate(90deg)}
.nav__links{display:flex;gap:var(--space-6)}
.nav__links a{font-size:15px;color:var(--text-muted);transition:color .2s ease}
.nav__links a:hover,.nav__links a.is-active{color:var(--ink-950)}
.nav__cta{margin:0}

/* mobile menu toggle -- hidden on desktop (.nav__links shows inline there);
   swaps to an X via the two outer bars rotating onto the middle one's spot,
   the middle bar just fading, matching the css-only style used elsewhere
   on the site rather than pulling in an icon font/svg set for one glyph */
.nav__toggle{display:none;flex-direction:column;justify-content:center;align-items:center;gap:5px;width:38px;height:38px;border:none;background:none;padding:0;cursor:pointer;flex-shrink:0}
.nav__toggle span{display:block;width:22px;height:2px;background:var(--ink-950);border-radius:2px;transition:transform .3s cubic-bezier(.2,.7,.2,1),opacity .2s ease}
.nav__toggle[aria-expanded="true"] span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.nav__toggle[aria-expanded="true"] span:nth-child(2){opacity:0}
.nav__toggle[aria-expanded="true"] span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;gap:var(--space-2);
  padding:13px 26px;border-radius:var(--radius-pill);
  font-family:var(--font-body);font-weight:var(--weight-medium);font-size:16px;
  border:1px solid transparent;cursor:pointer;white-space:nowrap;
  transition:background .18s ease,color .18s ease,transform .2s cubic-bezier(.2,.7,.2,1),box-shadow .28s ease,opacity .18s ease;
}
.btn--sm{padding:10px 20px;font-size:14px}
.btn__arrow{transition:transform .22s cubic-bezier(.2,.7,.2,1)}
.btn:hover .btn__arrow{transform:translate(2px,-2px)}
.btn:active{transform:translateY(0) scale(.985);opacity:.92}

.btn--primary{background:var(--action-fill);color:var(--text-inverse);border-color:var(--action-fill)}
.btn--primary .btn__arrow{fill:var(--white)}
.btn--primary:hover{background:var(--action-fill-hover);border-color:var(--action-fill-hover);transform:translateY(-2px);box-shadow:0 16px 30px -16px rgba(22,23,22,.55)}

.btn--outline{background:transparent;color:var(--ink-950);border-color:var(--ink-950)}
.btn--outline .btn__arrow{fill:var(--ink-950)}
.btn--outline:hover{background:var(--ink-950);color:var(--white);transform:translateY(-2px)}
.btn--outline:hover .btn__arrow{fill:var(--white)}

/* ---------- badge (eyebrow) ---------- */
.badge{display:inline-flex;align-items:center;padding:8px 16px;border-radius:var(--radius-pill);border:1px solid var(--line);background:var(--surface-card);color:var(--text-muted);font-size:13px;font-weight:var(--weight-medium);letter-spacing:var(--ls-eyebrow)}

/* ---------- rating badge ---------- */
.rating{display:inline-flex;flex-direction:column;align-items:center;gap:6px}
.rating__row{display:inline-flex;align-items:center}
.rating__avatars{display:flex;align-items:center}
.rating__avatars .av{width:28px;height:28px;border-radius:50%;border:2px solid var(--paper-0);margin-left:-8px;box-shadow:0 1px 3px rgba(22,23,22,.18);overflow:hidden}
.rating__avatars .av:first-child{margin-left:0}
.rating__avatars .av img{width:100%;height:100%;object-fit:cover;display:block}
.rating__stars{color:var(--rating-star);font-size:15px;letter-spacing:2px;margin-left:12px}
.rating__meta{font-size:14px;color:var(--text-body)}
.rating__meta strong{font-weight:var(--weight-semibold);color:var(--ink-950)}

/* ---------- hero ---------- */
.hero{position:relative;padding-top:var(--space-8);overflow:visible}
.mark-ghost{
  position:absolute;top:-30px;right:-30px;width:min(360px,42vw);aspect-ratio:1;
  background:var(--ink-950);opacity:.04;pointer-events:none;z-index:0;
  /* inlined as base64 (not url(assets/sparkle.svg)) -- an external mask
     reference is blocked by CORS when the page is opened as file:///...,
     which silently dropped this element; a data: URI has no such issue */
  -webkit-mask:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAzNyIgaGVpZ2h0PSIxMDM3IiB2aWV3Qm94PSIwIDAgMTAzNyAxMDM3IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNTE4LjUwMSA1MTguNUM1MTguNTAxIDQyNi44NjUgNDYyLjc4NyAzNTIuNTggMzk0LjA2MSAzNTIuNThDNDYyLjc4NyAzNTIuNTggNTE4LjUwMSAyNzguMjk1IDUxOC41MDEgMTg2LjY2QzUxOC41MDEgMjc4LjI5NSA1NzQuMjE0IDM1Mi41OCA2NDIuOTQxIDM1Mi41OEM1NzQuMjE0IDM1Mi41OCA1MTguNTAxIDQyNi44NjUgNTE4LjUwMSA1MTguNVoiIGZpbGw9ImJsYWNrIj48L3BhdGg+CjxwYXRoIGQ9Ik01MTguNTAxIDUxOC41QzUxOC41MDEgNjEwLjEzNSA0NjIuNzg3IDY4NC40MiAzOTQuMDYxIDY4NC40MkM0NjIuNzg3IDY4NC40MiA1MTguNTAxIDc1OC43MDUgNTE4LjUwMSA4NTAuMzRDNTE4LjUwMSA3NTguNzA1IDU3NC4yMTQgNjg0LjQyIDY0Mi45NDEgNjg0LjQyQzU3NC4yMTQgNjg0LjQyIDUxOC41MDEgNjEwLjEzNSA1MTguNTAxIDUxOC41WiIgZmlsbD0iYmxhY2siPjwvcGF0aD4KPHBhdGggZD0iTTUxOC41IDUxOC41MDRDNDI2Ljg2NSA1MTguNTA0IDM1Mi41OCA1NzQuMjE4IDM1Mi41OCA2NDIuOTQ0QzM1Mi41OCA1NzQuMjE4IDI3OC4yOTUgNTE4LjUwNCAxODYuNjYgNTE4LjUwNEMyNzguMjk1IDUxOC41MDQgMzUyLjU4IDQ2Mi43OSAzNTIuNTggMzk0LjA2NEMzNTIuNTggNDYyLjc5IDQyNi44NjUgNTE4LjUwNCA1MTguNSA1MTguNTA0WiIgZmlsbD0iYmxhY2siPjwvcGF0aD4KPHBhdGggZD0iTTUxOC41IDUxOC41MDRDNjEwLjEzNSA1MTguNTA0IDY4NC40MiA1NzQuMjE4IDY4NC40MiA2NDIuOTQ0QzY4NC40MiA1NzQuMjE4IDc1OC43MDUgNTE4LjUwNCA4NTAuMzQgNTE4LjUwNEM3NTguNzA1IDUxOC41MDQgNjg0LjQyIDQ2Mi43OSA2ODQuNDIgMzk0LjA2NEM2ODQuNDIgNDYyLjc5IDYxMC4xMzUgNTE4LjUwNCA1MTguNSA1MTguNTA0WiIgZmlsbD0iYmxhY2siPjwvcGF0aD4KPC9zdmc+) center/contain no-repeat;
  mask:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAzNyIgaGVpZ2h0PSIxMDM3IiB2aWV3Qm94PSIwIDAgMTAzNyAxMDM3IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNTE4LjUwMSA1MTguNUM1MTguNTAxIDQyNi44NjUgNDYyLjc4NyAzNTIuNTggMzk0LjA2MSAzNTIuNThDNDYyLjc4NyAzNTIuNTggNTE4LjUwMSAyNzguMjk1IDUxOC41MDEgMTg2LjY2QzUxOC41MDEgMjc4LjI5NSA1NzQuMjE0IDM1Mi41OCA2NDIuOTQxIDM1Mi41OEM1NzQuMjE0IDM1Mi41OCA1MTguNTAxIDQyNi44NjUgNTE4LjUwMSA1MTguNVoiIGZpbGw9ImJsYWNrIj48L3BhdGg+CjxwYXRoIGQ9Ik01MTguNTAxIDUxOC41QzUxOC41MDEgNjEwLjEzNSA0NjIuNzg3IDY4NC40MiAzOTQuMDYxIDY4NC40MkM0NjIuNzg3IDY4NC40MiA1MTguNTAxIDc1OC43MDUgNTE4LjUwMSA4NTAuMzRDNTE4LjUwMSA3NTguNzA1IDU3NC4yMTQgNjg0LjQyIDY0Mi45NDEgNjg0LjQyQzU3NC4yMTQgNjg0LjQyIDUxOC41MDEgNjEwLjEzNSA1MTguNTAxIDUxOC41WiIgZmlsbD0iYmxhY2siPjwvcGF0aD4KPHBhdGggZD0iTTUxOC41IDUxOC41MDRDNDI2Ljg2NSA1MTguNTA0IDM1Mi41OCA1NzQuMjE4IDM1Mi41OCA2NDIuOTQ0QzM1Mi41OCA1NzQuMjE4IDI3OC4yOTUgNTE4LjUwNCAxODYuNjYgNTE4LjUwNEMyNzguMjk1IDUxOC41MDQgMzUyLjU4IDQ2Mi43OSAzNTIuNTggMzk0LjA2NEMzNTIuNTggNDYyLjc5IDQyNi44NjUgNTE4LjUwNCA1MTguNSA1MTguNTA0WiIgZmlsbD0iYmxhY2siPjwvcGF0aD4KPHBhdGggZD0iTTUxOC41IDUxOC41MDRDNjEwLjEzNSA1MTguNTA0IDY4NC40MiA1NzQuMjE4IDY4NC40MiA2NDIuOTQ0QzY4NC40MiA1NzQuMjE4IDc1OC43MDUgNTE4LjUwNCA4NTAuMzQgNTE4LjUwNEM3NTguNzA1IDUxOC41MDQgNjg0LjQyIDQ2Mi43OSA2ODQuNDIgMzk0LjA2NEM2ODQuNDIgNDYyLjc5IDYxMC4xMzUgNTE4LjUwNCA1MTguNSA1MTguNTA0WiIgZmlsbD0iYmxhY2siPjwvcGF0aD4KPC9zdmc+) center/contain no-repeat;
  animation:spin 70s linear infinite;
}
.hero>*{position:relative;z-index:1}
.hero .rating{margin-bottom:var(--space-7)}
.hero__title{font-size:clamp(48px,7vw,88px);line-height:1.02;color:var(--ink-950);font-weight:600;letter-spacing:-.015em}
.hero__title--alt{font-style:italic;font-weight:400;color:var(--text-muted);margin-bottom:var(--space-5)}
.hero__lede{font-size:var(--text-body-l);color:var(--text-body);margin:var(--space-5) auto var(--space-6);max-width:520px}
.hero__lede strong{color:var(--ink-950);font-weight:var(--weight-semibold)}

/* --rise lives on .device (set from JS) so .device__stage can inherit it for
   its transform AND .device itself can inherit it for margin-bottom -- that
   second part collapses the box's reserved space in sync with how far the
   shot has risen out of it, so no dead gap opens up before the next section */
.device{position:relative;margin:var(--space-9) auto 0;max-width:760px;z-index:2;margin-bottom:var(--rise,0px)}
.device__stage{
  position:relative;transform:translateY(var(--rise,0px));
  will-change:transform;
}
.device__shot{position:relative;display:none;filter:drop-shadow(0 50px 90px rgba(22,23,22,.35))}
.device__shot img{width:100%;height:auto;display:block;border-radius:16px}
.device__shot--mac{display:block;max-width:100%;margin:0 auto}
.device__shot--iphone{max-width:230px;margin:0 auto}

/* ---------- 404 ---------- */
.notfound{min-height:calc(100vh - 160px);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-3)}
.notfound__eyebrow{font-size:var(--text-body-m);color:var(--text-muted);margin-bottom:var(--space-2)}
.notfound__title{font-size:clamp(40px,6.5vw,64px);line-height:1.08;color:var(--ink-950);font-weight:600;letter-spacing:-.015em}
.notfound__title--alt{color:var(--text-muted);font-weight:400;margin-bottom:var(--space-4)}
.notfound__lede{font-size:var(--text-body-l);color:var(--text-muted);max-width:440px;margin:0 auto var(--space-5)}

/* ---------- shop grid ---------- */
.shop{text-align:left}
.shop__head{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-6);margin-bottom:var(--space-8)}
.shop__intro .badge{margin-bottom:var(--space-5)}
.shop__title{font-size:clamp(30px,4vw,48px);color:var(--ink-950);font-weight:600;line-height:1.12;letter-spacing:-.012em;margin:0}
.shop__title:nth-of-type(2){color:var(--text-muted);font-weight:400}
.shop__view-all{flex-shrink:0;margin-bottom:6px}

.shop__grid{
  display:grid;
  grid-template-columns:repeat(4,1fr);
  grid-auto-rows:190px;
  grid-auto-flow:dense;
  gap:28px;
}
.product-card{display:flex;flex-direction:column;gap:14px;grid-column:span 1;grid-row:span 1;cursor:pointer}
.product-card[data-size="lg"]{grid-column:span 2;grid-row:span 2}
.product-card[data-size="md"]{grid-column:span 2;grid-row:span 1}
.product-card[data-size="sm"]{grid-column:span 1;grid-row:span 1}
/* light stagger so the grid doesn't read as a rigid checkerboard */
.product-card:nth-child(4n+2){transform:translateY(18px)}
.product-card:nth-child(4n+4){transform:translateY(-10px)}

.product-card__media{
  position:relative;flex:1 1 auto;min-height:0;border-radius:var(--radius-md);overflow:hidden;
  box-shadow:0 1px 0 rgba(22,23,22,.03),0 20px 40px -26px rgba(22,23,22,.4);
}
/* Casual-copy deterrents on product photography (these are the paid
   product, not decorative site imagery) -- disables the native
   drag-to-save-image gesture and long-press callout on iOS/context-menu
   image preview. Paired with a contextmenu preventDefault in site.js.
   Not real protection (see scripts/optimize_product.py for why baked-in
   watermarking is the part that actually matters), just removes the
   easiest one-click/one-drag paths for a casual visitor. */
.product-card__img,
.product-modal__screen img,
.product-modal__thumb img{
  -webkit-user-drag:none;user-drag:none;-webkit-touch-callout:none;
  -webkit-user-select:none;user-select:none;
}
.product-card__img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;transition:opacity .5s cubic-bezier(.2,.7,.2,1),transform .6s cubic-bezier(.2,.7,.2,1)}
.product-card__img--base{position:relative}
.product-card__img--hover{opacity:0}
.product-card:hover .product-card__img--base{opacity:0}
.product-card:hover .product-card__img--hover{opacity:1;transform:scale(1.04)}
.product-card__media[data-broken] .product-card__img{display:none}

.product-card__meta{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
.product-card__title{font-size:16px;font-weight:var(--weight-semibold);color:var(--ink-950);line-height:1.3}
.product-card__brand{font-size:var(--text-body-s);color:var(--text-muted);margin-top:2px}
.product-card__price{flex-shrink:0;white-space:nowrap;font-size:13px;font-weight:var(--weight-medium);color:var(--ink-950);background:var(--surface-card);border:1px solid var(--line);border-radius:var(--radius-pill);padding:8px 14px}

@media (max-width:820px){
  .shop__head{flex-direction:column;align-items:flex-start;gap:var(--space-5)}
  .shop__grid{grid-template-columns:repeat(2,1fr);grid-auto-rows:220px}
  .product-card[data-size="lg"]{grid-column:span 2;grid-row:span 2}
  .product-card[data-size="md"]{grid-column:span 2;grid-row:span 1}
  .product-card:nth-child(4n+2),.product-card:nth-child(4n+4){transform:none}
}
@media (max-width:560px){
  .shop__grid{grid-template-columns:1fr;grid-auto-rows:280px}
  .product-card[data-size="lg"],.product-card[data-size="md"]{grid-column:span 1}
  .product-card[data-size="lg"]{grid-row:span 1}
}

/* ---------- product detail modal ---------- */
/* Kept in the DOM always (not display:none) so opacity/transform can
   transition. visibility is delayed (not instant) on the way OUT so the
   backdrop/panel fade-out is actually visible before the element leaves
   rendering/hit-testing -- without this delay, visibility:hidden applies
   the instant .is-open is removed, which hides the whole subtree before its
   own opacity/transform transitions ever get a visible frame (this was why
   closing felt like a snap rather than an animation). Opening still needs
   to flip to visible instantly, hence transition-delay is overridden back
   to 0 on .is-open itself. */
.product-modal{
  position:fixed;inset:0;z-index:80;display:flex;align-items:center;justify-content:center;
  padding:var(--space-6);visibility:hidden;pointer-events:none;
  transition:visibility 0s linear .5s;
}
.product-modal.is-open{visibility:visible;pointer-events:auto;transition-delay:0s}
.product-modal__backdrop{
  position:absolute;inset:0;background:rgba(22,23,22,.55);
  -webkit-backdrop-filter:blur(0);backdrop-filter:blur(0);
  opacity:0;
  transition:opacity .45s cubic-bezier(.2,.7,.2,1),-webkit-backdrop-filter .5s ease,backdrop-filter .5s ease;
}
.product-modal.is-open .product-modal__backdrop{
  opacity:1;-webkit-backdrop-filter:blur(9px);backdrop-filter:blur(9px);
}
.product-modal__panel{
  position:relative;z-index:1;width:100%;max-width:1040px;max-height:88vh;
  display:flex;flex-direction:column;overflow:hidden;
  background:var(--paper-0);border-radius:var(--radius-md);
  box-shadow:var(--shadow-card),0 60px 120px -30px rgba(22,23,22,.55);
  transform:translateY(46px) scale(.92);opacity:0;
  transition:transform .5s cubic-bezier(.16,.9,.24,1),opacity .4s ease;
}
.product-modal.is-open .product-modal__panel{transform:none;opacity:1}
/* The only child that actually scrolls -- .product-modal__footer (the buy
   button) sits outside this, as a sibling flex item in .product-modal__panel,
   so it's never carried out of view by this element's own scrolling. */
.product-modal__scroll{flex:1 1 auto;min-height:0;overflow-y:auto}

/* content stagger, driven purely by .product-modal.is-open (not the
   sitewide scroll .reveal system / IntersectionObserver -- these elements
   are static, already in the DOM at page load, and need to replay their
   entrance every time the modal re-opens, which the one-shot scroll
   observer doesn't support). transition-delay lives ONLY on the .is-open
   rule, not the base rule, so closing reverts to delay:0 and everything
   fades out together instead of re-playing the stagger in reverse. */
.product-modal__stagger{
  opacity:0;transform:translateY(18px);filter:blur(9px);
  transition:opacity .45s cubic-bezier(.2,.7,.2,1),transform .45s cubic-bezier(.2,.7,.2,1),filter .45s ease;
}
.product-modal__stagger--scale{transform:translateY(18px) scale(.93)}
.product-modal.is-open .product-modal__stagger{
  opacity:1;transform:none;filter:blur(0);
  transition-delay:calc(var(--sd,0) * .08s);
}
[data-sd="0"]{--sd:0}[data-sd="1"]{--sd:1}[data-sd="2"]{--sd:2}[data-sd="3"]{--sd:3}[data-sd="4"]{--sd:4}[data-sd="5"]{--sd:5}

.product-modal__bar{padding:18px var(--space-6);border-bottom:1px solid var(--line)}
.product-modal__back{
  display:inline-flex;align-items:center;gap:8px;background:none;border:none;padding:0;
  font-family:var(--font-body);font-size:14px;color:var(--text-muted);cursor:pointer;
  transition:color .2s ease;
}
.product-modal__back svg{fill:currentColor}
.product-modal__back:hover{color:var(--ink-950)}

.product-modal__body{display:grid;grid-template-columns:1fr 1fr}
.product-modal__visual{
  padding:var(--space-7) var(--space-6);background:var(--surface-100);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-5);
  border-right:1px solid var(--line);
}
.product-modal__monitor{width:100%;max-width:400px}
.product-modal__screen{
  aspect-ratio:16/10;border-radius:10px;overflow:hidden;background:var(--ink-950);
  border:9px solid var(--white);box-shadow:var(--shadow-card),0 30px 60px -30px rgba(22,23,22,.45);
}
.product-modal__screen img{width:100%;height:100%;object-fit:cover;display:block;transition:opacity .25s ease}
.product-modal__neck{width:64px;height:30px;margin:0 auto;background:linear-gradient(to bottom,var(--white),var(--surface-200));clip-path:polygon(32% 0,68% 0,100% 100%,0 100%)}
.product-modal__base{width:190px;height:11px;margin:0 auto;border-radius:999px;background:linear-gradient(to bottom,var(--white),var(--surface-200));box-shadow:var(--shadow-card)}

.product-modal__thumbs{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;max-width:400px}
.product-modal__thumb{
  width:50px;height:50px;padding:0;border-radius:8px;overflow:hidden;cursor:pointer;
  border:2px solid transparent;background:none;transition:border-color .2s ease,transform .2s ease;
}
.product-modal__thumb img{width:100%;height:100%;object-fit:cover;display:block}
.product-modal__thumb:hover{transform:translateY(-2px)}
.product-modal__thumb.is-active{border-color:var(--ink-950)}

.product-modal__info{padding:var(--space-7) var(--space-6);display:flex;flex-direction:column}
.product-modal__title{font-size:clamp(26px,3vw,36px);color:var(--ink-950);font-weight:600;line-height:1.15}
.product-modal__price{font-size:19px;font-weight:var(--weight-semibold);color:var(--ink-950);margin-top:8px}
.product-modal__rating{display:inline-flex;align-self:flex-start;align-items:center;gap:5px;margin-top:12px;padding:6px 12px;border-radius:var(--radius-pill);background:var(--surface-card);font-size:13px;color:var(--text-muted)}
.product-modal__rating[hidden]{display:none}
.product-modal__rating svg{fill:var(--rating-star);flex-shrink:0}
.product-modal__rating strong{color:var(--ink-950);font-weight:var(--weight-semibold)}
.product-modal__rule{border:none;border-top:1px solid var(--line);margin:var(--space-5) 0}
.product-modal__desc{color:var(--text-body);line-height:1.65;font-size:15px}
.product-modal__whatyouget{margin-top:var(--space-6)}
.product-modal__whatyouget strong{display:block;margin-bottom:12px;color:var(--ink-950);font-size:14px;font-weight:var(--weight-semibold)}
.product-modal__whatyouget ul{list-style:none;display:flex;flex-direction:column;gap:10px}
.product-modal__whatyouget li{display:flex;align-items:center;gap:10px;font-size:14px;color:var(--text-body)}
.product-modal__whatyouget li::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--ink-950);flex-shrink:0}

/* Buy button lives in its own footer, a sibling of .product-modal__scroll
   rather than the last item inside it -- a plain position:sticky on the CTA
   itself (tried first) only "catches up" once you scroll far enough to pass
   its normal flow position, so on a tall single-column mobile layout (full
   gallery + description + bullets before it) it was invisible on open,
   exactly the "always be there" complaint. Pulling it out of the scrolling
   content entirely and into a fixed-height footer alongside
   .product-modal__scroll (both flex children of .product-modal__panel)
   means it's never part of what scrolls -- visible immediately, on every
   viewport, no scroll required. */
.product-modal__footer{
  flex-shrink:0;display:flex;justify-content:flex-end;
  padding:var(--space-5) var(--space-6);border-top:1px solid var(--line);
  background:var(--paper-0);
}

@media (max-width:820px){
  .product-modal__body{grid-template-columns:1fr}
  .product-modal__visual{border-right:none;border-bottom:1px solid var(--line);padding:var(--space-6) var(--space-5)}
  .product-modal__info{padding:var(--space-6) var(--space-5)}
  .product-modal__footer{padding:var(--space-4) var(--space-5)}
  .product-modal__cta{width:100%;justify-content:center}
}

/* ---------- product / bubbles ---------- */
.product .badge{margin-bottom:var(--space-5)}
.h2{font-size:clamp(32px,4.4vw,52px);color:var(--ink-950);font-weight:600;line-height:var(--lh-display);letter-spacing:-.012em;margin:0}
.h2 em{font-style:italic;font-weight:400}
.h2--muted{color:var(--text-muted);font-weight:400}
.product .h2:first-of-type{margin-top:var(--space-3)}
.product .h2--muted{margin-bottom:var(--space-5)}
.quote{font-style:italic;font-size:clamp(20px,2.4vw,26px);color:var(--text-muted);max-width:640px;margin:0 auto var(--space-6);line-height:1.4}

.bubbles{--bscale:1;display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:24px;max-width:940px;margin:var(--space-9) auto 0}
.bubble{width:calc(var(--size) * var(--bscale));height:calc(var(--size) * var(--bscale));flex:0 0 auto;transform:translateY(var(--py,0));will-change:transform}
.bubble:nth-child(2n){margin-top:36px}
.bubble:nth-child(3n){margin-top:-30px}
.bubble:nth-child(5n){margin-top:18px}
.bubble__float{width:100%;height:100%;animation:float var(--dur,7s) ease-in-out var(--delay,0s) infinite}
.bubble:nth-child(1){--dur:6.5s;--delay:-.4s}
.bubble:nth-child(2){--dur:8s;--delay:-1.6s}
.bubble:nth-child(3){--dur:7.2s;--delay:-.9s}
.bubble:nth-child(4){--dur:9s;--delay:-2.2s}
.bubble:nth-child(5){--dur:6.8s;--delay:-1.1s}
.bubble:nth-child(6){--dur:8.4s;--delay:-.3s}
.bubble:nth-child(7){--dur:7.6s;--delay:-1.9s}
.bubble:nth-child(8){--dur:9.4s;--delay:-.7s}
.bubble:nth-child(9){--dur:6.9s;--delay:-2.5s}
.bubble:nth-child(10){--dur:8.1s;--delay:-1.3s}
.bubble:nth-child(11){--dur:7.4s;--delay:-.5s}
.bubble__disc{width:100%;height:100%;border-radius:50%;overflow:hidden;border:4px solid var(--paper-0);box-shadow:0 0 0 1px var(--line),0 22px 44px -20px rgba(22,23,22,.5)}
.bubble__disc picture,.bubble__disc img{display:block;width:100%;height:100%;object-fit:cover}

/* ---------- FAQ ---------- */
.faq{max-width:760px}
.faq .badge{margin-bottom:var(--space-5)}
.faq .h2{margin-bottom:var(--space-3)}
.faq__lede{color:var(--text-muted);margin:0 auto var(--space-6);max-width:460px;font-size:var(--text-body-m)}
.accordion{display:flex;flex-direction:column;gap:12px;margin-top:var(--space-7);text-align:left}
.faq-item{background:var(--surface-card);border-radius:var(--radius-md);overflow:hidden;transition:background .2s ease,box-shadow .3s ease}
.faq-item:hover{background:var(--surface-card-alt)}
.faq-item.is-open{box-shadow:var(--shadow-card)}
.faq-item__head{width:100%;display:flex;justify-content:space-between;align-items:center;gap:16px;background:none;border:0;cursor:pointer;padding:18px 20px;font-size:16px;font-weight:var(--weight-medium);color:var(--ink-950);text-align:left}
.faq-item__chev{flex-shrink:0;color:var(--ink-950);transition:transform .3s ease}
.faq-item.is-open .faq-item__chev{transform:rotate(180deg)}
.faq-item__body{max-height:0;overflow:hidden;transition:max-height .4s cubic-bezier(.2,.7,.2,1)}
.faq-item.is-open .faq-item__body{max-height:260px}
.faq-item__body p{padding:2px 20px 18px;font-size:var(--text-body-s);color:var(--text-muted);line-height:var(--lh-body)}

/* ---------- closing band ---------- */
.band-wrap{max-width:var(--container-max);margin:0 auto;padding:0 var(--space-6) var(--space-9)}
.band{position:relative;border-radius:var(--radius-md);overflow:hidden;min-height:440px;display:flex;align-items:center;justify-content:center;padding:var(--space-8) var(--space-6);background:var(--surface-100)}
.band__bg{position:absolute;inset:0;z-index:0;overflow:hidden}
.band__bg picture,.band__bg img{display:block;width:100%;height:100%;object-fit:cover}
.band__bg img{
  opacity:.3;
  transform:scale(var(--band-scale,1.05));
  will-change:transform;
  transition:transform .1s linear;
}
.band__scrim{position:absolute;inset:0;background:rgba(255,255,255,.55);z-index:1}
.band__content{position:relative;z-index:2;text-align:center;display:flex;flex-direction:column;align-items:center}
.band__title{font-size:clamp(30px,4.2vw,48px);color:var(--ink-950);line-height:1.12;font-weight:400}
.band__title strong{font-weight:600}
.band .rating{margin:var(--space-5) 0 var(--space-6)}

/* ---------- footer ---------- */
.footer{background:var(--paper-0);border-top:1px solid var(--line);overflow:hidden}
.footer__top{max-width:var(--container-max);margin:0 auto;display:flex;flex-wrap:wrap;gap:44px;justify-content:space-between;padding:var(--space-8) var(--space-6) var(--space-6)}
.footer__brand{max-width:300px}
.footer__brand img{width:24px;margin-bottom:16px}
.footer__brand p{font-size:var(--text-body-s);color:var(--text-muted);line-height:var(--lh-body)}
.footer__social{display:flex;gap:12px;margin-top:18px}
.footer__social a{width:36px;height:36px;border-radius:50%;border:1px solid var(--line);display:inline-flex;align-items:center;justify-content:center;color:var(--text-muted);transition:color .2s,border-color .2s,transform .25s ease}
.footer__social a:hover{color:var(--ink-950);border-color:var(--ink-950);transform:translateY(-3px)}
.footer__col{display:flex;flex-direction:column;gap:12px}
.footer__col strong{font-size:15px;font-weight:var(--weight-semibold);color:var(--ink-950)}
.footer__col a{font-size:var(--text-body-s);color:var(--text-muted);transition:color .2s,padding-left .2s}
.footer__col a:hover{color:var(--ink-950);padding-left:3px}
.footer__rule{max-width:var(--container-max);margin:0 auto;border-top:1px solid var(--line)}
.footer__copy{max-width:var(--container-max);margin:0 auto;padding:20px var(--space-6);font-size:13px;color:var(--text-faint)}
.footer__wordmark{
  font-weight:600;font-size:clamp(64px,17.5vw,224px);line-height:.86;text-align:center;margin:0 12px;
  letter-spacing:.02em;user-select:none;
  background:linear-gradient(180deg,#161716 26%,rgba(22,23,22,0) 96%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}

/* ---------- painterly placeholders (offline stand-ins for impasto art) ---------- */
.paint{position:relative;overflow:hidden;background-color:#2c241f;isolation:isolate}
.paint::after{
  content:"";position:absolute;inset:0;pointer-events:none;opacity:.2;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.p1{background:radial-gradient(85% 85% at 24% 22%,#3f8560 0,rgba(63,133,96,0) 55%),radial-gradient(70% 70% at 82% 78%,#c7a24a 0,rgba(199,162,74,0) 52%),conic-gradient(from 200deg at 58% 42%,#12301f,#1e4832,#0e2117,#12301f)}
.p2{background:radial-gradient(80% 80% at 30% 25%,#2f7d86 0,rgba(47,125,134,0) 55%),radial-gradient(75% 75% at 78% 80%,#d98a4b 0,rgba(217,138,75,0) 50%),conic-gradient(from 150deg at 55% 45%,#0d2932,#154752,#0a1c24,#0d2932)}
.p3{background:radial-gradient(85% 85% at 22% 20%,#e08a4c 0,rgba(224,138,76,0) 55%),radial-gradient(70% 70% at 80% 75%,#8a3a24 0,rgba(138,58,36,0) 55%),conic-gradient(from 220deg at 60% 40%,#5a2515,#8f3f22,#3a160c,#5a2515)}
.p4{background:radial-gradient(82% 82% at 26% 24%,#a45a86 0,rgba(164,90,134,0) 55%),radial-gradient(70% 70% at 80% 78%,#e0a0ad 0,rgba(224,160,173,0) 50%),conic-gradient(from 180deg at 55% 45%,#3f1f3a,#5e2c4f,#2a1526,#3f1f3a)}
.p5{background:radial-gradient(85% 85% at 28% 22%,#3a4f8a 0,rgba(58,79,138,0) 55%),radial-gradient(65% 65% at 82% 80%,#8a6bc0 0,rgba(138,107,192,0) 52%),conic-gradient(from 210deg at 58% 42%,#141a33,#26305e,#0e1224,#141a33)}
.p6{background:radial-gradient(85% 85% at 24% 24%,#7a8a3f 0,rgba(122,138,63,0) 55%),radial-gradient(70% 70% at 80% 78%,#c9b45a 0,rgba(201,180,90,0) 50%),conic-gradient(from 190deg at 58% 44%,#2a3116,#3f4a1f,#1c210f,#2a3116)}
.p7{background:radial-gradient(90% 90% at 26% 22%,#e0a860 0,rgba(224,168,96,0) 55%),radial-gradient(75% 75% at 80% 80%,#b56a3a 0,rgba(181,106,58,0) 52%),conic-gradient(from 200deg at 56% 44%,#6e3f1e,#a5622f,#4a2913,#6e3f1e)}
.p8{background:radial-gradient(82% 82% at 26% 24%,#9c3f52 0,rgba(156,63,82,0) 55%),radial-gradient(68% 68% at 80% 78%,#d98a6b 0,rgba(217,138,107,0) 50%),conic-gradient(from 210deg at 58% 42%,#3f151f,#5e2231,#2a0e16,#3f151f)}
.p9{background:radial-gradient(85% 85% at 28% 22%,#4a6580 0,rgba(74,101,128,0) 55%),radial-gradient(65% 65% at 82% 80%,#94a8b8 0,rgba(148,168,184,0) 52%),conic-gradient(from 170deg at 56% 46%,#1c2731,#2e3f4c,#131b22,#1c2731)}
.p10{background:radial-gradient(85% 85% at 24% 24%,#d98a5a 0,rgba(217,138,90,0) 55%),radial-gradient(70% 70% at 80% 78%,#e0b48a 0,rgba(224,180,138,0) 50%),conic-gradient(from 200deg at 58% 44%,#6e3f24,#9c5c33,#4a2814,#6e3f24)}
.p11{background:radial-gradient(85% 85% at 26% 22%,#4a4f7a 0,rgba(74,79,122,0) 55%),radial-gradient(68% 68% at 80% 80%,#6b6b80 0,rgba(107,107,128,0) 52%),conic-gradient(from 190deg at 56% 44%,#1c1d2e,#30324a,#141522,#1c1d2e)}

/* ---------- reveal / motion system ---------- */
.reveal{opacity:0;transform:translateY(28px);filter:blur(14px);transition:opacity .85s cubic-bezier(.2,.7,.2,1),transform .85s cubic-bezier(.2,.7,.2,1),filter .85s ease;transition-delay:calc(var(--d,0)*.09s)}
.reveal.in{opacity:1;transform:none;filter:blur(0)}
.bubble__disc.reveal{transform:scale(.45);filter:blur(12px)}
.bubble__disc.reveal.in{transform:none;filter:blur(0)}
.footer__wordmark.reveal{transform:translateY(60px);filter:blur(22px)}
.footer__wordmark.reveal.in{transform:none;filter:blur(0)}

[data-d="0"]{--d:0}[data-d="1"]{--d:1}[data-d="2"]{--d:2}[data-d="3"]{--d:3}[data-d="4"]{--d:4}[data-d="5"]{--d:5}

@keyframes float{0%,100%{transform:translateY(0) rotate(0deg)}50%{transform:translateY(-12px) rotate(1.5deg)}}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- responsive ---------- */
@media (max-width:820px){
  .section{padding:var(--space-8) var(--space-5)}
  .nav__toggle{display:flex}
  .nav__links{
    position:absolute;top:100%;left:0;right:0;
    flex-direction:column;align-items:stretch;gap:0;
    background:var(--paper-0);border-bottom:1px solid var(--line);
    box-shadow:0 14px 34px -22px rgba(22,23,22,.35);
    padding:0 var(--space-6);max-height:0;overflow:hidden;opacity:0;
    transition:max-height .35s cubic-bezier(.2,.7,.2,1),opacity .25s ease;
  }
  .nav__links.is-open{max-height:340px;opacity:1;padding:var(--space-3) var(--space-6) var(--space-4)}
  .nav__links a{padding:var(--space-3) 0;border-bottom:1px solid var(--line);font-size:16px}
  .nav__links a:last-child{border-bottom:none}
  .footer__top{gap:30px}
  .device{margin-top:var(--space-8)}
  .bubbles{--bscale:.7;gap:14px;margin-top:var(--space-8)}
  .bubble:nth-child(2n),.bubble:nth-child(3n),.bubble:nth-child(5n){margin-top:8px}
}
@media (max-width:640px){
  .device__shot--mac{display:none}
  .device__shot--iphone{display:block}
  /* On mobile the device sits below the fold, so its blur/fade-in reveal
     only fired once scrolled into view -- it "suddenly appeared" mid-scroll,
     right as the rise was already carrying it over the title. Show it
     immediately (no appearance animation) so only the scroll-driven rise
     plays, exactly like desktop. The rise transform lives on .device__stage,
     so neutralising the reveal transform on .device itself is safe. */
  .device.reveal{opacity:1;transform:none;filter:none;transition:none}
  /* At the old 230px width the shot's own height (~460px, from the phone's
     tall native aspect ratio) ran to ~70% of a typical phone viewport --
     once the rise settled it, the shot alone filled almost the whole
     screen edge-to-edge, which read as "a big image parked in the middle
     of my screen" rather than a mockup rising past the hero copy. Smaller
     here so the settled shot is a clearly a moment in the scroll, not
     something that swallows the viewport. */
  .device__shot--iphone{max-width:168px}
}
@media (max-width:520px){
  .footer__wordmark{font-size:22vw}
  .band{min-height:380px}
  .bubbles{--bscale:.56;gap:10px}
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion:reduce){
  *{animation:none!important;scroll-behavior:auto!important;transition-duration:.001ms!important}
  .reveal{opacity:1!important;transform:none!important;filter:none!important}
  .bubble{transform:none!important}
  .device{margin-bottom:var(--space-9)!important}
  .device__stage{transform:none!important}
  .band__bg img{transform:none!important}
}
