/* ==========================================================================
   C'GARDEN — atelier register
   Structural conventions follow the luxury-maison pattern the client admires
   (two-row header, tabbed mega-menu, full-bleed editorial blocks, services
   trio, four-column footer). Everything expressive is C'Garden's own:
   the client-issued corporate palette (deep royal navy, powder rose, soft
   cream white, warm mist grey), Marcellus + Jost, and the dust hero that no
   other house has.

   Re-skinned 17 Aug 2026 from the earlier rose-gold/wine scheme. The old
   --rose / --wine / --blush constants are gone; --rose now means powder rose
   #F7D4CE, and --rose-deep / --black are mood tokens rather than fixed hues.
   ========================================================================== */

:root{
  /* ---- CORPORATE PALETTE — client-issued 17 Aug 2026 -------------------
     Stated ratio: 60% deep royal navy · 25% powder rose · 15% soft cream
     white · 10% warm mist grey. Navy leads, so navy is the default ground
     and the light mood is the alternate — not the other way round.

     One hard constraint drives everything below: POWDER ROSE ON CREAM WHITE
     IS 1.30:1. It can never carry type on a light ground. On navy it is
     11.10:1, so powder rose is a TYPE colour on navy and a FILL colour on
     cream. Every tint here is mixed from these four and nothing else. */
  --navy:#17224E;   /* deep royal navy  — 60% */
  --rose:#F7D4CE;   /* powder rose      — 25% */
  --cream:#F9F8F5;  /* soft cream white — 15% */
  --mist:#D9D9D6;   /* warm mist grey   — 10% */

  --navy-deep:#111838;  /* promo bar, plates — navy sunk 28% */
  --navy-2:#27315A;     /* raised surface on the navy ground */
  --navy-soft:#4D5576;  /* mid tint, 5.31:1 under powder rose */

  /* The full-bleed stages (hero, .pband, poster plate) stay dark in BOTH
     moods — metal only reads as metal against darkness — so this one is a
     constant, not a mood token. It is now the corporate navy rather than a
     near-black, which is the older and better ground for gold. */
  --black:var(--navy-deep);

  /* ---- LIGHT mood ----
     Everything below is re-declared under [data-theme="dark"]. Nothing else in
     the stylesheet hard-codes a surface colour, so the two moods stay in sync. */
  --paper:var(--cream);
  --paper-2:#EDECE9;   /* cream carried 38% toward mist grey */
  --ink:var(--navy);   /* 14.38:1 */
  --grey:#5B6280;      /* 5.64:1 — body copy */
  --grey-2:#5F6683;    /* 5.32:1 — captions and micro-labels */
  --hair:rgba(23,34,78,.16);
  --hair-2:rgba(23,34,78,.08);
  --veil:rgba(249,248,245,.93);   /* chips floating over imagery */
  --btn-bg:var(--navy);
  --btn-fg:var(--cream);
  --bar-bg:var(--navy);
  --bar-fg:rgba(249,248,245,.82);
  --rose-text:var(--navy);   /* powder rose fails as type here — see note above */
  --rose-fill:var(--rose);   /* …so on cream it appears as a FILL instead */
  --rose-deep:var(--navy-soft);  /* rules, underlines, focus, small fills */
  --mark:url("wordmark-navy.png");
  --mark-adjust:none;
  --shadow:rgba(23,34,78,.10);

  /* type */
  --dis:"Marcellus",Georgia,"Times New Roman",serif;
  --ut:"Jost","Helvetica Neue",Arial,sans-serif;
  --cn:"Noto Serif SC",serif;

  --pad:clamp(18px,4.4vw,64px);
  --bar:34px;    /* promo bar   */
  --row1:74px;   /* brand row   */
  --row2:52px;   /* nav row     */
}

/* ---- NAVY mood (the house ground, and the default) ----
   Not an inversion: the ground IS the corporate navy, and powder rose is let
   off the leash here because it finally has the contrast to carry type. Gold
   jewellery against navy is the oldest trick in the trade and it still works. */
[data-theme="dark"]{
  --paper:var(--navy);
  --paper-2:var(--navy-2);
  --ink:var(--cream);   /* 14.38:1 */
  --grey:var(--mist);   /* 10.80:1 — body copy */
  --grey-2:#8F93A2;     /* 4.99:1 — captions and micro-labels */
  --hair:rgba(247,212,206,.24);
  --hair-2:rgba(247,212,206,.11);
  --veil:rgba(23,34,78,.92);
  --btn-bg:var(--rose);
  --btn-fg:var(--navy);
  --bar-bg:var(--navy-deep);
  --bar-fg:rgba(249,248,245,.78);
  --rose-text:var(--rose);        /* 11.10:1 on navy */
  --rose-fill:var(--rose);
  --rose-deep:var(--rose);        /* powder rose earns its keep on this ground */
  --mark:url("wordmark-cream.png");
  --mark-adjust:none;
  --shadow:rgba(9,13,31,.50);
}
html{color-scheme:light}
[data-theme="dark"]{color-scheme:dark}
html,body{transition:background-color .5s ease,color .5s ease}

*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  background:var(--paper);color:var(--ink);
  font-family:var(--dis);font-size:16px;line-height:1.78;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
:focus-visible{outline:1px solid var(--rose-deep);outline-offset:3px}

/* ---- shared type atoms ------------------------------------------------- */
.lab{font-family:var(--ut);font-weight:300;font-size:9.5px;letter-spacing:.36em;
  text-transform:uppercase;color:var(--grey);display:block}
/* Display voice. Setting headlines in geometric sans CAPS is the single most
   recognisable move of the house the client referenced — so C'Garden goes the
   other way: an inscriptional serif in sentence case, which is also exactly
   what the approved banners already do. Jost stays, but only for small
   structural caps: nav, labels, buttons, prices. */
.ttl{font-family:var(--dis);font-weight:400;text-transform:none;letter-spacing:.01em;line-height:1.15}
.ser{font-family:var(--dis)}
.cn{font-family:var(--cn);font-weight:300;letter-spacing:.22em}

/* the underlined link — the maison-register call to action */
.rule{display:inline-block;font-family:var(--dis);font-size:15px;
  padding-bottom:5px;border-bottom:1px solid var(--rose-deep);
  transition:border-color .4s,color .4s}
.rule:hover{color:var(--rose-text);border-color:var(--rose)}
.rule.lt{border-bottom-color:rgba(249,248,245,.7);color:#fff}
.rule.lt:hover{color:var(--rose);border-bottom-color:var(--rose)}

.btn{display:inline-flex;align-items:center;justify-content:center;min-height:50px;padding:0 40px;
  font-family:var(--ut);font-weight:300;font-size:10px;letter-spacing:.3em;text-transform:uppercase;
  background:var(--btn-bg);color:var(--btn-fg);border:1px solid var(--btn-bg);
  transition:background .4s,color .4s,border-color .4s}
.btn:hover{background:var(--rose);border-color:var(--rose);color:var(--navy)}
[data-theme="dark"] .btn:hover{background:transparent;color:var(--rose)}
.btn.ghost{background:none;color:var(--ink);border-color:var(--hair)}
.btn.ghost:hover{background:var(--btn-bg);border-color:var(--btn-bg);color:var(--btn-fg)}
.btn[disabled]{opacity:.4;pointer-events:none}

.wrap{max-width:1440px;margin:0 auto}
.sec{padding:clamp(64px,9vw,124px) var(--pad)}
.sec.tight{padding-top:clamp(40px,5vw,64px)}
.mid{text-align:center}
.mid .intro{max-width:52ch;margin:20px auto 0;color:var(--grey);font-size:16px}
.hr{height:1px;background:var(--hair-2);border:0;margin:0 var(--pad)}

/* unconfirmed-data markers — hidden by the presentation toggle */
.tbc{font-family:var(--ut);font-style:normal;font-size:8px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--rose-text);border:1px solid rgba(247,212,206,.4);
  padding:2px 6px;margin-left:7px;vertical-align:middle;white-space:nowrap;font-weight:300}
/* HIDDEN PERMANENTLY, 19 Aug 2026, at the client's request. The markup is left
   in place rather than stripped, so the record of which figures are still
   unconfirmed survives in the source and can be switched back on with one line.
   .spin goes too: its qualifier was a .tbc, and without it the badge would
   claim a 360 view that does not exist yet. */
.tbc,.aiflag,.spin{display:none!important}
#tbcToggle{position:fixed;left:14px;bottom:14px;z-index:70;background:var(--veil);
  border:1px solid var(--hair);color:var(--grey);font-family:var(--ut);font-weight:300;
  font-size:8px;letter-spacing:.24em;text-transform:uppercase;padding:9px 13px;
  backdrop-filter:blur(8px);
  transition:color .35s,border-color .35s,transform .5s cubic-bezier(.2,.7,.3,1)}
body.booking #tbcToggle{transform:translateY(-72px)}
@media(max-width:640px){body.booking #tbcToggle{transform:translateY(-104px)}}
#tbcToggle:hover{color:var(--ink);border-color:var(--rose)}

/* ==========================================================================
   HEADER
   ========================================================================== */
/* auto-height so a long promo line wraps instead of running under the close
   button — the bar is content, not a fixed 34px slot */
.promo{min-height:var(--bar);background:var(--paper-2);display:flex;align-items:center;justify-content:center;
  flex-wrap:wrap;gap:6px 14px;padding:8px 46px;text-align:center;
  font-family:var(--ut);font-weight:300;font-size:9.5px;letter-spacing:.28em;text-transform:uppercase;
  position:relative;z-index:41;line-height:1.7}
.promo a{border-bottom:1px solid var(--rose-deep);padding-bottom:2px;white-space:nowrap}
.promo .x{position:absolute;right:12px;top:50%;transform:translateY(-50%);
  font-size:15px;line-height:1;color:var(--grey);padding:6px}
body.nopromo .promo{display:none}

header{position:sticky;top:0;z-index:40;background:var(--paper);
  border-bottom:1px solid var(--hair-2);transition:box-shadow .4s}
header.stuck{box-shadow:0 1px 24px var(--shadow)}

.row1{height:var(--row1);display:grid;grid-template-columns:1fr auto 1fr;align-items:center;padding:0 var(--pad)}
.row1 .util{display:flex;gap:26px;font-family:var(--ut);font-weight:300;font-size:9px;
  letter-spacing:.26em;text-transform:uppercase;color:var(--ink)}
.row1 .util a{opacity:.78;transition:opacity .3s}.row1 .util a:hover{opacity:1}
/* the wordmark PNG is rose gold, drawn for a dark ground — on cream it needs
   a touch of depth to clear contrast without leaving the brand hue */
/* the wordmark is the brand, so it has to out-weigh the nav links flanking it.
   At 22px and .72 brightness it read as the quietest thing in the header. */
.wordmark{height:30px;width:auto;margin:0 auto;content:var(--mark)}
@media(max-width:900px){.wordmark{height:25px;margin:0}}
.icons{display:flex;gap:18px;justify-content:flex-end;align-items:center}
.icons button,.icons a{position:relative;display:flex;padding:5px;color:var(--ink);opacity:.8;transition:opacity .3s}
.icons button:hover,.icons a:hover{opacity:1}
.icons svg{width:19px;height:19px;stroke:currentColor;fill:none;stroke-width:1.1}
.count{position:absolute;top:-1px;right:-3px;min-width:14px;height:14px;padding:0 3px;
  background:var(--rose-deep);color:#fff;border-radius:7px;
  font-family:var(--ut);font-size:8px;line-height:14px;text-align:center;font-weight:400;
  opacity:0;transform:scale(.6);transition:opacity .3s,transform .3s}
.count.on{opacity:1;transform:none}

.row2{height:var(--row2);display:flex;align-items:center;justify-content:center;gap:clamp(18px,3vw,42px);
  padding:0 var(--pad);position:relative}
.row2>a,.row2>.mi>a{font-family:var(--ut);font-weight:300;font-size:10px;letter-spacing:.24em;
  text-transform:uppercase;padding:14px 0;display:block;position:relative}
.row2 .mi>a::after{content:"";position:absolute;left:0;right:0;bottom:8px;height:1px;
  background:var(--rose-deep);transform:scaleX(0);transform-origin:center;transition:transform .4s}
.row2 .mi.open>a::after,.row2 .mi>a:hover::after{transform:scaleX(1)}
.row2 .srch{margin-left:auto;position:absolute;right:var(--pad)}
.row2 .srch svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:1.1}
.burger{display:none}

/* mega menu */
.mega{position:absolute;left:0;right:0;top:100%;background:var(--paper);
  border-top:1px solid var(--hair-2);border-bottom:1px solid var(--hair);
  padding:0 var(--pad);max-height:0;overflow:hidden;opacity:0;
  transition:max-height .5s cubic-bezier(.2,.7,.3,1),opacity .35s}
.mi.open .mega{max-height:640px;opacity:1}
.mega .inner{max-width:1200px;margin:0 auto;padding:34px 0 44px}
.tabs{display:flex;gap:32px;border-bottom:1px solid var(--hair-2);margin-bottom:34px;
  overflow-x:auto;scrollbar-width:none}
.tabs::-webkit-scrollbar{display:none}
.tabs button{font-family:var(--ut);font-weight:300;font-size:10px;letter-spacing:.24em;
  text-transform:uppercase;padding:0 0 13px;white-space:nowrap;color:var(--grey);
  border-bottom:1px solid transparent;margin-bottom:-1px;transition:color .3s,border-color .3s}
.tabs button.on{color:var(--ink);border-bottom-color:var(--rose-deep)}
/* capped, not 1fr — a rail of three would otherwise stretch each cell to ~380px
   and leave the icon swimming in empty space */
.rail{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(140px,186px);gap:22px;
  justify-content:center;overflow-x:auto;scrollbar-width:none;padding-bottom:6px}
.rail::-webkit-scrollbar{display:none}
.rail a{text-align:center}
.rail .th{aspect-ratio:1/1;background:var(--paper-2);overflow:hidden;margin-bottom:14px}
/* a rail cell can hold a category icon instead of a photograph */
.rail .th.ic{display:grid;place-items:center;background:var(--paper-2)}
.rail .th.ic svg{width:46%;height:46%;stroke:var(--ink);fill:none;stroke-width:1.3;
  stroke-linejoin:round;stroke-linecap:round;transition:stroke .4s}
.rail a:hover .th.ic svg{stroke:var(--rose-text)}
.rail .th img{width:100%;height:100%;object-fit:cover;transition:transform 1.1s cubic-bezier(.2,.7,.3,1)}
.rail a:hover .th img{transform:scale(1.05)}
.rail span{font-family:var(--ut);font-weight:300;font-size:9.5px;letter-spacing:.2em;text-transform:uppercase}
.mega .foot{display:flex;justify-content:center;margin-top:34px}
.megapanel{display:none}.megapanel.on{display:block}

/* mobile drawer */
.drawer{position:fixed;inset:0;z-index:45;background:var(--paper);padding:100px var(--pad) 40px;
  overflow-y:auto;transform:translateX(-100%);transition:transform .5s cubic-bezier(.2,.7,.3,1)}
body.menu .drawer{transform:none}
.drawer a{display:block;font-family:var(--ut);font-weight:300;font-size:13px;letter-spacing:.24em;
  text-transform:uppercase;padding:17px 0;border-bottom:1px solid var(--hair-2)}
.drawer .sub{font-size:10px;color:var(--grey);padding-left:18px;letter-spacing:.2em}

/* ==========================================================================
   HERO — auto-sliding banner
   Slide 1 is the live rose-gold dust field (C'Garden's signature, and the one
   thing on the page that could not have come from another house); slides 2+
   are the approved 1920×800 banners. Height tracks the banners' 2.4:1 ratio
   so their composition is not cropped on desktop.
   ========================================================================== */
.hero{position:relative;height:clamp(460px,41.7vw,760px);
  background:var(--black);overflow:hidden}

.slide{position:absolute;inset:0;opacity:0;pointer-events:none;
  transition:opacity 1.1s cubic-bezier(.4,0,.2,1);
  display:flex;align-items:flex-end;justify-content:center;text-align:center;
  padding:0 var(--pad) clamp(56px,8vh,96px)}
.slide.on{opacity:1;pointer-events:auto}
.slide>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0}

#dust{position:absolute;inset:0;z-index:0}
#glow{position:absolute;width:520px;height:520px;border-radius:50%;pointer-events:none;z-index:1;
  background:radial-gradient(circle,rgba(247,212,206,.10) 0%,rgba(247,212,206,.03) 42%,transparent 70%);
  transform:translate(-50%,-50%);opacity:0;transition:opacity .7s}
.hero.live #glow{opacity:1}

.slide .in{position:relative;z-index:2;max-width:56ch}
.slide .lab{color:var(--rose)}
.slide h1,.slide .slide-h{font-family:var(--dis);font-weight:400;letter-spacing:.01em;text-transform:none;
  font-size:clamp(28px,3.6vw,52px);color:#fff;margin:16px 0 14px;line-height:1.12}
.slide h1 em,.slide .slide-h em{font-style:normal;color:var(--rose);display:block}
.slide p{color:rgba(249,248,245,.8);font-size:15.5px;max-width:46ch;margin:0 auto 28px}
.slide .zh{font-family:var(--cn);font-weight:300;letter-spacing:.3em;
  color:rgba(249,248,245,.6);font-size:13px;margin-bottom:26px}

/* the banners already carry their headline, monogram and CTA as artwork, so
   the live copy is only raised on narrow screens where that artwork is cropped */
.slide .live{display:none}

/* out of the centred stack and into the corner: it stops colliding with the
   CTA, and a little asymmetry keeps the composition from reading as a template */
.hero .cue{position:absolute;left:clamp(26px,3.4vw,52px);bottom:26px;z-index:5;
  font-family:var(--ut);font-weight:300;font-size:8px;letter-spacing:.36em;text-transform:uppercase;
  color:rgba(249,248,245,.42);transition:opacity .5s}

/* controls */
.hdots{position:absolute;left:50%;bottom:18px;transform:translateX(-50%);z-index:6;
  display:flex;gap:9px}
.hdots button{width:26px;height:2px;background:rgba(249,248,245,.28);transition:background .4s}
.hdots button.on{background:var(--rose)}
.harw{position:absolute;top:50%;transform:translateY(-50%);z-index:6;width:44px;height:44px;
  display:grid;place-items:center;opacity:.5;transition:opacity .35s}
.harw:hover{opacity:1}
.harw.prev{left:6px}.harw.next{right:6px}
.harw svg{width:17px;height:17px;stroke:#fff;fill:none;stroke-width:1.1}
@media(hover:none){.harw{display:none}}

/* Narrow screens: a 2.4:1 banner is 162px tall at 390px wide, which is no hero
   at all. So the slide goes tall, the image is re-framed onto the ring, and the
   headline that was cropped away with the artwork is raised as live text —
   which also means it stays selectable, translatable and searchable. */
@media(max-width:820px){
  .hero{height:74svh;min-height:500px}
  .slide{padding-bottom:clamp(64px,10vh,110px)}
  /* Each banner bakes its headline into one half of a 3840px-wide image and
     carries a live HTML copy of it for the phone crop. So the phone crop MUST
     land on the photographic half: if it catches the baked type as well, the
     headline appears twice, overlapping itself.

     The 22% below dated from a three-slide hero and silently became wrong when
     slides 2 and 3 were added, because it is keyed to position rather than to
     content. Values follow the artwork: D puts its photo on the right, E on
     the left. Any new slide needs its own line here. */
  .slide[data-slide="1"]>img{object-position:76% center}   /* C, photo right  */
  .slide[data-slide="2"]>img{object-position:82% center}   /* D, photo right  */
  .slide[data-slide="3"]>img{object-position:20% center}   /* E, photo left   */
  .slide[data-slide]:not([data-slide="0"])::after{content:"";position:absolute;inset:0;z-index:1;
    background:linear-gradient(180deg,rgba(12,17,39,.42) 0%,rgba(12,17,39,.16) 26%,
      rgba(12,17,39,.60) 56%,rgba(12,17,39,.90) 100%)}
  .slide .live{display:block}
  .slide h1,.slide .slide-h{font-size:clamp(27px,8vw,38px)}
  .harw{display:none}
}

/* ==========================================================================
   EDITORIAL BLOCKS
   ========================================================================== */
.ed{position:relative;min-height:clamp(420px,64vh,700px);display:flex;align-items:center;
  justify-content:center;text-align:center;padding:clamp(60px,9vw,110px) var(--pad);
  background:var(--paper-2);overflow:hidden}
.ed>img,.ed>.bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0}
/* the scrim has to hold up over the client's own photography, which runs from
   near-black CAD renders to a saturated CNY red — a light gradient is not
   enough, so this is a radial plate behind the copy plus a base wash */
.ed::after{content:"";position:absolute;inset:0;z-index:1;
  background:
    radial-gradient(ellipse 62% 74% at 50% 52%,rgba(12,17,39,.72) 0%,rgba(12,17,39,.40) 55%,transparent 100%),
    linear-gradient(180deg,rgba(12,17,39,.46) 0%,rgba(12,17,39,.26) 45%,rgba(12,17,39,.58) 100%)}
.ed>img,.ed>.bg{filter:saturate(.9)}
.ed .in{position:relative;z-index:2;max-width:54ch;color:#fff;
  text-shadow:0 1px 24px rgba(12,17,39,.5)}
.ed h2{font-family:var(--dis);font-weight:400;text-transform:none;letter-spacing:.01em;line-height:1.14;
  font-size:clamp(26px,3.2vw,44px);margin:16px 0 14px}
.ed p{color:rgba(249,248,245,.88);font-size:16px;margin-bottom:26px}
.ed .lab{color:rgba(249,248,245,.66)}

/* two-up */
.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;background:var(--hair-2)}
.two>article{background:var(--paper);text-align:center;padding-bottom:clamp(40px,5vw,64px)}
.two .fig{aspect-ratio:4/3;overflow:hidden;background:var(--paper-2);margin-bottom:32px}
.two .fig img{width:100%;height:100%;object-fit:cover;transition:transform 1.4s cubic-bezier(.2,.7,.3,1)}
.two article:hover .fig img{transform:scale(1.04)}
.two h3{font-family:var(--dis);font-weight:400;text-transform:none;letter-spacing:.01em;line-height:1.2;
  font-size:clamp(21px,2.2vw,29px);margin-bottom:14px}
.two p{color:var(--grey);max-width:40ch;margin:0 auto 22px;padding:0 24px;font-size:15.5px}

/* split — image beside copy */
.split{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(36px,6vw,92px);align-items:center}
.split.flip .fig{order:2}
.split .fig{position:relative;background:var(--paper-2)}
.split .fig img{width:100%;aspect-ratio:4/5;object-fit:cover}
.split .fig figcaption{margin-top:14px;font-family:var(--ut);font-weight:300;font-size:8px;
  letter-spacing:.28em;text-transform:uppercase;color:var(--grey-2);text-align:center}
.split .copy h2{font-family:var(--dis);font-weight:400;text-transform:none;letter-spacing:.01em;line-height:1.15;
  font-size:clamp(26px,3vw,42px);margin:16px 0 0}
.split .copy p{color:var(--grey);margin-top:22px;max-width:46ch;font-size:16px}
.split .copy .rule,.split .copy .btn{margin-top:34px}
.ph{aspect-ratio:4/5;display:flex;align-items:center;justify-content:center;text-align:center;
  border:1px solid var(--hair-2);color:var(--grey-2);font-family:var(--ut);font-weight:300;
  font-size:8.5px;letter-spacing:.28em;text-transform:uppercase;line-height:2.4;padding:24px}

/* ==========================================================================
   PRODUCT CARDS + CAROUSEL
   ========================================================================== */
.carousel{position:relative}
.track{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(260px,1fr);gap:clamp(16px,2vw,28px);
  overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;padding-bottom:4px}
.track::-webkit-scrollbar{display:none}
.track>*{scroll-snap-align:start}
.arw{position:absolute;top:36%;z-index:3;width:42px;height:42px;border-radius:50%;
  background:var(--veil);border:1px solid var(--hair-2);display:grid;place-items:center;
  box-shadow:0 2px 14px var(--shadow);transition:background .3s,opacity .3s}
.arw:hover{background:var(--paper)}
.arw[disabled]{opacity:0;pointer-events:none}
.arw.prev{left:-6px}.arw.next{right:-6px}
.arw svg{width:14px;height:14px;stroke:var(--ink);fill:none;stroke-width:1.2}

.card{text-align:center;position:relative}
.card .fig{position:relative;aspect-ratio:1/1;background:var(--paper-2);overflow:hidden;margin-bottom:22px}
.card .fig img{width:100%;height:100%;object-fit:cover;transition:transform 1.4s cubic-bezier(.2,.7,.3,1)}
.card:hover .fig img{transform:scale(1.045)}
.badge{position:absolute;left:12px;top:12px;z-index:2;background:var(--veil);
  font-family:var(--ut);font-weight:300;font-size:8px;letter-spacing:.24em;text-transform:uppercase;
  padding:5px 9px;color:var(--ink)}
/* sits bottom-left so it never collides with the .badge in a narrow column */
.aiflag{position:absolute;left:12px;bottom:12px;z-index:2;background:rgba(23,34,78,.62);color:rgba(249,248,245,.9);
  font-family:var(--ut);font-weight:300;font-size:7.5px;letter-spacing:.2em;text-transform:uppercase;
  padding:4px 8px;white-space:nowrap;
  /* the badge is wider than a card at mobile widths; unconstrained it escaped
     its .fig and pushed the whole document 63px wide */
  max-width:calc(100% - 24px);overflow:hidden;text-overflow:ellipsis}
@media(max-width:560px){
  .aiflag{white-space:normal;line-height:1.55;text-overflow:clip}
}
.card .save{position:absolute;right:10px;bottom:10px;z-index:2;width:34px;height:34px;border-radius:50%;
  background:var(--veil);display:grid;place-items:center;opacity:0;transform:translateY(6px);
  transition:opacity .35s,transform .35s,background .3s}
.card:hover .save,.card .save.on{opacity:1;transform:none}
.card .save svg{width:15px;height:15px;stroke:var(--ink);fill:none;stroke-width:1.2}
.card .save.on svg{fill:var(--rose-deep);stroke:var(--rose-deep)}
.card h3{font-family:var(--dis);font-weight:400;text-transform:none;letter-spacing:.01em;
  font-size:17px;margin-bottom:7px;line-height:1.3}
.card .met{color:var(--grey);font-size:15px;margin-bottom:9px}
.card .px{font-family:var(--ut);font-weight:300;font-size:11px;letter-spacing:.16em;color:var(--ink)}

/* ==========================================================================
   STEPS / SERVICES / NEWSLETTER
   ========================================================================== */
.steps{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1px;margin-top:64px;background:var(--hair-2)}
.step{background:var(--paper);padding:40px 28px;text-align:center}
.step .n{font-family:var(--ut);font-weight:300;font-size:9.5px;letter-spacing:.3em;color:var(--rose-text);
  display:block;margin-bottom:18px}
.step h3{font-family:var(--ut);font-weight:300;font-size:11px;letter-spacing:.26em;text-transform:uppercase;margin-bottom:12px}
.step p{font-size:15px;color:var(--grey)}

.trio{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(24px,3vw,44px)}
.trio article{text-align:center}
.trio .fig{aspect-ratio:1/1;background:var(--paper-2);overflow:hidden;margin-bottom:28px}
.trio .fig img{width:100%;height:100%;object-fit:cover}
.trio h3{font-family:var(--dis);font-weight:400;text-transform:none;letter-spacing:.01em;
  font-size:clamp(20px,2vw,26px);margin-bottom:14px;line-height:1.25}
.trio p{color:var(--grey);max-width:34ch;margin:0 auto 20px;font-size:15.5px}

.news{background:var(--paper-2);padding:clamp(56px,7vw,90px) var(--pad);text-align:center}
.news form{display:flex;gap:0;max-width:520px;margin:30px auto 0}
.news input{flex:1;background:none;border:0;border-bottom:1px solid var(--hair);
  font-family:var(--dis);font-size:16px;padding:12px 4px;color:var(--ink)}
.news input:focus{outline:none;border-bottom-color:var(--rose-deep)}
.news input::placeholder{color:var(--grey-2)}
.news .btn{min-height:46px}
.news .fine{font-family:var(--ut);font-weight:300;font-size:8.5px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--grey-2);margin-top:18px}

/* ==========================================================================
   FOOTER
   ========================================================================== */
footer{background:var(--paper);border-top:1px solid var(--hair-2)}
.fcols{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(24px,4vw,60px);
  padding:clamp(56px,7vw,86px) var(--pad) clamp(40px,5vw,64px);max-width:1440px;margin:0 auto}
.fcols h4{font-family:var(--ut);font-weight:300;font-size:10px;letter-spacing:.3em;
  text-transform:uppercase;margin-bottom:24px}
.fcols a,.fcols p{display:block;font-family:var(--ut);font-weight:300;font-size:10.5px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--grey);padding:7px 0;transition:color .3s}
.fcols a:hover{color:var(--ink)}
.social{display:flex;gap:18px;padding-top:6px}
.social a{padding:0}
.social svg{width:17px;height:17px;stroke:var(--grey);fill:none;stroke-width:1.2;transition:stroke .3s}
.social a:hover svg{stroke:var(--ink)}
.fmark{text-align:center;padding:0 var(--pad) 40px}
.fmark img{height:19px;margin:0 auto;filter:var(--mark-adjust)}
.fbar{background:var(--bar-bg);color:var(--bar-fg);display:flex;align-items:center;
  justify-content:space-between;flex-wrap:wrap;gap:12px;padding:16px var(--pad);
  font-family:var(--ut);font-weight:300;font-size:9px;letter-spacing:.26em;text-transform:uppercase}
.fbar a{border-bottom:1px solid var(--rose);padding-bottom:2px;color:var(--rose)}

/* floating WhatsApp — a KL atelier's real channel, not a chat bot */
.wa{position:fixed;right:16px;bottom:16px;z-index:60;display:inline-flex;align-items:center;gap:10px;
  background:var(--btn-bg);color:var(--btn-fg);padding:12px 20px;
  font-family:var(--ut);font-weight:300;font-size:9px;letter-spacing:.26em;text-transform:uppercase;
  box-shadow:0 4px 22px var(--shadow);transition:background .4s,color .4s}
.wa:hover{background:var(--rose);color:var(--navy)}
.wa svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.3}

/* ==========================================================================
   PANELS — saved list / enquiry list / search
   ========================================================================== */
.scrim{position:fixed;inset:0;z-index:48;background:rgba(9,13,31,.52);opacity:0;pointer-events:none;
  transition:opacity .4s}
body.panel .scrim{opacity:1;pointer-events:auto}
.panel{position:fixed;top:0;right:0;bottom:0;width:min(420px,100%);z-index:50;background:var(--paper);
  transform:translateX(100%);transition:transform .5s cubic-bezier(.2,.7,.3,1);
  display:flex;flex-direction:column}
.panel.open{transform:none}
.panel .top{display:flex;align-items:center;justify-content:space-between;
  padding:26px var(--pad) 20px;border-bottom:1px solid var(--hair-2)}
.panel .top h2{font-family:var(--ut);font-weight:300;font-size:11px;letter-spacing:.3em;text-transform:uppercase}
.panel .top button{font-size:19px;line-height:1;color:var(--grey);padding:4px}
.panel .body{flex:1;overflow-y:auto;padding:22px var(--pad)}
.panel .empty{color:var(--grey-2);font-size:14px;text-align:center;padding:48px 0}
.panel .btm{padding:20px var(--pad) 26px;border-top:1px solid var(--hair-2)}
.panel .btm .btn{width:100%}
.pitem{display:grid;grid-template-columns:64px 1fr auto;gap:16px;align-items:center;
  padding:16px 0;border-bottom:1px solid var(--hair-2)}
.pitem img{width:64px;height:64px;object-fit:cover;background:var(--paper-2)}
.pitem b{display:block;font-family:var(--ut);font-weight:300;font-size:10.5px;letter-spacing:.18em;
  text-transform:uppercase;margin-bottom:5px}
.pitem span{font-size:13px;color:var(--grey)}
.pitem .rm{font-family:var(--ut);font-size:8.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--grey-2)}
.pitem .rm:hover{color:var(--rose-deep)}

.searchbar{position:fixed;top:0;left:0;right:0;z-index:52;background:var(--paper);
  border-bottom:1px solid var(--hair);padding:26px var(--pad);
  transform:translateY(-100%);transition:transform .45s cubic-bezier(.2,.7,.3,1)}
body.searching .searchbar{transform:none}
.searchbar form{display:flex;gap:16px;align-items:center;max-width:900px;margin:0 auto}
.searchbar input{flex:1;background:none;border:0;border-bottom:1px solid var(--hair);
  font-family:var(--dis);font-size:19px;padding:10px 2px}
.searchbar input:focus{outline:none;border-bottom-color:var(--rose-deep)}
.searchbar .x{font-size:20px;color:var(--grey)}
.sugg{max-width:900px;margin:20px auto 0;display:flex;gap:22px;flex-wrap:wrap}
.sugg a{font-family:var(--ut);font-weight:300;font-size:9.5px;letter-spacing:.22em;
  text-transform:uppercase;color:var(--grey)}
.sugg a:hover{color:var(--ink)}

/* toast */
#toast{position:fixed;left:50%;bottom:26px;transform:translate(-50%,20px);z-index:80;
  background:var(--btn-bg);color:var(--btn-fg);padding:13px 26px;
  font-family:var(--ut);font-weight:300;font-size:9px;letter-spacing:.26em;text-transform:uppercase;
  opacity:0;pointer-events:none;transition:opacity .35s,transform .35s}
#toast.on{opacity:1;transform:translate(-50%,0)}

/* reveal */
/* Scoped to html.js, which is set before first paint. Unscoped, this rule
   hid every revealed block on the site from anyone whose JavaScript did not
   run — a blocked script or a dropped connection left the page essentially
   blank, since the observer that adds .on never arrived. Found 25 Aug 2026
   while checking the icon animation's own fallback. */
html.js .rv{opacity:0;transform:translateY(20px);
  transition:opacity .95s cubic-bezier(.2,.7,.3,1),transform .95s cubic-bezier(.2,.7,.3,1)}
html.js .rv.on{opacity:1;transform:none}

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */
@media(max-width:1080px){
  .trio{grid-template-columns:1fr;gap:56px}
  .fcols{grid-template-columns:1fr 1fr;gap:36px}
}
@media(max-width:900px){
  :root{--row1:62px;--row2:0px}
  .row2{display:none}
  .row1{grid-template-columns:auto 1fr auto}
  .row1 .util{display:none}
  .burger{display:block;width:22px;height:14px;position:relative}
  .burger i{position:absolute;left:0;right:0;height:1px;background:var(--ink);transition:transform .4s,opacity .3s}
  .burger i:nth-child(1){top:0}.burger i:nth-child(2){top:6px}.burger i:nth-child(3){top:12px}
  body.menu .burger i:nth-child(1){transform:translateY(6px) rotate(45deg)}
  body.menu .burger i:nth-child(2){opacity:0}
  body.menu .burger i:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
  .two{grid-template-columns:1fr}
  .split{grid-template-columns:1fr;gap:44px}
  .split.flip .fig{order:0}
  .steps{grid-template-columns:1fr 1fr}
  .icons .hide-s{display:none}
}
@media(max-width:560px){
  .steps{grid-template-columns:1fr}
  .fcols{grid-template-columns:1fr}
  .news form{flex-direction:column;gap:18px}
  .fbar{justify-content:center;text-align:center}
  .wa span{display:none}
  .wa{padding:14px;border-radius:50%}
}
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .rv{opacity:1;transform:none}
}

/* ==========================================================================
   MOOD TOGGLE
   ========================================================================== */
.moodbtn{position:relative}
.moodbtn svg{width:19px;height:19px;stroke:currentColor;fill:none;stroke-width:1.1}
.moodbtn .moon{display:none}
[data-theme="dark"] .moodbtn .sun{display:none}
[data-theme="dark"] .moodbtn .moon{display:block}

/* Product photography is shot on two grounds. The swap is a crossfade rather
   than a hard cut so switching mood does not read as a page reload. */
img[data-themed]{transition:opacity .35s ease}
img[data-themed].swapping{opacity:0}

/* The hero stays a dark stage in both moods — it is a vitrine, and the rose
   gold only reads as metal against darkness. Everything below it follows the
   chosen mood. */

/* ==========================================================================
   PIECE BAND — full-bleed editorial banner for a single piece
   Same rule as the hero: a full-bleed band is always the dark stage, in both
   moods. Rose gold only reads as metal against darkness, and a dark band
   breaking a cream page is the register the client is after. Content surfaces
   above and below still follow the chosen mood.
   ========================================================================== */
.pband{position:relative;background:var(--black);overflow:hidden;display:block;
  height:clamp(420px,41.7vw,760px)}
.pband>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0}

/* the artwork already carries its headline, monogram and CTA — the live copy
   is only raised where the crop tightens and that artwork is cut away */
.pband .live{display:none}
.pband .in{position:relative;z-index:2;max-width:44ch}
.pband .lab{color:var(--rose)}
.pband h2{font-family:var(--dis);font-weight:400;letter-spacing:.01em;line-height:1.14;
  font-size:clamp(28px,3.4vw,46px);color:#fff;margin:14px 0 12px}
.pband h2 em{font-style:normal;color:var(--rose);display:block}
.pband .zh{font-family:var(--cn);font-weight:300;letter-spacing:.28em;
  color:rgba(249,248,245,.58);font-size:12.5px;margin-bottom:20px}
.pband p{color:rgba(249,248,245,.82);font-size:15.5px;margin-bottom:26px}

@media(max-width:820px){
  .pband{height:auto;min-height:78svh;display:flex;align-items:flex-end;
    padding:0 var(--pad) clamp(48px,7vh,80px);text-align:center}
  /* re-frame onto the wrist: the artwork puts the copy on one side and the
     piece on the other, and it is the piece that has to survive the crop */
  .pband[data-side="left"]>img{object-position:78% center}
  .pband[data-side="right"]>img{object-position:22% center}
  .pband::after{content:"";position:absolute;inset:0;z-index:1;
    background:linear-gradient(180deg,rgba(12,17,39,.40) 0%,rgba(12,17,39,.14) 26%,
      rgba(12,17,39,.62) 58%,rgba(12,17,39,.92) 100%)}
  .pband .live{display:block}
  .pband .in{max-width:none;margin:0 auto}
  .pband h2{font-size:clamp(27px,7.6vw,36px)}
}

/* ==========================================================================
   PRODUCT CATEGORIES
   The client's own taxonomy: four lines, with Jewellery carrying three
   sub-lines. Icons are a single inline SVG sprite — they inherit currentColor,
   so they follow the mood with no second set of files.
   ========================================================================== */
.catgrid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1px;
  margin-top:60px;background:var(--hair-2)}
.catgrid a{background:var(--paper);padding:46px 24px 40px;text-align:center;
  display:flex;flex-direction:column;align-items:center;
  transition:background .45s}
.catgrid a:hover{background:var(--paper-2)}
.catico{width:50px;height:50px;stroke:var(--ink);fill:none;stroke-width:1.25;
  stroke-linejoin:round;stroke-linecap:round;margin-bottom:24px;
  transition:stroke .45s,transform .55s cubic-bezier(.2,.7,.3,1)}
.catgrid a:hover .catico{stroke:var(--rose-text);transform:translateY(-3px)}
.catgrid h3{font-family:var(--dis);font-weight:400;font-size:clamp(17px,1.7vw,21px);
  line-height:1.3;margin-bottom:10px;min-height:2.6em;display:flex;align-items:center;
  justify-content:center;flex-wrap:wrap;gap:4px}
.catgrid p{font-size:14px;color:var(--grey);max-width:26ch}

/* the three Jewellery sub-lines, as a lighter rail beneath */
.subcats{display:flex;justify-content:center;flex-wrap:wrap;gap:1px;
  background:var(--hair-2);margin-top:1px}
.subcats a{background:var(--paper);flex:1 1 0;min-width:180px;
  display:flex;align-items:center;justify-content:center;gap:14px;
  padding:22px 20px;transition:background .45s}
.subcats a:hover{background:var(--paper-2)}
.subico{width:24px;height:24px;flex:0 0 24px;stroke:var(--grey);fill:none;stroke-width:1.4;
  stroke-linejoin:round;stroke-linecap:round;transition:stroke .45s}
.subcats a:hover .subico{stroke:var(--rose-text)}
.subcats span{font-family:var(--ut);font-weight:300;font-size:10.5px;
  letter-spacing:.22em;text-transform:uppercase}


@media(max-width:900px){
  .catgrid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .subcats a{flex:1 1 100%}
}
@media(max-width:520px){
  .catgrid{grid-template-columns:1fr}
  .catgrid a{padding:36px 22px 32px}
}

/* icon beside a filter row */
.filtico{width:19px;height:19px;flex:0 0 19px;stroke:currentColor;fill:none;stroke-width:1.4;
  stroke-linejoin:round;stroke-linecap:round;opacity:.75;margin-right:2px}

/* ==========================================================================
   BRAND MARKS
   The monogram existed only as the favicon and baked inside banner artwork.
   These are live elements, paired -light/-dark like the photography so the
   mark keeps its own colour rather than being filtered into it.
   ========================================================================== */
.mono{width:auto;display:block;margin:0 auto}
.hero .mono{height:34px;margin-bottom:22px;opacity:.95}

/* footer sign-off: monogram over wordmark, the full lockup */
.fmark{text-align:center;padding:0 var(--pad) 44px}
.fmark .mono{height:42px;margin-bottom:20px}
.fmark img.wordmark-foot{height:22px;margin:0 auto;content:var(--mark)}
.fmark .fline{font-family:var(--ut);font-weight:300;font-size:8.5px;letter-spacing:.36em;
  text-transform:uppercase;color:var(--grey-2);margin-top:18px}

@media(max-width:820px){
  .hero .mono{height:28px;margin-bottom:18px}
  .fmark .mono{height:36px}
}

/* ==========================================================================
   INTERACTIONS
   Everything here is CSS-first and progressively enhanced: nothing below is
   required for the page to work, and every motion rule is disabled under
   prefers-reduced-motion at the foot of this file.
   ========================================================================== */

/* --- 1. (removed 18 Aug) light sweep ---------------------------------------
   A specular highlight used to travel across the piece on hover. Removed at the
   client's request. Note the streaks still visible on the product shots are
   NOT this rule — they are baked into the AI photography itself; this overlay
   sat off-canvas at rest and only ever appeared under the cursor. */
.card .fig,.two .fig,.trio .fig,.rail .th{position:relative}

/* --- 2. scroll progress hairline ------------------------------------------
   Pure CSS scroll-driven animation; browsers without support simply never
   show it, which is why it is a hairline and not load-bearing. */
#progress{position:fixed;top:0;left:0;height:2px;width:100%;z-index:45;
  background:var(--rose);transform-origin:0 50%;transform:scaleX(0);pointer-events:none}
@supports (animation-timeline: scroll()){
  #progress{animation:progressGrow linear;animation-timeline:scroll(root block)}
}
@keyframes progressGrow{from{transform:scaleX(0)}to{transform:scaleX(1)}}

/* --- 3. parallax on the piece bands ---------------------------------------
   The artwork drifts slower than the band it sits in. Scroll-timeline only —
   no scroll listener, so it costs nothing on the main thread. */
@supports (animation-timeline: view()){
  @media (min-width:821px){
    .pband>img{animation:bandDrift linear both;animation-timeline:view();
      animation-range:entry 0% exit 100%;will-change:transform}
    /* scale(1.12) cropped 6% off EACH SIDE, which ate the banner artwork's own
       125px margin down to 18px on screen — the copy is baked into the image,
       so the crop was cutting into the type. A ±1.8% vertical drift only needs
       scale 1.036 to avoid exposing an edge; 1.04 leaves the margin intact. */
    @keyframes bandDrift{from{transform:scale(1.04) translateY(-1.8%)}
                         to{transform:scale(1.04) translateY(1.8%)}}
  }
}

/* --- 4. cross-document view transitions -----------------------------------
   Pages crossfade instead of blinking white. Three lines, ignored where
   unsupported. */
@view-transition{navigation:auto}
::view-transition-old(root),::view-transition-new(root){animation-duration:.32s}

/* --- 5. sticky consultation bar -------------------------------------------
   Not decoration: on a site whose whole purpose is bookings, this is the
   mechanism. Appears once the hero is behind you, dismissible for the session. */
#book{position:fixed;left:0;right:0;bottom:0;z-index:58;
  display:flex;align-items:center;justify-content:center;gap:clamp(14px,3vw,34px);
  flex-wrap:wrap;padding:14px var(--pad);
  background:var(--veil);backdrop-filter:blur(14px);
  border-top:1px solid var(--hair);
  transform:translateY(105%);transition:transform .55s cubic-bezier(.2,.7,.3,1)}
body.booking #book{transform:none}
#book p{font-family:var(--dis);font-size:15px;color:var(--ink);margin:0}
#book p b{font-weight:400}
#book .btn{min-height:44px;padding:0 32px}
/* --grey-2 lands at 4.49:1 against the bar's veil in dark mood — a hair under
   AA, so this one uses the body-copy grey instead */
#book .x{font-family:var(--ut);font-size:9px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--grey);padding:8px;background:none;border:0}
#book .x:hover{color:var(--ink)}
@media(max-width:640px){
  #book{gap:10px;padding:12px var(--pad)}
  #book p{font-size:13.5px;width:100%;text-align:center}
  #book .btn{flex:1;padding:0 18px;font-size:9px}
}
/* keep the floating WhatsApp pill clear of the bar once it is up */
body.booking .wa{transform:translateY(-72px)}
.wa{transition:background .4s,color .4s,transform .5s cubic-bezier(.2,.7,.3,1)}
@media(max-width:640px){body.booking .wa{transform:translateY(-96px)}}

@media(prefers-reduced-motion:reduce){
  .card .fig::after,.two .fig::after,.trio .fig::after,.rail .th::after{display:none}
  #progress{display:none}
  .pband>img{animation:none!important}
  #book{transition:none}
  @view-transition{navigation:none}
}

/* ==========================================================================
   WELCOME POSTER
   A modal, but composed as a poster: image plate on the left, invitation on
   the right. Always the dark stage in both moods, for the same reason the hero
   is — rose gold only reads as metal against darkness.
   ========================================================================== */
#poster,#merdeka{position:fixed;inset:0;z-index:90;display:grid;place-items:center;
  padding:clamp(16px,4vw,48px);
  background:rgba(9,13,31,.66);backdrop-filter:blur(6px);
  opacity:0;pointer-events:none;transition:opacity .6s ease}
body.poster #poster,body.poster #merdeka{opacity:1;pointer-events:auto}

.poster-card:focus{outline:none}
.poster-card{position:relative;width:min(1000px,100%);max-height:calc(100svh - 48px);
  overflow:auto;background:var(--black);color:#fff;
  border:1px solid rgba(247,212,206,.30);
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.04fr);
  transform:translateY(16px) scale(.985);opacity:0;
  transition:transform .7s cubic-bezier(.2,.7,.3,1),opacity .7s}
body.poster .poster-card{transform:none;opacity:1}

.poster-card .plate{position:relative;min-width:0;background:var(--navy-deep);overflow:hidden}
.poster-card .plate img{width:100%;height:100%;object-fit:cover;display:block}
/* a hairline of rose down the seam, the way a mount separates stone from metal */
.poster-card .plate::after{content:"";position:absolute;top:0;right:0;bottom:0;width:1px;
  background:linear-gradient(180deg,transparent,rgba(247,212,206,.55),transparent)}

.poster-body{min-width:0;padding:clamp(32px,4.4vw,60px);display:flex;flex-direction:column;
  align-items:center;justify-content:center;text-align:center}
.poster-body .mono{height:40px;margin-bottom:26px}
.poster-body .lab{color:var(--rose);margin-bottom:20px}
.poster-body h2{font-family:var(--dis);font-weight:400;letter-spacing:.01em;line-height:1.16;
  font-size:clamp(26px,2.7vw,38px);margin-bottom:18px}
.poster-body h2 em{font-style:normal;color:var(--rose);display:block}
.poster-body .zh{font-family:var(--cn);font-weight:300;letter-spacing:.28em;
  color:rgba(249,248,245,.55);font-size:12.5px;margin-bottom:26px}
.poster-body p{color:rgba(249,248,245,.74);font-size:15.5px;line-height:1.72;max-width:38ch;margin-bottom:20px}
/* The practical line under the promise. Smaller, pulled closer to the sentence
   it qualifies — but NOT dimmer: it keeps the same colour token, because
   reducing opacity on smaller text is exactly where the poster would drop
   below AA, and every text node on this site clears it. */
.poster-body p.fine{font-size:13px;line-height:1.6;margin-bottom:32px}
.poster-body .btn{background:var(--rose);border-color:var(--rose);color:var(--navy);width:100%;max-width:330px;padding-top:17px;padding-bottom:17px}
.poster-body .btn:hover{background:transparent;color:var(--rose)}
.poster-hr{width:44px;height:1px;background:rgba(247,212,206,.4);margin:34px 0 28px}
.poster-mail{display:flex;width:100%;max-width:330px;gap:0}
.poster-mail input{flex:1;min-width:0;background:none;border:0;
  border-bottom:1px solid rgba(247,212,206,.35);color:#fff;
  font-family:var(--dis);font-size:14.5px;padding:9px 2px}
.poster-mail input:focus{outline:none;border-bottom-color:var(--rose)}
.poster-mail input::placeholder{color:rgba(249,248,245,.4)}
.poster-mail button{font-family:var(--ut);font-weight:300;font-size:9px;letter-spacing:.24em;
  text-transform:uppercase;color:var(--rose);padding:0 0 0 16px;white-space:nowrap}
.poster-mail button:hover{color:#fff}
.poster-note{font-family:var(--ut);font-weight:300;font-size:8.5px;letter-spacing:.2em;
  text-transform:uppercase;color:rgba(249,248,245,.42);margin-top:14px}
.poster-later{font-family:var(--ut);font-weight:300;font-size:9px;letter-spacing:.24em;
  text-transform:uppercase;color:rgba(249,248,245,.5);margin-top:26px;
  border-bottom:1px solid rgba(249,248,245,.22);padding-bottom:3px}
.poster-later:hover{color:#fff;border-bottom-color:#fff}
.poster-x{position:absolute;top:12px;right:14px;z-index:3;width:36px;height:36px;
  display:grid;place-items:center;color:rgba(249,248,245,.62);font-size:20px;line-height:1;
  transition:color .3s}
.poster-x:hover{color:#fff}

@media(max-width:720px){
  /* Stacked, the plate's aspect-ratio demanded more height than the grid row
     was willing to give it under max-height, so the image overflowed onto the
     copy. Explicit rows + align-content:start lets the card scroll instead. */
  /* minmax(0,1fr), not 1fr: a bare 1fr is minmax(auto,1fr) and lets a wide
     min-content child blow the card past the viewport, which then drags every
     position:fixed bar out with it */
  .poster-card{grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto;align-content:start}
  .poster-card .plate{aspect-ratio:auto;height:30svh;min-height:180px;flex:none}
  .poster-card .plate::after{top:auto;left:0;right:0;bottom:0;width:auto;height:1px;
    background:linear-gradient(90deg,transparent,rgba(247,212,206,.55),transparent)}
  .poster-body{padding:30px 24px 34px}
  .poster-body .mono{height:32px;margin-bottom:16px}
}
@media(prefers-reduced-motion:reduce){
  #poster,.poster-card{transition:none}
}

/* ==========================================================================
   PREMIUM MOOD
   The dark stages were reading flat: a pure digital black with a centred stack
   on it. Four things fix that — depth in the ground, grain on the surface,
   real metal in the accent type, and a mount around the stage.
   ========================================================================== */

/* --- 1. depth in the ground -----------------------------------------------
   A warm pool of light behind the piece and a vignette at the edges, so the
   stage reads as a lit vitrine rather than a black rectangle. */
.hero,.pband,.ed,.banner,.jhero{isolation:isolate}
.hero::before,.pband::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(80% 58% at 50% 34%, rgba(247,212,206,.13), transparent 66%),
    radial-gradient(140% 96% at 50% 8%,  rgba(247,212,206,.10), transparent 60%),
    radial-gradient(120% 80% at 50% 108%, rgba(9,13,31,.86), transparent 62%)}
.pband::before{z-index:1}
#dust{z-index:1}
#glow{z-index:2}
.slide .in,.hero .cue{z-index:3}

/* --- 2. grain -------------------------------------------------------------
   ~1 KB of inline SVG noise. Flat black on a screen looks like a swatch; a
   trace of grain reads as a photographed surface. */
body::after{content:"";position:fixed;inset:0;z-index:120;pointer-events:none;
  opacity:.05;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  background-size:140px 140px}
[data-theme="dark"] body::after{opacity:.07}

/* --- 3. real metal in the accent type -------------------------------------
   Flat rose is a colour; a gradient with a highlight running through it is
   gold. Falls back to solid rose where background-clip:text is unsupported. */
.slide h1 em,.slide .slide-h em,.pband h2 em,.poster-body h2 em,.ed h2 em{
  color:var(--rose)}
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .slide h1 em,.slide .slide-h em,.pband h2 em,.poster-body h2 em,.ed h2 em{
    background:linear-gradient(96deg,#C9A9A6 0%,#F7D4CE 22%,#FDF1EE 38%,
      #E4C6C2 54%,#C9A9A6 74%,#F2DAD6 92%,#D9D9D6 100%);
    -webkit-background-clip:text;background-clip:text;
    -webkit-text-fill-color:transparent;color:transparent}
}

/* --- 4. the mount — REMOVED 19 Aug 2026 at the client's request ------------
   Was a hairline inset from the edge of every full-bleed stage (hero and the
   piece bands), powder rose at 16%. The client did not want the frame. */

/* --- 5. a slower, staggered entrance --------------------------------------
   Everything arriving at once is what makes a hero feel like a template. */
.slide.on .in>*{animation:heroRise .95s cubic-bezier(.2,.7,.3,1) both}
.slide.on .in>*:nth-child(1){animation-delay:.10s}
.slide.on .in>*:nth-child(2){animation-delay:.20s}
.slide.on .in>*:nth-child(3){animation-delay:.30s}
.slide.on .in>*:nth-child(4){animation-delay:.40s}
.slide.on .in>*:nth-child(5){animation-delay:.50s}
.slide.on .in>*:nth-child(6){animation-delay:.58s}
@keyframes heroRise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* a hairline under the eyebrow, so the label and headline are not just
   two centred lines of text */
.slide .lab::after,.pband .lab::after{content:"";display:block;width:34px;height:1px;
  background:rgba(247,212,206,.45);margin:14px auto 0}
.pband:not([data-side]) .lab::after{margin-left:0}

@media(prefers-reduced-motion:reduce){
  .slide.on .in>*{animation:none}
  body::after{display:none}
}

/* The banner slides fix the hero at 2.4:1, which is short for a stacked
   composition. Slide 0 has no baked artwork, so it can run a tighter stack and
   give the dust the clearance it needs inside the mount. */
.slide[data-slide="0"] .mono{height:26px;margin-bottom:13px}
.slide[data-slide="0"] .lab::after{margin-top:10px}
.slide[data-slide="0"] h1{margin:11px 0 9px}
.slide[data-slide="0"] p{margin-bottom:19px}
.slide[data-slide="0"]{padding-bottom:clamp(46px,6vh,70px)}

@media(max-width:820px){.hero .cue{display:none}}

/* ==========================================================================
   PDP — extended product page (added 19 Aug 2026)
   Structure follows the specialist-jeweller pattern the client referenced:
   rating under the title, a trust strip, a hard specification table, shipping
   by region, story blocks, service cards, testimonials and an FAQ.
   Everything expressive stays C'Garden's: navy ground, powder rose accents,
   Marcellus sentence-case headings, Jost for labels only.
   ========================================================================== */

/* --- star rating ---------------------------------------------------------- */
.rating{display:flex;align-items:center;gap:9px;margin:10px 0 4px}
.rating .stars{display:inline-flex;gap:2px}
.rating svg{width:14px;height:14px;fill:var(--rose-deep);stroke:none}
.rating span{font-family:var(--ut);font-weight:300;font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--grey-2)}

/* --- trust strip ---------------------------------------------------------- */
/* Six promises, not five: the row must divide evenly at 6/3/2 columns or the
   last card orphans on tablet. */
.trustrow{border-top:1px solid var(--hair-2);border-bottom:1px solid var(--hair-2);
  margin:0 var(--pad);padding:34px 0;
  display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:26px}
.trustrow div{text-align:center;padding:0 8px}
.trustrow svg{width:24px;height:24px;stroke:var(--rose-deep);fill:none;
  stroke-width:1.15;margin:0 auto 11px;display:block}
.trustrow h3{font-family:var(--ut);font-weight:400;font-size:10px;letter-spacing:.22em;
  text-transform:uppercase;color:var(--ink);margin-bottom:6px}
.trustrow p{font-size:12.5px;line-height:1.55;color:var(--grey-2);font-family:var(--dis)}
@media(max-width:1040px){.trustrow{grid-template-columns:repeat(3,minmax(0,1fr));gap:30px 18px}}
@media(max-width:600px){.trustrow{grid-template-columns:repeat(2,minmax(0,1fr));gap:26px 14px;padding:28px 0}}

/* --- specification table -------------------------------------------------- */
.specwrap{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 56px}
@media(max-width:820px){.specwrap{grid-template-columns:minmax(0,1fr)}}
.specwrap .row{display:flex;justify-content:space-between;align-items:baseline;gap:20px;
  padding:15px 0;border-bottom:1px solid var(--hair-2)}
.specwrap .row dt{font-family:var(--ut);font-weight:300;font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--grey-2);flex:0 0 auto;max-width:58%}
.specwrap .row dd{font-family:var(--dis);font-size:15px;color:var(--ink);text-align:right;min-width:0}
.specnote{margin-top:20px;font-size:12px;color:var(--grey-2);line-height:1.65}

/* --- shipping by region --------------------------------------------------- */
.shiprow{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1px;
  background:var(--hair-2);border:1px solid var(--hair-2)}
.shiprow div{background:var(--paper);padding:20px 22px}
.shiprow strong{display:block;font-family:var(--ut);font-weight:300;font-size:10px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--grey-2);margin-bottom:7px}
.shiprow span{font-family:var(--dis);font-size:15px;color:var(--ink)}

/* --- story blocks --------------------------------------------------------- */
.storyrow{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(28px,4vw,64px)}
@media(max-width:820px){.storyrow{grid-template-columns:minmax(0,1fr)}}
.storyrow article{padding:34px 0;border-top:1px solid var(--hair-2)}
.storyrow h3{font-family:var(--dis);font-weight:400;font-size:clamp(19px,2vw,25px);
  margin-bottom:12px;line-height:1.25}
.storyrow p{color:var(--grey);font-size:15px;margin-bottom:14px}

/* --- service cards -------------------------------------------------------- */
.svccards{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:18px}
@media(max-width:900px){.svccards{grid-template-columns:repeat(2,minmax(0,1fr))}}
.svccards a{display:block;padding:30px 24px;border:1px solid var(--hair);
  transition:border-color .4s,background .4s;background:var(--paper-2)}
.svccards a:hover{border-color:var(--rose-deep);background:var(--paper)}
.svccards svg{width:26px;height:26px;stroke:var(--rose-deep);fill:none;stroke-width:1.1;margin-bottom:15px}
.svccards h3{font-family:var(--dis);font-size:18px;font-weight:400;margin-bottom:7px}
.svccards p{font-size:13px;color:var(--grey-2);line-height:1.6}

/* --- testimonials --------------------------------------------------------- */
.quotes{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(20px,3vw,44px);text-align:left}
@media(max-width:820px){.quotes{grid-template-columns:minmax(0,1fr)}}
.quotes figure{border-top:1px solid var(--hair);padding-top:24px}
.quotes blockquote{font-family:var(--dis);font-size:16px;line-height:1.75;color:var(--ink);margin-bottom:16px}
.quotes figcaption{font-family:var(--ut);font-weight:300;font-size:10px;letter-spacing:.22em;
  text-transform:uppercase;color:var(--grey-2)}

/* --- FAQ ------------------------------------------------------------------ */
/* <details> so it works with JS off and stays keyboard-accessible for free. */
.faqs{max-width:860px;margin:0 auto;text-align:left}
.faqs details{border-bottom:1px solid var(--hair-2)}
.faqs summary{list-style:none;cursor:pointer;padding:21px 40px 21px 0;position:relative;
  font-family:var(--dis);font-size:17px;color:var(--ink);transition:color .3s}
.faqs summary::-webkit-details-marker{display:none}
.faqs summary:hover{color:var(--rose-text)}
.faqs summary::after{content:"";position:absolute;right:6px;top:50%;width:9px;height:9px;
  border-right:1px solid var(--rose-deep);border-bottom:1px solid var(--rose-deep);
  transform:translateY(-70%) rotate(45deg);transition:transform .35s}
.faqs details[open] summary::after{transform:translateY(-30%) rotate(-135deg)}
.faqs p{padding:0 0 22px;color:var(--grey);font-size:15px;max-width:74ch}

/* secondary calls to action beneath the primary enquiry button */
.acts-more{display:flex;gap:10px;flex-wrap:wrap;margin-top:12px}
.acts-more .btn{flex:1 1 190px;min-height:46px;padding:0 22px;font-size:9.5px}

/* ==========================================================================
   PAPER ORNAMENT — the bespoke-path section only (added 19 Aug 2026)
   Layered paper-cut florals and butterflies, generated in 22-paper and re-inked
   to powder rose. They enter on scroll, hold, leave, and replay on return.

   Scoped to .ornsec so nothing else on the site inherits it.
   ========================================================================== */
.ornsec{position:relative;overflow:hidden}          /* so they can leave frame cleanly */
.orn{position:absolute;top:50%;width:clamp(110px,13.5vw,225px);height:auto;z-index:0;
  pointer-events:none;user-select:none;opacity:0;
  transform:translateY(-50%) translateX(var(--out));
  /* opacity matched to the butterflies' 1.1s so the two vanish on the same
     frame — at .75s the sprays were already gone while the butterflies were
     still fading, which read as them being left behind */
  transition:transform 1.25s cubic-bezier(.22,.75,.28,1),opacity 1.1s ease}
.orn.l{left:-3.5%;--out:-118%}
.orn.r{right:-3.5%;--out:118%}
.orn.in{opacity:1;transform:translateY(-50%) translateX(0)}
/* REGRESSION FIX (19 Aug): `img[data-themed]{transition:opacity .35s}` at the top
   of this file is specificity 0,1,1 and beats a bare `.orn` at 0,1,0 — and the
   shorthand REPLACES rather than merges, so adding data-themed for the
   light-mood swap silently deleted the transform transition. The sprays had
   stopped sliding and were snapping into place. This selector outranks it. */
img.orn[data-themed]{
  transition:transform 1.25s cubic-bezier(.22,.75,.28,1),opacity 1.1s ease}
/* the art sits BEHIND the words, and the words are given room to clear it —
   at 1440px the sprays landed straight across the first and last step */
.ornsec .wrap{position:relative;z-index:1;
  padding-left:clamp(0px,11vw,215px);padding-right:clamp(0px,11vw,215px)}

/* --- butterflies ---
   Three nested elements, because natural flight is three motions at once and
   one element can only hold one transform: .bfly flies the route, .bw bobs once
   per full wingbeat, and the <img> beats the wings. The beat is ~0.3s — at the
   1.15s first tried, the eye reads a squeeze rather than a wing — and the
   squeeze stops at 72% because the body is a thin strip up the middle of the
   sprite and a deeper scale thins the body too. Each path is a CLOSED LOOP;
   `alternate` made them retrace their own route backwards, which nothing does. */
/* The fade matches the sprays' 1.25s slide so the two leave together, and the
   stagger is applied ONLY in the .on state — as a base-state delay it also
   delayed the exit, which is what made them drift out one by one. */
.bfly{position:absolute;z-index:2;pointer-events:none;opacity:0;
  transition:opacity 1.1s ease;transition-delay:0s;animation-play-state:paused}
.bfly .bw{display:block;animation:bob .62s ease-in-out infinite alternate;
  animation-play-state:paused}
.bfly img{display:block;width:100%;height:auto;transform-origin:50% 50%;
  animation:flap .31s ease-in-out infinite alternate;animation-play-state:paused;
  filter:drop-shadow(0 4px 7px rgba(9,13,31,.45))}
.ornsec.anim .bfly,.ornsec.anim .bfly .bw,.ornsec.anim .bfly img{animation-play-state:running}
.ornsec.on .bfly{opacity:1}
@keyframes flap{from{transform:scaleX(1)}to{transform:scaleX(.72)}}
@keyframes bob{from{transform:translateY(2px)}to{transform:translateY(-4px)}}
@keyframes fly1{0%,100%{transform:translate(0,0) rotate(-5deg)}
  14%{transform:translate(26px,-22px) rotate(9deg)}
  29%{transform:translate(54px,-52px) rotate(2deg)}
  44%{transform:translate(38px,-84px) rotate(-12deg)}
  60%{transform:translate(-4px,-96px) rotate(4deg)}
  78%{transform:translate(-34px,-58px) rotate(11deg)}
  90%{transform:translate(-22px,-24px) rotate(-3deg)}}
@keyframes fly2{0%,100%{transform:translate(0,0) rotate(6deg)}
  16%{transform:translate(-30px,-16px) rotate(-8deg)}
  33%{transform:translate(-52px,-44px) rotate(3deg)}
  50%{transform:translate(-24px,-72px) rotate(13deg)}
  67%{transform:translate(18px,-60px) rotate(-6deg)}
  84%{transform:translate(28px,-26px) rotate(8deg)}}
@keyframes fly3{0%,100%{transform:translate(0,0) rotate(-8deg)}
  18%{transform:translate(22px,18px) rotate(6deg)}
  36%{transform:translate(46px,-6px) rotate(-4deg)}
  54%{transform:translate(30px,-40px) rotate(12deg)}
  72%{transform:translate(-14px,-30px) rotate(-10deg)}
  88%{transform:translate(-20px,4px) rotate(3deg)}}
@keyframes fly4{0%,100%{transform:translate(0,0) rotate(4deg)}
  20%{transform:translate(-24px,-28px) rotate(-9deg)}
  40%{transform:translate(6px,-56px) rotate(7deg)}
  58%{transform:translate(40px,-38px) rotate(-5deg)}
  76%{transform:translate(30px,-6px) rotate(10deg)}}
/* no two share a period, so they never fall into visible lockstep */
.b1{top:20%;left:9.5%;width:60px;animation:fly1 13s ease-in-out infinite}
.ornsec.on .b1{transition-delay:.45s} .ornsec.on .b2{transition-delay:.75s}
.ornsec.on .b3{transition-delay:.6s}  .ornsec.on .b4{transition-delay:.9s}
.b2{top:63%;left:5%;width:42px;animation:fly3 17s ease-in-out infinite}
.b3{top:28%;right:8%;width:52px;animation:fly2 15s ease-in-out infinite}
.b4{top:72%;right:12.5%;width:38px;animation:fly4 19s ease-in-out infinite}
.b1 img{animation-duration:.33s} .b1 .bw{animation-duration:.66s}
.b2 img{animation-duration:.24s} .b2 .bw{animation-duration:.48s}
.b3 img{animation-duration:.29s} .b3 .bw{animation-duration:.58s}
.b4 img{animation-duration:.21s} .b4 .bw{animation-duration:.42s}

@media(max-width:860px){.orn,.bfly{display:none}}   /* too tight to earn its place */
@media(prefers-reduced-motion:reduce){
  .orn{transition:none;opacity:1;transform:translateY(-50%) translateX(0)}
  .bfly{opacity:1;animation:none}
  .bfly .bw,.bfly img{animation:none}
}


/* ======================================================================
   LANGUAGE  —  English / 中文
   ----------------------------------------------------------------------
   English is the default and, for now, the only complete language. Every
   Chinese node on the site carries one of four classes (.zh .cn .cnname
   .cnt), so English mode is a single rule rather than 28 pages of edits.

   Hidden with display:none rather than visibility or opacity so the text is
   removed from the accessibility tree and from find-in-page — a screen
   reader announcing Chinese on an English page is worse than showing it.
   ====================================================================== */
/* These four classes are DECORATIVE Chinese accents that used to sit beneath
   English headings — they were never translations. Now that a real 中文 layer
   exists they are hidden in both languages: in English because the page must
   be English, and in Chinese because the heading above them is already Chinese
   and the accent would simply repeat it. */
.zh, .cn, .cnname, .cnt{display:none !important}

.langbtn{display:flex;align-items:center;gap:4px;font-family:var(--ut);font-weight:300;
  font-size:9.5px;letter-spacing:.16em;line-height:1;padding:0 2px;white-space:nowrap}
.langbtn .lg{color:rgba(249,248,245,.45);transition:color .3s ease}
.langbtn .lgsep{font-style:normal;color:rgba(249,248,245,.28)}
/* the ACTIVE language is the lit one — the button reports state rather than
   asking a question, which is how the mood toggle beside it behaves */
html[data-lang="en"] .langbtn .lg-en,
html[data-lang="zh"] .langbtn .lg-zh{color:var(--rose)}
.langbtn:hover .lg{color:#fff}
.langbtn .lg-zh{font-family:var(--cn);font-size:10.5px;letter-spacing:.08em}
[data-theme="light"] .langbtn .lg{color:rgba(36,19,24,.5)}
[data-theme="light"] .langbtn .lgsep{color:rgba(36,19,24,.3)}
[data-theme="light"] .langbtn:hover .lg{color:var(--ink)}
@media(max-width:560px){.langbtn{font-size:9px;letter-spacing:.1em}}

/* ==========================================================================
   PHONES
   Audited 24 Aug 2026 across 320px (iPhone SE 1st gen) to 430px (Pro Max).
   The composition already held at every width; what did not hold was the
   hand. Controls were drawn at their optical size and left at it, so the
   burger was a 22x14 target and the mood, saved and enquiry buttons were 29px
   squares — all well under the 44px a fingertip actually needs. And the
   smallest labels, set for a desktop viewed at arm's length, fell to 8px on a
   screen held closer but rendered smaller.

   So: hit areas grow, artwork does not. The ::after plate is invisible and
   sits centred on each control, which means every icon stays exactly the size
   it was drawn while the area that responds to a thumb reaches the floor.
   Type is lifted only where it fell below legibility, and the tightest
   letter-spacing is eased in step so nothing reflows to a new line.
   ========================================================================== */
@media(max-width:820px){

  /* ---- finger-sized hit areas, unchanged artwork ------------------------ */
  /* .promo .x is deliberately left out: it is already position:absolute in its
     corner, and re-declaring it relative dropped it back into the flex flow,
     landing the close button in the middle of the bar. An absolutely
     positioned element is its own containing block, so its plate works as is. */
  .icons button,.icons a,.burger,#langBtn,
  .view button,.social a,.hdots button,.readmore,.filterBtn,.clear{position:relative}

  .icons button::after,.icons a::after,.burger::after,#langBtn::after,
  .promo .x::after,.view button::after,.social a::after,
  .hdots button::after,.readmore::after,.filterBtn::after,.clear::after{
    content:"";position:absolute;left:50%;top:50%;translate:-50% -50%;
    width:44px;height:44px}

  /* the language pill is wider than it is tall; only its height is short */
  #langBtn::after{width:100%;min-width:56px}
  /* slide dots are 2px rules by design — the plate does the catching */
  .hdots{gap:22px}
  .hdots button::after{width:34px}

  /* ---- lists of links: give the row a thumb's worth of height ----------- */
  .fcols a,.util a,.crumb a,.fbar a{display:inline-block;padding:9px 0}
  .social{gap:6px}
  .social a{padding:10px}

  /* ---- legibility floor ------------------------------------------------- */
  /* 8px and 9px labels are dense on a phone; each gains a point or two and
     sheds a little tracking so the line length does not grow with it. */
  .lab{font-size:10.5px;letter-spacing:.28em}
  .fmark .fline{font-size:11px;letter-spacing:.26em}
  .btn{font-size:11.5px;letter-spacing:.22em}
  .badge{font-size:9.5px;letter-spacing:.18em}
  .promo{font-size:11px}
  .wa{font-size:11px;letter-spacing:.18em}
  .card .px,.px{font-size:11.5px;letter-spacing:.12em}
  .fbar,.fbar *{font-size:11px;letter-spacing:.1em}
  .soon{font-size:11px}
  .filterBtn,.clear,.sz{font-size:11px;letter-spacing:.16em}
  .readmore{font-size:11.5px}
}

/* ---- the narrowest phones ------------------------------------------------
   At 320 and 360 the promo bar ran to three lines and the header crowded its
   own wordmark. Tracking is the first thing to give: it is decorative here,
   and the words matter more than the air between their letters. */
@media(max-width:365px){
  .promo{font-size:10.5px;letter-spacing:.06em;padding-right:44px}
  .promo .x{right:6px}
  .lab{letter-spacing:.2em}
  .btn{padding:0 24px;letter-spacing:.16em}
  .icons{gap:10px}
  .wa{padding:11px 15px;letter-spacing:.12em}
  .card h3{font-size:16px}
  .card .met{font-size:13.5px}
}

/* Rules the page-level <style> blocks and #id selectors were winning over.
   Matched at equal or higher specificity rather than reached for !important,
   so the cascade still reads in source order. */
@media(max-width:820px){
  #book p{font-size:14px}
  #book .btn{font-size:11.5px;letter-spacing:.18em;padding:0 20px}
  #book .x{font-size:11px;letter-spacing:.16em;padding:10px 8px}
  .fcols h4{font-size:11.5px;letter-spacing:.22em}
  .fcols a,.fbar a,.fbar span{font-size:11.5px}
  .util a{font-size:11px;letter-spacing:.14em}
  .crumb,.crumb a,.crumb span,.info .crumb{font-size:11px;letter-spacing:.14em}
  .sz{font-size:11.5px;min-height:44px}
  .rule,.rule.lt{font-size:11.5px;letter-spacing:.2em}
  .quotes .lab,.svccards h3,.storyrow h3{font-size:11.5px}
}

/* The plates must not touch each other: two overlapping hit areas are worse
   than one small one, because the wrong control answers. Where the icon row
   tightens on the narrowest screens the plate narrows with it, keeping a
   sliver of clearance between neighbours. */
/* At 320px the header row is full to the millimetre: wordmark plus five
   controls leaves no slack to widen a hit area into. So the row gives some
   back — a slightly smaller wordmark and a tighter language pill — and the
   plates take the space that frees up. 40px is the honest ceiling on a screen
   this narrow; it is still nearly double what these controls had before. */
@media(max-width:365px){
  .wordmark{height:21px}
  .langbtn{gap:2px;padding:0}
  .langbtn .lg-zh{font-size:9.5px;letter-spacing:.04em}
  /* the plate can never be wider than the pitch it sits in (icon + gap),
     or neighbouring hit areas overlap and the wrong control answers */
  .icons{gap:15px}
  .icons button::after,.icons a::after{width:42px}
}
@media(max-width:820px){
  /* text links that carry a rule under them: the rule is the affordance, but
     the line of text is only ~20px tall, so the row gets padded out */
  .rule,.readmore,.promo a{display:inline-block;padding:11px 0;min-height:44px}
  .promo a{padding:8px 0;min-height:0}
  .promo a::after{content:"";position:absolute;left:50%;top:50%;translate:-50% -50%;
    width:100%;min-width:64px;height:44px}
  .promo a{position:relative}
  .wa{padding:14px 20px;min-height:46px}
  .hdots button::after{width:40px;height:40px}
}

/* --- the welcome poster on a short screen ---------------------------------
   The card scrolls, so nothing was unreachable in the strict sense — but on a
   568px-tall handset the plate and the generous stack pushed "Book a
   consultation" 163px past the fold, and a modal that fills the screen gives
   no hint that it scrolls. A visitor on an iPhone SE simply never saw the
   button the whole poster exists to show them.

   Keyed to viewport HEIGHT, not width: it is the short screen that causes
   this, and a 430px-wide phone in landscape has the same problem. Everything
   here tightens rather than removes, so the poster still reads as the same
   piece — the plate keeps its role as an image, just a smaller one. */
@media(max-width:720px) and (max-height:720px){
  .poster-card .plate{height:16svh;min-height:96px}
  .poster-body{padding:18px 20px 22px}
  .poster-body .mono{height:24px;margin-bottom:10px}
  .poster-body .lab{margin-bottom:10px}
  .poster-body h2{font-size:22px;line-height:1.14;margin-bottom:10px}
  .poster-body .zh{font-size:11px;margin-bottom:12px;letter-spacing:.2em}
  .poster-body p{font-size:13.5px;line-height:1.5;margin-bottom:10px}
  .poster-body p.fine{font-size:11.5px;line-height:1.45;margin-bottom:14px}
  .poster-body .btn{padding-top:14px;padding-bottom:14px}
  /* the newsletter is the poster's secondary ask; on a screen this short it
     yields to the booking button rather than competing for the same fold */
  .poster-hr{margin:16px 0 14px}
  .poster-mail,.poster-note,.poster-hr{display:none}
  .poster-later{margin-top:14px;font-size:10.5px}
}

/* The overlay's own controls were missed by the first phone pass, because the
   audit had dismissed the poster before measuring. On a modal these two matter
   more than anything else on the page: if the way out is hard to hit, the
   visitor is trapped in it. The close cross gets a full 44px, and the quiet
   dismiss link comes up off 9px, which is a desktop label size on a screen
   held at reading distance. */
@media(max-width:820px){
  .poster-x{width:44px;height:44px;top:6px;right:6px;font-size:22px}
  .poster-later{font-size:11.5px;letter-spacing:.16em;padding:10px 6px;min-height:44px}
}

/* ==========================================================================
   THE FOUR CATEGORY ICONS DRAW THEMSELVES IN
   Every piece in this house begins as a drawing, so the four line icons are
   drawn rather than faded up: each stroke runs on as though a pencil were
   putting it there, one card after the next.

   pathLength="1" is set on every shape inside the four symbols, which
   normalises their real lengths to a single unit. Without it one dash value
   would draw the small centre stone and the long necklace arc at wildly
   different speeds and the icon would assemble itself out of order.

   The icons are <use> references into the sprite, and their shapes live in a
   shadow tree that CSS cannot select into. stroke-dasharray and
   stroke-dashoffset are INHERITED SVG properties, so they are set on the
   parent <svg> and reach the shapes that way.

   Guarded behind html.js, set before first paint. A stroke hidden by
   dashoffset with no script to reveal it is simply an invisible icon, so
   without scripting they sit there fully drawn and nothing is lost.
   ========================================================================== */
html.js .catgrid .catico{stroke-dasharray:1;stroke-dashoffset:1}
html.js .catgrid.on .catico{animation:catdraw 1.1s cubic-bezier(.62,0,.36,1) forwards}

/* staggered, so the row reads left to right like a hand moving across a page
   rather than four icons appearing at once */
html.js .catgrid.on a:nth-child(1) .catico{animation-delay:.04s}
html.js .catgrid.on a:nth-child(2) .catico{animation-delay:.20s}
html.js .catgrid.on a:nth-child(3) .catico{animation-delay:.36s}
html.js .catgrid.on a:nth-child(4) .catico{animation-delay:.52s}

@keyframes catdraw{ from{stroke-dashoffset:1} to{stroke-dashoffset:0} }

/* Hovering re-draws that one icon, and lifts it a little further than the
   base hover already does.

   The keyframes are a SEPARATE NAME from the entrance on purpose. Naming them
   catdraw again did nothing at all: the icon is already carrying
   animation-name:catdraw from the entrance, so the browser treated the hover
   rule as a property update on an animation that had already finished rather
   than as a new one, and the line never ran again. A distinct name is what
   makes it restart.

   'forwards' is not optional here either. Without it the hover animation ends
   by falling back to the declared stroke-dashoffset:1, which would make the
   icon vanish while the cursor was still on it.

   Skipped on touch, where there is no real hover and the rule would fire on
   tap, halfway through a navigation. */
@media(hover:hover){
  html.js .catgrid.on a:hover .catico{
    animation:catredraw .75s cubic-bezier(.62,0,.36,1) forwards;
    transform:translateY(-5px) scale(1.05)}
}
@keyframes catredraw{ from{stroke-dashoffset:1} to{stroke-dashoffset:0} }

@media(prefers-reduced-motion:reduce){
  html.js .catgrid .catico,
  html.js .catgrid.on .catico,
  html.js .catgrid.on a:hover .catico{animation:none;stroke-dashoffset:0}
}

/* ==========================================================================
   THE VIDEO SLIDE
   The Atelier Solitaire turning on its own axis. Unlike the other four slides
   this one carries no baked-in type: burnt-in text on a video cannot be
   cropped for a phone the way a still can, so the copy stays live HTML at
   every width and takes its legibility from a scrim.
   ========================================================================== */
.slide-video>.herovid{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;z-index:0;background:var(--black)}

/* .live is normally desktop-hidden because the other slides bake their words
   into the artwork. This slide has no baked words, so it must never hide. */
.slide-video .live{display:block}

/* The clip is a bright object on a dark ground, and the copy sits over the
   lower left. A plain flat veil would kill the gold, so the scrim is angled:
   heavy where the words are, clearing entirely across the ring. */
/* The copy lands centre-frame, inside the band of the ring, so an angled veil
   from the left did nothing where it was needed. This is a soft radial plate
   behind the words instead: it darkens the middle just enough for the body
   line to hold against the polished gold, and clears completely at the edges
   so the metal keeps its shine. */
.slide-video::after{content:"";position:absolute;inset:0;z-index:1;
  background:
    radial-gradient(58% 46% at 50% 62%,rgba(9,13,31,.78) 0%,rgba(9,13,31,.55) 45%,
      rgba(9,13,31,0) 100%),
    linear-gradient(180deg,rgba(9,13,31,.34) 0%,rgba(9,13,31,0) 22%,
      rgba(9,13,31,0) 58%,rgba(9,13,31,.55) 100%)}

/* Cover on a 16:9 clip in a wider hero crops the top and bottom, and what it
   was cutting was the point of the stone. Framed slightly high so the marquise
   stays whole. */
.slide-video>.herovid{object-position:50% 38%}
@media(max-width:820px){
  /* portrait crop puts the ring centre-frame, so the veil turns vertical and
     lifts off the middle of the picture */
  .slide-video::after{background:linear-gradient(180deg,rgba(9,13,31,.62) 0%,
    rgba(9,13,31,.20) 26%,rgba(9,13,31,.55) 62%,rgba(9,13,31,.92) 100%)}
}

/* Someone who has asked for less motion should not be handed an autoplaying
   film. The poster frame still shows the ring, so nothing is lost but the
   movement; cg.js also declines to call play() in that case. */
@media(prefers-reduced-motion:reduce){
  .slide-video>.herovid{display:none}
  .slide-video{background:var(--black) center/cover no-repeat
    url("assets/video/ring-spin-v1-poster.webp")}
}
