/* --- Typefaces, served from this site ----------------------------------------
   Fraunces and DM Sans used to load from Google's servers, which meant every visitor's
   IP address reached Google before a single word was read. Serving them from here
   removes the last third party from an ordinary visit, so the privacy page can say
   "no third parties" without an asterisk.

   Both faces are licensed under the SIL Open Font License, which explicitly permits
   redistribution like this. Their licence texts are in fonts/OFL-fraunces.txt and fonts/OFL-dmsans.txt,
   with the original copyright notices intact.

   The unicode-range lines are Google's own and are worth keeping: a browser downloads
   the latin-ext file only when the page actually shows a character from that range.
   The rupee sign (U+20B9) lives in latin-ext, which is why it is here at all - without
   it every price would silently fall back to a different typeface.

   font-display: swap shows the fallback immediately and swaps when the real face
   arrives, so slow connections read text rather than staring at blank space.
   ------------------------------------------------------------------------------ */

@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/dm-sans-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/dm-sans-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/fraunces-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/fraunces-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/fraunces-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/fraunces-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- Core layout ------------------------------------------------------------
   Header, hero, catalogue, how-it-works, visit, footer, dialogs and the base
   mobile breakpoint. This block shipped as a single minified line originally;
   it was expanded in place (whitespace only) so it can be read and edited. The
   sections below it were already formatted and are unchanged. --- */
:root {
  --bg: #09080d;
  --panel: #14111a;
  --panel-2: #1b1423;
  --plum: #ba86e5;
  --lavender: #dfbdff;
  --gold: #f3c86c;
  --ink: #fbf7ff;
  --muted: #afa6b5;
  --line: #ffffff1c
}

* {
  box-sizing: border-box
}

html {
  scroll-behavior: smooth
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: "DM Sans", sans-serif;
  line-height: 1.55;
  overflow-x: hidden
}

.noise {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .14;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E")
}

.orb {
  position: fixed;
  border-radius: 50%;
  filter: blur(90px);
  opacity: .23;
  z-index: -2;
  animation: drift 13s ease-in-out infinite alternate
}

.orb-one {
  width: 36rem;
  height: 36rem;
  background: #6d2fa7;
  top: -18rem;
  left: -12rem
}

.orb-two {
  width: 27rem;
  height: 27rem;
  background: #de6fbb;
  right: -14rem;
  bottom: 5rem;
  animation-delay: -7s
}

@keyframes drift {
  to {
    transform: translate(9rem, 6rem) scale(1.12)
  }
}

.site-header {
  height: 86px;
  max-width: 1280px;
  margin: auto;
  padding: 0 5vw;
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: relative;
  z-index: 2
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  color: var(--ink);
  font-weight: 700;
  letter-spacing: .22em;
  text-decoration: none;
  font-size: .9rem
}

.brand-mark {
  font-family: "Fraunces", Georgia, serif;
  font-size: 2.6rem;
  color: var(--gold);
  line-height: .6;
  font-style: italic;
  font-weight: 600
}

.site-header nav {
  display: flex;
  gap: 1.7rem;
  align-items: center
}

.site-header nav a {
  color: var(--ink);
  text-decoration: none;
  font-size: .88rem;
  font-weight: 600
}

.bag-button,
.staff-link {
  border: 1px solid #ffffff44;
  background: #ffffff0d;
  color: #fff;
  padding: .72rem 1rem;
  border-radius: 99px;
  font: 700 .86rem "DM Sans";
  cursor: pointer
}

.bag-button:hover,
.staff-link:hover {
  background: var(--plum);
  border-color: var(--plum)
}

.bag-button span {
  display: inline-grid;
  place-items: center;
  background: var(--gold);
  color: #201222;
  width: 1.35rem;
  height: 1.35rem;
  border-radius: 50%;
  margin-left: .25rem
}

.menu-button {
  display: none;
  background: none;
  border: 0;
  color: #fff;
  font: inherit;
  font-weight: 700
}

.hero {
  min-height: 620px;
  display: grid;
  grid-template-columns: 1.1fr .9fr;
  max-width: 1280px;
  margin: auto;
  padding: 4vw 5vw 6vw;
  gap: 5vw;
  align-items: center
}

.eyebrow {
  color: var(--gold);
  font-size: .73rem;
  text-transform: uppercase;
  letter-spacing: .17em;
  font-weight: 700;
  margin: 0 0 1.2rem
}

.live-dot {
  display: inline-block;
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: #b5ff75;
  box-shadow: 0 0 10px #b5ff75;
  animation: pulse 1.5s ease-in-out infinite;
  margin-left: .35rem
}

@keyframes pulse {
  50% {
    opacity: .2;
    transform: scale(.5)
  }
}

h1,
h2 {
  font-family: "Fraunces", Georgia, serif;
  line-height: .89;
  font-weight: 600;
  letter-spacing: -.045em
}

.hero h1 {
  font-size: clamp(4.3rem, 8vw, 7.4rem);
  margin: 0;
  max-width: 700px
}

.hero h1 em {
  color: var(--lavender);
  font-weight: 500;
  text-shadow: 0 0 35px #b987e668
}

.intro {
  font-size: 1.08rem;
  max-width: 460px;
  margin: 1.7rem 0 2rem;
  color: var(--muted)
}

.button {
  display: inline-block;
  border: 0;
  text-decoration: none;
  padding: .9rem 1.35rem;
  border-radius: 3px;
  font-size: .9rem;
  font-weight: 700;
  cursor: pointer;
  transition: transform .25s, box-shadow .25s
}

.button-primary {
  background: linear-gradient(115deg, #b47ce0, #f1b8e2);
  color: #190b1f;
  box-shadow: 0 0 30px #c585e656
}

.button-primary:hover {
  transform: translateY(-3px) rotate(-1deg);
  box-shadow: 0 9px 45px #eab0e696
}

.hero-art {
  height: 470px;
  position: relative;
  overflow: hidden;
  background: radial-gradient(circle at 69% 16%, #ffde9c 0 4%, transparent 25%), linear-gradient(145deg, #1c0e2d 0%, #6e2784 52%, #f07fba 130%);
  border: 1px solid #ffffff5e;
  border-radius: 150px 8px 150px 8px;
  box-shadow: 17px 20px 0 #8b48b146
}

.scan {
  position: absolute;
  inset: -100%;
  background: repeating-linear-gradient(0deg, transparent 0 7px, #fff2 8px 9px);
  animation: scan 10s linear infinite
}

@keyframes scan {
  to {
    transform: translateY(60px)
  }
}

.sun {
  position: absolute;
  width: 320px;
  height: 320px;
  border-radius: 50%;
  background: #f3c86c;
  opacity: .9;
  top: -85px;
  right: -70px
}

.silhouette {
  position: absolute;
  bottom: -75px;
  border-radius: 48% 48% 0 0;
  background: #170a22
}

.s-one {
  width: 220px;
  height: 390px;
  left: 30px;
  transform: rotate(10deg)
}

.s-two {
  width: 180px;
  height: 320px;
  right: 55px;
  background: #432a53;
  transform: rotate(-8deg)
}

.art-label {
  position: absolute;
  z-index: 2;
  left: 10%;
  top: 18%;
  color: #fff;
  font-family: "Fraunces", Georgia, serif;
  font-size: 9rem;
  font-style: italic;
  line-height: .5;
  margin: 0;
  text-shadow: 0 0 19px #200d2e
}

.art-label span {
  font-family: "DM Sans";
  letter-spacing: .14em;
  font-style: normal;
  font-size: 1.25rem;
  font-weight: 700
}

.art-stamp {
  position: absolute;
  bottom: 1.2rem;
  left: 1.2rem;
  font-size: .62rem;
  letter-spacing: .14em;
  color: #fff;
  writing-mode: vertical-rl
}

.ticker {
  overflow: hidden;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
  color: #d8c1eb;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .19em;
  padding: .8rem 0
}

.collections {
  max-width: 1280px;
  margin: auto;
  padding: 7rem 5vw
}

.section-heading {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 2rem;
  margin-bottom: 2.5rem
}

.section-heading h2,
.how h2 {
  font-size: clamp(3.5rem, 6vw, 5.3rem);
  margin: 0
}

.section-heading>p {
  max-width: 350px;
  color: var(--muted);
  margin: 0
}

.product-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.2rem
}

.product {
  background: linear-gradient(145deg, #241a2d, #17121d);
  border: 1px solid var(--line);
  padding: 1rem;
  min-height: 340px;
  display: flex;
  flex-direction: column;
  justify-content: end;
  position: relative;
  overflow: hidden;
  transition: transform .3s, border-color .3s
}

.product:hover {
  transform: translateY(-8px);
  border-color: #d99df0
}

.product-art {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 74% 20%, #ffffff99 0 7%, transparent 7.5%), linear-gradient(150deg, transparent 40%, #ffffff18 41% 44%, transparent 45%)
}

.product-art:after {
  content: "";
  position: absolute;
  width: 110%;
  height: 63%;
  left: -5%;
  bottom: -16%;
  background: #7d4c83;
  border-radius: 49% 49% 0 0
}

.product:nth-child(2) .product-art:after {
  background: #c16f8e
}

.product:nth-child(3) .product-art:after {
  background: #7e69a8
}

.product:nth-child(4) .product-art:after {
  background: #8a956f
}

.product-content {
  position: relative;
  background: #09080ddd;
  border: 1px solid #ffffff1a;
  padding: 1rem;
  backdrop-filter: blur(5px)
}

.product h3 {
  font-family: "Fraunces", Georgia, serif;
  font-size: 2rem;
  line-height: .9;
  margin: 0
}

.product p {
  font-size: .8rem;
  margin: .55rem 0 1rem;
  color: #d0c5d1
}

.product button {
  border: 0;
  background: none;
  padding: 0;
  color: var(--gold);
  font: 700 .83rem "DM Sans";
  cursor: pointer;
  text-align: left
}

.how {
  background: linear-gradient(135deg, #261132, #100d15);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 7rem 5vw
}

.how>.eyebrow {
  max-width: 1120px;
  margin-left: auto;
  margin-right: auto
}

.how h2 {
  max-width: 1120px;
  margin: 0 auto 3.5rem
}

.how ol {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 3rem;
  list-style: none
}

.how li {
  border-top: 1px solid #ffffff59;
  padding-top: 1rem
}

.how span {
  color: var(--gold);
  font-family: "Fraunces", Georgia, serif;
  font-size: 2rem
}

.how strong {
  display: block;
  font-family: "Fraunces", Georgia, serif;
  font-size: 2rem;
  font-weight: 600
}

.how p {
  color: #dfd3df;
  margin: .4rem 0
}

.visit {
  max-width: 1120px;
  margin: 0 auto;
  padding: 7rem 5vw;
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 9vw
}

.visit-card {
  background: linear-gradient(135deg, #8d45ac, #30133b);
  color: #fff;
  padding: 3.2rem;
  border: 1px solid #ffffff61;
  border-radius: 5px;
  box-shadow: 12px 12px 0 #e3a8dc40
}

.visit-card .eyebrow {
  color: #ffe29c
}

.visit h2 {
  font-size: 4.2rem;
  margin: 0 0 1.8rem
}

.visit address {
  font-style: normal;
  line-height: 1.8;
  margin-bottom: 1.8rem
}

.text-link {
  color: #fff;
  font-weight: 700;
  text-decoration: none;
  border-bottom: 1px solid var(--gold);
  padding-bottom: .15rem
}

.details {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2.3rem
}

.detail-label {
  display: block;
  text-transform: uppercase;
  letter-spacing: .16em;
  font-size: .72rem;
  color: var(--gold);
  font-weight: 700;
  margin-bottom: .25rem
}

.details strong,
.details a {
  font-family: "Fraunces", Georgia, serif;
  font-size: 2rem;
  font-weight: 600;
  color: var(--lavender);
  text-decoration: none;
  line-height: 1.1
}

.details p {
  margin: .35rem 0 0;
  color: var(--muted);
  font-size: .9rem
}

footer {
  background: #050507;
  border-top: 1px solid var(--line);
  color: #d8cdd8;
  min-height: 130px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 2rem 5vw;
  font-size: .82rem
}

footer .brand {
  color: #fff
}

footer p {
  margin: 0
}

.staff-link {
  font-size: .75rem;
  background: transparent;
  border: 1px solid #ffffff60
}

dialog {
  border: 1px solid #ffffff30;
  padding: 0;
  max-width: 600px;
  width: calc(100% - 2rem);
  background: #15111b;
  color: var(--ink);
  box-shadow: 0 24px 70px #000
}

dialog::backdrop {
  background: #08040ccc;
  backdrop-filter: blur(5px)
}

.dialog-head {
  padding: 2rem 2rem 1.2rem;
  display: flex;
  justify-content: space-between;
  align-items: start
}

.dialog-head h2,
.success h2 {
  font-size: 3rem;
  margin: 0
}

.icon-button {
  border: 0;
  background: transparent;
  color: #fff;
  font-size: 2rem;
  line-height: 1;
  cursor: pointer
}

form {
  padding: 0 2rem 2rem;
  display: grid;
  gap: 1rem
}

label {
  font-weight: 700;
  font-size: .82rem
}

input,
textarea,
select {
  display: block;
  width: 100%;
  margin-top: .35rem;
  border: 1px solid #ffffff32;
  background: #0a080e;
  color: #fff;
  padding: .7rem;
  font: 400 .95rem "DM Sans";
  border-radius: 2px
}

textarea {
  height: 90px;
  resize: vertical
}

.chosen-piece {
  display: none;
  background: #44224f;
  padding: .9rem;
  color: #fff;
  font-weight: 700;
  border-left: 3px solid var(--gold)
}

.chosen-piece.visible {
  display: block
}

.form-note {
  color: var(--muted);
  font-size: .78rem;
  margin: 0
}

.success {
  padding: 3.5rem 2.5rem;
  text-align: center
}

.success p:not(.eyebrow) {
  color: var(--muted)
}

.success-mark {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: #5d8439;
  color: #fff;
  margin: 0 auto 1.2rem;
  font-size: 1.5rem
}

.staff-tabs {
  padding: 0 2rem;
  border-bottom: 1px solid #ffffff24
}

.staff-tabs button {
  border: 0;
  background: none;
  padding: .8rem 1rem;
  font: 700 .85rem "DM Sans";
  color: var(--muted);
  cursor: pointer
}

.staff-tabs .active {
  color: var(--gold);
  border-bottom: 2px solid var(--gold)
}

#staffContent {
  padding: 1.5rem 2rem 2rem
}

.order-row {
  display: grid;
  grid-template-columns: 1.4fr 1fr auto;
  gap: 1rem;
  padding: 1rem 0;
  border-bottom: 1px solid #ffffff18;
  align-items: center
}

.order-row strong {
  display: block
}

.order-row span,
.empty {
  font-size: .8rem;
  color: var(--muted)
}

.status {
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: #d8ffb0;
  background: #34502a;
  padding: .35rem .5rem;
  white-space: nowrap
}

@media(max-width:800px) {
  .site-header {
    height: 72px
  }

  .menu-button {
    display: block
  }

  .site-header nav {
    display: none;
    position: absolute;
    z-index: 5;
    left: 1rem;
    right: 1rem;
    top: 64px;
    background: #17111e;
    padding: 1rem;
    border: 1px solid var(--line);
    box-shadow: 0 10px 25px #000;
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem
  }

  .site-header nav.open {
    display: flex
  }

  .hero {
    grid-template-columns: 1fr;
    padding-top: 3rem;
    min-height: auto
  }

  .hero-art {
    height: 360px;
    order: -1;
    border-radius: 80px 8px 80px 8px
  }

  .hero h1 {
    font-size: 4.6rem
  }

  .section-heading {
    display: block
  }

  .section-heading>p {
    margin-top: 1rem
  }

  .product-grid {
    grid-template-columns: repeat(2, 1fr)
  }

  .how {
    padding: 5rem 7vw
  }

  .how ol {
    grid-template-columns: 1fr;
    gap: 1.4rem
  }

  .visit {
    grid-template-columns: 1fr;
    padding-top: 5rem;
    padding-bottom: 5rem;
    gap: 4rem
  }

  .visit-card {
    padding: 2.4rem
  }

  .visit h2 {
    font-size: 3.6rem
  }

  footer {
    align-items: flex-start;
    flex-direction: column;
    gap: 1rem
  }

  .details strong,
  .details a {
    font-size: 1.7rem
  }

  .order-row {
    grid-template-columns: 1fr
  }

  .dialog-head,
  form,
  .support-body,
  #staffContent {
    padding-left: 1.25rem;
    padding-right: 1.25rem
  }
}

@media(prefers-reduced-motion:reduce) {

  *,
  *:before,
  *:after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important
  }
}

/* --- Moved from inline <style> blocks in index.html --- */

:root {
  --plum: #69109a;
  --lavender: #e0b3ff;
  --gold: #e8bd69;
}

.brand-logo {
  font-family: "Fraunces", Georgia, serif;
  color: var(--gold);
  font-size: 1.55rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-shadow: 0 0 14px #e8bd6955;
}

/* The mark: a fine-line sewing machine above the wordmark. The thread leaves the spool,
   runs down to the needle, and continues below as a dashed seam that doubles as the rule
   dividing the machine from the lettering. */
.crest-wrap {
  position: absolute;
  z-index: 3;
  left: 50%;
  top: 46%;
  transform: translate(-50%, -50%);
  /* Sized generously: the needle and presser foot are the details that make the mark
     legible as a sewing machine, and they disappear if the whole thing is drawn small. */
  width: min(22rem, 88%);
  display: grid;
  justify-items: center;
}

.crest-machine {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 0 20px #e8bd6930);
}

.crest-copy { text-align: center; margin-top: -.35rem; }

/* Brushed-gold lettering. The gradient is clipped to the glyphs, so the text
   colour is transparent and the depth comes from a drop-shadow instead. */
/* The display face needs air between the caps to read as a wordmark rather
   than a word. */
.crest-copy strong {
  display: block;
  font-family: "Fraunces", Georgia, serif;
  font-size: 2.85rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-indent: .14em;               /* balances the trailing letterspace so it stays centred */
  line-height: .9;
  background: linear-gradient(172deg, #fdefc8 0%, #e8bd69 46%, #c1913f 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 14px #e8bd6955);
}

/* The descriptor carries the actual meaning for anyone who doesn't know "boutique"
   on its own, so it is set in the sans for legibility rather than a script. */
.crest-copy span {
  display: block;
  font-family: "DM Sans", sans-serif;
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .3em;
  text-indent: .3em;
  color: #f0dfbe;
  margin-top: .55rem;
}
@media (max-width: 800px) {
  .crest-wrap { width: min(15rem, 80%); }
  .crest-copy strong { font-size: 2.1rem; letter-spacing: .1em; text-indent: .1em; }
  .crest-copy span { font-size: .56rem; letter-spacing: .22em; text-indent: .22em; margin-top: .4rem; }
}

.ticker-track { display: flex !important; width: max-content; animation: ticker-scroll 22s linear infinite; }
.ticker-track span { display: block !important; padding-right: 3rem; color: #d8c1eb !important; }
.ticker-track b { color: var(--gold); padding: 0 1rem; font-weight: 400; }
@keyframes ticker-scroll { to { transform: translateX(-25%); } }

.reveal { opacity: 0; transform: translateY(50px); transition: opacity .8s ease, transform .8s cubic-bezier(.2,.8,.2,1); }
.reveal.is-visible { opacity: 1; transform: none; }
.reveal .product { opacity: 0; transform: translateY(28px); transition: opacity .55s ease, transform .55s cubic-bezier(.2,.8,.2,1), border-color .3s; }
.reveal.is-visible .product { opacity: 1; transform: none; }
.reveal.is-visible .product:nth-child(2) { transition-delay: .08s; }
.reveal.is-visible .product:nth-child(3) { transition-delay: .16s; }
.reveal.is-visible .product:nth-child(4) { transition-delay: .24s; }
.reveal.is-visible .product:nth-child(5) { transition-delay: .32s; }
.reveal.is-visible .product:nth-child(6) { transition-delay: .4s; }
.how.reveal.is-visible li, .visit.reveal.is-visible .details > div { animation: rise .65s both; }
.how.reveal.is-visible li:nth-child(2), .visit.reveal.is-visible .details > div:nth-child(2) { animation-delay: .14s; }
.how.reveal.is-visible li:nth-child(3), .visit.reveal.is-visible .details > div:nth-child(3) { animation-delay: .28s; }
@keyframes rise { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }

.product-buy { display: flex; align-items: center; justify-content: space-between; gap: .7rem; }
.product-buy strong { color: #fff; font-size: .9rem; }
.product-buy button { white-space: nowrap; }

.bag-items { display: grid; gap: .7rem; }
.bag-line { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .8rem 0; border-bottom: 1px solid #ffffff1f; }
.bag-line strong, .bag-line span { display: block; }
.bag-line span { color: var(--muted); font-size: .8rem; }
.quantity { display: flex; gap: .7rem; align-items: center; }
.quantity button { border: 1px solid #ffffff37; background: #ffffff0c; color: #fff; border-radius: 50%; height: 1.75rem; width: 1.75rem; font-size: 1.1rem; cursor: pointer; }
.bag-total { display: flex; justify-content: space-between; align-items: center; padding: .9rem 0; border-top: 1px solid #ffffff3b; border-bottom: 1px solid #ffffff3b; }
.bag-total span { color: var(--muted); font-size: .85rem; }
.bag-total strong { font-family: "Fraunces", Georgia, serif; font-size: 2rem; color: var(--gold); }
button:disabled { cursor: not-allowed; opacity: .45; }

.order-id { color: var(--gold); font-weight: 700; }

/* Directions link in the visit card. The address block above it already carries
   its own bottom margin, so this only needs spacing beneath. */
.visit-card .text-link { display: inline-block; margin-bottom: 1.6rem; }
.visit-card .text-link:hover { color: #ffe29c; border-bottom-color: #ffe29c; }

/* --- Catalogue groups (Customization / Ready to wear) --- */

.product-group + .product-group { margin-top: 4rem; }
.group-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  font-family: "Fraunces", Georgia, serif;
  font-size: 2.1rem;
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1;
  margin: 0 0 1.4rem;
  padding-bottom: .9rem;
  border-bottom: 1px solid var(--line);
}
.group-heading span {
  font-family: "DM Sans", sans-serif;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gold);
}

/* Three across suits 6 and 5 items better than the original four. */
.product-grid { grid-template-columns: repeat(3, 1fr); }

/* Art colours cycle so no two neighbours match; overrides the 1-4 rules above. */
.product:nth-child(3n+1) .product-art:after { background: #7d4c83; }
.product:nth-child(3n+2) .product-art:after { background: #c16f8e; }
.product:nth-child(3n+3) .product-art:after { background: #7e69a8; }
.product-group:last-child .product:nth-child(3n+1) .product-art:after { background: #8a956f; }
.product-group:last-child .product:nth-child(3n+2) .product-art:after { background: #a2708f; }
.product-group:last-child .product:nth-child(3n+3) .product-art:after { background: #6b7fa3; }

@media (max-width: 900px) {
  .product-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
  .product-grid { grid-template-columns: 1fr; }
  .group-heading { font-size: 1.8rem; }
  .product { min-height: 260px; }
}

/* Header "Track order" — reads as a nav link, not a second primary button next to the bag. */
.nav-link-button {
  border: 0;
  background: none;
  padding: 0;
  color: var(--ink);
  font: 600 .88rem "DM Sans", sans-serif;
  cursor: pointer;
}
/* No colour change on hover: the neighbouring links do not do it, and the underline is
   already the signal. */

/* --- Product photography ---
   Sits above the CSS artwork and below .product-content, which keeps its own dark
   backing so the text stays legible over a photo. */
.product-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 20%;
  opacity: 0;
  transition: transform .55s cubic-bezier(.2, .8, .2, 1), opacity .4s ease;
}
.product-photo.is-loaded { opacity: 1; }
.product:hover .product-photo { transform: scale(1.05); }
/* Firm up the content panel only once a photo is actually showing behind it. */
.product:has(.product-photo.is-loaded) .product-content { background: #09080def; }

.option-gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; }
.option-gallery img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: center 20%;
  border: 1px solid var(--line);
}
.option-gallery:has(img:only-child) { grid-template-columns: minmax(0, 12rem); }

/* --- Option chooser --- */

.options { display: grid; gap: .6rem; }
.option {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  border: 1px solid var(--line);
  background: #ffffff08;
  padding: .85rem .95rem;
  cursor: pointer;
  font-weight: 400;
  transition: border-color .25s, background .25s;
}
.option:hover { border-color: #ffffff42; }
.option input { width: auto; margin: .2rem 0 0; accent-color: var(--gold); flex: none; }
.option:has(input:checked) { border-color: var(--gold); background: #e8bd690f; }
.option-body { display: block; }
.option-body strong { display: block; font-size: .95rem; }
.option-body em { display: block; font-style: normal; color: var(--gold); font-size: .84rem; margin-top: .1rem; }
.option-body i { display: block; font-style: normal; color: var(--muted); font-size: .76rem; margin-top: .2rem; }

/* --- Customer order tracking --- */

.track-results { padding: 0 2rem 2rem; display: grid; gap: 1.4rem; }
.track-results .empty { margin: 0; }
.track-order { border: 1px solid var(--line); background: #ffffff08; padding: 1.1rem; }
.track-order-head { display: flex; justify-content: space-between; gap: 1rem; margin-bottom: 1.2rem; }
.track-order-head span { display: block; color: var(--muted); font-size: .8rem; margin-top: .15rem; }
.track-order-head > div:last-child { text-align: right; }

.track-steps { list-style: none; display: grid; grid-template-columns: repeat(4, 1fr); gap: .4rem; margin: 0; padding: 0; }
.track-steps li {
  position: relative;
  padding-top: 1.1rem;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}
.track-steps li::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: #ffffff1f;
}
.track-steps li.done::before { background: #5d8439; }
.track-steps li.current::before { background: var(--gold); box-shadow: 0 0 12px #e8bd6988; }
.track-steps li.done { color: #b6d99a; }
.track-steps li.current { color: var(--gold); }

/* --- Staff order desk (admin.html) --- */

.admin-shell { max-width: 1000px; margin: 0 auto; padding: 2.5rem 5vw 5rem; }
.admin-banner {
  background: #4a2410;
  border: 1px solid #e8a06988;
  border-left: 3px solid #e8bd69;
  color: #ffe6c4;
  font-size: .82rem;
  line-height: 1.6;
  padding: .9rem 1.1rem;
  margin: 0 0 2.5rem;
}
.admin-banner strong { color: #fff; }
.admin-head { display: flex; align-items: end; justify-content: space-between; gap: 1.5rem; margin-bottom: 2rem; }
.admin-head h1 { font-family: "Fraunces", Georgia, serif; font-size: clamp(2.8rem, 6vw, 4rem); line-height: .9; letter-spacing: -.04em; font-weight: 600; margin: 0; }
.admin-shell .staff-tabs { padding: 0; }
.admin-shell #staffContent { padding: 1.5rem 0 0; }

/* Confirmation-call workflow. Every order is fitted, so nothing advances until called. */
.call-summary {
  margin: 0 0 1.2rem;
  padding: .7rem .9rem;
  background: #3a1f4d;
  border-left: 3px solid var(--gold);
  color: #f0dcb4;
  font-size: .82rem;
  font-weight: 700;
}
.order-row.awaiting-call { background: #ffffff07; }
.call-first {
  margin: .5rem 0 0;
  font-size: .76rem;
  color: #ffd9a8;
}
.order-actions { display: grid; gap: .5rem; justify-items: end; align-content: start; }
.call-action {
  border: 1px solid var(--gold);
  background: #e8bd6914;
  color: var(--gold);
  font: 700 .72rem "DM Sans", sans-serif;
  letter-spacing: .04em;
  padding: .4rem .6rem;
  cursor: pointer;
  white-space: nowrap;
  transition: background .25s;
}
.call-action:hover { background: #e8bd6930; }
.called-flag {
  font-size: .68rem;
  color: #b6d99a;
  white-space: nowrap;
}
.dial { color: var(--lavender); text-decoration: none; border-bottom: 1px solid #ffffff3d; }
.dial:hover { color: var(--gold); border-bottom-color: var(--gold); }
.order-notes { color: #cdbfd6; }

.order-custom { margin: .5rem 0 0; display: grid; gap: .25rem; }
.order-custom span {
  display: block;
  font-size: .78rem;
  color: #f0dcb4;
  border-left: 2px solid var(--gold);
  padding-left: .55rem;
}
.needs-quote {
  display: inline-block;
  margin-top: .3rem;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #ffd9a8;
  background: #4a2410;
  border: 1px solid #e8a06977;
  padding: .2rem .4rem;
}

@media (max-width: 800px) {
  /* The order desk is used on a phone, so the call and status controls need
     real touch targets rather than desktop-sized ones. */
  .order-actions { justify-items: stretch; gap: .6rem; margin-top: .9rem; }
  .call-action, .order-actions .status {
    padding: .75rem .8rem;
    font-size: .78rem;
    text-align: center;
  }
  .track-order-head { display: block; }
  .track-order-head > div:last-child { text-align: left; margin-top: .6rem; }
  .track-steps { grid-template-columns: repeat(2, 1fr); gap: .7rem; }
  .admin-head { display: block; }
  .admin-head .staff-link { display: inline-block; margin-top: 1rem; }
  .track-results { padding-left: 1.25rem; padding-right: 1.25rem; }
}

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal .product { opacity: 1; transform: none; }
}

dialog {
  opacity: 0;
  transform: translateY(28px) scale(.97);
  transition: opacity .24s ease, transform .24s cubic-bezier(.2,.8,.2,1), overlay .24s allow-discrete, display .24s allow-discrete;
}
dialog[open] { opacity: 1; transform: none; }
dialog::backdrop { opacity: 0; transition: opacity .24s ease, overlay .24s allow-discrete, display .24s allow-discrete; }
dialog[open]::backdrop { opacity: 1; }
@starting-style {
  dialog[open] { opacity: 0; transform: translateY(28px) scale(.97); }
  dialog[open]::backdrop { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  dialog, dialog::backdrop { transition: none; }
}

/* --- Motion -----------------------------------------------------------------
   One easing curve and short distances throughout, so the whole site feels like
   it moves the same way. The global prefers-reduced-motion rule at the top of
   this file switches all of it off. */

/* Page-load entrance. The hero previously just appeared with no transition. */
.hero-copy > *, .hero-art { animation: hero-in .85s cubic-bezier(.2, .8, .2, 1) both; }
.hero-copy > *:nth-child(2) { animation-delay: .08s; }
.hero-copy > *:nth-child(3) { animation-delay: .16s; }
.hero-copy > *:nth-child(4) { animation-delay: .24s; }
.hero-art { animation-name: hero-art-in; animation-delay: .1s; }

@keyframes hero-in { from { opacity: 0; transform: translateY(18px); } }
@keyframes hero-art-in { from { opacity: 0; transform: scale(.97); } }

/* The machine settles in first, then the wordmark under it. The whole SVG animates as
   one, so the stroked and filled groups inside stay in register. */
.crest-machine { animation: mark-in 1s cubic-bezier(.2, .8, .2, 1) .3s both; }
.crest-copy { animation: mark-in 1s cubic-bezier(.2, .8, .2, 1) .45s both; }
@keyframes mark-in {
  from { opacity: 0; transform: translateY(12px) scale(.96); }
}

/* The seam stitches itself across, left to right, once the mark has landed. */
.seam path[stroke-dasharray] {
  transform-box: fill-box;
  transform-origin: left center;
  animation: seam-in 1.1s cubic-bezier(.2, .8, .2, 1) .85s both;
}
@keyframes seam-in {
  from { opacity: 0; transform: scaleX(0); }
  to { opacity: .9; transform: scaleX(1); }
}

/* Header gains a backdrop once the hero is behind it. */
.site-header { transition: background .35s ease, box-shadow .35s ease; }
.site-header.is-scrolled {
  background: #09080dd9;
  backdrop-filter: blur(10px);
  box-shadow: 0 1px 0 var(--line);
}

/* Nav underline on hover. */
/* Track order and Support are <button>, because they open a dialog rather than go
   somewhere -- but they sit in the same row as the links and should behave like them on
   hover. The rule names both so the underline does not stop halfway along the nav. */
.site-header nav a,
.site-header nav .nav-link-button { position: relative; }
.site-header nav a::after,
.site-header nav .nav-link-button::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -5px;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .28s cubic-bezier(.2, .8, .2, 1);
}
.site-header nav a:hover::after,
.site-header nav .nav-link-button:hover::after { transform: scaleX(1); }

/* Product art drifts in slightly under the hover lift the card already has. */
.product-art { transition: transform .55s cubic-bezier(.2, .8, .2, 1); }
.product:hover .product-art { transform: scale(1.05); }

/* Bag badge acknowledges an item being added. */
.bag-button span.pop { animation: badge-pop .42s cubic-bezier(.2, .8, .2, 1); }
@keyframes badge-pop {
  40% { transform: scale(1.35); }
  100% { transform: scale(1); }
}

/* Keyboard focus needs to be visible; mouse users never see this. */
:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* --- Customer support -------------------------------------------------------
   The four-card section between the catalogue and Visit us is gone; these details now
   live in a dialog opened from the header. .support-link is kept because the dialog uses
   it -- it is the one piece of that section's styling still earning its place. */

/* Long addresses must wrap rather than force the line wider than its column. */
.support-link {
  display: inline-block;
  margin-top: .5rem;
  font-family: "Fraunces", Georgia, serif;
  font-size: 1.35rem;
  font-weight: 600;
  color: var(--lavender);
  text-decoration: none;
  line-height: 1.25;
  overflow-wrap: anywhere;
}
.support-link:hover { color: var(--gold); }

.footer-contact {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .6rem;
  font-size: .88rem;
}
.footer-contact a { color: var(--muted); text-decoration: none; overflow-wrap: anywhere; }
.footer-contact a:hover { color: var(--gold); }
.footer-contact span { color: var(--line); }

.form-note a { color: var(--lavender); text-decoration: none; border-bottom: 1px solid var(--line); }
.form-note a:hover { color: var(--gold); border-bottom-color: var(--gold); }


/* --- Display face -----------------------------------------------------------
   Fraunces replaces Bodoni Moda. Bodoni is a didone: its hairlines are what
   make it elegant on a printed page and what make it vanish on a phone held at
   arm's length. Fraunces keeps the high-contrast editorial feel but carries an
   optical-size axis, so the strokes thicken automatically as the type gets
   smaller instead of thinning to nothing.
   It sets wider and with a larger x-height than Bodoni, so the tracking that
   suited the old face is now too tight, and the headings need a little more
   leading. */

h1, h2, .product h3, .how strong, .details strong, .details a, .crest-copy strong {
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 0, "WONK" 0;   /* the plain cut, not the quirky one */
}
h1, h2 { letter-spacing: -.018em; line-height: .95; }
.hero h1 { font-size: clamp(3.9rem, 7.2vw, 6.6rem); }
.section-heading h2, .how h2 { font-size: clamp(3rem, 5.2vw, 4.6rem); }
.visit h2 { font-size: clamp(2.8rem, 4.6vw, 3.8rem); }
.crest-copy strong { letter-spacing: .1em; text-indent: .1em; }

/* --- Icons -----------------------------------------------------------------
   These were text characters (an up-right arrow, a tick, a star). iOS gives
   several of them an emoji presentation by default, which reads as clip art on
   a phone even though it looks like plain text on Windows. Drawing them as SVG
   means they inherit the surrounding colour and weight and render identically
   everywhere. Sized in em so they track the text they sit beside. */

.i-arrow, .i-check, .i-close {
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.i-arrow {
  width: .78em;
  height: .78em;
  stroke-width: 1.7;
  vertical-align: -.02em;
  margin-left: .12em;
  /* Nudges along its own diagonal on hover, rather than just sliding right. */
  transition: transform .3s cubic-bezier(.2, .8, .2, 1);
}
.button:hover .i-arrow, .text-link:hover .i-arrow, .details a:hover .i-arrow { transform: translate(.1em, -.1em); }
.support-link .i-arrow, .i-arrow[viewBox="0 0 14 14"] { flex: none; }
/* The two downward arrows should lead the eye down, not up. */
.button:hover .i-arrow[data-dir="down"], .support-link:hover .i-arrow { transform: translateY(.12em); }

.i-check { width: 1.5rem; height: 1.5rem; stroke-width: 2.4; }
.i-close { width: 1.05rem; height: 1.05rem; stroke-width: 1.8; }
.icon-button { display: inline-grid; place-items: center; padding: .5rem; }

/* Replaces the four-pointed star between ticker phrases. */
.tick-mark {
  display: inline-block;
  width: .42em;
  height: .42em;
  margin: 0 1rem;
  background: var(--gold);
  transform: rotate(45deg);
  vertical-align: .06em;
}

/* --- Reading on a phone -----------------------------------------------------
   Held at arm's length the small copy was the problem, not the headings, so
   the body sizes come up and the display sizes stay put. */

@media (max-width: 720px) {
  body { font-size: 1.02rem; }
  .intro { font-size: 1.12rem; }
  .product p { font-size: .95rem; }
  .product h3 { font-size: 1.9rem; }
  .support-list p, .details p, .form-note { font-size: 1rem; }
  .eyebrow, .detail-label { font-size: .82rem; letter-spacing: .13em; }
  .how p { font-size: 1.02rem; }
  footer { font-size: .95rem; }
  .ticker { font-size: .82rem; letter-spacing: .14em; }
  /* The phone menu stacks links and buttons in one column, so they have to be one
     size. This rule used to name only the links, which left Track order, Support and
     My order visibly smaller than the items above them. */
  .site-header nav a,
  .site-header nav .nav-link-button,
  .site-header nav .bag-button { font-size: 1rem; }
}

/* Errors from the database or the network, shown in the checkout form. */
.form-error {
  margin: 0 0 1rem;
  padding: .85rem 1rem;
  border: 1px solid #f0a3a3;
  border-left-width: 3px;
  border-radius: 4px;
  background: #f0a3a31a;
  color: #ffd7d7;
  font-size: .92rem;
  line-height: 1.5;
}
.form-error[hidden] { display: none; }

/* A submit button mid-request should look inert, not merely unresponsive. */
.button:disabled { opacity: .55; cursor: progress; transform: none; box-shadow: none; }

/* --- Staff sign-in ---------------------------------------------------------- */

.sign-in {
  max-width: 26rem;
  margin: 6vh auto 0;
  padding: 2.5rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: linear-gradient(145deg, #1b1423, #14111a);
}
.sign-in h1 { font-size: 2.6rem; margin: 0 0 .8rem; }
.sign-in .form-note { margin-bottom: 1.6rem; }
.sign-in label { display: block; margin-bottom: 1rem; font-size: .82rem; font-weight: 600; }
.sign-in input {
  display: block;
  width: 100%;
  margin-top: .4rem;
  padding: .8rem .9rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: #0e0b13;
  color: var(--ink);
  font: inherit;
}
.sign-in input:focus { border-color: var(--gold); outline: none; }
.sign-in button[type="submit"] { width: 100%; margin-top: .5rem; }
.sign-in .text-link { display: inline-block; margin-top: 1.5rem; font-size: .85rem; }

.admin-head-actions { display: flex; gap: .6rem; flex-wrap: wrap; }
#whoami { text-transform: none; letter-spacing: 0; color: var(--muted); }
.staff-tabs[hidden] { display: none; }

/* The customer was shown a figure that did not match the catalogue. Almost always means
   data.js and the catalogue table have drifted, not that anyone is being clever. */
.price-warning { background: #f0a3a31f; border-color: #f0a3a3; color: #ffd7d7; }

/* --- Payment state on the order desk ---------------------------------------- */

.pay-state { display: block; margin-top: .6rem; }
.pay-state select {
  width: 100%;
  margin-top: .2rem;
  padding: .45rem .55rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: #0e0b13;
  color: var(--ink);
  font: inherit;
  font-size: .85rem;
  cursor: pointer;
}
.pay-state select:disabled { opacity: .5; cursor: progress; }
/* Unpaid is the state that needs chasing, so it is the one that carries colour. */
.pay-unpaid select { border-color: #f0a3a3; color: #ffd7d7; }
.pay-paid select { border-color: #8fd39a; color: #d8f5dd; }
.pay-note { display: block; margin-top: .3rem; font-size: .78rem; color: var(--muted); }

/* --- Policies page ---------------------------------------------------------- */

.policy {
  max-width: 46rem;          /* ~75 characters a line; long policy text needs the limit */
  margin: 0 auto;
  padding: 3rem 5vw 6rem;
}
.policy h1 { font-size: clamp(3rem, 7vw, 4.4rem); margin: 0 0 1.2rem; }
.policy h2 {
  font-size: clamp(1.9rem, 3.4vw, 2.5rem);
  margin: 3.5rem 0 1rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
}
.policy h3 {
  font-family: "DM Sans", sans-serif;
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--gold);
  margin: 2rem 0 .6rem;
}
.policy p, .policy li { color: #d6cdd8; line-height: 1.75; }
.policy p { margin: 0 0 1rem; }
.policy ul { margin: 0 0 1.2rem; padding-left: 1.1rem; }
.policy li { margin-bottom: .55rem; }
.policy strong { color: var(--ink); }
.policy a { color: var(--lavender); }
.policy a:hover { color: var(--gold); }

.policy-intro { font-size: 1.1rem; color: var(--muted) !important; }
.policy-updated { font-size: .82rem; color: var(--muted) !important; }

.policy-nav {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: 2rem 0 1rem;
}
.policy-nav a {
  padding: .5rem .9rem;
  border: 1px solid var(--line);
  border-radius: 99px;
  font-size: .82rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--ink);
}
.policy-nav a:hover { border-color: var(--gold); color: var(--gold); }

/* Anchor links must not land under the sticky-ish header. */
.policy section { scroll-margin-top: 6rem; }

.policy-contact { list-style: none; padding-left: 0; }
.policy-contact li { margin-bottom: .8rem; }
.policy-contact strong {
  display: block;
  font-family: "DM Sans", sans-serif;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--gold);
  margin-bottom: .1rem;
}

/* --- Phone field with a country picker -------------------------------------- */

.phone-field {
  display: grid;
  grid-template-columns: minmax(8.5rem, auto) 1fr;
  gap: .5rem;
  margin-top: .4rem;
}
.phone-field select {
  min-width: 0;               /* without this the select refuses to shrink on a phone */
  padding: .8rem .6rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: #0e0b13;
  color: var(--ink);
  font: inherit;
  font-size: .9rem;
  cursor: pointer;
}
.phone-field input { margin-top: 0; }
.phone-field select:focus, .phone-field input:focus { border-color: var(--gold); outline: none; }

/* On a narrow phone the picker sits above the number rather than squeezing both. */
@media (max-width: 460px) {
  .phone-field { grid-template-columns: 1fr; }
}

/* --- Touch targets ----------------------------------------------------------
   Measured on a 390px viewport, where the primary call to action on every product
   card — "Choose options +" — was 113x17px. WCAG 2.2 asks for 24px as a minimum and
   Apple suggests 44pt for comfort; 17px is below both, and it is the control every
   customer has to hit to order anything.

   These are deliberately not `height` rules. Padding grows the hit area without
   changing where the text sits, so nothing shifts on desktop. */

.product-buy button {
  padding: .55rem 0;          /* 17px of text becomes a ~35px target, full card width */
  min-height: 2.75rem;
  display: inline-flex;
  align-items: center;
}
.quantity button {
  min-width: 2.5rem;
  min-height: 2.5rem;
}
.menu-button { padding: .7rem .4rem; margin-right: -.4rem; }
.icon-button { min-width: 2.5rem; min-height: 2.5rem; }
.sign-in .text-link { padding: .6rem 0; }

/* --- Dialog width -----------------------------------------------------------
   Was `width: calc(100% - 2rem)`. A dialog is in the top layer, so its percentage
   resolves against the initial containing block, not the viewport — and any element
   that sticks out past the viewport edge inflates that block. On a 390px phone the
   dialogs were measuring 435px, so their right edge was being clipped by the body's
   overflow-x: hidden rather than fitting.

   100vw is the viewport itself, so it cannot be inflated the same way. */
dialog {
  width: min(600px, calc(100vw - 2rem));
  max-width: none;
}

/* --- Stop the decorative background inflating the page ----------------------
   .orb-two is position: fixed with right: -14rem, so on a 390px phone its right edge
   sits at 800px. Fixed elements still contribute to the page's overflow area, which
   stretched the initial containing block to 480px. Everything that positions against
   that block inherited the error: the modal dialogs centred on 480 rather than 390 and
   ended up 24px past the screen edge, where body's overflow-x: hidden clipped them.

   `clip` rather than `hidden` on purpose: hidden makes the element a scroll container,
   which breaks position: fixed descendants and scroll anchoring. clip just stops the
   overflow counting, which is exactly what is wanted for decoration.

   Verified before and after on a 390px viewport: the order dialog moved from
   left 66 / right 414 (clipped) to left 21 / right 369 (centred). */
html { overflow-x: clip; }

/* --- 404 --------------------------------------------------------------------
   Deliberately not a joke page. Someone who lands here mistyped a URL or followed
   a stale link, and the useful thing is a route back plus the phone number. */

.not-found {
  max-width: 40rem;
  margin: 0 auto;
  padding: 12vh 5vw 8rem;
}
.not-found h1 { font-size: clamp(2.8rem, 7vw, 4.2rem); margin: 0 0 1.2rem; }
.not-found-intro { font-size: 1.1rem; color: var(--muted); margin: 0 0 2.5rem; }
.not-found-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.5rem;
  margin-bottom: 3rem;
}
.not-found .form-note { max-width: 34rem; line-height: 1.7; }

/* --- Container width, made consistent ---------------------------------------
   The header, hero and catalogue sit in 1280px; the how-it-works list, support and
   visit sections were 1120px. A 160px step halfway down the page reads as the lower
   half being narrower and over-centred, with more empty margin than the top. One
   width for everything. */

.visit, .how ol, .how h2, .how > .eyebrow { max-width: 1280px; }

/* --- Visit -------------------------------------------------------------------
   The gap was 9vw, which is 144px on a 1600px screen — it ate the row and squeezed the
   address card so narrow that "Visit Verve" broke onto two lines and the address ran
   one or two words per line. Clamped, so the gap stays generous without starving the
   columns. */

.visit { gap: clamp(2.5rem, 4vw, 5rem); align-items: center; }
.visit-card { padding: 2.8rem; }
.visit address { line-height: 1.75; }

/* --- Using the width available ----------------------------------------------
   Two things were stacking to leave large empty margins on a big monitor: a 1280px
   cap, and 5vw of padding inside it — which is another 96px a side at 1920, so the
   real content was 1088px in a 1905px window.

   The cap goes to 1440 and the padding is clamped, so a wide screen gains usable
   width instead of margin. Three products across stays: six items per group is two
   tidy rows of three, where four across would leave the same 4 + 2 orphan as the
   support cards did. The cards simply get bigger.

   Small screens are untouched — the clamp floor keeps the old comfortable gutter. */

.site-header, .hero, .collections, .stock, .visit, .how ol, .how h2, .how > .eyebrow {
  max-width: 1440px;
}
.site-header, .hero, .collections, .stock, .visit, .how {
  padding-inline: clamp(1.25rem, 5vw, 3.5rem);
}


/* --- Coming soon -------------------------------------------------------------
   Cards for what is arriving. Deliberately not styled as .product: a product card sells
   a service from a price and opens a chooser, while these are a teaser — the same veiled
   artwork on every card, with the name and price beneath.

   Four across, stepping down by whole columns. A partial last row left-aligns, which is
   right here — the count changes every week, so no arrangement is always even, and
   evenly-sized cards ending mid-row reads as a shelf rather than as the 3 + 1 orphan a
   fixed set of four cards produced.

   The section element itself is hidden by app.js when there is nothing arriving. */

.stock { margin-inline: auto; padding-block: 7rem 0; }

.stock-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.2rem;
}

.piece {
  background: linear-gradient(145deg, #241a2d, #17121d);
  border: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: transform .3s, border-color .3s;
}
.piece:hover { transform: translateY(-8px); border-color: #d99df0; }

/* The veil. One piece of artwork, the same on every card: two soft shapes that suggest a
   shoulder line and a drape, blurred until they are only a hint, behind a pane of frosted
   glass with a slow sheen crossing it. Nothing to upload and nothing to go stale — it says
   "something is coming" without pretending to show what.

   Pure CSS, so it costs no request, and it uses the site's own plum, rose and gold so it
   sits beside the product photography rather than looking like a missing image. */
.piece-veil {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(160deg, #2c1d38, #17111f);
  box-shadow: inset 0 0 0 1px #ffffff12;
}
.piece-veil span {
  position: absolute;
  border-radius: 48% 48% 0 0;
  filter: blur(22px);
  opacity: .85;
}
.piece-veil span:first-child {
  width: 58%;
  height: 78%;
  left: 10%;
  bottom: -12%;
  background: linear-gradient(180deg, #b47ce0, #6d2fa7);
  transform: rotate(6deg);
}
.piece-veil span:last-child {
  width: 46%;
  height: 62%;
  right: 6%;
  bottom: -8%;
  background: linear-gradient(180deg, #f1b8e2, #8b48b1);
  transform: rotate(-7deg);
}
/* The glass: a pale wash with a warm glint high on the right, echoing the hero's sun. */
.piece-veil::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(circle at 72% 16%, #ffde9c40 0 9%, transparent 32%),
    linear-gradient(180deg, #ffffff17, #ffffff05 60%);
  backdrop-filter: blur(6px);
}
/* The sheen: a narrow band of light that drifts across and rests. Long pauses, so a grid of
   these reads as glass catching the light rather than as a loading animation. */
.piece-veil::after {
  content: "";
  position: absolute;
  inset: -40% -60%;
  z-index: 2;
  background: linear-gradient(105deg, transparent 44%, #ffffff1c 50%, transparent 56%);
  transform: translateX(-60%);
  animation: veil-sheen 7s ease-in-out infinite;
}
@keyframes veil-sheen {
  0%, 40% { transform: translateX(-60%); }
  80%, 100% { transform: translateX(60%); }
}

.piece-content {
  padding: .95rem 1rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: .45rem;
  flex: 1;
}
.piece h3 {
  font-family: "Fraunces", Georgia, serif;
  font-size: 1.35rem;
  line-height: 1.05;
  font-weight: 600;
  letter-spacing: -.02em;
  margin: 0;
}
.piece p { font-size: .8rem; color: #d0c5d1; margin: 0; }

/* Price and actions pinned to the bottom, so cards with a one-line title and cards with
   a description still line their buttons up across a row. */
.piece-buy {
  margin-top: auto;
  padding-top: .5rem;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .6rem;
  flex-wrap: wrap;
}
.piece-buy strong { color: #fff; font-size: .9rem; }
.piece-actions { display: flex; gap: .75rem; }
/* Generous tap targets: these are the only call to action on the card, and the WCAG
   minimum was already missed once on this site by a link that looked fine on a desktop. */
.piece-actions a {
  color: var(--gold);
  font-size: .83rem;
  font-weight: 700;
  text-decoration: none;
  border-bottom: 1px solid #f3c86c66;
  padding-block: .35rem;
  min-height: 1.6rem;
}
.piece-actions a:hover { border-bottom-color: var(--gold); }

.reveal .piece { opacity: 0; transform: translateY(28px); transition: opacity .55s ease, transform .55s cubic-bezier(.2, .8, .2, 1), border-color .3s; }
.reveal.is-visible .piece { opacity: 1; transform: none; }

@media (max-width: 1080px) { .stock-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 800px) {
  .stock { padding-block-start: 5rem; }
  .stock-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .stock-grid { grid-template-columns: 1fr; gap: 1.6rem; }
  .piece h3 { font-size: 1.6rem; }
  .piece p { font-size: .95rem; }
}
@media (prefers-reduced-motion: reduce) {
  .reveal .piece { opacity: 1; transform: none; }
}

/* --- Stock desk (admin.html) -------------------------------------------------
   Deliberately plainer than the customer site. This screen gets used standing up, on a
   phone, with a garment in the other hand, so the form is wide fields and big taps
   rather than anything clever. */

.stock-form {
  padding: 0;
  margin: 1.25rem 0 2rem;
  gap: 1rem;
  border: 1px solid #ffffff1a;
  background: #ffffff06;
  padding: 1.25rem;
}
.stock-form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}
.stock-form input[type="file"] {
  padding: .55rem;
  font-size: .85rem;
}
.stock-preview img {
  display: block;
  max-height: 220px;
  border: 1px solid #ffffff24;
}

.stock-row {
  display: grid;
  grid-template-columns: 60px 1fr auto auto;
  gap: 1rem;
  align-items: center;
  padding: .8rem 0;
  border-bottom: 1px solid #ffffff18;
}
/* A thumbnail is what makes a list of numbers usable — "104" means nothing on its own,
   and the photo is how staff confirm they are editing the right garment. */
.stock-thumb {
  width: 60px;
  aspect-ratio: 3 / 4;
  background: #ffffff0d;
  border: 1px solid #ffffff1f;
  display: grid;
  place-items: center;
  overflow: hidden;
}
.stock-thumb img { width: 100%; height: 100%; object-fit: cover; }
.stock-thumb span { font-size: .58rem; color: var(--muted); text-align: center; line-height: 1.2; }

.stock-facts { min-width: 0; }
.stock-facts strong { display: block; }
.stock-facts span {
  display: block;
  font-size: .8rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}
.stock-row select { margin-top: 0; width: auto; min-width: 8.5rem; }

@media (max-width: 800px) {
  .stock-form-grid { grid-template-columns: 1fr; }
  /* Thumbnail and details on the first row, controls beneath, so nothing is squeezed to
     an untappable width on a phone. */
  .stock-row {
    grid-template-columns: 60px 1fr;
    gap: .75rem 1rem;
  }
  .stock-row select { grid-column: 1 / -1; width: 100%; }
  .stock-row button { grid-column: 1 / -1; justify-self: start; }
}

/* --- Sections met from above -------------------------------------------------
   app.js adds .is-settled to a section that comes into view from the top edge — reached
   by scrolling up after a nav jump or a mid-page reload. It should simply be there, so
   every transition and animation the reveal would normally play is switched off.

   Each selector matches the specificity of the rule it cancels and comes after it in the
   file, which is how it wins: .how.reveal.is-visible li is (0,3,1), and so is
   .how.reveal.is-settled li. Add a new animated element to a revealed section and it
   needs a line here too, or it will animate on the way up. */

.reveal.is-settled,
.reveal.is-settled .product,
.reveal.is-settled .piece { transition: none; }

.how.reveal.is-settled li,
.visit.reveal.is-settled .details > div { animation: none; }


/* --- Floating bag button (phones) -------------------------------------------
   The header is `position: relative`, so it scrolls away for good. On a desktop that is
   fine: the catalogue is short and the bag is a flick away. On a phone the catalogue is
   twelve cards tall, and once the header has gone there is no visible way back to the bag
   at all - you have to scroll all the way up to check out.

   It earns its place only when both are true: the bag has something in it, and the header
   has left the screen. An empty bag never floats a button over the page, so the shop looks
   the same as it always did until you have actually picked something.

   Phone only. On a desktop this never renders. */

.bag-fab { display: none; }

@media (max-width: 800px) {
  .bag-fab {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    position: fixed;
    z-index: 6;                 /* over the page, under the dialogs' top layer */
    right: 1.1rem;
    /* The inset keeps it clear of the iPhone home indicator. */
    bottom: calc(1.1rem + env(safe-area-inset-bottom, 0px));
    padding: .85rem 1.15rem;
    min-height: 2.75rem;        /* comfortably past the 24px WCAG minimum */
    border: 1px solid #e8bd6966;
    border-radius: 99px;
    background: #14111af2;
    backdrop-filter: blur(10px);
    box-shadow: 0 10px 30px #00000073;
    color: var(--ink);
    font: 700 .86rem "DM Sans", sans-serif;
    cursor: pointer;

    /* Hidden by default, and not reachable by keyboard or screen reader while hidden. */
    opacity: 0;
    visibility: hidden;
    transform: translateY(12px);
    transition: opacity .28s ease, transform .28s cubic-bezier(.2, .8, .2, 1), visibility .28s;
  }
  .bag-fab.is-shown {
    opacity: 1;
    visibility: visible;
    transform: none;
  }
  .bag-fab span {
    display: inline-grid;
    place-items: center;
    min-width: 1.35rem;
    height: 1.35rem;
    padding: 0 .35rem;
    border-radius: 99px;
    background: var(--gold);
    color: #201222;
  }
}


/* --- Show/hide password on the staff sign-in ---------------------------------
   The eye sits inside the field rather than beside it, so the form keeps its single
   column. The input gets right padding to match, or long passwords run under the icon.

   The margin that positioned the input moves to the wrapper, so that centring the button
   on the wrapper also centres it on the input rather than sitting half a margin low. */

.pw-field {
  position: relative;
  display: block;
  margin-top: .4rem;
}
.sign-in .pw-field input {
  margin-top: 0;
  padding-right: 3rem;
}
.pw-toggle {
  position: absolute;
  right: .25rem;
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  /* Comfortably past the 24px WCAG minimum, and thumb-sized on a shop phone. */
  min-width: 2.6rem;
  min-height: 2.6rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  cursor: pointer;
}
.pw-toggle:hover { color: var(--gold); }

.i-eye {
  width: 1.15rem;
  height: 1.15rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Plain eye means "reveal it"; the struck-through eye means "hide it again", so the icon
   always shows what the next press will do. */
.pw-toggle .i-eye-slash { display: none; }
.pw-toggle[aria-pressed="true"] .i-eye-slash { display: block; }


/* --- The Visit card ran off the right edge on a phone ------------------------
   .visit is a single-column grid below 800px, so the card and the details list share
   one track. A grid item's automatic minimum is its min-content width, and the email
   address in .details is one 30-character unbreakable token set at 1.7rem - about
   460px. That set the track to 460px on a 390px screen, stretched the purple card to
   match, and pushed it 110px past the edge, where html { overflow-x: clip } cut it off.
   Measured: card left 20, right 480, width 460, against a 350px content box.

   The fix the footer and support links already carry - let the long address wrap.
   min-width: 0 is belt and braces, so no future long word can inflate the track again. */

.visit > * { min-width: 0; }
.details a { overflow-wrap: anywhere; }


/* --- Phone performance -------------------------------------------------------
   The site felt like a shader was running on a phone, and one effectively was.

   .orb is filter: blur(90px) on fixed circles of 36rem and 27rem, animated forever by
   `drift`. Blur cost scales with radius x area, and animating a transform on a blurred
   element forces it to be re-rasterised rather than just re-composited - so the phone was
   re-blurring roughly a third of a megapixel, every frame, for decoration nobody looks at.

   A radial gradient is already soft, so the same look needs no blur filter and no motion:
   it is painted once and then simply sits there. Desktop keeps the real blur and the drift.

   The other two costs are backdrop-filter, which has to re-read whatever is behind it every
   frame - the header's repaints during scrolling, which is exactly when jank is felt - and
   .scan, which is inset: -100% (nine times the hero's area) animating forever over the hero
   art. On a phone the scan texture is invisible in practice; the header just needs a more
   opaque background instead of a blurred one.

   Everything here is inside a max-width query. Nothing changes on a desktop. */

@media (max-width: 800px) {
  .orb {
    filter: none;
    animation: none;
  }
  /* Colour and opacity are unchanged; only the way the softness is produced differs. */
  .orb-one {
    background: radial-gradient(circle, #6d2fa7 0%, rgba(109, 47, 167, .55) 42%, transparent 72%);
  }
  .orb-two {
    background: radial-gradient(circle, #de6fbb 0%, rgba(222, 111, 187, .55) 42%, transparent 72%);
  }

  /* Static texture rather than none, so the hero art keeps its grain without the
     permanent repaint. */
  .scan { animation: none; }

  /* backdrop-filter off, opacity up to compensate. The panels read the same; they just
     stop asking the compositor to blur the page behind them on every frame. */
  .site-header.is-scrolled {
    backdrop-filter: none;
    background: #09080df5;
  }
  .product-content {
    backdrop-filter: none;
    background: #09080df2;
  }
  .bag-fab { backdrop-filter: none; }
  dialog::backdrop {
    backdrop-filter: none;
    background: #08040cf0;
  }
  /* Coming soon is empty today, but it would carry the same cost the moment stock is
     added: a blurred pane plus a sheen animating forever, on every card at once. */
  .piece-veil::before { backdrop-filter: none; }
  .piece-veil::after { animation: none; }
  .piece-number { backdrop-filter: none; }
}


/* --- Keeping the order reference ---------------------------------------------
   The reference plus the phone number is how a customer reaches their own order, so the
   success dialog asks them to keep it rather than assuming they will. The copy button is a
   real button rather than a link, because it performs an action instead of navigating. */

.save-reference {
  margin: 0 0 1rem;
  padding: .85rem 1rem;
  border: 1px solid #e8bd6947;
  border-left-width: 3px;
  border-radius: 4px;
  background: #e8bd690f;
  color: var(--ink);
  font-size: .9rem;
  line-height: 1.6;
  text-align: left;
}
.save-reference strong { color: var(--gold); }

.copy-reference {
  display: inline-block;
  margin-top: .4rem;
  padding: .5rem .8rem;
  border: 1px solid #ffffff3d;
  border-radius: 99px;
  background: #ffffff0d;
  color: var(--ink);
  font: 700 .8rem "DM Sans", sans-serif;
  cursor: pointer;
  /* Comfortable target on a phone; this is tapped one-handed straight after ordering. */
  min-height: 2.5rem;
}
.copy-reference:hover { border-color: var(--gold); color: var(--gold); }


/* --- The support dialog ------------------------------------------------------
   What used to be a four-card section. Vertical list rather than a grid: inside a 600px
   dialog, columns would give each entry less room than it had on the page, and there is
   no reason to show contact details side by side.

   The dialog itself has padding: 0 and only `form` carries the inner padding, so this
   one -- which holds no form -- brings its own. */

.support-body {
  padding: 0 2rem 2rem;
  display: grid;
  gap: 1.4rem;
}

.support-list {
  display: grid;
  gap: 1.6rem;
}
.support-list > div {
  padding-top: 1.4rem;
  border-top: 1px solid var(--line);
}
.support-list > div:first-child { padding-top: 0; border-top: 0; }
.support-list p { margin: .45rem 0 0; color: var(--muted); font-size: .9rem; line-height: 1.65; }

/* One number, two ways to use it. The digits are stated once, above; these are the
   actions, so they are small and secondary rather than a second copy of the number. */
.detail-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .55rem;
  align-items: center;
}
.detail-actions a,
.details .detail-actions a {
  color: var(--lavender);
  font: 700 .82rem "DM Sans", sans-serif;
  text-decoration: none;
  border-bottom: 1px solid var(--line);
  /* Tappable without making the row taller than the text it sits under. */
  padding-bottom: .1rem;
}
.detail-actions a:hover { color: var(--gold); border-bottom-color: var(--gold); }
.detail-actions span { color: var(--line); }

/* In the Visit list the number is set at 2rem, so the actions need a little more air. */
.details .detail-actions { margin-top: .5rem; }
