:root {
  --bg: oklch(15% 0.02 265);
  --bg-raised: oklch(20% 0.025 265);
  --bg-raised-2: oklch(25% 0.03 265);
  --bg-sunken: oklch(18% 0.02 265);
  --bg-deep: oklch(14% 0.015 265);
  --border: oklch(33% 0.03 265);
  --border-track: oklch(30% 0.02 265);
  --text: oklch(96% 0.006 265);
  --text-dim: oklch(71% 0.02 265);
  --text-mid: oklch(85% 0.015 265);
  --text-soft: oklch(88% 0.01 265);
  --accent: oklch(54% 0.18 258);
  --accent-bright: oklch(72% 0.14 252);
  --accent-line: oklch(48% 0.13 258);
  --accent-tint: oklch(60% 0.17 255);
  --focus: oklch(76% 0.13 252);
  --warn: oklch(84% 0.13 90);
  --danger: oklch(64% 0.19 22);
  --danger-strong: oklch(50% 0.17 22);
  --success: oklch(72% 0.17 150);
  --on-accent: oklch(99% 0.005 258);
  --on-warn: oklch(16% 0.04 265);
  --weekend-bg: oklch(25% 0.06 20);
  --weekend-border: oklch(48% 0.13 22);
  --weekend-text: oklch(83% 0.1 25);
  --radius: 12px;
  --radius-sm: 8px;
  --max-width: 1080px;
  color-scheme: dark;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: "Public Sans", system-ui, -apple-system, Roboto, sans-serif;
  line-height: 1.55;
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

h1, h2, h3 { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: -0.025em; line-height: 1.15; margin: 0; }

a { color: var(--accent-bright); }
a:hover { color: oklch(81% 0.12 252); }

input:focus-visible, button:focus-visible, a:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--accent);
  color: var(--on-accent);
  padding: 0.75rem 1rem;
  z-index: 100;
  font-weight: 700;
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus { left: 0; }

/* ---------- Header ---------- */
.site-header {
  border-bottom: 1px solid var(--border);
  background: oklch(20% 0.025 265);
  position: sticky;
  top: 0;
  z-index: 10;
}
.site-header__inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0.9rem 1.5rem;
  display: flex;
  align-items: center;
  gap: 2rem;
  flex-wrap: wrap;
}
.brand {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  text-decoration: none;
  color: var(--text);
  cursor: pointer;
}
/* The mark is the white asset on the header's own background (issue #246), not
   the black one on a white disc. The disc existed only to make a black-on-white
   asset legible here, and it made the logo the single brightest object on an
   otherwise dark page. `contain` rather than `cover` because there is no longer
   a circle to fill and the transparent artwork carries its own margin. */
.brand__mark {
  display: inline-grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  overflow: hidden;
  flex-shrink: 0;
}
.brand__mark img { width: 100%; height: 100%; object-fit: contain; }
.brand__text { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.brand__name {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
/* Static purpose statement baked into the chrome for Google's OAuth crawler
   (it doesn't run JS, so it never sees the app's JS-rendered content). Kept
   deliberately small and quiet — it reads as a brand tagline, not a banner. */
.brand__tagline { font-size: 0.72rem; font-weight: 500; color: var(--text-dim); letter-spacing: 0; line-height: 1.2; }
@media (max-width: 480px) { .brand__tagline { display: none; } }
.primary-nav { display: flex; gap: 1.5rem; flex: 1; }
.primary-nav a {
  text-decoration: none;
  font-weight: 600;
  padding: 0.35rem 0.1rem;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  color: var(--text-dim);
}
.primary-nav a[aria-current="page"] { color: var(--text); border-bottom-color: var(--accent); }

.header-actions { display: flex; align-items: center; gap: 0.75rem; }
.avatar {
  display: inline-grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
  font-size: 0.75rem;
  text-decoration: none;
  flex-shrink: 0;
  object-fit: cover;
}
.avatar-lg { width: 3.2rem; height: 3.2rem; font-size: 1.1rem; }
/* No picture, and nothing that can honestly make two initials (#314). Muted
   rather than accent-filled: an avatar that cannot say who you are should not
   compete for attention with one that can, and the flat accent circle made an
   unknown account look as confident as a known one. */
.avatar--anon { background: var(--bg-raised-2); color: var(--text-dim); }
/* The credit mark. Icon-only: it says THAT there is credit and hands the
   client to the place that says how much. Round rather than a lozenge, because
   with no text a pill shape is just a stretched circle. */
.credit-pill {
  background: var(--bg-raised-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--accent-bright);
  text-decoration: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex: 0 0 auto;
  transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}
.credit-pill:hover { color: var(--accent); border-color: var(--accent-line); background: var(--bg-raised); }
.credit-pill__icon { display: block; }

/* The credit note at the top of booking step 1 (#11). Accent-tinted rather
   than a warning colour: this is the good kind of interruption, and it is the
   landing point for the header mark, so it carries the same spark. */
.book-credit {
  display: flex;
  gap: 0.7rem;
  align-items: flex-start;
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-sm);
  background: var(--bg-raised-2);
  padding: 0.85rem 1rem;
  margin: 0 0 1.1rem;
}
.book-credit__mark { color: var(--accent-bright); line-height: 0; padding-top: 0.1rem; flex: 0 0 auto; }
.book-credit__body { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.book-credit__title { margin: 0; font-weight: 700; font-size: 0.95rem; }
.book-credit__line { margin: 0; font-size: 0.85rem; color: var(--text-mid); }

/* ---------- Buttons ---------- */
.btn[hidden] { display: none; }
.btn {
  display: inline-block;
  border-radius: var(--radius-sm);
  padding: 0.65rem 1.2rem;
  font-weight: 700;
  font-size: 0.92rem;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  font-family: inherit;
}
.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: var(--accent-bright); }
.btn-secondary { background: transparent; color: var(--text); border-color: var(--accent-line); }
.btn-secondary:hover { border-color: var(--accent-bright); color: var(--accent-bright); }
.btn-plain { background: transparent; color: var(--text); border-color: var(--border); }
.btn-plain:hover { border-color: var(--accent-bright); }
.btn-outline-sso { background: var(--bg-raised-2); color: var(--text); border-color: var(--border); }
.btn-danger { background: var(--danger); color: #fff; border-color: var(--danger); }
.btn-danger:hover { background: var(--danger-strong); border-color: var(--danger-strong); }
.btn-link {
  background: transparent;
  border: none;
  padding: 0;
  color: var(--accent-bright);
  font-weight: 700;
  font-size: 0.85rem;
  cursor: pointer;
  font-family: inherit;
}
/* aria-disabled gets the same look as :disabled. A control that must stay
   FOCUSABLE while it is busy — the availability retry, which lives inside a
   modal focus trap (#523) — cannot use the real attribute, so the two have to
   be styled together or one of them silently looks live while it is not. */
.btn:disabled,
.btn[aria-disabled="true"] { background: oklch(28% 0.02 265); color: oklch(55% 0.02 265); cursor: not-allowed; border-color: transparent; }
.btn-block { display: block; width: 100%; text-align: center; }
.btn-sm { padding: 0.4rem 0.8rem; font-size: 0.82rem; }

/* ---------- Layout ---------- */
.app-main { max-width: var(--max-width); margin: 0 auto; padding: 2rem 1.5rem 4.5rem; min-height: 60vh; }
/* #main is focused programmatically on every load/navigation (for scroll reset
   and as the skip-link landmark), so it must not paint a focus ring around the
   whole content area. Interactive controls keep the global :focus-visible ring. */
.app-main:focus, .app-main:focus-visible { outline: none; }
/* Human-facing fine print at the foot of the home page: the fuller "what this
   app is" blurb, kept small and quiet so it stays out of the way. */
.home-fineprint { max-width: 60ch; margin: 2.5rem auto 0; font-size: 0.78rem; line-height: 1.5; color: var(--text-dim); text-align: center; }
.site-footer { border-top: 1px solid var(--border); color: var(--text-dim); font-size: 0.85rem; padding: 1.5rem; text-align: center; }
.site-footer img { height: 1.6rem; width: auto; opacity: 0.85; }
.site-footer__inner { display: flex; flex-direction: column; align-items: center; gap: 0.7rem; max-width: 60ch; margin: 0 auto; }
.site-footer__nav { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.35rem 1.1rem; }
.site-footer__nav a { color: var(--text-dim); text-decoration: underline; text-underline-offset: 2px; }
.site-footer__nav a:hover { color: var(--accent-bright); }
/* Social profile links (#284). Icon-only, so the tap target is sized rather
   than left to the 20px glyph: 44px is the minimum the rest of the site holds
   to, and an icon row in a footer is exactly where a thumb misses. */
.site-footer__social { display: flex; justify-content: center; gap: 0.25rem; }
.site-footer__social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 50%;
  color: var(--text-dim); transition: color 120ms ease, background-color 120ms ease;
}
.site-footer__social a:hover { color: var(--accent-bright); background: rgb(255 255 255 / 0.06); }
.site-footer__social svg { display: block; }

.site-footer__legal { margin: 0; opacity: 0.75; }

.view-header { margin-bottom: 1.75rem; }
.view-header h1 { font-size: 2rem; margin-bottom: 0.35rem; }
.view-header p { color: var(--text-dim); max-width: 60ch; margin: 0; }

.section-title { font-size: 1.7rem; margin: 0 0 0.3rem; }
.section-sub { color: var(--text-dim); max-width: 60ch; margin: 0 0 1.25rem; }

.card {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
}

.two-col { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 1.5rem; }
.two-col-wide { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 1.25rem; align-items: start; }
@media (max-width: 720px) {
  .two-col, .two-col-wide { grid-template-columns: 1fr; }
}

/* ---------- Forms ---------- */
.field { margin-bottom: 1.1rem; }
.field label { display: block; font-weight: 600; margin-bottom: 0.35rem; font-size: 0.92rem; }
.field .hint { font-size: 0.8rem; color: var(--text-dim); margin-top: 0.3rem; }
.field input[type="text"], .field input[type="email"], .field input[type="number"],
.field input[type="password"], .field textarea {
  width: 100%;
  padding: 0.6rem 0.7rem;
  background: var(--bg-raised-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 0.95rem;
  font-family: inherit;
}
.field textarea { resize: vertical; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.field-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1rem; }
@media (max-width: 720px) {
  .field-row, .field-row-3 { grid-template-columns: 1fr; }
}
fieldset { border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem; margin: 0 0 1.25rem; }
legend { font-weight: 700; padding: 0 0.4rem; }
.checkbox-row { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.3rem; }
.checkbox-row input { width: auto; }
.checkbox-row label { margin: 0; font-weight: 500; }

input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 6px; border-radius: 999px;
  background: var(--border-track); outline: none;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--accent-tint); border: 3px solid oklch(15% 0.02 265);
  cursor: pointer; box-shadow: 0 0 0 1px var(--border-track);
}
input[type="range"]::-moz-range-thumb {
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--accent-tint); border: 3px solid oklch(15% 0.02 265); cursor: pointer;
}
input[type="range"]::-moz-range-track { height: 6px; border-radius: 999px; background: var(--border-track); }

/* ---------- Hero ---------- */
/* The signed-out homepage now ships as real markup in index.html, generated
   from the catalog by tools/build.mjs (issue #123). Most visitors are signed
   out, so they get the page on the first byte and nothing here applies.

   A returning client or staff member gets the signed-in shell from JS instead.
   The inline classifier in <head> stamps data-audience before first paint, so
   they never see a flash of the guest hero. `pre-hydrate` is dropped by
   js/app.js after its first render: without it, this rule would still be live
   after a client signed out and would hide the guest page from them.

   With JavaScript off the classifier never runs, data-audience stays "guest",
   and the static page shows. */
html.pre-hydrate[data-audience="client"] #app > *,
html.pre-hydrate[data-audience="staff"] #app > * {
  display: none;
}

/* The no-JS fallback. Booking needs a live session and availability, so there
   is no honest way to offer a form here: this offers a human instead. */
.noscript-fallback {
  border: 1px solid var(--border);
  border-left: 5px solid var(--accent);
  border-radius: 14px;
  padding: 1.5rem;
  margin-bottom: 2.5rem;
  background: linear-gradient(135deg, oklch(22% 0.05 262), oklch(17% 0.03 265) 60%);
}
.noscript-fallback h2 { margin: 0 0 0.5rem; font-size: 1.4rem; }
.noscript-fallback p { margin: 0 0 1rem; color: var(--text-dim); max-width: 60ch; }
.noscript-fallback__links {
  list-style: none; margin: 0 0 1rem; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.6rem;
}
.noscript-fallback__address { margin: 0; font-size: 0.92rem; }

/* A band, not a billboard. This used to be 7rem of padding and a 3.1rem
   headline, which pushed the first bookable thing off the fold on a phone —
   and a visitor who came to book studio time is here for the price card, not
   for the photo. It is kept, small, because it is the only place that says
   what this studio is; the "Book a session" button it used to carry is gone,
   since the hourly card's own button is now directly underneath it. */
.hero-guest {
  position: relative; border-radius: 14px; overflow: hidden;
  display: flex; flex-direction: column; gap: 0.5rem;
  padding: 1.75rem 1.5rem; margin-bottom: 1.75rem;
  border: 1px solid var(--border);
  background-image: linear-gradient(180deg, oklch(15% 0.03 265 / 0.55), oklch(15% 0.03 265 / 0.95)), url("../images/band-live-session.webp");
  background-size: cover; background-position: center 35%;
}
.hero-guest__eyebrow { color: var(--accent-bright); font-weight: 700; margin: 0; letter-spacing: 0.02em; text-transform: uppercase; font-size: 0.78rem; }
.hero-guest h1 { font-size: clamp(1.6rem, 5vw, 2.1rem); max-width: 20ch; margin: 0; }
.hero-guest p.lede { max-width: 52ch; color: var(--text-dim); font-size: 0.95rem; margin: 0; }

.hero-authed {
  position: relative; border-radius: 14px; overflow: hidden; padding: 2rem; margin-bottom: 2rem;
  border: 1px solid oklch(40% 0.08 258); border-left: 5px solid var(--accent);
  background: linear-gradient(135deg, oklch(22% 0.05 262), oklch(17% 0.03 265) 60%);
}
.hero-authed__grid { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); gap: 1.75rem; align-items: start; }
@media (max-width: 720px) { .hero-authed__grid { grid-template-columns: 1fr; } }
.hero-authed__eyebrow {
  display: inline-flex; align-items: center; gap: 0.5rem;
  background: var(--accent); color: var(--on-accent); border-radius: 999px;
  padding: 0.3rem 0.85rem; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em;
}
.hero-authed h1 { font-size: 2.4rem; max-width: 18ch; margin: 0.85rem 0 0.5rem; }
/* The staff hero has no headline: the pill and the buttons already say what the
   screen is (issue #250). The eyebrow carries the h1 instead, so the page keeps
   exactly one heading rather than none. These override .hero-authed h1 above. */
.hero-authed h1.hero-authed__eyebrow--heading {
  font-size: 0.72rem;
  max-width: none;
  margin: 0 0 0.85rem;
}
.hero-authed p.lede { max-width: 46ch; color: var(--text-mid); font-size: 1.02rem; margin: 0 0 0.85rem; }
.hero-authed__actions { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.hero-authed__stats { display: flex; flex-direction: column; gap: 0.6rem; }
.hero-stat-tile { background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius); padding: 0.85rem 1.1rem; display: flex; flex-direction: column; gap: 0.3rem; }
.hero-stat-tile--session { border-color: var(--accent); }
.hero-stat-tile--credit { background: var(--accent-bright); color: var(--on-warn); border: none; }
.hero-stat-tile .tile-label { font-size: 0.64rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--accent-bright); }
.hero-stat-tile--credit .tile-label { color: var(--on-warn); }
.hero-stat-tile .tile-value { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 1.5rem; font-weight: 700; letter-spacing: -0.025em; line-height: 1.1; }
.hero-stat-tile--credit .tile-value { font-size: 2.4rem; letter-spacing: -0.03em; line-height: 1; margin: 0; }
.hero-stat-tile .tile-detail { font-size: 0.85rem; color: var(--text-mid); }
.hero-stat-row { display: flex; align-items: baseline; gap: 0.5rem; min-width: 0; }
.hero-stat-row .num { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 2rem; font-weight: 700; letter-spacing: -0.03em; color: var(--accent-bright); white-space: nowrap; flex-shrink: 0; }
.hero-stat-row .label { font-size: 0.88rem; color: var(--text-mid); font-weight: 600; min-width: 0; }
.status-badge {
  font-size: 0.64rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  border-radius: 999px; padding: 0.15rem 0.5rem; white-space: nowrap; align-self: flex-start;
  border: 1px solid currentColor;
}
.hero-empty {
  background: var(--bg-raised); border: 1px dashed oklch(40% 0.04 265); border-radius: var(--radius);
  padding: 1.1rem 1.25rem; color: var(--text-mid); font-size: 0.9rem; margin: 0;
}

.checklist { list-style: none; margin: 0 0 1.25rem; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; font-size: 0.92rem; color: var(--text-dim); }
.checklist li { padding-left: 1.4rem; position: relative; }
.checklist li::before { content: "\2713"; position: absolute; left: 0; color: var(--accent-bright); font-weight: 700; }
.checklist strong { color: var(--text); }

/* The fine print inside a purchase card: add-ons and what overage costs.
   Small and dim, but never behind a click — it answers "what does this cost me
   if I run long", which is the question that otherwise becomes an email. */
.buy-card .fine-print { border-top: 1px dashed var(--border); padding-top: 0.6rem; margin-top: 0.6rem; display: flex; flex-direction: column; gap: 0.35rem; }
.buy-card .fine-print p { font-size: 0.8rem; color: var(--text-dim); margin: 0; }
.buy-card .fine-print strong { color: var(--text); }

/* ---------- Rooms tabs ----------
   One room at a time: a strip of tabs, then that room's photo with its
   description right underneath. Switching is pure CSS on a checked radio, so
   the statically built index.html tabs before any JavaScript loads. The
   :nth-of-type pairs are written out to four rooms; add another pair here if
   GALLERY_ROOMS ever grows past that. */
.pull-quote { margin: 0 0 1.25rem; padding: 0 0 0 1rem; border-left: 3px solid var(--accent); font-size: 1.05rem; font-style: italic; max-width: 58ch; }
/* Off-screen, not display:none — the radios stay keyboard-reachable, which is
   what makes arrow keys move between tabs for free. */
.room-tabs__radio { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.room-tabs__strip { display: flex; gap: 0.25rem; overflow-x: auto; border-bottom: 1px solid var(--border); margin-bottom: 1rem; }
.room-tabs__tab {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.7rem 1rem;
  white-space: nowrap;
  cursor: pointer;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--text-dim);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.room-tabs__tab:hover { color: var(--text); }
.room-tabs__panel { display: none; }
.room-tabs__panel img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-raised-2); }
/* The description sits directly under the photo; the room is already named by
   its own tab, so there is no heading in between. */
.room-tabs__panel p { font-size: 0.92rem; color: var(--text-dim); margin: 0.75rem 0 0; max-width: 62ch; }

.room-tabs__radio:nth-of-type(1):checked ~ .room-tabs__strip .room-tabs__tab:nth-of-type(1),
.room-tabs__radio:nth-of-type(2):checked ~ .room-tabs__strip .room-tabs__tab:nth-of-type(2),
.room-tabs__radio:nth-of-type(3):checked ~ .room-tabs__strip .room-tabs__tab:nth-of-type(3),
.room-tabs__radio:nth-of-type(4):checked ~ .room-tabs__strip .room-tabs__tab:nth-of-type(4) {
  color: var(--text);
  border-bottom-color: var(--accent);
}
.room-tabs__radio:nth-of-type(1):focus-visible ~ .room-tabs__strip .room-tabs__tab:nth-of-type(1),
.room-tabs__radio:nth-of-type(2):focus-visible ~ .room-tabs__strip .room-tabs__tab:nth-of-type(2),
.room-tabs__radio:nth-of-type(3):focus-visible ~ .room-tabs__strip .room-tabs__tab:nth-of-type(3),
.room-tabs__radio:nth-of-type(4):focus-visible ~ .room-tabs__strip .room-tabs__tab:nth-of-type(4) {
  outline: 2px solid var(--accent-bright);
  outline-offset: -2px;
}
.room-tabs__radio:nth-of-type(1):checked ~ .room-tabs__panels .room-tabs__panel:nth-of-type(1),
.room-tabs__radio:nth-of-type(2):checked ~ .room-tabs__panels .room-tabs__panel:nth-of-type(2),
.room-tabs__radio:nth-of-type(3):checked ~ .room-tabs__panels .room-tabs__panel:nth-of-type(3),
.room-tabs__radio:nth-of-type(4):checked ~ .room-tabs__panels .room-tabs__panel:nth-of-type(4) {
  display: block;
}

.gear-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem; }
.gear-list li { padding: 0.75rem 1rem; background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: 0.92rem; color: var(--text-dim); }

.callout-banner { border-radius: var(--radius); padding: 1.1rem 1.25rem; border: 1px solid var(--border); background: var(--bg-raised-2); }
.callout-banner strong { display: block; margin: 0 0 0.35rem; font-size: 1rem; }

/* ---------- Notice banner (checkout / project) ---------- */
.notice-banner {
  position: relative; border-radius: var(--radius); padding: 1.1rem 2.5rem 1.1rem 1.25rem; margin-bottom: 1.5rem;
  border: 1px solid var(--accent-bright); background: oklch(60% 0.17 255 / 0.12);
}
.notice-banner strong { display: block; margin: 0 0 0.35rem; font-size: 1.05rem; }
.notice-banner p { margin: 0; }
.notice-dismiss { position: absolute; top: 0.6rem; right: 0.7rem; background: transparent; border: none; color: var(--text); font-size: 1.1rem; cursor: pointer; line-height: 1; padding: 0.2rem; }

/* ---------- Booking ---------- */
/* The book view is single-column and full-width: the slot picker is the
   width-hungry element, so it gets the whole content column, while the length
   control and the confirm/summary block are capped for comfortable reading. */
.book-length { max-width: 620px; margin-bottom: 1.5rem; }
.book-confirm { max-width: 480px; }
.book-hours-display { text-align: center; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-weight: 700; letter-spacing: -0.025em; font-size: 2.4rem; color: var(--accent-bright); margin-bottom: 0.6rem; }
.book-hours-range { display: flex; justify-content: space-between; font-size: 0.75rem; color: var(--text-dim); margin-top: 0.4rem; }
.day-nav { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin-bottom: 0.6rem; }
.day-nav__label { font-size: 0.85rem; font-weight: 600; color: var(--text-mid); }
.day-nav-btn { background: var(--bg-raised-2); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius-sm); width: 2.5rem; height: 2.5rem; font-size: 1.2rem; line-height: 1; cursor: pointer; font-family: inherit; flex-shrink: 0; }
.day-nav-btn:disabled { color: oklch(45% 0.02 265); cursor: not-allowed; }
/* On screens too narrow for all columns, scroll horizontally rather than
   crushing each day to an unreadable sliver. The fieldset wrapper needs
   min-width:0 — fieldsets default to min-width:min-content, which would
   otherwise let the grid's intrinsic width push the whole page wider than
   the viewport instead of scrolling inside this box. */
#book-form fieldset { min-width: 0; }
.day-grid-scroll { overflow-x: auto; padding-bottom: 0.25rem; }
.day-grid { display: grid; grid-template-columns: repeat(5, minmax(132px, 1fr)); gap: 0.5rem; min-width: 0; }
.day-col { border: 1px solid var(--border); border-radius: 10px; padding: 0.6rem 0.5rem; background: var(--bg-raised); display: flex; flex-direction: column; gap: 0.4rem; min-width: 0; }
.day-col--weekend { border-color: var(--weekend-border); background: var(--weekend-bg); }
.day-col__head { text-align: center; padding-bottom: 0.5rem; margin-bottom: 0.1rem; border-bottom: 1px solid var(--border); }
.day-col--weekend .day-col__head { border-bottom-color: var(--weekend-border); }
.day-col__dow { display: block; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700; color: var(--text-dim); }
.day-col--weekend .day-col__dow { color: var(--accent-bright); }
.day-col__num { display: block; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-weight: 700; letter-spacing: -0.025em; font-size: 1.5rem; line-height: 1.1; color: var(--text); }
.day-col--weekend .day-col__num { color: var(--weekend-text); }
.day-col .no-slots { font-size: 0.72rem; color: var(--text-dim); margin: 0; text-align: center; }
.slot-list { display: flex; flex-direction: column; gap: 0.35rem; }
.slot input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.slot label {
  display: flex; flex-direction: column; align-items: center; gap: 0.15rem;
  padding: 0.4rem 0.35rem; border: 1px solid var(--border); border-radius: 6px; cursor: pointer;
  font-size: 0.8rem; text-align: center; background: var(--bg); min-height: 44px; justify-content: center;
}
.slot input:checked + label { border-color: var(--accent); background: oklch(60% 0.17 255 / 0.26); color: var(--accent-bright); font-weight: 700; }
.slot .fullband { font-size: 0.58rem; text-transform: uppercase; letter-spacing: 0.04em; color: oklch(70% 0.16 25); font-weight: 700; }
.book-error { font-size: 0.85rem; color: var(--danger); margin: 0 0 0.75rem; }
/* The credit half-failure notice (#634). Deliberately NOT `.book-error`'s
   var(--danger): the booking held and only the credit failed to move, so this
   is a note about money to sort out, not a red refusal. --warn and a raised
   card match `.book-unavailable`, the other notice in this flow that reports
   something the studio will fix by hand. `tabindex="-1"` takes focus after the
   redraw (#397), so it gets a visible ring rather than a silent jump. */
.book-credit-failed {
  margin: 0 0 0.75rem;
  padding: 0.75rem;
  border: 1.5px solid var(--warn);
  border-radius: var(--radius-sm);
  background: var(--bg-raised);
  font-size: 0.85rem;
}
.book-credit-failed:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.book-total { font-size: 1.1rem; font-weight: 700; margin: 0.5rem 0; }
/* Pin the confirm/reschedule submit button to a >=44px touch target (issue #32).
   min-height keeps the floor even if font-size or line-height later shrinks the
   padding-derived height; the button still grows if the label wraps on narrow phones. */
#book-submit { min-height: 44px; padding: 0.75rem 1rem; }

/* ---------- Checkout ---------- */
.order-summary ul { margin: 0 0 0.75rem; padding-left: 1.1rem; font-size: 0.88rem; }
.order-summary .line-item { font-size: 0.85rem; display: flex; justify-content: space-between; margin: 0.75rem 0 0.2rem; }
.order-summary .total { font-size: 1.4rem; font-weight: 800; color: var(--accent-bright); margin: 0; }

/* ---------- Sign in ---------- */
.signin-card { max-width: 420px; margin: 2rem auto 0; text-align: center; background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem; }
.signin-card h2 { font-size: 1.5rem; margin: 0 0 0.5rem; }
.signin-card p { color: var(--text-dim); }
/* The sign-in failure has to look like a failure (#397). `.signin-card p` is
   one specificity point heavier than `.book-error`, so the refusal rendered in
   the same dim grey as the hint underneath it — visible, and reading as more
   fine print on a screen where the visitor is looking for the thing that went
   wrong. */
.signin-card p.book-error { color: var(--danger); }
.signin-sent-actions { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; margin-top: 1.25rem; }
/* `.btn-link` is padding:0 everywhere else, which made "Use a different
   address" a 16px-tall tap target on a phone — measured at 375px. It is the
   only repair for a mistyped address (#417), so it gets a real target. */
.signin-sent-actions .btn-link { min-height: 44px; padding: 0.6rem 1rem; }
.sso-buttons { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 1.25rem; }
.divider { display: flex; align-items: center; gap: 0.75rem; margin: 1.25rem 0; }
.divider span.line { flex: 1; height: 1px; background: var(--border); }
.divider span.label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
.signin-card form { text-align: left; }

/* ---------- Ledger table ---------- */
.ledger-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.ledger-table th { text-align: left; padding: 0.6rem 0.7rem; border-bottom: 1px solid var(--border); color: var(--text-dim); font-size: 0.8rem; text-transform: uppercase; }
.ledger-table td { padding: 0.6rem 0.7rem; border-bottom: 1px solid var(--border); }
.amount-positive { color: var(--accent-bright); font-weight: 700; }
.amount-negative { color: var(--danger); font-weight: 700; }

/* ---------- Progress ---------- */
.progress { height: 6px; border-radius: 999px; background: var(--bg-raised-2); border: 1px solid var(--border); overflow: hidden; }
.progress > span { display: block; height: 100%; background: linear-gradient(90deg, oklch(34% 0.12 258), var(--accent-bright)); }

/* ---------- Projects list ---------- */
.project-row { background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.25rem; margin-bottom: 1rem; display: flex; flex-direction: column; gap: 0.75rem; }
.project-row__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.project-row .kicker { font-size: 0.72rem; color: var(--text-dim); font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin: 0 0 0.2rem; }
.project-row h2 { font-size: 1.35rem; margin: 0 0 0.4rem; }
.project-row .meta { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.project-row .summary { font-size: 0.85rem; color: var(--text-dim); }
.project-row__actions { display: flex; gap: 0.5rem; flex-wrap: wrap; flex-shrink: 0; }
.progress-label { font-size: 0.72rem; color: var(--text-dim); font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin: 0 0 0.3rem; }
@media (max-width: 720px) {
  .project-row__head { flex-direction: column; align-items: stretch; }
  .project-row__actions { display: grid; grid-auto-flow: row; gap: 0.5rem; width: 100%; }
  .project-row__actions > * { width: 100%; text-align: center; }
}

/* ---------- Album art (project view) ---------- */
.albumart { display: flex; flex-direction: column; gap: 0.35rem; width: 132px; }
.albumart__drop {
  position: relative; width: 132px; height: 132px; border-radius: 10px; overflow: hidden;
  background: var(--bg-raised-2); border: 1px dashed var(--border);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.2rem;
  padding: 0.5rem; color: var(--text-dim); font: inherit; font-size: 0.75rem; line-height: 1.25; text-align: center;
  cursor: pointer; transition: border-color 120ms ease, background 120ms ease, color 120ms ease;
}
.albumart__drop:hover:not(:disabled) { border-color: var(--accent); color: var(--text); }
.albumart__drop.is-dragover { border-color: var(--accent); background: var(--accent-tint); border-style: solid; color: var(--text); }
.albumart__drop.has-art { border-style: solid; padding: 0; }
.albumart__drop:disabled { cursor: progress; }
.albumart__title { font-weight: 600; }
.albumart__hint { font-size: 0.68rem; }
.albumart__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.albumart__veil {
  position: absolute; inset: 0; display: grid; place-items: center; padding: 0.4rem;
  background: oklch(12% 0.02 265 / 0.72); color: var(--text); font-size: 0.72rem; text-align: center;
}
.albumart__note, .albumart__status { margin: 0; font-size: 0.68rem; line-height: 1.35; color: var(--text-dim); }
.albumart__status.is-error { color: var(--danger); font-weight: 600; }
.albumart__status:empty { display: none; }
@media (max-width: 720px) {
  .albumart { width: 100%; }
  .albumart__drop { width: 100%; max-width: 220px; height: auto; aspect-ratio: 1 / 1; }
}

/* ---------- File locker ---------- */
.completed-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 0.75rem; }
.completed-card { background: var(--bg-raised); border: 1px solid var(--border); border-radius: 10px; padding: 0.9rem 1rem; display: flex; flex-direction: column; gap: 0.45rem; }
.completed-card--open { border-color: var(--accent); grid-column: 1 / -1; }
.completed-card__head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; }
.completed-card__head span.name { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 1.05rem; font-weight: 700; letter-spacing: -0.02em; min-width: 0; }
.completed-card .meta { font-size: 0.8rem; color: var(--text-dim); }
.locker-door {
  position: relative; display: flex; align-items: center; gap: 0.7rem; width: 100%; margin-top: 0.15rem;
  padding: 0.6rem 0.75rem; cursor: pointer; font-family: inherit; font-size: 0.85rem; font-weight: 700; letter-spacing: 0.01em;
  color: var(--accent-bright); border: 1px solid oklch(40% 0.04 265);
  background: linear-gradient(90deg, oklch(28% 0.035 265), oklch(24% 0.03 265)); border-radius: var(--radius-sm);
  box-shadow: inset 0 1px 0 0 oklch(38% 0.04 265);
}
.locker-door[aria-expanded="true"] {
  border-color: var(--accent); border-bottom-color: transparent; border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  background: var(--bg-sunken); box-shadow: inset 0 2px 6px -3px rgba(0,0,0,0.8);
}
.locker-vent { flex-shrink: 0; width: 20px; height: 16px; border-radius: 2px; border: 1px solid oklch(48% 0.05 265); background: repeating-linear-gradient(180deg, oklch(72% 0.14 252 / 0.55) 0 2px, transparent 2px 4px); }
.locker-door[aria-expanded="true"] .locker-vent { border-color: oklch(40% 0.04 265); background: repeating-linear-gradient(180deg, oklch(72% 0.14 252 / 0.15) 0 2px, transparent 2px 4px); }
.locker-latch { flex-shrink: 0; display: grid; place-items: center; width: 16px; height: 22px; border-radius: 3px; border: 1px solid oklch(48% 0.05 265); background: oklch(30% 0.035 265); transition: transform 140ms ease; }
.locker-door[aria-expanded="true"] .locker-latch { transform: rotate(90deg); }
.locker-latch span { display: block; width: 4px; height: 12px; border-radius: 2px; background: var(--accent-bright); }
.locker-contents {
  border: 1px solid var(--accent); border-top: none; border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  background: var(--bg-deep); padding: 0.85rem;
  box-shadow: inset 0 10px 14px -10px rgba(0,0,0,1), inset 6px 0 8px -8px rgba(0,0,0,0.9), inset -6px 0 8px -8px rgba(0,0,0,0.9);
}
.locker-section-label { font-size: 0.72rem; color: var(--text-dim); font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin: 0 0 0.4rem; }
.file-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 0.4rem; }
.file-link {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  background: var(--bg-raised-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0.55rem 0.75rem; text-decoration: none; color: var(--text); font-size: 0.85rem;
}
.file-link:hover { border-color: var(--accent); }
.file-link .kind { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--accent-bright); white-space: nowrap; }

/* ---------- Waveform / mix review ---------- */
.mix-chip-row { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.mix-chip-row .kicker { font-size: 0.68rem; color: var(--text-dim); font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin-right: 0.2rem; }
.kicker__link { color: var(--accent-bright); text-decoration: none; }
.kicker__link:hover { text-decoration: underline; }
.mix-chip {
  border-radius: 999px; padding: 0.2rem 0.5rem; display: inline-flex; align-items: center; gap: 0.3rem;
  font-size: 0.72rem; font-weight: 700; cursor: pointer; font-family: inherit; white-space: nowrap;
  background: transparent; color: var(--text-mid); border: 1px solid var(--border);
}
.mix-chip.is-selected { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.mix-chip.is-taken-down { text-decoration: line-through; opacity: 0.55; }
.mix-chip.is-taken-down.is-selected { opacity: 0.85; }
.mix-play-row { display: flex; align-items: center; gap: 0.75rem; }
.play-btn {
  display: grid; place-items: center; border-radius: 50%; border: none; cursor: pointer; line-height: 1;
  font-family: inherit; flex-shrink: 0; background: var(--accent); color: var(--on-accent);
  position: relative;
}
.play-btn--sm { width: 26px; height: 26px; font-size: 0.62rem; }
.play-btn--lg { width: 40px; height: 40px; font-size: 0.9rem; }
.play-btn.is-playing { background: var(--accent-bright); }
.mix-play-row__info { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; min-width: 0; }
.mix-chip-row__meter { margin-left: auto; }
.mix-play-row .rev-title { margin: 0; font-size: 0.9rem; font-weight: 700; }
.mix-play-row .rev-meta { margin: 0; font-size: 0.8rem; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.rev-meta__sep { color: var(--border); margin: 0 0.05rem; }
.mix-rev-input {
  background: transparent; border: 1px solid transparent; border-radius: 6px; padding: 0.1rem 0.3rem; margin: 0 0 0 -0.35rem;
  color: var(--text); font-size: 0.9rem; font-weight: 700; font-family: inherit; max-width: 10ch;
}
.mix-rev-input:hover { border-color: var(--border); }
.mix-rev-input:focus { outline: none; border-color: var(--accent); background: var(--bg-raised-2); }

.dropzone {
  border: 1px dashed var(--border); border-radius: var(--radius-sm); padding: 1.1rem; text-align: center;
  transition: border-color 120ms ease, background 120ms ease;
}
.dropzone.is-dragover { border-color: var(--accent); background: var(--accent-tint); border-style: solid; }
.dropzone__title { margin: 0 0 0.6rem; font-size: 0.88rem; font-weight: 600; color: var(--text); }
.dropzone__title.is-error { color: var(--danger); }
.dropzone__hint { margin: 0.6rem 0 0; font-size: 0.75rem; color: var(--text-dim); }

.waveform { position: relative; height: 64px; display: flex; align-items: center; gap: 2px; padding: 0 1px; cursor: crosshair; }
.waveform.editing-mode { cursor: ew-resize; }
.wave-bar { flex: 1; min-width: 0; border-radius: 2px; background: var(--accent-tint); }
.playhead { position: absolute; top: 0; bottom: 0; left: 0; border-right: 2px solid var(--warn); background: oklch(84% 0.13 90 / 0.1); pointer-events: none; width: 0%; }
.pending-pin { position: absolute; top: -4px; bottom: -4px; width: 2px; background: var(--warn); pointer-events: none; }
.editing-line { position: absolute; top: -8px; bottom: -8px; width: 3px; border-radius: 2px; background: oklch(96% 0.13 95); box-shadow: 0 0 10px oklch(90% 0.15 95 / 0.85); pointer-events: none; transform: translateX(-50%); }
.note-pin {
  position: absolute; top: -6px; display: grid; place-items: center; width: 18px; height: 18px; border-radius: 50%;
  background: var(--warn); color: var(--on-warn); font-size: 0.6rem; font-weight: 700;
  transform: translateX(-50%); cursor: pointer; padding: 0; font-family: inherit; border: none;
}
.note-pin.is-editing { border: 2px solid var(--on-accent); }
/* Staff review: client note pins are position markers, not click targets. */
.note-pin.is-static { pointer-events: none; cursor: default; }
/* Touch (#521): the note pin and play buttons stay their small visual size but
   grow an invisible 44px hit area on coarse pointers, so a finger can land them
   without a mouse's precision. Precise pointers are left untouched — the wider
   zone would only steal clicks from adjacent bars. A static pin inherits its
   own pointer-events:none, so its pseudo-element is inert too. */
@media (pointer: coarse) {
  .note-pin::before,
  .play-btn::before {
    content: ""; position: absolute; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: 44px; height: 44px; border-radius: 50%;
  }
}
/* The same numbered pin shown beside a comment in the list, tying the list
   item to its marker on the timeline. */
.note-pin-bullet {
  display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; flex-shrink: 0;
  background: var(--warn); color: var(--on-warn); font-size: 0.66rem; font-weight: 700; line-height: 1;
}
.fix-pin {
  position: absolute; bottom: -7px; display: grid; place-items: center; width: 16px; height: 16px; border-radius: 50%;
  color: var(--on-accent); font-size: 0.62rem; font-weight: 700; line-height: 1; transform: translateX(-50%); pointer-events: none;
}
.fix-pin.open { background: var(--accent-tint); }
.fix-pin.good { background: var(--success); }
.fix-pin.reopened { background: var(--warn); }
.studio-note-pin {
  position: absolute; top: -6px; width: 10px; height: 10px; border-radius: 2px;
  background: var(--accent-bright); transform: translateX(-50%) rotate(45deg); pointer-events: none;
  box-shadow: 0 0 0 2px var(--bg);
}

.producer-notes { border: 1px solid var(--border); background: var(--bg-sunken); border-radius: var(--radius-sm); padding: 0.6rem 0.7rem; margin-bottom: 0.6rem; }
.producer-notes__title { margin: 0 0 0.3rem; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
.producer-notes__body { margin: 0; font-size: 0.85rem; color: var(--text-soft); white-space: pre-line; }

.producer-notes-edit {
  border: 1px solid var(--accent-line);
  background: var(--bg-sunken);
  border-radius: var(--radius-sm);
  padding: 0.7rem 0.8rem 0.8rem;
}
.producer-notes-edit__head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.5rem; }
.producer-notes-edit__title { margin: 0; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--accent-bright); }
.producer-notes-edit__hint { font-size: 0.7rem; color: var(--text-dim); font-style: italic; white-space: nowrap; }
.producer-notes-edit textarea {
  display: block;
  width: 100%;
  padding: 0.6rem 0.7rem;
  background: var(--bg-raised-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 0.88rem;
  font-family: inherit;
  line-height: 1.45;
  resize: vertical;
  transition: border-color 120ms ease;
}
.producer-notes-edit textarea:focus { outline: none; border-color: var(--accent); }
.producer-notes-edit textarea::placeholder { color: var(--text-dim); }
.producer-notes-edit__actions { display: flex; align-items: center; gap: 0.6rem; margin-top: 0.55rem; min-height: 1.6rem; }
.producer-notes-edit__saved[hidden] { display: none; }
.producer-notes-edit__saved {
  display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.78rem; font-weight: 600; color: var(--success);
}

.time-ticks { position: relative; height: 14px; border-top: 1px solid var(--border); }
.time-ticks span { position: absolute; transform: translateX(-50%); font-size: 0.62rem; color: var(--text-dim); top: 2px; }

.fixed-panel { border: 1px solid var(--accent-line); background: oklch(54% 0.18 258 / 0.12); border-radius: var(--radius-sm); padding: 0.6rem 0.7rem; margin-bottom: 0.6rem; }
.fixed-panel__title { margin: 0 0 0.4rem; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--accent-bright); }
.fixed-row { display: grid; grid-template-columns: auto auto minmax(0,1fr) auto; align-items: baseline; gap: 0.55rem; font-size: 0.82rem; padding-bottom: 0.4rem; }
.fixed-row .badge-dot { display: grid; place-items: center; width: 16px; height: 16px; border-radius: 50%; font-size: 0.62rem; font-weight: 700; color: var(--on-accent); }
.fixed-row .badge-dot.good { background: var(--success); }
.fixed-row .badge-dot.reopened { background: var(--warn); }
.fixed-row .badge-dot.open { background: var(--accent-tint); }
.fixed-row .time { font-weight: 700; color: var(--accent-bright); white-space: nowrap; }
.fixed-row .text { color: var(--text-soft); min-width: 0; }
.fixed-row .from { font-size: 0.7rem; color: var(--text-dim); white-space: nowrap; }
.fixed-actions { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; padding-left: 1.9rem; }
.pill-btn { border-radius: 999px; padding: 0.18rem 0.6rem; font-size: 0.7rem; font-weight: 700; cursor: pointer; font-family: inherit; white-space: nowrap; border: 1px solid var(--border); background: transparent; color: var(--text-mid); }
.pill-btn.on-good { background: var(--accent-tint); color: var(--on-accent); border-color: var(--accent-tint); }
.pill-btn.on-warn { background: var(--warn); color: var(--on-warn); border-color: var(--warn); }
.pill-btn.on-bad { background: var(--danger); color: #fff; border-color: var(--danger); }
.pill-btn.tone-line { color: var(--accent-bright); border-color: var(--accent-line); }
.pill-btn.tone-warn { color: var(--warn); border-color: var(--border); }

.comment-row { display: block; width: 100%; font-size: 0.82rem; border-radius: 6px; padding: 0.2rem 0.3rem; margin: 0 -0.3rem; box-sizing: border-box; }
.comment-row.is-editing { background: oklch(54% 0.18 258 / 0.18); }
.comment-grid { display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: baseline; gap: 0.6rem; font-size: 0.82rem; }
/* The index/time/text of a client note is one clickable target that seeks the
   mix and opens the composer — the same action as the numbered waveform pin,
   so a note can be picked from the list instead of hunting the 18px pin. */
.comment-select {
  display: grid; grid-template-columns: auto auto minmax(0,1fr); align-items: baseline; gap: 0.6rem;
  width: 100%; min-width: 0; text-align: left; font: inherit; color: inherit;
  background: transparent; border: none; border-radius: 6px; cursor: pointer;
  padding: 0.25rem 0.35rem; margin: -0.25rem 0 -0.25rem -0.35rem;
  transition: background-color 120ms ease;
}
.comment-select:hover { background: oklch(54% 0.18 258 / 0.14); }
.comment-select:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.comment-index { display: grid; place-items: center; width: 16px; height: 16px; border-radius: 50%; background: var(--warn); color: var(--on-warn); font-size: 0.6rem; font-weight: 700; }
.comment-time { font-weight: 700; color: var(--warn); white-space: nowrap; }
.comment-body { min-width: 0; }
.comment-text { display: block; color: var(--text-soft); }

/* Staff feedback item as a play/pause control: click to play from the note's
   lead-in, click again to pause. The leading icon reflects live playback. */
.feedback-toggle {
  display: grid; grid-template-columns: auto auto auto minmax(0,1fr); align-items: center; gap: 0.55rem;
  width: 100%; min-width: 0; text-align: left; font: inherit; color: inherit;
  background: transparent; border: none; border-radius: 6px; cursor: pointer;
  padding: 0.25rem 0.35rem; margin: -0.35rem -0.35rem 0;
  transition: background-color 120ms ease;
}
.feedback-toggle:hover { background: oklch(54% 0.18 258 / 0.14); }
.feedback-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.feedback-toggle__icon {
  display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  background: var(--accent); color: var(--on-accent);
}
.feedback-toggle__icon svg { width: 11px; height: 11px; display: block; }
.feedback-toggle .icon-pause { display: none; }
.feedback-toggle.is-playing .icon-play { display: none; }
.feedback-toggle.is-playing .icon-pause { display: block; }
.feedback-toggle.is-playing .feedback-toggle__icon { background: var(--warn); color: var(--on-warn); }
.comment-stamp { display: block; margin-top: 0.15rem; font-size: 0.68rem; color: oklch(66% 0.02 265); }
.comment-status { margin: 0.3rem 0 0 1.9rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.02em; }
.comment-actions { display: flex; align-items: center; gap: 0.3rem; white-space: nowrap; }
.icon-btn { display: grid; place-items: center; width: 26px; height: 26px; background: transparent; border: 1px solid var(--border); border-radius: 6px; color: var(--accent-bright); font-size: 0.8rem; line-height: 1; cursor: pointer; font-family: inherit; padding: 0; }
.icon-btn:hover { border-color: var(--accent); }
.icon-btn.danger { color: var(--text-dim); }
.icon-btn.danger:hover { border-color: var(--danger-strong); color: var(--danger); }
.thread-history { margin: 0 0 0.4rem; }
.thread-history__meta { margin: 0 0 0.3rem; font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-dim); }
.thread-entry { display: grid; grid-template-columns: auto minmax(0,1fr); gap: 0.5rem; align-items: baseline; padding: 0.25rem 0 0.25rem 0.6rem; border-left: 2px solid var(--border); }
.thread-entry.kind-studio { border-left-color: var(--accent-line); }
.thread-entry.kind-signoff { border-left-color: oklch(55% 0.14 150); }
.thread-entry.kind-artist { border-left-color: oklch(52% 0.09 90); }
.thread-entry .who { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; white-space: nowrap; }
.thread-entry .text { font-size: 0.8rem; min-width: 0; }
.comment-edit-form { display: flex; flex-direction: column; gap: 0.5rem; width: 100%; }
.comment-new-form { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.comment-new-form input[type="text"] { flex: 1; min-width: 180px; }
.pending-time-label { font-size: 0.78rem; font-weight: 700; color: var(--warn); white-space: nowrap; }
.reply-flag { margin: 0; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--accent-bright); }

/* ---------- Stage pills / note-stage buttons ---------- */
.stage-row { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }

/* Song view header callout: reference tracks + artist notes, shown as a
   full-width panel under the title/stage row (was a right-column card). */
.song-brief { display: grid; grid-template-columns: 1fr 1fr; gap: 0.9rem 1.75rem; margin-top: 1.1rem; background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem 1.25rem; }
.song-brief__col { min-width: 0; }
.song-brief__label { font-size: 0.7rem; color: var(--text-dim); font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin: 0 0 0.3rem; }
.song-brief__value { margin: 0; font-size: 0.85rem; color: var(--text-soft); white-space: pre-line; }
@media (max-width: 720px) { .song-brief { grid-template-columns: 1fr; gap: 0.85rem; } }
.stage-btn { border-radius: 999px; padding: 0.25rem 0.7rem; font-size: 0.72rem; font-weight: 700; cursor: pointer; font-family: inherit; background: transparent; color: var(--text-mid); border: 1px solid var(--border); }
.stage-btn.is-current { background: var(--warn); color: var(--on-warn); border-color: var(--warn); }
.stage-btn.is-done { background: var(--accent-bright); color: var(--on-warn); border-color: var(--accent-bright); }
.note-stages { list-style: none; margin: 0; padding: 0; display: grid; grid-auto-flow: column; }
.note-stage-btn { display: block; width: 100%; text-align: center; padding: 0.3rem 0.2rem; border: none; background: transparent; font-family: inherit; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; cursor: pointer; border-bottom: 2px solid var(--border-track); color: var(--text-dim); }
.note-bar { display: block; width: 100%; height: 6px; border: none; border-radius: 999px; padding: 0; cursor: pointer; background: var(--border-track); }

/* ---------- Song row (project detail) ---------- */
.song-row { display: flex; flex-direction: column; gap: 0.4rem; padding: 0.6rem; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-sunken); }
.song-row__top { display: grid; grid-template-columns: minmax(0,1fr) 7rem; align-items: center; gap: 0.6rem; }
.song-row__top input { min-width: 0; background: var(--bg-raised-2); border: 1px solid var(--border); border-radius: 6px; padding: 0.4rem 0.55rem; color: var(--text); font-size: 0.9rem; font-family: inherit; }
.song-row__status { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; white-space: nowrap; text-align: right; }
.song-row__mix-summary { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; padding: 0.4rem 0.5rem; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-raised-2); }
.song-row__mix-summary .rev { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.04em; color: var(--text-mid); white-space: nowrap; }
.song-row__mix-summary .meta { font-size: 0.72rem; color: var(--text-dim); white-space: nowrap; }
.mini-track { display: block; height: 4px; border-radius: 999px; background: var(--border-track); overflow: hidden; min-width: 0; flex: 1; }
.mini-track > span { display: block; height: 100%; border-radius: 999px; background: var(--accent-bright); width: 0%; }
.detail-toggle { background: transparent; border: 1px solid var(--border); border-radius: 6px; padding: 0.25rem 0.55rem; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--accent-bright); cursor: pointer; font-family: inherit; white-space: nowrap; }
.detail-toggle.is-open { border-color: var(--accent); }
.song-detail-panel { border: 1px solid var(--accent-line); border-radius: var(--radius-sm); background: var(--bg-deep); padding: 0.85rem; display: flex; flex-direction: column; gap: 0.7rem; }
.feedback-summary { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.02em; white-space: nowrap; }

/* ---------- Studio staff ---------- */
.studio-day-label { margin: 0 0 0.4rem; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
.studio-day-label.is-today { color: var(--warn); }
.studio-slot-btn {
  width: 100%; display: grid; grid-template-columns: 5.5rem auto minmax(0,1fr); align-items: baseline; gap: 0.6rem;
  text-align: left; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0.5rem 0.65rem; color: var(--text); font-family: inherit; font-size: 0.85rem; cursor: pointer;
}
.studio-slot-btn:hover { border-color: var(--accent); }
.studio-slot-btn .time { font-weight: 700; color: var(--accent-bright); white-space: nowrap; }
.studio-slot-btn .hrs { font-size: 0.75rem; color: var(--text-dim); white-space: nowrap; }
.grant-chip-row { display: flex; gap: 0.35rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
.grant-chip { display: flex; align-items: center; gap: 0.4rem; border-radius: 999px; padding: 0.25rem 0.7rem; font-size: 0.75rem; font-weight: 700; cursor: pointer; font-family: inherit; white-space: nowrap; background: transparent; color: var(--text-mid); border: 1px solid var(--border); }
.grant-chip.is-selected { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.grant-notice { margin: 0; font-size: 0.8rem; font-weight: 700; color: var(--success); }
.studio-job { background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.1rem 1.25rem; margin-bottom: 0.85rem; display: flex; flex-direction: column; gap: 0.75rem; }
.studio-job__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.studio-song-btn { width: 100%; display: grid; grid-template-columns: minmax(0,1fr) auto auto; align-items: center; gap: 0.6rem; padding: 0.5rem 0.6rem; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-sunken); color: var(--text); font-family: inherit; font-size: 0.85rem; text-align: left; cursor: pointer; }
.studio-song-btn:hover { border-color: var(--accent); }
.studio-song-btn .chevron { color: var(--text-dim); font-size: 0.75rem; white-space: nowrap; }
.delivered-row { background: var(--bg-sunken); border: 1px solid var(--border); border-radius: 10px; padding: 0.8rem 1rem; display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: center; gap: 0.75rem; }

/* ---------- Mobile tabbar ---------- */
.mobile-tabbar { display: none; position: sticky; bottom: 0; z-index: 11; grid-auto-flow: column; grid-auto-columns: 1fr; background: oklch(19% 0.025 265); border-top: 1px solid var(--border); padding: 0.35rem 0.4rem 0.5rem; }
.mobile-tab { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.25rem; min-height: 48px; padding: 0.35rem 0.2rem; border-radius: 10px; text-decoration: none; cursor: pointer; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.02em; color: var(--text-dim); }
.mobile-tab.is-active { color: var(--accent-bright); background: oklch(54% 0.18 258 / 0.14); }
.mobile-tab .dot { display: block; width: 18px; height: 3px; border-radius: 999px; background: var(--border-track); }
.mobile-tab.is-active .dot { background: var(--accent-tint); }

/* ---------- Responsive layout ---------- */
@media (max-width: 620px) {
  .two-col, .two-col-wide, .hero-authed__grid { grid-template-columns: 1fr !important; }
  .site-header__inner { padding: 0.7rem 1rem !important; gap: 0.6rem !important; flex-wrap: nowrap !important; }
  .primary-nav { display: none !important; }
  .brand__mark { width: 2rem !important; height: 2rem !important; }
  .brand__name { font-size: 1.02rem !important; }
  .header-actions { gap: 0.45rem !important; margin-left: auto; }
  .btn.header-signout { display: none !important; }
  .credit-pill { width: 32px !important; height: 32px !important; }
  .mobile-tabbar { display: grid !important; }
  .app-main { padding: 1.25rem 1rem 5.75rem !important; }
  .project-row__head { flex-direction: column !important; align-items: stretch !important; gap: 0.85rem !important; }
  .project-row__actions { display: grid !important; grid-auto-flow: row !important; gap: 0.5rem !important; width: 100% !important; }
  .project-row__actions > * { width: 100% !important; text-align: center !important; }
}

.text-dim { color: var(--text-dim); }
.small { font-size: 0.85rem; }

/* Visually hidden, still read by assistive tech. */
.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;
}

/* ---------------------------------------------------------------------
   Studio board: at-a-glance + priority tabs
   --------------------------------------------------------------------- */
.studio-head { margin-bottom: 1.1rem; }

/* Single board navigation: each tile is a tab that opens its own panel. The
   three count tiles size evenly; the settings tile sits compact on the right. */
.board-nav { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)) auto; gap: 0.7rem; margin-bottom: 1.5rem; }
.board-tile {
  position: relative;
  display: flex; flex-direction: column; gap: 0.3rem; align-items: flex-start; text-align: left;
  padding: 0.85rem 1rem; min-height: 44px; background: var(--bg-raised);
  border: 1px solid var(--border); border-radius: var(--radius); color: var(--text);
  font-family: inherit; cursor: pointer; transition: border-color 0.15s ease, background 0.15s ease;
}
.board-tile:hover { border-color: var(--accent-bright); }
/* Selection is the ONLY thing that gets the accent border + underline bar. */
.board-tile.is-active { border-color: var(--accent); background: var(--bg-raised-2); box-shadow: inset 0 -3px 0 0 var(--accent-bright); }
.board-tile__num { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 1.7rem; font-weight: 700; letter-spacing: -0.03em; line-height: 1; }
.board-tile__icon { display: flex; align-items: center; min-height: 1.7rem; color: var(--text-dim); }
.board-tile__label { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
/* Urgency is a quieter, distinct cue: an accent number + a corner dot. It must
   not reuse the border/background that signals selection. */
.board-tile--urgent .board-tile__num { color: var(--accent-bright); }
.board-tile--urgent::after {
  content: ""; position: absolute; top: 0.7rem; right: 0.7rem;
  width: 8px; height: 8px; border-radius: 999px; background: var(--accent-bright);
}
/* Settings tile: quieter, priority-3, sized to its content. */
.board-tile--muted { justify-content: center; align-items: center; gap: 0.35rem; padding-left: 1.15rem; padding-right: 1.15rem; }
.board-tile--muted.is-active .board-tile__icon { color: var(--accent-bright); }

/* Tools tab — launchable tool cards. */








/* ======================================================================
   Mastering Scorecard — upload + report
   ====================================================================== */
.mreport-shell { max-width: 920px; margin: 0 auto; }
.mreport__back {
  display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; font-weight: 600;
  color: var(--text-dim); text-decoration: none; margin-bottom: 1rem;
}
.mreport__back:hover { color: var(--accent-bright); }

/* ======================================================================
   Loudness UI (imported project screen + per-mix analysis)
   ====================================================================== */
.loud-badge { display: inline-flex; align-items: center; font-size: 0.62rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; padding: 0.14rem 0.45rem; border-radius: 999px; }
.loud-badge--present { color: var(--accent-bright); background: oklch(54% 0.18 258 / 0.16); border: 1px solid var(--accent-line); }
.loud-badge--absent { color: var(--text-dim); background: var(--bg-raised-2); border: 1px solid var(--border); }

.loud-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; }
.loud-stat { background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.85rem 1rem; display: flex; flex-direction: column; gap: 0.15rem; }
.loud-stat__label { font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); font-weight: 700; }
.loud-stat__value { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 1.4rem; font-weight: 800; letter-spacing: -0.02em; }
.loud-stat__sub { font-size: 0.75rem; color: var(--text-dim); }

.loud-bars { min-width: 160px; }
.loud-bars .loud-bar { height: 6px; border-radius: 4px; background: var(--bg-sunken); overflow: hidden; margin-bottom: 3px; }
.loud-bar__fill { display: block; height: 100%; border-radius: 4px; }
.loud-bar__fill--src { background: var(--border); }
.loud-bar__fill--mst { background: linear-gradient(90deg, var(--accent), var(--accent-bright)); }
.loud-bars__nums { display: flex; align-items: center; justify-content: space-between; gap: 0.4rem; margin-top: 0.15rem; font-size: 0.7rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.loud-bars__lift { color: var(--success); font-weight: 700; }

/* ---- Imported project screen ---- */
.pproj-head { margin-bottom: 1.75rem; }
.pproj-head__top { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 0.4rem; }
.pproj-head__meta { font-size: 0.8rem; color: var(--text-dim); }
.pproj-head__title { font-size: 2rem; margin: 0 0 0.6rem; letter-spacing: -0.02em; }
.pproj-artist { display: flex; flex-direction: column; gap: 0.25rem; max-width: 380px; }
.pproj-artist__label { font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); }
.pproj-artist input { width: 100%; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); padding: 0.5rem 0.7rem; font: inherit; }
.pproj-artist input:focus-visible { border-color: var(--accent-bright); outline: none; }
.pproj-head__hint { margin: 0.7rem 0 0; font-size: 0.8rem; color: var(--text-dim); }
.pproj-section { margin-bottom: 1.75rem; }
.pproj-h2 { font-size: 1.15rem; font-weight: 800; letter-spacing: -0.02em; margin-bottom: 0.7rem; }

.psong-list { display: flex; flex-direction: column; gap: 0.5rem; }
.psong { display: flex; align-items: center; gap: 1rem; padding: 0.9rem 1.1rem; background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius); text-decoration: none; color: var(--text); transition: border-color 0.15s ease, background 0.15s ease; }
.psong:hover { border-color: var(--accent-bright); background: var(--bg-raised-2); }
.psong__main { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; flex: 1; }
.psong__name { font-weight: 700; }
.psong__meta { display: flex; align-items: center; gap: 0.5rem; font-size: 0.78rem; color: var(--text-dim); flex-wrap: wrap; }
.psong__loud { font-size: 0.78rem; color: var(--text-soft); font-variant-numeric: tabular-nums; }
.psong__bars { flex-shrink: 0; }
.psong__chev { color: var(--text-dim); font-size: 1.4rem; line-height: 1; }
/* Album art on the staff project screen (read-only preview + download). */
.pproj-art { display: flex; align-items: flex-start; gap: 1rem; flex-wrap: wrap; }
.pproj-art__img { width: 160px; height: 160px; object-fit: cover; border-radius: 10px; border: 1px solid var(--border); display: block; }
.pproj-art__side { display: flex; flex-direction: column; gap: 0.45rem; align-items: flex-start; }
.pproj-art__status { margin: 0; font-size: 0.78rem; color: var(--text-dim); }
.pproj-art__status.is-error { color: var(--danger); font-weight: 600; }
.pproj-art__status:empty { display: none; }

.pproj-assign .text-dim { font-size: 0.85rem; margin: 0 0 0.7rem; max-width: 60ch; }
.pproj-assign__row { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.pproj-assign__select { background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); padding: 0.5rem 0.7rem; font: inherit; min-width: 240px; }
.pproj-assign__select:focus-visible { border-color: var(--accent-bright); outline: none; }
.pproj-head__client { font-size: 0.9rem; color: var(--text-soft); margin: 0; }
.pproj-head__client .pproj-artist__label { display: inline; margin-right: 0.4rem; }

/* Update-from-file control + diff/confirm panel. */
.pproj-update { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-top: 1rem; }
.pupd-error { font-size: 0.85rem; color: var(--danger); font-weight: 600; }
.pupd-panel { margin-top: 1rem; background: var(--bg-raised); border: 1px solid var(--accent-line); border-radius: var(--radius); padding: 1.1rem 1.25rem; }
.pupd-panel__title { margin: 0 0 0.8rem; font-weight: 800; font-size: 1.05rem; letter-spacing: -0.01em; }
.pupd-panel__body { display: flex; flex-direction: column; gap: 0.9rem; margin-bottom: 1rem; }
.pupd-group__title { margin: 0 0 0.35rem; font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); }
.pupd-list { margin: 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.85rem; color: var(--text-soft); font-variant-numeric: tabular-nums; }
.pupd-from { color: var(--text-dim); text-decoration: line-through; }
.pupd-to { color: var(--accent-bright); font-weight: 600; }
.pupd-panel__actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

.client-card__badge { margin-left: 0.5rem; vertical-align: middle; }

/* ---- Song view: project loudness + per-mix analysis ---- */
.song-head__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem 1.5rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
.song-head__titles { min-width: 0; }
.song-head__kicker { font-size: 0.72rem; color: var(--text-dim); font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin: 0 0 0.2rem; }
.song-head__title { font-size: 2rem; margin: 0; }
.song-status-callout { flex-shrink: 0; display: flex; flex-direction: column; gap: 0.45rem; background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius); padding: 0.7rem 0.85rem; }
.song-status-callout__label { font-size: 0.64rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); }

/* Song status as a progress stepper. */
.status-track { display: flex; align-items: flex-start; margin-top: 0.15rem; }
.status-node {
  flex: 1; position: relative; display: flex; flex-direction: column; align-items: center; gap: 0.4rem;
  background: none; border: none; padding: 0; cursor: pointer; font: inherit; min-width: 62px;
}
/* Connector line from the previous node, drawn behind the dots. */
.status-node:not(:first-child)::before {
  content: ""; position: absolute; top: 9px; right: 50%; width: 100%; height: 2px; background: var(--border-track); z-index: 0;
}
.status-node.is-done::before, .status-node.is-current::before { background: var(--accent); }
.status-node__dot {
  position: relative; z-index: 1; width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
  background: var(--bg-raised); border: 2px solid var(--border-track); color: var(--on-accent);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.status-node.is-done .status-node__dot { background: var(--accent); border-color: var(--accent); }
.status-node.is-current .status-node__dot { background: var(--warn); border-color: var(--warn); box-shadow: 0 0 0 3px oklch(84% 0.13 90 / 0.22); }
.status-node__label { font-size: 0.68rem; font-weight: 600; color: var(--text-dim); white-space: nowrap; }
.status-node.is-done .status-node__label { color: var(--text-mid); }
.status-node.is-current .status-node__label { color: var(--text); font-weight: 700; }
.status-node:hover .status-node__dot { border-color: var(--accent-bright); }
.status-node:focus-visible { outline: none; }
.status-node:focus-visible .status-node__dot { outline: 2px solid var(--focus); outline-offset: 2px; }

.mix-analysis { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-sunken); padding: 0.85rem 1rem; }
.mix-analysis__head { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.4rem; }
.mix-analysis__title { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
.mix-analysis__line { margin: 0 0 0.3rem; font-size: 0.9rem; color: var(--text-soft); font-variant-numeric: tabular-nums; }
.mix-analysis__target { margin: 0 0 0.6rem; font-size: 0.82rem; color: var(--text-dim); }
.mix-fmt-tag { display: inline-block; font-size: 0.64rem; font-weight: 700; letter-spacing: 0.05em; color: var(--accent-bright); background: oklch(54% 0.18 258 / 0.16); border-radius: 4px; padding: 0.05rem 0.35rem; vertical-align: middle; }
.mix-analysis__error { margin: 0 0 0.5rem; font-size: 0.85rem; color: var(--danger); }
.mix-analysis__actions { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.mix-analysis__note { font-size: 0.75rem; }

@media (max-width: 620px) {
  .loud-stats { grid-template-columns: repeat(2, 1fr); }
  .psong__bars { display: none; }
}

/* ---- Upload state ---- */
.scorecard-drop {
  background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 2.5rem 2rem; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 0.6rem;
}
.scorecard-drop__mark { width: 60px; height: 60px; margin-bottom: 0.3rem; display: flex; align-items: center; justify-content: center; }
.scorecard-drop__mark img { width: 100%; height: 100%; object-fit: contain; }
.scorecard-drop__title { font-size: 1.6rem; font-weight: 800; }
.scorecard-drop__lead { color: var(--text-dim); max-width: 46ch; margin: 0 0 0.6rem; font-size: 0.95rem; }
.scorecard-drop__zone {
  width: 100%; max-width: 480px; display: flex; flex-direction: column; align-items: center; gap: 0.35rem;
  padding: 2rem 1.5rem; border: 1.5px dashed var(--border); border-radius: var(--radius);
  background: var(--bg-sunken); cursor: pointer; transition: border-color 0.15s ease, background 0.15s ease;
}
.scorecard-drop__zone:hover, .scorecard-drop.is-drag .scorecard-drop__zone { border-color: var(--accent-bright); background: var(--bg-raised-2); }
.scorecard-drop__icon { color: var(--accent-bright); margin-bottom: 0.2rem; }
.scorecard-drop__zonetitle { font-weight: 700; }
.scorecard-drop__zonehint { font-size: 0.82rem; color: var(--text-dim); }
.scorecard-drop__zonehint code, .scorecard-drop__lead code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.92em; background: var(--bg-raised-2); padding: 0.05rem 0.3rem; border-radius: 4px; }
.scorecard-drop__error { margin: 0.6rem 0 0; font-size: 0.85rem; color: var(--danger); font-weight: 600; max-width: 44ch; }
.scorecard-drop__spinner { width: 40px; height: 40px; border-radius: 50%; border: 3px solid var(--border); border-top-color: var(--accent-bright); animation: scorecard-spin 0.8s linear infinite; margin-bottom: 0.4rem; }
@keyframes scorecard-spin { to { transform: rotate(360deg); } }

/* ---- Report shell ---- */
.mreport__toolbar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.mreport__toolbar .mreport__back { margin-bottom: 0; }
.mreport__toolbar-actions { display: flex; gap: 0.5rem; }
.mreport__toolbar-actions .btn { display: inline-flex; align-items: center; gap: 0.4rem; }

.mreport {
  background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 2.5rem; margin-top: 1rem; overflow: hidden;
}

/* Hero */
.mreport__hero {
  margin: -2.5rem -2.5rem 2rem; padding: 2.5rem;
  background:
    radial-gradient(120% 140% at 100% 0%, oklch(54% 0.18 258 / 0.28), transparent 60%),
    linear-gradient(180deg, var(--bg-raised-2), var(--bg-raised));
  border-bottom: 1px solid var(--border);
}
.mreport__brand { display: flex; flex-direction: column; align-items: flex-start; gap: 0.5rem; margin-bottom: 1.25rem; }
/* The wordmark asset is black on transparent. The on-screen report is dark, so
   invert it to white; @media print drops the filter to print it black. */
.mreport__wordmark { height: 34px; width: auto; filter: invert(1); }
.mreport__brandsub { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.14em; color: var(--text-dim); }
.mreport__cert-badge {
  display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.68rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.1em; color: var(--accent-bright);
  background: oklch(54% 0.18 258 / 0.16); border: 1px solid var(--accent-line);
  padding: 0.3rem 0.7rem; border-radius: 999px;
}
.mreport__title { font-size: 2.4rem; font-weight: 800; margin: 0.7rem 0 0.3rem; letter-spacing: -0.03em; }
.mreport__album { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 1.3rem; font-weight: 800; letter-spacing: -0.02em; margin: 0 0 0.2rem; display: flex; align-items: baseline; gap: 0.55rem; }
.mreport__album-label { font-family: "Public Sans", system-ui, sans-serif; font-size: 0.62rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent-bright); border: 1px solid var(--accent-line); border-radius: 4px; padding: 0.12rem 0.4rem; align-self: center; }
.mreport__project { color: var(--text-mid); font-weight: 600; margin: 0 0 1.1rem; }
.mreport__meta { display: flex; flex-wrap: wrap; gap: 0.4rem 1.5rem; font-size: 0.85rem; color: var(--text-dim); }
.mreport__meta b { color: var(--text-soft); font-weight: 600; margin-right: 0.35rem; }

/* Stat tiles */
.mreport__stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; margin-bottom: 1.75rem; }
.mreport-stat {
  background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0.9rem 1rem; display: flex; flex-direction: column; gap: 0.15rem;
}
.mreport-stat__label { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--text-dim); font-weight: 700; }
.mreport-stat__value { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 1.5rem; font-weight: 800; letter-spacing: -0.02em; }
.mreport-stat__sub { font-size: 0.75rem; color: var(--text-dim); }

/* Body copy */
.mreport__intro { color: var(--text-mid); font-size: 0.95rem; margin: 0 0 2rem; }
.mreport__section { margin-bottom: 2.25rem; }
.mreport__h2 { font-size: 1.25rem; font-weight: 800; letter-spacing: -0.02em; margin-bottom: 0.35rem; }
.mreport__h2::before { content: ""; display: block; width: 34px; height: 3px; border-radius: 2px; background: var(--accent); margin-bottom: 0.6rem; }
.mreport__sub { color: var(--text-dim); font-size: 0.9rem; margin: 0 0 1rem; max-width: 74ch; }
.mreport__fineprint { color: var(--text-dim); font-size: 0.78rem; font-style: italic; margin: 0.8rem 0 0; }

/* Tables */
.mreport-table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.mreport-table { width: 100%; border-collapse: collapse; font-size: 0.83rem; }
.mreport-table th {
  text-align: left; font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text-dim); font-weight: 700; padding: 0.7rem 0.85rem; background: var(--bg-sunken);
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
.mreport-table td { padding: 0.7rem 0.85rem; border-bottom: 1px solid var(--border-track); vertical-align: middle; }
.mreport-table tbody tr:last-child td { border-bottom: none; }
.mreport-table tbody tr:hover { background: oklch(54% 0.18 258 / 0.06); }
.mreport-t__num { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-weight: 800; color: var(--accent-bright); width: 1%; }
.mreport-t__song { font-weight: 700; white-space: nowrap; }
.mreport-num { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.mreport-file { display: inline-flex; align-items: baseline; gap: 0.45rem; font-size: 0.78rem; color: var(--text-dim); }
.mreport-file__tag {
  flex-shrink: 0; font-size: 0.6rem; font-weight: 800; letter-spacing: 0.05em; color: var(--accent-bright);
  background: oklch(54% 0.18 258 / 0.16); border-radius: 4px; padding: 0.1rem 0.35rem;
}
.mreport-file__tag--alt { color: var(--text-soft); background: var(--bg-raised-2); }
.mreport-fmt { display: block; margin-top: 0.2rem; font-size: 0.72rem; font-variant-numeric: tabular-nums; color: var(--accent-bright); font-weight: 600; }

/* Delivered-masters step: detect real compression from the exported files. */
.mreport-masters { margin-top: 0.9rem; }
.mreport-masters__drop {
  display: block; text-align: center; cursor: pointer; padding: 1rem 1.25rem;
  border: 1.5px dashed var(--border); border-radius: var(--radius-sm); background: var(--bg-sunken);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.mreport-masters.is-drag .mreport-masters__drop, .mreport-masters__drop:hover { border-color: var(--accent-bright); background: var(--bg-raised-2); }
.mreport-masters__title { display: block; font-weight: 700; font-size: 0.9rem; }
.mreport-masters__hint { display: block; margin-top: 0.25rem; font-size: 0.8rem; color: var(--text-dim); max-width: 70ch; margin-inline: auto; }
.mreport-masters--done { display: flex; gap: 0.6rem; align-items: flex-start; background: oklch(72% 0.17 150 / 0.1); border: 1px solid oklch(72% 0.17 150 / 0.35); border-radius: var(--radius-sm); padding: 0.8rem 1rem; }
.mreport-masters--done .mreport-masters__icon { color: var(--success); flex-shrink: 0; margin-top: 0.1rem; }
.mreport-masters--done p { margin: 0; font-size: 0.85rem; color: var(--text-soft); }

/* Loudness before/after bars */
.mreport-loud { min-width: 200px; }
.mreport-bars { display: flex; flex-direction: column; gap: 3px; }
.mreport-bar { height: 7px; border-radius: 4px; background: var(--bg-sunken); overflow: hidden; }
.mreport-bar__fill { display: block; height: 100%; border-radius: 4px; }
.mreport-bar__fill--src { background: var(--border); }
.mreport-bar__fill--mst { background: linear-gradient(90deg, var(--accent), var(--accent-bright)); }
.mreport-loud__nums { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.25rem; font-size: 0.72rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.mreport-loud__lift { color: var(--success); font-weight: 700; }

/* Consistency callout */
.mreport-callout {
  display: flex; gap: 0.75rem; align-items: flex-start; margin-top: 1rem;
  background: oklch(72% 0.17 150 / 0.1); border: 1px solid oklch(72% 0.17 150 / 0.35);
  border-radius: var(--radius-sm); padding: 0.9rem 1rem;
}
.mreport-callout__icon { color: var(--success); flex-shrink: 0; margin-top: 0.1rem; }
.mreport-callout p { margin: 0; font-size: 0.88rem; color: var(--text-soft); }

/* Plain-language guide */
.mreport-guide-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.75rem; }
.mreport-guide { background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 1rem 1.1rem; }
.mreport-guide__head { display: flex; align-items: baseline; gap: 0.5rem; margin-bottom: 0.4rem; }
.mreport-guide__term { font-weight: 800; font-size: 1rem; }
.mreport-guide__unit { font-size: 0.66rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent-bright); background: oklch(54% 0.18 258 / 0.16); padding: 0.12rem 0.4rem; border-radius: 4px; }
.mreport-guide__body { margin: 0; font-size: 0.85rem; color: var(--text-dim); }
.mreport-guide__body b { color: var(--text-soft); }

/* Certificate footer */
.mreport__cert {
  display: flex; gap: 1.25rem; align-items: center; margin: 0 -2.5rem -2.5rem; padding: 2rem 2.5rem;
  background: linear-gradient(180deg, var(--bg-raised), var(--bg-deep)); border-top: 1px solid var(--border);
}
.mreport__seal {
  flex-shrink: 0; width: 72px; height: 72px; border-radius: 50%; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px; text-align: center;
  border: 2px solid var(--accent-line); color: var(--accent-bright);
  font-size: 0.52rem; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; line-height: 1.15;
  background: oklch(54% 0.18 258 / 0.1);
}
.mreport__cert-text h3 { font-size: 1.05rem; font-weight: 800; margin-bottom: 0.35rem; }
.mreport__cert-text p { margin: 0; font-size: 0.85rem; color: var(--text-dim); }
.mreport__signoff { margin-top: 0.6rem !important; font-weight: 600; color: var(--text-soft) !important; font-size: 0.8rem !important; }

@media (max-width: 720px) {
  .mreport { padding: 1.5rem; }
  .mreport__hero { margin: -1.5rem -1.5rem 1.5rem; padding: 1.75rem 1.5rem; }
  .mreport__title { font-size: 1.9rem; }
  .mreport__stats { grid-template-columns: repeat(2, 1fr); }
  .mreport-guide-grid { grid-template-columns: 1fr; }
  .mreport__cert { margin: 0 -1.5rem -1.5rem; padding: 1.5rem; flex-direction: column; text-align: center; }
}

/* Print / Save-as-PDF: the on-screen report stays dark, but the printed PDF is
   a plain monochrome document — white paper, black text, thin gray rules — so
   it prints cleanly on any printer with minimal ink. The screen styles are left
   untouched; everything below is print-only. */
@media print {
  @page { margin: 12mm; }
  * { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }
  html, body { background: #fff !important; color: #000 !important; }
  .site-header, .site-footer, .mobile-tabbar, .sandbox-switcher, #sandbox-switcher,
  .mreport__toolbar, .mreport__back, #mreport-masters { display: none !important; }
  .app-main { max-width: none !important; padding: 0 !important; }
  .mreport-fmt { color: #000 !important; }
  .mreport-masters--done { background: #f4f4f4 !important; border: 1px solid #bbb !important; }
  .mreport-masters--done .mreport-masters__icon { color: #000 !important; }

  /* Flatten the whole report to black on white. */
  .mreport { border: none; box-shadow: none; padding: 0; margin: 0; border-radius: 0; background: #fff !important; }
  .mreport, .mreport * { color: #111 !important; }
  .mreport__brandsub, .mreport__project, .mreport__meta, .mreport__meta b, .mreport__sub,
  .mreport__fineprint, .mreport-stat__label, .mreport-stat__sub, .mreport-guide__body,
  .mreport-loud__nums, .mreport-file, .mreport__cert-text p { color: #444 !important; }

  /* Wordmark: drop the invert filter so it prints black on white paper. */
  .mreport__wordmark { filter: none !important; }

  /* Hero: no gradient, a firm rule underneath. */
  .mreport__hero { margin: 0 0 1.25rem !important; padding: 0 0 1rem !important;
    background: #fff !important; border-bottom: 2px solid #000 !important; border-radius: 0 !important; }
  .mreport__cert-badge { color: #000 !important; background: #fff !important; border: 1px solid #000 !important; }
  .mreport__h2::before { background: #000 !important; }

  /* Tiles, tables, cards: white fills, gray rules. */
  .mreport-stat, .mreport-guide { background: #fff !important; border: 1px solid #bbb !important; }
  .mreport-table-wrap { border: 1px solid #bbb !important; }
  .mreport-table th { background: #f0f0f0 !important; color: #000 !important; border-bottom: 1px solid #999 !important; }
  .mreport-table td { border-bottom: 1px solid #ddd !important; }
  .mreport-table tbody tr:hover { background: none !important; }
  .mreport-t__num { color: #000 !important; }
  .mreport-file__tag, .mreport-file__tag--alt, .mreport-guide__unit, .mreport__album-label {
    background: #eee !important; color: #000 !important; border: 1px solid #ccc !important; }

  /* Loudness before/after bars in grayscale. */
  .mreport-bar { background: #eee !important; }
  .mreport-bar__fill--src { background: #bbb !important; }
  .mreport-bar__fill--mst { background: #111 !important; }
  .mreport-loud__lift { color: #000 !important; font-weight: 700; }

  /* Callout + certificate. */
  .mreport-callout { background: #f4f4f4 !important; border: 1px solid #bbb !important; }
  .mreport-callout__icon { color: #000 !important; }
  .mreport__cert { background: #fff !important; border-top: 2px solid #000 !important;
    margin: 1.25rem 0 0 !important; padding: 1rem 0 0 !important; }
  .mreport__seal { background: #fff !important; border: 2px solid #000 !important; color: #000 !important; }

  /* Keep logical blocks from splitting across pages. */
  .mreport__section, .mreport-callout, .mreport-guide, .mreport__cert,
  .mreport-table-wrap, .mreport-stat, .mreport-table tr { break-inside: avoid; }
}

/* Cards inside a tab panel. */
.studio-card { margin-bottom: 1.25rem; }
.studio-card:last-child { margin-bottom: 0; }
.studio-card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem 1rem; flex-wrap: wrap; margin-bottom: 0.9rem; }
.studio-card__heading { min-width: 0; }
.studio-card__title { font-size: 1.05rem; font-weight: 700; letter-spacing: -0.01em; }
.studio-card__sub { margin: 0.2rem 0 0; font-size: 0.85rem; color: var(--text-dim); max-width: 65ch; }
.studio-card__controls { flex-shrink: 0; }
.studio-books { display: flex; flex-direction: column; gap: 0.9rem; }
.delivered-list { list-style: none; margin: 1rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }

@media (max-width: 620px) {
  /* 2×2 grid: requests | books / projects | settings. */
  .board-nav { grid-template-columns: repeat(2, 1fr); gap: 0.5rem; }
  .board-tile { padding: 0.7rem 0.85rem; }
  .board-tile__num { font-size: 1.4rem; }
  .board-tile--muted { flex-direction: row; justify-content: flex-start; align-items: center; }
  /* Keep the accordion rows succinct on phones — counts live in the expansion. */
  .client-toggle__summary { display: none; }
}

/* Clients tab: a succinct accordion — collapsed rows expand (one at a time)
   into a stack of client-specific modules. */
.client-list { display: flex; flex-direction: column; gap: 0.75rem; }
.client-card { padding: 0; overflow: hidden; }
.client-card.is-open { border-color: var(--accent-line); }
.client-card__headwrap { margin: 0; font-size: inherit; font-weight: inherit; }
.client-toggle {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 1rem 1.15rem; background: none; border: none; color: inherit; cursor: pointer;
  font-family: inherit; text-align: left;
}
.client-toggle:hover { background: var(--bg-raised-2); }
.client-toggle__id { min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.client-card__name { font-size: 1.05rem; font-weight: 700; letter-spacing: -0.01em; display: inline-flex; align-items: center; gap: 0.45rem; }
.client-card__email { font-size: 0.82rem; }
.client-dot { width: 8px; height: 8px; border-radius: 999px; background: var(--accent-bright); flex-shrink: 0; }
.client-toggle__right { display: flex; align-items: center; gap: 0.9rem; flex-shrink: 0; }
.client-toggle__summary { font-size: 0.82rem; white-space: nowrap; }
.client-chev { color: var(--text-dim); transition: transform 0.15s ease; flex-shrink: 0; }
.client-chev.is-open { transform: rotate(180deg); }
.client-card__modules { padding: 0 1.15rem 1.15rem; display: flex; flex-direction: column; gap: 0.75rem; }
.client-card__modules[hidden] { display: none; }

/* Item lists inside a module (projects, sessions, requests). */
.cl-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.cl-item { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem 0.75rem; padding: 0.5rem 0; flex-wrap: wrap; }
.cl-item + .cl-item { border-top: 1px solid var(--border); }
.cl-item__main { min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; flex: 1; }
.cl-item__title { font-weight: 700; font-size: 0.92rem; }
.cl-item__meta { font-size: 0.78rem; }
.cl-empty { margin: 0; font-size: 0.85rem; }

/* Alerts tab: clickable feedback rows that deep-link to the song. */

.alert-row { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.6rem 0.75rem; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); font-family: inherit; text-align: left; cursor: pointer; }
.alert-row:hover { border-color: var(--accent); }
.alert-row .chevron { color: var(--text-dim); font-size: 1.1rem; flex-shrink: 0; transition: transform 120ms ease; }
/* A row that EXPANDS turns its chevron down; one that navigates leaves it
   pointing along. Same glyph, two meanings, and the difference is the only
   thing telling you whether a tap will take you somewhere. */
.alert-row .chevron.is-open { transform: rotate(90deg); }

/* Projects module: each project sets status + lists its songs. */
.cl-project + .cl-project { border-top: 1px solid var(--border); margin-top: 0.75rem; padding-top: 0.75rem; }
.cl-project__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.5rem 0.75rem; flex-wrap: wrap; }
.cl-project__status { display: flex; gap: 0.3rem; flex-wrap: wrap; justify-content: flex-end; }
.cl-songs { list-style: none; margin: 0.6rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }

/* A single client-specific module inside a client card. */
.client-module { display: flex; flex-direction: column; gap: 0.65rem; padding: 0.85rem 0.9rem; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); }
.client-module__head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem 0.9rem; flex-wrap: wrap; }
/* margin:0 because these are <h2> now, not spans: the client screen is a
   top-level route and its five sections had no heading between the <h1> and
   the end of the page. The type is unchanged; only the outline is. */
.client-module__label { margin: 0; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
.credit-balance { font-size: 0.8rem; }
.credit-balance__amount { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 1.3rem; font-weight: 700; letter-spacing: -0.02em; color: var(--accent-bright); }

.credit-add { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
/* 40px on the outside, border included, so the shell matches the plain
   inputs and buttons it shares a row with rather than standing 2px proud. */
.credit-input { display: inline-flex; align-items: center; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-raised); padding-left: 0.55rem; box-sizing: border-box; min-height: 40px; }
.credit-input:focus-within { border-color: var(--accent); }
.credit-input__prefix { color: var(--text-dim); font-weight: 700; font-size: 0.9rem; }
/* The unit a grant is made in (#263). It replaced a hardcoded "$", so it sits
   where that prefix sat and reads as part of the field rather than as a second
   control beside it. */
.credit-input__unit {
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-family: inherit;
  font-weight: 700;
  font-size: 0.85rem;
  padding: 0.5rem 0.15rem 0.5rem 0;
  min-height: 38px;
}
.credit-input__unit:focus { outline: none; }
.credit-balance__amount + .credit-balance__amount { margin-left: 0.75rem; }
.credit-input input { width: 4.5rem; border: none; background: transparent; color: var(--text); font-family: inherit; font-size: 0.9rem; padding: 0.5rem 0.55rem; min-height: 38px; }
.credit-input input:focus { outline: none; }
.credit-add__notice { font-size: 0.82rem; font-weight: 700; color: var(--success); }
/* Moving granted hours onto a project (#263). Its heading gets its own line
   rather than sitting inline ahead of the controls, so the row starts where
   the grant row above it starts and the two read as a pair. */
.credit-apply { flex-direction: column; align-items: stretch; gap: 0.45rem; margin-top: 0.9rem; }
.credit-apply__row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.credit-apply__project { flex: 0 1 16rem; min-width: 10rem; }
/* The hours box takes the same bordered shell as the grant amount beside it.
   A bare number input is the one control here that can be read two ways --
   "2" of what -- and the shell is where the answer already lives. */
.credit-input--suffix { padding-left: 0; padding-right: 0.55rem; }
/* Narrower than the grant amount: this one is capped at the balance, so it is
   never more than a couple of characters, and the unit reads as attached to
   the number rather than stranded across the box. */
.credit-input--suffix input { width: 3.25rem; }
.credit-input__suffix { color: var(--text-dim); font-weight: 700; font-size: 0.9rem; }
/* Why a credit was awarded (#269), typed at award time. */
.credit-reason {
  flex: 1 1 12rem;
  min-width: 0;
  min-height: 40px;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-raised);
  color: var(--text);
  font-family: inherit;
  font-size: 0.9rem;
}
.credit-reason:focus { outline: none; border-color: var(--accent); }
/* The referral preset (#271): a shortcut beside Add, not a second primary. */
.credit-preset { white-space: nowrap; }
/* The award history, read where the next award is decided. */
.credit-history { margin-top: 0.9rem; }
.credit-log { list-style: none; margin: 0.4rem 0 0; padding: 0; }
.credit-log__row {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.35rem 0;
  border-top: 1px solid var(--border);
  font-size: 0.84rem;
}
.credit-log__amount { font-weight: 700; color: var(--success); white-space: nowrap; }
.credit-log__amount.is-spent { color: var(--text-dim); }
.credit-log__why { flex: 1 1 auto; min-width: 0; }
.credit-log__when { white-space: nowrap; font-size: 0.78rem; }

/* ---------------------------------------------------------------------
   Studio hours & availability (issue #1)
   --------------------------------------------------------------------- */

/* Collapsible board sections */
.card--accent { border-color: var(--accent); }
.studio-section { margin-bottom: 1.25rem; }
.sec-head { display: flex; align-items: flex-start; gap: 0.75rem; }
.sec-titlebtn {
  flex: 1; min-width: 0; text-align: left; background: none; border: none;
  padding: 0; cursor: pointer; color: inherit; display: block;
}
.sec-title { display: block; font-size: 1.05rem; font-weight: 700; letter-spacing: -0.01em; }
.sec-sub { display: block; font-size: 0.82rem; color: var(--text-dim); margin-top: 0.15rem; }
.sec-controls { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
.sec-toggle {
  width: 44px; height: 44px; flex-shrink: 0; display: inline-flex; align-items: center;
  justify-content: center; background: var(--bg-raised); border: 1px solid var(--border);
  border-radius: var(--radius-sm); color: var(--text); cursor: pointer;
}
.sec-toggle:hover { border-color: var(--accent-bright); }
.sec-chev { transition: transform 0.18s ease; }
.sec-chev.is-collapsed { transform: rotate(-90deg); }
.sec-body { margin-top: 0.9rem; }

/* Segmented control */
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.seg-btn {
  min-height: 40px; padding: 0 0.85rem; background: var(--bg-raised); border: none;
  color: var(--text-dim); font-size: 0.85rem; font-weight: 600; cursor: pointer;
  border-right: 1px solid var(--border);
}
.seg-btn:last-child { border-right: none; }
.seg-btn.on { background: var(--accent); color: var(--on-accent); }
.seg--sm .seg-btn { min-height: 32px; padding: 0 0.6rem; font-size: 0.78rem; }

/* Week grid */
.hg-tabs, .hg-modes { margin-bottom: 0.75rem; }
.hg-hint { font-size: 0.82rem; color: var(--text-dim); margin: 0 0 0.75rem; max-width: 65ch; }
.hg-weeknav { display: flex; align-items: center; justify-content: center; gap: 1rem; margin-bottom: 0.6rem; }
.hg-weeklabel { font-weight: 700; font-size: 0.9rem; }
.hg-grid {
  display: grid; grid-template-columns: 52px repeat(7, minmax(0, 1fr));
  border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden;
  user-select: none;
}
.hg-corner { background: var(--bg-sunken); }
.hg-colhead {
  background: var(--bg-sunken); border: none; border-bottom: 1px solid var(--border);
  border-left: 1px solid var(--border); padding: 0.35rem 0.2rem; cursor: pointer;
  color: var(--text); display: flex; flex-direction: column; align-items: center; gap: 1px;
}
.hg-colhead .hg-dow { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
.hg-colhead .hg-md { font-size: 0.72rem; color: var(--text-dim); }
.hg-colhead.is-today { background: var(--accent); color: var(--on-accent); }
.hg-colhead.is-today .hg-md { color: var(--on-accent); }
.hg-colhead.is-past { opacity: 0.45; cursor: default; }
.hg-gutter {
  height: 22px; font-size: 0.66rem; color: var(--text-dim); display: flex;
  align-items: center; justify-content: flex-end; padding-right: 0.35rem;
  border-top: 1px solid var(--border-track); background: var(--bg-sunken);
}
.hg-cell {
  height: 22px; border-top: 1px solid var(--border-track); border-left: 1px solid var(--border-track);
  position: relative; overflow: hidden; cursor: pointer;
}
/* Availability states must not read by color alone (a11y spec 2.1): open is
   the solid baseline; blocked uses diagonal stripes; booked uses a dot pattern
   (so multi-hour bookings stay distinct on rows below the client-name label);
   closed is the flat empty state. Paired with the text legend below. */
.hg-closed { background: var(--bg-deep); }
.hg-open { background: var(--accent); }
.hg-blocked {
  background: repeating-linear-gradient(-45deg, transparent, transparent 4px,
    color-mix(in oklch, var(--warn) 55%, transparent) 4px,
    color-mix(in oklch, var(--warn) 55%, transparent) 8px), var(--bg-raised);
}
.hg-booked {
  background: radial-gradient(color-mix(in oklch, var(--on-warn) 55%, transparent) 1.2px, transparent 1.3px)
    0 0 / 6px 6px, var(--success);
}
/* #561: an hour the studio's Google calendar says is taken.
   VISIBLY DISTINCT FROM BOTH NEIGHBOURS, AND NEVER BY COLOUR ALONE — the same
   rule .hg-blocked and .hg-booked already follow. Blocked is stripes leaning
   one way, booked is dots, and this is stripes leaning the OTHER way, so the
   three are told apart in greyscale, in high contrast, and on a printout.
   Wider and sparser than .hg-blocked on purpose: a block is a decision Mike
   made in this tool and can edit here, this is an observation of a calendar he
   edits somewhere else, and it should not invite a click that does nothing. */
.hg-calendar {
  background: repeating-linear-gradient(45deg, transparent, transparent 5px,
    color-mix(in oklch, var(--on-warn) 38%, transparent) 5px,
    color-mix(in oklch, var(--on-warn) 38%, transparent) 10px), var(--bg-raised);
  cursor: default;
}
.hg-calendar .hg-celllabel { color: var(--text); font-weight: 600; font-style: italic; }
.hg-legend .hg-calendar {
  background: repeating-linear-gradient(45deg, transparent, transparent 5px,
    color-mix(in oklch, var(--on-warn) 38%, transparent) 5px,
    color-mix(in oklch, var(--on-warn) 38%, transparent) 10px), var(--bg-raised);
}
.hg-cell.is-past { opacity: 0.45; cursor: default; }
.hg-cell.is-dragsel { box-shadow: inset 0 0 0 2px var(--focus); z-index: 1; }
.hg-celllabel {
  position: absolute; inset: 0; padding: 0 0.3rem; font-size: 0.64rem; font-weight: 700;
  color: var(--on-warn); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  display: flex; align-items: center;
}
.hg-booked .hg-celllabel { color: var(--on-warn); }
.hg-legend { display: flex; flex-wrap: wrap; gap: 1rem; margin: 0.7rem 0 0; font-size: 0.78rem; color: var(--text-dim); }
.hg-legend span { display: inline-flex; align-items: center; gap: 0.35rem; }
.hg-legend .sw { width: 14px; height: 14px; border-radius: 3px; display: inline-block; border: 1px solid var(--border); }
.hg-legend .hg-open { background: var(--accent); }
.hg-legend .hg-booked {
  background: radial-gradient(color-mix(in oklch, var(--on-warn) 55%, transparent) 1.2px, transparent 1.3px)
    0 0 / 6px 6px, var(--success);
}
.hg-legend .hg-blocked {
  background: repeating-linear-gradient(-45deg, transparent, transparent 3px,
    color-mix(in oklch, var(--warn) 55%, transparent) 3px,
    color-mix(in oklch, var(--warn) 55%, transparent) 6px), var(--bg-raised);
}
.hg-legend .hg-closed { background: var(--bg-deep); }

/* Staging / clear bars */
.hg-bar { margin-top: 0.9rem; padding: 0.9rem; border: 1px solid var(--accent-line); border-radius: var(--radius-sm); background: var(--bg-raised); }
.hg-bar__title { margin: 0 0 0.6rem; font-weight: 700; font-size: 0.92rem; }
.hg-bar__list { list-style: none; margin: 0 0 0.6rem; padding: 0; display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.85rem; }
.hg-bar__label { width: 100%; padding: 0.5rem 0.6rem; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); margin: 0.4rem 0; }
.hg-bar__actions { display: flex; gap: 0.5rem; margin-top: 0.4rem; }

/* Lists & forms */
.hg-lists { gap: 1.5rem; }
.hg-subhead { font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); margin: 0 0 0.6rem; }
.week-row { display: flex; align-items: flex-start; gap: 0.6rem; padding: 0.4rem 0; border-top: 1px solid var(--border-track); }
.week-row:first-of-type { border-top: none; }
.week-row__day { width: 2.5rem; font-weight: 700; font-size: 0.82rem; padding-top: 0.35rem; flex-shrink: 0; }
.week-row__wins { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.win-chip { display: inline-flex; align-items: center; gap: 0.25rem; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: 999px; padding: 0.2rem 0.5rem; font-size: 0.8rem; }
.win-chip input[type="time"] { background: none; border: none; color: var(--text); font-size: 0.8rem; width: 5.5rem; }
.win-x { background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 1rem; line-height: 1; padding: 0 0.15rem; }
.win-x:hover { color: var(--danger); }
.win-add { min-height: 32px; font-size: 0.8rem; }
.hg-fields { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.hg-field { display: flex; flex-direction: column; gap: 0.2rem; font-size: 0.78rem; color: var(--text-dim); }
.hg-field input, .hg-field select { background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); padding: 0.4rem 0.5rem; }
.hg-num { width: 6rem; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); padding: 0.4rem 0.5rem; }
.block-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.block-list li { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; padding: 0.5rem 0.6rem; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); }
.hg-rules { margin-top: 1.25rem; }
.rule { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.6rem; }
.rule__label { width: 6rem; font-size: 0.85rem; font-weight: 600; flex-shrink: 0; }

/* ---------- Studio contact settings (issue #126) ---------- */
/* Reuses .hg-field for the input styling; the label is a real <label> here
   rather than a wrapping span, so the hint can be aria-describedby instead of
   being read as part of the field's name. */
.contact-form { display: flex; flex-direction: column; gap: 0.9rem; max-width: 34rem; }
.contact-field { display: flex; flex-direction: column; gap: 0.2rem; }
.contact-field label > span { font-size: 0.85rem; font-weight: 600; color: var(--text); }
.contact-field input { width: 100%; }
.contact-field__hint { font-size: 0.78rem; color: var(--text-dim); }
/* Status is a sentence first. Colour only tints what the words already say. */
.contact-status { margin: 0.9rem 0 0; min-height: 1.2rem; font-size: 0.85rem; color: var(--text-dim); }
.contact-status.is-ok { color: var(--success); }
.contact-status.is-bad { color: var(--danger); }
.contact-preview { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--border-track); }
.contact-preview__body { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.4rem 0.9rem; }
.contact-preview__call { font-weight: 700; font-size: 1.05rem; }
.contact-preview__dials, .contact-preview__none { font-size: 0.8rem; color: var(--text-dim); }
.contact-noscript { margin: 0.8rem 0 0; font-size: 0.78rem; }

/* Blocked slots in the booking picker (staff override) */
.slot--blocked label { border-style: dashed; }
.slot-block-tag { font-size: 0.62rem; font-weight: 700; color: var(--warn); text-transform: uppercase; letter-spacing: 0.04em; }
.book-block-notice { margin: 0.75rem 0; padding: 0.75rem 0.9rem; border: 1px solid var(--warn); border-radius: var(--radius-sm); background: color-mix(in oklch, var(--warn) 12%, transparent); }
.book-block-notice p { margin: 0 0 0.5rem; font-size: 0.88rem; }

/* ---------- Booking changes (issue #12) ---------- */
/* Status-badge variants: colour reinforces a text label, never alone. */
.status-badge--pending { color: var(--warn); }
.status-badge--cancel { color: var(--danger); }

/* Client sessions list on the project view */
.session-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.session-row { display: flex; flex-direction: column; gap: 0.5rem; padding: 0.7rem 0.8rem; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); }
.session-row__main { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem 0.75rem; }
.session-when { font-weight: 600; }
.session-hours { font-size: 0.85rem; color: var(--text-dim); }
.session-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem; }
.session-help-link { margin-left: auto; }
.session-request-note { margin: 0; font-size: 0.85rem; color: var(--text-mid); }

/* Owner "Open requests" section */







/* Owner hero alert */
.hero-request-alert {
  display: inline-flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
  margin: 0 0 1.1rem; padding: 0.6rem 0.9rem;
  background: color-mix(in oklch, var(--warn) 16%, transparent);
  border: 1px solid var(--warn); border-radius: var(--radius-sm);
  color: var(--text); text-decoration: none; font-weight: 700;
}
.hero-request-alert:hover { border-color: var(--warn); color: var(--text); background: color-mix(in oklch, var(--warn) 24%, transparent); }
.hero-request-alert__count { font-size: 0.95rem; }
.hero-request-alert__cta { font-size: 0.82rem; color: var(--accent-bright); }

/* ---------- Modal (focus-trapped dialog, spec 2.2 / #20) ---------- */
.modal-overlay {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  padding: 1rem;
  background: oklch(10% 0.02 265 / 0.66);
}
.modal {
  width: 100%; max-width: 520px; max-height: calc(100vh - 2rem);
  overflow-y: auto;
  background: var(--bg-raised); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 1.25rem 1.4rem 1.4rem;
  box-shadow: 0 24px 60px oklch(0% 0 0 / 0.45);
}
.modal:focus-visible { outline: none; }
.modal__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; margin-bottom: 0.75rem; }
.modal__head h2 { font-size: 1.25rem; }
.modal__close { background: transparent; border: none; color: var(--text-dim); font-size: 1.6rem; line-height: 1; cursor: pointer; padding: 0 0.2rem; font-family: inherit; }
.modal__close:hover { color: var(--text); }
.modal__body-text { margin: 0 0 1rem; color: var(--text-mid); font-size: 0.92rem; }
.modal__actions { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-top: 0.5rem; }
/* The can't-reach-the-calendar block in the reschedule modal (#523). The
   message and its retry are wrapped together in one role="status" region so the
   button's "Checking…" relabel is actually announced; this keeps that wrapper
   from collapsing the spacing the two used to get separately. */
.modal__feed-down { margin-bottom: 1rem; }
.modal__feed-down .modal__body-text { margin-bottom: 0.75rem; }

/* Reschedule slot picker inside the modal */
/* tabindex="-1" so the modal can seed focus on the labelled group rather than
   on the × (#523). It is never reached by Tab, so it takes no focus ring — the
   same treatment #main gets for the same reason. */
.reschedule-picker { display: flex; flex-direction: column; gap: 0.8rem; margin-bottom: 0.5rem; max-height: 42vh; overflow-y: auto; }
.reschedule-picker:focus, .reschedule-picker:focus-visible { outline: none; }
.reschedule-day__label { margin: 0 0 0.35rem; font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-dim); }
.reschedule-slot-row { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.reschedule-slot {
  background: var(--bg-sunken); border: 1px solid var(--border); border-radius: 999px;
  padding: 0.35rem 0.75rem; font-size: 0.82rem; font-weight: 600; color: var(--text);
  cursor: pointer; font-family: inherit; white-space: nowrap;
}
.reschedule-slot:hover { border-color: var(--accent-bright); }
.reschedule-slot.is-selected { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.reschedule-help-fallback { display: inline-block; margin-top: 0.9rem; }

/* ---------- Booking-change request context (issue #98) ----------
   Client detail in (what they said when they raised the request) and Mike's
   handling log out (what he did about it). */

/* The client's own words, on an open request row. */
.request-said { font-size: 0.82rem; flex-basis: 100%; }
.request-detail__hint { margin: 0.35rem 0 0; font-size: 0.78rem; }

/* Sub-heading inside a client-card module ("Handled", "Handled before"). */
.cl-subhead {
  margin: 0.9rem 0 0.25rem; font-size: 0.72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim);
}

/* The handling log: newest first, one row per resolution. */
.handled-list { border-top: 1px solid var(--border); }
.handled-item { display: flex; flex-direction: column; align-items: flex-start; gap: 0.15rem; padding: 0.5rem 0; }
.handled-item + .handled-item { border-top: 1px solid var(--border); }
.handled-note { font-size: 0.85rem; color: var(--text-mid); }
/* "Handled in Square" is a TEXT marker; colour is only reinforcement. */
.status-badge--square { color: var(--accent-bright); }

/* Resolve dialog. */
.resolve-context {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.7rem;
  padding: 0.6rem 0.7rem; margin-bottom: 0.9rem; font-size: 0.85rem;
  background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.resolve-context__who { font-weight: 700; }
/* Breathing room between the read-only history and the note field below it. */
.modal__body .handled-list, .modal__body .cl-empty { margin-bottom: 1.1rem; }
.resolve-cancelled { margin: 0 0 0.75rem; font-size: 0.85rem; font-weight: 700; }
.check-row { display: flex; align-items: flex-start; gap: 0.5rem; margin: 0 0 0.5rem; }
.check-row input[type="checkbox"] { margin-top: 0.15rem; flex-shrink: 0; width: 1rem; height: 1rem; accent-color: var(--accent); }
.check-row label { font-size: 0.9rem; font-weight: 600; }
.check-hint { margin: -0.25rem 0 0.9rem 1.5rem; font-size: 0.78rem; }

/* An open request row carries a badge and an action alongside its text. On a
   phone that squeezes the booking line down to one word per line, so give the
   text the full width and let the badge and button wrap under it. */
@media (max-width: 640px) {
  .request-item .cl-item__main { flex-basis: 100%; }
}

/* ---------------------------------------------------------------------
   Square activity (issue #86) — staff-only listing of Square payments and
   refunds, grouped by client. Also used by the Clients tab Payments module.
   --------------------------------------------------------------------- */
.act-head { margin-bottom: 1.1rem; }
.act-head__title { font-size: 1.6rem; letter-spacing: -0.02em; margin: 0 0 0.25rem; }
.act-head__lead { margin: 0; font-size: 0.9rem; max-width: 62ch; }

.act-controls { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.75rem 1rem; margin-bottom: 0.9rem; }
.act-control { display: flex; flex-direction: column; gap: 0.25rem; }
.act-control__label { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
.act-select {
  background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text); padding: 0.45rem 0.6rem; font: inherit; min-width: 12rem;
  /* Same 40px as every input and button it shares a row with. */
  min-height: 40px;
}
.act-select:focus-visible { border-color: var(--accent-bright); outline: 2px solid var(--accent); outline-offset: 1px; }
.act-check { display: flex; align-items: center; gap: 0.45rem; font-size: 0.88rem; padding-bottom: 0.5rem; cursor: pointer; }
.act-check input { width: 1rem; height: 1rem; accent-color: var(--accent); }

/* #134: SQUARE_ENV / SQUARE_READ_ENV mismatch banner. Never rely on color
   alone -- the icon and the bold title both carry the "this is serious"
   signal independent of the danger-red border/background. */
.env-mismatch-banner {
  display: flex; align-items: flex-start; gap: 0.75rem;
  margin-bottom: 1rem; padding: 0.8rem 1rem;
  background: color-mix(in oklch, var(--danger) 14%, transparent);
  border: 2px solid var(--danger); border-radius: var(--radius-sm);
  color: var(--text);
}
.env-mismatch-banner svg { flex-shrink: 0; color: var(--danger); margin-top: 0.1rem; }
.env-mismatch-banner__title { margin: 0 0 0.2rem; font-weight: 700; }
.env-mismatch-banner__body { margin: 0; font-size: 0.88rem; max-width: 68ch; }

.act-status { margin-bottom: 1rem; display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem 0.9rem; }
.act-status__text { margin: 0; font-size: 0.88rem; }
.act-status__text.is-error { color: var(--danger); font-weight: 600; max-width: 62ch; }
.act-status__notice { margin: 0; font-size: 0.85rem; font-weight: 600; color: var(--accent-bright); }

.act-groups { display: flex; flex-direction: column; gap: 1rem; }
.act-group { padding: 1rem 1.1rem; }
.act-group__head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 0.5rem 1rem; margin-bottom: 0.6rem; }
.act-group__id { min-width: 0; }
.act-group__name { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.act-group__title { font-size: 1.05rem; margin: 0; }
.act-group__email { margin: 0.15rem 0 0; font-size: 0.82rem; }
.act-group__right { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.35rem 0.7rem; }
.act-group__total { font-weight: 700; font-size: 0.95rem; font-variant-numeric: tabular-nums; }
.act-group__count { font-size: 0.8rem; }
.act-group__link { font-size: 0.82rem; font-weight: 600; }
.act-group__actions { margin-top: 0.8rem; padding-top: 0.8rem; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 0.5rem; align-items: flex-start; }

/* Name field: capturing a name at create time (unmatched group) and renaming
   a placeholder afterward (group card + the per-client heading). */
.act-name { display: flex; flex-direction: column; gap: 0.25rem; width: 100%; max-width: 22rem; }
.act-name__input {
  width: 100%; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text); padding: 0.5rem 0.7rem; font: inherit;
}
.act-name__input:focus-visible { border-color: var(--accent-bright); outline: 2px solid var(--accent); outline-offset: 1px; }
.act-name__input--heading { font-size: 1.35rem; font-weight: 700; letter-spacing: -0.01em; padding: 0.3rem 0.5rem; }

.act-rows { list-style: none; margin: 0; padding: 0; }
.act-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.75rem;
  padding: 0.55rem 0; border-top: 1px solid var(--border);
}
.act-row:first-child { border-top: none; }
.act-row__when { display: flex; flex-direction: column; min-width: 8.5rem; }
.act-row__date { font-weight: 700; font-size: 0.88rem; }
.act-row__time { font-size: 0.76rem; }
.act-row__badges { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.act-row__meta { font-size: 0.8rem; flex: 1; min-width: 8rem; }
.act-row__amount { font-weight: 700; font-size: 0.95rem; font-variant-numeric: tabular-nums; margin-left: auto; }
.act-row__amount.is-refund { color: var(--danger); }
.act-row__receipt { font-size: 0.8rem; font-weight: 600; white-space: nowrap; }

.act-more { margin-top: 1rem; display: flex; justify-content: center; }

.act-merge { display: flex; flex-direction: column; gap: 0.5rem; width: 100%; }
.act-merge__title { margin: 0; font-weight: 700; font-size: 0.92rem; }
.act-merge__hint { margin: 0; font-size: 0.82rem; max-width: 62ch; }
.act-merge__row { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.act-merge--confirm { border-left: 3px solid var(--danger); padding-left: 0.75rem; }

/* The address a placeholder gets matched on (#276), above the merge panel.
   The input borrows .credit-reason's box rather than inventing a second one:
   these two fields sit inches apart on the same card, and a text box that is
   nearly-but-not-quite the neighbouring text box reads as a mistake. */
.lead-email { display: flex; flex-direction: column; gap: 0.45rem; width: 100%; margin-bottom: 1rem; }
.lead-email .act-merge__row { margin-top: 0.15rem; }
/* Sentence case, not the module heading's uppercase: this label sits directly
   under "MERGE INTO A CLIENT ACCOUNT", and two uppercase rules stacked read as
   two headings rather than a heading and a field. */
.lead-email__label { font-weight: 700; font-size: 0.92rem; color: var(--text); }
.lead-email__input {
  flex: 1 1 18rem;
  max-width: 26rem;
  min-width: 0;
  min-height: 40px;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-raised);
  color: var(--text);
  font-family: inherit;
  font-size: 0.9rem;
}
.lead-email__input::placeholder { color: var(--text-dim); }
.lead-email__input:focus-visible { border-color: var(--accent-bright); outline: 2px solid var(--accent); outline-offset: 1px; }
/* An address the browser itself rejects is marked while it is being fixed,
   not only on submit -- but never while the field is still empty or untouched,
   which would flag a placeholder Mike has simply not filled in yet. */
.lead-email__input:not(:placeholder-shown):user-invalid { border-color: var(--danger); }
.lead-email__notice { margin: 0; font-size: 0.82rem; font-weight: 600; max-width: 62ch; }
.lead-email__notice.is-error { color: var(--danger); }

/* A button standing beside a field matches that field's height. The inputs and
   selects on a client card are all 40px; .btn-sm's padding alone left the
   buttons at 30px, so every one of these rows sat a little out of true. Scoped
   to the rows where a button actually shares a line with a control -- .btn-sm
   elsewhere (inside table rows, next to headings) is correctly compact. */
.lead-email .act-merge__row .btn-sm,
.credit-add .btn-sm,
.act-merge__row .btn-sm {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
}

/* Clients tab: the Payments module reuses the row list inside a client card. */
.client-module__link { font-size: 0.78rem; font-weight: 600; }
.client-module__live { display: flex; flex-direction: column; gap: 0.5rem; align-items: flex-start; }
.client-module__live .act-rows { width: 100%; }
.cl-empty.is-error { color: var(--danger); font-weight: 600; }

.pproj-head__activity { margin: 0.4rem 0 0; font-size: 0.85rem; }

@media (max-width: 620px) {
  .act-select { min-width: 0; width: 100%; }
  .act-control { width: 100%; }
  .act-row__when { min-width: 100%; }
  .act-row__meta { min-width: 100%; flex-basis: 100%; }
  .act-row__amount { margin-left: 0; }
  .act-group__right { width: 100%; }
}

/* ---------- Self-service bookings on the account view (issue #51) ---------- */

/* Terminal session states. The badge text carries the meaning on its own; the
   muted colour only tells a finished booking apart from a live one. */
.status-badge--done { color: var(--text-dim); }

/* The account Sessions list carries a project line the project view doesn't, so
   give the controls a little air below it. */
.session-row .session-actions { margin-top: 0.15rem; }

/* ---------- Loading shells (issue #102) ----------
   The app paints before the session settles, so anything personalized needs a
   stand-in. Two rules hold everywhere: the stand-in carries real text naming
   what is being fetched (status is never motion or colour alone), and it
   occupies the real component's box so nothing shifts when the data lands.
   The global prefers-reduced-motion rule near the top of this file already
   flattens the shimmer below to a still surface. */

@keyframes nls-shell-pulse {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 0.85; }
}

/* Routes that cannot be drawn until auth resolves (#/book, #/account, the
   staff board). Reserves a slab of the main area so the footer does not jump
   up and then back down when the real view arrives. */
.route-shell {
  min-height: 60vh;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  padding: 2rem 0 0;
}
.route-shell__label { margin: 0; color: var(--text-mid); font-size: 1rem; font-weight: 600; }
.route-shell__bar {
  display: block; height: 0.85rem; width: min(100%, 34rem); border-radius: var(--radius-sm);
  background: var(--bg-raised-2);
  animation: nls-shell-pulse 1.6s ease-in-out infinite;
}
.route-shell__bar--short { width: min(100%, 21rem); }

/* Signed-in hero, before packages / credits / appointments arrive. */
.hero-authed--shell .hero-authed__eyebrow { background: var(--bg-raised-2); color: var(--text-mid); }
.hero-authed--shell h1 { color: var(--text-mid); }
/* CTA-shaped placeholders. Deliberately spans, not links: nothing focusable
   that does nothing. Sized so the real buttons land in the same place. */
.hero-authed--shell .btn.is-shell {
  min-width: 9.5rem; height: 2.6rem;
  background: var(--bg-raised-2); border-color: var(--bg-raised-2);
  animation: nls-shell-pulse 1.6s ease-in-out infinite;
}
/* Measured from the live tiles at 1280px: a next-session tile is ~99px, a
   credit tile ~112px and a project tile ~88px. Holding every shell tile in the
   middle of that range takes the hero's resize on swap from ~128px down to
   ~13px. It cannot be exactly zero: the real tile count and their contents
   differ per account, so the shell is sized for the common case (a session, a
   credit balance and one project) rather than pretending to know. */
.hero-stat-tile--shell { min-height: 6.6rem; justify-content: center; }
.hero-stat-tile--shell .tile-value--shell {
  font-family: inherit; font-size: 0.95rem; font-weight: 600; color: var(--text-mid);
  animation: nls-shell-pulse 1.6s ease-in-out infinite;
}
.hero-request-alert--shell {
  border-style: dashed; font-weight: 600; color: var(--text-mid);
  animation: nls-shell-pulse 1.6s ease-in-out infinite;
}

/* Header, before the profile and credit balance arrive. */
.avatar--shell { background: var(--bg-raised-2); animation: nls-shell-pulse 1.6s ease-in-out infinite; }

/* ---------------------------------------------------------------------
   The /book wizard (issue #184 and its step issues).
   Mobile-first, single column: this is the one flow most likely to be
   walked through on a phone in a rehearsal room. The wireframes are
   greyscale and carry structure only — every colour here is an existing
   token, and no state is signalled by colour alone.
   --------------------------------------------------------------------- */

.book-wizard {
  max-width: 30rem;
  margin: 0 auto;
}

.book-topbar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  border-bottom: 1px solid var(--border);
}
.book-topbar__title {
  font-size: 0.95rem;
  font-weight: 700;
  margin: 0;
  color: var(--text-mid);
}
.book-topbar__back {
  position: absolute;
  left: 0;
  display: grid;
  place-items: center;
  /* A 44px target: this is the one control on the screen that undoes a
     wrong turn, and it sits at the thumb-hostile top edge. */
  width: 2.75rem;
  height: 2.75rem;
  color: var(--text);
  text-decoration: none;
  font-size: 1.1rem;
}
.book-topbar__back:hover { color: var(--accent-bright); }

.book-progress { padding: 0.75rem 0 0.25rem; }
.book-progress__label {
  margin: 0 0 0.4rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-dim);
}
.book-progress__track { display: flex; gap: 0.25rem; }
.book-progress__seg {
  flex: 1;
  height: 3px;
  border-radius: 2px;
  background: var(--border-track);
}
.book-progress__seg.is-on { background: var(--accent); }

.book-step { padding: 0.5rem 0 2rem; }
.book-step__title { font-size: 1.25rem; margin: 0.5rem 0 0.25rem; }
.book-step__subtitle {
  margin: 0 0 1rem;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--text-dim);
}
.book-step__footer { margin-top: 1.5rem; }
/* The one control every step ends on, and the flow is mobile-first: give it a
   full 44px rather than the shared .btn's 40. */
.book-step__footer .btn { min-height: 2.75rem; }
.book-step__error {
  margin: 0 0 0.6rem;
  min-height: 1.2em;
  font-size: 0.85rem;
  color: var(--danger);
}
.book-step__error:empty { min-height: 0; }
/* Why you are on this step and not the one you asked for (#515). Deliberately
   NOT .book-step__error: opening a shared /book/review link is not a mistake
   the visitor made, and red text in an assertive live region says it was. */
/* A live region's sentence is present from the first paint and merely HIDDEN
   until mount() reveals it, so that the reveal is a mutation inside a region
   already in the document — which is the only thing a screen reader reliably
   announces (js/book/notice.js).

   visibility, not display:none and not a collapsed box. The text has to keep
   the exact space it will occupy once visible: it shares its paragraph with the
   retry button, and a box that grows when the sentence lands shoves that button
   out from under a thumb already reaching for it. Earlier rounds collapsed the
   chrome and then reserved a line box instead, and both were per-consumer
   guesses at a height that depends entirely on the copy — the reserve bound on
   nothing and the button moved 58px.

   No consumer classes here on purpose: every live region is covered because the
   rule matches the attribute the mechanism itself emits, so a new consumer
   cannot be left out of a list nobody remembers to update. */
[data-live-empty] {
  visibility: hidden;
}

.book-step__notice {
  margin: 0 0 1rem;
  padding: 0.6rem 0.75rem;
  border-left: 3px solid var(--accent-line);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--text-soft);
}

/* Service cards (step 1). The chosen card is marked by a heavier border AND
   the radio's own checked state, never by fill alone. */
.book-services { border: 0; padding: 0; margin: 0; }
.book-card {
  position: relative;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  padding: 0.9rem;
  margin-bottom: 0.7rem;
}
.book-card.is-chosen {
  border-color: var(--accent);
  border-width: 2px;
  background: var(--bg-raised);
}
.book-card__input {
  position: absolute;
  top: 0.95rem;
  left: 0.9rem;
  margin: 0;
}
.book-card__label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding-left: 1.6rem;
  cursor: pointer;
}
/* Stretch the label over the whole card so the target is the card, not the
   13px radio and a one-line strip of text next to it. The stepper is lifted
   above this overlay below, or its buttons would be unclickable. */
.book-card__label::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
}
.book-card__name { font-weight: 700; font-size: 0.95rem; }
.book-card__price { font-weight: 700; font-size: 0.95rem; white-space: nowrap; }
.book-card__desc {
  margin: 0.35rem 0 0;
  padding-left: 1.6rem;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--text-dim);
}
/* #516: the package included-list, aligned under the desc (past the radio)
   and tighter than the homepage .checklist so it sits inside the card. */
.book-card__includes {
  margin: 0.5rem 0 0.2rem;
  padding-left: 1.6rem;
  font-size: 0.8rem;
}

.book-stepper {
  position: relative;
  z-index: 1; /* above .book-card__label's stretched overlay */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.1rem;
  margin: 0.9rem 0 0.3rem;
}
/* A class-level `display` outranks the UA sheet's [hidden] rule, so the
   stepper would stay visible on an unchosen card without this. */
.book-stepper[hidden] { display: none; }
.book-stepper__btn {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  border: 1.5px solid var(--border);
  background: transparent;
  color: var(--text);
  font-size: 1.1rem;
  font-weight: 700;
  cursor: pointer;
}
.book-stepper__btn:hover { border-color: var(--accent-bright); color: var(--accent-bright); }
.book-stepper__value {
  min-width: 5rem;
  text-align: center;
  font-size: 1.25rem;
  font-weight: 700;
}
.book-stepper__total {
  margin: 0;
  text-align: center;
  font-size: 0.8rem;
  color: var(--text-dim);
}

.book-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.1rem 0 0.9rem;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
}
.book-divider::before,
.book-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* Step 1 focused on one service (issue #239): the card the visitor clicked on
   the homepage, alone. The way to the other two is a quiet text link, not a
   second button competing with Continue. */
.book-services--focused .book-card { margin-bottom: 0; }
.book-services__switch {
  margin: 0.9rem 0 0;
  font-size: 0.9rem;
}
.book-services__switch a { color: var(--text-dim); }
.book-services__switch a:hover,
.book-services__switch a:focus-visible { color: var(--text); }

/* Calendar + slots (step 2). */
.book-cal__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}
.book-cal__month { font-weight: 700; font-size: 0.95rem; }
.book-cal__page {
  width: 2.75rem;
  height: 2.75rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-size: 1.1rem;
  cursor: pointer;
}
.book-cal__page:hover { border-color: var(--accent-bright); color: var(--accent-bright); }
.book-cal__grid { width: 100%; border-collapse: collapse; }
.book-cal__grid th {
  padding: 0.3rem 0;
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--text-dim);
}
.book-cal__cell { padding: 2px; text-align: center; }
.book-cal__day {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 1;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  font-size: 0.85rem;
  color: var(--text-dim);
}
.book-cal__day.is-closed { color: var(--border); }
.book-cal__day.is-open {
  background: var(--bg-raised);
  color: var(--text);
  font-weight: 600;
  cursor: pointer;
}
.book-cal__day.is-open:hover { background: var(--bg-sunken); color: var(--accent-bright); }
.book-cal__day.is-chosen {
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
}

.book-slots__label,
.book-slots__prompt {
  margin: 1rem 0 0.5rem;
  font-size: 0.8rem;
  color: var(--text-dim);
}
.book-slots { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.book-slot {
  min-height: 2.75rem;
  padding: 0 0.85rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
}
.book-slot:hover { border-color: var(--accent-bright); color: var(--accent-bright); }
.book-slot.is-chosen {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.book-note {
  margin: 1rem 0 0;
  padding: 0.7rem 0.85rem;
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--text-dim);
}
.book-unavailable {
  margin: 0;
  padding: 1rem;
  border: 1.5px solid var(--warn);
  border-radius: var(--radius-sm);
  background: var(--bg-raised);
  font-size: 0.85rem;
  line-height: 1.5;
}
.book-unavailable__contact {
  color: var(--accent);
  font-weight: 600;
  text-decoration: underline;
}
/* The retry inside that notice (#523). It follows the sentence inline, so
   without this it abuts the full stop with no whitespace at all. It is also the
   single most important tap target on a screen that is already broken, and
   .btn-sm computes to about 34px — under the 44px coarse-pointer minimum #521
   adopted for the whole app. Same technique as #521: keep the small visual
   size, grow an invisible hit area on coarse pointers only. */
.book-unavailable__retry {
  position: relative;
  display: inline-block;
  margin: 0.6rem 0 0 0.4rem;
  vertical-align: middle;
}
@media (pointer: coarse) {
  .book-unavailable__retry::before {
    content: ""; position: absolute; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: 100%; min-width: 44px; height: 44px;
  }
}

/* Fields (steps 3 and 4). */
.book-field { margin-bottom: 0.85rem; }
.book-field__label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-mid);
}
.book-field__optional { font-weight: 400; color: var(--text-dim); }
.book-field__input,
.book-field__textarea {
  width: 100%;
  padding: 0.6rem 0.7rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-deep);
  color: var(--text);
  font: inherit;
  font-size: 0.9rem;
}
.book-field__input { min-height: 2.75rem; }
.book-field__textarea { resize: vertical; }

.book-pills { border: 0; padding: 0; margin: 0 0 1rem; }
.book-pills__row { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.4rem; }
.book-pill { position: relative; }
/* The input stays in the accessibility tree and keeps the label as its
   control — it is only visually replaced by the pill, so keyboard focus and
   checked state still work exactly as a native radio/checkbox does. */
.book-pill input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}
.book-pill label {
  display: grid;
  place-items: center;
  min-height: 2.5rem;
  padding: 0 0.8rem;
  border: 1.5px solid var(--border);
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-mid);
  cursor: pointer;
}
.book-pill input:checked + label {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
.book-pill input:focus-visible + label { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Review (step 5). */
.book-summary { margin: 0.5rem 0 0; }
.book-summary__row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.4rem 0;
  font-size: 0.88rem;
  color: var(--text-mid);
}
.book-summary__row.is-deduction { color: var(--success); }
.book-summary__row--total {
  margin-top: 0.4rem;
  padding-top: 0.7rem;
  border-top: 1.5px solid var(--border);
  font-weight: 700;
  font-size: 1rem;
  color: var(--text);
}
/* What a prepaid-hours draw leaves behind, under the total (#262). Quieter
   than a priced row: it is an account of the balance, not a charge. */
.book-summary__note {
  margin: 0.5rem 0 0;
  font-size: 0.8rem;
  color: var(--text-dim);
}
/* Stands in for the card field when hours cover the whole session. */
.book-covered {
  margin: 0.9rem 0 0;
  padding: 0.7rem 0.9rem;
  border-radius: var(--radius-sm);
  background: var(--bg-deep);
  font-size: 0.88rem;
  color: var(--success);
}
.book-card-field {
  min-height: 90px;
  padding: 0.5rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-deep);
}
.book-check {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin-top: 1rem;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--text-dim);
}
.book-check input { margin-top: 0.15rem; flex-shrink: 0; }

/* Confirmation. */
.book-done { text-align: center; padding-top: 1.5rem; }
.book-done__mark {
  display: grid;
  place-items: center;
  width: 3.4rem;
  height: 3.4rem;
  margin: 0 auto 1rem;
  border: 2.5px solid var(--success);
  border-radius: 50%;
  color: var(--success);
  font-size: 1.6rem;
}
.book-done__title { font-size: 1.2rem; margin: 0 0 0.4rem; }
.book-done__sub {
  margin: 0 0 1.25rem;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--text-dim);
}
.book-conf {
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  padding: 0.85rem;
  text-align: left;
}
.book-conf__line {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.3rem 0;
  font-size: 0.82rem;
  color: var(--text-dim);
}
.book-conf__line b { color: var(--text); }

.book-identity {
  padding: 0.85rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-raised);
  margin-bottom: 0.85rem;
}
.book-identity__label {
  margin: 0 0 0.2rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-dim);
}
.book-identity__name { margin: 0; font-weight: 700; }
.book-identity__email { margin: 0.1rem 0 0; font-size: 0.82rem; color: var(--text-dim); }

/* ---------------------------------------------------------------------
   Landing page (issues #207, #208, #9).
   Order is hero, pricing, rooms, gear. Mobile-first, and every
   colour is an existing token. There is deliberately no rating, star row
   or review count anywhere in here: the work and the clientele are the
   proof, so do not add one when a section looks thin.
   --------------------------------------------------------------------- */

.purchase { margin-bottom: 2.5rem; }
.buy-grid {
  list-style: none;
  margin: 0 0 0.5rem;
  padding: 0;
  display: grid;
  gap: 0.75rem;
  grid-template-columns: 1fr;
}
@media (min-width: 700px) {
  .buy-grid { grid-template-columns: repeat(2, 1fr); }
  .buy-grid--single { grid-template-columns: 1fr; }
}
.buy-card {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-raised);
}
.buy-card__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}
.buy-card__top h3 { margin: 0; font-size: 1.05rem; }
.buy-card__price { font-weight: 700; font-size: 1.05rem; white-space: nowrap; }
.buy-card__desc { margin: 0; font-size: 0.85rem; color: var(--text-dim); line-height: 1.45; }
.buy-card__detail { flex: 1; }
.buy-card .btn { margin-top: 0.25rem; min-height: 2.75rem; }

.buy-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.25rem 0;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
}
.buy-divider::before,
.buy-divider::after { content: ""; flex: 1; height: 1px; background: var(--border); }

.home-note {
  margin: 1rem 0 1.5rem;
  padding: 0.7rem 0.85rem;
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--text-dim);
}
/* ---------------------------------------------------------------------
   Keel queue (issue #196). One list, five filters, an aging clock a row.
   Status is never carried by colour alone here: `.is-urgent` only tints a
   row that already prints "Needs attention" with an icon, and `.is-stale`
   only weights a clock whose number already says how long it has been.
   --------------------------------------------------------------------- */

.queue { margin: 0; }
.queue__head h1 { margin: 0 0 0.35rem; }
.queue__sub { margin: 0 0 1.25rem; color: var(--text-dim); max-width: 62ch; }

.queue-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0.6rem;
  margin-bottom: 1rem;
}
.queue-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg-raised);
  color: var(--text-mid);
  font: inherit;
  font-size: 0.88rem;
  cursor: pointer;
}
.queue-tab:hover { border-color: var(--accent-bright); color: var(--text); }
.queue-tab.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}
.queue-tab__count {
  font-variant-numeric: tabular-nums;
  font-size: 0.78rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: color-mix(in oklch, currentColor 18%, transparent);
}

.queue-status { margin: 0 0 0.75rem; font-size: 0.85rem; color: var(--text-dim); }
.queue-empty {
  margin: 0;
  padding: 1.5rem;
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  color: var(--text-dim);
  text-align: center;
}

.queue-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem; }
.queue-row {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
  justify-content: space-between;
  padding: 0.85rem 1rem;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-left: 4px solid var(--border);
  border-radius: var(--radius-sm);
}
.queue-row.is-urgent { border-left-color: var(--danger); }
.queue-row__main { min-width: 0; }
.queue-row__title { margin: 0 0 0.2rem; display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: baseline; }
.queue-row__client { font-weight: 700; }
.queue-row__what { color: var(--text-mid); font-size: 0.9rem; }
.queue-row__body { margin: 0; font-size: 0.88rem; color: var(--text-dim); }
.queue-row__amount { margin-left: 0.5rem; font-variant-numeric: tabular-nums; color: var(--text-mid); }
.queue-row__detail {
  margin: 0.4rem 0 0;
  font-size: 0.88rem;
  color: var(--text-soft);
  border-left: 2px solid var(--border);
  padding-left: 0.6rem;
}
.queue-row__flag {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.45rem;
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--danger);
}
.queue-row__side { display: flex; flex-direction: column; align-items: flex-end; gap: 0.4rem; flex-shrink: 0; }
.queue-row__age { font-variant-numeric: tabular-nums; font-size: 0.85rem; color: var(--text-dim); }
.queue-row__age.is-stale { color: var(--warn); font-weight: 700; }
.queue-row__actions { display: flex; gap: 0.35rem; }

.queue-note { margin: 1.5rem 0 0; font-size: 0.8rem; max-width: 62ch; }

@media (max-width: 560px) {
  .queue-row { flex-direction: column; gap: 0.5rem; }
  .queue-row__side { flex-direction: row; align-items: center; justify-content: space-between; width: 100%; }
  .queue-tabs { gap: 0.3rem; }
  .queue-tab { padding: 0.4rem 0.6rem; font-size: 0.82rem; }
}

/* ---------------------------------------------------------------------
   Keel ledger (issue #198). A KPI row and a transaction table.

   The table stays a real table at every width: on a narrow screen
   .ledger-scroll scrolls it sideways inside a focusable labelled region
   rather than flattening the cells into pseudo-rows, which would strip the
   column headers of the meaning they are carrying.
   --------------------------------------------------------------------- */

.ledger { max-width: 1100px; margin: 0 auto; }
.ledger__head h1 { margin: 0 0 0.35rem; }
.ledger__sub { margin: 0 0 1.25rem; color: var(--text-dim); max-width: 62ch; }

.ledger-alert {
  margin: 0 0 1rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--danger);
  border-left: 4px solid var(--danger);
  border-radius: var(--radius-sm);
  background: var(--bg-raised);
}
.ledger-alert__title {
  margin: 0 0 0.3rem;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 700;
  color: var(--danger);
}
.ledger-alert__body { margin: 0; font-size: 0.88rem; color: var(--text-mid); }

.ledger-controls { display: flex; flex-wrap: wrap; gap: 0.75rem; margin: 0 0 0.75rem; }
.ledger-control { display: flex; align-items: center; gap: 0.45rem; }
.ledger-control__label { font-size: 0.85rem; color: var(--text-dim); }
.ledger-select {
  padding: 0.35rem 0.5rem;
  background: var(--bg-raised);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.ledger-status { margin: 0 0 0.75rem; font-size: 0.85rem; color: var(--text-dim); }

.ledger-kpis {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.6rem;
}
.ledger-kpi {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-left: 4px solid var(--border);
  border-radius: var(--radius-sm);
}
.ledger-kpi__btn {
  display: block; width: 100%; text-align: left;
  padding: 0.75rem 0.9rem;
  background: none; border: 0; border-radius: var(--radius-sm);
  color: inherit; font: inherit; cursor: pointer;
}
.ledger-kpi__btn:hover { background: var(--bg); }
/* Never colour alone: the pressed tile takes the accent on its left rule AND
   weights its label, so the state survives greyscale and high contrast. The
   warn tile keeps its danger rule — an unmatched payment does not stop being
   one because it is the tile you are reading. */
.ledger-kpi.is-active { border-left-color: var(--accent-bright); }
.ledger-kpi.is-active .ledger-kpi__label { color: var(--text); font-weight: 700; }
.ledger-kpi.is-warn { border-left-color: var(--danger); }
.ledger-kpi__label {
  margin: 0 0 0.3rem;
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-dim);
}
.ledger-kpi.is-warn .ledger-kpi__label { color: var(--danger); }
.ledger-kpi__value { display: block; margin: 0; font-size: 1.4rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.ledger-kpi__note { display: block; margin: 0.3rem 0 0; font-size: 0.78rem; color: var(--text-dim); }
.ledger-partial { margin: -0.5rem 0 1rem; font-size: 0.8rem; color: var(--warn); }

.ledger-scroll {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.ledger-scroll:focus-visible { outline: 2px solid var(--accent-bright); outline-offset: 2px; }
.ledger-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.ledger-th {
  text-align: left;
  padding: 0.6rem 0.75rem;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.ledger-th--amount, .ledger-cell--amount { text-align: right; }
.ledger-row { border-bottom: 1px solid var(--border); }
.ledger-row:last-child { border-bottom: 0; }
.ledger-row.is-anomaly { background: var(--bg-raised); }
.ledger-cell { padding: 0.6rem 0.75rem; vertical-align: top; }
.ledger-cell--when { white-space: nowrap; }
.ledger-when__date { display: block; }
.ledger-when__time { display: block; font-size: 0.8rem; color: var(--text-dim); }
.ledger-who__name { font-weight: 700; }
.ledger-who__hint, .ledger-type__note { display: block; font-size: 0.78rem; color: var(--text-dim); }
.ledger-type__status {
  display: block;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--danger);
}
.ledger-flag {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--danger);
}
.ledger-amount { font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.ledger-cell--amount.is-out .ledger-amount { color: var(--warn); }
.ledger-receipt { display: block; font-size: 0.78rem; }
.ledger-more { margin-top: 0.75rem; }
.ledger-empty {
  margin: 0;
  padding: 1.5rem;
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  color: var(--text-dim);
  text-align: center;
}
.ledger-note { margin: 1.5rem 0 0; font-size: 0.8rem; max-width: 62ch; }

@media (max-width: 560px) {
  .ledger-kpis { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
  .ledger-kpi__value { font-size: 1.15rem; }
  .ledger-table { font-size: 0.82rem; }
  .ledger-cell, .ledger-th { padding: 0.5rem 0.55rem; }
  /* On a narrow screen the table is wider than the viewport, so it scrolls —
     but the amount is the one column a ledger is read for, and a number you
     have to swipe sideways to find is a number that gets missed. It sticks to
     the right edge instead, opaque so the rest of the row passes underneath.
     The background is set per row state because a transparent sticky cell
     would show two rows at once. */
  /* With Method and Status gone, the four remaining columns are given fixed
     shares of the viewport so the table fits outright rather than scrolling —
     a ledger you have to swipe sideways is a ledger whose amounts get missed.
     The sticky rule stays as a backstop for a long client name pushing the
     table wide again. */
  .ledger-table { table-layout: fixed; }
  .ledger-th--when, .ledger-cell--when { width: 27%; }
  .ledger-th--who, .ledger-cell--who { width: 28%; }
  .ledger-th--type, .ledger-cell--type { width: 22%; }
  .ledger-th--amount, .ledger-cell--amount {
    width: 23%;
    position: sticky;
    right: 0;
    background: var(--bg);
    border-left: 1px solid var(--border);
  }
  .ledger-cell--when { white-space: normal; }
  .ledger-cell { overflow-wrap: anywhere; }
  .ledger-row.is-anomaly .ledger-cell--amount { background: var(--bg-raised); }
  /* Method is the widest column and the least load-bearing on a phone —
     "Visa ending 4242" is detail, while Type is what stops a minus sign being
     the only thing that says a row is money going out. Dropping the column
     (header and cells together, so the table stays consistent) is what lets
     Type sit on screen at rest instead of under the sticky amount. */
  /* Method and Status both come out at this width. Status can go because a
     row that did not settle now says so under its Type; a Status column that
     only ever reads "Completed" is the cheapest column to lose. */
  .ledger-th--method, .ledger-cell--method,
  .ledger-th--status, .ledger-cell--status { display: none; }
  /* Same trade, one step further: "Matched on their email address" is how
     sure we are, which is worth a column on a desktop and worth less than a
     legible Type column on a phone. The unmatched flag is NOT a hint and
     stays — the row that needs Mike is the one that must survive the squeeze. */
  .ledger-who__hint { display: none; }
}

/* Staff navigation bar (issue #222). Chrome above every staff route. ONE group
   of destinations — the two-group form that split screens by which data model
   they read is gone, and so are .staff-nav__groups/__group/__group-label. */
.staff-nav {
  margin: 0 0 1.5rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--border);
}
.staff-nav__links { display: flex; flex-wrap: wrap; gap: 0.1rem; }
/* The links are now direct children of the bar, so this is its only wrap rule.
   POLISH, NOT A FIX: measured at 375px the five destinations total ~335px and
   already sit on one row, so the media query removed above was a no-op — its
   only selectors were the group wrappers nothing emits any more. This buys a
   little room at the widths where they do start to wrap (~320px). */
@media (max-width: 560px) {
  .staff-nav__links { gap: 0.15rem 0.35rem; }
  .staff-nav__link { padding: 0.5rem 0.6rem; }
}
/* Deliberately NOT pills. The queue's filter bar directly below this is a pill
   tablist with a solid-accent active state, and giving nav the same treatment
   put two rows of identical blue pills on top of each other with different
   meanings: one navigates, one filters. Nav reads as underlined text links, so
   the accent pill stays unique to the control that actually toggles something.
   Padding is kept large enough to give a comfortable touch target on mobile. */
.staff-nav__link {
  padding: 0.35rem 0.55rem;
  border-bottom: 2px solid transparent;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  color: var(--text-mid);
  font-size: 0.9rem;
  text-decoration: none;
  white-space: nowrap;
}
.staff-nav__link:hover {
  color: var(--text);
  border-bottom-color: var(--border);
}
/* Never colour alone: the active link is also weighted and carries
   aria-current="page", so the state survives greyscale and high contrast. */
.staff-nav__link.is-active {
  color: var(--text);
  border-bottom-color: var(--accent-bright);
  font-weight: 600;
}


/* Studio calendar (issue #250, revised). A GRID on a desktop and an AGENDA on a
   phone, from one piece of markup.
   #250 ruled against a grid, and its reasoning was sound but only ever about
   phones: "who is in at 5" has to be readable one-handed, and seven columns at
   375px is about 50px each. On a desktop the same ruling produced a list of
   dates that did not look like a calendar at all, which is what a calendar is
   for — the SHAPE of a week, three empty days in a row included, is the thing
   being read.
   So: seven columns wide, and below 720px the columns collapse to one and the
   empty cells are dropped, which is the agenda #250 asked for. The hours editor
   still owns its own week grid and still means something different there
   (editing availability, not reading bookings). */
.sched-day { margin-bottom: 1.6rem; }
.sched-day__head {
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  margin: 0 0 0.5rem;
  padding-bottom: 0.35rem;
  border-bottom: 1px solid var(--border);
}
.sched-day--today .sched-day__head { color: var(--accent-bright); }
.sched-day__rows { list-style: none; margin: 0; padding: 0; }
.sched-row {
  display: grid;
  /* The client column is capped rather than free: at 1fr it stretched to half
     the row on a wide screen and left the project stranded at the far edge,
     which reads as two unrelated lists rather than one row. */
  grid-template-columns: 5.5rem 4rem minmax(8rem, 16rem) 1fr auto;
  align-items: baseline;
  gap: 0.5rem 0.75rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--border);
}
.sched-row:last-child { border-bottom: 0; }
.sched-row__time { font-weight: 700; }
.sched-row__len { color: var(--text-dim); font-size: 0.9rem; }
.sched-row__what { color: var(--text-dim); font-size: 0.92rem; }

@media (max-width: 640px) {
  /* Time and length on the first line, who and what beneath: the same
     information, stacked, rather than a row that needs a sideways scroll. */
  .sched-row {
    grid-template-columns: 5.5rem 1fr auto;
    row-gap: 0.15rem;
  }
  .sched-row__len { grid-column: 2; }
  .sched-row__who { grid-column: 1 / -1; }
  .sched-row__what { grid-column: 1 / -1; }
}

/* Saying whether a booking was real (#560).

   THE UNMARKED LINE TAKES NO WARN TONE, and that is a decision rather than an
   omission: "unknown is a real state", so this is a statement about how much of
   the book has been asserted on, not a defect count to be driven to zero. It
   gets the same dim treatment as every other quiet line on the screen — no
   colour, no icon, no border. Compare .ledger-kpi.is-warn, which is what a
   warning looks like here; this is deliberately not that. */
.sched-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}
.sched-chip {
  font: inherit;
  font-size: 0.85rem;
  color: var(--text-dim);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px;
  /* 44px of touch target on a phone, where this screen is most used. */
  padding: 0.45rem 0.9rem;
  min-height: 44px;
  cursor: pointer;
}
.sched-chip:hover { color: var(--text); border-color: var(--accent-line); }
.sched-chip[aria-pressed="true"] {
  color: var(--text);
  border-color: var(--accent-bright);
  /* State survives greyscale and high contrast, the same rule .staff-nav__link
     follows: the border alone would be a colour-only signal. */
  font-weight: 600;
}
.sched-unmarked {
  color: var(--text-dim);
  font-size: 0.88rem;
  margin: 0 0 1.2rem;
}

/* The write that did not land (#560). This one DOES take a warn tone, and it
   is the exception that proves .sched-unmarked's rule directly above: the
   unmarked count reports a true state of the book and must not nag, whereas
   this reports that the screen just failed to do the thing Mike asked for. */


/* Its own line, at every width, and NOT an implicit sixth grid column: rows
   carry a badge only sometimes, so letting the control land in whatever column
   was left over put it beside the badge on one row and wrapped into a vertical
   stack on the next. Nine rows have to be scanned as nine of the same thing. */




/* A test booking is dimmed, never hidden and never struck through: the hour is
   still taken, and the row is still the only place it can be unmarked. */
.sched-row--test .sched-row__who,
.sched-row--test .sched-row__what,
.sched-row--test .sched-row__time { opacity: 0.6; }

/* Digital wallets at checkout (#362).
   Wallets sit above the card field because a buyer who has one does not want to
   scroll past a card form to reach it. Both buttons are hidden until the SDK
   confirms the method is really available — a wallet button that does nothing
   reads as a broken site at the moment someone is trying to pay. */
.wallets { margin: 0 0 1rem; }
.wallet-btn {
  width: 100%;
  min-height: 44px; /* the touch target these are actually used at */
  border-radius: 8px;
  border: 1px solid transparent;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
/* Apple draws its own button, and we let it (#366).
   The first attempt set the label to the Apple logo glyph (U+F8FF), a
   private-use codepoint that renders as the logo on Apple platforms and as
   nothing anywhere else — so what shipped was a black button reading "Pay".
   -apple-pay-button is Safari's native control: Apple's mark, Apple's
   proportions, Apple's guidelines, and nothing for us to get wrong.
   The text inside stays for screen readers and for the fallback below. */
.wallet-btn--apple { background: #000; color: #fff; }
.wallet-btn--apple:hover { background: #111; }

@supports (-webkit-appearance: -apple-pay-button) {
  .wallet-btn--apple {
    -webkit-appearance: -apple-pay-button;
    -apple-pay-button-type: buy;
    -apple-pay-button-style: black;
    /* The native control draws its own label; ours would print over it. */
    font-size: 0;
    color: transparent;
  }
}
#google-pay-button { margin-top: 0.5rem; min-height: 44px; }
.wallet-divider {
  display: flex; align-items: center; gap: 0.75rem;
  margin: 1rem 0 0.5rem; color: var(--text-dim); font-size: 0.85rem;
}
.wallet-divider::before, .wallet-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}

/* ---------------------------------------------------------------------
   Recording work and payment (#550) — #/jobs and #/jobs/:id.

   Mobile first and checked at 375px, which is where Mike actually uses this:
   he types a lead standing in someone's building, not at a desk. Every control
   takes the shared boxes rather than the user-agent defaults, because a bare
   <select> renders 19px tall next to a 40px neighbour and the form ends up
   with three different control heights.

   The list is a real <table> at every width, scrolled sideways inside a
   focusable labelled region — the same rule the ledger keeps, so the column
   headers keep meaning something on a phone.
   --------------------------------------------------------------------- */
.jobs { max-width: 62rem; margin: 0 auto; }
.jobs__head { margin-bottom: 1rem; }
.jobs__sub { margin: 0.25rem 0 0; color: var(--text-dim); font-size: 0.9rem; }

/* The live region.
   Being present in every paint is NOT what makes it audible, and believing it
   was cost a review round. js/app.js rewrites the view with innerHTML, so this
   <p> is a brand-new node every paint however faithfully it is re-rendered,
   and a screen reader says nothing about a node that simply appeared with its
   text already in it. What makes it audible is js/book/notice.js: the sentence
   is emitted hidden and REVEALED a task later, so the announcement is a
   mutation inside a region that was already in the document. See the header of
   that file, and js/views/jobs.js's announcement(). */
.jobs-announce { margin: 0 0 0.75rem; min-height: 1.25rem; font-size: 0.88rem; color: var(--accent-bright); }

.jobs-error {
  margin: 0 0 0.9rem;
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--danger);
  border-radius: var(--radius-sm);
  background: color-mix(in oklch, var(--danger) 12%, transparent);
  font-size: 0.9rem;
}
.jobs-error:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

.jobs-lead { padding: 1rem; margin-bottom: 1.5rem; }
.jobs-lead__title { margin: 0; font-size: 1.05rem; }
.jobs-lead__sub { margin: 0.25rem 0 1rem; color: var(--text-dim); font-size: 0.85rem; }
.jobs-lead__submit { width: 100%; }

.jobs-fieldset { border: 0; padding: 0; margin: 0 0 1.25rem; }
.jobs-fieldset > legend {
  padding: 0; margin-bottom: 0.5rem;
  font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-dim);
}

.jobs-field { display: flex; flex-direction: column; gap: 0.3rem; margin: 0 0 0.85rem; }
/* A class-level `display` outranks the UA sheet's [hidden] rule, exactly as
   `.book-stepper[hidden]` above already records. Without this a field rendered
   `hidden` stays on screen, fully editable and silently ignored — which is what
   shipped here first: a second money input under the first, inviting Mike to
   type the same $250 twice, which is the precise thing the one-action form
   exists to prevent.
   Nothing on these screens toggles `hidden` any more — the form is rendered
   from state, so a field that does not apply does not exist — but the rule
   stays, because the next person to reach for `hidden` should not have to
   rediscover this. */
.jobs-field[hidden], .jobs-fieldset[hidden] { display: none; }
.jobs-field__label { font-size: 0.85rem; color: var(--text-mid); }
.jobs-field__hint { font-size: 0.78rem; color: var(--text-dim); }
.jobs-input, .jobs-textarea {
  width: 100%;
  min-height: 44px; /* a real touch target, not a 19px user-agent box */
  padding: 0.5rem 0.65rem;
  background: var(--bg-sunken);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: 1rem; /* 16px: anything smaller makes iOS zoom on focus */
}
.jobs-textarea { min-height: 5rem; resize: vertical; }
.jobs-input:focus-visible, .jobs-textarea:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

.jobs-list__title { font-size: 1rem; margin: 0 0 0.6rem; }
.jobs-empty { color: var(--text-dim); font-size: 0.9rem; padding: 0.75rem 0; }
.jobs-scroll { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.jobs-scroll:focus-visible { outline: 2px solid var(--accent-bright); outline-offset: 2px; }
.jobs-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.jobs-th {
  text-align: left; padding: 0.6rem 0.75rem;
  font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.03em;
  color: var(--text-dim); border-bottom: 1px solid var(--border); white-space: nowrap;
}
.jobs-cell { padding: 0.6rem 0.75rem; border-bottom: 1px solid var(--border); vertical-align: top; }
/* The Owed cell holds a SENTENCE now ("$250.00 agreed, not raised yet"), not
   just a figure, so it must wrap. `nowrap` was right when it was money and
   only money; left in place it forces the table wider than the phone and
   pushes the work column off the side. The figure itself still holds together,
   because the number is one token and nothing breaks inside it. */
.jobs-cell--amount { text-align: right; }
.jobs-row__link { display: block; font-weight: 600; }
.jobs-row__who { display: block; font-size: 0.8rem; color: var(--text-dim); }

.job-detail__back { margin: 0 0 0.5rem; font-size: 0.85rem; }
.job-kind {
  margin: 0 0 0.75rem; padding: 0.6rem 0.75rem;
  border-left: 3px solid var(--accent-line);
  background: var(--bg-sunken);
  font-size: 0.9rem; color: var(--text-mid);
}
.job-expected { margin: 0 0 1rem; font-size: 0.9rem; color: var(--text-dim); }

.job-money { list-style: none; display: grid; gap: 0.6rem; padding: 0; margin: 0 0 1.25rem; }
.job-money__tile { padding: 0.7rem 0.8rem; background: var(--bg-raised); border-radius: var(--radius-sm); }
.job-money__label { margin: 0; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-dim); }
.job-money__value { margin: 0.2rem 0 0; font-size: 1.25rem; font-variant-numeric: tabular-nums; }

.job-who { margin-bottom: 1.25rem; }
.job-who h2, .job-section h2, .job-record h2, .job-notes h2 { font-size: 1rem; margin: 0 0 0.5rem; }
.job-who__name { margin: 0; font-weight: 600; }
.job-who__contact, .job-who__from { margin: 0.2rem 0 0; font-size: 0.85rem; color: var(--text-dim); }

.job-section { margin-bottom: 1.25rem; }
.job-rows { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.5rem; }
.job-row {
  display: flex; flex-wrap: wrap; gap: 0.4rem 0.75rem; align-items: baseline;
  padding: 0.55rem 0.7rem; background: var(--bg-raised); border-radius: var(--radius-sm);
  font-size: 0.9rem;
}
.job-row__ref { font-variant-numeric: tabular-nums; color: var(--accent-bright); }
.job-row__main { flex: 1 1 12rem; }
.job-row__state, .job-row__rest, .job-row__when { font-size: 0.82rem; color: var(--text-dim); }

.job-record { padding: 1rem; margin-bottom: 1.5rem; }
.job-record__sub { margin: 0.25rem 0 1rem; color: var(--text-dim); font-size: 0.85rem; }
.job-record__mode { margin-bottom: 0.85rem; }
.job-record__choice { display: flex; align-items: center; gap: 0.5rem; min-height: 44px; font-size: 0.9rem; }
.job-record [type="radio"] { width: 1.1rem; height: 1.1rem; }

.job-notes { padding: 1rem; }
.job-notes__log { list-style: none; padding: 0; margin: 1rem 0 0; display: grid; gap: 0.6rem; }
.job-note { padding: 0.6rem 0.75rem; background: var(--bg-sunken); border-radius: var(--radius-sm); }
.job-note__body { margin: 0; font-size: 0.9rem; white-space: pre-wrap; }
.job-note__when { margin: 0.3rem 0 0; font-size: 0.78rem; color: var(--text-dim); }
.job-empty { margin: 0; color: var(--text-dim); font-size: 0.88rem; }

@media (min-width: 40rem) {
  .job-money { grid-template-columns: repeat(3, 1fr); }
  .jobs-lead__submit { width: auto; }
}

/* The open-receivables tile is a DIFFERENT question from the job's own
   outstanding figure, and is tinted so the two are not read as one number
   repeated. The mismatch line below them names the disagreement in words
   rather than leaving it to be noticed. */
.job-money__tile--open { border: 1px solid var(--accent-line); }
.job-money__mismatch {
  margin: -0.75rem 0 1.25rem;
  padding: 0.6rem 0.75rem;
  border-left: 3px solid var(--warn);
  background: var(--bg-sunken);
  font-size: 0.85rem;
  color: var(--text-mid);
}

/* The two Try again buttons, and the way back off a failed job screen (#550).
   Same ruling and same technique as .book-unavailable__retry above: .btn-sm
   computes to about 31px here, under the 44px coarse-pointer minimum #521
   adopted for the whole app, and a bare link is smaller still. These are the
   single most important targets on a screen that has already failed — on the
   not-found screen the back link is the only other way out — so they keep
   their small visual size and grow an invisible hit area on coarse pointers. */
.jobs-retry, .jobs-back {
  position: relative;
  display: inline-block;
  vertical-align: middle;
}
@media (pointer: coarse) {
  .jobs-retry::before, .jobs-back::before {
    content: ""; position: absolute; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: 100%; min-width: 44px; height: 44px;
  }
}


/* ---------------------------------------------------------------------------
   Classifying test data (#560). The one-time question in "For me", the badge
   every settled row shows instead, and the surfaces added around them.
   --------------------------------------------------------------------------- */

/* The two buttons of the one-time question. They sit at the end of a queue row
   and are the most-tapped new control in the app. */
.classify { display: inline-flex; gap: 0.35rem; flex-shrink: 0; }
/* 44px is the minimum the rest of the site holds itself to on a touch screen,
   and .btn-sm is about 30px. Grown rather than padded so the two targets stay
   side by side and do not start wrapping under the row they belong to. */
@media (pointer: coarse) {
  .classify .btn-sm { min-height: 44px; min-width: 56px; }
}

/* The settings toggle that decides whether marked-test rows are on screen. */
.purpose-toggle {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.4rem 0.6rem; cursor: pointer;
}
@media (pointer: coarse) { .purpose-toggle { min-height: 44px; } }

/* The queue's second table: what is new, under what is unresolved. */
.queue-needsme { margin-top: 1.75rem; display: grid; gap: 0.85rem; }

/* Badges at the end of a row — the channel a lead came in on, "gone quiet",
   an inherited test mark. Wraps under the text on a narrow screen rather than
   squeezing the name. */
.cl-item__badges {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.35rem; flex-shrink: 0;
}

/* The ledger labels a test client's settled money rather than withholding it. */
.ledger-who__test { margin-top: 0.2rem; align-self: flex-start; }

/* A heading with an action beside it: "Leads" + New lead, Projects + Import. */
.jobs-list__bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 0.6rem; margin: 1.5rem 0 0.75rem;
}
.jobs-list__bar .jobs-list__title { margin: 0; }

/* The comms thread on a lead, collapsed. <details> so it keeps its own state
   across the re-renders this screen does constantly. */
.comms-thread { margin-top: 0.5rem; }
.comms-thread > summary {
  cursor: pointer; color: var(--text-dim); font-size: 0.85rem;
  padding: 0.35rem 0; list-style-position: inside;
}
.comms-thread > summary:hover { color: var(--text); }
@media (pointer: coarse) { .comms-thread > summary { padding: 0.6rem 0; } }

/* "This one is a test" on the new-lead form. .jobs-field stacks its label above
   its control, which is right for every other field and wrong for a checkbox. */
.jobs-field--check {
  flex-direction: row; align-items: center; gap: 0.55rem;
  cursor: pointer; margin-top: 0.5rem;
}
@media (pointer: coarse) { .jobs-field--check { min-height: 44px; } }

/* Studio hours on the calendar, under the sessions, collapsed by default. */
.sched-hours {
  margin-top: 2rem;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
/* Padding lives on the summary and the body rather than the card, so the whole
   header strip is the hit target when it is closed — a card whose padding sits
   outside the <summary> has a dead border you can click and nothing happens. */
.sched-hours > summary {
  cursor: pointer; display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 0.5rem; padding: 1rem 1.25rem; list-style-position: inside;
  border-radius: var(--radius);
}
.sched-hours > summary:hover { color: var(--text); }
.sched-hours[open] > summary {
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius) var(--radius) 0 0;
}
@media (pointer: coarse) { .sched-hours > summary { padding: 1.15rem 1.25rem; } }
.sched-hours__title { font-weight: 600; }
.sched-hours__line { font-size: 0.9rem; }
.sched-hours__body { padding: 1.25rem; }


/* One client, in full (js/views/studioClient.js). The projects module holds a
   project's whole record inline, one open at a time. */
.cl-project.is-open { border-color: var(--border); }
.pproj-body { margin-top: 0.85rem; display: grid; gap: 1.25rem; }
.pproj-body .pproj-section { margin: 0; }


/* --- Studio calendar: two weeks ------------------------------------------ */
.sched-cal { margin: 0 0 2rem; }
.sched-week + .sched-week { margin-top: 1.5rem; }
.sched-week__label {
  font-size: 0.72rem; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-dim); margin: 0 0 0.5rem;
}
.sched-week__days { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.4rem; }

.sched-cell {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0.5rem 0.45rem; min-height: 6.5rem; display: flex; flex-direction: column; gap: 0.4rem;
}
/* A day already gone is still part of the week's shape, so it is shown and
   receded rather than removed. */
.sched-cell.is-past { opacity: 0.55; }
.sched-cell.is-today { border-color: var(--accent-bright); }
.sched-cell__head { display: flex; align-items: baseline; gap: 0.35rem; }
.sched-cell__dow { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
.sched-cell__num { font-size: 0.95rem; font-weight: 600; }
/* Never colour alone: today is also weighted, so the state survives greyscale. */
.sched-cell.is-today .sched-cell__num { color: var(--accent-bright); }
.sched-cell__items { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.3rem; }
/* Only an empty TODAY draws this (js/views/schedule.js dayCell). It is the one
   blank cell the phone rule keeps, so it is the one that has to say it is free
   rather than look unloaded. */
.sched-cell__empty { margin: 0; font-size: 0.78rem; }

.sched-chip__item {
  width: 100%; text-align: left; display: grid; gap: 0.1rem;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0.35rem 0.4rem; cursor: pointer; color: inherit; font: inherit;
}
.sched-chip__item:hover { border-color: var(--text-dim); }
.sched-chip__time { font-weight: 600; font-size: 0.8rem; }
.sched-chip__who { font-size: 0.8rem; }
.sched-chip__what { font-size: 0.72rem; }
.sched-chip__item.is-test { opacity: 0.7; }
@media (pointer: coarse) { .sched-chip__item { min-height: 44px; } }

/* The agenda #250 asked for: one column, and only the days with something on
   them. Fourteen rows, half of them blank, is not a list worth scrolling. */
@media (max-width: 720px) {
  .sched-week__days { grid-template-columns: 1fr; gap: 0.3rem; }
  .sched-cell { min-height: 0; flex-direction: row; align-items: baseline; gap: 0.75rem; }
  .sched-cell.is-empty { display: none; }
  /* ...but never today, whatever is or is not on it. `is-past` only RECEDES a
     day (opacity 0.55), so a phone kept every past day carrying a booking and
     dropped the one day the reader is standing on the moment it was free — and
     `aria-current="date"` went with it, which is the agenda's only you-are-here
     marker and the only one a screen reader ever had. */
  .sched-cell.is-empty.is-today { display: flex; }
  .sched-cell__head { min-width: 3.5rem; }
  .sched-cell__items { flex: 1; }
  .sched-cell__empty { flex: 1; }
}
