/* ============================================================
   VALLORA
   ------------------------------------------------------------
   Two grounds, one system. Everything colour-related reads from
   --fg / --bg / --dim / --line-c, which default to the dark
   brand ground here and are overridden in exactly one place
   (.shop) to flip that block to paper. That is why a button, a
   chip or a table needs no variant to work on either side.
   ============================================================ */

:root{
  --ink:#060606;
  --ink-2:#0e0e10;
  --ink-3:#16161a;
  --paper:#ece8e1;
  --paper-2:#e2ddd4;
  --paper-dim:#948f87;
  --ember:#c8813c;      /* pulled from the golden hour campaign frames */

  /* the theme hooks */
  --bg:var(--ink);
  --fg:var(--paper);
  --dim:var(--paper-dim);
  --line-c:rgba(236,232,225,.15);

  --wrap:1360px;
  --gut:clamp(20px,5vw,68px);

  --track-xl:.42em;
  --track-lg:.28em;
  --track-md:.18em;

  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-mask:cubic-bezier(.76,0,.24,1);
}

*,*::before,*::after{box-sizing:border-box}

/* The browser hides [hidden] with display:none, but that comes from the UA
   stylesheet, so ANY author rule setting display beats it. `.mobile-menu` did
   exactly that: it stayed in the layout at opacity 0, full screen, and quietly
   ate every click on the page underneath it. This rule makes the attribute mean
   what it says, everywhere, permanently. */
[hidden]{display:none !important}

html{
  -webkit-text-size-adjust:100%;
  scroll-behavior:smooth;
  /* the nav is fixed, so an anchor has to stop below it */
  scroll-padding-top:6rem;
}

body{
  margin:0;
  background:var(--ink);
  color:var(--paper);
  font-family:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  font-weight:300;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

img{display:block;max-width:100%;height:auto}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}

::selection{background:var(--ember);color:var(--ink)}

.skip{
  position:absolute;left:-9999px;top:0;z-index:500;
  padding:12px 20px;background:var(--paper);color:var(--ink);
}
.skip:focus{left:12px;top:12px}

:focus-visible{outline:2px solid var(--ember);outline-offset:3px}

.wrap{
  width:100%;
  max-width:var(--wrap);
  margin-inline:auto;
  padding-inline:var(--gut);
}

/* ── grain ──────────────────────────────────────────────────
   Sits over everything. Does the heavy lifting of making 640px
   source photography read as film rather than as low res. */

.grain{
  position:fixed;inset:-150%;
  z-index:300;
  pointer-events:none;
  opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 6s steps(6) infinite;
  will-change:transform;
}
@keyframes grain{
  0%{transform:translate(0,0)}
  20%{transform:translate(-6%,3%)}
  40%{transform:translate(4%,-5%)}
  60%{transform:translate(-3%,6%)}
  80%{transform:translate(6%,2%)}
  100%{transform:translate(0,0)}
}

/* ── scroll progress ────────────────────────────────────── */

.progress{
  position:fixed;top:0;left:0;z-index:200;
  width:100%;height:2px;
  pointer-events:none;
}
.progress span{
  display:block;height:100%;width:100%;
  background:var(--ember);
  transform:scaleX(0);
  transform-origin:left;
}

/* ── custom cursor ──────────────────────────────────────── */

.cursor{display:none}

@media (hover:hover) and (pointer:fine){
  .cursor{
    display:block;
    /* Above EVERYTHING, deliberately. The native cursor is hidden by
       cursor:none further down, so this element is the only pointer there is.
       Anything that paints over it leaves the customer with no cursor at all,
       which is what happened when the sign-in sheet (500) went in above the
       old 450. It is pointer-events:none, so being on top can never block a
       click. Keep this the highest number in the file. */
    position:fixed;top:0;left:0;z-index:9000;
    pointer-events:none;
    mix-blend-mode:difference;
    /* stays invisible until the pointer actually moves, otherwise it parks
       in the middle of the hero on load */
    opacity:0;
    transition:opacity .3s var(--ease);
  }
  .cursor.is-live{opacity:1}
  .cursor__dot,.cursor__ring{
    position:fixed;top:0;left:0;
    border-radius:50%;
    transform:translate(-50%,-50%);
  }
  .cursor__dot{width:5px;height:5px;background:var(--paper)}
  .cursor__ring{
    width:34px;height:34px;
    border:1px solid rgba(236,232,225,.5);
    display:grid;place-items:center;
    transition:width .4s var(--ease),height .4s var(--ease),
               background .4s var(--ease),border-color .4s var(--ease);
  }
  .cursor__label{
    font-size:.5rem;
    letter-spacing:var(--track-md);
    text-transform:uppercase;
    color:var(--ink);
    opacity:0;
    white-space:nowrap;
    transition:opacity .3s var(--ease);
  }
  .cursor.is-hover .cursor__ring{
    width:52px;height:52px;
    background:rgba(236,232,225,.16);
    border-color:transparent;
  }
  .cursor.is-view .cursor__ring{
    width:84px;height:84px;
    background:var(--paper);
    border-color:transparent;
  }
  .cursor.is-view .cursor__label{opacity:1}
  .cursor.is-view .cursor__dot{opacity:0}

  /* the real pointer would fight the custom one */
  .js body,.js a,.js button{cursor:none}
}

/* ── loader ─────────────────────────────────────────────────
   Only ever shown when scripting is alive, and main.js carries a
   hard timeout that lifts it regardless of what the image counter
   reports. A curtain must never be able to stay down. */

.loader{display:none}

.js .loader{
  display:grid;
  position:fixed;inset:0;z-index:400;
  place-content:center;
  justify-items:center;
  gap:1.6rem;
  background:var(--ink);
  transition:clip-path 1.05s var(--ease-mask);
  clip-path:inset(0 0 0 0);
}
.js .loader.is-out{clip-path:inset(0 0 100% 0)}
.js .loader.is-done{display:none}

.loader__mark{
  font-size:clamp(1.1rem,3.4vw,2rem);
  font-weight:200;
  letter-spacing:var(--track-xl);
  text-indent:var(--track-xl);
}
.loader__meta{
  display:flex;
  align-items:baseline;
  gap:2.4rem;
  font-size:.64rem;
  letter-spacing:var(--track-lg);
  text-transform:uppercase;
  color:var(--dim);
}
.loader__pct{
  font-family:"Archivo",sans-serif;
  font-weight:700;
  font-size:.9rem;
  letter-spacing:.06em;
  color:var(--paper);
  font-variant-numeric:tabular-nums;
}
.loader__bar{
  width:min(240px,52vw);height:1px;
  background:var(--line-c);
  overflow:hidden;
}
.loader__bar span{
  display:block;height:100%;width:100%;
  background:var(--paper);
  transform:scaleX(0);
  transform-origin:left;
  transition:transform .35s linear;
}

/* ── type ───────────────────────────────────────────────── */

.wordmark{
  font-weight:200;
  letter-spacing:var(--track-xl);
  text-transform:uppercase;
  margin:0;
  /* letter-spacing leaves a trailing gap after the last glyph, so a centred
     line reads half that gap too far left. compensate by half, not all of it. */
  text-indent:calc(var(--track-xl) / 2);
}
.wordmark--sm{font-size:.8rem;letter-spacing:var(--track-lg);text-indent:calc(var(--track-lg) / 2)}
.wordmark--hero{
  font-size:clamp(2.7rem,12.5vw,10rem);
  line-height:1;
  margin:.14em 0 0;
}

/* the heavy voice: everything the brand states rather than whispers */
.display{
  margin:0;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:clamp(2.3rem,7.6vw,6.4rem);
  line-height:.94;
  letter-spacing:-.028em;
  text-transform:uppercase;
}
/* the accent needs its own hook: the line splitter wraps the whole heading in
   spans of its own, so a bare `.display span` would paint every line ember */
.display .hl{color:var(--ember)}

/* outline cut, used once so it stays an event */
.display--outline{
  color:transparent;
  -webkit-text-stroke:1px var(--fg);
  paint-order:stroke fill;
}

.eyebrow{
  margin:0 0 1.2rem;
  font-size:.66rem;
  font-weight:400;
  letter-spacing:var(--track-lg);
  text-transform:uppercase;
  color:var(--dim);
}
.idx{color:var(--ember);margin-right:.7em}

.h3{
  margin:0 0 1.2rem;
  font-family:"Archivo",sans-serif;
  font-weight:700;
  font-size:clamp(1.6rem,3.4vw,2.6rem);
  line-height:1.05;
  letter-spacing:-.02em;
  text-transform:uppercase;
}

.lede{
  color:var(--dim);
  font-size:clamp(1rem,1.5vw,1.12rem);
  max-width:46ch;
}

.note{
  margin:.9rem 0 0;
  font-size:.76rem;
  line-height:1.6;
  letter-spacing:.03em;
  color:var(--dim);
}
.note a{border-bottom:1px solid var(--line-c)}
.note a:hover{border-color:var(--ember);color:var(--fg)}

/* underlined text link with a rule that draws in from the left */
.link{
  display:inline-block;
  font-size:.7rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--fg);
}
.link span{position:relative;display:inline-block;padding-bottom:.4em}
.link span::after{
  content:"";
  position:absolute;left:0;bottom:0;
  width:100%;height:1px;
  background:currentColor;
  transform:scaleX(0);
  transform-origin:right;
  transition:transform .55s var(--ease-mask);
}
.link:hover span::after{transform:scaleX(1);transform-origin:left}

/* ── buttons ────────────────────────────────────────────── */

.btn{
  position:relative;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  padding:1.05rem 2.3rem;
  border:1px solid var(--fg);
  color:var(--fg);
  font-size:.7rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  overflow:hidden;
  z-index:0;
  transition:color .5s var(--ease),border-color .5s var(--ease);
}
/* wipe fill rather than a flat colour swap */
.btn::before{
  content:"";
  position:absolute;inset:0;z-index:-1;
  background:var(--fg);
  transform:scaleY(0);
  transform-origin:bottom;
  transition:transform .55s var(--ease-mask);
}
.btn:hover{color:var(--bg)}
.btn:hover::before{transform:scaleY(1)}

.btn--solid{background:var(--fg);color:var(--bg)}
.btn--solid::before{background:var(--bg);transform-origin:top}
.btn--solid:hover{color:var(--fg)}
.btn--solid:hover::before{transform:scaleY(1);transform-origin:bottom}

.btn--ghost{border-color:var(--line-c)}
.btn--ghost:hover{border-color:var(--fg)}

.btn--sm{padding:.72rem 1.5rem;font-size:.64rem}

/* A leaning button must never slide underneath its neighbour: with both in
   normal flow, DOM order decides who paints on top, so lift the one being
   hovered. */
.magnetic{will-change:transform;position:relative}
.magnetic:hover{z-index:2}

/* ── nav ────────────────────────────────────────────────── */

/* the fixed top block: just the nav now that the announcement line is gone */
.top{position:fixed;inset:0 0 auto;z-index:100}

.nav{
  transition:background .5s var(--ease),backdrop-filter .5s var(--ease),
             border-color .5s var(--ease);
  border-bottom:1px solid transparent;
}
.top.is-stuck .nav{
  background:rgba(6,6,6,.72);
  backdrop-filter:blur(16px) saturate(1.2);
  -webkit-backdrop-filter:blur(16px) saturate(1.2);
  border-bottom-color:var(--line-c);
}
/* get out of the way on the way down, come back on the way up */
.top.is-hidden{transform:translateY(-101%)}
.top{transition:transform .55s var(--ease)}

/* Inner pages open on a solid nav rather than a transparent one. The landing
   is the only page whose first screen is a photograph for the nav to sit on,
   and over the paper store ground a transparent nav would be invisible. */
/* the .is-stuck rule above carries one more class, so an inner page's nav has
   to match that weight or it goes translucent the moment you scroll */
.top--solid .nav,
.top--solid.is-stuck .nav{
  background:var(--ink);
  backdrop-filter:none;
  -webkit-backdrop-filter:none;
  border-bottom-color:var(--line-c);
}

/* the wordmark is the logo on the landing, so it carries a little more weight
   there than it does as a back-to-home link on an inner page */
.top--home .wordmark--sm{font-size:.95rem}

/* three tracks, so the wordmark is centred on the VIEWPORT and not merely
   placed between two runs of links that happen to differ in width */
.nav__inner{
  max-width:var(--wrap);
  margin-inline:auto;
  padding:1.1rem var(--gut);
  display:grid;
  grid-template-columns:1fr auto 1fr;
  align-items:center;
  gap:1.5rem;
}
.nav__brand{justify-self:center;grid-column:2}

.nav__links{
  grid-column:1;
  display:flex;
  gap:2.2rem;
}
.nav__side{
  grid-column:3;
  justify-self:end;
  display:flex;
  align-items:center;
  gap:1.6rem;
}
.nav__links a{
  display:block;
  height:1.25em;
  overflow:hidden;
  font-size:.68rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
/* label rolls up and is replaced by a copy of itself */
.nav__links a span{
  display:block;
  transition:transform .5s var(--ease-mask);
}
.nav__links a span::after{
  content:attr(data-label);
  position:absolute;
  left:0;top:100%;
  color:var(--paper);
}
.nav__links a:hover span{transform:translateY(-100%)}

.nav__cta{
  display:inline-flex;
  align-items:center;
  gap:.6em;
  font-size:.66rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--paper);
  white-space:nowrap;
  will-change:transform;
}
/* icon links: the reference puts account and bag here, this brand has no cart,
   so the two real order channels take that slot instead */
.nav__ico{
  display:grid;place-items:center;
  width:34px;height:34px;
  color:var(--dim);
  transition:color .35s var(--ease);
}
.nav__ico:hover{color:var(--paper)}
.nav__ico svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.5}
.nav__dot{
  width:6px;height:6px;
  border-radius:50%;
  background:var(--ember);
  animation:pulse 2.6s var(--ease) infinite;
}
@keyframes pulse{
  0%,100%{opacity:1;transform:scale(1)}
  50%{opacity:.35;transform:scale(.8)}
}

.burger{
  display:none;
  width:34px;height:34px;
  margin-left:auto;
  position:relative;
}
.burger span{
  position:absolute;left:6px;
  width:22px;height:1px;
  background:var(--paper);
  transition:transform .4s var(--ease),opacity .3s var(--ease);
}
.burger span:nth-child(1){top:14px}
.burger span:nth-child(2){top:20px}
.burger[aria-expanded="true"] span:nth-child(1){transform:translateY(3px) rotate(45deg)}
.burger[aria-expanded="true"] span:nth-child(2){transform:translateY(-3px) rotate(-45deg)}

.mobile-menu{
  position:fixed;inset:0;z-index:95;
  background:var(--ink);
  display:grid;place-items:center;
  opacity:0;
  transition:opacity .4s var(--ease);
}
.mobile-menu.is-open{opacity:1}
.mobile-menu nav{
  display:flex;flex-direction:column;
  gap:1.6rem;
  width:min(420px,80vw);
}
.mobile-menu a{
  display:flex;
  align-items:baseline;
  gap:1rem;
  font-family:"Archivo",sans-serif;
  font-weight:700;
  font-size:1.7rem;
  letter-spacing:-.01em;
  text-transform:uppercase;
}
.mobile-menu a em{
  font-family:"Inter",sans-serif;
  font-style:normal;
  font-weight:300;
  font-size:.62rem;
  letter-spacing:var(--track-md);
  color:var(--ember);
}
.mobile-menu__cta{
  margin-top:1.4rem;
  padding:1rem 0;
  border-top:1px solid var(--line-c);
  font-size:.72rem !important;
  font-family:"Inter",sans-serif !important;
  font-weight:400 !important;
  letter-spacing:var(--track-md) !important;
  color:var(--dim);
}

/* ── hero ───────────────────────────────────────────────── */

/* The landing: one full-bleed campaign frame, the wordmark at full size, the
   drop title and exactly two doors in, following the client's reference. The
   block sits a little below centre so the photograph keeps the upper frame. */
.hero{
  position:relative;
  min-height:100svh;
  display:grid;
  align-content:center;
  justify-items:center;
  text-align:center;
  padding:9rem var(--gut) clamp(5rem,14vh,9rem);
  overflow:hidden;
  /* if a photo fails to load the gradient still reads as intentional */
  background:radial-gradient(120% 80% at 50% 0%,#1b1611 0%,var(--ink) 62%);
}

/* the one move made on the photography: it opens from a centre column to full
   bleed when the loader lifts. a mask, never a filter. */
.hero__mask{position:absolute;inset:0;overflow:hidden}
.js .hero__mask{
  clip-path:inset(0 32% 0 32%);
  transition:clip-path 1.5s var(--ease-mask);
}
.js .hero__mask.is-open{clip-path:inset(0 0 0 0)}

/* The overscan exists only so the parallax has somewhere to travel without
   revealing an edge. It was 12% top and bottom, which magnified a portrait
   frame that object-fit already has to crop hard in a landscape window. Keep
   it to what the movement actually needs. */
.hero__media{position:absolute;inset:-5% 0;will-change:transform}

.hero__slide{
  position:absolute;inset:0;
  opacity:0;
  transition:opacity 2.4s var(--ease);
}
.hero__slide.is-on{opacity:1}
.hero__slide img{
  width:100%;height:100%;
  object-fit:cover;
  object-position:center 45%;
  /* The old Instagram frames needed holding right back to keep the copy
     legible. The real hero is a black and white frame that is already mostly
     dark, so it only needs a touch, and the scrim below does the rest. */
  opacity:.9;
  /* no starting scale: the source is 960x1280, so covering a wide window
     already crops it hard, and anything on top of that is pure zoom */
  transform:scale(1.015);
  animation:heroDrift 30s var(--ease) forwards;
}
@keyframes heroDrift{to{transform:scale(1)}}

/* just enough to seat the type: dark at the very top under the nav, dark again
   at the bottom where the page continues, and largely out of the way between */
.hero__scrim{
  position:absolute;inset:0;
  background:
    linear-gradient(to bottom,rgba(6,6,6,.62) 0%,rgba(6,6,6,.12) 32%,rgba(6,6,6,.3) 62%,var(--ink) 98%),
    radial-gradient(64% 52% at 50% 52%,rgba(6,6,6,.42) 0%,transparent 78%);
}

/* the wordmark is sized against the viewport, not a text column, so the body
   is unconstrained and the prose inside carries its own measure */
.hero__body{position:relative;z-index:2;width:100%}

.hero__eyebrow{
  margin:0;
  font-size:.66rem;
  letter-spacing:var(--track-lg);
  text-transform:uppercase;
  color:var(--dim);
}

.hero__rule{
  width:min(360px,52vw);
  height:1px;
  margin:1.9rem auto 1.5rem;
  background:var(--line-c);
  overflow:hidden;
}
.hero__rule span{
  display:block;height:100%;width:100%;
  background:var(--ember);
  transform:scaleX(0);
  transform-origin:left;
  animation:ruleIn 1.4s var(--ease-mask) 1.1s forwards;
}
@keyframes ruleIn{to{transform:scaleX(1)}}

.hero__drop{
  margin:0 auto 1.8rem;
  font-family:"Archivo",sans-serif;
  font-size:clamp(.86rem,2.1vw,1.25rem);
  font-weight:700;
  letter-spacing:var(--track-lg);
  text-transform:uppercase;
  color:var(--paper);
}

/* side by side, and they stay side by side on a phone: the reference puts
   both doors on one line and that is the whole shape of the landing */
.hero__actions{
  display:flex;
  gap:1.1rem;
  justify-content:center;
}
.hero__actions .btn{min-width:clamp(8rem,26vw,11rem)}

.hero__foot{
  position:absolute;
  left:0;right:0;bottom:1.6rem;
  z-index:2;
  padding-inline:var(--gut);
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:1rem;
}
.hero__coord{
  font-size:.6rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}

.hero__scroll{width:1px;height:40px;overflow:hidden;flex:none}
.hero__scroll-line{
  display:block;width:1px;height:100%;
  background:var(--paper-dim);
  animation:scrollLine 2.4s var(--ease) infinite;
}
@keyframes scrollLine{
  0%{transform:translateY(-100%)}
  60%,100%{transform:translateY(100%)}
}

/* ── ticker ─────────────────────────────────────────────── */

.marquee{
  border-block:1px solid var(--line-c);
  padding:1.15rem 0;
  overflow:hidden;
  white-space:nowrap;
  background:var(--ink);
}
.marquee__track{
  display:inline-flex;
  align-items:center;
  gap:2.6rem;
  padding-left:2.6rem;
  will-change:transform;
}
.marquee span{
  font-family:"Archivo",sans-serif;
  font-size:.76rem;
  font-weight:700;
  letter-spacing:var(--track-lg);
  text-transform:uppercase;
  color:var(--dim);
}
.marquee i{color:var(--ember);font-size:.5rem;font-style:normal}

/* drifts on CSS alone; main.js switches this off only once it takes over, so a
   failed script leaves a moving ticker rather than a dead one */
.marquee__track{animation:slide 40s linear infinite}
@keyframes slide{to{transform:translateX(-50%)}}

/* ── the promise ────────────────────────────────────────────
   Three stanzas across, then the finale on its own. Each stanza
   sets up in dim type and lands on a bright line, which is the
   shape of the writing rather than a decision made about it. */

.creed{padding:clamp(4.5rem,11vw,8rem) 0 clamp(4rem,9vw,7rem)}

.creed__set{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:clamp(2rem,4vw,3.5rem);
  padding-top:clamp(1.5rem,3vw,2.5rem);
  border-top:1px solid var(--line-c);
}
.creed__stanza{
  margin:0;
  font-size:clamp(1rem,1.5vw,1.14rem);
  line-height:1.5;
}
.creed__stanza span{display:block;color:var(--dim)}
.creed__stanza b{
  display:block;
  margin-top:.7rem;
  font-weight:500;
  color:var(--fg);
}

.creed__end{
  margin-top:clamp(3.5rem,8vw,6rem);
  padding-top:clamp(2rem,4vw,3rem);
  border-top:1px solid var(--line-c);
  display:grid;
  gap:clamp(1.5rem,3vw,2.2rem);
  justify-items:center;
  text-align:center;
}
.creed__lines{
  margin:0;
  font-size:clamp(1.05rem,1.9vw,1.35rem);
  line-height:1.65;
}
.creed__lines span{display:block;color:var(--dim)}
.creed__lines span:last-child{color:var(--fg)}

.creed__welcome{
  margin:0;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:clamp(1.9rem,6vw,4.4rem);
  line-height:1;
  letter-spacing:-.03em;
  text-transform:uppercase;
}

/* ============================================================
   SHOP  ·  the inverted block
   ============================================================ */

.shop{
  --bg:var(--paper);
  --fg:var(--ink);
  --dim:#6d675e;
  --line-c:rgba(6,6,6,.16);
  background:var(--bg);
  color:var(--fg);
  padding:clamp(4.5rem,11vw,8.5rem) 0 clamp(5rem,12vw,9rem);
}
.shop ::selection{background:var(--ink);color:var(--paper)}

.shop__head{margin-bottom:clamp(2.6rem,5vw,4.2rem)}

.shop__headmeta{
  margin-top:clamp(1.8rem,3vw,2.6rem);
  padding-top:1.5rem;
  border-top:1px solid var(--line-c);
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:2rem;
}
.shop__headmeta p{margin:0;max-width:44ch;font-size:.92rem;color:var(--dim)}
.shop__count{
  flex:none;
  font-size:.66rem !important;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
}
.shop__count em{
  font-family:"Archivo",sans-serif;
  font-style:normal;
  font-weight:900;
  font-size:1.5rem;
  letter-spacing:-.02em;
  color:var(--fg);
  margin-right:.4em;
}

.shop__grid{
  display:grid;
  grid-template-columns:repeat(4,1fr);
  gap:clamp(2rem,3vw,2.6rem) clamp(1rem,1.8vw,1.6rem);
  align-items:start;
}

/* ── product card ───────────────────────────────────────── */

.card{position:relative}

.card__media{
  position:relative;
  display:block;
  aspect-ratio:4/5;
  overflow:hidden;
  background:linear-gradient(150deg,#d8d3c9,#c9c3b8);
}
.card__img{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
  transition:transform 1.3s var(--ease),opacity .7s var(--ease);
}
/* second frame crossfades under the pointer, the standard store tell that a
   card has more than one photo behind it */
.card__img--alt{opacity:0}
.card__media:hover .card__img{transform:scale(1.06)}
.card__media:hover .card__img--alt{opacity:1}

.card__badge{
  position:absolute;top:0;left:0;z-index:2;
  padding:.5rem .8rem;
  background:var(--ink);
  color:var(--paper);
  font-size:.56rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
}
.card__badge--tbc{background:transparent;color:var(--ink);border:1px dashed rgba(6,6,6,.45)}

.card__no{
  position:absolute;top:.55rem;right:.8rem;z-index:2;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:.8rem;
  letter-spacing:-.02em;
  color:rgba(255,255,255,.85);
  mix-blend-mode:difference;
}

/* quick look is an enhancement: no scripting, no button, the native
   <details> under the card carries the same content */
.card__open{
  position:absolute;left:0;right:0;bottom:0;z-index:2;
  display:none;
  padding:.95rem 1rem;
  background:var(--ink);
  color:var(--paper);
  font-size:.62rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  transform:translateY(100%);
  transition:transform .45s var(--ease-mask);
}
.js .card__open{display:block}
.card__media:hover .card__open,
.card__open:focus-visible{transform:none}

.card__row{
  display:flex;
  justify-content:space-between;
  align-items:baseline;
  gap:1rem;
  margin-top:1.1rem;
}
.card__name{
  margin:0;
  font-size:.74rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
}
.card__name em{font-style:normal;color:var(--dim)}
.card__price{
  margin:0;
  flex:none;
  font-size:.66rem;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--dim);
}
.card__sub{
  margin:.45rem 0 0;
  font-size:.76rem;
  color:var(--dim);
}
.card__name a:hover{color:var(--ember)}

/* sizing help block under the shop grid */
.shop__foot{
  display:grid;
  grid-template-columns:1.2fr .8fr;
  align-items:center;
  clear:both;
  gap:clamp(1.5rem,3vw,3rem);
  margin-top:clamp(3rem,6vw,5rem);
  padding-top:clamp(2rem,4vw,3rem);
  border-top:1px solid var(--line-c);
}
.shop__foot p{margin:0;max-width:42ch;font-size:.92rem;color:var(--dim)}
.shop__footcta{display:flex;flex-wrap:wrap;gap:.9rem;justify-content:flex-end}

.shop__more{margin:clamp(2.2rem,4vw,3rem) 0 0}

/* the three-up ethos summary on the landing. the long version, with the
   sticky stack, is the /ethos/ page. */
.brief{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:clamp(1.6rem,3vw,3rem);
  padding-top:clamp(1.5rem,3vw,2.5rem);
  border-top:1px solid var(--line-c);
}
.brief__no{
  display:block;
  margin-bottom:.9rem;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:.72rem;
  color:var(--ember);
}
.brief__col h3{
  margin:0 0 .6rem;
  font-family:"Archivo",sans-serif;
  font-weight:700;
  font-size:clamp(1rem,1.7vw,1.25rem);
  letter-spacing:-.01em;
  text-transform:uppercase;
}
.brief__col p{margin:0;font-size:.9rem;color:var(--dim)}

/* No product photography yet. An empty frame that says so beats borrowing a
   lookbook shot and letting it read as the product: these pieces are shot on
   a body in the field, which is not what a shop card is for. Drop an <img>
   back into .card__media and this disappears on its own. */
/* A piece added in the dashboard before it has been photographed. It keeps
   the card's shape so the grid does not jump when the photograph lands, and
   it is scoped to its own class rather than a bare span so .card__no and
   .card__open keep their own styling. */
.card__soon{
  display:grid;
  place-items:center;
  aspect-ratio:4/5;
  border:1px dashed var(--line-c);
  background:rgba(0,0,0,.025);
  font-size:.6rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}

.card__media--empty{
  display:grid;
  place-items:center;
  gap:.6rem;
  border:1px dashed var(--line-c);
  background:rgba(0,0,0,.025);
  text-align:center;
  padding:1.5rem;
}
.card__media--empty span{
  font-size:.6rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.card__media--empty svg{
  width:34px;height:34px;
  fill:none;stroke:var(--dim);stroke-width:1.2;
  opacity:.5;
}
.card__media--empty .card__badge{position:static;background:none;color:var(--dim);padding:0}
.card__media--empty:hover{border-color:var(--fg)}

/* native <details>, the no-JS path. main.js hides these and routes the same
   nodes into the overlay instead. */
.js .card__more{display:none}
.card__more{margin-top:1rem;border-top:1px solid var(--line-c)}
.card__more summary{
  list-style:none;
  cursor:pointer;
  padding:.9rem 0;
  font-size:.64rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.card__more summary::-webkit-details-marker{display:none}

/* ── product panel (shared by <details> and the overlay) ── */

.panel{padding:.4rem 0 1.6rem}

.panel__label{
  margin:2rem 0 .9rem;
  font-size:.64rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--fg);
}
.panel__label:first-child{margin-top:0}
.panel__label em{font-style:normal;font-weight:300;color:var(--dim);text-transform:none;letter-spacing:.02em}

.panel__sizes .note{margin-top:.8rem}

/* ── the sizer ──────────────────────────────────────────────
   The client's reference showed a fit scale: a row of marks with
   one filled. This is that scale turned into the control. Press
   a mark to take that size, and because the marks run small to
   large left to right, the thing that reports the fit and the
   thing that sets it are the same object. */

.sizer{margin:1.8rem 0}
.sizer__head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:1rem;
}
.sizer__head .panel__label{margin:0}
.sizer__guide{
  font-size:.6rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
  border-bottom:1px solid var(--line-c);
  padding-bottom:2px;
}
.sizer__guide:hover{color:var(--fg);border-color:var(--fg)}

.chips{display:grid;grid-template-columns:repeat(5,1fr);gap:.5rem;margin-top:.9rem}

/* the whole button is a hit area; only the mark inside it is drawn, so the
   marks stay the thin rules of the reference while staying easy to press */
.chip{
  display:grid;
  align-content:center;
  padding:.7rem 0;
  border:0;
  background:none;
  min-width:0;
  cursor:pointer;
}
.chip__bar{
  display:block;
  height:3px;
  background:rgba(6,6,6,.16);
  transition:background .3s var(--ease),height .25s var(--ease);
}
.chip:hover .chip__bar{background:rgba(6,6,6,.42)}

/* the filled mark, exactly as the reference reads it */
.chip.is-on .chip__bar{background:var(--fg);height:5px}

/* three labels across the row, not one per mark: the marks are a continuum
   and the labels name its ends and its middle */
.sizer__labels{
  display:flex;
  justify-content:space-between;
  gap:1rem;
  font-size:.6rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.sizer__labels span:nth-child(2){text-align:center}
.sizer__labels span:nth-child(3){text-align:right}

.sizer__fit [data-size-out]{color:var(--dim)}
.sizer__fit{
  margin:1.1rem 0 0;
  font-size:.74rem;
  letter-spacing:.02em;
  color:var(--dim);
}
.sizer__fit b{font-weight:500;color:var(--fg)}

/* an accessible name for each mark, since the visible labels only cover three
   of the five positions */
.sr-only{
  position:absolute;
  width:1px;height:1px;
  margin:-1px;padding:0;
  overflow:hidden;
  clip:rect(0 0 0 0);
  white-space:nowrap;
  border:0;
}

.panel__actions{
  margin-top:1.6rem;
  display:flex;
  flex-wrap:wrap;
  gap:.9rem;
}
/* the order label must never wrap: "Order on WhatsApp" breaking across two
   lines is the difference between a store and a draft */
.panel__actions .btn{flex:1 1 11rem;padding-inline:1.3rem;white-space:nowrap}

.specs{margin:0;padding:0;border-top:1px solid var(--line-c)}
.specs>div{
  display:flex;
  justify-content:space-between;
  gap:1.5rem;
  padding:.85rem 0;
  border-bottom:1px solid var(--line-c);
}
.specs dt{
  font-size:.64rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.specs dd{margin:0;font-size:.86rem;text-align:right}

.sizes{width:100%;border-collapse:collapse;font-size:.82rem}
.sizes th{
  font-size:.6rem;
  font-weight:400;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
  text-align:left;
  padding:.5rem .6rem;
  border-bottom:1px solid var(--line-c);
}
.sizes td{padding:.55rem .6rem;border-bottom:1px solid var(--line-c)}
/* measurements are unconfirmed: dashed flag, same convention as the quotes */
.sizes.is-placeholder{border:1px dashed var(--line-c);opacity:.8}

.care{margin:0;padding:0;list-style:none}
.care li{
  position:relative;
  padding:.55rem 0 .55rem 1.2rem;
  font-size:.85rem;
  color:var(--dim);
  border-bottom:1px solid var(--line-c);
}
.care li::before{
  content:"";
  position:absolute;left:0;top:1.05em;
  width:4px;height:4px;
  background:var(--ember);
}

body.is-locked{overflow:hidden}

/* ============================================================
   CART
   No accounts, no card fields. The cart is local, and checkout
   composes the whole order as a WhatsApp message.
   ============================================================ */

/* the bag lives in the nav and is injected by cart.js, because a cart with no
   scripting is not a cart and there is no markup fallback to write */
.bag{
  position:relative;
  display:grid;place-items:center;
  width:34px;height:34px;
  color:var(--dim);
  transition:color .35s var(--ease);
}
.bag:hover{color:var(--paper)}
.bag svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linejoin:round}
.bag__n{
  position:absolute;top:-2px;right:-4px;
  min-width:16px;height:16px;
  padding:0 4px;
  border-radius:9px;
  background:var(--ember);
  color:var(--ink);
  font-size:.56rem;
  font-weight:500;
  line-height:16px;
  text-align:center;
}
.bag__n[hidden]{display:none}

.cart{position:fixed;inset:0;z-index:395}
.cart[hidden]{display:none}

.cart__scrim{
  position:absolute;inset:0;
  background:rgba(6,6,6,.55);
  backdrop-filter:blur(5px);
  -webkit-backdrop-filter:blur(5px);
  opacity:0;
  transition:opacity .45s var(--ease);
}
.cart.is-open .cart__scrim{opacity:1}

/* the cart is part of the store, so it takes the paper ground with it */
.cart__panel{
  --bg:var(--paper);
  --fg:var(--ink);
  --dim:#6d675e;
  --line-c:rgba(6,6,6,.16);
  position:absolute;top:0;right:0;
  width:min(460px,100%);
  height:100%;
  display:flex;
  flex-direction:column;
  background:var(--bg);
  color:var(--fg);
  transform:translateX(100%);
  transition:transform .55s var(--ease-mask);
}
.cart.is-open .cart__panel{transform:none}

.cart__head{
  flex:none;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:1rem;
  padding:1.4rem clamp(1.2rem,3vw,1.8rem);
  border-bottom:1px solid var(--line-c);
}
.cart__head h2{
  margin:0;
  font-size:.72rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
}
.cart__head span{color:var(--dim)}

.cart__close{
  position:relative;
  width:34px;height:34px;
  flex:none;
}
.cart__close span{
  position:absolute;left:8px;top:16px;
  width:18px;height:1px;
  background:var(--fg);
}
.cart__close span:nth-child(1){transform:rotate(45deg)}
.cart__close span:nth-child(2){transform:rotate(-45deg)}

.cart__body{
  flex:1 1 auto;
  overflow-y:auto;
  overscroll-behavior:contain;
  padding:clamp(1.2rem,3vw,1.8rem);
}

.cart__list{list-style:none;margin:0;padding:0;display:grid;gap:1.2rem}
.cart__empty{margin:.5rem 0 0;font-size:.9rem;color:var(--dim)}
.cart__empty[hidden]{display:none}

.cart__item{
  display:grid;
  grid-template-columns:72px 1fr auto;
  gap:1rem;
  align-items:start;
  padding-bottom:1.2rem;
  border-bottom:1px solid var(--line-c);
}
.cart__thumb{display:block;aspect-ratio:4/5;overflow:hidden;background:#d8d3c9}
.cart__thumb img{width:100%;height:100%;object-fit:cover}
/* until the product shots land */
.cart__thumb--empty{background:none;border:1px dashed var(--line-c)}

.cart__name{
  display:block;
  font-size:.72rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
}
.cart__name:hover{color:var(--ember)}
.cart__meta{margin:.35rem 0 .7rem;font-size:.76rem;color:var(--dim)}
.cart__line{margin:0;font-size:.76rem;white-space:nowrap}

.cart__qty{display:flex;align-items:center;gap:.5rem}
.cart__qty button{
  width:26px;height:26px;
  border:1px solid var(--line-c);
  font-size:.85rem;
  line-height:1;
  transition:border-color .3s var(--ease),background .3s var(--ease);
}
.cart__qty button:hover{border-color:var(--fg)}
.cart__qty span{min-width:1.4rem;text-align:center;font-size:.8rem}
.cart__del{
  width:auto !important;
  margin-left:.4rem;
  border:0 !important;
  font-size:.62rem !important;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.cart__del:hover{color:var(--fg)}

.cart__keep{margin:1.4rem 0 0;font-size:.72rem;letter-spacing:var(--track-md);text-transform:uppercase}
.cart__keep[hidden]{display:none}
.cart__keep a{border-bottom:1px solid var(--line-c);padding-bottom:2px;color:var(--dim)}
.cart__keep a:hover{color:var(--fg);border-color:var(--fg)}

.cart__foot{
  flex:none;
  padding:clamp(1.2rem,3vw,1.6rem);
  border-top:1px solid var(--line-c);
  background:var(--bg);
}
.cart__total{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:1rem;
  margin-bottom:1rem;
  font-size:.66rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.cart__total strong{
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:1.1rem;
  letter-spacing:-.01em;
  color:var(--fg);
  text-transform:none;
}
.cart__send{width:100%}
.cart__send[aria-disabled="true"],
.sum__send[aria-disabled="true"]{opacity:.4;pointer-events:none}

/* ============================================================
   checkout page
   ============================================================ */

.checkout{padding-bottom:clamp(3rem,7vw,5rem)}
.checkout .page-head{padding-bottom:clamp(1.5rem,3vw,2.5rem)}

.checkout__empty{
  padding:clamp(2rem,4vw,3rem);
  border:1px dashed var(--line-c);
  max-width:44rem;
}
.checkout__empty[hidden]{display:none}
.checkout__empty p{margin:0 0 1.8rem;color:var(--dim);max-width:40ch}

.checkout__grid{
  display:grid;
  grid-template-columns:1.35fr .65fr;
  gap:clamp(2rem,4vw,3.5rem);
  align-items:start;
}
.checkout__grid[hidden]{display:none}

.checkout__main{display:grid;gap:clamp(2rem,4vw,3rem)}

/* the wide list has room for a per-line total, the drawer does not */
.cart__list--wide{border-top:1px solid var(--line-c);padding-top:1.4rem}
.cart__list--wide .cart__item{grid-template-columns:88px 1fr auto}

.checkout__keep{margin:1.4rem 0 0}

.checkout__details label{
  display:block;
  margin-bottom:.4rem;
  font-size:.58rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.checkout__details label span{text-transform:none;letter-spacing:.02em}
.checkout__details input,.checkout__details textarea{
  width:100%;
  padding:.8rem .9rem;
  border:1px solid var(--line-c);
  background:transparent;
  color:var(--fg);
  font:inherit;
  font-size:.9rem;
  border-radius:0;
  transition:border-color .3s var(--ease);
}
.checkout__details input:focus,.checkout__details textarea:focus{outline:none;border-color:var(--fg)}
.checkout__details textarea{min-height:6rem;resize:vertical}
.checkout__details .note{margin:0 0 1.4rem}
.rform__row--three{margin-bottom:1.2rem}

/* the summary follows you down the page */
.sum{
  position:sticky;
  top:7rem;
  padding:clamp(1.4rem,2.6vw,2rem);
  border:1px solid var(--line-c);
  background:rgba(0,0,0,.02);
}
.sum__rows{margin-bottom:1.4rem}
.sum__row{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:1rem;
  padding:.6rem 0;
  font-size:.8rem;
  color:var(--dim);
  border-bottom:1px solid var(--line-c);
}
.sum__row--big{
  border-bottom:0;
  padding-top:1rem;
  font-size:.66rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
}
.sum__row--big strong{
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:1.2rem;
  letter-spacing:-.01em;
  color:var(--fg);
  text-transform:none;
}
.sum__send{width:100%;cursor:pointer}
.sum__note{margin:1.2rem 0 0;font-size:.74rem;line-height:1.55;color:var(--dim)}
.sum__alt{margin:.9rem 0 0;font-size:.74rem;color:var(--dim)}
.sum__alt a,.sum__copy{border-bottom:1px solid var(--line-c)}
.sum__alt a:hover,.sum__copy:hover{color:var(--fg);border-color:var(--fg)}
.sum__copy{
  padding:0;
  font:inherit;
  font-size:.74rem;
  color:var(--dim);
}

/* what happens after the send button: WhatsApp opens in another tab, so this
   panel is the only thing left on screen to say the order is not finished
   until it is actually sent there */
.sent{
  margin-top:1.2rem;
  padding:1.1rem 1.2rem;
  border-left:2px solid var(--ember);
  background:rgba(200,129,60,.07);
}
.sent[hidden]{display:none}
.sent__t{
  margin:0 0 .5rem;
  font-size:.62rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
}
.sent p{margin:0;font-size:.8rem;line-height:1.55;color:var(--dim)}
.sent__acts{display:flex;flex-wrap:wrap;gap:.7rem;margin-top:1rem}
.sent__acts .btn{flex:1 1 8rem}
.sent__clear{
  margin-top:.9rem;
  padding:0;
  font-size:.68rem;
  letter-spacing:.03em;
  color:var(--dim);
  border-bottom:1px solid var(--line-c);
}
.sent__clear:hover{color:var(--fg);border-color:var(--fg)}
.cart__err{
  margin:0 0 .8rem;
  font-size:.78rem;
  color:#b4472f;
}
.cart__err[hidden]{display:none}
.cart__note{margin:.9rem 0 0;font-size:.7rem;line-height:1.5;color:var(--dim)}

/* ── buying row on a product page ───────────────────────── */


/* unavailable: the mark goes dashed instead of solid and cannot be pressed */
.chip.is-out{cursor:not-allowed}
.chip.is-out .chip__bar{
  background:none;
  height:0;
  border-top:2px dashed rgba(6,6,6,.28);
}
.chip.is-out:hover .chip__bar{background:none}

/* asks for a size when someone adds without picking one */
@keyframes ask{
  0%,100%{transform:translateX(0)}
  20%{transform:translateX(-5px)}
  40%{transform:translateX(5px)}
  60%{transform:translateX(-3px)}
  80%{transform:translateX(3px)}
}
.chips.is-asking{animation:ask .45s var(--ease)}

.buy{
  display:grid;
  grid-template-columns:auto 1fr;
  gap:.7rem;
  margin-top:1.6rem;
}
.qty{
  display:flex;
  align-items:center;
  border:1px solid var(--fg);
}
.qty button{
  width:44px;height:100%;
  font-size:1rem;
  line-height:1;
  transition:background .3s var(--ease),color .3s var(--ease);
}
.qty button:hover{background:var(--fg);color:var(--bg)}
.qty span{
  min-width:2.4rem;
  text-align:center;
  font-size:.85rem;
  font-variant-numeric:tabular-nums;
}
.buy .btn{width:100%}
.buy__err{
  grid-column:1/-1;
  margin:.2rem 0 0;
  font-size:.76rem;
  color:#b4472f;
}
.buy__err[hidden]{display:none}

.pdp__alt{
  margin-top:1rem;
  font-size:.76rem;
  color:var(--dim);
}
.pdp__alt a{border-bottom:1px solid var(--line-c)}
.pdp__alt a:hover{border-color:var(--fg);color:var(--fg)}

/* ============================================================
   inner pages
   Every page except the landing opens under a solid nav and a
   page head, so the top of a page always tells you where you are.
   ============================================================ */

/* clears the fixed nav, and keeps the last block off the footer */
.page{padding-top:5rem;padding-bottom:clamp(3rem,7vw,5rem)}

.page-head{padding:clamp(2.5rem,6vw,4.5rem) 0 clamp(2rem,4vw,3rem)}
.page-head .display{margin-top:.4rem}
.page-head__meta{
  margin:clamp(1.6rem,3vw,2.4rem) 0 0;
  padding-top:1.4rem;
  border-top:1px solid var(--line-c);
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:2rem;
  flex-wrap:wrap;
}
.page-head__meta p{margin:0;max-width:48ch;font-size:.95rem;color:var(--dim)}
.page-head__count{
  flex:none;
  font-size:.64rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.page-head__count em{
  font-family:"Archivo",sans-serif;
  font-style:normal;
  font-weight:900;
  font-size:1.5rem;
  letter-spacing:-.02em;
  color:var(--fg);
  margin-right:.4em;
}

/* the paper ground is the store: /shop/ and every product page */
.store{
  --bg:var(--paper);
  --fg:var(--ink);
  --dim:#6d675e;
  --line-c:rgba(6,6,6,.16);
  background:var(--bg);
  color:var(--fg);
}
.store ::selection{background:var(--ink);color:var(--paper)}

.crumbs{
  display:flex;
  align-items:center;
  gap:1.2rem;
  flex-wrap:wrap;
  font-size:.62rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.crumbs a:hover{color:var(--fg)}
.crumbs i{font-style:normal;opacity:.5;margin-inline:.5rem}
.crumbs__back{
  color:var(--fg);
  border-bottom:1px solid var(--line-c);
  padding-bottom:2px;
}
.crumbs__back:hover{border-color:var(--fg)}
.crumbs__trail{display:flex;align-items:center;flex-wrap:wrap}

/* ============================================================
   product page
   ============================================================ */

.pdp{padding-bottom:clamp(3rem,7vw,5rem)}

.pdp__grid{
  display:grid;
  grid-template-columns:1.12fr .88fr;
  gap:clamp(2rem,4vw,4rem);
  align-items:start;
  padding-top:clamp(1.5rem,3vw,2.5rem);
}

.pdp__media{display:grid;gap:clamp(.5rem,1vw,.9rem)}
.pdp__shot{
  margin:0;
  position:relative;
  aspect-ratio:4/5;
  overflow:hidden;
  background:linear-gradient(150deg,#d8d3c9,#c9c3b8);
}
.pdp__shot img{width:100%;height:100%;object-fit:cover}
.pdp__shot--wide{aspect-ratio:4/3}
/* the product photography is shot 3:4, so the frame matches it and nothing
   gets cropped off the top or the bottom of the piece */
.pdp__shot--photo{aspect-ratio:3/4}

/* no product shots yet, so the column says so rather than borrowing a
   lookbook frame and letting it read as the product */
.pdp__shot--empty{
  display:grid;
  place-items:center;
  align-content:center;
  gap:1.1rem;
  aspect-ratio:4/5;
  padding:clamp(1.5rem,4vw,3rem);
  border:1px dashed var(--line-c);
  background:rgba(0,0,0,.025);
  text-align:center;
}
.pdp__shot--empty svg{
  width:52px;height:52px;
  fill:none;stroke:var(--dim);stroke-width:1.1;
  opacity:.5;
}
.pdp__shot--empty figcaption{
  max-width:34ch;
  font-size:.82rem;
  line-height:1.6;
  color:var(--dim);
}
.pdp__shot--empty a{border-bottom:1px solid var(--line-c)}
.pdp__shot--empty a:hover{color:var(--fg);border-color:var(--fg)}

/* the buying column follows you down the photographs */
.pdp__panel{position:sticky;top:7rem}

.pdp__eyebrow{
  margin:0 0 .9rem;
  font-size:.6rem;
  letter-spacing:var(--track-lg);
  text-transform:uppercase;
  color:var(--ember);
}
.pdp__name{
  margin:0;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:clamp(1.7rem,3.4vw,2.7rem);
  line-height:.98;
  letter-spacing:-.028em;
  text-transform:uppercase;
}
.pdp__name em{font-style:normal;color:var(--dim)}
.pdp__price{
  margin:.9rem 0 1.8rem;
  padding-bottom:1.6rem;
  border-bottom:1px solid var(--line-c);
  font-size:.72rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.pdp__lede{margin:0 0 1.8rem;font-size:.95rem;color:var(--dim);max-width:44ch}

.pdp__tax{margin:.6rem 0 0;font-size:.74rem;color:var(--dim);max-width:38ch}

/* the thumbnail rail under the main frame, empty until there are shots */
.pdp__thumbs{
  display:grid;
  grid-template-columns:repeat(4,1fr);
  gap:.5rem;
  margin-top:.6rem;
  max-width:22rem;
}
.pdp__thumb{
  display:block;
  aspect-ratio:1;
  padding:0;
  overflow:hidden;
  border:1px dashed var(--line-c);
  background:rgba(0,0,0,.02);
  transition:border-color .3s var(--ease),opacity .3s var(--ease);
}
/* a real thumbnail is a button with a shot in it, and it is pressable */
button.pdp__thumb{cursor:pointer;opacity:.62}
button.pdp__thumb:hover{opacity:1;border-color:var(--fg)}
.pdp__thumb img{width:100%;height:100%;object-fit:cover;display:block}
.pdp__thumb.is-on{border-style:solid;border-color:var(--fg);opacity:1}

/* the main frame walks forward when there is somewhere to walk to */
.pdp__shot.is-gallery{cursor:pointer}

/* a second, quieter full-width action under the primary one */
.btn--line{
  border-color:var(--fg);
  background:none;
}
.buy__alt{width:100%;margin-top:.7rem}

/* description as labelled lines rather than a table: it reads faster and it
   does not pretend there is more spec than there is */
.pdp__desc{
  margin-top:clamp(1.8rem,3vw,2.4rem);
  padding-top:clamp(1.5rem,3vw,2rem);
  border-top:1px solid var(--line-c);
}
.pdp__desc>p{margin:0 0 1.3rem;font-size:.95rem;color:var(--dim);max-width:46ch}
.facts{margin:0;display:grid;gap:.45rem}
.facts>div{display:flex;gap:.5rem;font-size:.86rem}
.facts dt{color:var(--dim)}
.facts dt::after{content:":"}
.facts dd{margin:0}

/* accordions: the long copy folded away so the buying column stays short */
.acc{margin-top:clamp(1.8rem,3vw,2.4rem);border-top:1px solid var(--line-c)}
.acc__item{border-bottom:1px solid var(--line-c)}
.acc__item summary{
  list-style:none;
  cursor:pointer;
  padding:1.1rem 0;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:1.5rem;
  font-size:.68rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  transition:color .3s var(--ease);
}
.acc__item summary::-webkit-details-marker{display:none}
.acc__item summary::after{
  content:"";
  flex:none;
  width:9px;height:9px;
  border-right:1px solid currentColor;
  border-bottom:1px solid currentColor;
  transform:translateY(-2px) rotate(45deg);
  transition:transform .35s var(--ease);
}
.acc__item[open] summary::after{transform:translateY(2px) rotate(-135deg)}
.acc__item summary:hover{color:var(--ember)}
.acc__item>div{padding:0 0 1.6rem}
.acc__item .note:first-child{margin-top:0}

/* the rest of the drop, at the foot of a product page */
.also{
  margin-top:clamp(3rem,6vw,5rem);
  padding-top:clamp(2rem,4vw,3rem);
  border-top:1px solid var(--line-c);
}
.also__grid{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:clamp(1rem,2vw,1.6rem);
  margin-top:1.4rem;
}
.also__card{display:grid;gap:.7rem}
.also__frame{
  display:block;
  overflow:hidden;
  aspect-ratio:4/5;
  background:rgba(0,0,0,.02);
  transition:opacity .35s var(--ease);
}
.also__frame img{width:100%;height:100%;object-fit:cover;display:block}
.also__card:hover .also__frame{opacity:.86}
.also__frame svg{width:30px;height:30px;fill:none;stroke:var(--dim);stroke-width:1.2;opacity:.5}
.also__card:hover .also__frame{border-color:var(--fg)}
.also__name{
  font-size:.72rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
}
.also__price{font-size:.7rem;color:var(--dim)}

/* the unreleased pieces. dashed everywhere, per the repo convention that a
   placeholder must never be able to read as a finished product. */
.pdp__shot--tbc{outline:1px dashed var(--line-c);outline-offset:-1px}
.pdp__shot--tbc img{filter:grayscale(1);opacity:.55}
.pdp__shot--tbc figcaption{
  position:absolute;left:0;bottom:0;
  padding:.5rem .8rem;
  background:var(--bg);
  font-size:.58rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.specs--tbc dd{color:var(--dim)}
.tbc-note{
  margin:0 0 1.8rem;
  padding:1.1rem 1.2rem;
  border:1px dashed var(--line-c);
}
.tbc-note p{margin:0;font-size:.86rem;color:var(--dim)}

/* the long-form blocks under the two columns */
.pdp__detail{
  display:grid;
  grid-template-columns:repeat(2,1fr);
  gap:clamp(2rem,4vw,3.5rem);
  margin-top:clamp(3rem,6vw,5rem);
  padding-top:clamp(2rem,4vw,3rem);
  border-top:1px solid var(--line-c);
}

/* ── reviews ────────────────────────────────────────────── */

.reviews{
  margin-top:clamp(3rem,6vw,5rem);
  padding-top:clamp(2rem,4vw,3rem);
  border-top:1px solid var(--line-c);
}
.reviews__head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:1.5rem;
  flex-wrap:wrap;
  margin-bottom:1.8rem;
}
.reviews__act{display:flex;align-items:baseline;gap:1.2rem;flex-wrap:wrap}
.reviews__act .btn{flex:none}

.rform__lead{
  margin:0 0 1.3rem;
  font-size:.8rem;
  color:var(--dim);
}
.reviews__head h2{
  margin:0;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:clamp(1.4rem,2.6vw,2rem);
  letter-spacing:-.02em;
  text-transform:uppercase;
}
.reviews__grid{
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,20rem),1fr));
  gap:clamp(.8rem,1.6vw,1.2rem);
}

.review{
  margin:0;
  padding:1.5rem 1.4rem;
  border:1px solid var(--line-c);
  background:rgba(0,0,0,.02);
}
.review blockquote{margin:0 0 1.1rem;font-size:.95rem;line-height:1.55}
.review figcaption{
  font-size:.62rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.review__stars{
  display:block;
  margin-bottom:.8rem;
  font-size:.75rem;
  letter-spacing:.25em;
  color:var(--ember);
}
.review__stars span{opacity:.28}

/* the empty state is not an error: a drop with no reviews yet should say so
   and then ask, rather than showing a blank rectangle */
.reviews__empty{
  padding:1.8rem 1.5rem;
  border:1px dashed var(--line-c);
  font-size:.9rem;
  color:var(--dim);
}

.rform{
  margin-top:clamp(1.6rem,3vw,2.4rem);
  padding:clamp(1.4rem,2.6vw,2rem);
  border:1px solid var(--line-c);
}
.rform h3{
  margin:0 0 1.3rem;
  font-size:.66rem;
  font-weight:500;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
}
.rform__row{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:.8rem;
  margin-bottom:.8rem;
}
.rform label{
  display:block;
  margin-bottom:.4rem;
  font-size:.58rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
.rform input,.rform select,.rform textarea{
  width:100%;
  padding:.75rem .8rem;
  border:1px solid var(--line-c);
  background:transparent;
  color:var(--fg);
  font:inherit;
  font-size:.88rem;
  border-radius:0;
  transition:border-color .3s var(--ease);
}
.rform input:focus,.rform select:focus,.rform textarea:focus{
  outline:none;
  border-color:var(--fg);
}
.rform textarea{min-height:7rem;resize:vertical}
.rform__foot{
  margin-top:1.1rem;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:1rem;
  flex-wrap:wrap;
}
.rform__note{margin:0;font-size:.72rem;color:var(--dim);max-width:34ch}
.rform__msg{
  margin:1rem 0 0;
  padding:.9rem 1rem;
  border-left:2px solid var(--ember);
  font-size:.85rem;
  color:var(--dim);
}
.rform__msg[hidden]{display:none}
.rform button[disabled]{opacity:.5;cursor:default}

/* Shown instead of the form until config.js has the Supabase values. The
   route to leave a review still has to exist while the backend does not. */
.rform--offline{border-style:dashed}
/* the buttons grow to fill their row, and this row is the full page width, so
   without a cap they read as two enormous slabs */
.rform--offline .panel__actions{margin-top:1.3rem;max-width:38rem}
.rform--offline .rform__note{max-width:52ch}

/* the honeypot must be gone for people and present for bots, so it is moved
   off screen rather than display:none, which some bots skip */
.rform__hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

.pdp__next{
  display:flex;
  justify-content:space-between;
  gap:1.5rem;
  flex-wrap:wrap;
  margin-top:clamp(2.5rem,5vw,4rem);
  padding-top:1.6rem;
  border-top:1px solid var(--line-c);
}

/* ============================================================
   lookbook page
   Vertical editorial scroll. Every frame carries one line of
   brand meaning, bottom left, always visible.
   ============================================================ */

.lb{display:grid;gap:clamp(.6rem,1.4vw,1.2rem);padding-bottom:clamp(3rem,7vw,6rem)}

.lb__frame{
  margin:0;
  position:relative;
  overflow:hidden;
  background:linear-gradient(150deg,var(--ink-3),var(--ink-2));
}
.lb__frame img{
  width:100%;height:100%;
  object-fit:cover;
  transition:transform 1.4s var(--ease);
}
.lb__frame:hover img{transform:scale(1.03)}

/* The photography is shot portrait, so a full-width landscape frame would cut
   the head or the feet off every time. Single frames are therefore centred in
   a narrower column and kept portrait, pairs sit side by side, and the one
   landscape frame in the set is the only one that runs full width. */
.lb__frame--tall{aspect-ratio:4/5}
.lb__frame--port{aspect-ratio:3/4}
.lb__frame--wide{aspect-ratio:16/9}

.lb__row{display:grid;grid-template-columns:1fr 1fr;gap:clamp(.6rem,1.4vw,1.2rem)}
.lb__solo{max-width:min(100%,50rem);margin-inline:auto;width:100%}

.lb__cap{
  position:absolute;
  left:0;right:0;bottom:0;
  padding:4rem clamp(1.2rem,3vw,2.2rem) clamp(1.1rem,2vw,1.6rem);
  display:flex;
  align-items:baseline;
  gap:1rem;
  text-align:left;
  background:linear-gradient(to top,rgba(6,6,6,.88),rgba(6,6,6,.35) 45%,transparent);
}
.lb__cap b{
  flex:none;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:.72rem;
  letter-spacing:.02em;
  color:var(--ember);
}
.lb__cap span{
  font-size:clamp(.78rem,1.5vw,1rem);
  font-weight:400;
  letter-spacing:.01em;
  color:var(--paper);
  max-width:44ch;
}
.lb__cap i{
  display:block;
  font-style:normal;
  margin-top:.25rem;
  font-size:.64rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--paper-dim);
}

.lb__end{
  display:grid;
  grid-template-columns:1.2fr .8fr;
  align-items:center;
  gap:clamp(1.5rem,3vw,3rem);
  margin-top:clamp(3rem,6vw,5rem);
  padding-top:clamp(2rem,4vw,3rem);
  padding-bottom:clamp(2rem,5vw,4rem);
  border-top:1px solid var(--line-c);
}
.lb__end p{margin:0;max-width:40ch;font-size:.92rem;color:var(--dim)}

/* ── statement strip ────────────────────────────────────── */

.strip{
  display:grid;
  grid-template-columns:1.1fr .9fr;
  align-items:center;
  gap:clamp(2rem,6vw,5.5rem);
  max-width:var(--wrap);
  margin-inline:auto;
  padding:clamp(5rem,12vw,9rem) var(--gut);
}
.strip__img{
  margin:0;
  aspect-ratio:5/4;
  overflow:hidden;
  background:linear-gradient(150deg,var(--ink-3),var(--ink-2));
}
.strip__img img{width:100%;height:100%;object-fit:cover;object-position:center 30%}
.strip__copy p{color:var(--dim);max-width:36ch;margin:0 0 2rem}

/* ── lookbook ───────────────────────────────────────────── */

.lookbook{padding:clamp(4rem,10vw,7rem) 0 clamp(2rem,5vw,3.5rem)}

.lookbook__head{
  display:grid;
  gap:.4rem;
  margin-bottom:clamp(1.5rem,3vw,2.4rem);
}
.lookbook__meta{
  margin:1rem 0 0;
  font-size:.66rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}

/* pinned horizontal rail. all of it is gated on `js` so that if the script
   never runs the section falls back to ordinary vertical flow rather than a
   screen of empty space. */
.rail{position:relative}
.rail__inner{position:relative}

.rail__track{
  display:grid;
  grid-template-columns:repeat(2,1fr);
  gap:clamp(.6rem,1.4vw,1.1rem);
  padding-inline:var(--gut);
  max-width:var(--wrap);
  margin-inline:auto;
}

.rail__bar,.rail__hud{display:none}

.rail__end{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  justify-content:center;
  gap:1.4rem;
  padding:2.5rem 0;
}
.rail__end .eyebrow{margin:0}

@media (min-width:901px){
  .js .rail{height:440vh}

  .js .rail__inner{
    position:sticky;top:0;
    height:100vh;
    display:flex;
    align-items:center;
    overflow:hidden;
  }

  .js .rail__track{
    display:flex;
    grid-template-columns:none;
    align-items:center;
    gap:clamp(1rem,2.2vw,2rem);
    padding-inline:max(var(--gut),calc((100vw - var(--wrap)) / 2 + var(--gut)));
    max-width:none;
    margin:0;
    will-change:transform;
  }

  .js .rail__track > .gal{
    flex:none;
    height:66vh;
    width:auto;
    aspect-ratio:3/4;
  }
  .js .rail__track > .gal--wide{aspect-ratio:16/10}

  .js .rail__end{
    flex:none;
    width:min(38vw,420px);
    padding-inline:clamp(2rem,5vw,5rem);
  }

  /* fixed to the pinned viewport, so the section keeps its label and a live
     position readout while the track slides underneath */
  .js .rail__hud{
    display:flex;
    position:absolute;
    left:var(--gut);right:var(--gut);top:11vh;
    justify-content:space-between;
    align-items:baseline;
    font-size:.64rem;
    letter-spacing:var(--track-lg);
    text-transform:uppercase;
    color:var(--dim);
    pointer-events:none;
  }
  .js .rail__hud-count em{
    font-family:"Archivo",sans-serif;
    font-style:normal;
    font-weight:900;
    font-size:1.1rem;
    letter-spacing:-.02em;
    color:var(--paper);
  }

  .js .rail__bar{
    display:block;
    position:absolute;
    left:var(--gut);right:var(--gut);bottom:8vh;
    height:1px;
    background:var(--line-c);
  }
  .js .rail__bar span{
    display:block;height:100%;width:100%;
    background:var(--paper);
    transform:scaleX(0);
    transform-origin:left;
  }

  .js .rail.is-dragging{cursor:grabbing}
}

.gal{
  margin:0;
  position:relative;
  aspect-ratio:3/4;
  overflow:hidden;
  background:linear-gradient(150deg,var(--ink-3),var(--ink-2));
}
.gal--wide{grid-column:span 2;aspect-ratio:16/10}

.gal img{
  width:100%;height:100%;
  object-fit:cover;
  transition:transform 1.2s var(--ease);
}
.gal:hover img{transform:scale(1.05)}

/* this frame carries campaign text burned into its right third. bias the crop
   left so a portrait tile lands on the subject and drops the overlay. */
.gal--crop-left img{object-position:35% center}

.gal figcaption{
  position:absolute;
  left:0;right:0;bottom:0;
  padding:2.4rem 1.3rem 1.2rem;
  display:flex;
  align-items:baseline;
  gap:.8rem;
  font-size:.64rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  background:linear-gradient(to top,rgba(6,6,6,.85),transparent);
}
.gal figcaption span{color:var(--ember);flex:none}

/* ── ethos ──────────────────────────────────────────────── */

.ethos{
  padding:clamp(5rem,12vw,9rem) 0 clamp(3rem,6vw,5rem);
  border-top:1px solid var(--line-c);
}
.ethos__head{margin-bottom:clamp(3rem,6vw,5rem)}

/* sticky stack: each card pins slightly lower than the one before, so the
   previous card stays visible behind it as the next slides over */
.stack{
  max-width:var(--wrap);
  margin-inline:auto;
  padding:0 var(--gut) clamp(4rem,10vw,8rem);
  display:grid;
  gap:clamp(1.5rem,3vw,2.5rem);
}
/* the step between offsets is also the height of the band that stays visible
   when the next card slides over, so it has to clear the number and the
   title. any smaller and the stack just guillotines the headings. */
.stack__card{
  position:sticky;
  top:calc(14vh + var(--i) * 6.2rem);
  display:grid;
  align-content:start;
  gap:.9rem;
  min-height:34vh;
  padding:clamp(1.7rem,3vw,2.4rem) clamp(2rem,4vw,3.4rem) clamp(2.4rem,5vw,3.4rem);
  border:1px solid var(--line-c);
  background:linear-gradient(140deg,var(--ink-3),var(--ink-2) 65%,var(--ink));
}
.stack__no{
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:.8rem;
  letter-spacing:.02em;
  color:var(--ember);
}
.stack__card h3{
  margin:0;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:clamp(1.7rem,4.4vw,3.2rem);
  line-height:1;
  letter-spacing:-.025em;
  text-transform:uppercase;
}
.stack__card p{
  margin:.4rem 0 0;
  max-width:50ch;
  font-size:clamp(.95rem,1.4vw,1.06rem);
  color:var(--dim);
}

/* ── ethos + contact pages ──────────────────────────────── */

.ethos__facts,.contact__studio{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:clamp(1.6rem,3vw,3rem);
  margin:clamp(2rem,4vw,3.5rem) 0 clamp(3rem,6vw,5rem);
  padding-top:clamp(1.6rem,3vw,2.4rem);
  border-top:1px solid var(--line-c);
}
.ethos__facts p:not(.footer__label),
.contact__studio p:not(.footer__label){margin:0 0 .4rem;font-size:.92rem;color:var(--dim)}

/* the two order channels, as panels rather than buttons: on this page they
   are the content, not a call to action stuck under some */
.channels{
  display:grid;
  grid-template-columns:repeat(2,1fr);
  gap:clamp(.8rem,1.6vw,1.4rem);
}
.channel{
  display:grid;
  align-content:start;
  gap:.7rem;
  padding:clamp(1.8rem,3vw,2.6rem);
  border:1px solid var(--line-c);
  background:linear-gradient(140deg,var(--ink-3),var(--ink-2) 70%,var(--ink));
  transition:border-color .4s var(--ease),transform .5s var(--ease);
}
.channel:hover{border-color:var(--paper);transform:translateY(-3px)}
.channel__no{
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:.72rem;
  color:var(--ember);
}
.channel h2{
  margin:0;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:clamp(1.5rem,3vw,2.2rem);
  line-height:1;
  letter-spacing:-.025em;
  text-transform:uppercase;
}
.channel p{margin:0;max-width:36ch;font-size:.92rem;color:var(--dim)}
.channel__go{
  margin-top:.6rem;
  font-size:.64rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
}
.channel__go::after{content:" \2192"}

.faq{margin-top:clamp(3rem,6vw,5rem)}
.faq__item{border-bottom:1px solid var(--line-c)}
.faq__item summary{
  list-style:none;
  cursor:pointer;
  padding:1.2rem 0;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:1.5rem;
  font-size:.92rem;
  transition:color .35s var(--ease);
}
.faq__item summary::-webkit-details-marker{display:none}
.faq__item summary::after{
  content:"+";
  flex:none;
  font-size:1rem;
  color:var(--ember);
  transition:transform .4s var(--ease);
}
.faq__item[open] summary::after{transform:rotate(45deg)}
.faq__item summary:hover{color:var(--ember)}
.faq__item div{
  padding:0 0 1.4rem;
  max-width:62ch;
  font-size:.92rem;
  color:var(--dim);
}

/* ── contact ────────────────────────────────────────────── */

.contact{
  padding:clamp(5rem,12vw,9rem) 0;
  border-top:1px solid var(--line-c);
}
.contact__inner{text-align:center}
.contact__inner .lede{margin:1.6rem auto 0}
.contact__actions{
  margin-top:2.6rem;
  display:flex;
  flex-wrap:wrap;
  gap:1rem;
  justify-content:center;
}
.contact__handle{
  margin:2rem 0 0;
  font-size:.66rem;
  letter-spacing:var(--track-lg);
  text-transform:uppercase;
  color:var(--dim);
}

/* ── feedback (currently commented out in the markup) ───── */

.feedback__grid{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:clamp(1rem,2.4vw,1.8rem);
}
.quote{
  margin:0;
  padding:1.8rem 1.6rem;
  border:1px solid var(--line-c);
}
.quote blockquote{
  margin:0 0 1.2rem;
  font-size:.98rem;
  font-weight:200;
  line-height:1.55;
}
.quote figcaption{
  font-size:.66rem;
  letter-spacing:var(--track-md);
  text-transform:uppercase;
  color:var(--dim);
}
/* visual flag so placeholder copy cannot ship unnoticed */
.quote.is-placeholder{border-style:dashed;opacity:.6}

/* ── phase 02 ───────────────────────────────────────────── */

.next{
  position:relative;
  min-height:80svh;
  display:grid;
  place-items:center;
  text-align:center;
  padding:clamp(5rem,12vw,9rem) var(--gut);
  overflow:hidden;
  background:radial-gradient(120% 90% at 50% 100%,#1b1611 0%,var(--ink) 60%);
}
.next__media{position:absolute;inset:-12% 0;overflow:hidden;will-change:transform}
/* this frame has "PHASE-02 COMING SOON" burned into its right third, which
   would fight the real headline. push it off centre and blur it back into
   texture so only the firelight and the tech pack read. */
.next__media img{
  width:100%;height:100%;
  object-fit:cover;
  object-position:22% center;
  opacity:.32;
  filter:grayscale(.55) blur(3px);
  transform:scale(1.22);
}
.next__scrim{
  position:absolute;inset:0;
  background:linear-gradient(to bottom,var(--ink),rgba(6,6,6,.42) 45%,var(--ink));
}
.next__body{position:relative;z-index:2}

.next__title{
  margin:0;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:clamp(2.8rem,15vw,11rem);
  line-height:.9;
  letter-spacing:-.03em;
}
.next__sub{
  margin:1.4rem 0 2.8rem;
  font-size:.72rem;
  letter-spacing:var(--track-lg);
  text-transform:uppercase;
  color:var(--dim);
}

/* ── footer ─────────────────────────────────────────────── */

.footer{
  border-top:1px solid var(--line-c);
  padding-top:clamp(3.5rem,7vw,5.5rem);
  overflow:hidden;
}
.footer__top{
  display:grid;
  grid-template-columns:repeat(4,1fr);
  gap:2.5rem;
}
.footer__col--wide{grid-column:span 2}
.footer__label{
  margin:0 0 1.2rem;
  font-size:.6rem;
  letter-spacing:var(--track-lg);
  text-transform:uppercase;
  color:var(--ember);
}
.footer__nav{display:flex;flex-direction:column;gap:.7rem}
.footer__nav a{
  font-size:.78rem;
  letter-spacing:.04em;
  color:var(--dim);
  transition:color .35s var(--ease);
}
.footer__nav a:hover{color:var(--fg)}
.footer__note{margin:0 0 .5rem;font-size:.78rem;color:var(--dim)}
.footer__note--dim{opacity:.65}

/* the sign-off: sized against the viewport so it always runs edge to edge */
.footer__mark{
  margin-top:clamp(2.5rem,6vw,4.5rem);
  padding-inline:var(--gut);
  overflow:hidden;
  line-height:.78;
}
/* the CSS size is the safe floor: it must not clip with scripting off. main.js
   measures the glyphs and sets the exact size that fills the line. */
/* inline-block, not block: the fitter measures this element's own width, and a
   block would just report the container back and "fit" to nothing */
.footer__mark span{
  display:inline-block;
  font-family:"Archivo",sans-serif;
  font-weight:900;
  font-size:17vw;
  letter-spacing:-.035em;
  text-transform:uppercase;
  color:var(--paper);
  opacity:.14;
  white-space:nowrap;
}

.footer__legal{
  display:flex;
  justify-content:space-between;
  align-items:baseline;
  gap:1rem 2rem;
  flex-wrap:wrap;
  margin:0;
  padding:1.6rem 0 2rem;
  border-top:1px solid var(--line-c);
  font-size:.66rem;
  letter-spacing:.06em;
  color:var(--dim);
}

/* the build credit, quiet until you look for it */
.footer__by a{
  color:var(--fg);
  border-bottom:1px solid var(--line-c);
  padding-bottom:2px;
  transition:border-color .35s var(--ease);
}
.footer__by a:hover{border-color:var(--fg)}

/* The size row: the one control on the buy panel. Letters in boxes rather
   than an abstract scale, because this answer has to be unambiguous when the
   order is read back and something has to come off a shelf. */
.spicks{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.9rem}
.spick{
  min-width:3.4rem;
  padding:.65rem .8rem;
  background:transparent;
  color:var(--fg);
  border:1px solid var(--line-c);
  font:500 .82rem/1 Archivo,system-ui,sans-serif;
  letter-spacing:.06em;
  cursor:pointer;
  transition:border-color .3s var(--ease),background .3s var(--ease),color .3s var(--ease);
}
.spick:hover:not(:disabled){border-color:var(--fg)}
.spick.is-on{background:var(--fg);color:var(--bg);border-color:var(--fg)}
.spick:focus-visible{outline:2px solid var(--fg);outline-offset:2px}
/* Sold out stays on the page. Removing it reads as "this piece has no XL"
   rather than "the XL has gone". */
.spick.is-out{
  opacity:.35;
  cursor:not-allowed;
  text-decoration:line-through;
  border-style:dashed;
}
.spicks.is-asking{animation:ask .45s var(--ease)}

/* The fit scale is a picture of how the piece runs, not a set of buttons.
   Generated as spans with one filled, so there is nothing to press and
   nothing that looks pressable. */
.sizer--fixed .chip{
  display:block;
  background:none;
  border:0;
  padding:0;
  cursor:default;
}
.sizer--fixed .chips{pointer-events:none}
.sizer__guide--static{
  color:var(--dim);
  border-bottom:0;
  cursor:default;
}

/* ============================================================
   the sign-in sheet
   Sits over whatever they were doing rather than taking them to
   a page, because it interrupts an order in progress and the
   cart and the scroll position both have to survive it. Paper
   ground, like every other block that asks for a decision.
   ============================================================ */

.auth{position:fixed;inset:0;z-index:500}
.auth__scrim{
  position:absolute;inset:0;
  background:rgba(4,4,4,.72);
  backdrop-filter:blur(3px);
  animation:authFade .3s var(--ease) both;
}
.auth__panel{
  --bg:var(--paper);
  --fg:var(--ink);
  --dim:#6d675e;
  --line-c:rgba(6,6,6,.16);
  position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);
  width:min(28rem,calc(100% - 2rem));
  max-height:calc(100dvh - 2rem);
  overflow:auto;
  padding:clamp(1.5rem,4vw,2.4rem);
  background:var(--bg);
  color:var(--fg);
  animation:authRise .45s var(--ease-mask) both;
}
@keyframes authFade{from{opacity:0}to{opacity:1}}
@keyframes authRise{
  from{opacity:0;transform:translate(-50%,calc(-50% + 14px))}
  to{opacity:1;transform:translate(-50%,-50%)}
}

.auth__x{
  position:absolute;top:.6rem;right:.7rem;
  background:none;border:0;color:var(--dim);
  font-size:1.5rem;line-height:1;cursor:pointer;padding:.3rem .5rem;
}
.auth__x:hover{color:var(--fg)}

.auth__eyebrow{
  margin:0;font-size:.6rem;letter-spacing:var(--track-md);
  text-transform:uppercase;color:var(--dim);
}
.auth__title{
  font-family:Archivo,sans-serif;font-weight:900;
  font-size:clamp(1.5rem,5vw,2rem);letter-spacing:-.02em;
  margin:.35rem 0 .6rem;
}
.auth__lede{margin:0 0 1.4rem;font-size:.86rem;line-height:1.65;color:var(--dim)}

.auth__google{width:100%;justify-content:center;gap:.6rem}
.auth__or{
  display:flex;align-items:center;gap:.8rem;
  margin:1.1rem 0;font-size:.62rem;letter-spacing:var(--track-md);
  text-transform:uppercase;color:var(--dim);
}
.auth__or::before,.auth__or::after{
  content:"";flex:1;height:1px;background:var(--line-c);
}

.auth__field{margin-bottom:.9rem}
.auth__field label{
  display:block;font-size:.6rem;letter-spacing:var(--track-md);
  text-transform:uppercase;color:var(--dim);margin-bottom:.35rem;
}
.auth__field input{
  width:100%;
  background:transparent;
  color:var(--fg);
  border:1px solid var(--line-c);
  padding:.7rem .8rem;
  font:300 .95rem/1.4 Inter,system-ui,sans-serif;
  transition:border-color .3s var(--ease);
}
.auth__field input:focus{outline:none;border-color:var(--fg)}

.auth__msg{
  margin:0 0 .9rem;font-size:.78rem;line-height:1.55;color:var(--dim);
  border-left:2px solid var(--line-c);padding-left:.7rem;
}
.auth__msg.is-bad{color:#a8352a;border-left-color:#a8352a}

.auth__go{width:100%;justify-content:center;margin-top:.3rem}
.auth__go:disabled{opacity:.5;cursor:wait}

.auth__swap{
  margin:1.2rem 0 0;padding-top:1.1rem;border-top:1px solid var(--line-c);
  font-size:.78rem;color:var(--dim);text-align:center;
}
.auth__swap button{
  background:none;border:0;padding:0;cursor:pointer;
  color:var(--fg);font:inherit;
  border-bottom:1px solid var(--line-c);
}
.auth__swap button:hover{border-color:var(--fg)}

.footer__acct{
  display:flex;align-items:baseline;gap:.7rem;flex-wrap:wrap;
  margin:.5rem 0 0;font-size:.72rem;color:var(--dim);
}
.footer__acct span{
  overflow:hidden;text-overflow:ellipsis;max-width:14rem;white-space:nowrap;
}
.footer__acct button{
  background:none;border:0;padding:0;cursor:pointer;
  color:var(--fg);font:inherit;
  border-bottom:1px solid var(--line-c);
  transition:border-color .35s var(--ease);
}
.footer__acct button:hover{border-color:var(--fg)}

/* An order button that has not been unlocked yet. It stays a full, pressable
   button on purpose: greying it out would read as "sold out" rather than
   "one more step", and the press is what opens the sheet. */
.btn.is-gated{position:relative}

/* the way in to the dashboard: discreet, not hidden. It has to stay
   reachable by keyboard, so it dims rather than disappears, and it comes
   back to full strength on hover and on focus. */
.footer__admin{
  color:var(--dim);
  opacity:.35;
  font-size:.6rem;
  letter-spacing:.18em;
  text-transform:uppercase;
  transition:opacity .35s var(--ease),color .35s var(--ease);
}
.footer__admin:hover,
.footer__admin:focus-visible{opacity:1;color:var(--fg)}

/* ============================================================
   motion primitives
   Every hidden state is gated on .js so the page stays readable
   with scripting off or if main.js fails to load.
   ============================================================ */

.js .reveal{
  opacity:0;
  transform:translateY(24px);
  transition:opacity .95s var(--ease),transform .95s var(--ease);
  transition-delay:calc(var(--d,0) * 90ms);
}
.js .reveal.is-in{opacity:1;transform:none}

/* Clip driven image reveal.
   The clip goes on the IMAGE, never on the observed element itself. An element
   collapsed by its own clip-path reports no intersection area, so an
   IntersectionObserver watching it would never fire, and the class that lifts
   the clip would never be added. That deadlock shipped once already and blanked
   every image on the page. Keep the observed box unclipped. */
.js .unmask > img,
.js .unmask .card__img,
.js .unmask > .card__media > .card__img{
  clip-path:inset(0 0 100% 0);
  transition:clip-path 1.15s var(--ease-mask);
  transition-delay:calc(var(--d,0) * 90ms);
}
.js .unmask.is-in > img,
.js .unmask.is-in .card__img{clip-path:inset(0 0 0 0)}

/* split text: each line/char sits in an overflow-hidden mask and slides up */
.line{display:block;overflow:hidden}
.line__inner,.char{display:inline-block;will-change:transform}

/* each char is its own inline-block, which hands the browser a break
   opportunity between every letter. these runs must never wrap. */
[data-split="chars"]{white-space:nowrap}

/* tracking would otherwise land twice: once inside each single-char box and
   again between the boxes. keep it on the parent only. */
[data-split="chars"] .char{letter-spacing:0}

.js .line__inner{
  transform:translateY(105%);
  transition:transform 1s var(--ease-mask);
  transition-delay:calc(var(--d,0) * 1ms);
}
.js .is-in .line__inner{transform:none}

.js .char{
  opacity:0;
  transform:translateY(60%);
  transition:opacity .7s var(--ease),transform .8s var(--ease-mask);
  transition-delay:calc(var(--d,0) * 1ms);
}
.js .is-in .char{opacity:1;transform:none}

/* ============================================================
   responsive
   ============================================================ */

@media (max-width:1200px){
  .shop__grid{grid-template-columns:repeat(2,1fr);gap:clamp(2rem,4vw,3rem) clamp(1rem,2vw,1.6rem)}
}

@media (max-width:900px){
  .nav__links{display:none}
  .nav__cta{display:none}
  .burger{display:grid;place-items:center}
  /* burger left, wordmark centred, icons right: the reference's phone layout */
  .nav__inner{grid-template-columns:1fr auto 1fr}
  /* margin-left:auto on the base rule is what centres it in the old flex nav;
     in the three-track grid it drags the burger off the left edge */
  .burger{grid-column:1;justify-self:start;margin-left:0}

  .pdp__grid{grid-template-columns:1fr;gap:1.8rem}
  .pdp__panel{position:static}
  .pdp__detail{grid-template-columns:1fr}

  .rform__row{grid-template-columns:1fr 1fr}

  .checkout__grid{grid-template-columns:1fr}
  /* the summary stops following and simply sits after the form */
  .sum{position:static}

  .also__grid{grid-template-columns:1fr 1fr}
  .creed__set{grid-template-columns:1fr;gap:2rem}

  .lb__row{grid-template-columns:1fr}
  .brief{grid-template-columns:1fr;gap:1.8rem}
  .shop__foot,.lb__end{grid-template-columns:1fr}
  .shop__footcta{justify-content:flex-start}
  .channels{grid-template-columns:1fr}
  .ethos__facts,.contact__studio{grid-template-columns:1fr;gap:1.6rem}

  .strip{grid-template-columns:1fr}
  .strip__copy p{max-width:none}

  .shop__headmeta{flex-direction:column;gap:1.2rem}

  .stack__card{min-height:auto;top:calc(12vh + var(--i) * 2rem)}

  .rail__track{grid-template-columns:repeat(2,1fr)}
  .gal--wide{grid-column:span 2}

  .footer__top{grid-template-columns:repeat(2,1fr);gap:2rem}
  .footer__col--wide{grid-column:span 2}
  .footer__mark span{font-size:22vw}
}

@media (max-width:560px){
  :root{--track-xl:.3em;--track-lg:.22em}

  .hero{min-height:92svh;padding-top:7rem}
  /* the two doors stay on one line, they just get tighter */
  .hero__actions{gap:.6rem}
  .hero__actions .btn{padding-inline:1rem;min-width:0;flex:1 1 0}
  .hero__coord{display:none}
  .hero__foot{justify-content:center}

  .page{padding-top:4.6rem}

  /* Burger one side, bag the other, wordmark dead centre. The two social icons
     make the right-hand track wider than the left, which drags the centred
     wordmark off centre, and they are already in the menu and the footer. */
  .nav__ico{display:none}
  .nav__side{gap:.6rem}

  .rform__row{grid-template-columns:1fr}
  .cart__list--wide .cart__item{grid-template-columns:64px 1fr}
  .cart__list--wide .cart__line{grid-column:2;margin-top:.4rem}
  .lb__cap{padding-bottom:1rem}
  /* a 32% inset on a phone leaves a sliver, open it wider */
  .js .hero__mask{clip-path:inset(0 18% 0 18%)}


  /* two columns hold on phones, like a real store grid, so tighten the type */
  .shop__grid{gap:1.8rem .8rem}
  .card__row{flex-direction:column;gap:.15rem}
  .card__name{font-size:.66rem}
  .card__sub{font-size:.7rem}
  .card__badge{font-size:.5rem;padding:.4rem .55rem}

  .specs>div{flex-direction:column;gap:.25rem}
  .specs dd{text-align:left}

  .panel__actions .btn{flex:1 1 100%}

  .rail__track{grid-template-columns:1fr}
  .gal,.gal--wide{grid-column:span 1;aspect-ratio:4/5}

  .footer__legal{flex-direction:column;gap:.4rem}
  .footer__mark span{font-size:25vw}
}

/* NOTE ON IMAGERY
   The photography is placeholder: 640px frames off the public Instagram grid,
   pending real shots from the brand. Per-image grading and an SVG sharpen
   convolution were tried and deliberately removed, so what renders is the
   source frame untouched. When the real photography lands, grade it here
   rather than reintroducing a sharpen pass. The one exception is the
   placeholder product cards, which are greyed ON PURPOSE to read as empty
   slots, not as photography.

   If you ever do bring back `filter:url(#someId)`: an unresolvable reference
   does not degrade, Chrome drops the element from painting entirely. Gate it
   behind a class set only after confirming the filter is in the document. */

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  .js .reveal,.js .line__inner,.js .char{opacity:1;transform:none}
  .js .unmask > img,.js .unmask .card__img{clip-path:none}
  .js .hero__mask{clip-path:none}
  .grain{animation:none}
  .cursor{display:none}
  .js body,.js a,.js button{cursor:auto}
  .loader{display:none !important}
  .stack__card{position:static}
}
