:root{
  /* ---- ground: plain white, as she asked. Neutrals biased faintly cool so
     they sit under the cyan rather than fighting it. ---- */
  --ground:#FFFFFF;
  --ground-2:#F4F8F8;
  --surface:#FFFFFF;
  --surface-2:#F4F8F8;

  --ink:#14181A;
  --ink-2:#4C5B5E;
  --ink-3:#7C8B8E;
  --line:#E3EBEB;
  --line-2:#CBD8D9;

  /* ---- the three logo hues, resampled from assets/img/brand/logo.jpg ----
     She redrew the logo on 7 Sep: "Since we weren't able to incorporate a more
     neon theme, I have changed the colors of the logo to match it as close as
     possible ... I want to follow this colors wherever we can on the website."

     These are read off the letterforms of the new file, not guessed. They are
     a good deal deeper than the neons they replace — 2.8:1 and 3.9:1 on white
     against 1.6:1 and 3.7:1 — so they carry far more of the page on their own. */
  --green:#76AB2B;
  --cyan:#02A9B0;
  --pink:#F42767;

  /* Deepened twins, each the shallowest darkening of its hue that clears
     4.5:1 on white. Hue for fills, dots, badges and rules; twin for anything
     you read. Still needed: the logo greens and teals are 2.8:1. */
  --green-ink:#598120;
  --cyan-ink:#018389;
  --pink-ink:#E0235E;

  /* legacy names, kept so existing rules keep resolving */
  --berry:var(--pink-ink);
  --teal:var(--cyan-ink);
  --leaf:var(--green-ink);
  --plum:var(--pink-ink);
  --brass:#A97A1E;          /* warning only — semantic, not a brand hue */

  /* 8pt spacing scale */
  --s1:.5rem; --s2:1rem; --s3:1.5rem; --s4:2rem; --s5:3rem; --s6:4rem;

  --pad:clamp(1.25rem,.9rem + 3.4vw,4.5rem);
  --gap:clamp(1.4rem,1rem + 2vw,2.6rem);
  --sec:clamp(3rem,2.2rem + 4vw,6.5rem);

  /* headings capped — the old hero filled a whole phone with three words */
  --d1:clamp(2.6rem,1.8rem + 3.6vw,4.6rem);
  --d2:clamp(1.75rem,1.35rem + 1.8vw,2.75rem);
  --d3:clamp(1.22rem,1.05rem + .8vw,1.6rem);

  --r:20px; --r-s:16px;
  --e1:0 1px 2px rgba(20,24,26,.04);
  --e2:0 2px 6px rgba(20,24,26,.045), 0 14px 34px -22px rgba(20,24,26,.22);
  --e3:0 3px 10px rgba(20,24,26,.05), 0 26px 56px -28px rgba(20,24,26,.28);

  --ease:cubic-bezier(.22,1,.36,1);
  --ease-io:cubic-bezier(.65,.02,.28,1);
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;background:var(--ground);color:var(--ink);
  font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,sans-serif;
  font-size:clamp(1rem,.96rem + .2vw,1.1rem);line-height:1.65;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
  /* iOS paints a translucent grey box over anything you tap, on top of our own
     feedback and a beat behind it. It is the single loudest "this is a web
     page" tell on a phone. Off here, and every pressable thing gets a real
     :active state below instead — never remove one without the other. */
  -webkit-tap-highlight-color:transparent;
}

/* Chrome is not prose. Double-tapping a button should press it twice, not
   select its label; a stray highlight over a nav pill reads as a glitch.
   Prose, prices and anything a customer might want to copy keep selection. */
button,nav,.label,.sectabs,.tabs,.stp,.cstep,.tile b,.tile small,
.card .ct,.badge,.pill{user-select:none;-webkit-user-select:none}
p,h1,h2,h3,input,textarea,.price,.qv-desc,.faq-a,.mono{user-select:text;-webkit-user-select:text}

/* Tracking is a function of size, not a constant. Apple sets it per optical
   size for a reason: at 4.6rem the same -0.012em reads loose, and at 1.2rem it
   reads cramped. Three steps tied to the existing --d1/--d2/--d3 scale. */
h1,h2,h3{font-family:"Outfit",ui-sans-serif,system-ui,sans-serif;font-weight:600;line-height:1.08;letter-spacing:-.015em;margin:0;text-wrap:balance}
.hero h1,#hero-h1,.brandmark{letter-spacing:-.028em}   /* display: tightest */
h3,.qv-info h3,.door h3{letter-spacing:-.012em}         /* sub-head: nearly none */
.card .nm,.tile b{letter-spacing:-.008em}               /* card titles: barely */
p{margin:0;text-wrap:pretty}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
img{display:block;max-width:100%}
:focus-visible{outline:3px solid var(--berry);outline-offset:4px;border-radius:6px}
.mono{font-family:"DM Mono",ui-monospace,monospace;font-variant-numeric:tabular-nums}
.label{font-family:"DM Mono",ui-monospace,monospace;font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-3)}

/* ---------------- chromatic offset, deepened ---------------- */
/* Hero type: no offset copy behind the glyphs — that duplicate was what made the
   counters of b, d and o look pinched. Depth now comes from a layered shadow and
   a real 3D tilt that follows the pointer. */
.chroma{position:relative;display:inline-block;color:var(--ink);
  transition:color .5s var(--ease)}
.chroma.c{color:var(--berry)}

#hero-h1{
  transform-style:preserve-3d;
  transition:transform .5s var(--ease);
  will-change:transform;
}
#hero-h1 .lnwrap > span{
  transition:transform 1.05s var(--ease), opacity .8s ease, text-shadow .5s var(--ease);
}
.settled #hero-h1, #hero-h1.settled{}
#hero-h1.lift .lnwrap:nth-child(1) > span{transform:translateZ(26px)}
#hero-h1.lift .lnwrap:nth-child(2) > span{transform:translateZ(46px)}
#hero-h1.lift .lnwrap:nth-child(3) > span{transform:translateZ(66px)}
#hero-h1.lift .chroma{text-shadow:
   .012em .016em 0 color-mix(in srgb, var(--brass) 45%, transparent),
   .024em .034em .5px color-mix(in srgb, var(--berry) 22%, transparent)}
#hero-h1.lift .chroma.c{text-shadow:
   .012em .016em 0 color-mix(in srgb, var(--berry) 40%, transparent),
   .024em .034em .5px color-mix(in srgb, var(--teal) 22%, transparent)}

/* ---------------- motion primitives ---------------- */
html.js [data-rise]{opacity:0;transform:translateY(26px)}
html.js [data-rise].seen{opacity:1;transform:none;transition:opacity .9s var(--ease),transform .9s var(--ease)}
html.js [data-wipe]{clip-path:inset(0 0 100% 0)}
html.js [data-wipe].seen{clip-path:inset(0 0 0 0);transition:clip-path 1.05s var(--ease-io)}
html.js [data-zoom] img{transform:scale(1.14);transition:transform 1.3s var(--ease)}
html.js [data-zoom].seen img{transform:scale(1)}

/* hero line masks */
.lnwrap{display:block;overflow:hidden;padding-bottom:.06em}
html.js .lnwrap > span{display:block;transform:translateY(110%);opacity:0}
html.js .settled .lnwrap > span{transform:none;opacity:1;transition:transform 1.05s var(--ease),opacity .8s ease}
html.js .settled .lnwrap:nth-child(2) > span{transition-delay:.09s}
html.js .settled .lnwrap:nth-child(3) > span{transition-delay:.18s}

/* screen transitions */
.screen{display:none}
.screen.on{display:block}
/* no fill-mode: if the animation never runs (hidden tab), the screen sits at
   its natural, visible state instead of being pinned at frame zero */
html.js .screen.entering{animation:scr .62s var(--ease)}
@keyframes scr{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}

/* ---------------- header ---------------- */
.top{position:sticky;top:0;z-index:60;background:color-mix(in srgb,var(--ground) 86%,transparent);backdrop-filter:blur(16px) saturate(1.3);border-bottom:1px solid var(--line)}
/* Two lines, always. The name is centred on the first and the tabs run under
   it — "first line center alignment All Things Quirky in Bold", "Then next
   line the Home Charms Custom ise as it is".

   The first line is a three-column grid rather than a flex row so the name is
   centred on the *page*, not on the space the tools happen to leave. An empty
   left cell mirrors the tools' width, which is what keeps it honest. */
.top .in{padding:clamp(.7rem,.45rem + .6vw,1rem) var(--pad) clamp(.5rem,.35rem + .4vw,.7rem);max-width:1560px;margin:0 auto}
.topline{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:var(--s3)}
.topline .tools{grid-column:3;justify-self:end}
.brand{grid-column:2;justify-self:center;display:flex;align-items:center;gap:.7rem;flex-shrink:0;
  padding:.2rem .5rem;border-radius:12px;transition:transform .35s var(--ease),background .25s}
.brand:hover{transform:translateY(-1px);background:color-mix(in srgb,var(--ink) 4%,transparent)}
.brandmark{font-family:"Outfit",ui-sans-serif,sans-serif;font-weight:700;font-size:clamp(1.5rem,1.15rem + 1.5vw,2.35rem);
  letter-spacing:-.025em;line-height:1;white-space:nowrap}
.logo{height:clamp(40px,30px + 2.4vw,58px);width:auto;mix-blend-mode:multiply;flex-shrink:0}
.logo.foot{height:74px}

/* pagination */
.pager{display:flex;justify-content:center;align-items:center;gap:.4rem;flex-wrap:wrap;
  margin-top:clamp(2rem,1.4rem + 2vw,3.4rem)}
.pager button{min-width:2.5rem;height:2.5rem;padding:0 .7rem;border:1.5px solid var(--line);
  border-radius:100px;font-size:.87rem;font-weight:700;color:var(--ink-2);background:var(--surface);
  transition:border-color .25s,background .25s,color .25s,transform .3s var(--ease)}
.pager button:hover:not(:disabled){border-color:var(--ink);transform:translateY(-2px)}
.pager button[aria-current="true"]{background:var(--ink);border-color:var(--ink);color:var(--surface)}
.pager button:disabled{opacity:.32;cursor:not-allowed}
.pager .count{margin-left:.6rem;font-family:"DM Mono",monospace;font-size:.76rem;color:var(--ink-3)}

/* variant picker */
.vpick{position:absolute;inset:0;background:color-mix(in srgb,var(--surface) 95%,transparent);
  backdrop-filter:blur(4px);display:none;flex-direction:column;justify-content:center;gap:.55rem;padding:1rem}
.vpick.on{display:flex}
.vpick .t{font-family:"DM Mono",monospace;font-size:.62rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--ink-3);text-align:center}
.vpick .opts{display:flex;flex-wrap:wrap;gap:.35rem;justify-content:center}
.vpick button{width:2.1rem;height:2.1rem;border:1.5px solid var(--line-2);border-radius:8px;
  font-weight:700;font-size:.85rem;color:var(--ink-2);background:var(--surface);transition:.2s}
.vpick button:hover{border-color:var(--berry);background:var(--berry);color:#fff;transform:translateY(-2px)}
.card .vr{cursor:default}
.brandmark i{font-style:normal}
.brandmark .a{color:var(--leaf)}.brandmark .b{color:var(--teal)}.brandmark .c{color:var(--berry)}
.pending{font-size:.55rem;letter-spacing:.11em;color:var(--ink-3);border:1px dashed var(--line-2);padding:.16rem .38rem;border-radius:4px;white-space:nowrap;font-family:"DM Mono",monospace}
/* margin:0 auto rather than margin-left:auto — pinned hard right, the first and
   last buttons sat flush against the edge and their pill looked squashed the
   moment it filled in. The padding and the trailing spacer keep both ends off
   the edge; a scroll container drops trailing padding, hence the ::after. */
nav.main{display:flex;gap:.2rem;margin:0 auto;padding:0 .45rem;overflow-x:auto;scrollbar-width:none;
  justify-content:safe center}

/* A sideways tab strip with a visible edge: the side that has more behind it
   fades out and grows an arrow. Neither appears when everything already fits,
   so on a wide desktop this is invisible. */
.nshort{display:none}
.scroller{position:relative;min-width:0}
.navscroller{flex:1 1 auto;display:flex}
.scroller::before,.scroller::after{
  content:"";position:absolute;top:0;bottom:0;width:48px;z-index:2;
  pointer-events:none;opacity:0;transition:opacity .25s;
}
.scroller::before{left:0;background:linear-gradient(to right,var(--ground),transparent)}
.scroller::after{right:0;background:linear-gradient(to left,var(--ground),transparent)}
.scroller.can-l::before,.scroller.can-r::after{opacity:1}
.scroll-ar{
  position:absolute;top:50%;transform:translateY(-50%);z-index:3;
  width:30px;height:30px;border-radius:100px;
  border:1px solid var(--line-2);background:var(--surface);box-shadow:var(--e1);
  display:grid;place-items:center;font-size:1.25rem;line-height:1;color:var(--ink-2);
  opacity:0;pointer-events:none;transition:opacity .25s,background .25s,color .25s;
}
.scroll-ar.l{left:0}
.scroll-ar.r{right:0}
.scroller.can-l .scroll-ar.l,.scroller.can-r .scroll-ar.r{opacity:1;pointer-events:auto}
.scroll-ar:hover{background:var(--ink);color:var(--surface);border-color:var(--ink)}
@media(pointer:coarse){ .scroll-ar{width:38px;height:38px;font-size:1.45rem} }
nav.main::after{content:"";flex:0 0 .45rem}
nav.main::-webkit-scrollbar{display:none}
nav.main button{position:relative;padding:.5rem .62rem;border-radius:100px;font-size:.83rem;font-weight:600;color:var(--ink-2);white-space:nowrap;transition:color .3s}
nav.main button::before{content:"";position:absolute;inset:0;border-radius:100px;background:var(--ink);transform:scale(.7);opacity:0;transition:transform .42s var(--ease),opacity .3s;z-index:-1}
nav.main button:hover{color:var(--ink)}
nav.main button[aria-current="true"]{color:var(--surface)}
nav.main button[aria-current="true"]::before{transform:scale(1);opacity:1}
.tools{display:flex;align-items:center;gap:.55rem;flex-shrink:0}
.cur{display:flex;border:1px solid var(--line-2);border-radius:100px;overflow:hidden}
.cur button{padding:.34rem .62rem;font-size:.7rem;font-weight:700;font-family:"DM Mono",monospace;color:var(--ink-3);transition:.3s}
.cur button[aria-pressed="true"]{background:var(--ink);color:var(--surface)}

/* Region and currency.

   One button in the header opens one small panel. It replaced a pair of
   INR/USD pills, so it has to stay about that wide or the tools row stops
   fitting beside a centred brand name on a phone — which is why the country
   name is the part that goes when there is no room, and the flag is what
   carries the meaning on its own. */
.regionwrap{position:relative}
.regionbtn{
  display:inline-flex;align-items:center;gap:.42rem;
  border:1px solid var(--line-2);border-radius:100px;padding:.34rem .68rem;
  background:var(--surface);color:var(--ink-2);
  font-size:.72rem;font-weight:700;line-height:1.1;
  transition:border-color .3s,transform .35s var(--ease);
}
.regionbtn:hover{border-color:var(--ink-3);transform:translateY(-1px)}
.regionbtn .rflag{font-size:.95rem;line-height:1}
.regionbtn .rcur{font-family:"DM Mono",monospace;color:var(--ink-3);
  padding-left:.42rem;border-left:1px solid var(--line-2)}

.regionpop{
  position:absolute;top:calc(100% + .55rem);right:0;z-index:60;
  width:min(19rem,calc(100vw - 2rem));
  background:var(--surface);border:1px solid var(--line-2);border-radius:16px;
  padding:var(--s3);box-shadow:0 18px 44px rgba(0,0,0,.13);
  display:grid;gap:var(--s3);
  animation:regionpop .18s var(--ease);
}
@keyframes regionpop{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.regionpop{animation:none}}
.regionpop .rrow{display:grid;gap:.45rem}
.regionpop label,.regionpop .rlabel{
  font-size:.68rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3)}
.regionpop select{
  width:100%;padding:.55rem .7rem;border:1px solid var(--line-2);border-radius:10px;
  background:var(--surface);color:var(--ink);font-size:.86rem}
.regionpop .cur{align-self:start}
.regionpop .cur button{padding:.44rem .9rem;font-size:.76rem}
.regionpop .hint{margin:0;font-size:.74rem;line-height:1.45}
.regionpop .cta{width:100%;padding:.6rem;font-size:.82rem}
.cartbtn{display:flex;align-items:center;gap:.5rem;background:var(--ink);color:var(--surface);padding:.52rem .95rem;border-radius:100px;font-size:.82rem;font-weight:700;transition:transform .35s var(--ease),background .3s}
.cartbtn:hover{transform:translateY(-2px);background:var(--berry)}
.cartbtn .n{background:var(--berry);border-radius:100px;min-width:1.25rem;height:1.25rem;display:grid;place-items:center;font-size:.68rem;transition:background .3s}
.cartbtn:hover .n{background:var(--ink)}
.cartbtn.bump{animation:bump .5s var(--ease)}
.wishbtn{
  display:inline-flex;align-items:center;gap:.4rem;
  border:1px solid var(--line-2);border-radius:100px;padding:.42rem .7rem;
  font-size:.78rem;font-weight:700;color:var(--ink-2);background:var(--surface);
  transition:border-color .3s,color .3s,transform .35s var(--ease);
}
.wishbtn:hover{border-color:var(--berry);color:var(--berry);transform:translateY(-2px)}
.wishbtn .hrt{font-size:.95rem;line-height:1}
.wishbtn .n{font-family:"DM Mono",monospace;font-size:.7rem}

/* the heart on a card sits beside Add, never over the photograph — the same
   rule the stock badges follow, and for the same reason */
.rowacts{display:inline-flex;align-items:center;gap:.4rem}
.wish{
  width:2rem;height:2rem;border-radius:100px;border:1px solid var(--line-2);
  display:grid;place-items:center;font-size:1rem;line-height:1;color:var(--ink-3);
  background:var(--surface);transition:color .25s,border-color .25s,transform .3s var(--ease);
}
.wish:hover{color:var(--berry);border-color:var(--berry)}
.wish[aria-pressed="true"]{color:var(--berry);border-color:var(--berry)}
.wish[aria-pressed="true"]:active{transform:scale(.88)}
.qv-acts{display:flex;gap:.5rem;margin-top:.7rem}
.qv-acts .opt{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:.4rem}
@media(max-width:760px){ .wish{width:2.4rem;height:2.4rem} }
@keyframes bump{0%,100%{transform:none}35%{transform:scale(1.11) translateY(-2px)}}

/* On a phone the tools would collide with a centred name long before the name
   is big enough for her to see it. So below 760px the tools drop to their own
   right-aligned line and the name gets the full width of the first one — which
   is what she asked for in the first place. */
@media(max-width:760px){
  .topline{grid-template-columns:1fr;gap:.35rem;justify-items:center}
  .brand{grid-column:1}
  .topline .tools{grid-column:1;justify-self:center}
  .navscroller{width:100%}
  nav.main{width:100%;margin-left:0;padding-bottom:.2rem}
  .pending{display:none}
}

/* On a phone the nav stops being a thing you swipe and becomes a thing you
   read. Her question was the right one: "will ppl using mobile phones know to
   swipe them to look for other tabs?" — no, and an arrow only tells you there
   is more, it doesn't show you what. So it wraps instead, every section on
   screen at once, and the type comes down far enough that eight of them fit in
   two rows without taking the whole first screen.

   Two names per tab is what makes two rows possible: "Fridge Magnets" alone is
   wider than a third of the row. */
@media(max-width:760px){
  .nlong{display:none}
  .nshort{display:inline}
  nav.main{
    flex-wrap:wrap;justify-content:center;overflow:visible;
    gap:.28rem;padding:0;row-gap:.3rem;
  }
  nav.main::after{display:none}          /* the scroll spacer has no job now */

  /* Both strips wrap on a phone, so nothing can scroll and no arrow is ever
     the right answer. scrollHints works this out from the measurements and
     reaches the same conclusion, but a hair after layout settles — which was
     enough to flash an arrow on the first paint after a rotate. Saying it in
     CSS makes it certain instead of merely usually true. */
  .scroller .scroll-ar{display:none}
  .scroller::before,.scroller::after{display:none}
}

main{max-width:1560px;margin:0 auto}
.screen{padding:0 var(--pad) clamp(6rem,4rem + 6vw,11rem)}

/* ---------------- hero ---------------- */
.hero{padding:clamp(3.5rem,2rem + 7vw,9rem) 0 clamp(3rem,2rem + 4vw,6rem);text-align:center;position:relative}
.hero h1{font-size:var(--d1);line-height:1.02}
.hero .sub{margin:clamp(1.8rem,1rem + 1.6vw,2.8rem) auto 0;max-width:36ch;color:var(--ink-2);font-size:clamp(1.02rem,.96rem + .4vw,1.28rem);line-height:1.55}
/* the wash is drawn as radial gradients with transparent stops, so it dissolves
   into the page instead of being a blurred square clipped by its container */
.blob{display:none}
.hero::before{
  content:"";position:absolute;top:-16%;bottom:-8%;
  left:50%;width:100vw;transform:translateX(-50%);
  z-index:-2;pointer-events:none;
  background:
    radial-gradient(34% 38% at 27% 30%, color-mix(in srgb, var(--berry) 24%, transparent) 0%,
                    color-mix(in srgb, var(--berry) 10%, transparent) 42%, transparent 74%),
    radial-gradient(32% 36% at 73% 36%, color-mix(in srgb, var(--teal) 22%, transparent) 0%,
                    color-mix(in srgb, var(--teal)  9%, transparent) 44%, transparent 76%),
    radial-gradient(46% 34% at 50% 2%, color-mix(in srgb, var(--brass) 11%, transparent) 0%, transparent 72%);
}
/* doors */
.doors{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,340px),1fr));gap:var(--gap);margin-top:clamp(3rem,2rem + 3.5vw,5.5rem)}
.door{
  position:relative;overflow:hidden;border-radius:var(--r);border:1px solid var(--line);
  background:var(--surface);padding:clamp(1.9rem,1.3rem + 2.2vw,3.2rem);text-align:left;
  display:flex;flex-direction:column;gap:var(--s2);min-height:clamp(290px,25vw,380px);
  transition:transform .6s var(--ease),box-shadow .6s var(--ease),border-color .4s;
  transform-style:preserve-3d;
}
.door:hover{box-shadow:var(--e3);border-color:var(--line-2)}

/* Each door carries its own colour: green for Customise, blue for Ready-made.
   The neon pair is too pale to read as an accent on white, so the tint and the
   glow are mixed from the deepened twins. Three steps — resting, hover, and
   pressed — because on a phone there is no hover and the tap has to answer. */
.door.d1{border-color:color-mix(in srgb,var(--green-ink) 46%,var(--line));
  box-shadow:0 0 0 1px color-mix(in srgb,var(--green-ink) 9%,transparent),
             0 14px 40px -14px color-mix(in srgb,var(--green-ink) 62%,transparent)}
.door.d2{border-color:color-mix(in srgb,var(--cyan-ink) 46%,var(--line));
  box-shadow:0 0 0 1px color-mix(in srgb,var(--cyan-ink) 9%,transparent),
             0 14px 40px -14px color-mix(in srgb,var(--cyan-ink) 62%,transparent)}
.door.d1:hover,.door.d1:focus-visible{border-color:color-mix(in srgb,var(--green-ink) 52%,var(--line));
  box-shadow:0 0 0 1px color-mix(in srgb,var(--green-ink) 16%,transparent),
             0 18px 48px -16px color-mix(in srgb,var(--green-ink) 68%,transparent)}
.door.d2:hover,.door.d2:focus-visible{border-color:color-mix(in srgb,var(--cyan-ink) 52%,var(--line));
  box-shadow:0 0 0 1px color-mix(in srgb,var(--cyan-ink) 16%,transparent),
             0 18px 48px -16px color-mix(in srgb,var(--cyan-ink) 68%,transparent)}
.door.d1:active{border-color:var(--green-ink);background:color-mix(in srgb,var(--green) 9%,var(--surface));
  box-shadow:0 0 0 2px color-mix(in srgb,var(--green-ink) 26%,transparent),
             0 10px 34px -14px color-mix(in srgb,var(--green-ink) 80%,transparent)}
.door.d2:active{border-color:var(--cyan-ink);background:color-mix(in srgb,var(--cyan) 9%,var(--surface));
  box-shadow:0 0 0 2px color-mix(in srgb,var(--cyan-ink) 26%,transparent),
             0 10px 34px -14px color-mix(in srgb,var(--cyan-ink) 80%,transparent)}
.door:active{transform:scale(.988)}
.door h3{font-size:var(--d3);margin-top:.2rem}
.door p{color:var(--ink-2);font-size:.98rem;max-width:32ch;line-height:1.6}
@media(max-width:640px){.door .float{display:none}.door{min-height:auto}}
@media(min-width:641px){.door .label,.door h3,.door p{padding-right:clamp(96px,13vw,164px)}}
.door .go{margin-top:auto;padding-top:var(--s3);display:flex;align-items:center;gap:.55rem;font-weight:800;font-size:.9rem}
.door .go .ar{display:inline-grid;place-items:center;width:1.9rem;height:1.9rem;border-radius:100px;border:1.5px solid var(--ink);transition:transform .45s var(--ease),background .35s,color .35s}
.door:hover .go .ar{transform:translateX(7px);background:var(--ink);color:var(--surface)}
.door .wash{position:absolute;inset:auto -22% -50% auto;width:70%;aspect-ratio:1;border-radius:50%;filter:blur(64px);opacity:.36;pointer-events:none;transition:opacity .6s,transform .8s var(--ease)}
.door:hover .wash{opacity:.48;transform:scale(1.16)}
.door:active .wash{opacity:.6;transform:scale(1.2)}
.door.d1 .wash{background:var(--green)} .door.d2 .wash{background:var(--cyan)}
.door .float{position:absolute;right:clamp(1.1rem,2.4vw,2.2rem);top:clamp(1.1rem,2.4vw,2.2rem);width:clamp(92px,12vw,148px);border-radius:14px;box-shadow:var(--e2);transform:rotate(6deg);transition:transform .7s var(--ease)}
.door:hover .float{transform:rotate(-4deg) scale(1.07) translateY(-5px)}

/* ---------------- section heads ---------------- */
.sec{padding-top:var(--sec)}
.sechead{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--s3);flex-wrap:wrap;margin-bottom:clamp(2rem,1.4rem + 1.8vw,3.2rem);padding-bottom:var(--s3);position:relative}
.sechead::after{content:"";position:absolute;left:0;bottom:0;height:3px;border-radius:99px;width:100%;
  background:var(--hue,var(--ink));transform-origin:left;transform:scaleX(0);transition:transform 1.1s var(--ease-io)}
.sechead.seen::after{transform:scaleX(1)}
.sechead h2{font-size:var(--d2);color:var(--hue-ink,var(--ink))}

/* Section headings cycle green -> cyan -> pink, the way she described it:
   splashes of the logo's three colours, in that order, repeating. */
[data-hue="green"]{--hue:var(--green);--hue-ink:var(--green-ink)}
[data-hue="cyan"] {--hue:var(--cyan); --hue-ink:var(--cyan-ink)}
[data-hue="pink"] {--hue:var(--pink); --hue-ink:var(--pink-ink)}
.sechead .r{color:var(--ink-3);font-size:.88rem}

/* ---------------- five tiles ---------------- */
.strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,196px),1fr));gap:var(--s2)}
.tile{
  border:1px solid var(--line);border-radius:var(--r-s);padding:clamp(1.15rem,.9rem + .7vw,1.6rem);text-align:left;background:var(--surface);
  transition:transform .5s var(--ease),box-shadow .5s,border-color .35s,background .35s;
  display:flex;flex-direction:column;gap:.4rem;min-height:142px;
}
.tile:hover{transform:translateY(-6px);border-color:var(--ink);box-shadow:var(--e2)}
.tile b{font-family:"Outfit",ui-sans-serif,sans-serif;font-size:.98rem;font-weight:600;letter-spacing:-.025em;line-height:1.25}
.tile small{color:var(--ink-3);font-size:.79rem;margin-top:auto}
.tile .dot{width:.6rem;height:.6rem;border-radius:100px;margin-bottom:.5rem;transition:transform .5s var(--ease)}
.tile:hover .dot{transform:scale(1.9)}

/* ---------------- a glimpse of everything ----------------
   Six rows, two products each, and an arrow into the category. The arrow is a
   column of its own rather than a link in the heading, because she drew it as
   the thing that sits after the two photographs. */
.glimpse{display:flex;flex-direction:column;gap:clamp(1.6rem,1rem + 1.6vw,2.6rem)}
.ghead{display:flex;align-items:baseline;gap:.7rem;flex-wrap:wrap;margin-bottom:.7rem}
.ghead b{font-family:"Outfit",ui-sans-serif,sans-serif;font-size:1rem;font-weight:600;letter-spacing:-.025em}
.ghead small{color:var(--ink-3);font-size:.79rem}
/* Two notes, and the second one is the correction to the first.

   "reduce the size of all the boxes in glimpse of everything by little, they
    feel too big" — they were over 400px each on a wide window, bigger than a
   real product card, for something meant to be a glimpse.

   The first attempt capped the whole row at 760px. That shrank the tiles and
   introduced a worse problem: "it looks like there's too much empty space on
   right side now". Capping the row leaves the leftover width *inside* the
   section, so it reads as a hole in the layout rather than as a margin.

   Two more attempts before this one, both worth recording because both look
   right until you resize:

   Capping the *tiles* and letting the arrow take the leftover put a 745px
   "and more" panel beside a 291px tile on a wide window — three times a tile.
   Capping the *row* at 960px looked perfect at the width the page happens to
   render at here and puts the hole straight back on a real 1,400px monitor,
   because `.sec` has no max-width of its own: whatever the row does not use is
   inside the section, not outside it.

   So: no cap at all, and all three columns proportional — the arrow fixed at
   .55 of a tile, so it can never balloon past them. The row fills whatever it
   is given at every width, which is the actual complaint, and the tiles are a
   third larger than the 270 that prompted it. They do grow on a very wide
   monitor, and that is the trade: two products cannot fill a 1,300px row and
   also stay small. The reason 410px felt too big before was not only the size
   — it was 49px of internal padding shrinking the product inside a large box.
   That padding is 6% now, so the product fills the tile it is given. */
.gcells{display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr) minmax(104px,.55fr);
  gap:var(--s2);align-items:stretch}
.gcell{
  position:relative;border:1px solid var(--line);border-radius:var(--r-s);background:var(--surface);
  aspect-ratio:1;overflow:hidden;display:grid;place-items:center;
  transition:transform .5s var(--ease),box-shadow .5s,border-color .35s;
}
.gcell:hover{transform:translateY(-5px);border-color:var(--ink);box-shadow:var(--e2)}
/* Two opposite notes, six days apart, and the answer sits between them.

   "If you could slightly reduce the size of the images on the home page of the
    items" — the product used to sit edge to edge, which read as cropped.
   "i feel like there is too much white gap between the box and the charms" —
    12% went too far the other way, and on a charm card it compounds: the card
    already carries its own margin around the charms, so the tile was padding
    a photograph that was padded.

   6% keeps the frame visible without the tile looking half empty. Still a
   percentage rather than a fixed 8px, so it holds the same proportion whether
   the tile is 106px on a phone or 270px on a desktop — a rem would shrink to
   nothing on the big one. */
.gcell img{width:100%;height:100%;object-fit:contain;padding:6%}

/* A lazily-loaded photograph arriving with no bridge.

   These are `loading="lazy"`, so on a phone the lower rows fetch as you reach
   them and each photograph *appears* — a hard cut from an empty tile to a
   product. Product cards elsewhere already handle this with [data-zoom]; the
   glimpse tiles had nothing. A fade is enough: the tile is already drawn, so
   the only jarring part is the content snapping in.

   Driven by a class rather than by `img { opacity: 0 }` so a photograph that
   is already in cache — every tile above the fold on a second visit — is
   painted opaque on the first frame and never fades at all. Fading a cached
   image is how a fast page is made to feel slow. */
.gcell img{opacity:1}
html.js .gcell img.loading{opacity:0}
html.js .gcell img{transition:opacity .42s var(--ease)}
@media(prefers-reduced-motion:reduce){
  html.js .gcell img{transition:opacity .12s linear}
}

/* A category she has opened before there is anything in it — her five new
   ones. It spans the two product cells so the arrow still sits where it does
   on every other row, and the row keeps its height rather than collapsing. */
.emptycat{
  grid-column:1/-1;margin:0;display:grid;place-items:center;text-align:center;
  border:1px dashed var(--line-2);border-radius:var(--r-s);background:var(--surface-2);
  color:var(--ink-3);font-size:.82rem;line-height:1.5;padding:var(--s3);min-height:8rem;
}
.gcell.empty{background:var(--surface-2);border-style:dashed;pointer-events:none}
.gcell .noshot{color:var(--ink-3);font-size:.72rem;text-align:center;line-height:1.5}
.gmore{
  border:1px solid var(--line);border-radius:var(--r-s);background:var(--surface-2);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;
  font-size:.82rem;color:var(--ink-2);font-weight:500;
  transition:transform .5s var(--ease),box-shadow .5s,border-color .35s,background .35s,color .35s;
}
.gmore .ar{font-size:1.5rem;line-height:1;transition:transform .45s var(--ease)}
/* "when u hover its too black make it more subtle."

   The fill used to go to full ink. That was fine when this panel was a 104px
   icon column; the row now gives it around 190px beside two 340px tiles, and a
   block of solid near-black at that size stops reading as a hover state and
   starts reading as a hole punched in the page.

   So the hover moves the *border and the arrow* rather than the ground. The
   surface lifts by one step, which is the same move a product card makes, and
   the arrow still slides — that was always the part carrying the invitation. */
.gmore:hover{background:var(--surface);border-color:var(--ink-3);box-shadow:var(--e2);color:var(--ink)}
.gmore:hover .ar{transform:translateX(5px);color:var(--cyan-ink)}
@media(max-width:560px){
  .gcells{grid-template-columns:1fr 1fr}
  .gmore{grid-column:1/-1;flex-direction:row;padding:.85rem}
}

/* ---------------- the short FAQ ---------------- */
.faq{display:grid;gap:.55rem;max-width:70ch}
.faq details{
  border:1px solid var(--line);border-radius:var(--r-s);background:var(--surface);
  padding:.85rem 1.1rem;transition:border-color .3s,box-shadow .4s;
}
.faq details[open]{border-color:var(--line-2);box-shadow:var(--e1)}
.faq summary{
  cursor:pointer;list-style:none;font-family:"Outfit",ui-sans-serif,sans-serif;
  font-size:.94rem;font-weight:600;letter-spacing:-.015em;
  display:flex;justify-content:space-between;align-items:center;gap:var(--s2);
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{
  content:"+";font-family:"DM Mono",monospace;font-size:1.1rem;color:var(--ink-3);
  transition:transform .22s var(--ease),color .22s var(--ease);
}
/* the glyph swaps instantly; the half-turn is what carries the change */
.faq details[open] summary::after{content:"\2212";transform:rotate(180deg);color:var(--ink)}
/* `open` stays true until a close has finished playing, so the marker and the
   paragraph follow the *intent* instead — otherwise both snap at the very end */
.faq details[data-want="closed"] summary::after{content:"+";transform:none;color:var(--ink-3)}

/* An accordion is the one place height is worth animating — there is no
   transform that opens a box. Kept to 220ms because it costs layout on every
   frame, and closing is quicker than opening: you have already read it. */
.faq-a{overflow:hidden;transition:height .22s var(--ease),opacity .22s var(--ease)}
.faq details:not([open]) .faq-a{height:0;opacity:0}
.faq-a p{
  margin:.7rem 0 0;font-size:.88rem;line-height:1.65;color:var(--ink-2);max-width:62ch;
  transition:transform .26s var(--ease);
}
.faq details:not([open]) .faq-a p,
.faq details[data-want="closed"] .faq-a p{transform:translateY(-6px)}

@media(prefers-reduced-motion:reduce){
  /* the fade stays — it still says which panel changed — the movement goes */
  .faq-a{transition:opacity .15s ease}
  .faq-a p,.faq summary::after{transition:none}
}

/* ---------------- shop ---------------- */
.shopwrap{display:grid;grid-template-columns:230px 1fr;gap:clamp(2.4rem,1.4rem + 3.6vw,5.5rem);align-items:start}
@media(max-width:900px){.shopwrap{grid-template-columns:1fr;gap:var(--s4)}}
.side{position:sticky;top:96px}
@media(max-width:900px){.side{position:static}}
.side h4{font-family:"Outfit",ui-sans-serif,sans-serif;font-size:.82rem;letter-spacing:-.01em;margin:0 0 var(--s2);font-weight:600}
.cats{display:flex;flex-direction:column;gap:.3rem}
@media(max-width:900px){.cats{flex-direction:row;flex-wrap:wrap}}
.cats button{
  text-align:left;padding:.6rem .85rem;border-radius:9px;font-size:.9rem;font-weight:500;color:var(--ink-2);
  transition:background .3s,color .3s,padding-left .35s var(--ease);display:flex;justify-content:space-between;gap:var(--s2);
}
@media(max-width:900px){.cats button{border:1px solid var(--line);border-radius:100px}}
.cats button:hover{background:var(--surface-2);color:var(--ink);padding-left:1.1rem}
.cats button[aria-pressed="true"]{background:var(--ink);color:var(--surface)}
.cats button[aria-pressed="true"] .n{color:color-mix(in srgb,var(--surface) 55%,transparent)}
.cats .n{font-family:"DM Mono",monospace;font-size:.74rem;color:var(--ink-3)}

/* ---------------- cards ---------------- */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,236px),1fr));gap:clamp(1.1rem,.7rem + 1.3vw,1.9rem)}
.grid.wide{grid-template-columns:repeat(auto-fill,minmax(min(100%,286px),1fr))}
.card{
  border:1px solid var(--line);border-radius:var(--r-s);overflow:hidden;background:var(--surface);
  display:flex;flex-direction:column;transition:transform .5s var(--ease),box-shadow .5s,border-color .35s;
}
.card:hover{transform:translateY(-7px);box-shadow:var(--e3);border-color:var(--line-2)}
.card .ph{position:relative;aspect-ratio:1;background:var(--surface-2);overflow:hidden}
/* width:100% because .card is a centred flex column — a grid child would
   otherwise shrink to the size of the two words inside it */
.card .ph.empty{display:grid;place-items:center;width:100%;border-bottom:1px dashed var(--line-2)}
.noshot{font-family:"DM Mono",monospace;font-size:.65rem;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-3);line-height:1.9;text-align:center}
/* contain, not cover. Every product photo is a square on white, so the two are
   identical for the catalogue as it stands — but cover silently guillotined the
   tall book covers, and it would do the same to any off-square photo uploaded
   through the dashboard later. */
.card .ph img{width:100%;height:100%;object-fit:contain;transition:transform .8s var(--ease)}
.card:hover .ph img{transform:scale(1.07)}
/* badges sit under the photo now, not on it — over the plate they hid the
   hand-written design numbers, so you couldn't tell which design was which */
.tags{display:flex;flex-wrap:wrap;gap:.35rem;margin:.15rem 0 .1rem}
.card .vr{background:var(--surface-2);border:1px solid var(--line);border-radius:100px;padding:.2rem .6rem;font-size:.66rem;font-family:"DM Mono",monospace;letter-spacing:.05em;color:var(--ink-2)}
.card .bd{padding:clamp(1rem,.85rem + .5vw,1.35rem);display:flex;flex-direction:column;gap:.4rem;flex:1}
.card .ct{font-size:.68rem;color:var(--ink-3);font-family:"DM Mono",monospace;letter-spacing:.13em;text-transform:uppercase}
.card .nm{font-weight:700;font-size:.95rem;line-height:1.35}
.card .ds{font-size:.79rem;color:var(--ink-3);line-height:1.5}
.card .row{display:flex;align-items:center;justify-content:space-between;gap:var(--s2);margin-top:auto;padding-top:var(--s2)}
.card .pr{font-family:"DM Mono",monospace;font-weight:500;font-size:.98rem}
.add{background:var(--ink);color:var(--surface);border-radius:100px;padding:.46rem .95rem;font-size:.78rem;font-weight:700;transition:background .3s,transform .3s var(--ease);white-space:nowrap}
.add:hover{background:var(--berry);transform:translateY(-2px)}
.add.done{background:var(--leaf)}

.phold{
  aspect-ratio:1;background:repeating-linear-gradient(45deg,var(--surface-2) 0 11px,var(--surface) 11px 22px);
  display:grid;place-items:center;text-align:center;padding:var(--s2);
}
.phold span{font-family:"DM Mono",monospace;font-size:.65rem;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-3);line-height:1.9}

/* ---------------- builder ---------------- */
.steps{display:flex;gap:.6rem;margin:0 0 var(--s5);flex-wrap:wrap}
.stp{display:flex;align-items:center;gap:.6rem;padding:.6rem 1.1rem;border:1px solid var(--line);border-radius:100px;font-size:.85rem;font-weight:600;color:var(--ink-3);transition:.45s var(--ease)}
.stp b{font-family:"DM Mono",monospace;font-size:.7rem}
.stp[data-on="1"]{border-color:var(--ink);color:var(--ink)}
.stp[data-done="1"]{background:var(--leaf);border-color:var(--leaf);color:var(--surface)}

.build{display:grid;grid-template-columns:1fr 372px;gap:clamp(1.8rem,1.2rem + 2.6vw,3.4rem);align-items:start}
@media(max-width:1020px){.build{grid-template-columns:1fr}}
.panel{border:1px solid var(--line);border-radius:var(--r);padding:clamp(1.5rem,1.1rem + 1.5vw,2.4rem);background:var(--surface)}
.panel + .panel{margin-top:var(--gap)}
.panel h3{font-size:1.12rem;letter-spacing:-.03em}
.panel .hint{color:var(--ink-2);font-size:.9rem;margin:.6rem 0 var(--s3);line-height:1.6;max-width:46ch}

.bases{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,178px),1fr));gap:var(--s2)}
.base{
  border:1.5px solid var(--line);border-radius:var(--r-s);padding:clamp(1.05rem,.9rem + .5vw,1.4rem);text-align:left;
  display:flex;flex-direction:column;gap:.42rem;transition:border-color .35s,background .35s,transform .45s var(--ease);
}
.base:hover{transform:translateY(-4px);border-color:var(--line-2)}
.base[aria-pressed="true"]{border-color:var(--ink);background:var(--surface-2)}
/* fixed box, not a bare <img> — the pictures are different shapes, and without
   a box of its own each tile's text started at a different height */
.base .baseart{display:block;width:84px;height:84px;margin-bottom:.55rem;flex-shrink:0}
.base .baseart img{width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply}
.base b{font-size:.94rem;font-weight:700;line-height:1.3}
/* the meta line takes up the slack so the price sits on the same baseline in
   every tile, however many lines "on a lobster clasp" happens to wrap to */
.base .meta{font-size:.74rem;color:var(--ink-3);flex:1 0 auto}
.base .p{font-family:"DM Mono",monospace;font-size:.82rem;color:var(--ink-2);margin-top:auto;padding-top:.3rem}

.opts{display:flex;flex-wrap:wrap;gap:.55rem}
.opt{border:1.5px solid var(--line);border-radius:100px;padding:.48rem 1.05rem;font-size:.85rem;font-weight:600;color:var(--ink-2);transition:.3s}
.opt:hover{border-color:var(--line-2);transform:translateY(-2px)}
.opt[aria-pressed="true"]{border-color:var(--ink);background:var(--ink);color:var(--surface)}
/* A colour pill shows the colour. "I don't know how ppl would choose it coz it
   doesn't zoom so it's not visible" — the photograph of ten clasps cannot be a
   picker at tile size, so the word carries the colour beside it. The ring is
   there so a white or a pale enamel still reads as a disc rather than a gap. */
.opt.swatch{display:inline-flex;align-items:center;gap:.5rem}
.opt.swatch::before{
  content:"";width:.85em;height:.85em;border-radius:50%;flex:0 0 auto;
  background:var(--sw);box-shadow:inset 0 0 0 1px rgb(0 0 0 / .22);
}
.opt .sw{display:inline-block;width:.66rem;height:.66rem;border-radius:100px;margin-right:.5rem;vertical-align:-1px;border:1px solid rgba(0,0,0,.14)}

.arrange{display:flex;flex-wrap:wrap;gap:var(--s2);min-height:128px;padding:var(--s3);border:1px dashed var(--line-2);border-radius:var(--r-s);background:var(--surface-2)}
.arrange:empty::after{content:"Charms you add will line up here";font-size:.87rem;color:var(--ink-3);margin:auto}
.chip{position:relative;width:84px;border-radius:10px;overflow:hidden;background:var(--surface);border:1px solid var(--line);cursor:grab;transition:transform .4s var(--ease),box-shadow .4s,border-color .3s}
.chip:active{cursor:grabbing}
.chip.pop{animation:pop .55s var(--ease)}
@keyframes pop{0%{transform:scale(.5);opacity:0}60%{transform:scale(1.09)}100%{transform:none;opacity:1}}
.chip.drag{opacity:.3}
.chip.over{transform:translateY(-6px) scale(1.04);box-shadow:var(--e2);border-color:var(--berry)}
.chip img{aspect-ratio:1;object-fit:cover;width:100%;pointer-events:none}
.chip .ix{position:absolute;left:4px;top:4px;background:var(--ink);color:var(--surface);border-radius:100px;width:1.15rem;height:1.15rem;display:grid;place-items:center;font-size:.63rem;font-family:"DM Mono",monospace}
.chip .x{position:absolute;right:3px;top:3px;background:color-mix(in srgb,var(--surface) 94%,transparent);border-radius:100px;width:1.2rem;height:1.2rem;display:grid;place-items:center;font-size:.9rem;line-height:1;opacity:0;transition:opacity .25s}
.chip:hover .x,.chip:focus-within .x{opacity:1}
.chip .mv{position:absolute;inset:auto 0 0 0;display:flex;justify-content:space-between;background:color-mix(in srgb,var(--surface) 94%,transparent);opacity:0;transition:opacity .25s}
.chip:hover .mv,.chip:focus-within .mv{opacity:1}
.chip .mv button{flex:1;font-size:.82rem;line-height:1.6;color:var(--ink-2)}
.chip .mv button:hover{background:var(--surface-2);color:var(--ink)}

.sum{position:sticky;top:96px;border:1.5px solid var(--ink);border-radius:var(--r);overflow:hidden;background:var(--surface);box-shadow:var(--e2)}
@media(max-width:1020px){.sum{position:static}}
.sum .hd{padding:1.2rem 1.5rem;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:center;gap:var(--s2)}
.sum .hd b{font-family:"Outfit",ui-sans-serif,sans-serif;font-size:.95rem;font-weight:600;letter-spacing:-.025em}
.sum .bd{padding:1.5rem;display:flex;flex-direction:column;gap:.85rem}
.li{display:flex;justify-content:space-between;gap:var(--s3);font-size:.9rem}
.li .k{color:var(--ink-2)}
.li .v{font-family:"DM Mono",monospace;white-space:nowrap}
.li.ord{flex-direction:column;gap:.35rem}
.li.ord .v{white-space:normal;font-size:.78rem;line-height:1.65;color:var(--ink-2)}
.li.tot{border-top:1.5px solid var(--ink);margin-top:.5rem;padding-top:var(--s2);font-weight:800;font-size:1.05rem}
.li.tot .v{font-size:1.2rem;transition:opacity .25s}
.li.tot .v.flash{animation:flash .55s var(--ease)}
@keyframes flash{0%{opacity:.25;transform:translateY(-4px)}100%{opacity:1;transform:none}}
.cta{width:100%;background:var(--ink);color:var(--surface);border-radius:100px;padding:.95rem;font-weight:800;font-size:.94rem;margin-top:var(--s2);transition:background .3s,transform .3s var(--ease)}
.cta:hover:not(:disabled){background:var(--berry);transform:translateY(-2px)}
.cta:disabled{opacity:.3;cursor:not-allowed}
.warn{background:#FBF0DC;border:1px solid #E3C994;border-radius:var(--r-s);padding:.9rem 1.1rem;font-size:.85rem;color:#6C4C13;display:none;margin-top:var(--s3);line-height:1.6}
.warn.on{display:block;animation:scr .5s var(--ease) both}

/* flying charm */
.fly{position:fixed;z-index:95;border-radius:10px;overflow:hidden;pointer-events:none;box-shadow:var(--e3)}
.fly img{width:100%;height:100%;object-fit:cover}

/* ---------------- pdp ---------------- */
.pdp{display:grid;grid-template-columns:1.05fr 1fr;gap:clamp(2rem,1.2rem + 3.2vw,4.5rem);align-items:start}
@media(max-width:900px){.pdp{grid-template-columns:1fr}}
.gal{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--s2)}
.gal .phold{border:1px solid var(--line);border-radius:var(--r-s)}
.pdp h2{font-size:var(--d2);margin:.6rem 0 0}
.price{font-family:"DM Mono",monospace;font-size:1.65rem;font-weight:500;margin:var(--s2) 0 var(--s4)}
.fieldset{border:none;padding:0;margin:0 0 var(--s4)}
.fieldset legend{padding:0;font-family:"DM Mono",monospace;font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-3);margin-bottom:.8rem}
textarea{width:100%;border:1.5px solid var(--line);border-radius:var(--r-s);padding:.9rem 1rem;font:inherit;font-size:.92rem;resize:vertical;min-height:92px;background:var(--surface);color:var(--ink)}
textarea:focus{border-color:var(--ink);outline:none}
.care{border-top:1px solid var(--line);margin-top:var(--s4);padding-top:var(--s3);display:flex;flex-direction:column;gap:var(--s2)}
.care .r{display:flex;gap:var(--s3);font-size:.88rem;color:var(--ink-2);line-height:1.6}
.care .r b{min-width:6rem;color:var(--ink);font-size:.66rem;font-family:"DM Mono",monospace;letter-spacing:.16em;text-transform:uppercase;padding-top:.22rem}

/* ---------------- drawer ---------------- */
.scrim{position:fixed;inset:0;background:rgba(28,24,20,.44);opacity:0;pointer-events:none;transition:opacity .45s;z-index:70;backdrop-filter:blur(3px)}
.scrim.on{opacity:1;pointer-events:auto}
.drawer{position:fixed;top:0;right:0;bottom:0;width:min(94vw,432px);background:var(--ground);z-index:80;transform:translateX(101%);transition:transform .55s var(--ease);display:flex;flex-direction:column;border-left:1px solid var(--line)}
.drawer.on{transform:none}
.drawer .hd{padding:1.3rem 1.5rem;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:center}
/* the close cross has to be a real target on a phone, not a 20px glyph */
.drawer .hd button{min-width:44px;min-height:44px;display:grid;place-items:center;margin:-.4rem -.5rem -.4rem 0;color:var(--ink-2)}
#qv-specs{margin:.3rem 0 .2rem;padding-top:.8rem;border-top:1px solid var(--line)}
.sw-match{background:conic-gradient(from 200deg,#EFCE84,#B08535,#E4E2DC,#A5A49E,#EFCE84)}
.specs{display:grid;grid-template-columns:auto 1fr;gap:.45rem 1.1rem;margin:.9rem 0 0;font-size:.9rem}
.specs dt{font-family:"DM Mono",monospace;font-size:.66rem;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-3);padding-top:.2rem}
.specs dd{margin:0;color:var(--ink-2);line-height:1.6}
@media(max-width:560px){.specs{grid-template-columns:1fr;gap:.15rem .5rem}.specs dd{margin-bottom:.6rem}}
.keepshopping{display:flex;justify-content:center;width:100%;margin-top:.6rem}
.drawer .hd b{font-family:"Outfit",ui-sans-serif,sans-serif;font-size:1.02rem;font-weight:600;letter-spacing:-.03em}
.drawer .bd{flex:1;overflow-y:auto;padding:1.5rem;display:flex;flex-direction:column;gap:var(--s3)}
.drawer .ft{padding:1.5rem;border-top:1px solid var(--line)}
.crow{display:flex;gap:var(--s2);align-items:center;animation:scr .5s var(--ease) both}
.crow img{width:60px;height:60px;border-radius:9px;object-fit:cover;border:1px solid var(--line);flex-shrink:0}
.crow .t{flex:1;min-width:0}
.crow .t b{display:block;font-size:.9rem;font-weight:700;line-height:1.35}
.crow .t small{color:var(--ink-3);font-size:.75rem;font-family:"DM Mono",monospace;line-height:1.5}
.empty{margin:auto;text-align:center;color:var(--ink-3);font-size:.9rem;line-height:1.8}

footer{border-top:1px solid var(--line);padding:var(--s5) var(--pad) var(--s6);background:var(--ground-2)}
footer .in{max-width:1560px;margin:0 auto;display:flex;justify-content:space-between;gap:var(--s4);flex-wrap:wrap;align-items:flex-end}
footer .note{font-size:.8rem;color:var(--ink-3);max-width:52ch;line-height:1.75;margin-top:.8rem}
/* her contact line and the policy links, under the note */
footer .foot-contact{font-size:.84rem;color:var(--ink-3);line-height:1.8;margin-top:.9rem;max-width:62ch}
footer .foot-contact a,footer .foot-links a,footer .label a{color:var(--ink-2);text-decoration:underline;
  text-decoration-color:var(--line-2);text-underline-offset:3px}
footer .foot-contact a:hover,footer .foot-links a:hover,footer .label a:hover{color:var(--ink);text-decoration-color:currentColor}
footer .foot-links{display:flex;flex-wrap:wrap;gap:.3rem 1.1rem;margin-top:.7rem;font-size:.84rem}
/* The footer's one sentence. .label is tracked capitals, which is right for a
   two-word tag and hard work for a sentence with a link in it. */
footer .label{text-transform:none;letter-spacing:.02em;font-size:.8rem;line-height:1.6;max-width:36ch}
/* The region picker, now in the footer: its pop-up opens upward, from the
   button's left edge, because there is no room below the last thing on the
   page. Set in full so the header-era placement (and its phone override,
   which centred it under the button) cannot leak in. */
footer .regionwrap{align-self:flex-end}
/* No animation here: the phone rule gives the pop-up keyframes built around
   translateX(-50%) -- it was centred under a header button -- and that kept it
   centred on a button at the far left of the footer, half off the screen. */
footer .regionpop{top:auto;bottom:calc(100% + .55rem);left:0;right:auto;transform:none;animation:none}
/* There is room down here for the country's name, which the header had to drop. */
footer .regionbtn .rname{display:inline}

.toast{position:fixed;left:50%;bottom:1.8rem;transform:translate(-50%,calc(100% + 4rem));
  background:var(--ink);color:var(--surface);padding:.8rem 1.4rem;border-radius:100px;font-size:.87rem;
  font-weight:600;z-index:90;opacity:0;pointer-events:none;box-shadow:var(--e3);
  transition:transform .5s var(--ease),opacity .3s}
.toast.on{transform:translate(-50%,0);opacity:1}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{animation:none!important;transition:none!important}
  html.js [data-rise],html.js [data-pop],html.js [data-wipe],html.js .lnwrap > span{opacity:1;transform:none;clip-path:none}
  html.js [data-zoom] img{transform:none}
  .sechead::after{transform:scaleX(1)}
  #hero-h1{transform:none!important}
}

/* ---------------- gallery on the product page ---------------- */
.gal .gmain{grid-column:span 2;width:100%;aspect-ratio:1;object-fit:cover;border-radius:var(--r-s);border:1px solid var(--line)}
.gal .gthumb{width:100%;aspect-ratio:1;object-fit:cover;border-radius:var(--r-s);border:1px solid var(--line);
  transition:transform .5s var(--ease)}
.gal .gthumb:hover{transform:translateY(-4px)}

/* ---------------- checkout ---------------- */
.cowrap{display:grid;grid-template-columns:1fr 372px;gap:clamp(1.8rem,1.2rem + 2.6vw,3.4rem);align-items:start}
@media(max-width:1020px){.cowrap{grid-template-columns:1fr}}
.costeps{display:flex;gap:.6rem;margin-bottom:var(--s4);flex-wrap:wrap}
.cstep{display:flex;align-items:center;gap:.6rem;padding:.6rem 1.1rem;border:1px solid var(--line);
  border-radius:100px;font-size:.85rem;font-weight:600;color:var(--ink-3);transition:.4s var(--ease)}
.cstep b{font-family:"DM Mono",monospace;font-size:.7rem}
.cstep[aria-current="true"]{border-color:var(--ink);color:var(--ink)}
.cstep[data-done="1"]{background:var(--leaf);border-color:var(--leaf);color:var(--surface)}
.copane{display:none}
.copane.on{display:block;animation:scr .5s var(--ease)}

.fgrid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s2) var(--s3)}
@media(max-width:640px){.fgrid{grid-template-columns:1fr}}
.f2.wide{grid-column:1/-1}
.f2 label{display:block;font-family:"DM Mono",monospace;font-size:.65rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3);margin-bottom:.45rem}
.f2 input{width:100%;border:1.5px solid var(--line);border-radius:10px;background:var(--surface);
  padding:.72rem .95rem;font:inherit;font-size:.92rem;color:var(--ink);transition:border-color .25s}
.f2 input:focus{outline:none;border-color:var(--ink)}
.f2 input.bad{border-color:var(--berry);background:color-mix(in srgb,var(--berry) 5%,transparent)}

.coitem{display:flex;gap:var(--s2);align-items:center;padding:.85rem 0;border-bottom:1px solid var(--line)}
.coitem:last-of-type{border-bottom:none}
.coitem img{width:56px;height:56px;border-radius:9px;object-fit:cover;border:1px solid var(--line);flex-shrink:0}
.coitem .t{flex:1;min-width:0}
.coitem .t b{display:block;font-size:.9rem;font-weight:700}
.coitem .t small{color:var(--ink-3);font-size:.76rem;font-family:"DM Mono",monospace;line-height:1.5}
/* Which charms, under the build's detail line. The <small> above it is inline,
   so without display:block the list ran straight on from "chain colour: …" and
   read as part of it. One rule for both, sat after both base rules. */
.crow .t small.cpicks,.coitem .t small.cpicks{display:block;margin-top:.2rem;color:var(--ink);line-height:1.45}
.coitem .p{font-family:"DM Mono",monospace;font-weight:500;white-space:nowrap}

.coupon{margin-top:var(--s3);padding-top:var(--s3);border-top:1px solid var(--line)}
.coupon label{display:block;font-family:"DM Mono",monospace;font-size:.65rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3);margin-bottom:.5rem}
.crow2{display:flex;gap:.6rem}
.crow2 input{flex:1;border:1.5px solid var(--line);border-radius:100px;background:var(--surface);
  padding:.68rem 1.1rem;font:inherit;font-size:.9rem;color:var(--ink);text-transform:uppercase;letter-spacing:.05em}
.crow2 input:focus{outline:none;border-color:var(--ink)}
.btn-apply{border:1.5px solid var(--ink);border-radius:100px;padding:.68rem 1.3rem;font-weight:700;
  font-size:.85rem;transition:.25s;white-space:nowrap}
.btn-apply:hover{background:var(--ink);color:var(--surface)}
.cmsg{font-size:.84rem;margin-top:.6rem;min-height:1.2em}
.cmsg.ok{color:var(--leaf);font-weight:600}
.cmsg.no{color:var(--berry);font-weight:600}
.li.save .v,.li.save .k{color:var(--leaf);font-weight:700}

.done{display:none;text-align:center;padding:clamp(3rem,2rem + 5vw,6rem) 1rem;flex-direction:column;
  align-items:center;gap:.7rem}
.done.on{display:flex;animation:scr .6s var(--ease)}
.done .tick{width:4rem;height:4rem;border-radius:100px;background:var(--leaf);color:var(--surface);
  display:grid;place-items:center;font-size:1.9rem;margin-bottom:var(--s2)}
.done h2{font-size:var(--d2)}
.done p{max-width:46ch;color:var(--ink-2)}
.done .muted{font-size:.88rem;color:var(--ink-3)}

/* ---------------- quantity stepper ---------------- */
.qty{display:flex;align-items:center;gap:.3rem;margin-top:.45rem}
.qty button{width:1.6rem;height:1.6rem;border:1.5px solid var(--line);border-radius:7px;background:var(--surface);
  font-size:.9rem;font-weight:700;line-height:1;color:var(--ink-2);display:grid;place-items:center;
  transition:border-color .2s,background .2s,color .2s}
.qty button:hover{border-color:var(--ink);background:var(--ink);color:var(--surface)}
.qty > span{min-width:1.5rem;text-align:center;font-family:"DM Mono",monospace;font-size:.85rem;
  font-variant-numeric:tabular-nums}
.qty .rm{width:auto;padding:0 .55rem;font-size:.68rem;font-weight:600;letter-spacing:.04em;
  font-family:"DM Mono",monospace;border-color:transparent;color:var(--ink-3);margin-left:.2rem}
.qty .rm:hover{background:none;border-color:var(--berry);color:var(--berry)}
.coitem .qty{margin-top:.4rem}

/* ---------------- cart drawer extras ---------------- */
.coupon.tight{margin-top:0;padding-top:0;border-top:none;margin-bottom:var(--s2)}
.coupon.tight label{margin-bottom:.4rem}
.coupon.tight .cmsg{margin-top:.45rem;font-size:.8rem}
.shipnote{font-size:.76rem;color:var(--ink-3);text-align:center;margin-top:.5rem;
  font-family:"DM Mono",monospace;letter-spacing:.04em}
#cart-totals .li{font-size:.85rem;padding:.1rem 0}

/* ---------------- checkout, refined ---------------- */
.costeps{align-items:center}
.cline{flex:1;max-width:70px;height:1.5px;background:var(--line-2);border-radius:2px}
@media(max-width:520px){.cline{display:none}}
#s-checkout .panel{box-shadow:var(--e2)}
.trust{display:flex;flex-wrap:wrap;gap:.5rem 1.2rem;margin-top:var(--s3);padding-top:var(--s3);
  border-top:1px solid var(--line)}
.trust span{font-family:"DM Mono",monospace;font-size:.7rem;letter-spacing:.06em;color:var(--ink-3);
  display:flex;align-items:center;gap:.4rem}
.trust span::before{content:"";width:.45rem;height:.45rem;border-radius:100px;background:var(--leaf)}
#co-summary{position:sticky;top:96px}
@media(max-width:1020px){#co-summary{position:static}}
#co-items{margin-bottom:var(--s2)}
.copane h3{letter-spacing:-.03em}
#co-back{width:100%;text-align:center}
.f2 input::placeholder{color:var(--ink-3);opacity:.65}

/* ---------------- stock signalling ---------------- */
.stockbadge{border-radius:100px;padding:.22rem .65rem;
  font-family:"DM Mono",monospace;font-size:.64rem;letter-spacing:.07em;text-transform:uppercase;
  font-weight:500;backdrop-filter:blur(6px)}
.stockbadge.out{background:color-mix(in srgb,var(--ink) 88%,transparent);color:var(--surface)}
.stockbadge.low{background:color-mix(in srgb,var(--brass) 92%,transparent);color:#fff}
.card.soldout .ph img{filter:grayscale(.75) opacity(.62)}
.card.soldout:hover{transform:none;box-shadow:none}
.add:disabled{background:var(--line-2);cursor:not-allowed}
.add:disabled:hover{background:var(--line-2);transform:none}

/* charm name under each chip in the build strip */
.chip{width:96px}
.chip .cname{display:block;font-size:.62rem;line-height:1.25;padding:.3rem .35rem .38rem;
  text-align:center;color:var(--ink-2);border-top:1px solid var(--line);background:var(--surface);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chip .mv{inset:auto 0 1.55rem 0}

/* ---------------- payment method ---------------- */
.pays{display:flex;flex-direction:column;gap:.6rem}
.pay{display:flex;align-items:center;gap:1rem;width:100%;text-align:left;
  border:1.5px solid var(--line);border-radius:var(--r-s);padding:1rem 1.15rem;background:var(--surface);
  transition:border-color .25s,background .25s,transform .3s var(--ease)}
.pay:hover:not(:disabled){border-color:var(--line-2);transform:translateY(-2px)}
.pay.on{border-color:var(--ink);background:var(--surface-2)}
.pay.off{opacity:.5;cursor:not-allowed}
.pmark{width:2.6rem;height:2.6rem;border-radius:9px;display:grid;place-items:center;flex-shrink:0;
  font-family:"DM Mono",monospace;font-size:.72rem;font-weight:600;letter-spacing:.02em;color:#fff}
.pmark.upi{background:var(--teal)} .pmark.card{background:var(--ink);font-size:.9rem}
.pmark.bank{background:var(--plum)} .pmark.wallet{background:var(--brass)}
.pmark.cod{background:var(--line-2);color:var(--ink-3);font-size:.6rem}
.pay .pt{flex:1;min-width:0}
.pay .pt b{display:block;font-size:.94rem;font-weight:700}
.pay .pt small{color:var(--ink-3);font-size:.8rem;line-height:1.5}
.pcheck{width:1.15rem;height:1.15rem;border-radius:100px;border:1.5px solid var(--line-2);flex-shrink:0;
  position:relative;transition:.25s}
.pay.on .pcheck{border-color:var(--ink);background:var(--ink)}
.pay.on .pcheck::after{content:"";position:absolute;left:.34rem;top:.16rem;width:.28rem;height:.55rem;
  border:solid var(--surface);border-width:0 2px 2px 0;transform:rotate(45deg)}
.payfoot{margin-top:var(--s3);padding-top:var(--s3);border-top:1px solid var(--line)}
.lock{font-family:"DM Mono",monospace;font-size:.72rem;color:var(--ink-3);display:flex;
  align-items:center;gap:.5rem;line-height:1.6}
.lock::before{content:"";width:.45rem;height:.45rem;border-radius:100px;background:var(--leaf);flex-shrink:0}


/* ==========================================================================
   Tile entrance — the five sub-brands on the home page
   Scroll-triggered once by the same IntersectionObserver as [data-rise], but
   shorter and staggered so the row reads as one group arriving, not five
   unrelated fades. Transform + opacity only.
   ========================================================================== */
/* A transition, not keyframes: a transition can't be left pinned at frame
   zero if it never gets to run. The per-tile delay is set inline by the
   observer and cleared once it has played, so it never slows the hover. */
html.js [data-pop]{opacity:0;transform:translateY(14px) scale(.97)}
html.js [data-pop].seen{opacity:1;transform:none;
  transition:opacity .42s var(--ease),transform .42s var(--ease),
             box-shadow .5s var(--ease),border-color .35s,background .35s}



/* ==========================================================================
   Phone — two products per row, everything sized for a thumb
   ========================================================================== */
@media(max-width:760px){
  /* every section stays on screen, in a row you can flick through */
  .tools{gap:.4rem}
  .cur button{padding:.42rem .5rem;font-size:.64rem}
  /* The country name is what goes when the row runs out of width. The flag and
     the currency code together still say which country and which money, and
     the panel behind the button spells it out in full the moment it opens.
     Dropping the currency instead would leave a flag that looks like a
     language switch. */
  .regionbtn{padding:.34rem .55rem;gap:.34rem;min-height:36px}
  .regionbtn .rname{display:none}
  .regionbtn .rcur{font-size:.66rem}
  /* Centred under the button rather than right-aligned, because at 375px a
     19rem panel hung off the right edge runs past the left gutter. The panel
     keeps a transform of its own now, so it needs its own keyframes — the
     desktop ones would animate translateX(-50%) away and drop it half a panel
     to the right on the way in. */
  .regionpop{right:auto;left:50%;transform:translateX(-50%);
    width:min(20rem,calc(100vw - 1.6rem));animation:regionpopm .18s var(--ease)}
  @keyframes regionpopm{
    from{opacity:0;transform:translate(-50%,-6px)}
    to{opacity:1;transform:translate(-50%,0)}
  }
  .regionpop .cur button{min-height:40px}
  .cartbtn{padding:0 .8rem;min-height:44px;font-size:.78rem}
  .navscroller{width:100%}
  /* The nav is the one strip allowed outside the page gutter. At 375px the
     gutter costs it 54px, which is the difference between the nine tabs
     wrapping to two rows and wrapping to three — and three was the thing she
     looked at and said "there's all of random empty space". */
  nav.main{width:auto;margin:.15rem calc(var(--pad) * -0.72) 0;padding:.1rem .2rem}
  nav.main button{font-size:.76rem;padding:.42rem .55rem;min-height:34px}

  /* two per row, everywhere products are shown */
  .grid,.grid.wide{grid-template-columns:repeat(2,minmax(0,1fr));gap:.75rem}
  .card .bd{padding:.7rem .75rem .8rem;gap:.28rem}
  .card .ct{font-size:.6rem;letter-spacing:.1em}
  .card .nm{font-size:.83rem;line-height:1.3}
  .card .ds{font-size:.72rem;line-height:1.45;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .card .row{flex-wrap:wrap;gap:.45rem;padding-top:.6rem}
  .card .pr{font-size:.87rem}
  .card .vr,.stockbadge{font-size:.6rem;padding:.18rem .5rem}
  .add{min-height:44px;display:inline-flex;align-items:center;padding:0 .95rem;font-size:.76rem}
  .vpick button{width:2.5rem;height:2.5rem}

  /* six sub-brands: three clean rows of two */
  .strip{grid-template-columns:repeat(2,minmax(0,1fr));gap:.7rem}
  .tile{min-height:0;padding:.95rem 1rem;gap:.3rem}
  .tile b{font-size:.88rem}
  .tile small{font-size:.72rem;margin-top:.25rem}

  /* charm categories: six filters, three across, two rows */
  .side h4{margin-bottom:.6rem}
  .cats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.4rem}
  .cats button{flex-direction:column;align-items:center;justify-content:center;gap:.05rem;
    min-height:52px;padding:.5rem .35rem;border-radius:12px;text-align:center;
    font-size:.76rem;line-height:1.2}
  .cats button:hover{padding-left:.35rem}
  .cats .n{font-size:.65rem}

  /* pagination: thumb-sized */
  .pager{gap:.35rem;margin-top:1.8rem}
  .pager button{min-width:44px;height:44px;font-size:.82rem}
  .pager .count{width:100%;margin:.5rem 0 0;text-align:center}

  /* build + checkout: nothing sits in a squeezed column */
  .steps,.costeps{gap:.4rem;flex-wrap:wrap}
  .stp,.cstep{padding:.55rem .85rem;font-size:.78rem;flex:1 1 auto;justify-content:center}
  .bases{grid-template-columns:repeat(2,minmax(0,1fr))}
  .opt{min-height:44px;display:inline-flex;align-items:center;padding:.5rem 1rem}
  .arrange{padding:var(--s2);min-height:104px}
  /* iOS zooms the whole page when a focused field is under 16px */
  .f2 input,.crow2 input,textarea{font-size:16px}
  .crow2{flex-wrap:wrap}
  .crow2 input{min-height:44px;flex:1 1 60%}
  .btn-apply{min-height:44px}
  .pay{padding:.85rem .9rem}

  /* drawer + typography balance */
  .drawer{width:min(94vw,432px)}
  .drawer .bd,.drawer .ft{padding:1.15rem}
  .sechead{margin-bottom:1.6rem;padding-bottom:1rem}
  .sechead .r{font-size:.8rem}
  .sum .bd,.sum .hd{padding:1.15rem}
}

@media(max-width:400px){
  .brandmark{font-size:1.62rem}   /* still the biggest thing in the header */
  .cartbtn{padding:0 .75rem}
  .cats button{font-size:.71rem}
}

/* Touch devices fire a hover on tap and then keep it — no lift, no colour
   flip that outlives the finger. */
@media(hover:none),(pointer:coarse){
  .tile:hover,.card:hover,.door:hover,.add:hover,.opt:hover,.cta:hover:not(:disabled),
  .cartbtn:hover,.pager button:hover:not(:disabled),
  .gal .gthumb:hover,.vpick button:hover{transform:none}
  .card:hover{box-shadow:none;border-color:var(--line)}
  .tile:hover{box-shadow:none;border-color:var(--line)}
  .tile:hover .dot{transform:none}
  .add:hover{background:var(--ink)}
  .cartbtn:hover{background:var(--ink)}
  .cta:hover:not(:disabled){background:var(--ink)}
  .cats button:hover{background:none;color:var(--ink-2);padding-left:.35rem}
  .cats button[aria-pressed="true"]:hover{background:var(--ink);color:var(--surface)}
  .vpick button:hover{background:var(--surface);color:var(--ink-2);border-color:var(--line-2)}
  .card:hover .ph img{transform:scale(1)}
}

body.noscroll{overflow:hidden}

/* ==========================================================================
   Quick view. On a laptop it is a panel over the grid. On a phone it is a
   full page with its own back bar — nothing of the list showing through,
   nothing to pinch or reset. The photo just sits there at a good size.
   ========================================================================== */
.qv{
  position:fixed;z-index:85;left:50%;top:50%;translate:-50% -50%;
  width:min(1020px,94vw);max-height:min(92vh,880px);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--e3);overflow:auto;overscroll-behavior:contain;
  opacity:0;pointer-events:none;transform:scale(.97);
  transition:opacity .22s var(--ease),transform .28s var(--ease);
}
.qv.on{opacity:1;pointer-events:auto;transform:none}
@media (prefers-reduced-motion:reduce){.qv{transition:opacity .15s linear;transform:none}}

.qv-bar{
  position:sticky;top:0;z-index:3;display:flex;align-items:center;gap:.8rem;
  padding:.55rem .8rem;background:var(--surface);border-bottom:1px solid var(--line);
}
.qv-back{
  display:inline-flex;align-items:center;gap:.5rem;min-height:44px;padding:0 1rem 0 .8rem;
  border-radius:100px;border:1.5px solid var(--line);background:var(--surface);
  font-size:.85rem;font-weight:700;color:var(--ink-2);
  transition:border-color .2s,color .2s;flex:none;
}
.qv-back:hover{border-color:var(--ink);color:var(--ink)}
.qv-back .ar{font-size:1.05rem;line-height:1}
.qv-bar-t{
  font-family:"Outfit",ui-sans-serif,sans-serif;font-weight:400;font-size:.95rem;
  color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;
}
.qv-in{display:grid;grid-template-columns:1.1fr .9fr;gap:clamp(1.2rem,.8rem + 1.6vw,2.2rem);padding:clamp(1.1rem,.8rem + 1vw,1.8rem)}
@media(max-width:820px){.qv-in{grid-template-columns:1fr}}

.qv-stage{
  position:relative;aspect-ratio:1;border-radius:var(--r-s);overflow:hidden;
  background:var(--surface-2);border:1px solid var(--line);
}
.qv-stage img{width:100%;height:100%;object-fit:contain;display:block}
/* only ever seen when the card thumbnail wasn't cached — a deep link, or a
   product scrolled past too fast to load. Better an empty frame than the
   previous product's photograph. */
.qv-stage.loading img{opacity:0}
.qv-stage.loading::after{
  content:"";position:absolute;inset:0;border-radius:inherit;
  background:linear-gradient(100deg,var(--surface-2) 30%,var(--surface) 50%,var(--surface-2) 70%);
  background-size:220% 100%;animation:qvshim 1.1s linear infinite;
}
@keyframes qvshim{from{background-position:120% 0}to{background-position:-20% 0}}
@media(prefers-reduced-motion:reduce){ .qv-stage.loading::after{animation:none} }
.qv-imgnote{margin:.5rem 2px 0;font-size:.68rem;line-height:1.5;color:var(--ink-3);text-align:center}

/* The chosen option, pictured, in the space under the product photograph.

   "You see that empty space at the bottom of the main accessory. Can you add an
   image of how either the dainty daily wear chain will look like or how the
   blingy party wear chain will look like? So don't show both at once ... it
   alternates between them as you pick and choose."

   One picture, not two: the pair of tiles the Customise side uses is a picker
   and needs both visible, this is a preview of a choice already made and the
   column is not wide enough to show both without shrinking each to a thumbnail
   of a chain, which is the one thing a photograph of a chain cannot survive. */
.qv-optart{
  margin:var(--s3) 0 0;padding:var(--s3);border:1px solid var(--line);
  border-radius:var(--r-s);background:var(--surface-2);
}
.qv-optart img{display:block;width:100%;max-width:340px;margin:0 auto;border-radius:calc(var(--r-s) * .7)}
.qv-optart .k{
  display:block;margin:0 0 .5rem;font-size:.66rem;letter-spacing:.09em;
  text-transform:uppercase;color:var(--cyan-ink);font-weight:600;
}
.qv-optart figcaption{margin:.6rem 0 0;font-size:.78rem;line-height:1.55;color:var(--ink-2);text-align:center}

/* The photo strip under the quick view stage.

   A carousel, but the kind that shows you what it holds rather than making you
   swipe to find out — her soaps carry two pictures, the bar itself and the
   benefits sheet, and both are worth looking at rather than one being buried.
   It renders only when there is a second photograph, so every other product in
   the shop is untouched. */
/* Her own masthead, sitting above the shelf heading rather than replacing it —
   the heading is what a screen reader and the tab history read. */
.shelf-banner{
  display:block;width:100%;height:auto;border-radius:var(--r-s);
  border:1px solid var(--line);margin:0 0 clamp(.9rem,.6rem + .8vw,1.4rem);
}
/* Her two newer mastheads are drawn 2.5:1 where The Quirky Bar is 7:1. Left at
   width:100% a 2.5:1 banner is 480px tall on a desktop and eats the whole
   first screen before a single product. These are lettering on white, so they
   cap their height and centre instead — and drop the frame, because a logo
   floating in the middle of a bordered box reads as a mistake rather than a
   masthead. */
.shelf-banner.tall{
  width:auto;max-width:100%;max-height:clamp(110px,7rem + 7vw,220px);
  margin-inline:auto;border:0;border-radius:0;
}

.qv-thumbs{display:flex;gap:.5rem;margin:.6rem 0 0;justify-content:center;flex-wrap:wrap}
.qv-thumbs button{
  width:56px;height:56px;padding:0;border-radius:calc(var(--r-s) * .6);
  border:1px solid var(--line);background:var(--surface-2);overflow:hidden;
  cursor:pointer;transition:border-color .18s ease,box-shadow .18s ease;
}
.qv-thumbs img{width:100%;height:100%;object-fit:contain;display:block}
.qv-thumbs button[aria-selected="true"]{
  border-color:var(--cyan-ink);box-shadow:0 0 0 2px color-mix(in srgb,var(--cyan-ink) 28%,transparent);
}
.qv-thumbs button:focus-visible{outline:2px solid var(--cyan-ink);outline-offset:2px}
@media(prefers-reduced-motion:reduce){ .qv-thumbs button{transition:none} }

.qv-info{display:flex;flex-direction:column;gap:.7rem;min-width:0}
.qv-info h3{font-size:clamp(1.35rem,1.1rem + 1vw,1.9rem)}
.qv-price{font-family:"DM Mono",monospace;font-size:1.35rem;font-weight:500}
.qv-desc{font-size:.88rem;color:var(--ink-2);line-height:1.55}
.qv-desc:empty{display:none}
.qv-field{display:flex;flex-direction:column;gap:.45rem;margin-top:.2rem}
.qv-field label{font-family:"DM Mono",monospace;font-size:.66rem;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-3)}
.qv-field select{
  width:100%;min-height:48px;border:1.5px solid var(--line-2);border-radius:12px;background:var(--surface);
  padding:.6rem .85rem;font:inherit;font-size:16px;color:var(--ink);
}
.qv-field select:focus{outline:none;border-color:var(--ink)}

/* picking the attachment by its photograph rather than by its name */
.partpick{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:.5rem}
.part{
  display:flex;flex-direction:column;align-items:center;gap:.3rem;
  padding:.5rem .3rem;border:1.5px solid var(--line);border-radius:12px;
  background:var(--surface);transition:border-color .25s,transform .25s var(--ease);
}
.part img{width:100%;max-width:72px;aspect-ratio:1;object-fit:contain;mix-blend-mode:multiply}
.part span{font-size:.7rem;font-weight:600;color:var(--ink-2);line-height:1.2;text-align:center}
.part[aria-pressed="true"]{border-color:var(--ink);background:var(--surface-2)}
.part[aria-pressed="true"] span{color:var(--ink)}
.partnote{
  display:flex;gap:.7rem;align-items:center;margin:.55rem 0 0;
  padding:.6rem .7rem;border:1px solid var(--line);border-radius:12px;background:var(--surface-2);
}
.partnote img{width:96px;height:96px;object-fit:contain;border-radius:8px;flex-shrink:0;mix-blend-mode:multiply}
.partnote figcaption{font-size:.76rem;line-height:1.5;color:var(--ink-3)}
/* An option made of photographs. Two or three values, not four, so the tiles
   are wider than the attachment picker and the chain is actually readable —
   which was the whole complaint: "The image is just one, how do ppl know which
   is which?" */
.optpics{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:.55rem}
.optpics .part img{max-width:none;width:100%}
/* two chains, two bookmarks and two ear fittings can each contribute a line */
.optnote{flex-direction:column;align-items:flex-start;gap:.35rem}

/* "Pls add some color to the tab add more from the charms library" — the one
   button on the page that starts a journey rather than settling a choice, so
   it is the one that carries a hue.

   Asked for twice. The first answer was a tinted outline, and she looked at it
   and asked again: "Give this tab a color so it stands out". An 8% wash does
   not stand out next to a row of white pills, so it is a filled button now —
   the teal solid, the same weight as Add to cart, reading as an action rather
   than a choice. */
.opt.tinted{
  border-color:var(--cyan-ink);background:var(--cyan-ink);color:#fff;
  box-shadow:0 2px 10px color-mix(in srgb,var(--cyan-ink) 26%,transparent);
}
.opt.tinted:hover{
  border-color:var(--berry);background:var(--berry);color:#fff;
  box-shadow:0 4px 14px color-mix(in srgb,var(--berry) 30%,transparent);
}

@media(max-width:420px){ .partpick{grid-template-columns:repeat(2,minmax(0,1fr))} }
.qty{display:flex;align-items:center;gap:.4rem}
.qty button{
  width:44px;height:44px;border:1.5px solid var(--line);border-radius:10px;background:var(--surface);
  font-size:1.05rem;font-weight:700;color:var(--ink-2);transition:border-color .2s,background .2s,color .2s;
}
.qty button:hover{border-color:var(--ink);background:var(--ink);color:var(--surface)}
.qty input{
  width:4rem;height:44px;text-align:center;border:1.5px solid var(--line);border-radius:10px;
  background:var(--surface);font-family:"DM Mono",monospace;font-size:16px;color:var(--ink);
}
.qty input:focus{outline:none;border-color:var(--ink)}
.qv-build{margin-top:.2rem;width:100%;justify-content:center;text-align:center}
[hidden]{display:none!important}   /* author display rules must not beat it */

/* phone: a page, not a panel. inset:0 leaves nothing showing behind it. */
@media(max-width:820px){
  .qv{
    inset:0;width:auto;height:auto;max-width:none;max-height:none;
    translate:none;border:none;border-radius:0;box-shadow:none;background:var(--ground);
    transform:translateY(1.5%);
  }
  .qv.on{transform:none}
  .qv-bar{padding:.5rem .7rem;background:var(--ground)}
  .qv-in{padding:1rem 1rem 3rem;gap:1.1rem}
  .qv-stage{aspect-ratio:1;max-height:52vh;margin:0 auto;width:100%}
  .qv-info h3{font-size:1.5rem}
  .qv-price{font-size:1.5rem}
}

/* cards are now openable — the whole tile is the hit area */
.card .ph{cursor:zoom-in}
.card .nm{cursor:pointer}

/* ==========================================================================
   Library navigation — a rail you can scan, a search that finds things, and
   a list that keeps going. Built for a thousand charms, not twenty-four.
   ========================================================================== */
.libbar{display:flex;align-items:center;gap:.8rem;margin-bottom:clamp(1rem,.8rem + .6vw,1.4rem);flex-wrap:wrap}
.libsearch{
  flex:1;min-width:200px;min-height:48px;border:1.5px solid var(--line-2);border-radius:100px;
  background:var(--surface);padding:.7rem 1.15rem;font:inherit;font-size:16px;color:var(--ink);
  transition:border-color .25s,box-shadow .25s;
}
.libsearch::placeholder{color:var(--ink-3)}
.libsearch:focus{outline:none;border-color:var(--cyan-ink);box-shadow:0 0 0 3px color-mix(in srgb,var(--cyan) 22%,transparent)}
.libcount{font-family:"DM Mono",monospace;font-size:.78rem;color:var(--ink-3);white-space:nowrap}

.cats button .n{flex:none}
.cats button.empty{opacity:.42;pointer-events:none}
.catmore{
  margin-top:.6rem;width:100%;min-height:44px;border:1.5px dashed var(--line-2);border-radius:12px;
  font-size:.8rem;font-weight:700;color:var(--ink-2);background:none;transition:border-color .25s,color .25s;
}
.catmore:hover{border-color:var(--ink);color:var(--ink)}
.catmore:empty{display:none}

.more{display:flex;flex-direction:column;align-items:center;gap:.7rem;margin-top:clamp(1.6rem,1.2rem + 1.4vw,2.6rem)}
.more:empty{margin:0}
.btn-more{
  min-height:48px;padding:0 1.6rem;border-radius:100px;border:1.5px solid var(--ink);
  background:var(--surface);font-weight:700;font-size:.88rem;color:var(--ink);
  display:inline-flex;align-items:center;gap:.6rem;transition:background .25s,color .25s,transform .3s var(--ease);
}
.btn-more:hover{background:var(--ink);color:var(--surface);transform:translateY(-2px)}
.more .libcount{font-size:.76rem}

/* the way back out of the library, always visible while you're building */
.buildbar{
  position:fixed;left:50%;bottom:1rem;translate:-50% 0;z-index:70;
  display:none;align-items:center;gap:.8rem;padding:.5rem .5rem .5rem 1.15rem;
  background:var(--ink);color:var(--surface);border-radius:100px;box-shadow:var(--e3);
  max-width:calc(100vw - 2rem);
}
.buildbar.on{display:flex}

/* Ask a question. Sits opposite the build bar so the two never collide, and
   stays out of the way of the cart drawer, which is z-index 80 and above. */
.wa{
  position:fixed;right:1rem;bottom:1rem;z-index:65;
  display:inline-flex;align-items:center;gap:.55rem;
  min-height:46px;padding:0 1.05rem 0 .85rem;border-radius:100px;
  background:#25D366;color:#0B3E22;box-shadow:var(--e3);
  font-size:.84rem;font-weight:700;text-decoration:none;
  transition:transform .35s var(--ease),filter .3s;
}
.wa:hover{transform:translateY(-3px);filter:brightness(1.05)}
.wa svg{width:22px;height:22px;flex:none}
@media(max-width:560px){
  /* on a phone the label eats the row the build bar needs, so drop to the mark */
  .wa{padding:0;width:48px;justify-content:center;bottom:1rem}
  .wa span{display:none}
}
.buildbar b{font-size:.85rem;font-weight:700;white-space:nowrap}
.buildbar .go{
  min-height:40px;padding:0 1rem;border-radius:100px;background:var(--surface);color:var(--ink);
  font-size:.82rem;font-weight:700;display:inline-flex;align-items:center;white-space:nowrap;
}
@media(max-width:760px){
  .buildbar{bottom:.8rem;padding-left:1rem}
  .buildbar b{font-size:.8rem}
}
.nores{grid-column:1/-1;color:var(--ink-2);font-size:.95rem;padding:2rem 0;text-align:center}



/* The category rail scrolls on its own. With 98 categories open you should
   not have to scroll past the entire library to reach the bottom of the list. */
@media(min-width:901px){
  .side{max-height:calc(100vh - 130px);display:flex;flex-direction:column}
  .side h4,.catmore{flex:none}
  .side .cats{flex:1;min-height:0;overflow-y:auto;padding-right:.35rem;overscroll-behavior:contain;scrollbar-width:thin}
}
@media(max-width:900px){
  .side .cats{
    max-height:min(44vh,300px);overflow-y:auto;overscroll-behavior:contain;
    border:1px solid var(--line);border-radius:14px;padding:.5rem;
  }
}

/* The section bar scrolls sideways and fades at the edge so it reads as
   scrollable — no hidden menu, everything she sells is one flick away. */
nav.main{
  scroll-behavior:smooth;-webkit-overflow-scrolling:touch;
  scroll-snap-type:x proximity;scroll-padding-inline:1rem;
  mask-image:linear-gradient(to right,transparent 0,#000 12px,#000 calc(100% - 20px),transparent 100%);
}
nav.main button{scroll-snap-align:center}
@media(hover:none),(pointer:coarse){
  nav.main{mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 22px),transparent 100%)}
}

/* ==========================================================================
   Colour instead of black. Her note: "instead of black we'll keep using some
   form of one of three of this colour" — the explanatory line inside the box
   stays grey on purpose: it's a footnote, not a highlight.

   Then, looking at a card: "So everything is green here. Can we make the price
   in pink, Add to cart in blue?" She is right that the card was reading as one
   colour — the label and the button were both green and the price was the only
   blue. Price is pink now and both add buttons are blue, which leaves one of
   each hue on a card: green on the section label, pink on the price, blue on
   the button.
   ========================================================================== */
.add{background:var(--cyan-ink)}
.add:hover{background:var(--ink)}
.card .pr{color:var(--pink-ink);font-weight:600}
.qv-price{color:var(--pink-ink);font-weight:600}
.qty input{color:var(--cyan-ink);font-weight:500}
.qty button{color:var(--cyan-ink);border-color:color-mix(in srgb,var(--cyan) 42%,var(--line))}
.qty button:hover{background:var(--cyan-ink);border-color:var(--cyan-ink);color:#fff}

/* every field label takes a hue; personalisation is the pink one */
.qv-field label{color:var(--cyan-ink)}
#qv-pwrap label,.fieldset legend{color:var(--pink-ink)}
#qv-note-box,#pdp-note{font-size:16px}
#qv-note-box::placeholder,#pdp-note::placeholder{color:var(--ink-3)}   /* footnote, stays quiet */

.card .nm{font-family:"Outfit",ui-sans-serif,sans-serif;font-weight:600;font-size:1rem}
.card .ct{color:var(--green-ink);font-weight:500}
.cta{background:var(--cyan-ink)}                     /* the other "Add to cart" */
.cta:hover:not(:disabled){background:var(--ink)}
.cartbtn{background:var(--ink)}
.cartbtn .n{background:var(--cyan)}
.cartbtn .n{color:var(--ink);font-weight:700}
.stockbadge.low{background:var(--pink);color:#fff}
.sechead .r{color:var(--ink-3)}
.tile b{font-weight:600}
nav.main button[aria-current="true"]::before{background:var(--ink)}
.opt[aria-pressed="true"]{background:var(--cyan-ink);border-color:var(--cyan-ink)}
.base[aria-pressed="true"]{border-color:var(--cyan-ink)}
.btn-more{border-color:var(--green-ink);color:var(--green-ink)}
.btn-more:hover{background:var(--green-ink);color:#fff}
.cats button[aria-pressed="true"]{background:var(--cyan-ink)}

/* ==========================================================================
   Arranging. The tile shows the one charm they picked, cropped out of the
   supplier's plate photo. Arrows are the primary control — drag fights page
   scroll on a phone, so it stays a desktop bonus.
   ========================================================================== */
.chip{
  width:auto;min-width:104px;max-width:132px;overflow:visible;padding:.5rem;
  cursor:default;                      /* drag is a bonus, not the instruction */
}
.chip .x{opacity:1;right:-6px;top:-6px;border:1px solid var(--line);box-shadow:var(--e1)}
.chip .mv{position:static;inset:auto;opacity:1;background:none}
.chip .shot{
  display:block;width:100%;aspect-ratio:1;border-radius:10px;
  background-color:var(--surface);background-position:center;background-size:cover;
  object-fit:cover;border:1px solid var(--line);
}
.chip .cname{
  display:block;font-size:.7rem;line-height:1.3;color:var(--ink-2);
  margin-top:.4rem;text-align:center;
}
.chip .mv{display:flex;gap:.3rem;margin-top:.45rem;justify-content:center}
.chip .mv button{
  width:40px;height:40px;border:1.5px solid var(--line-2);border-radius:10px;
  background:var(--surface);color:var(--cyan-ink);font-size:1rem;font-weight:700;
  display:grid;place-items:center;transition:background .2s,border-color .2s,color .2s;
}
.chip .mv button:hover:not(:disabled){background:var(--cyan-ink);border-color:var(--cyan-ink);color:#fff}
.chip .mv button:disabled{opacity:.3;cursor:not-allowed}
.chip .ix{
  position:absolute;top:-8px;left:-8px;z-index:2;min-width:1.5rem;height:1.5rem;padding:0 .3rem;
  border-radius:100px;background:var(--cyan-ink);color:#fff;
  font-family:"DM Mono",monospace;font-size:.7rem;display:grid;place-items:center;
}

/* The live preview: a drawn chain with the real charm crops hung on it.
   Everything inside the stage is positioned in per-cent, so when one of her
   photographed chains replaces the drawing the charms do not move. */
.preview{margin:1.2rem 0 0;padding:0;display:flex;flex-direction:column;gap:.6rem}
.pvstage{
  position:relative;width:100%;max-width:420px;aspect-ratio:5/4;
  border-radius:var(--r-s);border:1px solid var(--line);background:var(--surface);
  overflow:hidden;
}
.pvchain,.pvbase{position:absolute;inset:0;width:100%;height:100%}
.pvbase{object-fit:contain}
.pvring{
  position:absolute;width:9px;height:9px;margin:-4px 0 0 -4px;
  border:1.5px solid;border-radius:100px;background:transparent;
}
.pvcharm{
  position:absolute;aspect-ratio:1;transform:translate(-50%,5px);
  background-repeat:no-repeat;
  transition:left .32s cubic-bezier(.34,.9,.3,1),top .32s cubic-bezier(.34,.9,.3,1),
             width .32s ease,height .32s ease;
}
.pvcharm.loose{transform:translate(-50%,-50%)}
.preview .cap{font-size:.78rem;color:var(--ink-3);line-height:1.5;max-width:44ch}
@media(prefers-reduced-motion:reduce){ .pvcharm{transition:none} }

@media(max-width:760px){
  .chip .mv button{width:44px;height:44px}
  .chip .cname{font-size:.66rem}
  .pvstage{max-width:100%}
}
/* drag is a pointer nicety, never the only way to reorder */
@media(hover:none),(pointer:coarse){ .chip{cursor:default} }

@media(hover:hover) and (pointer:fine){ .chip{cursor:grab} .chip:active{cursor:grabbing} }

/* ==========================================================================
   Ready-made: four sections you click into. Her call — sections rather than
   filters, "so people know what they're looking at".
   ========================================================================== */
.sectabs{
  display:flex;gap:.4rem;overflow-x:auto;scrollbar-width:none;
  margin-bottom:.9rem;padding-bottom:.2rem;
}
.sectabs::-webkit-scrollbar{display:none}
.sectabs button{
  flex:none;min-height:44px;padding:.55rem 1.15rem;border-radius:100px;
  border:1.5px solid var(--line);background:var(--surface);
  font-size:.9rem;font-weight:700;color:var(--ink-2);white-space:nowrap;
  transition:background .25s,border-color .25s,color .25s;
}
.sectabs button:hover{border-color:var(--line-2);color:var(--ink)}
.sectabs button[aria-current="true"]{background:var(--cyan-ink);border-color:var(--cyan-ink);color:#fff}

/* The phone version of the section tabs.

   It has to live *after* the block above, not up with the other mobile rules:
   a media query adds no specificity, so an override written earlier in the
   file quietly loses to the base rule and nothing happens.

   Five pills, two rows. Three rows left a ragged half-empty last row — her
   note. The two long names decide it: row one has to take "Bracelet /
   Necklace" and "Bag, phone & keyring" together, so the type and the padding
   come down until it does. The tap target is held at 40px regardless. */
@media(max-width:760px){
  .sectabs{flex-wrap:wrap;overflow:visible;gap:.3rem}
  .sectabs button{
    flex:0 0 auto;font-size:.76rem;padding:.4rem .62rem;min-height:40px;
    display:inline-flex;align-items:center;
  }
}
.sechint{font-size:.86rem;color:var(--ink-3);line-height:1.55;max-width:60ch;margin:0 0 1.2rem}

.toolbar{display:flex;justify-content:flex-end;align-items:center;gap:.7rem;margin-bottom:1.1rem}
.sortwrap{display:flex;align-items:center;gap:.5rem}
.sortwrap span{
  font-family:"DM Mono",monospace;font-size:.66rem;letter-spacing:.13em;
  text-transform:uppercase;color:var(--ink-3);
}
.sortwrap select{
  min-height:44px;border:1.5px solid var(--line);border-radius:100px;background:var(--surface);
  padding:.45rem 1rem;font:inherit;font-size:.86rem;color:var(--ink);
}
.sortwrap select:focus{outline:none;border-color:var(--ink)}
@media(max-width:760px){
  .toolbar{justify-content:stretch}
  .sortwrap{width:100%}
  .sortwrap select{flex:1;font-size:16px}
  .sechint{font-size:.82rem;margin-bottom:1rem}
}

/* ==========================================================================
   About — "A short version of whatever the website has to give"
   ========================================================================== */
.about{max-width:1100px;margin:0 auto}
/* "Can the image be bigger", and then "make the logo even bigger ... since she
   wants to highlight her brand. Fill up that empty space but still make it look
   clean."

   The old row was `auto 1fr`: the logo took its intrinsic width, the text took
   everything left, and because the paragraphs are capped at 62ch for
   readability the row ended in a band of nothing. Giving the logo a *share* of
   the row rather than a height is what closes that gap — it grows with the
   column instead of sitting in it, and the text column narrows to meet it, so
   the space fills without either side being stretched.

   Two thirds / one third rather than half and half: the logo is square and the
   lede is two paragraphs, and at 50% the logo starts to read as the subject of
   the page rather than its mark. */
.aboutlede{
  display:grid;grid-template-columns:minmax(220px,34%) 1fr;
  gap:clamp(1.4rem,.9rem + 2.4vw,3.2rem);
  align-items:center;
}
.logo.big{
  width:100%;height:auto;max-width:340px;justify-self:center;
  mix-blend-mode:multiply;
}
.aboutlede p{font-size:clamp(1rem,.94rem + .3vw,1.14rem);line-height:1.7;color:var(--ink-2);margin:0 0 1rem;max-width:62ch}
.aboutlede p:last-child{margin-bottom:0}

.abgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,270px),1fr));gap:var(--s2)}
.abcard{
  border:1px solid var(--line);border-radius:var(--r);background:var(--surface);
  padding:clamp(1.1rem,.9rem + .8vw,1.5rem);
}
.abcard h4{
  font-family:"DM Mono",monospace;font-size:.68rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--teal);margin:0 0 .6rem;font-weight:500;
}
.abcard p{margin:0;font-size:.9rem;line-height:1.65;color:var(--ink-2)}
.abask{margin-top:var(--sec);max-width:64ch}

/* the About doors have no photograph, so the tile must not reserve room for one */
#s-about .door .float{display:none}

@media(max-width:640px){
  .aboutlede{grid-template-columns:1fr;justify-items:center;text-align:center}
  .aboutlede p{text-align:left}
  /* One column, so `width:100%` on the logo would be the full screen and the
     first thing under the heading would be a 375px square. It keeps its share
     of the width rather than all of it. */
  .logo.big{width:min(64%,260px)}
  .abask{margin-left:auto;margin-right:auto}
}

/* ==========================================================================
   Press feedback  —  respond on pointer-down, not on release
   ==========================================================================
   Apple's first rule of fluid interfaces: the moment lag appears, directness
   "falls off a cliff". Every surface here already lifts on :hover, which a
   thumb never fires — so on a phone the whole interface was silent until the
   action completed. These are the pressed states. Short and ease-out, because
   a press is an acknowledgement, not an animation.

   Placed at the end of the file deliberately: a media query adds no
   specificity, and several of these selectors are re-declared in the phone
   block further up. Last wins. */
.card:active,.tile:active,.door:active,.gmore:active,.gcell:active,
.add:active,.cta:active:not(:disabled),.opt:active,.wish:active,
nav.main button:active,.sectabs button:active,.cats button:active,
.cartbtn:active,.wishbtn:active,.pager button:active:not(:disabled),
.qv-thumbs button:active,.partpick button:active{
  transform:scale(.978);
  transition:transform 90ms cubic-bezier(.2,0,.2,1);
}
/* A card is big, so the same scale reads as a bigger movement. Pull it back,
   and let the photograph settle with it rather than staying pin-sharp. */
.card:active{transform:scale(.988)}
.door:active{transform:scale(.992)}
/* The lift and the press are the same property, so hover must not win while a
   finger is down. */
.card:hover:active,.tile:hover:active,.door:hover:active,
.gcell:hover:active{transform:scale(.988)}

@media(prefers-reduced-motion:reduce){
  .card:active,.tile:active,.door:active,.gmore:active,.gcell:active,.add:active,
  .cta:active:not(:disabled),.opt:active,.wish:active,nav.main button:active,
  .sectabs button:active,.cats button:active,.cartbtn:active,.wishbtn:active,
  .pager button:active:not(:disabled),.qv-thumbs button:active,
  .partpick button:active{transform:none;opacity:.72;transition:opacity 90ms linear}
}

/* ==========================================================================
   Material, depth and the scroll edge
   ==========================================================================
   Translucency is how a surface says "I am floating above your content"
   rather than "I am a different page". Three surfaces earn it: the header,
   the quick view and the cart drawer. Everything else stays opaque, because
   a light translucent surface stacked on another light translucent one is
   where legibility collapses.

   Bigger surface reads as thicker: the quick view and drawer take a stronger
   blur and a deeper shadow than the header, which takes more than a chip.
   ========================================================================== */
@supports (backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px)){

  /* --- 8. the quick view as a real material ------------------------------ */
  .qv{
    background:color-mix(in srgb,var(--surface) 82%,transparent);
    /* the blur itself is animated further down, so the material forms as the
       panel settles rather than snapping on; see "materialise, don't fade" */
    border-top-color:color-mix(in srgb,#fff 62%,var(--line));
  }
  .qv-bar{
    background:color-mix(in srgb,var(--surface) 72%,transparent);
    -webkit-backdrop-filter:blur(20px) saturate(180%);
    backdrop-filter:blur(20px) saturate(180%);
    border-bottom-color:color-mix(in srgb,var(--line) 60%,transparent);
  }
  /* --- 8. the cart drawer, likewise -------------------------------------- */
  .drawer{
    background:color-mix(in srgb,var(--ground) 84%,transparent);
    -webkit-backdrop-filter:blur(30px) saturate(180%);
    backdrop-filter:blur(30px) saturate(180%);
    border-left-color:color-mix(in srgb,#fff 55%,var(--line));
  }
  /* On a phone the quick view is a full page, not a panel over the grid —
     there is nothing behind it to show through, so blur is pure cost. */
  @media(max-width:760px){
    .qv{background:var(--surface);-webkit-backdrop-filter:none;backdrop-filter:none}
  }
}

/* --- 9. materialise, don't fade ------------------------------------------
   A pane of glass arriving has a blur that resolves as it settles. What must
   animate is the *backdrop* blur — the material forming — not a filter on the
   panel itself. Blurring the panel was tried first and is wrong twice over: it
   blurs the product photograph, which is the one thing that should be sharp
   from the first frame, and `filter` on a fixed element makes it a containing
   block for its own descendants.

   So: backdrop blur and scale move together, 0 -> 30px against .97 -> 1. */
.qv{
  transition:opacity .22s var(--ease),transform .34s var(--ease),
             -webkit-backdrop-filter .34s var(--ease),backdrop-filter .34s var(--ease);
}
@supports (backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px)){
  @media(min-width:761px){
    .qv{-webkit-backdrop-filter:blur(0px) saturate(100%);backdrop-filter:blur(0px) saturate(100%)}
    .qv.on{-webkit-backdrop-filter:blur(30px) saturate(180%);backdrop-filter:blur(30px) saturate(180%)}
  }
}

/* --- 11. push the page back when a sheet comes forward --------------------
   The scrim dimmed but the page stayed put, so the sheet read as *instead of*
   the page rather than *in front of* it. Scaling the content back is the iOS
   card-modal move; 0.972 is enough to read as depth and small enough that
   nobody catches it happening. transform-origin at the top because that is
   where the eye is. */
main{
  transition:transform .42s var(--ease),filter .42s var(--ease);
  transform-origin:50% 0;
}
body.pushback main{transform:scale(.972);filter:brightness(.96)}

/* --- 10. scroll edge, not a hairline --------------------------------------
   A 1px rule under floating chrome is the pre-material way of saying "the
   header ends here". The material way is to let content fade into the blur,
   and only once there is something to fade — at the top of the page the edge
   should not exist at all. `.scrolled` is set by app.js. */
.top{border-bottom:1px solid transparent;transition:border-color .3s ease}
.top::after{
  content:"";position:absolute;left:0;right:0;top:100%;height:22px;
  pointer-events:none;opacity:0;transition:opacity .3s ease;
  background:linear-gradient(to bottom,
    color-mix(in srgb,var(--ground) 72%,transparent), transparent);
}
body.scrolled .top{border-bottom-color:color-mix(in srgb,var(--line) 70%,transparent)}
body.scrolled .top::after{opacity:1}

@media(prefers-reduced-motion:reduce){
  main{transition:none}
  body.pushback main{transform:none;filter:none}
  .qv{filter:none}
  .qv.on{filter:none}
}

/* --- 16/17. honour the other two display preferences ----------------------
   Reduced transparency means frostier and solid, not merely less blur.
   More contrast means near-solid grounds with a defined border. */
@media(prefers-reduced-transparency:reduce){
  .top,.qv,.qv-bar,.drawer{
    background:var(--surface);
    -webkit-backdrop-filter:none;backdrop-filter:none;
  }
  .drawer{background:var(--ground)}
  .scrim{backdrop-filter:none;background:rgba(28,24,20,.6)}
  .top::after{display:none}
}
@media(prefers-contrast:more){
  .top,.qv,.drawer{background:var(--surface);-webkit-backdrop-filter:none;backdrop-filter:none}
  .card,.tile,.door,.panel,.abcard{border-color:var(--ink-2)}
  .top{border-bottom:1px solid var(--ink-2)}
  :focus-visible{outline-width:4px}
}

/* A category that exists before there is anything in it. Muted rather than
   hidden: she wants the five live now, and a tile that looks the same as a
   stocked one promises products that are not there yet. */
.tile.soon{opacity:.72}
.tile.soon:hover{opacity:1}
.tile.soon small{font-style:italic}


/* The announcement bar.

   "can the free shipping above 1000/500 be mentioned somewhere to motivate
    buying / Like as a header other sites have", and then: put the sale and the
   coupons up there too, and let them scroll.

   Several messages, one strip, so it moves. The track holds the run twice and
   translates by exactly -50%, which is what makes the loop seamless — at the
   halfway point the second copy sits precisely where the first started, so
   there is no jump to hide. Anything less exact shows a seam every cycle.

   `--sbdur` is set per render from how many messages there are, so two do not
   crawl and eight do not race.

   It is taller than it was — she asked for that, and the type is bigger with
   it, because a strip that scrolls has to be readable in a glance rather than
   studied. */
.shipbar{
  background:var(--green-ink);color:#fff;
  font-size:.82rem;font-weight:600;letter-spacing:.01em;
  padding:.62rem 0;line-height:1.4;
  overflow:hidden;position:relative;
}
.shipbar:empty{display:none}
.shipbar b{font-weight:800}

.sbtrack{display:flex;width:max-content;animation:sbscroll var(--sbdur,30s) linear infinite}
.sbrun{display:flex;flex:none}
.sbit{
  padding:0 clamp(1.1rem,3vw,2.2rem);white-space:nowrap;
  display:inline-flex;align-items:center;gap:.4rem;
}
/* A dot between messages, so two of them never read as one sentence. */
.sbit + .sbit::before{
  content:"";width:4px;height:4px;border-radius:50%;
  background:rgba(255,255,255,.5);margin-right:.55rem;
}
@keyframes sbscroll{ from{transform:translateX(0)} to{transform:translateX(-50%)} }

/* Pause on hover, so a coupon code can actually be read and copied. */
.shipbar:hover .sbtrack{animation-play-state:paused}

/* One message, or reduced motion: no movement. The content is identical and
   still all there — it simply centres and stays put rather than being animated
   past someone who asked the system not to animate things. */
.shipbar.still .sbtrack{animation:none;width:100%;justify-content:center}
.shipbar.still .sbrun:last-child{display:none}
.shipbar.still .sbrun{flex-wrap:wrap;justify-content:center}
@media (prefers-reduced-motion:reduce){
  .shipbar .sbtrack{animation:none}
}

@media(max-width:760px){
  .shipbar{font-size:.74rem;padding:.5rem 0}
  .sbit{padding:0 1rem}
}

/* ---------------- a sale price ----------------
   The struck-through original is the point of the whole feature — "if I were
   to run like a 10% discount wherein original price is slashed by that amount".
   It sits *after* the live price rather than before it, so the number you read
   first is the one you pay, and it is set smaller and lighter so the pair reads
   as one price with a note rather than as two competing figures. */
.pr.onsale{color:var(--pink-ink)}
.was{
  font-family:"DM Mono",ui-monospace,monospace;
  font-size:.78em;color:var(--ink-3);text-decoration:line-through;
  margin-left:.4rem;white-space:nowrap;
}

/* The offer badge on a card. Deliberately not a corner ribbon over the
   photograph — badges go under the photo here, the same rule that keeps the
   design numbers on a charm card visible. */
.saletag{
  display:inline-flex;align-items:center;
  font-size:.68rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:var(--pink-ink);background:color-mix(in srgb,var(--pink) 13%,var(--surface));
  border-radius:100px;padding:.16rem .5rem;
}

/* GST, under the order total. A note about the total rather than a part of it,
   which is why it sits below the rule and not in the list above. */
.gstnote{
  margin:.55rem 0 0;padding-top:.55rem;border-top:1px solid var(--line);
  font-size:.75rem;line-height:1.5;color:var(--ink-3);
}


/* What the basket is close to but has not reached.
   Under the total, because that is the moment someone decides whether to add
   one more thing — "I wanted the add worth 200 more for Free shipping here". */
.nudges{display:grid;gap:.3rem;margin:.55rem 0 0}
.nudges:empty{display:none}
.nudge{
  margin:0;font-size:.78rem;line-height:1.45;color:var(--green-ink);
  background:color-mix(in srgb,var(--green) 11%,var(--surface));
  border-radius:8px;padding:.42rem .6rem;
}
.nudge b{font-weight:800}

/* An offer that belongs to a whole section, stated on its page.
   A basket rule cannot show on a card — whether an earring is free depends on
   how many are in the cart — so this is the only place a customer learns about
   it before the checkout. */
.secoffer{
  margin:.5rem 0 0;font-size:.86rem;line-height:1.5;
  display:inline-flex;flex-wrap:wrap;align-items:baseline;gap:.4rem;
  color:var(--pink-ink);
  background:color-mix(in srgb,var(--pink) 10%,var(--surface));
  border-radius:100px;padding:.4rem .85rem;
}
.secoffer b{font-weight:800}
.secoffer span{color:var(--ink-3);font-weight:500;font-size:.8rem}

/* A price that is a placeholder, said in the quick view. Small and grey — it
   is a caveat on the number above it, not an announcement. */
.provnote{margin:.15rem 0 0;font-size:.78rem;color:#6b6b6b;line-height:1.35}

/* Delivery time by PIN code (deliveryEta in app.js). Hidden until the server
   has a Delhivery key. */
.qv-eta .etarow{display:flex;gap:.5rem}
.qv-eta input{flex:1;min-width:0;font:inherit;font-size:16px;padding:.62rem .8rem;
  border:1.5px solid var(--line-2);border-radius:12px;background:var(--surface);color:var(--ink)}
.qv-eta input:focus{outline:none;border-color:var(--ink)}
.qv-eta button{flex:none;padding:.62rem 1rem;border:1.5px solid var(--ink);border-radius:12px;
  font-weight:700;font-size:.85rem}
.qv-eta button:active{transform:translateY(1px)}
#qv-eta:empty{display:none}
.co-eta{color:var(--green-ink)}
