/* ==========================================================================
   mystore — storefront styles
   Luxury register: warm ivory paper, deep forest, champagne gold accents,
   square corners, generous whitespace. See PRD section 7.
   ========================================================================== */

:root {
  --paper: #f7f4ee;
  --card: #fffdf9;
  --ink: #191d1a;
  --deep: #173f31;
  --deep2: #0e2c22;
  --gold: #b3905e;
  --gold-soft: #efe6d6;
  --line: #e6e0d3;
  --muted: #7a776d;
  --danger: #a34632;

  --serif: "Cormorant Garamond", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  --shell: 1180px;
  --gutter: clamp(16px, 4vw, 40px);
  --shadow: 0 18px 40px -28px rgba(23, 63, 49, 0.55);
}

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
}

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

/* The `hidden` attribute only sets `display: none` at UA-stylesheet priority, so
   any element that declares its own `display` (the hero grid, the login gate,
   the carousel dots) would keep showing. Make `hidden` mean hidden. */
[hidden] { display: none !important; }

a { color: inherit; }

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

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

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--deep);
  color: #fff;
  padding: 12px 18px;
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
}
.skip-link:focus { left: 12px; top: 12px; }

/* --- Eyebrow / headings ------------------------------------------------- */

.eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin: 0 0 10px;
}

.section-head {
  text-align: center;
  margin-bottom: clamp(24px, 4vw, 40px);
}

.section-head h2 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(28px, 4vw, 40px);
  line-height: 1.15;
  margin: 0;
  letter-spacing: 0.01em;
}

.rule {
  width: 46px;
  height: 1px;
  background: var(--gold);
  margin: 14px auto 0;
  border: 0;
}

/* --- Announcement bar --------------------------------------------------- */

.announce {
  background: var(--deep2);
  color: color-mix(in srgb, var(--on-deep) 84%, var(--gold));
  text-align: center;
  padding: 9px var(--gutter);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* --- Header ------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: saturate(180%) blur(8px);
  border-bottom: 1px solid var(--line);
}

.site-header .shell {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  /* Deep enough for the logo and the store name to sit side by side. */
  min-height: clamp(78px, 8vw, 104px);
  /* Wraps when it has to rather than at one chosen width: with the wider brand,
     768px was too narrow for a single row but above the phone breakpoint, so the
     nav ran 8px off the side of the page. */
  flex-wrap: wrap;
  row-gap: 10px;
}

/* Lets the nav shrink instead of pushing past the edge. */
.site-header .nav { min-width: 0; }
.site-header .brand { min-width: 0; }

.brand {
  /* Logo first, wordmark beside it, both hanging off the left edge. */
  display: inline-flex;
  align-items: center;
  gap: clamp(10px, 1.4vw, 18px);
  text-decoration: none;
  color: var(--deep);
  white-space: nowrap;
}

/* The logo beside the wordmark. Capped, or an uploaded 400px square fills the
   header: these rules were lost when the wordmark block was rewritten, and the
   mark rendered at its natural size. */
.brand-logo {
  height: clamp(38px, 5vw, 58px);
  width: auto;
  max-width: min(200px, 34vw);
  object-fit: contain;
  flex: 0 0 auto;
}

/* The wordmark keeps to one line, except where a narrow phone needs it to wrap. */
.brand .brand-name { white-space: nowrap; }
@media (max-width: 420px) {
  .brand .brand-name { white-space: normal; line-height: 1.15; }
}

/* Anywhere else the name appears -- the footer's copyright line -- it is just
   words in a sentence and inherits the surrounding type. */
footer .brand-name,
.site-footer .brand-name {
  font: inherit;
  letter-spacing: inherit;
  text-transform: none;
  color: inherit;
  padding: 0;
  background: none;
  border: 0;
}

/*
 * The wordmark, driven entirely by settings.
 *
 * Every property here reads a custom property with a fallback, so the store
 * works untouched and the owner can change the face, weight, slant, case,
 * spacing, size, colour and what sits around it without a deploy. The colour
 * falls back to the theme's deep tone and is contrast-checked on save; the
 * accent falls back to the theme's gold and is only ever used for a rule or a
 * frame, never for the lettering.
 */
.brand .brand-name,
.brand > :not(.brand-logo) {
  position: relative;
  font-family: var(--brand-font, var(--serif));
  font-size: calc(clamp(25px, 3.4vw, 37px) * var(--brand-scale, 1));
  font-weight: var(--brand-weight, 600);
  font-style: var(--brand-style, normal);
  letter-spacing: var(--brand-tracking, 0.055em);
  text-transform: var(--brand-case, uppercase);
  line-height: 1.05;
  /* ink, not deep: deep is a dark brand tone and reads at 1.4:1 on a dark
     theme's paper. ink is the tone every theme guarantees against its page. */
  color: var(--brand-color, var(--ink));
}

/* Nothing around the name. */
.brand[data-brand-decoration="none"] .brand-name { padding: 0; }

/* A hairline under it, fading out. */
.brand[data-brand-decoration="underline"] .brand-name { padding-bottom: 7px; }
.brand[data-brand-decoration="underline"] .brand-name::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: linear-gradient(
    90deg,
    var(--brand-accent, var(--gold)) 0%,
    color-mix(in srgb, var(--brand-accent, var(--gold)) 25%, transparent) 100%
  );
}

/* A frame around it. */
.brand[data-brand-decoration="box"] .brand-name {
  padding: 0.28em 0.5em;
  border: 1px solid var(--brand-accent, var(--gold));
  border-radius: var(--brand-radius, 0);
}

/* A filled plate. The lettering flips to the theme's on-deep tone, which is the
   colour that is legible on a dark fill -- keeping the configured colour here
   would be the one combination guaranteed to disappear. */
.brand[data-brand-decoration="block"] .brand-name {
  padding: 0.28em 0.55em;
  background: var(--brand-accent, var(--deep));
  color: var(--brand-on-accent, var(--on-deep));
  border-radius: var(--brand-radius, 0);
}
/* Side room to match the corner shape, supplied as a value rather than derived
   from the radius: dividing the radius produced invalid CSS at 0 and an absurd
   185px at the pill's 999px. */
.brand[data-brand-decoration="block"] .brand-name,
.brand[data-brand-decoration="box"] .brand-name {
  padding-inline: var(--brand-pad-inline, 0.6em);
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(14px, 3vw, 30px);
}

.nav a,
.nav button {
  appearance: none;
  background: none;
  border: 0;
  padding: 6px 0;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;
  border-bottom: 1px solid transparent;
}
.nav a:hover,
.nav button:hover,
.nav [aria-current="page"] { border-bottom-color: var(--gold); }

.search {
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--line);
  gap: 8px;
}
.search input {
  appearance: none;
  border: 0;
  background: transparent;
  font-family: var(--sans);
  font-size: 13px;
  padding: 8px 2px;
  width: clamp(110px, 18vw, 200px);
  color: var(--ink);
}
.search input:focus { outline: none; }
.search:focus-within { border-bottom-color: var(--gold); }
.search button {
  appearance: none;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--muted);
  padding: 6px;
  line-height: 0;
}

/* Below ~760px the brand, search field and links cannot share one row.
   The search moves to a line of its own rather than overflowing the viewport. */
@media (max-width: 760px) {
  .site-header .shell {
    flex-wrap: wrap;
    row-gap: 8px;
    min-height: 0;
    padding-block: 10px;
  }

  /*
   * Three rows: the name with the links beside it, the search, the category
   * strip. The search is a child of .nav, not of the shell, so it wraps inside
   * the nav rather than being placed by the shell -- pinning the nav to its
   * content width instead forced a 345px block into 288px of space and pushed
   * the page sideways.
   */
  .brand { flex: 0 1 auto; min-width: 0; }

  /*
   * Two rows on a phone: the name with the search beside it, then the category
   * strip. The Home and Collection links are dropped here -- the wordmark links
   * home and the strip opens with "All" -- because keeping them cost a whole row
   * and the header was taking a fifth of the screen.
   */
  .site-header .nav > a { display: none; }
  .site-header .nav {
    flex: 1 1 0;
    min-width: 0;
    justify-content: flex-end;
    gap: 12px;
  }
  .site-header .nav .search {
    order: 0;
    flex: 1 1 auto;
    min-width: 0;
  }
  .category-strip { padding-block: 9px; }

  .brand-name,
  .brand > :not(.brand-logo) { font-size: calc(21px * var(--brand-scale, 1)); }
  .brand[data-brand-decoration="underline"] .brand-name { padding-bottom: 5px; }

  .search input { width: 100%; flex: 1 1 auto; }
}

@media (max-width: 420px) {
  .brand .brand-name,
  .brand > :not(.brand-logo) { font-size: calc(18px * var(--brand-scale, 1)); }
  .site-header .nav { gap: 12px; }
  .nav a { font-size: 10.5px; letter-spacing: 0.11em; }
}

/* --- Hero carousel ------------------------------------------------------ */

.hero {
  position: relative;
  /* The shape of the artwork the owner uploads: 1920x683, so a banner cut to
     spec fills the box exactly, with nothing cropped and no bands. Capped by
     viewport height so a tall, narrow window cannot hand the hero the whole
     screen and push the catalogue out of sight. */
  aspect-ratio: var(--hero-shape, 1920 / 683);
  max-height: 68vh;
  display: grid;
  isolation: isolate;
  background: linear-gradient(160deg, var(--deep) 0%, var(--deep2) 100%);
  overflow: hidden;
}

/* The slides live inside .hero-track, so the track has to be the grid that
   stacks them — otherwise they flow one below the other instead of crossfading. */
.hero-track {
  grid-area: 1 / 1;
  display: grid;
}

.hero-slide {
  grid-area: 1 / 1;
  position: relative;
  display: grid;
  place-items: center;
  /* The CTA and dots are absolutely positioned at the bottom of the hero, so the
     slide reserves room for them — otherwise long headlines collide with the
     button on narrow screens. */
  padding: clamp(28px, 6vh, 72px) var(--gutter) clamp(136px, 18vh, 164px);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  opacity: 0;
  transition: opacity 1.1s ease;
  pointer-events: none;
}
.hero-slide.is-active { opacity: 1; pointer-events: auto; }

/* "Show whole image": for artwork that carries its own text, which cropping
   would cut. Two layers -- a blurred zoomed copy filling the box, then the
   complete artwork centred on top of it -- so nothing is cropped and no bare
   letterbox bars appear whatever shape the upload is. */
.hero-fill,
.hero-art {
  position: absolute;
  inset: 0;
  background-position: center;
  background-repeat: no-repeat;
}
.hero-fill {
  z-index: 0;
  background-size: cover;
  filter: blur(26px) saturate(1.15) brightness(0.72);
  /* Scaled up so the blur does not pull transparent edges into the box. */
  transform: scale(1.14);
}
.hero-art {
  z-index: 1;
  background-size: contain;
}
/* A far lighter scrim than a photographic banner gets: the artwork supplies its
   own contrast, and darkening it would dull the print. */
.hero-slide.is-fit::before {
  z-index: 2;
  background: linear-gradient(rgba(14, 26, 20, 0.06), rgba(14, 26, 20, 0.22));
}

.hero-slide::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(rgba(14, 26, 20, 0.35), rgba(14, 26, 20, 0.55));
}

.hero-inner {
  position: relative;
  z-index: 3;
  text-align: center;
  color: var(--on-deep);
  max-width: 680px;
}

.hero-rule {
  width: 54px;
  height: 1px;
  background: var(--gold);
  margin: 0 auto 22px;
  border: 0;
}

.hero h1 {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(34px, 6.4vw, 62px);
  line-height: 1.08;
  margin: 0 0 16px;
  text-wrap: balance;
}

.hero p {
  margin: 0 auto 30px;
  max-width: 46ch;
  font-size: clamp(14px, 1.6vw, 17px);
  color: color-mix(in srgb, var(--on-deep) 86%, transparent);
  text-wrap: pretty;
}


.hero-dots {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: clamp(20px, 3vh, 30px);
  z-index: 3;
  display: flex;
  gap: 10px;
}

.hero-dots button {
  appearance: none;
  width: 9px;
  height: 9px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--on-deep) 75%, transparent);
  background: transparent;
  cursor: pointer;
}
.hero-dots button[aria-current="true"] { background: var(--gold); border-color: var(--gold); }

/* --- Buttons ------------------------------------------------------------ */

.btn {
  display: inline-block;
  appearance: none;
  border: 1px solid var(--deep);
  background: var(--deep);
  color: var(--on-deep);
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  padding: 15px 34px;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}
.btn:hover { background: var(--deep2); border-color: var(--deep2); }

.btn-light {
  background: transparent;
  border-color: color-mix(in srgb, var(--on-deep) 70%, transparent);
  color: var(--on-deep);
}
.btn-light:hover { background: color-mix(in srgb, var(--on-deep) 12%, transparent); border-color: var(--on-deep); }

.btn-ghost {
  background: transparent;
  color: var(--deep);
}
.btn-ghost:hover { background: var(--deep); color: var(--on-deep); }

.btn[disabled] {
  cursor: not-allowed;
  opacity: 0.5;
  background: var(--muted);
  border-color: var(--muted);
}

.link-quiet {
  display: inline-block;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--deep);
  text-decoration: none;
  border-bottom: 1px solid var(--gold);
  padding-bottom: 3px;
}

.back-link {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
}
.back-link:hover { color: var(--deep); }

/* --- Sections ----------------------------------------------------------- */

/* padding-block, not the shorthand: `padding: x 0` also set padding-inline to
   zero, which overrode the gutter .shell sets and ran every section — the
   collection grid, the product gallery — edge to edge on a phone. */
.section { padding-block: clamp(48px, 7vw, 86px); }
.section + .section { padding-block-start: 0; }
.section[hidden] { display: none; }

/* --- Category tiles ----------------------------------------------------- */

.category-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: clamp(12px, 2vw, 22px);
}

.category-tile {
  position: relative;
  text-decoration: none;
  display: block;
  /* Square, because category art is square: a 4:5 portrait box cropped 20% off
     the width of every tile in the catalogue -- 10% from each side, straight
     through the piece the tile is meant to be showing. */
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border: 1px solid var(--line);
  background: linear-gradient(160deg, var(--deep) 0%, var(--deep2) 100%);
  cursor: pointer;
  padding: 0;
  text-align: left;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
/* The lift belongs to the tile; the shadow belongs to the art, which is round.
   On the square tile it drew a rectangular shadow around a circular image. */
.category-tile:hover { transform: translateY(-4px); }

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

/* Art that is not the tile's shape shows whole instead of being cropped, over a
   blurred copy of itself -- the tiles share one box so the grid stays even, and
   bare colour in the leftover space reads as a broken image. */
.category-tile.is-contained img {
  object-fit: contain;
  /* Positioned so it paints above the backdrop below. */
  position: relative;
}
.category-tile.is-contained::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--tile-art);
  background-size: cover;
  background-position: center;
  filter: blur(18px) brightness(0.68) saturate(1.1);
  transform: scale(1.16);
}

.category-tile::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  /* Above the artwork, below the label it exists to make readable. */
  z-index: 1;
  height: 62%;
  background: linear-gradient(rgba(14, 26, 20, 0), rgba(14, 26, 20, 0.72));
}

.category-tile span {
  position: absolute;
  z-index: 2;
  left: 0; right: 0; bottom: 18px;
  text-align: center;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(18px, 2.2vw, 23px);
  color: var(--on-deep);
  padding-inline: 10px;
}

/* A "show whole image" banner on a phone: the box is nearly square there
   (min-height wins over the width), so wide artwork floated in blurred bands —
   up to 129px above and below a 3:1 banner, two thirds of the box empty. On a
   phone the box takes the shape of the artwork instead, and the controls move
   below it, because 200px of height cannot hold an overlaid button as well. */
@media (max-width: 759px) {
  .hero,
  .hero.is-art {
    display: block;
    min-height: 0;
    max-height: none;
    aspect-ratio: auto;
  }
  .hero .hero-track { aspect-ratio: var(--hero-shape, 1920 / 683); }
  .hero.is-art .hero-track { aspect-ratio: var(--hero-ratio, 2); }
  .hero .hero-slide,
  .hero.is-art .hero-slide { padding: 0; }

  /* No scrim and no overlaid headline: artwork kept whole is artwork that
     carries its own words, so the overlay would print them twice. */
  .hero.is-art .hero-slide::before { display: none; }
  .hero.is-art .hero-inner { display: none; }

  .hero .hero-dots {
    position: static;
    transform: none;
    display: flex;
    justify-content: center;
  }
  .hero .hero-dots { padding: 14px 0 18px; }
  /* The artwork carries its own words at this size. */
  .hero .hero-inner { display: none; }
  .hero .hero-slide::before { display: none; }
}

/* --- Product grid & cards ----------------------------------------------- */

.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: clamp(16px, 2.4vw, 30px);
}

/* A minimum column width means one column on every phone, which makes each tile
   as wide as the screen. Two columns of 180px plus the gap need 372px, but a
   390px phone only offers 358px inside the gutter, so the category grid
   collapsed to one 358px square per row while the products beside it sat
   two-up. Every tile grid is explicitly two-up on a phone. */
@media (max-width: 759px) {
  .category-grid,
  .product-grid,
  .skeleton-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
  }
}

.card {
  position: relative;
  text-decoration: none;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--line);
  cursor: pointer;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: center;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow); }

.card-media {
  position: relative;
  /* Set per product, so a piece shot on a stand is not cropped square. */
  aspect-ratio: var(--media-ratio, 1 / 1);
  background: var(--gold-soft);
  overflow: hidden;
}
.card-media img { width: 100%; height: 100%; object-fit: cover; }

.card-media .placeholder {
  display: grid;
  place-items: center;
  width: 100%; height: 100%;
  font-size: 34px;
  color: var(--muted);
}

/*
 * A sold-out piece keeps its own colours.
 *
 * This used to be grayscale(1) at 55% opacity, which hid the one thing a shopper
 * is looking at -- a saree's colour -- and made the photo look broken rather
 * than unavailable. The "Sold out" mark says what the greying was trying to say,
 * and says it in words.
 */
.card.is-sold-out .card-media img { filter: none; opacity: 1; }

.tag {
  position: absolute;
  z-index: 2;
  top: 10px;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 5px 9px;
  color: var(--on-deep);
}
.tag-promo { right: 10px; background: var(--deep); }
.tag-sold { left: 10px; background: var(--danger); }

.card-body { padding: 16px 14px 20px; }

.card-eyebrow {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin: 0 0 7px;
}

.card-name {
  font-family: var(--serif);
  font-size: clamp(17px, 2vw, 21px);
  font-weight: 500;
  line-height: 1.25;
  margin: 0 0 8px;
}

.card-price {
  margin: 0;
  font-size: 13px;
  color: var(--muted);
  letter-spacing: 0.04em;
}

/* --- Prices -------------------------------------------------------------
   A sale shows three parts: what you pay, the former price struck through,
   and the saving. The current price carries the weight so the eye lands on it
   first; the former price recedes. */
.price-now { color: var(--ink); }
.price-now.is-sale { font-weight: 600; }

.price-was {
  margin-inline-start: 8px;
  color: var(--muted);
  /* The strike is the whole point of the element, so it is drawn deliberately
     rather than left to the browser's default weight. */
  text-decoration-thickness: 1px;
  text-decoration-color: var(--muted);
}

.price-off {
  margin-inline-start: 8px;
  font-size: 0.82em;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--danger);
}

/* --- Collection view ---------------------------------------------------- */

.chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-bottom: clamp(26px, 4vw, 42px);
}

.chip {
  appearance: none;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 9px 18px;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.chip:hover { border-color: var(--gold); }
.chip[aria-pressed="true"] { background: var(--deep); border-color: var(--deep); color: var(--on-deep); }

/* The back link and the title share one row. The two 1fr side columns are
   equal, so the title stays optically centred on the page while the link sits
   in the left one. */
.view-head {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: 20px;
  margin-bottom: clamp(22px, 3vw, 34px);
}
.view-head .back-row {
  grid-column: 1;
  justify-self: start;
}
.view-head .section-head {
  grid-column: 2;
  margin-bottom: 0;
}

/* The collection and product views open straight into their content: no tall
   pad under the nav, and on the collection the rule tucked closer to the
   heading. */
#listView .section,
#detailView .section { padding-block-start: clamp(18px, 2vw, 26px); }
#listView .rule { margin-block-start: 8px; }
/* Flex, not a bare line box: the paragraph's strut would otherwise push the
   small back link a few pixels down and the two pages would open unevenly. */
#detailView .back-row {
  display: flex;
  margin: 0 0 16px;
}

/* Narrow screens: one row would crowd, so it stacks as before — back link
   above a centred title. */
@media (max-width: 620px) {
  .view-head {
    grid-template-columns: 1fr;
    row-gap: 12px;
  }
  .view-head .back-row,
  .view-head .section-head { grid-column: 1; }
}

.chip-child { font-size: 10px; padding: 8px 14px; }

/* --- More pieces, under a product --------------------------------------- */

/* A hairline and a generous gap: the row is a change of subject, not more of
   the product above it. */
.related {
  margin-block-start: clamp(52px, 8vw, 88px);
  padding-block-start: clamp(32px, 5vw, 56px);
  border-block-start: 1px solid var(--line);
}

/* --- Detail view -------------------------------------------------------- */

.detail {
  display: grid;
  gap: clamp(24px, 4vw, 54px);
  align-items: start;
}

/* On a phone the photo is a whole screenful, so with the name inside the text
   column it sat about 970px down the page — the product had no visible title
   until you scrolled past the image and its thumbnails. The name and price
   come first instead, then the photo, then the rest. */
.detail-head { order: -1; }
.detail-head .detail-name,
.detail-head .detail-price { margin-block-end: 0; }

@media (min-width: 760px) {
  .detail {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas:
      "media head"
      "media info";
    grid-template-rows: auto 1fr;
    column-gap: clamp(24px, 4vw, 54px);
    row-gap: 18px;
  }
  .detail-media { grid-area: media; }
  .detail-head { grid-area: head; }
  .detail-info { grid-area: info; }
}

.gallery-main {
  aspect-ratio: var(--media-ratio, 1 / 1);
  background: var(--gold-soft);
  border: 1px solid var(--line);
  overflow: hidden;
  position: relative;
  /* The browser keeps vertical scrolling; sideways movement is the gallery's,
     so a swipe through the photos does not fight the page. */
  touch-action: pan-y;
  /* A drag across the photo is a swipe, not a text or image selection. */
  user-select: none;
  -webkit-user-select: none;
}
.gallery-main img { width: 100%; height: 100%; object-fit: cover; }
.gallery-main .placeholder { display: grid; place-items: center; height: 100%; font-size: 54px; color: var(--muted); }
/* Same on the product page: the photo is the reason the page was opened. */
.gallery-main.is-sold-out img { filter: none; opacity: 1; }

.thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 12px;
}
.thumbs button {
  width: 68px;
  height: auto;
  aspect-ratio: var(--media-ratio, 1 / 1);
  padding: 0;
  border: 1px solid var(--line);
  background: var(--gold-soft);
  cursor: pointer;
  overflow: hidden;
}
.thumbs button[aria-current="true"] { border-color: var(--gold); box-shadow: inset 0 0 0 1px var(--gold); }
.thumbs img { width: 100%; height: 100%; object-fit: cover; }

.detail-name {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(30px, 4.6vw, 48px);
  line-height: 1.1;
  margin: 0 0 14px;
}

.detail-price {
  font-size: 19px;
  letter-spacing: 0.05em;
  color: var(--ink);
  margin: 0 0 20px;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
}
/* The spacing is carried by the margins on the parts themselves, so a card and
   the product page set the trio identically. */
.detail-price .price-was { font-size: 0.85em; }

.detail-desc {
  color: var(--ink);
  margin: 0 0 30px;
  max-width: 60ch;
}
.detail-desc p { margin: 0 0 14px; }
.detail-desc p:last-child { margin-bottom: 0; }
.detail-desc h3,
.detail-desc h4 {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 22px 0 8px;
}
.detail-desc ul,
.detail-desc ol { margin: 0 0 14px; padding-left: 20px; }
.detail-desc li { margin-bottom: 5px; }
.detail-desc blockquote {
  margin: 0 0 14px;
  padding-left: 14px;
  border-left: 1px solid var(--gold);
  font-family: var(--serif);
  font-style: italic;
  font-size: 17px;
}
.detail-desc a { color: var(--accent-text); text-underline-offset: 3px; }
.detail-desc strong { font-weight: 600; }

/* Attribute list on the product page. */
.spec {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 18px;
  margin: 0 0 28px;
  font-size: 13px;
}
.spec dt {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  align-self: center;
}
.spec dd { margin: 0; color: var(--ink); }

.detail-meta {
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  color: var(--muted);
  letter-spacing: 0.04em;
}
.detail-meta p { margin: 0 0 6px; }
.detail-sku { letter-spacing: 0.12em; text-transform: uppercase; font-size: 11px; }

.sold-note {
  color: var(--danger);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin: 0 0 16px;
}

.buy-slot { min-height: 52px; }
.buy-slot form { margin: 0; }

/* --- Variant options ---------------------------------------------------- */

.options { margin: 0 0 26px; display: grid; gap: 16px; }

.option-name {
  margin: 0 0 8px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
}

.option-values { display: flex; flex-wrap: wrap; gap: 8px; }

.option-chip[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
  text-decoration: line-through;
}
.option-chip[disabled]:hover { border-color: var(--line); }

/* --- Email capture band ------------------------------------------------- */

.capture {
  background: linear-gradient(140deg, var(--deep) 0%, var(--deep2) 100%);
  color: var(--on-deep);
  padding: clamp(44px, 6vw, 72px) 0;
  margin-top: clamp(48px, 7vw, 86px);
  text-align: center;
}
.capture h2 {
  font-family: var(--serif);
  font-weight: 400;
  font-style: italic;
  font-size: clamp(26px, 3.6vw, 38px);
  margin: 0 0 10px;
}
.capture p { margin: 0 auto 26px; max-width: 44ch; color: color-mix(in srgb, var(--on-deep) 80%, transparent); font-size: 14px; }
.capture .eyebrow { color: var(--gold); }

.capture-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  max-width: 520px;
  margin-inline: auto;
}
.capture-form input {
  flex: 1 1 240px;
  min-width: 0;
  appearance: none;
  border: 1px solid color-mix(in srgb, var(--on-deep) 40%, transparent);
  background: color-mix(in srgb, var(--on-deep) 6%, transparent);
  color: var(--on-deep);
  font-family: var(--sans);
  font-size: 14px;
  padding: 14px 16px;
}
.capture-form input::placeholder { color: color-mix(in srgb, var(--on-deep) 55%, transparent); }
.capture-form input:focus { outline: none; border-color: var(--gold); }

.capture-msg {
  margin: 16px 0 0;
  font-size: 13px;
  min-height: 20px;
  letter-spacing: 0.04em;
}
.capture-msg.is-error { color: #ffbcae; }
.capture-msg.is-ok { color: var(--gold-soft); }

/* --- Footer ------------------------------------------------------------- */

.site-footer {
  background: var(--paper);
  border-top: 1px solid var(--line);
  padding: 40px 0;
  font-size: 12px;
  color: var(--muted);
}
.site-footer .shell {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  justify-content: space-between;
  align-items: center;
}
.site-footer a { color: var(--muted); text-decoration: none; letter-spacing: 0.16em; text-transform: uppercase; font-size: 11px; }
.site-footer a:hover { color: var(--deep); }

/* --- States ------------------------------------------------------------- */

.empty {
  text-align: center;
  color: var(--muted);
  padding: clamp(40px, 8vw, 90px) 0;
}
.empty h2 {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  color: var(--ink);
  font-size: clamp(24px, 3.4vw, 34px);
  margin: 0 0 12px;
}
.empty p { margin: 0 auto 18px; max-width: 44ch; }

.skeleton-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 24px; }
.skeleton {
  aspect-ratio: 3 / 4;
  background: linear-gradient(100deg, var(--gold-soft) 30%, #f6f1e7 50%, var(--gold-soft) 70%);
  background-size: 300% 100%;
  animation: shimmer 1.4s linear infinite;
}
@keyframes shimmer {
  from { background-position: 150% 0; }
  to { background-position: -50% 0; }
}

.toast {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translate(-50%, 16px);
  z-index: 60;
  background: var(--deep2);
  color: var(--on-deep);
  padding: 13px 22px;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.toast.is-visible { opacity: 1; transform: translate(-50%, 0); }

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .hero-slide { transition: none; }
}

/* --- Share row ---------------------------------------------------------- */

.share {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 22px;
}

.share-label {
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}

.share-btn {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--deep);
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.share-btn:hover,
.share-btn:focus-visible {
  background: var(--deep);
  border-color: var(--deep);
  color: var(--on-deep);
}
.share-btn svg { width: 20px; height: 20px; display: block; }

/* --- Popular categories -------------------------------------------------- */

/* A row of the promoted categories, above the banner, so they are reachable
   without scrolling past it. Scrolls sideways on a phone rather than wrapping
   into a block that pushes the banner down the page. */
.category-strip {
  display: flex;
  gap: clamp(14px, 2vw, 30px);
  align-items: center;
  /*
   * `center` alone loses the first items when the row overflows: the overflow is
   * split both ways, so the start scrolls off to the left and cannot be reached.
   * On a phone that showed the strip already cut mid-word. `safe center` centres
   * only while everything fits and falls back to the start when it does not.
   */
  justify-content: flex-start;
  justify-content: safe center;
  padding: 12px var(--gutter);
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  scrollbar-width: none;
}
.category-strip::-webkit-scrollbar { display: none; }

.category-strip a {
  flex: 0 0 auto;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  white-space: nowrap;
}
.category-strip a:hover,
.category-strip a:focus-visible { border-bottom-color: var(--gold); }

/* Round category art, with the name beneath it rather than across it: a circle
   would clip a label laid over the bottom of the tile. */
.category-tile {
  aspect-ratio: auto;
  border: 0;
  background: none;
  overflow: visible;
  display: grid;
  gap: 12px;
  justify-items: center;
  /* Rows sized to their content, not stretched to fill the tile. Tiles stretch
     to the tallest in the row, and the spare height was being handed to the art
     row -- which a photo ignores (its height comes from its ratio) but the
     placeholder took, so one circle rendered 215px beside 202px neighbours. */
  align-content: start;
  text-align: center;
}
.category-tile img,
.category-tile.is-contained img {
  aspect-ratio: 1 / 1;
  width: 100%;
  height: auto;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--line);
  background: var(--gold-soft);
}
.category-tile.is-contained::before { display: none; }
.category-tile::after { display: none; }
.category-tile span {
  position: static;
  inset: auto;
  color: var(--ink);
  font-size: clamp(13px, 1.5vw, 16px);
  letter-spacing: 0.04em;
  padding: 0;
}
.category-tile:hover img,
.category-tile:focus-visible img,
.category-tile:hover .tile-blank { box-shadow: var(--shadow); }

/* Holds the circle's place when a category has no photo yet. */
.tile-blank {
  width: 100%;
  aspect-ratio: 1 / 1;
  /* Belt to the align-content brace above: never taller than its own ratio. */
  align-self: start;
  border-radius: 50%;
  background: var(--gold-soft);
  border: 1px solid var(--line);
}

/* --- The rail under a product ------------------------------------------- */

/*
 * A sideways shelf rather than a grid: the row holds more pieces than fit, so
 * it scrolls. Touch scrolls it directly; the arrows are for a mouse, and they
 * hide themselves when there is nothing to scroll.
 */
.rail {
  position: relative;
}

.rail-track {
  display: flex;
  /*
   * Each card keeps its own height. Stretching is the flex default, and with
   * mixed photo shapes in one row it padded every square card with dead space:
   * measured on the home rail, one 3:4 card made six 1:1 cards 474px tall for
   * 342px of content.
   */
  align-items: start;
  gap: 16px;
  overflow-x: auto;
  scroll-behavior: smooth;
  scroll-snap-type: x proximity;
  /* Room for the cards' hover lift, which would otherwise be clipped. */
  padding: 6px 2px 10px;
  scrollbar-width: thin;
}

.rail-track > .card {
  flex: 0 0 clamp(150px, 42vw, 232px);
  scroll-snap-align: start;
}

.rail-arrow {
  position: absolute;
  top: calc(50% - 22px);
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--card);
  color: var(--ink);
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: opacity 0.2s ease, background 0.2s ease;
}
.rail-arrow svg { width: 20px; height: 20px; }
.rail-prev { left: -6px; }
.rail-next { right: -6px; }
.rail-arrow:hover { background: var(--gold-soft); }
.rail-arrow:disabled { opacity: 0.3; cursor: default; }

/* On a touch screen the finger is the control, so the arrows stay out of the
   way of the cards. */
@media (hover: none) {
  .rail-arrow { display: none; }
}

/*
 * The product's title, under its name.
 *
 * Smaller and lighter than the name: the name identifies the piece, the title
 * describes it, and running them together on one line made both harder to scan.
 */
.card-title {
  margin: 2px 0 0;
  font-size: 0.82em;
  line-height: 1.35;
  color: var(--muted);
  text-wrap: pretty;
}

/*
 * Which variant a card is for, following the name on the same line.
 *
 * Small enough that the name still leads, and in the quieter tone, so the pair
 * reads as one thing -- this piece, in this colourway -- rather than as two
 * competing lines. em-relative, so it tracks the name at every viewport.
 */
.card-variant {
  /*
   * Set like the category label at the top of the card: the page sans,
   * uppercase, letterspaced. It sits inside the name, which is serif, so the
   * family has to be stated -- inheriting is what made it read as small serif
   * caps rather than as a label.
   */
  font-family: var(--sans);
  font-size: 8px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  /*
   * Dark, without being the flat near-black the name is set in. Mixed from the
   * palette's own two ends rather than picked as a literal, so it follows every
   * theme: across all thirteen it lands at 11.3-12.5:1 against the card, where
   * ink itself is 14-17.8. The brand's deep tone was the obvious candidate and
   * is unusable -- on the two onyx themes it measures 1.32:1, a dark green on a
   * dark card.
   *
   * The plain declaration first is the fallback for anything without color-mix.
   */
  color: var(--muted);
  color: color-mix(in srgb, var(--ink) 88%, var(--card));
  /*
   * A label too wide for the card wraps inside itself rather than running out of
   * it; `anywhere` is the last resort for one word that still will not fit.
   * Forbidding the wrap outright (white-space: nowrap) kept the label whole but
   * pushed "Violet-Yellow Deluxe" straight out of a 360px card.
   */
  overflow-wrap: anywhere;
}

.card-variant::before {
  /*
   * A non-breaking hyphen (U+2011), not a plain one.
   *
   * The dash belongs to the label, not to the name, so it is drawn here rather
   * than written into the markup. A hyphen-minus is Unicode line-break class
   * HY, which permits a break right after it -- and rule LB12a exempts it from
   * the usual "no break before a non-breaking space" -- so even "-\00a0" split,
   * measured on a 360px card as the dash alone on one line (top 670) and the
   * colourway on the next (top 692). U+2011 is class GL: nothing breaks either
   * side of it, so the dash always travels with the label, and the space before
   * it in the markup stays the one place a break may fall. It draws the same
   * glyph.
   */
  content: "\2011\00a0";
  letter-spacing: normal;
}

.detail-title {
  margin: 6px 0 0;
  font-family: var(--serif);
  font-size: clamp(15px, 1.9vw, 20px);
  line-height: 1.3;
  color: var(--ink-soft, var(--muted));
  text-wrap: pretty;
}

/*
 * An option whose variants are all sold out.
 *
 * Struck through and quietened, but still a working control: choosing it is how
 * a shopper gets to the waiting list. Distinct from a disabled chip, which is a
 * combination that does not exist at all and cannot be chosen.
 */
.option-chip.is-sold-out {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  color: var(--muted);
  border-color: var(--line);
}
.option-chip.is-sold-out[aria-pressed="true"] {
  /* Still legible as the current choice, which is where the form appears. */
  color: var(--on-deep);
  text-decoration-color: color-mix(in srgb, var(--on-deep) 60%, transparent);
}

/*
 * The same offer on a card, for a piece that is sold out.
 *
 * Underlined and in the accent tone so it reads as the thing the card will do,
 * rather than as another line of description. It is text, not a control: the
 * card is already one link, and a button inside a link is invalid markup that no
 * keyboard can reach.
 */
.card-notify {
  margin: 6px 0 0;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.card:hover .card-notify { color: var(--deep); }

/* --- "Tell me when it's back" -------------------------------------------- */

/*
 * Shown under the disabled Sold out button, which would otherwise be the end of
 * the page for a shopper who wanted exactly this piece.
 */
.notify { margin-top: 14px; }

.notify-open {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  font-family: var(--sans);
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.notify-open:hover { color: var(--deep); }

.notify-form {
  display: grid;
  gap: 10px;
  margin-top: 12px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card);
  max-width: 340px;
}

.notify-what { margin: 0; font-size: 13px; color: var(--muted); }

.notify-field { display: grid; gap: 4px; }
.notify-field > span {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
/* The word "optional" belongs to the label, not to the emphasis of a heading. */
.notify-field em { font-style: normal; font-weight: 400; letter-spacing: 0.04em; text-transform: none; }

.notify-field input {
  font-family: var(--sans);
  font-size: 15px;
  padding: 9px 11px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  color: var(--ink);
}
.notify-field input:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

.notify-msg:empty { display: none; }
.notify-msg { margin: 0; font-size: 13px; color: var(--muted); }

.notify-done {
  margin: 0;
  font-size: 14px;
  color: color-mix(in srgb, var(--ink) 88%, var(--card));
}

/* --- Subcategory row ------------------------------------------------------ */

/*
 * The second filter row, and deliberately not a copy of the first.
 *
 * The rows answer different questions -- which part of the shop, then where
 * inside it -- so the second is smaller, rounded, and quieter, and sits closer
 * to the grid it is narrowing. They used to be one wrapped line distinguished
 * by a "└" glyph, which at chip size read as a stray character.
 */
.chips-sub {
  margin-top: -6px;
  padding-bottom: 4px;
}

.chip-sub {
  font-size: 10px;
  letter-spacing: 0.1em;
  padding: 6px 14px;
  border-radius: 999px;
  border-color: color-mix(in srgb, var(--line) 70%, transparent);
  background: transparent;
  color: var(--muted);
}
.chip-sub:hover { color: var(--ink); border-color: var(--gold); }
.chip-sub[aria-pressed="true"] {
  background: var(--gold-soft, color-mix(in srgb, var(--gold) 16%, transparent));
  border-color: var(--gold);
  color: var(--ink);
}

/* --- Growing the listing -------------------------------------------------- */

.list-more {
  display: grid;
  justify-items: center;
  gap: 10px;
  padding: 28px 0 4px;
}

.list-count {
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
