/* ══════════════════════════════════════════════════════════════════════════
   GymGuard — shared dark theme (Lucide icons, fully responsive)
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ══ Design tokens — the ONLY place colours are defined. See frontend/DESIGN.md.
     Monochrome: black and white, with greys between. Colour is reserved for
     meaning (green ok, red bad, amber owed, purple refunded) and never used
     for decoration or branding. Night is the default; Day overrides below. */
  color-scheme: dark;
  --bg: #0a0a0a;
  --panel: #111111;
  --card: #161616;
  --card-hover: #1d1d1d;
  --border: #262626;
  --border-strong: #363636;
  --text: #fafafa;
  --muted: #a3a3a3;
  --faint: #6e6e6e;
  --accent: #fafafa;
  --accent-hover: #e0e0e0;
  --accent-dim: rgba(255, 255, 255, 0.07);
  --accent-text: #0a0a0a;
  --hover-tint: rgba(255, 255, 255, 0.03);
  --scrim: rgba(0, 0, 0, 0.7);
  --code-text: #d4d4d4;
  --switch-knob: #ffffff;
  --scrollbar: #2e2e2e;
  --focus-border: #5c5c5c;
  --green: #22c55e;
  --green-dim: rgba(34, 197, 94, 0.12);
  --red: #ef4444;
  --red-dim: rgba(239, 68, 68, 0.12);
  --amber: #f59e0b;
  --amber-dim: rgba(245, 158, 11, 0.12);
  --purple: #a855f7;
  --purple-dim: rgba(168, 85, 247, 0.12);
  /* Neutral "info" — discounts, renewals, notes. Not a colour on purpose. */
  --info: #d4d4d4;
  --info-dim: rgba(255, 255, 255, 0.08);
  /* Chart series: ink, then greys. */
  --chart-1: #e5e5e5;
  --chart-2: #8a8a8a;
  --chart-3: #bdbdbd;
  --chart-4: #5e5e5e;
  --chart-5: #3a3a3a;
  --radius: 10px;
  --radius-sm: 7px;
  --sidebar-w: 264px;
  --topbar-h: 64px;
  --font: "Inter", -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-display: "Inter", -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
  --ring: 0 0 0 3px rgba(255, 255, 255, 0.14);
}

/* ── Day ─────────────────────────────────────────────────────────────────── */
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f5f5f5;
  --panel: #ffffff;
  --card: #ffffff;
  --card-hover: #f4f4f4;
  --border: #e4e4e4;
  --border-strong: #d0d0d0;
  --text: #0a0a0a;
  --muted: #555555;
  --faint: #8c8c8c;
  --accent: #0a0a0a;
  --accent-hover: #262626;
  --accent-dim: rgba(0, 0, 0, 0.05);
  --accent-text: #ffffff;
  --hover-tint: rgba(0, 0, 0, 0.025);
  --scrim: rgba(10, 10, 10, 0.4);
  --code-text: #262626;
  --switch-knob: #ffffff;
  --scrollbar: #cfcfcf;
  --focus-border: #8c8c8c;
  --green: #15803d;
  --green-dim: rgba(22, 163, 74, 0.1);
  --red: #dc2626;
  --red-dim: rgba(220, 38, 38, 0.08);
  --amber: #b45309;
  --amber-dim: rgba(217, 119, 6, 0.1);
  --purple: #7e22ce;
  --purple-dim: rgba(147, 51, 234, 0.08);
  --info: #404040;
  --info-dim: rgba(0, 0, 0, 0.05);
  --chart-1: #171717;
  --chart-2: #8a8a8a;
  --chart-3: #4a4a4a;
  --chart-4: #b5b5b5;
  --chart-5: #d9d9d9;
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.12);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
  --ring: 0 0 0 3px rgba(0, 0, 0, 0.1);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* `hidden` is set from JS all over these pages, and the browser's own
   `[hidden] { display: none }` is weaker than any class of ours that sets a
   display — a flex row would keep showing while the code believed it gone.
   This makes the attribute mean what it says, everywhere. */
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
input, select, textarea { font-family: inherit; }

/* ── Typography system ───────────────────────────────────────────────────── */
/* Display font for headings/numbers; Inter for body; JetBrains Mono for IDs. */

h1, h2, h3, h4,
.brand-name,
.section-title,
.stat-value,
.welcome h2,
.auth-hero h1,
.auth-card h2,
.panel-head h3,
.modal-head h3,
.tpl-head h4 {
  font-family: var(--font-display);
  font-weight: 600;
}

.auth-hero h1, .welcome h2, .auth-card h2 { font-weight: 700; }
.stat-value { font-weight: 700; }

.mono, .tpl-key { font-family: var(--font-mono); }

/* Money and counts line up digit under digit. Only on figures: Inter's tabular
   set also widens the hyphen, which spreads words like "check-in" apart. */
.stat-value, .pay-v, td, .led-amt, .rcp-amt, .sc-total, .sc-stat b, .sc-pay b,
.sub-money b, .sub-inst-amt, .rc-amt, .rc-row b { font-variant-numeric: tabular-nums; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--scrollbar); border-radius: 8px; border: 2px solid var(--bg); }
::-webkit-scrollbar-track { background: transparent; }
::selection { background: var(--accent); color: var(--accent-text); }

/* ── Lucide icons ────────────────────────────────────────────────────────── */

svg.lucide { width: 18px; height: 18px; stroke-width: 2; flex: none; }
.btn svg.lucide { width: 16px; height: 16px; }
.btn-sm svg.lucide { width: 14px; height: 14px; }
.brand-mark svg.lucide { width: 22px; height: 22px; }
.stat-ico svg.lucide { width: 17px; height: 17px; color: var(--muted); }
.empty-state svg.lucide { width: 34px; height: 34px; color: var(--faint); margin-bottom: 12px; }
.modal-close svg.lucide { width: 18px; height: 18px; }
.auth-point .dot svg.lucide { width: 13px; height: 13px; }
.search-wrap svg.lucide {
  width: 15px; height: 15px; color: var(--faint);
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  pointer-events: none;
}

/* ── Auth (login) layout ─────────────────────────────────────────────────── */

.auth-shell {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  grid-template-columns: 1.05fr 1fr;
}

.auth-brand {
  background: var(--panel);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 48px 56px;
}

.brand-row { display: flex; align-items: center; gap: 12px; min-width: 0; }

.brand-mark {
  width: 42px; height: 42px; flex: none;
  border-radius: 12px;
  background: var(--accent);
  color: var(--accent-text);
  display: grid; place-items: center;
}

.brand-name { font-size: 18px; font-weight: 700; letter-spacing: -0.02em; white-space: nowrap; }
/* No nowrap: the gym name is appended here and a long one must wrap inside the
   sidebar rather than run out of it. */
.brand-sub { font-size: 12px; color: var(--muted); margin-top: 1px; }

.auth-hero h1 {
  font-size: clamp(30px, 3.4vw, 42px);
  line-height: 1.12;
  letter-spacing: -0.03em;
  font-weight: 700;
  max-width: 480px;
}

.auth-hero p { color: var(--muted); margin-top: 16px; max-width: 420px; line-height: 1.65; }

.auth-points { margin-top: 34px; display: flex; flex-direction: column; gap: 14px; }

.auth-point { display: flex; align-items: center; gap: 12px; color: var(--muted); font-size: 13.5px; }

.auth-point .dot {
  width: 28px; height: 28px; border-radius: 9px; flex: none;
  background: var(--card); border: 1px solid var(--border);
  display: grid; place-items: center; color: var(--green);
}

.auth-foot { color: var(--faint); font-size: 12px; }

.auth-side {
  display: flex; align-items: center; justify-content: center;
  padding: 40px 24px;
}

.auth-card { width: 100%; max-width: 420px; }

.auth-card h2 { font-size: 24px; letter-spacing: -0.02em; margin-bottom: 6px; }
.auth-card > p { color: var(--muted); margin-bottom: 26px; }

.role-tabs {
  display: grid; grid-template-columns: 1fr 1fr;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 4px; gap: 4px;
  margin-bottom: 22px;
}

.role-tab {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: 0; background: transparent; color: var(--muted);
  padding: 10px 8px; border-radius: 7px; font-size: 13.5px; font-weight: 600;
  transition: all .15s ease;
}
.role-tab svg.lucide { width: 15px; height: 15px; }
.role-tab.active { background: var(--accent); color: var(--accent-text); }
/* Same pill shape as the payment-history switch (.mp-tabs). */
.role-tabs, .role-tab { border-radius: 999px; }

/* ── Forms ───────────────────────────────────────────────────────────────── */

.field { margin-bottom: 16px; }
.field label { display: block; font-size: 12.5px; font-weight: 600; color: var(--muted); margin-bottom: 7px; }

.field input, .field select, .field textarea {
  width: 100%;
  background: var(--card);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: var(--radius-sm);
  padding: 11px 13px;
  font-size: 14px;
  outline: none;
  transition: border-color .15s ease, box-shadow .15s ease;
}

.field textarea { resize: vertical; min-height: 90px; line-height: 1.5; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--focus-border); box-shadow: var(--ring); }
.field input::placeholder, .field textarea::placeholder { color: var(--faint); }
.field input:disabled { opacity: .6; cursor: not-allowed; }

.field select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%238f8f99' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 36px;
}

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

.check-row { display: flex; align-items: center; gap: 9px; margin: 4px 0 14px; }
.check-row input { width: 15px; height: 15px; accent-color: var(--accent); }
.check-row label { font-size: 13px; color: var(--muted); }

/* ── Buttons ─────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border-radius: var(--radius-sm);
  padding: 11px 18px;
  font-size: 13.5px; font-weight: 600;
  border: 1px solid transparent;
  transition: all .15s ease;
  white-space: nowrap;
}
.btn:focus-visible { outline: none; box-shadow: var(--ring); }
.btn:active { transform: translateY(1px); }

.btn-primary { background: var(--accent); color: var(--accent-text); width: 100%; }
.btn-primary:hover { background: var(--accent-hover); }

.btn-ghost {
  background: var(--card); color: var(--text);
  border-color: var(--border); width: 100%;
}
.btn-ghost:hover { background: var(--card-hover); border-color: var(--border-strong); }

.btn-sm { padding: 7px 12px; font-size: 12.5px; width: auto; border-radius: 8px; }
.btn-danger-ghost { background: transparent; color: var(--red); border-color: transparent; }
.btn-danger-ghost:hover { background: var(--red-dim); }
.btn-danger { background: var(--red); color: #fff; }
.btn-danger:hover { opacity: .9; }
.btn[disabled], .btn:disabled { opacity: .45; cursor: not-allowed; pointer-events: none; }

.icon-btn {
  display: inline-grid; place-items: center;
  width: 38px; height: 38px; flex: none;
  border-radius: 10px;
  background: transparent; border: 1px solid transparent;
  color: var(--muted);
  transition: all .14s ease;
}
.icon-btn:hover { background: var(--card); color: var(--text); border-color: var(--border); }

/* Day/Night switch: shows the sun at night (tap for day) and the moon by day. */
.theme-toggle { border-color: var(--border); color: var(--muted); }
.theme-toggle:hover { color: var(--text); }
.theme-toggle svg.lucide { width: 17px; height: 17px; }
.theme-toggle .when-light { display: none; }
:root[data-theme="light"] .theme-toggle .when-light { display: inline-block; }
:root[data-theme="light"] .theme-toggle .when-dark { display: none; }
.auth-side { position: relative; }
.auth-theme { position: absolute; top: 20px; right: 20px; }
.scan-top-actions { display: flex; align-items: center; gap: 8px; }

.divider {
  display: flex; align-items: center; gap: 12px;
  color: var(--faint); font-size: 12px; margin: 20px 0;
}
.divider::before, .divider::after { content: ""; height: 1px; flex: 1; background: var(--border); }

/* ── App shell (dashboard) ───────────────────────────────────────────────── */

.shell { display: flex; min-height: 100vh; min-height: 100dvh; }

.sidebar {
  width: var(--sidebar-w);
  background: var(--panel);
  border-right: 1px solid var(--border);
  padding: 22px 16px;
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh; height: 100dvh;
  z-index: 95;
}

.sidebar .brand-row { padding: 0 8px 22px; }

.nav { display: flex; flex-direction: column; gap: 4px; flex: 1; overflow-y: auto; }

.nav-item {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 13px;
  border-radius: 10px;
  color: var(--muted);
  font-weight: 600; font-size: 13.5px;
  border: 0; background: transparent; text-align: left;
  transition: all .13s ease;
  width: 100%;
}

.nav-item:hover { color: var(--text); background: var(--card); }
/* Tinted row with a brand bar on the left — marks the page without shouting. */
.nav-item.active { background: var(--accent-dim); color: var(--text); box-shadow: inset 3px 0 0 var(--accent); }
.nav-item.active .ico { color: var(--text); }
.nav-item .ico { width: 20px; display: inline-flex; align-items: center; justify-content: center; flex: none; }

.sidebar-foot { border-top: 1px solid var(--border); padding-top: 14px; display: flex; flex-direction: column; gap: 4px; }

.sidebar-backdrop {
  display: none;
  position: fixed; inset: 0; z-index: 90;
  background: var(--scrim);
}

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: var(--topbar-h);
  padding: 10px 32px;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
  position: sticky; top: 0; z-index: 80;
}

.topbar-left { display: flex; align-items: center; gap: 10px; min-width: 0; }

.menu-btn { display: none; }

.crumb { color: var(--muted); font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.crumb b { color: var(--text); font-weight: 600; }

.top-right { display: flex; align-items: center; gap: 14px; flex: none; }

.who { text-align: right; line-height: 1.25; }
.who .who-name { font-weight: 600; font-size: 13.5px; }
.who .who-role { color: var(--muted); font-size: 11.5px; }

.avatar {
  width: 38px; height: 38px; border-radius: 50%; flex: none;
  background: var(--card-hover);
  border: 1px solid var(--border-strong);
  display: grid; place-items: center;
  font-weight: 700; font-size: 13px;
}

/* The avatar is a button so the menu opens from the keyboard too. */
button.avatar { cursor: pointer; color: var(--text); font-family: inherit; }
button.avatar:hover { border-color: var(--accent); }

.who-menu { position: relative; }

.who-menu-pop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 90;
  min-width: 190px; padding: 6px;
  display: none; flex-direction: column; gap: 2px;
  background: var(--panel);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
}
.who-menu-pop.open { display: flex; animation: fade-up .14s ease; }

.who-menu-item {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 11px; border-radius: 8px;
  background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 13px; text-align: left;
  color: var(--text);
}
.who-menu-item:hover { background: var(--card-hover); }
.who-menu-item.danger { color: var(--red); }
.who-menu-item i { width: 15px; height: 15px; }

.content {
  padding: 30px 32px 60px;
  display: flex; flex-direction: column; gap: 24px;
  width: 100%; max-width: 1480px; margin: 0 auto;
}

.page-section { display: none; flex-direction: column; gap: 24px; }
.page-section.active { display: flex; animation: fade-up var(--reveal-dur) var(--reveal-ease) both; }

@keyframes fade-up { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ── Reveal ───────────────────────────────────────────────────────────────
   Data that arrives after a spinner has to *arrive*: a table that swaps a
   loader for forty rows in one frame reads as a jolt, not as an answer. One
   curve and one duration for every such hand-over on every page, so the app
   moves the same way whichever screen the owner is on. `gg-reveal` is put on
   by GG.reveal / the global loader-swap observer in api.js, never by hand in
   a template — the animation has to restart on each hand-over, and a class
   already sitting in the markup would only ever play once. */
:root { --reveal-dur: .34s; --reveal-ease: cubic-bezier(.2, .75, .25, 1); }

@keyframes gg-reveal { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.gg-reveal, .gg-reveal-stagger > * {
  animation: gg-reveal var(--reveal-dur) var(--reveal-ease) both;
}

/* The stagger is a sweep down the list, not a per-row entrance: it stays small
   (30ms) and stops climbing after ten, or a long table would still be dealing
   itself out a second after the data landed. */
.gg-reveal-stagger > *:nth-child(1) { animation-delay: 0ms; }
.gg-reveal-stagger > *:nth-child(2) { animation-delay: 30ms; }
.gg-reveal-stagger > *:nth-child(3) { animation-delay: 60ms; }
.gg-reveal-stagger > *:nth-child(4) { animation-delay: 90ms; }
.gg-reveal-stagger > *:nth-child(5) { animation-delay: 120ms; }
.gg-reveal-stagger > *:nth-child(6) { animation-delay: 150ms; }
.gg-reveal-stagger > *:nth-child(7) { animation-delay: 180ms; }
.gg-reveal-stagger > *:nth-child(8) { animation-delay: 210ms; }
.gg-reveal-stagger > *:nth-child(9) { animation-delay: 240ms; }
.gg-reveal-stagger > *:nth-child(n+10) { animation-delay: 270ms; }

.section-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}

/* ── Welcome banner ──────────────────────────────────────────────────────── */

.welcome {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 26px 28px;
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  flex-wrap: wrap;
}

.welcome .hello { color: var(--muted); font-size: 13px; }
.welcome h2 { font-size: clamp(21px, 2.6vw, 26px); letter-spacing: -0.02em; margin: 3px 0 5px; }
.welcome .sub { color: var(--muted); font-size: 13.5px; }
.welcome-actions { display: flex; gap: 10px; flex-wrap: wrap; }

/* ── Stat cards ──────────────────────────────────────────────────────────── */

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: 16px;
}

.stat-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 22px;
  transition: border-color .15s ease, transform .15s ease;
  /* Each card is a <button> — every stat opens the list behind it. Undo what a
     button brings with it so the tile still reads as a tile. */
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.stat-card:focus-visible { outline: none; border-color: var(--border-strong); box-shadow: var(--ring); }

.stat-card:hover { border-color: var(--border-strong); transform: translateY(-1px); }

.stat-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; gap: 8px; }
.stat-label { color: var(--muted); font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }

.stat-ico {
  width: 36px; height: 36px; border-radius: 10px; flex: none;
  background: var(--panel); border: 1px solid var(--border);
  display: grid; place-items: center;
}

.stat-value { font-size: clamp(26px, 2.8vw, 32px); font-weight: 700; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.stat-foot { margin-top: 8px; font-size: 12.5px; color: var(--muted); }
.stat-foot .up { color: var(--green); }
.stat-foot .down { color: var(--red); }

/* ── Panels / tables ─────────────────────────────────────────────────────── */

.panel {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.panel-head {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 18px 22px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}

.panel-head h3 { font-size: 15.5px; letter-spacing: -0.01em; }
/* Small muted note — used under panel titles, form fields and in modals */
.hint { color: var(--muted); font-size: 12.5px; margin-top: 2px; }
.panel-tools { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

.search-wrap { position: relative; }

.search-input {
  background: var(--panel); border: 1px solid var(--border); color: var(--text);
  border-radius: 8px; padding: 8px 12px 8px 34px; font-size: 13px; outline: none; width: 240px; max-width: 100%;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.search-input:focus { border-color: var(--focus-border); box-shadow: var(--ring); }
.search-input::placeholder { color: var(--faint); }

.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

table { width: 100%; border-collapse: collapse; }

thead th {
  text-align: left; padding: 11px 22px;
  color: var(--muted); font-size: 11px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  border-bottom: 1px solid var(--border);
  background: var(--hover-tint);
  white-space: nowrap;
}

tbody td { padding: 13px 22px; border-bottom: 1px solid var(--border); font-size: 13.5px; white-space: nowrap; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr { transition: background .12s ease; }
tbody tr:hover { background: var(--hover-tint); }

.row-actions { display: inline-flex; gap: 6px; }

.cell-main { font-weight: 600; }
.cell-sub { color: var(--muted); font-size: 12px; margin-top: 2px; }
.mono { font-size: 12.5px; color: var(--muted); }

.empty-state { padding: 46px 20px; text-align: center; color: var(--muted); }

/* ── Badges ──────────────────────────────────────────────────────────────── */

.badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600;
  white-space: nowrap;
}

.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.badge-green { background: var(--green-dim); color: var(--green); }
.badge-red { background: var(--red-dim); color: var(--red); }
.badge-amber { background: var(--amber-dim); color: var(--amber); }
.badge-blue { background: var(--info-dim); color: var(--info); }
.badge-purple { background: var(--purple-dim); color: var(--purple); }
.badge-gray { background: var(--accent-dim); color: var(--muted); }

/* ── Badge button (clickable status) ─────────────────────────────────────── */
.badge-btn {
  border: 1px solid transparent;
  cursor: pointer;
  background: inherit;
  font-family: inherit;
  transition: all 0.15s ease;
  user-select: none;
}
.badge-btn:hover {
  filter: brightness(1.22);
  border-color: currentColor;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}
.badge-btn:active {
  transform: translateY(0);
}

/* ── Status Modal Styles ─────────────────────────────────────────────────── */
.status-member-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 8px);
  margin-bottom: 16px;
}
.status-member-name {
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
}
.status-member-meta {
  font-size: 12px;
  color: var(--muted);
  margin-top: 2px;
}
.status-options-grid {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.status-option-card {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 8px);
  background: var(--card);
  cursor: pointer;
  transition: all 0.15s ease;
}
.status-option-card input[type="radio"] {
  margin-top: 3px;
  accent-color: var(--accent);
  width: 16px;
  height: 16px;
  flex: none;
}
.status-option-card:hover {
  background: var(--card-hover);
  border-color: var(--border-strong);
}
.status-option-card.is-selected {
  border-color: var(--accent);
  background: var(--accent-dim);
}
.status-option-info {
  flex: 1;
}
.status-option-top {
  display: flex;
  align-items: center;
  gap: 8px;
}
.status-pill {
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.status-option-desc {
  font-size: 12px;
  color: var(--muted);
  margin-top: 4px;
  line-height: 1.4;
}

/* ── Toggle switch ───────────────────────────────────────────────────────── */

.switch { position: relative; display: inline-block; width: 40px; height: 22px; flex: none; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider {
  position: absolute; inset: 0; border-radius: 999px;
  background: var(--border-strong); transition: .18s; cursor: pointer;
}
.switch .slider::before {
  content: ""; position: absolute; width: 16px; height: 16px;
  border-radius: 50%; background: var(--switch-knob); top: 3px; left: 3px; transition: .18s;
  box-shadow: 0 1px 3px rgba(0,0,0,.4);
}
.switch input:checked + .slider { background: var(--green); }
.switch input:checked + .slider::before { transform: translateX(18px); }
.switch input:focus-visible + .slider { box-shadow: var(--ring); }

/* ── Template cards ──────────────────────────────────────────────────────── */

.tpl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 330px), 1fr));
  gap: 16px;
}

.tpl-card {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 20px;
  display: flex; flex-direction: column; gap: 12px;
  transition: border-color .15s ease, transform .15s ease;
}
.tpl-card:hover { border-color: var(--border-strong); transform: translateY(-1px); }

.tpl-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.tpl-head h4 { font-size: 14.5px; }
.tpl-key { color: var(--faint); font-size: 11.5px; margin-top: 3px; word-break: break-all; }
.tpl-desc { color: var(--muted); font-size: 12.5px; line-height: 1.55; }

.tpl-body {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 12px 14px;
  font-size: 12.5px; color: var(--code-text); line-height: 1.6;
  white-space: pre-wrap; max-height: 120px; overflow-y: auto;
  overflow-wrap: anywhere;
}

.tpl-label { font-size: 11px; font-weight: 700; letter-spacing: .07em; color: var(--faint); text-transform: uppercase; margin-bottom: 6px; }
.tpl-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: auto; padding-top: 4px; flex-wrap: wrap; }

/* ── Modal ───────────────────────────────────────────────────────────────── */

.modal-overlay {
  position: fixed; inset: 0; z-index: 100;
  background: var(--scrim);
  display: none; align-items: flex-start; justify-content: center;
  padding: 7vh 16px 16px; overflow-y: auto;
}
.modal-overlay.open { display: flex; }

.modal {
  background: var(--panel);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  width: 100%; max-width: 520px;
  padding: 26px;
  animation: pop .16s ease;
  box-shadow: var(--shadow-lg);
}

.modal.wide { max-width: 680px; }

@keyframes pop { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } }

.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 20px; }
.modal-head h3 { font-size: 17px; letter-spacing: -0.01em; }
.modal-close {
  display: inline-grid; place-items: center;
  width: 32px; height: 32px; border-radius: 8px; flex: none;
  background: none; border: 0; color: var(--muted);
  transition: all .13s ease;
}
.modal-close:hover { color: var(--text); background: var(--card); }
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; flex-wrap: wrap; }
.modal-actions .btn { width: auto; }

/* ── Toasts ──────────────────────────────────────────────────────────────── */

.toast-wrap {
  position: fixed; bottom: 22px; right: 22px; z-index: 200;
  display: flex; flex-direction: column; gap: 10px;
  max-width: min(380px, calc(100vw - 32px));
}

.toast {
  background: var(--panel);
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--green);
  color: var(--text);
  border-radius: 10px;
  padding: 13px 16px;
  min-width: min(260px, calc(100vw - 44px));
  font-size: 13px;
  box-shadow: var(--shadow-lg);
  animation: slide-in .18s ease;
}
.toast.err { border-left-color: var(--red); }
.toast .t-title { font-weight: 700; margin-bottom: 2px; }
.toast .t-msg { color: var(--muted); line-height: 1.45; word-break: break-word; }

@keyframes slide-in { from { transform: translateX(14px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ── Misc ────────────────────────────────────────────────────────────────── */

.form-error {
  display: none;
  background: var(--red-dim); color: var(--red);
  border: 1px solid rgba(239,68,68,.25);
  border-radius: var(--radius-sm);
  padding: 11px 13px; font-size: 13px; margin-bottom: 16px; line-height: 1.5;
}
.form-error.show { display: block; }

/* Required fields: a red star on the label, a plain footnote above the
   buttons (no box), and — when something is wrong — a red edge on the box and
   one red line under it saying what to do. */
.req { color: var(--red); font-weight: 700; margin-left: 1px; }
.req-note { font-size: 12px; color: var(--faint); margin: 12px 0 0; }
.req-note .req { margin: 0 2px 0 0; }
.field input.is-invalid, .field select.is-invalid,
input.is-invalid, select.is-invalid { border-color: var(--red); }
.field input.is-invalid:focus, .field select.is-invalid:focus,
input.is-invalid:focus, select.is-invalid:focus { box-shadow: 0 0 0 3px var(--red-dim); }
.field-error { margin-top: 6px; font-size: 12px; line-height: 1.45; color: var(--red); }
.field-row > .field-error { grid-column: 1 / -1; margin: -8px 0 8px; }

.skeleton-row td { color: var(--faint); }

.pager {
  display: flex; align-items: center; gap: 12px; padding: 14px 22px;
  border-top: 1px solid var(--border); color: var(--muted); font-size: 12.5px;
  flex-wrap: wrap;
}
.pager .spacer { flex: 1; }

.section-title { font-size: clamp(17px, 2.2vw, 19px); letter-spacing: -0.02em; }
.section-sub { color: var(--muted); font-size: 13px; margin-top: 3px; }

.chip-row { display: flex; gap: 8px; flex-wrap: wrap; }
/* A choice pill. Icon and text sit on one centred line (an inline SVG would
   otherwise ride up on the text baseline), and the chosen one is the solid
   accent pill — the same "this one" as the payment-history switch. */
.chip {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  background: var(--panel); border: 1px solid var(--border); color: var(--muted);
  padding: 6px 12px; border-radius: 999px; font-size: 12px; font-weight: 600;
  line-height: 1.2; cursor: pointer;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.chip svg.lucide { width: 14px; height: 14px; }
.chip:hover { color: var(--text); border-color: var(--border-strong); }
.chip.active { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.field > .hint { margin-top: 6px; font-size: 12px; }

/* Step 3: trainer picker with its profile button, and the hour-slot pair. The
   button is a square the height of the select beside it, so the row reads as
   one control. */
.pt-trainer-row { display: flex; gap: 8px; align-items: stretch; }
.pt-trainer-row select { flex: 1; min-width: 0; }
.icon-btn.field-btn {
  width: 44px; height: auto; border-radius: var(--radius-sm);
  background: var(--card); border-color: var(--border);
}
.icon-btn.field-btn:hover:not(:disabled) { border-color: var(--border-strong); color: var(--text); }
.icon-btn.field-btn:disabled { opacity: .45; cursor: not-allowed; }
.pt-slot-row { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: center; }
.pt-slot-to { color: var(--faint); font-size: 13px; font-weight: 500; }
.pt-slot-cell { display: block; min-width: 0; }
.pt-slot-cell > select, .pt-slot-cell > input { width: 100%; }
/* Paid by: a real decision on every payment, so the pills are full size. */
#pay-method-row .chip { padding: 9px 16px; font-size: 13px; min-height: 38px; }
#pay-method-row .chip svg.lucide { width: 16px; height: 16px; }

.spinning { animation: spin-ico .8s linear infinite; }
@keyframes spin-ico { to { transform: rotate(360deg); } }

/* ── Table tools: sortable headers, size select, export, show-more ───────── */
/* Injected by js/table-tools.js. The header styling below only adds the sort
   affordance — the 11px uppercase/nowrap look of `thead th` stays as-is. */

thead th.sortable {
  cursor: pointer;
  user-select: none;
  padding-right: 30px;                 /* room for the caret, so it never
                                          overlaps a long column title */
  position: relative;
  transition: color .12s ease, background .12s ease;
}
thead th.sortable:hover { color: var(--text); background: var(--hover-tint); }
thead th.sortable:focus-visible {
  outline: none; color: var(--text);
  box-shadow: inset var(--ring);
}

/* Neutral state shows a dimmed double chevron; it brightens to a single
   direction once the column is the active sort. */
thead th.sortable::after {
  content: "";
  position: absolute; right: 12px; top: 50%;
  width: 8px; height: 10px; margin-top: -5px;
  opacity: .32;
  background: currentColor;
  transition: opacity .12s ease;
  -webkit-mask: var(--ggt-caret-both) center / 8px 10px no-repeat;
          mask: var(--ggt-caret-both) center / 8px 10px no-repeat;
}
thead th.sortable:hover::after { opacity: .6; }
thead th.sorted::after { opacity: 1; }
thead th.sorted.asc::after {
  -webkit-mask: var(--ggt-caret-up) center / 8px 10px no-repeat;
          mask: var(--ggt-caret-up) center / 8px 10px no-repeat;
}
thead th.sorted.desc::after {
  -webkit-mask: var(--ggt-caret-down) center / 8px 10px no-repeat;
          mask: var(--ggt-caret-down) center / 8px 10px no-repeat;
}

.ggt-tools { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Panels with no title of their own get a header holding only the tools —
   push them right so they line up with every other panel's controls. */
.panel-head > .panel-tools:only-child { margin-left: auto; }

.size-select {
  background: var(--panel); border: 1px solid var(--border); color: var(--muted);
  border-radius: 8px; padding: 7px 26px 7px 11px; font-size: 12.5px; font-weight: 600;
  font-family: inherit; cursor: pointer; outline: none;
  appearance: none; -webkit-appearance: none;
  background-image: var(--ggt-caret-down-svg);
  background-repeat: no-repeat;
  background-position: right 9px center;
  background-size: 9px;
  transition: border-color .13s ease, color .13s ease;
}
.size-select:hover { color: var(--text); border-color: var(--border-strong); }
.size-select:focus-visible { border-color: var(--border-strong); box-shadow: var(--ring); }
.size-select option { background: var(--panel); color: var(--text); }

.date-input {
  background: var(--panel); border: 1px solid var(--border); color: var(--text);
  border-radius: 8px; padding: 7px 10px; font-size: 12.5px; font-family: inherit;
  outline: none; min-width: 132px;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.date-input:hover { border-color: var(--border-strong); }
.date-input:focus { border-color: var(--focus-border); box-shadow: var(--ring); }
.date-input:invalid { border-color: var(--red); }
/* The native picker icon is near-black on the dark panel without this. */
.date-input::-webkit-calendar-picker-indicator {
  filter: invert(.62); cursor: pointer; opacity: .8;
}
.date-input::-webkit-calendar-picker-indicator:hover { opacity: 1; }

.ggt-date-wrap { display: inline-flex; align-items: center; gap: 6px; }
.ggt-dash { color: var(--faint); font-size: 13px; }
.ggt-clear { padding: 6px 8px; }

/* Export button + its little format menu.
   The menu is position:fixed, not absolute — `.panel` sets overflow:hidden for
   its rounded corners, which would clip a dropdown on a short panel. JS sets
   top/left from the button rect and closes it on scroll. */
.ggt-export { position: relative; display: inline-flex; }
.ggt-menu {
  position: fixed; z-index: 60;
  display: flex; flex-direction: column; min-width: 168px; padding: 5px;
  background: var(--card); border: 1px solid var(--border-strong);
  border-radius: 10px; box-shadow: var(--shadow-lg);
}
.ggt-menu[hidden] { display: none; }
.ggt-menu-item {
  display: flex; align-items: center; gap: 9px;
  background: none; border: 0; color: var(--text);
  font: inherit; font-size: 13px; text-align: left;
  padding: 9px 11px; border-radius: 7px; cursor: pointer;
  transition: background .12s ease;
}
.ggt-menu-item:hover { background: var(--card-hover); }
.ggt-menu-item:focus-visible { outline: none; background: var(--card-hover); box-shadow: var(--ring); }
.ggt-menu-item svg.lucide { width: 15px; height: 15px; color: var(--muted); flex: none; }

/* Footer under the table — replaces the old Prev/Next pager */
.ggt-foot {
  display: flex; align-items: center; gap: 12px; padding: 14px 22px;
  border-top: 1px solid var(--border); color: var(--muted); font-size: 12.5px;
  flex-wrap: wrap;
}
.ggt-count { color: var(--muted); }
.ggt-note { color: var(--amber); font-size: 12px; margin-left: auto; }
.ggt-note[hidden] { display: none; }
.ggt-more[hidden] { display: none; }
.ggt-more.is-loading .more-loader { display: inline-flex !important; }
.ggt-more.is-loading svg.lucide { display: none !important; }

/* ── Dashboard drill-downs ──────────────────────────────────────────────────
   The page behind a stat card: a row of tiles saying how many are in each
   bucket, and under the one you pick, that bucket's table. */

/* The panel inside already draws its own border and rounds its own corners. */
.drill-panel[hidden] { display: none; }
.drill-panel .panel-head { flex-wrap: wrap; gap: 10px; }

/* The question above the numbers: which set of members the tiles are counting.
   Chips on the left, the month pager pushed to the right — one row on a desktop,
   wrapping to two on a phone. */
.drill-chips {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px; margin-bottom: 14px;
}
.drill-chips[hidden] { display: none; }
.drill-chips .chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px; font-size: 12.5px;
}
/* The count rides inside the chip, so picking a category and reading how many
   are in it is one glance rather than two. */
.chip-n {
  font-size: 11.5px; font-weight: 700; line-height: 1;
  padding: 3px 7px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--border); color: var(--muted);
}
.chip.active .chip-n { background: var(--accent-text); border-color: var(--accent-text); color: var(--accent); }
/* Refunded is a different question from the other three — money already
   returned, not money still owed — so it sits apart with a rule between. */
.chip-apart {
  margin-left: 10px; padding-left: 22px; position: relative;
}
.chip-apart::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 1px; height: 22px; background: var(--border);
}
.month-pager { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.month-pager .btn[disabled] { opacity: .4; cursor: default; pointer-events: none; }
.month-pager-at {
  font-size: 12px; font-weight: 600; color: var(--muted);
  min-width: 8.5em; text-align: center;
}

/* Same grid as the dashboard's stat cards, one step narrower: these hold a
   month or a trainer's name rather than a two-word label. */
.drill-tiles {
  display: grid; gap: 14px; margin-bottom: 18px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}
.drill-tile {
  display: block; width: 100%; text-align: left; font: inherit; color: inherit;
  background: var(--card); border: 1px solid var(--border); border-radius: 14px;
  padding: 15px 17px; cursor: pointer; transition: all .14s ease;
}
.drill-tile:hover { background: var(--card-hover); border-color: var(--border-strong); transform: translateY(-1px); }
.drill-tile:focus-visible { outline: none; border-color: var(--border-strong); box-shadow: var(--ring); }
/* The open bucket is the one the table below belongs to, so it reads as
   pressed rather than merely highlighted. */
.drill-tile.active { background: var(--card-hover); border-color: var(--accent); }
.dt-label {
  display: block; font-size: 11.5px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dt-value { display: block; font-size: 26px; font-weight: 700; line-height: 1.25; margin-top: 6px; }
/* Nothing is chosen yet, so there is no number to print — the line says that in
   words, and drops to the size of words rather than shouting a sentence at 26px. */
.dt-value.dt-muted { font-size: 14.5px; font-weight: 600; color: var(--muted); line-height: 1.6; }
.dt-foot {
  display: block; font-size: 12px; color: var(--muted); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* The custom-month tile: a month box that *is* a tile, sitting where the next
   month would. The owner asked for it beside the months rather than as a
   calendar control off to one side, so the input covers the tile invisibly —
   the tile's own three lines are what you read, and clicking anywhere on it is
   clicking the box. It keeps the tile's own border and hover so it reads as one
   of the row, not as a form field dropped among them. */
.drill-tile.dt-custom { position: relative; }
.dt-custom-wrapper { position: relative; }
.cmp-popup {
  position: absolute; top: calc(100% + 8px); left: 0; width: 260px;
  background: var(--card); border: 1px solid var(--border-strong);
  border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.5);
  z-index: 1000; padding: 12px; color: var(--text); cursor: default;
}
.cmp-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.cmp-btn { background: transparent; border: none; color: var(--muted); cursor: pointer; padding: 6px 12px; border-radius: 6px; font-size: 14px; transition: all 0.1s; }
.cmp-btn:hover { background: var(--card-hover); color: var(--text); }
.cmp-year { font-weight: 600; font-size: 16px; cursor: pointer; padding: 4px 8px; border-radius: 6px; border: none; background: transparent; color: var(--text); transition: background 0.1s; text-decoration: underline dotted; text-underline-offset: 3px; }
.cmp-year:hover { background: var(--card-hover); }
.cmp-months-grid, .cmp-years-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.cmp-month, .cmp-year-btn { background: transparent; border: 1px solid var(--border); border-radius: 6px; padding: 10px 0; color: var(--text); cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.1s; }
.cmp-month:hover, .cmp-year-btn:hover:not([disabled]) { background: var(--card-hover); border-color: var(--border-strong); }
.cmp-month.active, .cmp-year-btn.active { background: var(--accent); color: var(--accent-text) !important; font-weight: 700; border-color: var(--accent); }
.cmp-footer { margin-top: 12px; display: flex; justify-content: space-between; align-items: center; }
.cmp-clear { background: transparent; border: none; color: var(--red); cursor: pointer; font-size: 14px; font-weight: 500; padding: 6px 12px; border-radius: 6px; }
.cmp-clear:hover { background: rgba(239, 68, 68, 0.1); }
.cmp-this-month { background: transparent; border: none; color: var(--info); cursor: pointer; font-size: 14px; font-weight: 500; padding: 6px 12px; border-radius: 6px; }
.cmp-this-month:hover { background: var(--info-dim); }

/* Caret masks — inline SVG so no extra network requests. */
:root {
  --ggt-caret-both: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 10'%3E%3Cpath d='M4 0L7 3.6H1z'/%3E%3Cpath d='M4 10L1 6.4h6z'/%3E%3C/svg%3E");
  --ggt-caret-up: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 10'%3E%3Cpath d='M4 1.4L7.4 6.4H0.6z'/%3E%3C/svg%3E");
  --ggt-caret-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 10'%3E%3Cpath d='M4 8.6L0.6 3.6h6.8z'/%3E%3C/svg%3E");
  --ggt-caret-down-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6' fill='none' stroke='%238f8f99' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
}

/* ══════════════════════════════════════════════════════════════════════════
   Responsive
   ══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 1120px) {
  .content { padding: 24px 22px 56px; }
  .topbar { padding: 10px 22px; }
}

@media (max-width: 980px) {
  /* login: single column, hide brand panel */
  .auth-shell { grid-template-columns: 1fr; }
  .auth-brand { display: none; }
  .auth-side { padding: 32px 18px; }

  /* sidebar becomes an off-canvas drawer */
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0;
    transform: translateX(-102%);
    transition: transform .22s ease;
    box-shadow: none;
    width: min(300px, 84vw);
  }
  body.nav-open .sidebar { transform: none; box-shadow: var(--shadow-lg); }
  body.nav-open .sidebar-backdrop { display: block; }
  body.nav-open { overflow: hidden; }

  .menu-btn { display: inline-grid; }

  .content { padding: 20px 16px 52px; }
  .topbar { padding: 8px 14px; }

  .welcome { padding: 20px; }
  .welcome-actions { width: 100%; }
  .welcome-actions .btn { flex: 1; }

  .panel-head { padding: 15px 16px; }
  thead th, tbody td { padding-left: 16px; padding-right: 16px; }
  .pager, .ggt-foot { padding: 12px 16px; }

  .search-input { width: 100%; }
  .search-wrap { width: 100%; }
  .panel-tools { width: 100%; }
  .section-head .btn { width: 100%; }
}

@media (max-width: 620px) {
  .who { display: none; }
  .field-row { grid-template-columns: 1fr; gap: 0; }
  /* ── Modals become bottom sheets ────────────────────────────────────────────
     A phone has no room for a floating dialog. The long forms — the member
     wizard above all — used to run off the bottom of the screen with Save and
     Next somewhere below the fold, and a modal taller than the viewport had its
     top clipped, because `align-items: flex-end` on a scrolling overlay cannot
     scroll back up past the start. So the sheet is pinned to the bottom edge,
     capped at the viewport, and scrolls INSIDE itself. */
  .modal-overlay { padding: 0; align-items: flex-end; overflow: hidden; }
  .modal {
    max-width: none;
    max-height: 92vh;
    max-height: 92dvh;          /* dvh where supported: excludes the URL bar */
    padding: 18px 15px 0;       /* the sticky action bar carries the bottom */
    border-bottom: 0;
    border-radius: var(--radius) var(--radius) 0 0;
    animation: sheet-up .2s ease;
    overflow-y: auto; overscroll-behavior: contain;
  }
  .modal.wide { max-width: none; }

  /* Title and ✕ ride along at the top of the scroll, so there is always a way
     out of a sheet without scrolling back up. The modal's own `overflow-y`
     clips this bar to the rounded top corners. */
  .modal:has(.modal-head) { padding-top: 0; }
  .modal-head {
    position: sticky; top: 0; z-index: 3;
    margin: 0 -15px 16px; padding: 16px 15px 12px;
    background: var(--panel); border-bottom: 1px solid var(--border);
  }
  /* Modals that end in content rather than buttons keep a bottom edge of their
     own — the sticky bar below supplies it for the ones that have it. */
  .modal:not(:has(.modal-actions)) { padding-bottom: calc(16px + env(safe-area-inset-bottom)); }

  /* 16px is the threshold below which iOS Safari zooms the page on focus — the
     worst thing about filling this form on a phone, because every tap into a
     field left the layout blown up and scrolled sideways. */
  .field input, .field select, .field textarea { font-size: 16px; }

  /* The buttons ride at the bottom of the sheet instead of sitting at the end of
     a long scroll. Negative side margins let the bar span the sheet's padding so
     no content shows through beneath it. */
  .modal-actions {
    position: sticky; bottom: 0; z-index: 2;
    margin: 18px -15px 0;
    padding: 12px 15px calc(12px + env(safe-area-inset-bottom));
    background: var(--panel); border-top: 1px solid var(--border);
  }
  .modal-actions .btn { flex: 1; }

  .stat-value { font-size: 26px; }
  .toast-wrap { right: 16px; bottom: 16px; left: 16px; }

  /* Table tools stack instead of squeezing: dates on their own row, export and
     size select side by side. The table itself keeps its horizontal scroll. */
  .ggt-tools { width: 100%; }
  .ggt-date-wrap { width: 100%; }
  .ggt-date-wrap .date-input { flex: 1; min-width: 0; }
  .size-select { flex: 1; }
  .ggt-export, .ggt-export .btn { flex: 1; justify-content: center; }
  .ggt-menu { left: 0; right: auto; }
  .ggt-note { margin-left: 0; width: 100%; }

  @keyframes sheet-up { from { transform: translateY(16px); opacity: 0; } to { transform: none; opacity: 1; } }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ── Dashboard charts ────────────────────────────────────────────────────── */
/* Chart colours come from the --chart-* tokens (see :root). */
.chart-box { padding: 18px 22px 22px; }
.chart-box svg { display: block; width: 100%; height: auto; }
.chart-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 900px) { .chart-2col { grid-template-columns: 1fr; } }

.chart-tip {
  position: fixed; z-index: 90; pointer-events: none;
  background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 8px; padding: 7px 11px; font-size: 12.5px;
  color: var(--text); box-shadow: var(--shadow-lg);
  opacity: 0; transition: opacity .1s ease;
}
.chart-tip.show { opacity: 1; }
.chart-tip .tip-label { color: var(--muted); font-size: 11.5px; margin-bottom: 2px; }

.hbar-row { display: grid; grid-template-columns: 130px 1fr 44px; align-items: center; gap: 10px; margin: 9px 0; }
.hbar-name { font-size: 12.5px; color: var(--muted); text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hbar-track { height: 18px; display: flex; align-items: center; }
.hbar-fill { height: 18px; border-radius: 0 4px 4px 0; min-width: 2px; }
.hbar-val { font-size: 12.5px; color: var(--text); font-weight: 600; }

.meter-wrap { margin-bottom: 18px; }
.meter-head { display: flex; justify-content: space-between; margin-bottom: 8px; font-size: 13px; }
.meter-track { height: 14px; border-radius: 7px; background: var(--accent-dim); overflow: hidden; }
.meter-fill { height: 100%; border-radius: 7px 0 0 7px; background: var(--chart-1); }

/* ── Trainer cards ───────────────────────────────────────────────────────── */
.trainer-photo {
  width: 56px; height: 56px; border-radius: 14px; flex-shrink: 0;
  background: var(--card-hover); background-size: cover; background-position: center;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 600; font-size: 19px; color: var(--muted);
  border: 1px solid var(--border);
}
.trainer-head { display: flex; gap: 14px; align-items: center; }
.trainer-meta { font-size: 12.5px; color: var(--muted); margin-top: 3px; }

/* ── Pie/donut charts (compact) ──────────────────────────────────────────── */
.chart-3col { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 18px; }
@media (max-width: 1100px) { .chart-3col { grid-template-columns: 1fr; } }

.donut-wrap { display: flex; align-items: center; gap: 20px; }
.chart-box .donut-svg { width: 128px; height: 128px; flex-shrink: 0; }
.donut-svg circle { transition: opacity .12s ease; cursor: default; }
.donut-svg circle:hover { opacity: .82; }

.donut-legend { min-width: 0; flex: 1; }
.legend-row { display: flex; align-items: center; gap: 8px; margin: 6px 0; font-size: 12.5px; }
.legend-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.legend-name { color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.legend-val { margin-left: auto; font-weight: 600; color: var(--text); }

/* ── Trainer cards v2 (professional) ─────────────────────────────────────── */
.trainer-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 18px; }

.trainer-card {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 0; display: flex; flex-direction: column; overflow: hidden;
  transition: border-color .15s ease, transform .15s ease;
}
.trainer-card:hover { border-color: var(--border-strong); transform: translateY(-2px); }

/* ── Trainer card photo slideshow ──────────────────────────────────────────
   The hero area is a relative container; slide divs stack on top of each
   other via absolute positioning.  Only the active slide is visible.       */
.tc-slideshow {
  position: relative; width: 100%; aspect-ratio: 4 / 3; overflow: hidden;
  border-bottom: 1px solid var(--border);
  background: var(--card-hover);
}

.tc-slide {
  position: absolute; inset: 0;
  background-size: cover; background-position: center top;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity .35s ease;
  pointer-events: none;
}
.tc-slide.tc-slide-active { opacity: 1; pointer-events: auto; }

.tc-initials {
  font-family: var(--font-display); font-weight: 600; font-size: 48px; color: var(--muted);
}

/* Navigation arrows */
.tc-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 34px; height: 34px; border-radius: 50%;
  background: rgba(10, 12, 16, .78);
  border: 1px solid rgba(255,255,255,.12);
  color: #fff; display: grid; place-items: center;
  cursor: pointer; z-index: 2;
  transition: background .15s ease, opacity .15s ease;
  opacity: 0;
}
.tc-slideshow:hover .tc-arrow { opacity: 1; }
.tc-arrow:hover { background: rgba(0,0,0,.78); }
.tc-arrow i { width: 18px; height: 18px; }
.tc-prev { left: 10px; }
.tc-next { right: 10px; }

/* Dot indicators */
.tc-dots {
  position: absolute; bottom: 9px; left: 50%; transform: translateX(-50%);
  display: flex; gap: 5px; z-index: 2;
}
.tc-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: rgba(255,255,255,.40); cursor: pointer;
  transition: background .2s ease, transform .2s ease;
}
.tc-dot.tc-dot-active { background: #fff; transform: scale(1.25); }

/* Legacy hero kept for any code not yet migrated */
.trainer-photo-hero {
  width: 100%; height: 200px;
  background: var(--card-hover); background-size: cover; background-position: center top;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 600; font-size: 48px; color: var(--muted);
  border-bottom: 1px solid var(--border);
}

/* ── 24-hour Shifts Timeline modal ─────────────────────────────────────────
   Each row = one clock-hour.  A row with members is clickable; the detail
   panel below it expands with a smooth height animation.                   */

.sh-timeline { display: flex; flex-direction: column; gap: 2px; padding: 4px 0; }

.sh-hour-row {
  display: grid; grid-template-columns: 1fr 36px 54px;
  align-items: center; gap: 10px;
  padding: 10px 14px; border-radius: 10px;
  background: var(--card-hover);
  font-size: 13.5px; transition: background .13s ease;
  user-select: none;
}
.sh-hour-row.sh-clickable { cursor: pointer; }
.sh-hour-row.sh-clickable:hover { background: var(--border); }
.sh-hour-row.sh-row-expanded { background: var(--border); border-radius: 10px 10px 0 0; }
.sh-hour-row.sh-has-members { background: rgba(34,197,94,.08); }
.sh-hour-row.sh-has-members:hover { background: rgba(34,197,94,.15); }
.sh-hour-row.sh-has-members.sh-row-expanded { background: rgba(34,197,94,.15); border-radius: 10px 10px 0 0; }

.sh-hour-label { font-family: var(--font-mono); font-size: 13px; color: var(--text); }
.sh-hour-to { color: var(--muted); font-size: 12px; }

.sh-hour-count {
  display: grid; place-items: center;
  width: 28px; height: 28px; border-radius: 50%;
  font-weight: 700; font-size: 13px;
  background: var(--card); color: var(--faint); border: 1px solid var(--border);
  justify-self: center;
}
.sh-count-active { background: var(--green-dim); color: var(--green); border-color: transparent; }

.sh-hour-free { font-size: 12px; color: var(--faint); text-align: right; }

.sh-hour-chevron {
  display: flex; align-items: center; justify-content: flex-end;
  color: var(--muted); transition: transform .22s ease;
}
.sh-row-expanded .sh-hour-chevron { transform: rotate(180deg); }
.sh-hour-chevron i { width: 16px; height: 16px; }

/* Expandable member detail panel */
.sh-detail {
  max-height: 0; overflow: hidden;
  transition: max-height .28s ease, padding .22s ease;
  background: var(--card); border-radius: 0 0 10px 10px;
  border: 1px solid var(--border); border-top: none;
  padding: 0 14px;
}
.sh-detail.sh-detail-open { max-height: 600px; padding: 10px 14px 12px; }

.sh-member-entry {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  gap: 4px 12px; padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.sh-member-entry:last-child { border-bottom: none; }

.sh-member-name { font-weight: 600; font-size: 13.5px; grid-column: 1; }
.sh-member-slot {
  font-family: var(--font-mono); font-size: 12px; color: var(--muted);
  grid-column: 1;
}
.sh-member-dur {
  grid-column: 2; grid-row: 1 / 3;
  font-size: 12px; font-weight: 600; color: var(--green);
  background: var(--green-dim); border-radius: 20px;
  padding: 3px 10px; white-space: nowrap; align-self: center;
}

.sh-empty { color: var(--muted); font-size: 13.5px; padding: 24px 0; text-align: center; }
.trainer-details-wrap {
  padding: 22px;
  display: flex; flex-direction: column; gap: 16px;
}

/* ── Trainer photo gallery ─────────────────────────────────────────────── */

.t-gallery { display: flex; flex-wrap: wrap; gap: 8px; }
.t-gallery:empty { display: none; }

.t-shot {
  position: relative;
  width: 74px; height: 74px; border-radius: 10px; overflow: hidden;
  background: var(--card-hover) center/cover no-repeat;
  border: 1px solid var(--border);
}
.t-shot-del {
  position: absolute; top: 3px; right: 3px;
  width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center;
  border: 0; cursor: pointer; padding: 0;
  background: var(--panel); color: var(--red);
}
.t-shot-del i { width: 12px; height: 12px; }
.t-shot-del:hover { background: var(--red); color: #fff; }

/* Read-only variant used in the profile popup — bigger, and scrolls sideways
   rather than growing the popup to ten rows tall. */
.t-gallery-view {
  display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px;
}
.t-gallery-view .t-shot { width: 118px; height: 118px; flex: none; }

/* ── Trainer timetable: who is with this trainer, and when ─────────────── */

.tt { display: flex; flex-direction: column; gap: 2px; }

.tt-row {
  display: grid; grid-template-columns: 104px 26px 1fr;
  align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 9px;
  background: var(--card-hover);
  font-size: 13px;
}
/* A free stretch is deliberately quiet — it is the absence of work, and it
   should read as a gap on the page the way it is a gap in the day. */
.tt-row.free { background: none; color: var(--faint); }

.tt-time { font-family: var(--font-mono); font-size: 12px; white-space: nowrap; }
.tt-count {
  display: grid; place-items: center;
  width: 24px; height: 24px; border-radius: 50%;
  font-weight: 700; font-size: 12px;
  background: var(--green-dim); color: var(--green);
}
.tt-row.free .tt-count { background: none; color: var(--faint); font-weight: 500; }
.tt-who { color: var(--text); overflow-wrap: anywhere; }
.tt-row.free .tt-who { color: var(--faint); }

.tt-empty { color: var(--muted); font-size: 13px; padding: 6px 0; }
.tt-note {
  margin-top: 8px; font-size: 12.5px; color: var(--muted); line-height: 1.55;
}
.tt-note b { color: var(--text); }

.tt-card-block { display: flex; flex-direction: column; gap: 8px; }
.tt-card-head {
  display: flex; align-items: center; gap: 6px;
  font-size: 11.5px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted);
}
.tt-card-head i { width: 13px; height: 13px; }

/* ── Trainer profile popup ─────────────────────────────────────────────── */

.tp-hero { display: flex; gap: 16px; align-items: center; margin-bottom: 18px; }
.tp-face {
  width: 82px; height: 82px; flex: none; border-radius: 16px;
  background: var(--card-hover) center/cover no-repeat;
  border: 1px solid var(--border);
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 600; font-size: 26px; color: var(--muted);
}
.tp-hero h4 { font-size: 18px; margin-bottom: 3px; }
.tp-spec { color: var(--muted); font-size: 13px; margin-bottom: 7px; }

.tp-facts { display: flex; gap: 10px; margin-bottom: 18px; }
.tp-fact {
  flex: 1; padding: 11px 13px; border-radius: 11px;
  background: var(--card-hover); border: 1px solid var(--border);
}
.tp-fact span {
  display: block; font-size: 11px; color: var(--muted);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 3px;
}
.tp-fact b { font-size: 15px; }

.tp-bio {
  color: var(--muted); font-size: 13.5px; line-height: 1.65;
  white-space: pre-wrap; margin-bottom: 18px;
}

.tp-block { margin-bottom: 18px; }
.tp-block:last-child { margin-bottom: 0; }
.tp-block-head {
  font-size: 11.5px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 9px;
}
.trainer-name-wrap { text-align: center; min-width: 0; }
.trainer-name-wrap h4 { margin: 0 0 4px; font-size: 18px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.trainer-spec { font-size: 13.5px; color: var(--muted); margin-bottom: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.trainer-stats {
  display: grid; grid-template-columns: 1fr 1fr 1fr;
  border-top: 1px solid var(--border); border-bottom: none;
  padding: 16px 0 0;
}
.trainer-stat { text-align: center; }
.trainer-stat + .trainer-stat { border-left: 1px solid var(--border); }
.trainer-stat b { display: block; font-family: var(--font-display); font-size: 16px; margin-bottom: 2px; }
.trainer-stat span { font-size: 11px; color: var(--faint); text-transform: uppercase; letter-spacing: .05em; }

.trainer-actions { display: flex; gap: 8px; margin-top: 4px; }
.trainer-actions .btn { flex: 1; justify-content: center; }

.empty-hero {
  grid-column: 1 / -1; text-align: center; padding: 64px 24px;
  background: var(--card); border: 1px dashed var(--border-strong); border-radius: var(--radius);
}
.empty-hero .eh-ico {
  width: 64px; height: 64px; margin: 0 auto 18px; border-radius: 18px;
  background: var(--card-hover); border: 1px solid var(--border-strong);
  display: flex; align-items: center; justify-content: center; color: var(--muted);
}
.empty-hero .eh-ico svg { width: 28px; height: 28px; }
.empty-hero h4 { margin: 0 0 6px; font-size: 16px; }
.empty-hero p { color: var(--muted); font-size: 13px; margin: 0 0 18px; }

/* ── Member wizard: step rail, panes, footer ─────────────────────────────── */
/* Four steps but one form — the panes are hidden siblings, so a field the user
   filled on step 1 is still in the DOM (and still submitted) from step 4. */

.wiz-rail {
  display: flex; align-items: center; gap: 6px;
  list-style: none; margin: 0 0 20px; padding: 0;
  overflow-x: auto; scrollbar-width: none;
}
.wiz-rail::-webkit-scrollbar { display: none; }

.wiz-step {
  position: relative;
  display: flex; align-items: center; gap: 8px; flex: none;
  padding: 7px 12px 7px 8px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--panel);
  color: var(--faint); font-size: 12.5px; font-weight: 600;
  cursor: pointer; transition: color .13s ease, border-color .13s ease, background .13s ease;
}
.wiz-step:hover { color: var(--muted); border-color: var(--border-strong); }
.wiz-step + .wiz-step::before {
  content: ""; position: absolute;
  top: 50%; left: -7px; width: 6px; height: 1px;
  background: var(--border-strong);
}
.wiz-num {
  display: inline-grid; place-items: center; flex: none;
  width: 21px; height: 21px; border-radius: 50%;
  background: var(--card); border: 1px solid var(--border-strong);
  font-family: var(--font-display); font-size: 11.5px;
}
.wiz-step.is-current { color: var(--text); border-color: var(--accent); background: var(--card); }
.wiz-step.is-current .wiz-num { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
/* Done steps are simply filled in: full-strength text, a solid edge — no colour. */
.wiz-step.is-done { color: var(--text); border-color: var(--border-strong); }
.wiz-step.is-done .wiz-num { background: var(--accent-dim); color: var(--text); border-color: var(--border-strong); }

/* The way into this member's payment history, parked at the end of the rail
   beside the Payment step — the only thing up there that is not a step, so it is
   a bare icon rather than another chip pretending to be one. */
.wiz-tail { flex: none; display: flex; align-items: center; margin-left: 4px; }
.wiz-hist {
  display: inline-grid; place-items: center; flex: none;
  width: 32px; height: 32px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--border);
  color: var(--faint); cursor: pointer;
  transition: color .13s ease, border-color .13s ease, background .13s ease;
}
.wiz-hist:hover { color: var(--text); background: var(--card); border-color: var(--border-strong); }
.wiz-hist svg.lucide { width: 16px; height: 16px; }

.wiz-hint {
  display: flex; gap: 9px; align-items: flex-start;
  margin-top: 4px; padding: 11px 13px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--muted); font-size: 12.5px; line-height: 1.55;
}
.wiz-hint b { color: var(--text); font-weight: 600; }
.wiz-hint svg { width: 15px; height: 15px; flex: none; margin-top: 1px; color: var(--faint); }

.wiz-actions .spacer { flex: 1; }
.wiz-actions { align-items: center; }
.lbl-note { color: var(--faint); font-weight: 400; }

/* ── Step 2: the membership already on file ──────────────────────────────── */
/* Stated before anything new is picked, so an extension is never mistaken for
   a first sale and old dues cannot be missed. */

.cur-card {
  display: flex; flex-direction: column; gap: 7px;
  margin-bottom: 16px; padding: 12px 14px;
  background: var(--card); border: 1px solid var(--border);
  border-left: 2px solid var(--border-strong);
  border-radius: var(--radius-sm);
}
.cur-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.cur-k {
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--faint); flex: none;
}
.cur-v { font-size: 12.5px; color: var(--text); text-align: right; }
.cur-v.is-ok { color: var(--green); }
.cur-v.is-warn { color: var(--amber); }
.cur-v.is-bad { color: var(--red); font-weight: 600; }
.cur-note {
  margin-top: 2px; padding-top: 8px; border-top: 1px dashed var(--border-strong);
  font-size: 12px; color: var(--muted); line-height: 1.5;
}
.cur-note b { color: var(--text); font-weight: 600; }
.cur-card.is-overdue { border-left-color: var(--red); }
.cur-card.is-renewal { border-left-color: var(--info); }

/* "Same plan again" — the one-click renewal. It sits inside the card that states
   what they have, because that is what it repeats: a full-width target with the
   plan and the day it would run to written on it, so the desk never has to open
   the dropdown to sell the commonest thing in the shop. */
.again-btn {
  display: flex; align-items: center; gap: 10px; width: 100%;
  margin-top: 3px; padding: 9px 11px; text-align: left; cursor: pointer;
  background: rgba(52, 211, 153, .07);
  border: 1px solid rgba(52, 211, 153, .28);
  border-radius: var(--radius-sm); color: var(--text);
  font-family: inherit; transition: background .15s, border-color .15s;
}
.again-btn:hover { background: rgba(52, 211, 153, .13); border-color: rgba(52, 211, 153, .5); }
.again-ico {
  display: flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; flex: none; border-radius: 7px;
  background: rgba(52, 211, 153, .14); color: var(--green);
}
.again-ico svg { width: 14px; height: 14px; }
.again-ico.is-done { display: none; }
.again-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.again-txt b { font-size: 12.5px; font-weight: 600; }
.again-txt span { font-size: 11.5px; color: var(--muted); line-height: 1.45; }
/* Once the renewal is queued the button reports the decision instead of
   offering it — same place, dashed instead of filled. It stays a target though:
   clicking it again is how the decision is taken back, so the hover says
   "remove" rather than "add". */
.again-btn.is-on {
  background: transparent; border-style: dashed;
  border-color: rgba(52, 211, 153, .3);
}
.again-btn.is-on:hover {
  background: rgba(248, 113, 113, .08); border-color: rgba(248, 113, 113, .42);
}
.again-btn.is-on .again-ico { display: none; }
.again-btn.is-on .again-ico.is-done { display: flex; }
/* The button already separates the note from the rows above it — a second dashed
   rule right under a dashed box is just noise. */
.again-btn:not([hidden]) + .cur-note { margin-top: 0; padding-top: 0; border-top: none; }

/* ── Payment step: derived totals, ledger, receipt ───────────────────────── */
/* Everything on the left of "Outstanding" is arithmetic, not input: the owner
   only ever types the amount received. */

.pay-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  background: var(--border); border: 1px solid var(--border);
  border-radius: var(--radius-sm); overflow: hidden; margin-bottom: 18px;
}
.pay-cell { background: var(--card); padding: 12px 14px; min-width: 0; }
.pay-k {
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pay-v { font-family: var(--font-display); font-size: 17px; letter-spacing: -0.01em; }
.pay-cell-sub {
  margin-top: 4px; font-size: 11px; color: var(--faint); line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pay-cell.is-balance { background: var(--card-hover); }
.pay-cell.is-balance .pay-v { color: var(--amber); }
.pay-cell.is-balance.is-clear .pay-v { color: var(--green); }

/* The bill, as a receipt rather than a form: list price, what came off it, what
   is actually being charged. Nothing here is typed — step 2 decided all three,
   so there is no way for the payment step to disagree with the plan. */
.pay-break {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 10px 12px;
}
.pb-rows { display: flex; flex-direction: column; gap: 6px; }
.pb-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 12.5px; }
.pb-row span { color: var(--faint); }
.pb-row b { font-family: var(--font-display); font-size: 13.5px; font-weight: 500; }
.pb-row.is-off span, .pb-row.is-off b { color: var(--info); }
.pb-row.is-total { margin-top: 2px; padding-top: 7px; border-top: 1px dashed var(--border-strong); }
.pb-row.is-total span { color: var(--muted); }
.pb-row.is-total b { font-size: 16px; }
.pb-foot {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  margin-top: 9px; padding-top: 8px; border-top: 1px solid var(--border);
  font-size: 11.5px; color: var(--faint); line-height: 1.45;
}
.lnk-btn {
  flex: none; background: none; border: none; padding: 0;
  color: var(--accent); font-size: 11.5px; font-weight: 600; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.lnk-btn:hover { color: var(--text); }

/* Step 2's price box — the discount is given here, beside the plan, and the
   arithmetic is shown so the number the desk collects is never a surprise. */
.price-box {
  margin-bottom: 16px; padding: 13px 14px 11px;
  background: var(--card); border: 1px solid var(--border);
  border-left: 2px solid var(--border-strong);
  border-radius: var(--radius-sm);
}
.price-box .field { margin-bottom: 12px; }
/* A gate row is a question before it is a form: it is the whole box until it is
   ticked, so it sits flush with no stray margin, and its label is clickable —
   true of the discount in the price box and of the carried-over dues in the
   accordion block alike, so it is not scoped to either. */
.check-row.is-gate { margin: 0 0 11px; }
.check-row.is-gate label { cursor: pointer; }
.disc-row { display: flex; align-items: center; gap: 8px; }
.disc-row input { flex: 1; }
.disc-row .chip { padding: 9px 11px; }

/* Access settings — the two switches that only mean something once a membership
   exists, kept together and out of the way of filing a new member. */
.acc-block {
  margin-top: 16px; padding: 12px 14px 2px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.acc-head {
  display: flex; align-items: center; gap: 7px; margin-bottom: 10px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--faint);
}
.acc-head svg { width: 13px; height: 13px; }
.wiz-hint.is-warn { border-color: rgba(245, 158, 11, .38); color: var(--amber); }
.wiz-hint.is-warn svg { color: var(--amber); }
.wiz-hint.is-warn b { color: var(--amber); }

/* Refund form — the receipt it comes out of, restated at the top so nobody
   hands money back against the wrong invoice. */
.rf-head {
  margin-bottom: 16px; padding: 11px 13px;
  background: var(--card); border: 1px solid var(--border);
  border-left: 2px solid var(--red); border-radius: var(--radius-sm);
}
.rf-inv { font-family: var(--font-mono); font-size: 12.5px; color: var(--text); }
.rf-sub { margin-top: 4px; font-size: 12px; color: var(--muted); line-height: 1.5; }

/* The refund modal asks two things and only one of them is about money. The
   second one has a destructive answer, so that chip wears the colour of the
   button it agrees with — a shut door should not look like any other toggle. */
#rf-mem-row .chip[data-mem="end"].active {
  background: var(--red-dim); border-color: rgba(239, 68, 68, .45); color: var(--red);
}
/* The date is the answer's small print: it belongs under the answer, tucked in
   far enough to read as part of it rather than as the next question. */
#rf-inactive-wrap { margin-top: -4px; padding-left: 11px; border-left: 2px solid var(--red-dim); }

/* Discount badge — same shape wherever money is shown (ledger, receipt). */
.tag-disc {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  background: var(--info-dim); color: var(--info);
  font-size: 10.5px; font-weight: 700; letter-spacing: .03em;
}

/* Money handed back, wearing the same badge shape as a discount so a ledger row
   reads at a glance: what was taken, what came off, what went back out. */
.tag-ref {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  background: var(--red-dim); color: var(--red);
  font-size: 10.5px; font-weight: 700; letter-spacing: .03em;
}
.led-row.is-refunded { border-left: 2px solid var(--red); }
/* A refund receipt in the history: money going the other way. */
.led-row.is-refund { border-left: 2px solid var(--red); background: var(--red-dim); }
.led-amt-back { color: var(--red); }
.rc-amt.is-back { color: var(--red); }

/* Coaching billed on the same receipt as a membership. Its own colour, because
   it is neither a discount nor money going back — it is a second thing sold. */
.tag-pt {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  background: var(--purple-dim); color: var(--purple);
  font-size: 10.5px; font-weight: 700; letter-spacing: .03em;
}
.rf-btn {
  flex: none; background: none; border: none; padding: 0;
  color: var(--red); font-size: 11.5px; font-weight: 600; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.rf-btn:hover { color: var(--text); }
.rc-row.is-back span, .rc-row.is-back b { color: var(--red); }

/* One block per subscription the member has taken, oldest first. */
.sub-list { display: flex; flex-direction: column; gap: 8px; max-height: 260px; overflow-y: auto; }
.sub-row {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 12px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 10px 12px;
}
.sub-name { font-size: 13px; color: var(--text); display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.sub-name span { color: var(--faint); font-size: 11.5px; }
.sub-name span.tag-disc { color: var(--info); }
/* `.sub-name span` greys every span in the row; the badges are the exception —
   without this the PT tag would arrive here in the same faint grey as the
   duration beside it and stop reading as a badge at all. */
.sub-name span.tag-pt { color: var(--purple); }
.sub-when { grid-column: 1 / -1; font-size: 11.5px; color: var(--faint); }
.sub-money { text-align: right; font-size: 11.5px; color: var(--muted); white-space: nowrap; }
.sub-money b { font-family: var(--font-display); font-size: 14px; font-weight: 500; color: var(--text); }
.sub-left { grid-column: 1 / -1; font-size: 11.5px; color: var(--amber); }
.sub-row.is-clear .sub-left { color: var(--green); }
.sub-bar { grid-column: 1 / -1; height: 3px; border-radius: 2px; background: var(--border); overflow: hidden; }
.sub-bar i { display: block; height: 100%; background: var(--amber); }
.sub-row.is-clear .sub-bar i { background: var(--green); }
/* A subscription whose money went back out: not owed, not earned either. */
.sub-row.is-void { border-color: var(--red-dim); }
.sub-row.is-void .sub-left { color: var(--red); }

/* One subscription paid in pieces — the point the owner made: "he paid for that
   one plan twice, separately". Each piece names its own receipt, so the desk can
   see where the money came from without matching invoices up by hand. */
.sub-inst { grid-column: 1 / -1; margin-top: 6px; border-top: 1px dashed var(--border); padding-top: 6px; }
.sub-inst-head {
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 4px;
}
.sub-inst-row {
  display: grid; grid-template-columns: auto 1fr auto auto; gap: 8px;
  align-items: baseline; font-size: 11.5px; color: var(--muted); padding: 2px 0;
}
.sub-inst-amt { font-family: var(--font-display); font-size: 12.5px; color: var(--text); }
.sub-inst-when { color: var(--faint); white-space: nowrap; }
/* ── Subscription card, payment history ──────────────────────────────────
   One sale per card. Status is a pill in the header, the money sits in named
   boxes, and the refund is a small outlined button in the footer — the rarest
   thing done here, so the quietest thing on the card. */
.sc-list { display: flex; flex-direction: column; gap: 12px; }
.sc {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 14px 16px 0;
  display: flex; flex-direction: column; gap: 10px;
}
.sc.is-refunded { background: color-mix(in srgb, var(--card) 88%, var(--red) 3%); }
.sc-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.sc-title { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-width: 0; }
.sc-n {
  font-family: var(--font-mono); font-size: 11px; color: var(--muted);
  background: var(--card-hover); border: 1px solid var(--border-strong);
  border-radius: 6px; padding: 1px 6px;
}
.sc-name { font-family: var(--font-display); font-size: 15px; font-weight: 500; color: var(--text); }
.sc-pill {
  font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 2px 8px; border-radius: 999px; white-space: nowrap;
}
.sc-pill.is-paid { background: var(--green-dim); color: var(--green); }
.sc-pill.is-due { background: var(--amber-dim); color: var(--amber); }
.sc-pill.is-refunded { background: var(--red-dim); color: var(--red); }
.sc-pill.is-ended { background: var(--border); color: var(--muted); }
.sc.is-ended .sc-bar i { background: var(--faint); }
.sc-total { font-family: var(--font-display); font-size: 17px; letter-spacing: -0.01em; white-space: nowrap; }
.sc.is-refunded .sc-total { color: var(--muted); text-decoration: line-through; text-decoration-thickness: 1px; }
.sc-meta {
  font-size: 12px; color: var(--muted); line-height: 1.6;
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; margin-top: -4px;
}
.sc-meta .dot { font-style: normal; color: var(--faint); }
.sc-meta .mono, .sc-pay .mono { font-family: var(--font-mono); font-size: 11px; color: var(--faint); }
.sc-tag { font-size: 11px; color: var(--faint); }
.sc-bar { height: 4px; border-radius: 2px; background: var(--border); overflow: hidden; }
.sc-bar i { display: block; height: 100%; background: var(--amber); border-radius: 2px; }
.sc.is-paid .sc-bar i { background: var(--green); }
.sc-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 8px; }
.sc-stat {
  background: var(--card-hover); border: 1px solid var(--border);
  border-radius: 8px; padding: 7px 10px; min-width: 0;
}
.sc-stat span {
  display: block; font-size: 10px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 2px;
}
.sc-stat b { font-family: var(--font-display); font-size: 14px; font-weight: 500; color: var(--text); }
.sc-stat.is-paid b { color: var(--green); }
.sc-stat.is-due b { color: var(--amber); }
.sc-stat.is-back b { color: var(--red); }
.sc-stat.is-off b, .sc-stat.is-zero b { color: var(--muted); }
.sc-pays { font-size: 12px; color: var(--muted); }
.sc-pays summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 4px;
  color: var(--muted); font-size: 12px; padding: 2px 0; user-select: none;
}
.sc-pays summary::-webkit-details-marker { display: none; }
.sc-pays summary:hover { color: var(--text); }
.sc-pays summary svg { width: 14px; height: 14px; transition: transform .15s ease; }
.sc-pays[open] summary svg { transform: rotate(180deg); }
.sc-pays[open] summary { margin-bottom: 4px; }
.sc-pay {
  display: grid; grid-template-columns: auto auto 1fr auto; gap: 10px;
  align-items: baseline; padding: 4px 0;
}
.sc-pay + .sc-pay { border-top: 1px dashed var(--border); }
.sc-pay-when { color: var(--faint); text-align: right; white-space: nowrap; }
.sc-pay b { font-family: var(--font-display); font-weight: 500; color: var(--text); }
.sc-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  margin: 2px -16px 0; padding: 10px 16px; border-top: 1px solid var(--border);
  font-size: 12px; color: var(--muted);
}
.sc-foot b { color: var(--text); font-weight: 600; }
.sc-foot.is-done span { display: inline-flex; align-items: center; gap: 6px; }
.sc-foot.is-done svg { width: 14px; height: 14px; color: var(--red); }
.sc-foot.is-muted span { display: inline-flex; align-items: center; gap: 6px; color: var(--faint); }
.sc-foot.is-muted svg { width: 14px; height: 14px; }
.sc:not(:has(.sc-foot)) { padding-bottom: 14px; }
/* Money leaving the till, so it is red — but outlined and small: a deliberate
   click, not the first thing the eye lands on. */
.btn-refund-sm {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; min-height: 32px; border-radius: 8px;
  background: transparent; color: var(--red); border: 1px solid rgba(239, 68, 68, .45);
  font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
  transition: background .15s ease, border-color .15s ease;
}
.btn-refund-sm:hover { background: var(--red-dim); border-color: var(--red); }
.btn-refund-sm:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(239, 68, 68, .3); }
.btn-refund-sm svg { width: 14px; height: 14px; }
.sc-foot .btn-link {
  background: none; border: 0; padding: 0; font: inherit; font-size: 12px;
  color: var(--text); text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: var(--faint); cursor: pointer;
}
.sc-foot .btn-link:hover { text-decoration-color: var(--text); }
/* Receipt rows in the history: icon, what + when, amount. */
.led-row.rcp {
  grid-template-columns: auto 1fr auto; align-items: center; gap: 12px;
  padding: 11px 14px;
}
.led-row.rcp:focus-visible { outline: none; border-color: var(--border-strong); }
.led-row.rcp.is-refunded { border-left: 1px solid var(--border); }
.led-row.rcp.is-refund { background: var(--card); border-left: 1px solid var(--border); }
.rcp-ico {
  width: 32px; height: 32px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center; flex: none;
}
.rcp-ico svg { width: 16px; height: 16px; }
.rcp-ico.is-in { background: var(--green-dim); color: var(--green); }
.rcp-ico.is-out { background: var(--red-dim); color: var(--red); }
.rcp-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.rcp-top { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.rcp-no { font-family: var(--font-mono); font-size: 12.5px; color: var(--text); }
.rcp-how { font-size: 12px; color: var(--muted); }
.rcp-sub { font-size: 11.5px; color: var(--faint); display: flex; flex-wrap: wrap; gap: 2px 6px; }
.rcp-sub .dot { font-style: normal; }
.rcp-sub.is-back { color: var(--red); }
.rcp-due { color: var(--amber); }
.rcp-amt {
  font-family: var(--font-display); font-size: 15px; text-align: right; white-space: nowrap;
  display: flex; flex-direction: column; align-items: flex-end; gap: 4px;
}
.rcp-amt.is-back { color: var(--red); }

/* The history reads inside a modal that scrolls on its own; a second scroller
   around the receipts only hid the oldest ones. */
#mp-ledger.led-list { max-height: none; overflow: visible; }
@media (max-width: 520px) {
  .sc { padding: 12px 12px 0; }
  .sc-foot { margin: 2px -12px 0; padding: 10px 12px; }
  .sc-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sc-pay { grid-template-columns: auto 1fr auto; }
  .sc-pay-when { grid-column: 1 / -1; text-align: left; order: 5; }
}

/* Payment history: one member's money, read rather than taken — a second view of
   the member modal, not a page, so it is styled to sit inside it. */
.mp-top { display: flex; align-items: center; gap: 8px; margin: 4px 0 16px; }
.mp-top .spacer { flex: 1; }
.mp-head { margin-bottom: 16px; }
.mp-title { font-family: var(--font-display); font-size: 17px; letter-spacing: -0.01em; }
.mp-sub { color: var(--muted); font-size: 12.5px; margin-top: 2px; }
/* A status-level refund is recorded here, not a reversal of money: the banner
   states the fact and the receipts below are left as they are. Purple to match
   the Members-list "Refunded" badge. */
.mp-refunded {
  display: flex; align-items: center; gap: 8px;
  background: var(--purple-dim); color: var(--purple);
  border: 1px solid rgba(168, 85, 247, 0.32);
  border-radius: var(--radius-sm); padding: 10px 12px;
  font-size: 12.5px; font-weight: 600; margin-bottom: 16px;
}
.mp-refunded svg { width: 15px; height: 15px; flex: none; }
/* The `.pay-cell` grid is borrowed from the wizard's summary strip, but standing
   on its own here it needs its own border and corners — inside the wizard those
   come from the row that wraps it. */
.mp-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 10px; margin-bottom: 18px;
}
.mp-strip .pay-cell {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.mp-strip .pay-cell-sub { white-space: normal; }
/* Three tiles side by side, even on a phone — the three numbers are read together. */
@media (max-width: 520px) {
  .mp-strip { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
  .mp-strip .pay-cell { padding: 10px; }
  .mp-strip .pay-v { font-size: 15px; }
}

/* Subscriptions | Receipts — a pill switch. One solid accent pill (black by
   day, white by night) sits behind the chosen tab and slides to the other on
   a switch; the tabs themselves are transparent and only change text colour.
   Geometry: 4px padding and a 4px gap, so each half is 50% − 6px wide and the
   pill moves by its own width plus the gap. */
.mp-tabs {
  position: relative;
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 999px; padding: 4px; margin: 0 0 14px;
}
.mp-tab-ind {
  position: absolute; top: 4px; bottom: 4px; left: 4px;
  width: calc(50% - 6px);
  border-radius: 999px; background: var(--accent);
  box-shadow: var(--shadow-sm);
  transition: transform .32s var(--reveal-ease);
  pointer-events: none;
}
.mp-tabs[data-active="ledger"] .mp-tab-ind,
.mp-tabs[data-active="offline"] .mp-tab-ind { transform: translateX(calc(100% + 4px)); }
/* A switch the owner may not change: still shows the answer, takes no clicks. */
.mp-tabs.is-locked .mp-tab { cursor: not-allowed; }
.mp-tabs.is-locked .mp-tab:not(.active) { opacity: .55; }
.mp-tab {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  border: 0; background: transparent; color: var(--muted);
  padding: 9px 12px; border-radius: 999px;
  font: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer; transition: color .25s ease;
  -webkit-tap-highlight-color: transparent;
}
.mp-tab:hover:not(.active) { color: var(--text); }
.mp-tab:focus-visible { outline: none; box-shadow: var(--ring); }
.mp-tab svg { width: 15px; height: 15px; }
.mp-tab.active { color: var(--accent-text); }
.mp-tab-n {
  min-width: 20px; padding: 1px 6px; border-radius: 999px;
  background: var(--border); color: var(--muted);
  font-size: 11px; font-weight: 700; line-height: 1.5; text-align: center;
  transition: background .25s ease, color .25s ease;
}
/* On the pill the count flips to the page colour, so it reads as a chip on it. */
.mp-tab.active .mp-tab-n { background: var(--accent-text); color: var(--accent); }
#mp-subs-wrap .mp-hint, #mp-ledger-wrap .mp-hint { margin: 0 0 10px; }

.mp-hint { color: var(--faint); font-size: 11.5px; margin: -4px 0 10px; }

.led-wrap { margin-top: 18px; border-top: 1px solid var(--border); padding-top: 16px; }
/* The first block already has the strip above it; a second rule over it would
   only draw a line under a line. Kept after `.led-wrap` so the sheet reads in the
   order it resolves in. */
.led-wrap.is-first { margin-top: 0; border-top: 0; padding-top: 0; }
.led-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  font-size: 11px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 10px;
}
.led-total { color: var(--text); font-family: var(--font-display); letter-spacing: 0; font-size: 13px; text-transform: none; }
.led-list { display: flex; flex-direction: column; gap: 8px; max-height: 240px; overflow-y: auto; }

.led-row {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 12px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 10px 12px;
  cursor: pointer; transition: border-color .13s ease;
}
.led-row:hover { border-color: var(--border-strong); }
.led-amt { font-family: var(--font-display); font-size: 15px; text-align: right; }
.led-when { font-size: 12.5px; color: var(--text); }
.led-sub { grid-column: 1 / -1; font-size: 11.5px; color: var(--muted); display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.led-inv { font-family: var(--font-mono); font-size: 11px; color: var(--faint); }
.led-empty { color: var(--faint); font-size: 12.5px; padding: 6px 0; }

.receipt {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 18px 20px;
}
.rc-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; margin-bottom: 16px; }
.rc-gym { font-family: var(--font-display); font-size: 16px; }
.rc-no { font-family: var(--font-mono); font-size: 12px; color: var(--muted); text-align: right; }
.rc-amt { font-family: var(--font-display); font-size: 30px; letter-spacing: -0.02em; color: var(--green); margin-bottom: 2px; }
.rc-when { font-size: 12.5px; color: var(--muted); margin-bottom: 16px; }
.rc-rows { display: flex; flex-direction: column; gap: 8px; border-top: 1px dashed var(--border-strong); padding-top: 14px; }
.rc-row { display: flex; justify-content: space-between; gap: 12px; font-size: 13px; }
.rc-row span { color: var(--muted); }
.rc-row b { font-weight: 600; }
.rc-foot { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--border-strong); font-size: 11.5px; color: var(--faint); }

/* ── The member wizard on a phone ──────────────────────────────────────────────
   The four-step form is the longest thing in the app, so it is the one that
   suffers most on a small screen. The sheet rules above give it a capped height
   and a sticky head/foot; what is left here is the wizard's own furniture:
   the step rail, the money grids, and the action row. */
@media (max-width: 620px) {
  /* Four money cells across a phone left every label clipped to an ellipsis
     ("Received in to…"). Two across, wrapping instead of clipping. */
  .pay-grid { grid-template-columns: 1fr 1fr; }
  .pay-k { white-space: normal; overflow: visible; text-overflow: clip; }
  .pay-cell-sub { white-space: normal; overflow: visible; text-overflow: clip; }

  /* Hiding every label left four bare circles that said nothing about where you
     were. The current step keeps its name; the rest shrink to numbers. */
  .wiz-step { padding: 8px; min-height: 38px; }
  .wiz-step .wiz-label { display: none; }
  .wiz-step.is-current { padding-right: 13px; }
  .wiz-step.is-current .wiz-label { display: inline; }
  .wiz-num { width: 24px; height: 24px; font-size: 12px; }
  .wiz-hist { width: 38px; height: 38px; }

  /* Back and Next share the top row — the pair you press most — and Save gets a
     full-width row of its own beneath them. Cancel goes: the sticky ✕ in the
     head is always on screen now, so the row does not need a third way out. */
  .wiz-actions { flex-wrap: wrap; gap: 8px; }
  .wiz-actions .spacer { display: none; }
  .wiz-actions .btn[data-close="member-modal"] { display: none; }
  .wiz-actions .btn { min-height: 44px; }   /* thumb-sized, not pointer-sized */
  .wiz-actions #member-save-btn { order: 3; flex: 1 0 100%; }

  /* The history view ends in a list, not in buttons, so it needs the bottom
     edge the sticky action bar would otherwise have given it. */
  #member-hist { padding-bottom: calc(6px + env(safe-area-inset-bottom)); }

  /* Inner scrollers inside a sheet that is itself scrolling: a drag that starts
     on a receipt list used to move that list instead of the form. Let them run
     to full height and leave the scrolling to the sheet. */
  .sub-list, .led-list { max-height: none; overflow: visible; }

  /* The discount input and its two preset chips stop fighting over one line. */
  .disc-row { flex-wrap: wrap; }
  .disc-row input { flex: 1 0 100%; }

  /* Invoice · method · amount stay on one line; the timestamp drops below it
     rather than squeezing all four into 320px. */
  .sub-inst-row { grid-template-columns: auto 1fr auto; }
  .sub-inst-when { grid-column: 1 / -1; }
}

/* ── Modern Trainer Profile Popup ────────────────────────────────────────── */

.tp-hero-modern {
  display: flex;
  gap: 24px;
  align-items: center;
  padding: 24px;
  margin-bottom: 24px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  position: relative;
  overflow: hidden;
}

.tp-hero-modern::before { content: none; }

.tp-avatar-wrapper {
  position: relative;
  flex: none;
}

.tp-face-modern {
  width: 96px;
  height: 96px;
  border-radius: 14px;
  background: var(--card-hover) center/cover no-repeat;
  border: 1px solid var(--border-strong);
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 36px;
  color: var(--muted);
}

.tp-status-indicator {
  position: absolute;
  bottom: -2px;
  right: -2px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--bg);
  border: 3px solid var(--card);
  display: flex;
  align-items: center;
  justify-content: center;
}
.tp-status-indicator::after {
  content: '';
  width: 14px;
  height: 14px;
  border-radius: 50%;
}
.tp-status-indicator.active::after {
  background: var(--green);
}
.tp-status-indicator.inactive::after {
  background: var(--muted);
}

.tp-info-modern {
  display: flex;
  flex-direction: column;
  gap: 6px;
  z-index: 1;
}

.tp-name-modern {
  font-size: 26px;
  font-weight: 700;
  margin: 0;
  color: var(--text);
  letter-spacing: -0.02em;
}

.tp-spec-modern {
  font-size: 15px;
  color: var(--muted);
  font-weight: 500;
}

.badge-modern {
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  width: fit-content;
  margin-top: 6px;
}
.badge-modern-active {
  background: rgba(16, 185, 129, 0.15);
  color: var(--green);
  border: 1px solid rgba(16, 185, 129, 0.3);
}
.badge-modern-inactive {
  background: rgba(107, 114, 128, 0.15);
  color: var(--muted);
  border: 1px solid rgba(107, 114, 128, 0.3);
}

.tp-stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}

.tp-stat-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: all 0.2s ease;
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.tp-stat-card:hover {
  background: var(--card-hover);
  transform: translateY(-4px);
  border-color: var(--border-strong);
  box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}

.tp-stat-label {
  font-size: 12px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
}

.tp-stat-value {
  font-size: 20px;
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--text);
}

.tp-bio-modern {
  background: var(--hover-tint);
  border-left: 4px solid var(--brand);
  padding: 18px 24px;
  border-radius: 0 16px 16px 0;
  color: var(--text);
  font-size: 15px;
  line-height: 1.7;
  margin-bottom: 24px;
  font-style: italic;
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

.tp-block-modern {
  margin-bottom: 28px;
}
.tp-block-modern:last-child {
  margin-bottom: 0;
}

.tp-block-head-modern {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text);
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.tp-block-head-modern::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--border), transparent);
}

.t-gallery-view-modern {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  padding-bottom: 12px;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
.t-gallery-view-modern::-webkit-scrollbar {
  height: 8px;
}
.t-gallery-view-modern::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 4px;
}

.t-shot-modern {
  width: 150px;
  height: 150px;
  flex: none;
  border-radius: 20px;
  background: var(--card-hover) center/cover no-repeat;
  border: 1px solid var(--border);
  box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.t-shot-modern:hover {
  transform: scale(1.04) translateY(-4px);
  box-shadow: 0 12px 24px rgba(0,0,0,0.25);
  border-color: var(--border-strong);
}

.tp-timetable-modern {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 16px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

.tp-timetable-modern .tt-row {
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 18px;
  margin-bottom: 10px;
  transition: all 0.2s ease;
}
.tp-timetable-modern .tt-row:last-child {
  margin-bottom: 0;
}
.tp-timetable-modern .tt-row:hover {
  background: var(--card-hover);
  transform: translateX(6px);
  border-color: var(--border-strong);
}

.tp-timetable-modern .tt-row.free {
  background: transparent;
  border-style: dashed;
  opacity: 0.8;
}
.tp-timetable-modern .tt-row.free:hover {
  opacity: 1;
  background: var(--card);
}

.tp-timetable-modern .tt-time {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  flex-shrink: 0;
}
.tp-timetable-modern .tt-count {
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(120, 110, 255, 0.15);
  color: var(--brand);
  border-radius: 10px;
  width: 30px;
  height: 30px;
  font-size: 14px;
  flex-shrink: 0;
}
.tp-timetable-modern .tt-row.free .tt-count {
  background: var(--border);
  color: var(--muted);
}

.tp-timetable-modern .tt-who {
  font-weight: 500;
  color: var(--text);
  font-size: 15px;
  flex: 1;
  min-width: 0;
  overflow-wrap: break-word;
  word-break: break-word;
}
.tp-timetable-modern .tt-row.free .tt-who {
  color: var(--muted);
}

/* ── Photo viewer (lightbox) ──────────────────────────────────────────────
   A trainer's card hero is 200px tall and cropped to fill — fine for telling
   two trainers apart, useless for actually looking at a photo. Clicking one
   opens it here at full size, and only ever *that* trainer's photos: the
   viewer is a closer look at one person, not a tour of the gym's whole roster.
   The details ride underneath because a photo without a name attached is the
   one thing a viewer like this must not become. */
/* A photo is looked at on black in either theme, so the viewer pins the night
   tokens for everything inside it. */
.pv-overlay {
  color-scheme: dark;
  --text: #fafafa; --muted: #a3a3a3; --faint: #6e6e6e;
  --border: #262626; --border-strong: #363636; --card: #161616;
  color: var(--text);
  position: fixed; inset: 0; z-index: 200;
  background: rgba(8, 8, 8, 0.96);
  display: none; flex-direction: column;
  animation: gg-reveal .2s var(--reveal-ease) both;
}
.pv-overlay.open { display: flex; }

.pv-close {
  position: absolute; top: 16px; right: 18px; z-index: 3;
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, 0.08); border: 0; color: var(--text);
  transition: background .13s ease;
}
.pv-close:hover { background: rgba(255, 255, 255, 0.16); }
.pv-close svg.lucide { width: 20px; height: 20px; }

/* The stage takes whatever height is left once the details have had theirs, so
   a tall photo on a short laptop shrinks instead of pushing the name off. */
.pv-stage {
  position: relative; flex: 1 1 auto; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 56px 68px 10px;
  /* The swipe has to be ours: left/right must page, not scroll the overlay. */
  touch-action: pan-y;
}

.pv-img {
  max-width: 100%; max-height: 100%;
  object-fit: contain;            /* never crop — the whole point of opening it */
  border-radius: 10px;
  user-select: none; -webkit-user-drag: none;
  animation: gg-reveal .22s var(--reveal-ease) both;
}

.pv-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, 0.1); border: 0; color: var(--text);
  transition: background .13s ease;
}
.pv-arrow:hover { background: rgba(255, 255, 255, 0.2); }
.pv-prev { left: 14px; }
.pv-next { right: 14px; }
.pv-arrow svg.lucide { width: 22px; height: 22px; }

.pv-counter {
  position: absolute; top: 18px; left: 50%; transform: translateX(-50%);
  font-size: 12px; font-weight: 600; letter-spacing: .04em;
  color: var(--muted); font-variant-numeric: tabular-nums;
}

.pv-dots { display: flex; gap: 7px; justify-content: center; padding: 10px 0 2px; }
.pv-dot {
  width: 7px; height: 7px; border-radius: 50%; padding: 0; border: 0;
  background: rgba(255, 255, 255, 0.26); transition: all .15s ease;
}
.pv-dot-active { background: var(--text); transform: scale(1.35); }

.pv-meta {
  flex: none; border-top: 1px solid var(--border);
  background: var(--panel);
  padding: 16px 22px 20px; text-align: center;
  max-height: 34vh; overflow-y: auto;
}
.pv-meta h4 { font-family: var(--font-display); font-size: 19px; letter-spacing: -0.01em; }
.pv-meta .pv-spec { color: var(--muted); font-size: 13px; margin: 3px 0 9px; }
.pv-meta .pv-bio { color: var(--muted); font-size: 13px; line-height: 1.55; margin-top: 12px; max-width: 620px; margin-inline: auto; }

.pv-stats {
  display: flex; justify-content: center; flex-wrap: wrap;
  gap: 10px 28px; margin-top: 12px;
}
.pv-stat { display: flex; flex-direction: column; gap: 2px; min-width: 76px; }
.pv-stat b { font-family: var(--font-display); font-size: 16px; }
.pv-stat span { font-size: 10px; letter-spacing: .09em; text-transform: uppercase; color: var(--faint); }

@media (max-width: 640px) {
  .pv-stage { padding: 52px 12px 6px; }
  .pv-arrow { width: 38px; height: 38px; }
  .pv-prev { left: 6px; }
  .pv-next { right: 6px; }
  .pv-meta { padding: 13px 16px 18px; max-height: 40vh; }
}

/* The card hero and the profile thumbnails are now buttons in all but name. */
.tc-slide[data-pv-open], .t-shot-modern[data-pv-open], .tp-face-modern[data-pv-open] { cursor: zoom-in; }


/* ── Gym Settings: how this gym runs ──────────────────────────────────────── */
.mode-desc { margin: 4px 0 0; font-size: 12.5px; color: var(--muted); line-height: 1.55; }
.mode-lock {
  margin: 10px 0 0; font-size: 12px; color: var(--faint);
  display: flex; align-items: center; gap: 6px;
}
.mode-lock svg.lucide { width: 13px; height: 13px; }

/* ── Gym Settings: fingerprint devices ────────────────────────────────────── */
.dev-list { display: flex; flex-direction: column; }
.dev-row {
  display: grid; grid-template-columns: auto 1fr auto; gap: 12px; align-items: center;
  padding: 13px 22px; border-top: 1px solid var(--border);
}
.dev-row:first-child { border-top: 0; }
.dev-row.is-off { opacity: .6; }
.dev-ico {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent-dim); color: var(--text);
}
.dev-ico svg.lucide { width: 17px; height: 17px; }
.dev-main { min-width: 0; }
.dev-name { font-size: 13.5px; font-weight: 600; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.dev-name .mono { font-size: 11.5px; font-weight: 400; color: var(--faint); }
.dev-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.dev-empty {
  display: flex; align-items: center; gap: 12px; padding: 18px 22px;
  color: var(--muted); font-size: 12.5px;
}
.dev-empty svg.lucide { width: 22px; height: 22px; color: var(--faint); }
.dev-empty b { display: block; color: var(--text); font-size: 13px; margin-bottom: 2px; }
.dev-empty span { display: block; }
.dev-key-lead { font-size: 13px; color: var(--muted); line-height: 1.55; margin: 0 0 12px; }
.dev-key-row { display: flex; gap: 8px; align-items: stretch; }
.dev-key {
  flex: 1; min-width: 0; padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--card); border: 1px solid var(--border-strong);
  font-family: var(--font-mono); font-size: 12.5px; color: var(--text);
  overflow-wrap: anywhere; user-select: all;
}
.dev-key.is-hidden { color: var(--muted); letter-spacing: .12em; user-select: none; }
.dev-key-row .dev-key-eye { width: auto; flex: none; padding-left: 11px; padding-right: 11px; }
.dev-key-note {
  margin: 12px 0 0; font-size: 12px; color: var(--muted); line-height: 1.5;
  display: flex; gap: 6px; align-items: flex-start;
}
.dev-key-note svg.lucide { width: 14px; height: 14px; flex: none; margin-top: 2px; }
.dev-actions { display: inline-flex; align-items: center; gap: 8px; flex: none; }
.dev-actions .icon-btn { width: 32px; height: 32px; }
.dev-key-warn {
  margin: 12px 0 0; font-size: 12px; color: var(--amber); line-height: 1.5;
  display: flex; gap: 6px; align-items: flex-start;
}
.dev-key-warn svg.lucide { width: 14px; height: 14px; flex: none; margin-top: 2px; }
@media (max-width: 520px) {
  .dev-row { padding: 12px 16px; }
  .dev-key-row { flex-direction: column; }
}


/* ── Gym Settings: GymGuard Desktop (offline gyms) ────────────────────────── */
.desk-sync { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
.desk-sync-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.desk-sync-title { font-size: 13.5px; font-weight: 600; }
.desk-list { margin: 0 -22px -22px; border-top: 1px solid var(--border); }
.desk-conflicts {
  display: flex; align-items: center; gap: 8px; width: 100%; margin-bottom: 12px;
  padding: 10px 12px; border-radius: var(--radius-sm); cursor: pointer;
  background: var(--amber-dim); color: var(--amber); border: 1px solid transparent;
  font: inherit; font-size: 12.5px; font-weight: 600; text-align: left;
}
.desk-conflicts:hover { border-color: var(--amber); }
.desk-conflicts svg.lucide { width: 15px; height: 15px; }
.conflicts-list { display: flex; flex-direction: column; gap: 8px; max-height: 50vh; overflow-y: auto; }
.conflict-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card);
}
@media (max-width: 520px) {
  .desk-sync-head { flex-direction: column; }
  .desk-list { margin: 0 -16px -22px; }
  .conflict-row { flex-direction: column; align-items: flex-start; }
}

/* ── Desk Sync (GymGuard Desktop only) ───────────────────────────────────── */
.ds-hero {
  display: flex; align-items: center; gap: 16px;
  padding: 18px 20px; margin-bottom: 16px;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
}
.ds-hero-ico {
  width: 46px; height: 46px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent-dim); color: var(--text);
}
.ds-hero-ico svg.lucide { width: 22px; height: 22px; }
.ds-hero.is-ok .ds-hero-ico { background: var(--green-dim); color: var(--green); }
.ds-hero.is-off .ds-hero-ico { background: var(--amber-dim); color: var(--amber); }
.ds-hero.is-bad .ds-hero-ico { background: var(--red-dim); color: var(--red); }
.ds-hero-main { min-width: 0; }
.ds-hero-title { font-size: 16px; font-weight: 700; letter-spacing: -0.01em; }
.ds-hero-sub { font-size: 13px; color: var(--muted); margin-top: 3px; line-height: 1.5; }
.stat-value.ds-value { font-size: 22px; }
#section-desksync .panel { margin-top: 16px; }
.ds-list { display: flex; flex-direction: column; }
.ds-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 20px; border-top: 1px solid var(--border);
}
.ds-row:first-child { border-top: 0; }
.ds-row-main { min-width: 0; font-size: 13px; }
.ds-row-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.ds-note { font-size: 12px; color: var(--faint); margin: 0; padding: 10px 20px 14px; word-break: break-all; }
@media (max-width: 600px) {
  .ds-hero { padding: 14px 16px; }
  .ds-row { padding: 12px 16px; }
}

/* GymGuard Desktop switched off: covers the app until offline mode is on again. */
.desk-blocked {
  position: fixed; inset: 0; z-index: 2000;
  display: flex; align-items: center; justify-content: center; padding: 16px;
  background: var(--bg);
}
.desk-blocked[hidden] { display: none; }
.desk-blocked-card {
  max-width: 520px; width: 100%; text-align: center;
  padding: 32px 28px; background: var(--card);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.desk-blocked-ico {
  width: 56px; height: 56px; border-radius: 50%; margin: 0 auto 16px;
  display: flex; align-items: center; justify-content: center;
  background: var(--red-dim); color: var(--red);
}
.desk-blocked-ico svg.lucide { width: 26px; height: 26px; }
.desk-blocked-card h2 { font-size: 19px; letter-spacing: -0.01em; margin: 0 0 6px; }
.desk-blocked-who { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--faint); margin: 0 0 14px; }
.desk-blocked-card p { font-size: 13.5px; color: var(--muted); line-height: 1.6; margin: 0 0 12px; }
.desk-blocked-pending { color: var(--amber) !important; }
.desk-blocked-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-top: 18px; }

/* Which fingerprint device took a scan (Live Entry Feed). */
.dev-tag { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text); white-space: nowrap; }
.dev-tag svg.lucide { width: 14px; height: 14px; color: var(--muted); flex: none; }
.dev-actions .dev-remove:hover { color: var(--red); border-color: var(--red); }
