/* opal.cy — Shimmer Runway.
   Warm off-white, warm charcoal, an opal glow behind key moments,
   arches for every photo, pill buttons. Phone first. */

@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-latin-wght-normal.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-latin-wght-italic.woff2") format("woff2");
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-latin-wght-normal.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #fbf8f3;
  --bg-deep: #f2ebe1;
  --surface: #fffcf7;
  --ink: #2a2622;
  --ink-soft: #6b6159;
  --ink-lift: #413a34;
  --sand: #e7d9c6;
  --clay: #c9ad8e;
  --line: rgba(42, 38, 34, .14);
  --opal-1: #f6d9e4;
  --opal-2: #d7e9f7;
  --opal-3: #e3f5e1;
  --opal-4: #fbefd2;
  --opal-5: #ecdcf7;
  --serif: "Fraunces", "Iowan Old Style", Georgia, serif;
  --sans: "Inter", -apple-system, "Segoe UI", system-ui, sans-serif;
  --gutter: clamp(16px, 4.5vw, 44px);
  --max: 1280px;
  --max-tight: 1080px;
  --ease: cubic-bezier(.2, .7, .2, 1);
  --arch: 100vmax 100vmax 0 0;
  --tabbar-space: calc(84px + env(safe-area-inset-bottom));
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 88px; }
body {
  margin: 0;
  min-height: 100svh;
  background: var(--bg);
  color: var(--ink);
  font: 400 16px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  padding-bottom: var(--tabbar-space);
  overflow-x: hidden;
}
img { display: block; max-width: 100%; }
a { color: inherit; }
h1, h2, h3 { margin: 0; font-weight: 300; }
p { margin: 0; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .35s; }

.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 100;
  background: var(--ink); color: var(--bg); padding: 10px 16px; border-radius: 999px;
  text-decoration: none; font-size: 14px;
}
.skip-link:focus { top: 12px; }

/* ------------------------------------------------------------ top bar */
.topbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; justify-content: center;
  min-height: 60px; padding: 8px var(--gutter);
  background: rgba(251, 248, 243, .72);
  -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
}
.wordmark {
  display: inline-block; padding: 7px 6px;
  font: italic 400 30px/1 var(--serif);
  letter-spacing: -.01em; text-decoration: none; color: var(--ink);
}
/* Sized by height, because the logo is wordmark over BOUTIQUE and it is the
   height that has to sit inside the bar. width:auto keeps it from being
   squashed on a narrow phone. */
.logo { height: 46px; width: auto; }
@media (min-width: 948px) { .logo { height: 56px; } }
.topnav { display: none; }

/* ------------------------------------------------------------ tab bar */
.tabbar {
  position: fixed; z-index: 50;
  left: 12px; right: 12px; bottom: calc(12px + env(safe-area-inset-bottom));
  display: grid; grid-template-columns: repeat(4, 1fr);
  height: 60px; padding: 0 6px;
  border-radius: 30px; border: 1px solid var(--line);
  background: rgba(255, 252, 247, .78);
  -webkit-backdrop-filter: blur(18px) saturate(1.2); backdrop-filter: blur(18px) saturate(1.2);
  box-shadow: 0 12px 30px -18px rgba(42, 38, 34, .45);
}
.tab {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  color: var(--ink-soft); text-decoration: none;
  font: 500 10px/1 var(--sans); letter-spacing: .12em; text-transform: uppercase;
}
.tab-icon { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.tab[aria-current="page"] { color: var(--ink); }
.tab[aria-current="page"] .tab-icon { stroke-width: 1.9; }

/* --------------------------------------------------------------- glow */
.sheen {
  position: absolute; inset: -50%; z-index: -1; pointer-events: none;
  background: conic-gradient(from 0deg, var(--opal-1), var(--opal-2), var(--opal-3), var(--opal-4), var(--opal-5), var(--opal-1));
  filter: blur(70px);
  opacity: .75;
  animation: sheen-spin 40s linear infinite;
}
.sheen-soft { opacity: .45; }
@keyframes sheen-spin { to { transform: rotate(1turn); } }
/* Let the glow melt into the page instead of stopping at a hard edge. */
.hero::after, .brand-head::after, .visit-hero::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 28%; z-index: -1; pointer-events: none;
  background: linear-gradient(180deg, rgba(251, 248, 243, 0), var(--bg) 88%);
}

/* ------------------------------------------------------------- arches */
.arch {
  position: relative; display: block; overflow: hidden;
  border-radius: var(--arch);
  background: linear-gradient(180deg, var(--bg-deep), var(--sand));
}
/* A photo the POS has a WebP of comes as <picture>; it must add nothing to the
   arch's layout, so the <img> inside sizes itself exactly as it always did. */
.arch picture { display: contents; }
.arch img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.2s var(--ease), opacity .5s var(--ease); }
.arch-card { aspect-ratio: 5 / 7; }
.arch-empty { position: absolute; inset: 0; background: linear-gradient(180deg, var(--surface), var(--bg-deep)); }

/* ------------------------------------------------------------ buttons */
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 0 24px;
  border: 1px solid var(--ink); border-radius: 999px;
  background: var(--ink); color: var(--bg);
  font: 500 12px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase;
  text-decoration: none; cursor: pointer;
  transition: background-color .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease);
}
.button:hover { background: var(--ink-lift); }
.button-quiet { background: transparent; color: var(--ink); }
.button-quiet:hover { background: rgba(42, 38, 34, .06); }
.button[disabled] { background: transparent; color: var(--ink-soft); border-color: var(--line); cursor: not-allowed; }
/* The display above otherwise beats the UA's [hidden] rule, so the Checkout
   button site.js hides on an empty cart would stay on the page. */
.button[hidden] { display: none; }
.button-block { width: 100%; }

.chips {
  display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none;
  padding: 6px var(--gutter) 10px; max-width: var(--max); margin: 0 auto;
}
.chips::-webkit-scrollbar { display: none; }
.chip {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 0 18px; border: 1px solid var(--ink); border-radius: 999px;
  background: rgba(255, 252, 247, .5);
  font: 500 11px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase;
  text-decoration: none; color: var(--ink); white-space: nowrap;
}
.chip:hover { background: var(--ink); color: var(--bg); }

/* ----------------------------------------------------------- sections */
.main { display: block; }
.section { max-width: var(--max); margin: 0 auto; padding: 48px var(--gutter); }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 24px; }
.section-title { font: italic 300 clamp(34px, 7vw, 60px)/1 var(--serif); letter-spacing: -.02em; }
.link-more {
  display: inline-block; padding: 17px 0; margin: -17px 0;
  font: 500 11px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase; text-underline-offset: 5px;
  /* Beside a heading that wraps on a phone, "See all" must not wrap with it. */
  flex: none; white-space: nowrap;
}
.page-head { max-width: var(--max); margin: 0 auto; padding: 28px var(--gutter) 12px; }
/* The cart and the checkout use a narrower container than the rest of the site.
   Their title and their content both carry it, so on a wide screen the title,
   the first cart line and the first field all begin on the same left edge, and
   the panel on the right ends at the title's own right gutter. Below 1080px it
   changes nothing, so the phone layout is untouched. */
.page-head.width-tight, .section.width-tight { max-width: var(--max-tight); }
.page-title { font: 300 clamp(48px, 13vw, 112px)/.92 var(--serif); letter-spacing: -.03em; }
.page-sub { margin-top: 10px; color: var(--ink-soft); font-size: 14px; }
.empty { color: var(--ink-soft); font: italic 300 22px/1.4 var(--serif); padding: 24px 0; }

/* -------------------------------------------------------------- cards */
.grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px 14px;
}
.card-link { display: block; text-decoration: none; color: inherit; }
/* Two rows: the photograph, then the dots. The dots' row is reserved on every
   card, with dots or without, so two pieces beside each other keep their titles
   on one line when one has five photographs and the other has one. The room
   under the photograph is what the arch's shadow needs; a gallery has to carry
   that as its own padding, because overflow-x has made it a box that clips. */
.card-media { display: grid; grid-template-rows: auto 8px; }
.card-media > .arch { margin-bottom: 12px; }
.card .arch { box-shadow: 0 22px 32px -26px rgba(80, 60, 40, .55); }
.card-meta { display: grid; gap: 4px; margin-top: 14px; text-align: center; }
.card-brand { font: 500 10px/1.2 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft); }
.card-title { font: 400 17px/1.2 var(--serif); }
.card-price { font-size: 13px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }

/* The photos of one piece, swiped on a touch screen without leaving the grid.
   One photo fills the card and snaps, the way the item page's gallery does;
   the dots below it are the same dots. The bottom padding is there to let the
   arch's shadow out of a box that overflow-x has made a clipping one, and
   overscroll-behavior stops a swipe past the last photo turning into the
   browser's own back gesture. Every arch carries aspect-ratio 5 / 7, so the
   grid is its final height before a single photograph has arrived. */
.card-gallery {
  display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; overscroll-behavior-x: contain; padding-bottom: 12px;
}
.card-gallery::-webkit-scrollbar { display: none; }
.card-shot { display: block; flex: 0 0 100%; scroll-snap-align: center; }
/* Held back until the shopper reaches for them — see site.js. An image inside a
   box the page has not drawn is never fetched, so a shop page asks for the same
   two photographs a piece it always did, however many the shop now sends.
   Behind the `.js` class, like `.reveal`: without a script every photograph is
   on the card as it always was, and the browser's own lazy loading decides.
   That gate was measured rather than assumed — site.js is deferred, so it was
   worth knowing whether the browser makes up its mind about an image before the
   script has set the class. On a grid of 44 pieces with five photographs each
   at 375 px, 92 of the 95 held-back photographs were never asked for either
   way; the three that were had already been fetched by the piece's own page
   earlier in the same visit and came out of the browser's cache. */
.js .card-shot[data-gallery-defer] { display: none; }
.card-dots { display: flex; align-items: center; justify-content: center; gap: 6px; }

@media (hover: hover) {
  /* A mouse keeps the card exactly as it was before the gallery: the first
     photo, the second laid over it and faded in on hover, and any others left
     out of the page altogether — so a desktop grid never asks for a third
     photograph, and the hover and layout behaviour here is unchanged, down to
     the fourteen pixels between the photograph and the piece's name. */
  .card-media { grid-template-rows: auto 0; }
  .card-media > .arch { margin-bottom: 0; }
  .card-gallery { display: block; position: relative; overflow: visible; padding-bottom: 0; scroll-snap-type: none; }
  .card-shot:nth-child(2) { position: absolute; inset: 0; opacity: 0; transition: opacity .6s var(--ease); }
  .card-shot:nth-child(n+3) { display: none; }
  .card-dots { display: none; }
  .card-link:hover .card-shot:nth-child(2) { opacity: 1; }
  .card-link:hover img { transform: scale(1.03); }
}

/* ----------------------------------------------------- message pages */
.message {
  position: relative; isolation: isolate; overflow: hidden;
  max-width: 900px; margin: 24px var(--gutter) 40px;
  padding: clamp(96px, 22vw, 180px) var(--gutter) 56px;
  border-radius: 100vmax 100vmax 32px 32px;
  background: var(--surface); text-align: center;
}
@media (min-width: 948px) { .message { margin: 40px auto; } }
.message-title { font: 300 clamp(42px, 10vw, 88px)/.95 var(--serif); letter-spacing: -.02em; }
.message-title em { font-style: italic; }
.message-text { margin: 18px auto 0; max-width: 32ch; color: var(--ink-soft); }
.message-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-top: 28px; }

/* The paid confirmation, inside the same arch-topped message card as every other
   state. The pieces are shown the way the cart shows them — the same arch
   thumbnail, the same row — so a customer sees the objects they chose rather
   than a list of strings. The total carries the weight; the line prices step
   back so they do not compete with it. */
.order-summary { position: relative; margin: 32px auto 0; max-width: 34rem; text-align: left; }
/* The card is far taller than the other message pages, and the glow behind it
   would wash right over the order. This settles it out below the thank-you, the
   way the home page's arches melt into the page, so the colour stays the one
   memorable moment and the pieces are read on a calm surface. */
.order-summary::before {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset: -32px -100vmax -100vmax;
  background: linear-gradient(180deg, rgba(255, 252, 247, 0), var(--surface) 96px);
}
.order-lines { list-style: none; margin: 0; padding: 0; }
.order-line {
  display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; gap: 14px; align-items: center;
  padding: 14px 0; border-top: 1px solid var(--line);
}
/* A piece with no photo keeps its column: a quiet arch, never a gap or a broken
   image. The arch's own aspect-ratio holds the row's height before the picture
   arrives, so nothing moves as they load. */
.order-thumb { width: 56px; aspect-ratio: 5 / 7; }
/* A card's empty arch fades from the page's own surface, which on this card —
   itself a surface — leaves nothing to see. Here it keeps the arch's own
   gradient, so the row still reads as a piece with no picture. */
.order-thumb .arch-empty { background: linear-gradient(180deg, var(--bg-deep), var(--sand)); }
.order-line-text { display: grid; gap: 3px; min-width: 0; }
.order-line-title { font: 400 16px/1.25 var(--serif); }
.order-line-meta { font-size: 12px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.order-line-price { font-size: 14px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.order-total {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding-top: 16px; border-top: 1px solid var(--line);
}
.order-total-label { font: 500 11px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft); }
.order-total-figure { font: 400 26px/1 var(--serif); font-variant-numeric: tabular-nums; }
.order-next { margin-top: 26px; }
.order-next-title { font: 500 11px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft); }
.order-next-text { margin-top: 8px; color: var(--ink-soft); font-size: 15px; }

@media (min-width: 948px) {
  /* The same two columns as the cart and the checkout, so the three pages read
     as one step after the other: the pieces on the left, and on the right what
     was paid and what happens now. No box around it — the message card is
     already the surface, and a second one inside it would be a shape this site
     does not have. */
  .order-summary { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: 48px; align-items: start; max-width: none; margin-top: 40px; }
  /* A bigger photo, and the row spaced to match, exactly as /cart does. */
  .order-line { grid-template-columns: 88px minmax(0, 1fr) auto; gap: 20px; padding: 18px 0; }
  .order-thumb { width: 88px; }
  /* The total's rule lines up with the first line's, so the two columns start
     together. */
  .order-total { padding-top: 14px; }
}

/* ------------------------------------------------------------- footer */
.footer { padding: 56px var(--gutter) 32px; text-align: center; color: var(--ink-soft); font-size: 14px; }
.footer .wordmark { font-size: 40px; }
.logo-foot { height: 70px; margin: 0 auto; }
.footer-lines { margin-top: 14px; line-height: 1.8; }
.footer-note { margin-top: 18px; font: italic 300 18px/1.4 var(--serif); color: var(--ink); }
.footer-fine { margin-top: 18px; font-size: 12px; }
.footer a { display: inline-block; padding: 12px 2px; margin: -12px 0; text-underline-offset: 4px; }

/* ------------------------------------------------------------- reveal */
.js .reveal { opacity: 0; transform: translateY(24px); transition: opacity .9s var(--ease), transform .9s var(--ease); }
.js .reveal.is-in { opacity: 1; transform: none; }

/* ------------------------------------------------------------ desktop */
@media (min-width: 700px) {
  .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 900px) {
  body { padding-bottom: 0; }
  .tabbar { display: none; }
  .topbar { justify-content: space-between; min-height: 72px; }
  .topnav { display: flex; gap: 28px; }
  .topnav a {
    font: 500 11px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase;
    text-decoration: none; padding: 8px 0; border-bottom: 1px solid transparent;
  }
  .topnav a:hover, .topnav a[aria-current="page"] { border-bottom-color: var(--ink); }
  /* The count sits on the link it belongs to. Without this it has no
     positioned ancestor to hang from and lands in the middle of the page --
     which is exactly what it did: a bare number floating above the shop,
     with the word Cart 500px away in the corner. */
  .topnav a { position: relative; }
  .topnav-cart { display: grid; place-items: center; padding: 4px 0; border-bottom: 0; }
  .topnav-cart:hover, .topnav-cart[aria-current="page"] { border-bottom-color: transparent; }
  .topnav-icon { width: 22px; height: 22px; fill: none; stroke: currentColor;
    stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; display: block; }
  .topnav-cart:hover .topnav-icon, .topnav-cart[aria-current="page"] .topnav-icon { stroke-width: 2; }
  /* On the basket it hangs off the top-right corner, the way a shopper expects,
     rather than the tab bar's centred placement. */
  .topnav-cart .tab-count { top: -5px; left: auto; right: -9px; margin-left: 0; }
}
@media (min-width: 1100px) {
  .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 48px 24px; }
}

/* ------------------------------------------------------ reduced motion */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; scroll-behavior: auto !important;
  }
  .js .reveal { opacity: 1; transform: none; }
}

/* =============================================================== home */
.hero {
  /* Arch size follows the phone's width but never outgrows its height, so the runway,
     "new in" and the category chips all fit on the first screen. */
  --arch-w: clamp(150px, min(58vw, 44svh * .625), 280px);
  --arch-h: calc(var(--arch-w) * 1.6);
  --runway-top: 16px;
  --runway-step: 34px;
  position: relative; isolation: isolate; overflow: hidden;
}
/* --runway-duration is the no-JS fallback: roughly 2.5s per arch for a typical 8-arch set. */
.runway { position: relative; overflow: hidden; padding: var(--runway-top) 0 calc(var(--runway-step) + 48px); --runway-duration: 20s; }
.runway-track {
  display: flex; width: max-content; margin: 0; padding: 0; list-style: none;
  animation: runway var(--runway-duration) linear infinite;
}
.runway:hover .runway-track,
.runway:focus-within .runway-track,
.runway.is-held .runway-track { animation-play-state: paused; }
@keyframes runway { to { transform: translateX(-50%); } }
.runway-item { flex: none; margin-right: 14px; }
.runway-item-low { transform: translateY(var(--runway-step)); }
.runway-link { position: relative; display: block; text-decoration: none; color: var(--ink); }
.arch-runway {
  width: var(--arch-w); aspect-ratio: 5 / 8;
  box-shadow: 0 26px 40px -28px rgba(80, 60, 40, .6);
}
.runway-link:hover img { transform: scale(1.05); }
.runway-link:focus-visible { outline: none; }
.runway-link:focus-visible .arch { outline: 2px solid var(--ink); outline-offset: 3px; }
.runway-label {
  position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%);
  max-width: calc(100% - 20px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 7px 12px; border-radius: 999px;
  background: rgba(251, 248, 243, .82);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  font: 500 10px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase;
}
.hero-type {
  /* Sits over the lower half of the arches and ends just above their labels. */
  position: absolute; left: 0; right: 0; z-index: 2;
  top: calc(var(--runway-top) + var(--arch-h) - 46px);
  transform: translateY(-100%);
  margin: 0; text-align: center; pointer-events: none;
  font-family: var(--serif); font-weight: 300; line-height: .82;
  font-size: clamp(76px, min(24vw, var(--arch-h) * .48), 230px); letter-spacing: -.03em;
}
.hero-outline {
  display: block; font-style: italic; color: transparent;
  -webkit-text-stroke: 1.2px var(--ink);
  filter: drop-shadow(0 1px 0 rgba(251, 248, 243, .7));
}
.hero-solid { display: block; color: var(--ink); text-shadow: 0 2px 24px rgba(251, 248, 243, .65); }
/* No runway (nothing in stock yet): "new in" stands alone in the glow. */
.hero h1 + .hero-type { position: relative; top: auto; transform: none; padding: 64px 0 88px; }
@supports not (-webkit-text-stroke: 1px) {
  .hero-outline { color: var(--ink); filter: none; text-shadow: 0 2px 24px rgba(251, 248, 243, .65); }
}

.visit-strip {
  position: relative; isolation: isolate; overflow: hidden;
  max-width: var(--max); margin: 32px var(--gutter) 24px;
  padding: clamp(96px, 20vw, 170px) var(--gutter) 56px;
  border-radius: 100vmax 100vmax 32px 32px;
  background: var(--surface); text-align: center;
}
@media (min-width: 1368px) { .visit-strip { margin: 48px auto 24px; } }
.visit-strip-title { font: 300 clamp(44px, 10vw, 92px)/.95 var(--serif); letter-spacing: -.02em; }
.visit-strip-title em { font-style: italic; }
.visit-strip-address { margin: 16px auto 26px; max-width: 34ch; color: var(--ink-soft); }

@media (min-width: 900px) {
  .hero { --runway-top: 28px; --runway-step: 56px; }
  .runway-item { margin-right: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  .runway { overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; }
  .runway-track { animation: none; padding-left: var(--gutter); }
  .runway-item[data-copy] { display: none; }
  .runway-item { scroll-snap-align: start; }
}

/* =============================================================== shop */
.section-tight { padding-top: 16px; }
.filters {
  display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none;
  max-width: var(--max); margin: 0 auto; padding: 8px var(--gutter);
}
.filters::-webkit-scrollbar { display: none; }
.filter { position: relative; flex: none; }
.filter select {
  -webkit-appearance: none; appearance: none;
  min-height: 44px; padding: 0 36px 0 16px;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%232a2622' stroke-width='1.4'/%3E%3C/svg%3E") no-repeat right 15px center;
  color: var(--ink); font: 500 12px/1 var(--sans); letter-spacing: .04em; cursor: pointer;
}
.filter select:hover { border-color: var(--ink); }
/* Apply stays for keyboard and no-JS visitors; site.js hides it once a pointer is used. */
.js .filters.is-pointer .filters-apply { display: none; }
.chips-active { align-items: center; padding-top: 2px; }
.chip-remove { background: var(--ink); color: var(--bg); }
.chip-remove:hover { background: var(--ink-lift); }

/* ============================================================= brands */
.brand-list {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 14px;
}
.brand-tile { display: block; text-decoration: none; color: var(--ink); text-align: center; }
.arch-tile {
  aspect-ratio: 5 / 6; display: grid; place-items: center;
  background: linear-gradient(180deg, var(--surface), var(--bg-deep));
  box-shadow: inset 0 0 0 1px var(--line);
}
.brand-tile-logo { width: 62%; height: 50%; object-fit: contain; mix-blend-mode: multiply; }
.brand-tile-initial { font: italic 300 clamp(56px, 16vw, 96px)/1 var(--serif); }
.brand-tile-name { display: block; margin-top: 12px; font: 500 11px/1.3 var(--sans); letter-spacing: .14em; text-transform: uppercase; }
.brand-tile:hover .arch-tile { box-shadow: inset 0 0 0 1px var(--ink); }

.brand-head {
  position: relative; isolation: isolate; overflow: hidden;
  display: grid; justify-items: center; gap: 24px;
  padding: 24px var(--gutter) 40px; text-align: center;
}
.arch-brand { width: min(72vw, 420px); aspect-ratio: 5 / 7; box-shadow: 0 30px 50px -34px rgba(80, 60, 40, .6); }
.brand-text { display: grid; justify-items: center; gap: 14px; max-width: 40ch; }
.brand-logo { max-width: 180px; max-height: 64px; object-fit: contain; mix-blend-mode: multiply; }
.brand-intro { font: italic 300 clamp(19px, 3.6vw, 24px)/1.45 var(--serif); color: var(--ink); }

@media (min-width: 700px) {
  .brand-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 900px) {
  .brand-head { grid-template-columns: auto minmax(0, 1fr); justify-items: start; align-items: center; gap: 56px; max-width: var(--max); margin: 0 auto; text-align: left; }
  .brand-text { justify-items: start; }
}
@media (min-width: 1100px) {
  .brand-list { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 44px 24px; }
}

/* =============================================================== item */
.product { max-width: var(--max); margin: 0 auto; }
.gallery {
  display: flex; gap: 12px; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
  padding: 8px var(--gutter) 44px; scroll-padding: 0 var(--gutter);
}
.gallery::-webkit-scrollbar { display: none; }
.gallery:focus-visible { outline-offset: -4px; }
.gallery-slide { flex: 0 0 84%; margin: 0; scroll-snap-align: center; }
.gallery-single .arch { width: 84%; margin: 0 auto; }
.arch-hero { aspect-ratio: 5 / 7; box-shadow: 0 30px 50px -36px rgba(80, 60, 40, .6); }
.gallery-dots { display: flex; justify-content: center; gap: 7px; margin-top: -26px; }
.dot { width: 6px; height: 6px; border-radius: 50%; background: var(--line); transition: background-color .3s var(--ease), transform .3s var(--ease); }
.dot.is-active { background: var(--ink); transform: scale(1.25); }

.product-info { display: grid; gap: 18px; padding: 26px var(--gutter) 8px; }
.product-brand {
  justify-self: start; padding: 17px 0; margin: -17px 0;
  font: 500 11px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase;
  text-underline-offset: 5px; color: var(--ink-soft);
}
.product-title { font: 300 clamp(38px, 9vw, 64px)/.98 var(--serif); letter-spacing: -.02em; }
.product-price { font: 400 24px/1 var(--serif); font-variant-numeric: tabular-nums; }
.sizes { border: 0; margin: 0; padding: 0; min-width: 0; }
.sizes-legend { padding: 0; margin-bottom: 10px; font: 500 11px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft); }
.sizes-list { display: flex; flex-wrap: wrap; gap: 8px; }
.size { position: relative; }
.size input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.size-name {
  display: grid; place-items: center; min-width: 54px; height: 46px; padding: 0 16px;
  border: 1px solid var(--line); border-radius: 999px;
  font: 500 13px/1 var(--sans); letter-spacing: .04em;
  transition: background-color .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
}
.size input:hover + .size-name { border-color: var(--ink); }
.size input:checked + .size-name { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.size input:focus-visible + .size-name { outline: 2px solid var(--ink); outline-offset: 3px; }
.product-colour { font-size: 14px; color: var(--ink-soft); }
/* Colour first, then size: the sizes of the other colours are hidden. */
.size[hidden] { display: none; }
.sizes-hint { margin: 0 0 10px; font-size: 14px; color: var(--ink-soft); }
.product-cta { display: grid; gap: 10px; }
.product-cta-note { font-size: 14px; color: var(--ink-soft); text-align: center; }
.product-cta-note a { display: inline-block; padding: 13px 2px; margin: -13px 0; color: var(--ink); text-underline-offset: 4px; }
/* Add to cart needs JavaScript (the cart itself lives in localStorage); without
   it, fall back to the old "visit the boutique" copy. Both render; CSS picks
   one, driven by the .js/.no-js class site.js sets on <html>. */
.product-cta-js, .product-cta-nojs { display: grid; gap: 10px; }
.no-js .product-cta-js { display: none; }
.js .product-cta-nojs { display: none; }
.product-description { display: grid; gap: 12px; max-width: 60ch; color: var(--ink-soft); font-size: 15px; line-height: 1.75; }
.product-more { font-size: 13px; color: var(--ink-soft); }
.product-more a { color: var(--ink); text-underline-offset: 4px; display: inline-block; padding: 8px 0; }

/* The trail above a piece or a brand: quiet, one line, and every crumb a
   finger can hit. */
.crumbs { max-width: var(--max); margin: 0 auto; padding: 14px var(--gutter) 0; }
.crumbs ol { display: flex; flex-wrap: wrap; align-items: center; margin: 0; padding: 0; list-style: none;
  font: 500 11px/1 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-soft); }
.crumbs li + li::before { content: "/"; padding: 0 10px; color: var(--clay); }
.crumbs a { display: inline-block; padding: 12px 0; color: var(--ink-soft); text-underline-offset: 4px; }
.crumbs [aria-current] { color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 60vw; }

@media (min-width: 900px) {
  .product {
    display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
    gap: 56px; padding: 24px var(--gutter) 24px; align-items: start;
  }
  .gallery { flex-direction: column; overflow: visible; padding: 0; gap: 20px; scroll-snap-type: none; }
  .gallery-slide { flex: none; }
  .gallery-single .arch { width: 100%; }
  .gallery-dots { display: none; }
  .product-info { position: sticky; top: 96px; padding: 12px 0; }
}

/* ============================================================== visit */
.visit-hero {
  position: relative; isolation: isolate; overflow: hidden;
  display: grid; place-items: center; min-height: clamp(420px, 66svh, 640px);
  padding: 24px var(--gutter);
}
.arch-visit {
  position: absolute; width: min(64vw, 380px, 56svh * .7); aspect-ratio: 5 / 7;
  background: linear-gradient(180deg, var(--bg-deep) 0%, var(--sand) 55%, var(--clay) 100%);
  box-shadow: 0 34px 60px -36px rgba(80, 60, 40, .55);
}
.visit-title {
  position: relative; text-align: center;
  font: 300 clamp(52px, 13vw, 124px)/.9 var(--serif); letter-spacing: -.03em;
}
.visit-title em { display: block; font-style: italic; }
.visit-grid {
  display: grid; gap: 40px; max-width: var(--max); margin: 0 auto;
  padding: 32px var(--gutter) 56px; text-align: center;
}
.visit-block { display: grid; justify-items: center; gap: 16px; }
.visit-heading { font: 500 11px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft); }
.visit-text { font: 300 24px/1.45 var(--serif); font-style: normal; }
.visit-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }

@media (min-width: 900px) {
  .visit-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; }
}

/* =============================================================== cart */
.tab { position: relative; }
.tab-count {
  position: absolute; top: 4px; left: 50%; margin-left: 6px;
  min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 999px; background: var(--ink); color: var(--bg);
  font: 500 10px/17px var(--sans); text-align: center;
}
.cart-backdrop { position: fixed; inset: 0; z-index: 60; background: rgba(42, 38, 34, .32); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.cart-drawer {
  position: fixed; z-index: 70; top: 0; right: 0; bottom: 0;
  width: min(420px, 92vw); display: flex; flex-direction: column;
  background: var(--surface); box-shadow: -20px 0 50px -30px rgba(42, 38, 34, .6);
  transform: translateX(100%); transition: transform .45s var(--ease);
}
.cart-drawer.is-open { transform: none; }
.cart-drawer-head { display: flex; align-items: center; justify-content: space-between; padding: 20px var(--gutter) 10px; }
.cart-drawer-title { font: italic 300 26px/1 var(--serif); }
.cart-close { border: 0; background: none; font: 300 30px/1 var(--serif); color: var(--ink); cursor: pointer; min-width: 44px; min-height: 44px; }
.cart-drawer-lines { flex: 1; overflow-y: auto; padding: 8px var(--gutter); }
.cart-drawer-foot { padding: 16px var(--gutter) calc(20px + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); display: grid; gap: 10px; }
.cart-line { display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; gap: 14px; align-items: center; padding: 14px 0; border-bottom: 1px solid var(--line); }
.cart-thumb { width: 56px; aspect-ratio: 5 / 7; }
.cart-line-text { display: grid; gap: 3px; min-width: 0; }
.cart-line-title { font: 400 16px/1.25 var(--serif); text-decoration: none; }
.cart-line-size { font-size: 12px; color: var(--ink-soft); }
.cart-line-price { font-size: 14px; font-variant-numeric: tabular-nums; }
.cart-line-controls { display: grid; gap: 6px; justify-items: end; }
.cart-qty { min-height: 40px; padding: 0 10px; border: 1px solid var(--line); border-radius: 999px; background: var(--bg); font: 500 13px/1 var(--sans); }
.cart-remove { min-height: 44px; border: 0; background: none; color: var(--ink-soft); font: 500 11px/1 var(--sans); letter-spacing: .12em; text-transform: uppercase; cursor: pointer; }
.cart-remove:hover { color: var(--ink); }
.cart-total { font: 400 22px/1 var(--serif); font-variant-numeric: tabular-nums; }
.cart-free { font-size: 13px; }
.cart-page { max-width: 640px; }
.cart-foot { max-width: 640px; display: grid; gap: 10px; padding-top: 18px; }

@media (min-width: 900px) {
  /* Two columns: the lines on the left, and a panel on the right that stays in
     view while a long cart scrolls past it. align-items: start is what lets the
     panel move inside its grid area — stretched to the full row it could not. */
  .cart-layout { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 56px; align-items: start; }
  .cart-layout .cart-page { max-width: none; }
  .cart-layout .cart-foot {
    max-width: none; position: sticky; top: 96px;
    padding: 20px; border-radius: 20px; background: var(--surface);
  }
  /* A bigger photo, and the row spaced to match. The drawer keeps its 56px. */
  .cart-page .cart-line { grid-template-columns: 88px minmax(0, 1fr) auto; gap: 20px; padding: 18px 0; }
  .cart-page .cart-thumb { width: 88px; }
  /* An empty cart has nothing for the panel to sit beside, so it folds back to
     one column rather than stranding a box on the right. */
  .cart-layout.is-empty { display: block; }
  .cart-layout.is-empty .cart-foot { max-width: 340px; position: static; padding: 18px 0 0; background: none; }
}

/* =========================================================== checkout */
.flash { border-radius: 18px; padding: 14px 18px; margin: 0 var(--gutter) 18px; font-size: 14px; }
.flash p { margin: 0 0 6px; }
.flash p:last-child { margin-bottom: 0; }
.flash-error { background: #fbeae4; border: 1px solid rgba(179, 73, 47, .35); color: #8a3a24; }
.flash-error a { color: inherit; text-decoration-color: rgba(138, 58, 36, .45); }
/* One quiet line at the top of the cart when the shop has run out of something.
   It sits inside the cart's own lines, which already have the gutter. */
.flash-quiet { background: var(--bg-deep); border: 1px solid var(--line); color: var(--ink-soft); margin: 14px 0; }
.checkout-wrap { max-width: var(--max-tight); margin: 0 auto; }
.checkout { max-width: 560px; display: grid; gap: 18px; padding: 0 var(--gutter) 40px; }
.checkout-fields { display: grid; gap: 18px; }
.checkout-row { display: grid; gap: 12px; }
.checkout fieldset { border: 0; margin: 0; padding: 0; display: grid; gap: 12px; }
/* An author display value otherwise beats the UA's [hidden] rule; restore it so
   site.js can show or hide the delivery address by toggling the attribute. */
.checkout fieldset[hidden] { display: none; }
.checkout legend { padding: 0 0 6px; font: 500 11px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft); }
.checkout label.field { display: grid; gap: 6px; font-size: 13px; color: var(--ink-soft); }
.checkout input[type="text"], .checkout input[type="email"], .checkout input[type="tel"], .checkout textarea {
  width: 100%; min-height: 48px; padding: 12px 16px;
  border: 1px solid var(--line); border-radius: 16px; background: var(--surface);
  color: var(--ink); font: 400 16px/1.4 var(--sans);
}
.checkout textarea { min-height: 88px; resize: vertical; }
.checkout input:focus-visible, .checkout textarea:focus-visible { border-color: var(--ink); }
.checkout-choice { display: flex; gap: 10px; flex-wrap: wrap; }
.checkout-choice label { position: relative; }
.checkout-choice input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.checkout-choice span { display: grid; place-items: center; min-height: 48px; padding: 0 20px; border: 1px solid var(--line); border-radius: 999px; font: 500 13px/1 var(--sans); }
.checkout-choice input:checked + span { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.checkout-summary { padding: 16px; border-radius: 20px; background: var(--surface); display: grid; gap: 6px; }
.checkout-line { font-size: 14px; }
.checkout-total { font: 400 18px/1 var(--serif); padding-top: 6px; }
.checkout-secure { font-size: 12px; color: var(--ink-soft); text-align: center; }
.checkout-legal { font-size: 13px; line-height: 1.55; color: var(--ink-soft); }
.checkout-legal a { color: var(--ink); text-underline-offset: 3px; }

@media (min-width: 900px) {
  /* The same two columns as the cart, so the two pages read as one step after
     the other. The summary is first in the markup — a phone reads it above the
     fields — so the columns are named here rather than left to source order. */
  .checkout { max-width: none; grid-template-columns: minmax(0, 1fr) 340px; gap: 56px; align-items: start; }
  .checkout-fields { grid-column: 1; grid-row: 1; }
  .checkout-summary { grid-column: 2; grid-row: 1; position: sticky; top: 96px; padding: 20px; }
  .checkout-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (prefers-reduced-motion: reduce) {
  .cart-drawer { transition: none; }
  .consent { transition: none; }
}

/* ============================================================== consent */
/* The cookie banner, in the same materials as the tab bar it sits above: the
   warm surface, one hairline, the blur, and the same soft shadow. No new colour
   and no new shape — it is a quiet card at the foot of the page, not an alarm.

   Fixed, so nothing on the page moves when it appears, and lifted clear of the
   phone tab bar by --tabbar-space rather than sitting over it. Its z-index is
   below the cart backdrop (60) and drawer (70) on purpose: opening the cart
   covers the banner rather than fighting it. */
.consent {
  position: fixed; z-index: 55;
  left: 12px; right: 12px; bottom: var(--tabbar-space);
  max-width: 680px; margin: 0 auto;
  display: grid; gap: 16px;
  padding: 20px;
  border: 1px solid var(--line); border-radius: 24px;
  background: rgba(255, 252, 247, .94);
  -webkit-backdrop-filter: blur(18px) saturate(1.2); backdrop-filter: blur(18px) saturate(1.2);
  box-shadow: 0 18px 40px -22px rgba(42, 38, 34, .5);
  opacity: 0; transform: translateY(14px);
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}
.consent.is-in { opacity: 1; transform: none; }
/* The display above otherwise beats the UA's [hidden] rule, and the banner
   would be on the page before anyone had asked for it. */
.consent[hidden] { display: none; }
/* Room for the close button, so a wrapped title never runs under it. */
/* A paragraph since 1.6.0 (see views/layout.php), so it outranks the
   banner's own paragraph rule below rather than inheriting its size. */
.consent-text .consent-title { margin-top: 0; padding-right: 44px; font: italic 300 24px/1 var(--serif); color: var(--ink); }
.consent-text p { margin-top: 8px; font-size: 14px; line-height: 1.6; color: var(--ink-soft); }
.consent-text a { color: var(--ink); text-underline-offset: 3px; }
/* Two buttons of exactly the same size, weight and colour. Refusing must be as
   easy as accepting, so neither of these may ever become a filled button beside
   a faint link.

   Stacked on a narrow phone, where "Only essential" would otherwise wrap
   inside its pill and the two would stop looking like one another. */
.consent-actions { display: grid; gap: 10px; }
.consent-actions .button { width: 100%; padding: 0 12px; }
@media (min-width: 460px) {
  .consent-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.consent-close {
  position: absolute; top: 8px; right: 8px;
  min-width: 44px; min-height: 44px;
  border: 0; background: none; color: var(--ink-soft);
  font: 300 26px/1 var(--serif); cursor: pointer;
}
.consent-close:hover { color: var(--ink); }
/* The footer's way back to the banner, dressed as the links beside it. */
.consent-reopen {
  display: inline-block; padding: 12px 2px; margin: -12px 0;
  border: 0; background: none; color: inherit; cursor: pointer;
  font: inherit; text-decoration: underline; text-underline-offset: 4px;
}
.consent-reopen:hover { color: var(--ink); }
/* Without JavaScript nothing is stored and nothing could ever be loaded, so
   there is no choice to reopen. */
.no-js .consent-reopen { display: none; }

@media (min-width: 900px) {
  /* The tab bar is gone here, so the banner settles at the foot of the window,
     and the two answers sit beside the text rather than under it. */
  .consent {
    bottom: 20px; max-width: 760px;
    grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 24px;
    padding: 22px 26px;
  }
  .consent-actions { grid-template-columns: auto auto; }
  .consent-actions .button { padding: 0 22px; }
}

/* ============================================================== legal */
/* Terms, Returns, Privacy and Cookies: a calm reading column under the usual page head. */
.legal-head { padding-bottom: 20px; }
.legal-nav { margin-bottom: 18px; font: 500 11px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--ink-soft); }
.legal-nav a { display: inline-block; padding: 12px 2px; margin: -12px 0; color: var(--ink-soft); text-decoration: none; }
.legal-nav a:hover { color: var(--ink); }
.legal-nav a[aria-current="page"] { color: var(--ink); text-decoration: underline; text-underline-offset: 5px; }
.legal-head .page-title { font-size: clamp(44px, 11vw, 88px); }
.legal {
  max-width: var(--max); margin: 0 auto; padding: 8px var(--gutter) 56px;
  font-size: 16px; line-height: 1.7; color: var(--ink-lift);
}
.legal > * { max-width: 42rem; } /* about 68 characters of the body text */
.legal h2 { margin: 40px 0 10px; font: 400 clamp(22px, 5vw, 27px)/1.2 var(--serif); letter-spacing: -.01em; color: var(--ink); }
.legal p + p, .legal p + ul, .legal ul + p, .legal p + .legal-seller, .legal .legal-seller + p { margin-top: 14px; }
.legal ul { margin: 0; padding-left: 1.25em; list-style: disc; }
.legal li + li { margin-top: 8px; }
.legal li::marker { color: var(--clay); }
.legal a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: rgba(42, 38, 34, .4); overflow-wrap: anywhere; }
.legal a:hover { text-decoration-color: var(--ink); }
.legal strong { font-weight: 500; color: var(--ink); }
/* The names the Cookies page has to quote are stored keys, not prose, so they
   are marked as such — but in the page's own typeface. A monospace face would
   be a second voice on a page that has only ever had one. */
.legal code { font: 500 .94em/1.4 var(--sans); letter-spacing: .01em; color: var(--ink); overflow-wrap: anywhere; }
.legal-intro { font: italic 300 clamp(20px, 4.6vw, 24px)/1.45 var(--serif); color: var(--ink); }
.legal-intro strong { font-weight: 400; }
.legal-seller { margin-top: 14px; padding: 16px 20px; border-left: 2px solid var(--sand); font-style: normal; }
.legal .legal-seller p { margin: 0; }
.legal-seller-name { font: 400 18px/1.4 var(--serif); color: var(--ink); }
.legal-form { margin-top: 48px; padding: 4px 22px 24px; border: 1px solid var(--line); border-radius: 24px; background: var(--surface); }
.legal-form h2 { margin-top: 20px; }
.legal-form-lines { list-style: none; padding: 0; margin-top: 16px; }
.legal .legal-form-lines { padding-left: 0; list-style: none; }
.legal-form-lines li { padding: 10px 0; border-bottom: 1px solid var(--line); }
.legal-form-lines li + li { margin-top: 0; }
.legal-blank { display: block; min-height: 26px; }
.legal-updated { margin-top: 48px; font-size: 13px; color: var(--ink-soft); }
@media print {
  .topbar, .tabbar, .footer, .legal-nav, .cart-drawer, .cart-backdrop, .consent { display: none !important; }
  body { padding-bottom: 0; }
}
