/* ============================================================
   ROSSE ENGRAVING — site stylesheet
   Direction: Concept 1 "Liquid". Pure black ground, spectral
   bloom, frosted floating chrome, oversized tight display type.
   Deliberately dark-only.

   Everything above section 7 is carried over unchanged from the
   original single-page build. New components below reuse the
   same tokens, radii, blurs and easing curves.

   SECTIONS
     1.  Tokens
     2.  Base + type scale
     3.  Navigation (desktop pill + mobile drawer + cart)
     4.  Hero / page headers
     5.  Marquee strip
     6.  Sections + glass cards
     7.  Product cards + shop grid
     8.  Product detail page
     9.  Forms (shared by quote, product options, checkout)
     10. Multi-step form (quote wizard)
     11. Cart + checkout
     12. Process steps / turnaround / FAQ
     13. Materials grid
     14. Closing CTA + footer
     15. Tags, notices, toast
     16. Motion
     17. Real product media, gallery, lightbox, video
   ============================================================ */

/* ---------- 1. tokens ---------- */
:root{
  --ink:#000000;
  --panel:#0B0B0D;
  --text:#F5F5F7;
  --muted:#86868B;
  --line:rgba(255,255,255,.10);
  --glass:rgba(255,255,255,.055);
  --glass-hi:rgba(255,255,255,.14);
  --cyan:#5AC8FA;
  --violet:#BF5AF2;
  --amber:#FF9F0A;
  --green:#30D158;
  --red:#FF453A;
  --maxw:1120px;
  --font:-apple-system,"SF Pro Display","SF Pro Text",BlinkMacSystemFont,"Helvetica Neue",Helvetica,Arial,sans-serif;

  /* ---- display / brand face -------------------------------------------
     The owner asked for "Felix Titling Kerned" as the brand display face.
     No licensed web font file has been supplied, and none is embedded here —
     see the @font-face block below and the note in README.md.

     The family is listed FIRST so that the moment a licensed file is added
     (or on a machine that already has it installed) it takes over for the
     display elements only, with the existing face as the fallback. Body copy,
     forms and interface controls deliberately keep --font. */
  --font-display:"Felix Titling Kerned","Felix Titling",var(--font);
}

/* ---------------------------------------------------------------------
   FELIX TITLING KERNED — supplied by the owner (Sept 2026).

   Self-hosted from the owner's file, converted to woff2/woff. Nothing is
   fetched from a third-party CDN.

   LICENCE NOTE: the embedded metadata reads
     "Digitized data copyright The Monotype Corporation 1991-1995"
   with fsType 0x0008 (Editable Embedding — embedding permitted, subsetting
   not blocked). fsType is the foundry's machine-readable permission and it
   allows this, but Monotype sell desktop and webfont licences separately —
   see the note in README.md. The owner is responsible for holding web rights.

   font-display:swap so headings render immediately in the fallback and
   reflow once the face arrives — it is 21 KB, so that window is tiny.
   --------------------------------------------------------------------- */
@font-face{
  font-family:"Felix Titling Kerned";
  src:url("../fonts/felix-titling-kerned.woff2") format("woff2"),
      url("../fonts/felix-titling-kerned.woff") format("woff");
  font-weight:400;
  font-style:normal;
  font-display:swap;
}

/* ---------- 2. base + type ---------- */
*{box-sizing:border-box}
/* The `hidden` attribute must always win. Component rules that set a display
   (.btn is inline-flex, for instance) have the same specificity as the UA's
   [hidden] rule but come from the author sheet, so they silently defeat it —
   which had left the quote form's "Send my request" button visible on step 1.
   Found during the responsive QA pass. */
[hidden]{display:none!important}
body{
  margin:0;background:var(--ink);color:var(--text);
  font-family:var(--font);
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
body.no-scroll{overflow:hidden}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 24px}
.wrap-narrow{max-width:780px;margin:0 auto;padding:0 24px}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid var(--cyan);outline-offset:3px;border-radius:6px}
img{max-width:100%;display:block}
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}
/* Honeypot. Moved off-screen rather than display:none — some bots skip
   hidden inputs but fill in everything else, which is the whole point. */
.hp-field{
  position:absolute;left:-9999px;top:auto;width:1px;height:1px;
  overflow:hidden;
}
.skip-link{
  position:absolute;top:-100px;left:16px;z-index:100;
  background:var(--text);color:#000;padding:12px 18px;border-radius:12px;
  font-size:.85rem;font-weight:600;transition:top .2s;
}
.skip-link:focus{top:16px}

h1,h2,h3{margin:0;text-wrap:balance;font-weight:600;letter-spacing:-.035em;line-height:1.04}
/* Display face applies to headline type, the eyebrow labels and the brand
   wordmark. Never to body copy, form labels, hints, buttons or totals —
   a titling face is unreadable at those sizes and lengths. */
h1,h2,.brand-name,.eyebrow{font-family:var(--font-display)}


h1{font-size:clamp(2.9rem,7.5vw,5.75rem)}
h2{font-size:clamp(2.1rem,4.6vw,3.4rem)}
h3{font-size:1.3rem;letter-spacing:-.02em}

/* Felix Titling is an all-capitals titling face, so it needs different
   metrics from the tight sans the scale was originally tuned for:
     - the -.035em tracking collided the caps (R/K, and the full stop
       tucking under the preceding letter), so headings go to slightly
       positive tracking instead;
     - caps set much wider than mixed case, so the sizes come down to keep
       long lines like "Marked to remember." inside the column.
   Body copy, h3, buttons and form text are untouched. */
h1,h2{letter-spacing:.006em}
h1{font-size:clamp(2.35rem,5.9vw,4.9rem);line-height:1.06}
h2{font-size:clamp(1.85rem,3.9vw,2.95rem);line-height:1.08}
.brand-name{letter-spacing:.02em}
h4{margin:0;font-size:1rem;font-weight:600;letter-spacing:-.015em}
p{margin:0;line-height:1.55}
.lede{font-size:clamp(1.05rem,1.65vw,1.3rem);color:var(--muted);max-width:34ch;font-weight:400;letter-spacing:-.01em}
.eyebrow{
  font-size:.72rem;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted);
}
.shine{
  background:linear-gradient(180deg,#FFFFFF 0%,#FFFFFF 42%,#8E8E93 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.muted{color:var(--muted)}
.small{font-size:.85rem}
.tiny{font-size:.78rem}
.stack{display:flex;flex-direction:column;gap:14px}
.stack-sm{display:flex;flex-direction:column;gap:8px}

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  padding:11px 20px;border-radius:999px;font-size:.875rem;font-weight:500;
  letter-spacing:-.01em;border:1px solid transparent;cursor:pointer;
  font-family:inherit;
  transition:transform .3s cubic-bezier(.2,.8,.2,1), background .3s, box-shadow .3s;
}
.btn-primary{background:var(--text);color:#000}
.btn-primary:hover{transform:translateY(-1px);box-shadow:0 8px 24px rgba(255,255,255,.16)}
.btn-ghost{background:var(--glass);border-color:var(--line);color:var(--text)}
.btn-ghost:hover{background:rgba(255,255,255,.11);transform:translateY(-1px)}
/* Outlined secondary action. Used beside a solid primary so the hierarchy
   reads instantly without shouting — no fill, just a defined edge. */
.btn-outline{
  background:transparent;border-color:rgba(255,255,255,.34);color:var(--text);
}
.btn-outline:hover{
  background:rgba(255,255,255,.07);border-color:rgba(255,255,255,.55);
  transform:translateY(-1px);
}
.btn-block{width:100%}
.btn-lg{padding:14px 26px;font-size:.95rem}
.btn[disabled],.btn[aria-disabled="true"]{opacity:.45;cursor:not-allowed;transform:none;box-shadow:none}
.btn-quiet{
  background:transparent;border-color:transparent;color:var(--muted);
  padding:6px 10px;font-size:.82rem;
}
.btn-quiet:hover{color:var(--text);background:var(--glass)}
.link-underline{color:var(--cyan);border-bottom:1px solid rgba(90,200,250,.4);padding-bottom:1px}
.link-underline:hover{border-bottom-color:var(--cyan)}

/* ---------- 3. navigation ---------- */
.nav{position:fixed;top:14px;left:0;right:0;z-index:50;display:flex;justify-content:center;padding:0 16px}
.nav-pill{
  display:flex;align-items:center;gap:18px;
  width:100%;max-width:var(--maxw);
  padding:9px 10px 9px 22px;
  border-radius:999px;
  background:rgba(22,22,24,.62);
  border:1px solid var(--line);
  backdrop-filter:blur(28px) saturate(180%);
  -webkit-backdrop-filter:blur(28px) saturate(180%);
  box-shadow:0 1px 0 rgba(255,255,255,.09) inset, 0 12px 40px rgba(0,0,0,.6);
}
/* Official mark + wordmark. The SVG ships with a light fill because a
   file loaded through <img> can't inherit the page's currentColor. */
.brand{display:flex;align-items:center;gap:10px;flex:0 0 auto}
.brand-mark{width:32px;height:32px;display:block;flex:0 0 auto}
.brand-name{font-weight:600;letter-spacing:-.02em;font-size:1rem;white-space:nowrap}
.brand-name span{color:var(--muted);font-weight:400}
@media(max-width:420px){
  /* keep the mark, drop the second word so the pill never wraps */
  .brand-name span{display:none}
}
.foot-mark{width:38px;height:38px;margin-bottom:4px;opacity:.9}
.nav-links{display:flex;gap:20px;margin-left:auto;font-size:.845rem;color:var(--muted)}
.nav-links a{transition:color .25s;white-space:nowrap}
.nav-links a:hover{color:var(--text)}
.nav-links a[aria-current="page"]{color:var(--text)}
.nav-actions{display:flex;align-items:center;gap:8px;margin-left:auto}
.nav-links + .nav-actions{margin-left:4px}
.nav .btn{padding:9px 18px}

/* cart button + live count badge */
.cart-btn{
  position:relative;width:38px;height:38px;border-radius:999px;
  display:grid;place-items:center;flex:0 0 auto;
  background:var(--glass);border:1px solid var(--line);color:var(--text);
  cursor:pointer;transition:background .3s,border-color .3s,transform .3s;
}
.cart-btn:hover{background:rgba(255,255,255,.12);border-color:var(--glass-hi);transform:translateY(-1px)}
.cart-btn svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.5}
.cart-count{
  position:absolute;top:-5px;right:-5px;min-width:18px;height:18px;padding:0 5px;
  border-radius:999px;background:var(--cyan);color:#001018;
  font-size:.68rem;font-weight:700;line-height:18px;text-align:center;
  border:2px solid #161618;
}

/* hamburger — visible below the desktop breakpoint only */
.nav-toggle{
  display:none;width:38px;height:38px;border-radius:999px;
  background:var(--glass);border:1px solid var(--line);color:var(--text);
  cursor:pointer;place-items:center;
}
.nav-toggle svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.6}
.nav-toggle .ico-close{display:none}
.nav-toggle[aria-expanded="true"] .ico-open{display:none}
.nav-toggle[aria-expanded="true"] .ico-close{display:block}

@media(max-width:1140px){
  .nav-links{display:none}
  .nav-toggle{display:grid}
  .nav-quote-btn{display:none}
}

/* mobile drawer */
.nav-drawer{
  position:fixed;inset:0;z-index:49;
  background:rgba(0,0,0,.78);
  backdrop-filter:blur(24px) saturate(160%);
  -webkit-backdrop-filter:blur(24px) saturate(160%);
  display:flex;flex-direction:column;justify-content:center;
  padding:100px 28px 44px;overflow-y:auto;
  /* visibility flips instantly on open (so links are focusable straight away)
     and is delayed on close so the fade-out is still visible */
  opacity:0;visibility:hidden;transition:opacity .35s, visibility 0s linear .35s;
}
.nav-drawer.open{opacity:1;visibility:visible;transition:opacity .35s, visibility 0s}
.nav-drawer nav{display:flex;flex-direction:column;gap:2px;max-width:520px;width:100%;margin:0 auto}
.nav-drawer nav a{
  font-size:1.55rem;font-weight:600;letter-spacing:-.03em;padding:14px 4px;
  border-bottom:1px solid var(--line);transition:color .25s,padding-left .25s;
}
.nav-drawer nav a:hover,.nav-drawer nav a:focus-visible{padding-left:10px}
.nav-drawer nav a[aria-current="page"]{color:var(--cyan)}
.drawer-foot{max-width:520px;width:100%;margin:26px auto 0;display:flex;flex-direction:column;gap:10px}

/* ---------- 4. hero + page headers ---------- */
.hero{position:relative;padding:184px 0 40px;text-align:center;overflow:hidden}
.bloom{
  position:absolute;left:50%;top:-120px;transform:translateX(-50%);
  width:min(1300px,150vw);height:900px;pointer-events:none;z-index:0;
  background:
    radial-gradient(38% 44% at 50% 46%, rgba(90,200,250,.22), transparent 70%),
    radial-gradient(30% 38% at 33% 58%, rgba(191,90,242,.20), transparent 72%),
    radial-gradient(26% 30% at 66% 62%, rgba(255,159,10,.14), transparent 72%);
  filter:blur(30px);
}
.hero .wrap{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;gap:26px}
.hero .lede{max-width:46ch;text-align:center}
.cta-row{display:flex;gap:12px;flex-wrap:wrap;justify-content:center}

/* the two ordering paths, spelled out under the hero buttons */
.path-hint{
  display:flex;gap:14px 30px;flex-wrap:wrap;justify-content:center;
  font-size:.82rem;color:var(--muted);max-width:58ch;
}
.path-hint span{display:flex;gap:8px;align-items:baseline}
.path-hint b{color:var(--text);font-weight:600}

/* compact header used on every interior page */
.page-head{position:relative;padding:150px 0 30px;overflow:hidden}
.page-head .bloom{height:620px;top:-230px;filter:blur(40px);opacity:.85}
.page-head .wrap{position:relative;z-index:1;display:flex;flex-direction:column;gap:18px;align-items:flex-start}
.page-head h1{font-size:clamp(2.3rem,5.4vw,3.9rem)}
.page-head .lede{max-width:54ch}

.crumbs{display:flex;gap:8px;align-items:center;font-size:.8rem;color:var(--muted);flex-wrap:wrap}
.crumbs a:hover{color:var(--text)}
.crumbs i{font-style:normal;opacity:.45}

/* social row */
.socials{display:flex;align-items:center;gap:14px;color:var(--muted);font-size:.82rem;flex-wrap:wrap;justify-content:center}
.social-ico{
  width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  background:var(--glass);border:1px solid var(--line);
  transition:background .3s,transform .3s,border-color .3s;
}
.social-ico:hover{background:rgba(255,255,255,.12);border-color:var(--glass-hi);transform:translateY(-2px)}
.social-ico svg{width:16px;height:16px;fill:var(--text)}

/* CSS-rendered tumbler (stand-in for a real product photo) */
.stage{position:relative;z-index:1;margin-top:26px;display:flex;justify-content:center;perspective:1200px}
.tumbler{
  position:relative;width:190px;height:330px;
  border-radius:22px/16px;
  clip-path:polygon(9% 0,91% 0,84% 100%,16% 100%);
  background:
    repeating-linear-gradient(90deg,rgba(255,255,255,.035) 0 1px,transparent 1px 3px),
    linear-gradient(90deg,#141416 0%,#4A4A4F 16%,#C9C9CE 37%,#F0F0F2 44%,#9C9CA2 58%,#3A3A3E 80%,#111113 100%);
  box-shadow:0 40px 80px rgba(0,0,0,.8), 0 0 60px rgba(90,200,250,.10);
}
.tumbler::before{ /* rim highlight */
  content:"";position:absolute;inset:0 0 auto 0;height:16px;
  background:linear-gradient(180deg,rgba(255,255,255,.55),transparent);
}
.tumbler::after{ /* engraved monogram */
  content:"R";position:absolute;inset:0;display:grid;place-items:center;
  font-size:2.6rem;font-weight:600;letter-spacing:-.03em;
  color:rgba(20,20,22,.72);
  text-shadow:0 1px 0 rgba(255,255,255,.45), 0 -1px 1px rgba(0,0,0,.5);
}
.reflection{
  width:190px;height:80px;margin-top:6px;
  clip-path:polygon(16% 0,84% 0,91% 100%,9% 100%);
  background:linear-gradient(180deg,rgba(200,200,210,.20),transparent 72%);
  filter:blur(3px);
}
.stage-col{display:flex;flex-direction:column;align-items:center}

/* ---------- 5. marquee ---------- */
.strip{
  margin-top:64px;border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  overflow:hidden;padding:18px 0;background:linear-gradient(180deg,rgba(255,255,255,.02),transparent);
}
/* Conveyor-belt marquee.

   Two things matter for a seamless loop:

   1. The gap lives INSIDE the group, as a trailing margin on every item —
      including the last. That makes a group's rendered width exactly equal
      to its pitch, so copies tile with identical spacing and there is no
      wider seam where one copy meets the next. (A `gap` on the track put a
      gap *between* the copies too, which made -50% land half a gap short.)

   2. The shift is one whole group, not 50% of the track. site.js measures
      the group and clones it until the track is at least one group wider
      than the viewport, so content is always entering on the right as it
      leaves on the left — then sets --strip-shift/--strip-copies. The
      fallbacks below keep it sane if the script never runs. */
.strip-track{
  display:flex;
  width:max-content;
  flex-shrink:0;
  white-space:nowrap;
  will-change:transform;
  animation:strip-scroll var(--strip-duration,32s) linear infinite;
}
.strip-group{display:flex;flex-shrink:0}
.strip-group span{
  font-size:.78rem;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);
  margin-right:56px;
}
@keyframes strip-scroll{
  from{transform:translateX(0)}
  to{transform:translateX(calc(-1 * var(--strip-shift, 50%)))}
}

/* ---------- 6. sections + glass cards ---------- */
section{padding:110px 0}
section.tight{padding:70px 0}
section.top{padding-top:40px}
.sec-head{display:flex;flex-direction:column;gap:14px;max-width:52ch;margin-bottom:52px}
.sec-head.center{margin-left:auto;margin-right:auto;text-align:center;align-items:center}

.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.cards.two{grid-template-columns:repeat(2,1fr)}
@media(max-width:900px){.cards,.cards.two{grid-template-columns:1fr}}
.card{
  position:relative;overflow:hidden;isolation:isolate;
  padding:30px 26px 34px;border-radius:24px;
  background:var(--glass);border:1px solid var(--line);
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  box-shadow:0 1px 0 rgba(255,255,255,.08) inset;
  display:flex;flex-direction:column;gap:12px;min-height:280px;
  transition:transform .45s cubic-bezier(.2,.8,.2,1), background .45s, border-color .45s;
}
.card:hover{transform:translateY(-6px);background:rgba(255,255,255,.085);border-color:var(--glass-hi)}
.card .spec{ /* pointer-tracked specular highlight */
  position:absolute;inset:-40%;z-index:-1;opacity:0;transition:opacity .4s;
  background:radial-gradient(320px circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,.13),transparent 62%);
}
.card:hover .spec{opacity:1}
.card p{color:var(--muted);font-size:.95rem}
.card .note{margin-top:auto;font-size:.82rem;color:var(--muted);letter-spacing:.02em}
.card .card-cta{margin-top:auto;padding-top:8px}
.card.flat{min-height:0}
.glyph{
  width:44px;height:44px;border-radius:12px;display:grid;place-items:center;
  background:linear-gradient(160deg,rgba(255,255,255,.16),rgba(255,255,255,.03));
  border:1px solid var(--line);margin-bottom:6px;
}
.glyph svg{width:22px;height:22px;stroke:var(--text);fill:none;stroke-width:1.4}

/* a panel is a card without the hover lift — used for form and cart surfaces */
.panel{
  border-radius:24px;padding:28px;
  background:var(--glass);border:1px solid var(--line);
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  box-shadow:0 1px 0 rgba(255,255,255,.08) inset;
}
.panel + .panel{margin-top:18px}
.panel-head{margin-bottom:22px;display:flex;flex-direction:column;gap:8px}
@media(max-width:560px){.panel{padding:22px 18px}}

/* ---------- 7. product cards ---------- */
.product-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
@media(max-width:900px){.product-grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.product-grid{grid-template-columns:1fr}}

.product-card{
  position:relative;overflow:hidden;isolation:isolate;
  border-radius:24px;border:1px solid var(--line);
  background:var(--glass);
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  box-shadow:0 1px 0 rgba(255,255,255,.08) inset;
  display:flex;flex-direction:column;
  transition:transform .45s cubic-bezier(.2,.8,.2,1), background .45s, border-color .45s;
}
.product-card:hover{transform:translateY(-6px);background:rgba(255,255,255,.085);border-color:var(--glass-hi)}
.product-card .spec{
  position:absolute;inset:-40%;z-index:-1;opacity:0;transition:opacity .4s;
  background:radial-gradient(320px circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,.13),transparent 62%);
}
.product-card:hover .spec{opacity:1}
/* 4:5 to suit the owner's tall product photography. The images fed in here
   are purpose-built crops framed around the product (see products.js
   `card: true`), so `cover` no longer chops logos off the bottom. */
.product-media{
  position:relative;aspect-ratio:4/5;overflow:hidden;
  border-bottom:1px solid var(--line);
  display:grid;place-items:center;
  background:#0E0E11;
}
.product-media picture{display:block;width:100%;height:100%}
.product-media img{
  /* the card box already fixes the ratio, so the baked-in width/height
     attributes must not fight it */
  width:100%;height:100%;object-fit:cover;object-position:center;
  transition:transform .6s cubic-bezier(.2,.8,.2,1);
}
.product-card:hover .product-media img{transform:scale(1.035)}
/* dashed chip shown wherever real product photography is still missing */
.ph-label{
  position:relative;z-index:2;font-size:.66rem;letter-spacing:.16em;text-transform:uppercase;
  color:rgba(255,255,255,.78);text-shadow:0 1px 4px rgba(0,0,0,.8);
  border:1px dashed rgba(255,255,255,.3);border-radius:999px;padding:7px 13px;
  background:rgba(0,0,0,.3);backdrop-filter:blur(6px);
}
.product-tags{position:absolute;top:12px;left:12px;z-index:3;display:flex;gap:6px;flex-wrap:wrap}
.product-body{padding:20px 22px 24px;display:flex;flex-direction:column;gap:8px;flex:1}
/* Titles and blurbs are clamped so cards in a row share the same internal
   rhythm. The CTA baseline itself comes from the stretched grid row plus
   `.product-actions{margin-top:auto}` below — the clamps keep the text block
   from varying wildly, they don't do the aligning on their own. */
.product-body h3{
  font-size:1.12rem;min-height:2.3em;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.product-body p{
  color:var(--muted);font-size:.89rem;line-height:1.45;min-height:2.6em;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.product-price{font-size:1.02rem;font-weight:600;letter-spacing:-.02em}
.product-price small{font-size:.78rem;font-weight:400;color:var(--muted);letter-spacing:0}
.product-price.quote{color:var(--muted);font-weight:500;font-size:.92rem}
.product-actions{margin-top:auto;padding-top:16px;display:flex;gap:9px;flex-wrap:wrap}
.product-actions .btn{flex:1;min-width:140px}
/* cards stretch to the tallest in the row */
.product-grid{align-items:stretch}

/* shop filters */
.filter-row{display:flex;gap:9px;flex-wrap:wrap;margin-bottom:34px}
.chip{
  padding:9px 16px;border-radius:999px;font-size:.82rem;cursor:pointer;
  background:var(--glass);border:1px solid var(--line);color:var(--muted);
  font-family:inherit;transition:background .3s,color .3s,border-color .3s;
}
.chip:hover{color:var(--text)}
.chip[aria-pressed="true"]{background:var(--text);color:#000;border-color:var(--text)}

/* ---------- 8. product detail ---------- */
.product-layout{display:grid;grid-template-columns:1fr 1fr;gap:38px;align-items:start}
@media(max-width:880px){.product-layout{grid-template-columns:1fr;gap:26px}}
.gallery{position:sticky;top:96px}
@media(max-width:880px){.gallery{position:static}}
/* 3:4 suits the owner's tall phone photography: a square crop cut into
   the piece itself. object-position keeps the product centred. */
.gallery-main{
  aspect-ratio:3/4;border-radius:26px;overflow:hidden;border:1px solid var(--line);
  display:grid;place-items:center;position:relative;background:var(--panel);
}
.gallery-main img{width:100%;height:100%;object-fit:cover;object-position:center}
.gallery-thumbs{display:flex;gap:10px;margin-top:12px;flex-wrap:wrap}
.gallery-thumbs button{
  width:64px;height:64px;border-radius:14px;overflow:hidden;padding:0;cursor:pointer;
  border:1px solid var(--line);background:var(--glass);
}
.gallery-thumbs button[aria-current="true"]{border-color:var(--cyan)}
.price-block{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;margin:4px 0 2px}
.price-lg{font-size:2rem;font-weight:600;letter-spacing:-.03em}
.price-lg small{font-size:.85rem;font-weight:400;color:var(--muted);letter-spacing:0;margin-left:2px}
.detail-head{display:flex;flex-direction:column;gap:12px;margin-bottom:24px}
/* fixed product facts (material/colour/size) — statements, not choices */
.spec-list{list-style:none;margin:6px 0 0;padding:0;border-top:1px solid var(--line)}
.spec-list li{display:flex;justify-content:space-between;gap:16px;padding:9px 0;border-bottom:1px solid var(--line);font-size:.86rem}
.spec-list .k{color:var(--muted)}
.spec-list .v{font-weight:500}
.detail-head .tags{display:flex;gap:8px;flex-wrap:wrap}
.live-total{
  display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  padding:16px 18px;border-radius:16px;
  background:rgba(90,200,250,.07);border:1px solid rgba(90,200,250,.24);
  margin-bottom:16px;
}
.live-total .lt-label{font-size:.82rem;color:var(--muted)}
.live-total .lt-value{font-size:1.4rem;font-weight:600;letter-spacing:-.03em}

/* ---------- 9. forms ---------- */
.field{display:flex;flex-direction:column;gap:8px;margin-bottom:18px}
.field > label,.field-label{
  font-size:.82rem;font-weight:600;letter-spacing:-.005em;color:var(--text);
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
}
.field .hint{font-size:.78rem;color:var(--muted);line-height:1.45}
.req{color:var(--cyan);font-weight:400}
.optional{color:var(--muted);font-weight:400;font-size:.75rem;letter-spacing:0}

input[type=text],input[type=email],input[type=tel],input[type=number],
input[type=date],input[type=search],select,textarea{
  width:100%;padding:12px 14px;border-radius:14px;
  background:rgba(255,255,255,.045);
  border:1px solid var(--line);
  color:var(--text);font-family:inherit;font-size:.92rem;
  transition:border-color .25s,background .25s,box-shadow .25s;
  -webkit-appearance:none;appearance:none;
}
textarea{min-height:110px;resize:vertical;line-height:1.5}
input::placeholder,textarea::placeholder{color:#5A5A60}
input:hover,select:hover,textarea:hover{background:rgba(255,255,255,.07)}
input:focus,select:focus,textarea:focus{
  outline:none;border-color:var(--cyan);background:rgba(255,255,255,.07);
  box-shadow:0 0 0 3px rgba(90,200,250,.16);
}
select{
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2386868B' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 14px center;background-size:11px;
  padding-right:38px;
}
select option{background:#151517;color:var(--text)}
input[type=date]::-webkit-calendar-picker-indicator{filter:invert(.6);cursor:pointer}

.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:0 18px}
@media(max-width:600px){.grid-2{grid-template-columns:1fr}}

/* radio + checkbox rendered as selectable glass tiles */
.choice-row{display:flex;gap:10px;flex-wrap:wrap}
.choice-row.col{flex-direction:column}
.choice{
  position:relative;display:flex;align-items:center;gap:10px;
  padding:12px 16px;border-radius:14px;cursor:pointer;
  background:rgba(255,255,255,.045);border:1px solid var(--line);
  font-size:.88rem;transition:background .25s,border-color .25s;
}
.choice:hover{background:rgba(255,255,255,.08)}
.choice input{position:absolute;opacity:0;width:0;height:0}
.choice .dot{
  width:16px;height:16px;border-radius:50%;border:1.5px solid var(--muted);
  flex:0 0 auto;display:grid;place-items:center;transition:border-color .25s;
}
.choice .dot::after{content:"";width:8px;height:8px;border-radius:50%;background:var(--cyan);transform:scale(0);transition:transform .25s}
.choice input:checked ~ .dot{border-color:var(--cyan)}
.choice input:checked ~ .dot::after{transform:scale(1)}
.choice.checked{border-color:var(--glass-hi);background:rgba(255,255,255,.10)}
.choice input:focus-visible ~ .dot{outline:2px solid var(--cyan);outline-offset:4px}
.choice.box .dot{border-radius:5px}
.choice.box .dot::after{border-radius:2px}
.choice .c-label{display:flex;flex-direction:column;gap:2px}
.choice .c-sub{font-size:.75rem;color:var(--muted)}

/* file upload */
.dropzone{
  border:1px dashed rgba(255,255,255,.22);border-radius:18px;
  padding:26px 20px;text-align:center;cursor:pointer;
  background:rgba(255,255,255,.028);
  transition:border-color .25s,background .25s;
  display:flex;flex-direction:column;align-items:center;gap:8px;
}
.dropzone:hover,.dropzone.drag{border-color:var(--cyan);background:rgba(90,200,250,.06)}
.dropzone svg{width:24px;height:24px;stroke:var(--muted);fill:none;stroke-width:1.4}
.dropzone strong{font-size:.9rem;font-weight:600}
.dropzone input[type=file]{position:absolute;opacity:0;width:0;height:0}
.file-list{list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:8px}
.file-list li{
  display:flex;align-items:center;gap:10px;font-size:.83rem;
  padding:9px 12px;border-radius:12px;background:rgba(255,255,255,.05);border:1px solid var(--line);
}
.file-list li .fname{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.file-list li .fsize{color:var(--muted);font-size:.76rem;white-space:nowrap}

/* validation */
.field.invalid input,.field.invalid select,.field.invalid textarea{border-color:var(--red)}
.field.invalid .choice{border-color:rgba(255,69,58,.5)}
.err{color:var(--red);font-size:.78rem;display:none}
.field.invalid .err{display:block}
.form-error{
  display:none;gap:10px;align-items:flex-start;margin-bottom:18px;
  padding:13px 16px;border-radius:14px;font-size:.85rem;
  background:rgba(255,69,58,.08);border:1px solid rgba(255,69,58,.3);color:#FFB3AE;
}
.form-error.show{display:flex}

fieldset{border:0;padding:0;margin:0 0 20px}
legend{padding:0;font-size:.82rem;font-weight:600;margin-bottom:10px}
.fs-block{margin-bottom:20px}

/* ---------- 10. multi-step wizard ---------- */
/* Progress is signalled three ways at once — a filled/ringed dot, a
   checkmark replacing the number once done, and weight/contrast on the
   label — so it never depends on colour alone. Each step also carries
   screen-reader-only state text (see quote.js). */
.stepper{display:flex;gap:0;margin:0 0 34px;padding:0;list-style:none}
.stepper li{flex:1;position:relative;min-width:0}

/* connector between dots */
.stepper li::before{
  content:"";position:absolute;top:15px;left:0;right:50%;height:2px;
  background:var(--line);z-index:0;
}
.stepper li:first-child::before{display:none}
.stepper li[data-state="current"]::before,
.stepper li[data-state="done"]::before{background:rgba(90,200,250,.5)}

.stepper .s-btn{
  position:relative;z-index:1;
  display:flex;flex-direction:column;align-items:center;gap:9px;
  width:100%;padding:0 6px;background:none;border:0;font-family:inherit;
  color:inherit;text-align:center;cursor:default;
}
.stepper .s-btn:not(:disabled){cursor:pointer}
.stepper .s-btn:disabled{opacity:1}

.stepper .s-dot{
  width:32px;height:32px;border-radius:50%;
  display:grid;place-items:center;flex:0 0 auto;
  background:var(--panel);border:2px solid var(--line);
  transition:border-color .35s,background .35s,transform .35s,box-shadow .35s;
}
.stepper .s-num{
  font-size:.72rem;font-weight:700;letter-spacing:.06em;color:var(--muted);
  font-variant-numeric:tabular-nums;transition:color .3s;
}
.stepper .s-check{width:16px;height:16px;color:#001018;display:none}

.stepper li[data-state="current"] .s-dot{
  border-color:var(--cyan);background:rgba(90,200,250,.14);
  box-shadow:0 0 0 4px rgba(90,200,250,.14);
}
.stepper li[data-state="current"] .s-num{color:var(--cyan)}

.stepper li[data-state="done"] .s-dot{background:var(--cyan);border-color:var(--cyan)}
.stepper li[data-state="done"] .s-num{display:none}
.stepper li[data-state="done"] .s-check{display:block}

.stepper .s-t{
  font-size:.85rem;font-weight:500;letter-spacing:-.01em;color:var(--muted);
  transition:color .3s,font-weight .3s;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;
}
.stepper li[data-state="current"] .s-t{color:var(--text);font-weight:600}
.stepper li[data-state="done"] .s-t{color:#B8B8BE}
.stepper .s-btn:not(:disabled):hover .s-t{color:var(--text)}
.stepper .s-btn:focus-visible{outline:2px solid var(--cyan);outline-offset:4px;border-radius:12px}

@media(max-width:560px){
  /* Wrap to two lines rather than truncating — "Timing & review" was
     rendering as "Timing &…" at 320px with no way to read it. */
  .stepper .s-t{
    font-size:.72rem;white-space:normal;overflow:visible;
    line-height:1.25;text-wrap:balance;
  }
  .stepper .s-dot{width:28px;height:28px}
  .stepper li::before{top:13px}
}
@media(prefers-reduced-motion:reduce){
  .stepper .s-dot,.stepper .s-t{transition:none}
}
.form-nav{display:flex;gap:10px;align-items:center;margin-top:26px;flex-wrap:wrap}
.form-nav .spacer{flex:1}

/* review list on the final step */
.review-list{list-style:none;margin:0;padding:0}
.review-list li{
  display:flex;gap:16px;justify-content:space-between;padding:11px 0;
  border-bottom:1px solid var(--line);font-size:.88rem;
}
.review-list li:last-child{border-bottom:0}
.review-list .k{color:var(--muted);flex:0 0 40%}
.review-list .v{text-align:right;word-break:break-word;flex:1}

/* success state */
.success{text-align:center;display:flex;flex-direction:column;align-items:center;gap:18px;padding:52px 28px}
.success .tick{
  width:64px;height:64px;border-radius:50%;display:grid;place-items:center;
  background:radial-gradient(circle at 30% 25%,rgba(48,209,88,.35),rgba(48,209,88,.10));
  border:1px solid rgba(48,209,88,.4);
}
.success .tick svg{width:28px;height:28px;stroke:var(--green);fill:none;stroke-width:2}
.success h2{font-size:clamp(1.7rem,3.4vw,2.4rem)}
.success .lede{text-align:center;max-width:50ch}
.success .next-steps{
  text-align:left;max-width:440px;width:100%;margin-top:6px;
  display:flex;flex-direction:column;gap:14px;
}
.success .next-steps li{display:flex;gap:12px;font-size:.88rem;color:var(--muted);line-height:1.5}
.success .next-steps .n{
  flex:0 0 auto;width:22px;height:22px;border-radius:50%;display:grid;place-items:center;
  background:var(--glass);border:1px solid var(--line);
  font-size:.7rem;font-weight:700;color:var(--cyan);
}
.ref-code{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.8rem;
  padding:8px 14px;border-radius:999px;background:var(--glass);border:1px solid var(--line);
  color:var(--muted);letter-spacing:.06em;
}

/* ---------- 11. cart + checkout ---------- */
.cart-layout{display:grid;grid-template-columns:1fr 372px;gap:24px;align-items:start}
@media(max-width:940px){.cart-layout{grid-template-columns:1fr}}
.summary{position:sticky;top:96px}
@media(max-width:940px){.summary{position:static}}

.cart-line{
  display:grid;grid-template-columns:88px 1fr auto;gap:18px;
  padding:22px 0;border-bottom:1px solid var(--line);
}
.cart-line:first-child{padding-top:0}
.cart-line:last-child{border-bottom:0;padding-bottom:0}
@media(max-width:560px){
  .cart-line{grid-template-columns:64px 1fr;gap:14px}
  .cart-right{grid-column:1/-1;flex-direction:row;align-items:center;justify-content:space-between;text-align:left}
  .cart-thumb{width:64px;height:64px}
}
.cart-thumb{
  width:88px;height:88px;border-radius:16px;overflow:hidden;
  border:1px solid var(--line);display:grid;place-items:center;
}
.cart-thumb img{width:100%;height:100%;object-fit:cover}
.cart-info{display:flex;flex-direction:column;gap:7px;min-width:0}
.cart-info h3{font-size:1rem}
.custom-summary{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:3px}
.custom-summary li{font-size:.8rem;color:var(--muted);word-break:break-word}
.custom-summary li b{color:#B8B8BE;font-weight:500}
.cart-right{display:flex;flex-direction:column;align-items:flex-end;gap:10px;text-align:right}
.cart-right .unit{font-size:.78rem;color:var(--muted)}
.cart-right .line-total{font-size:1rem;font-weight:600;letter-spacing:-.02em}
.qty{display:flex;align-items:center;border:1px solid var(--line);border-radius:999px;overflow:hidden;background:rgba(255,255,255,.045)}
.qty button{
  width:32px;height:32px;background:transparent;border:0;color:var(--text);
  cursor:pointer;font-size:1rem;line-height:1;transition:background .25s;font-family:inherit;
}
.qty button:hover{background:rgba(255,255,255,.1)}
.qty input{
  width:42px;text-align:center;border:0;background:transparent;padding:0;
  border-radius:0;font-size:.88rem;color:var(--text);font-family:inherit;
  -moz-appearance:textfield;
}
.qty input::-webkit-outer-spin-button,.qty input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.qty input:focus{box-shadow:none;background:rgba(255,255,255,.08)}
.line-actions{display:flex;gap:2px}

.totals{list-style:none;margin:0;padding:0}
.totals li{display:flex;justify-content:space-between;gap:16px;padding:10px 0;font-size:.9rem;color:var(--muted)}
.totals li .v{color:var(--text)}
.totals li.grand{
  border-top:1px solid var(--line);margin-top:6px;padding-top:16px;
  font-size:1.15rem;color:var(--text);font-weight:600;letter-spacing:-.02em;
}
.empty-state{text-align:center;padding:64px 24px;display:flex;flex-direction:column;align-items:center;gap:16px}
.empty-state .glyph{margin:0 auto 6px}

/* ---------- 12. process / turnaround / faq ---------- */
/* Numbered process steps: equal columns separated by a hairline on each
   cell's right edge.

   The gutter has to sit on BOTH sides of every interior divider. Padding
   on one side only (which is what this used to be: 28px right, 0 left)
   leaves the next column's text starting flush against the line.

   Row edges are found with :nth-child rather than :first-child /
   :last-child, because once the grid reflows to two columns those two
   pseudo-classes no longer describe the ends of a row — the old rule left
   a stray divider hanging on the section's right edge at that width. */
.steps{
  --step-gutter:26px;
  display:grid;grid-template-columns:repeat(3,1fr);gap:0;
  border-top:1px solid var(--line);
}
.steps.four{grid-template-columns:repeat(4,1fr)}
.steps.five{grid-template-columns:repeat(5,1fr)}

.step{
  padding:34px var(--step-gutter);
  border-right:1px solid var(--line);
  display:flex;flex-direction:column;gap:10px;
}

/* Row edges stay flush with the section so the grid still lines up with
   the container, rather than looking inset. Each column count overrides
   the previous block at equal specificity, so source order decides. */
.steps > .step:nth-child(3n+1){padding-left:0}
.steps > .step:nth-child(3n){padding-right:0;border-right:0}

.steps.four > .step{padding-left:var(--step-gutter);padding-right:var(--step-gutter);border-right:1px solid var(--line)}
.steps.four > .step:nth-child(4n+1){padding-left:0}
.steps.four > .step:nth-child(4n){padding-right:0;border-right:0}

.steps.five > .step{padding-left:var(--step-gutter);padding-right:var(--step-gutter);border-right:1px solid var(--line)}
.steps.five > .step:nth-child(5n+1){padding-left:0}
.steps.five > .step:nth-child(5n){padding-right:0;border-right:0}

/* An incomplete final row still ends without a trailing divider. */
.step:last-child{border-right:0}

@media(max-width:1000px){
  .steps.four,.steps.five{grid-template-columns:repeat(2,1fr)}
  /* Two columns: row edges move, so re-derive them. :nth-child(n) matches
     everything and simply matches the specificity of the rules above, so
     these win on source order instead of needing !important. */
  .steps.four > .step:nth-child(n),
  .steps.five > .step:nth-child(n){
    padding-left:var(--step-gutter);padding-right:var(--step-gutter);
    border-right:1px solid var(--line);
  }
  .steps.four > .step:nth-child(2n+1),
  .steps.five > .step:nth-child(2n+1){padding-left:0}
  .steps.four > .step:nth-child(2n),
  .steps.five > .step:nth-child(2n){padding-right:0;border-right:0}
  .steps.four > .step:last-child,
  .steps.five > .step:last-child{border-right:0}
}

@media(max-width:820px){
  .steps,.steps.four,.steps.five{grid-template-columns:1fr}
  /* Stacked: the dividers are horizontal now, so there is nothing to clear
     and the text should line up with the rest of the page. */
  .steps > .step:nth-child(n),
  .steps.four > .step:nth-child(n),
  .steps.five > .step:nth-child(n){
    border-right:0;border-bottom:1px solid var(--line);
    padding-left:0;padding-right:0;
  }
}
.step-n{
  font-size:.75rem;font-weight:600;letter-spacing:.14em;color:var(--cyan);
  font-variant-numeric:tabular-nums;
}
.step-n.violet{color:var(--violet)}
.step-n.amber{color:var(--amber)}
.step p{color:var(--muted);font-size:.95rem;max-width:32ch}
.step h3{font-size:1.1rem}

/* two labelled ordering tracks */
.track{margin-bottom:70px}
.track:last-child{margin-bottom:0}
.track-head{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:10px}
.track-sub{color:var(--muted);font-size:.95rem;max-width:56ch;margin-bottom:22px}

/* turnaround rows */
.turnaround{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
@media(max-width:900px){.turnaround{grid-template-columns:1fr}}
.turn-card{
  border-radius:22px;padding:26px 24px;border:1px solid var(--line);
  background:var(--glass);display:flex;flex-direction:column;gap:10px;
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
}
.turn-time{font-size:1.45rem;font-weight:600;letter-spacing:-.03em;line-height:1.15}
.turn-card p{color:var(--muted);font-size:.9rem}
.turn-card .eyebrow{margin-bottom:2px}

/* FAQ accordion */
.faq{border-top:1px solid var(--line)}
.faq details{border-bottom:1px solid var(--line)}
.faq summary{
  cursor:pointer;padding:22px 40px 22px 0;position:relative;list-style:none;
  font-size:1.05rem;font-weight:600;letter-spacing:-.02em;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{
  content:"";position:absolute;right:8px;top:50%;width:11px;height:11px;
  border-right:1.5px solid var(--muted);border-bottom:1.5px solid var(--muted);
  transform:translateY(-70%) rotate(45deg);transition:transform .3s;
}
.faq details[open] summary::after{transform:translateY(-30%) rotate(225deg)}
.faq .faq-body{padding:0 0 24px;color:var(--muted);font-size:.95rem;max-width:66ch;display:flex;flex-direction:column;gap:12px}

/* ---------- 13. materials grid ---------- */
.mats{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
@media(max-width:900px){.mats{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){.mats{grid-template-columns:1fr}}
.mat{
  position:relative;height:210px;border-radius:20px;overflow:hidden;
  border:1px solid var(--line);display:flex;align-items:flex-end;padding:18px;
  transition:transform .45s cubic-bezier(.2,.8,.2,1);
}
.mat:hover{transform:translateY(-4px)}
.mat span{
  position:relative;z-index:2;font-size:.8rem;letter-spacing:.14em;text-transform:uppercase;
  font-weight:600;color:rgba(255,255,255,.92);text-shadow:0 1px 3px rgba(0,0,0,.7);
}
.mat::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,transparent 45%,rgba(0,0,0,.72))}

/* material swatches — also used as product photo placeholders */
.m-walnut{background:
  repeating-linear-gradient(96deg,rgba(0,0,0,.11) 0 1px,transparent 1px 7px,rgba(0,0,0,.06) 7px 9px,transparent 9px 15px),
  linear-gradient(150deg,#4A2E1C,#7A4A2B 45%,#3A2415)}
.m-steel{background:
  repeating-linear-gradient(90deg,rgba(255,255,255,.05) 0 1px,transparent 1px 4px),
  linear-gradient(120deg,#2B2D31,#8E9198 48%,#31343A)}
.m-slate{background:
  radial-gradient(120% 90% at 20% 10%,rgba(255,255,255,.10),transparent 60%),
  linear-gradient(160deg,#1D2124,#33383D)}
.m-brass{background:
  repeating-linear-gradient(90deg,rgba(255,255,255,.06) 0 1px,transparent 1px 5px),
  linear-gradient(120deg,#4A3813,#C9A227 46%,#5C4517)}
.m-leather{background:
  radial-gradient(80% 60% at 30% 30%,rgba(255,255,255,.07),transparent 70%),
  linear-gradient(150deg,#2E1F18,#5A3A2A)}
.m-glass{background:
  linear-gradient(135deg,rgba(90,200,250,.28),rgba(255,255,255,.06) 40%,rgba(191,90,242,.20)),
  #14161A}
.m-paper{background:
  radial-gradient(90% 70% at 25% 20%,rgba(255,255,255,.12),transparent 65%),
  linear-gradient(150deg,#1A1A1E,#3C3C42)}
.m-mixed{background:
  radial-gradient(70% 60% at 25% 20%,rgba(90,200,250,.18),transparent 65%),
  radial-gradient(60% 60% at 75% 70%,rgba(255,159,10,.14),transparent 65%),
  linear-gradient(150deg,#17171A,#2C2C31)}

/* ---------- 14. closer + footer ---------- */
.closer{
  position:relative;overflow:hidden;border-radius:32px;padding:88px 32px;text-align:center;
  border:1px solid var(--line);
  background:radial-gradient(90% 130% at 50% 0%,rgba(90,200,250,.16),transparent 60%),var(--panel);
  display:flex;flex-direction:column;align-items:center;gap:22px;
}
.closer.compact{padding:56px 28px}
.closer.violet{background:radial-gradient(90% 130% at 50% 0%,rgba(191,90,242,.16),transparent 60%),var(--panel)}
.closer .lede{text-align:center;max-width:46ch}
.closer .fineprint{font-size:.85rem;color:var(--muted);max-width:46ch}

footer{border-top:1px solid var(--line);padding:44px 0 40px;margin-top:60px}
.foot{display:flex;justify-content:space-between;gap:28px;flex-wrap:wrap;color:var(--muted);font-size:.85rem}
.foot a:hover{color:var(--text)}
.foot-col{display:flex;flex-direction:column;gap:9px}
.foot-col strong{color:var(--text);font-weight:600;font-size:.85rem}
.foot-legal{
  max-width:var(--maxw);margin:34px auto 0;padding:20px 24px 0;
  border-top:1px solid var(--line);color:var(--muted);font-size:.78rem;
  display:flex;justify-content:space-between;gap:18px;flex-wrap:wrap;
}

/* ---------- 15. tags, notices, toast ---------- */
.tag{
  display:inline-flex;align-items:center;gap:6px;
  padding:5px 11px;border-radius:999px;font-size:.68rem;font-weight:600;
  letter-spacing:.09em;text-transform:uppercase;white-space:nowrap;
  border:1px solid var(--line);background:var(--glass);color:var(--muted);
}
.tag-buy{color:var(--cyan);border-color:rgba(90,200,250,.32);background:rgba(90,200,250,.10)}
.tag-quote{color:var(--violet);border-color:rgba(191,90,242,.32);background:rgba(191,90,242,.10)}
.tag-bulk{color:var(--amber);border-color:rgba(255,159,10,.32);background:rgba(255,159,10,.10)}
.tag-todo{color:var(--amber);border-color:rgba(255,159,10,.35);background:rgba(255,159,10,.08)}
/* Payment status badges — assets/js/payment.js */
.tag-paid{color:var(--green);border-color:rgba(48,209,88,.32);background:rgba(48,209,88,.10)}
.tag-due{color:var(--amber);border-color:rgba(255,159,10,.32);background:rgba(255,159,10,.10)}
.tag-refunded{color:var(--red);border-color:rgba(255,69,58,.32);background:rgba(255,69,58,.10)}

.notice{
  display:flex;gap:12px;padding:14px 16px;border-radius:16px;
  background:rgba(255,255,255,.04);border:1px solid var(--line);
  font-size:.85rem;color:var(--muted);line-height:1.5;
}
.notice svg{width:17px;height:17px;flex:0 0 auto;margin-top:2px;stroke:var(--muted);fill:none;stroke-width:1.5}
.notice b{color:var(--text);font-weight:600}
.notice.cyan{border-color:rgba(90,200,250,.28);background:rgba(90,200,250,.07)}
.notice.cyan svg{stroke:var(--cyan)}
.notice.amber{border-color:rgba(255,159,10,.28);background:rgba(255,159,10,.07)}
.notice.amber svg{stroke:var(--amber)}
.notice.violet{border-color:rgba(191,90,242,.28);background:rgba(191,90,242,.07)}
.notice.violet svg{stroke:var(--violet)}

/* owner-facing placeholder marker — toggled by SITE.showPlaceholderNotes */
.todo-note{
  font-size:.74rem;color:var(--amber);letter-spacing:.01em;line-height:1.45;
}
.todo-note::before{content:"TODO — ";font-weight:700;letter-spacing:.08em}
body.hide-todo .todo-note,body.hide-todo .tag-todo{display:none}

/* toast */
.toast{
  position:fixed;left:50%;bottom:26px;transform:translate(-50%,20px);
  z-index:80;display:flex;align-items:center;gap:14px;
  padding:13px 20px;border-radius:999px;
  background:rgba(22,22,24,.9);border:1px solid var(--glass-hi);
  backdrop-filter:blur(24px);-webkit-backdrop-filter:blur(24px);
  box-shadow:0 16px 44px rgba(0,0,0,.7);
  font-size:.87rem;opacity:0;visibility:hidden;
  transition:opacity .35s,transform .35s,visibility .35s;
  max-width:calc(100vw - 32px);
}
.toast.show{opacity:1;visibility:visible;transform:translate(-50%,0)}
.toast a{color:var(--cyan);white-space:nowrap}

/* ---------- 16. motion ---------- */
/* content is visible by default; only JS opts into the reveal, so the
   page never renders blank if the script fails to run.

   The reveal runs as a keyframe animation rather than a transition.
   Same movement, but a transition on a freshly inserted element can
   fail to start (leaving it stuck at opacity 0), whereas an animation
   with `forwards` always lands on its final frame. Product pages and
   the gallery are rendered from JS, so this matters. */
/* .in sets the finished state directly AND plays the animation. If the
   animation never runs — background tab, reduced motion, an engine that
   drops it — the element is simply visible rather than stuck at zero. */
.js .rise{opacity:0;transform:translateY(22px)}
.js .rise.in{opacity:1;transform:none;animation:rise-in .9s cubic-bezier(.2,.8,.2,1)}
@keyframes rise-in{
  from{opacity:0;transform:translateY(22px)}
  to{opacity:1;transform:none}
}
@media(prefers-reduced-motion:reduce){
  .js .rise{opacity:1;transform:none}
  .js .rise.in{animation:none}
  .strip-track{animation:none}
  *{scroll-behavior:auto!important}
  /* Blanket suppression so hover lifts, image zooms and card transitions
     added later can't reintroduce motion. Transforms are neutralised
     explicitly, since a near-zero duration would still jump to the end
     state. (review finding 27) */
  *,*::before,*::after{
    animation-duration:.01ms!important;
    animation-iteration-count:1!important;
    transition-duration:.01ms!important;
  }
  .product-card:hover,.g-item:hover,.work-tile:hover,.mat:hover,
  .card:hover,.btn:hover,.cart-btn:hover,.social-ico:hover{transform:none}
  .product-card:hover .product-media img,
  .g-item:hover .g-open img,.g-item:hover .g-open video{transform:none}
}

/* ============================================================
   17. REAL PRODUCT MEDIA
   Added when the owner's real photography replaced the CSS
   placeholders. Reuses the existing tokens, radii and easing.
   ============================================================ */

/* .product-media is defined once, in section 7 — the duplicate that used to
   sit here has been removed so there is a single authoritative definition. */
.gallery-main picture{display:block;width:100%;height:100%}

/* ---------- hero product photo ---------- */
/* Replaces the CSS-drawn tumbler. The photo's own near-black
   background is faded out at the edges so the product appears to sit
   inside the existing spectral bloom rather than in a pasted-on box. */
.hero-photo{
  position:relative;z-index:1;margin-top:18px;
  display:flex;justify-content:center;
}
.hero-photo-inner{
  position:relative;
  width:min(460px,84vw);
  border-radius:28px;
  overflow:hidden;
  /* soft oval vignette: no hard photo edge anywhere */
  -webkit-mask-image:radial-gradient(66% 66% at 50% 50%,#000 42%,rgba(0,0,0,.45) 66%,transparent 88%);
  mask-image:radial-gradient(66% 66% at 50% 50%,#000 42%,rgba(0,0,0,.45) 66%,transparent 88%);
}
.hero-photo-inner img{
  width:100%;height:auto;display:block;
  filter:contrast(1.06) saturate(.96);
}
/* a faint cyan lift under the piece, matching the bloom above it */
.hero-photo::after{
  content:"";position:absolute;left:50%;bottom:-6%;transform:translateX(-50%);
  width:min(520px,90vw);height:120px;pointer-events:none;
  background:radial-gradient(50% 60% at 50% 50%,rgba(90,200,250,.16),transparent 70%);
  filter:blur(18px);
}
@media(max-width:560px){.hero-photo-inner{width:min(360px,88vw)}}

/* ---------- homepage recent-work strip ---------- */
.work-strip{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
@media(max-width:760px){.work-strip{grid-template-columns:repeat(2,1fr)}}
.work-tile{
  position:relative;display:block;border-radius:18px;overflow:hidden;
  /* 4:5 matches the product card crops these tiles are fed from — a 1:1 tile
     re-cropped them and cut ~20% off the bottom of each engraving. */
  border:1px solid var(--line);aspect-ratio:4/5;
  transition:transform .45s cubic-bezier(.2,.8,.2,1),border-color .45s;
}
.work-tile:hover{transform:translateY(-4px);border-color:var(--glass-hi)}
.work-tile picture{display:block;width:100%;height:100%}
.work-tile img{width:100%;height:100%;object-fit:cover}
.work-tile::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,transparent 55%,rgba(0,0,0,.8))}
.work-cap{
  position:absolute;left:14px;right:14px;bottom:12px;z-index:2;
  font-size:.78rem;font-weight:500;letter-spacing:-.01em;
  color:rgba(255,255,255,.94);text-shadow:0 1px 4px rgba(0,0,0,.8);
}

/* ---------- Our Work gallery (masonry) ---------- */
/* CSS columns keep each photo's natural proportions — nothing is
   squashed into a uniform grid. */
.gallery-wall{columns:3;column-gap:16px}
@media(max-width:1000px){.gallery-wall{columns:2}}
@media(max-width:600px){.gallery-wall{columns:1}}
.g-item{
  break-inside:avoid;margin:0 0 16px;
  border-radius:20px;overflow:hidden;
  border:1px solid var(--line);background:var(--glass);
  transition:transform .45s cubic-bezier(.2,.8,.2,1),border-color .45s;
}
.g-item:hover{transform:translateY(-4px);border-color:var(--glass-hi)}
.g-open{
  display:block;width:100%;padding:0;border:0;background:none;cursor:zoom-in;
  position:relative;line-height:0;
}
/* The tile clips overflow (for the hover zoom), which would clip an outset
   focus ring to nothing. Draw it inset instead, on the tile itself. */
.g-open:focus-visible{outline:none}
.g-item:focus-within{border-color:var(--cyan)}
.g-item:focus-within .g-open{box-shadow:inset 0 0 0 2px var(--cyan)}
.g-open picture{display:block}
.g-open img,.g-open video{width:100%;height:auto;display:block}
.g-play{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:52px;height:52px;border-radius:50%;display:grid;place-items:center;
  background:rgba(0,0,0,.5);border:1px solid var(--glass-hi);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  opacity:.85;transition:opacity .3s;
}
.g-item:hover .g-play{opacity:1}
.g-play svg{width:22px;height:22px;fill:var(--text)}
.g-cap{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:12px 14px;flex-wrap:wrap;
}
.g-title{font-size:.85rem;letter-spacing:-.01em}
.g-quote{font-size:.78rem;color:var(--cyan);white-space:nowrap}
.g-quote:hover{text-decoration:underline}

/* ---------- lightbox ---------- */
.lb{
  position:fixed;inset:0;z-index:90;
  display:flex;align-items:center;justify-content:center;
  padding:64px 20px 88px;
  background:rgba(0,0,0,.9);
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  opacity:0;transition:opacity .25s;
}
/* The [hidden] attribute has the same specificity as .lb, so without this
   rule the class's display:flex wins the cascade and the closed lightbox
   stays laid out full-screen — invisible but still catching every click
   on the page underneath it. */
.lb[hidden]{display:none}
.lb.open{opacity:1}
.lb-stage{max-width:min(1100px,100%);max-height:100%;display:flex;align-items:center;justify-content:center}
.lb-stage img,.lb-stage video{
  max-width:100%;max-height:calc(100vh - 160px);
  width:auto;height:auto;border-radius:18px;
  box-shadow:0 30px 80px rgba(0,0,0,.8);
}
.lb-close,.lb-nav{
  position:absolute;z-index:2;
  width:44px;height:44px;border-radius:50%;display:grid;place-items:center;
  background:var(--glass);border:1px solid var(--line);color:var(--text);
  cursor:pointer;transition:background .3s,border-color .3s;
}
.lb-close:hover,.lb-nav:hover{background:rgba(255,255,255,.14);border-color:var(--glass-hi)}
.lb-close svg,.lb-nav svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.6}
.lb-close{top:18px;right:18px}
.lb-prev{left:18px;top:50%;transform:translateY(-50%)}
.lb-next{right:18px;top:50%;transform:translateY(-50%)}
.lb-bar{
  position:absolute;left:0;right:0;bottom:0;
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:16px 22px;flex-wrap:wrap;
  background:linear-gradient(180deg,transparent,rgba(0,0,0,.75));
  font-size:.88rem;color:var(--muted);
}
@media(max-width:640px){
  .lb{padding:56px 12px 96px}
  .lb-prev{left:8px}.lb-next{right:8px}
  .lb-bar{justify-content:center;text-align:center}
}

/* ---------- inline product video ---------- */
.product-video{
  margin-top:14px;border-radius:20px;overflow:hidden;
  border:1px solid var(--line);position:relative;background:var(--panel);
}
.product-video video{width:100%;height:auto;display:block}
.product-video figcaption{
  padding:10px 14px;font-size:.78rem;color:var(--muted);
  border-top:1px solid var(--line);
}

/* ---------- featured video band ---------- */
.film{
  display:grid;grid-template-columns:1fr 1fr;gap:34px;align-items:center;
}
@media(max-width:900px){.film{grid-template-columns:1fr;gap:24px}}
.film-frame{
  border-radius:26px;overflow:hidden;border:1px solid var(--line);
  box-shadow:0 30px 70px rgba(0,0,0,.7);position:relative;background:var(--panel);
}
.film-frame video{width:100%;height:auto;display:block}

/* The masonry wall fades in as a whole. Per-tile .rise transitions are
   unreliable inside CSS multi-column layout, so the wall handles it. */
.gallery-wall{opacity:0;transition:opacity .6s cubic-bezier(.2,.8,.2,1)}
.gallery-wall.g-in{opacity:1}
@media(prefers-reduced-motion:reduce){.gallery-wall{opacity:1;transition:none}}


/* ============================================================
   18. OWNER FEEDBACK PASS
   Logo lockup, relocated socials, upgraded quote stepper,
   text-us callout, gallery polish, review cards.
   ============================================================ */

/* socials moved out of the hero — they sit with a section heading now */
.socials-inline{
  justify-content:flex-start;margin-top:4px;
  font-size:.8rem;
}
.socials-inline .social-ico{width:32px;height:32px}

/* ---------- starting-price reference (quote page) ---------- */
.price-table{
  list-style:none;margin:0;padding:0;
  border-top:1px solid var(--line);
}
.price-table li{
  display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  padding:12px 0;border-bottom:1px solid var(--line);font-size:.92rem;
}
.price-table .pt-name{font-weight:500}
.price-table .pt-price{font-weight:600;letter-spacing:-.02em;white-space:nowrap}
.price-table .pt-price.soft{color:var(--muted);font-weight:500}

/* ---------- text-us callout ---------- */
.text-card{
  display:flex;align-items:center;gap:20px;flex-wrap:wrap;
  padding:22px 24px;border-radius:22px;
  background:radial-gradient(120% 160% at 0% 0%,rgba(90,200,250,.10),transparent 60%),var(--glass);
  border:1px solid var(--line);
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
}
.text-card .tc-icon{
  width:46px;height:46px;border-radius:14px;flex:0 0 auto;display:grid;place-items:center;
  background:linear-gradient(160deg,rgba(255,255,255,.16),rgba(255,255,255,.03));
  border:1px solid var(--line);
}
.text-card .tc-icon svg{width:22px;height:22px;stroke:var(--cyan);fill:none;stroke-width:1.5}
.text-card .tc-body{flex:1;min-width:200px;display:flex;flex-direction:column;gap:3px}
.text-card .tc-title{font-size:1.02rem;font-weight:600;letter-spacing:-.02em}
.text-card .tc-sub{font-size:.86rem;color:var(--muted)}
/* the number stays readable (and selectable) for desktop visitors who
   can't action an sms: link */
.text-card .tc-num{
  font-size:.92rem;font-weight:600;letter-spacing:.01em;
  color:var(--text);user-select:all;
}
@media(max-width:560px){
  .text-card{gap:14px;padding:20px}
  .text-card .btn{width:100%}
}

/* ---------- gallery polish ---------- */
.g-open{overflow:hidden}
.g-open picture,.g-open img,.g-open video{
  transition:transform .7s cubic-bezier(.2,.8,.2,1);
}
.g-item:hover .g-open img,.g-item:hover .g-open video{transform:scale(1.045)}
.g-item{position:relative}
.g-mat{
  position:absolute;top:12px;left:12px;z-index:3;
  padding:5px 10px;border-radius:999px;
  font-size:.64rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:rgba(255,255,255,.9);background:rgba(0,0,0,.5);
  border:1px solid rgba(255,255,255,.18);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  /* Always visible: the material is real information customers scan for,
     and hiding it behind :hover also hides it from touch users on hybrid
     devices that report hover:hover. It lifts slightly on hover instead. */
  opacity:.82;transition:opacity .35s,transform .35s;
}
.g-item:hover .g-mat,.g-item:focus-within .g-mat{opacity:1;transform:translateY(-1px)}

/* ---------- customer reviews ---------- */
/* The section only renders when REVIEWS in products.js has real entries. */
.review-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
@media(max-width:900px){.review-grid{grid-template-columns:1fr}}
.review-card{
  padding:26px 24px;border-radius:22px;
  background:var(--glass);border:1px solid var(--line);
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  display:flex;flex-direction:column;gap:14px;
}
.review-card blockquote{margin:0;font-size:.95rem;line-height:1.6}
.review-card .rv-who{
  margin-top:auto;font-size:.82rem;color:var(--muted);
  display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;
}
.review-card .rv-stars{color:var(--amber);letter-spacing:.1em;font-size:.85rem}

/* Touch targets. On coarse pointers the small pill controls grow to a
   comfortable minimum — found during the responsive QA pass, where filter
   chips measured 35px tall on tablet/mobile. */
/* `any-pointer` rather than `pointer`: a touchscreen laptop reports its
   primary pointer as fine, but its users still tap. */
@media (any-pointer: coarse) {
  .chip{min-height:44px;padding-top:0;padding-bottom:0;display:inline-flex;align-items:center}
  .btn{min-height:44px}
  .btn-quiet{min-height:44px}
  .social-ico{width:44px;height:44px}
  .qty button{width:44px;height:44px}
  /* the hamburger is the ONLY route to navigation below 1140px */
  .nav-toggle,.cart-btn{width:44px;height:44px}
  .lb-close,.lb-nav{width:48px;height:48px}
  /* inline gallery link was ~15px tall */
  .g-quote{display:inline-flex;align-items:center;min-height:44px}
  .gallery-thumbs button{width:56px;height:56px}
}
