/* ==========================================================================
   Liquid Gold Exchange — site layer
   Page-level patterns built on top of design-system/styles.css.
   Same rule as the component layer: SEMANTIC tokens only, never raw --lgx-*,
   so anything here keeps working inside [data-zone="navy"].
   ========================================================================== */

/* --------------------------------------------------------------------------
   Paper grain
   Flat #F3EFE5 reads as a screen colour; the brand's ivory is an uncoated
   stock. A single tiling noise layer at 3.5% gives the page the tooth of
   paper without shipping an image or touching contrast.
   -------------------------------------------------------------------------- */

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: 0.035;
  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='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}


/* --------------------------------------------------------------------------
   Logo lockup
   The mark is inline SVG (brand/logo/lgx-mark.svg redrawn as markup) and the
   wordmark is live text in Cinzel — so it stays selectable, scalable and
   themeable. Swap for the studio's outlined lockup when it arrives.
   -------------------------------------------------------------------------- */

.lgx-lockup {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;      /* it is the home link on every page */
  text-decoration: none;
  color: var(--brand-mark);
}
/* The mark is 周六福 (HQ, 10 Aug 2026) and no vector of it exists yet, so it
   is a PNG for now — painted through a mask rather than dropped in as an
   <img>. The mask is what preserves the behaviour the inline <svg> had: the
   shape takes `currentColor`, so one file serves gold on the navy header and
   the inherited colour everywhere else, and no second inverted asset is
   needed. assets/img/zlf-mark.png is generated by tools/build-assets.py from
   brand/logo/zlf-mark-source.png; when the studio's SVG arrives, change the
   source file and the url() and nothing else here moves.
   -webkit- first: Safari still needs the prefix for mask shorthand. */
.lgx-lockup__mark,
.cover__mark,
.auth__mark {
  aspect-ratio: 1153 / 528;   /* the source's own ink bounds */
  background-color: currentColor;
  -webkit-mask: url("../img/zlf-mark.png") center / contain no-repeat;
          mask: url("../img/zlf-mark.png") center / contain no-repeat;
}

.lgx-lockup__mark { width: 78px; flex: none; }
.lgx-lockup__word {
  font-family: var(--font-display);
  font-size: 0.8125rem;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.2em;
  line-height: 1.15;
  text-transform: uppercase;
  white-space: nowrap;
}
.lgx-lockup__word small {
  display: block;
  font-family: var(--font-ui);
  font-size: 0.5rem;
  font-weight: var(--weight-medium);
  letter-spacing: 0.24em;
  color: var(--text-secondary);
  margin-top: 3px;
}

/* Chinese lockup. These two tracking values are hard-coded rather than
   tokenised, so the :lang(zh) token rebind in the design system does not
   reach them — they need saying explicitly.
   鎏金汇 is three characters against nineteen Latin ones, so it also needs
   the size back that the Latin wordmark gets from sheer length. */
.lgx-lockup__word:lang(zh) {
  font-family: var(--font-cn-display);
  font-size: 1.0625rem;
  letter-spacing: 0.12em;
  line-height: 1.2;
}
.lgx-lockup__word:lang(zh) small {
  font-size: 0.5rem;
  letter-spacing: 0.2em;   /* the sub-line stays Latin, so it keeps its air */
  margin-top: 4px;
}

/* Stacked lockup — hero, footer, print. Mark above, wordmark under a rule. */
.lgx-lockup--stacked {
  flex-direction: column;
  gap: var(--space-4);
  text-align: center;
}
.lgx-lockup--stacked .lgx-lockup__mark { width: 150px; }
.lgx-lockup--stacked .lgx-lockup__word {
  font-size: 1.125rem;
  letter-spacing: 0.34em;
  text-indent: 0.34em;   /* optical re-centre: tracking pads the right edge */
}


/* --------------------------------------------------------------------------
   Header — sticky, with the price ticker docked underneath
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--surface-page);
  border-bottom: var(--border-width-hair) solid var(--border-subtle);
}
.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  padding-block: var(--space-3);
}
.site-header__actions { display: flex; align-items: center; gap: var(--space-3); }

.site-nav { display: flex; gap: var(--space-6); align-items: center; }
.site-nav a {
  font-family: var(--font-ui);
  font-size: var(--text-body-s);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--text-primary);
  padding-block: var(--space-2);
  border-bottom: var(--border-width-rule) solid transparent;
  transition: border-color var(--duration-normal) var(--ease-standard);
}
.site-nav a:hover,
.site-nav a[aria-current="page"] { border-bottom-color: var(--border-gold); }

.site-header__toggle {
  display: none;
  background: none;
  border: var(--border-width-hair) solid var(--border-subtle);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  padding: var(--space-2) var(--space-4);
  min-height: 44px;          /* was 33px — this is a mobile-only control */
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  cursor: pointer;
}

/* Language switch — the Chinese site does not exist yet, so this is an
   honest placeholder rather than a dead link. */
/* An <a> now, not a <button> — it navigates to the other language's copy of
   the current page, so it must be a real link: middle-clickable, followable
   by a crawler, and working with JavaScript off. */
.lang-switch {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-caps);
  color: var(--text-secondary);
  text-decoration: none;
  background: none;
  border: var(--border-width-hair) solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-4);
  min-height: 44px;          /* was 35px */
  cursor: pointer;
  transition: border-color var(--duration-normal) var(--ease-standard),
              color var(--duration-normal) var(--ease-standard);
}
.lang-switch:hover { border-color: var(--border-gold); color: var(--text-accent); }


/* --------------------------------------------------------------------------
   Cover — the full-viewport opening screen
   One screen: mark, established line, tagline, scroll cue. Nothing else. The
   real hero follows on scroll, so this carries no navigation weight and can
   afford to be almost empty.
   -------------------------------------------------------------------------- */

.cover {
  position: relative;
  /* The header stays in flow (sticky, never fixed) so nothing jumps when it
     leaves cover mode. Subtracting its height keeps the scroll cue on-screen.
     --header-h is measured by site.js once the webfonts have landed; until
     then — and on a JS-less render — this fallback stands in. 117px is the
     measured height of the lockup row plus the ticker at desktop width, so
     the untouched value is close rather than merely safe. */
  min-height: calc(100svh - var(--header-h, 117px));
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--surface-sunken);   /* navy-950 inside a navy zone */
  text-align: center;
  /* Vertical padding scales with the viewport. Fixed --space-9 (96px top and
     bottom) pushed the cover to 674px inside a 601px box on a 720px-tall
     screen — the one thing this section exists to avoid. */
  padding: clamp(var(--space-5), 7vh, var(--space-9)) var(--container-pad);
}

/* Two stacked glows: a wide cool lift off the flat navy, and a tight warm
   one directly behind the mark so the gold reads as lit rather than printed. */
.cover::before,
.cover::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 46%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  pointer-events: none;
}
.cover::before {
  width: min(1100px, 130vw);
  aspect-ratio: 1;
  background: radial-gradient(circle,
              color-mix(in srgb, #FFFFFF 5%, transparent) 0%,
              transparent 62%);
}
.cover::after {
  width: min(620px, 84vw);
  aspect-ratio: 1;
  background: radial-gradient(circle,
              color-mix(in srgb, var(--border-gold) 16%, transparent) 0%,
              transparent 66%);
}

.cover__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(var(--space-4), 5vh, var(--space-7));
}

.cover__mark {
  /* The vh cap is what keeps the composition on one screen on a laptop; the
     vw term is what keeps it from going tiny on a narrow phone.
     Widened for the 周六福 lockup: at 2.18:1 the old 250px cap stood only
     115px tall, half the monogram's presence on the same screen. The vh cap
     is now generous because width no longer drives height nearly as hard. */
  width: min(clamp(230px, 34vw, 420px), 88vh);
  height: auto;
  color: var(--brand-mark);
  filter: drop-shadow(0 0 34px color-mix(in srgb, var(--border-gold) 34%, transparent));
}

/* Rule with the establishment line set into it, rather than a diamond. */
.cover__est {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-secondary);
}
.cover__est::before,
.cover__est::after {
  content: "";
  width: clamp(28px, 6vw, 56px);
  height: 1px;
  background: currentColor;
  opacity: 0.45;
}

/* Cinzel is uppercase-only by rule and has no italic, so the tagline is set
   in Lora italic — same editorial register, inside the type system. */
.cover__tagline {
  font-family: var(--font-body);
  font-style: italic;
  font-size: clamp(1.75rem, 4.6vw, 3.25rem);
  line-height: 1.22;
  color: var(--text-primary);
  margin: 0;
  max-width: 18ch;
}
.cover__tagline span { display: block; }
/* The second line hangs right of the first — the ellipsis carries across the
   gap, so the two halves read as one sentence broken over a breath. */
.cover__tagline span + span { margin-left: clamp(1rem, 6vw, 4.5rem); }

/* Chinese has no italic. Synthesised obliques on CJK are a well-known
   typographic sin — the browser shears the glyphs, which for characters built
   from balanced strokes destroys the letterform. The Chinese tagline carries
   the same editorial weight through the display serif and a wider measure
   instead. */
.cover__tagline:lang(zh) {
  font-family: var(--font-cn-display);
  font-style: normal;
  font-weight: var(--weight-regular);
  letter-spacing: 0.14em;
  line-height: 1.5;
  max-width: 22ch;
}
.auth__quote:lang(zh) {
  font-family: var(--font-cn-display);
  font-style: normal;
  letter-spacing: 0.1em;
}

.cover__scroll {
  position: absolute;
  left: 50%;
  bottom: var(--space-6);
  transform: translateX(-50%);
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
  text-decoration: none;
}
.cover__scroll:hover { color: var(--text-accent); }
.cover__scroll svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 1.5; }

/* Entrance — a slow settle, staggered top to bottom. */
@keyframes cover-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes cover-bob {
  0%, 100% { transform: translate(-50%, 0); }
  50%      { transform: translate(-50%, 5px); }
}
.cover__mark,
.cover__est,
.cover__tagline { animation: cover-rise 900ms var(--ease-out) both; }
.cover__est      { animation-delay: 180ms; }
.cover__tagline  { animation-delay: 340ms; }
.cover__scroll   { animation: cover-rise 900ms var(--ease-out) 700ms both,
                              cover-bob 2.6s var(--ease-standard) 1.6s infinite; }

@media (prefers-reduced-motion: reduce) {
  .cover__mark, .cover__est, .cover__tagline, .cover__scroll { animation: none; }
}

/* Header while the cover fills the screen: no chrome, no nav, no ticker —
   just the lockup and the one action. Restored on scroll by site.js. */
/* Same navy as the cover, not transparent — the header keeps its place in
   flow, and the two surfaces read as one continuous field. */
.site-header[data-cover="true"] {
  background: var(--surface-sunken);
  border-bottom-color: transparent;
}
/* visibility, not display, on every one of these: each keeps its box, so the
   header measures identically in both states and nothing below it jumps when
   cover mode ends mid-scroll. On mobile the Menu button and 中文 switch were
   the culprits — they wrap onto a second row and cost 57px. */
.site-header[data-cover="true"] .site-nav,
.site-header[data-cover="true"] .lang-switch,
.site-header[data-cover="true"] .site-header__toggle,
.site-header[data-cover="true"] .lgx-ticker { visibility: hidden; }
.site-header { transition: background-color var(--duration-slow) var(--ease-standard),
                           border-color var(--duration-slow) var(--ease-standard); }


/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  overflow: hidden;
  padding-block: var(--space-10) var(--space-9);
}
/* Soft gold bloom, bottom-right — echoes the liquid-gold motif in the
   catalogue covers without shipping a 2MB photograph. */
.hero::after {
  content: "";
  position: absolute;
  right: -18%;
  bottom: -45%;
  width: 70%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle,
              color-mix(in srgb, var(--border-gold) 24%, transparent) 0%,
              transparent 68%);
  pointer-events: none;
}
.hero__inner { position: relative; z-index: 1; max-width: 780px; }
.hero__title { margin-bottom: var(--space-5); }
.hero__actions { display: flex; gap: var(--space-4); flex-wrap: wrap; margin-top: var(--space-7); }

.hero--page { padding-block: var(--space-8) var(--space-7); }


/* --------------------------------------------------------------------------
   Editorial — text beside an image
   The two-column block the About section was missing. Text never exceeds its
   measure, so the image is what fills the width rather than slack whitespace.
   -------------------------------------------------------------------------- */

.editorial {
  display: grid;
  grid-template-columns: 1.02fr 0.98fr;
  gap: var(--space-9);
  align-items: center;
}
.editorial--flip .editorial__media { order: -1; }
.editorial__body > :last-child { margin-bottom: 0; }

/* Offset hairline frame behind the image — the same device as the printed
   collateral's double border, rebuilt as depth rather than decoration. */
.figure-frame {
  position: relative;
  padding: 0 var(--space-4) var(--space-4) 0;
}
.figure-frame::before {
  content: "";
  position: absolute;
  inset: var(--space-4) 0 0 var(--space-4);
  border: var(--border-width-hair) solid var(--border-gold);
  opacity: 0.5;
  pointer-events: none;
}
.figure-frame img {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--radius-sm);
}
.figure-frame--tall img { aspect-ratio: 4 / 5; }
.figure-caption {
  margin: var(--space-4) 0 0;
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-muted);
}


/* --------------------------------------------------------------------------
   Full-bleed image band
   -------------------------------------------------------------------------- */

.band { position: relative; overflow: hidden; }
.band__img { display: block; width: 100%; height: clamp(240px, 32vw, 420px); object-fit: cover; }
.band__cap {
  padding-block: var(--space-5);
  text-align: center;
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}


/* --------------------------------------------------------------------------
   Hero media — the sealed bar sits on near-black navy, so it dissolves into
   a navy hero rather than sitting on it as a pasted rectangle.
   -------------------------------------------------------------------------- */

.hero--split .hero__inner { max-width: none; display: grid;
                            grid-template-columns: 1.1fr 0.9fr; gap: var(--space-8);
                            align-items: center; }
.hero__copy { max-width: 620px; }
.hero__media { position: relative; }
.hero__media img {
  display: block;
  width: 100%;
  max-width: 420px;
  margin-inline: auto;
  border-radius: var(--radius-md);
  -webkit-mask-image: radial-gradient(ellipse at center, #000 52%, transparent 84%);
          mask-image: radial-gradient(ellipse at center, #000 52%, transparent 84%);
}


/* --------------------------------------------------------------------------
   Reveal on scroll — a slow settle, never a slide-show
   -------------------------------------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 800ms var(--ease-out), transform 800ms var(--ease-out);
}
.reveal.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}


/* --------------------------------------------------------------------------
   Stat bar
   -------------------------------------------------------------------------- */

.stat-bar {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  border-top: var(--border-width-hair) solid var(--border-subtle);
}
.stat {
  padding: var(--space-6) var(--space-5);
  border-right: var(--border-width-hair) solid var(--border-subtle);
}
.stat:last-child { border-right: 0; }
.stat__value {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  letter-spacing: 0.04em;
  line-height: 1;
  color: var(--text-accent);
  display: block;
}
.stat__label {
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
  display: block;
  margin-top: var(--space-3);
}


/* --------------------------------------------------------------------------
   Section header — left-aligned variant with the dash rule
   -------------------------------------------------------------------------- */

.sec-head { max-width: 720px; margin-bottom: var(--space-7); }
.sec-head__eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-accent);
  margin-bottom: var(--space-4);
}
.sec-head__eyebrow::before {
  content: "";
  width: 32px; height: 1px;
  background: var(--border-gold);
  flex: none;
}
.sec-head__title { margin-bottom: var(--space-4); }
.sec-head--center { margin-inline: auto; text-align: center; }
.sec-head--center .sec-head__eyebrow { justify-content: center; }


/* --------------------------------------------------------------------------
   FAQ
   --------------------------------------------------------------------------
   A <dl>, not a stack of headings and not a <details> accordion. The question
   really is a term and the answer really is its definition, and a bullion FAQ
   is read by people comparing two answers against each other — collapsing
   them behind a click hides exactly the copy that is doing the reassuring.
   Everything here is open, printable and findable by ctrl-F. */
.faq { margin: 0; }
.faq__q {
  font-family: var(--font-display);
  font-size: var(--text-h4);
  font-weight: var(--weight-semibold);
  line-height: 1.35;
  color: var(--text-primary);
  padding-top: var(--space-6);
  border-top: 1px solid var(--border-subtle);
}
.faq__q:first-of-type { padding-top: 0; border-top: 0; }
.faq__a {
  margin: 0;
  padding-bottom: var(--space-6);
}
.faq__a > .lgx-body { margin-top: var(--space-3); }
/* The gold rule under the question is the same device the section heads use,
   scaled down — it is what stops a long <dl> reading as undifferentiated. */
.faq__q::after {
  content: "";
  display: block;
  width: 28px;
  height: 1px;
  margin-top: var(--space-3);
  background: var(--border-gold);
}


/* --------------------------------------------------------------------------
   Category card — the six-up product-family grid
   -------------------------------------------------------------------------- */

.cat-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-6);
  background: var(--surface-raised);
  border: var(--border-width-hair) solid var(--border-subtle);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--duration-normal) var(--ease-standard),
              transform var(--duration-normal) var(--ease-out);
}
.cat-card:hover { border-color: var(--border-gold); transform: translateY(-2px); }
.cat-card__icon { width: 34px; height: 34px; color: var(--border-gold);
                  stroke: currentColor; fill: none; stroke-width: 1.25; }
.cat-card__title {
  font-family: var(--font-display);
  font-size: var(--text-h4);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  margin: var(--space-2) 0 0;
  color: var(--text-primary);
}
.cat-card__cn { font-family: var(--font-cn-display); font-size: var(--text-body-s);
                color: var(--text-muted); margin: 0; }
.cat-card__note { font-size: var(--text-body-s); color: var(--text-secondary); margin: 0; }
.cat-card__more {
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-accent);
  margin-top: auto;
  padding-top: var(--space-4);
}


/* Six categories want 3×2, not the auto-fit 4+2 the generic grid produces. */
.cat-grid { display: grid; gap: var(--space-5); grid-template-columns: repeat(3, 1fr); }


/* --------------------------------------------------------------------------
   Numbered reason list — "Why LGX"
   -------------------------------------------------------------------------- */

.reason {
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: var(--space-4);
  padding-block: var(--space-5);
  border-top: var(--border-width-hair) solid var(--border-subtle);
}
.reason__num {
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-caps);
  color: var(--border-gold);
  padding-top: 4px;
}
.reason__title {
  font-family: var(--font-display);
  font-size: var(--text-h4);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  margin: 0 0 var(--space-2);
}
.reason__body { margin: 0; color: var(--text-secondary); font-size: var(--text-body-s); }

/* auto-fit + minmax collapses on its own, so this one never needed a media
   query — but it was still layout living in a style attribute, and the point
   of moving the others was that you cannot tell which is which from a grep. */
.reason-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 0 var(--space-8);
}


/* --------------------------------------------------------------------------
   Enquiry layout
   --------------------------------------------------------------------------
   These two were inline `style="grid-template-columns:…"` on the elements
   themselves, which no media query can reach. At 390px the result was a
   147px-wide form beside a 164px contact column, with 62px text inputs — the
   page's only conversion path, unusable, on the device most people would
   open it from.

   Inline styles are not a shortcut for layout that has to respond. If it can
   change at a breakpoint, it belongs in a class.
   -------------------------------------------------------------------------- */

.enquiry-layout {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: var(--space-8);
}

.enquiry-honeypot { position: absolute !important; left: -10000px !important; width: 1px; height: 1px; }
.enquiry-turnstile { margin: var(--space-5) 0; min-height: 65px; }

/* Two form fields side by side. */
.field-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5);
}

@media (max-width: 900px) {
  .enquiry-layout { grid-template-columns: 1fr; gap: var(--space-7); }
}
@media (max-width: 620px) {
  /* Below this a paired row gives each field under ~160px, which is not
     enough for an email address to be readable while it is being typed. */
  .field-pair { grid-template-columns: 1fr; gap: var(--space-4); }
}


/* --------------------------------------------------------------------------
   Contact rows
   -------------------------------------------------------------------------- */

.contact-row {
  display: grid;
  grid-template-columns: 28px 120px 1fr;
  gap: var(--space-4);
  align-items: start;
  padding-block: var(--space-4);
  border-bottom: var(--border-width-hair) solid var(--border-subtle);
}
.contact-row__icon { width: 20px; height: 20px; color: var(--border-gold);
                     stroke: currentColor; fill: none; stroke-width: 1.4; }
.contact-row__label {
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
  padding-top: 2px;
}
.contact-row__value { font-family: var(--font-ui); font-size: var(--text-body-s); }
/* Email and phone are mailto:/tel: links, not text — on a phone the desk's
   number should be one tap. 44px so it is a real target. */
.contact-row__value a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--text-primary);
  text-decoration: none;
  border-bottom: var(--border-width-hair) solid var(--border-gold-faint);
}
.contact-row__value a:hover { color: var(--text-accent); border-bottom-color: var(--border-gold); }


/* --------------------------------------------------------------------------
   Catalogue: filter rail + results
   -------------------------------------------------------------------------- */

.catalogue { display: grid; grid-template-columns: 240px 1fr; gap: var(--space-7); }

/* --header-h is published by site.js and tracks the real sticky header,
   including the ticker row. The old hard-coded 96px was ~20px short, so the
   top of the rail tucked under the header. */
.filters { align-self: start; position: sticky;
           top: calc(var(--header-h, 117px) + var(--space-4)); }
/* <fieldset>, so the group name is announced with each checkbox rather than
   sitting next to them as decoration. Everything below undoes the UA's
   fieldset chrome — the visual result is identical to the old <div>. */
.filter-group {
  border: 0; margin: 0; min-width: 0;
  padding: var(--space-5) 0;
  border-bottom: var(--border-width-hair) solid var(--border-subtle);
}
.filter-group:first-of-type { padding-top: 0; }
.filter-group__title {
  /* A <legend> renders specially by default. `display: block` normalises it
     into ordinary flow, which is what this layout wants.

     NOT `float: left` — that is the old hack for this, and here it made the
     legend occupy the whole line box, leaving the flex container beside it
     exactly 0px wide and collapsing every filter row. */
  display: block;
  width: 100%;
  padding: 0;
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 var(--space-3);
}
.filter-opts { display: flex; flex-direction: column; }
/* The rows were 24px tall with 12px between them — a 15px checkbox and a line
   of 14px text. min-height makes the whole label a 44px target without making
   the rail look like a list of buttons. */
.filter-opt {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: 44px;
  font-family: var(--font-ui); font-size: var(--text-body-s);
  color: var(--text-secondary); cursor: pointer;
}
.filter-opt input { accent-color: var(--border-gold); width: 18px; height: 18px;
                    flex: none; cursor: pointer; }
.filter-opt:hover { color: var(--text-primary); }
.filter-opt__count { margin-left: auto; font-size: var(--text-caption); color: var(--text-muted); }

.results-bar {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-4); flex-wrap: wrap;
  padding-bottom: var(--space-5);
  border-bottom: var(--border-width-hair) solid var(--border-subtle);
  margin-bottom: var(--space-6);
}
.results-count { font-family: var(--font-ui); font-size: var(--text-body-s); color: var(--text-secondary); }
.results-count b { color: var(--text-primary); font-variant-numeric: tabular-nums; }

.results-grid { display: grid; gap: var(--space-5);
                grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); }
.results-empty { padding: var(--space-8); text-align: center; color: var(--text-muted); }


/* --------------------------------------------------------------------------
   Bar illustration — stands in for product photography
   -------------------------------------------------------------------------- */

.bar-art { width: 100%; height: auto; max-width: 190px; }


/* --------------------------------------------------------------------------
   Product detail
   -------------------------------------------------------------------------- */

.pdp { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-8); align-items: start; }
/* Unknown ?sku=. Spans both columns and drops the two-up layout — there is
   no product to put beside the message. */
.pdp:has(.pdp__notfound) { grid-template-columns: 1fr; }
.pdp__notfound { padding-block: var(--space-8); max-width: 46ch; }
.pdp__media {
  display: grid; place-items: center;
  background: var(--surface-sunken);
  border: var(--border-width-hair) solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: var(--space-9) var(--space-7);
  aspect-ratio: 1;
}
.pdp__media .bar-art { max-width: 340px; }
/* These were <div>s with cursor:pointer and aria-selected and no handler —
   they looked like a gallery and did nothing. Now they are real buttons in a
   tablist, and site.js only renders the strip when a product actually has
   more than one view. */
.pdp__thumbs { display: flex; gap: var(--space-3); margin-top: var(--space-4); }
.pdp__thumb {
  width: 74px; aspect-ratio: 1;
  display: grid; place-items: center;
  background: var(--surface-sunken);
  border: var(--border-width-hair) solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: var(--space-2);
  cursor: pointer;
  transition: border-color var(--duration-normal) var(--ease-standard);
}
.pdp__thumb:hover { border-color: var(--border-gold-faint); }
.pdp__thumb[aria-selected="true"] { border-color: var(--border-gold); }


/* --------------------------------------------------------------------------
   Price skeleton
   Prices arrive after the spot feed does. The cards render immediately with
   a shimmer where the number goes, so a slow feed costs you the price — not
   the entire catalogue. Sized to the text it replaces so nothing reflows.
   -------------------------------------------------------------------------- */

.price-skel {
  display: inline-block;
  vertical-align: middle;
  min-width: 7ch;
  height: 1em;
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg,
              var(--surface-sunken) 0%,
              color-mix(in srgb, var(--border-gold) 18%, var(--surface-sunken)) 50%,
              var(--surface-sunken) 100%);
  background-size: 200% 100%;
  animation: price-shimmer 1.4s var(--ease-standard) infinite;
}
@keyframes price-shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .price-skel { animation: none; }
}

/* Spot board went stale — the feed stopped answering. The number stays on
   screen (it was true once) but stops looking current. */
[data-spot-stale="true"] .lgx-ticker__value,
[data-spot-stale="true"] .lgx-product__price,
[data-spot-stale="true"] .price-panel__total { opacity: 0.55; }

.price-panel {
  border: var(--border-width-hair) solid var(--border-gold-faint);
  border-radius: var(--radius-sm);
  padding: var(--space-5);
  background: var(--surface-raised);
}
.price-panel__row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-4); padding-block: var(--space-2);
  font-family: var(--font-ui); font-size: var(--text-body-s);
  font-variant-numeric: tabular-nums;
}
.price-panel__row--total {
  border-top: var(--border-width-hair) solid var(--border-subtle);
  margin-top: var(--space-3); padding-top: var(--space-4);
}
.price-panel__total {
  font-size: var(--text-h2); font-weight: var(--weight-semibold);
  font-family: var(--font-ui); line-height: 1;
}
.price-panel__muted { color: var(--text-muted); }

/* The AUD marker beside a figure.
   --------------------------------------------------------------------------
   Not decoration. Intl renders AUD as a bare "$" in both en-AU and zh-CN, so
   the number alone does not say which dollar it is. Every future price surface needs one of these, or a
   column label that does the same job.

   Sized down and muted so it reads as a unit rather than competing with the
   figure, but it is never display:none and never hidden below a breakpoint:
   the smallest screen is exactly where a lone "$" is most likely to be all
   the reader sees. */
.price-ccy {
  margin-left: 0.4em;
  font-size: var(--text-caption);
  font-weight: var(--weight-regular);
  color: var(--text-muted);
  white-space: nowrap;
}

/* The pre-login boundary. Everything past this point needs an account, which
   does not exist yet — so it is stated, not faked with a dead button. */
.gate {
  margin-top: var(--space-5);
  padding: var(--space-5);
  border: var(--border-width-hair) dashed var(--border-gold-faint);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
}
.gate__title {
  font-family: var(--font-ui); font-size: var(--text-caption);
  font-weight: var(--weight-semibold); letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase; color: var(--text-accent); margin: 0 0 var(--space-2);
}
.gate p { margin: 0 0 var(--space-4); font-size: var(--text-body-s); color: var(--text-secondary); }
.gate__actions { display: flex; gap: var(--space-3); flex-wrap: wrap; }

.feature-list { list-style: none; margin: 0; padding: 0;
                display: flex; flex-direction: column; gap: var(--space-3); }
.feature-list li { display: grid; grid-template-columns: 16px 1fr; gap: var(--space-3);
                   font-size: var(--text-body-s); color: var(--text-secondary); }
.feature-list li::before { content: "◆"; color: var(--border-gold); font-size: 8px; line-height: 1.9; }


/* --------------------------------------------------------------------------
   Auth — the Login to Platform screen
   Split: brand panel left, form right. The whole page is the login; there is
   no site chrome to distract from the one thing it does.
   -------------------------------------------------------------------------- */

.auth { display: grid; grid-template-columns: 1fr 1fr; min-height: 100svh; }

.auth__brand {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-8);
  padding: var(--space-7);
}
.auth__brand::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: min(560px, 90%);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle,
              color-mix(in srgb, var(--border-gold) 14%, transparent) 0%,
              transparent 66%);
  pointer-events: none;
}
.auth__brand > * { position: relative; z-index: 1; }
.auth__brand-centre {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-5);
  margin: auto 0;
}
.auth__mark {
  width: clamp(160px, 20vw, 240px);   /* widened for the 2.18:1 lockup */
  color: var(--brand-mark);
  filter: drop-shadow(0 0 28px color-mix(in srgb, var(--border-gold) 30%, transparent));
}
.auth__quote {
  font-family: var(--font-body);
  font-style: italic;
  font-size: clamp(1.25rem, 2vw, 1.75rem);
  line-height: 1.3;
  margin: 0;
  max-width: 20ch;
}
.auth__points { list-style: none; margin: 0; padding: 0;
                display: flex; flex-direction: column; gap: var(--space-3); }
.auth__points li {
  display: grid; grid-template-columns: 14px 1fr; gap: var(--space-3);
  font-family: var(--font-ui); font-size: var(--text-body-s);
  color: var(--text-secondary);
}
.auth__points li::before { content: "◆"; color: var(--border-gold); font-size: 7px; line-height: 2.2; }

.auth__panel {
  display: grid;
  place-items: center;
  padding: var(--space-7);
  background: var(--surface-page);
}
.auth__form { width: 100%; max-width: 400px; }
.auth__head { margin-bottom: var(--space-7); }
.auth__actions {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4); flex-wrap: wrap; margin-top: var(--space-5);
}
.auth__check {
  display: flex; align-items: center; gap: var(--space-2);
  font-family: var(--font-ui); font-size: var(--text-body-s);
  color: var(--text-secondary); cursor: pointer;
}
.auth__check input { accent-color: var(--border-gold); width: 15px; height: 15px; cursor: pointer; }
.auth__submit { width: 100%; margin-top: var(--space-6); }

/* Contact channels — what replaced the login form. Two cards, each a single
   tap to a real channel, because that is genuinely how a client reaches the
   desk until the platform exists. */
.auth__channels {
  display: grid;
  gap: var(--space-4);
  margin-top: var(--space-7);
}
.auth__channel {
  display: grid;
  grid-template-columns: 24px 1fr;
  grid-template-areas:
    "icon  label"
    ".     value"
    ".     note";
  gap: var(--space-1) var(--space-4);
  align-items: center;
  padding: var(--space-5);
  min-height: 44px;
  background: var(--surface-raised);
  border: var(--border-width-hair) solid var(--border-subtle);
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: border-color var(--duration-normal) var(--ease-standard);
}
.auth__channel:hover { border-color: var(--border-gold); }
.auth__channel-icon {
  grid-area: icon;
  width: 20px; height: 20px;
  color: var(--border-gold);
  stroke: currentColor; fill: none; stroke-width: 1.4;
}
.auth__channel-label {
  grid-area: label;
  font-family: var(--font-ui);
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}
[lang^="zh"] .auth__channel-label { text-transform: none; }
.auth__channel-value {
  grid-area: value;
  font-family: var(--font-ui);
  font-size: var(--text-body-l);
  color: var(--text-primary);
}
.auth__channel .lgx-caption { grid-area: note; }
.auth__alt {
  margin-top: var(--space-7); padding-top: var(--space-5);
  border-top: var(--border-width-hair) solid var(--border-subtle);
  font-family: var(--font-ui); font-size: var(--text-body-s); color: var(--text-secondary);
}
/* The login screen has no site header, so the language switch lives up here
   beside the back link — the one row on this page that is navigation. */
.auth__topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4); margin-bottom: var(--space-6);
}
.auth__back {
  display: inline-flex; align-items: center; gap: var(--space-2);
  min-height: 44px;
  font-family: var(--font-ui); font-size: var(--text-caption);
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--text-muted); text-decoration: none;
}
.auth__back:hover { color: var(--text-accent); }
.auth__legal {
  margin-top: var(--space-7);
  font-family: var(--font-ui); font-size: var(--text-caption);
  line-height: 1.7; color: var(--text-muted);
}

@media (max-width: 900px) {
  .auth { grid-template-columns: 1fr; min-height: 0; }
  .auth__brand { padding: var(--space-7) var(--space-5); }
  .auth__brand-centre { margin: 0; }
  .auth__panel { padding: var(--space-7) var(--space-5) var(--space-8); }
  /* Was display:none. These three lines are the only reason a prospect who
     is not yet a client keeps reading — they belong on the small screen more
     than the large one. Laid out as a row of short items instead. */
  .auth__points {
    margin-top: var(--space-6);
    padding-top: var(--space-5);
    border-top: var(--border-width-hair) solid var(--border-subtle);
  }
}


/* --------------------------------------------------------------------------
   Endorsement band — Zhou Liu Fu
   -------------------------------------------------------------------------- */

.endorse { display: grid; grid-template-columns: 1fr 1.4fr; gap: var(--space-8); align-items: center; }
.endorse__seal {
  display: grid; place-items: center; text-align: center;
  aspect-ratio: 1; max-width: 240px; margin-inline: auto;
  border: var(--border-width-hair) solid var(--border-gold-faint);
  border-radius: 50%;
  padding: var(--space-6);
}
.endorse__cn {
  font-family: var(--font-cn-display); font-weight: var(--weight-bold);
  font-size: 2rem; letter-spacing: 0.12em; color: var(--text-accent); line-height: 1.2;
}
.endorse__en {
  font-family: var(--font-ui); font-size: var(--text-caption);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--text-secondary); margin-top: var(--space-3);
}


/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.site-footer { padding-block: var(--space-8) var(--space-6); }
.site-footer__cols {
  display: grid; gap: var(--space-6);
  grid-template-columns: 1.6fr repeat(3, 1fr);
}
/* These were <h5> purely because they look small. Nothing on these pages uses
   h3 or h4, so the document outline jumped h2 → h5. They are <h2> now and the
   class carries the size. */
.site-footer__title {
  font-family: var(--font-ui); font-size: var(--text-caption);
  font-weight: var(--weight-semibold); letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase; color: var(--text-accent); margin: 0 0 var(--space-4);
}
.site-footer ul { list-style: none; margin: 0; padding: 0;
                  display: flex; flex-direction: column; gap: var(--space-2); }
.site-footer a { font-family: var(--font-ui); font-size: var(--text-body-s);
                 color: var(--text-secondary); text-decoration: none; }
.site-footer a:hover { color: var(--text-primary); }
.site-footer__legal {
  margin-top: var(--space-7); padding-top: var(--space-5);
  border-top: var(--border-width-hair) solid var(--border-subtle);
  font-family: var(--font-ui); font-size: var(--text-caption); color: var(--text-muted);
  display: flex; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap;
}
.site-footer__disclaimer {
  margin-top: var(--space-4); font-family: var(--font-ui);
  font-size: var(--text-caption); line-height: 1.7; color: var(--text-muted); max-width: 80ch;
}


/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 1000px) {
  .cat-grid { grid-template-columns: repeat(2, 1fr); }
  .editorial { grid-template-columns: 1fr; gap: var(--space-7); }
  .editorial--flip .editorial__media { order: 0; }
  .hero--split .hero__inner { grid-template-columns: 1fr; }
  /* This used to be display:none. The sealed-bar photograph is the strongest
     asset on the site and phones are most of the traffic — dropping it there
     is backwards. It stacks under the copy at a smaller size instead. */
  .hero__media img { max-width: 300px; }
  .catalogue { grid-template-columns: 1fr; }
  .filters { position: static; }
  .pdp { grid-template-columns: 1fr; gap: var(--space-6); }
  .endorse { grid-template-columns: 1fr; }
  .site-footer__cols { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 760px) {
  .cat-grid { grid-template-columns: 1fr; }

  /* Wrapped, the four ticker items ate the entire first screen. One line that
     scrolls sideways instead. */
  .lgx-ticker {
    flex-wrap: nowrap;
    overflow-x: auto;
    gap: var(--space-5);
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .lgx-ticker::-webkit-scrollbar { display: none; }
  .lgx-ticker__item { flex: none; }

  .site-header__toggle { display: block; }
  .site-nav {
    display: none;
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);        /* was --space-1: 4px, under the 8px minimum */
    padding-block: var(--space-4);
    border-top: var(--border-width-hair) solid var(--border-subtle);
  }
  /* Full-width rows at 44px. Stacked nav items are the easiest thing on a
     phone to mis-tap, and these were 42px tall with 4px between them. */
  .site-nav a {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding-block: 0;
    border-bottom: 0;
    border-left: var(--border-width-rule) solid transparent;
    padding-left: var(--space-4);
  }
  .site-nav a:hover,
  .site-nav a[aria-current="page"] {
    border-bottom-color: transparent;
    border-left-color: var(--border-gold);
  }
  .site-header[data-open="true"] .site-nav { display: flex; }
  .site-header__bar { flex-wrap: wrap; }
  .hero { padding-block: var(--space-8) var(--space-7); }
  .stat { border-right: 0; border-bottom: var(--border-width-hair) solid var(--border-subtle); }
  .contact-row { grid-template-columns: 24px 1fr; }
  .contact-row__label { grid-column: 2; }
  .contact-row__value { grid-column: 2; }
  .site-footer__cols { grid-template-columns: 1fr; }

  /* Stacked, these were 18px rows 8px apart — the densest mis-tap risk left
     on the site. Full-width 44px rows on touch; unchanged on desktop, where
     a pointer makes the density a virtue rather than a hazard. */
  .site-footer ul { gap: 0; }
  .site-footer li a {
    display: flex;
    align-items: center;
    min-height: 44px;
  }
}

@media (max-width: 480px) {
  :root { --text-display-xl: 2.25rem; --text-h1: 1.75rem; --text-h2: 1.5rem; }
  .lgx-lockup__word { font-size: 0.6875rem; letter-spacing: 0.16em; }
  /* Sized by height, not width: 34px suited the old near-square monogram but
     the 周六福 lockup is 2.18:1, and 34px wide left it 16px tall — unreadable
     next to the wordmark. 58px keeps roughly the monogram's cap height. */
  .lgx-lockup__mark { width: 58px; }
  /* nowrap + 0.24em tracking made this single line ~194px, which pushed the
     login button onto a second row and doubled the header height. The footer
     carries the endorsement anyway. */
  .lgx-lockup__word small { display: none; }
  .hero__actions .lgx-btn { width: 100%; }
}
