:root {
  --bg: #f6f6f7;
  --surface: #ffffff;
  --surface-alt: #faf9f8;
  --border: #e8e7e6;
  --border-strong: #d6d4d2;
  --text: #17181a;
  --text-muted: #6d6e72;
  --text-faint: #9a9b9f;

  /* mediaPro International brand: orange / black / white / grey */
  --brand: #f5820c;
  --brand-600: #d96f00;
  --brand-50: #fff2e5;
  --brand-100: #ffe1bf;

  --dark: #0c0c0d;
  --dark-surface: #17181a;
  --dark-border: #2c2d30;

  --danger: #e11d48;
  --danger-600: #be123c;
  --danger-50: #fef1f4;

  --success: #059669;
  --success-50: #ecfdf5;

  --warning: #b45309;
  --warning-50: #fffbeb;

  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;

  --shadow-sm: 0 1px 2px rgba(12, 12, 13, 0.06);
  --shadow: 0 2px 8px rgba(12, 12, 13, 0.06), 0 1px 2px rgba(12, 12, 13, 0.05);
  --shadow-lg: 0 12px 32px rgba(12, 12, 13, 0.14), 0 4px 10px rgba(12, 12, 13, 0.07);

  --ease: cubic-bezier(0.4, 0, 0.2, 1);
}

/* ---------- theme: dark mode (v26) ----------
   The app's "page" surfaces (--bg/--surface/--text/etc.) were always
   light-mode-only. The header/nav already used a separate always-dark
   --dark/--dark-surface/--dark-border trio (untouched here — the header
   already looks the same in both themes, by design). This block
   overrides the light-mode variables above when the <html> element
   carries data-theme="dark" — set by theme.js on every page, from the
   per-device choice made in profile.html (My Details > Appearance).
   See js/theme.js for the System/Light/Dark selection + persistence
   logic, and js/profile.js for the picker UI itself. */
html[data-theme="dark"] {
  --bg: #0c0c0d;
  --surface: #17181a;
  --surface-alt: #1d1e21;
  --border: #2c2d30;
  --border-strong: #3a3b3f;
  --text: #f2f2f3;
  --text-muted: #a3a4a8;
  --text-faint: #6d6e72;

  --brand-50: #2b1d0d;
  --brand-100: #3d2a12;

  --danger-50: #2b1116;
  --success-50: #0c2019;
  --warning-50: #241a08;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
  --shadow: 0 2px 8px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5), 0 4px 10px rgba(0, 0, 0, 0.35);
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  font-family: "Sora", "Inter", -apple-system, sans-serif;
  letter-spacing: -0.01em;
}

::selection {
  background: var(--brand-100);
}

/* ---------- config warning ---------- */
.config-warning {
  background: var(--warning-50);
  color: #92400e;
  padding: 10px 16px;
  font-size: 13.5px;
  text-align: center;
  border-bottom: 1px solid #fde68a;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

/* ---------- topbar ---------- */
header.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 28px;
  background: var(--dark);
  border-bottom: 1px solid var(--dark-border);
  position: sticky;
  top: 0;
  z-index: 20;
  /* Wrap is a no-op at desktop widths (nothing overflows there), but it's
     what stops schedule.html's button row — up to 8 buttons: Home, Manage,
     Portal, SOPs, Growth, Calendar sync, Edit details, Logout — from being
     clipped or forcing horizontal scroll on a phone-width screen. */
  flex-wrap: wrap;
  row-gap: 10px;
}

header.topbar .brand {
  display: flex;
  align-items: center;
  gap: 12px;
  font-weight: 700;
  font-size: 15.5px;
  color: white;
}

header.topbar .brand .logo-img {
  height: 22px;
  width: auto;
  display: block;
}

/* v27b: white backing plate removed per user's explicit request — logo
   sits directly on the dark header now. Its "Pro" text is black, so it
   will be hard to read there; kept as a no-op class (still referenced in
   the HTML) in case a light-text logo variant arrives later and the
   plate needs reinstating. */
.logo-plate {
  display: flex;
  align-items: center;
}

header.topbar .brand .brand-text {
  padding-left: 12px;
  border-left: 1px solid var(--dark-border);
  line-height: 1.25;
}

header.topbar .brand .brand-text small {
  display: block;
  font-weight: 500;
  color: #9a9ba0;
  font-size: 11.5px;
  margin-top: 1px;
}

header.topbar .who {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 14px;
  font-size: 14px;
}

header.topbar .who .avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--brand);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 12.5px;
}

header.topbar .who .name {
  color: white;
  font-weight: 600;
}

header.topbar .who button.secondary {
  background: transparent;
  color: #e5e5e6;
  border-color: var(--dark-border);
}

header.topbar .who button.secondary:hover {
  background: var(--dark-surface);
  border-color: #45464b;
}

/* ---------- mobile nav (hamburger + dropdown, v26) ----------
   Hidden entirely above the tablet breakpoint — #tabs behaves exactly as
   it always has on a real desktop screen. Below the breakpoint, the
   hamburger replaces the always-visible tab strip: JS (wireMobileNav() in
   js/admin-src/01-bootstrap-nav.js) toggles the SAME #tabs element between
   its normal horizontal layout and this full-width vertical dropdown —
   no duplicate buttons, no separate click wiring to keep in sync, so a
   permission-hidden tab (TAB_ACCESS) or the approvals badge stays correct
   in both layouts automatically. */
.mobile-nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--dark-border);
  border-radius: var(--radius-sm);
  color: white;
  padding: 7px;
  align-items: center;
  justify-content: center;
}

.mobile-nav-toggle:hover {
  background: var(--dark-surface);
}

@media (max-width: 900px) {
  .mobile-nav-toggle {
    display: flex;
  }

  /* Tab strip becomes a hidden-by-default dropdown panel, anchored under
     the header. #tabs already holds every real tab button (including the
     Crew/Admin dropdown children) — collapsing THOSE inner sub-menus flat
     into the list too, rather than nesting a caret-menu inside a
     hamburger menu (two levels of "tap to reveal" on a phone is worse
     than one longer flat list). */
  nav.tabs.top-tabs {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 90;
    flex-direction: column;
    align-items: stretch;
    overflow-y: auto;
    background: var(--dark);
    border-bottom: none;
    padding: 64px 0 24px;
    gap: 0;
  }

  nav.tabs.top-tabs.mobile-open {
    display: flex;
  }

  nav.tabs.top-tabs .tab-btn,
  nav.tabs.top-tabs .nav-dropdown-trigger {
    width: 100%;
    justify-content: flex-start;
    padding: 15px 22px;
    font-size: 15.5px;
    border-radius: 0;
    border-bottom: 1px solid var(--dark-border);
    color: #c7c8cd;
  }

  nav.tabs.top-tabs .tab-btn.active {
    color: var(--brand);
    background: var(--dark-surface);
    border-bottom: 1px solid var(--dark-border);
  }

  /* The Crew / Admin caret-triggered sub-menus: force them permanently
     open and inline (flat list), instead of the desktop's
     click-to-reveal floating panel — see .nav-dropdown-menu.open for the
     desktop version this overrides. */
  nav.tabs.top-tabs .nav-dropdown {
    display: contents;
  }
  nav.tabs.top-tabs .nav-caret-btn {
    display: none;
  }
  nav.tabs.top-tabs .nav-dropdown-menu {
    position: static;
    display: contents;
  }
  nav.tabs.top-tabs .nav-dropdown-item {
    padding-left: 40px;
    font-size: 14.5px;
    color: #9a9ba0;
  }
  nav.tabs.top-tabs .nav-dropdown-trigger {
    display: none;
  }
}

/* ---------- notification bell (v26) ---------- */
.notif-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.notif-bell-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px 8px !important;
}

.notif-bell-btn svg {
  width: 20px;
  height: 20px;
}

.notif-badge {
  position: absolute;
  top: 0;
  right: 0;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  border-radius: 999px;
  background: var(--brand);
  color: white;
  font-size: 10px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

.notif-panel {
  position: absolute;
  top: calc(100% + 10px);
  left: 0;
  width: 320px;
  max-height: 420px;
  overflow-y: auto;
  background: var(--dark-surface);
  border: 1px solid var(--dark-border);
  border-radius: 10px;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.4);
  z-index: 200;
}

.notif-panel-header {
  padding: 12px 14px;
  font-weight: 700;
  font-size: 13px;
  color: white;
  border-bottom: 1px solid var(--dark-border);
  position: sticky;
  top: 0;
  background: var(--dark-surface);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.notif-clear-btn {
  background: none;
  border: none;
  color: var(--brand);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
}

.notif-clear-btn:hover {
  text-decoration: underline;
}

.notif-empty {
  padding: 24px 14px;
  text-align: center;
  color: #9a9ba0;
  font-size: 13px;
}

.notif-item {
  padding: 10px 14px;
  border-bottom: 1px solid var(--dark-border);
  font-size: 13px;
  line-height: 1.4;
}

.notif-item:last-child {
  border-bottom: none;
}

.notif-item.unread {
  background: rgba(245, 130, 12, 0.08);
}

.notif-item-message {
  color: #e5e5e6;
}

.notif-item-time {
  margin-top: 3px;
  color: #808187;
  font-size: 11px;
}

main {
  max-width: 980px;
  margin: 0 auto;
  padding: 28px 20px 72px;
}

/* ---------- admin: sticky top nav ---------- */
.admin-sticky-top {
  position: sticky;
  top: 0;
  z-index: 20;
}

.admin-sticky-top header.topbar {
  position: static;
}

.top-tabs {
  background: var(--dark);
  border-bottom: 1px solid var(--dark-border);
  margin-bottom: 0;
  padding: 0 22px;
}

.top-tabs button {
  color: #b6b7bc;
  position: relative;
}

.top-tabs button:hover {
  background: var(--dark-surface);
  color: white;
}

.top-tabs button.active {
  color: var(--brand);
  border-bottom-color: var(--brand);
}

/* ---------- top-nav dropdowns (v22 Part 4: Crew/Portal/Admin) ---------- */
/* .nav-dropdown is a plain inline flex item sitting inline with the other
   flat .tab-btn buttons in #tabs — the trigger(s) look identical to a
   normal top-tab button, the menu itself is `position: fixed` (computed
   from the trigger's own bounding box at open time) rather than absolutely
   positioned inside #tabs, specifically so it isn't clipped by #tabs'
   `overflow-x: auto` (an ancestor with overflow-x set to anything but
   visible forces overflow-y to an implicit `auto` too per the CSS spec,
   which would otherwise crop any dropdown menu tall enough to hang below
   the nav bar). */
.nav-dropdown {
  position: relative;
  display: flex;
  align-items: stretch;
}

.nav-dropdown-trigger {
  background: none;
  border: none;
  color: #b6b7bc;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0 14px;
  font-weight: 600;
  font-size: 14px;
  font-family: inherit;
  cursor: pointer;
  box-shadow: none;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}

.nav-dropdown-trigger:hover {
  background: var(--dark-surface);
  color: white;
}

.nav-dropdown-trigger[aria-expanded="true"] {
  color: var(--brand);
  border-bottom-color: var(--brand);
}

.nav-caret-icon {
  display: inline-block;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  opacity: 0.75;
  margin-top: 1px;
}

/* The small standalone caret next to the "Crew" tab-btn itself — same
   visual language as .nav-dropdown-trigger's caret, just without a text
   label since "Crew" already has one right next to it. */
.nav-caret-btn {
  background: none;
  border: none;
  color: #b6b7bc;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  cursor: pointer;
  box-shadow: none;
  border-bottom: 2px solid transparent;
  padding: 0;
}

.nav-caret-btn::after {
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  opacity: 0.75;
}

.nav-caret-btn:hover {
  background: var(--dark-surface);
  color: white;
}

.nav-caret-btn[aria-expanded="true"] {
  color: var(--brand);
  border-bottom-color: var(--brand);
}

.nav-dropdown-menu {
  display: none;
  position: fixed;
  z-index: 500;
  min-width: 190px;
  background: var(--dark-surface);
  border: 1px solid var(--dark-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  padding: 6px;
  flex-direction: column;
  gap: 2px;
}

.nav-dropdown-menu.open {
  display: flex;
}

/* Real .tab-btn elements reused inside a dropdown menu need the vertical,
   full-width, left-aligned treatment instead of the horizontal top-tab
   look — descendant selector wins the specificity/order tie against the
   plain `.top-tabs button` rules above since it's more specific. */
.nav-dropdown-menu .tab-btn {
  justify-content: flex-start;
  width: 100%;
  border-bottom: none;
  border-radius: var(--radius-sm);
  padding: 9px 12px;
}

.nav-dropdown-menu .tab-btn.active {
  background: var(--dark);
  color: var(--brand);
}

.nav-dropdown-menu .tab-btn:hover {
  background: var(--dark);
}

/* v27p: header "⋮ More" menu items — same vertical/full-width/left-
   aligned treatment as .nav-dropdown-menu .tab-btn above, but these are
   plain action buttons (not tab-switchers), so they get their own rule
   instead of also carrying the .tab-btn class. */
.nav-dropdown-menu .nav-dropdown-item {
  justify-content: flex-start;
  width: 100%;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  color: #e5e5e6;
  font-size: 14px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  box-shadow: none;
  text-align: left;
}

.nav-dropdown-menu .nav-dropdown-item:hover {
  background: var(--dark);
}

/* The header's own trigger ("⋮ More") sits among plain .secondary
   buttons, not inside #tabs, so it needs the header's light-on-dark
   button look instead of nav-dropdown-trigger's default (built for the
   dark #tabs bar, which is coincidentally the same background here —
   this just makes the border/hover consistent with its .secondary
   siblings in .who). */
header.topbar .who .nav-dropdown-trigger {
  border: 1px solid var(--dark-border);
  border-radius: var(--radius-sm);
  height: 34px;
  /* v27p: icon-only now (no "More" text) — the base .nav-dropdown-trigger
     padding/gap was sized for icon+text side by side; tighten to match
     its icon-only .secondary siblings (Home/Back/Logout) in .who. */
  padding: 0 9px;
  gap: 0;
}

header.topbar .who .nav-dropdown-trigger:hover {
  background: var(--dark-surface);
  border-color: #45464b;
}

.nav-dropdown-menu .tab-badge {
  margin-left: auto;
}

.admin-shell main {
  padding-top: 26px;
  /* v20: the admin screen has the densest tables/forms in the app (wide
     equipment/crew/assignments tables, side-by-side stat cards) — widen
     just this shell's content column. Every other page (schedule, sops,
     growth, profile — profile keeps its own narrower 640px inline
     override) stays at the global 980px width above. */
  max-width: 1400px;
}

.tab-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 17px;
  height: 17px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--danger);
  color: white;
  font-size: 10.5px;
  font-weight: 700;
  margin-left: 2px;
}

.centered-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  /* v25b: was a dark, orange-tinted gradient. Philip asked for a plain
     white page — so no gradient, no dark ground, and the card below drops
     its dark treatment to match. */
  background: #ffffff;
}

/* ---------- cards ---------- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 28px;
  box-shadow: var(--shadow);
}

.login-card {
  width: 100%;
  max-width: 400px;
  /* v25b: light card on the now-white page. Kept as a card (rather than a
     bare form on the background) so the inputs still have an edge to sit
     against on a wide screen. */
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.login-card .login-logo {
  width: 100%;
  max-width: 260px;
  height: auto;
  display: block;
  margin: 0 auto 22px;
  border-radius: 8px;
}

/* v25b: the .login-wordmark rule is gone with the "ATC Group" text it
   styled — the pre-login pages carry no company name now. If a logo is
   ever wanted back, .login-card .login-logo above is still here for it. */

.login-card h1 {
  font-size: 19px;
  margin: 0 0 4px;
  text-align: center;
  color: var(--text);
}

.login-card p.subtitle {
  color: var(--text-muted);
  margin: 0 0 22px;
  font-size: 13.5px;
  text-align: center;
}

.login-card label {
  color: var(--text-muted);
}

/* Scoped with .card.login-card (both classes are on the element) so this
   reliably beats the generic input[type=...] rules below, regardless of
   source order — otherwise the dark theme's white text loses the
   specificity tie and renders as dark-on-dark while typing. */
/* v25b: light inputs, matching the rest of the app's forms. The
   .card.login-card double-class scoping is kept — it was there to win a
   specificity tie against the generic input rules further down, and that
   is still true whichever colours it sets. */
.card.login-card input {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text);
}

.card.login-card input:focus {
  background: var(--surface);
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(245, 130, 12, 0.18);
  color: var(--text);
}

.login-card .hint {
  color: var(--text-muted);
  justify-content: center;
}

.hidden-block {
  display: none !important;
}

/* v27e: collapsed-by-default Crew Needed / Stock Needed event cards. */
.event-card-toggle:hover {
  opacity: 0.85;
}
.event-card-caret {
  color: var(--muted-foreground, #888);
  font-size: 13px;
  line-height: 1;
  user-select: none;
}


.forgot-link {
  text-align: center;
  margin: 14px 0 0;
  font-size: 13px;
}

.forgot-link a {
  color: var(--brand);
  text-decoration: none;
  font-weight: 600;
}

.forgot-link a:hover {
  text-decoration: underline;
}

/* v27o: password field eye-toggle, shared by login + change-password. */
.password-field {
  position: relative;
}
.password-field input[type="password"],
.password-field input[type="text"] {
  padding-right: 42px;
}
.password-toggle-btn {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  padding: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.password-toggle-btn svg {
  width: 18px;
  height: 18px;
}
.password-toggle-btn:hover {
  color: var(--text);
  background: var(--surface-alt);
}

/* ---------- forms ---------- */
label {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 6px;
  margin-top: 14px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
input[type="datetime-local"],
input[type="tel"],
select,
textarea {
  width: 100%;
  padding: 10px 13px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 14.5px;
  font-family: inherit;
  background: var(--surface-alt);
  color: var(--text);
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}

textarea {
  resize: vertical;
  min-height: 64px;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-100);
  background: var(--surface);
}

/* ---------- buttons ---------- */
button,
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: none;
  border-radius: var(--radius-sm);
  padding: 10px 17px;
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  background: var(--brand);
  color: white;
  transition: background 0.15s var(--ease), transform 0.05s var(--ease), box-shadow 0.15s var(--ease);
  box-shadow: 0 1px 2px rgba(245, 130, 12, 0.25);
}

button:hover,
.btn:hover {
  background: var(--brand-600);
}

button:active,
.btn:active {
  transform: translateY(1px);
}

button.secondary,
.btn.secondary {
  background: var(--surface);
  color: var(--text);
  border: 1.5px solid var(--border-strong);
  box-shadow: none;
}

button.secondary:hover,
.btn.secondary:hover {
  background: var(--bg);
  border-color: var(--text-faint);
}

button.danger,
.btn.danger {
  background: var(--danger);
  box-shadow: 0 1px 2px rgba(225, 29, 72, 0.2);
}

button.danger:hover,
.btn.danger:hover {
  background: var(--danger-600);
}

button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

button.full-width {
  width: 100%;
  margin-top: 22px;
  padding: 11px 17px;
}

button svg,
.btn svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.error-text {
  color: var(--danger);
  font-size: 13px;
  margin-top: 12px;
  min-height: 1em;
}

/* ---------- stat cards ---------- */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-bottom: 28px;
}

.stat-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 20px;
  box-shadow: var(--shadow-sm);
  display: flex;
  align-items: center;
  gap: 14px;
}

.stat-card .stat-icon {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.stat-card .stat-icon svg {
  width: 20px;
  height: 20px;
}

.stat-card.events .stat-icon { background: var(--brand-50); color: var(--brand-600); }
.stat-card.crew .stat-icon { background: var(--success-50); color: var(--success); }
.stat-card.week .stat-icon { background: var(--warning-50); color: var(--warning); }

.stat-card .stat-value {
  font-size: 22px;
  font-weight: 700;
  line-height: 1.1;
  font-family: "Sora", "Inter", sans-serif;
}

.stat-card .stat-label {
  font-size: 12.5px;
  color: var(--text-muted);
  margin-top: 2px;
}

/* ---------- tabs ---------- */
.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1.5px solid var(--border);
  margin-bottom: 24px;
  overflow-x: auto;
}

.tabs button {
  background: none;
  color: var(--text-muted);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  padding: 10px 16px;
  font-weight: 600;
  font-size: 14px;
  border-bottom: 2px solid transparent;
  box-shadow: none;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.tabs button svg {
  width: 16px;
  height: 16px;
  opacity: 0.8;
}

.tabs button:hover {
  background: var(--bg);
  color: var(--text);
}

.tabs button.active {
  color: var(--brand);
  border-bottom: 2px solid var(--brand);
  background: none;
}

.section {
  display: none;
  animation: fadeIn 0.2s var(--ease);
}

.section.active {
  display: block;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}

.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
  gap: 12px;
  flex-wrap: wrap;
}

.section-header h2 {
  font-size: 19px;
  margin: 0;
}

/* ---------- tables ---------- */
.table-scroll {
  overflow-x: auto;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

table {
  width: 100%;
  border-collapse: collapse;
  min-width: 480px;
}

.table-scroll table {
  border: none;
  box-shadow: none;
  border-radius: 0;
}

/* v27l: card-per-person Permissions layout (replaces the v27k grouped
   table, which was too cramped at 16 sub-areas even collapsed). */
.perm-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 12px 18px;
  margin-bottom: 8px;
  box-shadow: var(--shadow-sm);
}
.perm-card-head {
  font-size: 15px;
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: none;
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 8px;
}
.perm-card-caret {
  font-size: 11px;
  color: var(--text-muted);
  width: 12px;
}
.perm-card-body {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.perm-card-head .meta {
  color: var(--text-muted);
  font-weight: 400;
  font-size: 13px;
}
.perm-card-ungrouped {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 24px;
  margin-bottom: 14px;
}
.perm-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 220px;
}
.perm-row label {
  flex: 1;
  font-size: 13.5px;
  color: var(--text-muted);
}
.perm-row select {
  min-width: 130px;
}
.perm-group {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-top: 10px;
  overflow: hidden;
}
.perm-group-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  cursor: pointer;
  user-select: none;
  background: var(--surface-alt);
}
.perm-group-bar:hover {
  background: var(--surface-hover, var(--surface-alt));
}
.perm-group.is-open .perm-group-bar {
  border-bottom: 1px solid var(--border);
}
.perm-group-caret {
  font-size: 11px;
  color: var(--text-muted);
  width: 12px;
}
.perm-group-agg {
  margin-left: auto;
}
.perm-group-body {
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.perm-bulk-row {
  padding-bottom: 12px;
  margin-bottom: 4px;
  border-bottom: 1px dashed var(--border);
}
.perm-bulk-row label {
  font-weight: 600;
  color: var(--text);
}
.pill.mixed {
  background: hsl(35, 70%, 92%);
  color: hsl(35, 70%, 30%);
}
.pill.none {
  background: #f1f2f5;
  color: var(--text-muted);
}
.pill.view {
  background: #eef1f5;
  color: #475569;
}
.pill.edit {
  background: var(--brand-50, #fff3e6);
  color: var(--brand-600, #b5590a);
}
.pill.manage {
  background: var(--success-50);
  color: var(--success);
}
th,
td {
  text-align: left;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
  vertical-align: middle;
}

th {
  background: var(--surface-alt);
  color: var(--text-muted);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 700;
}

tbody tr {
  transition: background 0.1s var(--ease);
}

tbody tr:hover {
  background: var(--surface-alt);
}

tr:last-child td {
  border-bottom: none;
}

/* v25g fix: this used to be `display: flex`. A <td> with display:flex stops
   being a table cell, so it no longer stretches to the row's height or
   participates in the table's column layout — the action buttons ended up
   8px short of the row and sitting above its vertical centre, which is the
   misalignment visible against every other column. It stays a table cell
   now; the buttons are laid out inside it instead. */
td.actions {
  white-space: nowrap;
  text-align: right;
  vertical-align: middle;
}

td.actions button {
  padding: 6px 12px;
  font-size: 13px;
  vertical-align: middle;
}

/* Tables that still show two or three full-text action buttons inline
   (Crew, Dry Hire, Branch Shipments) space and wrap them here, rather than
   by making the cell itself a flex container. */
td.actions.wrap-actions {
  white-space: normal;
}

td.actions.wrap-actions button {
  margin: 2px 0;
}

td.actions.wrap-actions button + button {
  margin-left: 8px;
}

/* ---------- pills ---------- */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 11px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
}

.pill::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.pill.admin { background: #f3effe; color: #7c3aed; }
.pill.crew { background: var(--brand-50); color: var(--brand-600); }
.pill.inactive { background: var(--danger-50); color: var(--danger-600); }
.pill.upcoming { background: var(--success-50); color: var(--success); }
.pill.past { background: #f1f2f5; color: var(--text-muted); }

/* ---------- empty / loading states ---------- */
.empty-state {
  text-align: center;
  color: var(--text-muted);
  padding: 48px 20px;
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--radius);
  font-size: 14px;
  background: var(--surface-alt);
}

.empty-state .empty-icon {
  width: 42px;
  height: 42px;
  margin: 0 auto 12px;
  color: var(--text-faint);
}

.empty-state .empty-icon svg {
  width: 100%;
  height: 100%;
}

.empty-state strong {
  display: block;
  color: var(--text);
  font-size: 14.5px;
  margin-bottom: 4px;
}

.loading {
  color: var(--text-muted);
  font-size: 14px;
  padding: 8px 0;
  display: flex;
  align-items: center;
  gap: 10px;
}

.spinner {
  width: 16px;
  height: 16px;
  border: 2px solid var(--border-strong);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  flex-shrink: 0;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

@keyframes shimmer {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/* ---------- schedule / assignment cards ---------- */
.greeting-banner {
  background: linear-gradient(135deg, var(--dark) 0%, #2a2115 55%, var(--brand) 130%);
  color: white;
  border-radius: var(--radius-lg);
  padding: 24px 26px;
  margin-bottom: 26px;
  box-shadow: 0 8px 24px rgba(12, 12, 13, 0.3);
}

.greeting-banner h1 {
  margin: 0 0 4px;
  font-size: 21px;
}

.greeting-banner p {
  margin: 0;
  opacity: 0.9;
  font-size: 14px;
}

.group-heading {
  font-size: 12.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  margin: 28px 0 12px;
}

.group-heading:first-child {
  margin-top: 0;
}

.assignment-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--brand);
  border-radius: var(--radius);
  padding: 18px 20px;
  margin-bottom: 12px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.15s var(--ease), transform 0.15s var(--ease);
}

.assignment-card:hover {
  box-shadow: var(--shadow);
}

.assignment-card.is-past {
  border-left-color: var(--border-strong);
  opacity: 0.8;
}

.assignment-card .event-name {
  font-weight: 700;
  font-size: 16px;
  margin: 0 0 2px;
}

.assignment-card .event-venue {
  color: var(--text-muted);
  font-size: 13.5px;
  margin: 0 0 14px;
  display: flex;
  align-items: center;
  gap: 6px;
}

.assignment-card .event-venue svg {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
}

.assignment-card .meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  font-size: 14px;
  margin-bottom: 4px;
}

.assignment-card .meta-row .label {
  color: var(--text-faint);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  display: block;
  margin-bottom: 3px;
  font-weight: 700;
}

.assignment-card .meta-row .value {
  font-weight: 600;
}

.assignment-card .notes {
  font-size: 13.5px;
  color: var(--text);
  background: var(--surface-alt);
  border-radius: var(--radius-sm);
  padding: 10px 13px;
  margin-top: 12px;
  border: 1px solid var(--border);
}

/* ---------- weekly schedule view (schedule.html, v18) ---------- */
.week-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.week-nav-btns {
  display: flex;
  gap: 8px;
}

.week-nav-btns button {
  padding: 8px 13px;
  font-size: 13px;
}

.week-range {
  font-weight: 700;
  font-size: 14.5px;
  font-family: "Sora", "Inter", sans-serif;
  color: var(--text-muted);
}

/* Its own horizontally-scrolling container (same principle as
   .table-scroll) — 7 day columns of real event cards need real width per
   column, so on a phone this scrolls sideways rather than squeezing every
   column unreadably thin. */
.week-grid-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.week-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 10px;
}

/* v25r: this was `min-width: 900px`, which forced a horizontal scrollbar on
   every screen narrower than that - including the desktop one it was
   designed for, and hopelessly on a phone. Seven columns now share whatever
   width there is, and below 760px the week stacks into a day-per-row list,
   which is the shape a phone actually wants. */
@media (max-width: 760px) {
  .week-grid {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .week-day-col {
    display: grid;
    grid-template-columns: 62px minmax(0, 1fr);
    gap: 10px;
    align-items: start;
    padding: 9px 0;
    border-bottom: 1px solid var(--border);
  }
  .week-day-col:last-child { border-bottom: none; }
  /* The header becomes a fixed-width gutter: day and date side by side. */
  .week-day-header {
    display: flex;
    align-items: baseline;
    gap: 6px;
    border-bottom: none;
    padding: 0;
    text-align: left;
  }
  .week-day-name { font-size: 11px; }
  .week-day-num { font-size: 17px; }
  /* A day with nothing on it should take one quiet line, not a whole card. */
  .week-day-col .week-day-empty {
    padding: 0;
    border: none;
    background: none;
    text-align: left;
    font-size: 12.5px;
  }
}

.week-day-col {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.week-day-header {
  text-align: center;
  padding-bottom: 8px;
  border-bottom: 2px solid var(--border);
  margin-bottom: 2px;
}

.week-day-header.is-today {
  border-bottom-color: var(--brand);
}

.week-day-name {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  font-weight: 700;
}

.week-day-header.is-today .week-day-name {
  color: var(--brand-600);
}

.week-day-num {
  font-size: 18px;
  font-weight: 700;
  font-family: "Sora", "Inter", sans-serif;
  margin-top: 2px;
}

.week-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  box-shadow: var(--shadow-sm);
}

.week-card .wc-event {
  font-weight: 700;
  font-size: 13.5px;
  margin-bottom: 3px;
}

.week-card .wc-meta {
  color: var(--text-muted);
  font-size: 12px;
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 2px;
}

.week-card .wc-meta svg {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}

.week-day-empty {
  color: var(--text-faint);
  font-size: 12px;
  text-align: center;
  padding-top: 14px;
}

@media (max-width: 640px) {
  .week-nav-btns {
    gap: 6px;
  }
  .week-nav-btns button {
    padding: 9px 10px;
    font-size: 12.5px;
  }
}

/* ---------- modal ---------- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(17, 20, 30, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 100;
  animation: fadeIn 0.15s var(--ease);
}

.modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 26px;
  width: 100%;
  max-width: 460px;
  max-height: 90vh;
  overflow-y: auto;
  box-shadow: var(--shadow-lg);
  animation: modalIn 0.18s var(--ease);
}

@keyframes modalIn {
  from { opacity: 0; transform: scale(0.97) translateY(6px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

.modal h3 {
  margin: 0 0 4px;
  font-size: 17.5px;
}

.modal .modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 22px;
}

.modal.confirm-modal {
  max-width: 380px;
}

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

.modal.xwide {
  max-width: 860px;
}

@media (max-width: 680px) {
  .modal.wide,
  .modal.xwide {
    max-width: 100%;
  }
}

.modal.confirm-modal p {
  color: var(--text-muted);
  font-size: 14px;
  margin: 6px 0 0;
}

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

/* v25i fix: this was `display: flex`, which turns every inline element in
   the hint's own sentence — a <strong>, an <a> — into a separate flex ITEM,
   so it breaks out of the text and sits in its own column. Eleven hints
   across the app were laying out as staggered fragments because of it, the
   Crew tab's being the most visible. The icon is positioned inline instead,
   so the hint is ordinary flowing text again. */
.hint {
  color: var(--text-muted);
  font-size: 12.5px;
  margin-top: 4px;
  line-height: 1.55;
}

/* v27: a plain inline text-button — used where an action needs to sit
   next to a form field (e.g. "Manage categories" under the equipment
   item Category select) without the visual weight of a bordered
   .secondary button. */
.link-btn {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.link-btn:hover {
  text-decoration: underline;
}

/* Terms & Conditions text shown on profile.html first-time completion
   (v23: no longer also at index.html/freelancer-portal.js — invite-only
   onboarding removed both). */
.terms-box {
  max-height: 160px;
  overflow-y: auto;
  white-space: pre-line;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-muted);
  background: var(--bg-soft, #f7f7f8);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  margin-top: 6px;
}

.hint svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  vertical-align: -3px;
  margin-right: 5px;
  color: var(--text-faint);
}

/* ---------- toasts ---------- */
#toast-root {
  position: fixed;
  bottom: 22px;
  right: 22px;
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-end;
}

.toast {
  background: var(--text);
  color: white;
  padding: 12px 16px;
  border-radius: var(--radius-sm);
  font-size: 13.5px;
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  display: flex;
  align-items: center;
  gap: 10px;
  animation: toastIn 0.2s var(--ease);
  max-width: 320px;
}

.toast svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.toast.success svg { color: #4ade80; }
.toast.error { background: var(--danger-600); }
.toast.error svg { color: white; }

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

/* v26: base (desktop) state — hidden entirely above the phone
   breakpoint. MUST sit here, before the @media block below, not after
   it anywhere later in the file: CSS applies whichever same-specificity
   rule comes LAST in source order, @media condition or not, so a later
   unconditioned "display: none" would silently beat this block's
   "display: inline-flex" even while the media query correctly matched —
   which is exactly the bug that made the toggle button (and the whole
   collapsible filter bar behind it, including the Equipment search box)
   invisible on a real phone despite every other part working. */
.filter-toggle-btn {
  display: none;
}

@media (max-width: 640px) {
  header.topbar {
    padding: 12px 16px;
  }
  header.topbar .brand .brand-text small {
    display: none;
  }
  header.topbar .who .name {
    display: none;
  }
  header.topbar .who button span {
    display: none;
  }
  /* v27p: the "⋮ More" trigger itself is icon-only now (no "More" text
     label — Philip: "remove the text More"), so only the dropdown MENU
     items (SOPs/My Growth/etc) need their labels forced visible here;
     everything else in .who still goes icon-only at this width. */
  header.topbar .who .nav-dropdown-item span {
    display: inline;
  }
  header.topbar .who {
    gap: 8px;
  }
  main {
    padding: 18px 14px 56px;
  }
  .field-row {
    grid-template-columns: 1fr;
  }
  .stat-grid {
    grid-template-columns: 1fr;
  }
  #toast-root {
    left: 14px;
    right: 14px;
    bottom: 14px;
    align-items: stretch;
  }
  .toast {
    max-width: none;
  }

  /* iOS Safari zooms the whole page in when a focused form field renders
     below 16px — every field here was 14.5px, so typing anywhere (login,
     a modal, adding a crew member) triggered an unwanted zoom on phones.
     16px+ keeps the keyboard focus from zooming, and select needs the
     tap-target bump on its own since it isn't in the padding rule below. */
  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="date"],
  input[type="datetime-local"],
  input[type="tel"],
  select,
  textarea {
    font-size: 16px;
  }

  /* Bigger touch targets for the compact action buttons inside table rows
     (View/Edit/Pay etc.) — 6px vertical padding is a fine mouse target but
     tight for a thumb. */
  td.actions button {
    padding: 9px 12px;
  }

  .modal {
    padding: 20px;
  }

  /* Attendance calendar (admin.html) — 7 fixed columns get cramped once
     gutters and cell padding eat into a phone-width screen. */
  .att-cal-grid {
    gap: 3px;
  }
  .att-cal-cell {
    min-height: 44px;
    padding: 4px;
  }
  .att-cal-daynum {
    font-size: 11px;
    margin-bottom: 2px;
  }
  .att-cal-weekday {
    font-size: 9.5px;
  }

  /* Equipment/Stock header actions: Import and Backup (export) are
     desktop file-picker/download workflows crew rarely if ever need on
     a phone in the field — hiding them here reclaims space for the
     buttons that matter on a phone (Add item). Add item / Categories /
     Stock demand / Check availability stay — those are used on-site.
     "+ Add item" itself (id=add-equipment-item-btn) is intentionally
     NOT hidden. */
  #import-inventory-btn,
  #export-inventory-btn {
    display: none;
  }

  /* Collapsible filter bar toggle (Timeline / Equipment tabs) — see
     .filter-toggle-btn base rule and wireFilterToggles() in
     js/admin-src/01-bootstrap-nav.js. Filter bar starts collapsed via
     the [hidden] attribute JS sets on load; toggling adds/removes it. */
  .filter-toggle-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    width: 100%;
    justify-content: center;
    padding: 10px 14px;
    margin-bottom: 12px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text);
    font-weight: 600;
    font-size: 13.5px;
    box-shadow: var(--shadow-sm);
  }
  .filter-toggle-btn.open {
    color: var(--brand);
    border-color: var(--brand);
  }
  .filter-bar[hidden] {
    display: none;
  }
}

/* ---------- responsive tables: card layout on phones ----------
   Every table row already renders each <td data-label="..."> — that
   labeling was in place across the whole app (Crew, Events, Equipment/
   Stock, Accommodation, Growth, etc.) with no CSS ever consuming it.
   Below 900px (tablet and phone alike — the same tier the hamburger nav
   switches on) a plain data table runs out of room and either clips
   columns or forces a hidden-scrollbar horizontal scroll a user has no
   visual cue exists (v26 first pass used 480px/phone-only here, which
   left tablet-width users staring at a table cut off mid-column with no
   indication more was off-screen — see the "SPEC column chopped" report).
   Each <tr> becomes its own card and each
   <td> becomes a labeled row inside it, using the existing data-label
   attribute instead of touching any JS render function.
   - Header row is hidden (labels move onto each cell instead).
   - A <td> with no data-label (e.g. an avatar-only cell) hides its own
     label rather than printing a colon with nothing after it.
   - td.actions (View/Edit/Remove buttons) spans full width as a footer
     row inside the card, buttons laid out with a gap instead of the
     desktop's nowrap/text-align:right.
   Scoped to .table-scroll table only — the one wrapper class already
   used by every real data table in the app (confirmed via grep before
   writing this rule), so nothing outside a real table is affected. */
@media (max-width: 900px) {
  .table-scroll {
    border: none;
    background: transparent;
    box-shadow: none;
    overflow-x: visible;
  }

  .table-scroll table {
    min-width: 0;
  }

  .table-scroll thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  .table-scroll tbody tr {
    display: block;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 6px 10px;
    margin-bottom: 8px;
  }

  .table-scroll tbody tr:last-child {
    margin-bottom: 0;
  }

  .table-scroll td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    padding: 5px 0;
    border-bottom: 1px solid var(--border);
    text-align: right;
    font-size: 12.5px;
    min-height: 0;
    line-height: 1.25;
  }

  .table-scroll td:last-child {
    border-bottom: none;
  }

  .table-scroll td[data-label]::before {
    content: attr(data-label);
    font-weight: 600;
    font-size: 10.5px;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--text-faint, var(--text-muted));
    text-align: left;
    flex-shrink: 0;
  }

  /* v26 fix: an earlier pass here truncated long item names with an
     ellipsis to save height — that hid real information (you couldn't
     read a long product name at all), so names wrap normally again.
     Card height is instead cut by putting Type/In stock/Out of service
     side-by-side on the Equipment table specifically, see
     .eq-stock-table below. */
  .table-scroll td .eq-sub,
  .table-scroll td .hint {
    display: inline;
    margin: 0 0 0 5px;
    font-size: 11px;
  }

  /* Equipment/Stock table specifically: the Item cell's "Make" sub-line
     (e.g. "Acme" under "Acme Gemini") is dropped entirely in card mode —
     narrower cards mean the full item name matters more than the make,
     and removing it gives the name itself more room to breathe. Desktop
     table is unaffected — .eq-sub still shows there. */
  .table-scroll .eq-stock-table td .eq-sub {
    display: none;
  }

  /* Cell with no data-label (e.g. bare avatar/photo cell) — no label
     row, just let the cell's own content lay out full-width. */
  .table-scroll td:not([data-label]),
  .table-scroll td[data-label=""] {
    justify-content: flex-start;
  }
  .table-scroll td:not([data-label])::before,
  .table-scroll td[data-label=""]::before {
    content: none;
  }

  /* Actions cell becomes a full-width footer of buttons, not a
     right-aligned label row like every other cell. */
  .table-scroll td.actions {
    justify-content: flex-end;
    flex-wrap: wrap;
    text-align: left;
  }
  .table-scroll td.actions::before {
    content: none;
  }
  .table-scroll td.actions.wrap-actions button {
    margin: 3px 0 3px 8px;
  }

  /* Equipment/Stock table specifically: Category and Specs were asked to
     drop out in card mode — Name/Type/In stock/Out of service stay, per
     the user's own scoping ("reduce the amount of information ... Name,
     Type, In Stock, and Out of service"). Desktop table is unaffected —
     both columns still render normally there. */
  .table-scroll .eq-stock-table td[data-label="Category"],
  .table-scroll .eq-stock-table td[data-label="Specs"] {
    display: none;
  }

  /* Item cell: label ("ITEM") and the item name sit on one line, side
     by side — label as a narrow fixed-width column on the left, name
     filling the rest of the row and wrapping normally within that
     space. (Earlier passes tried stacking label above name for more
     width, then truncating with an ellipsis — both were reported as
     worse: user wants them back on one row, using the full width up to
     where the row itself ends, same shape as every other card cell.) */
  .table-scroll .eq-stock-table td[data-label="Item"] {
    flex-direction: row;
    align-items: flex-start;
    text-align: left;
    gap: 10px;
  }
  .table-scroll .eq-stock-table td[data-label="Item"]::before {
    text-align: left;
    flex: 0 0 auto;
    padding-top: 2px;
  }
  .table-scroll .eq-stock-table td[data-label="Item"] strong {
    display: block;
    flex: 1 1 auto;
    min-width: 0;
  }

  /* Type / In stock / Out of service side-by-side in one compact row
     instead of three full-width label/value lines — cuts card height
     without hiding anything (Item's own row is untouched, full name
     still wraps normally above). Each becomes a narrow column with its
     label stacked above the value, rather than the label-left/value-
     right layout every other card cell uses, since there isn't room for
     both a label and a value side-by-side at a third of the width. */
  .table-scroll .eq-stock-table td[data-label="Type"],
  .table-scroll .eq-stock-table td[data-label="In stock"],
  .table-scroll .eq-stock-table td[data-label="Out of service"] {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    width: auto;
    flex: 1 1 0;
    gap: 2px;
    text-align: left;
    padding: 5px 6px 5px 0;
    border-bottom: none;
  }
  .table-scroll .eq-stock-table td[data-label="Type"]::before,
  .table-scroll .eq-stock-table td[data-label="In stock"]::before,
  .table-scroll .eq-stock-table td[data-label="Out of service"]::before {
    text-align: left;
  }
  /* The three sit in their own shared bottom-border row — a single rule
     underlines all three together instead of each cell drawing (and
     wasting space on) its own. */
  .table-scroll .eq-stock-table td[data-label="Out of service"] {
    border-bottom: 1px solid var(--border);
    padding-bottom: 8px;
    margin-bottom: 3px;
  }

  /* v26: mobile-only "Sort by" dropdown for tables whose real sort
     controls (clickable <th> headers) just got hidden above along with
     the rest of <thead> — see equipItemsTableHtml() in
     js/admin-src/06-equipment-stock.js. Hidden above this breakpoint via
     the base .mobile-sort-bar rule (outside this media query). */
  .mobile-sort-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
  }
}

/* Base (desktop) state for the mobile sort bar — never shown above the
   900px breakpoint; the @media block above turns it back on. */
.mobile-sort-bar {
  display: none;
}
.mobile-sort-bar label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
}
.mobile-sort-bar select {
  flex: 1;
}

/* Smoother momentum scrolling on iOS for the app's horizontally-scrolling
   strips: wide tables and the admin top-nav (13 tabs won't all fit on a
   phone, so it scrolls rather than wrapping into a multi-row nav). */
.table-scroll,
.tabs {
  -webkit-overflow-scrolling: touch;
}

/* Hide the scrollbar track/arrows on these horizontally-scrolling strips
   (tab nav, wide tables) — content still scrolls by touch/trackpad/drag,
   just without the native scrollbar bar-and-arrows UI sitting under it.
   On a real phone this is mostly invisible already (touch scrollbars
   auto-hide), but a desktop browser resized down to phone width shows
   the full classic scrollbar, which is what this was fixing. */
.table-scroll,
.tabs,
.top-tabs {
  scrollbar-width: none;
}
.table-scroll::-webkit-scrollbar,
.tabs::-webkit-scrollbar,
.top-tabs::-webkit-scrollbar {
  display: none;
}

/* ---------- status / cert pills ---------- */
.pill.status-quoted { background: #eef1f5; color: #475569; }
.pill.status-verbal { background: var(--warning-50); color: var(--warning); }
.pill.status-confirmed { background: var(--success-50); color: var(--success); }
.pill.status-postponed { background: #f1f2f5; color: #6b7280; }
.pill.status-cancelled { background: var(--danger-50); color: var(--danger-600); }

.pill.cert-valid { background: var(--success-50); color: var(--success); }
.pill.cert-soon { background: var(--warning-50); color: var(--warning); }
.pill.cert-expired { background: var(--danger-50); color: var(--danger-600); }
.pill.cert-none { background: #f1f2f5; color: var(--text-faint); }

.pill.freelancer { background: #f3effe; color: #7c3aed; }
.pill.staff { background: var(--brand-50); color: var(--brand-600); }

/* ---------- accommodation chips ---------- */
.chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 14px;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 6px 8px 6px 14px;
  font-size: 13px;
  box-shadow: var(--shadow-sm);
}

.chip button {
  background: none;
  border: none;
  padding: 4px;
  margin: 0;
  color: var(--text-faint);
  cursor: pointer;
  display: flex;
  box-shadow: none;
}

.chip button svg {
  width: 13px;
  height: 13px;
}

.chip button:hover {
  color: var(--danger);
  background: var(--danger-50);
  border-radius: 50%;
}

.inline-add-form {
  display: flex;
  gap: 8px;
  max-width: 420px;
}

.inline-add-form input {
  flex: 1;
}

/* ---------- requirement gauges ---------- */
.req-gauge-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 10px;
  margin-bottom: 8px;
}

.req-gauge {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
}

.req-gauge .req-role {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 6px;
}

.req-gauge .req-count {
  font-size: 15px;
  font-weight: 700;
}

.req-gauge .req-count.short { color: var(--danger); }
.req-gauge .req-count.full { color: var(--success); }

.req-gauge .req-bar {
  height: 5px;
  border-radius: 3px;
  background: var(--border);
  margin-top: 8px;
  overflow: hidden;
}

.req-gauge .req-bar-fill {
  height: 100%;
  background: var(--success);
  border-radius: 3px;
}

.req-gauge .req-bar-fill.short {
  background: var(--danger);
}

.freelancer-suggest {
  margin-top: 6px;
  font-size: 12.5px;
  color: var(--text-muted);
}

.freelancer-suggest button {
  padding: 3px 9px;
  font-size: 12px;
  margin-left: 4px;
}

/* ---------- document / photo uploads ---------- */
.row-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}

.row-avatar-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--brand-50);
  color: var(--brand-600);
  font-weight: 700;
  font-size: 12px;
}

.doc-preview {
  display: block;
  width: 72px;
  height: 72px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  margin-bottom: 8px;
}

input[type="file"] {
  width: 100%;
  padding: 9px 10px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-family: inherit;
  background: var(--surface-alt);
  color: var(--text);
}

/* ---------- SOPs ---------- */
.sop-card {
  padding: 18px 20px;
  margin-bottom: 12px;
}

.sop-card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.sop-card-header strong {
  font-size: 15.5px;
}

.sop-body {
  font-size: 14px;
  color: var(--text);
  white-space: pre-wrap;
  line-height: 1.6;
}

.timeline-phase {
  position: absolute;
  top: 3px;
  bottom: 3px;
  border-radius: 5px;
  font-size: 11px;
  font-weight: 600;
  color: white;
  display: flex;
  align-items: center;
  padding: 0 8px;
  overflow: hidden;
  white-space: nowrap;
  min-width: 4px;
}

.timeline-phase.full { background: var(--success); }
.timeline-phase.partial { background: var(--warning); }
.timeline-phase.empty-req { background: var(--danger); }
.timeline-phase.inactive { background: var(--text-faint); }

/* Per-event colour (hue set inline via style="--event-hue: N"); phase type
   is then encoded as a lightness/pattern variation of that same hue so
   events stay easy to tell apart AND setup/show/dismantle stay legible. */
.timeline-phase {
  background: hsl(var(--event-hue, 210), 62%, 46%);
}

.timeline-phase.phase-setup {
  background: hsl(var(--event-hue, 210), 55%, 62%);
}

.timeline-phase.phase-show {
  background: hsl(var(--event-hue, 210), 68%, 40%);
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.35);
}

.timeline-phase.phase-dismantle {
  background: repeating-linear-gradient(
    135deg,
    hsl(var(--event-hue, 210), 55%, 30%),
    hsl(var(--event-hue, 210), 55%, 30%) 6px,
    hsl(var(--event-hue, 210), 55%, 38%) 6px,
    hsl(var(--event-hue, 210), 55%, 38%) 12px
  );
}

.timeline-phase.phase-rehearsals {
  background: hsl(var(--event-hue, 210), 40%, 55%);
}

.timeline-phase.inactive {
  background: var(--text-faint) !important;
}

.event-color-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
  background: hsl(var(--event-hue, 210), 62%, 46%);
}

/* v20 (part 2): the Event Hub entry point — clicking an event's name/row
   opens it. Underlined on hover so it reads as clickable without looking
   like a plain link at rest (the whole row is already the click target). */
.event-hub-link:hover {
  text-decoration: underline;
}

/* ---------- EQUIPMENT TRACKING (v11) ---------- */
.eq-suggest-box {
  background: var(--brand-50);
  border: 1px solid var(--brand-100);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin: 4px 0 18px;
  font-size: 13px;
  color: var(--text);
}
.eq-suggest-box strong {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--brand-600);
  font-size: 12.5px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-bottom: 8px;
}
.eq-suggest-box ul {
  margin: 0;
  padding-left: 18px;
}
.eq-suggest-box li {
  margin-bottom: 3px;
}

.eq-line-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.eq-line-row:last-child {
  border-bottom: none;
}
.eq-line-row .eq-line-main {
  flex: 1 1 220px;
  min-width: 0;
}
.eq-line-row .eq-line-name {
  font-weight: 600;
  font-size: 13.5px;
}
.eq-line-row .eq-line-meta {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 2px;
}
.eq-line-row .eq-line-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: center;
}
.eq-line-row .eq-line-actions input[type="number"] {
  width: 64px;
  padding: 6px 8px;
}

.eq-qty-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  font-weight: 700;
  padding: 2px 9px;
  border-radius: 100px;
}
.eq-qty-pill.good { background: var(--success-50); color: var(--success); }
.eq-qty-pill.low { background: var(--warning-50); color: var(--warning); }
.eq-qty-pill.zero { background: var(--danger-50); color: var(--danger-600); }

/* v19: box breakdown on a prepped/picked line — reuses .eq-suggest-box for
   the highlighted wrapper look. */
.eq-box-list {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.eq-box-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 12.5px;
  background: var(--bg-alt, var(--brand-50));
  border-radius: 6px;
  padding: 5px 10px;
}
.eq-box-row input[type="number"] {
  width: 64px;
  padding: 4px 6px;
}

/* ---------- TIMELINE REDESIGN (v10): by-person / by-role / by-event views ---------- */
.tl2-picker {
  display: inline-flex;
  gap: 3px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 11px;
  padding: 3px;
  margin-bottom: 16px;
}
.tl2-picker button {
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  background: none;
  border: none;
  border-radius: 8px;
  padding: 7px 14px;
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.tl2-picker button.active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }
.tl2-picker button:hover:not(.active) { color: var(--text); }

.tl2-shell {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.tl2-toolbar {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-alt);
  font-size: 12.5px;
  color: var(--text-muted);
}
.tl2-conflict-pill {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--danger-50);
  color: var(--danger-600);
  font-weight: 700;
  font-size: 12px;
  padding: 5px 11px;
  border-radius: 100px;
}
.tl2-conflict-pill.ok { background: var(--success-50); color: var(--success); }

.tl2-scroller { overflow-x: auto; }
.tl2-inner { position: relative; min-width: max-content; }

.tl2-day-header { display: flex; position: sticky; top: 0; z-index: 5; background: var(--surface); }
.tl2-name-col-header {
  width: var(--tl2-namecol); flex: 0 0 auto; position: sticky; left: 0; z-index: 6;
  background: var(--surface); border-right: 1px solid var(--border); border-bottom: 1px solid var(--border);
  display: flex; align-items: flex-end; padding: 6px 12px 8px; font-size: 11px; font-weight: 700;
  color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.05em;
}
.tl2-day-cell {
  width: var(--tl2-daycol); flex: 0 0 auto; text-align: center; padding: 6px 2px 8px;
  border-bottom: 1px solid var(--border); border-left: 1px solid var(--border);
  font-size: 10px; color: var(--text-faint); line-height: 1.35;
}
.tl2-day-cell .dow { display: block; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; }
.tl2-day-cell.weekend { background: var(--surface-alt); }
.tl2-day-cell.is-today .dow { color: var(--brand); }

.tl2-today-line {
  position: absolute; top: 0; bottom: 0; width: 2px; background: var(--brand);
  z-index: 4; pointer-events: none; opacity: 0.65;
}
.tl2-today-flag {
  position: absolute; top: -1px; font-size: 9px; font-weight: 800; color: #fff;
  background: var(--brand); padding: 1px 5px 2px; border-radius: 0 0 5px 0;
  z-index: 7; letter-spacing: 0.03em; white-space: nowrap;
}

.tl2-row { display: flex; border-bottom: 1px solid var(--border); }
.tl2-row:last-child { border-bottom: none; }
.tl2-row:hover { background: var(--surface-alt); }
.tl2-name-cell {
  width: var(--tl2-namecol); flex: 0 0 auto; position: sticky; left: 0; z-index: 3;
  background: var(--surface); border-right: 1px solid var(--border);
  padding: 8px 12px; display: flex; flex-direction: column; justify-content: center; gap: 2px;
}
.tl2-row:hover .tl2-name-cell { background: var(--surface-alt); }
.tl2-name-cell .primary { font-weight: 600; font-size: 13px; display: flex; align-items: center; gap: 6px; }
.tl2-name-cell .secondary { font-size: 11px; color: var(--text-muted); }
.tl2-conflict-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--danger); flex: 0 0 auto; }

.tl2-lane-area { position: relative; }
.tl2-lane-bg { position: absolute; inset: 0; display: flex; }
.tl2-lane-bg > div { width: var(--tl2-daycol); flex: 0 0 auto; border-left: 1px solid var(--border); }
.tl2-lane-bg > div.weekend { background: var(--surface-alt); }

.tl2-bar {
  position: absolute; border-radius: 6px; font-size: 10.5px; font-weight: 600; color: #fff;
  display: flex; align-items: center; padding: 0 7px; white-space: nowrap; overflow: hidden;
  box-shadow: 0 1px 2px rgba(12, 12, 13, 0.15);
}
.tl2-bar.conflicted { outline: 2px solid var(--danger); outline-offset: -1px; }
.tl2-bar .warn-ico { margin-right: 4px; }

/* by-role group headers (Option A grouping) */
.tl2-role-group-header { display: flex; background: var(--surface-alt); border-bottom: 1px solid var(--border); }
.tl2-role-group-header .tl2-name-cell {
  background: var(--surface-alt); font-weight: 700; font-size: 11px; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--text-muted); flex-direction: row; align-items: center; gap: 8px;
}
.tl2-role-group-header .tl2-lane-area { background: var(--surface-alt); }
.tl2-role-count { background: var(--surface); border: 1px solid var(--border); border-radius: 100px; padding: 1px 8px; font-size: 10px; color: var(--text-faint); font-weight: 700; }

/* by-event refined (Option C) */
.tl2-event-row { flex-direction: column; align-items: stretch; cursor: pointer; }
.tl2-event-row .tl2-row-main { display: flex; }
.tl2-staff-badge { margin-left: auto; font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 100px; flex: 0 0 auto; align-self: flex-start; margin-top: 4px; }
.tl2-staff-badge.full { background: var(--success-50); color: var(--success); }
.tl2-staff-badge.partial { background: var(--warning-50); color: var(--warning); }
.tl2-staff-badge.empty-req { background: var(--danger-50); color: var(--danger-600); }
.tl2-staff-badge.inactive { background: #f1f2f5; color: var(--text-faint); }
.tl2-seg { position: absolute; top: 8px; height: 20px; border-radius: 5px; }
.tl2-event-detail {
  display: none; padding: 12px 16px 16px calc(var(--tl2-namecol) + 16px); background: var(--surface-alt);
  border-top: 1px dashed var(--border); font-size: 12.5px;
}
.tl2-event-row.expanded .tl2-event-detail { display: block; }

.tl2-legend { display: flex; gap: 16px; flex-wrap: wrap; padding: 10px 14px; border-top: 1px solid var(--border); background: var(--surface-alt); font-size: 11.5px; color: var(--text-muted); }
.tl2-legend span { display: inline-flex; align-items: center; gap: 6px; }
.tl2-legend .sw { width: 11px; height: 11px; border-radius: 3px; flex: 0 0 auto; }

/* ---------- dashboard ---------- */
.dash-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 20px;
  align-items: start;
}

@media (max-width: 860px) {
  .dash-grid {
    grid-template-columns: 1fr;
  }
}

.dash-card {
  padding: 20px 22px;
  margin-bottom: 18px;
}

.dash-card h3 {
  font-size: 15px;
  margin: 0 0 4px;
}

.dash-card .dash-sub {
  color: var(--text-muted);
  font-size: 13px;
  margin: 0 0 14px;
}

.dash-today-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}

.dash-today-item:last-child {
  border-bottom: none;
}

.dash-today-item .name {
  font-weight: 600;
  font-size: 14px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.dash-today-item .meta {
  font-size: 12.5px;
  color: var(--text-muted);
}

.dash-quicklink {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-bottom: 8px;
  background: var(--surface-alt);
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}

.dash-quicklink:hover {
  border-color: var(--brand);
}

.dash-quicklink .count {
  background: var(--danger);
  color: white;
  border-radius: 999px;
  min-width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11.5px;
  padding: 0 6px;
}

.dash-quicklink .count.zero {
  background: var(--success);
}

.attendance-summary-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 6px;
}

.attendance-chip {
  flex: 1;
  min-width: 90px;
  text-align: center;
  border-radius: var(--radius-sm);
  padding: 10px 8px;
  border: 1px solid var(--border);
  background: var(--surface-alt);
}

.attendance-chip .n {
  font-size: 19px;
  font-weight: 700;
  font-family: "Sora", "Inter", sans-serif;
}

.attendance-chip .l {
  font-size: 11px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

/* ---------- registration requests / freelancer approvals ---------- */
.request-card {
  padding: 16px 18px;
  margin-bottom: 10px;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 14px;
  flex-wrap: wrap;
}

.request-card .req-info strong {
  font-size: 15px;
}

.request-card .req-info .meta {
  font-size: 12.5px;
  color: var(--text-muted);
  margin-top: 3px;
}

.request-card .req-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}

/* ---------- attendance widget (crew-facing) ---------- */
.attendance-widget {
  padding: 18px 20px;
  margin-bottom: 22px;
}

.attendance-widget .aw-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 10px;
}

.attendance-widget button.aw-opt {
  background: var(--surface-alt);
  color: var(--text);
  border: 1.5px solid var(--border-strong);
  box-shadow: none;
  flex: 1;
  min-width: 100px;
}

.attendance-widget button.aw-opt.selected {
  background: var(--brand-50);
  border-color: var(--brand);
  color: var(--brand-600);
}

#leave-widget {
  padding: 18px 20px;
  margin-bottom: 22px;
}

.attendance-day-card {
  background: var(--surface-alt);
}

/* ---------- admin attendance calendar ---------- */
.att-cal-legend {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 12.5px;
  color: var(--text-muted);
  margin-bottom: 16px;
}

.att-cal-legend .dot,
.att-cal-day-detail .dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  margin-right: 5px;
  vertical-align: middle;
}

.att-cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

.att-cal-header h3 {
  margin: 0;
  font-size: 15.5px;
}

.att-cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.att-cal-weekdays {
  margin-bottom: 4px;
}

.att-cal-weekday {
  text-align: center;
  font-size: 11px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding-bottom: 4px;
}

.att-cal-cell {
  min-height: 64px;
  max-height: 84px;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 6px;
  background: var(--surface);
  cursor: pointer;
}

.att-cal-cell:hover {
  border-color: var(--border-strong);
}

.att-cal-cell.empty {
  border: none;
  background: transparent;
  cursor: default;
}

.att-cal-cell.is-today {
  border-color: var(--brand);
  box-shadow: inset 0 0 0 1px var(--brand);
}

.att-cal-daynum {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 4px;
}

.att-cal-dots {
  display: flex;
  gap: 3px;
  flex-wrap: wrap;
}

.att-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  border-radius: 8px;
  padding: 0 4px;
  font-size: 10px;
  font-weight: 700;
  color: #fff;
}

/* Timeline "Calendar" view — reuses .att-cal-grid/-cell/-header/-daynum
 * for layout, event colouring reuses the --event-hue custom property. */
.tl-cal-events {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.tl-cal-event-chip {
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1.3;
  padding: 1px 5px;
  border-radius: 5px;
  background: hsl(var(--event-hue, 210), 55%, 92%);
  color: hsl(var(--event-hue, 210), 55%, 28%);
  border: 1px solid hsl(var(--event-hue, 210), 55%, 78%);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}

.tl-cal-more {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-muted);
  padding: 1px 5px;
  cursor: pointer;
}
.tl-cal-more:hover {
  color: var(--text);
}

/* v27h: "+N more" opens a floating popover instead of expanding the cell
   in place — a taller cell would push the whole grid row (and everything
   below it) around every time a day is toggled. */
.tl-cal-popover {
  position: fixed;
  z-index: 400;
  min-width: 180px;
  max-width: 260px;
  max-height: 260px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg, 0 8px 24px rgba(0, 0, 0, 0.35));
  padding: 8px;
}
.tl-cal-popover .tl-cal-popover-title {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.tl-cal-popover .tl-cal-events {
  gap: 3px;
}

/* v22: app-wide footer — a thin credit/legal-links strip pinned to the
 * bottom of every page (signed-in app pages via ui.js's renderAppFooter(),
 * plus the standalone pages that don't load ui.js — index.html and
 * reset-password.html carry their own copy of this same markup/classes
 * inline, see those files). Deliberately understated (small text, muted
 * colour) — this is a footer credit line, not a nav element. */
.app-footer {
  margin-top: 40px;
  padding: 18px 24px 22px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px 16px;
  font-size: 12px;
  color: var(--text-faint);
  text-align: center;
}

.app-footer a {
  color: var(--text-muted);
  text-decoration: none;
}

.app-footer a:hover {
  color: var(--brand-600);
  text-decoration: underline;
}

.app-footer .app-footer-sep {
  color: var(--border-strong);
}

/* Terms & Conditions / Privacy Policy standalone pages */
.legal-page {
  max-width: 760px;
  margin: 0 auto;
  padding: 40px 20px 20px;
}

.legal-page h1 {
  font-family: "Sora", sans-serif;
  font-size: 26px;
  margin-bottom: 4px;
}

.legal-page .legal-updated {
  color: var(--text-faint);
  font-size: 13px;
  margin-bottom: 28px;
}

.legal-page h2 {
  font-family: "Sora", sans-serif;
  font-size: 16.5px;
  margin: 28px 0 8px;
}

.legal-page p,
.legal-page li {
  color: var(--text-muted);
  font-size: 14.5px;
  line-height: 1.65;
}

.legal-page ul {
  padding-left: 20px;
  margin: 6px 0 0;
}

.legal-page .legal-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
  font-size: 13px;
  color: var(--text-muted);
  text-decoration: none;
}

.legal-page .legal-back:hover {
  color: var(--brand-600);
}

/* ---------- v25d: Add/Edit Event — dated phase rows + preview strip ----- */
/* Replaces the old "days per phase" number inputs. Each phase is a row you
   can date directly; the strip underneath shows the resulting shape. */
.ev-phases-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 18px 0 8px;
}
.ev-phases-head button { padding: 7px 12px; font-size: 12.5px; }

.ev-phase-row {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px;
  margin-bottom: 8px;
  background: var(--surface);
}
.ev-phase-row.invalid { border-color: var(--danger); background: var(--danger-50); }

.ev-phase-main {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.ev-phase-main select { flex: 0 0 140px; margin: 0; }
.ev-phase-main input[type="date"] { flex: 1 1 140px; min-width: 130px; margin: 0; }
.ev-phase-arrow { color: var(--text-faint); flex: 0 0 auto; }

.ev-phase-swatch {
  width: 10px;
  height: 26px;
  border-radius: 3px;
  flex: 0 0 auto;
  --event-hue: 210;
}

.ev-phase-crew-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 8px 11px;
  font-size: 12.5px;
  white-space: nowrap;
}
.ev-phase-crew-btn svg { width: 14px; height: 14px; }

.ev-phase-remove {
  flex: 0 0 auto;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
  border-radius: 8px;
  width: 32px;
  height: 32px;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}
.ev-phase-remove:hover { background: var(--danger-50); color: var(--danger-600); border-color: var(--danger); }

.ev-phase-warn { color: var(--danger-600); font-size: 12px; margin: 8px 0 0; display: flex; align-items: center; gap: 6px; }
.ev-phase-warn svg { width: 14px; height: 14px; }
.ev-phase-empty { margin: 0 0 8px; }

.ev-phase-crew { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--border); }
.ev-crew-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px 12px; }
.ev-crew-grid label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 0;
  text-transform: none;
  font-weight: 500;
  font-size: 12.5px;
  color: var(--text);
}
.ev-crew-grid input { width: 62px; flex: 0 0 62px; margin: 0; padding: 6px 8px; text-align: center; }

/* Preview strip */
.ev-strip { border: 1px solid var(--border); border-radius: 10px; padding: 10px; background: var(--bg); margin-bottom: 16px; }
.ev-strip-scroll { overflow-x: auto; }
.ev-strip-inner { display: inline-block; min-width: 100%; }
.ev-strip-row { display: flex; align-items: center; gap: 8px; margin-bottom: 3px; }
.ev-strip-label { flex: 0 0 78px; font-size: 11.5px; font-weight: 600; color: var(--text-muted); text-align: right; }
.ev-strip-lane { position: relative; height: 18px; flex: 0 0 auto; background: repeating-linear-gradient(90deg, transparent, transparent calc(100% - 1px), var(--border) calc(100% - 1px), var(--border) 100%); }
.ev-strip-bar { position: absolute; top: 2px; height: 14px; border-radius: 3px; --event-hue: 210; }
.ev-strip-header .ev-strip-lane { background: none; height: auto; }
.ev-strip-day { font-size: 9.5px; color: var(--text-faint); text-align: center; flex: 0 0 auto; }
.ev-strip-day.weekend { color: var(--brand-600); font-weight: 700; }

@media (max-width: 640px) {
  .ev-crew-grid { grid-template-columns: repeat(2, 1fr); }
  .ev-phase-main select, .ev-phase-main input[type="date"] { flex: 1 1 100%; }
}

/* ---------- v25e: event equipment picker ------------------------------- */
/* Replaces the search box + <select size=6> + quantity + "Add to list"
   four-control block. One filterable list; each row carries its own
   quantity stepper and Add button so several items go on without
   re-searching. */
.eq-picker-filters { display: flex; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.eq-picker-filters input { flex: 2 1 200px; margin: 0; }
.eq-picker-filters select { flex: 1 1 150px; margin: 0; }

.eq-picker-list { max-height: 320px; overflow-y: auto; border: 1px solid var(--border); border-radius: 10px; }

.eq-picker-row {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--border);
}
.eq-picker-row:last-child { border-bottom: none; }
.eq-picker-row:hover { background: var(--brand-50); }
.eq-picker-row.over { background: var(--warning-50); }

.eq-picker-name { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.eq-picker-name strong { font-size: 13px; }
.eq-picker-meta { font-size: 11.5px; color: var(--text-muted); }
.eq-picker-source { font-size: 11px; color: var(--text-faint); }

.eq-picker-avail { font-size: 12px; font-weight: 700; color: var(--success); text-align: right; white-space: nowrap; }
.eq-picker-avail span { display: block; font-size: 10.5px; font-weight: 500; color: var(--text-faint); }
.eq-picker-avail.none { color: var(--danger-600); }

.eq-picker-qty { display: flex; align-items: center; gap: 0; }
.eq-picker-qty button {
  width: 28px; height: 30px; padding: 0; font-size: 15px; line-height: 1;
  background: var(--surface); color: var(--text-muted);
  border: 1px solid var(--border); cursor: pointer;
}
.eq-picker-qty button:first-child { border-radius: 7px 0 0 7px; }
.eq-picker-qty button:last-child { border-radius: 0 7px 7px 0; }
.eq-picker-qty button:hover { background: var(--brand-50); color: var(--brand-600); }
.eq-picker-qty input {
  width: 48px; height: 30px; margin: 0; padding: 0 4px; text-align: center;
  border-radius: 0; border-left: none; border-right: none; font-size: 13px;
}

.eq-picker-add { padding: 7px 14px; font-size: 12.5px; white-space: nowrap; }
.eq-picker-add:disabled { opacity: 0.45; cursor: not-allowed; }

.eq-picker-warn {
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: 6px;
  font-size: 11.5px; color: var(--warning);
}
.eq-picker-warn svg { width: 13px; height: 13px; flex: 0 0 auto; }

@media (max-width: 620px) {
  .eq-picker-row { grid-template-columns: 1fr auto; row-gap: 8px; }
  .eq-picker-qty { grid-column: 1; }
  .eq-picker-add { grid-column: 2; }
}

/* ---------- v25e: equipment item form groups + Add stock --------------- */
.eq-form-group {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  margin-top: 16px;
  background: var(--bg);
}
.eq-form-group-title {
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-muted);
  margin-bottom: 10px;
}
.eq-form-group-title span {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  color: var(--text-faint);
}
.eq-form-group > label:first-of-type { margin-top: 0; }

.eq-check {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 0 0;
  text-transform: none;
  font-weight: 500;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}
.eq-check input { width: auto; margin: 0; flex: 0 0 auto; }

.eq-conditional {
  margin-top: 10px;
  padding-left: 12px;
  border-left: 2px solid var(--brand-100);
}
.eq-conditional > label:first-child { margin-top: 0; }

/* Add stock (receive a delivery) */
.rs-summary {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg);
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.rs-summary > div { display: flex; flex-direction: column; }
.rs-summary input { margin: 0; width: 100px; text-align: center; font-size: 16px; font-weight: 700; }
.rs-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--text-muted); font-weight: 700; }
.rs-summary strong { font-size: 22px; line-height: 1.4; }
.rs-plus, .rs-eq { font-size: 18px; color: var(--text-faint); padding-bottom: 6px; }
#rs-total { color: var(--brand-600); }

/* ---------- v25f: compact stock rows + per-row Actions dropdown -------- */
/* Was five full-text buttons stacking four deep in a narrow cell, which
   set the height of every row in the table. One trigger now, with the
   options in a menu. */
.row-menu-wrap { position: relative; display: inline-block; }

.row-menu-btn { padding: 6px 12px; font-size: 13px; white-space: nowrap; }
.row-menu-caret { font-size: 10px; opacity: 0.7; margin-left: 2px; }

/* position: fixed, not absolute — .table-scroll sets overflow-x:auto, which
   makes the browser compute overflow-y:auto too, and that clips absolutely
   positioned descendants. A fixed element escapes that (no transformed
   ancestor here), so the menu is placed from the trigger's rect in JS and
   closed on scroll so it can't drift away from its row. */
.row-menu {
  position: fixed;
  z-index: 200;
  min-width: 190px;
  padding: 5px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: 1px;
}
/* `display: flex` above beats the browser's built-in `[hidden]{display:none}`
   on specificity, which left every row's menu permanently on screen. Restore
   it explicitly. */
.row-menu[hidden] { display: none; }

.row-menu button {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 10px;
  background: transparent;
  border: none;
  border-radius: 7px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}
.row-menu button svg { width: 15px; height: 15px; flex: 0 0 auto; color: var(--text-muted); }
.row-menu button:hover:not(:disabled) { background: var(--brand-50); color: var(--brand-600); }
.row-menu button:hover:not(:disabled) svg { color: var(--brand-600); }
.row-menu button:disabled { opacity: 0.4; cursor: not-allowed; }
.row-menu button.danger-item { color: var(--danger-600); }
.row-menu button.danger-item svg { color: var(--danger-600); }
.row-menu button.danger-item:hover { background: var(--danger-50); color: var(--danger-600); }
.row-menu-sep { height: 1px; background: var(--border); margin: 4px 2px; }

/* Compact cell content */
.eq-stock-table td { vertical-align: middle; }
.eq-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 1px; }
.eq-specs { font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.eq-dash { color: var(--text-faint); }

.eq-svc {
  display: inline-block;
  font-size: 11.5px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 100px;
  margin-right: 4px;
  white-space: nowrap;
}
.eq-svc.dmg { background: var(--danger-50); color: var(--danger-600); }
.eq-svc.rep { background: var(--warning-50); color: var(--warning); }
.eq-svc-photo { color: var(--text-muted); vertical-align: middle; display: inline-flex; }
.eq-svc-photo svg { width: 15px; height: 15px; }
.eq-svc-photo:hover { color: var(--brand-600); }

/* ---------- v25g: compact Stock-tab insights bar ---------------------- */
/* Replaces three stacked full-width cards (Stock demand, availability
   search, Low stock) that took ~950px before the stock list began. */
.eq-insights {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  margin-bottom: 18px;
}
.eq-insights-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  flex-wrap: wrap;
}
.eq-insight-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  font-size: 12.5px;
  font-weight: 600;
  background: var(--bg);
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
}
.eq-insight-toggle:hover { background: var(--brand-50); color: var(--brand-600); }
.eq-insight-toggle.open { background: var(--brand-50); color: var(--brand-600); border-color: var(--brand-100); }
.eq-insight-caret { font-size: 10px; opacity: 0.7; transition: transform 0.15s ease; }
.eq-insight-toggle.open .eq-insight-caret { transform: rotate(180deg); }

.eq-insights-alert { margin-left: auto; min-width: 0; }
.eq-low-lead {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--danger-600);
  white-space: nowrap;
  margin-right: 8px;
}
.eq-low-lead svg { width: 15px; height: 15px; }
.eq-low-items { display: inline-flex; flex-wrap: wrap; gap: 6px; vertical-align: middle; }

.eq-insight-panel {
  padding: 14px;
  border-top: 1px solid var(--border);
}

@media (max-width: 720px) {
  .eq-insights-alert { margin-left: 0; width: 100%; }
}

/* ---------------------------------------------------------------
   v25a — wide-screen density.

   Two measured problems on a 2000px monitor: the admin shell stopped
   at 1400px so ~600px went unused, and in the 600-row stock list the
   Item column took 611px of a 1358px table while its content averages
   about 30 characters. Rows were 56px tall, so a list of hundreds
   showed a dozen at a time.

   Padding only — no display changes on cells, which is what previously
   knocked the row action buttons out of line.
   --------------------------------------------------------------- */
.admin-shell main {
  max-width: min(1800px, 95vw);
}

.eq-stock-table th,
.eq-stock-table td {
  padding: 7px 14px;
}

.eq-stock-table td {
  font-size: 13.5px;
}

/* Stop the name column swallowing the free width; the columns beside it
   are fixed-content, so without this the remainder all lands on Item. */
.eq-stock-table th:first-child,
.eq-stock-table td:first-child {
  width: 34%;
}

/* Numeric and short-label columns don't need to grow at all. */
.eq-stock-table th:nth-child(2),
.eq-stock-table td:nth-child(2),
.eq-stock-table th:nth-child(4),
.eq-stock-table td:nth-child(4),
.eq-stock-table th:nth-child(6),
.eq-stock-table td:nth-child(6) {
  width: 1%;
  white-space: nowrap;
}

/* v25h — sortable stock columns. The heading is the control, so it needs to
   look clickable and show which way it is sorting. */
.eq-stock-table th.eq-sort {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.eq-stock-table th.eq-sort:hover {
  color: var(--text);
  background: var(--border);
}
.eq-stock-table th.eq-sort:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: -2px;
}
.eq-stock-table th.eq-sort.active {
  color: var(--brand-600);
}
.eq-sort-caret {
  display: inline-block;
  width: 9px;
  margin-left: 4px;
  font-size: 9px;
  line-height: 1;
}

/* v25h — quoted work is a warning, not a hold. It reads as advisory unless
   the quoted total would actually overrun what is left. */
.eq-quote-warn {
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-muted);
}
.eq-quote-warn.over {
  color: var(--warning);
  font-weight: 600;
}
.eq-quote-warn svg {
  width: 12px;
  height: 12px;
  vertical-align: -2px;
  margin-right: 3px;
}

/* v25i — "Crew needed, month by month" above the per-event breakdown. */
.resourcing {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  padding: 16px 18px;
  margin-bottom: 18px;
}
.resourcing-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 16px;
  margin-bottom: 12px;
}
.resourcing-head h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
}
.resourcing-range {
  font-size: 12px;
  color: var(--text-muted);
}
.resourcing-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}
.resourcing-table th,
.resourcing-table td {
  padding: 7px 12px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  white-space: nowrap;
}
.resourcing-table th {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  font-weight: 700;
}
.resourcing-table th.num,
.resourcing-table td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* The busiest month is the one that decides your hiring, so it is marked. */
.resourcing-table th.peak,
.resourcing-table td.peak {
  background: var(--brand-50);
  color: var(--brand-600);
}
.resourcing-table tfoot td {
  border-top: 2px solid var(--border-strong);
  border-bottom: none;
  font-weight: 700;
  font-size: 15px;
}
.q-extra {
  color: var(--warning);
  font-weight: 600;
  font-size: 11.5px;
  margin-left: 3px;
}
.resourcing-note {
  margin: 8px 0 0;
  font-size: 11.5px;
  color: var(--text-muted);
}
.resourcing-short {
  margin-top: 12px;
  font-size: 12.5px;
  color: var(--warning);
}
.resourcing-short svg {
  width: 13px;
  height: 13px;
  vertical-align: -2px;
  margin-right: 4px;
}

/* v25i — the dashboard now opens with what needs a decision. Four cards:
   crew needed by month, stock shortfalls, phases still needing crew, and
   crew double-booked. A card with nothing in it goes quiet rather than
   disappearing, so the row stays stable from day to day. */
.exceptions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}
.exc-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  padding: 13px 15px;
  border-top: 3px solid var(--border-strong);
}
.exc-card[data-exc-tab] { cursor: pointer; }
.exc-card[data-exc-tab]:hover { border-color: var(--border-strong); box-shadow: var(--shadow); }
.exc-card.short { border-top-color: var(--warning); }
.exc-card.unstaffed { border-top-color: var(--brand); }
.exc-card.clash { border-top-color: var(--danger); }
.exc-card.crewload { border-top-color: var(--dark); }
.exc-card.ok { border-top-color: var(--success); }

.exc-head {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin-bottom: 8px;
}
.exc-n {
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.exc-card.short .exc-n { color: var(--warning); }
.exc-card.clash .exc-n { color: var(--danger); }
.exc-card.ok .exc-n { color: var(--success); }
.exc-l {
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  font-weight: 700;
}
.exc-body { font-size: 12.5px; }
.exc-body.muted { color: var(--text-faint); }
.exc-row {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 2px 0;
}
.exc-row span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.exc-row b { font-variant-numeric: tabular-nums; white-space: nowrap; }
.exc-more { color: var(--text-faint); font-size: 11.5px; padding-top: 2px; }

.exc-months { display: flex; gap: 8px; }
.exc-month {
  flex: 1;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px 8px;
  text-align: center;
}
.exc-month.now { border-color: var(--brand); background: var(--brand-50); }
.exc-month-n {
  font-size: 19px;
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.exc-month.now .exc-month-n { color: var(--brand-600); }
.exc-month-l { font-size: 10.5px; color: var(--text-muted); white-space: nowrap; }


/* v25j — "Who is working": days booked per person over the chosen range,
   with the idle ones kept visible because they are the point of the view. */
.resourcing.util { margin-top: 4px; }
.util-table td { vertical-align: middle; }
.util-table tr.idle td { color: var(--text-faint); }
.util-fl {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 1px 5px;
  margin-left: 5px;
}
.util-bar-cell {
  display: table-cell;
  white-space: nowrap;
  min-width: 130px;
}
.util-bar {
  display: inline-block;
  width: 90px;
  height: 7px;
  border-radius: 4px;
  background: var(--border);
  overflow: hidden;
  vertical-align: middle;
  margin-right: 7px;
}
.util-bar > span {
  display: block;
  height: 100%;
  background: var(--brand);
  border-radius: 4px;
}
.util-pct {
  font-size: 11.5px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* v25o — one compact filter bar, shared by Timeline and Equipment.
   Both tabs were spending 300-500px on controls before showing a single row
   of actual content: two stacked full-width field rows, plus separate rows
   for the mode picker and the view tabs. Everything now sits on one line
   and only wraps on a narrow screen. */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 9px 14px;
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.fb-field { display: flex; flex-direction: column; gap: 3px; }
.fb-field.fb-grow { flex: 1 1 200px; min-width: 160px; }
/* v27f: outside .filter-bar's row layout (e.g. the standalone "View"
   field above the By-person/By-event picker), a plain flex-column div's
   default align-items:stretch forces its .tl2-picker child to fill the
   full row width, leaving a big empty dark strip next to the pill
   buttons. Cross-axis alignment corrected to hug content instead. */
#timeline-layout-field,
#timeline-view-field {
  align-items: flex-start;
}
.fb-field > label {
  margin: 0;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-weight: 700;
  color: var(--text-muted);
  white-space: nowrap;
}
.fb-field select,
.fb-field input[type="text"],
.fb-field input[type="date"] {
  margin: 0;
  height: 32px;
  padding: 3px 9px;
  font-size: 13.5px;
}

/* v25p — every control in the bar is the same segmented control.
   Quick range, Showing and View had arrived from three different places and
   looked it: an orange segmented group, a grey pill, and underlined tabs,
   sitting side by side doing the same job. One style for all three. */
.filter-bar .fb-tabs,
.filter-bar .tl2-picker,
.fb-presets {
  display: flex;
  gap: 0;
  height: 32px;
  margin: 0;
  border-bottom: none;
  background: none;
  padding: 0;
  border-radius: var(--radius);
}
.filter-bar .fb-tabs .tab-btn,
.filter-bar .tl2-picker button,
.fb-presets button {
  margin: 0;
  padding: 0 11px;
  height: 32px;
  font-size: 12.5px;
  font-weight: 600;
  background: var(--surface);
  color: var(--text-muted);
  border: 1px solid var(--border-strong);
  border-radius: 0;
  box-shadow: none;
  white-space: nowrap;
}
.filter-bar .fb-tabs .tab-btn:first-child,
.filter-bar .tl2-picker button:first-child,
.fb-presets button:first-child { border-radius: var(--radius) 0 0 var(--radius); }
.filter-bar .fb-tabs .tab-btn:last-child,
.filter-bar .tl2-picker button:last-child,
.fb-presets button:last-child { border-radius: 0 var(--radius) var(--radius) 0; }
.filter-bar .fb-tabs .tab-btn + .tab-btn,
.filter-bar .tl2-picker button + button,
.fb-presets button + button { border-left: none; }
.filter-bar .fb-tabs .tab-btn:hover,
.filter-bar .tl2-picker button:hover,
.fb-presets button:hover { background: var(--surface-alt); color: var(--text); }
.filter-bar .fb-tabs .tab-btn.active,
.filter-bar .tl2-picker button.active,
.fb-presets button.active {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}
/* The underline the tab component normally draws has no place inside a
   segmented control. */
.filter-bar .fb-tabs .tab-btn::after { display: none; }

.fb-check {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  margin: 0;
  font-size: 12.5px;
  font-weight: 500;
  text-transform: none;
  color: var(--text);
  white-space: nowrap;
  cursor: pointer;
}
.fb-check input { width: auto; margin: 0; cursor: pointer; }

/* v25l — the month tiles open the detail behind their number. */
.exc-month[data-crew-month] { cursor: pointer; transition: border-color .1s var(--ease), background .1s var(--ease); }
.exc-month[data-crew-month]:hover { border-color: var(--brand); background: var(--brand-50); }
.exc-month[data-crew-month]:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.resourcing-table td.muted { color: var(--text-faint); }

/* v25l — the crew-detail modal carries a six-column table, which does not
   fit the standard dialog width. */
.modal.modal-wide {
  max-width: min(860px, 94vw);
  width: min(860px, 94vw);
}
.modal.modal-wide .resourcing-table th,
.modal.modal-wide .resourcing-table td {
  padding: 5px 10px;
  font-size: 13px;
}

/* v25m — equipment shortfall drill-down: each short item followed by the
   jobs asking for it, indented so the hierarchy reads without a second
   table or an expander. */
.exc-card[data-exc-action] { cursor: pointer; }
.eqd-table tr.eqd-item td { border-top: 1px solid var(--border-strong); padding-top: 9px; }
.eqd-table tr.eqd-item:first-child td { border-top: none; }
.eqd-cat { font-size: 11px; color: var(--text-muted); font-weight: 400; }
.eqd-table tr.eqd-booking td {
  border-bottom: none;
  padding-top: 2px;
  padding-bottom: 2px;
  font-size: 12.5px;
  color: var(--text-muted);
}
.eqd-table tr.eqd-booking td:first-child { padding-left: 24px; }
.eqd-sub { color: var(--text-muted); font-weight: 400; }
.eqd-table .pill { margin-left: 6px; }

/* v25o — tighten the chrome above the stock list. Measured: 506px of header
   before the first row on a 1000px-tall window, i.e. half the screen spent
   on controls. The filter bar took the biggest bite and is handled above;
   this reclaims the rest from margins and an oversized explainer. */
#section-equipment > .hint,
#section-timeline > .hint {
  font-size: 12.5px;
  padding: 7px 11px;
  margin: 0 0 12px;
}
#equipment-subtabs { margin-bottom: 12px !important; }

/* v26: sub-tab strips (Equipment's Stock/Damaged/Dry Hire/Branch
   Shipments/Repairs, and any other .tabs that isn't the main hamburger-
   collapsed top nav) silently scroll sideways on narrow screens once
   they don't all fit — the scrollbar itself is intentionally hidden
   app-wide (see the .tabs::-webkit-scrollbar rule), which means there
   was NO visual cue at all that "Repairs" (or whichever tab is last)
   existed off-screen — this was reported as "the Repairs tab is being
   cut off" after Damaged was added tipped 5 tabs past what fits. A
   plain CSS fade on the right edge signals "more to scroll" without
   needing a hamburger/dropdown treatment for what's a short, single-row
   list of tabs (unlike the much longer main nav). Pure CSS, no JS: it's
   always rendered when this rule matches, whether or not the strip is
   actually overflowing today — a static hint, not a dynamic one, which
   is an acceptable simplification for a 3-8 item sub-tab strip. */
/* v26: base (desktop) state for the Equipment sub-tab mobile <select> —
   MUST sit before the @media block below in source order (same reason
   as .filter-toggle-btn's base rule earlier in this file: a later
   unconditioned rule always wins over an earlier @media-scoped one at
   equal specificity, regardless of whether the media query matches). */
.mobile-tab-select-wrap {
  display: none;
}
.mobile-tab-select-wrap select {
  width: 100%;
  font-weight: 600;
}

@media (max-width: 640px) {
  .tabs:not(#tabs) {
    position: relative;
    mask-image: linear-gradient(to right, black calc(100% - 28px), transparent 100%);
    -webkit-mask-image: linear-gradient(to right, black calc(100% - 28px), transparent 100%);
  }

  /* Equipment sub-tabs (Stock/Dry Hire/Branch Shipments/Damaged/Repairs)
     get a real dropdown instead of relying on the fade-hint above —
     scrolling a hidden-scrollbar tab strip to discover "Repairs" wasn't
     discoverable enough on its own (user report: "we might need to do a
     drop down menu ... when the buttons gets to many"). The <select> IS
     the real navigation control here, wired in
     wireEquipSubtabMobileSelect() (js/admin-src/06-equipment-stock.js)
     to fire the exact same click handler as its matching tab-btn, so
     there is only one source of truth for "which sub-tab is active". */
  #equipment-subtabs {
    display: none;
  }
  .mobile-tab-select-wrap {
    display: block;
    margin-bottom: 14px;
  }
}

/* The two lookup panels are a toolbar, not a section of their own. */
.eq-insights { margin-bottom: 12px !important; }
.eq-insights-bar { padding: 5px 6px; gap: 6px; }
.eq-insight-toggle { padding: 5px 10px; font-size: 12.5px; }

#equip-panel-stock > .section-header,
#section-timeline .section-header { margin-bottom: 10px; }
#equip-panel-stock > .section-header h2 { font-size: 15px; }

/* The stock list is long; its own header does not need to shout. */
#section-equipment > .section-header { margin-bottom: 10px; }

/* v25q — the "you entered an email but nobody will be emailed" warning on
   the Add crew member form. */
.hint.warn-hint {
  border-left-color: var(--warning);
  background: var(--warning-50);
  color: var(--text);
  margin-top: 6px;
}
.hint.warn-hint a { color: var(--warning); font-weight: 600; }
