/* ── Design tokens — see DESIGN_SYSTEM.html. No raw value belongs below this block. ── */
    :root{
      /* surfaces */
      --surface-night:#151612; --surface-night-soft:#20211b;
      --surface-paper:#eee9df; --surface-plate:#fbfaf1;
      /* text: three tones per surface */
      --on-dark-1:#eee9df; --on-dark-2:rgba(238,233,223,.74); --on-dark-3:rgba(238,233,223,.52);
      --on-light-1:#1d211b; --on-light-2:#5f5e54; --on-light-3:rgba(29,33,27,.50);
      /* accent */
      /* accent — switchable; every value measured AA on both surfaces */
      --gold:#c7a25a; --gold-soft:#d8b66f; --gold-ink:#7d5716;
      /* lines */
      --line-on-dark:rgba(238,233,223,.16); --line-on-light:rgba(29,33,27,.14);
      /* fills — the same ink as the lines, at plate strength */
      --fill-on-dark:rgba(238,233,223,.07);
      /* metal — a highlight and a shade of the accent, for the primary button */
      --metal-lit:#fffdf7; --metal-dim:#d9d3c6; --metal-edge:#5f5a4e;
      /* silk — the light and the shade of a fold, on a dark surface */
      --silk-lit:rgba(238,233,223,.055); --silk-dim:rgba(0,0,0,.20);
      /* type */
      --font-display:"Cormorant Garamond",Georgia,serif;
      --font-text:"DM Sans",ui-sans-serif,system-ui,sans-serif;
      --font-mono:"IBM Plex Mono",ui-monospace,monospace;
      /* the body face is a serif: it needs a little more size and
         line than the grotesque it replaced, or it reads thin */
      --fs-nano:.62rem; --fs-micro:.68rem; --fs-small:.84rem; --fs-body:1.04rem;
      --fs-title:1.13rem; --fs-lg:1.44rem;
      --fs-h3:clamp(1.5rem,2vw,2rem);
      --fs-quote:clamp(1.9rem,3.4vw,3.4rem);
      --fs-h2:clamp(3rem,5.8vw,6rem);
      --fs-h1:clamp(3.4rem,7.1vw,7.1rem);
      --fs-lede:1.04rem;
      --lh-display:.86; --lh-title:1.15; --lh-body:1.6; --lh-loose:1.75;
      --ls-display:-.045em; --ls-title:-.025em; --ls-micro:.12em; --ls-wide:.22em;
      /* space — 4px grid */
      --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px;
      /* the fixed header's height. Load-bearing: it is also the scroll
         offset for every in-page anchor, so the two can never drift. */
      --nav-h:76px;
      /* the minimum comfortable tap target; four controls were under it */
      --tap-min:44px;
      --sp-7:32px; --sp-8:40px; --sp-9:48px; --sp-10:64px; --sp-11:96px; --sp-12:128px;
      /* layout */
      --radius:4px; --measure-max:1240px;
    }
    :root[data-palette="none"]  { --gold:var(--on-dark-1); --gold-soft:var(--on-dark-1); --gold-ink:var(--on-light-1) }
    :root[data-palette="indigo"]{ --gold:#7d93bd; --gold-soft:#9aabcd; --gold-ink:#33456b }
    :root[data-palette="rust"]  { --gold:#c4735a; --gold-soft:#d38f79; --gold-ink:#8a4028 }
    :root[data-palette="bone"]  { --gold:#cfc4ad; --gold-soft:#e0d8c7; --gold-ink:#6b6252 }
    :root[data-corners="sharp"]{ --radius:0px }
    :root[data-corners="soft"] { --radius:8px }
    :root{
      /* motion */
      --dur-fast:150ms; --dur-base:220ms; --dur-slow:600ms; --dur-spin:800ms;
      --dur-sweep:300ms;   /* the CTA thread: a flourish, not feedback */
      --ease-out:cubic-bezier(.2,.7,.2,1); --ease-inout:cubic-bezier(.4,0,.2,1);
    }

    *{box-sizing:border-box}
    /* scroll-padding-top keeps in-page anchors clear of the fixed header.
       Without it every #link lands with its heading hidden behind the nav. */
    html{scroll-behavior:smooth;scroll-padding-top:var(--nav-h)}
    body{
      margin:0;
      color:var(--on-light-1);
      background:var(--surface-paper);
      font-family:var(--font-text);
      -webkit-font-smoothing:antialiased;
      overflow-x:hidden;
    }
    body.menu-open{overflow:hidden}
    img{display:block;max-width:100%}
    figure,blockquote{margin:0}
    a{color:inherit}
    button{font:inherit}
    :focus-visible{outline:2px solid var(--gold-soft);outline-offset:4px}
    .wrap{width:min(var(--measure-max),calc(100% - 48px));margin:0 auto}
    .eyebrow,.micro,.button,.path-index,.process-index,.footer-meta{
      font-family:var(--font-mono);
      text-transform:uppercase;
      letter-spacing:var(--ls-micro);
    }
    .eyebrow{display:flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-micro);color:var(--gold);line-height:var(--lh-title)}
    .section-light .eyebrow{color:var(--gold-ink)}
    .eyebrow::before{content:"";width:28px;height:1px;background:currentColor;display:block}
    .micro{font-size:var(--fs-nano);color:var(--on-light-2);line-height:var(--lh-body)}
    .button{
      display:inline-flex;align-items:center;justify-content:center;gap:var(--sp-3);
      min-height:48px;padding:0 var(--sp-5);border:1px solid var(--gold);
      border-radius:var(--radius);font-size:var(--fs-micro);text-decoration:none;white-space:nowrap;
      transition:background var(--dur-base) var(--ease-out),color var(--dur-base) var(--ease-out),border-color var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out);
    }
    :root[data-arrow="none"] .button::after,:root[data-arrow="none"] .plate-cta::after,:root[data-arrow="none"] .specimen-cta::after,:root[data-arrow="none"] .path-arrow{display:none}
    :root[data-arrow="primary"] .button:not(.button-solid)::after,:root[data-arrow="primary"] .specimen-cta::after{display:none}
    .button::after{content:"↗";font-size:var(--fs-body);line-height:0;transition:transform var(--dur-base) var(--ease-out)}
    .button:hover{transform:translateY(-2px)}
    .button:hover::after{transform:translate(3px,-3px)}
    /* ══ THE PRIMARY BUTTON ══════════════════════════════════════════
       A ring of metal turning around a dark face — the Liquid Metal
       button from 21st, in this site's colours. The reference is chrome
       on a pill; this is the accent on `--radius`, because the accent
       here is `#eee9df` and a chrome ring would introduce a colour the
       page does not use.

       An earlier version ran the highlight *across* an ivory fill
       instead of around a dark one. It was quieter, and it was not what
       was asked for. This is the shape of the example.

       Two backgrounds, not a pseudo-element: the face is clipped to the
       padding box and the ring to the border box, so the gradient shows
       only in the 2px border. Padding, min-height and the label all stay
       exactly as they were, and there is no inner element to wrap.

       `@property` is what makes the angle animatable. Without it a conic
       gradient cannot transition at all, and rotating the element
       instead drags the band across the face as a diagonal line. */
    @property --metal-turn{syntax:'<angle>';inherits:false;initial-value:0deg}
    .button-solid{
      --metal-turn:0deg;
      /* the face is a variable so a section can darken it without
         restating the gradient — and so hover is one line, not a copy */
      --btn-face:var(--surface-night-soft);
      color:var(--on-dark-1);
      border:2px solid transparent;
      /* <button> defaults to buttonface; without this the submit button
         paints a solid grey over the whole thing */
      background-color:transparent;
      background-image:
        linear-gradient(var(--btn-face),var(--btn-face)),
        conic-gradient(from var(--metal-turn),
          var(--metal-edge) 0deg, var(--metal-lit) 58deg, var(--gold) 118deg,
          var(--metal-edge) 190deg, var(--metal-lit) 252deg, var(--gold) 312deg,
          var(--metal-edge) 360deg);
      background-origin:border-box;
      background-clip:padding-box,border-box;
      animation:metal-turn 5.5s linear infinite}
    @keyframes metal-turn{to{--metal-turn:360deg}}
    .button-solid:hover{--btn-face:var(--surface-night)}



    .button-quiet{color:inherit;border-color:currentColor;background:transparent;opacity:.9}
    .button-quiet:hover{color:var(--gold-soft);border-color:var(--gold-soft)}

    /* pressed — the click has to land before anything else happens.
       Without this the button is a picture until the new tab appears,
       and on a slow phone that reads as "nothing happened, tap again". */
    .button:active{transform:translateY(0) scale(.985);transition-duration:var(--dur-fast)}

    /* working — the arrow gives way to a turning ring and the label says
       so. pointer-events go with it, so the second tap can't fire. */
    .btn-spin{display:none;flex:none;width:var(--sp-4);height:var(--sp-4);
      border:2px solid currentColor;border-right-color:transparent;border-radius:50%}
    .button.is-busy{pointer-events:none;opacity:.9}
    .button.is-busy .btn-spin{display:block;animation:btnspin var(--dur-spin) linear infinite}
    .button.is-busy::after{display:none}
    @keyframes btnspin{to{transform:rotate(360deg)}}

    /* ══ SILK ════════════════════════════════════════════════════════
       Folds of light across the dark surfaces. Flat colour reads as a
       screen; a surface with a fold in it reads as a material, and this
       is a clothing brand. The stops are soft by construction, so there
       is no blur filter and nothing to composite — one background image
       per section, drifting on a slow loop.

       It is the section's own background-image, not an overlay, so
       nothing stacks above the content and the light sections are
       untouched. `.scene` is excluded: it composes its own light.

       The folds do not move. A drifting version was built and
       measured first: animating background-position repaints the
       whole section every frame and took 1440 from 60fps to 41.
       Over a 34s loop the movement was barely perceptible anyway,
       so it buys nothing for a third of the frame rate. */
    .section-dark,.enquiry,footer{
      background-image:linear-gradient(100deg,
        transparent 0%, var(--silk-lit) 9%, transparent 19%,
        var(--silk-dim) 28%, transparent 38%,
        var(--silk-lit) 47%, transparent 57%,
        var(--silk-dim) 67%, transparent 77%,
        var(--silk-lit) 86%, transparent 100%);
      background-size:100% 100%; background-position:0 0}

    /* 11vw is the intent, but the 88px floor was set for a desktop
       viewport: at 390 it is 23% of the screen at the top and again at
       the bottom of every section, so the page reads as mostly gaps.
       Below 700 the floor drops to 56. */
    .section{padding:clamp(88px,11vw,164px) 0}
    .section-dark{background-color:var(--surface-night);color:var(--surface-paper)}
    .section-light{background:var(--surface-paper);color:var(--on-light-1)}
    .section-head{max-width:680px}
    .section-head h2{margin:var(--sp-4) 0 var(--sp-5)}
    .section-head p{max-width:53ch;color:var(--on-light-2);font-size:var(--fs-body);line-height:var(--lh-loose)}
    .section-dark .section-head p{color:var(--on-dark-3)}
    h1,h2,h3,p{margin-top:0}
    h1,h2{font-family:var(--font-display);font-weight:500;letter-spacing:var(--ls-display)}
    h1{font-size:var(--fs-h1);line-height:var(--lh-display);max-width:8ch}
    h2{font-size:var(--fs-h2);line-height:var(--lh-display);max-width:12ch}
    h3{font-size:var(--fs-title);line-height:var(--lh-title);font-weight:600;letter-spacing:var(--ls-title)}

    /* Navigation */
    .site-nav{
      position:fixed;top:0;left:0;right:0;z-index:20;display:flex;align-items:center;justify-content:space-between;
      min-height:var(--nav-h);padding:0 clamp(24px,5vw,56px);
      background-color:transparent;background-image:none;
      color:var(--surface-paper);border-bottom:1px solid transparent;
    }
    .brand{display:inline-flex;align-items:center;gap:var(--sp-3);min-height:44px;text-decoration:none}
    .brand-mark{width:auto;height:32px}
    .brand-word{width:112px;height:auto}
    .nav-right{display:flex;align-items:center;gap:clamp(18px,3vw,42px)}
    .nav-links{display:flex;align-items:center;gap:clamp(18px,2.6vw,34px)}
    .nav-links .menu-cta{display:none}
    @media (max-width:700px){.nav-links .menu-cta{display:flex}}
    .nav-links a{display:inline-flex;align-items:center;min-height:44px;font-size:var(--fs-small);text-decoration:none;color:var(--on-dark-2);transition:color var(--dur-fast) var(--ease-out)}
    .nav-links a{position:relative}
    .nav-links a:not(.menu-cta)::after{content:"";position:absolute;left:0;right:0;bottom:10px;height:1px;
      background:var(--gold);transform:scaleX(0);transform-origin:left;transition:transform var(--dur-base) var(--ease-out)}
    .nav-links a:not(.menu-cta):hover::after{transform:scaleX(1)}
    .nav-links a:hover{color:var(--surface-paper)}
    .nav-cta{min-height:44px;padding:0 var(--sp-4);font-size:var(--fs-nano)}
    .menu-toggle{display:none;width:44px;height:44px;padding:0;border:1px solid var(--gold);background:transparent;color:var(--surface-paper);cursor:pointer}
    .menu-toggle span,.menu-toggle span::before,.menu-toggle span::after{display:block;width:18px;height:1px;margin:auto;background:currentColor;content:"";transition:transform var(--dur-fast) var(--ease-out),opacity var(--dur-fast) var(--ease-out)}
    .menu-toggle span::before{transform:translateY(-6px)}
    .menu-toggle span::after{transform:translateY(5px)}
    .menu-toggle[aria-expanded="true"] span{background:transparent}
    .menu-toggle[aria-expanded="true"] span::before{transform:translateY(0) rotate(45deg)}
    .menu-toggle[aria-expanded="true"] span::after{transform:translateY(-1px) rotate(-45deg)}

    /* Hero: product first, technology second */
    .hero{position:relative;min-height:100svh;display:grid;place-items:center;overflow:hidden;background:var(--surface-night);color:var(--surface-paper)}
    .hero::before{content:"";position:absolute;inset:0;pointer-events:none;background:radial-gradient(circle at 80% 45%,rgba(195,154,74,.12),transparent 27%)}

    .hero-grid{position:relative;z-index:1;display:grid;grid-template-columns:minmax(0,1fr) minmax(360px,1fr);gap:clamp(36px,5vw,72px);align-items:center;padding:clamp(36px,4.4vw,64px) 0}
    .hero-copy{padding:0}
    .hero-copy .eyebrow{margin-bottom:var(--sp-5)}
    .hero-copy h1{margin-bottom:var(--sp-5);max-width:12ch}
    .hero-copy h1 em{color:var(--gold-soft);font-style:italic}
    .hero-lede{max-width:46ch;margin-bottom:var(--sp-6);color:var(--on-dark-2);font-size:var(--fs-lede);line-height:var(--lh-body)}
    .hero-actions{display:flex;align-items:center;gap:var(--sp-4);flex-wrap:wrap}
    /* the qualifier under the CTAs, and a qualifier is a sentence, not a
       statistic. It used to carry .micro, which is the mono/uppercase/
       letterspaced voice the deleted proof strip spoke in — the wrong
       register for the one line that tells a visitor whether to bother.
       It now reads in the body face; .hero-note stays because the atelier
       hero hangs the text-shadow off it. */
    .hero-note{margin-top:var(--sp-5);font-size:var(--fs-small);
      line-height:var(--lh-body);color:var(--on-dark-2)}
    /* Hero product: cut out of its studio backdrop, lit by the page instead of a box */
    .hero-product-wrap{position:relative;display:grid;justify-items:center;gap:var(--sp-6)}
    .hero-stage{--px:0;--py:0;position:relative;width:min(100%,530px);margin-top:-2.5%;perspective:1400px}
    /* Two soft lights: a wide fill that seats the piece in the page, and a tighter key
       behind the shoulders so the rim light on the fabric reads as lighting, not as a cut edge. */
    .hero-stage-light{position:absolute;left:50%;top:46%;width:168%;aspect-ratio:1/1.02;pointer-events:none;
      transform:translate3d(calc(-50% + (var(--px) * 6px)),calc(-50% + (var(--py) * 6px)),0);
      background:radial-gradient(ellipse at 50% 46%,rgba(150,140,128,.17),rgba(150,140,128,.075) 34%,rgba(150,140,128,.022) 56%,rgba(150,140,128,0) 76%)}
    .hero-stage-key{position:absolute;left:50%;top:38%;width:104%;aspect-ratio:1/.62;pointer-events:none;
      transform:translate3d(calc(-50% + (var(--px) * 9px)),calc(-50% + (var(--py) * 8px)),0);
      background:radial-gradient(ellipse at 50% 50%,rgba(186,172,150,.16),rgba(186,172,150,.05) 45%,rgba(186,172,150,0) 72%)}
    .hero-product{position:relative;margin:0;transform-style:preserve-3d;
      transform:translate3d(calc(var(--px) * 15px),calc(var(--py) * 12px),0) rotateY(calc(var(--px) * 2.2deg)) rotateX(calc(var(--py) * -1.8deg))}
    .hero-product picture{position:relative;z-index:1;display:block}
    .hero-product img{display:block;width:100%;height:auto;aspect-ratio:2948/3748}
    /* Contact shadow: a tight dark core right under the hem plus a wider soft spread,
       so the piece sits on a surface instead of floating. */
    .hero-product-shadow{position:absolute;z-index:0;left:50%;bottom:-1.2%;width:44%;height:2.6%;pointer-events:none;
      transform:translate3d(calc(-50% + (var(--px) * 7px)),0,0) scaleX(calc(1 + (var(--py) * .03)));
      background:radial-gradient(ellipse at 50% 50%,rgba(0,0,0,.85),rgba(0,0,0,.45) 42%,rgba(0,0,0,0) 74%);filter:blur(3px)}
    .hero-product-shadow::after{content:"";position:absolute;left:50%;top:50%;width:190%;height:520%;transform:translate(-50%,-42%);
      background:radial-gradient(ellipse at 50% 50%,rgba(0,0,0,.42),rgba(0,0,0,.16) 44%,rgba(0,0,0,0) 72%);filter:blur(12px)}
    .hero-product-meta{display:flex;align-items:baseline;gap:var(--sp-4);color:var(--on-dark-2)}
    .hero-product-meta b{font:500 1.05rem/1 "IBM Plex Mono",monospace;color:var(--gold-soft)}
    .hero-product-meta .micro{color:inherit}
    .hero-product-meta .divider{width:34px;height:1px;background:var(--line-on-dark)}

    /* Three paths */
    .path-grid{margin-top:var(--sp-10);border-top:1px solid var(--line-on-light)}

    .path{display:grid;grid-template-columns:90px minmax(180px,.7fr) minmax(240px,1fr) auto;gap:var(--sp-6);align-items:center;padding:var(--sp-7) 0;border-bottom:1px solid var(--line-on-light);text-decoration:none;transition:padding var(--dur-base) var(--ease-out),color var(--dur-base) var(--ease-out)}
    .path:hover{padding-left:12px;color:var(--gold-ink)}
    .path-index{font-size:var(--fs-micro);color:var(--gold-ink)}
    .path h3{margin:0;font-size:var(--fs-h3);font-weight:500}
    .path p{margin:0;color:var(--on-light-2);font-size:var(--fs-body);line-height:var(--lh-body);max-width:48ch}
    .path-arrow{font-size:var(--fs-lg);color:var(--gold-ink);transition:transform var(--dur-base) var(--ease-out)}
    .path:hover .path-arrow{transform:translate(4px,-4px)}

    /* Collection */
    .collection-head{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--sp-7);margin-bottom:var(--sp-10)}
    .collection-head .section-head{max-width:600px}
    .collection-head .button{margin-bottom:var(--sp-1)}
    /* Collection — one continuous ivory specimen sheet.
       The three pieces share a single field, so they read as one capsule
       instead of three cards. Photography is tone-matched to --plate,
       which is why no frame or divider is needed anywhere. */
    .capsule{border-radius:var(--radius);padding:clamp(30px,3.4vw,58px) clamp(26px,3.2vw,56px) clamp(34px,3.6vw,60px);background:var(--surface-plate);color:var(--on-light-1)}
    .capsule-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-6);
      padding-bottom:var(--sp-3);margin-bottom:clamp(18px,2.2vw,30px);border-bottom:1px solid var(--line-on-light)}
    .capsule-head .micro{color:var(--gold-ink)}
    .capsule-head .capsule-count{color:var(--on-light-2)}
    .specimens{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(22px,3vw,44px)}
    .specimen{display:flex;flex-direction:column;min-width:0}
    .specimen-media{margin:0 0 calc(-1 * var(--sp-3))}
    .specimen-media img{display:block;width:100%;height:auto;aspect-ratio:4/5;border-radius:var(--radius)}
    .specimen-rule{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-3);
      padding-bottom:var(--sp-2);border-bottom:1px solid var(--line-on-light)}
    .specimen-rule .specimen-no{font-family:var(--font-mono);font-size:var(--fs-nano);letter-spacing:var(--ls-micro);color:var(--gold-ink)}
    .specimen-rule .specimen-cat{font-family:var(--font-mono);font-size:var(--fs-nano);letter-spacing:var(--ls-wide);text-transform:uppercase;color:var(--on-light-3)}
    .specimen h3{margin:var(--sp-3) 0 var(--sp-2);font-family:var(--font-display);font-weight:500;
      font-size:var(--fs-h3);line-height:1;letter-spacing:var(--ls-title);color:var(--on-light-1)}
    .specimen-desc{margin:0 0 var(--sp-3);color:var(--on-light-2);font-size:var(--fs-small);line-height:var(--lh-body)}
    .specimen-craft{margin:0 0 var(--sp-4);color:var(--gold-ink)}
    .specimen-details{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-2);margin:0 0 var(--sp-5);padding:0;list-style:none}
    .specimen-details figure{margin:0}
    .specimen-details .art{overflow:hidden;aspect-ratio:1/1;background:var(--surface-plate);border-radius:var(--radius)}
    .specimen-details img{display:block;width:100%;height:100%;object-fit:cover;transition:transform var(--dur-base) var(--ease-out)}
    .specimen-details li:hover img,.specimen-details li:focus-within img{transform:scale(1.06)}
    .specimen-details figcaption{margin-top:var(--sp-2);font-family:var(--font-mono);font-size:var(--fs-nano);letter-spacing:var(--ls-micro);text-transform:uppercase;color:var(--on-light-2)}
    .specimen-cta{display:inline-flex;align-items:center;align-self:flex-start;margin-top:auto;min-height:44px;
      color:var(--on-light-1);font:500 .6rem/1 "IBM Plex Mono",monospace;letter-spacing:var(--ls-micro);text-transform:uppercase;
      text-decoration:none;border-bottom:1px solid var(--gold-ink)}
    .specimen-cta::after{content:"↗";margin-left:var(--sp-2);color:var(--gold-ink);font-size:var(--fs-body);transition:transform var(--dur-fast) var(--ease-out)}
    .specimen-cta:hover::after{transform:translate(3px,-3px)}

    /* ── bento gallery ──────────────────────────────────────────────
       Six columns, and the row height is set to exactly one column
       width. That one decision is what makes the shapes honest:
         tall    2 col x 3 row -> 2:3
         wide    3 col x 2 row -> 3:2
         square  2 col x 2 row -> 1:1
       The crops in tools/mkcollection.py are cut to those same three
       ratios, so object-fit never has to discard any of the garment.
       The row height needs the container's inline size, which is what
       cqw is for; the @supports block below carries browsers without
       container queries.

       Tile shape follows garment shape (docs/next_session.md): a full
       back print gets a tall cell, a chest panel or a flat lay gets a
       wide one, a macro detail gets a square. A tall garment in a wide
       tile is cropped to nothing.                                    */
    /* the frame exists only so the grid has something to measure: an
       element cannot answer its own container query, so putting
       container-type on .bento itself made 100cqw resolve against the
       viewport and every tile came out the wrong shape. */
    .bento-frame{container-type:inline-size;margin:var(--sp-8) 0 0}
    .bento{--bento-gap:clamp(8px,1.1vw,16px);
      display:grid;grid-template-columns:repeat(6,minmax(0,1fr));
      grid-auto-rows:calc((100cqw - 5 * var(--bento-gap)) / 6);
      grid-auto-flow:row dense;gap:var(--bento-gap);
      margin:0;padding:0;list-style:none}
    .bento-cell{min-width:0}
    .bento-cell--tall{grid-column:span 2;grid-row:span 3}
    .bento-cell--wide{grid-column:span 3;grid-row:span 2}
    .bento-cell--square{grid-column:span 2;grid-row:span 2}

    .bento-tile{position:relative;display:block;width:100%;height:100%;
      overflow:hidden;border-radius:var(--radius);background:var(--surface-plate);
      text-decoration:none;color:var(--surface-paper);
      transition:transform var(--dur-base) var(--ease-out)}
    .bento-tile img{display:block;width:100%;height:100%;object-fit:cover;
      transition:transform var(--dur-slow) var(--ease-out)}
    .bento-tile:hover img,.bento-tile:focus-visible img{transform:scale(1.035)}
    .bento-tile:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
    /* the label sits on the photograph, so it carries its own ground */
    .bento-tile::after{content:"";position:absolute;inset:auto 0 0 0;height:58%;
      background:linear-gradient(to top,rgba(10,11,8,.82),rgba(10,11,8,.34) 46%,transparent);
      pointer-events:none}
    .bento-label{position:absolute;left:0;right:0;bottom:0;z-index:1;
      display:flex;flex-direction:column;gap:2px;
      padding:var(--sp-4) var(--sp-4) calc(var(--sp-3) + 2px)}
    .bento-cat{font-family:var(--font-mono);font-size:var(--fs-nano);
      letter-spacing:var(--ls-wide);text-transform:uppercase;color:var(--gold-soft)}
    .bento-name{font-family:var(--font-text);font-size:var(--fs-small);
      font-weight:500;line-height:1.25;color:var(--surface-paper)}
    /* the description is real text in the tile so it is in the document
       for a crawler and a screen reader; the dialog reads it from here
       rather than duplicating it into an attribute */
    .bento-desc{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
      overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

    /* Below 900 the grid halves: a tall cell is still 2:3 but takes half
       the row, and a wide one goes full width. Below 700 the squares pair
       up two to a row rather than sitting alone at full bleed. */
    /* Below 901 a tile is one column wide instead of two, and the row unit
       has to halve with it: a square is then 1 col x 2 rows, so the row is
       half a column rather than a whole one. Getting that wrong is what
       rendered a 2:3 tile at 0.32 the first time -- three whole columns of
       height for something that should be one and a half. For n columns the
       row is R = (100cqw - (2n-1) * gap) / 2n; three columns and six happen
       to land on the same expression.
         square  1 col x 2 row -> 1:1   exactly
         tall    1 col x 3 row -> 0.66  (2:3, exact to half a gap)
         wide    2 col x 3 row -> 1.33  (the 3:2 crop gives up ~11% of its
                                         width here; the alternative is a
                                         2:1 letterbox, which gives up more) */
    @media (max-width:900px){
      .bento{grid-template-columns:repeat(3,minmax(0,1fr));
        grid-auto-rows:calc((100cqw - 5 * var(--bento-gap)) / 6)}
      .bento-cell--tall{grid-column:span 1;grid-row:span 3}
      .bento-cell--wide{grid-column:span 2;grid-row:span 3}
      .bento-cell--square{grid-column:span 1;grid-row:span 2}
    }
    @media (max-width:700px){
      .bento{grid-template-columns:repeat(2,minmax(0,1fr));
        grid-auto-rows:calc((100cqw - 3 * var(--bento-gap)) / 4)}
      .bento-cell--tall{grid-column:span 1;grid-row:span 3}
      .bento-cell--wide{grid-column:span 2;grid-row:span 3}
      .bento-cell--square{grid-column:span 1;grid-row:span 2}
      .bento-label{padding:var(--sp-3)}
    }
    /* Without container queries there is no way to say "row height = one
       column", so the tiles carry their own ratio and the grid stops
       trying to interlock. Everything is still there, still legible,
       still clickable; it just reads as a plain gallery. */
    @supports not (container-type:inline-size){
      .bento{grid-auto-rows:auto}
      .bento-frame{margin-top:var(--sp-8)}
      .bento-cell--tall .bento-tile{aspect-ratio:2/3}
      .bento-cell--wide .bento-tile{aspect-ratio:3/2}
      .bento-cell--square .bento-tile{aspect-ratio:1/1}
      .bento-cell{grid-row:span 1 !important}
    }

    /* ── the piece dialog ───────────────────────────────────────────
       Native <dialog>, so the focus trap, the Escape key and the inert
       background are the browser's job rather than ours.            */
    .piece-dialog{width:min(920px,calc(100vw - 2 * var(--sp-5)));max-width:none;
      padding:0;border:0;border-radius:var(--radius);overflow:hidden;
      background:var(--surface-plate);color:var(--on-light-1)}
    .piece-dialog::backdrop{background:rgba(10,11,8,.72)}
    .piece-dialog[open]{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr)}
    .piece-media{margin:0;background:var(--surface-night)}
    .piece-media img{display:block;width:100%;height:100%;max-height:76vh;object-fit:cover}
    .piece-body{display:flex;flex-direction:column;align-items:flex-start;
      gap:var(--sp-3);padding:clamp(22px,2.6vw,36px)}
    .piece-body h3{margin:0;font-size:var(--fs-lg);font-weight:500}
    .piece-cat{color:var(--gold-ink)}
    .piece-desc{margin:0;color:var(--on-light-2);font-size:var(--fs-body);
      line-height:var(--lh-body)}
    .piece-made{margin:0;padding-top:var(--sp-3);border-top:1px solid var(--line-on-light);
      color:var(--on-light-3);font-size:var(--fs-small);line-height:var(--lh-body)}
    .piece-cta{margin-top:var(--sp-2)}
    /* The close control sits on the cream panel at desktop and over the
       photograph once the dialog stacks, so it cannot take its colour from
       either. It carries its own dark disc instead -- as ivory-on-transparent
       it was invisible against the panel, on the one control that closes
       the dialog. The 44px target stays; only the disc is smaller. */
    .piece-close-form{position:absolute;top:0;right:0;z-index:2;margin:var(--sp-2)}
    .piece-close{display:grid;place-items:center;width:36px;height:36px;
      border:0;border-radius:50%;background:rgba(10,11,8,.62);
      color:var(--surface-paper);font-size:22px;line-height:1;cursor:pointer;
      transition:background var(--dur-base) var(--ease-out)}
    .piece-close:hover{background:rgba(10,11,8,.82)}
    .piece-close:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
    @media (max-width:760px){
      .piece-dialog[open]{grid-template-columns:1fr;max-height:88vh;overflow:auto}
      .piece-media img{max-height:44vh}
      .piece-close{color:var(--surface-paper)}
    }

    /* Process */
    .process-layout{display:grid;grid-template-columns:minmax(240px,.7fr) minmax(0,1.3fr);gap:clamp(50px,10vw,160px);align-items:start}
    .process-list{border-top:1px solid var(--line-on-light)}
    .process-step{display:grid;grid-template-columns:64px 1fr;gap:var(--sp-5);padding:var(--sp-6) 0;border-bottom:1px solid var(--line-on-light)}
    .process-index{font-size:var(--fs-nano);color:var(--gold-ink)}
    .process-step h3{margin-bottom:var(--sp-2);font-size:var(--fs-lg);font-weight:500}
    .process-step p{margin:0;max-width:45ch;color:var(--on-light-2);font-size:var(--fs-body);line-height:var(--lh-body)}
    .process-aside{position:sticky;top:112px}
    .aside-card{margin-top:var(--sp-7);padding:var(--sp-6);background:var(--surface-night);color:var(--surface-paper);border-radius:var(--radius)}
    .aside-card p{margin:var(--sp-4) 0 0;color:var(--on-dark-3);font-size:var(--fs-small);line-height:var(--lh-loose)}
    .aside-rule{height:1px;margin:var(--sp-6) 0;background:var(--line-on-dark)}
    .aside-facts{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3)}
    .aside-fact strong{display:block;margin-bottom:var(--sp-1);color:var(--gold-soft);font:500 1.05rem/1 "IBM Plex Mono",monospace}
    .aside-fact span{color:var(--on-dark-3);font-size:var(--fs-micro);line-height:var(--lh-body)}

    /* Custom work */
    .custom-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(30px,7vw,110px);align-items:center}
    .custom-copy h2{max-width:6ch}
    .custom-copy p{max-width:45ch;color:var(--on-dark-3);font-size:var(--fs-body);line-height:var(--lh-loose)}
    .custom-list{display:grid;grid-template-columns:1fr 1fr;gap:1px;margin-top:var(--sp-7);background:var(--line-on-dark);border:1px solid var(--line-on-dark)}
    .custom-list span{padding:var(--sp-3);background:var(--surface-night);color:var(--surface-paper);font-size:var(--fs-small)}
    .custom-quote{position:relative;max-width:22ch;margin:var(--sp-10) 0 0;padding:var(--sp-1) 0 var(--sp-1) var(--sp-8);border-left:1px solid var(--gold);font-family:var(--font-display);font-size:var(--fs-quote);font-style:italic;line-height:var(--lh-title);color:var(--surface-paper)}
    .custom-quote::before{content:"“";position:absolute;top:-6px;left:-20px;padding:0 var(--sp-2);background:var(--surface-night);color:var(--gold);font-size:var(--fs-h3);font-style:normal;line-height:1}

    .offer-grid{display:grid;grid-template-columns:1fr 1fr;gap:1px;margin-top:var(--sp-9);background:var(--line-on-dark);border:1px solid var(--line-on-dark);border-radius:var(--radius);overflow:hidden}
    .offer{display:flex;flex-direction:column;padding:var(--sp-7) var(--sp-7) var(--sp-7);background:var(--surface-night)}
    .offer-index{margin-bottom:var(--sp-4);font-family:var(--font-mono);font-size:var(--fs-nano);letter-spacing:var(--ls-micro);color:var(--gold-soft)}
    .offer h3{margin-bottom:var(--sp-3);font-family:var(--font-display);font-size:var(--fs-h3);font-weight:500;letter-spacing:var(--ls-title);color:var(--surface-paper)}
    .offer > p{margin:0 0 var(--sp-5);max-width:42ch;color:var(--on-dark-3);font-size:var(--fs-body);line-height:var(--lh-loose)}
    .offer-list{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-2) var(--sp-4);margin:0 0 var(--sp-6);padding:0;list-style:none}
    .offer-list li{position:relative;padding-left:16px;color:var(--surface-paper);font-size:var(--fs-small);line-height:var(--lh-body)}
    .offer-list li::before{content:"";position:absolute;left:0;top:.6em;width:6px;height:1px;background:var(--gold-soft)}
    .offer .button{margin-top:auto;align-self:flex-start}
    .enquiry-note{margin:var(--sp-6) 0 0;color:var(--on-dark-3);font-size:var(--fs-small);line-height:var(--lh-body)}
    .collection-note{margin:0 0 var(--sp-8);padding:var(--sp-3) 0 0;border-top:1px solid var(--line-on-dark);color:var(--on-dark-3);font-size:var(--fs-small);line-height:var(--lh-body)}

    /* Contact */
    .contact{padding:clamp(100px,13vw,190px) 0;background:var(--surface-night-soft);color:var(--surface-paper);
      border-top:1px solid var(--line-on-dark);border-bottom:1px solid var(--line-on-dark)}
    .contact-grid{display:grid;grid-template-columns:1fr auto;gap:var(--sp-8);align-items:end}
    .contact h2{max-width:7ch;margin-bottom:var(--sp-5)}
    .contact p{max-width:44ch;margin:0;color:var(--on-dark-2);font-size:var(--fs-body);line-height:var(--lh-loose)}
    .contact .button{margin-bottom:var(--sp-1);border-color:var(--surface-night);color:var(--surface-night)}
    .contact .button:hover{background:var(--gold);color:var(--surface-night)}

    /* Footer */
    footer{padding:var(--sp-7) 0 var(--sp-6);background-color:var(--surface-night);color:var(--surface-paper)}
    .footer-row{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-7);padding-bottom:var(--sp-7);border-bottom:1px solid var(--line-on-dark)}
    .footer-brand{display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-4) var(--sp-6)}
    .footer-lockup{display:grid;gap:var(--sp-3);justify-items:start}
    .footer-signature{display:flex;align-items:center;gap:var(--sp-3)}
    .footer-signature .brand-mark{height:34px}
    .footer-word{width:132px;height:auto}
    /* the tagline is set as type, not artwork: as an image it renders ~4px tall */
    .footer-tagline{display:flex;align-items:center;gap:var(--sp-3);margin:0;
      font-family:var(--font-mono);font-size:var(--fs-nano);letter-spacing:var(--ls-wide);
      text-transform:uppercase;color:var(--gold);white-space:nowrap}
    .footer-tagline::before,.footer-tagline::after{content:"";width:26px;height:1px;background:currentColor;opacity:.7}
    .footer-brand span{color:var(--on-dark-3);font-size:var(--fs-small)}
    /* six links now, so the row must be allowed to wrap */
    .footer-contact{display:flex;flex-direction:column;gap:var(--sp-2)}
    /* ══ SOCIAL RAIL ═════════════════════════════════════════════════
       One raised plate holding the three social accounts as glyphs.
       Hover and keyboard focus drive the same four things: the plate
       lights, the glyph rises to full ink, a rule draws under it, and
       the account is named above. No JS — :hover and :focus-visible do
       all of it, so it works before site.js runs and with it disabled. */
    .social-rail{display:flex;align-items:center;gap:var(--sp-2);
      padding:var(--sp-2);border:1px solid var(--line-on-dark);
      border-radius:var(--radius);background:var(--surface-night-soft)}
    /* 44px, not 40: these were the smallest targets on the page and sat
       4px apart, which is a mis-tap waiting to happen. The glyph inside
       is unchanged; only the box it sits in grew. */
    .social-dot{position:relative;display:flex;align-items:center;justify-content:center;
      width:var(--tap-min);height:var(--tap-min);border-radius:var(--radius);text-decoration:none}
    .social-dot::before{content:"";position:absolute;inset:var(--sp-1);
      border-radius:var(--radius);background:var(--fill-on-dark);
      opacity:0;transform:scale(.9);
      transition:opacity var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out)}
    .social-glyph{position:relative;z-index:1;display:block;color:var(--on-dark-3);
      transition:color var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out)}
    .social-glyph svg{display:block;width:18px;height:18px}
    .social-underline{position:absolute;bottom:var(--sp-1);left:50%;translate:-50% 0;
      width:0;height:2px;border-radius:var(--radius);background:var(--on-dark-1);opacity:0;
      transition:width var(--dur-base) var(--ease-out),opacity var(--dur-base) var(--ease-out)}
    .social-tip{position:absolute;bottom:calc(100% + var(--sp-2));left:50%;translate:-50% var(--sp-1);
      padding:var(--sp-1) var(--sp-2);border-radius:var(--radius);
      background:var(--surface-paper);color:var(--on-light-1);
      font-family:var(--font-mono);font-size:var(--fs-nano);
      text-transform:uppercase;letter-spacing:var(--ls-micro);line-height:var(--lh-title);
      white-space:nowrap;opacity:0;pointer-events:none;
      transition:opacity var(--dur-base) var(--ease-out),translate var(--dur-base) var(--ease-out)}
    .social-tip::after{content:"";position:absolute;top:100%;left:50%;
      width:var(--sp-2);height:var(--sp-2);
      background:var(--surface-paper);translate:-50% -50%;rotate:45deg}
    .social-dot:hover::before,.social-dot:focus-visible::before{opacity:1;transform:scale(1)}
    .social-dot:hover .social-glyph,.social-dot:focus-visible .social-glyph{color:var(--on-dark-1);transform:scale(1.1)}
    .social-dot:hover .social-underline,.social-dot:focus-visible .social-underline{width:var(--sp-3);opacity:1}
    .social-dot:hover .social-tip,.social-dot:focus-visible .social-tip{opacity:1;translate:-50% 0}

    .footer-mail a{color:inherit;text-decoration:none;border-bottom:1px solid var(--line-on-dark);padding-bottom:2px}
    .footer-mail a:hover{color:var(--gold-soft);border-bottom-color:currentColor}
    .footer-side{display:flex;align-items:center;gap:var(--sp-7)}
    .footer-links{display:flex;flex-wrap:wrap;gap:0 var(--sp-6);
      color:var(--on-dark-3);font-size:var(--fs-small)}
    .footer-links a{display:inline-flex;align-items:center;min-height:44px;text-decoration:none}
    .footer-links a:hover{color:var(--gold-soft)}
    .footer-meta{display:flex;justify-content:space-between;gap:var(--sp-6);padding-top:var(--sp-5);color:var(--on-dark-3);font-size:var(--fs-nano)}

    html.js [data-reveal]{opacity:0;transform:translateY(18px);transition:opacity var(--dur-slow) var(--ease-out),transform var(--dur-slow) var(--ease-out)}
    html.js [data-reveal].is-visible{opacity:1;transform:none}

    @media (min-width:901px) and (max-height:940px){
      .hero-grid{padding:var(--sp-6) 0}
      :root{--fs-h1:clamp(3.2rem,5.4vw,5.4rem)}
      .hero-copy .eyebrow{margin-bottom:var(--sp-3)}
      .hero-copy h1{margin-bottom:var(--sp-4)}
      :root{--fs-lede:.96rem}
      .hero-note{margin-top:var(--sp-3)}
      .hero-product-wrap{gap:var(--sp-4)}
      .hero-stage{width:min(100%,425px)}
    }
    @media (max-width:900px){
      .hero-grid{grid-template-columns:1fr;gap:var(--sp-9)}
      .hero-copy{max-width:620px}
      .hero-product-wrap{justify-items:center}
      .hero-stage{width:min(84%,490px)}
      .path{grid-template-columns:64px minmax(170px,.8fr) 1fr auto}
      .process-layout{grid-template-columns:1fr;gap:var(--sp-9)}
      .process-aside{position:static}
      .custom-grid{grid-template-columns:1fr;gap:var(--sp-9)}
      .offer-grid{grid-template-columns:1fr}
    }
    @media (max-width:700px){
      :root{--nav-h:64px}
      .wrap{width:min(var(--measure-max),calc(100% - 40px))}
      .site-nav{padding:0 var(--sp-5)}
      .brand-mark{height:26px}
      .brand-word{width:92px}
      .nav-right{gap:var(--sp-2)}
      .nav-cta{display:none}
      .menu-toggle{display:block}
      .nav-links{position:absolute;top:64px;left:0;right:0;display:grid;gap:0;padding:var(--sp-2) var(--sp-5) var(--sp-5);background:var(--surface-night);border-bottom:1px solid var(--line-on-dark);transform:translateY(-12px);opacity:0;pointer-events:none;transition:opacity var(--dur-fast) var(--ease-out),transform var(--dur-fast) var(--ease-out)}
      .nav-links.is-open{transform:none;opacity:1;pointer-events:auto}
      .nav-links a{padding:var(--sp-4) 0;border-bottom:1px solid var(--line-on-dark);font-size:var(--fs-small)}
      .nav-links a:last-child{border-bottom:0}
      .menu-cta{color:var(--gold-soft)}
      .hero{min-height:auto}
      .hero-grid{padding:var(--sp-7) 0 var(--sp-8);gap:var(--sp-6)}
      :root{--fs-h1:clamp(2.8rem,12.4vw,4rem)}
      h1{line-height:.9}
      :root{--fs-h2:clamp(2.6rem,11vw,3.6rem)}
      h2{line-height:.92}
      .hero-copy .eyebrow{margin-bottom:var(--sp-3)}
      .hero-copy h1{margin-bottom:var(--sp-4)}
      :root{--fs-lede:.92rem}
      .hero-lede{line-height:var(--lh-body);margin-bottom:var(--sp-5)}
      .hero-note{margin-top:var(--sp-3)}
      .section{padding:clamp(56px,13vw,88px) 0}

      /* Two full-width boxes one above the other, both dark, both with a
         pale edge — at this size the metal ring is too fine to separate
         them and neither reads as the primary. The secondary drops its
         box and becomes what it is: a link. */
      .hero-actions{align-items:stretch;flex-direction:column;gap:var(--sp-3)}
      .hero-actions .button-solid{width:100%}
      .hero-actions .button-quiet{width:auto;align-self:flex-start;
        min-height:44px;padding:0;border:none;background:none;
        color:var(--on-dark-2);text-decoration:underline;
        text-underline-offset:5px;text-decoration-thickness:1px}
      .hero-actions .button-quiet:hover{color:var(--gold-soft)}
      .hero-stage{width:100%}
      .hero-product{transform:none}
      .hero-product-meta{gap:var(--sp-3)}
      .collection-head{display:block;margin-bottom:var(--sp-8)}
      .collection-head .button{margin-top:var(--sp-6)}
      .specimens{grid-template-columns:1fr;gap:clamp(34px,6vw,52px)}
      .specimen-media{margin-bottom:var(--sp-4)}
      .specimen-details{max-width:420px}
      .path{grid-template-columns:46px 1fr 20px;gap:var(--sp-3);padding:var(--sp-6) 0}
      .path p{grid-column:2 / -1;font-size:var(--fs-small)}
      .path-arrow{grid-column:3;grid-row:1}
      .custom-list{grid-template-columns:1fr}
      .offer{padding:var(--sp-6) var(--sp-5)}
      .offer-list{grid-template-columns:1fr}
      .custom-quote{margin:var(--sp-3) 0;padding-left:28px}
      .contact-grid{grid-template-columns:1fr;align-items:start}
      .contact .button{width:100%;margin-top:var(--sp-6)}
      .footer-row{align-items:flex-start;flex-direction:column}
      .footer-brand{flex-direction:column;align-items:flex-start;gap:var(--sp-4)}
      .footer-side{flex-direction:column;align-items:flex-start;gap:var(--sp-5)}
      .footer-links{flex-wrap:wrap;gap:var(--sp-3) var(--sp-5)}
      .footer-meta{display:block;line-height:var(--lh-loose)}
      .footer-meta span{display:block}
    }


    /* ── type systems ───────────────────────────────────────────── */
    :root[data-type="wide"]{   /* heavy grotesque, wide — Fear of God register */
      --font-display:"Archivo Black","Archivo",system-ui,sans-serif;
      --font-text:"Newsreader",Georgia,serif;
      --display-case:uppercase; --display-ls:-.025em; --display-lh:.92; --display-weight:400;
    }
    :root[data-type="condensed"]{  /* tall condensed caps — poster register */
      --font-display:"Anton","Archivo Narrow",system-ui,sans-serif;
      --font-text:"Newsreader",Georgia,serif;
      --display-case:uppercase; --display-ls:.005em; --display-lh:.9; --display-weight:400;
    }
    :root[data-type="serif"]{      /* the current build, kept for comparison */
      --font-display:"Cormorant Garamond",Georgia,serif;
      --font-text:"DM Sans",ui-sans-serif,system-ui,sans-serif;
      --display-case:none; --display-ls:-.045em; --display-lh:.86; --display-weight:500;
    }
    h1,h2{text-transform:var(--display-case);letter-spacing:var(--display-ls);
      line-height:var(--display-lh);font-weight:var(--display-weight)}
    :root[data-type="wide"] h1,:root[data-type="condensed"] h1{max-width:14ch}
    :root[data-type="wide"] h2,:root[data-type="condensed"] h2{max-width:16ch}
    :root[data-type="wide"] .hero-copy h1 em,:root[data-type="condensed"] .hero-copy h1 em{font-style:normal}
    :root[data-type="wide"] .specimen h3,:root[data-type="condensed"] .specimen h3,
    :root[data-type="wide"] .path h3,:root[data-type="condensed"] .path h3,
    :root[data-type="wide"] .offer h3,:root[data-type="condensed"] .offer h3{
      font-family:var(--font-display);text-transform:uppercase;letter-spacing:-.01em;font-weight:400}
    :root[data-type="wide"] .custom-quote,:root[data-type="condensed"] .custom-quote{
      font-family:var(--font-display);font-style:normal;text-transform:uppercase;letter-spacing:-.02em;line-height:.98}

    /* ── editorial grid ─────────────────────────────── */
    /* the grid only exists above 900px; below that the template stack is correct */
    @media (min-width:901px){
      :root[data-layout="grid"] .hero-grid{
        display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:0 var(--sp-6);align-items:center}
      :root[data-layout="grid"] .hero-copy{grid-column:1 / span 6}
      :root[data-layout="grid"] .hero-product-wrap{grid-column:7 / span 6;justify-items:end}
      :root[data-layout="grid"] .hero-stage{width:min(100%,560px)}
      /* the paths section steps in from the margin instead of sitting dead centre */
      :root[data-layout="grid"] #paths .section-head{margin-left:8.333%}
      :root[data-layout="grid"] #paths .path-list{margin-left:8.333%}
      /* the collection head puts the CTA on its own column, not floated opposite */
      :root[data-layout="grid"] .collection-head{
        display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--sp-6);align-items:end}
      :root[data-layout="grid"] .collection-head .section-head{grid-column:1 / span 7}
      :root[data-layout="grid"] .collection-head .button{grid-column:10 / span 3;justify-self:end}
      :root[data-layout="grid"] .collection-note{margin-left:8.333%;max-width:56ch}
      /* the process aside breaks the container and bleeds toward the edge */
      :root[data-layout="grid"] .process-layout{grid-template-columns:minmax(0,4fr) minmax(0,8fr)}
    }


    /* ══ PREMIUM MOTION LAYER ═══════════════════════════════════════ */

    /* 1 ── intro curtain: one 1.6s opening, once per session */
        /* the curtain only exists when the script can lift it — without JS the
       page must never be left behind a black overlay */
    .intro{display:none}
    html.js .intro{position:fixed;inset:0;z-index:120;
      display:grid;place-items:center;overflow:hidden}
    /* author styles beat the UA [hidden] rule, so display must be reset
       explicitly — without this the finished curtain stays over the page and
       swallows every click on the site. */
    .intro[hidden],html.js .intro[hidden]{display:none!important}
    .intro.is-lifting{pointer-events:none}
    .intro-mark{position:relative;z-index:1;width:clamp(76px,9vw,128px);height:auto;overflow:visible}
    .intro-mark path{fill:transparent;stroke:var(--surface-paper);stroke-width:9;
      stroke-linejoin:round;
      stroke-dasharray:var(--len,3000);stroke-dashoffset:var(--len,3000);
      transition:stroke-dashoffset 1100ms cubic-bezier(.5,0,.2,1),fill 420ms ease 780ms}
    .intro-mark .g-gold path{stroke:var(--gold)}
    .intro.is-drawing .intro-mark path{stroke-dashoffset:0;fill:var(--surface-paper)}
    .intro.is-drawing .intro-mark .g-gold path{fill:var(--gold)}
    .intro-curtain{position:absolute;inset:0;z-index:0;background:var(--surface-night);
      transform-origin:top;transition:transform 900ms cubic-bezier(.76,0,.24,1)}
    .intro.is-lifting .intro-curtain{transform:scaleY(0)}
    .intro.is-lifting .intro-mark{opacity:0;transform:translateY(-14px) scale(.94);
      transition:opacity 380ms ease,transform 520ms cubic-bezier(.5,0,.2,1)}
    /* the page underneath holds still until the curtain starts to lift */
    html.intro-active,html.intro-active body{overflow:hidden}

    /* 2 ── kinetic type: every display line rises out of its own mask */
    .msk{display:inline-block;overflow:hidden;vertical-align:bottom;
      padding-bottom:.09em;margin-bottom:-.09em}
    .msk-i{display:inline-block;transform:translateY(112%);opacity:0;
      transition:transform 940ms cubic-bezier(.16,1,.3,1),opacity 520ms linear;
      transition-delay:var(--d,0ms)}
    .is-typed .msk-i{transform:none;opacity:1}

    /* 3 ── marquee: a slow, continuous strip that keeps the page alive */
    .marquee{--speed:46s;position:relative;overflow:hidden;
      border-block:1px solid var(--line-on-dark);
      background:var(--surface-night);color:var(--on-dark-2);
      padding:var(--sp-5) 0;
      -webkit-mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent);
      mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent)}
    .marquee-light{background:var(--surface-paper);color:var(--on-light-2);
      border-color:var(--line-on-light)}
    .marquee-track{display:flex;width:max-content;
      animation:marquee var(--speed) linear infinite}
    .marquee:hover .marquee-track{animation-play-state:paused}
    .marquee-set{display:flex;flex:none;align-items:center}
    .marquee-set span{display:inline-flex;align-items:center;gap:var(--sp-6);
      padding-inline:var(--sp-6);white-space:nowrap;
      font-family:var(--font-mono);font-size:var(--fs-micro);
      letter-spacing:var(--ls-wide);text-transform:uppercase}
    .marquee-set span::after{content:"";width:5px;height:5px;flex:none;
      background:currentColor;opacity:.45;transform:rotate(45deg)}
    @keyframes marquee{to{transform:translateX(-50%)}}

    /* 4 ── the nav inverts with the section behind it */
    .site-nav{transition:background var(--dur-slow) var(--ease-out),
      color var(--dur-slow) var(--ease-out),border-color var(--dur-slow) var(--ease-out)}
    .site-nav.is-compact.on-light{background:var(--surface-paper);color:var(--on-light-1);
      border-bottom-color:var(--line-on-light)}
    .site-nav.is-compact.on-light .nav-links a{color:var(--on-light-2)}
    .site-nav.is-compact.on-light .nav-links a:hover{color:var(--on-light-1)}
    .site-nav.is-compact.on-light .brand-mark{--logo-ink:#1d211b}
    .site-nav.is-compact.on-light .brand-word{filter:invert(1) brightness(.22)}
    .site-nav.is-compact.on-light .menu-toggle span,
    .site-nav.is-compact.on-light .menu-toggle span::before,
    .site-nav.is-compact.on-light .menu-toggle span::after{background:var(--on-light-1)}
    /* each section boundary fades instead of butting flat against the next */
    .section-light::before,.section-dark::before{content:"";position:absolute;
      left:0;right:0;top:0;height:110px;pointer-events:none}
    .section-light::before{background:linear-gradient(var(--surface-night),transparent);opacity:.05}
    .section-dark::before{background:linear-gradient(rgba(0,0,0,.55),transparent);opacity:.6}

    /* 5 ── the process pins and tracks which step you are reading */
    .process-aside{transition:none}
    .process-progress{margin-top:var(--sp-7);display:flex;align-items:center;gap:var(--sp-4)}
    .process-progress-rail{position:relative;flex:1;height:2px;background:var(--line-on-light)}
    .process-progress-fill{position:absolute;inset:0 auto 0 0;width:25%;
      background:var(--on-light-1);transition:width 620ms cubic-bezier(.16,1,.3,1)}
    .process-progress-count{font-family:var(--font-mono);font-size:var(--fs-micro);
      letter-spacing:var(--ls-micro);color:var(--on-light-2);font-variant-numeric:tabular-nums}
    .process-step{position:relative}
    /* the read step stays lit, the rest recede — beats [data-reveal] on specificity */
    html.js .process-step[data-reveal].is-visible{opacity:.34;
      transition:opacity 460ms var(--ease-out)}
    html.js .process-step[data-reveal].is-visible.is-active,
    html.js .process-step[data-reveal].is-visible.is-past{opacity:1}
    .process-step::before{content:"";position:absolute;left:0;top:-1px;width:0;height:2px;
      background:var(--on-light-1);transition:width 620ms cubic-bezier(.16,1,.3,1)}
    .process-step.is-active::before{width:100%}

    /* the product settles into place once the curtain is gone */
    html.js .hero-product-wrap{opacity:0;transform:translate3d(0,26px,0) scale(.975);
      transition:opacity 900ms var(--ease-out) 180ms,
                 transform 1200ms cubic-bezier(.16,1,.3,1) 180ms}
    html.js .hero.is-typed .hero-product-wrap{opacity:1;transform:none}

    /* 6 ── scale contrast: one oversized word behind the product */
    .hero-ghost{position:absolute;z-index:0;right:-6%;top:50%;
      transform:translate3d(calc(var(--px,0)*-9px),calc(-50% + var(--py,0)*-6px),0);
      font-family:var(--font-display);font-weight:var(--display-weight,400);
      text-transform:uppercase;letter-spacing:-.05em;line-height:.8;
      font-size:clamp(9rem,21vw,20rem);white-space:nowrap;pointer-events:none;
      color:transparent;-webkit-text-stroke:1px rgba(238,233,223,.085);
      opacity:0;transition:opacity 1400ms var(--ease-out) 300ms}
    .hero.is-typed .hero-ghost{opacity:1}
    /* the headline is allowed to run past its column and over the product */
    @media (min-width:1100px){
      .hero-copy h1{max-width:none;width:126%;position:relative;z-index:2}
    }

    @media (max-width:900px){
      .hero-ghost{font-size:clamp(6rem,30vw,11rem);right:-14%}
      .process-progress{display:none}
      html.js .process-step{opacity:1}
    }
    @media (prefers-reduced-motion:reduce){
      html.js .hero-product-wrap{opacity:1;transform:none;transition:none}
      html.js .process-step[data-reveal].is-visible{opacity:1}
      .marquee-track{animation:none}
      .msk-i{transform:none;opacity:1;transition:none}
      .intro{display:none}
      .hero-ghost{opacity:1;transition:none}
      .process-step::before{transition:none}
    }





    /* ══ PHASE A — CONTEMPORARY ATELIER PRECISION ═══════════════════
       Header, CTA and credentials rail as one system.
       The thread motif appears three times and no more:
         1. the navigation underline
         2. the sweep inside the CTA
         3. the separator rule in the rail
       ═══════════════════════════════════════════════════════════════ */

    /* ── header ─────────────────────────────────────────────────── */
    /* The surface fades only while compact: in when the header leaves the
       top, and between dark and paper as sections pass. Back at the top it
       cuts straight to transparent. When it faded out too, a quick return
       from a paper section (Home, the logo, a flick) reached scroll 0 with
       the paper background still on screen over the hero for --dur-slow,
       and for far longer in a throttled background tab. */
    .site-nav{transition:min-height var(--dur-slow) var(--ease-out)}
    .site-nav.is-compact{transition:min-height var(--dur-slow) var(--ease-out),
      background var(--dur-slow) var(--ease-out),
      border-color var(--dur-slow) var(--ease-out)}
    .site-nav{border-bottom:1px solid transparent}
    .site-nav.is-compact{min-height:64px;border-bottom-color:var(--line-on-dark);
      background-color:rgba(21,22,18,.96);
      background-image:linear-gradient(100deg,
        transparent 0%, var(--silk-lit) 9%, transparent 19%,
        var(--silk-dim) 28%, transparent 38%,
        var(--silk-lit) 47%, transparent 57%,
        var(--silk-dim) 67%, transparent 77%,
        var(--silk-lit) 86%, transparent 100%);
      background-size:100% 100%}
    .site-nav.is-compact .brand-mark{height:23px}
    .site-nav.is-compact .brand-word{width:100px}

    /* navigation reads as fashion, not as a toolbar: the interface face at
       a comfortable size, sentence case, no letter-spacing theatrics */
    .nav-links a{position:relative;padding:10px 0;
      font-family:var(--font-text);font-size:15px;font-weight:500;
      letter-spacing:-.005em;text-transform:none;color:var(--on-dark-2);
      transition:color var(--dur-base) var(--ease-out)}
    .nav-links a:hover,.nav-links a:focus-visible{color:var(--on-dark-1)}
    /* vertical character roll — two stacked copies inside one mask */
    .roll{display:block;overflow:hidden;position:relative}
    .roll > span{display:block;transition:transform var(--dur-slow) var(--ease-out)}
    .roll > span + span{position:absolute;inset:0;transform:translateY(100%)}
    .nav-links a:hover .roll > span,
    .nav-links a:focus-visible .roll > span{transform:translateY(-100%)}
    .nav-links a:hover .roll > span + span,
    .nav-links a:focus-visible .roll > span + span{transform:translateY(0)}
    /* THREAD 1 — one hair thick, drawn from the left */
    .nav-links a:not(.menu-cta)::after{content:"";position:absolute;
      left:0;right:0;bottom:4px;height:1px;background:var(--gold);opacity:.75;
      transform:scaleX(0);transform-origin:left;
      transition:transform var(--dur-slow) var(--ease-out)}
    .nav-links a:hover::after,.nav-links a:focus-visible::after{transform:scaleX(1)}
    .nav-links a:focus-visible .roll{box-shadow:0 0 0 1px rgba(238,233,223,.28)}

    /* ── CTA ────────────────────────────────────────────────────── */
    /* one silhouette: solid ivory, no border, no stitched frame */
    .nav-cta{position:relative;overflow:hidden;
      background:var(--surface-paper);color:var(--surface-night)!important;
      border:0!important;padding:13px 20px 13px 22px;
      font-size:12.5px;font-weight:600;letter-spacing:.085em;
      transition:background var(--dur-base) var(--ease-out)}
    .nav-cta:hover,.nav-cta:focus-visible{background:var(--gold-soft)}
    .nav-cta::after{position:relative;z-index:1;
      transition:transform var(--dur-base) var(--ease-out)}
    .nav-cta:hover::after,.nav-cta:focus-visible::after{transform:translate(3px,-3px)}
    /* THREAD 2 — a single hair sweeps through and leaves. It ran at a raw
       640ms, which broke rule 3 and, next to a 220ms colour change, left
       the hover resolving in two speeds. --dur-sweep is its own token
       rather than --dur-slow because this is a flourish that trails the
       gesture, not a surface that opens. */
    .nav-cta > .cta-thread{position:absolute;left:0;top:50%;width:45%;height:1px;
      background:linear-gradient(90deg,transparent,var(--surface-night),transparent);
      opacity:0;transform:translateX(-110%);pointer-events:none}
    .nav-cta:hover > .cta-thread,.nav-cta:focus-visible > .cta-thread{
      animation:cta-sweep var(--dur-sweep) var(--ease-out) forwards}
    @keyframes cta-sweep{
      0%{opacity:0;transform:translateX(-110%)}
      18%{opacity:.55} 82%{opacity:.55}
      100%{opacity:0;transform:translateX(330%)}}

    /* ── credentials rail (atmosphere) ──────────────────────────── */
    /* the atmosphere line, so it is deliberately unhurried: sentence case,
       the interface face, larger than the nav it sits under */
    .marquee{--rail-fade:linear-gradient(90deg,transparent 0,rgba(0,0,0,.22) 7%,
        #000 22%,#000 78%,rgba(0,0,0,.22) 93%,transparent 100%);
      -webkit-mask-image:var(--rail-fade);mask-image:var(--rail-fade);
      padding:19px 0}
    .marquee-set span{font-family:var(--font-text);font-size:17px;font-weight:400;
      letter-spacing:-.004em;text-transform:none;padding-inline:0;gap:0;
      color:var(--on-dark-2)}
    .marquee-light .marquee-set span{color:var(--on-light-2)}
    /* THREAD 3 — the separator rule */
    .marquee-set span::after{content:"";width:30px;height:1px;flex:none;
      margin:0 34px;background:var(--line-on-dark);
      opacity:1;transform:none}
    .marquee-light .marquee-set span::after{background:var(--line-on-light)}
    @media (max-width:820px){
      .marquee-set span{font-size:15px}
      .marquee-set span::after{width:22px;margin:0 24px}
    }
    @media (prefers-reduced-motion:reduce){
      .roll > span{transition:none}
      .button:active{transform:none}
      .combo-btn::after{transition:none}
      .button-solid{animation:none}
      .button.is-busy .btn-spin{animation:none}
      .social-dot::before,.social-glyph,.social-underline,.social-tip{transition:none}
      .social-dot:hover .social-glyph,.social-dot:focus-visible .social-glyph{transform:none}
      .nav-links a::after{transition:none}
      .nav-cta > .cta-thread{display:none}
      .site-nav,.site-nav.is-compact{transition:none}
    }

    /* ══ ENQUIRY FORM ════════════════════════════════════════════════
       No backend and no third-party account: the form composes one
       formatted message and hands it to WhatsApp, which is where
       Hoodify already answers customers. Nothing is stored or sent
       anywhere else. */
    .enquiry{background-color:var(--surface-night-soft);color:var(--surface-paper);
      padding:clamp(56px,8vw,110px) 0}
    .enquiry-grid{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);
      gap:clamp(36px,6vw,88px);align-items:start}
    .enquiry-intro h2{margin-bottom:var(--sp-5)}
    .enquiry-intro p{margin:0 0 var(--sp-7);max-width:38ch;color:var(--on-dark-2);
      font-size:var(--fs-body);line-height:var(--lh-body)}
    .enquiry-note{display:flex;gap:var(--sp-3);align-items:flex-start;
      padding-top:var(--sp-6);border-top:1px solid var(--line-on-dark);
      font-family:var(--font-mono);font-size:var(--fs-micro);
      letter-spacing:var(--ls-micro);text-transform:uppercase;
      color:var(--on-dark-3);max-width:34ch;line-height:1.7}

    .field{display:block;margin-bottom:var(--sp-6)}
    .field-row{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-5)}
    .field > span:not(.field-error){display:block;margin-bottom:var(--sp-2);
      font-family:var(--font-mono);font-size:var(--fs-micro);
      letter-spacing:var(--ls-micro);text-transform:uppercase;color:var(--on-dark-2)}
    .field .opt{text-transform:none;letter-spacing:0;color:var(--on-dark-3)}
    .field input,.field select,.field textarea{
      width:100%;padding:13px 14px;border-radius:var(--radius);
      background:rgba(238,233,223,.045);
      border:1px solid var(--line-on-dark);
      color:var(--surface-paper);font-family:var(--font-text);
      font-size:var(--fs-body);line-height:1.45;
      transition:border-color var(--dur-base) var(--ease-out),
                 background var(--dur-base) var(--ease-out)}
    .field textarea{min-height:118px;resize:vertical}
    .field select{appearance:none;
      background-image:linear-gradient(45deg,transparent 50%,var(--on-dark-2) 50%),
        linear-gradient(135deg,var(--on-dark-2) 50%,transparent 50%);
      background-position:calc(100% - 18px) 50%,calc(100% - 13px) 50%;
      background-size:5px 5px,5px 5px;background-repeat:no-repeat;
      padding-right:40px}
    .field select option{background:var(--surface-night);color:var(--surface-paper)}
    .field input::placeholder,.field textarea::placeholder{color:var(--on-dark-3)}
    .field input:hover,.field select:hover,.field textarea:hover{
      border-color:rgba(238,233,223,.30)}
    /* outline:2px solid transparent rather than outline:none -- it renders
       as nothing normally, so the border-colour cue is still the design,
       but forced-colors mode repaints it and the field keeps a focus ring
       instead of losing it entirely. */
    .field input:focus,.field select:focus,.field textarea:focus{
      outline:2px solid transparent;outline-offset:2px;border-color:var(--gold-soft);
      background:rgba(238,233,223,.075)}
    /* the error only appears once the field has actually been submitted wrong */
    .field.is-bad input,.field.is-bad select,.field.is-bad textarea{
      border-color:#c96a5c}
    .field .field-error{display:none;margin-top:var(--sp-2);
      font-family:var(--font-mono);font-size:var(--fs-micro);
      letter-spacing:var(--ls-micro);color:#e08a7d}
    .field.is-bad .field-error{display:block}
    /* the error sits under the control, never beside the label */
    .field.is-bad .field-error{width:100%}

    /* ══ COMBO ═══════════════════════════════════════════════════════
       A listbox that belongs to this page. A native <select> hands the
       choice to the operating system: on Android it throws a sheet up
       from the bottom of the screen, and it is the one control on the
       site that cannot be styled at all.

       The <select> stays in the DOM and stays the source of truth. It
       holds the value, the form reads it, validation and the CTA
       prefill go on working untouched, and with JS off it is simply
       visible again — so this can only ever add, never break. */
    .field .combo{position:relative}
    .field .combo + select{position:absolute;width:1px;height:1px;padding:0;
      margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
    .combo-btn{width:100%;padding:13px 40px 13px 14px;border-radius:var(--radius);
      background:rgba(238,233,223,.045);border:1px solid var(--line-on-dark);
      color:var(--surface-paper);font-family:var(--font-text);font-size:var(--fs-body);
      line-height:1.45;text-align:left;cursor:pointer;
      transition:border-color var(--dur-base) var(--ease-out),
                 background var(--dur-base) var(--ease-out)}
    .combo-btn[data-empty="true"]{color:var(--on-dark-3)}
    .combo-btn:hover{border-color:rgba(238,233,223,.30)}
    .combo-btn:focus-visible{outline:2px solid transparent;outline-offset:2px;
      border-color:var(--gold-soft);
      background:rgba(238,233,223,.075)}
    .combo.is-open .combo-btn{border-color:var(--gold-soft);background:rgba(238,233,223,.075)}
    .field.is-bad .combo-btn{border-color:#c96a5c}
    .combo-btn::after{content:"";position:absolute;right:16px;top:50%;
      width:7px;height:7px;margin-top:-5px;border-right:1px solid var(--on-dark-2);
      border-bottom:1px solid var(--on-dark-2);transform:rotate(45deg);
      transition:transform var(--dur-base) var(--ease-out)}
    .combo.is-open .combo-btn::after{transform:rotate(225deg);margin-top:-2px}

    .combo-list{position:absolute;left:0;right:0;top:calc(100% + var(--sp-1));
      z-index:6;margin:0;padding:var(--sp-1);list-style:none;
      background:var(--surface-night);border:1px solid var(--line-on-dark);
      border-radius:var(--radius);max-height:250px;overflow-y:auto;
      box-shadow:0 18px 40px -12px rgba(0,0,0,.65)}
    .combo-list[hidden]{display:none!important}
    .combo-list li{padding:11px 13px;border-radius:var(--radius);cursor:pointer;
      font-size:var(--fs-body);line-height:1.4;color:var(--on-dark-2)}
    .combo-list li[aria-selected="true"]{color:var(--on-dark-1)}
    .combo-list li.is-active{background:var(--fill-on-dark);color:var(--on-dark-1)}

    .enquiry-send{display:flex;align-items:center;gap:var(--sp-5);
      flex-wrap:wrap;margin-top:var(--sp-7)}
    /* The enquiry sits on `surface-night-soft`, which is also the
       button's face — so here the face goes a shade darker, or the
       ring reads as floating on nothing. */
    .enquiry-send .button-solid{--btn-face:var(--surface-night)}
    .enquiry-alt{font-size:var(--fs-small);color:var(--on-dark-3)}
    .enquiry-alt a{color:var(--on-dark-2);text-decoration:underline;
      text-underline-offset:3px;text-decoration-thickness:1px}
    .enquiry-alt a:hover{color:var(--surface-paper)}

    /* Hit-area expanders. Three links were well under 44px tall and the
       footer's FAQ was 28px wide. An absolutely positioned ::after pushes
       the target out to a thumb-sized box while leaving the type exactly
       where it is -- nothing moves, nothing resizes. */
    .enquiry-alt a,.footer-mail a,.footer-links a{position:relative}
    .enquiry-alt a::after,.footer-mail a::after,.footer-links a::after{
      content:"";position:absolute;left:calc(-1 * var(--sp-2));right:calc(-1 * var(--sp-2));
      top:50%;height:var(--tap-min);transform:translateY(-50%)}

    /* success replaces the form in place — the visitor is told exactly
       what happened, because WhatsApp opens in another tab */
    .enquiry-done{display:none;padding:var(--sp-8);border:1px solid var(--line-on-dark);border-radius:var(--radius);
      background:rgba(238,233,223,.04)}
    .enquiry.is-sent .enquiry-form{display:none}
    .enquiry.is-sent .enquiry-done{display:block}
    .enquiry-done h3{margin:0 0 var(--sp-4);font-size:var(--fs-lg);font-weight:500}
    .enquiry-done p{margin:0 0 var(--sp-5);color:var(--on-dark-2);max-width:44ch}
    .enquiry-done .link-quiet{background:none;border:0;padding:0;cursor:pointer;
      font-family:var(--font-mono);font-size:var(--fs-micro);
      letter-spacing:var(--ls-micro);text-transform:uppercase;
      color:var(--on-dark-3);text-decoration:underline;text-underline-offset:3px}
    .enquiry-done .link-quiet:hover{color:var(--surface-paper)}

    @media (max-width:900px){
      .enquiry-grid{grid-template-columns:1fr;gap:var(--sp-9)}
      .enquiry-intro p{max-width:none}
      .enquiry-note{max-width:none}
    }
    @media (max-width:560px){
      .field-row{grid-template-columns:1fr;gap:0}
    }

    /* ══ FAQ ═════════════════════════════════════════════════════════
       The FaqSection pattern from 21st: a centred header, a stack of
       bordered cards that expand, and a contact block underneath.
       The reference is Tailwind on rounded-lg cards with a chevron that
       turns 180°; this is the same shape in the site's tokens — plate
       fill on paper, `--radius` corners, `--line-on-light` border. */
    .faq{background:var(--surface-paper);color:var(--on-light-1);
      padding:clamp(56px,8vw,110px) 0}
    .faq-head{max-width:62ch;margin:0 auto var(--sp-10);text-align:center}
    /* .faq is not .section-light, so the eyebrow inherited --gold — ivory
       under data-palette="none", i.e. invisible on paper. Pre-existing;
       it only showed once the header was centred. */
    .faq .eyebrow{color:var(--gold-ink);justify-content:center}
    .faq-head h2{margin:var(--sp-4) 0 0}
    .faq-lede{margin:var(--sp-5) auto 0;max-width:54ch;
      color:var(--on-light-2);font-size:var(--fs-lede);line-height:var(--lh-body)}

    .faq-list{display:flex;flex-direction:column;gap:var(--sp-4);
      max-width:820px;margin:0 auto}
    .faq-item{border:1px solid var(--line-on-light);border-radius:var(--radius);
      background:var(--surface-plate);overflow:hidden;
      transition:border-color var(--dur-base) var(--ease-out)}
    .faq-item:hover{border-color:var(--on-light-3)}
    .faq-item:has(.faq-q[aria-expanded="true"]){border-color:var(--on-light-2)}
    .faq-item h3{margin:0}
    .faq-q{width:100%;display:flex;align-items:center;justify-content:space-between;
      gap:var(--sp-5);padding:var(--sp-6);background:none;border:0;cursor:pointer;
      text-align:left;font-family:var(--font-text);font-size:var(--fs-title);
      font-weight:500;line-height:1.4;color:var(--on-light-1)}
    .faq-q:hover{color:#000}
    .faq-q:focus-visible{outline:1px solid var(--on-light-1);outline-offset:-4px}
    .faq-chev{flex:none;width:20px;height:20px;fill:none;stroke:var(--on-light-2);
      stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;
      transition:transform var(--dur-base) var(--ease-out)}
    .faq-q[aria-expanded="true"] .faq-chev{transform:rotate(180deg)}
    .faq-a{overflow:hidden;height:0;transition:height var(--dur-slow) var(--ease-out)}
    .faq-a > div{padding:0 var(--sp-6) var(--sp-6);max-width:58ch;
      color:var(--on-light-2);font-size:var(--fs-body);line-height:var(--lh-body)}
    .faq-a p{margin:0 0 var(--sp-3)}
    .faq-a p:last-child{margin:0}

    .faq-contact{max-width:820px;margin:var(--sp-9) auto 0;text-align:center;
      padding:var(--sp-9) var(--sp-6);border:1px solid var(--line-on-light);
      border-radius:var(--radius);background:var(--surface-plate)}
    .faq-contact-mark{display:inline-flex;align-items:center;justify-content:center;
      width:44px;height:44px;border-radius:var(--radius);
      border:1px solid var(--line-on-light);color:var(--on-light-2)}
    .faq-contact-mark svg{width:20px;height:20px;fill:none;stroke:currentColor;
      stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
    .faq-contact-title{margin:var(--sp-5) 0 0;font-family:var(--font-text);
      font-size:var(--fs-lg);font-weight:500;line-height:var(--lh-title);
      letter-spacing:var(--ls-title)}
    .faq-contact-text{margin:var(--sp-3) auto var(--sp-6);max-width:46ch;
      color:var(--on-light-2);font-size:var(--fs-body);line-height:var(--lh-body)}
    .faq-contact .button-quiet{color:var(--on-light-1);border-color:var(--on-light-1)}
    .faq-contact .button-quiet:hover{color:var(--gold-ink);border-color:var(--gold-ink)}

    @media (max-width:700px){
      .faq-q{padding:var(--sp-5)}
      .faq-a > div{padding:0 var(--sp-5) var(--sp-5)}
      .faq-contact{padding:var(--sp-8) var(--sp-5)}
    }
    @media (prefers-reduced-motion:reduce){
      .faq-a{transition:none}
      .faq-chev{transition:none}
    }

    /* ══ ATELIER HERO ═══════════════════════════════════════════════
       The client's own machine, mid-stitch. The frame's left 42% averages
       lum 11/255, so the headline sits straight on the photograph with no
       plate behind it; the scrim below only guards the crop at extreme
       aspect ratios. */
    .hero-atelier{position:absolute;inset:0;z-index:0;overflow:hidden}
    .hero-atelier img{position:absolute;inset:0;width:100%;height:100%;
      object-fit:cover;object-position:72% 50%;
      transform:scale(1.06) translate3d(calc(var(--px,0) * 13px),calc(var(--py,0) * 9px),0);
      transition:transform 1400ms var(--ease-out),opacity 1200ms var(--ease-out);
      will-change:transform}
    html.js .hero-atelier img{opacity:0;transform:scale(1.12)}
    html.js .hero.is-typed .hero-atelier img{opacity:1;
      transform:scale(1.06) translate3d(calc(var(--px,0) * 13px),calc(var(--py,0) * 9px),0)}
    /* keeps the copy legible whatever the crop does to the dark side */
    .hero-atelier::after{content:"";position:absolute;inset:0;
      background:linear-gradient(100deg,rgba(10,11,8,.92) 0%,rgba(10,11,8,.72) 26%,
        rgba(10,11,8,.18) 48%,transparent 66%)}
    /* a slow bloom near the needles — the layer nearest the camera, so it
       carries the most pointer travel */
    .hero-atelier::before{content:"";position:absolute;z-index:1;
      right:6%;top:26%;width:46%;aspect-ratio:1.6;border-radius:50%;
      background:radial-gradient(ellipse at 50% 50%,rgba(214,186,150,.11),transparent 68%);
      transform:translate3d(calc(var(--px,0) * 22px),calc(var(--py,0) * 15px),0)}

    :root[data-hero="atelier"] .hero-product-wrap,
    :root[data-hero="atelier"] .hero-ghost{display:none}
    :root[data-hero="atelier"] .hero-grid{grid-template-columns:minmax(0,1fr)}
    :root[data-hero="atelier"] .hero-copy{max-width:min(560px,46vw);position:relative;z-index:2}
    :root[data-hero="atelier"] .hero{min-height:100svh}
    :root[data-hero="product"] .hero-atelier{display:none}
    /* the micro line can land on the stitching at phone crops */
    :root[data-hero="atelier"] .hero-note{text-shadow:0 1px 10px rgba(10,11,8,.92),0 0 3px rgba(10,11,8,.8)}

    /* ── data-hero="shader" ─────────────────────────────────────────
       A third hero ground: an animated WebGL2 field instead of the atelier
       photograph. It reuses the atelier variant's layout wholesale -- one
       column, the copy capped and raised above the ground -- so the two can
       be compared with only the background changing.

       The canvas is painted by site.js. Everything here still works if that
       never runs: .hero-shader carries --surface-night, so a browser without
       WebGL2, or a visitor with JS off, gets a solid dark hero rather than a
       transparent hole. */
    .hero-shader{display:none}
    /* The ground under the canvas. It is not a placeholder: whenever the
       shader is not running -- a low-end device, no WebGL2, reduced motion,
       or the frame watchdog having stopped it -- this gradient is the hero,
       so it has to read as a deliberate surface on its own rather than as
       a blank rectangle waiting for something. */
    :root[data-hero="shader"] .hero-shader{display:block;position:absolute;
      inset:0;z-index:0;overflow:hidden;
      background:
        radial-gradient(122% 92% at 78% 40%,rgba(124,101,56,.20),rgba(124,101,56,0) 58%),
        radial-gradient(84% 64% at 26% 84%,rgba(92,80,54,.13),rgba(92,80,54,0) 62%),
        var(--surface-night)}
    /* a canvas that is not being painted should not sit over that ground */
    :root[data-hero="shader"] .hero-shader[data-shader="off"] .hero-shader-canvas{display:none}
    /* Fails closed: the canvas is invisible until site.js has drawn a frame
       and checked it, and only then flips data-shader to on or static. Any
       failure on the way -- no WebGL2, a shader that will not compile, a
       blank first frame, a thrown error -- leaves the gradient above showing
       instead of a blank or black rectangle. */
    .hero-shader-canvas{display:block;width:100%;height:100%;opacity:0;
      transition:opacity var(--dur-slow) var(--ease-out)}
    .hero-shader[data-shader="on"] .hero-shader-canvas,
    .hero-shader[data-shader="static"] .hero-shader-canvas{opacity:1}
    /* the same legibility scrim .hero-atelier gets from its ::after -- the
       shader is brightest on the right, the copy sits on the left */
    :root[data-hero="shader"] .hero-shader::after{content:"";position:absolute;
      inset:0;z-index:1;pointer-events:none;
      background:linear-gradient(100deg,rgba(10,11,8,.92) 0%,rgba(10,11,8,.72) 26%,
        rgba(10,11,8,.18) 48%,transparent 66%)}

    :root[data-hero="shader"] .hero-atelier,
    :root[data-hero="shader"] .hero-product-wrap,
    :root[data-hero="shader"] .hero-ghost{display:none}
    :root[data-hero="shader"] .hero-grid{grid-template-columns:minmax(0,1fr)}
    :root[data-hero="shader"] .hero-copy{max-width:min(560px,46vw);
      position:relative;z-index:2}
    :root[data-hero="shader"] .hero{min-height:100svh}
    :root[data-hero="shader"] .hero-note{text-shadow:0 1px 10px rgba(10,11,8,.92),
      0 0 3px rgba(10,11,8,.8)}

    /* the thread that runs out from under the headline, drawn once */
    .hero-thread{display:block;width:min(320px,62%);height:22px;overflow:visible;
      margin:0 0 var(--sp-6)}
    .hero-thread path{fill:none;stroke:#d3c3a6;stroke-width:1.4;stroke-linecap:round;
      opacity:.85;stroke-dasharray:var(--htl,340);stroke-dashoffset:var(--htl,340);
      transition:stroke-dashoffset 1500ms cubic-bezier(.2,.7,.2,1) 620ms}
    .hero.is-typed .hero-thread path{stroke-dashoffset:0}
    :root[data-hero="product"] .hero-thread{display:none}


    @media (max-width:900px){
      :root[data-hero="atelier"] .hero-copy{max-width:none}
      :root[data-hero="shader"] .hero-copy{max-width:none}
      /* the copy sits over the upper half here too, so the scrim turns
         vertical exactly as the atelier one does */
      :root[data-hero="shader"] .hero-shader::after{
        background:linear-gradient(180deg,rgba(10,11,8,.90) 0%,
          rgba(10,11,8,.80) 30%,rgba(10,11,8,.58) 52%,rgba(10,11,8,.30) 74%,
          rgba(10,11,8,.62) 100%)}
      .hero-atelier img{object-position:50% 58%}
      /* the copy sits over the upper half, the stitching stays readable below */
      .hero-atelier::after{background:linear-gradient(180deg,rgba(10,11,8,.90) 0%,
        rgba(10,11,8,.80) 30%,rgba(10,11,8,.58) 52%,rgba(10,11,8,.30) 74%,
        rgba(10,11,8,.62) 100%)}
      .hero-atelier::before{display:none}
    }
    @media (prefers-reduced-motion:reduce){
      html.js .hero-atelier img{opacity:1;transform:scale(1.04);transition:none}
      .hero-thread path{stroke-dashoffset:0;transition:none}
      .button:hover::before{animation:none}
    }

    /* ── proof — "Every piece starts on the machine." ────────────────
       The section that replaced the pinned signature scene. It takes the
       site's own rhythm from .section, .section-dark and .wrap rather than
       defining new spacing, so this block owns only the caption and the
       frame.

       It shipped with no CSS at all. On a phone that meant a portrait crop
       at full viewport width -- 585px tall at 390px -- with the caption
       loose underneath and a scrim sitting over nothing. */
    .proof-line{margin:0 0 var(--sp-8);max-width:20ch;
      font-family:var(--font-display);font-weight:var(--display-weight,500);
      font-size:var(--fs-quote);line-height:var(--display-lh,var(--lh-title));
      letter-spacing:var(--display-ls,var(--ls-title));
      text-transform:var(--display-case,none);color:var(--surface-paper)}
    .proof-media{display:block;margin:0;overflow:hidden;
      border-radius:var(--radius);background:var(--surface-night-soft)}
    /* Always landscape. 16:9 is the photograph's own shape to within a
       percent, so on a wide screen nothing is cropped. Everything worth
       seeing -- the needle row, the hoop, the blossom -- sits in the right
       two-thirds and the left third is near-black, so any crop pins right. */
    .proof-img{width:100%;height:auto;aspect-ratio:16/9;
      object-fit:cover;object-position:100% 50%}
    @media (max-width:700px){
      .proof-line{margin-bottom:var(--sp-6)}
      /* 4:3 on a phone: still landscape, but tall enough at 350px wide for
         the needles, the hoop and the stitching to read. Pinned right, the
         crop spends itself on the empty edge rather than the subject. */
      .proof-img{aspect-ratio:4/3}
    }

    /* ?shaderdebug -- an on-device readout of what the shader decided.
       Only ever created on request; see the note in site.js. */
    .shader-debug{position:fixed;left:var(--sp-2);right:var(--sp-2);
      bottom:var(--sp-2);z-index:9999;margin:0;padding:var(--sp-3);
      border-radius:var(--radius);background:rgba(10,11,8,.92);
      color:var(--surface-paper);font-family:var(--font-mono);
      font-size:var(--fs-micro);line-height:var(--lh-body);
      white-space:pre-wrap;word-break:break-word}

    /* ── background grounds ─────────────────────────────────────── */
    .bg-layer{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden}
    .bg-layer > *{position:absolute;inset:0;opacity:0;transition:opacity var(--dur-slow) var(--ease-out)}
    /* main and footer are raised so they clear .bg-layer (fixed, z-index 0).
       .site-nav is deliberately NOT in this list: it sets its own
       position:fixed and z-index:20, and being named here silently
       dragged it back to position:relative. That put the header in normal
       flow above the hero, where its transparent background revealed the
       cream body -- an ivory wordmark and hamburger at 1.00:1. */
    main,footer{position:relative;z-index:1}
    .bg-studio{background:
      radial-gradient(120% 80% at 50% -10%, rgba(255,252,244,.09), rgba(255,252,244,0) 60%),
      radial-gradient(100% 70% at 50% 110%, rgba(0,0,0,.26), rgba(0,0,0,0) 62%)}
    :root[data-bg="studio"] .bg-studio{opacity:1}
    .bg-thread svg{width:100%;height:100%}
    .bg-thread path{fill:none;stroke:var(--on-dark-1);stroke-width:1;vector-effect:non-scaling-stroke;
      stroke-dasharray:2600;stroke-dashoffset:2600;animation:bgdraw 2800ms var(--ease-out) forwards}
    .bg-thread path:nth-child(2){animation-delay:120ms}.bg-thread path:nth-child(3){animation-delay:240ms}
    .bg-thread path:nth-child(4){animation-delay:360ms}.bg-thread path:nth-child(5){animation-delay:480ms}
    .bg-thread path:nth-child(6){animation-delay:600ms}
    @keyframes bgdraw{to{stroke-dashoffset:0}}
    :root[data-bg="thread"] .bg-thread{opacity:1}
    :root[data-motion="none"] .bg-thread path{animation:none;stroke-dashoffset:0}
    .bg-pattern{background-size:52px 52px;
      background-image:linear-gradient(to right,var(--line-on-dark) 1px,transparent 1px),
                       linear-gradient(to bottom,var(--line-on-dark) 1px,transparent 1px)}
    .bg-pattern::after{content:"";position:absolute;inset:0;
      background:radial-gradient(80% 60% at 50% 40%, transparent 26%, var(--surface-night) 76%)}
    :root[data-bg="pattern"] .bg-pattern{opacity:.5}
    .bg-weave{background-size:6px 6px;
      background-image:repeating-linear-gradient(45deg,var(--line-on-dark) 0 1px,transparent 1px 6px),
                       repeating-linear-gradient(-45deg,var(--line-on-dark) 0 1px,transparent 1px 6px)}
    :root[data-bg="weave"] .bg-weave{opacity:.45}
    /* the grounds only read on the dark sections; light sections stay opaque */
    .section-light,.contact,.capsule{position:relative;z-index:1}

    /* ── thread motion on rules ─────────────────────────────────── */
    :root[data-motion="thread"] .eyebrow::before{width:0;animation:rule 700ms var(--ease-out) .2s forwards}
    @keyframes rule{to{width:28px}}
    :root[data-motion="wipe"] .hero-product{clip-path:inset(100% 0 0 0);animation:wipeup 900ms var(--ease-out) .15s forwards}
    @keyframes wipeup{to{clip-path:inset(0 0 0 0)}}

    @media (prefers-reduced-motion:reduce){
      .bg-thread path{animation:none;stroke-dashoffset:0}
      .eyebrow::before{animation:none;width:28px}
      .hero-product{animation:none;clip-path:none}
    }
    @media (prefers-reduced-motion:reduce){
      html{scroll-behavior:auto}
      *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}
      [data-reveal]{opacity:1;transform:none}
      .hero-stage{--px:0!important;--py:0!important}
    }
