/* ==========================================================================
   Ariana Precious Stones — Core Stylesheet
   Afghan emeralds & tourmalines · direct from source
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Design tokens
   -------------------------------------------------------------------------- */

:root {
  /* Ink — the jewel-box dark */
  --ink-900: #050807;
  --ink-800: #0a0f0d;
  --ink-700: #101815;
  --ink-600: #17211d;
  --ink-500: #1f2c27;

  /* Bone — the gallery light */
  --bone-100: #fdfcf9;
  --bone-200: #f7f4ed;
  --bone-300: #efeae0;
  --bone-400: #e2dbcd;

  /* Stone hues */
  --emerald-deep: #0a5c40;
  --emerald: #0f7a55;
  --emerald-bright: #2fbf8f;
  --indicolite: #0d6b7d;
  --lagoon: #37a8b6;
  --rubellite: #a8375c;

  /* Metals */
  --gold: #c2a15f;
  --gold-light: #e3cd9a;
  --gold-deep: #8d7238;
  --bronze: #a9855a;
  --gold-ink: #7a6230;

  /* Semantic */
  --bg: var(--ink-900);
  --fg: var(--bone-200);
  --muted: #8b9791;
  --muted-dark: #7b8681;
  --rule: rgba(194, 161, 95, 0.28);
  --rule-soft: rgba(247, 244, 237, 0.1);

  /* A panel, and the same panel hovered or active. These are re-pointed by
     each band below rather than fixed here, because a panel painted an
     absolute ink disappears the moment the band underneath it lands on the
     same value — .capability__item and .office both did.

     They stay opaque. A translucent wash would seem to solve it more neatly,
     but .capability and .offices draw their hairlines by showing --rule-soft
     through 1px grid gaps, and a see-through card stacks that wash under
     itself: the cards lifted far enough to push their own muted text under
     4.5:1. */
  --surface: var(--ink-800);
  --surface-hi: var(--ink-700);

  /* Type */
  --font-display: "Cormorant Garamond", "Iowan Old Style", "Palatino Linotype",
    Palatino, Georgia, "Times New Roman", serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;

  /* Scale — fluid */
  /* The two small steps have a floor set for a phone, not for a desktop.
     At 360px the old scale bottomed out at 11.0px for --step--2 and 13.3px
     for --step--1, and those two carry most of the supporting copy on the
     site: the spec lists, the figure captions, the office rows, the register
     meta. Eleven-pixel text is readable on a 27-inch monitor at arm's length
     and tiring on a phone held at forty centimetres, which is where a buyer
     actually reads this. The desktop end is unchanged to within half a pixel;
     only the small end moves. */
  /* Micro-labels: table headers, tags, filter names, the language button.
     Uppercase and tracked, so they carry at a smaller size than body copy —
     but they had drifted to fifteen separate hard-coded values between 8.0px
     and 9.9px, which is guesswork rather than a scale, and unreadable on a
     phone either way. One step, with a floor of 11.2px. */
  --step--3: clamp(0.7rem, 0.68rem + 0.1vw, 0.78rem);
  --step--2: clamp(0.78rem, 0.74rem + 0.18vw, 0.85rem);
  --step--1: clamp(0.875rem, 0.84rem + 0.16vw, 0.98rem);
  --step-0: clamp(1rem, 0.96rem + 0.2vw, 1.13rem);
  --step-1: clamp(1.2rem, 1.13rem + 0.34vw, 1.5rem);
  --step-2: clamp(1.44rem, 1.33rem + 0.55vw, 2rem);
  --step-3: clamp(1.73rem, 1.55rem + 0.88vw, 2.66rem);
  --step-4: clamp(2.07rem, 1.8rem + 1.36vw, 3.55rem);
  --step-5: clamp(2.49rem, 2.07rem + 2.08vw, 4.73rem);
  --step-6: clamp(2.99rem, 2.36rem + 3.13vw, 6.31rem);

  /* Space */
  --space-3xs: 0.25rem;
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-s: 1rem;
  --space-m: 1.5rem;
  --space-l: 2.25rem;
  --space-xl: 3.5rem;
  --space-2xl: 5rem;
  --space-3xl: 7.5rem;
  --space-4xl: 11rem;

  /* Layout */
  --measure: 68ch;
  --gutter: clamp(1.25rem, 4vw, 3.5rem);
  --max-width: 1360px;
  --max-width-narrow: 940px;

  /* Motion */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 180ms;
  --dur: 420ms;
  --dur-slow: 900ms;

  /* Effects */
  --shadow-soft: 0 1px 2px rgba(0, 0, 0, 0.16), 0 8px 30px rgba(0, 0, 0, 0.22);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, 0.14), 0 24px 60px rgba(0, 0, 0, 0.34);
  --radius: 2px;
  --header-h: 84px;
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.65;
  font-weight: 350;
  letter-spacing: 0.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

body.is-locked {
  overflow: hidden;
}

img,
svg,
video {
  display: block;
  max-width: 100%;
}

img {
  height: auto;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

a {
  color: inherit;
  text-decoration: none;
}

ul,
ol {
  list-style: none;
  padding: 0;
}

:focus-visible {
  outline: 2px solid var(--gold-light);
  outline-offset: 3px;
  border-radius: 1px;
}

::selection {
  background: var(--emerald);
  color: var(--bone-100);
}

hr {
  border: 0;
  border-top: 1px solid var(--rule-soft);
}

/* --------------------------------------------------------------------------
   3. Typography
   -------------------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.012em;
  text-wrap: balance;
}

h1 {
  font-size: var(--step-5);
}
h2 {
  font-size: var(--step-4);
}
h3 {
  font-size: var(--step-2);
  line-height: 1.18;
}
h4 {
  font-size: var(--step-1);
  line-height: 1.3;
}

p {
  text-wrap: pretty;
}

.lede {
  font-size: var(--step-1);
  line-height: 1.55;
  font-weight: 300;
  color: color-mix(in srgb, var(--fg) 88%, transparent);
  max-width: 56ch;
}

.prose {
  max-width: var(--measure);
}

.prose p + p {
  margin-top: 1.15em;
}

.prose strong {
  font-weight: 500;
  color: var(--bone-100);
}

.muted {
  color: var(--muted);
}

.serif {
  font-family: var(--font-display);
}

/* Eyebrow — the letterspaced small-caps label */
.eyebrow {
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--gold);
  display: block;
}

/* Ruled label — echoes the brand's typographic banner */
.rule-label {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(0.75rem, 2vw, 1.5rem);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold);
  text-align: center;
}

.rule-label::before,
.rule-label::after {
  content: "";
  height: 1px;
  flex: 1 1 auto;
  max-width: 92px;
  background: linear-gradient(90deg, transparent, var(--gold));
}

.rule-label::after {
  background: linear-gradient(270deg, transparent, var(--gold));
}

.rule-label--start {
  justify-content: flex-start;
}
.rule-label--start::before {
  display: none;
}
.rule-label--start::after {
  max-width: 64px;
}

/* Drop the first letter on featured editorial */
.dropcap::first-letter {
  font-family: var(--font-display);
  font-size: 3.6em;
  line-height: 0.82;
  float: left;
  padding: 0.06em 0.12em 0 0;
  color: var(--gold);
}

/* Physical float and padding above, so both need flipping — otherwise the cap
   lands at the END of the first line in Hebrew, indenting the wrong edge. */
[dir="rtl"] .dropcap::first-letter {
  float: right;
  padding: 0.06em 0 0 0.12em;
}

/* No drop cap in the cursive Arabic scripts. ::first-letter cuts the opening
   letter out of the word, which breaks the join that the rest of the word is
   drawn to expect — and where the sentence opens on a guillemet, as the Arabic
   does, the cap is set on the punctuation instead. There is no drop-cap
   tradition in this typography to preserve, so the paragraph simply runs on. */
:is([lang="ar"], [lang="fa-AF"], [lang="ps"], [lang="ur"])
  .dropcap:not([lang="en"])::first-letter {
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  float: none;
  padding: 0;
  color: inherit;
}

/* --------------------------------------------------------------------------
   4. Layout primitives
   -------------------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap--narrow {
  max-width: var(--max-width-narrow);
}

.section {
  padding-block: clamp(4rem, 10vw, var(--space-3xl));
  position: relative;
}

.section--tight {
  padding-block: clamp(3rem, 7vw, var(--space-2xl));
}

.section--tall {
  padding-block: clamp(5rem, 13vw, var(--space-4xl));
}

/* Two tones above the page black, breaking a long page into bands. These
   carried bone backgrounds until the house asked for a dark site throughout;
   around forty rules existed only to undo the dark styling on bone, and went
   with them, because the base styles are dark-first and are correct again as
   soon as the background is.

   Each band also lifts --surface, so a panel is always one step above the
   band it sits on rather than a fixed colour that some band will eventually
   match. The ladder stops at ink-500: --muted on anything lighter falls
   under 4.5:1, and --muted carries most of the supporting copy. */

/* Banded sections, kept dark.

   These were --ink-800 and --ink-700. On a page that alternates them the
   lighter one read as a grey slab rather than as a change of ground, and the
   700 in particular carries enough green to look like a different palette
   instead of the same one a shade apart. The band is worth keeping — it stops
   a long page reading as one undifferentiated black — but it only needs to be
   perceptible, not obvious. Both now sit within a couple of steps of the base,
   and the card surfaces inside them move with them so the contrast between a
   card and its section is unchanged. */
.section--deep {
  background: #070b0a;
  --surface: #0c1211;
  --surface-hi: #111917;
}

.section--slate {
  background: #090e0c;
  --surface: #0e1514;
  --surface-hi: #131b19;
}

.section-head {
  display: grid;
  gap: var(--space-m);
  margin-bottom: clamp(2.5rem, 6vw, var(--space-2xl));
}

.section-head--center {
  justify-items: center;
  text-align: center;
}

.section-head--center .lede {
  text-align: center;
}

.section-head--split {
  grid-template-columns: 1fr;
  align-items: end;
}

@media (min-width: 62rem) {
  .section-head--split {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    gap: var(--space-xl);
  }
}

.stack > * + * {
  margin-top: var(--flow, 1.15rem);
}

.grid {
  display: grid;
  gap: var(--space-m);
}

/* Cards in a grid stretch to the tallest by default, which is right when
   they hold comparable amounts of text. It is wrong where one of them holds a
   photograph: on the grading section that left "What we do to a stone" as a
   panel with 440px of nothing under three lines of copy. Opt that one grid
   out rather than every grid, since the others are text against text. */
.grid--top {
  align-items: start;
}

/* align-items alone does nothing here: .tile carries height:100% so that a
   row of tiles fills its tallest, and that resolves against the grid area,
   which is still the row. The height has to go with it. */
.grid--top > .tile {
  height: auto;
}

@media (min-width: 40rem) {
  .grid--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .grid--3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 62rem) {
  .grid--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .grid--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (min-width: 40rem) and (max-width: 61.99rem) {
  .grid--4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Hairline divider with a centred gem lozenge */
.divider {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  color: var(--gold);
}

.divider::before,
.divider::after {
  content: "";
  height: 1px;
  flex: 1;
  background: var(--rule);
}

.divider span {
  width: 7px;
  height: 7px;
  transform: rotate(45deg);
  background: currentColor;
  display: block;
}

/* --------------------------------------------------------------------------
   5. Buttons & links
   -------------------------------------------------------------------------- */

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--bone-100);
  --btn-bd: rgba(247, 244, 237, 0.34);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.7em;
  padding: 0.95em 1.9em;
  /* A thumb needs 44px. The padding alone gave 41 — close enough to look
     right and just short enough to be missed, which is the worst kind of
     wrong on a touch screen. */
  min-height: 46px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bd);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  line-height: 1;
  border-radius: var(--radius);
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition: color var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
  white-space: nowrap;
}

/* On a phone a long label has nowhere to go. The button keeps its text on one
   line, and hides its overflow so the fill animation can sweep across it, so
   anything too long was being cut off mid-word rather than wrapping — silently,
   with no ellipsis to say so. Measured at 360px: the Italian "Vedete cosa è
   realisticamente disponibile" wanted 386px inside a 318px box, and the email
   button was 369px wide on a 360px screen, hanging 29px off the side.

   Wrapping is the honest fix. Shrinking the type is the alternative, and this
   site has already had its small type raised once for being unreadable on a
   phone. The email address is a single unbreakable token, so it needs leave to
   break inside as well. Both are confined to narrow screens: on a desktop the
   labels fit on one line and should stay there. */
@media (max-width: 30rem) {
  .btn {
    white-space: normal;
    overflow-wrap: anywhere;
    line-height: 1.25;
    text-align: center;
    max-width: 100%;
  }
}

.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--btn-fill, var(--bone-100));
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform var(--dur) var(--ease-out);
}

.btn:hover::after,
.btn:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left center;
}

.btn:hover,
.btn:focus-visible {
  color: var(--btn-fg-hover, var(--ink-900));
  border-color: var(--btn-fill, var(--bone-100));
}

.btn:active {
  transform: translateY(1px);
}

.btn--gold {
  --btn-bd: var(--gold);
  --btn-fill: var(--gold);
  --btn-fg: var(--gold-light);
  --btn-fg-hover: var(--ink-900);
}

.btn--solid {
  --btn-bg: var(--emerald);
  --btn-bd: var(--emerald);
  --btn-fill: var(--emerald-bright);
  --btn-fg: var(--bone-100);
  --btn-fg-hover: var(--ink-900);
}

/* Ink on a pale ground. The capability sheet is the only place left that
   needs it — everywhere else the page went dark and the default button,
   which is bone on ink, is the right one. */
.btn--dark {
  --btn-bd: rgba(10, 15, 13, 0.34);
  --btn-fg: var(--ink-800);
  --btn-fill: var(--ink-800);
  --btn-fg-hover: var(--bone-100);
}

.btn--sm {
  padding: 0.72em 1.35em;
  font-size: var(--step--2);
}

.btn--block {
  width: 100%;
}

/* Understated arrow link */
.link {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  /* These are standalone calls to action, never set inside a paragraph, so
     giving them a thumb's height costs no prose rhythm. They were 28px. */
  min-height: 46px;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  padding-bottom: 0.35em;
  position: relative;
  transition: color var(--dur) var(--ease-out);
}

.link::before {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  height: 1px;
  width: 100%;
  background: currentColor;
  transform: scaleX(0.32);
  transform-origin: left;
  transition: transform var(--dur) var(--ease-out);
}

.link:hover::before,
.link:focus-visible::before {
  transform: scaleX(1);
}

.link svg {
  width: 1em;
  height: 1em;
  transition: transform var(--dur) var(--ease-out);
}

.link:hover svg {
  transform: translateX(4px);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  align-items: center;
}

/* --------------------------------------------------------------------------
   6. Header & navigation
   -------------------------------------------------------------------------- */

.skip-link {
  position: absolute;
  left: 50%;
  top: 0;
  translate: -50% -120%;
  z-index: 200;
  background: var(--gold);
  color: var(--ink-900);
  padding: 0.75rem 1.5rem;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  transition: translate var(--dur) var(--ease-out);
}

.skip-link:focus {
  translate: -50% 0;
}

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  /* Above the drawer (120), not below it.
     The burger already has a close state — aria-expanded="true" rotates its
     bars into a cross — but at z-index 100 the whole header, burger included,
     was painted underneath the open drawer. The burger's own z-index of 130
     could not save it: that number only ranks it inside the header's stacking
     context, and the context itself was behind. So the full-screen menu had no
     visible way out, and a tap where the cross should be landed on the drawer.
     Escape and the scrim still worked, which is presumably why it survived. */
  z-index: 140;
  height: var(--header-h);
  display: flex;
  align-items: center;
  transition: background var(--dur) var(--ease-out),
    height var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out),
    backdrop-filter var(--dur) var(--ease-out);
  border-bottom: 1px solid transparent;
}

.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(5, 8, 7, 0.72) 0%,
    rgba(5, 8, 7, 0) 100%
  );
  opacity: 1;
  transition: opacity var(--dur) var(--ease-out);
  pointer-events: none;
}

.site-header.is-stuck {
  height: 68px;
  background: rgba(5, 8, 7, 0.86);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border-bottom-color: var(--rule-soft);
}

.site-header.is-stuck::before {
  opacity: 0;
}

.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  position: relative;
  z-index: 1;
}

/* Wordmark */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  flex-shrink: 0;
  /* 38px without this. It is the one link on every page that a lost reader
     reaches for, so it gets a full thumb. */
  min-height: 46px;
}

.brand__mark {
  width: 30px;
  height: 38px;
  flex-shrink: 0;
  transition: transform var(--dur-slow) var(--ease-out);
}

.brand:hover .brand__mark {
  transform: rotate(-6deg) scale(1.06);
}

.brand__type {
  display: grid;
  gap: 0.14em;
  line-height: 1;
}

.brand__name {
  font-family: var(--font-display);
  font-size: 1.36rem;
  letter-spacing: 0.02em;
  color: var(--bone-100);
  white-space: nowrap;
}

.brand__sub {
  font-size: 0.52rem;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--gold);
  white-space: nowrap;
}

/* Primary nav */
.nav {
  display: none;
}

/* 72rem, not 62rem. The row is brand + seven nav links + language select +
   CTA, and at 62rem those add up to about 1330px of content in a 992px
   header. Nothing wrapped or scrolled — body has overflow-x:hidden, so the
   overflow was simply cut off the right edge and the CTA disappeared. */
@media (min-width: 72rem) {
  .nav {
    display: flex;
    align-items: center;
    gap: clamp(1.2rem, 2.6vw, 2.4rem);
  }
}

.nav a {
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--bone-200) 82%, transparent);
  position: relative;
  padding-block: 0.5rem;
  transition: color var(--dur) var(--ease-out);
  white-space: nowrap;
}

.nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur) var(--ease-out);
}

.nav a:hover,
.nav a[aria-current="page"] {
  color: var(--bone-100);
}

.nav a:hover::after,
.nav a:focus-visible::after,
.nav a[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-s);
}

.header-actions .btn {
  display: none;
}

@media (min-width: 48rem) {
  .header-actions .btn {
    display: inline-flex;
  }
}

/* Between the nav appearing (72rem) and the row genuinely fitting, something
   has to give. The nav is the more useful affordance on a laptop, and this CTA
   is repeated in the hero, the footer and the drawer — so the button stands
   down for that band rather than being clipped.

   Where the row genuinely fits depends on the language, and 87.5rem was only
   ever right for English-length navigation. Measured, by stepping the viewport
   from 1400px up until the button stopped overflowing its own header:

     Russian 1800px · Dutch 1760 · French 1740 · German 1720 · Spanish 1680
     English and Portuguese 1560 · Italian and Turkish 1500
     Arabic, Hebrew, Dari, Pashto, Urdu, Hindi, both Chinese, Japanese,
     Thai — all fit by 1400

   At 1440px, a common laptop, the button was running 52px past the edge in
   English and 133px in German, on every page. So the band now ends at
   112.5rem, and the scripts with shorter navigation get their button back at
   87.5rem where they demonstrably fit. */
@media (min-width: 72rem) and (max-width: 112.49rem) {
  .header-actions .btn {
    display: none;
  }

  /* The same band, tighter navigation. Even without the button the row can
     run out of width: Russian calls itself "Русский", the longest of the
     nineteen endonyms, and at 1200px that pushed the language control 58px
     past the edge of the header. Six gaps between seven nav items, so a
     smaller gap buys back more than the shortfall without the row reading as
     cramped. */
  .nav {
    gap: clamp(0.85rem, 1.6vw, 1.7rem);
  }
}

/* At the very bottom of that band — the width where the navigation has just
   replaced the burger — even the tightened gaps leave Russian 28px short. The
   language control keeps its flag and its caret and drops its label, which is
   the smallest thing that can go: the button still carries its accessible
   name, and the flag alone is unambiguous next to a caret. Six rem of width
   for the sake of one word. */
@media (min-width: 72rem) and (max-width: 78rem) {
  /* Hidden from the eye, not from the accessibility tree. display:none would
     take the label out of the tree entirely and leave the control announcing
     itself as "button" with no name — it is the only text it has. Clipping it
     keeps the name and takes the width. */
  .langpick__btn > span {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

@media (min-width: 87.5rem) and (max-width: 112.49rem) {
  :is([lang="ar"], [lang="he"], [lang="fa-AF"], [lang="ps"], [lang="ur"],
      [lang="hi"], [lang="zh-Hant"], [lang="zh-Hans"], [lang="ja"], [lang="th"])
    .header-actions .btn {
    display: inline-flex;
  }
}

/* Burger */
.burger {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  position: relative;
  z-index: 130;
  margin-right: -10px;
}

/* Must match the .nav breakpoint exactly, or there is a band with neither
   navigation nor a way to open the drawer. */
@media (min-width: 72rem) {
  .burger {
    display: none;
  }
}

.burger span {
  display: block;
  width: 24px;
  height: 1px;
  background: var(--bone-100);
  position: relative;
  transition: background var(--dur-fast) var(--ease-out);
}

.burger span::before,
.burger span::after {
  content: "";
  position: absolute;
  left: 0;
  width: 24px;
  height: 1px;
  background: var(--bone-100);
  transition: transform var(--dur) var(--ease-out);
}

.burger span::before {
  top: -7px;
}
.burger span::after {
  top: 7px;
}

.burger[aria-expanded="true"] span {
  background: transparent;
}

.burger[aria-expanded="true"] span::before {
  transform: translateY(7px) rotate(45deg);
}

.burger[aria-expanded="true"] span::after {
  transform: translateY(-7px) rotate(-45deg);
}

/* Mobile drawer */
.drawer {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: var(--ink-900);
  display: grid;
  grid-template-rows: var(--header-h) 1fr auto;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur) var(--ease-out),
    visibility var(--dur) var(--ease-out);
}

.drawer.is-open {
  opacity: 1;
  visibility: visible;
}

.drawer__inner {
  display: grid;
  /* `safe` matters. Plain `center` centres the overflow too, so on a short
     phone the first item is pushed above the scroll origin and can never be
     reached — the menu simply loses its top entry. `safe center` falls back
     to start-alignment the moment the content is taller than the box. */
  align-content: safe center;
  gap: var(--space-xs);
  padding-inline: var(--gutter);
  padding-block: var(--space-s);
  /* A grid item defaults to min-height:auto, which refuses to shrink below
     its content and pushes the footer off-screen instead of scrolling. */
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.drawer__inner a {
  font-family: var(--font-display);
  /* Seven items plus a footer have to fit a 568px-tall phone, so the size is
     capped against viewport height as well as width. Below that it scrolls,
     which is fine — what is not fine is content you cannot scroll to. */
  font-size: min(var(--step-3), 5.4vh);
  color: var(--bone-200);
  padding-block: 0.26em;
  /* Never below the 44px minimum touch target, however short the screen. */
  min-height: 46px;
  border-bottom: 1px solid var(--rule-soft);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 500ms var(--ease-out), transform 500ms var(--ease-out),
    color var(--dur) var(--ease-out);
}

.drawer.is-open .drawer__inner a {
  opacity: 1;
  transform: none;
  transition-delay: calc(60ms * var(--i, 0) + 100ms);
}

.drawer__inner a:hover,
.drawer__inner a[aria-current="page"] {
  color: var(--gold-light);
}

.drawer__inner a span {
  font-family: var(--font-body);
  font-size: var(--step--3);
  letter-spacing: 0.28em;
  color: var(--muted-dark);
}

.drawer__foot {
  padding: var(--space-s) var(--gutter) var(--space-m);
  display: grid;
  gap: var(--space-xs);
  border-top: 1px solid var(--rule-soft);
}

.drawer__foot a {
  color: var(--gold);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
}

/* --------------------------------------------------------------------------
   7. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-items: center;
  padding-top: calc(var(--header-h) + 2rem);
  padding-bottom: var(--space-2xl);
  overflow: hidden;
  background:
    radial-gradient(
      120% 90% at 50% 42%,
      rgba(15, 122, 85, 0.2) 0%,
      rgba(10, 92, 64, 0.06) 38%,
      transparent 72%
    ),
    var(--ink-900);
}

.hero__grain,
.section--grain::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* overlay blending lifts a dark ground as much as it textures it; at 0.4 the
     grain was doing more lightening than graining */
  opacity: 0.22;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.4'/%3E%3C/svg%3E");
}

.section--grain {
  position: relative;
  isolation: isolate;
}

.hero__glow {
  position: absolute;
  left: 50%;
  top: 46%;
  width: min(78vw, 780px);
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(47, 191, 143, 0.24) 0%,
    rgba(15, 122, 85, 0.12) 34%,
    transparent 66%
  );
  filter: blur(28px);
  animation: breathe 9s var(--ease-in-out) infinite;
  pointer-events: none;
}

@keyframes breathe {
  0%,
  100% {
    transform: scale(1);
    opacity: 0.85;
  }
  50% {
    transform: scale(1.1);
    opacity: 1;
  }
}

.hero__inner {
  position: relative;
  z-index: 2;
  display: grid;
  justify-items: center;
  text-align: center;
  gap: var(--space-m);
}

/* Two-class selector so this wins against `.gem { width: 100% }`,
   which is declared later in the sheet. */
.hero .hero__crystal {
  width: clamp(96px, 15vw, 168px);
  margin-bottom: var(--space-xs);
  filter: drop-shadow(0 18px 44px rgba(15, 122, 85, 0.55));
  animation: float 7s var(--ease-in-out) infinite;
}

@keyframes float {
  0%,
  100% {
    transform: translateY(0) rotate(0deg);
  }
  50% {
    transform: translateY(-14px) rotate(2deg);
  }
}

.hero h1 {
  font-size: var(--step-6);
  font-weight: 300;
  line-height: 0.98;
  max-width: 16ch;
}

.hero h1 em {
  font-style: italic;
  color: var(--gold-light);
}

.hero__lede {
  max-width: 58ch;
  font-size: var(--step-1);
  font-weight: 300;
  color: color-mix(in srgb, var(--bone-200) 78%, transparent);
}

.hero__meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-s) var(--space-l);
  margin-top: var(--space-s);
  font-size: var(--step--2);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
}

.hero__meta li {
  display: flex;
  align-items: center;
  gap: 0.7em;
}

.hero__meta li::before {
  content: "";
  width: 5px;
  height: 5px;
  background: var(--gold);
  transform: rotate(45deg);
  flex-shrink: 0;
}

.hero__scroll {
  /* Fixed, not absolute. The hero is min-height:100svh but its CONTENT runs
     taller than that on a phone, so an absolutely-positioned cue sat at the
     bottom of a 1763px box — below the fold on first paint, and only visible
     once the reader had already started scrolling. Exactly backwards. */
  position: fixed;
  /* Centred under the hero, which is where a scroll cue belongs — it points
     down the middle of the page the reader is about to travel.

     It sat in the right margin before, to guarantee it could never land on
     the hero copy: fixed to the viewport, a centred cue shares a column with
     the centred hero text, and on a short window or a deep translation the two
     can meet. That guarantee is now bought a better way — the cue is only
     shown when there is demonstrably room for it (see the height query below),
     and it leaves the moment the reader starts moving. */
  left: 50%;
  translate: -50% 0;
  bottom: clamp(1.5rem, 4vh, 2.75rem);
  z-index: 2;
  pointer-events: none;
  transition: opacity 400ms var(--ease-out), translate 400ms var(--ease-out);
  display: grid;
  justify-items: center;
  gap: 0.75rem;
  font-size: var(--step--3);
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--muted-dark);
}

/* On a phone the hero copy runs edge to edge, so there is no empty margin for
   the cue to sit in — and none is needed: the content is visibly cut off by
   the fold, which says "scroll" more plainly than the label does. */
@media (max-width: 700px) {
  .hero__scroll { display: none; }
}

/* Gone as soon as the reader starts moving, and it does not come back.
   The horizontal half must be repeated here: `translate` is one property, so
   writing `0 14px` would silently undo the centring above and the cue would
   jump right by half its width on its way out. */
.hero__scroll.is-gone {
  opacity: 0;
  translate: -50% 14px;
}

/* Only shown when the window is tall enough that a centred cue cannot collide
   with the hero copy above it. Short windows — a laptop with the browser
   chrome and a dock, or a landscape phone — simply do not get one, and lose
   nothing: on a short window the content is already visibly cut off by the
   fold, which says "scroll" more plainly than the label does. */
@media (max-height: 700px) {
  .hero__scroll { display: none; }
}

.hero__scroll i {
  display: block;
  width: 1px;
  height: 52px;
  background: linear-gradient(180deg, var(--gold), transparent);
  position: relative;
  overflow: hidden;
}

.hero__scroll i::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--gold-light);
  animation: trickle 2.6s var(--ease-in-out) infinite;
}

@keyframes trickle {
  0% {
    transform: translateY(-100%);
  }
  60%,
  100% {
    transform: translateY(100%);
  }
}

/* Page hero — inner pages */
.page-hero {
  position: relative;
  padding-top: calc(var(--header-h) + clamp(3.5rem, 9vw, 7rem));
  padding-bottom: clamp(3rem, 8vw, 5.5rem);
  background:
    radial-gradient(
      100% 120% at 78% 0%,
      rgba(13, 107, 125, 0.22) 0%,
      transparent 62%
    ),
    radial-gradient(
      90% 100% at 12% 100%,
      rgba(15, 122, 85, 0.16) 0%,
      transparent 60%
    ),
    var(--ink-900);
  overflow: hidden;
  isolation: isolate;
}

.page-hero__inner {
  display: grid;
  gap: var(--space-m);
  max-width: 62ch;
  position: relative;
  z-index: 2;
}

.page-hero h1 {
  font-size: var(--step-5);
  font-weight: 300;
}

/* Two-class selector, for the same reason as `.hero .hero__crystal`. */
.page-hero .page-hero__figure {
  position: absolute;
  right: -4%;
  top: 50%;
  translate: 0 -50%;
  width: min(42vw, 460px);
  opacity: 0.16;
  z-index: 1;
  pointer-events: none;
}

/* Breadcrumb */
.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6em;
  font-size: var(--step--2);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted-dark);
}

.crumbs a:hover {
  color: var(--gold);
}

.crumbs li + li::before {
  content: "/";
  margin-right: 0.6em;
  color: var(--rule);
}

.crumbs li {
  display: flex;
  align-items: center;
}

/* --------------------------------------------------------------------------
   8. Gem rendering (SVG sprite driven)
   -------------------------------------------------------------------------- */

.gem {
  display: block;
  width: 100%;
  height: auto;
  color: var(--gem, var(--emerald));
  filter: drop-shadow(0 12px 26px color-mix(in srgb, var(--gem, var(--emerald)) 42%, transparent));
  transition: transform var(--dur-slow) var(--ease-out),
    filter var(--dur-slow) var(--ease-out);
}

.gem-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Stage — the plinth a stone sits on */
.gem-stage {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  padding: clamp(1.25rem, 4vw, 2.5rem);
  background:
    radial-gradient(
      70% 70% at 50% 46%,
      color-mix(in srgb, var(--gem, var(--emerald)) 22%, transparent) 0%,
      transparent 70%
    ),
    linear-gradient(160deg, var(--ink-700), var(--ink-900));
  overflow: hidden;
  isolation: isolate;
}

.gem-stage::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    115deg,
    transparent 38%,
    rgba(255, 255, 255, 0.06) 48%,
    transparent 58%
  );
  translate: -120% 0;
  transition: translate 1.1s var(--ease-out);
  pointer-events: none;
}

.gem-card:hover .gem-stage::after {
  translate: 120% 0;
}

.gem-stage .gem {
  width: min(62%, 220px);
}

.gem-card:hover .gem {
  transform: scale(1.07) rotate(-2deg);
  filter: drop-shadow(0 18px 40px color-mix(in srgb, var(--gem, var(--emerald)) 62%, transparent));
}

/* --------------------------------------------------------------------------
   9. Cards
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  background: var(--ink-800);
  border: 1px solid var(--rule-soft);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color var(--dur) var(--ease-out),
    transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}

.card:hover {
  border-color: var(--rule);
  transform: translateY(-4px);
  box-shadow: var(--shadow-lift);
}

.card__body {
  padding: clamp(1.25rem, 3vw, 1.9rem);
  display: grid;
  gap: 0.7rem;
}

.card__title {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.15;
}

.card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.1rem;
  font-size: var(--step--2);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.card__foot {
  margin-top: 0.4rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--rule-soft);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.card__price {
  font-family: var(--font-display);
  font-size: var(--step-1);
  color: var(--gold-light);
}

/* Gem card — inventory tile */
.gem-card {
  cursor: pointer;
  text-align: left;
  width: 100%;
  font: inherit;
  color: inherit;
  /* Grid so the body fills the card and the price row can be pinned to the
     bottom — keeps prices aligned across a row when titles wrap unevenly.
     The absolutely-positioned tag is out of flow and creates no track. */
  display: grid;
  grid-template-rows: auto 1fr;
}

.gem-card .card__body {
  grid-template-rows: auto auto 1fr;
}

.gem-card .card__foot {
  align-self: end;
}

.gem-card__tag {
  position: absolute;
  top: 1rem;
  left: 1rem;
  z-index: 2;
  font-size: var(--step--3);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  padding: 0.45em 0.9em;
  background: rgba(5, 8, 7, 0.7);
  backdrop-filter: blur(6px);
  border: 1px solid var(--rule);
  color: var(--gold-light);
}

.gem-card__tag--sold {
  color: var(--muted);
  border-color: var(--rule-soft);
}

.gem-card.is-hidden {
  display: none;
}

/* Feature card — collections landing */
.feature {
  position: relative;
  display: grid;
  align-content: end;
  min-height: clamp(360px, 46vw, 520px);
  padding: clamp(1.5rem, 4vw, 2.75rem);
  overflow: hidden;
  isolation: isolate;
  border: 1px solid var(--rule-soft);
  background: linear-gradient(165deg, var(--ink-700), var(--ink-900));
  transition: border-color var(--dur) var(--ease-out);
}

.feature:hover {
  border-color: var(--rule);
}

.feature::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background: radial-gradient(
    76% 60% at 50% 34%,
    color-mix(in srgb, var(--gem, var(--emerald)) 34%, transparent) 0%,
    transparent 70%
  );
  transition: transform var(--dur-slow) var(--ease-out);
}

.feature:hover::before {
  transform: scale(1.14);
}

.feature__gem {
  position: absolute;
  left: 50%;
  top: 34%;
  translate: -50% -50%;
  width: min(48%, 190px);
  z-index: -1;
  transition: transform var(--dur-slow) var(--ease-out);
}

.feature:hover .feature__gem {
  transform: translateY(-8px) scale(1.05);
}

.feature__body {
  display: grid;
  gap: 0.65rem;
}

.feature h3 {
  font-size: var(--step-3);
}

.feature p {
  color: var(--muted);
  font-size: var(--step--1);
  max-width: 42ch;
}

/* Value / step card */
.tile {
  display: grid;
  /* With height:100% and the default `stretch`, a grid's rows grow to fill
     the tile — so in a row of tiles the short ones pushed their heading into
     the middle while the long one kept its heading at the top, and no two
     titles in a row lined up. Pack to the start and let the slack fall to
     the bottom of the box, where it reads as padding rather than drift. */
  align-content: start;
  gap: var(--space-xs);
  padding: clamp(1.5rem, 3.5vw, 2.25rem);
  border: 1px solid var(--rule-soft);
  background: linear-gradient(
    180deg,
    rgba(23, 33, 29, 0.6),
    rgba(10, 15, 13, 0.3)
  );
  transition: border-color var(--dur) var(--ease-out),
    background var(--dur) var(--ease-out);
  height: 100%;
}

.tile:hover {
  border-color: var(--rule);
  background: linear-gradient(
    180deg,
    rgba(31, 44, 39, 0.7),
    rgba(10, 15, 13, 0.4)
  );
}

.tile__icon {
  width: 34px;
  height: 34px;
  color: var(--gold);
  margin-bottom: 0.3rem;
}

.tile h3 {
  font-size: var(--step-1);
}

.tile p {
  font-size: var(--step--1);
  color: var(--muted);
  line-height: 1.6;
}

.tile__num {
  font-family: var(--font-display);
  font-size: var(--step-3);
  color: var(--gold);
  line-height: 1;
  opacity: 0.85;
}

/* --------------------------------------------------------------------------
   10. Stats
   -------------------------------------------------------------------------- */

.stats {
  display: grid;
  gap: 1px;
  background: var(--rule-soft);
  border-block: 1px solid var(--rule-soft);
}

@media (min-width: 40rem) {
  .stats {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 62rem) {
  .stats {
    grid-template-columns: repeat(4, 1fr);
  }
}

.stat {
  background: var(--bg);
  padding: clamp(1.75rem, 4vw, 2.75rem) clamp(1rem, 3vw, 2rem);
  display: grid;
  gap: 0.5rem;
  justify-items: center;
  text-align: center;
}

.stat__num {
  font-family: var(--font-display);
  font-size: var(--step-4);
  line-height: 1;
  color: var(--gold-light);
  font-weight: 300;
}

.stat__label {
  font-size: var(--step--2);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --------------------------------------------------------------------------
   11. Marquee
   -------------------------------------------------------------------------- */

.marquee {
  overflow: hidden;
  border-block: 1px solid var(--rule-soft);
  padding-block: 1.35rem;
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent,
    #000 12%,
    #000 88%,
    transparent
  );
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}

.marquee__track {
  display: flex;
  width: max-content;
  animation: slide 46s linear infinite;
}

.marquee:hover .marquee__track {
  animation-play-state: paused;
}

@keyframes slide {
  to {
    transform: translateX(-50%);
  }
}

.marquee__group {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.marquee__item {
  display: inline-flex;
  align-items: center;
  gap: 1.6rem;
  padding-inline: 1.6rem;
  font-family: var(--font-display);
  font-size: var(--step-1);
  color: color-mix(in srgb, var(--fg) 62%, transparent);
  white-space: nowrap;
}

.marquee__item::after {
  content: "";
  width: 6px;
  height: 6px;
  transform: rotate(45deg);
  background: var(--gold);
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   12. Split / editorial blocks
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  gap: clamp(2rem, 6vw, var(--space-2xl));
  align-items: center;
}

@media (min-width: 62rem) {
  .split {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .split--wide-left {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  }
  .split--wide-right {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  }
  .split__media--first {
    order: -1;
  }
}

/* Grid items carry min-width: auto, which refuses to shrink a column below
   its longest word. The two-column rules above already guard against it with
   minmax(0, 1fr); the single-column phone layout did not, and there it is
   worse — the column simply grows past the viewport and body's overflow-x:
   hidden clips the text off the edge rather than scrolling to it.
   Invisible in English, where no word is long enough to trigger it. Measured
   at 360px it pushed the copy 59px off the edge in German, 47 in Italian,
   33 in French, 26 in Spanish, 21 in Dutch and 19 in Russian. */
.split > *,
.split__body > * {
  min-width: 0;
}

.split__body {
  display: grid;
  gap: var(--space-m);
  align-content: start;
}

.frame {
  position: relative;
  padding: clamp(1rem, 3vw, 2rem);
  border: 1px solid var(--rule);
  isolation: isolate;
}

.frame::before {
  content: "";
  position: absolute;
  inset: clamp(0.5rem, 1.5vw, 0.9rem);
  border: 1px solid var(--rule-soft);
  pointer-events: none;
}

.frame__inner {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  background: radial-gradient(
    62% 62% at 50% 46%,
    color-mix(in srgb, var(--gem, var(--emerald)) 28%, transparent) 0%,
    transparent 72%
  );
}

.frame__inner .gem {
  width: min(60%, 260px);
  animation: float 8s var(--ease-in-out) infinite;
}

/* Spec list — used for stone attributes */
.specs {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--rule-soft);
}

.specs div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding-block: 0.85rem;
  border-bottom: 1px solid var(--rule-soft);
  font-size: var(--step--1);
}

.specs dt {
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-size: var(--step--2);
  color: var(--muted);
}

.specs dd {
  margin: 0;
  text-align: right;
  font-family: var(--font-display);
  font-size: var(--step-0);
  color: var(--bone-100);
}

/* --------------------------------------------------------------------------
   13. Origin map
   -------------------------------------------------------------------------- */

.map {
  position: relative;
  width: 100%;
}

.map svg {
  width: 100%;
  height: auto;
  overflow: visible;
}

.map__outline {
  fill: rgba(31, 44, 39, 0.55);
  stroke: var(--rule);
  stroke-width: 1.5;
  stroke-linejoin: round;
}

.map__pin {
  cursor: pointer;
}

.map__pin circle {
  transition: r var(--dur) var(--ease-out), opacity var(--dur) var(--ease-out);
}

.map__pin .halo {
  fill: var(--pin, var(--emerald-bright));
  opacity: 0.16;
  animation: pulse 3.2s var(--ease-in-out) infinite;
  animation-delay: var(--delay, 0s);
}

.map__pin .dot {
  fill: var(--pin, var(--emerald-bright));
}

.map__pin:hover .halo,
.map__pin.is-active .halo {
  opacity: 0.34;
}

@keyframes pulse {
  0%,
  100% {
    transform: scale(1);
    opacity: 0.14;
  }
  50% {
    transform: scale(1.5);
    opacity: 0.3;
  }
}

.map__label {
  font-family: var(--font-body);
  font-size: 9px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  fill: var(--bone-200);
}

.map__leader {
  stroke: var(--rule);
  stroke-width: 1;
}

.origin-list {
  display: grid;
  gap: 1px;
  background: var(--rule-soft);
  border: 1px solid var(--rule-soft);
}

.origin-list button {
  display: grid;
  gap: 0.4rem;
  padding: clamp(1.1rem, 3vw, 1.6rem);
  text-align: left;
  background: var(--surface);
  transition: background var(--dur) var(--ease-out);
  width: 100%;
}

.origin-list button:hover,
.origin-list button.is-active {
  background: var(--surface-hi);
}

.origin-list button.is-active {
  box-shadow: inset 3px 0 0 var(--pin, var(--emerald-bright));
}

.origin-list h3 {
  font-size: var(--step-1);
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.origin-list h3::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--pin, var(--emerald-bright));
  flex-shrink: 0;
}

.origin-list p {
  font-size: var(--step--1);
  color: var(--muted);
  line-height: 1.55;
}

/* --------------------------------------------------------------------------
   14. Process timeline
   -------------------------------------------------------------------------- */

.timeline {
  display: grid;
  gap: 0;
  counter-reset: step;
  position: relative;
}

.timeline__item {
  display: grid;
  gap: var(--space-xs);
  grid-template-columns: auto 1fr;
  column-gap: clamp(1.25rem, 4vw, 2.5rem);
  padding-block: clamp(1.5rem, 4vw, 2.5rem);
  border-top: 1px solid var(--rule-soft);
  align-items: start;
}

.timeline__item:last-child {
  border-bottom: 1px solid var(--rule-soft);
}

.timeline__num {
  font-family: var(--font-display);
  font-size: var(--step-2);
  color: var(--gold);
  line-height: 1;
  padding-top: 0.1em;
  min-width: 2.4ch;
  opacity: 0.9;
}

.timeline__body {
  display: grid;
  gap: 0.5rem;
}

.timeline__body h3 {
  font-size: var(--step-1);
}

.timeline__body p {
  color: var(--muted);
  font-size: var(--step--1);
  max-width: 62ch;
}

@media (min-width: 62rem) {
  .timeline--split .timeline__item {
    grid-template-columns: auto minmax(0, 22ch) minmax(0, 1fr);
  }
  .timeline--split .timeline__body {
    display: contents;
  }
  .timeline--split .timeline__body h3 {
    align-self: start;
  }
}

/* --------------------------------------------------------------------------
   15. Filters
   -------------------------------------------------------------------------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
  align-items: flex-end;
  justify-content: space-between;
  padding-bottom: var(--space-m);
  border-bottom: 1px solid var(--rule-soft);
  margin-bottom: var(--space-xl);
}

.filter-group {
  display: grid;
  gap: 0.7rem;
}

.filter-group__label {
  font-size: var(--step--3);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--muted-dark);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.chip {
  padding: 0.55em 1.1em;
  border: 1px solid var(--rule-soft);
  font-size: var(--step--2);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  border-radius: 100px;
  transition: color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
  white-space: nowrap;
}

.chip:hover {
  color: var(--bone-100);
  border-color: var(--rule);
}

.chip[aria-pressed="true"] {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--ink-900);
  font-weight: 500;
}

.result-count {
  font-size: var(--step--1);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.empty-state {
  padding: var(--space-2xl) 0;
  text-align: center;
  display: grid;
  gap: var(--space-s);
  justify-items: center;
}

.empty-state[hidden] {
  display: none;
}

/* --------------------------------------------------------------------------
   16. Lightbox / stone detail
   -------------------------------------------------------------------------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: grid;
  place-items: center;
  padding: var(--gutter);
  background: rgba(5, 8, 7, 0.9);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur) var(--ease-out),
    visibility var(--dur) var(--ease-out);
}

.lightbox.is-open {
  opacity: 1;
  visibility: visible;
}

.lightbox__panel {
  position: relative;
  width: min(100%, 980px);
  max-height: 88svh;
  overflow-y: auto;
  background: var(--ink-800);
  border: 1px solid var(--rule);
  display: grid;
  transform: translateY(24px) scale(0.98);
  transition: transform var(--dur) var(--ease-out);
}

.lightbox.is-open .lightbox__panel {
  transform: none;
}

@media (min-width: 52rem) {
  .lightbox__panel {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
}

.lightbox__media {
  display: grid;
  place-items: center;
  padding: clamp(2rem, 6vw, 3.5rem);
  background: radial-gradient(
      68% 68% at 50% 46%,
      color-mix(in srgb, var(--gem, var(--emerald)) 30%, transparent) 0%,
      transparent 72%
    ),
    var(--ink-900);
  min-height: 260px;
}

.lightbox__media .gem {
  width: min(72%, 260px);
  animation: float 7s var(--ease-in-out) infinite;
}

.lightbox__body {
  padding: clamp(1.75rem, 5vw, 3rem);
  display: grid;
  gap: var(--space-m);
  align-content: start;
}

.lightbox__close {
  position: absolute;
  top: 0.85rem;
  right: 0.85rem;
  z-index: 3;
  /* 44, not 40. It is the only way out of a modal on a touch screen, and the
     rest of the site was already raised to 44 for exactly this reason — this
     one sat inside the dialog and was missed. */
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule-soft);
  background: rgba(5, 8, 7, 0.6);
  color: var(--bone-200);
  border-radius: 50%;
  transition: background var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.lightbox__close:hover {
  background: var(--gold);
  color: var(--ink-900);
  transform: rotate(90deg);
}

/* --------------------------------------------------------------------------
   17. Testimonials
   -------------------------------------------------------------------------- */

.quote {
  display: grid;
  gap: var(--space-m);
  padding: clamp(1.75rem, 4vw, 2.5rem);
  border: 1px solid var(--rule-soft);
  background: linear-gradient(180deg, rgba(23, 33, 29, 0.5), transparent);
  height: 100%;
  align-content: start;
}

.quote__mark {
  font-family: var(--font-display);
  font-size: 3.4rem;
  line-height: 0.6;
  color: var(--gold);
  opacity: 0.55;
  height: 0.5em;
}

.quote p {
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.42;
  font-style: italic;
  color: var(--bone-100);
}

.quote footer {
  display: grid;
  gap: 0.2rem;
  font-size: var(--step--2);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  padding-top: 0.6rem;
  border-top: 1px solid var(--rule-soft);
}

.quote cite {
  font-style: normal;
  color: var(--gold-light);
}

.field {
  display: grid;
  gap: 0.5rem;
}

.field label {
  font-size: 0.72rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 0.9rem 1rem;
  background: rgba(5, 8, 7, 0.4);
  border: 1px solid var(--rule-soft);
  border-radius: var(--radius);
  color: var(--bone-100);
  font-size: var(--step-0);
  font-weight: 300;
  transition: border-color var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
}

.field textarea {
  min-height: 148px;
  resize: vertical;
  line-height: 1.6;
}

.field select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23c2a15f' stroke-width='1.5'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  background-size: 12px;
  padding-right: 2.5rem;
  cursor: pointer;
}

.field input::placeholder,
.field textarea::placeholder {
  color: var(--muted-dark);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--gold);
  background: rgba(5, 8, 7, 0.6);
}

.form__note {
  font-size: var(--step--2);
  color: var(--muted-dark);
  line-height: 1.6;
}

/* --------------------------------------------------------------------------
   19. Contact panel
   -------------------------------------------------------------------------- */

.contact-grid {
  display: grid;
  gap: clamp(2rem, 6vw, 4rem);
}

@media (min-width: 62rem) {
  .contact-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  }

  /* The right column held the enquiry form. Without it there are four short
     paragraphs against a left column of eight items — at 1440px that left
     roughly 760px of nothing beside the details, and the address scrolled out
     of sight exactly when a reader had finished deciding to use it.

     Sticky rather than restructured: the one thing this page is for is the
     address, and this keeps it beside the reader the whole way down. */
  .contact-grid > :last-child {
    position: sticky;
    top: calc(var(--header-h) + 2rem);
    align-self: start;
  }
}

/* A sticky panel needs somewhere to stick. If the viewport is shorter than the
   panel the reader can never see its foot, so it only applies when there is
   room — and it is switched off entirely for print, where nothing scrolls. */
@media (min-width: 62rem) and (max-height: 40rem) {
  .contact-grid > :last-child { position: static; }
}

@media print {
  .contact-grid > :last-child { position: static; }
}

.contact-list {
  display: grid;
  gap: var(--space-l);
}

.contact-item {
  display: grid;
  gap: 0.4rem;
  padding-bottom: var(--space-m);
  border-bottom: 1px solid var(--rule-soft);
}

.contact-item h3 {
  font-size: 0.72rem;
  font-family: var(--font-body);
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--muted-dark);
  font-weight: 500;
}

.contact-item a,
.contact-item p {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.3;
  color: var(--bone-100);
  transition: color var(--dur) var(--ease-out);
  word-break: break-word;
}

.contact-item a:hover {
  color: var(--gold);
}

.contact-item small {
  font-family: var(--font-body);
  font-size: var(--step--1);
  color: var(--muted);
  line-height: 1.5;
}

/* --------------------------------------------------------------------------
   20. CTA band
   -------------------------------------------------------------------------- */

.cta {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(140deg, var(--ink-700) 0%, var(--ink-900) 60%);
  border-block: 1px solid var(--rule-soft);
}

.cta::before {
  content: "";
  position: absolute;
  inset: -30% -10% auto auto;
  width: min(60vw, 620px);
  aspect-ratio: 1;
  background: radial-gradient(
    circle,
    rgba(13, 107, 125, 0.3),
    transparent 66%
  );
  filter: blur(16px);
  z-index: -1;
}

.cta::after {
  content: "";
  position: absolute;
  inset: auto auto -40% -10%;
  width: min(55vw, 560px);
  aspect-ratio: 1;
  background: radial-gradient(circle, rgba(15, 122, 85, 0.26), transparent 66%);
  filter: blur(16px);
  z-index: -1;
}

.cta__inner {
  display: grid;
  gap: var(--space-m);
  justify-items: center;
  text-align: center;
  max-width: 62ch;
  margin-inline: auto;
}

.cta h2 {
  font-size: var(--step-4);
  font-weight: 300;
}

/* --------------------------------------------------------------------------
   21. Footer
   -------------------------------------------------------------------------- */

.site-footer {
  background: var(--ink-900);
  border-top: 1px solid var(--rule-soft);
  padding-top: clamp(3rem, 8vw, var(--space-2xl));
}

.footer-grid {
  display: grid;
  gap: var(--space-xl);
  padding-bottom: var(--space-xl);
}

@media (min-width: 48rem) {
  .footer-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 68rem) {
  .footer-grid {
    grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
    gap: var(--space-l);
  }
}

.footer-brand {
  display: grid;
  gap: var(--space-m);
  align-content: start;
  max-width: 42ch;
}

.footer-brand p {
  font-size: var(--step--1);
  color: var(--muted);
  line-height: 1.7;
}

.footer-emblem {
  width: 160px;
  color: var(--gold);
}

.footer-col h3 {
  font-family: var(--font-body);
  font-size: var(--step--3);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--gold);
  font-weight: 500;
  margin-bottom: var(--space-s);
}

.footer-col ul {
  display: grid;
  gap: 0.65rem;
}

.footer-col a,
.footer-col li {
  font-size: var(--step--1);
  color: var(--muted);
  transition: color var(--dur-fast) var(--ease-out);
  line-height: 1.5;
}

.footer-col a:hover {
  color: var(--bone-100);
}

.footer-bottom {
  border-top: 1px solid var(--rule-soft);
  padding-block: var(--space-m);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s) var(--space-l);
  align-items: center;
  justify-content: space-between;
  font-size: var(--step--2);
  color: var(--muted-dark);
}

.footer-bottom ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
}

.footer-bottom a:hover {
  color: var(--gold);
}

.socials {
  display: flex;
  gap: 0.6rem;
}

.socials a {
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule-soft);
  border-radius: 50%;
  color: var(--muted);
  transition: color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.socials a:hover {
  color: var(--gold);
  border-color: var(--gold);
  transform: translateY(-2px);
}

.socials svg {
  width: 16px;
  height: 16px;
}

/* --------------------------------------------------------------------------
   22. Utilities & motion
   -------------------------------------------------------------------------- */

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.text-center {
  text-align: center;
}

.center-x {
  margin-inline: auto;
}

/* Scroll reveal.
   Every hiding rule is scoped to `.js`, which an inline script in <head>
   puts on <html>. Without JavaScript the class never lands, nothing is
   hidden, and the page renders in full — rather than sitting at opacity 0
   waiting for an observer that will never run. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 900ms var(--ease-out), transform 900ms var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}

.js [data-reveal="fade"] {
  transform: none;
}

.js [data-reveal="left"] {
  transform: translateX(-28px);
}

.js [data-reveal="right"] {
  transform: translateX(28px);
}

.js [data-reveal="scale"] {
  transform: scale(0.96);
}

/* Declared after the variants, and one class heavier, so it always wins */
.js [data-reveal].is-visible {
  opacity: 1;
  transform: none;
}

/* Stagger helper */
.js [data-stagger] > * {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 800ms var(--ease-out), transform 800ms var(--ease-out);
}

.js [data-stagger].is-visible > * {
  opacity: 1;
  transform: none;
}

.js [data-stagger].is-visible > *:nth-child(1) { transition-delay: 0ms; }
.js [data-stagger].is-visible > *:nth-child(2) { transition-delay: 90ms; }
.js [data-stagger].is-visible > *:nth-child(3) { transition-delay: 180ms; }
.js [data-stagger].is-visible > *:nth-child(4) { transition-delay: 270ms; }
.js [data-stagger].is-visible > *:nth-child(5) { transition-delay: 360ms; }
.js [data-stagger].is-visible > *:nth-child(6) { transition-delay: 450ms; }
.js [data-stagger].is-visible > *:nth-child(7) { transition-delay: 540ms; }
.js [data-stagger].is-visible > *:nth-child(8) { transition-delay: 630ms; }
.js [data-stagger].is-visible > *:nth-child(9) { transition-delay: 720ms; }

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .js [data-reveal],
  .js [data-stagger] > * {
    opacity: 1 !important;
    transform: none !important;
  }
}

@media print {
  .site-header,
  .drawer,
  .hero__scroll,
  .cta,
  .socials {
    display: none !important;
  }

  /* Only the capability sheet is designed for paper, and it brings its own
     treatment. But browsers drop background colours when printing, so a
     reader who prints any other page gets a dark-theme palette on white:
     pale grey body copy, gold that reads as beige. Swap in the same light
     tokens the sheet uses so the page at least stays readable. */
  body {
    background: #fff;
    color: #000;
    --fg: #0a0f0d;
    --muted: #55605b;
    --muted-dark: #66716c;
    --gold: var(--gold-ink);
    --gold-light: var(--gold-deep);
    --rule: rgba(122, 98, 48, 0.38);
    --rule-soft: rgba(10, 15, 13, 0.14);
    --surface: #fff;
    --surface-hi: #f2efe8;
  }

  .section--deep,
  .section--slate,
  .section--grain {
    background: #fff;
  }
}


/* ═══════════════ Traced stones ═══════════════
   Three layers in the same box, and only one of them is ever visible.

   Underneath, untouched, is the SVG the site has always shipped: it is what a
   reader sees with JavaScript off, or if these files never arrive. Over it, a
   still rendered at build time — that is what nearly everyone sees, nearly all
   of the time, and it costs one small image. Over that, a canvas that only
   exists once somebody has pointed at the stone, and only while they are.

   Each fades in over the one below rather than replacing it, so nothing ever
   flashes a hole while it waits for something to load. */
/* The traced stone IS the element: a canvas that replaces the <svg> in the
   same box, with the same classes, so the stylesheet cannot tell them apart.
   It is visible from the moment it exists — first as the loading pulse
   (below), then as the stone. The old rule here hid every .gem3d until a
   "live" class that no longer exists: that was the invisible-stones bug. */
.gem { transition: opacity var(--dur, .28s) var(--ease-out, ease),
                   transform var(--dur-slow, .5s) var(--ease-out, ease),
                   filter var(--dur-slow, .5s) var(--ease-out, ease); }

@media (prefers-reduced-motion: reduce) {
  .gem3d, .gem { transition: none; }
}

/* ═══════════════ Touch and small screens ═══════════════
   Two things the phone audit turned up, and one it got wrong.

   Wrong first: it counted twenty-odd tap targets under forty pixels on every
   page and called them all faults. Nineteen of them are links inside running
   prose, where the forty-four-pixel guideline does not apply — it is for
   standalone controls, and padding an inline link to that height wrecks the
   line spacing of the paragraph around it. Left alone deliberately.

   The two that are real are the standalone ones: a bare link acting as a
   control, and the <summary> that opens a disclosure. Both were about twenty
   pixels tall, which is a genuinely difficult thing to hit with a thumb. They
   get a proper target on touch devices only, so nothing changes for a mouse.

   And the text: the specification tables and tool labels sat at 11.3px, with
   the wordmark's second line at 8.3px. That is fine on a desk and too small in
   a hand — forty-eight cells of it on the studio page alone. */
@media (pointer: coarse) {
  .prose a,
  p a, li a, dd a { /* left as they are: inline prose, see above */ }

  main summary,
  .accordion__head,
  a.link, a.arrow-link, .link--quiet {
    min-height: 46px;
    display: inline-flex;
    align-items: center;
  }
}

/* In pixels, not rem. This site scales its root font-size, so a rem-based
   breakpoint is measured against a moving ruler — 40rem resolved somewhere
   other than intended and the table rules never applied at all, which the
   check caught because the count of small text went UP rather than down. */
@media (max-width: 640px) {
  table.matrix td, table.matrix th,
  table td, table th, .matrix td, .matrix th {
    font-size: 13px;      /* readable in a hand, still clearly tabular */
  }
  .control__label { font-size: 13px; }
  .brand__sub { font-size: 10px; letter-spacing: 0.22em; }
  .sizer__scalebar { font-size: 12px; }
  .matrix, .matrix tbody, .matrix thead { font-size: 13px; }

  /* Raise the bottom of the type scale rather than the elements sitting on it.

     The smallest step bottoms out at 11.2px, and on a phone that step is
     carrying real work: the footer headings, the card tags, the filter
     labels and the tile numbers all take their size from it. Chasing those
     selectors one at a time was the first attempt and it kept finding more —
     they have one cause, so they get one fix, and anything added later that
     uses the step inherits it.

     The tracking comes down as the size goes up. These are uppercase labels
     set at 0.28em, which is a judgement made for 11px; keeping it at 12px
     widens every one of them by about a character, and .gem-card__tag is
     absolutely positioned over a corner with no room to grow into. */
  :root { --step--3: 0.75rem; }
  .footer-col h3,
  .gem-card__tag,
  .filter-group__label { letter-spacing: 0.2em; }
}

/* The carat sizer's shape control carries the whole cut range now — two dozen
   buttons, not six — so it has to be allowed to wrap. A segmented control is
   normally a single row by definition, and left as one this became a
   horizontally scrolling strip that hid most of the range behind a gesture
   nobody would think to make. */
.segmented--wrap {
  flex-wrap: wrap;
}

/* ---------- the range of cuts, on the collections page ---------------- */

/* auto-fill rather than a fixed column count: twenty-five tiles want four
   across on a laptop, two on a phone and six on a wide screen, and none of
   those is worth a breakpoint of its own. */
.cut-range {
  list-style: none;
  margin: var(--space-l) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--space-m);
}

.cut-tile {
  display: grid;
  justify-items: center;
  gap: 0.35rem;
  padding: var(--space-s) 0.5rem var(--space-m);
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--ink-800);
  text-align: center;
}

/* The stone sets its own height; the tile must not stretch it, or the
   traced canvas is handed a box with the wrong aspect and the stone comes
   out of the tracer already squashed. */
.cut-tile .gem {
  width: 96px;
  height: 96px;
  flex: none;
}

.cut-tile__name {
  font-size: var(--step--1);
  font-weight: 500;
  color: var(--bone);
}

.cut-tile__family {
  font-size: var(--step--3);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted-dark);
}

/* ---------- the colour explorer's draggable range --------------------- */

/* The track carries the variety's own gradient, set from JS as --track, so
   the control shows the range before you touch it. */
input[type="range"].spectrum__range {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  margin: var(--space-s) 0 0;
  /* 44px tall because it is DRAGGED, not tapped: the check flagged it at 26
     and a finger needs the same room to grab a slider as to hit a button. The
     visible track stays 14px and is centred in that box, so the control looks
     the same and is twice as easy to catch. */
  height: 44px;
  background: transparent;
  cursor: grab;
}
input[type="range"].spectrum__range:active { cursor: grabbing; }

input[type="range"].spectrum__range::-webkit-slider-runnable-track {
  height: 14px;
  border-radius: 2px;
  border: 1px solid var(--line);
  background: var(--track, var(--ink-700));
}
input[type="range"].spectrum__range::-moz-range-track {
  height: 14px;
  border-radius: 2px;
  border: 1px solid var(--line);
  background: var(--track, var(--ink-700));
}

/* A thin bright bar rather than a round knob: it reads as a position on a
   spectrum, and it does not hide the colour underneath it the way a disc
   the width of the track would. */
input[type="range"].spectrum__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 4px;
  height: 30px;
  margin-top: -9px;
  border-radius: 1px;
  background: var(--bone);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.55);
}
input[type="range"].spectrum__range::-moz-range-thumb {
  width: 4px;
  height: 30px;
  border: none;
  border-radius: 1px;
  background: var(--bone);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.55);
}

input[type="range"].spectrum__range:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* ---------- stones can be picked up and turned ------------------------ */

/* The cursor is the only thing telling a reader the stone is theirs to move.
   Applied by gem3d.js rather than in the markup, so it appears only when a
   tracer is actually going to respond to the pointer — a grab cursor over a
   flat drawing that cannot move is worse than no cursor at all. */
.gem--grabbable { cursor: grab; }
.gem--grabbable.is-turning { cursor: grabbing; }

/* A stone being turned should not also be selecting the text around it. */
.gem--grabbable.is-turning,
.gem--grabbable.is-turning * { user-select: none; -webkit-user-select: none; }

/* ---------- contact: long values must not push the page wide ----------- */

/* A grid or flex item defaults to min-width:auto, which means it refuses to
   shrink below the widest unbreakable thing inside it. On the contact page
   that thing is info@arianapreciousstones.com — 31 characters with nowhere to
   break — so on a phone the whole column was forced 28px wider than the
   screen and EVERY line in it was clipped at the right edge, not just the
   address. The lines looked individually fine, which is why it read as text
   escaping its box rather than as a layout that was too wide.

   Two parts, and both are needed: let the items shrink, and give the long
   tokens somewhere to break. */
.contact-grid,
.contact-grid > *,
.offices,
.offices > * {
  min-width: 0;
}

/* Addresses, URLs and phone numbers break anywhere rather than overhang.

   Scoped to .contact-grid at first, which missed the case that prompted it:
   the same address also sits inside a numbered card in a .grid--3 further
   down, where it ran past the card border. An email address should never
   overhang its container anywhere on the site, so the rule is not scoped to a
   component — it follows the thing that actually causes the problem, which is
   a long unbreakable token.

   Applied to those values only. Setting ordinary prose to break "anywhere"
   would split words mid-syllable for no reason. */
a[href^="mailto:"],
a[href^="tel:"],
.contact-value {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* ---------- the house's own material ---------------------------------- */

/* The clip is portrait phone footage. Rather than stretch it, it sits in a
   wide band and is cropped by object-fit, so the parcel fills the width and
   the band keeps a shape that suits the page. */
/* The clip is 352x640 off a phone. Stretched across a 21:9 band it was being
   upscaled three and a half times, and no encode setting rescues that — the
   detail is not in the file. So it is shown at close to its own size instead,
   in its own portrait shape, where every pixel is a real one. */
.house-video {
  margin-top: var(--space-l);
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
  background: var(--ink-900);
  /* 4:5, not the clip's native 11:20. The parcel fills the middle of the
     frame, so cropping the top and bottom loses nothing and brings the
     column down to roughly the height of the copy beside it — which is what
     stops the section reading as a tall picture with a gap next to it. */
  aspect-ratio: 4 / 5;
  max-width: 340px;
}
.house-video video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

@media (max-width: 640px) {
  .house-video { max-width: 100%; }
}

/* A reader who has asked for less motion should not be handed a loop. The
   poster still shows, because it is a still frame of the same parcel. */
@media (prefers-reduced-motion: reduce) {
  .house-video video { display: none; }
  .house-video {
    background-image: url("../video/parcel-poster.webp");
    background-size: cover;
    background-position: center;
  }
}

.house-strip {
  list-style: none;
  margin: var(--space-l) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-m);
}
.house-strip li {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
  background: var(--ink-800);
}
/* No fixed aspect ratio and no cover. Forcing every one of these into a 4:3
   box meant cropping some a second time and, worse, stretching the small ones
   past their own pixel width — the same upscaling mistake that made the first
   import look soft, just moved into CSS. They are laid out in columns and each
   keeps its own shape. */
.house-strip img {
  display: block;
  width: 100%;
  height: auto;
}

/* A masonry-ish column flow, so portraits and landscapes sit together without
   any of them being cropped to match. */
/* Equal height, natural width. A masonry column flow was tried first and left
   large ragged holes wherever a portrait sat next to a landscape — the images
   have wildly different shapes, so matching their heights is the only thing
   that lines them up without cropping any of them. */
.house-strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
  align-items: flex-start;
}
.house-strip li { flex: 0 1 auto; }
.house-strip img {
  height: 300px;
  width: auto;
  max-width: 100%;
}
@media (max-width: 640px) {
  .house-strip img { height: auto; width: 100%; }
}

/* ---------- corrections after looking at the rendered page ------------- */


/* The clip is portrait and was sitting alone in a full-width band, so most of
   the section was empty. It goes beside the copy instead, which is what the
   space was for. */
.house-video-row {
  display: grid;
  gap: var(--space-l);
  align-items: start;
}
@media (min-width: 52rem) {
  .house-video-row { grid-template-columns: 352px minmax(0, 1fr); }
}
.house-video { margin-top: 0; }

/* A single photograph placed in the flow of a page, sized to its own pixels
   and never beyond them. */
/* Never wider than 420px and never taller than a screenful. These are phone
   photographs of 600-960px; shown large they are both soft and marooned in an
   empty section, which is exactly how they looked. */
.house-single {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: 3px;
  overflow: hidden;
  background: var(--ink-800);
  max-width: 420px;
}
.house-single img { max-height: 60vh; width: auto; max-width: 100%; }
[data-house-single] { padding-block: var(--space-l); }
.house-single img { display: block; width: 100%; height: auto; }

/* ---------- the language offer ---------------------------------------- */

/* A card in the corner, not a blocking overlay. The reader is offered their
   language; they are not stopped from reading the page while they decide. */
.langask {
  position: fixed;
  z-index: 60;
  inset-inline-start: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  max-width: 22rem;
  padding: var(--space-m);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: 3px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.55);
  display: grid;
  gap: 0.85rem;
  animation: langask-in 320ms var(--ease-out) both;
}
@keyframes langask-in {
  from { opacity: 0; translate: 0 12px; }
  to   { opacity: 1; translate: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .langask { animation: none; }
}
.langask__msg { margin: 0; font-size: var(--step--1); line-height: 1.55; color: var(--bone); }
.langask__row { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.langask .btn { min-height: 46px; }

@media (max-width: 640px) {
  .langask {
    inset-inline: 0.75rem;
    max-width: none;
    bottom: 0.75rem;
  }
}

/* --------------------------------------------------------------------------
   Phone pass: what the 390px audit found on every page
   -------------------------------------------------------------------------- */
@media (max-width: 48rem) {
  /* The page-hero stone sits at right:-4%, which on a phone puts its right
     edge 16px past the viewport, so it renders sliced off. At desktop sizes
     the bleed reads as intentional; at this width it reads as a mistake. */
  .page-hero .page-hero__figure {
    right: 4%;
    width: 40vw;
  }

  /* Footer links were 17–19px tall: seven navigation links and the legal
     row, all below the 44px touch minimum, on every page. The lists keep
     their rhythm from the target height instead of from a gap. */
  .footer-col ul { gap: 0; }
  .footer-col a,
  .footer-bottom a,
  .drawer__foot a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  .footer-bottom ul { gap: 0 var(--space-m); }
  .socials a { width: 44px; height: 44px; }
}

@media (max-width: 48rem) {
  /* "Kabul", "Dubai", "Privacy" are 34–43px wide as text; a target has to be
     44px in both directions to be reliably tapped. */
  .footer-col a,
  .footer-bottom a { min-width: 44px; justify-content: flex-start; }
}

@media (max-width: 48rem) {
  /* The email-address button. Uppercase with wide tracking, the address is
     wider than a phone screen and has no point at which it can break, so it
     wrapped as "…STONES.C / OM". An address reads as an address in lower
     case; the tracking comes in to let it sit on one line. */
  .btn[href^="mailto:"] {
    text-transform: none;
    letter-spacing: 0.04em;
    font-size: var(--step--1);
    word-break: keep-all;
    overflow-wrap: normal;
  }
}

/* --------------------------------------------------------------------------
   Traced stones: the canvas that replaces the drawing
   -------------------------------------------------------------------------- */
/* With JavaScript on, the flat drawing is never painted — not for the frame
   before the script runs, not on a browser without a worker. The only reader
   who sees it is one with no script at all (or a script that failed to load,
   which flags the root with gem3d-off). */
.js:not(.gem3d-off) svg.gem use { opacity: 0 !important; }

/* Before the script arrives — the first paint on a slow connection — the
   drawing's box already pulses, so a stone is never a blank hole. The same
   pulse the canvas carries below; the script hands one over to the other
   when it replaces the element. */
.js:not(.gem3d-off) svg.gem {
  background: radial-gradient(circle at 50% 52%, currentColor 0%, transparent 62%) center / 70% 70% no-repeat;
  animation: gem3dLoad 1.4s var(--ease-in-out, ease-in-out) infinite;
}
@media (prefers-reduced-motion: reduce) {
  .js:not(.gem3d-off) svg.gem { animation: none; opacity: 0.28; }
}

canvas.gem { display: block; background: transparent; }

/* Loading: a soft pulse in the stone's own colour, in the box the stone will
   occupy, until its first traced frame lands — then the class comes off and
   the .gem opacity transition fades the stone in. currentColor is --gem. */
canvas.gem3d--loading {
  opacity: 0.32;
  background: radial-gradient(circle at 50% 52%, currentColor 0%, transparent 62%) center / 70% 70% no-repeat;
  animation: gem3dLoad 1.4s var(--ease-in-out, ease-in-out) infinite !important;
}

@keyframes gem3dLoad {
  0%, 100% { background-size: 56% 56%; opacity: 0.20; }
  50%      { background-size: 84% 84%; opacity: 0.40; }
}

@media (prefers-reduced-motion: reduce) {
  canvas.gem3d--loading { animation: none !important; opacity: 0.28; }
}

/* --------------------------------------------------------------------------
   Mobile drawer: fit the VISIBLE viewport
   -------------------------------------------------------------------------- */
/* inset:0 on a fixed panel is the layout viewport, which on iOS Safari runs
   underneath the browser's bottom toolbar. With the footer pinned to that
   hidden edge and the links squeezed into the track above it, the last link —
   Contact — sat behind the toolbar on older iPhones. Sized to the visible
   height instead, in three notations for three generations of browser, and
   the footer keeps clear of the home indicator. */
.drawer {
  height: 100vh;
  height: -webkit-fill-available;
  height: 100dvh;
}

.drawer__foot {
  padding-bottom: calc(var(--space-m) + env(safe-area-inset-bottom, 0px));
}
