/* ==========================================================================
   kore — design system

   neutral system after rhodeskin.com: warm white ground, warm grey body text,
   near-black ink, hairlines instead of shadows, no accent colour at all.
   size carries hierarchy, not weight or colour.
   ========================================================================== */

:root {
  --base:       #FDFBF7;
  --panel:      #F1F0ED;
  --deep:       #E9E7E2;
  --ink:        #303030;
  --body:       #67645E;
  --hairline:   #DED9D0;
  --line-soft:  #EDE9E2;
  /* the blush, used as a surface rather than a mark: at this tint it reads as
     colour as a block but is far too pale to work as a line or an indicator.
     saturation pulled back roughly 30% from the original for a softer tone */
  --blush:      #F9E9EB;
  --blush-deep: #F1D3DA;

  --maxw:       1440px;
  --gutter:     clamp(1.25rem, 4vw, 4.5rem);
  --section:    clamp(4.5rem, 10vw, 9rem);

  /* full-bleed sections push their content in to meet the .wrap column */
  --pad-col:    max(var(--gutter), calc((100% - var(--maxw)) / 2 + var(--gutter)));
  --track-tight: -0.035em;
  --track-body:  -0.012em;

  --ease:       cubic-bezier(0.22, 0.61, 0.36, 1);
  --dur:        0.7s;

  /* one z-index scale, so nothing reaches for 9999 */
  --z-scrim:    1;
  --z-content:  2;
  --z-controls: 3;
  --z-head:     50;
  --z-skip:     100;
}

/* ---------- reset ---------- */

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

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

/* Lenis drives scrolling itself on the pages that load it */
html.has-lenis { scroll-behavior: auto; }

/* a sticky header must not cover whatever we jump to */
:target, main[id] { scroll-margin-top: clamp(5rem, 9vw, 6.5rem); }

body {
  margin: 0;
  background: var(--base);
  color: var(--ink);
  font-family: "Jost", ui-sans-serif, system-ui, sans-serif;
  font-weight: 300;
  font-size: clamp(1rem, 0.94rem + 0.2vw, 1.0625rem);
  line-height: 1.65;
  letter-spacing: var(--track-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { display: block; max-width: 100%; }
button, input, select { font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; }

h1, h2, h3, p, ul, figure, blockquote { margin: 0; }
ul { padding: 0; list-style: none; }

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

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

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

/* keyboard users can jump the header on every page */
.skip {
  position: fixed;
  top: 0;
  left: 0;
  z-index: var(--z-skip);
  padding: 0.75rem 1.25rem;
  background: var(--ink);
  color: var(--base);
  font-size: 0.875rem;
  transform: translateY(-120%);
  transition: transform 0.2s var(--ease);
}
.skip:focus { transform: translateY(0); }

/* available to screen readers, invisible on screen */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- type scale ---------- */

h1, h2, h3 { text-wrap: balance; }
p, li, dd { text-wrap: pretty; }

h1, .t-h1 {
  font-size: clamp(1.9rem, 4.6vw, 3.5rem);
  font-weight: 300;
  line-height: 1.06;
  letter-spacing: var(--track-tight);
}

h2, .t-h2 {
  font-size: clamp(1.4rem, 2.6vw, 2.25rem);
  font-weight: 300;
  line-height: 1.14;
  letter-spacing: var(--track-tight);
}

.t-small {
  font-size: 0.8125rem;
  letter-spacing: 0.01em;
  color: var(--body);
}

/* Jost at 300 goes thin and fragile below ~14px, so small text steps up */
.t-small, .card__price, .price__code, .trust,
.community__meta, .switcher__label, .step__num, .announce__item,
.select, .site-nav, .specs li {
  font-weight: 400;
}

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

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

.section { padding-block: var(--section); }

/* full-bleed bands. the surface change is the divider, not a hairline rule,
   which is how Rhode and Glossier create the pulse down the page */
.band { padding-block: var(--section); }
.band--panel { background: var(--panel); }
.band--blush { background: var(--blush); }

/* a section heading that introduces the block directly beneath it */
.section--lead { padding-bottom: clamp(1.75rem, 3.5vw, 3rem); }

.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem 2rem;
  flex-wrap: wrap;
  padding-bottom: clamp(1.75rem, 3.5vw, 3rem);
}

.grid { display: grid; gap: clamp(1.5rem, 2.6vw, 3rem) clamp(1rem, 1.8vw, 2rem); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.pad-top { padding-top: clamp(2.5rem, 5vw, 4rem); }
.pb-section { padding-bottom: var(--section); }

/* ---------- links & buttons ---------- */

.link-underline {
  display: inline-block;
  position: relative;
  font-size: 0.875rem;
  letter-spacing: 0.02em;
  padding-bottom: 0.35rem;
}
.link-underline::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transform-origin: left;
  transition: transform 0.5s var(--ease);
}
.link-underline:hover::after { transform: scaleX(0.35); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1.0625rem 2.25rem;
  border: 1px solid var(--ink);
  background: transparent;
  border-radius: 0;
  font-size: 0.875rem;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background 0.45s var(--ease), color 0.45s var(--ease),
              border-color 0.45s var(--ease), box-shadow 0.45s var(--ease),
              transform 0.16s var(--ease);
}
.btn:hover { background: var(--ink); color: var(--base); }
.btn:active { transform: translateY(1px); }

.btn--order {
  width: 100%;
  background: var(--blush);
  color: var(--ink);
  border-color: var(--blush);
  box-shadow: 0 0 0 0 rgba(252, 230, 233, 0);
}
.btn--order:hover {
  background: var(--blush-deep);
  border-color: var(--blush-deep);
  color: var(--ink);
  box-shadow: 0 0 30px -6px rgba(247, 205, 214, 0.95);
}
/* the second route to the same order, drawn quieter than the first */
.btn--order--ghost {
  background: transparent;
  border-color: var(--hairline);
  box-shadow: none;
}
.btn--order--ghost:hover {
  background: transparent;
  border-color: var(--ink);
  color: var(--ink);
  box-shadow: none;
}

/* stacked, not side by side: the detail column is about 400px, so half-width
   buttons cannot hold labels long enough to read clearly */
.order__actions {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
/* a larger label than the site's standard button, and slim side padding so the
   long instagram label stays on one line on the narrowest phones */
.order__actions .btn--order {
  font-size: 1rem;
  padding-inline: 0.75rem;
}
.order__copy { margin-top: 1rem; }
/* a real button, drawn as text, so the order route stays the loud one */
.link-button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font: inherit;
  font-size: 0.8125rem;
  letter-spacing: inherit;
  color: var(--body);
  text-decoration: underline;
  text-underline-offset: 0.25em;
}
.link-button:hover { color: var(--ink); }

/* ---------- announcement ---------- */
/* after rhodeskin.com: a light rounded bar inset from the page edges,
   not a flush dark strip. values taken from their theme.css */

.announce {
  padding: 0.9375rem var(--pad-col);
}
.announce__inner {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 2.5rem;
  padding: 0.625rem 0.9375rem;
  border-radius: 0.625rem;
  background: var(--blush);
  color: var(--ink);
  overflow: hidden;
}
.announce__item {
  position: absolute;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  opacity: 0;
  transition: opacity 0.7s var(--ease);
}
.announce__item.is-active { opacity: 1; }

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

.site-head {
  position: sticky;
  top: 0;
  z-index: var(--z-head);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: clamp(1.1rem, 2.2vw, 1.6rem) var(--pad-col);
  background: color-mix(in srgb, var(--base) 88%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--hairline);
}

.wordmark {
  font-size: clamp(1.3rem, 2.1vw, 1.75rem);
  font-weight: 400;
  letter-spacing: -0.04em;
  line-height: 1;
}

.site-head__right {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 2.5vw, 2.25rem);
}
.site-head__tools { display: flex; align-items: center; }

/* the one currency control for the whole site, sat quietly in the header */
.select--compact {
  padding: 0.4rem 1.75rem 0.4rem 0.55rem;
  font-size: 0.8125rem;
  border-color: transparent;
  background-position: right 0.5rem center;
  transition: border-color 0.35s var(--ease);
}
.select--compact:hover,
.select--compact:focus-visible { border-color: var(--hairline); }

.site-nav {
  display: flex;
  gap: clamp(1.25rem, 3vw, 2.5rem);
  font-size: 0.875rem;
  letter-spacing: 0.015em;
}
.site-nav a { position: relative; padding-bottom: 0.2rem; }
.site-nav a::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.45s var(--ease);
}
.site-nav a:hover::after,
.site-nav a[aria-current="page"]::after { transform: scaleX(1); }

/* ---------- hero slider ---------- */

.hero { position: relative; }

.hero__slides {
  position: relative;
  /* dvh second: iOS Safari's vh excludes the collapsing toolbar */
  height: clamp(30rem, 84vh, 52rem);
  height: clamp(30rem, 84dvh, 52rem);
  background: var(--panel);
  /* the scroll zoom scales the frame past its box; without this it paints
     over the section below and looks like a stray band */
  overflow: hidden;
}

/* each slide carries its own scrim, so a dark frame can flip the treatment
   without affecting the light ones */
.hero__slide::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: var(--z-scrim);
  pointer-events: none;
  background: linear-gradient(
    to top,
    rgba(253, 251, 247, 0.96) 0%,
    rgba(253, 251, 247, 0.72) 24%,
    rgba(253, 251, 247, 0) 56%
  );
}

/* A dark frame carries its copy higher up, not along the base. The bracelets
   sit at 80-95% of this photograph, so a base-anchored headline would sit on
   top of the jewellery. Lifting the text frees the whole lower band. */
.hero__slide--dark .hero__content { bottom: 32%; }

/* the scrim becomes a band behind the text rather than a gradient along the
   base, so the jewellery below stays clear and her face above stays clear */
.hero__slide--dark::after {
  background: linear-gradient(
    to bottom,
    rgba(28, 26, 24, 0) 44%,
    rgba(28, 26, 24, 0.62) 60%,
    rgba(28, 26, 24, 0.40) 73%,
    rgba(28, 26, 24, 0) 90%
  );
}
.hero__slide--dark .hero__title,
.hero__slide--dark .hero__cta { color: var(--base); }

.hero__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.1s var(--ease);
  pointer-events: none;
}
.hero__slide.is-active { opacity: 1; pointer-events: auto; }
/* the frame carries the scroll zoom, the image inside it carries the load
   animation, so the two transforms never fight over the same element */
.hero__frame {
  position: absolute;
  inset: 0;
  transform: scale(var(--zoom, 1));
  will-change: transform;
}
.hero__frame img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 66% center;
}

.hero__content {
  position: absolute;
  left: var(--pad-col);
  right: var(--pad-col);
  bottom: clamp(2rem, 7vh, 4.5rem);
  max-width: min(64ch, 62vw);
  z-index: var(--z-content);
}

.hero__title {
  font-size: clamp(2.5rem, 8vw, 7.5rem);
  font-weight: 300;
  line-height: 0.9;
  letter-spacing: -0.05em;
  margin-bottom: clamp(1.25rem, 3vh, 2.25rem);
}

.hero__cta {
  display: inline-block;
  padding-bottom: 0.4rem;
  position: relative;
  font-size: clamp(1rem, 1.4vw, 1.375rem);
  letter-spacing: 0.01em;
}
.hero__cta::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transition: transform 0.5s var(--ease);
  transform-origin: left;
}
.hero__cta:hover::after { transform: scaleX(0.4); }

.hero__dots {
  position: absolute;
  right: var(--pad-col);
  bottom: clamp(2rem, 7vh, 4.5rem);
  display: flex;
  gap: 0.5rem;
  z-index: var(--z-controls);
}
/* 24px tall hit area around a 2px line (WCAG 2.2 target size) */
.hero__dot {
  position: relative;
  width: 34px;
  height: 24px;
  border: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
  transition: opacity 0.16s var(--ease);
}
.hero__dot::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 2px;
  margin-top: -1px;
  background: rgba(48, 48, 48, 0.28);
  transition: background 0.45s var(--ease), height 0.3s var(--ease), margin-top 0.3s var(--ease);
}
/* active is thicker as well as darker, so it does not rely on colour alone */
.hero__dot[aria-selected="true"]::before {
  background: var(--ink);
  height: 4px;
  margin-top: -2px;
}
.hero__dot:active { opacity: 0.6; }

/* the dots sit over whichever slide is showing, so they flip with it */
.hero.is-dark .hero__dot::before { background: rgba(253, 251, 247, 0.45); }
.hero.is-dark .hero__dot[aria-selected="true"]::before { background: var(--base); }

/* ---------- product card ---------- */

.card { display: block; }

.card__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--panel);
}
/* GSAP scrubs --zoom on this frame while hover scales the image inside it, so
   the two transforms compose instead of overwriting each other */
.card__frame {
  position: absolute;
  inset: 0;
  transform: scale(var(--zoom, 1));
  will-change: transform;
}
.card__frame img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease), opacity 0.55s var(--ease);
}
/* a second angle crossfades in on hover. only added on hover-capable devices */
.card__frame img + img {
  position: absolute;
  inset: 0;
  opacity: 0;
}
/* hover only exists with a mouse, and on touch a stuck :hover would leave a
   card zoomed, so the reveal is confined to devices that can actually hover */
@media (hover: hover) and (pointer: fine) {
  .card:hover .card__frame img,
  .card:focus-visible .card__frame img { transform: scale(1.05); }
  .card:active .card__frame img { transform: scale(1.02); }
  .card:hover .card__frame img + img,
  .card:focus-visible .card__frame img + img { opacity: 1; }
}

/* the shop grid on a touch device: the second photo is reached by swiping the
   card sideways, because there is no hover to reveal it */
.card__frame--swipe {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.card__frame--swipe::-webkit-scrollbar { display: none; }
.card__frame--swipe img { flex: 0 0 100%; scroll-snap-align: start; }
.card__frame--swipe img + img { position: static; opacity: 1; }

/* press and hold a card in the featured row to see its second photo */
.card.is-peeking .card__frame img + img { opacity: 1; }

/* name above price, both left aligned. space-between pushed a card's price
   closer to the next card's name than to its own, which read as jumbled. */
.card__row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  padding-top: 1.05rem;
}
.card__name { font-size: 0.9375rem; letter-spacing: var(--track-body); }
.card__price { font-size: 0.875rem; color: var(--body); font-variant-numeric: tabular-nums; }

/* ---------- collection slider ---------- */

.slider { position: relative; }

.slider__viewport { overflow: hidden; }

.slider__track {
  display: flex;
  gap: clamp(0.75rem, 1.6vw, 1.5rem);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding-inline: var(--pad-col);
  /* without this the snap treats the track's own padding as scrollable and
     scrolls it away, which parks the first card flush against the page edge */
  scroll-padding-inline: var(--pad-col);
  /* a native grab cursor, so it costs nothing per pointer move */
  cursor: grab;
}
.slider__track:active { cursor: grabbing; }
.slider__track::-webkit-scrollbar { display: none; }

.slider__item {
  flex: 0 0 clamp(13rem, 24vw, 21rem);
  scroll-snap-align: start;
}

.slider__foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 1.5rem;
  padding: clamp(1.5rem, 3vw, 2.25rem) var(--pad-col) 0;
}

.slider__nav { display: flex; gap: 0.5rem; }
.slider__btn {
  width: 46px; height: 46px;
  display: grid;
  place-items: center;
  border: 1px solid var(--hairline);
  background: transparent;
  cursor: pointer;
  transition: border-color 0.4s var(--ease), opacity 0.4s var(--ease),
              transform 0.16s var(--ease);
}
.slider__btn:hover { border-color: var(--ink); }
.slider__btn:active { transform: translateY(1px); }
.slider__btn[disabled] { opacity: 0.3; cursor: default; }
.slider__btn[disabled]:hover { border-color: var(--hairline); }
.slider__btn[disabled]:active { transform: none; }
.slider__btn svg { width: 15px; height: 15px; stroke: var(--ink); fill: none; }

/* ---------- split feature (after rhodeskin.com) ---------- */
/* the copy lives in a rounded tinted panel rather than sitting over the
   photograph, so nothing needs a scrim and text stays legible on any image */

.split {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: clamp(0.75rem, 1.6vw, 1.25rem);
  align-items: stretch;
  padding-inline: var(--pad-col);
}

.split__panel {
  display: flex;
  align-items: center;
  background: var(--blush);
  border-radius: 0.625rem;
  padding: clamp(2.25rem, 6vw, 5rem) clamp(1.5rem, 5vw, 4.5rem);
}

.split__copy { max-width: 44ch; }
.split__copy h2 { margin-bottom: 1.1rem; }
.split__copy p { color: var(--body); margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }

.split__media {
  position: relative;
  border-radius: 0.625rem;
  overflow: hidden;
  background: var(--panel);
  /* portrait, because the photograph is 2:3 and a landscape slot would crop
     half of it away */
  aspect-ratio: 3 / 4;
  will-change: transform;
}
/* scroll-linked zoom, the effect the reference site uses on its large imagery */
.split__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(var(--zoom, 1));
}

/* the outlined pill Rhode uses on these panels */
.btn--pill {
  border-radius: 999px;
  padding: 0.9rem 1.9rem;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.btn--pill:hover {
  background: var(--blush-deep);
  border-color: var(--blush-deep);
  color: var(--ink);
}

/* ---------- community ---------- */

.community__list {
  display: grid;
  /* two tracks, because there are two routes left now that WhatsApp has gone */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.5rem, 3vw, 3rem);
}
.community__item {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--hairline);
  transition: border-color 0.45s var(--ease);
}
.community__item:hover { border-color: var(--ink); }
.community__icon { flex: none; width: 22px; height: 22px; stroke: var(--ink); fill: none; }
.community__label { font-size: 0.9375rem; }
.community__meta { display: block; font-size: 0.8125rem; color: var(--body); }

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

.site-foot { padding: clamp(3rem, 6vw, 5rem) var(--pad-col); border-top: 1px solid var(--hairline); }
.site-foot__inner {
  display: flex;
  justify-content: space-between;
  gap: 1.5rem 3rem;
  flex-wrap: wrap;
  align-items: baseline;
}

/* ---------- page head ---------- */

.page-head { padding-top: clamp(3rem, 7vw, 6rem); padding-bottom: clamp(2rem, 4vw, 3.5rem); }
.page-head__lead { color: var(--body); max-width: 46ch; margin-top: 1rem; }
.page-head__row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem 2.5rem;
  flex-wrap: wrap;
}

/* ---------- currency switcher ---------- */

.switcher { display: flex; align-items: center; gap: 0.85rem; }
.switcher__label { font-size: 0.8125rem; color: var(--body); }

.select {
  appearance: none;
  border: 1px solid var(--hairline);
  background-color: transparent;
  border-radius: 0;
  padding: 0.7rem 2.4rem 0.7rem 1rem;
  cursor: pointer;
  font-size: 0.875rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%2367645E' stroke-width='1.2'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.9rem center;
  background-size: 11px;
  transition: border-color 0.4s var(--ease);
}
.select:hover { border-color: var(--ink); }

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

.product {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(2rem, 4vw, 4.5rem);
  align-items: start;
}
.product__gallery { grid-column: 1 / span 7; }
.product__detail  { grid-column: 9 / span 4; position: sticky; top: clamp(5rem, 9vw, 7rem); }

.carousel { position: relative; }
.carousel__track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  gap: 1px;
  background: var(--line-soft);
}
.carousel__track::-webkit-scrollbar { display: none; }
.carousel__slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
  aspect-ratio: 4 / 5;
  background: var(--panel);
  overflow: hidden;
}
.carousel__slide img,
.carousel__slide video { width: 100%; height: 100%; object-fit: cover; display: block; }

.carousel__dots { display: flex; gap: 0.5rem; padding-top: 1.1rem; }
/* a one-photo product has nothing to page through, so the dots are dropped */
.carousel__dots[hidden] { display: none; }
/* optional caption under the gallery, saying which variant the shots show */
.gallery__note { margin-top: 1rem; font-size: 1rem; color: var(--body); }
/* 24px tall hit area around a 2px line (WCAG 2.2 target size) */
.carousel__dot {
  position: relative;
  width: 34px;
  height: 24px;
  border: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
  transition: opacity 0.16s var(--ease);
}
.carousel__dot::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 2px;
  margin-top: -1px;
  background: var(--hairline);
  transition: background 0.4s var(--ease), height 0.3s var(--ease), margin-top 0.3s var(--ease);
}
.carousel__dot[aria-selected="true"]::before {
  background: var(--ink);
  height: 4px;
  margin-top: -2px;
}
.carousel__dot:active { opacity: 0.6; }

.detail__name { margin-bottom: 0.75rem; }
/* product names are normalised to title case by the sync script, so the page
   shows whatever the data holds rather than transforming it here */
.detail__material { font-size: 0.8125rem; color: var(--body); margin-bottom: 0.85rem; }
.detail__blurb { color: var(--body); max-width: 46ch; margin-bottom: clamp(1.75rem, 3vw, 2.5rem); }

.selector { display: grid; gap: 1.1rem; margin-bottom: 1.6rem; }
.selector__field { display: grid; gap: 0.5rem; }
.selector .select { width: 100%; }
/* the wrapper is display: grid, which would otherwise beat the hidden attribute */
.selector__field[hidden] { display: none; }

.price {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding-block: 1.35rem;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  margin-bottom: 1.6rem;
}
.price__value {
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  font-weight: 300;
  line-height: 1.1;
  letter-spacing: var(--track-tight);
  font-variant-numeric: tabular-nums;
  transition: opacity 0.3s var(--ease);
}
.price__value.is-updating { opacity: 0; }
.price__code { font-size: 0.8125rem; color: var(--body); }
.price__note { font-size: 0.8125rem; color: var(--body); margin: -0.7rem 0 1.75rem; }

.trust { font-size: 0.8125rem; color: var(--body); margin-bottom: 1.75rem; }

.specs { margin-top: clamp(1.75rem, 3vw, 2.5rem); border-top: 1px solid var(--hairline); padding-top: 1.5rem; }
.specs li {
  display: flex;
  justify-content: space-between;
  gap: 1.5rem;
  padding-block: 0.65rem;
  border-bottom: 1px solid var(--hairline);
  font-size: 0.875rem;
}
.specs li span:last-child { color: var(--body); text-align: right; }

/* ---------- back link ---------- */

.backlink {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--body);
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
  transition: color 0.35s var(--ease);
}
.backlink:hover { color: var(--ink); }
.backlink svg { width: 13px; height: 13px; stroke: currentColor; fill: none; }
.product__back { grid-column: 1 / -1; }

/* ---------- how to order ---------- */

/* capped so the rows stop short of the far edge instead of stretching across
   the page, which also leaves the descriptions room to sit on one line */
.steps { display: grid; gap: 0; max-width: 60rem; }
.step {
  display: grid;
  /* the number sits beside the whole block, and the description runs under its
     own title rather than being pushed to the far edge of the page */
  grid-template-columns: clamp(3.5rem, 7vw, 5.5rem) minmax(0, 1fr);
  gap: 0.75rem clamp(1rem, 2.5vw, 2rem);
  align-items: start;
  padding-block: clamp(2rem, 4.5vw, 3.5rem);
  border-top: 1px solid var(--hairline);
}
.step:last-child { border-bottom: 1px solid var(--hairline); }
.step__num {
  grid-column: 1;
  grid-row: 1 / span 2;
  font-size: clamp(1.25rem, 2.4vw, 2rem);
  font-weight: 300;
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--track-tight);
}
.step__icon { width: 26px; height: 26px; stroke: var(--ink); fill: none; margin-bottom: 0.9rem; }
.step__body { grid-column: 2; grid-row: 1; }
.step__body h2 {
  font-size: clamp(1.15rem, 1.8vw, 1.5rem);
  font-weight: 300;
  letter-spacing: var(--track-tight);
}
.step__note { grid-column: 2; grid-row: 2; color: var(--body); max-width: 90ch; }

.faq { display: grid; gap: 0; max-width: 62ch; }
.faq details { border-bottom: 1px solid var(--hairline); }
.faq summary {
  cursor: pointer;
  list-style: none;
  padding-block: 1.5rem;
  display: flex;
  justify-content: space-between;
  gap: 2rem;
  align-items: baseline;
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  letter-spacing: var(--track-tight);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  color: var(--body);
  font-size: 1.25rem;
  line-height: 1;
  transition: transform 0.4s var(--ease);
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq details p { padding-bottom: 1.75rem; color: var(--body); max-width: 58ch; }

/* ---------- loading skeleton ---------- */
/* placeholder cells sit inside the real grid, so the layout does not jump */

.skeleton__cell { display: block; }
.skeleton__media {
  aspect-ratio: 4 / 5;
  background: var(--panel);
}
.skeleton__line {
  height: 0.7rem;
  margin-top: 1.05rem;
  background: var(--panel);
  width: 62%;
}
.skeleton__line--short { width: 34%; }

@media (prefers-reduced-motion: no-preference) {
  .skeleton__media,
  .skeleton__line { animation: skeleton-pulse 1.6s var(--ease) infinite; }
}
@keyframes skeleton-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

/* ---------- responsive ---------- */

@media (max-width: 1100px) {
  .product__gallery { grid-column: 1 / -1; }
  .product__detail  { grid-column: 1 / -1; position: static; }
  .hero__content { max-width: min(64ch, 100%); }
}

@media (max-width: 900px) {
  .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .community__list { grid-template-columns: 1fr; }
  .step { grid-template-columns: minmax(0, 1fr); gap: 0.65rem; }
  .step__num, .step__body, .step__note { grid-column: 1; grid-row: auto; }
  .split { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 560px) {
  .grid--4 { grid-template-columns: 1fr; }
  .hero__slides {
    height: clamp(26rem, 64vh, 38rem);
    height: clamp(26rem, 64dvh, 38rem);
  }
  .hero__dots { right: auto; left: var(--pad-col); bottom: 1.5rem; }
  .hero__content { bottom: 3.5rem; }
}

/* ---------- motion preferences ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
