/* FootedByReesey — shared styles for static pages (booking, services, challenge, terms) */
:root {
  --ink: #060608;
  --ink-2: #0b0b10;
  --royal: #2b4bff;
  --royal-soft: #5e78ff;
  --royal-deep: #14206b;
  --cream: #f1e9db;
  --cream-dim: rgba(241, 233, 219, 0.62);
  --cream-faint: rgba(241, 233, 219, 0.16);
  --display: 'Anton', 'Arial Narrow', sans-serif;
  --body: 'Space Grotesk', system-ui, sans-serif;
  --mono: ui-monospace, 'Cascadia Mono', 'Consolas', monospace;
  --pad: clamp(1.25rem, 4vw, 4rem);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
  background: var(--ink);
  color: var(--cream);
  font-family: var(--body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Static sideways, but it zooms - see the matching note in styles.css.
   pan-y alone silently blocked pinch on every platform, including the iOS
   devices the viewport meta tag never governed. */
html,
body {
  overflow-x: clip;
  max-width: 100%;
  touch-action: pan-y pinch-zoom;
}
@supports not (overflow: clip) {
  html { overflow-x: hidden; }
}
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
img, video { max-width: 100%; display: block; }
.mono { font-family: var(--mono); letter-spacing: 0.18em; text-transform: uppercase; font-size: 0.72rem; }
:focus-visible { outline: 2px solid var(--royal-soft); outline-offset: 3px; }

.grain {
  position: fixed; inset: -100px; z-index: 40; pointer-events: none; opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* nav */
.pnav {
  /* fixed so .pnav-hidden can slide it out on scroll-down; see the note on
     .nav in styles.css for why viewport-fit=cover was dropped */
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  transition: transform 0.32s ease;
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.1rem var(--pad);
  background: linear-gradient(180deg, rgba(6, 6, 8, 0.92), rgba(6, 6, 8, 0));
}
.pnav.pnav-hidden { transform: translateY(-115%); }
/* after the shorthand above, else it is reset; see the note on .nav */
.pnav { padding-top: calc(1.1rem + env(safe-area-inset-top, 0px)); }
.pnav .lace { width: 60px; height: auto; opacity: 0.92; }
.pnav-links { display: flex; gap: clamp(0.8rem, 2.5vw, 1.8rem); align-items: center; }
.pnav-right { display: flex; align-items: center; gap: 0.6rem; }
@media (max-width: 560px) {
  .pnav { padding: 0.85rem var(--pad); padding-top: calc(0.85rem + env(safe-area-inset-top, 0px)); }
  .pnav .lace { width: 48px; }
  .pnav-right { gap: 0.45rem; }
  .pnav-right .pnav-cta { padding: 0.7em 1em; font-size: 0.62rem; letter-spacing: 0.1em; }
  .pnav-right .nav-burger { width: 42px; height: 42px; }
}
.pnav-links a.mono { color: var(--cream-dim); transition: color 0.25s; }
.pnav-links a.mono:hover { color: var(--royal-soft); }
.pnav-cta,
.pnav-links a.mono.pnav-cta {
  background: var(--royal, #2b4bff);
  color: #fff;
  border: 1px solid var(--royal, #2b4bff);
  border-radius: 999px;
  padding: 0.8em 1.4em;
  font-size: 0.74rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  box-shadow: 0 4px 20px rgba(43, 75, 255, 0.4);
  transition: background 0.2s, transform 0.2s;
  white-space: nowrap;
}
.pnav-links a.mono.pnav-cta:hover { background: #3d5bff; color: #fff; transform: translateY(-1px); }
@media (max-width: 700px) { .pnav-links a.mono.hide-sm { display: none; } }

/* buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6rem;
  font-family: var(--mono); font-size: 0.78rem; letter-spacing: 0.18em; text-transform: uppercase;
  padding: 1.05rem 2.2rem; border-radius: 999px;
  transition: transform 0.25s, background 0.25s, color 0.25s, border-color 0.25s, box-shadow 0.25s;
}
.btn-primary { background: var(--royal); color: #fff; box-shadow: 0 12px 50px rgba(43, 75, 255, 0.35); }
.btn-primary:hover { background: var(--cream); color: var(--ink); transform: translateY(-3px); }
.btn-ghost { border: 1px solid rgba(241, 233, 219, 0.4); color: var(--cream); }
.btn-ghost:hover { border-color: var(--royal-soft); color: var(--royal-soft); transform: translateY(-3px); }

/* page scaffolding */
.page { max-width: 1060px; margin: 0 auto; padding: clamp(7rem, 14vh, 9rem) var(--pad) 5rem; }
.eyebrow { color: var(--royal-soft); margin-bottom: 1rem; display: block; }
.page-title {
  font-family: var(--display); font-weight: 400;
  font-size: clamp(3rem, 9vw, 6.5rem);
  line-height: 0.92; text-transform: uppercase;
  margin-bottom: 1.2rem;
}
.page-title em { font-style: normal; color: var(--royal-soft); }
.lede { color: var(--cream-dim); max-width: 58ch; font-size: clamp(1rem, 1.6vw, 1.15rem); }
.lede b, .panel b { color: var(--cream); font-weight: 600; }
section.block { margin-top: clamp(3rem, 7vh, 5rem); }
.block-title {
  font-family: var(--display); font-weight: 400;
  font-size: clamp(1.8rem, 4.5vw, 3rem);
  text-transform: uppercase; line-height: 0.95;
  margin-bottom: 1.4rem;
}
.panel {
  border: 1px solid var(--cream-faint);
  background: rgba(11, 11, 16, 0.85);
  border-radius: 18px;
  padding: clamp(1.4rem, 3vw, 2.2rem);
}
.panel + .panel { margin-top: 1rem; }
.panel p { color: var(--cream-dim); font-size: 0.98rem; }
/* The marker is positioned, NOT a flex item.
   `display: flex` on the li made "<b>Label</b> rest of the sentence" into two
   separate flex items, so the bold ran down one narrow column and the sentence
   down another - one word per line on a phone (Jonah, 5 Sep). Block flow with
   an absolutely placed bullet keeps the whole line as one piece of text. */
.ticklist { list-style: none; display: flex; flex-direction: column; gap: 0.8rem; }
.ticklist li {
  position: relative;
  padding-left: 1.5rem;
  color: var(--cream-dim);
  line-height: 1.55;
}
.ticklist li::before {
  content: "✦";
  position: absolute;
  left: 0;
  top: 0.05em;
  color: var(--royal-soft);
  font-size: 0.8rem;
}
.ticklist li b { color: var(--cream); }
.price-tag {
  font-family: var(--display); font-size: clamp(2.2rem, 6vw, 3.6rem);
  color: var(--royal-soft); line-height: 1;
}
/* Card prices.

   These were a mono .eyebrow, which set the number in the same small grey
   uppercase type as a section label and parked it in the corner of the card -
   Jonah, 5 Sep: hard to see on both desktop and phone. It is the thing people
   scan a service card for, so it takes the display face and the same royal as
   .price-tag on the detail pages, and the two now agree. */
.card-price {
  display: block;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2rem, 5.2vw, 2.8rem);
  line-height: 1;
  color: var(--royal-soft);
  margin-bottom: 0.75rem;
}
/* A compound price ("$60 minor - $180 full") is a sentence, not a number, and
   at the size above it wraps to three lines inside a narrow card. */
.card-price-long { font-size: clamp(1.25rem, 3.1vw, 1.65rem); }

.grid-2 { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

/* Hand-off and confirm: locations, map, then the two stages as steps. Numbered
   because it IS a sequence, and the reader's question is always "what happens
   next" rather than "what is the policy". */
.ho-head {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.2rem, 3.2vw, 1.5rem);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--cream);
  margin: 1.8rem 0 0.6rem;
}
.ho-head:first-child { margin-top: 0.4rem; }
.ho-lede { color: var(--cream-dim); font-size: 0.98rem; margin-bottom: 1rem; }

/* The "nothing to choose here" notice above the drop-off map.
   Full brightness, not --cream-dim: the line it replaces said the same thing
   in dim text under a heading, and the customer who got confused read straight
   past it. A notice that answers the question someone is about to get wrong
   has to be the brightest thing in the panel, not the quietest. */
.ho-notice {
  display: flex;
  gap: 0.7rem;
  align-items: flex-start;
  margin: 0.4rem 0 0.2rem;
  padding: 0.95rem 1.05rem;
  border: 1px solid rgba(94, 120, 255, 0.4);
  border-radius: 14px;
  background: rgba(94, 120, 255, 0.09);
  color: var(--cream);
  font-size: 0.98rem;
  line-height: 1.55;
}
.ho-notice b { color: var(--cream); }
.ho-notice-i {
  flex: none;
  width: 1.35rem;
  height: 1.35rem;
  margin-top: 0.12rem;
  border: 1px solid rgba(94, 120, 255, 0.55);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 0.75rem;
  line-height: 1.28rem;
  text-align: center;
  color: var(--royal-soft);
}

/* The two hubs and their drop-off days, as text. These were popups on the map
   pins; nobody reads a popup they have to discover, and the tap that opened it
   was the thing making the pins feel selectable. */
.ho-hubs {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 0.6rem;
  margin: 0.75rem 0 0;
  padding: 0;
}
.ho-hubs li {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--cream-faint);
  border-radius: 12px;
}
.ho-hubs b { color: var(--cream); font-size: 0.98rem; }
.ho-hubs span { color: var(--cream-dim); font-size: 0.88rem; }

/* The picked drop-off venue, under the map. Added 9 Sep 2026 when the street
   address stopped being a post-deposit secret: the lock box is the access
   control, not the address, and hiding a partner shop that has its own signage
   and its own Google listing only cost people the one fact they decide on -
   how far away it is. It replaces the two-hub .ho-hubs list, because only the
   selected hub is drawn on the map now and describing the other one here would
   put back the "which am I choosing" question the map already caused once.

   Every trading hour is a drop-off hour at both hubs from 9 Sep 2026, so every
   open day carries the tag and only a Closed day does not. The tag is kept
   rather than dropped because the hubs need not always agree, and because the
   day a pair is COLLECTED by Reesey is a different fact again - her run - which
   the card states in its own sentence. */
.hub-card {
  margin: 0.85rem 0 0;
  padding: 1rem 1.1rem;
  border: 1px solid var(--cream-faint);
  border-radius: 14px;
}
.hub-card .hub-name { display: block; color: var(--cream); font-size: 1.06rem; }
.hub-card .hub-addr { margin: 0.3rem 0 0; color: var(--cream-dim); font-size: 0.94rem; line-height: 1.55; }
.hub-card .hub-drop { margin: 0.6rem 0 0; color: var(--cream); font-size: 0.94rem; line-height: 1.55; }
.hub-card .btn { margin-top: 0.95rem; }
.hub-hours {
  list-style: none;
  margin: 0.95rem 0 0;
  padding: 0.9rem 0 0;
  border-top: 1px solid var(--cream-faint);
}
.hub-hours li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.9rem;
  padding: 0.24rem 0;
  color: var(--cream-dim);
  font-size: 0.9rem;
}
.hub-hours li b { color: var(--cream-dim); font-weight: 400; }
.hub-hours li.is-drop b, .hub-hours li.is-drop span { color: var(--cream); }
.hub-tag {
  margin-left: 0.45rem;
  padding: 0.1rem 0.4rem;
  border-radius: 5px;
  background: rgba(94, 120, 255, 0.18);
  color: var(--cream);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}
.ho-steps {
  list-style: none;
  counter-reset: ho;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin: 0;
}
/* Same trap as .ticklist: as a grid, the <b> and the sentence after it became
   two items in two columns and the text collapsed to one word per line. The
   number is positioned instead, and everything else is ordinary block text. */
.ho-steps li {
  counter-increment: ho;
  position: relative;
  padding-left: 2.5rem;
  min-height: 1.7rem;
  color: var(--cream-dim);
  font-size: 0.98rem;
  line-height: 1.55;
}
.ho-steps li::before {
  content: counter(ho);
  position: absolute;
  left: 0;
  top: 0;
  width: 1.7rem;
  height: 1.7rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  line-height: 1.62rem;
  text-align: center;
  color: var(--royal-soft);
  border: 1px solid rgba(94, 120, 255, 0.45);
  border-radius: 999px;
}
.ho-steps li b { color: var(--cream); }
/* Step lists whose first line is a title. The label sits on its own line so the
   eye can run down the five titles and stop at the one it wants, instead of
   reading five full sentences to find it. */
.ho-steps-titled li b {
  display: block;
  margin-bottom: 0.2rem;
  font-size: 0.86rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.ho-steps-titled li { font-size: 0.94rem; }
.ho-steps a { color: var(--royal-soft); }

/* forms */
form label.f-label { display: block; margin: 1.1rem 0 0.45rem; color: var(--cream-dim); font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.22em; text-transform: uppercase; }
form input[type="text"], form input[type="tel"], form input[type="email"], form textarea, form select {
  width: 100%; background: var(--ink); color: var(--cream);
  border: 1px solid var(--cream-faint); border-radius: 12px;
  font-family: var(--body); font-size: 1rem;
  padding: 0.95rem 1.1rem;
}
/* native select widgets ignore the dark styling in some engines and paint a
   white control under cream text; owning the appearance keeps it legible */
form select {
  -webkit-appearance: none; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23f1e9db' stroke-width='2'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 1.1rem center;
  padding-right: 2.6rem;
}
section[id], [id].panel, [id].block { scroll-margin-top: 92px; }
form input:focus, form textarea:focus { outline: none; border-color: var(--royal); }
form input[type="file"] { width: 100%; color: var(--cream-dim); font-size: 0.85rem; padding: 0.7rem 0; }
form input[type="file"]::file-selector-button {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase;
  background: var(--royal-deep); color: var(--cream); border: 1px solid var(--royal);
  border-radius: 999px; padding: 0.6rem 1.2rem; margin-right: 1rem; cursor: pointer;
}
.opt-card {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  border: 1px solid var(--cream-faint); border-radius: 14px;
  padding: 1.05rem 1.2rem; margin-top: 0.7rem;
  cursor: pointer; transition: border-color 0.2s, background 0.2s;
}
/* Hover is confined to devices that actually hover. On a phone a tap left the
   card in :hover, and the hover border was near-identical to the selected one,
   so a card looked chosen when it was not. */
@media (hover: hover) {
  .opt-card:hover { border-color: var(--royal-soft); }
}
/* Selection is read straight off the radio/checkbox, so it cannot drift from
   the truth the way a JS-managed class can. .selected stays as the fallback. */
.opt-card.selected,
.opt-card:has(input:checked) {
  border-color: var(--royal);
  background: rgba(43, 75, 255, 0.12);
  box-shadow: inset 0 0 0 1px var(--royal);
}
.opt-card:has(input:checked) .on::before,
.opt-card.selected .on::before {
  content: "\2713";
  display: inline-block;
  width: 1.1em;
  margin-right: 0.35em;
  color: var(--royal-soft);
  font-weight: 700;
}
.opt-card:has(input:focus-visible) { outline: 2px solid var(--royal-soft); outline-offset: 2px; }
.opt-card .on { font-weight: 600; }
.opt-card .od { color: var(--cream-dim); font-size: 0.85rem; display: block; font-weight: 400; }
.opt-card .op { font-family: var(--mono); color: var(--royal-soft); white-space: nowrap; }
.opt-card input { position: absolute; opacity: 0; pointer-events: none; }

/* step machinery */
.steps-bar { display: flex; gap: 0.5rem; margin: 1.6rem 0; }
.steps-bar i { flex: 1; height: 3px; border-radius: 3px; background: var(--cream-faint); }
.steps-bar i.on { background: var(--royal); }
/* Each step is a <fieldset>, and nothing ever reset it - so the browser's own
   groove border was drawing a box around every step, with the buttons and the
   terms line pressed up against it (Jonah, 5 Sep). min-width:0 matters too: a
   fieldset has an intrinsic minimum width that stops its contents shrinking
   properly on a narrow screen. */
.fstep { display: none; border: 0; padding: 0; margin: 0; min-width: 0; }
.fstep > legend { padding: 0; margin-bottom: 0.9rem; }
.fstep.active { display: block; animation: fadeup 0.4s ease; }
@keyframes fadeup { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.step-nav { display: flex; justify-content: space-between; gap: 1rem; margin-top: 1.8rem; }
.f-error { color: #ff7a6b; font-size: 0.85rem; margin-top: 0.8rem; display: none; }

/* map
   Shorter than it was (320px). At full height it was the largest thing in the
   hand-off panel, and size reads as importance: a big map at the top of a
   booking step looks like the step. It is context, so it is sized like
   context. Inert, so no grab cursor and no tap highlight either. */
#dropmap {
  height: 240px;
  border-radius: 18px;
  border: 1px solid var(--cream-faint);
  z-index: 1;
  cursor: default;
  -webkit-tap-highlight-color: transparent;
}
#dropmap .leaflet-marker-icon { cursor: default; }
.dropmap-name {
  display: block;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: center;
  white-space: nowrap;
  color: #f1e9db;
  text-shadow: 0 1px 6px #060608, 0 0 14px #060608;
}
.map-note { margin-top: 0.8rem; color: var(--cream-dim); font-size: 0.9rem; }

/* faq/details */
details.qa { border: 1px solid var(--cream-faint); border-radius: 14px; padding: 1.1rem 1.3rem; margin-top: 0.8rem; }
details.qa summary { cursor: pointer; font-weight: 600; color: var(--cream); }
details.qa[open] { border-color: var(--royal-deep); }
details.qa p { color: var(--cream-dim); margin-top: 0.7rem; font-size: 0.95rem; }

/* footer */
.pfoot {
  border-top: 1px solid var(--cream-faint);
  margin-top: 4rem; padding: 2rem var(--pad);
  display: flex; flex-wrap: wrap; gap: 1.2rem; align-items: center; justify-content: space-between;
}
.pfoot a { color: var(--cream-dim); } .pfoot a:hover { color: var(--royal-soft); }

/* specialty multi-select dropdown */
.spec-dd { border: 1px solid var(--cream-faint); border-radius: 14px; margin-top: 0.3rem; }
.spec-dd summary {
  list-style: none; cursor: pointer;
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  padding: 0.95rem 1.2rem; color: var(--cream-dim); font-size: 0.95rem;
}
.spec-dd summary::-webkit-details-marker { display: none; }
.spec-dd[open] { border-color: var(--royal); }
.spec-dd summary i { color: var(--royal-soft); font-style: normal; transition: transform 0.2s; }
.spec-dd[open] summary i { transform: rotate(180deg); }
.spec-dd .spec-list { padding: 0 0.9rem 0.9rem; }

/* Newsletter block, shared with the home page. Kept identical so the section
   reads the same wherever it appears. */
/* ---------- newsletter ---------- */
/* Not blue and not black. Her palette is only ink, royal and cream, so with
   blue ruled out cream is the one genuinely on-brand alternative - and it makes
   this the one light panel on the site, which is what makes it stand out.
   Two consequences handled below:
     - the logo PNG is white on transparent, so it would vanish here; it is
       filtered to ink.
     - cream between two dark sections is the harshest possible seam, so both
       edges carry a gradient that fades ink into the panel instead of butting
       against it. That was the "too abrupt" complaint. */
.newsletter {
  position: relative;
  padding: clamp(4.5rem, 11vw, 7rem) var(--pad) clamp(4rem, 10vw, 6rem);
  background-color: #f1e9db;
  background-image:
    /* paper grain: light enough to feel rather than see. Overlay, not multiply -
       multiply dragged the cream down into a dull greige. */
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.22'/%3E%3C/svg%3E"),
    radial-gradient(130% 100% at 50% -10%, #fbf6ec 0%, #f1e9db 52%, #e9dfcd 100%);
  background-blend-mode: overlay, normal;
  background-size: 200px 200px, auto;
}
/* Shaped seams, not blended ones. Fading ink into cream necessarily passes
   through grey, which read as a smudge across both edges. Instead the cream
   rises into the dark section along an organic torn line, and the ink below
   rises into the cream the same way - a crisp edge the eye takes as designed.
   preserveAspectRatio=none so the curve stretches to any width. */
.newsletter::before,
.newsletter::after {
  content: "";
  position: absolute;
  left: -1px;
  right: -1px;
  height: clamp(34px, 4.5vw, 62px);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  pointer-events: none;
}
.newsletter::before {
  top: 0;
  transform: translateY(-99%);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 64' preserveAspectRatio='none'%3E%3Cpath d='M0 64 L0 41 C 120 30 232 47 349 39 C 470 31 548 12 668 14 C 792 16 872 38 996 36 C 1112 34 1200 17 1310 20 C 1372 22 1410 30 1440 34 L1440 64 Z' fill='%23f1e9db'/%3E%3C/svg%3E");
}
.newsletter::after {
  bottom: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 64' preserveAspectRatio='none'%3E%3Cpath d='M0 64 L0 38 C 128 26 250 44 372 37 C 498 30 566 12 690 14 C 806 16 890 37 1012 35 C 1128 33 1214 16 1330 19 C 1382 20 1414 28 1440 33 L1440 64 Z' fill='%23060608'/%3E%3C/svg%3E");
}
.nl-inner {
  position: relative;
  z-index: 1;
  max-width: 1180px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
}
.nl-mark { display: flex; justify-content: center; }
/* The full lockup - mark plus SNEAKER RESTORATION STUDIO underneath - rather
   than the bare mark, so it reads the way the logo always does. White on
   transparent, so it is taken to ink to sit on the light panel. */
.nl-mark .nl-lockup {
  width: clamp(180px, 22vw, 320px);
  height: auto;
  display: block;
  filter: brightness(0);
}
/* the right column is centred as a block, like the reference */
.nl-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.6rem;
  min-width: 0;
}
.nl-title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.5rem, 3.1vw, 2.55rem);
  line-height: 1.1;
  letter-spacing: 0.01em;
  color: var(--ink);
  max-width: 26ch;
}
.nl-sub { font-size: clamp(0.98rem, 1.35vw, 1.15rem); color: rgba(6, 6, 8, 0.66); }
.nl-form { display: flex; gap: 0.7rem; margin-top: 1.1rem; width: 100%; max-width: 540px; }
.nl-mail {
  flex: 1 1 auto;
  min-width: 0;
  background: #fff;
  border: 1px solid rgba(6, 6, 8, 0.18);
  border-radius: 12px;
  color: var(--ink);
  padding: 1rem 1.15rem;
  font: inherit;
}
.nl-mail::placeholder { color: rgba(6, 6, 8, 0.42); }
.nl-mail:focus { outline: none; border-color: var(--royal); box-shadow: 0 0 0 3px rgba(43, 75, 255, 0.16); }
.nl-btn {
  flex: 0 0 auto;
  background: var(--royal);
  color: #fff;
  border: 0;
  border-radius: 12px;
  padding: 1rem 1.8rem;
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.2s, transform 0.2s;
}
.nl-btn:hover { background: #3d5bff; transform: translateY(-1px); }
@media (max-width: 820px) {
  .nl-inner { grid-template-columns: 1fr; justify-items: center; gap: 1.6rem; }
  .nl-title { max-width: 24ch; }
  .nl-form { flex-direction: column; max-width: 420px; margin-top: 0.9rem; }
  .nl-btn { width: 100%; }
}

/* ---------- site footer (every page) ---------- */
/* One slim bar everywhere. No (c) glyph - the year and the name, then the three
   links, in the order Jonah specified. */
.sfoot {
  border-top: 1px solid rgba(241, 233, 219, 0.12);
  background: #0a0a0d;
  padding: 1.4rem var(--pad);
}
.sfoot-inner {
  max-width: 1180px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem 0.8rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  color: rgba(241, 233, 219, 0.84);
  text-align: center;
}
.sfoot-inner a {
  color: var(--cream);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.sfoot-inner a:hover { color: var(--cream); }
.sfoot-sep, .sfoot-dot { opacity: 0.55; }
@media (max-width: 560px) {
  .sfoot-inner { font-size: 0.66rem; letter-spacing: 0.05em; gap: 0.35rem 0.6rem; }
}

/* ---------- contact form ---------- */
.cform { margin-top: 2.2rem; max-width: 720px; }
/* section headings inside the form, matching the reference's grouping */
.cf-group {
  font-family: var(--body);
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--cream);
  margin: 2.1rem 0 0.2rem;
}
.cf-group:first-of-type { margin-top: 0.6rem; }
.cf-group .req,
.f-label .req {
  font-family: var(--body);
  font-size: 0.8rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--cream-dim);
}
.cf-help { color: var(--cream-dim); font-size: 0.92rem; margin: 0.35rem 0 0.7rem; }
/* first and last name sit side by side, stacking on narrow screens */
.cf-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 620px) { .cf-row { grid-template-columns: 1fr; gap: 0.2rem; } }
.cf-checks { display: flex; flex-direction: column; gap: 0.65rem; margin-top: 0.9rem; }
.cf-check {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  cursor: pointer;
  color: var(--cream);
  font-size: 1rem;
}
.cf-check input {
  appearance: none;
  -webkit-appearance: none;
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  border: 1px solid rgba(241, 233, 219, 0.42);
  border-radius: 6px;
  background: var(--ink);
  cursor: pointer;
  position: relative;
  transition: border-color 0.15s, background 0.15s;
}
.cf-check input:hover { border-color: var(--royal-soft); }
.cf-check input:checked { background: var(--royal); border-color: var(--royal); }
/* the tick is drawn rather than relying on a font glyph */
.cf-check input:checked::after {
  content: "";
  position: absolute;
  left: 6px;
  top: 2px;
  width: 7px;
  height: 12px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.cf-check input:focus-visible { outline: 2px solid var(--royal-soft); outline-offset: 2px; }
.cf-submit { margin-top: 2rem; display: inline-flex; letter-spacing: 0.2em; }

/* ---------- header menu (shared with the home page) ---------- */
/* Lifted from the home stylesheet so the two headers cannot drift apart. The
   overlay markup is built by /nav.js. */
.nav-burger {
  width: 46px; height: 46px; border-radius: 999px; flex: 0 0 auto;
  border: 1px solid rgba(241, 233, 219, 0.35); background: rgba(6, 6, 8, 0.35);
  display: grid; place-items: center; cursor: pointer; padding: 0;
  transition: border-color 0.2s;
}
.nav-burger i { display: block; width: 18px; height: 2px; background: var(--cream); margin: 2.5px 0; border-radius: 2px; }
.nav-burger:hover { border-color: var(--royal-soft); }
.menu {
  position: fixed; inset: 0; z-index: 300; background: #060608;
  display: none; flex-direction: column;
  padding: 1.1rem var(--pad) max(2rem, env(safe-area-inset-bottom));
  overflow-y: auto;
}
.menu.open { display: flex; }
.menu-top { display: flex; align-items: center; justify-content: space-between; }
.menu-top .lace { width: clamp(100px, 17vw, 122px); height: auto; }
.menu-close {
  width: 46px; height: 46px; border-radius: 999px; flex: 0 0 auto;
  border: 1px solid rgba(241, 233, 219, 0.35); background: none;
  color: var(--cream); font-size: 1.1rem; cursor: pointer; line-height: 1;
  transition: color 0.2s, border-color 0.2s;
}
.menu-close:hover { border-color: var(--royal-soft); color: var(--royal-soft); }
.menu-links { display: flex; flex-direction: column; gap: 0.4rem; margin: clamp(1.7rem, 6vh, 3rem) 0 0; }
.menu-links a {
  font-family: var(--display);
  font-size: clamp(1.9rem, 7.5vw, 3rem);
  letter-spacing: 0.02em; text-transform: uppercase; line-height: 1.16;
  color: var(--cream); text-decoration: none; width: fit-content;
  transition: color 0.18s;
}
.menu-links a:hover { color: var(--royal-soft); }
.menu-social { display: flex; gap: 0.9rem; margin-top: clamp(1.8rem, 5vh, 2.6rem); }
.menu-social a {
  width: 56px; height: 56px; border-radius: 50%;
  border: 1.5px solid rgba(241, 233, 219, 0.45);
  display: grid; place-items: center; color: var(--cream);
  transition: color 0.2s, border-color 0.2s, background 0.2s, transform 0.2s;
}
.menu-social a:hover, .menu-social a:active {
  color: #fff; border-color: var(--royal); background: var(--royal);
  transform: translateY(-2px);
}
.menu-social svg { width: 23px; height: 23px; display: block; }
.menu-book {
  margin-top: 1.7rem; display: inline-block; width: fit-content;
  font-family: var(--mono); font-size: 0.92rem; letter-spacing: 0.18em; text-transform: uppercase;
  background: var(--royal); color: #fff; text-decoration: none;
  border-radius: 999px; padding: 1.1rem 2.4rem;
  box-shadow: 0 6px 30px rgba(43, 75, 255, 0.45);
  transition: background 0.2s;
}
.menu-book:hover { background: #3d5bff; }
.menu-foot { margin-top: auto; padding-top: 2rem; color: rgba(241, 233, 219, 0.4); font-size: 0.62rem; letter-spacing: 0.16em; }

/* The shared form styling above targets form input[type="email"], which
   outranks a plain .nl-mail class - that turned this field dark on the static
   pages while the home page stayed white. Scoped under .newsletter so it wins
   on specificity, not on ordering. */
.newsletter input.nl-mail {
  background: #fff;
  color: var(--ink);
  border: 1px solid rgba(6, 6, 8, 0.18);
  border-radius: 12px;
  padding: 1rem 1.15rem;
  font: inherit;
  width: auto;
}
.newsletter input.nl-mail::placeholder { color: rgba(6, 6, 8, 0.42); }
.newsletter input.nl-mail:focus {
  outline: none;
  background: #fff;
  border-color: var(--royal);
  box-shadow: 0 0 0 3px rgba(43, 75, 255, 0.16);
}

/* ---------- deposit / balance panel on the private booking page ---------- */
.iv-panel {
  margin-top: 1rem;
  padding: 1rem 1.1rem 1.15rem;
  border: 1px solid rgba(43, 75, 255, 0.32);
  border-radius: 14px;
  background: rgba(43, 75, 255, 0.06);
}
.iv-head { display: flex; align-items: baseline; gap: 0.7rem; flex-wrap: wrap; margin-bottom: 0.7rem; }
.iv-hint { font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.5; }
.iv-row { display: flex; align-items: flex-end; gap: 1rem; flex-wrap: wrap; }
.iv-row label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.66rem;
  letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.7; }
.iv-total { width: 9rem; background: #fff; color: var(--ink); border: 1px solid rgba(6, 6, 8, 0.18);
  border-radius: 10px; padding: 0.6rem 0.7rem; font: inherit; font-size: 1rem; }
.iv-split { font-size: 0.72rem; opacity: 0.75; padding-bottom: 0.55rem; }
.iv-split b { color: var(--cream); }
.iv-check { display: flex; align-items: center; gap: 0.45rem; margin: 0.75rem 0 0;
  font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.8; }
.iv-note { width: 100%; margin-top: 0.8rem; min-height: 5.5rem; resize: vertical;
  background: rgba(6, 6, 8, 0.5); color: var(--cream); border: 1px solid var(--cream-faint);
  border-radius: 10px; padding: 0.7rem 0.8rem; font: inherit; font-size: 0.9rem; line-height: 1.5; }
.iv-actions { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-top: 0.85rem; }
.iv-actions .btn { font-size: 0.68rem; padding: 0.8rem 1.4rem; }
.iv-result { margin-top: 0.9rem; padding-top: 0.85rem; border-top: 1px solid var(--cream-faint); }
.iv-ok b { color: #7ee3a6; font-size: 0.74rem; letter-spacing: 0.12em; }
.iv-linkrow { margin-top: 0.35rem; font-size: 0.85rem; }
.iv-linkrow a { color: #8fa2ff; }
.iv-linkrow .mono { font-size: 0.72rem; opacity: 0.55; margin-left: 0.5rem; }
/* already-sent invoices, so she can see state without opening Stripe */
.iv-sent { font-size: 0.78rem; margin-bottom: 0.45rem; }
.iv-sent b { font-size: 0.7rem; letter-spacing: 0.1em; }
.iv-sent a { color: #8fa2ff; }
.iv-sent.paid b { color: #7ee3a6; }
@media (max-width: 560px) {
  .iv-row { gap: 0.6rem; }
  .iv-total { width: 100%; }
  .iv-actions { flex-direction: column; align-items: stretch; }
  .iv-actions .btn { text-align: center; }
}

/* what the customer actually asked for - email always sends, so this is the
   reminder that the text is the part they will read */
.iv-pref {
  margin: 0 0 0.8rem;
  padding: 0.55rem 0.75rem;
  border-left: 3px solid var(--royal);
  background: rgba(43, 75, 255, 0.1);
  border-radius: 0 8px 8px 0;
  font-size: 0.82rem;
  line-height: 1.45;
}
.iv-pref b { color: var(--cream); text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.78rem; }

/* ---------- drop-off details, shown once the deposit is paid ---------- */
.do-panel {
  margin-top: 0.9rem;
  padding: 1rem 1.1rem 1.15rem;
  border: 1px solid rgba(126, 227, 166, 0.3);
  border-radius: 14px;
  background: rgba(126, 227, 166, 0.05);
}
.do-body { font-size: 0.85rem; }
.do-row { display: flex; gap: 1rem; flex-wrap: wrap; align-items: flex-end; }
.do-row label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.66rem;
  letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.7; }
.do-tag { width: 11rem; background: #fff; color: var(--ink); border: 1px solid rgba(6, 6, 8, 0.18);
  border-radius: 10px; padding: 0.55rem 0.7rem; font: inherit; font-size: 0.95rem; }
.do-loc { background: var(--ink-2); color: var(--cream); border: 1px solid var(--cream-faint);
  border-radius: 10px; padding: 0.55rem 0.6rem; font: inherit; font-size: 0.85rem; }
.do-out { margin-top: 0.85rem; padding-top: 0.8rem; border-top: 1px solid var(--cream-faint); }
/* the one state that must be impossible to miss: paid, but they were never
   told where to bring the shoes */
.do-warn {
  padding: 0.7rem 0.85rem;
  border-left: 3px solid #ffb020;
  background: rgba(255, 176, 32, 0.12);
  border-radius: 0 8px 8px 0;
  font-size: 0.85rem;
  line-height: 1.5;
  text-transform: none;
  letter-spacing: 0;
}
@media (max-width: 560px) {
  .do-row { gap: 0.6rem; }
  .do-tag, .do-loc { width: 100%; }
}
.do-bag, .do-loc { background: var(--ink-2); color: var(--cream); border: 1px solid var(--cream-faint);
  border-radius: 10px; padding: 0.55rem 0.6rem; font: inherit; font-size: 0.85rem; min-width: 9rem; }
.do-bag option:disabled { color: rgba(241, 233, 219, 0.35); }
.do-meta { margin-top: 0.55rem; font-size: 0.66rem; letter-spacing: 0.1em;
  text-transform: uppercase; opacity: 0.5; }

/* ---------- booking: photo tiles ("show us the shoes") ---------- */
/* Ten optional slots would be a wall of grey file inputs, so each one is a
   square tile that fills with the chosen photo. Someone adding four side shots
   can then see which is which instead of four identical boxes. */
.shot-note { font-size: 0.9rem; line-height: 1.5; color: var(--cream-dim); margin: 0 0 1.1rem; }
.shot-group { margin-bottom: 1.1rem; }
.shot-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.45rem; }
.shot-head b { font-size: 0.82rem; letter-spacing: 0.1em; text-transform: uppercase; }
.shot-head span { font-size: 0.64rem; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.45; }
/* An angle the customer has not filled, once they have tried to move on. Marked
   rather than only counted: "every angle needs a photo" is no help on a phone
   where three of the four groups are off screen. */
.shot-group.needs-photo { position: relative; }
.shot-group.needs-photo .shot-head b { color: #ffb4a8; }
.shot-group.needs-photo .shot-head b::after {
  content: "needs a photo";
  margin-left: 0.6rem;
  font-family: var(--mono);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  color: #ffb4a8;
  opacity: 0.85;
}
.shot-group.needs-photo .shot-grid {
  outline: 1px solid rgba(255, 140, 120, 0.5);
  outline-offset: 6px;
  border-radius: 10px;
}
.shot-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 0.5rem; }
.shot { position: relative; cursor: pointer; }
/* the input stays focusable for keyboard and screen readers, just not visible */
.shot input { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; }
.shot-box {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.15rem;
  aspect-ratio: 1;
  border: 1px dashed rgba(241, 233, 219, 0.28);
  border-radius: 12px;
  background: rgba(241, 233, 219, 0.03);
  overflow: hidden;
  transition: border-color 0.18s, background 0.18s;
}
.shot-box i { font-style: normal; font-size: 1.15rem; line-height: 1; opacity: 0.5; }
.shot-box em {
  font-style: normal; font-family: var(--mono); font-size: 0.62rem;
  letter-spacing: 0.1em; opacity: 0.45;
}
.shot input:focus-visible + .shot-box { border-color: var(--royal-soft); outline: 2px solid var(--royal-soft); outline-offset: 2px; }
.shot:hover .shot-box { border-color: rgba(241, 233, 219, 0.5); }
.shot.has .shot-box { border-style: solid; border-color: var(--royal); background: rgba(43, 75, 255, 0.1); }
.shot.has .shot-box i, .shot.has .shot-box em { display: none; }
.shot-box img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* ---------- booking: agree-to-terms checkbox ---------- */
/* A real, visible box rather than a card that merely highlights - agreeing to
   terms should look like a deliberate tick, not a selected option. */
.agree { display: flex; align-items: flex-start; gap: 0.7rem; margin-top: 1.1rem; cursor: pointer; }
.agree input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.agree-box {
  flex: 0 0 auto; width: 22px; height: 22px; margin-top: 0.1rem;
  border: 1.5px solid rgba(241, 233, 219, 0.45); border-radius: 6px;
  background: rgba(6, 6, 8, 0.4);
  position: relative; transition: background 0.15s, border-color 0.15s;
}
.agree input:checked + .agree-box { background: var(--royal); border-color: var(--royal); }
.agree input:checked + .agree-box::after {
  content: ""; position: absolute; left: 6px; top: 2px;
  width: 6px; height: 11px; border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.agree input:focus-visible + .agree-box { outline: 2px solid var(--royal-soft); outline-offset: 2px; }
.agree-text { font-size: 0.95rem; line-height: 1.45; }

/* ---------- booking: step buttons ---------- */
/* The shared .btn is a big marketing pill; inside a form it reads as oversized
   and childlike. Tighter padding and a softer radius so they look like form
   controls. */
.step-nav { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin-top: 1.5rem; }
.step-nav .btn {
  font-size: 0.72rem; letter-spacing: 0.14em;
  padding: 0.9rem 1.55rem; border-radius: 12px;
}
.step-nav .btn-primary { box-shadow: 0 6px 22px rgba(43, 75, 255, 0.28); }
@media (max-width: 480px) {
  .shot-grid { grid-template-columns: repeat(auto-fill, minmax(74px, 1fr)); gap: 0.4rem; }
}

/* ---------- booking on a phone ----------

   The form is four screens long and the controls that move you through it were
   the smallest things on the page. Jonah, 5 Sep: make the mobile booking view
   better. Four changes, all about the thumb:

   1. The step bar sticks, so "which of the four am I on" is always answerable.
   2. Next and Back sit in a bar at the bottom of the screen, where the thumb
      already is, instead of at the end of a long scroll.
   3. Every tap target clears 48px.
   4. Inputs are 16px, because anything smaller makes iOS zoom the page on
      focus and the visitor then has to pinch back out to see the form. */
@media (max-width: 640px) {
  .steps-bar {
    position: sticky;
    top: 0;
    z-index: 20;
    margin: 0 0 1.2rem;
    padding: 0.85rem 0;
    background: linear-gradient(var(--ink) 72%, rgba(6, 6, 8, 0));
  }
  .steps-bar i { height: 4px; }

  .page { padding-bottom: 7.5rem; }
  /* Room to breathe between the blocks inside a step, and enough at the end
     that the last field can scroll clear of the sticky bar. */
  .fstep .panel { padding: 1.5rem 1.35rem; }
  .fstep .panel + .panel { margin-top: 1.2rem; }
  .fstep > legend { margin-bottom: 1.1rem; }
  .fstep .lede { margin-bottom: 1.2rem; }
  /* .agree-note and .ship-note are declared further down this file, so at equal
     specificity they would win over these. Scoped to .page to outrank them
     without moving anything. */
  .page .agree-note { margin-top: 1.3rem; padding: 0 0.4rem 0.6rem; line-height: 1.6; }
  .f-error { margin-top: 1rem; }
  .opt-card + .opt-card { margin-top: 0.7rem; }
  #dropmap { height: 200px; margin-top: 0.4rem; }
  .ho-notice { font-size: 0.95rem; padding: 0.9rem 0.95rem; }
  .ho-hubs { grid-template-columns: 1fr; gap: 0.5rem; }
  .map-note { margin-top: 1rem; line-height: 1.6; }
  .page .ship-note { margin-top: 0.8rem; line-height: 1.6; }
  .shot-note { margin-bottom: 1.4rem; }

  .step-nav {
    position: sticky;
    bottom: 0;
    z-index: 20;
    gap: 0.7rem;
    margin-top: 2rem;
    /* Opaque from the top of the bar down, with a short fade above it. The old
       gradient only reached full opacity a third of the way in, so a field
       sitting under the bar showed through behind the buttons. */
    padding: 1.1rem 0 max(1rem, env(safe-area-inset-bottom));
    background: var(--ink);
    box-shadow: 0 -18px 22px -12px var(--ink), 0 -34px 26px -20px var(--ink);
  }
  .step-nav .btn {
    flex: 1 1 0;
    text-align: center;
    padding: 1.05rem 0.8rem;
    font-size: 0.7rem;
    min-height: 48px;
  }
  /* Back is the escape hatch, not the action. Half the width of Next. */
  .step-nav .btn-ghost { flex: 0 1 34%; }

  .opt-card { padding: 1.05rem 1.15rem; min-height: 48px; }
  .opt-card .od { font-size: 0.82rem; margin-top: 0.15rem; }

  form input[type="text"], form input[type="tel"], form input[type="email"],
  form textarea, form select {
    font-size: 16px;
    padding: 1rem 1.05rem;
  }
  form label.f-label { margin-top: 1.3rem; }

  .shot-grid { grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); }
  .ho-steps li { padding-left: 2.25rem; font-size: 0.94rem; }
}

/* Dark map without an API key: OSM's tiles are light, so invert just the tile
   pane. Markers and controls live in other panes and keep their real colours. */
#dropmap .leaflet-tile-pane {
  /* grayscale BEFORE invert: OSM's green landcover and pink roads otherwise
     invert into muddy magenta and green. Desaturating first gives a clean dark
     neutral that matches the rest of the site. */
  filter: grayscale(1) invert(1) brightness(0.72) contrast(1.18);
}
#dropmap .leaflet-control-attribution {
  background: rgba(6, 6, 8, 0.7) !important;
  color: rgba(241, 233, 219, 0.55) !important;
}
#dropmap .leaflet-control-attribution a { color: rgba(143, 162, 255, 0.8) !important; }

/* mail-in return address */
.ship-row { display: flex; gap: 0.5rem; margin-top: 0.5rem; }
.ship-row #ship-city { flex: 1 1 auto; }
.ship-row #ship-state { flex: 0 0 5.5rem; text-transform: uppercase; }
.ship-note { margin-top: 0.5rem; font-size: 0.62rem; letter-spacing: 0.12em;
  text-transform: uppercase; opacity: 0.45; }
.ship-lead { margin: 0 0 0.8rem; font-size: 0.86rem; line-height: 1.5; color: var(--cream-dim); }
.ship-lead b { color: var(--cream); }

/* ---------- bag board + collection manifest ---------- */
.bb-wrap { border: 1px solid var(--cream-faint); border-radius: 14px; background: rgba(241,233,219,0.02); }
.bb-summary { cursor: pointer; padding: 0.9rem 1.1rem; display: flex; align-items: baseline;
  justify-content: space-between; gap: 0.8rem; flex-wrap: wrap; list-style: none; }
.bb-summary::-webkit-details-marker { display: none; }
.bb-summary b { font-size: 0.95rem; }
.bb-summary span { font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.55; }
.bb-body { padding: 0 1.1rem 1.1rem; }
.bb-sec { margin-top: 0.4rem; }
.bb-h { font-size: 0.64rem; letter-spacing: 0.16em; text-transform: uppercase; opacity: 0.45;
  margin: 1rem 0 0.55rem; }
.bb-run, .bb-pool { border: 1px solid var(--cream-faint); border-radius: 12px;
  padding: 0.75rem 0.9rem; margin-bottom: 0.6rem; }
/* a hub with nothing waiting should read as "do not drive here" */
.bb-run.empty { opacity: 0.5; border-style: dashed; }
.bb-run-h { display: flex; align-items: baseline; justify-content: space-between; gap: 0.7rem; flex-wrap: wrap; }
.bb-run-h b { font-size: 0.9rem; }
.bb-run-h span { font-size: 0.64rem; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.6; }
.bb-list { margin-top: 0.6rem; display: flex; flex-direction: column; gap: 0.35rem; }
.bb-item { display: flex; align-items: baseline; gap: 0.6rem; font-size: 0.85rem; flex-wrap: wrap; }
.bb-bag { font-size: 0.62rem; letter-spacing: 0.1em; padding: 0.2rem 0.45rem;
  border: 1px solid var(--cream-faint); border-radius: 6px; opacity: 0.85; }
.bb-svc { font-size: 0.62rem; letter-spacing: 0.08em; opacity: 0.45; }
.bb-none { margin: 0.5rem 0 0; font-size: 0.78rem; line-height: 1.5; opacity: 0.55; }
.bb-chips { display: grid; grid-template-columns: repeat(auto-fill, minmax(40px, 1fr)); gap: 0.35rem; margin-top: 0.6rem; }
.bb-chip { display: flex; align-items: center; justify-content: center; aspect-ratio: 1;
  border-radius: 9px; font-family: var(--mono); font-size: 0.78rem; border: 1px solid; }
.bb-chip.free { border-color: rgba(126,227,166,0.35); background: rgba(126,227,166,0.08);
  color: rgba(126,227,166,0.85); }
.bb-chip.out { border-color: rgba(255,176,32,0.5); background: rgba(255,176,32,0.14);
  color: #ffd98a; cursor: pointer; }
.bb-chip.out:hover { background: rgba(255,176,32,0.26); }
.bb-chip.out:disabled { opacity: 0.4; cursor: default; }
@media (max-width: 560px) {
  .bb-chips { grid-template-columns: repeat(auto-fill, minmax(36px, 1fr)); }
  .bb-body { padding: 0 0.8rem 0.9rem; }
}

/* ---------- completion panel ---------- */
.cp-panel { margin-top: 0.9rem; padding: 1rem 1.1rem 1.15rem;
  border: 1px solid rgba(143,162,255,0.35); border-radius: 14px; background: rgba(43,75,255,0.05); }
.cp-track { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.9rem; }
.cp-step { font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase;
  padding: 0.28rem 0.55rem; border-radius: 999px;
  border: 1px solid var(--cream-faint); opacity: 0.45; }
.cp-step.on { opacity: 1; border-color: rgba(126,227,166,0.5);
  background: rgba(126,227,166,0.12); color: #7ee3a6; }
.cp-h { font-size: 0.64rem; letter-spacing: 0.16em; text-transform: uppercase;
  opacity: 0.5; margin: 0 0 0.5rem; }
.cp-shots { max-width: 26rem; }
.cp-shots .shot.busy .shot-box { opacity: 0.45; }
.cp-note { min-height: 4.5rem; }
.cp-money { margin-top: 0.7rem; font-size: 0.68rem; letter-spacing: 0.1em;
  text-transform: uppercase; opacity: 0.7; }
.cp-money b { color: var(--cream); }
.cp-warn { margin-top: 0.7rem; padding: 0.6rem 0.8rem; border-left: 3px solid #ffb020;
  background: rgba(255,176,32,0.12); border-radius: 0 8px 8px 0; font-size: 0.82rem; line-height: 1.45; }
.cp-out { margin-top: 0.9rem; padding-top: 0.85rem; border-top: 1px solid var(--cream-faint); }
.cp-got { font-size: 0.66rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: #7ee3a6; align-self: center; }

/* ---------- escalation gate on the invoice panel ---------- */
/* escalate fires on blurry photos, wrong pair count, suspected counterfeit,
   mould, and damage beyond restoration. Her deposit is non-refundable, so
   invoicing a standard price on one of those is a real dispute - hence a tick
   before the send, carrying the reason so she need not scroll back up. */
.iv-esc { margin: 0 0 0.85rem; padding: 0.75rem 0.9rem;
  border-left: 3px solid #ffb020; background: rgba(255,176,32,0.13);
  border-radius: 0 10px 10px 0; font-size: 0.86rem; line-height: 1.5; }
.iv-esc.done { border-left-color: rgba(126,227,166,0.7); background: rgba(126,227,166,0.08); }
.iv-esc b { display: block; font-size: 0.7rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: #ffd98a; margin-bottom: 0.35rem; }
.iv-esc.done b { color: #7ee3a6; }
.iv-esc ul { margin: 0.2rem 0 0; padding-left: 1.1rem; }
.iv-esc li { margin: 0.2rem 0; }
.iv-esc p { margin: 0.2rem 0 0; }
.iv-ack { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.7rem;
  font-size: 0.78rem; cursor: pointer; }
.iv-ack input { width: 18px; height: 18px; accent-color: #2b4bff; }

/* newsletter signup confirmation, shown only on arrival from the form */
.sub-ok { margin: 0 0 1.6rem; padding: 0.9rem 1.1rem;
  border-left: 3px solid #7ee3a6; background: rgba(126,227,166,0.1);
  border-radius: 0 12px 12px 0; font-size: 0.95rem; line-height: 1.55; }
.sub-ok b { color: #7ee3a6; }

/* per-booking delete: quiet until hovered, so it is never the obvious tap */
.rv-del { font-size: 0.6rem; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 0.3rem 0.6rem; border-radius: 8px; cursor: pointer;
  border: 1px solid rgba(255,75,58,0.35); background: transparent;
  color: rgba(255,156,145,0.75); transition: background 0.15s, color 0.15s; }
.rv-del:hover { background: rgba(255,75,58,0.16); color: #ff9c91; }
.rv-del:disabled { opacity: 0.5; cursor: default; }

/* The last line of Reesey's story, and her tagline. Sized up because it is the
   line she closes on, not a caption. */
.panel p.about-kicker,
.about-kicker {
  margin-top: 0.9rem;
  font-family: Anton, Impact, sans-serif;
  font-size: clamp(1.1rem, 3vw, 1.5rem);
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--royal-soft);
}

/* Her Important Service Policies. Bordered rather than plain because it is the
   last thing read before committing money, and it should not scan as body copy. */
.policy-panel { border-left: 2px solid var(--royal-soft); }
.panel p.policy-head, .policy-head { margin-bottom: 0.7rem; text-transform: uppercase;
  letter-spacing: 0.12em; font-size: 0.72rem; color: var(--cream); }
.agree-text a { color: var(--royal-soft); }
/* The optional consent sits visually subordinate to the required agreement, so
   nobody reads them as one compound condition. */
.agree-optional { margin-top: 0.9rem; opacity: 0.9; }
.agree-optional .agree-text { font-size: 0.86rem; }

/* The line under Send My Booking. It replaced a policy panel and two tick
   boxes (5 Sep), so it is the only place the customer is told what submitting
   commits them to - the two links have to look like links, which is why they
   carry the brand blue and an underline rather than inheriting the muted body
   colour around them. */
.agree-note {
  margin-top: 0.9rem;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--cream-dim);
  text-align: center;
}
.agree-note a {
  color: var(--royal-soft);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.agree-note a:hover { color: var(--cream); }
.agree-optional .agree-text i { opacity: 0.6; font-style: normal; }

/* Terms page: the effective/updated line under the title. */
.legal-dates { margin-top: 0.9rem; font-size: 0.68rem; letter-spacing: 0.14em;
  text-transform: uppercase; opacity: 0.5; }
.legal .block-title { font-size: clamp(1rem, 2.4vw, 1.2rem); }

/* ================= private booking page: collapsible cards ================= */
/* Each booking is a <details>. Closed, the summary is the whole triage view;
   open, the working panels appear in order. */
details.rv-card { padding: 0; overflow: hidden; }
details.rv-card > .rv-sum { list-style: none; cursor: pointer; display: grid;
  grid-template-columns: 1fr auto; grid-template-areas: "main pills" "meta chev";
  gap: 0.35rem 0.8rem; align-items: center; padding: 0.95rem 1.1rem; }
details.rv-card > .rv-sum::-webkit-details-marker { display: none; }
details.rv-card[open] > .rv-sum { border-bottom: 1px solid var(--cream-faint); }
.rv-sum-main { grid-area: main; min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; }
.rv-sum-name { font-size: 1rem; color: var(--cream); }
.rv-sum-svc { font-size: 0.82rem; color: var(--cream-dim); overflow-wrap: anywhere; }
.rv-pills { grid-area: pills; display: flex; gap: 0.35rem; flex-wrap: wrap; justify-content: flex-end; }
.rv-sum-meta { grid-area: meta; font-size: 0.64rem; letter-spacing: 0.1em; opacity: 0.5; }
.rv-chev { grid-area: chev; justify-self: end; opacity: 0.5; transition: transform 0.2s; font-size: 1.1rem; line-height: 1; }
details.rv-card[open] .rv-chev { transform: rotate(180deg); }
.rv-body { padding: 0.9rem 1.1rem 1.15rem; }
.rv-tools { margin-bottom: 0.9rem; }
/* Bag tag: the number she matches at the lock box, so it sits first on the
   folded row, large, while the bag is out. Gone once the bag is marked back. */
details.rv-card.has-bag > .rv-sum { grid-template-columns: auto 1fr auto; grid-template-areas: "bag main pills" "bag meta chev"; }
.rv-bag { grid-area: bag; align-self: center; display: flex; flex-direction: column; align-items: center;
  justify-content: center; min-width: 3.4rem; padding: 0.4rem 0.5rem 0.35rem; border: 1.5px solid #ffd98a;
  border-radius: 0.6rem; color: #ffd98a; background: rgba(255,190,60,0.08); font-family: var(--mono);
  font-size: 1.55rem; font-weight: 700; line-height: 1; }
.rv-bag i { font-style: normal; font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; opacity: 0.75; margin-bottom: 0.15rem; }
.rv-bag small { font-size: 0.5rem; letter-spacing: 0.14em; opacity: 0.7; margin-top: 0.2rem; }
/* What the scan says the pair is: her second matching key, right under the name. */
.rv-sum-shoe { font-size: 0.88rem; color: var(--cream); opacity: 0.92; overflow-wrap: anywhere; }
@media (max-width: 640px) {
  details.rv-card > .rv-sum { grid-template-columns: 1fr auto; grid-template-areas: "main chev" "pills pills" "meta meta"; }
  details.rv-card.has-bag > .rv-sum { grid-template-columns: auto 1fr auto; grid-template-areas: "bag main chev" "pills pills pills" "meta meta meta"; }
  .rv-pills { justify-content: flex-start; }
}

/* pills: one visual language for status, money and scan */
.rv-pill { font-family: var(--mono); font-size: 0.58rem; letter-spacing: 0.1em; text-transform: uppercase;
  padding: 0.28rem 0.55rem; border-radius: 999px; border: 1px solid var(--cream-faint); white-space: nowrap; }
.rv-pill.st-new { color: var(--cream); border-color: rgba(241,233,219,0.35); }
.rv-pill.st-held { color: #f0a93b; border-color: rgba(240,169,59,0.5); }
.rv-pill.st-quoted { color: #8fa2ff; border-color: rgba(143,162,255,0.5); }
.rv-pill.st-prog { color: #ffd98a; border-color: rgba(255,190,60,0.45); }
.rv-pill.st-ready { color: #7ee3a6; border-color: rgba(126,227,166,0.5); }
.rv-pill.st-done { color: var(--cream-dim); opacity: 0.7; }
.rv-pill.m-none { opacity: 0.5; }
.rv-pill.m-sent { color: #ffd98a; border-color: rgba(255,190,60,0.45); background: rgba(255,190,60,0.08); }
.rv-pill.m-paid { color: #7ee3a6; border-color: rgba(126,227,166,0.5); background: rgba(126,227,166,0.08); }
.rv-pill.ai-wait { opacity: 0.5; }
.rv-pill.ai-accept { color: #7ee3a6; border-color: rgba(126,227,166,0.5); }
.rv-pill.ai-escalate { color: #ffd98a; border-color: rgba(255,190,60,0.5); background: rgba(255,190,60,0.1); }
.rv-pill.ai-decline { color: #ff9c91; border-color: rgba(255,75,58,0.5); }

/* numbered step on each working panel */
.stp { display: inline-grid; place-items: center; width: 1.45rem; height: 1.45rem; border-radius: 50%;
  background: var(--royal); color: #fff; font-style: normal; font-family: var(--mono); font-size: 0.7rem;
  font-weight: 700; margin-right: 0.15rem; flex: 0 0 auto; }

/* the AI panel, folded */
.ai-shoe-inline { font-size: 0.9rem; color: var(--cream-dim); min-width: 0; overflow-wrap: anywhere; }
.ai-conf.ok { color: #7be3a8; } .ai-conf.warn { color: #ffd98a; }
.ai-match { font-size: 0.7em; color: #7be3a8; letter-spacing: 0.08em; }
.ai-more { margin-top: 0.6rem; }
.ai-more > summary { cursor: pointer; list-style: none; font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: #8fa2ff; padding: 0.45rem 0; }
.ai-more > summary::-webkit-details-marker { display: none; }
.ai-more > summary::before { content: "+ "; }
.ai-more[open] > summary::before { content: "\2212 "; }

/* escalation: reason first, the rest folded */
.iv-esc-first { margin-top: 0.35rem; }
.iv-esc-more { margin-top: 0.35rem; }
.iv-esc-more > summary { cursor: pointer; list-style: none; font-size: 0.64rem; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.7; }
.iv-esc-more > summary::-webkit-details-marker { display: none; }
.iv-esc-more ul { margin: 0.4rem 0 0 1rem; padding: 0; font-size: 0.85rem; }

/* action bars: same size everywhere, full-width taps on a phone */
.iv-actions .btn, .ai-actions .btn { font-size: 0.66rem; padding: 0.85rem 1.2rem; letter-spacing: 0.12em; }
@media (max-width: 640px) {
  .iv-actions, .ai-actions { flex-direction: column; }
  .iv-actions .btn, .ai-actions .btn, .iv-actions a.btn { width: 100%; text-align: center; }
  .rv-tools { gap: 0.6rem; }
  .rv-tools .rv-status { margin-left: 0; }
  .rv-photos a { width: calc(33.33% - 0.4rem); height: auto; aspect-ratio: 1; }
}
.ai-note { display: block; font-size: 0.74rem; opacity: 0.6; margin-top: 0.7rem; }

/* photo step: one block per pair */
.pair-block { padding: 1rem 1rem 0.2rem; border: 1px solid var(--cream-faint); border-radius: 14px; margin-bottom: 1rem; }
.pair-block + .pair-block { margin-top: 1rem; }
.pair-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.8rem; }
.pair-head b { font-size: 0.95rem; }
.pair-hint { font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.45; }
.add-pair { margin: 0 0 1.2rem; }
/* a tile whose photo is still uploading */
.shot.busy .shot-box::after { content: ""; position: absolute; inset: auto 6px 6px auto; width: 10px; height: 10px;
  border-radius: 50%; border: 2px solid rgba(143,162,255,0.35); border-top-color: #8fa2ff; animation: shotSpin 0.8s linear infinite; }
@keyframes shotSpin { to { transform: rotate(360deg); } }

/* one-tap contact row on each booking */
.rv-contact { display: flex; gap: 0.5rem; flex-wrap: wrap; margin: 0 0 1rem; }
.rv-contact .rv-ct { font-size: 0.62rem; padding: 0.65rem 0.95rem; letter-spacing: 0.1em; display: inline-flex; align-items: center; gap: 0.45rem; }
.rv-contact .rv-ct.pref { border-color: var(--royal-soft); color: var(--royal-soft); }
.rv-contact .rv-ct i { font-style: normal; font-size: 0.55rem; opacity: 0.75; padding: 0.12rem 0.4rem; border-radius: 999px; background: rgba(143,162,255,0.15); }
.iv-pref-act { display: inline-block; margin-left: 0.5rem; color: var(--royal-soft); font-weight: 600; text-decoration: none; white-space: nowrap; }
.iv-pref-act:hover { text-decoration: underline; }
@media (max-width: 640px) {
  .rv-contact .rv-ct { flex: 1 1 auto; justify-content: center; }
}

/* service being invoiced, with the scan's recommendation beside it */
.iv-svc { display: flex; align-items: flex-end; gap: 0.8rem; flex-wrap: wrap; margin: 0 0 0.8rem; }
.iv-svc label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.7; }
.iv-svc select { padding: 0.55rem 0.7rem; border-radius: 8px; background: #101018; color: inherit; border: 1px solid rgba(241,233,219,0.25); font: inherit; font-size: 0.9rem; min-width: 14rem; }
.iv-svc .iv-use-ai { font-size: 0.62rem; padding: 0.7rem 1rem; border-color: rgba(255,190,60,0.5); color: #ffd98a; }
.iv-svc .iv-use-ai:disabled { opacity: 0.7; border-color: rgba(126,227,166,0.5); color: #7ee3a6; transform: none; }
/* The message box is now the only place this text is written, so it gets a
   label saying what it is and a quiet state that says whether it is saved. */
.iv-note-wrap { display: block; margin-top: 0.9rem; }
.iv-note-lbl {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.35rem;
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cream-dim);
}
.iv-note-state, .iv-total-state { font-style: normal; opacity: 0.75; letter-spacing: 0.1em; font-size: 0.9em; }
.iv-note-state:empty, .iv-total-state:empty { display: none; }
/* Agreed total is the only number here now, so its label carries the same
   saved state the message box does. */
.iv-row label { display: flex; align-items: center; gap: 0.45rem; flex-wrap: wrap; }
.iv-svc-note { font-size: 0.62rem; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.55; align-self: center; }
.iv-svc-note.ok { color: #7ee3a6; opacity: 0.9; }
@media (max-width: 640px) { .iv-svc select { width: 100%; } .iv-svc label { width: 100%; } .iv-svc .iv-use-ai { width: 100%; } }


/* Unfinished bookings: people who reached step 3 and stopped. A worklist for
   Reesey, not a dashboard - one line each, with the two ways to reach them. */
.dr-row { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem;
  flex-wrap: wrap; border: 1px solid var(--cream-faint); border-radius: 12px;
  padding: 0.7rem 0.9rem; margin-bottom: 0.55rem; }
.dr-who { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.dr-who b { font-size: 0.92rem; }
.dr-meta { font-size: 0.66rem; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.55; }
.dr-acts { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.dr-acts .btn { padding: 0.38rem 0.7rem; font-size: 0.74rem; }
@media (max-width: 640px) {
  .dr-row { align-items: stretch; }
  .dr-acts { width: 100%; }
  .dr-acts .btn { flex: 1; text-align: center; }
}

/* Booking form: the offer, the proof and the reassurance. Deliberately quiet -
   they sit beside the actual controls and must not compete with them. */
.bk-gift {
  border: 1px solid rgba(94, 120, 255, 0.4); border-left: 3px solid var(--royal-soft);
  border-radius: 12px; background: rgba(43, 75, 255, 0.08);
  padding: 0.75rem 0.95rem; margin: 0 0 0.9rem; font-size: 0.92rem;
}
.bk-proof {
  border: 1px solid var(--cream-faint); border-radius: 12px;
  padding: 0.8rem 0.95rem; margin: 0 0 1.4rem;
}
.bk-proof p { font-size: 0.88rem; color: var(--cream-dim); margin: 0.3rem 0 0.45rem; }
.bk-proof cite {
  font-family: var(--mono); font-style: normal; font-size: 0.66rem;
  letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.55;
}
.bk-stars { color: #ffd166; letter-spacing: 0.14em; font-size: 0.8rem; }
.page .bk-safe {
  border: 1px solid var(--cream-faint); border-radius: 12px;
  padding: 0.75rem 0.95rem; margin: 1rem 0 0.9rem;
  font-size: 0.9rem; color: var(--cream-dim);
}
.page .bk-safe b { color: var(--cream); }

/* Horizontal scrollers on the interior pages. Same rule and the same reason as
   the reviews carousel in styles.css: html/body are locked to pan-y, and a
   scroller that answers with pan-x ALONE makes a vertical swipe an unpermitted
   gesture, so the page freezes under the user's thumb. Both axes, never one. */
[data-hscroll] { touch-action: pan-x pan-y pinch-zoom; }

/* Rate picker in the invoice panel. Exactly one rate is selected at a time and
   the Buy button always buys that one, so the price she confirmed in the dialog
   is the price that gets charged. */
.iv-rate-pick { font-size: 0.74rem; padding: 0.4rem 0.7rem; }
.iv-rate-pick.on {
  border-color: var(--royal-soft);
  background: rgba(43, 75, 255, 0.16);
  color: var(--cream);
}

/* Mail-in vs drop-off, stated on the folded booking row. They are different
   jobs - one arrives in a box, the other is collected from a lock box - and the
   bag chip's location code reads like a collection point unless this says
   otherwise. Mail-in is the one that gets the loud colour because it is the
   exception and the one with a parcel in the post. */
.rv-pill.ho-mail { color: #8fa2ff; border-color: rgba(143,162,255,0.55); background: rgba(43,75,255,0.14); }
/* The meet-up is the one that needs something FROM HER before it can move: a
   message to agree a time. So it gets its own colour rather than sharing the
   quiet drop-off styling, which would let it sit unnoticed in a list. */
.rv-pill.ho-meet { color: #ffc46b; border-color: rgba(255,196,107,0.5); background: rgba(255,196,107,0.12); }
.rv-pill.ho-drop { color: var(--cream-dim); border-color: var(--cream-faint); }
.rv-bag.mail { border-color: rgba(143,162,255,0.45); }
.rv-bag.mail small { color: #8fa2ff; opacity: 0.9; }

/* One-tap free Lace Swap. The offer promised something buried in a collapsed
   dropdown, so the button does the finding. */
.bk-gift p { margin: 0; }
.bk-gift-add {
  margin-top: 0.7rem; cursor: pointer;
  background: var(--royal); color: #fff; border: 1px solid var(--royal);
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.14em;
  text-transform: uppercase; padding: 0.6rem 1.1rem; border-radius: 999px;
}
.bk-gift-add:hover { background: var(--royal-soft); border-color: var(--royal-soft); }
.bk-gift-add.on {
  background: transparent; color: #7ee3a6; border-color: rgba(126,227,166,0.55);
}
.bk-gift-add.on::before { content: "\2713  "; }
/* $20 struck through next to a ticked box, so nobody thinks they just agreed
   to pay for it. */
.opt-card.is-gift .op s { opacity: 0.5; margin-right: 0.35rem; }
.opt-card.is-gift .op { color: #7ee3a6; }

/* A gift checkbox that is NOT pre-ticked is saying something - that this person
   has had it before. Colour it so she reads the reason rather than the tick. */
.iv-check.warn { color: #ffd98a; }

/* The bag <select> sized itself to its LONGEST option - and the options carry
   holder names ("Bag 7 - Marcus Bell"), so it grew straight past the edge of
   the card. min-width:0 lets the flex item shrink below its content, which is
   the bit flexbox does not do by default. */
.do-row { min-width: 0; }
.do-row label { flex: 1 1 12rem; min-width: 0; max-width: 100%; }
.do-row select { max-width: 100%; width: 100%; text-overflow: ellipsis; }
.do-bag { background: var(--ink-2); color: var(--cream); border: 1px solid var(--cream-faint);
  border-radius: 10px; padding: 0.55rem 0.6rem; font: inherit; font-size: 0.85rem; }
.do-meta { overflow-wrap: anywhere; }

/* Collapsible sections inside a booking card. Every panel used to be open at
   once, so reading one booking meant scrolling past the scan, the invoice, the
   hand-off details and the finish steps whether or not any of them needed her
   (Jonah, 5 Sep). Each now opens only at the stage it is actually the next
   thing to do: the scan when it is not a clean accept, Quote & deposit until
   the deposit is paid, hand-off details once it is paid and not yet sent, and
   Finish the job until the balance is paid. */
details.sec > summary {
  cursor: pointer;
  list-style: none;
  position: relative;
  padding-right: 1.6rem;
}
details.sec > summary::-webkit-details-marker { display: none; }
/* One chevron, rotating - the same affordance the booking cards already use. */
details.sec > summary::after {
  content: "\25BE";
  position: absolute;
  right: 0.35rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.7rem;
  opacity: 0.5;
  transition: transform 0.18s ease;
}
details.sec[open] > summary::after { transform: translateY(-50%) rotate(180deg); }
details.sec > summary:hover::after { opacity: 0.9; }
/* A closed section should not keep the bottom padding of an open one. */
details.sec:not([open]) { padding-bottom: 0.75rem; }
details.sec > summary:focus-visible { outline: 2px solid var(--royal-soft); outline-offset: 3px; border-radius: 8px; }
@media (prefers-reduced-motion: reduce) {
  details.sec > summary::after { transition: none; }
}


/* ---- The Wall ----
   A gallery someone browses looking for their own shoe, so the controls sit
   above the fold and the grid does the rest. Cards flip on tap; there is no
   drag handle per card, because seventeen of those on one page fight the
   page scroll and a tap is what people already try on a photo. */
.wl-tools { display: flex; flex-direction: column; gap: 0.9rem; margin: 0 0 1.8rem; }
.wl-search input {
  width: 100%; padding: 0.85rem 1rem; border-radius: 12px; font: inherit;
  color: var(--cream); background: var(--ink-2);
  border: 1px solid var(--cream-faint);
}
.wl-search input:focus-visible { outline: 2px solid var(--royal); outline-offset: 2px; }
.wl-search input::placeholder { color: var(--cream-dim); }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.wl-chips { display: flex; flex-wrap: wrap; gap: 0.45rem; }
.wl-chip {
  display: inline-flex; align-items: center; gap: 0.4rem;
  background: transparent; color: var(--cream); font: inherit;
  font-size: 0.74rem; letter-spacing: 0.08em; text-transform: uppercase;
  border: 1px solid var(--cream-faint); border-radius: 999px;
  padding: 0.62rem 0.9rem; cursor: pointer; min-height: 42px;
}
.wl-chip i { font-style: normal; opacity: 0.45; font-size: 0.9em; }
.wl-chip:hover { border-color: var(--royal-soft); }
.wl-chip.on { background: var(--royal); border-color: var(--royal); color: #fff; }
.wl-chip.on i { opacity: 0.75; }
.wl-count { font-size: 0.74rem; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.45; margin: 0; }

.wl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  gap: 0.7rem; }
@media (min-width: 40rem) {
  .wl-grid { grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: 1rem; }
}
.wl-card {
  display: block; width: 100%; text-align: left; padding: 0; cursor: pointer;
  background: transparent; border: 0; color: inherit; font: inherit;
}
.wl-shot {
  position: relative; display: block; aspect-ratio: 1; border-radius: 12px;
  overflow: hidden; background: #fff; border: 1px solid var(--cream-faint);
}
.wl-shot img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; background: #fff;
  transition: opacity 0.28s ease;
}
.wl-shot.cover img { object-fit: cover; }
/* After on top by default; flipping the card fades it out to reveal the before
   underneath, which is already stacked in the same box so nothing reflows. */
.wl-before { opacity: 0; }
.wl-card[aria-pressed="true"] .wl-after { opacity: 0; }
.wl-card[aria-pressed="true"] .wl-before { opacity: 1; }
.wl-state {
  position: absolute; left: 0.6rem; bottom: 0.6rem; z-index: 2;
  font-size: 0.62rem; letter-spacing: 0.14em; text-transform: uppercase;
  background: rgba(6, 6, 8, 0.72); color: var(--cream);
  padding: 0.25rem 0.55rem; border-radius: 999px;
}
.wl-card:focus-visible .wl-shot { outline: 2px solid var(--royal); outline-offset: 3px; }
.wl-card:hover .wl-shot { border-color: var(--royal-soft); }
.wl-meta { display: block; padding: 0.6rem 0.15rem 0; }
.wl-label { display: block; font-size: 0.82rem; line-height: 1.3; }
@media (min-width: 40rem) { .wl-label { font-size: 0.92rem; } }
.wl-brand { display: block; font-size: 0.68rem; letter-spacing: 0.1em;
  text-transform: uppercase; opacity: 0.45; margin-top: 0.1rem; }
.wl-empty, .wl-msg { opacity: 0.6; text-align: center; padding: 2rem 0; }
@media (prefers-reduced-motion: reduce) { .wl-shot img { transition: none; } }


/* ---- Reesey Custom: the work itself ----
   The wide in-progress shot leads, because "she paints these by hand" is the
   claim and that photo is the evidence. The two finished shots sit under it as
   a pair, side by side where there is room and stacked where there is not. */
.cu-fig { margin: 0; }
.cu-fig img {
  display: block; width: 100%; height: auto;
  border-radius: 14px; border: 1px solid var(--cream-faint); background: #fff;
}
.cu-fig figcaption {
  font-size: 0.78rem; letter-spacing: 0.02em; color: var(--cream-dim);
  margin-top: 0.55rem;
}
.cu-wide { margin-bottom: 1rem; }
.cu-pair { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 46rem) { .cu-pair { grid-template-columns: 1fr 1fr; } }
.cu-note { font-size: 0.88rem; color: var(--cream-dim); margin: 1.1rem 0 0; max-width: 42ch; }

/* Two buttons in a row need a real gap, not the whitespace between two
   inline-blocks - at narrow widths they were almost touching. */
.btn-row {
  display: flex; flex-wrap: wrap; gap: 0.85rem;
  align-items: center; justify-content: center;
}
@media (max-width: 26rem) {
  .btn-row { flex-direction: column; align-items: stretch; }
  .btn-row .btn { width: 100%; text-align: center; }
}


/* Specialty names as chips rather than a sentence with seven prices in it.
   The prices live one click away on /services/specialty/, which is the only
   place they should have to be kept up to date. */
.spec-tags { list-style: none; display: flex; flex-wrap: wrap; gap: 0.45rem;
  margin: 0 0 1.4rem; padding: 0; }
.spec-tags li {
  font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase;
  border: 1px solid var(--cream-faint); border-radius: 999px;
  padding: 0.42rem 0.85rem; color: var(--cream-dim);
}


/* ---- The handover: client videos ----
   All five are portrait phone clips, so the cards are portrait too rather than
   letterboxed into a 16:9 box. A snap row on a phone - which is the shape these
   were shot in and the device most people will watch them on - and a grid once
   there is width for one.

   preload="none" with a poster on every clip: five videos is 16MB, and nobody
   should pay for that on a phone plan before tapping one. Nothing autoplays;
   these have sound and audio that starts by itself is the reason people leave. */
.vr-lede { margin-bottom: 1.3rem; }
.vr-row {
  display: grid; grid-auto-flow: column; grid-auto-columns: 15rem;
  gap: 0.8rem; overflow-x: auto; padding-bottom: 0.8rem;
  scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
}
.vr-card { margin: 0; scroll-snap-align: start; }
.vr-vid {
  display: block; width: 100%; height: auto; aspect-ratio: 404 / 720;
  background: #101018; border-radius: 14px;
  border: 1px solid var(--cream-faint);
}
.vr-card figcaption {
  font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase;
  opacity: 0.4; margin-top: 0.4rem;
}
/* Stays a horizontal slider at every width. It used to wrap into a grid on
   desktop, but these sit at the top of the page now and one scrolling row of
   handovers reads as a reel, where a wrapped block of five reads as a wall. */
@media (min-width: 52rem) {
  .vr-row { grid-auto-columns: 17rem; gap: 1rem; }
}

/* ---------- in-app assistant (Instagram, Facebook, TikTok) ---------- */
/* Only ever rendered by ask-reesey-inapp.js, which runs solely in WebViews
   that refuse a microphone. Everywhere else the ElevenLabs widget is used and
   none of this exists. Sized and placed to clear the .bookbar, same as the
   widget does. */
.ir-root { position: fixed; inset: auto 0 0 0; z-index: 58; pointer-events: none; }
.ir-root > * { pointer-events: auto; }

.ir-fab {
  position: fixed; right: 14px;
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  display: inline-flex; align-items: center; gap: 8px;
  padding: 11px 16px; border: 0; border-radius: 999px;
  background: var(--blue, #2b4bff); color: #fff;
  font-family: var(--mono); font-size: 0.74rem; letter-spacing: 0.06em;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.45); cursor: pointer;
}
.ir-orb {
  width: 16px; height: 16px; border-radius: 50%;
  background: radial-gradient(circle at 32% 30%, #f1e9db, #2b4bff 70%);
}

/* An author `display` rule BEATS the hidden attribute, so `.ir-panel` setting
   display:flex meant hidden did nothing at all: the panel was visible from
   page load and the close button could not shut it. The attribute selector is
   more specific than the class, so this is what actually hides it. Any future
   element here that toggles `hidden` needs the same guard. */
.ir-panel[hidden] { display: none !important; }

/* The button and the panel are the same control in two states, so only one is
   ever on screen. */
.ir-root.ir-open .ir-fab { display: none; }

.ir-panel {
  position: fixed; left: 10px; right: 10px;
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  display: flex; flex-direction: column; max-height: 56vh;
  background: #0d0d12; color: var(--cream, #f1e9db);
  border: 1px solid rgba(241, 233, 219, 0.16); border-radius: 14px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.6); overflow: hidden;
}
.ir-head {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border-bottom: 1px solid rgba(241, 233, 219, 0.12);
}
.ir-title {
  flex: 1; font-family: var(--mono); font-size: 0.64rem;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: rgba(241, 233, 219, 0.66);
}
.ir-title b { color: var(--cream, #f1e9db); font-weight: 600; }
.ir-icon {
  background: none; border: 0; cursor: pointer;
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: rgba(241, 233, 219, 0.62); padding: 4px 6px;
}

.ir-log { flex: 1; overflow-y: auto; padding: 10px 12px; display: flex; flex-direction: column; gap: 7px; }
.ir-msg {
  max-width: 86%; padding: 9px 12px; border-radius: 12px;
  font-size: 0.86rem; line-height: 1.45; white-space: pre-wrap;
}
.ir-you { align-self: flex-end; background: var(--blue, #2b4bff); color: #fff; border-bottom-right-radius: 4px; }
.ir-her { align-self: flex-start; background: #17171f; border-bottom-left-radius: 4px; }

.ir-form { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid rgba(241, 233, 219, 0.12); }
.ir-input {
  flex: 1; min-width: 0; padding: 10px 12px; border-radius: 999px;
  border: 1px solid rgba(241, 233, 219, 0.2); background: #17171f;
  color: var(--cream, #f1e9db); font-size: 16px; /* 16px stops iOS zooming on focus */
}
.ir-send {
  border: 0; border-radius: 999px; padding: 0 16px; cursor: pointer;
  background: var(--blue, #2b4bff); color: #fff;
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.08em;
}
.ir-send:disabled { opacity: 0.5; }

.ir-foot {
  margin: 0; padding: 0 12px 9px;
  font-size: 0.6rem; line-height: 1.35; color: rgba(241, 233, 219, 0.45);
}

/* The voice state, said as a state rather than as a verb. "Mute" only means
   something to somebody who already knows sound is coming; "Voice on" tells
   the person who has not pressed anything yet that she is going to talk. */
.ir-voice { color: var(--blue, #2b4bff) !important; }
.ir-voice::before {
  content: ""; display: inline-block; width: 6px; height: 6px;
  margin-right: 5px; border-radius: 50%; background: currentColor;
  vertical-align: middle;
}

/* Her bubble moves while the audio plays. This is the signal that does the
   most work: somebody who SEES it understands she is talking without reading
   a word about it, which is the difference between "a chatbot replied" and
   "she just spoke to me". */
.ir-speaking { position: relative; padding-bottom: 18px; }
.ir-speaking::after {
  content: ""; position: absolute; left: 12px; bottom: 7px;
  width: 22px; height: 9px;
  background:
    linear-gradient(var(--blue, #2b4bff) 0 0) 0    50% / 3px 40% no-repeat,
    linear-gradient(var(--blue, #2b4bff) 0 0) 50%  50% / 3px 100% no-repeat,
    linear-gradient(var(--blue, #2b4bff) 0 0) 100% 50% / 3px 65% no-repeat;
  animation: ir-eq 0.85s ease-in-out infinite;
}
@keyframes ir-eq {
  0%, 100% { background-size: 3px 40%, 3px 100%, 3px 65%; }
  33%      { background-size: 3px 100%, 3px 45%, 3px 90%; }
  66%      { background-size: 3px 60%, 3px 85%, 3px 35%; }
}
@media (prefers-reduced-motion: reduce) {
  .ir-speaking::after { animation: none; }
}
