/* ==========================================================================
   Keefirivunts v3 — design system

   Reference: dinh van. White, sparse, geometric, no ornament. The restraint is
   the luxury signal; anything that decorates reads as cheaper, not richer.

   Rules this file holds to:
   - White, never cream.
   - Sentence case. No letterspaced all-caps headings.
   - One accent, used almost never. Gold is in the photographs, not the interface.
   - Space is the main design material. When in doubt, add more.
   ========================================================================== */

/* Playfair Display — the brand's own voice. The KEEFIRIVUNTS wordmark is a
   high-contrast Didone, so the display face has to be a serif or the logo sits
   in the page like a guest. Self-hosted (59 KB, two subsets): loading it from
   Google would hand every visitor's IP to a third party and reopen the consent
   problem that was closed in August. latin-ext carries the Estonian o-tilde. */
@font-face {
    font-family: "Playfair Display";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("/fonts/playfair-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
    font-family: "Playfair Display";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("/fonts/playfair-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+2C60-2C7F, U+A720-A7FF;
}

/* True italic, not a browser-synthesised slant. On a Didone the fake oblique
   shears the thin strokes and looks broken. Only the hero uses it, so only the
   home page ever downloads these 36 KB. */
@font-face {
    font-family: "Playfair Display";
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url("/fonts/playfair-italic-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
    font-family: "Playfair Display";
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url("/fonts/playfair-italic-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+2C60-2C7F, U+A720-A7FF;
}

:root {
    /* Type. Swapped to a self-hosted licensed face once one is chosen — that is a
       single change here, and no other file needs to know. Google Fonts is
       deliberately not used: fetching it hands visitor IPs to a third party and
       reopens the consent problem that was closed in August. */
    --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif;
    --font-display: "Playfair Display", Georgia, "Times New Roman", serif;

    --ink: #111111;
    --ink-soft: #6b6b6b;
    --ink-faint: #9a9a9a;
    --line: #e6e6e6;
    --line-soft: #f1f1f1;
    --bg: #ffffff;
    --bg-sunk: #fafafa;
    --accent: #111111;

    /* A minor third (~1.2). Deliberately shallow and deliberately capped low:
       the display sizes here top out around 56px, where a mass-market site would
       run to 80 or more. Large type is how a sale is announced; restraint is how
       confidence is. Five steps, and hierarchy comes from space rather than from
       finding a bigger size. */
    --step--1: 0.8125rem;    /* 13px — labels, captions, prices under a card */
    --step-0: 0.9375rem;     /* 15px — body */
    --step-1: 1.0625rem;     /* 17px — lede */
    --step-2: 1.375rem;      /* 22px — small headings */
    --step-3: 1.75rem;       /* 28px — section headings */
    --step-4: clamp(1.875rem, 3vw, 2.5rem);    /* 30 → 40px — page titles */
    --step-5: clamp(2.25rem, 4vw, 3.5rem);     /* 36 → 56px — hero only */

    /* Wider than a typical content column on purpose. At 90rem the page sat in
       the middle of a large display with air either side, which reads as a
       template; letting the grid run closer to the edges reads as a gallery. The
       measure stays narrow so prose is still readable — it is the images that
       want the width, not the words. */
    --gutter: clamp(1.25rem, 3.2vw, 5rem);
    --measure: 34rem;
    --shell: 118rem;

    --masthead-h: 4.75rem;

    --pace: 420ms;
    --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

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

html { -webkit-text-size-adjust: 100%; }

/* Body copy is 15px, not 16. The rule people quote — "never below 16px" — is
   really about FORM FIELDS: iOS Safari zooms the page when an input under 16px
   takes focus. It has nothing to do with paragraphs, and setting every input to
   16px below buys the smaller body text without the zoom. Slightly small,
   generously spaced text reads as considered; 16px everywhere reads as a
   template. */
body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: var(--step-0);
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

img { max-width: 100%; height: auto; display: block; }

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

h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 400;
    line-height: 1.12;
    letter-spacing: -0.005em;  /* a Didone is already tight; tracking out reads as dated */
    margin: 0;
    text-wrap: balance;
}

h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }

p { margin: 0 0 1.1em; max-width: var(--measure); }

::selection { background: var(--ink); color: var(--bg); }

:focus-visible {
    outline: 1px solid var(--ink);
    outline-offset: 3px;
}

/* --- layout ------------------------------------------------------------- */

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

.shell--narrow { max-width: 62rem; }

/* Reading width: the column plus its gutters, so the text is centred on the page
   rather than parked at the left of a wider one. */
.shell--read { max-width: 52rem; }

.section { padding-block: clamp(4rem, 9vw, 8.5rem); }
.section--tight { padding-block: clamp(2.5rem, 5vw, 4.5rem); }
.section--sunk { background: var(--bg-sunk); }

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

/* --- eyebrow ------------------------------------------------------------ */
/* The one place small tracking is allowed: tiny label text, where it aids
   legibility rather than shouting. Never on a heading. */
.eyebrow {
    font-size: var(--step--1);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin: 0 0 1.25rem;
}

.lede {
    font-size: var(--step-1);
    color: var(--ink-soft);
    max-width: var(--measure);
}

/* --- header ------------------------------------------------------------- */

.masthead {
    position: sticky;
    top: 0;
    z-index: 50;
    background: color-mix(in srgb, var(--bg) 88%, transparent);
    backdrop-filter: saturate(140%) blur(14px);
    border-bottom: 1px solid transparent;
    transition: border-color var(--pace) var(--ease);
}

.masthead[data-scrolled="true"] { border-bottom-color: var(--line); }

.masthead__inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 1rem;
    min-height: 4.75rem;
}

.wordmark {
    grid-column: 2;
    justify-self: center;
    font-size: var(--step-1);
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.nav {
    display: flex;
    gap: clamp(1rem, 2.4vw, 2.25rem);
    align-items: center;
    font-size: var(--step--1);
}

.nav--end { grid-column: 3; justify-content: flex-end; }

/* Underline grows from the left rather than fading in — a small, quiet motion. */
.nav a {
    position: relative;
    padding-block: 0.35rem;
    color: var(--ink-soft);
    transition: color var(--pace) var(--ease);
}

.nav a::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0.1rem;
    width: 100%;
    height: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--pace) var(--ease);
}

.nav a:hover { color: var(--ink); }
.nav a:hover::after,
.nav a[aria-current="page"]::after { transform: scaleX(1); }

.lang {
    display: inline-flex;
    gap: 0.4rem;
    color: var(--ink-faint);
}

.lang [aria-current="true"] { color: var(--ink); }

/* --- buttons ------------------------------------------------------------ */

.btn {
    --btn-ink: var(--bg);
    --btn-bg: var(--ink);
    --btn-fill: var(--bg);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 1rem 2rem;
    min-height: 3.25rem;
    border: 1px solid var(--btn-bg);
    color: var(--btn-ink);
    font: inherit;
    font-size: var(--step--1);
    letter-spacing: 0.02em;
    cursor: pointer;
    position: relative;

    /* The fill slides up as a background layer rather than as a ::before
       overlay. The overlay version only stayed behind the label because
       `.btn > *` lifted element children above it — so any button whose label
       was a bare text node got painted over and turned into a blank white
       rectangle on hover. That caught us repeatedly, once per new button, and it
       could only ever be fixed one button at a time. A background cannot cover
       its own element's text, so the whole class of bug is gone and a <span>
       wrapper is no longer load-bearing. */
    background-color: var(--btn-bg);
    background-image: linear-gradient(var(--btn-fill), var(--btn-fill));
    background-repeat: no-repeat;
    background-position: 50% 100%;
    background-size: 100% 0;

    transition: color var(--pace) var(--ease),
                border-color var(--pace) var(--ease),
                background-size var(--pace) var(--ease);
}

.btn:hover { color: var(--ink); background-size: 100% 100%; }

.btn--ghost {
    --btn-bg: transparent;
    --btn-ink: var(--ink);
    --btn-fill: var(--ink);
    border-color: var(--line);
}

.btn--ghost:hover { color: var(--bg); border-color: var(--ink); }

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

.btn[disabled] { opacity: 0.35; pointer-events: none; }

/* --- product grid ------------------------------------------------------- */

.grid-products {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
    gap: clamp(1.5rem, 3.5vw, 3.5rem) clamp(1rem, 2.5vw, 2.5rem);
}

.card__frame {
    position: relative;
    aspect-ratio: 4 / 5;
    background: var(--bg-sunk);
    overflow: hidden;
}

.card__frame img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: opacity var(--pace) var(--ease), transform 900ms var(--ease);
}

/* Second photograph on hover — the product shown two ways, not an effect. */
.card__frame img + img {
    position: absolute;
    inset: 0;
    opacity: 0;
}

.card:hover .card__frame img { transform: scale(1.03); }
.card:hover .card__frame img + img { opacity: 1; }

.card__body { padding-top: 1rem; }

.card__name {
    font-size: var(--step-0);
    letter-spacing: -0.01em;
    margin: 0 0 0.25rem;
}

.card__price {
    font-size: var(--step--1);
    color: var(--ink-soft);
    margin: 0;
}

/* --- product page ------------------------------------------------------- */

.pdp {
    display: grid;
    gap: clamp(2rem, 5vw, 5rem);
    grid-template-columns: 1fr;
}

@media (min-width: 60rem) {
    .pdp { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); align-items: start; }
    .pdp__info { position: sticky; top: 7rem; }
}

/* One ring, large, with the other frames under it. The swipe rail showed 86% of
   the first image and hid the rest behind a gesture nobody is told about. */
.pdp__gallery { display: grid; gap: 0.6rem; }

@media (min-width: 60rem) {
    .pdp__gallery { max-width: 88%; margin-inline: auto; }
}

.pdp__stage { background: var(--bg-sunk); position: relative; }

/* Arrows on the photograph, revealed on hover on a pointer device and always
   present on touch, where there is no hover to reveal them with. */
.pdp__nav {
    position: absolute; top: 50%; transform: translateY(-50%);
    display: grid; place-items: center;
    width: 2.75rem; height: 2.75rem;
    appearance: none; border: 0; cursor: pointer;
    background: rgba(255, 255, 255, 0.82);
    color: var(--ink);
    opacity: 0; transition: opacity var(--pace) var(--ease);
}
.pdp__nav svg { width: 1.1rem; height: 1.1rem; }
.pdp__nav--prev { left: 0.5rem; }
.pdp__nav--next { right: 0.5rem; }
.pdp__stage:hover .pdp__nav,
.pdp__nav:focus-visible { opacity: 1; }

@media (hover: none) {
    .pdp__nav { opacity: 1; }
}
.pdp__stage img { width: 100%; height: auto; display: block; aspect-ratio: 4 / 5; object-fit: cover; }

.pdp__thumbs {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    scrollbar-width: none;
    overscroll-behavior-x: contain;
}
.pdp__thumbs::-webkit-scrollbar { display: none; }

.pdp__thumb {
    border: 0;
    /* About a quarter of the gallery column, so four sit across it and each is
       large enough to actually tell two angles of the same ring apart. */
    flex: 0 0 clamp(5.5rem, 23%, 11rem);
    appearance: none; padding: 0; cursor: pointer;
    background: var(--bg-sunk);
    transition: opacity var(--pace) var(--ease);
    opacity: 0.42;
}
.pdp__thumb img { width: 100%; height: auto; display: block; aspect-ratio: 4 / 5; object-fit: cover; }
.pdp__thumb:hover { opacity: 1; }
.pdp__thumb[aria-selected="true"] { opacity: 1; }

/* The certificate beside the stone choice, which is where "is this real?" is
   actually asked. */
.pdp__cert { display: flex; align-items: center; gap: 0.75rem; margin: 0.9rem 0 0; }
.pdp__cert img { height: 2.25rem; width: auto; opacity: 0.8; flex: 0 0 auto; }
.pdp__cert span { font-size: var(--step--1); color: var(--ink-faint); }

.pdp__price {
    font-size: var(--step-2);
    letter-spacing: -0.02em;
    margin: 0.75rem 0 0;
}

.pdp__note { font-size: var(--step--1); color: var(--ink-faint); }

/* --- option pills ------------------------------------------------------- */
/* Pills, not a select. The choice is part of the object; hiding six stone sizes
   inside a dropdown makes the most consequential decision the least visible. */

.field { margin-block: 2rem; }

.field__label {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: var(--step--1);
    color: var(--ink-soft);
    margin-bottom: 0.75rem;
}

.field__value { color: var(--ink); }

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

.pill {
    appearance: none;
    border: 1px solid var(--line);
    background: transparent;
    color: var(--ink);
    font: inherit;
    font-size: var(--step--1);
    padding: 0.65rem 1.1rem;
    min-height: 2.75rem;
    cursor: pointer;
    transition: border-color var(--pace) var(--ease), background var(--pace) var(--ease), color var(--pace) var(--ease);
}

.pill:hover { border-color: var(--ink-faint); }

.pill[aria-pressed="true"] {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--bg);
}

.pill[disabled] {
    color: var(--ink-faint);
    text-decoration: line-through;
    cursor: not-allowed;
}

/* --- disclosure --------------------------------------------------------- */

.disclosure { border-top: 1px solid var(--line); }
.disclosure:last-of-type { border-bottom: 1px solid var(--line); }

.disclosure summary {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 1.25rem 0;
    cursor: pointer;
    list-style: none;
    font-size: var(--step-0);
}

.disclosure summary::-webkit-details-marker { display: none; }

.disclosure summary::after {
    content: "";
    width: 0.6rem;
    height: 0.6rem;
    border-right: 1px solid var(--ink-soft);
    border-bottom: 1px solid var(--ink-soft);
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform var(--pace) var(--ease);
    flex: none;
}

.disclosure[open] summary::after { transform: rotate(225deg) translate(-2px, -2px); }

.disclosure__body { padding-bottom: 1.5rem; color: var(--ink-soft); }

/* --- editorial ---------------------------------------------------------- */

.hero {
    position: relative;
    min-height: min(86vh, 52rem);
    display: grid;
    align-items: end;
    overflow: hidden;
}

.hero__body {
    position: relative;
    padding-block: clamp(2.5rem, 6vw, 5rem);
    color: var(--bg);
}

.hero--light .hero__body { color: var(--ink); }

.hero h1 { font-size: var(--step-5); max-width: 14ch; }

.split {
    display: grid;
    gap: clamp(2rem, 5vw, 4.5rem);
    align-items: center;
}

@media (min-width: 56rem) {
    .split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .split--wide-first { grid-template-columns: 1.3fr 1fr; }
}

/* --- table -------------------------------------------------------------- */

.ledger { width: 100%; border-collapse: collapse; font-size: var(--step-0); }
.ledger th, .ledger td { text-align: left; padding: 0.9rem 0; border-bottom: 1px solid var(--line-soft); }
.ledger th { font-weight: 400; color: var(--ink-soft); }
.ledger td:last-child, .ledger th:last-child { text-align: right; }

/* --- footer ------------------------------------------------------------- */

.colophon {
    border-top: 1px solid var(--line);
    padding-block: clamp(3rem, 6vw, 5rem) 2rem;
    font-size: var(--step--1);
    color: var(--ink-soft);
}

.colophon__cols {
    display: grid;
    gap: 2.5rem;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}

.colophon h4 { font-size: var(--step--1); color: var(--ink); margin-bottom: 0.9rem; letter-spacing: 0; }

.colophon ul { list-style: none; margin: 0; padding: 0; }
.colophon li + li { margin-top: 0.5rem; }
.colophon a:hover { color: var(--ink); }

.colophon__base {
    margin-top: 3rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--line-soft);
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    justify-content: space-between;
    color: var(--ink-faint);
}

/* --- utilities ---------------------------------------------------------- */

.crumbs { font-size: var(--step--1); color: var(--ink-faint); margin-bottom: 2rem; }
.crumbs a:hover { color: var(--ink); }
.crumbs span + span::before { content: "/"; margin-inline: 0.5rem; color: var(--line); }

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

/* Also clears the measure. Paragraphs are capped at 34rem for readability, which
   silently left-aligned any centred element that happened to be a <p>. */
.center { text-align: center; max-width: none; }
.flow-tight { --stack-gap: 0.5rem; }

.skip {
    position: absolute;
    left: -9999px;
}
.skip:focus {
    left: var(--gutter);
    top: 0.5rem;
    z-index: 100;
    background: var(--ink);
    color: var(--bg);
    padding: 0.75rem 1.25rem;
}

/* Motion is decoration; anyone who has asked for less should get none. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* --- masthead: burger / logo / utilities -------------------------------- */
/* Reference: Brunello Cucinelli. Navigation collapses to one word so the
   wordmark sits alone in the middle. A row of links either side would compete
   with the logo; a single "Menüü" defers to it. */

.masthead__logo {
    grid-column: 2;
    justify-self: center;
    display: block;
}

.masthead__logo img {
    height: clamp(0.85rem, 1.5vw, 1.1rem);
    width: auto;
}

.burger {
    display: inline-flex;
    align-items: center;
    gap: 0.7rem;
    background: none;
    border: 0;
    padding: 0.5rem 0;
    margin: 0;
    font: inherit;
    font-size: var(--step--1);
    color: var(--ink);
    cursor: pointer;
}

.burger__rules {
    display: grid;
    gap: 4px;
    width: 1.15rem;
    flex: none;
}

.burger__rules span {
    display: block;
    height: 1px;
    background: currentColor;
    transition: transform var(--pace) var(--ease), opacity var(--pace) var(--ease);
}

.burger:hover .burger__rules span:first-child { transform: translateX(2px); }
.burger:hover .burger__rules span:last-child { transform: translateX(-2px); }

.icon-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: var(--ink-soft);
    font-size: var(--step--1);
    transition: color var(--pace) var(--ease);
}

.icon-btn:hover { color: var(--ink); }
.icon-btn svg { width: 1.05rem; height: 1.05rem; flex: none; }

.cart-count {
    font-variant-numeric: tabular-nums;
}

/* --- menu drawer -------------------------------------------------------- */

.scrim {
    position: fixed;
    inset: 0;
    z-index: 90;
    background: rgba(17, 17, 17, 0.18);
    backdrop-filter: blur(18px) saturate(120%);
    -webkit-backdrop-filter: blur(18px) saturate(120%);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--pace) var(--ease), visibility var(--pace) var(--ease);
}

.drawer {
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    z-index: 91;
    width: min(31rem, 92vw);
    background: var(--bg);
    display: flex;
    flex-direction: column;
    padding: clamp(1.5rem, 3vw, 2.5rem) clamp(1.75rem, 4vw, 3.5rem) clamp(1.5rem, 3vw, 2.5rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    transform: translateX(-101%);
    transition: transform var(--pace) var(--ease);
    visibility: hidden;
}

/* Full width on a phone. A panel covering 92% of the screen leaves a strip of
   the page behind it, which reads as a rendering fault rather than a drawer —
   and the traffic here is overwhelmingly mobile. */
@media (max-width: 40rem) {
    .drawer { width: 100vw; }
}

/* Scoped to the menu's own elements. `.drawer` and `.scrim` matched the cart
   too, so opening the menu slid both drawers in at once. */
[data-menu-open="true"] .scrim:not(.scrim--cart) { opacity: 1; visibility: visible; }
[data-menu-open="true"] #menu-drawer { transform: translateX(0); visibility: visible; }
[data-menu-open="true"] { overflow: hidden; }

.drawer__close {
    background: none;
    border: 0;
    padding: 0.5rem;
    margin: 0 0 clamp(2rem, 5vw, 3.5rem) -0.5rem;
    align-self: flex-start;
    cursor: pointer;
    color: var(--ink);
    line-height: 0;
}

.drawer__close svg { width: 1.1rem; height: 1.1rem; }

.drawer__close:focus { outline: none; }

.drawer__primary {
    list-style: none;
    margin: 0 0 auto;
    padding: 0;
}

.drawer__primary a {
    font-family: var(--font-display);
    font-size: clamp(1.75rem, 3.4vw, 2.5rem);
    line-height: 1.35;
    display: inline-block;
    position: relative;
}

/* The underline is the whole hover state. On type this size, anything more
   is noise. */
.drawer__primary a::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0.22em;
    height: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--pace) var(--ease);
}

.drawer__primary a:hover::after,
.drawer__primary a[aria-current="page"]::after { transform: scaleX(1); }

.drawer__secondary {
    list-style: none;
    margin: clamp(2rem, 5vw, 3.5rem) 0 0;
    padding: 0;
    font-size: var(--step-0);
    color: var(--ink-soft);
}

.drawer__secondary li + li { margin-top: 0.6rem; }
.drawer__secondary a:hover { color: var(--ink); }

.drawer__foot {
    margin-top: clamp(2rem, 4vw, 3rem);
    padding-top: 1.5rem;
    border-top: 1px solid var(--line-soft);
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1.5rem;
    align-items: center;
    font-size: var(--step--1);
    color: var(--ink-faint);
}

.drawer__foot a:hover { color: var(--ink); }

.drawer__lang {
    margin-inline-start: auto;
    display: inline-flex;
    gap: 0.5rem;
}

.drawer__lang [aria-current="true"] { color: var(--ink); }

/* No JavaScript: the drawer never opens, so the burger must not be the only
   way in. The footer already carries every link it holds. */
.no-js .burger { display: none; }

/* --- footer logo -------------------------------------------------------- */

.colophon__mark img {
    height: 0.95rem;
    width: auto;
    margin-bottom: 1.1rem;
}

/* The hint only exists while the button is genuinely blocked. */
[data-add][data-missing="false"] ~ [data-add-hint] { display: none; }

/* --- collection block --------------------------------------------------- */

.collection { padding-block: clamp(2rem, 4vw, 3.5rem) clamp(2.5rem, 5vw, 4.5rem); }

.collection__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1.5rem;
    padding-bottom: 1.5rem;
    margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
    border-bottom: 1px solid var(--line);
}

.collection__head h2 { font-size: var(--step-2); }

.collection__more {
    font-size: var(--step--1);
    color: var(--ink-faint);
    white-space: nowrap;
}

.collection__more:hover { color: var(--ink); }

/* --- imported prose ----------------------------------------------------- */
/* Bodies come from WordPress, so the styling has to be defensive: whatever the
   old editor emitted must land inside the measure and the type scale. */

/*
   Long-form reading is a different job from interface text, so the article body
   sets its own type: 17px at 1.7, in a column of 66 characters. The research
   converges on 50–75 characters with 66 the sweet spot, 16–20px, and 1.5–1.6
   line height; a serif page can carry the looser end.

   The bug this replaces: the column was capped at the 34rem measure but sat
   inside a 62rem shell, so every paragraph hugged the left edge with a third of
   the page empty beside it. It read as broken rather than narrow.
*/
.prose {
    margin-top: clamp(2rem, 4vw, 3rem);
    font-size: var(--step-1);
    line-height: 1.7;
}

.prose > * {
    max-width: 66ch;
    margin-inline: auto;
}

.prose h2 { font-size: var(--step-3); margin: 2.2em 0 0.5em; line-height: 1.2; }
.prose h3 { font-size: var(--step-2); margin: 1.8em 0 0.4em; line-height: 1.25; }
.prose h4 { font-size: var(--step-1); margin: 1.6em 0 0.4em; }
.prose p, .prose li { color: var(--ink-soft); }
.prose p { margin-bottom: 1.35em; }
.prose > :first-child { margin-top: 0; }

/* The opening paragraph does the work of a standfirst. */
.prose > p:first-of-type { font-size: var(--step-2); line-height: 1.55; color: var(--ink); }

.prose strong { color: var(--ink); font-weight: 500; }
.prose a { text-decoration: underline; text-underline-offset: 0.2em; }
.prose a:hover { color: var(--ink); }
/* Pictures break the column, because a photograph confined to the measure looks
   like an accident. */
.prose img {
    max-width: min(100%, 52rem);
    height: auto;
    margin-block: 2.5rem;
    background: var(--bg-sunk);
}
.prose ul, .prose ol { padding-left: 1.2em; margin-block: 1.2em; }
.prose li + li { margin-top: 0.4em; }
.prose blockquote {
    margin: 2.5rem 0;
    padding-left: 1.5rem;
    border-left: 1px solid var(--line);
    font-family: var(--font-display);
    font-size: var(--step-2);
    color: var(--ink);
}
.prose table { width: 100%; border-collapse: collapse; margin-block: 2rem; max-width: none; }
.prose th, .prose td { text-align: left; padding: 0.75rem 0.5rem; border-bottom: 1px solid var(--line-soft); }
.prose iframe, .prose video { max-width: 100%; }

/* Cart is icon-only in the header; the label lives in aria-label. */
.icon-btn--bare svg { width: 1.15rem; height: 1.15rem; }
.masthead .lang { font-size: var(--step--1); }
.masthead .lang a { color: var(--ink-faint); }
.masthead .lang a[aria-current="true"] { color: var(--ink); }

/* --- front page --------------------------------------------------------- */

.cta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 2rem;
}

/* Three assurances, set as quiet text rather than badges. Badges are what a
   marketplace uses to look trustworthy; a maker just says the thing. */
.assurances {
    list-style: none;
    margin: 2.5rem 0 0;
    padding: 1.5rem 0 0;
    border-top: 1px solid var(--line);
    display: grid;
    gap: 0.5rem;
    font-size: var(--step--1);
    color: var(--ink-soft);
}

.review-grid {
    display: grid;
    gap: clamp(1.5rem, 3vw, 2.5rem);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
}

/* Six on a phone; all eight once the grid is wide enough to show them. */
@media (max-width: 63.99rem) { .review-grid .review:nth-child(n+7) { display: none; } }

.review {
    margin: 0;
    padding-top: 1.25rem;
    border-top: 1px solid var(--line);
}

.review__stars {
    color: var(--ink);
    font-size: var(--step--1);
    letter-spacing: 0.2em;
    margin-bottom: 0.9rem;
}

.review blockquote {
    margin: 0 0 1rem;
    font-size: var(--step-0);
    color: var(--ink-soft);
}

.review figcaption {
    font-size: var(--step--1);
    color: var(--ink-faint);
}

.guide-grid {
    display: grid;
    gap: clamp(1.25rem, 2.5vw, 2rem);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
}

.guide {
    display: block;
    padding-top: 1.25rem;
    border-top: 1px solid var(--line);
}

.guide h3 { font-size: var(--step-1); margin-bottom: 0.5rem; }
.guide p { font-size: var(--step--1); color: var(--ink-soft); margin: 0; }
.guide:hover h3 { text-decoration: underline; text-underline-offset: 0.2em; }

/* --- mobile buy bar ----------------------------------------------------- */
/*
   Mobile carts abandon at 80.45% against 68.62% on desktop, and this shop's
   traffic is Reels — overwhelmingly phones. The single worst thing a phone
   visitor meets is a buy button that has scrolled away, so it comes back and
   stays. Hidden on desktop, where the info column is already sticky.
*/

.buybar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.75rem var(--gutter);
    padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
    background: color-mix(in srgb, var(--bg) 92%, transparent);
    backdrop-filter: saturate(140%) blur(14px);
    border-top: 1px solid var(--line);
    transform: translateY(101%);
    transition: transform var(--pace) var(--ease);
}

.buybar[data-shown="true"] { transform: translateY(0); }

.buybar__meta { min-width: 0; }

.buybar__name {
    font-size: var(--step--1);
    color: var(--ink-soft);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.buybar__price {
    font-family: var(--font-display);
    font-size: var(--step-1);
}

.buybar .btn {
    margin-left: auto;
    flex: none;
    padding-inline: 1.5rem;
    min-height: 3rem;
}

@media (min-width: 60rem) {
    .buybar { display: none; }
}

/* Room for the bar so it never covers the last line of the page. */
@media (max-width: 59.99rem) {
    body:has(.buybar) { padding-bottom: 5rem; }
}

/* --- mobile refinements ------------------------------------------------- */

@media (max-width: 47.99rem) {
    /* Two rings per row still reads as a gallery; one per row reads as a list
       and doubles the scroll to see the range. */
    .grid-products {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 1.5rem 0.75rem;
    }

    .collection__head { flex-wrap: wrap; gap: 0.35rem; }

    /* The wordmark keeps the middle column; the burger loses its label so the
       three regions never collide at 360px. */
    .burger span:not(.burger__rules):not(.burger__rules span) { display: none; }

    .masthead__inner { min-height: 3.75rem; }

    .cta-row .btn { flex: 1 1 100%; }

    /* Comfortable thumb targets on the one control that gets tapped most. */
    .pill { min-height: 3rem; padding-inline: 1.15rem; }
}

/* --- cart drawer -------------------------------------------------------- */
/* The menu's twin, entering from the right. Same scrim, same motion, same
   escape behaviour — one pattern to learn instead of two. */

.drawer--cart {
    inset-inline: auto 0;
    transform: translateX(101%);
    width: min(28rem, 92vw);
}

[data-cart-open="true"] .drawer--cart { transform: translateX(0); visibility: visible; }
[data-cart-open="true"] .scrim--cart { opacity: 1; visibility: visible; }
[data-cart-open="true"] { overflow: hidden; }

.drawer__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.drawer__title { font-size: var(--step-2); }
.drawer__bar .drawer__close { margin: 0 -0.5rem 0 0; }

.cart-lines { list-style: none; margin: 0; padding: 0; flex: 1; overflow-y: auto; }

.cart-line {
    display: grid;
    grid-template-columns: 5rem 1fr;
    gap: 1rem;
    padding-block: 1.25rem;
    border-top: 1px solid var(--line-soft);
}

.cart-line img { width: 100%; aspect-ratio: 4/5; object-fit: cover; background: var(--bg-sunk); }

.cart-line__head {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    align-items: baseline;
}

.cart-line__head a { flex: 1; }
.cart-line__spec { font-size: var(--step--1); color: var(--ink-faint); margin: 0.35rem 0 0.6rem; }

.cart-line__actions {
    display: flex;
    gap: 1rem;
    align-items: center;
    font-size: var(--step--1);
    color: var(--ink-soft);
}

.cart-line__actions button {
    background: none;
    border: 0;
    padding: 0.35rem 0;
    font: inherit;
    color: var(--ink-faint);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

.cart-line__actions button:hover { color: var(--ink); }

.cart-foot {
    margin-top: auto;
    padding-top: 1.5rem;
    border-top: 1px solid var(--line);
}

.cart-foot__row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    font-size: var(--step--1);
    color: var(--ink-soft);
    margin-bottom: 0.6rem;
}

.cart-foot__row--total {
    font-size: var(--step-1);
    color: var(--ink);
    margin-bottom: 1.25rem;
}

.cart-count {
    font-variant-numeric: tabular-nums;
    font-size: 0.6875rem;
    line-height: 1;
    min-width: 1.05rem;
    height: 1.05rem;
    padding-inline: 0.2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    background: var(--ink);
    color: var(--bg);
    margin-left: -0.4rem;
    align-self: flex-start;
}

/* --- full-bleed hero ---------------------------------------------------- */

.hero {
    position: relative;
    min-height: 100svh;             /* svh, not vh: vh hides the CTA behind mobile browser chrome */
    display: grid;
    align-items: end;
    overflow: hidden;
    background: var(--bg-sunk);
}

.hero__media { position: absolute; inset: 0; }

.hero__media img { width: 100%; height: 100%; object-fit: cover; }

/* A gradient, not a flat overlay. The type stays legible without dimming the
   photograph, which is the thing being sold. */
.hero::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.18) 38%, transparent 68%);
}

.hero__body {
    position: relative;
    z-index: 1;
    /* width:100% matters. .shell carries margin-inline:auto, and on a grid item
       auto margins size the box to its content and centre it instead of
       stretching — which pushed the whole hero inwards and left it out of line
       with every other section on the page. */
    width: 100%;
    padding-block: clamp(2.5rem, 7vw, 6rem);
    color: #fff;
}

.hero h1 { font-size: var(--step-5); max-width: 16ch; }
.hero__lede { color: rgba(255, 255, 255, 0.86); margin-top: 1.25rem; }

.btn--light { --btn-bg: #fff; --btn-ink: var(--ink); --btn-fill: var(--ink); border-color: #fff; }
.btn--light:hover { color: #fff; border-color: var(--ink); }

.btn--outline-light { --btn-bg: transparent; --btn-ink: #fff; --btn-fill: #fff; border-color: rgba(255, 255, 255, 0.55); }
.btn--outline-light:hover { color: var(--ink); border-color: #fff; }

@media (min-width: 48rem) {
}

/* --- centred section head ----------------------------------------------- */

.section-head {
    text-align: center;
    max-width: 46rem;
    margin: 0 auto clamp(2rem, 4vw, 3rem);
}

.section-head .lede { margin: 1rem auto 0; max-width: 40rem; }

.card__name {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.card__arrow {
    width: 0.95rem;
    height: 0.95rem;
    flex: none;
    opacity: 0;
    transform: translateX(-0.35rem);
    transition: opacity var(--pace) var(--ease), transform var(--pace) var(--ease);
}

.card:hover .card__arrow { opacity: 1; transform: translateX(0); }

/* On touch there is no hover, so the cue is simply always there. */
@media (hover: none) {
    .card__arrow { opacity: 0.45; transform: none; }
}

/* Two by two on phones. A horizontal rail hides half the selection behind a
   swipe most people never make; a 2x2 block shows all four at once, which is the
   whole point of putting them directly under the hero. */
@media (max-width: 47.99rem) {
    .grid-products--rail {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 1.5rem 0.75rem;
    }
}

/* --- header over the hero ----------------------------------------------- */
/*
   On the home page the header sits on top of the photograph rather than above
   it, and inverts to white while it is there. Everywhere else it is the ordinary
   bar and the page simply starts below it.
*/

.masthead {
    position: fixed;
    left: 0;
    right: 0;
}

/* Only pages without a full-bleed hero need to reserve the space. */
body:not(.has-hero) main { padding-top: var(--masthead-h, 4.75rem); }

.masthead__logo { position: relative; display: grid; }

.masthead__mark {
    grid-area: 1 / 1;
    transition: opacity var(--pace) var(--ease);
}

.masthead__mark--light { opacity: 0; }

.masthead[data-over-hero="true"] {
    background: transparent;
    backdrop-filter: none;
    border-bottom-color: transparent;
    color: #fff;
}

.masthead[data-over-hero="true"] .burger,
.masthead[data-over-hero="true"] .icon-btn,
.masthead[data-over-hero="true"] .lang a[aria-current="true"] { color: #fff; }

.masthead[data-over-hero="true"] .lang a { color: rgba(255, 255, 255, 0.62); }

.masthead[data-over-hero="true"] .masthead__mark--dark { opacity: 0; }
.masthead[data-over-hero="true"] .masthead__mark--light { opacity: 1; }

.masthead[data-over-hero="true"] .cart-count { background: #fff; color: var(--ink); }

/* The hero fills the screen including the strip beneath the header. */
body.has-hero .hero { margin-top: 0; }

@media (max-width: 47.99rem) {
    :root { --masthead-h: 3.75rem; }
}

/* --- hero, matching the live composition -------------------------------- */
/* Type sits at the optical centre-left over the darkest part of the frame,
   not pinned to the bottom edge. */

.hero { align-items: center; }

.hero__body { padding-block: clamp(4rem, 12vh, 9rem); }

.hero__title { max-width: 18ch; }
.hero__title em { font-style: italic; }

.hero__lede { max-width: 38rem; margin-top: 1.5rem; }

.hero .cta-row { margin-top: 2.25rem; }

.hero__proof {
    display: inline-block;
    margin-top: 2rem;
    opacity: 0.92;
    transition: opacity var(--pace) var(--ease);
}

.hero__proof:hover { opacity: 1; }
.hero__proof img { width: clamp(9rem, 15vw, 11.5rem); height: auto; }

/* Darker at the left, where the words are, and clear on the right where the
   ring is. A flat scrim would dim the only thing being sold. */
.hero::after {
    background:
        linear-gradient(to right, rgba(0, 0, 0, 0.62) 0%, rgba(0, 0, 0, 0.28) 45%, transparent 72%),
        linear-gradient(to top, rgba(0, 0, 0, 0.45) 0%, transparent 40%);
}

@media (max-width: 47.99rem) {
    .hero { align-items: end; }
    .hero__body { padding-block: clamp(2rem, 6vh, 4rem) clamp(2.5rem, 8vh, 5rem); }
    .hero::after {
        background: linear-gradient(to top, rgba(0, 0, 0, 0.72) 0%, rgba(0, 0, 0, 0.35) 45%, transparent 78%);
    }
}

/* --- google attribution ------------------------------------------------- */
/* The only colour in the interface, and it earns its place: the mark is what
   makes the rating read as third-party rather than self-reported. */

.google-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 1.25rem;
    font-size: var(--step--1);
}

.google-badge__mark { width: 1.15rem; height: 1.15rem; flex: none; }
.google-badge__stars { letter-spacing: 0.14em; color: var(--ink); }
.google-badge__score { color: var(--ink-soft); font-variant-numeric: tabular-nums; }

.showcase .eyebrow { color: rgba(255, 255, 255, 0.5); }

@media (max-width: 47.99rem) {
}

/* --- cross-document view transitions ------------------------------------ */
/*
   The ring's photograph morphs from the grid into the product page instead of
   the page blanking and reloading. Native, no framework, and browsers without
   support simply navigate normally.

   Each card names its image after the product it shows, and the product page
   gives its first image the same name — so the browser has a pair to animate
   between. Names must be unique within a page, and they are: one card per
   product.
*/
/* Off since 2026-08-08: a partial implementation holds the navigation and never
   completes it, which left an Android WebView with one reachable page. The
   names below stay — inert without this line, and one line to restore. */
/* @view-transition { navigation: auto; } */

::view-transition-old(root),
::view-transition-new(root) {
    animation-duration: 260ms;
    animation-timing-function: var(--ease);
}

/* The image is the thing that travels; the rest of the page just crossfades. */
::view-transition-group(*) { animation-duration: 420ms; }

/* Motion is decoration. Anyone who asked for less gets a plain navigation. */
@media (prefers-reduced-motion: reduce) {
    @view-transition { navigation: none; }
}

/* --- native popover sheet ----------------------------------------------- */
/* <dialog>/popover semantics with none of the library. Light dismiss, Escape
   and focus return are the browser's job here, not ours. */

.sheet {
    border: 0;
    padding: clamp(1.5rem, 3vw, 2.5rem);
    max-width: min(34rem, 92vw);
    width: 100%;
    background: var(--bg);
    color: var(--ink);
    margin: auto;
}

.sheet::backdrop {
    background: rgba(17, 17, 17, 0.2);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
}

.sheet__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.sheet__bar h2 { font-size: var(--step-2); }
.sheet__body p { color: var(--ink-soft); }
.sheet__body a { text-decoration: underline; text-underline-offset: 0.2em; color: var(--ink); }

.link-quiet {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: var(--ink);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

/* Slides up from the bottom edge on a phone, where a centred box is awkward. */
@media (max-width: 47.99rem) {
    .sheet {
        margin: auto auto 0;
        max-width: 100%;
        padding-bottom: max(1.5rem, env(safe-area-inset-bottom));
    }
}

/* --- collections page --------------------------------------------------- */

.shop__title { font-size: var(--step-5); }
.shop__title em { font-style: italic; }

.mark {
    display: block;
    width: clamp(1.5rem, 2.4vw, 2rem);
    height: auto;
    margin: clamp(1.5rem, 3vw, 2.5rem) auto clamp(1.25rem, 2.5vw, 2rem);
}

.collection-jump {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem 1.75rem;
    padding-bottom: clamp(1.5rem, 3vw, 2.25rem);
    border-bottom: 1px solid var(--line);
    font-family: var(--font-display);
    font-size: var(--step-1);
}

.collection-jump a { position: relative; }
.collection-jump a:hover { text-decoration: underline; text-underline-offset: 0.25em; }

.collection__split { display: grid; gap: clamp(1.5rem, 3vw, 3rem); }

@media (min-width: 60rem) {
    .collection__split { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); align-items: start; }
    /* Stays with its rings while they scroll past. */
    .collection__intro { position: sticky; top: 7rem; }
}

.collection__intro h2 {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--step-3);
    margin-bottom: 1rem;
}

.collection__intro p { font-size: var(--step--1); color: var(--ink-soft); }

/* Name and price centred beneath the ring, as on the live page. */
.grid-products--roomy .card__body { text-align: center; }
.grid-products--roomy .card__frame { background: transparent; }
.grid-products--roomy .card__name { display: inline-flex; justify-content: center; }

.certs { border-top: 1px solid var(--line); }

.certs__marks {
    list-style: none;
    margin: 0 0 clamp(1.5rem, 3vw, 2.5rem);
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: clamp(1.5rem, 5vw, 4rem);
}

.certs__marks img { height: clamp(2.5rem, 5vw, 3.5rem); width: auto; }
.certs p { margin-inline: auto; max-width: 46rem; }
.certs a { text-decoration: underline; text-underline-offset: 0.2em; color: var(--ink); }

/* Four across, as on the live page. The auto-fill default gave three once the
   sticky description column took its 15rem, and a squarer frame suits rings
   photographed on white — the 4:5 portrait was mostly empty background. */
.grid-products--roomy {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(1.5rem, 3vw, 2.5rem) clamp(0.75rem, 1.5vw, 1.5rem);
}

.grid-products--roomy .card__frame { aspect-ratio: 1 / 1; }

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

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

/* --- variation selectors ------------------------------------------------ */
/*
   Rebuilt after the selected option went unnoticed. Three changes, each aimed at
   the same failure: the chosen value now appears in the label itself rather than
   floated to the right, the selected pill is unmistakable rather than merely
   darker, and the whole choice is restated above the button.

   Baymard puts visual swatches 15–20% ahead of text options on add-to-cart, and
   attributes 17% of cart abandonment to confusing option selection.
*/

.field__chosen {
    color: var(--ink);
    font-weight: 500;
}

.field__chosen:not(:empty)::before {
    content: " — ";
    color: var(--ink-faint);
    font-weight: 400;
}

.pill {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    border-width: 1px;
}

/* Selected reads as selected: filled and dark against an outlined row. The
   offset ring that used to sit outside the border drew a second box around every
   chosen option — two frames around one button. The fill is enough now that the
   controls render properly. */
.pill[aria-checked="true"] {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--bg);
}

.pills { gap: 0.65rem; }

/* The metal, as the metal. */
.pill__swatch {
    width: 1.1rem;
    height: 1.1rem;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.16);
    flex: none;
}

.pill[aria-checked="true"] .pill__swatch {
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45);
}

.chosen-summary {
    margin: 0 0 0.25rem;
    font-size: var(--step--1);
    color: var(--ink-soft);
    max-width: none;
}

.chosen-summary:empty { display: none; }

/* The one place 16px is mandatory: anything that can take focus on iOS. Below
   this the browser zooms the viewport and the layout lurches mid-checkout. */
input, select, textarea {
    font-size: max(1rem, var(--step-0));
}

/* --- compact size picker ------------------------------------------------ */
/* Twenty-one ring sizes is a lot of furniture. They are numbers, not decisions
   with character, so they can be smaller and denser than the stone and metal
   choices without becoming harder to hit — 2.5rem still clears the 44px target
   with the gap included. */

.pills--compact { gap: 0.4rem; }

.pills--compact .pill {
    min-height: 2.5rem;
    padding-inline: 0.7rem;
    font-size: var(--step--1);
    font-variant-numeric: tabular-nums;
    min-width: 3rem;
    justify-content: center;
}

/* --- clickable reviews -------------------------------------------------- */

.review {
    display: block;
    transition: border-color var(--pace) var(--ease);
}

a.review:hover { border-top-color: var(--ink); }
a.review:hover figcaption { color: var(--ink); }

.review__out {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: var(--step--1);
    color: var(--ink-faint);
    margin-top: 0.6rem;
}

a.review:hover .review__out { color: var(--ink); }

/* --- made in line ------------------------------------------------------- */

.made-in img { width: 0.9rem; height: auto; opacity: 0.55; }

.review__body { margin: 0 0 1rem; font-size: var(--step-0); color: var(--ink-soft); max-width: none; }

/* Flags are set at a size where the emoji renders as an emoji rather than a
   smudge, and the inactive one is dimmed instead of hidden. */
.lang {
    display: inline-flex;
    align-items: center;
    line-height: 1;
    opacity: 0.8;
    transition: opacity var(--pace) var(--ease);
}

.flag {
    width: 1.3rem;
    height: auto;
    display: block;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12);
}

.masthead[data-over-hero="true"] .flag { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.35); }

.lang:hover { opacity: 1; }
.lang::after { display: none; }

/* --- forms -------------------------------------------------------------- */

.form { margin-top: clamp(2rem, 4vw, 3rem); display: grid; gap: 1.25rem; max-width: 34rem; }
.form__pair { display: grid; gap: 1.25rem; }
@media (min-width: 40rem) { .form__pair { grid-template-columns: 1fr 1fr; } }

.form__row { display: grid; gap: 0.4rem; }
/* The attribute has to beat the rule above, or a row marked hidden — the parcel
   machine search, which is useless without its script — is displayed anyway. */
.form__row[hidden], .form__hint[hidden] { display: none; }
.form__row > span { font-size: var(--step--1); color: var(--ink-soft); }

/* Radios and checkboxes are excluded on purpose. appearance:none strips a
   checkbox of its tick and a radio of its dot, leaving an empty square that
   never visibly changes when clicked — the control looked decorative and the
   whole page read as a mock-up. Text inputs still get the flat treatment. */
.form input:not([type="radio"]):not([type="checkbox"]),
.form select,
.form textarea {
    width: 100%;
    padding: 0.85rem 1rem;
    border: 1px solid var(--line);
    background: var(--bg);
    color: var(--ink);
    font-family: inherit;
    border-radius: 0;
    -webkit-appearance: none;
    appearance: none;
}

.form textarea { resize: vertical; }
.form input:not([type="radio"]):not([type="checkbox"]):focus,
.form select:focus,
.form textarea:focus { outline: none; border-color: var(--ink); }
.form .btn { justify-self: start; }

/* The honeypot: gone for people, present for bots. Not display:none, which some
   bots specifically skip. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.notice { padding: 1rem 1.25rem; margin: 1.5rem 0 0; font-size: var(--step-0); max-width: 34rem; }
.notice--good { background: var(--bg-sunk); color: var(--ink); }
.notice--bad { background: #fdf3f3; color: #7a2020; list-style: none; padding-left: 1.25rem; }
.notice--bad li + li { margin-top: 0.35rem; }

.card__excerpt { font-size: var(--step--1); color: var(--ink-soft); margin: 0.35rem 0 0; }

/* --- education hub ------------------------------------------------------ */

.reads { list-style: none; margin: 0; padding: 0; }

.reads li { border-top: 1px solid var(--line-soft); }
.reads li:last-child { border-bottom: 1px solid var(--line-soft); }

.reads a { display: block; padding: 1.1rem 0; }
.reads h3 { font-size: var(--step-1); margin-bottom: 0.2rem; }
.reads p { font-size: var(--step--1); color: var(--ink-soft); margin: 0; max-width: 46rem; }
.reads a:hover h3 { text-decoration: underline; text-underline-offset: 0.2em; }

.article-cta {
    border-top: 1px solid var(--line);
    padding-top: clamp(2rem, 4vw, 3rem);
    margin-top: clamp(2rem, 4vw, 3rem);
}

.article-cta h2 { font-size: var(--step-2); margin-bottom: 0.75rem; }
.article-cta p { color: var(--ink-soft); margin-bottom: 1.5rem; }

.pdp__learn { margin: 1.5rem 0 0; font-size: var(--step--1); }
.pdp__learn a { color: var(--ink-soft); text-decoration: underline; text-underline-offset: 0.2em; }
.pdp__learn a:hover { color: var(--ink); }

/* Category copy sits under the title at reading width, not full page width. */
.category__intro { margin-top: clamp(1.5rem, 3vw, 2rem); }
.category__intro > * { margin-inline: 0; }
.category__intro > p:first-of-type { font-size: var(--step-1); color: var(--ink-soft); line-height: 1.7; }

/* --- order confirmation ------------------------------------------------- */

.order-meta { display: flex; flex-wrap: wrap; gap: 1.5rem 2.5rem; margin: 1.75rem 0 0; }
.order-meta dt { font-size: var(--step--1); color: var(--ink-faint); margin-bottom: 0.2rem; }
.order-meta dd { margin: 0; }

.order-block { margin-top: clamp(2rem, 4vw, 3rem); }
.order-block h2 { font-size: var(--step-1); margin-bottom: 0.6rem; }
.order-block p { color: var(--ink-soft); }

/* --- ring size system switcher ------------------------------------------- */

.sizesys { display: inline-flex; gap: 0; border: 1px solid var(--line); margin-bottom: 0.75rem; }
.sizesys__opt {
    appearance: none; background: none; border: 0; cursor: pointer;
    padding: 0.4rem 0.7rem;
    font: inherit; font-size: var(--step--1); color: var(--ink-faint);
    border-right: 1px solid var(--line);
}
.sizesys__opt:last-child { border-right: 0; }
.sizesys__opt:hover { color: var(--ink); }
.sizesys__opt[aria-checked="true"] { background: var(--ink); color: var(--bg); }

/* The millimetre stays visible once a size is chosen in another system —
   it is what actually gets made. */
.sizesys__note { margin: 0.5rem 0 0; }

/* --- reassurance stack --------------------------------------------------- */

.assure { list-style: none; margin: 1.5rem 0 0; padding: 1.1rem 0 0; border-top: 1px solid var(--line-soft); display: grid; gap: 0.5rem; }
.assure li { position: relative; padding-left: 1.4rem; font-size: var(--step--1); color: var(--ink-soft); }
.assure li::before {
    content: ''; position: absolute; left: 0; top: 0.42em;
    width: 0.5rem; height: 0.28rem;
    border-left: 1px solid var(--ink); border-bottom: 1px solid var(--ink);
    transform: rotate(-45deg);
}
.assure__ssl { font-size: var(--step--2); color: var(--ink-faint); margin: 0.9rem 0 0; }
.paylogos--small { margin-top: 0.6rem; gap: 0.35rem; }
.paylogos--small img { height: 1.25rem; }

/* --- certification line -------------------------------------------------- */

.certline {
    margin: 0;
    max-width: 46rem;
    font-size: var(--step--1);
    color: var(--ink-soft);
    line-height: 1.7;
}
.certline strong {
    display: block;
    font-weight: 400;
    color: var(--ink);
    font-size: var(--step-0);
    margin-bottom: 0.2rem;
}

/* --- certification marks and the maker's creed --------------------------- */

/* Sized by width, not height, so the pair is always side by side: at 390px each
   mark takes half the row minus the gap and the height follows. A fixed height
   was both too small to read as a credential and liable to wrap on a phone. */
.certmarks {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: clamp(1rem, 4vw, 2.5rem);
    margin: 0 0 1.1rem;
    max-width: 23rem;
}
/* Bounded as a pair rather than individually. The container decides the block's
   width and each mark takes half of it, so the two are the same size as each
   other and side by side at every viewport — on a 390px phone that is 163px
   wide and about 64px tall, against the 26px they were. */
.certmarks img {
    width: auto;
    height: auto;
    max-width: calc(50% - clamp(0.5rem, 2vw, 1.25rem));
    opacity: 0.8;
}

.colophon__creed { margin: 1.25rem 0 0; padding: 0; border: 0; max-width: 24rem; }
.colophon__creed p {
    margin: 0;
    font-size: var(--step-0);
    line-height: 1.65;
    color: var(--ink-soft);
    font-style: italic;
}
.colophon__creed cite {
    display: block;
    margin-top: 0.6rem;
    font-style: normal;
    font-size: var(--step--1);
    color: var(--ink-faint);
    letter-spacing: 0.04em;
}

/* Visible to a screen reader, not to the eye. */
.sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* --- natural diamond range ----------------------------------------------- */

.card__badge {
    display: inline-block;
    font-size: var(--step--2);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin-bottom: 0.3rem;
}

/* The process, numbered, because the absence of a price needs explaining before
   a visitor reads it as evasion. */
.steps-list { counter-reset: step; list-style: none; margin: 1.5rem 0 0; padding: 0; display: grid; gap: 1rem; max-width: 44rem; }
.steps-list li { counter-increment: step; position: relative; padding-left: 2.6rem; color: var(--ink-soft); line-height: 1.7; }
.steps-list li::before {
    content: counter(step);
    position: absolute; left: 0; top: 0.1em;
    display: grid; place-items: center;
    width: 1.7rem; height: 1.7rem;
    border: 1px solid var(--line); border-radius: 50%;
    font-size: var(--step--2); color: var(--ink-faint);
}

/* A footnote under the row it explains, quieter than the options themselves. */
.pdp__footnote { margin: 0.7rem 0 0; max-width: 34rem; line-height: 1.6; }

/* --- header mark swap ----------------------------------------------------- */

/* The wordmark hands over to the maker's mark once the page has moved. Both sit
   in the same grid cell so nothing in the header shifts as they cross-fade. */
.masthead__logo { display: grid; }
.masthead__logo > * { grid-area: 1 / 1; align-self: center; }

/* Scoped through .masthead__logo on purpose: `.masthead__logo img` sets a
   1.1rem height for the wordmark and outranks a single class, so every attempt
   to size the icon was silently overridden back to wordmark height. The header
   is 4.75rem tall, which leaves room for this comfortably. */
.masthead__logo .masthead__icon {
    width: 1.9rem;
    height: 1.9rem;
    opacity: 0;
    transition: opacity var(--pace) var(--ease);
    /* Centred in the wordmark's own cell so the header does not appear to jump
       sideways as the two cross-fade. */
    justify-self: center;
}

.masthead[data-scrolled="true"] .masthead__icon { opacity: 1; }
.masthead[data-scrolled="true"] .masthead__mark--dark { opacity: 0; }

/* Over the hero the white wordmark is doing the work. */
.masthead[data-over-hero="true"] .masthead__icon { opacity: 0; }

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

/* --- atelier block in the footer ------------------------------------------ */

.colophon__atelier {
    font-style: normal;
    font-size: var(--step--1);
    line-height: 1.9;
    color: var(--ink-soft);
}
.colophon__atelier a { text-decoration: underline; text-underline-offset: 0.2em; }
.colophon__atelier a:hover { color: var(--ink); }
.colophon__atelier strong { font-weight: 400; color: var(--ink); }

.colophon__book { margin: 0.9rem 0 0; font-size: var(--step--1); }
.colophon__book a { text-decoration: underline; text-underline-offset: 0.2em; }

/* --- accidental zoom ------------------------------------------------------ */

/*
 * Kills double-tap-to-zoom, which is what fires accidentally: a tap on a link
 * or a pill followed quickly by a scroll reads as a double tap, and the page
 * jumps to 200%. It also removes the 300ms delay browsers hold every tap for
 * while they wait to see whether a second one is coming, so every button on the
 * site feels quicker.
 *
 * Pinch zoom is deliberately left alone. Someone reading a 12px ring size on a
 * phone may genuinely need it, and `user-scalable=no` in the viewport — the
 * usual way this gets "fixed" — is ignored by iOS Safari anyway, so it would
 * have cost accessibility everywhere and changed nothing on an iPhone.
 */
html {
    touch-action: manipulation;
}

/* Belt and braces for the controls people actually tap in quick succession. */
button,
a,
label,
summary,
input,
select,
.pill,
.pay__method,
.pdp__thumb {
    touch-action: manipulation;
}

/* --- mobile drawer fixes, deliberately last ------------------------------- */

/*
 * .drawer--cart sets its own width further up the file, and a media query adds
 * no specificity — so the earlier full-width rule lost the cascade purely on
 * source order, and the cart kept its 92vw strip of page showing behind it.
 * These live at the end of the file so nothing can out-order them.
 */
@media (max-width: 40rem) {
    .drawer,
    .drawer--cart { width: 100vw; }
}

/*
 * The box around the close X is iOS painting its default tap highlight, plus a
 * focus ring on the button the drawer moves focus to when it opens. Focus does
 * have to move there for a screen reader, so the ring is kept for keyboard use
 * — where it is the only way to see where you are — and dropped for touch.
 */
.drawer__close,
.burger,
.pdp__nav,
.pdp__thumb,
.pill,
.pay__method,
.btn {
    -webkit-tap-highlight-color: transparent;
}

.drawer__close {
    appearance: none;
    -webkit-appearance: none;
    border: 0;
    outline: none;
    box-shadow: none;
}

.drawer__close:focus { outline: none; box-shadow: none; }
.drawer__close:focus-visible { outline: 1px solid var(--ink); outline-offset: 2px; }

/* --- certificate line in the cart ---------------------------------------- */

.cart-cert {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.9rem 0;
    border-top: 1px solid var(--line-soft);
    font-size: var(--step--1); color: var(--ink-soft);
}
.cart-cert__marks { display: flex; align-items: center; gap: 0.5rem; flex: 0 0 auto; }
.cart-cert__marks img { height: 1.6rem; width: auto; opacity: 0.8; }

/*
 * The drawer takes focus when it opens, not the close button inside it. Safari
 * treats a programmatic .focus() as focus-visible, so focusing the button drew
 * the keyboard ring every single time a drawer was opened by tapping — which is
 * the box that would not go away. A container is the correct target for a
 * dialog regardless, and it draws nothing.
 */
.drawer:focus,
.drawer:focus-visible { outline: none; }

/* --- image fallbacks ------------------------------------------------------ */

.card__frame, .pdp__stage, .pdp__thumb, .cart-line img {
    background: var(--bg-sunk);
}

/*
 * The hero's ground, and deliberately the last word on it.
 *
 * The hero text is white and sits on a photograph. A later rule sets the hero to
 * var(--bg-sunk), which is light — so a browser that cannot decode the image
 * renders white on near-white. That is not a broken image, it is an invisible
 * page, and it is what an Android in-app browser reported.
 *
 * Declared at the end of the file because a media query adds no specificity and
 * this has to beat every earlier .hero rule regardless of where one is added.
 */
.hero { background: #2b2622; }

.split__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.split__actions .btn { flex: 1 1 auto; }
/* Side by side these two squeeze to a few characters each on a narrow phone,
   which is where most of this traffic arrives. Stack them instead. */
@media (max-width: 26rem) { .split__actions .btn { flex: 1 1 100%; } }

/* --- the cookie notice -----------------------------------------------------
 *
 * This had no styles at all, so it rendered as plain text at the foot of the
 * page — a legally required notice sitting below the footer where nobody would
 * ever meet it, and no way to accept or decline without scrolling to the end of
 * the site. It is a bar at the bottom of the viewport now, above everything.
 */
.consent {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 80;
    background: var(--bg, #fff);
    border-top: 1px solid var(--line);
    box-shadow: 0 -8px 30px -20px rgba(28, 26, 23, 0.5);
    padding: clamp(0.9rem, 3vw, 1.25rem);
}

.consent[hidden] { display: none; }

.consent__inner {
    max-width: 62rem;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: clamp(0.75rem, 3vw, 2rem);
    flex-wrap: wrap;
}

.consent__text {
    flex: 1 1 22rem;
    margin: 0;
    font-size: var(--step--1);
    color: var(--ink-soft);
    line-height: 1.5;
}
.consent__text a { color: var(--ink); text-decoration: underline; text-underline-offset: 0.2em; }

.consent__actions { display: flex; gap: 0.6rem; flex: 0 0 auto; }
/* Smaller than a page button: this is a decision about cookies, not the point
   of the visit. */
.consent__actions .btn { min-height: 2.6rem; padding: 0.6rem 1.2rem; }

@media (max-width: 40rem) {
    .consent__actions { width: 100%; }
    .consent__actions .btn { flex: 1 1 0; }
}
