/* "Quiet Instrument" design tokens — see DESIGN.md. Legacy names kept as
   aliases so existing var() references pick up the new palette. */
:root {
  /* neutrals (warm) */
  --canvas: #f6f4ef;
  --surface-raised: #fdfcf9;
  --border-strong: #cfc8b8;
  /* ink */
  --ink: #1b2432;
  --ink-2: #5a6474;
  --ink-3: #98a0ac;
  /* accent & brass */
  --accent: #042f66;
  --accent-soft: #e8eef7;
  --brass: #a8905a;
  --brass-soft: #f3eddf;
  /* fills (between surface and border) */
  --fill: #f1eee5;
  /* leave pigments */
  --leave-vacation: #2e7d74;
  --leave-vacation-2: #5aa198;
  --leave-sick-2: #c79a55;
  --leave-emergency-2: #c26a55;
  --leave-vacation-soft: #dcebe9;
  --leave-sick: #b07c2a;
  --leave-sick-soft: #f2e7d3;
  --leave-emergency: #a8432f;
  --leave-emergency-soft: #f1deda;
  --leave-unpaid: #7a8494;
  /* vessel polarity */
  --yin-bg: #0e2a47;
  --yin-fg: #fdfbf4;
  --yang-bg: #e9e0c6;
  --yang-fg: #1b2432;
  /* semantic */
  --success-soft: #dfede4;
  --warning: #b07c2a;
  --warning-soft: #f2e7d3;
  /* Half-strength warning, for a deadline that is real but months away (the
     passport's four-month window). Not a third pigment: the same ochre pulled
     toward the muted ink, and it re-resolves in dark mode because both
     operands are redefined on the same root element. */
  --warning-quiet: color-mix(in srgb, var(--warning) 60%, var(--ink-3) 40%);
  --error: #a8432f;
  --error-soft: #f1deda;
  --info: #3a5f8a;
  --info-soft: #e2eaf2;
  /* typography */
  --font-ui: "Public Sans", system-ui, -apple-system, sans-serif;
  --font-data: "IBM Plex Mono", ui-monospace, SFMono-Regular, monospace;
  /* The brand's heading face, then its small-title face (DESIGN.md). */
  --font-display: "Utile Display", var(--font-ui);
  --font-title: "Presicav", var(--font-ui);
  --text-2xs: 0.6875rem;
  --text-xs: 0.75rem;
  --text-sm: 0.8125rem;
  --text-base: 0.875rem;
  --text-lg: 1.25rem;
  --text-stat: 1.75rem;
  /* radii & shadows */
  --r-sm: 4px;
  --r-md: 8px;
  --r-lg: 12px;
  --shadow-card: 0 1px 2px rgba(27, 36, 50, 0.05);
  --shadow-pop: 0 12px 32px rgba(27, 36, 50, 0.14);
  /* legacy aliases (remapped) */
  --brand-navy: var(--accent);
  --brand-gold: var(--brass);
  --surface: var(--canvas);
  --card: #ffffff;
  --text: var(--ink);
  --muted: var(--ink-2);
  --border: #e7e2d6;
  --danger: var(--error);
  --success: #2e7d52;
}

/* Dark theme — same token names, night values (see DESIGN.md). Applied by the
   navbar toggle / prefers-color-scheme via data-theme on <html>. */
[data-theme='dark'] {
  --canvas: #14181f;
  --card: #1b212b;
  --surface-raised: #1f2631;
  --fill: #262d38;
  --border: #2a3240;
  --border-strong: #3a4454;
  --ink: #e8e6de;
  --ink-2: #9ba4b0;
  --ink-3: #6b7482;
  --accent: #8fb0dc;
  --accent-soft: #1e2a3c;
  /* Solid action surfaces (primary buttons) need a darker blue than the
     text/link accent so white labels keep their contrast. */
  --brand-navy: #2e4d7b;
  --brass: #c4ac74;
  --brass-soft: #2a2617;
  --leave-vacation: #3f9a8e;
  --leave-vacation-soft: #17302d;
  --leave-vacation-2: #57b3a6;
  --leave-sick: #ce9c4b;
  --leave-sick-soft: #32270f;
  --leave-sick-2: #d9b070;
  --leave-emergency: #c56a55;
  --leave-emergency-soft: #331b15;
  --leave-emergency-2: #d28a78;
  --leave-unpaid: #8a94a4;
  --yin-bg: #1d4066;
  --yin-fg: #e8eef7;
  --yang-bg: #3a3427;
  --yang-fg: #e8e6de;
  --success: #57a97e;
  --success-soft: #16281e;
  --warning: #ce9c4b;
  --warning-soft: #32270f;
  --error: #c56a55;
  --error-soft: #331b15;
  --info: #6e93be;
  --info-soft: #1a2634;
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-pop: 0 12px 32px rgba(0, 0, 0, 0.55);
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: var(--font-ui);
  color: var(--text);
  background: var(--surface);
  min-height: 100vh;
}

/* Headings in the brand's display face: page, card and dialog titles. It has
   one weight, Regular, and it is set by its shape rather than by weight, so a
   title that asks for 600 renders the true Regular (no synthesised bold). */
h1,
h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-synthesis: none;
}

/* data / numerals — tabular mono everywhere numbers must align */
.mono,
.num {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}

a {
  color: inherit;
  text-decoration: none;
}

/* The section switcher stays put while the page scrolls under it. Its live
   height is published as --navbar-h by authNav.js, so anything that also
   sticks to the top of the document (the tips staff table head) can clear it.
   z-index 60 sits above every in-page layer (max 30) and below the full-screen
   editors (120) and toasts (1000). */
.navbar {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 1.25rem;
  background: var(--card);
  color: var(--ink);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-card);
}

.navbar-brand {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.navbar-links {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.navbar-user {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin-left: auto;
}

.navbar-user-label {
  font-size: 0.85rem;
  opacity: 0.92;
  white-space: nowrap;
}

.navbar-logout-btn,
.navbar-password-btn {
  padding: 0.35rem 0.75rem;
  font-size: 0.85rem;
}

.theme-toggle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  padding: 0;
}

.theme-toggle-btn:hover {
  background: var(--fill);
  color: var(--ink);
}

/* Reminder center bell (navbar, all signed-in pages).
   Count renders as quiet brass mono for every severity — see DESIGN.md. */
.navbar-reminders {
  position: relative;
  margin-left: auto;
}

.navbar-reminders + .navbar-user {
  margin-left: 0;
}

/* Page-scoped activity-log dropdown (attendance) — sits next to the bell
   and reuses the bell/panel styling. */
.navbar-activity {
  position: relative;
  margin-left: auto;
}

.navbar-reminders + .navbar-activity,
.navbar-activity ~ .navbar-reminders {
  margin-left: 0;
}

.navbar-activity + .navbar-user {
  margin-left: 0;
}

.navbar-activity[open] .reminders-bell {
  background: var(--fill);
  color: var(--ink);
}

.reminders-bell {
  list-style: none;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  color: var(--ink-2);
  background: transparent;
  cursor: pointer;
}

.reminders-bell::-webkit-details-marker {
  display: none;
}

.reminders-bell:hover,
.navbar-reminders[open] .reminders-bell {
  background: var(--fill);
  color: var(--ink);
}

/* No-alarm policy (DESIGN.md): the reminder count is quiet brass mono text,
   never a red badge — red is reserved for actual expiries inside the panel. */
.reminders-badge {
  position: absolute;
  top: -6px;
  right: -8px;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 999px;
  border: 1px solid var(--brass);
  background: var(--brass-soft);
  color: var(--brass);
  font-family: var(--font-data);
  font-size: 0.66rem;
  font-weight: 500;
  line-height: 1;
}

.reminders-badge--expired,
.reminders-badge--soon {
  background: var(--brass-soft);
}

.reminders-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 10px);
  width: min(340px, calc(100vw - 2rem));
  max-height: 420px;
  overflow-y: auto;
  padding: 0.8rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  color: var(--text);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.18);
  z-index: 80;
}

.reminders-section + .reminders-section {
  margin-top: 0.7rem;
  padding-top: 0.65rem;
  border-top: 1px solid var(--border);
}

.reminders-section-title {
  margin: 0 0 0.4rem;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

.reminders-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.32rem;
}

.reminders-row {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  font-size: 0.85rem;
  line-height: 1.35;
}

.reminders-dot {
  flex: none;
  align-self: center;
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

/* Match the staff-directory HR alert dot colors. */
.reminders-dot--expired {
  background: var(--error);
}

.reminders-dot--soon {
  background: var(--warning);
}

/* Real, but months out — the passport's long window. Same half-strength ochre
   the immigration table gives the date itself, so the bell and the page rank
   the same item the same way. */
.reminders-dot--ahead {
  background: var(--warning-quiet);
}

/* "Changed by the agent" is news, not a deadline — so it never borrows the
   expiry palette. Brass is the app's mark for time passing, which is exactly
   what a new entry is; an already-seen one keeps its place in the column as a
   hairline ring, so the list still reads as a column of dots. */
.reminders-dot--new {
  background: var(--brass);
}

.reminders-dot--quiet {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--border-strong);
}

.reminders-staff-link {
  color: var(--brand-navy);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.reminders-staff-link:hover {
  text-decoration: underline;
}

.reminders-item-text {
  color: var(--muted);
}

/* Immigration rows: name (truncating) on the left, date pinned right. Without
   this the label's nowrap pushes the date out of the column and it wraps one
   word — or one digit — per line. */
.reminders-row-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.reminders-item-kind {
  font-weight: 400;
  color: var(--muted);
}

.reminders-row-date {
  flex: none;
  margin-left: auto;
  white-space: nowrap;
}

.reminders-more {
  display: inline-block;
  margin-top: 0.4rem;
  font-size: 0.8rem;
  color: var(--brand-navy);
}

.reminders-empty {
  margin: 0.2rem 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.reminders-footer {
  margin-top: 0.7rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--border);
  text-align: right;
}

.reminders-send-digest-btn {
  font-size: 0.8rem;
  padding: 0.3rem 0.7rem;
}

.login-page-body {
  min-height: 100vh;
  background: var(--page-bg, var(--canvas));
}

.login-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(100vh - 2rem);
  padding: 1rem;
}

.login-page .login-card {
  width: min(100%, 24rem);
}

.users-table td.actions-col {
  white-space: nowrap;
}

.users-table td.users-actions-col {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
}

.users-table .danger-text {
  color: var(--danger);
}

.audit-log-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.audit-log-list li {
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border-subtle, var(--border));
  font-size: 0.9rem;
}

.audit-log-list li:last-child {
  border-bottom: none;
}

.audit-log-meta {
  color: var(--text-muted, var(--ink-2));
  font-size: 0.8rem;
}

.nav-link {
  padding: 0.45rem 0.85rem;
  border-radius: var(--r-md);
  color: var(--ink-2);
  font-size: 0.875rem;
}

.nav-link:hover {
  background: var(--fill);
  color: var(--ink);
}

.nav-link.active {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 500;
}

.page {
  max-width: 1600px;
  margin: 0 auto;
  padding: 1.25rem;
}

.page-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}

.page-title {
  margin: 0;
  font-size: 1.35rem;
  letter-spacing: -0.01em;
}

.page-subtitle {
  margin: 0.25rem 0 0;
  color: var(--muted);
}

.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
}

.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
}

.controls-card {
  padding: 1rem;
  margin-bottom: 1rem;
}

label {
  font-size: 0.875rem;
  color: var(--muted);
  display: block;
  margin-bottom: 0.25rem;
}

input,
select,
textarea,
button {
  font: inherit;
}

input,
select,
textarea {
  width: 100%;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
}

button,
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.55rem 0.95rem;
  border: none;
  border-radius: 8px;
  background: var(--brand-navy);
  color: #fff;
  cursor: pointer;
}

/* The rule above sets `display` on the element itself, which outranks the
   user-agent [hidden] rule — without this, a hidden button still paints. */
button[hidden],
.btn[hidden] {
  display: none;
}

/* Edit-only controls, gone for a read-only account. `data-role` is written
   into <html> by the server (roleNav.ts), so they never paint at all;
   `.is-read-only` is the client's fallback once /auth/status answers. */
html[data-role="viewer"] .viewer-hidden,
html.is-read-only .viewer-hidden {
  display: none !important;
}

button.secondary,
.btn.secondary {
  background: var(--card);
  color: var(--text);
  border: 1px solid var(--border-strong);
}

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

button:hover,
.btn:hover {
  filter: brightness(1.05);
}

.field-inline {
  min-width: 180px;
}

/* Dashboard integrations card (Lot 17). */
.dashboard-integration-hint {
  margin: 0 0 0.5rem;
  color: var(--ink-2);
  font-size: var(--text-xs);
}

.dashboard-integration-row {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}

.dashboard-feed-url {
  flex: 1;
  min-width: 0;
  font-family: var(--font-data);
  font-size: var(--text-xs);
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--surface-raised);
  color: var(--ink);
}

.dashboard-integration-btn {
  padding: 0.3rem 0.7rem;
  font-size: var(--text-xs);
  border-radius: var(--r-md);
}

/* Dashboard leave-request review card (Lot 16). */
.dashboard-request {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--border);
}

.dashboard-request:last-child {
  border-bottom: none;
}

.dashboard-request-summary {
  font-size: var(--text-base);
  line-height: 1.45;
}

.dashboard-request-meta {
  display: inline-block;
  margin-left: 0.35rem;
  color: var(--ink-2);
  font-size: var(--text-xs);
}

.dashboard-request-actions {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.dashboard-request-btn {
  padding: 0.3rem 0.7rem;
  font-size: var(--text-xs);
  border-radius: var(--r-md);
}

.dashboard-request-btn--reject {
  color: var(--error);
  border-color: var(--error);
}

/* Pending leave requests shown in the staff profile modal (Lot 16). */
.staff-profile-pending-requests {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin: 0.5rem 0;
}

.staff-profile-pending-request {
  padding: 0.4rem 0.7rem;
  border-radius: var(--r-md);
  border: 1px solid var(--brass);
  background: var(--brass-soft);
  color: var(--ink);
  font-size: var(--text-sm);
}

/* Leave-type pigment dots — replace the retired emoji icons (DESIGN.md). */
.leave-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  flex-shrink: 0;
  vertical-align: baseline;
}

.leave-dot--vacation {
  background: var(--leave-vacation);
}

.leave-dot--sick {
  background: var(--leave-sick);
}

.leave-dot--emergency {
  background: var(--leave-emergency);
}

.leave-dot--unpaid {
  background: repeating-linear-gradient(45deg, var(--leave-unpaid) 0 2px, transparent 2px 4px);
}

/* Inline form error — persistent, unlike toasts (see StaffVacationsApi.showFormError). */
.form-error {
  margin: 0.6rem 0 0;
  padding: 0.5rem 0.7rem;
  border-radius: var(--r-md);
  border: 1px solid var(--error);
  background: var(--error-soft);
  color: var(--error);
  font-size: var(--text-sm);
}

.form-error[hidden] {
  display: none;
}

.timeline-card {
  padding: 0.5rem;
  min-height: 520px;
}

#timeline {
  min-height: 480px;
  border-radius: 8px;
}

.badge {
  display: inline-block;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  font-size: 0.8rem;
  color: #fff;
  font-weight: 600;
}

.table-wrap {
  overflow: auto;
}

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

th,
td {
  padding: 0.75rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: middle;
}

th {
  background: var(--card);
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
  border-bottom: 1px solid var(--border-strong);
}

tr:hover td {
  background: var(--surface-raised);
}

.status-pill {
  display: inline-block;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
}

.status-pill.active {
  background: var(--success-soft);
  color: var(--success);
}

.status-pill.inactive {
  background: var(--error-soft);
  color: var(--error);
}

.staff-admin-tools {
  margin-top: 0.85rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
}

.staff-admin-hint {
  margin: 0 0 0.5rem;
  font-size: 0.82rem;
  color: var(--muted);
}

.staff-admin-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 0.75rem;
}

.staff-admin-row label {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
}

.staff-row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 0.55rem;
  align-items: center;
}

/* Manage staff / departments tables — compact rows for desktop browsing */
#manage-section .table-wrap th,
#manage-section .table-wrap td {
  padding: 0.35rem 0.65rem;
}

#manage-section .table-wrap th {
  padding-top: 0.45rem;
  padding-bottom: 0.45rem;
  font-size: 0.78rem;
}

#manage-section .table-wrap td {
  font-size: 0.9rem;
  line-height: 1.35;
}

#manage-section .status-toggle input {
  width: 2.1rem;
  height: 1.1rem;
}

#manage-section .status-toggle-label {
  font-size: 0.75rem;
  min-width: 2.8rem;
}

.status-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  cursor: pointer;
  user-select: none;
}

.status-toggle input {
  width: 2.4rem;
  height: 1.25rem;
  margin: 0;
  accent-color: var(--brand-navy);
  cursor: pointer;
}

.status-toggle-label {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
  min-width: 3.2rem;
}

.status-toggle input:not(:checked) + .status-toggle-label {
  color: var(--error);
}

.status-toggle input:checked + .status-toggle-label {
  color: var(--success);
}

.tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
}

.tab-btn {
  background: var(--fill);
  color: var(--text);
}

.tab-btn.active {
  background: var(--brand-navy);
  color: #fff;
}

.tab-panel {
  display: none;
}

.tab-panel.active {
  display: block;
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0.85rem;
  margin-bottom: 1rem;
}

.form-actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.login-card {
  max-width: 420px;
  margin: 4rem auto;
  padding: 1.5rem;
}

.login-error {
  margin: 0.75rem 0 0;
  padding: 0.65rem 0.75rem;
  border-radius: 8px;
  background: var(--error-soft);
  color: var(--error);
  font-size: 0.9rem;
}

.login-error.hidden {
  display: none;
}

.hidden {
  display: none !important;
}

#toast-container {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.toast {
  background: var(--brand-navy);
  color: #fff;
  padding: 0.75rem 1rem;
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.toast-error {
  background: var(--danger);
}

.toast-success {
  background: var(--success);
}

.toast-info {
  background: var(--ink);
  /* Ink flips light in dark mode, so the text has to flip with it: white on
     white is what a plain toast read as after dark. */
  color: var(--canvas);
}

/* Something happened, it worked, and it is not what you were expecting: a line
   saved into a month other than the one on screen. Neither the success green
   nor the destructive clay, so it takes the warning ochre. Written the way the
   rest of the app writes a warning surface, a soft ochre ground with an ochre
   hairline and ordinary ink on it, which is also what keeps it readable in
   both themes without a dark-mode rule of its own. */
.toast-warning {
  background: var(--warning-soft);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--warning), var(--shadow-pop);
}

.toast-persistent {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  max-width: min(26rem, calc(100vw - 2rem));
  padding: 0.75rem 0.5rem 0.75rem 1rem;
}

.toast-persistent .toast-body {
  flex: 1;
  font-size: 0.875rem;
  line-height: 1.45;
  min-width: 0;
}

.toast-title {
  margin: 0 0 0.5rem;
  font-weight: 600;
}

.toast-list {
  margin: 0;
  padding-left: 1.1rem;
  max-height: min(16rem, 45vh);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.toast-list li {
  padding-right: 0.25rem;
}

.toast-dismiss {
  flex-shrink: 0;
  margin: 0;
  padding: 0.15rem 0.4rem;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: inherit;
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0.8;
}

.toast-dismiss:hover {
  opacity: 1;
  background: rgba(255, 255, 255, 0.12);
}

.toast-hide {
  opacity: 0;
  transform: translateY(8px);
}

.empty-state {
  padding: 2rem;
  text-align: center;
  color: var(--muted);
}

.link-button {
  background: none;
  border: none;
  color: var(--brand-navy);
  padding: 0;
  text-decoration: underline;
  cursor: pointer;
}

@media (max-width: 768px) {
  .page-title {
    font-size: 1.35rem;
  }

  /* Two lines, not four. Stacked one control per line the bar was ~190px tall,
     a quarter of a phone screen spent on a name and two icons: the account and
     the two toggles share the first line, the sections take the second. It
     still scrolls away with the page rather than being pinned. */
  .navbar {
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.5rem;
    padding: 0.45rem 0.75rem;
  }

  /* Who is signed in reads first, the controls sit at the far end, and the
     sections take the line below. */
  .navbar-user {
    order: 1;
    margin-left: 0;
    gap: 0.45rem;
  }

  .navbar-reminders {
    order: 2;
    margin-left: auto;
  }

  .theme-toggle-btn {
    order: 3;
    margin-left: 0;
  }

  .navbar-user-label {
    font-size: 0.78rem;
  }

  .navbar-logout-btn {
    padding: 0.22rem 0.5rem;
    font-size: 0.78rem;
  }

  /* The row of sections keeps its own width, which is half again as wide as a
     phone, and every page slid sideways under it. It scrolls on its own
     instead, dragged with a thumb, and the page under it stays put. The width
     is set outright: a flex item is not squeezed below what it holds unless it
     is told the line's width. */
  .navbar-links {
    order: 4;
    width: 100%;
    flex-wrap: nowrap;
    min-width: 0;
    overflow-x: auto;
    /* Horizontally, and only horizontally: a strip that also scrolls a few
       pixels up and down drifts under the thumb on every sideways drag. */
    overflow-y: hidden;
    touch-action: pan-x;
    scrollbar-width: none;
  }

  .navbar-links::-webkit-scrollbar { display: none; }

  .navbar .nav-link {
    padding: 0.3rem 0.5rem;
  }

  .tips-editor--page .tips-staff-table thead th {
    top: 0;
  }
}

@media (min-width: 1200px) {
  .timeline-card {
    min-height: 680px;
  }

  #timeline {
    min-height: 640px;
  }

  .page-title {
    font-size: 2rem;
  }
}

.dashboard-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1rem;
  padding: 1rem 1.25rem;
  margin-bottom: 1rem;
}

.summary-stat {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.summary-value {
  font-family: var(--font-data);
  font-size: 1.4rem;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.summary-label {
  font-size: 0.8rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.summary-stat-warn.has-issues {
  cursor: pointer;
}

.summary-stat-warn.has-issues .summary-value {
  color: var(--danger);
}

.timeline-group-label {
  padding: 0.1rem 0.35rem 0.1rem 0.2rem;
  min-width: 148px;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-start;
}

.group-title-row {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
  width: 100%;
}

.group-identity {
  display: flex;
  flex-direction: column;
  gap: 0;
  min-width: 0;
  flex: 1;
}

.group-badges {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  flex-shrink: 0;
}

.group-name-row {
  display: flex;
  align-items: baseline;
  gap: 0.15rem;
  min-width: 0;
}

/* The clip is there for the ellipsis of a name too long for the column, and it
   must not shave the ones that fit. A glyph's ink runs past its advance: the
   last letter by most of a pixel on WebKit at 3x, the foot of a leading A or W,
   the tail of a y. So the clip box gets breathing room on every side (a line
   height that holds the whole ascent and descent, padding at the ends) and the
   negative margin gives the width back, so nothing beside the name moves. */
.group-name {
  font-weight: 600;
  font-size: 0.78rem;
  line-height: 1.3;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

button.group-name.linklike {
  margin: 0 -0.15em;
  padding: 0 0.15em;
  border: none;
  background: none;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  max-width: 100%;
}

button.group-name.linklike:hover,
button.group-name.linklike:focus-visible {
  color: var(--brand-navy);
  text-decoration: underline;
}

.group-pending-days {
  flex-shrink: 0;
  font-size: 0.68rem;
  font-weight: 500;
  line-height: 1.15;
  color: var(--muted);
  white-space: nowrap;
}

.group-meta {
  font-size: 0.64rem;
  line-height: 1.1;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.reconciliation-card {
  padding: 1rem;
  margin-bottom: 1rem;
  border-left: 4px solid var(--danger);
}

.reconciliation-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.75rem;
}

.reconciliation-header h2 {
  margin: 0;
  font-size: 1rem;
}

.reconciliation-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.65rem;
}

.reconciliation-item {
  padding: 0.65rem 0.75rem;
  background: var(--surface-raised);
  border-radius: 8px;
  border: 1px solid var(--border);
}

.reconciliation-item p {
  margin: 0.35rem 0 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.vis-item.board-yin-bg {
  background-color: rgba(14, 42, 71, 0.10) !important;
  border: none !important;
}

.vis-item.board-yang-bg {
  background-color: rgba(168, 144, 90, 0.16) !important;
  border: none !important;
}

.vis-item.board-yin-bg .vis-item-content,
.vis-item.board-yang-bg .vis-item-content {
  visibility: hidden;
}

/* Shared leave presentation — timeline + profile calendar */
.leave-vacation,
.spvc-bar--vacation {
  background-color: var(--leave-vacation);
}

.leave-sick,
.spvc-bar--sick {
  background-color: var(--leave-sick);
}

.leave-emergency,
.spvc-bar--emergency {
  background-color: var(--leave-emergency);
}

.leave-unpaid:not(.leave-absence):not(.leave-vacation):not(.leave-sick):not(.leave-emergency),
.spvc-bar--unpaid:not(.spvc-bar--absence):not(.spvc-bar--vacation):not(.spvc-bar--sick):not(.spvc-bar--emergency) {
  background: repeating-linear-gradient(
    -45deg,
    var(--border),
    var(--border) 2px,
    var(--leave-unpaid) 2px,
    var(--leave-unpaid) 4px
  );
}

/* Booked "Unpaid" keeps the full slate hatch above — it is a decision, and it
   reads as firmly as a paid bar does. An off day no leave column claimed is a
   hole in the record, not a decision: it washes out to a pale hatch so the two
   are never mistaken for each other on the same row. */
.leave-absence:not(.leave-vacation):not(.leave-sick):not(.leave-emergency),
.spvc-bar--absence:not(.spvc-bar--vacation):not(.spvc-bar--sick):not(.spvc-bar--emergency) {
  background: repeating-linear-gradient(
    -45deg,
    var(--card),
    var(--card) 2px,
    color-mix(in srgb, var(--leave-unpaid) 32%, var(--card)) 2px,
    color-mix(in srgb, var(--leave-unpaid) 32%, var(--card)) 4px
  );
}

.leave-historical,
.spvc-bar--historical {
  opacity: 1;
}

.leave-tentative,
.spvc-bar--tentative {
  border: 2px dashed color-mix(in srgb, var(--ink) 45%, transparent);
  opacity: 0.55;
}

/* Planned (confirmed) = soft fill + pigment outline; history stays solid. */
.leave-confirmed.leave-vacation,
.spvc-bar--confirmed.spvc-bar--vacation {
  background-color: var(--leave-vacation-soft);
  border: 2px solid var(--leave-vacation);
}

/* Employment departure (not a leave type) */
.leave-departure-marker.leave-departure-confirmed,
.leave-swatch.leave-departure.leave-departure-marker.leave-departure-confirmed {
  background-color: var(--ink-2);
  border: 2px solid var(--ink);
}

.leave-departure-marker.leave-departure-tentative,
.leave-swatch.leave-departure.leave-departure-marker.leave-departure-tentative {
  background-color: var(--ink-3);
  border: 2px dashed var(--ink-2);
  opacity: 0.85;
}

.vis-item.leave-departure-marker {
  z-index: 2;
}

.vis-item.leave-departure-marker .vis-item-content {
  color: #fff;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.vis-item.leave-departure-after {
  background-color: rgba(100, 116, 139, 0.12) !important;
  border: none !important;
}

/* Employment start (arrival) — mirror of the departure visuals. */
.vis-item.leave-arrival-marker {
  background-color: var(--success) !important;
  border: 2px solid var(--success) !important;
  color: #fff !important;
}

.vis-item.leave-arrival-before {
  background: repeating-linear-gradient(
    -45deg,
    rgba(100, 116, 139, 0.28),
    rgba(100, 116, 139, 0.28) 4px,
    transparent 4px,
    transparent 9px
  ) !important;
  border: none !important;
}

.vis-item.leave-departure-after.leave-departure-tentative {
  background: repeating-linear-gradient(
    -45deg,
    rgba(148, 163, 184, 0.08),
    rgba(148, 163, 184, 0.08) 4px,
    rgba(100, 116, 139, 0.14) 4px,
    rgba(100, 116, 139, 0.14) 8px
  ) !important;
}

.vis-item.leave-departure-after .vis-item-content {
  visibility: hidden;
}

.leave-swatch.leave-departure.leave-departure-after.leave-departure-confirmed {
  background-color: rgba(100, 116, 139, 0.35);
}

.group-departure-hint {
  font-size: 0.72rem;
  color: var(--muted);
  font-weight: 500;
}

.timeline-departure-hint {
  margin: 0 0 0.75rem;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--muted);
}

.timeline-group-departure {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.35rem;
  height: 1.35rem;
  padding: 0;
  margin-left: 0.15rem;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  opacity: 0.65;
}

.timeline-group-departure:hover {
  color: var(--brand-navy);
  opacity: 1;
}

.leave-confirmed.leave-sick,
.spvc-bar--confirmed.spvc-bar--sick {
  background-color: var(--leave-sick-soft);
  border: 2px solid var(--leave-sick);
}

.leave-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem 0.85rem;
  align-items: center;
  font-size: 0.72rem;
  color: var(--muted);
}

.leave-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.leave-legend-swatch {
  display: inline-block;
  width: 1.1rem;
  height: 0.55rem;
  border-radius: 999px;
  flex-shrink: 0;
}

.leave-swatch.leave-vacation { background-color: var(--leave-vacation); }
.leave-swatch.leave-sick { background-color: var(--leave-sick); }
.leave-swatch.leave-emergency { background-color: var(--leave-emergency); }
.leave-swatch.leave-absence { background: var(--leave-unpaid); }
.leave-swatch.leave-tentative { border: 2px dashed var(--ink-2); background: var(--info-soft); opacity: 0.55; }
.leave-swatch.leave-confirmed { background: var(--leave-vacation-soft); border: 2px solid var(--leave-vacation); }

.board-yin-swatch { background: rgba(14, 42, 71, 0.35); }
.board-yang-swatch { background: rgba(168, 144, 90, 0.45); }

/* Timeline page layout (aligned with attendance command bar) */
body:has(.timeline-page) {
  overflow: hidden;
  height: 100dvh;
  display: flex;
  flex-direction: column;
}

body:has(.timeline-page) .navbar {
  flex-shrink: 0;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

body:has(.timeline-page) .timeline-page {
  flex: 1;
  min-height: 0;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  padding: 0.4rem 0.75rem 0.5rem;
  margin: 0;
  overflow: hidden;
}

body:has(.timeline-page) .timeline-command-bar {
  flex-shrink: 0;
  min-width: 0;
  width: 100%;
  max-width: 100%;
}

.timeline-command-bar {
  flex-shrink: 0;
  padding: 0.65rem 0.85rem;
  border-radius: 12px;
}

.timeline-command-bar--compact {
  padding: 0.4rem 0.55rem;
}

.timeline-toolbar {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 2.1rem;
  flex-wrap: nowrap;
}

.timeline-toolbar-filters {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  flex-shrink: 0;
}

.timeline-toolbar-filters select {
  max-width: 8.25rem;
  min-width: 0;
  padding: 0.28rem 0.4rem;
  font-size: 0.76rem;
  border-radius: 6px;
}

/* Presence options carry a count suffix ("Upcoming leave · 12"). */
.timeline-toolbar-filters #presence-filter {
  max-width: 10.5rem;
}

.timeline-toolbar-filters .timeline-staff-search {
  width: 8.5rem;
  min-width: 0;
  padding: 0.28rem 0.5rem;
  font-size: 0.76rem;
  border-radius: 6px;
}

.timeline-range-toggle {
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  padding: 0.15rem;
  border-radius: 7px;
  background: var(--fill);
  border: 1px solid var(--border);
  flex-shrink: 0;
}

.timeline-range-btn {
  border: none;
  border-radius: 5px;
  padding: 0.22rem 0.5rem;
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--muted);
  background: transparent;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.12s, color 0.12s, box-shadow 0.12s;
}

.timeline-range-btn:hover:not(.is-active) {
  color: var(--text);
  background: color-mix(in srgb, var(--card) 70%, transparent);
}

.timeline-range-btn.is-active {
  color: #fff;
  background: var(--brand-navy);
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.18);
}

.timeline-range-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.timeline-toolbar-spacer {
  flex: 1 1 auto;
  min-width: 0.25rem;
}

.timeline-toolbar-actions {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  flex-shrink: 0;
}

.timeline-toolbar-btn {
  padding: 0.3rem 0.55rem;
  font-size: 0.76rem;
  line-height: 1.2;
}

.timeline-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border-radius: 6px;
  flex-shrink: 0;
}

.timeline-icon-btn--danger {
  color: var(--error);
  border-color: var(--error-soft);
}

.timeline-icon-btn--lock {
  color: var(--accent);
  border-color: var(--border-strong);
  background: var(--info-soft);
}

.timeline-unlock-menu.hidden,
.timeline-overflow-menu.hidden {
  display: none !important;
}

.timeline-toolbar-menu {
  position: relative;
}

.timeline-toolbar-menu > summary {
  list-style: none;
  cursor: pointer;
}

.timeline-toolbar-menu > summary::-webkit-details-marker {
  display: none;
}

.timeline-toolbar-menu[open] > summary {
  border-color: var(--brand-navy);
  color: var(--brand-navy);
}

.timeline-toolbar-menu-body {
  position: absolute;
  right: 0;
  top: calc(100% + 0.3rem);
  z-index: 30;
  min-width: 12rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
}

.timeline-overflow-menu-body button {
  width: 100%;
  margin-top: 0.35rem;
  font-size: 0.78rem;
}

.timeline-unlock-menu-body {
  min-width: 14rem;
}

.timeline-unlock-copy {
  margin: 0 0 0.45rem;
  font-size: 0.78rem;
  color: var(--muted);
}

.timeline-login-form {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.timeline-login-form input[type="password"] {
  flex: 1;
  min-width: 0;
  max-width: 7rem;
  padding: 0.35rem 0.45rem;
  font-size: 0.8rem;
}

.timeline-toolbar-login-error {
  margin: 0.25rem 0 0;
  font-size: 0.78rem;
}

.timeline-grid-card {
  flex: 1;
  min-height: 12rem;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  padding: 0.35rem;
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.timeline-page #timeline {
  flex: 1;
  min-height: 0;
  min-width: 0;
  width: 100%;
  height: 100%;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
  overscroll-behavior-x: contain;
  overscroll-behavior-y: auto;
}

.timeline-page .vis-timeline {
  font-family: var(--font-ui);
  border-color: var(--border);
  font-size: 0.7rem;
  width: 100% !important;
  max-height: 100%;
  overscroll-behavior-x: contain;
}

.timeline-page .vis-panel.vis-left,
.timeline-page .vis-panel.vis-center,
.timeline-page .vis-panel.vis-right {
  border-color: var(--border);
  overscroll-behavior-x: contain;
}

/* No native scrolling on the labels panel: it fights the vis redraws that
   reset its scrollTop (names drift from the rows, bottom unreachable).
   Wheel gestures route through the timeline scroll instead
   (setupTimelineVerticalScrollSync in timeline.js); vis still positions
   the panel programmatically. */
.timeline-page .vis-left.vis-panel.vis-vertical-scroll {
  overflow-y: hidden;
}

.timeline-page .vis-time-axis .vis-grid.vis-minor,
.timeline-page .vis-time-axis .vis-grid.vis-major {
  border-left-color: transparent;
}

/* Week boundaries (Saturday → Saturday): light blue dotted vertical lines (JS overlay on vis-content) */
.timeline-week-grid-overlay {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
}

.timeline-week-grid-line {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: repeating-linear-gradient(
    to bottom,
    var(--border-strong) 0,
    var(--border-strong) 5px,
    transparent 5px,
    transparent 12px
  );
  transform: translateX(-0.5px);
}

/* Custom header replaces native axis grid — no dotted week lines in the header */
.timeline-page .vis-time-axis .vis-grid.vis-saturday,
.timeline-page .vis-time-axis .vis-grid.vis-major,
.timeline-page .vis-time-axis .vis-grid.vis-minor {
  border-left-color: transparent !important;
  border-left-style: none !important;
}

.timeline-page .vis-panel.vis-center .vis-background .vis-grid.vis-vertical {
  border-left-style: dotted;
}

.timeline-page .vis-panel.vis-center .vis-background .vis-grid.vis-vertical.vis-minor,
.timeline-page .vis-panel.vis-center .vis-background .vis-grid.vis-vertical.vis-major {
  border-left-width: 1px;
  border-left-color: transparent;
}

.timeline-page .vis-panel.vis-center .vis-background .vis-grid.vis-vertical.vis-saturday {
  border-left-width: 1px;
  border-left-color: var(--border-strong);
}

.timeline-page[data-timeline-axis="week-coarse"] .vis-panel.vis-center .vis-background .vis-grid.vis-vertical.vis-major {
  border-left-style: dotted;
  border-left-color: var(--border-strong);
}

.timeline-page .vis-panel.vis-center .vis-background .vis-grid.vis-vertical.vis-odd {
  background: transparent;
}

.timeline-page .vis-panel.vis-center .vis-background .vis-grid.vis-vertical.vis-saturday,
.timeline-page .vis-panel.vis-center .vis-background .vis-grid.vis-vertical.vis-sunday {
  background: transparent;
}

.timeline-page .vis-panel.vis-center .vis-background .vis-grid.vis-vertical.vis-today,
.timeline-page .vis-time-axis .vis-grid.vis-today {
  background: rgba(168, 144, 90, 0.10);
  border-left-color: var(--brass) !important;
}

.timeline-page .vis-current-time {
  background-color: var(--brass);
  width: 2px;
  pointer-events: none;
  z-index: 1;
}

/* Native axis labels hidden — custom 3-row header in timeline.js */
.timeline-page .vis-time-axis .vis-text {
  display: none !important;
}

.timeline-page .vis-panel.vis-top {
  background: var(--surface-raised);
  min-height: 58px;
  position: relative;
  overflow: visible;
}

.timeline-month-band-overlay {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 5;
  overflow: hidden;
  background: var(--surface-raised);
  border-bottom: 1px solid var(--fill);
}

.timeline-axis-month-separator {
  position: absolute;
  top: 0;
  height: 100%;
  width: 1px;
  background: var(--fill);
  transform: translateX(-0.5px);
  pointer-events: none;
}

.timeline-axis-month-label {
  position: absolute;
  top: 0;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: translateX(-50%);
  box-sizing: border-box;
  white-space: nowrap;
  font-weight: 600;
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  color: var(--ink);
  padding: 0 4px;
  max-width: min(12rem, 40vw);
  overflow: hidden;
  text-overflow: ellipsis;
  z-index: 1;
}

.timeline-page .vis-panel.vis-top .vis-time-axis {
  overflow: visible !important;
}

.timeline-page .vis-panel.vis-top .vis-time-axis.vis-foreground {
  min-height: 58px;
  height: 58px !important;
  z-index: 1;
}

.timeline-custom-axis-overlay {
  position: absolute;
  top: 18px;
  left: 0;
  pointer-events: none;
  z-index: 4;
  overflow: hidden;
  box-sizing: border-box;
  padding: 4px 0;
}

.timeline-axis-day-col {
  position: absolute;
  top: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  height: 100%;
  box-sizing: border-box;
  overflow: hidden;
  padding: 2px 1px;
}

.timeline-page[data-timeline-axis-labels="lines-only"] .timeline-custom-axis-overlay {
  display: block;
}

/* Fine day column separators in the header row — always visible at every zoom */
.timeline-axis-day-col.timeline-axis-day-col--sep {
  border-left: 1px solid var(--fill);
  box-sizing: border-box;
}

.timeline-axis-weekday {
  font-size: 0.58rem;
  font-weight: 500;
  color: var(--ink-2);
  line-height: 1.1;
  max-width: 100%;
  overflow: hidden;
  text-overflow: clip;
  white-space: nowrap;
  min-width: 0;
}

.timeline-axis-date {
  font-size: 0.62rem;
  font-weight: 500;
  color: var(--ink-2);
  line-height: 1.1;
  max-width: 100%;
  overflow: hidden;
  text-overflow: clip;
  white-space: nowrap;
  min-width: 0;
}

.timeline-axis-day-col.timeline-axis-saturday {
  background: rgba(168, 144, 90, 0.14);
}

.timeline-axis-day-col.timeline-axis-saturday .timeline-axis-weekday,
.timeline-axis-day-col.timeline-axis-saturday .timeline-axis-date {
  color: var(--brass);
  font-weight: 600;
}

.timeline-axis-day-col.timeline-axis-saturday-date-only .timeline-axis-date {
  font-size: calc(0.62rem - 1px);
}

.timeline-page .vis-foreground .vis-group,
.timeline-page .vis-labelset .vis-label {
  /* Row separator as an inset shadow, NOT a border: a border adds 1px to
     every row's offsetHeight while vis-timeline sizes rows from content
     only — the accumulated pixels became bottom rows the vertical scroll
     could never reach. border-bottom: none also kills vis's own default
     row border, which has the same layout problem. */
  border-bottom: none;
  box-shadow: inset 0 -1px 0 var(--border);
  box-sizing: border-box;
  transition: background-color 0.12s ease;
}

.timeline-page .vis-label.timeline-row-hover,
.timeline-page .vis-panel.vis-center .vis-background .vis-group.timeline-row-hover,
.timeline-page .vis-foreground .vis-group.timeline-row-hover {
  background-color: var(--fill) !important;
}

/* Designation section separators (attendance position) — full row, left label + grid */
.timeline-page .vis-label.timeline-designation-header,
.timeline-page .vis-panel.vis-center .vis-background .vis-group.timeline-designation-header,
.timeline-page .vis-foreground .vis-group.timeline-designation-header {
  background: var(--border) !important;
  border-top: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
}

.timeline-page .vis-label.timeline-designation-section--0:not(.timeline-designation-header),
.timeline-page .vis-panel.vis-center .vis-background .vis-group.timeline-designation-section--0:not(.timeline-designation-header),
.timeline-page .vis-foreground .vis-group.timeline-designation-section--0:not(.timeline-designation-header) {
  background-color: var(--card);
}

.timeline-page .vis-label.timeline-designation-section--1:not(.timeline-designation-header),
.timeline-page .vis-panel.vis-center .vis-background .vis-group.timeline-designation-section--1:not(.timeline-designation-header),
.timeline-page .vis-foreground .vis-group.timeline-designation-section--1:not(.timeline-designation-header) {
  background-color: var(--surface-raised);
}

/* Staff rows keep their height through relayouts: vis-timeline derives group
   height from the label inner, which stale inline clamps must never shrink. */
.timeline-page .vis-labelset .vis-label.timeline-staff-row .vis-inner {
  min-height: 32px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
}

.timeline-page .vis-label.timeline-designation-header .vis-inner {
  height: 100%;
  min-height: 24px;
  padding: 0;
  align-items: stretch;
}

.timeline-designation-header-label {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: stretch;
}

.timeline-designation-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.35rem;
  width: 100%;
  flex: 1;
  min-width: 0;
  padding: 0 0.45rem;
  box-sizing: border-box;
}

.timeline-designation-header-title {
  flex: 1;
  min-width: 0;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink);
  text-transform: uppercase;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.timeline-designation-header-count {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.15rem;
  padding: 0.08rem 0.42rem;
  border-radius: 999px;
  font-size: 0.62rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
  background: var(--fill);
  border: 1px solid var(--border-strong);
}

.timeline-page .vis-panel.vis-center .vis-foreground .vis-item.vis-range {
  top: 5px !important;
}

/* The app's tooltip, in place of the browser's, which waits a second before it
   appears (see js/tooltip.js). Ink on the page's own ground rather than the
   info blue of the timeline's cursor readout: that one is a reading of the
   data, this one is a label saying what something is. Fixed to the body, so no
   column's overflow can clip it, and untouchable, so it cannot come between the
   pointer and the button it is describing. */
.ui-tooltip {
  position: fixed;
  z-index: 1300;
  max-width: min(20rem, calc(100vw - 1.5rem));
  padding: 0.3rem 0.5rem;
  border-radius: 6px;
  background: var(--ink);
  color: var(--canvas);
  font-size: var(--text-xs);
  font-weight: 400;
  line-height: 1.35;
  white-space: normal;
  pointer-events: none;
  box-shadow: 0 4px 12px rgb(27 36 50 / 18%);
}

/* A tip that is a list (see js/tooltip.js): one block per question, the
   people it is about under it, names at the app's loudest weight. */
.ui-tooltip-block + .ui-tooltip-block {
  margin-top: 0.4rem;
  padding-top: 0.4rem;
  border-top: 1px solid color-mix(in srgb, var(--canvas) 25%, transparent);
}

.ui-tooltip-list {
  margin: 0.2rem 0 0;
  padding-left: 1rem;
}

.ui-tooltip-list strong {
  font-weight: 600;
}

.timeline-cursor-tooltip {
  position: fixed;
  z-index: 1200;
  max-width: min(22rem, calc(100vw - 1.5rem));
  padding: 0.45rem 0.65rem;
  border-radius: 8px;
  border: 1px solid var(--info);
  background: var(--info-soft);
  color: var(--info);
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1.35;
  pointer-events: none;
  box-shadow: 0 6px 18px rgba(15, 23, 42, 0.14);
}

.timeline-cursor-tooltip-body {
  display: block;
}

.timeline-cursor-tooltip-type {
  display: block;
  font-weight: 600;
}

.timeline-cursor-tooltip-main {
  display: block;
  font-weight: 500;
}

/* Flight-ticket info on its own line, under a hairline separator */
.timeline-cursor-tooltip-flight {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.35rem;
  padding-top: 0.35rem;
  border-top: 1px solid color-mix(in srgb, var(--info) 30%, transparent);
  font-weight: 500;
}

.timeline-cursor-tooltip-flight .timeline-bar-flight {
  display: inline-flex;
  flex: none;
}

.timeline-cursor-tooltip-flight .timeline-bar-flight svg {
  width: 14px;
  height: 14px;
  display: block;
}

.timeline-page .vis-item.vis-range {
  border-radius: 4px;
  border-width: 1px;
  height: 22px !important;
  min-height: 22px !important;
  max-height: 22px !important;
  overflow: hidden;
}

.timeline-page .vis-item.vis-range .vis-item-content {
  padding: 0 5px;
  overflow: hidden;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  /* Keep bar dates centered in the bar (override vis-timeline auto overflow shift) */
  left: 0 !important;
  transform: none !important;
}

/* Planned leave only — subtle in-bar grips hint at horizontal resize */
.timeline-page .vis-item.vis-range:not(.leave-historical) .vis-item-content {
  position: relative;
  padding: 0 11px;
}

.timeline-page .vis-item.vis-range:not(.leave-historical) .vis-item-content::before,
.timeline-page .vis-item.vis-range:not(.leave-historical) .vis-item-content::after {
  content: '';
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 2px;
  height: 10px;
  border-radius: 1px;
  background: currentColor;
  opacity: 0.42;
  pointer-events: none;
}

.timeline-page .vis-item.vis-range:not(.leave-historical) .vis-item-content::before {
  left: 4px;
}

.timeline-page .vis-item.vis-range:not(.leave-historical) .vis-item-content::after {
  right: 4px;
}

.timeline-page .vis-item.vis-range .timeline-bar-label {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
  line-height: 1;
  color: inherit;
  pointer-events: none;
  user-select: none;
}

.timeline-page .vis-item.vis-range .timeline-bar-label--hidden {
  display: none;
}

.timeline-page .vis-item.vis-range .timeline-bar-content {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  min-width: 0;
}

/* Flight-ticket badge: plane = covered, plane with slash = not covered. */
.timeline-page .vis-item.vis-range .timeline-bar-flight {
  display: inline-flex;
  flex: none;
  color: inherit;
  pointer-events: none;
  user-select: none;
}

.timeline-page .vis-item.vis-range .timeline-bar-flight svg {
  width: 13px;
  height: 13px;
  display: block;
}

.timeline-page .vis-item.vis-range .timeline-bar-flight--not-covered {
  opacity: 0.85;
}

.timeline-page .vis-item.vis-range .timeline-bar-flight--hidden {
  display: none;
}

.timeline-page[data-range-preset="month"] .vis-item.vis-range .timeline-bar-label {
  font-size: 0.7rem;
}

.timeline-page[data-range-preset="quarter"] .vis-item.vis-range .timeline-bar-label {
  font-size: 0.66rem;
}

.timeline-page[data-range-preset="semester"] .vis-item.vis-range .timeline-bar-label {
  font-size: 0.62rem;
}

/* Bar labels: white on solid pigments (DESIGN.md), ink on hatched patterns. */
.timeline-page .vis-item.vis-range {
  color: #fff;
}

/* Selection must keep the leave pigment — the library default repaints
   selected items yellow (#FFF785), which mangled tentative bars. These sit
   BEFORE the status-specific rules so confirmed/historical shades still win. */
.timeline-page .vis-item.leave-vacation {
  background-color: var(--leave-vacation) !important;
  border-color: var(--leave-vacation) !important;
}

.timeline-page .vis-item.leave-sick {
  background-color: var(--leave-sick) !important;
  border-color: var(--leave-sick) !important;
}

.timeline-page .vis-item.leave-emergency {
  background-color: var(--leave-emergency) !important;
  border-color: var(--leave-emergency) !important;
}

.timeline-page .vis-item.vis-selected:not(.leave-historical) {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 55%, transparent);
}

.vis-item.leave-vacation.leave-historical {
  background-color: var(--leave-vacation) !important;
  border-color: var(--leave-vacation) !important;
  color: #fff !important;
}

.vis-item.leave-sick,
.vis-item.leave-sick.leave-historical,
.vis-item.leave-sick.leave-unpaid {
  background: var(--leave-sick) !important;
  border-color: var(--leave-sick) !important;
  color: #fff !important;
}

.vis-item.leave-emergency.leave-historical {
  background-color: var(--leave-emergency) !important;
  border-color: var(--leave-emergency) !important;
  color: #fff !important;
}

/* `leave-unpaid` rides along on absence bars too (vacationItemClassName), so
   the strong hatch excludes `leave-absence` explicitly — otherwise the two
   would be one look again, which is exactly what the Unpaid column exists to
   stop. */
.vis-item.leave-unpaid:not(.leave-absence):not(.leave-vacation):not(.leave-sick):not(.leave-emergency) {
  background: repeating-linear-gradient(
    -45deg,
    var(--border),
    var(--border) 3px,
    var(--leave-unpaid) 3px,
    var(--leave-unpaid) 6px
  ) !important;
  border-color: var(--ink-2) !important;
  color: var(--ink) !important;
}

/* An unrecorded absence next to a booked Unpaid bar: pale hatch, dashed edge —
   the timeline says "nobody decided this yet" without shouting. */
.vis-item.leave-absence:not(.leave-vacation):not(.leave-sick):not(.leave-emergency) {
  background: repeating-linear-gradient(
    -45deg,
    var(--card),
    var(--card) 3px,
    color-mix(in srgb, var(--leave-unpaid) 32%, var(--card)) 3px,
    color-mix(in srgb, var(--leave-unpaid) 32%, var(--card)) 6px
  ) !important;
  border: 1px dashed var(--leave-unpaid) !important;
  color: var(--ink-2) !important;
}

/* Planned leave (not yet history): soft fill + pigment outline + ink text.
   History stays the solid filled bar — a plan reads as an outline that
   attendance "fills in" once the dates actually happened, so planned and
   historical dates are distinguishable at a glance. */
.timeline-page .vis-item.leave-vacation:not(.leave-historical) {
  background-color: var(--leave-vacation-soft) !important;
  border: 2px solid var(--leave-vacation) !important;
  color: var(--ink) !important;
}

.timeline-page .vis-item.leave-sick:not(.leave-historical) {
  background: var(--leave-sick-soft) !important;
  border: 2px solid var(--leave-sick) !important;
  color: var(--ink) !important;
}

.timeline-page .vis-item.leave-emergency:not(.leave-historical) {
  background: var(--leave-emergency-soft) !important;
  border: 2px solid var(--leave-emergency) !important;
  color: var(--ink) !important;
}

.vis-item.leave-tentative,
.timeline-page .vis-item.leave-tentative:not(.leave-historical) {
  border-style: dashed !important;
  opacity: 0.8;
}

.timeline-page .vis-item.vis-range.leave-historical,
.timeline-page .vis-item.vis-range.leave-tentative,
.timeline-page .vis-item.vis-range.leave-confirmed {
  cursor: pointer;
}

.timeline-page .vis-item.vis-range:not(.leave-historical) {
  cursor: grab;
}

.timeline-page .vis-item.vis-range.vis-selected:not(.leave-historical) {
  cursor: grabbing;
  z-index: 2;
}

.timeline-page .vis-item.vis-selected {
  overflow: visible;
  z-index: 4;
}

.timeline-page .vis-item.vis-selected .vis-delete {
  display: block;
  top: -9px;
  right: -9px;
  left: auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--error) !important;
  background-image: none !important;
  border: 2px solid var(--card);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  z-index: 6;
  pointer-events: auto;
  cursor: pointer;
}

.timeline-page .vis-item.vis-selected .vis-delete::after {
  content: '×';
  display: block;
  width: 100%;
  font: 600 12px/14px var(--font-ui);
  text-align: center;
  color: #fff;
}

.timeline-page .vis-item.leave-historical .vis-delete,
.timeline-page .vis-item.leave-departure-marker .vis-delete {
  display: none !important;
}

.timeline-page .vis-labelset .vis-label {
  border-right: 1px solid var(--border);
  padding: 0;
  box-sizing: border-box;
}

.timeline-page .vis-labelset .vis-label .vis-inner {
  min-height: 32px;
  height: 100%;
  /* vis's default 5px vertical padding pushes the inner's natural height
     past 32px, which vis then adopts as the row height — keep rows at the
     32px the design intends. */
  padding-top: 3px;
  padding-bottom: 3px;
  display: flex;
  align-items: center;
  box-sizing: border-box;
}

/* Designation header rows are pure section separators — keep them slim so
   more staff rows fit on screen. */
.timeline-page .vis-labelset .vis-label.timeline-designation-header .vis-inner {
  min-height: 24px;
}

.group-dept-dot {
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 999px;
  flex-shrink: 0;
}

.group-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  flex-shrink: 0;
  margin-left: auto;
}

.timeline-group-plan {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 1.35rem;
  height: 1.35rem;
  margin: 0;
  padding: 0;
  border: 1px solid var(--info-soft);
  border-radius: 6px;
  background: var(--info-soft);
  color: var(--info);
  box-shadow: 0 1px 2px rgba(58, 95, 138, 0.1);
  cursor: pointer;
  text-decoration: none;
  line-height: 0;
  opacity: 0;
  transition: opacity 0.12s ease, background-color 0.12s ease, border-color 0.12s ease;
}

.timeline-group-plan-icon {
  display: block;
  width: 0.72rem;
  height: 0.72rem;
}

.timeline-group-label:hover .timeline-group-plan,
.timeline-group-plan:focus-visible {
  opacity: 1;
}

.timeline-group-plan:hover {
  background: var(--info-soft);
  border-color: var(--leave-vacation-2);
}

.timeline-group-plan:focus-visible {
  outline: 2px solid #0891b2;
  outline-offset: 1px;
}

.timeline-plan-dialog {
  --plan-teal: var(--leave-vacation);
  --plan-teal-hover: #256a62;
  --plan-orange: var(--warning);
  --plan-orange-hover: #96691f;
  --plan-surface-muted: var(--fill);
  --plan-label: var(--ink-3);
  border: none;
  border-radius: 16px;
  padding: 0;
  width: min(100vw - 2rem, 32rem);
  max-width: 32rem;
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.2);
  overflow: hidden;
}

.timeline-plan-dialog::backdrop {
  background: rgba(15, 23, 42, 0.4);
  backdrop-filter: blur(3px);
}

.timeline-plan-form {
  padding: 1.35rem 1.5rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1.15rem;
  background: var(--card);
}

.timeline-plan-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.timeline-plan-header-text {
  min-width: 0;
}

.timeline-plan-staff-name {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
}

.timeline-plan-staff-role {
  margin: 0.2rem 0 0;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--plan-teal);
}

.timeline-plan-close {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--ink-3);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}

.timeline-plan-close:hover {
  background: var(--plan-surface-muted);
  color: var(--text);
}

.timeline-plan-section {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.timeline-plan-section-label {
  margin: 0;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--plan-label);
}

.timeline-plan-segment {
  display: flex;
  gap: 0.35rem;
  padding: 0.3rem;
  background: var(--plan-surface-muted);
  border-radius: 12px;
}

.timeline-plan-segment-btn {
  flex: 1;
  border: none;
  border-radius: 10px;
  padding: 0.65rem 0.5rem;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--ink-2);
  background: transparent;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, box-shadow 0.15s;
}

.timeline-plan-segment-btn:hover:not(.is-active) {
  color: var(--text);
  background: color-mix(in srgb, var(--card) 65%, transparent);
}

.timeline-plan-segment-btn.is-active {
  color: #fff;
  background: var(--plan-teal);
  box-shadow: 0 2px 8px rgba(46, 125, 116, 0.35);
}

.timeline-plan-status-toggle {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.65rem;
}

.timeline-plan-status-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  border: 2px solid transparent;
  border-radius: 12px;
  padding: 0.85rem 0.65rem;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.timeline-plan-status-btn.tentative {
  color: var(--warning);
  background: var(--warning-soft);
}

.timeline-plan-status-btn.tentative.is-active {
  color: #fff;
  background: var(--plan-orange);
  border-color: var(--plan-orange);
  box-shadow: 0 2px 10px rgba(176, 124, 42, 0.35);
}

.timeline-plan-status-btn.confirmed {
  color: var(--success);
  background: var(--plan-surface-muted);
}

.timeline-plan-status-btn.confirmed.is-active {
  color: #fff;
  background: var(--success);
  border-color: var(--success);
  box-shadow: 0 2px 10px rgba(46, 125, 82, 0.3);
}

.timeline-plan-status-btn:not(.is-active):hover {
  filter: brightness(0.97);
}

.timeline-plan-status-icon {
  font-size: 1rem;
  line-height: 1;
}

.timeline-plan-dates-readonly input[type="date"] {
  background: var(--surface-muted, var(--canvas));
  color: var(--text-secondary, var(--ink-2));
  pointer-events: none;
}

.timeline-plan-split-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary, var(--ink));
  cursor: pointer;
}

.timeline-plan-split-fields {
  margin-top: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.timeline-plan-historical-hint {
  margin: 0.75rem 0 0;
  font-size: 0.8125rem;
  color: var(--text-secondary, var(--ink-2));
}

.timeline-plan-dates {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.85rem;
}

.timeline-plan-date-field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.timeline-plan-date-field label {
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--ink-2);
}

.timeline-plan-date-field input[type="date"],
.timeline-plan-form textarea {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.65rem 0.75rem;
  font: inherit;
  font-size: 0.92rem;
  color: var(--text);
  background: var(--card);
}

.timeline-plan-date-field input[type="date"]:focus,
.timeline-plan-form textarea:focus {
  outline: 2px solid rgba(46, 125, 116, 0.35);
  outline-offset: 1px;
  border-color: var(--plan-teal);
}

.timeline-plan-form textarea {
  resize: vertical;
  min-height: 5.5rem;
  line-height: 1.45;
}

.timeline-plan-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.25rem;
  padding-top: 0.35rem;
}

.timeline-plan-delete {
  border: none;
  background: transparent;
  color: var(--danger);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  padding: 0.45rem 0.25rem;
}

.timeline-plan-delete:hover {
  text-decoration: underline;
}

.timeline-plan-footer-actions {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin-left: auto;
}

.timeline-plan-cancel {
  border: none;
  border-radius: 10px;
  padding: 0.65rem 1.1rem;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--text);
  background: var(--plan-surface-muted);
  cursor: pointer;
}

.timeline-plan-cancel:hover {
  background: var(--fill);
}

.timeline-plan-save {
  border: none;
  border-radius: 10px;
  padding: 0.65rem 1.25rem;
  font-size: 0.92rem;
  font-weight: 600;
  color: #fff;
  background: var(--plan-teal);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(46, 125, 116, 0.3);
}

.timeline-plan-save:hover {
  background: var(--plan-teal-hover);
}

.vacation-row-historical td {
  color: var(--muted);
}

.muted-hint {
  font-size: 0.78rem;
  color: var(--muted);
  font-style: italic;
}

.import-result {
  margin-top: 1rem;
  padding: 0.85rem;
  background: var(--surface-raised);
  border-radius: 8px;
  font-size: 0.9rem;
}

.import-result pre {
  white-space: pre-wrap;
  margin: 0.5rem 0 0;
  font-size: 0.8rem;
}

.attendance-page {
  padding: 0.65rem 1rem 1.25rem;
}

/* Éditeur plein viewport : scroll uniquement dans le corps du tableau, en-têtes toujours visibles */
body:has(.attendance-page #editor-section:not(.hidden)) {
  overflow: hidden;
  height: 100dvh;
  display: flex;
  flex-direction: column;
}

body:has(.attendance-page #editor-section:not(.hidden)) .navbar {
  flex-shrink: 0;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

body:has(.attendance-page #editor-section:not(.hidden)) .attendance-page {
  flex: 1;
  min-height: 0;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 0.4rem 0.75rem 0.5rem;
  margin: 0;
}

body:has(.attendance-page #editor-section:not(.hidden)) .attendance-page #editor-section {
  flex: 1;
  min-height: 0;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

body:has(.attendance-page #editor-section:not(.hidden)) .attendance-page #grid-section:not(.hidden) {
  flex: 1;
  min-height: 0;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  margin-bottom: 0;
}

body:has(.attendance-page #editor-section:not(.hidden)) .attendance-page #editor-section .attendance-command-bar,
body:has(.attendance-page #editor-section:not(.hidden)) .attendance-page #empty-month {
  flex-shrink: 0;
  min-width: 0;
  max-width: 100%;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.attendance-command-bar {
  padding: 0.4rem 0.65rem 0.35rem;
  margin-bottom: 0.45rem;
}

/* Three zones: what you are looking at (month · search · sort), what needs
   attention (comments, departures), what you can do (More · finalize · save). */
.attendance-command-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.45rem 0.75rem;
}

.attendance-command-primary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.4rem;
  min-width: 0;
  flex: 0 1 auto;
}

.attendance-command-primary > #month-select {
  width: auto;
  min-width: 9.5rem;
  max-width: 14rem;
  padding: 0.35rem 0.55rem;
  font-size: 0.82rem;
  font-weight: 600;
}

.attendance-command-notices {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
  flex: 1 1 auto;
  justify-content: center;
}

.attendance-command-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.35rem 0.5rem;
  flex-shrink: 0;
}

.attendance-command-actions button {
  padding: 0.38rem 0.75rem;
  font-size: 0.82rem;
}

.attendance-command-actions .save-status {
  font-size: 0.78rem;
  white-space: nowrap;
  padding-right: 0.15rem;
}

.admin-fields-btn.is-unlocked {
  border-color: var(--accent);
  color: var(--accent);
}

.attendance-more-menu {
  position: relative;
  font-size: 0.82rem;
}

.attendance-more-menu summary {
  list-style: none;
  cursor: pointer;
  padding: 0.38rem 0.65rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--card);
  color: var(--text);
  user-select: none;
}

.attendance-more-menu summary::-webkit-details-marker {
  display: none;
}

.attendance-more-menu[open] summary {
  border-color: var(--brand-navy);
  color: var(--brand-navy);
}

.attendance-more-menu-body {
  position: absolute;
  right: 0;
  top: calc(100% + 0.35rem);
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 10.5rem;
  padding: 0.45rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
}

.attendance-more-menu-body button {
  width: 100%;
  font-size: 0.78rem;
  padding: 0.42rem 0.55rem;
  margin: 0;
}

.attendance-more-menu-divider {
  margin: 0.15rem 0;
  border: none;
  border-top: 1px solid var(--border);
}

/* Always open, like the Vacation timeline search: one less click, and no
   expanding panel to push the toolbar onto a second line. */
.attendance-grid-search-control {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}

.attendance-grid-search-input {
  width: 10.5rem;
  min-width: 0;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--card);
  font-size: 0.82rem;
}

.attendance-grid-search-input:focus {
  outline: 2px solid var(--brand-navy);
  outline-offset: 0;
  border-color: var(--brand-navy);
}

.attendance-grid-search-input:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  background: var(--fill);
}

.attendance-search-meta {
  font-size: 0.72rem;
  color: var(--muted);
  white-space: nowrap;
  flex-shrink: 0;
  max-width: 7rem;
  overflow: hidden;
  text-overflow: ellipsis;
}

.attendance-sort-menu {
  position: relative;
  font-size: 0.82rem;
}

.attendance-sort-menu summary {
  list-style: none;
  cursor: pointer;
  padding: 0.38rem 0.65rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--card);
  color: var(--text);
  user-select: none;
}

.attendance-sort-menu summary::-webkit-details-marker {
  display: none;
}

.attendance-sort-menu summary.is-disabled {
  opacity: 0.45;
  pointer-events: none;
  cursor: default;
}

.attendance-sort-menu[open] summary {
  border-color: var(--brand-navy);
  color: var(--brand-navy);
}

.attendance-sort-menu summary.has-active-sort {
  border-color: var(--border-strong);
  background: var(--info-soft);
  color: var(--brand-navy);
}

.attendance-sort-menu-body {
  position: absolute;
  left: 0;
  top: calc(100% + 0.35rem);
  z-index: 20;
  min-width: 15rem;
  padding: 0.55rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
}

.attendance-sort-hint {
  margin: 0 0 0.55rem;
  font-size: 0.72rem;
  line-height: 1.35;
  color: var(--muted);
}

.attendance-sort-group + .attendance-sort-group {
  margin-top: 0.55rem;
  padding-top: 0.55rem;
  border-top: 1px solid var(--border);
}

.attendance-sort-label {
  display: block;
  margin-bottom: 0.3rem;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--brand-navy);
}

.attendance-sort-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.35rem;
}

.attendance-sort-actions button {
  width: 100%;
  font-size: 0.74rem;
  padding: 0.38rem 0.45rem;
  white-space: nowrap;
}

.attendance-sort-actions button.is-active {
  border-color: var(--brand-navy);
  background: var(--info-soft);
  color: var(--brand-navy);
}

.attendance-sort-week-hint {
  margin: 0 0 0.45rem;
  font-size: 0.68rem;
  line-height: 1.35;
  color: var(--muted);
}

.attendance-sort-week-picker {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin-bottom: 0.4rem;
}

.attendance-sort-week-picker-label {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--brand-navy);
  flex-shrink: 0;
}

.attendance-sort-week-picker select {
  flex: 1;
  min-width: 0;
  font-size: 0.74rem;
  padding: 0.32rem 0.4rem;
}

.admin-pin-dialog {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0;
  max-width: 22rem;
  width: calc(100% - 2rem);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
}

.admin-pin-dialog::backdrop {
  background: rgba(15, 23, 42, 0.45);
}

.admin-pin-dialog form {
  padding: 1.1rem 1.15rem 1rem;
}

.admin-pin-title {
  margin: 0 0 0.35rem;
  font-size: 1.05rem;
}

.admin-pin-message {
  margin: 0 0 0.85rem;
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.45;
}

.admin-pin-actions {
  margin-top: 0.85rem;
  justify-content: flex-end;
}

.leave-adjust-dialog {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0;
  max-width: 24rem;
  width: calc(100% - 2rem);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
}

.leave-adjust-dialog::backdrop {
  background: rgba(15, 23, 42, 0.45);
}

.leave-adjust-dialog form {
  padding: 1.1rem 1.15rem 1rem;
}

.leave-adjust-title {
  margin: 0 0 0.35rem;
  font-size: 1.05rem;
}

.leave-adjust-message {
  margin: 0 0 0.85rem;
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.45;
}

/* What the timeline already planned for these days — a fact to check the
   choice against, so it sits apart from the question without competing. */
.leave-adjust-hint {
  /* Two facts may stack here (timeline plan, then what the row already holds). */
  white-space: pre-line;
  margin: -0.5rem 0 0;
  padding: 0.4rem 0.55rem;
  border-left: 2px solid var(--border-strong);
  background: var(--fill);
  border-radius: 0 4px 4px 0;
  font-size: 0.78rem;
  color: var(--ink-2);
  line-height: 1.4;
}

/* The four categories are the question; "Not now" is the way out of it. They
   sit on separate rows so the dismiss button never reads as a fifth type.
   Equal columns rather than flex: four buttons of one width read as one set of
   choices, and no category is emphasised by being wider than its neighbours. */
.leave-adjust-choices {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.45rem;
  margin-top: 0.85rem;
}

.leave-adjust-choices button {
  min-width: 0;
}

/* Unpaid is the exception among the four: the unpaid slate names it without
   competing with the paid categories for attention. */
.leave-adjust-choices .leave-adjust-unpaid {
  color: var(--leave-unpaid);
}

.leave-adjust-actions {
  margin-top: 0.55rem;
  padding-top: 0.55rem;
  border-top: 1px solid var(--border);
  gap: 0.45rem;
  justify-content: flex-end;
}

.leave-adjust-actions button {
  min-width: 5.5rem;
}

.unsaved-changes-dialog {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0;
  max-width: 26rem;
  width: calc(100% - 2rem);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
}

.unsaved-changes-dialog::backdrop {
  background: rgba(15, 23, 42, 0.45);
}

.unsaved-changes-dialog form {
  padding: 1.1rem 1.15rem 1rem;
}

.unsaved-changes-title {
  margin: 0 0 0.35rem;
  font-size: 1.05rem;
}

.unsaved-changes-message {
  margin: 0 0 0.85rem;
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.45;
}

.unsaved-changes-actions {
  margin-top: 0.85rem;
  flex-wrap: wrap;
  gap: 0.45rem;
  justify-content: flex-end;
}

.unsaved-changes-actions button {
  flex: 1 1 auto;
  min-width: 6.5rem;
}

.tips-other-currency-input {
  width: 100%;
  box-sizing: border-box;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  font-family: var(--font-data, ui-monospace, monospace);
  font-size: 1rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.tips-other-currency-input:focus {
  outline: none;
  border-color: var(--brass);
}

.tips-other-currency-error {
  margin: 0.4rem 0 0;
  font-size: 0.78rem;
  color: var(--error);
}

.finalize-check-dialog {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0;
  max-width: 30rem;
  width: calc(100% - 2rem);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
}

.finalize-check-dialog::backdrop {
  background: rgba(15, 23, 42, 0.45);
}

.finalize-check-dialog form {
  padding: 1.1rem 1.15rem 1rem;
}

.finalize-check-title {
  margin: 0 0 0.35rem;
  font-size: 1.05rem;
}

.finalize-check-message {
  margin: 0 0 0.85rem;
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.45;
}

/* Index of what needs reading, in full ink: the list below scrolls, so a
   second family of findings must be announced before it can be scrolled to. */
.finalize-check-counts {
  margin: 0 0 0.7rem;
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--text);
}

/* The all-clear. It takes the shape of the finding list it replaces, in the
   success tint, so "checked, nothing found" is as visible as a finding would
   have been rather than an empty dialog the manager has to interpret. */
.finalize-check-clear {
  margin: 0 0 0.85rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid color-mix(in srgb, var(--success) 35%, var(--border));
  background: color-mix(in srgb, var(--success) 10%, transparent);
  border-radius: 8px;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--text);
}

/* One scroll for the whole check list, so two families of findings cannot
   stack into a dialog taller than the screen. */
.finalize-check-groups {
  margin: 0 0 0.85rem;
  max-height: 17rem;
  overflow-y: auto;
}

.finalize-check-group + .finalize-check-group {
  margin-top: 0.85rem;
}

.finalize-check-group-title {
  margin: 0 0 0.3rem;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
}

.finalize-check-group .finalize-check-message {
  margin-bottom: 0.4rem;
}

.finalize-check-list {
  margin: 0;
  padding: 0.6rem 0.75rem 0.6rem 1.6rem;
  border: 1px solid color-mix(in srgb, var(--warning) 35%, var(--border));
  background: color-mix(in srgb, var(--warning) 10%, transparent);
  border-radius: 8px;
  font-size: 0.82rem;
  line-height: 1.5;
}

.finalize-check-list li + li {
  margin-top: 0.3rem;
}

.finalize-check-actions {
  margin-top: 0.85rem;
  flex-wrap: wrap;
  gap: 0.45rem;
  justify-content: flex-end;
}

.finalize-check-actions button {
  flex: 1 1 auto;
  min-width: 6.5rem;
}

.staff-profile-dialog {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0;
  max-width: 56rem;
  width: calc(100% - 1.5rem);
  max-height: calc(100vh - 2rem);
  box-shadow: 0 16px 48px rgba(15, 23, 42, 0.2);
}

.staff-profile-dialog::backdrop {
  background: rgba(15, 23, 42, 0.45);
}

.staff-profile-shell {
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 2rem);
}

.staff-profile-header {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 1rem 1.1rem 0.85rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface-raised);
}

.staff-profile-identity {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  flex: 1;
  min-width: 0;
}

.staff-profile-avatar-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}

.staff-profile-avatar {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--fill);
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--border);
}

.staff-profile-photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.staff-profile-initials {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-2);
  user-select: none;
}

.staff-profile-photo-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.25rem;
  max-width: 6.5rem;
}

.staff-profile-photo-btn {
  font-size: 0.65rem;
  padding: 0.2rem 0.4rem;
  line-height: 1.2;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.staff-profile-heading {
  flex: 1;
  min-width: 0;
}

.staff-profile-title {
  margin: 0;
  font-size: 1.2rem;
  line-height: 1.2;
}

.staff-profile-meta {
  margin: 0.2rem 0 0;
  font-size: 0.84rem;
  color: var(--muted);
}

.staff-profile-submeta {
  margin: 0.15rem 0 0;
  font-size: 0.82rem;
  color: var(--muted);
}

.staff-profile-close-btn {
  border: none;
  background: transparent;
  font-size: 1.5rem;
  line-height: 1;
  padding: 0 0.2rem;
  color: var(--muted);
  cursor: pointer;
}

.staff-profile-close-btn:hover {
  color: var(--accent);
}

.staff-profile-body {
  overflow: auto;
  padding: 1rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.staff-profile-columns {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 1rem;
}

.staff-profile-panel {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.85rem;
  background: var(--card);
}

.staff-profile-panel-wide {
  grid-column: 1 / -1;
}

.staff-profile-section-title {
  margin: 0 0 0.65rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.staff-profile-section-title-spaced {
  margin-top: 1rem;
}

.staff-profile-fields {
  display: grid;
  gap: 0.45rem;
}

.staff-profile-fields label {
  margin: 0.35rem 0 0;
  font-size: 0.75rem;
}

.staff-profile-fields input,
.staff-profile-fields textarea,
.staff-profile-panel-wide textarea {
  width: 100%;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.875rem;
}

.staff-profile-vacation-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 0.75rem;
  margin-bottom: 0.65rem;
}

.staff-profile-vacation-header .staff-profile-section-title {
  margin-bottom: 0;
}

.staff-profile-vacation-add-btn {
  font-size: 0.8rem;
  padding: 0.35rem 0.65rem;
  white-space: nowrap;
}

.staff-profile-vacation-add {
  margin-bottom: 0.75rem;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-raised);
}

.staff-profile-vacation-add-fields {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
  gap: 0.5rem 0.75rem;
}

.staff-profile-vacation-add-row-wide {
  grid-column: 1 / -1;
}

.staff-profile-vacation-add-row label {
  display: block;
  margin: 0 0 0.25rem;
  font-size: 0.75rem;
  color: var(--muted);
}

.staff-profile-vacation-add-row input,
.staff-profile-vacation-add-row select {
  width: 100%;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.875rem;
}

.staff-profile-vacation-add-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.65rem;
}

.staff-profile-vacation-calendar {
  margin-top: 0.15rem;
}

.staff-profile-leave-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.staff-profile-leave-toolbar {
  display: flex;
  justify-content: flex-end;
}

.staff-profile-panel-attendance {
  border-color: color-mix(in srgb, var(--brand-navy) 12%, var(--border));
  background: var(--card);
}

.staff-profile-attendance-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.35rem 0.75rem;
  margin-bottom: 0.85rem;
}

.staff-profile-attendance-title {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent);
}

.staff-profile-attendance-month {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: var(--fill);
  border: 1px solid var(--border);
}

.staff-profile-attendance-fields {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.staff-profile-attendance-field label {
  display: block;
  margin: 0 0 0.35rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted);
}

.staff-profile-attendance-field input,
.staff-profile-attendance-field textarea {
  width: 100%;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.875rem;
}

.staff-profile-attendance-period-wrap input[type="date"] {
  max-width: 14rem;
}

/* Attendance spans the row above; the two employment-period panels sit
   side by side underneath — start on the left, end on the right. */
.staff-profile-editors {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 0.85rem;
  align-items: start;
}

.staff-profile-editors > .staff-profile-panel {
  margin: 0;
}

.staff-profile-editors > .staff-profile-panel-attendance {
  grid-column: 1 / -1;
}

@media (max-width: 760px) {
  .staff-profile-editors {
    grid-template-columns: 1fr;
  }
}

.staff-profile-panel-departure,
.staff-profile-panel-employment {
  border-color: color-mix(in srgb, var(--brand-navy) 12%, var(--border));
  background: var(--card);
}

.staff-profile-panel-departure .staff-profile-departure-hint,
.staff-profile-panel-employment .staff-profile-departure-hint {
  margin: -0.35rem 0 0.85rem;
}

.staff-profile-panel-departure select {
  width: 100%;
  max-width: 14rem;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.875rem;
  background: var(--card);
}

.staff-profile-panel-departure input[type="date"],
.staff-profile-panel-employment input[type="date"] {
  max-width: 14rem;
}

.staff-profile-panel-departure input:disabled,
.staff-profile-panel-departure select:disabled,
.staff-profile-panel-employment input:disabled {
  background: var(--fill);
  color: var(--muted);
}

.staff-profile-field-hint {
  margin: 0.35rem 0 0;
  font-size: 0.72rem;
  line-height: 1.4;
  color: var(--muted);
}

.staff-profile-details {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
}

.staff-profile-details summary {
  cursor: pointer;
  padding: 0.55rem 0.75rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
  list-style: none;
  user-select: none;
}

.staff-profile-details summary::-webkit-details-marker {
  display: none;
}

.staff-profile-details summary::before {
  content: '▸ ';
  display: inline-block;
  transition: transform 0.15s ease;
}

.staff-profile-details[open] summary::before {
  transform: rotate(90deg);
}

.staff-profile-details-body {
  padding: 0 0.75rem 0.75rem;
}

.staff-profile-panel-nested {
  padding: 0.65rem 0.7rem;
  background: var(--surface-raised);
}

.staff-profile-columns-compact {
  gap: 0.65rem;
}

.staff-profile-fields-compact {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.35rem 0.65rem;
}

.staff-profile-fields-compact .staff-profile-notes-label,
.staff-profile-fields-compact #staff-profile-notes {
  grid-column: 1 / -1;
}

.staff-profile-fields-compact label {
  margin-top: 0.15rem;
}

.staff-profile-documents,
.staff-profile-comment-history {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.staff-profile-document,
.staff-profile-history-item {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.6rem;
  background: var(--surface-raised);
}

.staff-profile-document-name,
.staff-profile-history-month {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
}

.staff-profile-document-sub {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.75rem;
  color: var(--muted);
}

/* Staff profile — annual vacation mini-calendars */
.spvc-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 0.75rem;
  margin-bottom: 0.65rem;
}

.spvc-year-nav {
  display: flex;
  align-items: baseline;
  gap: 0.65rem;
  flex-wrap: wrap;
}

.spvc-year-label {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--accent);
  line-height: 1.2;
}

.spvc-filter-caption {
  display: block;
  margin-bottom: 0.2rem;
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.spvc-filter-label--year {
  flex: 0 0 5.5rem;
  max-width: 6rem;
}

.spvc-year-controls {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.spvc-nav-btn {
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--accent);
  border-radius: 6px;
  padding: 0.2rem 0.45rem;
  font-size: 0.78rem;
  line-height: 1.2;
  cursor: pointer;
}

.spvc-nav-btn:hover {
  border-color: var(--border-strong);
  background: var(--surface-raised);
}

.spvc-nav-btn.spvc-today {
  font-weight: 600;
}

.spvc-filter-label {
  margin: 0;
  flex: 1 1 10rem;
  max-width: 14rem;
}

.spvc-filter {
  width: 100%;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.75rem;
  background: var(--card);
  color: var(--accent);
}

.spvc-empty-year {
  margin: 0 0 0.5rem;
}

.spvc-month-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.85rem 0.65rem;
}

.spvc-month-grid--window {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.spvc-month {
  min-width: 0;
}

.spvc-month-name {
  margin: 0 0 0.35rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--ink);
}

.spvc-month-dow {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
  margin-bottom: 0.2rem;
}

.spvc-dow {
  text-align: center;
  font-size: 0.58rem;
  font-weight: 600;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.spvc-dow--weekend {
  color: var(--warning);
}

.spvc-month-weeks {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.spvc-week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
  position: relative;
  min-height: calc(1.15rem + var(--spvc-bar-rows, 1) * 0.42rem);
}

.spvc-day {
  position: relative;
  z-index: 1;
  min-height: 1.15rem;
  padding: 0.1rem 0.05rem 0.5rem;
  text-align: center;
  border-radius: 4px;
  background: var(--card);
}

.spvc-day--pad {
  background: transparent;
  min-height: 0;
  padding: 0;
}

.spvc-day--weekend {
  background: var(--surface-raised);
}

.spvc-day-num {
  font-size: 0.62rem;
  line-height: 1.1;
  color: var(--ink-2);
  font-weight: 500;
}

.spvc-week-bars {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.12rem;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
  height: calc(var(--spvc-bar-rows, 1) * 0.38rem);
  pointer-events: none;
  z-index: 2;
}

.spvc-bar {
  align-self: end;
  height: 0.34rem;
  margin: 0 1px;
  border-radius: 999px;
  transform: translateY(calc(var(--bar-track, 0) * -0.36rem));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--card) 35%, transparent) inset;
}

.spvc-bar--tentative {
  box-sizing: border-box;
}

.spvc-bar--unpaid {
  background-color: var(--ink-2);
}

.spvc-legend {
  margin-bottom: 0.55rem;
}

.spvc-layout {
  display: block;
}

.spvc-main {
  min-width: 0;
}

.spvc-recap {
  margin-bottom: 0.75rem;
  border: 1px solid color-mix(in srgb, var(--accent) 22%, var(--border));
  border-radius: 10px;
  padding: 0.7rem 0.8rem;
  background: var(--info-soft);
}

.spvc-recap-header {
  margin-bottom: 0.55rem;
}

.spvc-recap-title {
  margin: 0;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--accent);
}

.spvc-recap-source {
  margin: 0.2rem 0 0;
  font-size: 0.68rem;
  color: var(--muted);
}

.spvc-recap-metrics {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.45rem;
  margin-bottom: 0.55rem;
}

.spvc-metric {
  padding: 0.45rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: color-mix(in srgb, var(--card) 85%, transparent);
}

.spvc-metric--pending {
  border-color: color-mix(in srgb, var(--accent) 35%, var(--border));
  background: var(--card);
}

.spvc-metric-label {
  display: block;
  font-size: 0.64rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.spvc-metric-value {
  display: block;
  margin-top: 0.15rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.spvc-metric--pending .spvc-metric-value {
  color: var(--accent);
}

.spvc-metric-hint {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.62rem;
  color: var(--muted);
  line-height: 1.3;
}

.spvc-recap-list--compact {
  padding-top: 0.45rem;
  border-top: 1px solid var(--border);
}

.spvc-recap-list {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.spvc-recap-row {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  font-size: 0.72rem;
}

.spvc-recap-row dt {
  margin: 0;
  color: var(--muted);
}

.spvc-recap-row dd {
  margin: 0;
  font-weight: 600;
  color: var(--accent);
}

.spvc-recap-row--highlight {
  padding-bottom: 0.35rem;
  margin-bottom: 0.15rem;
  border-bottom: 1px solid var(--border);
}

.spvc-recap-row--highlight dd {
  color: var(--accent);
}

.spvc-day-icon {
  position: absolute;
  left: 0.05rem;
  bottom: 0.05rem;
  font-size: 0.48rem;
  line-height: 1;
  pointer-events: none;
}

@media (max-width: 900px) {
  .spvc-month-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .staff-profile-attendance-grid {
    grid-template-columns: 1fr;
  }

  .staff-profile-fields-compact {
    grid-template-columns: 1fr;
  }

  .spvc-recap-metrics {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 520px) {
  .spvc-month-grid,
  .spvc-month-grid--window {
    grid-template-columns: 1fr;
  }

  .spvc-filter-label {
    max-width: none;
    flex-basis: 100%;
  }

  .staff-profile-columns {
    grid-template-columns: 1fr;
  }
}

.staff-profile-document {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.65rem;
}

.staff-profile-document-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.staff-profile-doc-link,
.staff-profile-doc-delete {
  font-size: 0.75rem;
  padding: 0.25rem 0.5rem;
}

.staff-profile-upload {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
  display: grid;
  gap: 0.4rem;
}

.staff-profile-upload-row {
  display: grid;
  gap: 0.25rem;
}

.staff-profile-history-text {
  margin: 0.35rem 0 0;
  font-size: 0.82rem;
  line-height: 1.45;
  white-space: pre-wrap;
}

.staff-profile-empty {
  margin: 0;
  font-size: 0.82rem;
  color: var(--muted);
}

.staff-profile-footer {
  padding: 0.75rem 1.1rem 1rem;
  border-top: 1px solid var(--border);
  justify-content: flex-end;
}

/* A save in flight on an already-filled dialog: the content is still valid, so
   it stays legible and only stops responding. */
.staff-profile-dialog.is-busy {
  pointer-events: none;
  opacity: 0.72;
}

/* Waiting for a member's data on a freshly-opened dialog. There is nothing to
   read yet, so the body is held blank at the height a loaded profile occupies
   (~62rem, measured) — the dialog no longer opens small and then jumps. No
   shimmer: DESIGN.md, Motion. */
.staff-profile-dialog.is-pending {
  pointer-events: none;
}

.staff-profile-dialog.is-pending .staff-profile-shell {
  min-height: min(62rem, calc(100vh - 2rem));
}

.staff-profile-dialog.is-pending .staff-profile-body > * {
  visibility: hidden;
}

.staff-profile-dialog.is-pending .staff-profile-body::before {
  content: 'Loading…';
  display: block;
  padding: 2rem 0;
  text-align: center;
  font-family: var(--font-data);
  font-size: var(--text-sm);
  color: var(--ink-3);
}

.attendance-grid .grid-staff-name {
  display: inline;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--accent);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent) 35%, transparent);
  text-underline-offset: 2px;
  cursor: pointer;
}

.attendance-grid .grid-staff-name:hover {
  text-decoration-color: var(--accent);
}

.attendance-grid .grid-staff-name:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

.attendance-grid .grid-staff-name-cell {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  flex-wrap: wrap;
  max-width: 100%;
}

/* Row flags — a comment written on the month, a departure landing in it.
   Neutral ink on purpose: they inform, they do not alarm. */
.attendance-grid .grid-row-flag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: var(--r-sm);
  background: none;
  line-height: 0;
  color: var(--ink-3);
  cursor: pointer;
}

.attendance-grid .grid-row-flag-comment {
  color: var(--ink-2);
}

.attendance-grid .grid-row-flag-departure {
  color: var(--ink);
}

.attendance-grid .grid-row-flag:hover {
  color: var(--accent);
}

.attendance-grid .grid-row-flag:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.attendance-grid tr.grid-row-highlight td {
  background: var(--brass-soft);
  transition: background 0.4s ease;
}

@media (max-width: 720px) {
  .staff-profile-columns {
    grid-template-columns: 1fr;
  }
}

.attendance-grid .admin-select-shell {
  display: block;
  width: 100%;
  cursor: pointer;
}

.attendance-grid .admin-select-shell select:disabled {
  opacity: 1;
  color: inherit;
  -webkit-text-fill-color: inherit;
  cursor: pointer;
  pointer-events: none;
}

@media (max-width: 720px) {
  body:has(.attendance-page #editor-section:not(.hidden)) .attendance-page {
    padding: 0.35rem 0.45rem 0.45rem;
  }

  .attendance-command-row {
    flex-direction: column;
    align-items: stretch;
  }

  .attendance-command-actions,
  .attendance-command-notices {
    justify-content: flex-start;
  }

  .attendance-command-primary > #month-select {
    flex: 1;
    max-width: none;
  }

  .attendance-grid-search-control {
    flex: 1 1 8rem;
  }

  .attendance-grid-search-input {
    flex: 1;
    width: auto;
  }
}

@media (max-width: 768px) {
  body:has(.attendance-page #editor-section:not(.hidden)) .navbar {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
  }

  body:has(.attendance-page #editor-section:not(.hidden)) .navbar-links {
    flex: 1 1 auto;
    justify-content: flex-end;
  }
}

.attendance-grid-card {
  padding: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  width: 100%;
  max-width: 100%;
}

.attendance-grid-search-empty {
  margin: 0;
  padding: 0.45rem 0.85rem;
  font-size: 0.8125rem;
  color: var(--muted);
  border-bottom: 1px solid var(--border);
  background: var(--warning-soft);
}

/* Comments & departures menu — the command bar's middle zone, so the
   sheet keeps every pixel of vertical space for crew rows. Summary = one icon
   + count per kind, counts in brass mono (the house style for counts, never a
   red badge). Body = who is concerned, clickable, plus an optional filter. */
.attendance-flags-menu summary {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.attendance-flags-count {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  color: var(--muted);
}

.attendance-flags-count b {
  font-family: var(--font-data);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--brass);
}

/* The panel hangs from the whole command bar, centred on the page, not from
   its small summary button: wide enough that a comment reads on one or two
   lines instead of five (owner feedback 2026-10-15). It still scrolls when a
   month carries many flags. */
.attendance-command-bar {
  position: relative;
}

.attendance-flags-menu {
  position: static;
}

.attendance-flags-body {
  left: 50%;
  right: auto;
  top: calc(100% + 0.35rem);
  transform: translateX(-50%);
  gap: 0;
  width: min(46rem, calc(100vw - 2rem));
  max-height: min(36rem, calc(100vh - 10rem));
  overflow-y: auto;
  padding: 0.85rem 1rem;
  border-radius: var(--r-lg);
  box-shadow: 0 12px 32px rgba(27, 36, 50, 0.14);
}

.attendance-flags-section + .attendance-flags-section {
  margin-top: 0.65rem;
  padding-top: 0.65rem;
  border-top: 1px solid var(--border);
}

.attendance-flags-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0 0.5rem 0.35rem;
}

.attendance-flags-section-head h3 {
  margin: 0;
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ink-2);
}

.attendance-flags-filter {
  padding: 0;
  border: none;
  background: none;
  font-family: inherit;
  font-size: var(--text-xs);
  color: var(--accent);
  cursor: pointer;
  white-space: nowrap;
}

/* The menu body stretches its buttons to full width; this one is a link. */
.attendance-flags-body .attendance-flags-filter {
  width: auto;
}

.attendance-flags-filter:hover {
  text-decoration: underline;
}

.attendance-flags-filter[aria-pressed='true'] {
  font-weight: 500;
}

.attendance-flags-item {
  display: grid;
  grid-template-columns: minmax(7rem, 10rem) 1fr; /* name, then what it is about */
  align-items: baseline;
  justify-items: start; /* the global button rule centers its children */
  gap: 0.1rem 1rem;
  width: 100%;
  padding: 0.4rem 0.5rem;
  border: none;
  border-radius: var(--r-sm);
  background: none;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}

.attendance-flags-item:hover {
  background: var(--surface-raised);
}

.attendance-flags-item-name {
  font-size: var(--text-base);
  font-weight: 500;
  color: var(--text);
}

.attendance-flags-item-detail {
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--muted);
}

@media (max-width: 720px) {
  .attendance-flags-item {
    grid-template-columns: 1fr;
  }
}

.attendance-flags-hint {
  margin: 0.65rem 0 0;
  padding: 0.55rem 0.5rem 0;
  border-top: 1px solid var(--border);
  font-size: var(--text-xs);
  line-height: 1.4;
  color: var(--ink-3);
}

.attendance-grid-wrap {
  flex: 1;
  min-height: 0;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  background: var(--card);
}

.attendance-grid {
  width: 100%;
  min-width: max-content;
  table-layout: auto;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 0.85rem;
  --sticky-col-1-width: 5rem;
  --sticky-col-2-width: 5.5rem;
  --week-yin-width: 4.4rem;
  --week-days-width: 2.65rem;
  --week-pair-width: calc(var(--week-yin-width) + var(--week-days-width));
  --col-leave-width: 3.1rem;
  --col-calc-width: 4.75rem;
  --col-manual-width: 4.75rem;
  --grid-value-font-size: 0.62rem;
  --grid-value-line-height: 1.25;
}

.attendance-grid th,
.attendance-grid td {
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: 0;
  vertical-align: middle;
}

.attendance-grid thead th {
  background: var(--fill);
  padding: 0.35rem 0.25rem;
  font-size: 0.72rem;
}

/* Sticky header rows — z-index below corner/name columns */
.attendance-grid thead tr:first-child th:not(.sticky-col) {
  position: sticky;
  top: 0;
  z-index: 2;
}

/* Corner cells (NAME + DESIGNATION): sticky top + left, always on top when scrolling */
.attendance-grid thead .sticky-col {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--fill);
  box-shadow: 2px 0 5px rgba(15, 23, 42, 0.08);
}

.attendance-grid th.col-data {
  font-size: 0.62rem;
  line-height: 1.15;
  padding: 0.25rem 0.12rem;
  white-space: normal;
  text-align: center;
  font-weight: 600;
  vertical-align: middle;
  hyphens: auto;
}

.attendance-grid th.col-leave,
.attendance-grid td.cell-leave {
  width: var(--col-leave-width);
  min-width: var(--col-leave-width);
  max-width: var(--col-leave-width);
}

/* Unpaid sits beside the three paid columns but is not one of them — the slate
   figures carry that on their own. No extra rule down its left edge: every cell
   already draws a border-right, so adding one here stacked two lines and read
   as a heavier separator than the rest of the grid. */
.attendance-grid th.col-leave-unpaid {
  color: var(--leave-unpaid);
}

.attendance-grid td.cell-leave-unpaid input {
  color: var(--leave-unpaid);
}

.attendance-grid th.col-calc,
.attendance-grid td.cell-calc {
  width: var(--col-calc-width);
  min-width: var(--col-calc-width);
  max-width: var(--col-calc-width);
}

.attendance-grid th.col-manual,
.attendance-grid td.cell-manual {
  width: var(--col-manual-width);
  min-width: var(--col-manual-width);
  max-width: var(--col-manual-width);
}

.attendance-grid .sticky-col {
  position: sticky;
  left: 0;
  background: var(--card);
  padding: 0.35rem 0.5rem;
  width: max-content;
  white-space: nowrap;
}

.attendance-grid tbody .sticky-col {
  z-index: 3;
  background: var(--card);
}

/* The grid always holds a row per crew member; the search and the
   comments/departures filter hide rows rather than rebuild the table. */
.attendance-grid tbody tr.is-filtered-out {
  display: none;
}

.attendance-grid tbody tr:hover td {
  background: var(--fill);
}

.attendance-grid tbody tr:hover .sticky-col {
  background: var(--fill);
}

.attendance-grid tbody .sticky-col-2 {
  box-shadow: 2px 0 5px rgba(15, 23, 42, 0.06);
}

.attendance-grid .sticky-col-1 {
  width: max-content;
  min-width: 0;
}

.attendance-grid .sticky-col-2 {
  left: var(--sticky-col-1-width);
  width: max-content;
  min-width: 0;
}

.staff-profile-attendance-period-wrap {
  margin-bottom: 1rem;
}

.staff-profile-attendance-period-wrap input[type="date"] {
  width: 100%;
  max-width: 14rem;
}

.staff-profile-field-hint {
  font-size: 0.8rem;
  color: var(--muted);
  margin: 0.35rem 0 0;
  line-height: 1.4;
}

.add-staff-month-hint {
  font-size: 0.8rem;
  color: var(--muted);
  margin: -0.25rem 0 0.75rem;
}

.attendance-grid .staff-designation {
  font-size: 0.75rem;
  color: var(--muted);
  padding: 0.2rem 0.25rem;
}

.attendance-grid select.grid-designation,
.attendance-grid select.grid-dive-flag,
.attendance-grid select.grid-vessel {
  width: 100%;
  max-width: 100%;
  font-size: 0.68rem;
  font-weight: 600;
  border: 1px solid transparent;
  background-color: transparent;
  color: inherit;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath fill='%2394a3b8' d='M1 1l4 4 4-4' stroke='%2394a3b8' stroke-width='0.5' fill-rule='evenodd'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.1rem center;
  background-size: 0.42rem 0.26rem;
  padding: 0.18rem 0.5rem 0.18rem 0.06rem;
}

.attendance-grid select.grid-designation,
.attendance-grid select.grid-dive-flag {
  text-transform: uppercase;
}

.attendance-grid select.grid-vessel {
  text-align: center;
  /* Safari ignores text-align for the closed value of a select — needs text-align-last */
  text-align-last: center;
  font-weight: 500;
  text-transform: none;
  font-size: var(--grid-value-font-size);
  line-height: var(--grid-value-line-height);
  border-radius: 3px;
}

.attendance-grid select.grid-dive-flag {
  text-align: center;
  text-align-last: center;
  padding-left: 0.5rem;
  padding-right: 0.5rem;
}

.attendance-grid select.grid-vessel.vessel-yin {
  background-color: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

.attendance-grid select.grid-vessel.vessel-yang {
  background-color: var(--brass-soft);
  color: var(--yang-fg);
  font-weight: 600;
}

.attendance-grid select.grid-vessel.vessel-no-days {
  font-style: italic;
  font-weight: 400;
}

.attendance-grid select.grid-vessel.vessel-no-days.vessel-yin {
  color: var(--ink-3);
}

.attendance-grid select.grid-vessel.vessel-no-days.vessel-yang {
  color: var(--brass);
}

/* Week slot with no date: the column is inert — no vessel, no caret to invite a pick */
.attendance-grid select.grid-vessel:disabled {
  color: var(--border-strong);
  opacity: 1;
  cursor: default;
  background-image: none;
}

.attendance-grid select.grid-designation:focus,
.attendance-grid select.grid-dive-flag:focus,
.attendance-grid select.grid-vessel:focus {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  background: var(--card);
}

.attendance-grid td.cell-ab-editable {
  padding: 0.1rem;
  text-align: center;
}

.week-header-inner {
  display: flex;
  flex-direction: column;
  gap: 0.28rem;
  min-width: 0;
  width: 100%;
  max-width: var(--week-pair-width);
  padding: 0.05rem 0;
}

.week-tours-stack {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

.week-tour-row {
  display: flex;
  align-items: center;
  gap: 0.28rem;
  min-width: 0;
  padding: 0.12rem 0.28rem 0.14rem;
  border-radius: 4px;
  border: 1px solid rgba(15, 23, 42, 0.08);
  background: var(--surface-raised);
}

.week-tour-row.week-tour-yang {
  border-left: 2px solid var(--brand-gold);
  background: var(--brass-soft);
}

.week-tour-row.week-tour-yin {
  border-left: 2px solid var(--accent);
  background: var(--accent-soft);
}

.week-tour-row.is-set .week-tour-input {
  font-weight: 600;
  color: inherit;
}

.week-tour-row.is-maintenance {
  background: var(--brass-soft);
  border-color: #e0d3ac;
}

.week-tour-row.is-maintenance .week-tour-input {
  color: var(--warning);
  font-weight: 600;
  letter-spacing: 0.04em;
}

.week-tour-chip-badge {
  flex: 0 0 auto;
  min-width: 1.85rem;
  font-size: 0.58rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1;
  text-align: left;
}

.week-tour-yang .week-tour-chip-badge {
  color: var(--brass);
}

.week-tour-yin .week-tour-chip-badge {
  color: var(--accent);
}

.week-tour-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  text-align: center;
  font-size: 0.72rem;
  font-weight: 500;
  padding: 0.06rem 0.04rem;
  color: var(--text);
}

.week-tour-input::placeholder {
  color: var(--border-strong);
  font-weight: 400;
}

.week-tour-input:focus {
  outline: none;
  background: color-mix(in srgb, var(--card) 85%, transparent);
  border-radius: 2px;
}

.week-date-chip {
  display: block;
  position: relative;
  width: 100%;
  padding: 0.1rem 0.2rem;
  border-radius: 4px;
  border: 1px dashed rgba(15, 23, 42, 0.12);
  background: color-mix(in srgb, var(--card) 55%, transparent);
}

.week-date-chip.is-set {
  border-style: solid;
  border-color: rgba(4, 47, 102, 0.15);
  background: var(--card);
}

.week-date-chip .week-start {
  display: block;
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  border: none;
  background: transparent;
  font-size: 0.68rem;
  font-weight: 500;
  line-height: 1.25;
  padding: 0.08rem 0;
  color: var(--text);
  cursor: pointer;
}

.week-date-chip .week-start::-webkit-datetime-edit {
  padding: 0;
}

/* An empty week slot must read as empty. Safari paints today's date in grey as
   the placeholder of a blank date input, so the slot looks like a real week;
   Chrome paints dd/mm/yyyy. Blank the native text in both and show our own —,
   matching the tour inputs. Typing restores the native text. */
.week-date-chip:not(.is-set) .week-start {
  color: transparent;
}

.week-date-chip:not(.is-set)::after {
  content: '—';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.68rem;
  line-height: 1.25;
  color: var(--border-strong);
  pointer-events: none;
}

.week-date-chip:not(.is-set):focus-within .week-start {
  color: var(--text);
}

.week-date-chip:not(.is-set):focus-within::after {
  content: none;
}

.week-date-chip .week-start::-webkit-calendar-picker-indicator {
  margin: 0;
  padding: 0;
  cursor: pointer;
  opacity: 0.75;
}

.week-date-chip .week-start:focus {
  outline: none;
}

.attendance-grid th.week-header {
  width: var(--week-pair-width);
  min-width: var(--week-pair-width);
  max-width: var(--week-pair-width);
  box-sizing: border-box;
}

.attendance-grid th.week-header.week-slot-empty,
.attendance-grid td.week-slot-empty {
  background: var(--fill);
}

.attendance-grid thead th.week-slot-empty {
  background: var(--border);
}

.attendance-grid td.week-slot-empty input {
  color: var(--muted);
}

.attendance-grid td.week-slot-empty input:not(:placeholder-shown),
.attendance-grid td.week-slot-empty input:focus {
  color: inherit;
}

.week-label {
  display: flex;
  flex-direction: column;
  gap: 0.08rem;
  font-weight: 600;
  font-size: 0.65rem;
  text-transform: none;
  letter-spacing: 0;
}

.week-label input {
  font-weight: 500;
  padding: 0.15rem 0.2rem;
  font-size: 0.72rem;
  min-width: 0;
  max-width: 100%;
}

.week-label input[type="date"] {
  font-size: 0.68rem;
}

.attendance-grid input[type="text"],
.attendance-grid input[type="number"],
.attendance-grid input[type="date"] {
  width: 100%;
  border: none;
  background: transparent;
  padding: 0.35rem 0.4rem;
  border-radius: 0;
}

/* Excel-style: type numbers manually, no stepper arrows */
.attendance-grid input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}

.attendance-grid input[type="number"]::-webkit-outer-spin-button,
.attendance-grid input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.attendance-grid .week-label input {
  padding: 0.15rem 0.2rem;
  font-size: 0.72rem;
}

.attendance-grid .week-label input[type="date"] {
  font-size: 0.68rem;
}

.attendance-grid input:focus {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  background: var(--card);
}

.cell-vessel {
  width: var(--week-yin-width);
  min-width: var(--week-yin-width);
  max-width: var(--week-yin-width);
}

.attendance-grid .cell-vessel input,
.attendance-grid .cell-vessel select.grid-vessel {
  text-align: center;
  font-weight: 500;
  padding: 0.18rem 0.5rem 0.18rem 0.06rem;
  letter-spacing: 0;
}

.attendance-grid .cell-days input,
.attendance-grid .cell-days input.grid-days {
  text-align: center;
  padding: 0.22rem 0.08rem;
}

.attendance-grid .cell-days input.grid-days.is-days-partial {
  color: var(--muted);
  font-weight: 400;
  font-size: var(--grid-value-font-size);
  line-height: var(--grid-value-line-height);
}

.attendance-grid .cell-days input.grid-days.is-days-full {
  color: var(--text);
  font-weight: 600;
  font-size: var(--grid-value-font-size);
  line-height: var(--grid-value-line-height);
}

.cell-days {
  width: var(--week-days-width);
  min-width: var(--week-days-width);
  max-width: var(--week-days-width);
}

.cell-calc,
.col-calc {
  background: var(--surface-raised);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.attendance-grid .calc-readonly {
  padding: 0.22rem 0.1rem;
  color: var(--muted);
}

.attendance-grid .cell-leave input,
.attendance-grid .cell-manual input {
  width: 100%;
  min-width: 0;
  padding: 0.22rem 0.1rem;
  text-align: center;
}

.attendance-grid .cell-manual input {
  padding: 0.22rem 0.12rem;
}

/* Same typography for every numeric / vessel value in the grid body */
.attendance-grid td.calc-readonly,
.attendance-grid td.cell-calc,
.attendance-grid td.cell-vessel select.grid-vessel,
.attendance-grid td.cell-days input,
.attendance-grid td.cell-leave input,
.attendance-grid td.cell-manual input,
.attendance-grid td.cell-ab-editable select.grid-dive-flag {
  font-size: var(--grid-value-font-size);
  line-height: var(--grid-value-line-height);
  font-variant-numeric: tabular-nums;
}

.save-status.is-dirty {
  color: var(--warning);
  font-weight: 600;
}

/* Weekly tips editor */
body.tips-editor-open {
  overflow: hidden;
}

.tips-page-main {
  padding-top: 0.35rem;
  padding-bottom: 0.75rem;
}

.tips-page #tips-workspace {
  display: block;
}

.tips-editor {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  overflow: hidden;
}

.tips-editor--page {
  position: static;
  inset: auto;
  z-index: auto;
  display: block;
  flex: none;
  min-height: auto;
  overflow: visible;
}

/* Standalone page: scroll the document, not a nested pane (wheel over cards/tables). */
body.tips-page .tips-editor-body {
  flex: none;
  overflow: visible;
  overscroll-behavior: auto;
  min-height: auto;
}

.tips-editor.hidden {
  display: none;
}

.tips-editor .card {
  padding: 0.6rem 0.75rem;
}

.tips-editor-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.65rem 1rem;
  margin: 0.5rem 0.75rem 0;
  flex-shrink: 0;
}

.tips-editor-title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.25;
}

.tips-editor-subtitle,
.tips-editor-meta {
  margin: 0.2rem 0 0;
  color: var(--muted);
  font-size: 0.78rem;
  line-height: 1.35;
}

.tips-editor-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.3rem 0.45rem;
  flex-shrink: 0;
}

.tips-editor-actions button {
  padding: 0.32rem 0.65rem;
  font-size: 0.78rem;
}

.tips-editor-actions .save-status {
  font-size: 0.74rem;
  white-space: nowrap;
  padding-right: 0.15rem;
}

.tips-editor-body {
  flex: 1;
  overflow: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 0.5rem 0.75rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.tips-editor-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.55rem;
  align-items: start;
  min-width: 0;
}

.tips-editor-sources {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  min-width: 0;
}

@media (min-width: 960px) {
  .tips-editor-main {
    grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.1fr);
  }

  .tips-staff-card {
    grid-column: 2;
    grid-row: 1;
  }

  .tips-editor-sources {
    grid-column: 1;
    grid-row: 1;
  }
}

.tips-controls-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem 0.75rem;
  align-items: flex-end;
}

.tips-controls-row label {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  margin: 0;
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.tips-controls-row select {
  min-width: 9rem;
  width: auto;
  padding: 0.3rem 0.5rem;
  font-size: 0.8125rem;
  font-weight: 500;
  text-transform: none;
  letter-spacing: normal;
}

.tips-controls-row > button {
  padding: 0.32rem 0.7rem;
  font-size: 0.8125rem;
}

.tips-summary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7.25rem, 1fr));
  gap: 0.35rem;
  margin-top: 0.55rem;
  padding-top: 0.55rem;
  border-top: 1px solid var(--border);
}

.tips-summary-grid > div {
  padding: 0.3rem 0.45rem;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: 6px;
}

.tips-summary-grid strong {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.875rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
}

.tips-summary-label {
  display: block;
  font-size: 0.64rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  line-height: 1.2;
}

.tips-panel h3,
.tips-staff-card h3,
.tips-exchange-card h3 {
  margin: 0 0 0.35rem;
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.3;
}

.tips-staff-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.tips-staff-heading-title {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.tips-staff-heading-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}

.tips-staff-heading-actions button {
  font-size: 0.72rem;
  padding: 0.2rem 0.55rem;
}

.tips-staff-edit-hint {
  margin: 0 0 0.35rem;
  font-size: 0.72rem;
  color: var(--muted);
  line-height: 1.35;
}

/* A week this account reads but does not enter: whose it is, said once. */
.tips-edit-notice {
  margin: 0 0 0.45rem;
  padding: 0.4rem 0.55rem;
  border-radius: 4px;
  background: var(--info-soft);
  color: var(--info);
  font-size: 0.72rem;
  line-height: 1.35;
}

.tips-roster-notice {
  margin: 0 0 0.45rem;
  padding: 0.4rem 0.55rem;
  border-radius: 4px;
  background: var(--warning-soft);
  color: var(--warning);
  font-size: 0.72rem;
  line-height: 1.35;
}

.tips-staff-days-input {
  width: 3.25rem;
  max-width: 100%;
  padding: 0.15rem 0.3rem;
  font-size: 0.8rem;
  text-align: right;
}

.tips-staff-actions-col {
  width: 2rem;
  padding-left: 0.15rem !important;
  padding-right: 0.15rem !important;
  text-align: center;
  vertical-align: middle;
}

.tips-remove-staff-btn {
  min-width: 1.6rem;
  padding: 0.1rem 0.35rem;
  line-height: 1.2;
}

.tips-staff-count-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.08rem 0.45rem;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--muted);
  background: var(--fill);
  border: 1px solid var(--border);
  letter-spacing: normal;
  text-transform: none;
}

.tips-panel-cash-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.35rem;
}

.tips-panel-cash .tips-panel-cash-header h3 {
  margin: 0;
}

.tips-cash-total {
  font-size: 0.85rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tips-exchange-table {
  width: auto;
  min-width: 16rem;
  max-width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.tips-exchange-table th,
.tips-exchange-table td {
  border: 1px solid var(--border);
  padding: 0.5rem 0.7rem;
  text-align: left;
  vertical-align: middle;
}

.tips-exchange-table thead th {
  background: var(--fill);
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}

.tips-rate-input {
  width: 7rem;
  min-width: 0;
}

.tips-rate-fixed {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.tips-currency-select {
  width: 100%;
  min-width: 4.5rem;
}

.tips-rate-warning {
  margin: 1rem 0 0;
  padding: 0.55rem 0.75rem;
  border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--warning, var(--warning)) 35%, var(--border));
  background: color-mix(in srgb, var(--warning, var(--warning)) 12%, transparent);
  color: var(--text);
  font-size: 0.8rem;
  line-height: 1.45;
}

.tips-rate-warning.hidden {
  display: none;
}

.tips-cabin-table,
.tips-staff-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8125rem;
}

.tips-cabin-table th,
.tips-staff-table th,
.tips-cabin-table td,
.tips-staff-table td {
  border: 1px solid var(--border);
  padding: 0.2rem 0.35rem;
  text-align: left;
  vertical-align: middle;
}

.tips-cabin-table thead th,
.tips-staff-table thead th {
  background: var(--fill);
  padding: 0.28rem 0.35rem;
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
  white-space: nowrap;
}

.tips-cabin-table td:has(input),
.tips-cabin-table td:has(select) {
  padding: 0.15rem 0.3rem;
}

.add-staff-month-dialog {
  /* A modal must never hand its scroll to the page behind it. Without this,
     a wheel that reaches either end of a tall dialog carries on into whatever
     scrolls underneath (on Immigration and Attendance that is the sheet), and
     because the browser latches a gesture to the target it picked, the dialog
     then sits frozen for the rest of the gesture: it reads as "scrolling has
     stopped working". Clicking a field is what usually sets it off, since
     bringing the field into view parks the dialog at one end of its scroll.
     Same reasoning as `.staff-profile-edit-dialog`, applied to the shared
     recipe so every dialog built on it is covered. */
  overscroll-behavior: contain;
  max-width: 28rem;
  border: none;
  border-radius: 12px;
  padding: 1.25rem 1.35rem;
}

.add-staff-month-dialog::backdrop {
  background: rgba(15, 23, 42, 0.45);
}

.add-staff-month-title {
  margin: 0 0 0.35rem;
  font-size: 1.1rem;
}

.add-staff-month-hint,
.add-staff-month-empty {
  margin: 0 0 0.85rem;
  font-size: 0.8125rem;
  color: var(--muted);
  line-height: 1.45;
}

.add-staff-month-dialog label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.8125rem;
  font-weight: 600;
}

.add-staff-month-dialog select,
.add-staff-month-dialog input[type="text"],
.add-staff-month-dialog input[type="month"] {
  width: 100%;
  margin-bottom: 0.75rem;
  box-sizing: border-box;
}

.add-staff-month-actions {
  margin-top: 0.25rem;
}

.tips-cabin-table-footer {
  margin-top: 0.35rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.tips-cabin-table .tips-recipient-select {
  min-width: 6.5rem;
}

.tips-cc-split {
  font-size: 0.75rem;
  color: var(--text-secondary, var(--ink-2));
  font-variant-numeric: tabular-nums;
}

.tips-add-row-btn {
  padding: 0.25rem 0.55rem;
  font-size: 0.75rem;
}

.tips-cabin-actions-col {
  width: 1.85rem;
  padding-left: 0.15rem !important;
  padding-right: 0.15rem !important;
  text-align: center;
  vertical-align: middle;
}

.tips-remove-row-btn {
  min-width: 1.5rem;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  line-height: 1;
  font-size: 1rem;
}

.tips-cabin-input.tips-equ-usd-synced,
.tips-equ-usd-synced.tips-cabin-input {
  background: var(--surface-muted, var(--canvas));
  color: var(--text-secondary, var(--ink-2));
}

.tips-cabin-input,
.tips-inline-input,
.tips-carried-input,
.tips-rate-input,
.tips-cash-input,
.tips-currency-select {
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  padding: 0.25rem 0.4rem;
  font-size: 0.8125rem;
  border-radius: 5px;
}

.tips-carried-input,
.tips-base-amount-input {
  margin-top: 0.1rem;
}

.tips-summary-editable {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.tips-summary-hint {
  font-size: 0.66rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
}

.tips-cash-inline {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 0.3rem 0.4rem;
}

.tips-cash-inline label {
  display: flex;
  flex-direction: column;
  gap: 0.12rem;
  margin: 0;
  font-size: 0.64rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.tips-cash-inline .tips-cash-input {
  padding: 0.2rem 0.35rem;
  font-size: 0.78rem;
}

.tips-staff-table-wrap {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
}

.tips-staff-table {
  margin: 0;
}

.tips-staff-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  box-shadow: 0 1px 0 var(--border);
}

/* On the standalone tips page the document scrolls, so this head sticks to the
   viewport and has to start below the navbar. In the full-screen editor the
   navbar is covered and the scroll container is .tips-editor-body, where top: 0
   is already right. */
.tips-editor--page .tips-staff-table thead th {
  top: var(--navbar-h, 52px);
}

.tips-staff-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.tips-staff-table td.empty-state {
  padding: 1.25rem 1rem;
  text-align: center;
}

.tips-amount-cell {
  min-width: 9rem;
}

.tips-amount-cell .tips-inline-input {
  min-width: 6.5rem;
}

.tips-amount-hint {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.72rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.tips-signature-cell {
  min-width: 4.5rem;
  height: 1.35rem;
}

/* ——— Tips in foreign currency (Lot 24) ——— */

.tips-cash-mvr-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0.55rem 0 0.25rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
}

.tips-cash-inline-mvr {
  grid-template-columns: repeat(7, minmax(0, 1fr));
}

@media (max-width: 720px) {
  .tips-cash-inline-mvr {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.tips-day-label {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.64rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.tips-day-input {
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  padding: 0.24rem 0.4rem;
}

.tips-foreign-table .tips-lot-code {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.03em;
}

/* A remainder only takes a colour once it is worth more than one share. */
.tips-foreign-table .tips-lot-residue-loud {
  color: var(--warning);
  font-weight: 600;
}

.tips-lot-open-btn {
  padding: 0.12rem 0.5rem;
  font-size: 0.75rem;
}

.tips-staff-taken {
  display: block;
  font-size: 0.68rem;
  font-weight: 400;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.tips-currency-dialog {
  width: min(38rem, 94vw);
  padding: 1rem 1.1rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--card);
  color: var(--text);
}

.tips-currency-dialog::backdrop {
  background: rgba(27, 36, 50, 0.32);
}

.tips-currency-movements-table {
  width: 100%;
  margin-bottom: 0.75rem;
}

.tips-currency-add {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 0.65rem;
  margin: 0;
  padding: 0.6rem 0.7rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 8px;
}

.tips-currency-add legend {
  padding: 0 0.35rem;
  font-size: 0.64rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.tips-currency-add label {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: 0.64rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.tips-currency-add input,
.tips-currency-add select {
  min-width: 7rem;
  font-size: 0.8125rem;
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
  color: var(--text);
}

.tips-currency-add button {
  padding: 0.3rem 0.75rem;
  font-size: 0.8125rem;
}

.tips-currency-error {
  margin: 0.55rem 0 0;
  font-size: 0.8rem;
  color: var(--error);
}

@media (max-width: 720px) {
  .tips-editor-header {
    flex-direction: column;
    align-items: stretch;
  }

  .tips-editor-actions {
    justify-content: flex-start;
  }

  .tips-cash-inline {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ——— Staff directory (Manage) ——— */

.manage-staff-panel {
  padding: 0.85rem 1rem 1rem;
}

.manage-page-title {
  margin: 0;
  font-size: 1.35rem;
}

.manage-header-compact {
  margin-bottom: 0.75rem;
}

.manage-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.65rem;
}

.manage-header-actions {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.manage-toolbar-compact {
  margin-bottom: 0.45rem;
}

.manage-hint-details {
  margin-bottom: 0.65rem;
  font-size: 0.78rem;
  color: var(--muted);
}

.manage-hint-details summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--brand-navy);
}

.manage-hint-details p {
  margin: 0.35rem 0 0;
  line-height: 1.45;
}

.staff-directory-table {
  table-layout: fixed;
  width: 100%;
}

/* Percent widths sum to 100% — avoids uneven gaps from mixing rem + % */
.staff-directory-table .staff-col-name {
  width: 21%;
}

.staff-directory-table .staff-col-full-name {
  width: 29%;
}

.staff-directory-table .staff-col-designation {
  width: 18%;
}

.staff-directory-table .staff-col-pending {
  width: 12%;
}

.staff-directory-table .staff-col-active {
  width: 13%;
}

.staff-directory-table .staff-col-actions {
  width: 7%;
}

/* Compact rhythm, and the same on every column (name ↔ full name ↔ designation
   ↔ …). This belongs to the table recipe rather than to the Manage page: the
   immigration workspace reuses `.staff-directory-table` and was inheriting the
   loose 0.75rem default instead, which made its rows twice the height of the
   directory's for the same kind of data. */
.staff-directory-table th,
.staff-directory-table td {
  padding-left: 0.75rem;
  padding-right: 0.75rem;
}

.staff-directory-table th {
  padding-top: 0.45rem;
  padding-bottom: 0.45rem;
}

.staff-directory-table td {
  padding-top: 0.35rem;
  padding-bottom: 0.35rem;
}

.staff-directory-table td:first-child,
.staff-directory-table .designation-col {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.staff-directory-table th[data-sort-key] {
  cursor: pointer;
  user-select: none;
}

.staff-directory-table th[data-sort-key]:hover {
  color: var(--ink);
}

.staff-directory-table th[data-sort-key].sorted {
  color: var(--accent);
}

.staff-directory-table th[aria-sort='ascending']::after {
  content: ' ↑';
}

.staff-directory-table th[aria-sort='descending']::after {
  content: ' ↓';
}

.staff-directory-table .num-col {
  text-align: right;
  white-space: nowrap;
}

.staff-directory-table td.num-col {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.staff-directory-table th.num-col {
  text-align: right;
}

.staff-directory-table .full-name-col {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.staff-directory-table .active-col {
  white-space: nowrap;
  text-align: center;
}

.staff-directory-table th.active-col {
  text-align: center;
}

#manage-section .staff-directory-table .status-toggle {
  flex-wrap: nowrap;
  justify-content: center;
  width: 100%;
}

#manage-section .staff-directory-table .status-toggle-label {
  display: inline-block;
  min-width: 3.55rem;
  text-align: left;
}

.staff-directory-name {
  font-weight: 600;
  color: var(--brand-navy);
  text-decoration: none;
}

.staff-directory-name:hover {
  text-decoration: underline;
}

/* HR expiry alert next to the name: small dot + count.
   Colors match the staff-hub document badges (expired / expires soon). */
.staff-hr-alert {
  display: inline-flex;
  align-items: center;
  gap: 0.22rem;
  margin-left: 0.45rem;
  font-size: 0.72rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: default;
}

.staff-hr-alert::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}

.staff-hr-alert-expired {
  color: var(--error);
}

.staff-hr-alert-soon {
  color: var(--warning);
}

.staff-directory-table .actions-col {
  text-align: center;
}

.staff-directory-table th.actions-col {
  text-align: center;
}

.staff-row-menu {
  position: relative;
  display: inline-block;
}

.staff-row-menu-trigger {
  list-style: none;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: 0.15rem 0.35rem;
  border-radius: 6px;
  color: var(--muted);
  user-select: none;
}

.staff-row-menu-trigger::-webkit-details-marker {
  display: none;
}

.staff-row-menu-trigger:hover {
  background: var(--fill);
  color: var(--brand-navy);
}

.staff-row-menu-body {
  position: absolute;
  right: 0;
  z-index: 20;
  min-width: 7rem;
  margin-top: 0.2rem;
  padding: 0.35rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.15rem;
}

.staff-row-menu-body .link-button {
  text-align: left;
  padding: 0.35rem 0.5rem;
  border-radius: 4px;
}

.staff-row-menu-body .link-button:hover {
  background: var(--fill);
}

.staff-row-menu-danger {
  color: var(--danger);
}

.staff-form-dialog .form-grid {
  margin-top: 0.5rem;
}

.staff-profile-edit-dialog {
  max-width: 32rem;
}

.staff-profile-edit-form {
  margin-top: 0.35rem;
  grid-template-columns: minmax(6rem, 0.85fr) minmax(0, 2.15fr);
}

.staff-profile-edit-form .staff-profile-edit-notes {
  grid-column: 1 / -1;
}

.staff-profile-edit-form label {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
}

.staff-profile-edit-form input,
.staff-profile-edit-form select,
.staff-profile-edit-form textarea {
  width: 100%;
  box-sizing: border-box;
}

.staff-profile-edit-form .staff-profile-edit-contact {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.65rem 0.85rem;
}

.staff-profile-edit-actions {
  grid-column: 1 / -1;
  margin-bottom: 0;
}


/* ——— Staff record hub ——— */

.staff-hub-page .page {
  max-width: 1100px;
}

.staff-hub-card {
  padding: 1rem 1.1rem;
}

.staff-hub-header-compact {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  margin-bottom: 0.85rem;
}

.staff-hub-header-main {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.staff-hub-title-row {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  max-width: 100%;
}

.staff-hub-title-row .page-title {
  margin: 0;
}

.staff-hub-edit-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  margin: 0 0 0 0.1rem;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  flex-shrink: 0;
  opacity: 0.55;
  transition: color 0.15s ease, opacity 0.15s ease;
}

.staff-hub-edit-btn:hover {
  color: var(--brand-navy);
  opacity: 1;
}

.staff-hub-edit-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  opacity: 1;
}

.staff-hub-submeta {
  margin: 0.15rem 0 0;
  font-size: 0.82rem;
  color: var(--muted);
}

.staff-hub-back {
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
}

.staff-hub-back:hover {
  color: var(--brand-navy);
}

.staff-hub-identity {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}

.staff-hub-avatar {
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--fill);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  flex-shrink: 0;
}

.staff-hub-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.staff-hub-initials {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--brand-navy);
}

.staff-hub-heading .page-title {
  margin: 0;
  font-size: 1.45rem;
}

.staff-hub-meta {
  margin: 0.2rem 0 0;
  font-size: 0.88rem;
  color: var(--muted);
}

.staff-hub-timeline-btn {
  align-self: flex-start;
  font-size: 0.84rem;
}

.staff-hub-section-title {
  margin: 0 0 0.35rem;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--brand-navy);
}

.staff-hub-directory-hint {
  margin: 0 0 0.75rem;
  font-size: 0.8rem;
  color: var(--muted);
  line-height: 1.45;
}

.staff-hub-field-hint {
  margin: 0.2rem 0 0;
  font-size: 0.72rem;
  color: var(--muted);
  line-height: 1.35;
}

.staff-hub-directory-common-name {
  grid-column: span 1;
}

.staff-hub-directory-full-name {
  grid-column: span 3;
}

.staff-hub-directory-fields {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.65rem 0.85rem;
}

.staff-hub-directory-fields label {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
}

.staff-hub-directory-fields input,
.staff-hub-directory-fields select,
.staff-hub-directory-fields textarea {
  width: 100%;
  box-sizing: border-box;
}

.staff-hub-directory-notes {
  grid-column: 1 / -1;
}

.staff-hub-directory-actions {
  margin-top: 0.75rem;
  margin-bottom: 0;
}

.staff-hub-avatar-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  flex-shrink: 0;
}

.staff-hub-photo-actions {
  display: flex;
  gap: 0.55rem;
}

.staff-hub-photo-btn {
  border: none;
  background: transparent;
  padding: 0;
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
}

.staff-hub-photo-btn:hover {
  color: var(--brand-navy);
  text-decoration: underline;
}

.staff-hub-photo-btn-danger:hover {
  color: var(--danger);
}

.staff-hub-contact-card {
  margin-top: 0.75rem;
}

.staff-hub-contact-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
}

.staff-hub-detail-list {
  margin: 0;
  display: grid;
  gap: 0.5rem;
}

.staff-hub-detail-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}

.staff-hub-detail-row dt {
  font-size: 0.8rem;
  color: var(--muted);
}

.staff-hub-detail-row dd {
  margin: 0;
  font-size: 0.875rem;
  text-align: right;
  overflow-wrap: anywhere;
}

.staff-hub-stint-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.staff-hub-stint-line {
  font-size: 0.875rem;
}

.staff-hub-stint-muted {
  color: var(--muted);
  font-size: 0.8rem;
}

.staff-hub-stint-notes {
  margin: 0.15rem 0 0;
  font-size: 0.78rem;
  color: var(--muted);
  line-height: 1.4;
}

.staff-hub-doc-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.staff-hub-doc-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.55rem 0;
  border-top: 1px solid var(--border);
}

.staff-hub-doc-row:first-child {
  border-top: none;
  padding-top: 0;
}

.staff-hub-doc-main {
  min-width: 0;
}

.staff-hub-doc-name-line {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.45rem;
}

.staff-hub-doc-name {
  font-size: 0.875rem;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.staff-hub-doc-chip {
  display: inline-block;
  padding: 0.08rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
}

.staff-hub-doc-badge {
  display: inline-block;
  padding: 0.08rem 0.5rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  white-space: nowrap;
}

.staff-hub-doc-badge-expired {
  color: var(--error);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--danger) 35%, var(--border));
}

.staff-hub-doc-badge-soon {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--warning) 40%, var(--border));
}

.staff-hub-doc-meta {
  margin: 0.2rem 0 0;
  font-size: 0.78rem;
  color: var(--muted);
}

.staff-hub-doc-actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-shrink: 0;
  padding-top: 0.15rem;
}

.staff-hub-doc-action {
  border: none;
  background: transparent;
  padding: 0;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
}

.staff-hub-doc-action:hover {
  color: var(--brand-navy);
  text-decoration: underline;
}

.staff-hub-doc-action-danger:hover {
  color: var(--danger);
}

.staff-hub-doc-empty {
  margin: 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.staff-hub-doc-edit-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
}

.staff-hub-doc-edit-form input,
.staff-hub-doc-edit-form select,
.staff-hub-doc-upload input,
.staff-hub-doc-upload select {
  width: auto;
}

.staff-hub-doc-edit-form input[type="text"] {
  flex: 1 1 10rem;
  min-width: 0;
}

.staff-hub-doc-edit-actions {
  display: flex;
  gap: 0.5rem;
}

.staff-hub-doc-upload {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--border);
}

.staff-hub-doc-upload input[type="file"] {
  flex: 1 1 12rem;
  min-width: 0;
  font-size: 0.8rem;
}

.staff-hub-doc-upload input[type="text"] {
  flex: 1 1 9rem;
  min-width: 0;
}

.staff-hub-training-notes {
  margin: 0.2rem 0 0;
  font-size: 0.78rem;
  color: var(--muted);
  line-height: 1.4;
}

a.staff-hub-training-cert:hover {
  color: var(--brand-navy);
  border-color: var(--brand-navy);
  text-decoration: underline;
}

.staff-hub-skill-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}

.staff-hub-skill-chip {
  display: inline-block;
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--card);
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}

button.staff-hub-skill-chip {
  cursor: pointer;
}

button.staff-hub-skill-chip:hover {
  border-color: var(--brand-navy);
}

/* Level intensity: basic = plain, then progressively stronger navy tint. */
.staff-hub-skill-chip-basic {
  color: var(--muted);
}

.staff-hub-skill-chip-intermediate {
  border-color: color-mix(in srgb, var(--brand-navy) 25%, var(--border));
  background: color-mix(in srgb, var(--brand-navy) 4%, var(--card));
}

.staff-hub-skill-chip-advanced {
  border-color: color-mix(in srgb, var(--brand-navy) 45%, var(--border));
  background: color-mix(in srgb, var(--brand-navy) 8%, var(--card));
  color: var(--brand-navy);
}

.staff-hub-skill-chip-expert {
  border-color: color-mix(in srgb, var(--brand-navy) 70%, var(--border));
  background: color-mix(in srgb, var(--brand-navy) 13%, var(--card));
  color: var(--brand-navy);
}

.staff-hub-skill-hint {
  margin: 0.5rem 0 0;
  font-size: 0.72rem;
  color: var(--muted);
}

.staff-hub-skill-edit-form {
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--border);
}

.staff-hub-skill-delete:hover {
  color: var(--danger);
  border-color: var(--danger);
}

.staff-hub-leave-card {
  margin-top: 0.75rem;
  padding: 1.1rem 1.15rem;
}

.staff-hub-header-compact + .staff-hub-leave-card {
  margin-top: 0;
}

.staff-leave-dashboard {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.staff-leave-dashboard-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding-bottom: 0.15rem;
  border-bottom: 1px solid var(--border);
}

.staff-leave-dashboard-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--brand-navy);
  letter-spacing: -0.01em;
}

.staff-leave-year-filter {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0;
}

.staff-leave-year-filter-label {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.staff-leave-year-select {
  min-width: 5.5rem;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--brand-navy);
}

.staff-leave-kpi-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.65rem;
}

.staff-leave-kpi-row--two {
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
}

.staff-leave-dashboard-tools {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}

.staff-leave-dashboard-actions:empty {
  display: none;
}

.staff-leave-dashboard-actions .staff-profile-vacation-add-btn {
  padding: 0.35rem 0.7rem;
  font-size: 0.8rem;
  white-space: nowrap;
}

.staff-profile-leave-toolbar:empty {
  display: none;
}

.staff-leave-hero-delta {
  font-size: 0.8rem;
  color: var(--accent);
  line-height: 1.35;
}

.staff-leave-hero-delta strong {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.staff-leave-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.5rem;
  padding: 0.55rem 0.7rem;
  border-radius: 10px;
  border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
  background: var(--surface-raised);
  font-size: 0.8rem;
  color: var(--muted);
}

.staff-leave-chips-year {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--muted);
  padding-right: 0.15rem;
}

.staff-leave-chips-total {
  font-weight: 600;
  color: var(--brand-navy);
  font-variant-numeric: tabular-nums;
}

.staff-leave-chips-total--planned {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.staff-leave-chips-none {
  color: var(--muted);
}

.staff-leave-chips-sep {
  width: 1px;
  align-self: stretch;
  margin: 0.1rem 0.3rem;
  background: var(--border);
}

.staff-leave-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--text);
  white-space: nowrap;
}

.staff-leave-chip strong {
  font-weight: 600;
  color: var(--brand-navy);
  font-variant-numeric: tabular-nums;
}

.staff-leave-chip--planned {
  border-style: dashed;
}

.staff-leave-coming-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}

.staff-leave-coming-range {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
}

.staff-leave-panel.staff-leave-panel--coming {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  min-height: 0;
}

.staff-leave-panel--coming .staff-leave-section-label {
  margin-bottom: 0;
}

.staff-leave-kpi {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.75rem 0.85rem;
  border-radius: 12px;
  border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
  background: var(--card);
  box-shadow: 0 1px 2px rgb(15 23 42 / 4%);
  min-height: 4.5rem;
}

.staff-leave-kpi--balance {
  background: var(--surface-raised);
}

.staff-leave-kpi--pending {
  border-color: color-mix(in srgb, var(--accent) 22%, var(--border));
  background: var(--info-soft);
}

.staff-leave-kpi--next {
  background: var(--surface-raised);
}

.staff-leave-kpi-label {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

.staff-leave-kpi-value {
  font-family: var(--font-data);
  font-size: 1.35rem;
  font-weight: 400;
  line-height: 1.15;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.staff-leave-kpi--pending .staff-leave-kpi-value {
  color: var(--accent);
}

.staff-leave-kpi-value--compact {
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1.35;
}

.staff-leave-kpi-value--muted {
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--muted);
}

.staff-leave-kpi-foot {
  margin-top: auto;
  font-size: 0.72rem;
  color: var(--muted);
  line-height: 1.35;
}

.staff-leave-breakdown {
  padding: 0.75rem 0.85rem;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface-raised);
}

.staff-leave-section-label {
  margin: 0 0 0.55rem;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

.staff-leave-metrics {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 0.5rem 0.65rem;
  margin: 0;
}

.staff-leave-metric {
  margin: 0;
  min-width: 0;
}

.staff-leave-metric-label {
  margin: 0;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--muted);
  line-height: 1.3;
}

.staff-leave-metric-value {
  margin: 0.15rem 0 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--brand-navy);
  font-variant-numeric: tabular-nums;
}

.staff-leave-panels {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 0.75rem;
  align-items: start;
}

.staff-leave-panel {
  padding: 0.75rem 0.85rem;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--card);
  min-height: 8rem;
}

.staff-leave-panel--timeline {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}

.staff-leave-empty {
  margin: 0.25rem 0 0;
  font-size: 0.84rem;
  color: var(--muted);
  line-height: 1.45;
}

.staff-leave-upcoming-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.staff-leave-upcoming-item {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.55rem;
  border-radius: 8px;
  background: var(--surface-raised);
  border: 1px solid transparent;
}

.staff-leave-upcoming-item:hover {
  border-color: color-mix(in srgb, var(--border) 70%, transparent);
  background: var(--fill);
}

.staff-leave-upcoming-status {
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--ink-3);
}

.staff-leave-upcoming-status--confirmed {
  background: var(--accent);
}

.staff-leave-upcoming-status--tentative {
  background: var(--card);
  border: 2px solid var(--accent);
  box-sizing: border-box;
}

.staff-leave-upcoming-status--historical {
  background: var(--ink-2);
}

.staff-leave-upcoming-body {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.staff-leave-upcoming-dates {
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--brand-navy);
  line-height: 1.3;
}

.staff-leave-upcoming-meta {
  font-size: 0.72rem;
  color: var(--muted);
  line-height: 1.3;
}

.staff-leave-upcoming-days {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--brand-navy);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.staff-leave-minibar {
  padding: 0.55rem 0.15rem 0.15rem;
  border-radius: 10px;
  background: var(--surface-raised);
  border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
}

.staff-leave-minibar-months {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.25rem;
  margin-bottom: 0.45rem;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--muted);
  text-align: center;
}

.staff-leave-minibar-track {
  position: relative;
  height: 0.75rem;
  border-radius: 6px;
  background: var(--fill);
  overflow: hidden;
}

.staff-leave-minibar-seg {
  position: absolute;
  top: 1px;
  bottom: 1px;
  border-radius: 4px;
}

.staff-leave-legend {
  margin: 0;
  padding-top: 0.15rem;
  gap: 0.45rem 0.75rem;
  font-size: 0.68rem;
}

@media (max-width: 900px) {
  .staff-leave-kpi-row,
  .staff-leave-kpi-row--two {
    grid-template-columns: 1fr;
  }

  .staff-leave-metrics {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .staff-leave-panels {
    grid-template-columns: 1fr;
  }

  .staff-hub-directory-fields {
    grid-template-columns: minmax(6rem, 1fr) minmax(0, 3fr);
  }

  .staff-hub-directory-common-name,
  .staff-hub-directory-full-name {
    grid-column: auto;
  }
}

@media (max-width: 520px) {
  .staff-hub-directory-fields,
  .staff-profile-edit-form {
    grid-template-columns: 1fr;
  }

  .staff-hub-timeline-btn {
    width: 100%;
    text-align: center;
  }
}

/* Global HR dashboard (Roadmap Lot 13, admin-only). */
.dashboard-denied-card,
.dashboard-loading-card {
  padding: 1.5rem;
}

.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1rem;
}

.dashboard-card {
  padding: 1rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.dashboard-card-title {
  margin: 0 0 0.15rem;
  font-size: 1.05rem;
}

.dashboard-kpi-value {
  margin: 0;
  font-family: var(--font-data);
  font-size: var(--text-stat);
  font-weight: 400;
  line-height: 1.1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.dashboard-kpi-value--compact {
  font-size: 1.4rem;
}

.dashboard-kpi-value--danger {
  color: var(--danger);
}

.dashboard-kpi-value--warning {
  color: var(--warning);
}

.dashboard-kpi-label {
  margin: 0 0 0.5rem;
  font-size: 0.8rem;
  color: var(--muted);
}

.dashboard-kpi-row {
  display: flex;
  gap: 1.5rem;
  margin-bottom: 0.25rem;
}

.dashboard-section-label {
  margin: 0.5rem 0 0.4rem;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

.dashboard-chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.dashboard-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: var(--fill);
  font-size: 0.8rem;
}

.dashboard-chip-label {
  color: var(--text);
}

.dashboard-chip-value {
  font-weight: 600;
  color: var(--brand-navy);
}

.dashboard-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.dashboard-list-row {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.85rem;
  line-height: 1.35;
}

.dashboard-list-link {
  color: var(--brand-navy);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.dashboard-list-link:hover {
  text-decoration: underline;
}

.dashboard-list-detail {
  color: var(--muted);
}

.dashboard-dot {
  flex: none;
  align-self: center;
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.dashboard-dot--expired {
  background: var(--error);
}

.dashboard-dot--soon {
  background: var(--warning);
}

.dashboard-empty {
  margin: 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.dashboard-card-link {
  align-self: flex-start;
  margin-top: 0.4rem;
  font-size: 0.85rem;
  padding: 0.4rem 0.8rem;
}

/* ============================================================
   Printable planning view (/print.html, Lot 18)
   ============================================================ */

.print-page {
  background: var(--canvas);
}

.print-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 1.25rem;
  background: var(--card);
  border-bottom: 1px solid var(--border);
}

.print-back {
  color: var(--accent);
  font-size: var(--text-base);
}

.print-controls-middle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.print-month-label {
  min-width: 5.2rem;
  text-align: center;
  font-size: var(--text-base);
}

.print-sheet {
  max-width: 1400px;
  margin: 1rem auto;
  padding: 1.25rem 1.5rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}

.print-sheet-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.9rem;
}

.print-title {
  margin: 0;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
}

.print-subtitle {
  margin: 0.15rem 0 0;
  color: var(--ink-2);
  font-size: var(--text-sm);
}

.print-meta {
  color: var(--ink-3);
  font-size: var(--text-xs);
}

.print-loading {
  color: var(--ink-2);
  padding: 1rem 0;
}

.print-grid {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.print-grid th,
.print-grid td {
  border: 1px solid var(--border);
  padding: 0;
  height: 22px;
}

.print-name-head,
.print-name {
  width: 130px;
  padding: 0 6px !important;
  text-align: left;
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.print-name {
  font-weight: 500;
}

.print-day-head {
  text-align: center;
  font-size: 8.5px;
  line-height: 1.15;
  color: var(--ink-2);
  border-bottom: 1px solid var(--border-strong) !important;
}

.print-day-head .print-day-letter {
  display: block;
  font-weight: 400;
  color: var(--ink-3);
}

.print-day-head--saturday,
.print-cell--saturday {
  background: var(--brass-soft);
}

.print-day-head--today {
  color: var(--brass);
  font-weight: 600;
}

.print-cell--today {
  box-shadow: inset 2px 0 0 var(--brass);
}

.print-group-row td {
  background: var(--fill);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
  padding: 2px 6px !important;
}

.print-cell--vacation { background: var(--leave-vacation); }
.print-cell--sick { background: var(--leave-sick); }
.print-cell--emergency { background: var(--leave-emergency); }

.print-cell--unpaid {
  background: repeating-linear-gradient(45deg, var(--leave-unpaid) 0 3px, var(--card) 3px 6px);
}

/* Unclaimed off day — same hatch, washed out, so print keeps the same
   decision-vs-gap reading as the screen. */
.print-cell--absence {
  background: repeating-linear-gradient(
    45deg,
    color-mix(in srgb, var(--leave-unpaid) 32%, var(--card)) 0 3px,
    var(--card) 3px 6px
  );
}

.print-cell--departed {
  background: repeating-linear-gradient(45deg, var(--ink-3) 0 2px, var(--card) 2px 6px);
}

.print-cell--tentative {
  opacity: 0.55;
  background-image: repeating-linear-gradient(45deg, transparent 0 3px, var(--card) 3px 5px);
}

.print-legend {
  display: flex;
  gap: 1.1rem;
  flex-wrap: wrap;
  margin-top: 0.8rem;
  font-size: 11px;
  color: var(--ink-2);
}

.print-swatch {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 2px;
  margin-right: 5px;
  vertical-align: -2px;
  border: 1px solid var(--border);
}

.print-swatch--unpaid {
  background: repeating-linear-gradient(45deg, var(--leave-unpaid) 0 3px, var(--card) 3px 6px);
}

.print-swatch--absence {
  background: repeating-linear-gradient(
    45deg,
    color-mix(in srgb, var(--leave-unpaid) 32%, var(--card)) 0 3px,
    var(--card) 3px 6px
  );
}

.print-swatch--tentative {
  opacity: 0.55;
  background-image: repeating-linear-gradient(45deg, transparent 0 3px, var(--card) 3px 5px);
}

@page {
  size: A4 landscape;
  margin: 10mm;
}

@media print {
  .print-controls,
  #toast-container {
    display: none !important;
  }

  .print-page {
    background: #fff;
  }

  .print-sheet {
    max-width: none;
    margin: 0;
    padding: 0;
    border: none;
    border-radius: 0;
  }

  .print-grid th,
  .print-grid td {
    height: 18px;
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }

  .print-group-row {
    break-inside: avoid;
  }

  .print-grid tr {
    break-inside: avoid;
  }
}

/* ============================================================
   Weekly crew lists (/crew.html, Lot 19)
   ============================================================ */

.crew-main {
  max-width: 1400px;
}

.crew-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: nowrap;
  gap: 0.75rem;
  padding: 0.55rem 1rem;
  margin-bottom: 0.9rem;
  position: relative;
}

@media (max-width: 1080px) {
  .crew-toolbar {
    flex-wrap: wrap;
  }
}

.crew-toolbar-week {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

.crew-week-label {
  font-size: var(--text-base);
}

.crew-status-chip {
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  font-size: var(--text-xs);
  font-weight: 500;
  background: var(--fill);
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.crew-status-chip--final {
  background: var(--success-soft);
  color: var(--success);
}

.crew-meta {
  color: var(--ink-3);
  font-size: var(--text-xs);
}

.crew-toolbar-actions {
  display: flex;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.crew-completeness {
  margin: 0 0 0.9rem;
  padding: 0.5rem 0.8rem;
  border-radius: var(--r-md);
  border: 1px solid var(--brass);
  background: var(--brass-soft);
  color: var(--ink);
  font-size: var(--text-sm);
}

.crew-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 0.9rem;
  align-items: start;
}

.crew-column {
  padding: 0.9rem 1rem;
}

.crew-column--pool {
  background: var(--surface-raised);
}

.crew-column-title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.6rem;
  font-size: var(--text-base);
  font-weight: 600;
}

.vessel-chip {
  display: inline-block;
  border-radius: var(--r-sm);
  padding: 2px 10px;
  font: 600 11px/1.6 var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.vessel-chip--yin {
  background: var(--yin-bg);
  color: var(--yin-fg);
}

.vessel-chip--yang {
  background: var(--yang-bg);
  color: var(--yang-fg);
}

.crew-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.crew-empty {
  color: var(--ink-3);
  font-size: var(--text-sm);
  padding: 0.3rem 0;
}

.crew-chip {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--card);
}

.crew-chip--on-leave {
  opacity: 0.75;
  border-style: dashed;
}

/* Assigned rows are one compact line, sheet-style: name left,
   designation pushed to the right edge, remove button last. */
.crew-chip--assigned {
  flex-direction: row;
  align-items: center;
  gap: 0.45rem;
  padding: 0.25rem 0.45rem 0.25rem 0.6rem;
}

.crew-chip--assigned .crew-chip-designation,
.crew-chip--pool .crew-chip-main .crew-chip-designation {
  margin-left: auto;
  text-align: right;
  flex-shrink: 0;
}

.crew-chip--assigned .crew-assign-btn--remove {
  flex-shrink: 0;
}

/* Was not on this boat last week — light green card, the Excel convention. */
.crew-chip--changed {
  background: var(--success-soft);
}

/* Pool rows: name + designation on the first line, availability tags and
   the Yin/Yang buttons below. */
.crew-chip--pool .crew-chip-sub {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-wrap: wrap;
}

.crew-chip-main {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.crew-chip-name {
  font-weight: 500;
  font-size: var(--text-base);
}

.crew-chip-designation {
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
}

.crew-chip-badges {
  display: flex;
  gap: 0.3rem;
  flex-wrap: wrap;
}

.crew-chip-badges:empty {
  display: none;
}

.crew-badge {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  font-size: var(--text-2xs);
  font-weight: 500;
}

.crew-badge--leave {
  background: var(--error-soft);
  color: var(--error);
}

.crew-badge--returns {
  background: var(--leave-vacation-soft);
  color: var(--leave-vacation);
}

.crew-badge--pending {
  background: var(--brass-soft);
  color: var(--brass);
}

.crew-badge--starts {
  background: var(--success-soft);
  color: var(--success);
}

.crew-badge--last-day {
  background: var(--warning-soft);
  color: var(--warning);
}

/* Inactive in the directory, still on this saved week — a neutral fact about
   the record, not an alert: the plan is history and stays as it was. */
.crew-badge--inactive {
  background: var(--fill);
  color: var(--ink-2);
}

.crew-chip-actions {
  display: flex;
  gap: 0.3rem;
}

.crew-assign-btn {
  padding: 0.15rem 0.55rem;
  font-size: var(--text-xs);
  border-radius: var(--r-sm);
  border: 1px solid var(--border-strong);
  background: var(--card);
  color: var(--ink);
  cursor: pointer;
}

.crew-assign-btn:hover {
  background: var(--fill);
}

.crew-assign-btn--remove {
  color: var(--error);
  border-color: var(--error);
}

.crew-reset-btn {
  color: var(--error);
  border-color: var(--error);
}

/* Per-vessel cruise metadata inputs (tour + guest split). */
.crew-vessel-meta {
  display: flex;
  gap: 0.35rem;
  flex-wrap: nowrap;
  margin: -0.2rem 0 0.6rem;
}

.crew-meta-input {
  flex: 1;
  min-width: 0;
  width: auto;
  padding: 0.3rem 0.45rem;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--card);
  color: var(--ink);
  font-size: var(--text-sm);
}

.crew-meta-input::placeholder {
  color: var(--ink-3);
  font-family: var(--font-ui);
  font-size: var(--text-xs);
}

/* Numeric spinners eat half the field at this size. */
.crew-meta-input::-webkit-outer-spin-button,
.crew-meta-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.crew-meta-input[type='number'] {
  -moz-appearance: textfield;
  appearance: textfield;
}

/* Distribution sheet — hidden on screen, this is the ONLY thing that prints. */
/* Month-end finalization — compact inline group in the command-bar actions row. */
.attendance-finalization {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.78rem;
  color: var(--ink-2);
}

.attendance-finalization[hidden] {
  display: none;
}

.attendance-final-chip {
  padding: 0.12rem 0.5rem;
  border-radius: 999px;
  background: var(--success-soft);
  color: var(--success);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.attendance-signoff-chip {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: var(--fill);
  color: var(--ink-2);
  font-size: 0.72rem;
  font-weight: 500;
  white-space: nowrap;
}

.crew-sheet {
  display: none;
}

.crew-sheet-title {
  margin: 0 0 5mm;
  font-size: 15pt;
  font-weight: 600;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.crew-sheet-boats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8mm;
  align-items: start;
}

.crew-sheet-boat-title {
  margin: 0;
  padding: 2mm 3mm;
  border-radius: 4px;
  font-size: 12pt;
  font-weight: 600;
}

.crew-sheet-boat--yang .crew-sheet-boat-title {
  background: #e9e0c6;
  color: #1b2432;
}

.crew-sheet-boat--yin .crew-sheet-boat-title {
  background: #0e2a47;
  color: #fdfbf4;
}

.crew-sheet-count {
  font-weight: 500;
  font-size: 10pt;
}

.crew-sheet-guests {
  margin: 1.5mm 0 0;
  font-size: 9.5pt;
  color: #5a6474;
}

.crew-sheet-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 2mm;
}

.crew-sheet-table td {
  padding: 1.4mm 1mm;
  border-bottom: 0.3pt solid #c8c2b2;
  font-size: 10pt;
}

.crew-sheet-name {
  font-weight: 500;
  color: #1b2432;
}

/* Was not on this boat last week — light green row, same convention as
   the old Excel sheet. Fixed palette, the shared sheet must not depend
   on the theme. */
.crew-sheet-row--changed td {
  background: #d9ead3;
}

.crew-sheet-note {
  margin: 4mm 0 0;
  font-size: 8.5pt;
  color: #5a6474;
}

.crew-sheet-note-swatch {
  display: inline-block;
  width: 8pt;
  height: 8pt;
  margin-right: 4px;
  vertical-align: -1pt;
  background: #d9ead3;
  border: 0.3pt solid #c8c2b2;
}

.crew-sheet-designation {
  text-align: right;
  font-size: 7.5pt;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #5a6474;
}

@media print {
  /* Only the distribution sheet prints — no app chrome, no page furniture. */
  .crew-page .navbar,
  .crew-page .crew-toolbar,
  .crew-page .crew-completeness,
  .crew-page .crew-columns,
  .crew-page #toast-container {
    display: none !important;
  }

  .crew-page {
    background: #fff;
  }

  .crew-page .crew-main {
    margin: 0;
    padding: 0;
    max-width: none;
  }

  .crew-page .crew-sheet {
    display: block;
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }

  .crew-page .crew-sheet tr {
    break-inside: avoid;
  }
}

/* Keep the navbar on one line: tighter links, no wrapping. At 1280px the
   nine links, three icons and the user took 1387px of the 1240 there are
   (2026-09-28): the links and gaps are tighter, the brand is the short
   wordmark, and the user's name is what gives way, cut with an ellipsis
   (the whole of it on hover), never Log out breaking onto two lines. */
.navbar {
  gap: 0.75rem;
}

.navbar-links {
  flex-wrap: nowrap;
  gap: 0.25rem;
}

.navbar .nav-link {
  padding: 0.4rem 0.5rem;
  white-space: nowrap;
}

.navbar-brand {
  white-space: nowrap;
}

.navbar-user {
  min-width: 0;
}

.navbar-user-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 0.8rem;
}

.navbar-logout-btn {
  flex-shrink: 0;
  white-space: nowrap;
}

/* Below 1260px the wordmark gives its room to the user's name. */
@media (max-width: 1259px) {
  .navbar-brand {
    display: none;
  }
}

/* Crew week selection controls (calendar jump + saved plans menu).
   The date range button IS the calendar trigger; the input stays hidden. */
.crew-week-display {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--card);
  color: var(--ink);
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
  white-space: nowrap;
  cursor: pointer;
}

.crew-week-display:hover {
  background: var(--fill);
}

.crew-week-display svg {
  color: var(--ink-3);
  flex-shrink: 0;
}

.crew-week-input-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.crew-this-week-btn {
  padding: 0.3rem 0.7rem;
  font-size: var(--text-xs);
}

.crew-saved-plans {
  max-width: 12rem;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--card);
  color: var(--ink);
  font-size: var(--text-xs);
}

/* Lot 20 — staff hub compliance */

/* Section labels grouping the (now longer) edit dialogs — the DESIGN.md
   uppercase 11px micro-label, with a hairline to separate groups. */
.staff-profile-edit-section {
  grid-column: 1 / -1;
  margin: 0.35rem 0 -0.35rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--border);
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.staff-profile-edit-section-first {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

/* Street address takes the full row of its group grid. */
.staff-profile-edit-contact .staff-profile-edit-span {
  grid-column: 1 / -1;
}

/* Both edit dialogs carry more fields since Lot 20 — a little more width
   keeps the two-column groups readable. */
.staff-profile-edit-dialog {
  max-width: 36rem;
}

/* Neutral "Missing" pill — missing data is a gap, not an emergency. */
.staff-hub-doc-badge-muted {
  color: var(--muted);
  background: var(--fill);
  border: 1px solid var(--border);
}

/* Address block in the Contact & employment card. */
.staff-hub-address-block {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.staff-hub-emergency-line {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.staff-hub-emergency-name {
  font-weight: 600;
}

.staff-hub-emergency-relation {
  color: var(--muted);
  font-size: 0.8rem;
  margin-right: 0.15rem;
}

/* "Admin only" tag next to the Family panel title. */
.staff-hub-admin-tag {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.05rem 0.45rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--fill);
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  color: var(--muted);
}

/* Card header: title left, Edit HR details right — the action is visible
   before reading the rows (owner feedback 2026-07-20). */
.staff-hub-compliance-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.35rem;
}

.staff-hub-compliance-header .staff-hub-section-title {
  margin-bottom: 0;
}

.staff-hub-flights-hint {
  margin: 0.3rem 0 0;
  font-size: 0.75rem;
}

.staff-hub-compliance-header .secondary {
  font-size: 0.8rem;
  padding: 0.35rem 0.75rem;
}

/* ============================================================
   Lot 20 delta — staff directory VISA / MEDICAL columns (admin)
   ============================================================ */

/* Widths active only while manage.js has inserted the two compliance cols:
   name 21→15, full name 29→20, designation 18→13, pending 12→7, active 13→11,
   actions 7→6 — plus 2 × 14% renewal columns = 100%. */
.staff-directory-table:has(.staff-col-compliance) .staff-col-name {
  width: 15%;
}

.staff-directory-table:has(.staff-col-compliance) .staff-col-full-name {
  width: 20%;
}

.staff-directory-table:has(.staff-col-compliance) .staff-col-designation {
  width: 13%;
}

.staff-directory-table:has(.staff-col-compliance) .staff-col-pending {
  width: 7%;
}

.staff-directory-table:has(.staff-col-compliance) .staff-col-active {
  width: 11%;
}

.staff-directory-table:has(.staff-col-compliance) .staff-col-actions {
  width: 6%;
}

.staff-directory-table .staff-col-compliance {
  width: 14%;
}

/* Renewal dates scan like a tide table: Plex Mono, right-aligned, color only
   when something needs attention (error past, warning within threshold). */
.staff-directory-table .compliance-date-col {
  text-align: right;
  white-space: nowrap;
}

/* The header centres over its column — right-aligned labels read as though
   they belong to the column on their left. The values stay right-aligned. */
.immigration-table thead th.compliance-date-col {
  text-align: center;
}

.staff-directory-table td.compliance-date-col {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.staff-compliance-date--expired {
  color: var(--error);
  font-weight: 500;
}

.staff-compliance-date--soon {
  color: var(--warning);
  font-weight: 500;
}

/* Lot 21 — immigration workspace (/immigration.html). Same data-surface recipe
   as the staff directory, but carrying every column of the agent's report, so
   the table is wider than the viewport and scrolls inside .table-wrap. Fixed
   pixel widths (not percentages) keep the columns honest while it scrolls. */
.immigration-table {
  table-layout: fixed;
  min-width: 1720px;
  /* `separate`, not the inherited `collapse`: a collapsed table has no cell
     boxes of its own, so neither the frozen column's shadow nor the group
     rules paint. The attendance grid switches for the same reason. Spacing is
     zeroed so the rows still read as one continuous sheet, and the row rules
     move to the cells (a collapsed <tr> border does not survive either). */
  border-collapse: separate;
  border-spacing: 0;
  /* One type scale for the sheet: text cells inherit --text-base, the mono
     columns drop to --text-sm. Three sizes on one row read as three tables. */
  font-size: var(--text-base);
}

/* The controls sit in their own bar so the sheet below can scroll under a
   frozen header — the shape Attendance already uses. */
/* Full-viewport sheet, exactly as the attendance editor: the page itself does
   not scroll, only the table body does, so the header rows stay put and the
   sheet always reaches the bottom of the window instead of stopping at a fixed
   height with dead space under it. Scoped to the loaded page so the "loading"
   and "no access" cards keep the ordinary page flow. */
.immigration-page {
  padding: 0.4rem 0.75rem 0.5rem;
}

body:has(.immigration-page #immigration-content:not(.hidden)) {
  overflow: hidden;
  height: 100dvh;
  display: flex;
  flex-direction: column;
}

body:has(.immigration-page #immigration-content:not(.hidden)) .navbar {
  flex-shrink: 0;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

body:has(.immigration-page #immigration-content:not(.hidden)) .immigration-page {
  flex: 1;
  min-height: 0;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  margin: 0;
}

body:has(.immigration-page #immigration-content:not(.hidden)) #immigration-content {
  flex: 1;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

body:has(.immigration-page #immigration-content:not(.hidden)) .immigration-command-bar {
  flex-shrink: 0;
  min-width: 0;
  max-width: 100%;
}

body:has(.immigration-page #immigration-content:not(.hidden)) .immigration-sheet {
  flex: 1;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  margin-bottom: 0;
}

.immigration-command-bar {
  padding: 0.4rem 0.65rem;
  margin-bottom: 0.45rem;
}

.immigration-command-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.45rem 0.75rem;
}

.immigration-command-primary,
.immigration-command-secondary {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

/* Control sizing copied from the attendance command bar, not re-chosen: the
   page-default input is 39px tall against that bar's 28px, which by itself
   made this header sit a dozen pixels lower than the one it is meant to
   match. Same padding, same font size, same border treatment. */
.immigration-command-primary > input[type='search'] {
  width: 14rem;
  min-width: 0;
  max-width: 100%;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--card);
  font-size: 0.82rem;
}

.immigration-command-primary > input[type='search']:focus {
  outline: 2px solid var(--brand-navy);
  outline-offset: 0;
  border-color: var(--brand-navy);
}

.immigration-command-primary > select {
  width: auto;
  padding: 0.35rem 0.55rem;
  font-size: 0.82rem;
  font-weight: 600;
}

.immigration-sheet {
  padding: 0;
  overflow: hidden;
}

/* The sheet scrolls inside the card, so the header can stick to its top. It
   takes the height the flex column gives it rather than a `calc(100vh - …)`
   guess, which went stale as soon as anything above changed height. */
.immigration-table-wrap {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

/* Frozen header, both tiers. The group row sits above the label row, so it
   takes the lower offset and the higher z-index goes to whatever also
   freezes horizontally (the name column). */
.immigration-table thead th {
  position: sticky;
  z-index: 2;
  background: var(--fill);
}

.immigration-table thead .immigration-group-row th {
  top: 0;
}

/* The label row pins directly below the group row. Its offset is the group
   row's measured height (`syncStickyHeaderOffset` sets the variable) — a
   hardcoded value leaves a gap at other font sizes, and body rows scroll
   through the gap. The fallback only has to be close. */
.immigration-table thead tr:last-child th {
  top: var(--immigration-group-height, 20px);
  box-shadow: 0 1px 0 var(--border-strong);
}

/* Group boundaries: a rule down the left edge of each document block, so the
   five blocks stay separable once the table has been scrolled sideways. */
.immigration-table th.immigration-group-start,
.immigration-table td.immigration-group-start {
  border-left: 1px solid var(--border-strong);
}

/* With `separate` borders the row rule has to live on the cells. */
.immigration-table tbody td {
  border-bottom: 1px solid var(--border);
}

.immigration-table thead th {
  border-bottom: none;
}

/* The name cell holds a flag dot beside the button, so it lays out as a row. */
.immigration-table td.immigration-sticky-col {
  display: flex;
  align-items: center;
}

.immigration-table {
  --immigration-col-1-width: 118px;
}

.immigration-table .immigration-col-name { width: var(--immigration-col-1-width); }
/* ~15 characters, then an ellipsis. A wrapped name doubles its row's height,
   and with a frozen name column beside it the short name already identifies
   the person; the full value stays in the title. */
.immigration-table .immigration-col-fullname { width: 168px; }
.immigration-table .immigration-col-ref { width: 118px; }
.immigration-table .immigration-col-state { width: 132px; }
.immigration-table .immigration-col-occupation { width: 168px; }
/* Wide enough for the longest rendered date ("27 Sep 2026") in Plex Mono —
   a clipped date is worse than no date, and these must never ellipsize. */
.immigration-table .immigration-col-date { width: 116px; }

/* Document grouping above the column labels — without it, three columns all
   called "Number" say nothing about which permit they belong to. */
.immigration-table .immigration-group {
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
  text-align: left;
  padding-top: 0.35rem;
  padding-bottom: 0.05rem;
  border-bottom: 1px solid var(--border);
}

/* The staff block is context, not a document: no rule under it. */
.immigration-table .immigration-group--plain {
  color: var(--ink-3);
  border-bottom-color: transparent;
}

/* Every body cell stays on one line: with 16 columns a single wrapping value
   ("CRUISE DIRECTOR") would double the height of its row and break the scan.
   Long values ellipsize and tell the rest through their title attribute. */
.immigration-table tbody td {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.immigration-table .immigration-state,
.immigration-table .immigration-occupation {
  color: var(--ink-2);
}

/* Permit / visa / passport numbers: mono, so they can be compared character by
   character against whatever the agent has open beside this page. */
.immigration-table .immigration-ref {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* A date that is informational only (the permit fee) never takes a colour. */
.immigration-date--plain {
  color: var(--ink-2);
}

/* A date raised because its document needs a long run-up, not because it is
   close: today only the passport, whose window is four months against everyone
   else's one. Same warning pigment — it IS a warning — held back to about half
   strength against the muted ink and left at normal weight, so a glance down
   the column separates "this month" from "start it now, it lands in spring"
   without inventing a third colour. No new token: color-mix over two that
   already flip correctly in dark mode. */
.immigration-date--ahead {
  color: var(--warning-quiet);
}

/* The work permit's expiry, reached, with the automatic renewal unconfirmed.
   A dotted rule under the date — "unverified" where a solid one would read as
   a link. Deliberately colourless: it rides ON TOP of whichever tone the date
   already carries (amber on the day, red once it is past), so it adds the one
   thing the tone cannot say without inventing a third colour DESIGN.md does
   not have. */
.immigration-date--verify {
  text-decoration: underline dotted currentColor;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

/* No name on file yet — muted, like every other unknown value on the row. */
.immigration-name--unknown {
  color: var(--ink-3);
}

/* A scan slot in the update dialog: what is on file, and what you can do. It
   sits inside the block of the document it belongs to, so it no longer has to
   name it ("Work permit scan" → "Scan") — the heading above already did. */
.immigration-file-row {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem 0.5rem;
  margin-top: 0.15rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
  font-size: var(--text-sm);
}

.immigration-file-label {
  flex: none;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
}

.immigration-file-state {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink);
}

.immigration-file-row.is-empty .immigration-file-state {
  color: var(--ink-3);
}

.immigration-file-actions {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.immigration-file-actions .link-button {
  font-size: var(--text-xs);
}

.immigration-file-upload {
  padding: 0.15rem 0.5rem;
  font-size: var(--text-xs);
}

/* Archiving is destructive-shaped even though nothing is deleted, so it sits
   apart from the fields above rather than reading as one more of them. */
.immigration-archive-row {
  grid-column: 1 / -1;
  margin-top: 0.35rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--border);
}

.immigration-archive-toggle {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: var(--text-base);
  color: var(--ink);
  cursor: pointer;
}

.immigration-archive-toggle input {
  width: auto;
  margin: 0;
}

/* Report actions menu. The generic `.link-button` it used to borrow is an
   underlined 16px link: two of them wrapped onto four lines inside a 7rem
   popover and read as raw HTML rather than as part of the app. */
.immigration-menu {
  position: relative;
  display: inline-block;
}

.immigration-menu-trigger {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--ink-2);
  cursor: pointer;
  user-select: none;
}

.immigration-menu-trigger::-webkit-details-marker {
  display: none;
}

.immigration-menu-trigger:hover,
.immigration-menu[open] > .immigration-menu-trigger {
  background: var(--fill);
  border-color: var(--border-strong);
  color: var(--ink);
}

.immigration-menu-trigger:focus-visible {
  outline: 2px solid var(--brand-navy);
  outline-offset: 1px;
}

.immigration-menu-body {
  position: absolute;
  right: 0;
  z-index: 20;
  width: 17rem;
  margin-top: 0.3rem;
  padding: 0.25rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  box-shadow: 0 12px 32px rgba(27, 36, 50, 0.14);
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.immigration-menu-item {
  display: flex;
  flex-direction: column;
  /* Buttons carry `align-items: center` from the UA sheet, which centres both
     lines inside the popover instead of aligning them to its left edge. */
  align-items: flex-start;
  gap: 0.1rem;
  width: 100%;
  padding: 0.4rem 0.55rem;
  border: none;
  border-radius: 5px;
  background: none;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.immigration-menu-item:hover,
.immigration-menu-item:focus-visible {
  background: var(--surface-raised);
  outline: none;
}

.immigration-menu-label {
  font-size: var(--text-base);
  font-weight: 500;
  color: var(--ink);
}

/* Says which way the file travels — the one thing worth spelling out here. */
.immigration-menu-hint {
  font-size: var(--text-xs);
  line-height: 1.35;
  color: var(--ink-3);
}

/* Import preview — a plain, scannable account of what is about to happen. */
.immigration-import-body {
  max-height: 45vh;
  overflow-y: auto;
  margin: 0.5rem 0 1rem;
}

.immigration-import-summary {
  margin: 0 0 0.75rem;
  font-size: var(--text-base);
  color: var(--ink);
}

.immigration-import-heading {
  margin: 0.9rem 0 0.3rem;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
}

.immigration-import-heading.is-warning {
  color: var(--warning);
}

.immigration-import-list {
  margin: 0;
  padding-left: 1.1rem;
  font-size: var(--text-sm);
  color: var(--ink-2);
}

.immigration-import-list li {
  margin: 0.1rem 0;
}

/* An outstanding permit decision, flagged on the name: the standing column is
   gone, but this one is work waiting and has to stay visible. Warning tone,
   the same an approaching renewal uses — red stays for what has lapsed. */
.immigration-name-flag {
  display: inline-block;
  flex: none;
  width: 6px;
  height: 6px;
  margin-right: 0.35rem;
  border-radius: 50%;
  background: var(--warning);
}

/* Former staff: quiet throughout. Their papers are meant to have lapsed, so
   the dates stay legible for the record but carry no warning colour. */
.immigration-date--former {
  color: var(--ink-3);
}

.immigration-row--former td {
  color: var(--ink-3);
}

/* The name column freezes: the table is twice the viewport wide, and without
   it you lose track of whose row you are reading — and of the way into the
   record, which is the name itself. Same pattern as the attendance grid. */
/* Two frozen columns — name and name on permit — exactly the attendance
   grid's arrangement, down to the shadow: one soft drop on the right edge of
   the frozen block, nothing between the two columns inside it. The group
   header spans both, so the STAFF box and the frozen block end together
   instead of breaking mid-way. */
.immigration-table th.immigration-sticky-col,
.immigration-table td.immigration-sticky-col {
  position: sticky;
  left: 0;
  z-index: 3;
  background: var(--card);
}

.immigration-table thead th.immigration-sticky-col,
.immigration-table thead th.immigration-sticky-col-2 {
  background: var(--fill);
}

.immigration-table th.immigration-sticky-col-2,
.immigration-table td.immigration-sticky-col-2 {
  position: sticky;
  left: var(--immigration-col-1-width);
  z-index: 3;
  background: var(--card);
}

/* The right edge of the frozen block, wherever it falls. */
.immigration-table tbody .immigration-sticky-edge {
  box-shadow: 2px 0 5px rgba(15, 23, 42, 0.06);
}

.immigration-table thead th.immigration-sticky-col,
.immigration-table thead th.immigration-sticky-col-2 {
  z-index: 5;
}

/* The label row already carries the rule under the header, so the edge cell
   states both shadows — a second `box-shadow` would replace the first. */
.immigration-table thead tr:last-child th.immigration-sticky-edge {
  box-shadow: 0 1px 0 var(--border-strong), 2px 0 5px rgba(15, 23, 42, 0.08);
}

.immigration-table thead .immigration-group-row th.immigration-sticky-edge {
  box-shadow: 2px 0 5px rgba(15, 23, 42, 0.08);
}

/* A cell spanning both frozen columns must measure exactly their combined
   width, padding included, or the group header overhangs the block it labels. */
.immigration-table th,
.immigration-table td {
  box-sizing: border-box;
  /* 0.5rem sideways, as the attendance grid — the shared 0.75rem made these
     columns visibly airier than the sheet they sit beside in the nav. */
  padding-left: 0.5rem;
  padding-right: 0.5rem;
}

/* The opaque background above would otherwise swallow the row hover. */
.immigration-table tbody tr:hover td.immigration-sticky-col,
.immigration-table tbody tr:hover td.immigration-sticky-col-2 {
  background: var(--surface-raised);
}

/* The name IS the control that opens the record — styled as text, not as a
   button, so the column still reads as a column. */
.immigration-name-btn {
  all: unset;
  cursor: pointer;
  color: var(--accent);
  font: inherit;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block;
}

.immigration-name-btn:hover {
  text-decoration: underline;
}

.immigration-name-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}



/* Counts sit in the header row, next to the title — brass-free, ink by default
   and pigment only on the expired / expiring parts. */
.immigration-counts {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

/* Each figure is also the way to the names behind it. It has to stay reading
   as a counts line, not as a row of buttons, so the control is invisible until
   the pointer is on it — the affordance is the underline on hover, nothing
   more. Colour comes from the tone class the count already carried. */
.immigration-count-chip {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
  border-radius: 0;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 3px;
  transition: text-decoration-color 150ms ease-out;
}

/* The tone classes the chips carry are defined earlier in this file, so the
   `color: inherit` above outranked them on source order alone and the whole
   counts line rendered in one grey — the classes had been inert since the line
   was built. Restated here at two-class specificity, so a count reads in the
   same colour as the dates it is counting. */
.immigration-count-chip.staff-compliance-date--expired {
  color: var(--error);
}

.immigration-count-chip.staff-compliance-date--soon {
  color: var(--warning);
}

.immigration-count-chip.immigration-date--ahead {
  color: var(--warning-quiet);
}

.immigration-count-chip.immigration-date--former {
  color: var(--ink-3);
}

.immigration-count-chip:hover {
  text-decoration-color: currentColor;
}

.immigration-count-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.immigration-count-sep {
  color: var(--ink-3);
  margin: 0 0.35rem;
}

/* The empty state is a sentence, not a data cell: it may wrap, and it is not
   subject to the single-line rule the rest of the body follows. */
.immigration-table td.immigration-empty {
  white-space: normal;
  overflow: visible;
  padding: 1rem 0.75rem;
  color: var(--ink-2);
  font-size: var(--text-base);
  max-width: 70ch;
}

.immigration-footnote {
  flex-shrink: 0;
  margin: 0.4rem 0 0;
  padding: 0 0.5rem 0.35rem;
  font-size: var(--text-xs);
  color: var(--ink-3);
}

/* Fourteen fields need more room than the 448px staff dialog. A <dialog> is
   shrink-to-fit, so an auto-fit grid inside it would keep collapsing to one
   column no matter how high max-width goes — set an explicit width instead. */
.immigration-dialog {
  width: 36rem;
  max-width: calc(100vw - 2rem);
  background: var(--card);
  color: var(--ink);
  /* The footer below pins itself to the bottom of the scrollport and carries
     its own bottom padding, so the dialog gives up its own: otherwise the bar
     and its resting place differ and it jumps at the end of the scroll. */
  padding-bottom: 0;
}

/* Who the record is, before any document. A rule under it, because the identity
   is the one thing on this screen that is not a field. */
.immigration-dialog-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.85rem;
  padding-bottom: 0.65rem;
  border-bottom: 1px solid var(--border-strong);
}

.immigration-dialog-title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.immigration-dialog-sub {
  margin: 0.15rem 0 0;
  font-size: var(--text-xs);
  color: var(--ink-2);
}

/* Only shown when there is something to say — an ordinary crew member on the
   roster carries no chip at all. */
.immigration-dialog-standing {
  flex: none;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  background: var(--fill);
  color: var(--ink-2);
  font-size: var(--text-2xs);
  font-weight: 500;
  white-space: nowrap;
}

.immigration-dialog-standing.is-warning {
  background: var(--warning-soft);
  color: var(--warning);
}

.immigration-form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin: 0;
}

/* One document per block. The dialog used to be a single flat grid with
   micro-labels floating in it, which put a permit number, a medical date and an
   archive checkbox at the same reading level. */
.immigration-section {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--card);
}

.immigration-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.4rem 0.8rem;
  border-bottom: 1px solid var(--border);
  border-radius: var(--r-md) var(--r-md) 0 0;
  background: var(--surface-raised);
}

.immigration-section-title {
  margin: 0;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink);
}

/* The block's verdict, so a section can be judged before it is read. The dates
   themselves are in the fields below — this says what they mean. */
.immigration-section-status {
  font-family: var(--font-data);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.immigration-section-status.is-muted {
  color: var(--ink-3);
}

.immigration-section-body {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.65rem 0.8rem;
  padding: 0.7rem 0.8rem 0.75rem;
}

.immigration-field--full {
  grid-column: 1 / -1;
}

/* Two single-date documents side by side — neither fills a row of its own. */
.immigration-section-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
}

@media (max-width: 40rem) {
  .immigration-section-pair {
    grid-template-columns: 1fr;
  }
}

/* Labels drop to the quietest voice in the dialog: the section heading is the
   loud one, and the value in the field is what the eye should land on. */
.immigration-form label {
  margin-bottom: 0.2rem;
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--ink-2);
}

/* Spacing between fields is the grid's job now, not the input's. */
.immigration-dialog .immigration-form input,
.immigration-dialog .immigration-form select {
  margin-bottom: 0;
}

/* End of contract, seen by anyone who is not an admin: the company decides it,
   so the agent gets the facts and no controls. */
.immigration-readout-list {
  grid-column: 1 / -1;
  display: grid;
  gap: 0.3rem;
  margin: 0;
}

.immigration-readout-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.immigration-readout-row dt {
  font-size: var(--text-xs);
  color: var(--ink-2);
}

.immigration-readout-row dd {
  margin: 0;
  font-size: var(--text-base);
  text-align: right;
  color: var(--ink);
}

.immigration-readout--unset {
  color: var(--ink-3);
}

.immigration-readout-todo {
  margin: 0.1rem 0 0;
  font-size: var(--text-xs);
  color: var(--warning);
  text-align: right;
}

.immigration-readout-empty {
  grid-column: 1 / -1;
  margin: 0;
  font-size: var(--text-base);
  color: var(--ink-2);
}

.immigration-readout-note {
  grid-column: 1 / -1;
  margin: 0.5rem 0 0;
  padding-top: 0.55rem;
  border-top: 1px solid var(--border);
  font-size: var(--text-xs);
  line-height: 1.45;
  color: var(--ink-2);
}

/* Pinned to the bottom of the dialog's scrollport and bled over the dialog's
   own side padding (1.35rem), so the bar spans edge to edge and no field
   scrolls through beside or beneath it. Six document blocks put Save a long
   way down otherwise. */
.immigration-dialog-actions {
  position: sticky;
  bottom: 0;
  z-index: 1;
  align-items: center;
  margin: 0.35rem -1.35rem 0;
  padding: 0.6rem 1.35rem 1.25rem;
  background: var(--card);
  border-top: 1px solid var(--border);
}

.immigration-dialog-footnote {
  margin-left: auto;
  font-size: var(--text-xs);
  color: var(--ink-3);
}

/* Lot 20 — staff hub compact Leave strip (replaces the full leave dashboard
   on the hub only; the attendance quick modal keeps the full panel). */
.staff-hub-leave-strip {
  display: flex;
  align-items: flex-start;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.staff-hub-leave-strip .staff-hub-section-title {
  margin: 0;
  min-width: 8rem;
}

.staff-hub-leave-stats {
  display: flex;
  gap: 2.5rem;
  flex-wrap: wrap;
}

.staff-hub-leave-stat {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.staff-hub-leave-label {
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
}

.staff-hub-leave-value {
  font-size: 1rem;
  color: var(--ink);
}

.staff-hub-leave-value.mono {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}

.staff-hub-leave-muted {
  color: var(--ink-3);
}

.staff-hub-leave-foot {
  font-size: var(--text-xs);
  color: var(--ink-3);
}

/* Immigration compliance: two panels on one line, kept to a readable width
   instead of stretching across the whole card. */
.staff-hub-compliance-grid {
  grid-template-columns: repeat(auto-fit, minmax(15rem, 22rem));
}

/* Immigration panels: title line with a small inline Edit, and the in-place
   two-date edit form (owner decision 2026-07-20 — edit where the data lives). */
.staff-hub-panel-title-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.staff-hub-panel-title-line .staff-profile-section-title {
  margin-bottom: 0;
}

.staff-hub-panel-edit-btn {
  font-size: 0.72rem;
  padding: 0.15rem 0.55rem;
}

.staff-hub-panel-edit-form {
  display: grid;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.staff-hub-panel-edit-field {
  display: grid;
  grid-template-columns: 7rem 1fr;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--text-xs);
  color: var(--ink-2);
}

.staff-hub-panel-edit-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.25rem;
}

.staff-hub-panel-edit-actions button {
  font-size: 0.78rem;
  padding: 0.3rem 0.8rem;
}

/* Staff hub UX pass */

/* Edit profile dialog: modest widening so the two-column groups breathe. */
.staff-profile-edit-dialog {
  max-width: 40rem;
}

/* Bug fix: the admin-only wrapper is a plain div inside the form grid and
   used to collapse into a single narrow cell. It now spans the full form
   width, and its inner section labels + field groups lay out exactly like
   the manager sections (they carry the same grid-column: 1 / -1 rules). */
.staff-profile-edit-form #staff-edit-hr-sections {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.85rem;
}

/* The "Admin only" tag sits inline after the section label text — never
   broken across lines. */
.staff-hub-admin-tag {
  white-space: nowrap;
}

/* Narrow fallback: collapse the field groups (and the admin wrapper) to a
   single column together with the form itself. */
@media (max-width: 520px) {
  .staff-profile-edit-form .staff-profile-edit-contact,
  .staff-profile-edit-form #staff-edit-hr-sections {
    grid-template-columns: 1fr;
  }
}

/* Notes panel on the Contact & employment card — directory notes with the
   author's line breaks preserved. */
.staff-hub-notes-block {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  white-space: pre-line;
  overflow-wrap: anywhere;
}

/* Staff hub: Leave + Flights share the top row; long values keep one line. */
.staff-hub-top-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(15rem, 20rem);
  gap: 1rem;
  align-items: stretch;
}

.staff-hub-top-row .staff-hub-card {
  margin: 0;
}

@media (max-width: 860px) {
  .staff-hub-top-row {
    grid-template-columns: 1fr;
  }
}

/* Detail rows never wrap: labels stay put, long values ellipsize on one
   line (full text remains readable in the edit dialog). */
.staff-hub-detail-row dt {
  flex: none;
  white-space: nowrap;
}

.staff-hub-detail-row dd {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  overflow-wrap: normal;
}

/* One-line detail rows, properly: every level of the grid/flex chain must be
   allowed to shrink below its content (min-width: 0), otherwise nowrap text
   widens the panel and bleeds under the neighbouring card instead of
   ellipsizing. The full value stays available as a hover tooltip (set in
   staffPage.js). */
.staff-hub-contact-grid > .staff-profile-panel {
  min-width: 0;
}

.staff-hub-contact-grid .staff-hub-detail-list,
.staff-hub-contact-grid .staff-hub-detail-row {
  min-width: 0;
  max-width: 100%;
}

/* ============================================================
   Staff hub — readable field layout (owner feedback 2026-07-20)
   Cards are for READING: label above value, values get the full
   panel width and wrap on word boundaries — nothing truncates.
   ============================================================ */

/* Contact card only (the Immigration card keeps its tabular date rows):
   6-column grid, Identity double-width, history spans the full row. */
#staff-hub-contact-panel .staff-hub-contact-grid {
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

#staff-hub-contact-panel .staff-profile-panel {
  grid-column: span 2;
  min-width: 0;
}

#staff-hub-contact-panel .staff-hub-panel--wide {
  grid-column: span 4;
}

#staff-hub-contact-panel .staff-hub-panel--full {
  grid-column: 1 / -1;
}

.staff-hub-field-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.65rem 1.25rem;
}

/* Vertical variant: one field per line (Contact, Key dates). */
.staff-hub-field-grid--stack {
  grid-template-columns: minmax(0, 1fr);
}

.staff-hub-field {
  min-width: 0;
}

.staff-hub-field-label {
  display: block;
  font-size: var(--text-xs);
  color: var(--muted);
  margin-bottom: 0.1rem;
}

.staff-hub-field-value {
  font-size: 0.875rem;
  color: var(--ink);
  overflow-wrap: break-word;
}

/* Tablet: two panels per row, Identity still full-width. */
@media (max-width: 980px) {
  #staff-hub-contact-panel .staff-hub-contact-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  #staff-hub-contact-panel .staff-profile-panel {
    grid-column: span 1;
  }
  #staff-hub-contact-panel .staff-hub-panel--wide,
  #staff-hub-contact-panel .staff-hub-panel--full {
    grid-column: 1 / -1;
  }
}

@media (max-width: 600px) {
  #staff-hub-contact-panel .staff-hub-contact-grid {
    grid-template-columns: 1fr;
  }
  #staff-hub-contact-panel .staff-profile-panel {
    grid-column: 1 / -1;
  }
}

/* ——— Edit profile: sticky save bar + unsaved-changes guard ——— */

/* The DIALOG stays the scroll container (its UA max-height + overflow), so the
   wheel scrolls the form from anywhere over the modal — title, footer and
   padding included. An inner scroller would leave those areas inert and chain
   the scroll to the page behind the modal instead.
   overscroll-behavior stops that chaining at the ends of the form too. */
.staff-profile-edit-dialog {
  overscroll-behavior: contain;
  /* The footer carries its own bottom padding and must end flush with the
     dialog, so the dialog's bottom padding and the form's bottom margin both
     go — otherwise the pinned bar and its resting place differ and it jumps
     at the end of the scroll. */
  padding-bottom: 0;
}

.staff-profile-edit-dialog .staff-profile-edit-form {
  margin-bottom: 0;
}

/* Pinned to the bottom of the dialog's scrollport, bled over the dialog's own
   padding (1.25rem 1.35rem) so the bar spans edge to edge and nothing scrolls
   through beside or beneath it. Its own padding-bottom replaces the dialog's
   and keeps the buttons clear of the edge. */
.staff-profile-edit-form .staff-profile-edit-footer {
  position: sticky;
  bottom: 0;
  z-index: 1;
  grid-column: 1 / -1;
  margin: 0.35rem -1.35rem 0;
  padding: 0.6rem 1.35rem 1.25rem;
  background: var(--card);
  border-top: 1px solid var(--border);
}

.staff-profile-edit-form .staff-profile-edit-footer .form-error {
  margin: 0 0 0.5rem;
}

.staff-profile-edit-form .staff-profile-edit-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0;
}

/* Quiet ochre marker — the form has changes that are not on the server yet.
   Not an error, so no clay/red per the red-discipline rule. */
.staff-profile-edit-dirty {
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--warning);
}

/* ==========================================================================
   Petty cash (PETTY_CASH_SPEC.md)
   The cash box each vessel's Cruise Manager holds. Built on the same recipe as
   Attendance and Immigration: a compact command bar over a dense table, colour
   only where it means something (a variance, a missing receipt, a low float).
   ========================================================================== */

.pettycash-page-main {
  max-width: 1400px;
}

.pettycash-command-bar {
  padding: 0.4rem 0.65rem;
  margin-bottom: 0.5rem;
  position: relative;
}

.pettycash-command-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.45rem 0.75rem;
}

.pettycash-command-primary,
.pettycash-command-actions {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

/* Control sizing follows the attendance command bar rather than the page
   defaults, which are 39px tall against that bar's 28px. */
.pettycash-command-bar select,
.pettycash-command-bar input {
  padding: 0.35rem 0.55rem;
  font-size: 0.82rem;
  width: auto;
  min-width: 8rem;
}

.pettycash-command-actions button {
  padding: 0.38rem 0.75rem;
  font-size: 0.82rem;
}

/* Vessel polarity, the app's existing Yin / Yang chips — no third hue. */
.pettycash-box-switch {
  display: inline-flex;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  overflow: hidden;
}

.pettycash-box-tab {
  border: none;
  /* Same inherited 8px as the section tabs: on a segmented control it leaves
     the filled half notched where the two meet. The rounding belongs to the
     container, which clips them. */
  border-radius: 0;
  background: transparent;
  color: var(--ink-2);
  font-family: var(--font-ui);
  font-size: 0.82rem;
  font-weight: 500;
  padding: 0.35rem 0.85rem;
  cursor: pointer;
}

.pettycash-box-tab.is-yin.active { background: var(--yin-bg); color: var(--yin-fg); }
.pettycash-box-tab.is-yang.active { background: var(--yang-bg); color: var(--yang-fg); }

/* One book, one chip: a Cruise Manager gets a label, not a choice. */
span.pettycash-box-tab {
  cursor: default;
}

/* The month's state, and a count's verdict. DESIGN.md's badge recipe: pill,
   soft background, pigment text, 6px dot. The app's legacy `.badge` is white
   text with no background of its own and no modifiers defined, so every badge
   built on it was invisible on a light card and only legible in dark mode. */
.pettycash-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: var(--text-xs);
  font-weight: 500;
  white-space: nowrap;
}

.pettycash-pill::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: currentColor;
}

.pettycash-pill--neutral { background: var(--fill); color: var(--ink-2); }
.pettycash-pill--info { background: var(--info-soft); color: var(--info); }
.pettycash-pill--success { background: var(--success-soft); color: var(--success); }
.pettycash-pill--warning { background: var(--warning-soft); color: var(--warning); }

/* Why the month on screen takes no new line. On its own row: inside the
   controls it wrapped the buttons onto a second line. */
.pettycash-closed-note {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  margin: 0.4rem 0 0;
  font-size: var(--text-xs);
  color: var(--warning);
}

/* Reading the other vessel's book is not a warning, it is a fact about the
   account: quiet ink, not the ochre that means something is owed. */
.pettycash-closed-note .link-button {
  font-size: var(--text-xs);
  color: var(--accent);
}

.pettycash-custody {
  font-size: var(--text-xs);
  color: var(--ink-2);
  white-space: nowrap;
}

/* A handover recorded and not yet confirmed: something waits on a person,
   so it reads in the warning ochre, at normal weight. */
.pettycash-custody-pending {
  color: var(--warning);
}

/* The balance strip: one figure per currency, because the box holds several at
   once and a single USD total is what made the workbook's variance untraceable. */
.pettycash-balances {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 1.1rem;
  margin-top: 0.45rem;
  padding-top: 0.4rem;
  border-top: 1px solid var(--border);
}

.pettycash-balance,
.pettycash-balance-total {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35rem;
}

.pettycash-balance-currency {
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.pettycash-balance-amount {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-base);
  color: var(--ink);
}

.pettycash-balance-usd,
.pettycash-flow {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  color: var(--ink-3);
}

.pettycash-balance-total .pettycash-balance-amount { font-weight: 500; }

/* Below the weekly float: ochre, because it is a deadline of a kind (the box
   runs out), never red — nothing has gone wrong yet. */
.pettycash-balance.is-low .pettycash-balance-amount { color: var(--warning); }
.pettycash-balance.is-empty { color: var(--ink-3); font-size: var(--text-sm); }

/* The two purses the box is actually run in lead the strip, and each one is
   the way into its own lines: a balance you can click is the shortest sentence
   for "these dollars, and what they did" (decision 42). Foreign notes follow
   as the one thing they are, money waiting to go ashore. */
button.pettycash-balance {
  padding: 0.1rem 0.35rem;
  margin-left: -0.35rem;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  cursor: pointer;
  font: inherit;
  transition: background-color 150ms ease-out, border-color 150ms ease-out;
}

button.pettycash-balance:hover { background: var(--surface-raised); }
button.pettycash-balance.is-selected {
  border-color: var(--border-strong);
  background: var(--surface-raised);
}

button.pettycash-balance:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* A purse below nothing is not a shortfall to top up, it is cash that moved
   without being written down: clay, because something has gone wrong. */
.pettycash-balance.is-negative .pettycash-balance-amount { color: var(--error); }

/* What a guest paid with, one row per currency. A repeater rather than one
   amount, because a bill can be settled by card and by three sets of notes at
   once (decision 41). */
.pettycash-tenders {
  margin-top: 0.9rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--border);
}

.pettycash-tenders h3 {
  margin: 0 0 0.15rem;
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.pettycash-tenders-hint {
  margin: 0 0 0.5rem;
  font-size: var(--text-xs);
  color: var(--ink-3);
}

.pettycash-tender-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
}

.pettycash-tender-row input { width: 9rem; }
.pettycash-tender-row select { width: 6.5rem; }

.pettycash-tender-usd {
  flex: 1;
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  color: var(--ink-3);
}

/* A settlement that does not reach its bill: the same clay as a purse below
   zero, and for the same reason, a movement of notes nobody wrote down. */
.pettycash-change-line.is-short { color: var(--error); }

/* What needs attention lives on a bell in the command bar (2026-08-27). A band
   of alerts across the page pushed the ledger below the fold, and the ledger is
   the page; the bell is the app's own idiom for "there is something waiting". */
.pettycash-alerts {
  position: relative;
  display: flex;
  align-items: center;
  /* Off the card's edge: the mark is round, so its own box already looks
     tighter to the border than a button's would. */
  margin-right: 0.35rem;
}

/* Sized past `.pettycash-command-actions button`, which is the rule for the
   text buttons that used to sit here. */
.pettycash-command-actions .pettycash-alerts-btn {
  position: relative;
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-2);
}

.pettycash-command-actions .pettycash-alerts-btn:hover,
.pettycash-command-actions .pettycash-alerts-btn[aria-expanded='true'] {
  background: var(--fill);
  color: var(--ink);
  filter: none;
}

/* No-alarm policy (DESIGN.md): the count is quiet brass mono, never a red
   badge. Severity is carried by the dots inside the panel, where it can be
   read as a sentence rather than shouted as a colour. */
.pettycash-alert-badge {
  position: absolute;
  top: -4px;
  right: -6px;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  border: 1px solid var(--brass);
  background: var(--brass-soft);
  color: var(--brass);
  font-family: var(--font-data);
  font-size: 0.64rem;
  font-weight: 500;
  line-height: 1;
}

.pettycash-alerts-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 0.35rem);
  z-index: 30;
  width: 30rem;
  max-width: calc(100vw - 2rem);
  max-height: 60vh;
  overflow-y: auto;
  padding: 0.5rem;
  background: var(--card);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
}

.pettycash-alerts-summary {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.1rem 0.35rem 0.4rem;
  font-size: var(--text-sm);
  color: var(--ink-2);
}

.pettycash-check-sep { color: var(--ink-3); }
.pettycash-check-count.is-blocking { color: var(--error); font-weight: 500; }
.pettycash-check-count.is-warning { color: var(--warning); }
.pettycash-check-count.is-info { color: var(--ink-2); }

.pettycash-checks-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.pettycash-check {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.65rem;
  border-radius: var(--r-md);
  font-size: var(--text-sm);
  background: var(--card);
  border: 1px solid var(--border);
}

.pettycash-check-text { flex: 1; min-width: 0; }
.pettycash-check-action { flex-shrink: 0; font-size: var(--text-sm); }

.pettycash-check-dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  flex-shrink: 0;
}

.pettycash-check--error { background: var(--error-soft); border-color: transparent; color: var(--ink); }
.pettycash-check--error .pettycash-check-dot { background: var(--error); }
.pettycash-check--warning { background: var(--warning-soft); border-color: transparent; }
.pettycash-check--warning .pettycash-check-dot { background: var(--warning); }
.pettycash-check--info { background: var(--info-soft); border-color: transparent; }
.pettycash-check--info .pettycash-check-dot { background: var(--info); }

/* The sections and their actions share one rule, so Add line reads as
   belonging to the sheet under it rather than to the box header above. */
.pettycash-tabbar {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}

.pettycash-tabs {
  display: flex;
  gap: 0.15rem;
  min-width: 0;
  overflow-x: auto;
}

.pettycash-tab-actions {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding-bottom: 0.3rem;
  flex-shrink: 0;
}

.pettycash-tab-actions button {
  padding: 0.38rem 0.75rem;
  font-size: 0.82rem;
}

.pettycash-tab {
  border: none;
  /* The app's global button rule rounds every button to 8px, and a 2px bottom
     border on a rounded box curves up at both ends: the active tab read as
     half a rounded rectangle rather than an underline. A tab is a rule under a
     word, so it takes square corners. */
  border-radius: 0;
  background: transparent;
  padding: 0.4rem 0.75rem;
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--ink-2);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.pettycash-tab.active { color: var(--accent); border-bottom-color: var(--accent); }

.pettycash-tab-count {
  font-family: var(--font-data);
  font-size: var(--text-2xs);
  color: var(--brass);
}

.pettycash-panel { padding: 0.65rem; }

/* Said where it bites: the count cannot be saved until the difference is. */
.pettycash-count-note-hint {
  margin: 0.35rem 0 0;
  font-size: var(--text-sm);
  color: var(--warning);
}

/* A hint on the left, the section's own action on the right. */
.pettycash-panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.pettycash-panel-head button {
  flex-shrink: 0;
  padding: 0.38rem 0.75rem;
  font-size: 0.82rem;
}

/* The section's own action, with nothing to its left, and clear of whatever
   the panel lists underneath it. */
.pettycash-panel-head--bare {
  justify-content: flex-end;
  margin-bottom: 0.75rem;
}

.pettycash-panel-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.5rem;
}

.pettycash-panel-toolbar input,
.pettycash-panel-toolbar select {
  padding: 0.35rem 0.55rem;
  font-size: 0.82rem;
  width: auto;
  min-width: 9rem;
}

.pettycash-panel-toolbar input[type='search'] { min-width: 16rem; flex: 1 1 16rem; }

.pettycash-panel-summary,
.pettycash-panel-hint {
  font-size: var(--text-xs);
  color: var(--ink-2);
}

.pettycash-panel-summary {
  font-family: var(--font-data);
  margin-left: auto;
  white-space: nowrap;
}

/* The ledger's count and net take a line of their own under the filters, at
   every width. Beside them it sat right or dropped below depending on how long
   the chosen category and the net's own wording were, so changing the currency
   moved the whole toolbar (owner, 2026-10-10). The line wraps on a phone
   rather than pushing the page sideways. */
.pettycash-panel-summary--own-line {
  flex-basis: 100%;
  text-align: right;
  white-space: normal;
}

.pettycash-panel-hint { margin: 0 0 0.6rem; max-width: 70ch; }

/* The one way into a list that has no rows of its own to add. Sized with the
   sentence it sits in, so it reads as a word, not a button dropped in a line. */
.pettycash-panel-hint .link-button {
  font-size: inherit;
  color: var(--accent);
}

/* The table's own body size. Without it the cells that carry no size class,
   the two description columns, the staff name and the Edit / Delete buttons,
   fell back to the 16px document default and read a size larger than the mono
   columns beside them. `--text-base` is what DESIGN.md gives table cells; the
   mono columns stay at `--text-sm`, which is a smaller number but the same
   optical size, because Plex Mono sets wider than Public Sans. */
.pettycash-table {
  font-size: var(--text-base);
}

/* Numbers scan like a tide table: mono, tabular, right-aligned. */
.pettycash-table .pettycash-ref,
.pettycash-table .pettycash-date,
.pettycash-table .pettycash-amount,
.pettycash-table .pettycash-usd,
.pettycash-table .pettycash-currency,
.pettycash-table .pettycash-variance {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
}

.pettycash-table .pettycash-ref { color: var(--ink-3); }
.pettycash-table .pettycash-currency { color: var(--ink-2); }
.pettycash-table .pettycash-usd { color: var(--ink-2); }
.pettycash-table .pettycash-amount.is-out { color: var(--ink); }
.pettycash-table .pettycash-amount.is-in { color: var(--success); }
/* A receipt paid from an advance: a figure, not a movement. No sign, quiet ink. */
.pettycash-table .pettycash-amount.is-from-advance { color: var(--ink-3); }
.pettycash-table .pettycash-by { font-size: var(--text-xs); color: var(--ink-3); }
/* A line a correction has undone. It stays on the book, because the IN / OUT
   numbers are written on the paper receipts and cannot develop a hole, so it
   has to say on its face that its figure no longer counts: the whole row
   washes back to the quiet ink and the amount is struck through. No colour of
   its own — red is emergency leave, expiries and destructive buttons, and this
   is neither an alarm nor an error (DESIGN.md, red discipline). The mark says
   which line undid it, so the reader can find the pair. */
.pettycash-table tr.is-reversed td { color: var(--ink-3); }
.pettycash-table tr.is-reversed .pettycash-amount,
.pettycash-table tr.is-reversed .pettycash-usd { text-decoration: line-through; }
.pettycash-table tr.is-reversed .pettycash-amount.is-in,
.pettycash-table tr.is-reversed .pettycash-amount.is-out { color: var(--ink-3); }
.pettycash-table .pettycash-reversed {
  color: var(--ink-3);
  font-size: var(--text-xs);
}
.pettycash-table .pettycash-reversed::before { content: ' · '; }
/* Did the cash cross. The same two-tone the receipt column uses one cell to the
   right: witnessed is a settled fact and goes quiet, waiting for a witness is
   the open item and takes the ochre at 500, exactly as unfiled paper does. No
   green on the confirmed one — success is a badge state in this app, and a
   movement that went as movements go is not news (DESIGN.md, colour always
   means something). Red is never in it either: nothing here is an error. */
.pettycash-table .pettycash-crossed {
  color: var(--ink-3);
  font-size: var(--text-xs);
}
.pettycash-table .pettycash-uncrossed {
  color: var(--warning);
  font-size: var(--text-xs);
  font-weight: 500;
}
/* The separator carries its own margins rather than leaning on the spaces in
   the string: this one sits in a flex row, where a leading space collapses. */
.pettycash-table .pettycash-crossed::before,
.pettycash-table .pettycash-uncrossed::before {
  content: '·';
  color: var(--ink-3);
  margin: 0 0.35em;
}
/* Every cell in this table truncates with an ellipsis, which would make the
   crossing mark the first thing to disappear behind a long description — the
   one line that most needs saying would be the one not said. The cell is a
   flex row instead: the description takes the ellipsis, the mark keeps its
   width. Applied to every row, marked or not, so there is one layout here and
   not two. */
.pettycash-table .pettycash-what-row {
  display: flex;
  align-items: baseline;
  min-width: 0;
}
.pettycash-table .pettycash-what-main {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pettycash-table .pettycash-crossed,
.pettycash-table .pettycash-uncrossed { flex: 0 0 auto; }
/* A receipt spent out of an advance: a dot where the sign would be, centred
   against the figure on its own line. Six pixels rather than the width of a
   sentence, on the one table whose item column already truncates (owner,
   2026-09-08). What it means is printed under the rows, because a mark cannot
   explain itself and a tooltip explains nothing on a tablet. */
.pettycash-from-advance {
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-right: 5px;
  border-radius: 50%;
  background: var(--ink-3);
  vertical-align: middle;
}
/* A figure on the row that no line of this advance put there: it was spent
   past an earlier advance of the same person's and landed here (decision 53).
   The open ring reads as "not filled in from here" against the solid dot one
   table over, and the words are under the table, where a tablet can read them
   without hovering (DESIGN.md, marks in a table row). */
.pettycash-carried {
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-right: 5px;
  border: 1px solid var(--ink-3);
  border-radius: 50%;
  vertical-align: middle;
}
/* What the marks above mean, said once. Same voice as the ledger's summary
   line: ink-2 at the hint size, no rule, no box. */
.pettycash-table-note {
  margin: 0.5rem 0 0;
  color: var(--ink-2);
  font-size: var(--text-xs);
  line-height: 1.5;
}
.pettycash-table-note .pettycash-carried { margin-right: 6px; }
/* A receipt in this person's name sits off the advance: something to look at,
   so the warning pigment, filled where the carried mark is a ring. */
.pettycash-off-advance {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 5px;
  border-radius: 50%;
  background: var(--warning);
  vertical-align: middle;
}
.pettycash-table-note .pettycash-off-advance { margin-right: 6px; }
/* Given up on. It goes as quiet as a reversed line, and for the same reason:
   it is on the page to be found and undone, not to be read as a live figure.
   No red, this is neither an alarm nor an error (DESIGN.md, red discipline). */
.pettycash-table tr.is-written-off td { color: var(--ink-3); }
.pettycash-table tr.is-written-off .pettycash-usd { text-decoration: line-through; }
.pettycash-table tr.is-written-off .pettycash-row-actions,
.pettycash-table tr.is-written-off td:last-child { text-decoration: none; }
/* The receipt state goes quiet with the rest of the row: ochre on a line that
   does not count is the page asking for paper that was never going to exist. */
.pettycash-table tr.is-reversed .pettycash-receipt-missing,
.pettycash-table tr.is-reversed .pettycash-receipt-ok,
.pettycash-table tr.is-reversed .pettycash-receipt-na { color: var(--ink-3); }
/* Column widths are set once here rather than left to the browser: with twelve
   columns and every cell on one line, auto layout starves the description,
   which is the column the Cruise Manager actually reads. `table-layout: fixed`
   is what makes the browser honour them: left to itself it was collapsing the
   description to nothing whenever the month's descriptions happened to be
   short, and truncating the currency header to "C…". */
#pc-ledger-table { table-layout: fixed; width: 100%; }
/* Twelve columns in about a thousand pixels: the ones whose content is bounded
   (reference, date, currency, the three money columns, the author) are given
   exactly what their longest value needs, and the description is left unsized
   so `table-layout: fixed` hands it everything that is left. The inherited
   0.75rem cell padding costs 24px a column, which is a quarter of the currency
   column, so this table takes a tighter one. */
.pettycash-table th,
.pettycash-table td {
  padding-left: 0.4rem;
  padding-right: 0.4rem;
}

.pc-col-ref { width: 72px; }
.pc-col-date { width: 66px; }
/* Wide enough for the longest thing a line can be, "Change back from an
   advance", so the column is read rather than guessed at. */
.pc-col-what-is { width: 224px; }
.pc-col-when { width: 116px; }
.pc-col-who { width: 96px; }
/* Wide enough for the longest act on the trail, which is now "Handover undone":
   a verb column that ellipses its verb is a column that says nothing. */
.pc-col-act { width: 156px; }
/* A crew name is the thing you scan the column for: "Moha…" is not a name.
   The item column carries the rest of the width and gives this one its due. */
.pc-col-staff { width: 124px; }
.pc-col-amount { width: 100px; }
.pc-col-cur { width: 48px; }
.pc-col-usd { width: 92px; }
.pc-col-receipt { width: 76px; }
.pc-col-by { width: 72px; }
/* Three icon buttons and the room to press them: Edit, then Delete or Reverse,
   and Acknowledge on an office movement the office is reading. Words needed 116
   pixels and still cut the third one; the item column keeps the difference. */
.pc-col-actions { width: 88px; }

.pettycash-table td,
.pettycash-table th {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* What a line was: the label the year is searched on, then its note in the
   quieter ink. One column, because "Taxi | Taxi | Taxi to the airport" was the
   same fact written three times. */
.pettycash-table .pettycash-what { max-width: 34rem; }
.pettycash-table .pettycash-note { color: var(--ink-2); }
.pettycash-table .pettycash-note::before { content: ' · '; color: var(--ink-3); }
/* The booking the line belongs to: mono, because it is a number to be read off
   the row and matched against the reservation, not prose. */
.pettycash-table .pettycash-booking {
  color: var(--ink-2);
  font-family: var(--font-data);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}
.pettycash-table .pettycash-booking::before {
  content: ' · ';
  color: var(--ink-3);
  font-family: var(--font-ui);
}
.pettycash-table .pettycash-row-actions { overflow: visible; }

.pettycash-receipt-ok { color: var(--ink-3); font-size: var(--text-xs); }
.pettycash-receipt-na { color: var(--ink-3); font-size: var(--text-xs); }
.pettycash-receipt-missing { color: var(--warning); font-size: var(--text-xs); font-weight: 500; }

.pettycash-outstanding.is-late { color: var(--warning); font-weight: 500; }
/* What one person holds in all, under their advances (decision 53). */
.pettycash-holding-row td {
  border-top: 1px solid var(--border-strong);
  font-weight: 500;
}
.pettycash-variance-row .pettycash-variance { color: var(--error); }

.pettycash-row-actions { white-space: nowrap; text-align: right; }
.pettycash-row-actions .link-button + .link-button { margin-left: 0.5rem; }

/* What can be done to a line, drawn rather than spelled out: three words in a
   column this table cannot spare truncated the third of them, and it was the
   item column that was paying for them. Quiet until the row is under the
   pointer, because eleven columns of ink with a row of buttons shouting at the
   end of each is not a page anybody reads. */
.pettycash-row-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
  vertical-align: middle;
}
.pettycash-row-btn + .pettycash-row-btn { margin-left: 2px; }
.pettycash-row-btn:hover { color: var(--ink); background: var(--surface-raised); }
/* Red is for the destructive one and nothing else (DESIGN.md, red discipline),
   and only once the pointer is on it: a trash can in red down the whole column
   is an alarm about a page where nothing is wrong. */
.pettycash-row-btn[data-delete]:hover { color: var(--error); background: var(--error-soft); }
.pettycash-row-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  color: var(--ink);
}
tr:hover .pettycash-row-btn { color: var(--ink-2); }

/* Filing a scan by hand: the Cruise Manager often holds the paper the crew
   never photographed. Same row as the rate form on the Rates panel. */
.pettycash-receipt-upload {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 0.65rem;
}

/* The form, and at the far end which scans are being shown: one row, because
   the panel is a working surface and not a stack of bands. */
.pettycash-receipt-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 0.65rem;
  margin: 0 0 0.75rem;
}

.pettycash-receipt-bar > .pettycash-receipt-upload { flex: 1 1 auto; margin: 0; }

/* Set apart from the form's own fields by a hairline: filing a scan and
   looking one up are two things, and the button between them is the one
   action on the panel. */
.pettycash-receipt-scope {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  margin-left: auto;
  padding-left: 0.9rem;
  border-left: 1px solid var(--border);
  font-size: var(--text-xs);
}

.pettycash-receipt-scope select { height: 2.1rem; padding-top: 0; padding-bottom: 0; }

/* Direct children only. The crew picker in this row is a div with a label of
   its own inside it, and an unscoped `label:last-of-type` is that label too:
   it took `flex: 1 1 16rem` inside a column and grew downwards, standing the
   word "Who spent it" 250px above its own field. */
.pettycash-receipt-upload > label,
.pettycash-receipt-upload > .pettycash-picker {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: var(--text-xs);
  /* The app's forms give a label 4px under it, which in a row of controls is
     4px the button does not have: enough to read as crooked. */
  margin-bottom: 0;
}

/* Wide enough to read a name and its department in the list under it, and no
   wider: the note is the field that takes the rest of the row. */
.pettycash-receipt-upload > .pettycash-picker { flex: 0 1 15rem; }

.pettycash-receipt-upload > label:last-of-type { flex: 1 1 16rem; }

/* The button is a field in this row, so it is the height of one: the page's
   default button is 3px taller than the input beside it, which is exactly
   enough to read as crooked. The file input keeps its own height and the row
   lines their bottoms up. */
.pettycash-receipt-upload input:not([type='file']),
.pettycash-receipt-upload button {
  height: 2.1rem;
  padding-top: 0;
  padding-bottom: 0;
}

/* The receipt column is a control, not a label: it must not look like a
   button, only read as the word it already showed. */
button.pettycash-receipt-missing {
  font-size: var(--text-xs);
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 2px;
}

a.pettycash-receipt-ok { text-decoration: underline; text-underline-offset: 2px; }

/* Receipts inbox: the photo beside what was read off it. */
.pettycash-receipt-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 0.75rem;
}

.pettycash-receipt-grid .empty-state { grid-column: 1 / -1; }

.pettycash-receipt-card {
  display: flex;
  gap: 0.65rem;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 0.6rem;
  background: var(--card);
}

.pettycash-receipt-thumb {
  flex: 0 0 96px;
  height: 128px;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--fill);
  display: block;
}

.pettycash-receipt-thumb img { width: 100%; height: 100%; object-fit: cover; }

/* A PDF has no thumbnail of its own without a renderer, so it is shown as
   what it is: a document that opens. */
.pettycash-receipt-doc {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  height: 100%;
  padding: 0.4rem;
  text-align: center;
  font-size: var(--text-2xs);
  color: var(--ink-3);
  overflow-wrap: anywhere;
}

.pettycash-receipt-doc strong {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  color: var(--ink-2);
  letter-spacing: 0.06em;
}

.pettycash-receipt-body { min-width: 0; display: flex; flex-direction: column; gap: 0.3rem; }
.pettycash-receipt-who { font-size: var(--text-xs); color: var(--ink-3); margin: 0; }
.pettycash-receipt-note { font-size: var(--text-sm); margin: 0; }
.pettycash-receipt-read { font-size: var(--text-sm); margin: 0; font-family: var(--font-data); }
.pettycash-receipt-read--none { color: var(--ink-3); font-family: var(--font-ui); }
/* The reason, under the fact: quieter than the line above it, because it is
   read once and acted on, not scanned. */
.pettycash-receipt-why { font-size: var(--text-xs); color: var(--ink-3); }

/* Where a scan went, on a card that is no longer waiting for anything. The
   line number is the mono half, because that is what is written on the paper
   and what is looked up. */
.pettycash-receipt-where {
  font-size: var(--text-xs);
  color: var(--ink-2);
  margin: 0;
}

.pettycash-receipt-where strong {
  font-family: var(--font-data);
  font-weight: 500;
  color: var(--ink);
}

/* What the photo attached to a line gave, said in the dialog that is still
   being filled in. */
.pettycash-receipt-status { font-size: var(--text-xs); color: var(--ink-3); }
.pettycash-receipt-status.is-read { color: var(--success); font-weight: 500; }
.pettycash-receipt-actions { display: flex; gap: 0.35rem; margin-top: auto; }
.pettycash-receipt-actions button { padding: 0.3rem 0.6rem; font-size: var(--text-xs); }

.pettycash-count-card {
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 0.65rem;
  margin-bottom: 0.6rem;
}

.pettycash-count-card header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 0.9rem;
}

/* The title holds the left; the verdict and what can be done with the count
   sit together on the right. Spread evenly, a card with two actions put its
   pill and Delete in the middle of nowhere. */
.pettycash-count-card header h3 { margin-right: auto; }

.pettycash-count-card h3 {
  margin: 0;
  font-size: var(--text-base);
  font-weight: 600;
  text-transform: capitalize;
}

.pettycash-count-who,
.pettycash-count-note { font-size: var(--text-xs); color: var(--ink-2); margin: 0.2rem 0 0.45rem; }

.pettycash-rate-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.pettycash-rate-form label {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: var(--text-xs);
  margin-bottom: 0;
}

.pettycash-rate-form button {
  height: 2.1rem;
  padding-top: 0;
  padding-bottom: 0;
  font-size: 0.82rem;
}

/* The rate's own arithmetic, on demand: a link in the row, a bubble under it. */
.pettycash-rate-help {
  position: relative;
  display: flex;
  align-items: center;
  height: 2.1rem;
  margin-left: 0.35rem;
}

.pettycash-rate-form .pettycash-rate-help .link-button {
  height: auto;
  font-size: var(--text-xs);
  color: var(--accent);
}

.pettycash-rate-help-panel {
  position: absolute;
  left: 0;
  top: calc(100% + 0.35rem);
  z-index: 30;
  width: 26rem;
  max-width: calc(100vw - 2rem);
  padding: 0.6rem 0.75rem;
  background: var(--card);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
  font-size: var(--text-sm);
  color: var(--ink);
}

.pettycash-rate-help-panel ol {
  margin: 0;
  padding-left: 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.pettycash-rate-help-panel a { color: var(--accent); }

.pettycash-rate-help-example {
  margin: 0.5rem 0 0;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
  color: var(--ink-2);
}

.pettycash-rate-help-example .num {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}
.pettycash-rate-form input,
.pettycash-rate-form select { padding: 0.35rem 0.55rem; font-size: 0.82rem; min-width: 9rem; }

.pettycash-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 0.3rem);
  z-index: 30;
  background: var(--card);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
  display: flex;
  flex-direction: column;
  min-width: 15rem;
  padding: 0.25rem;
}

/* The app's global button rule centres its label with justify-content, so
   text-align alone was never going to move these: a menu is a list of things
   to read down, and a reader's eye needs one left edge, not five. */
.pettycash-menu button {
  background: transparent;
  border: none;
  justify-content: flex-start;
  text-align: left;
  padding: 0.4rem 0.6rem;
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  color: var(--ink);
  border-radius: var(--r-sm);
  cursor: pointer;
}

.pettycash-menu button:hover { background: var(--surface-raised); }

.pettycash-dialog {
  max-width: 40rem;
  width: calc(100vw - 2rem);
  /* A tall dialog keeps its own scroll: without this a wheel or a trackpad
     reaching either end carries on into the ledger behind it, and the dialog
     then sits frozen for the rest of the gesture (owner, 2026-10-26: the
     vessel login preview could not be scrolled). Same as the shared recipe
     on .add-staff-month-dialog. */
  overscroll-behavior: contain;
}

/* The vessel login preview: under each person, what of theirs moves. */
.pettycash-names-table td { white-space: normal; }
.pettycash-names-what td {
  padding-top: 0;
  color: var(--ink-2);
  font-size: var(--text-xs);
}

/* A refusal has to be visible before the click: the handover cannot be saved
   until the box has been counted, so the button says so. */
.pettycash-dialog button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  filter: none;
}
.pettycash-dialog--wide { max-width: 62rem; }
/* Receipt links is four short columns and one field: given the width of a
   spreadsheet it spread a name to one edge and a date to the other, and the
   search box under it became a banner with a list floating loose beneath. It
   reads down the page instead, at about the width of a phone. */
.pettycash-dialog--narrow { max-width: 30rem; }

/* A crew link, once it exists: the address in a field you can select, because
   a clipboard write can be refused and a link nobody can read again is a link
   that gets issued twice. */
.pettycash-capture-fresh {
  margin: 0.6rem 0 0.75rem;
  padding: 0.6rem 0.7rem;
  border-radius: var(--r-md);
  background: var(--brass-soft);
}

.pettycash-capture-fresh-line {
  margin: 0 0 0.4rem;
  font-size: var(--text-xs);
  color: var(--ink);
}

.pettycash-capture-copy { display: flex; gap: 0.4rem; }
.pettycash-capture-copy button { white-space: nowrap; }
#pc-capture-table .pettycash-row-actions { display: flex; gap: 0.75rem; justify-content: flex-end; }
.pettycash-capture-copy input {
  flex: 1 1 auto;
  font-family: var(--font-data);
  font-size: var(--text-xs);
}

.pettycash-capture-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-top: 0.75rem;
}

/* The field, whether it is a plain label or the crew picker. It stops well
   short of the dialog's edge: a search box the width of the room it sits in
   is a box you cannot tell the list under it belongs to. */
.pettycash-capture-form > label,
.pettycash-capture-form > .pettycash-picker {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: var(--text-xs);
  max-width: 22rem;
}

.pettycash-picker > label { flex: none; }

.pettycash-form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.5rem 0.65rem;
}

.pettycash-form-grid label { display: flex; flex-direction: column; gap: 0.2rem; font-size: var(--text-xs); }

/* Picking a person out of fifty. A <select> in the directory's department
   order is a list to read; this one takes a name and narrows to it. Laid out
   like the labels beside it so it sits in the same grid without a seam. */
.pettycash-picker {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: var(--text-xs);
}

/* The width of the field it hangs from, exactly: that is what says which field
   it belongs to. The fields it hangs from are the ones kept narrow enough for
   that to be a list rather than a banner. */
.pettycash-picker-list {
  position: absolute;
  z-index: 30;
  top: 100%;
  left: 0;
  right: 0;
  margin: 0.15rem 0 0;
  padding: 0.2rem;
  max-height: 15rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  list-style: none;
  background: var(--card);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: 0 12px 32px rgba(27, 36, 50, 0.14);
}

/* Opened upward, when the room below is the dialog's edge. */
.pettycash-picker-list.is-above {
  top: auto;
  bottom: 100%;
  margin: 0 0 0.15rem;
}

.pettycash-picker-option {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.9rem;
  padding: 0.3rem 0.45rem;
  border-radius: var(--r-sm);
  cursor: pointer;
  font-size: var(--text-sm);
}

.pettycash-picker-option.is-active { background: var(--surface-raised); }
.pettycash-picker-option[aria-selected="true"] { font-weight: 500; }

/* Neither half of a row pushes the other out of the list. In a picker narrow
   enough to have to choose, the name you are reading for keeps its room and
   the second line is the one that gives way. */
.pettycash-picker-option > span:first-child {
  flex: 0 0 auto;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The department, or the full name when the short one is not it: what tells
   two Mohameds apart without making the row shout. */
.pettycash-picker-quiet {
  flex: 0 1 auto;
  min-width: 0;
  font-size: var(--text-xs);
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pettycash-picker-empty {
  padding: 0.35rem 0.45rem;
  font-size: var(--text-xs);
  color: var(--ink-3);
}
.pettycash-form-wide { grid-column: 1 / -1; }
/* The two fields that carry the line: wide enough to read a whole label. */
.pettycash-form-half { grid-column: span 2; }
.pettycash-optional { color: var(--ink-3); font-weight: 400; }

/* The guest-change block: a fact, a decision, and what the decision will cost
   you next. Set apart from the fields above because it is a question, not
   another thing to type. */
.pettycash-change {
  margin-top: 0.75rem;
  padding: 0.6rem 0.7rem;
  border-radius: var(--r-md);
  background: var(--brass-soft);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.pettycash-change label {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: var(--text-xs);
}

/* A yes/no sits on one line: the question is short and the answer is a tick. */
.pettycash-change label.pettycash-change-check {
  flex-direction: row;
  align-items: center;
  gap: 0.4rem;
}

.pettycash-change-check input {
  width: auto;
  margin: 0;
}

.pettycash-change-line {
  margin: 0;
  font-size: var(--text-sm);
  font-family: var(--font-data);
  color: var(--ink);
}

.pettycash-change-hint {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--ink-2);
}

.pettycash-entry-usd {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  color: var(--ink-2);
  margin: 0.6rem 0 0;
}

.pettycash-dialog-error {
  color: var(--error);
  font-size: var(--text-sm);
  margin: 0.5rem 0 0;
}

/* A question the save asked back, not a refusal: ochre, never red. */
.pettycash-dialog-error.is-warning {
  color: var(--warning);
}

/* The count sheet: one column per currency, notes largest first, exactly the
   order the cash is stacked in. */
.pettycash-count-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 0.75rem;
  margin: 0.75rem 0;
}

.pettycash-count-currency h3 {
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin: 0 0 0.3rem;
}

.pettycash-denomination {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.2rem;
}

.pettycash-denomination-value {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
  color: var(--ink-2);
  width: 3rem;
  text-align: right;
}

.pettycash-denomination input {
  width: 4.5rem;
  padding: 0.25rem 0.4rem;
  font-family: var(--font-data);
  font-size: var(--text-sm);
}

.pettycash-count-add select {
  width: 100%;
  padding: 0.3rem 0.4rem;
  font-size: var(--text-sm);
}

.pettycash-count-subtotal {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
  border-top: 1px solid var(--border);
  padding-top: 0.25rem;
  margin: 0.3rem 0 0;
  text-align: right;
}

.pettycash-count-verdict {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  padding: 0.5rem 0.65rem;
  border-radius: var(--r-md);
  background: var(--fill);
}

.pettycash-verdict {
  display: flex;
  flex-direction: column;
  font-size: var(--text-xs);
  font-family: var(--font-data);
}

.pettycash-verdict strong { font-size: var(--text-base); font-weight: 500; }
.pettycash-verdict.is-ok strong { color: var(--success); }
.pettycash-verdict.is-off strong { color: var(--error); }
.pettycash-verdict-detail { color: var(--ink-3); }

/* --- Handing the box over: the dialog, then the sheet that is printed ---- */

.pettycash-handover-count {
  margin-bottom: 0.75rem;
  padding: 0.5rem 0.65rem;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-raised);
}

.pettycash-handover-count h3 {
  margin: 0 0 0.35rem;
  font-size: var(--text-sm);
  font-weight: 600;
}

.pettycash-handover-count table { margin-top: 0.35rem; }

.pettycash-handover-count.is-missing {
  background: var(--warning-soft);
  border-color: transparent;
}

.pettycash-handover-note {
  margin: 0.35rem 0 0;
  font-size: var(--text-sm);
  color: var(--ink-2);
}

#pc-handover-sheet { text-decoration: none; }

/* The envelopes and whatever else travels with the cash: a short editable list
   inside the dialog, on the same table recipe as the rest of the section. */
.pettycash-handover-extras {
  margin-bottom: 0.75rem;
}

.pettycash-handover-extras .pettycash-panel-head {
  align-items: center;
  margin-bottom: 0.25rem;
}

.pettycash-handover-extras input,
.pettycash-handover-extras select {
  width: 100%;
  min-width: 0;
  padding: 0.25rem 0.4rem;
  font-size: var(--text-sm);
}

.pettycash-handover-extras td { overflow: visible; }
.pettycash-handover-extras th:nth-child(3),
.pettycash-handover-extras td:nth-child(3) { width: 7rem; }
.pettycash-handover-extras th:nth-child(4),
.pettycash-handover-extras td:nth-child(4) { width: 5.5rem; }
.pettycash-handover-extras th:last-child,
.pettycash-handover-extras td:last-child { width: 5rem; }

/* Room to write on the printed sheet: whatever the drawer gives up while the
   two managers are standing over it goes in pen, on a ruled line. */
.handover-blank-row td {
  height: 1.6rem;
}

/* The printed sheet (/pettycash-handover.html). Portrait, one page: the
   paper it replaces is signed by both managers and filed by the office. */
.handover-sheet {
  max-width: 820px;
}

.handover-parties {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2.5rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.9rem;
}

.handover-field {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.handover-field-label {
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
}

.handover-field-value {
  font-size: var(--text-base);
}

.handover-field-value.num {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}

.handover-section-title {
  margin: 1rem 0 0.4rem;
  font-size: var(--text-sm);
  font-weight: 600;
}

.handover-currency {
  margin-bottom: 0.9rem;
  break-inside: avoid;
}

.handover-total-row td {
  border-top: 1px solid var(--border-strong);
  font-weight: 500;
}

.handover-variance.is-off { color: var(--error); }
.handover-variance.is-ok { color: var(--success); }

.handover-signatures {
  display: flex;
  gap: 2.5rem;
  margin-top: 2rem;
}

.handover-signature {
  flex: 1 1 0;
}

.handover-signature-line {
  height: 2.6rem;
  border-bottom: 1px solid var(--ink-3);
}

.handover-signature-name {
  margin: 0.3rem 0 0;
  font-size: var(--text-xs);
  color: var(--ink-2);
}

/* --- The crew capture page: one phone, one thumb, nothing else ---------- */

.capture-page {
  background: var(--canvas);
  min-height: 100vh;
}

.capture-shell {
  max-width: 30rem;
  margin: 0 auto;
  padding: 1.25rem 1rem 3rem;
}

.capture-header h1 {
  font-size: var(--text-lg);
  font-weight: 600;
  margin: 0;
}

.capture-who {
  font-size: var(--text-sm);
  color: var(--ink-2);
  margin: 0.2rem 0 1rem;
}

.capture-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  box-shadow: var(--shadow-card);
}

.capture-card label { display: flex; flex-direction: column; gap: 0.3rem; font-size: var(--text-sm); }
.capture-row { display: flex; gap: 0.6rem; }
.capture-row label { flex: 1; }

/* The photo is the point of the page: a target you cannot miss with a thumb. */
.capture-photo { position: relative; }
.capture-photo input[type='file'] { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; }

.capture-photo-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 3.5rem;
  border: 2px dashed var(--border-strong);
  border-radius: var(--r-md);
  color: var(--accent);
  font-weight: 500;
}

.capture-sources { display: flex; flex-direction: column; gap: 0.5rem; }

/* A computer has no camera to point at a receipt, and there the first button
   would only open the same file picker as the second. */
@media (hover: hover) and (pointer: fine) {
  .capture-photo--camera { display: none; }
}

.capture-picked {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--muted);
  overflow-wrap: anywhere;
}

.capture-preview {
  width: 100%;
  max-height: 16rem;
  object-fit: contain;
  border-radius: var(--r-md);
  margin-top: 0.5rem;
}

.capture-page input,
.capture-page select,
.capture-page button {
  font-size: 1rem;
  padding: 0.65rem 0.75rem;
}

.capture-page button { min-height: 3rem; }

/* What became of the photo, said where the crew member is looking. */
.capture-status {
  font-size: var(--text-sm);
  color: var(--ink-2);
  margin: 0;
}

.capture-status.is-read {
  color: var(--success);
  font-weight: 500;
}

.capture-status.is-quiet { color: var(--ink-3); }
.capture-error { color: var(--error); font-size: var(--text-sm); margin: 0; }
.capture-card h2 { font-size: var(--text-base); font-weight: 600; margin: 0; }

/* ——— A phone, at the desk in the crew mess or on the jetty ———
   The book is normally kept on a laptop, but a Cruise Manager checking a
   figure between guests has a phone in their hand, and until now the whole
   page slid sideways under the navbar. Nothing is hidden at this width: a
   petty cash you can only half read is one you stop reading. */
@media (max-width: 760px) {
  .page {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
  }

  /* Who holds the box is a sentence, and a sentence wraps. Held on one line it
     ran off the card and said "Nobody has taken the p". */
  .pettycash-custody {
    white-space: normal;
    flex: 1 0 100%;
  }

  .pettycash-command-primary,
  .pettycash-command-actions {
    flex-wrap: wrap;
  }

  /* What needs attention keeps to the right-hand end of the card, wherever it
     lands: full width it left a band of empty card, and at the start of its
     line it read as a bullet under the custody sentence. */
  .pettycash-command-actions {
    margin-left: auto;
    justify-content: flex-end;
  }

  /* The sections and the buttons stop sharing a line: the strip was scrolling
     under More and Add entry, so the last section was always half hidden
     behind them. Buttons first, thumb-sized, then the sections across the
     whole width. */
  .pettycash-tabbar {
    flex-wrap: wrap;
    align-items: stretch;
    gap: 0.35rem;
  }

  .pettycash-tab-actions {
    order: 1;
    width: 100%;
    justify-content: flex-end;
    padding-bottom: 0;
  }

  .pettycash-tab-actions button {
    min-height: 2.5rem;
  }

  .pettycash-tabs {
    order: 2;
    width: 100%;
    /* Sideways, and only sideways. The strip could scroll a couple of pixels
       vertically too, which is what made it float under the thumb whenever it
       was dragged across. */
    overflow-y: hidden;
    touch-action: pan-x;
    scrollbar-width: none;
  }

  .pettycash-tabs::-webkit-scrollbar { display: none; }

  /* A wide table scrolls inside its card (.table-wrap), and on a phone it needs
     to be obvious that it does. */
  .pettycash-table {
    font-size: 0.8rem;
  }

  .pettycash-panel-toolbar input,
  .pettycash-panel-toolbar select {
    flex: 1 1 9rem;
    min-width: 0;
  }

  .pettycash-dialog {
    width: calc(100vw - 1rem);
    padding: 1rem;
  }

  /* Fingers, not a mouse: the app's 0.35rem controls are fine under a cursor
     and are a coin toss under a thumb. */
  .pettycash-dialog input,
  .pettycash-dialog select,
  .pettycash-dialog button {
    min-height: 2.5rem;
    font-size: 0.95rem;
  }

  .pettycash-menu {
    max-width: calc(100vw - 1.5rem);
  }
}

/* ——— Directory → Freelance guides (owner ask 2026-09-19) ——————————————————————
   The ranked pool of freelance guides, and one guide's sheet.
   Reuses the directory table recipe; stars are data, drawn in ink, never
   in the action color or brass. "Do not hire" is the one word in --error. */
.guides-table .guide-col-rank { width: 4%; }
.guides-table .guide-col-name { width: 14%; }
.guides-table .guide-col-full-name { width: 12%; }
.guides-table .guide-col-standing { width: 10%; }
.guides-table .guide-col-rating { width: 10%; }
.guides-table .guide-col-reviews { width: 7%; }
.guides-table .guide-col-cruises { width: 7%; }
.guides-table .guide-col-last { width: 12%; }
.guides-table .guide-col-next { width: 12%; }
.guides-table .guide-col-phone { width: 12%; }

/* Five stars must never be cut to four and an ellipsis. */
.guides-table td.guide-rating-cell {
  text-overflow: clip;
}

.guides-table td {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.guides-table th[data-guide-sort] {
  cursor: pointer;
  user-select: none;
}

.guides-table th[data-guide-sort]:hover {
  color: var(--ink);
}

.guides-table th[data-guide-sort].sorted {
  color: var(--accent);
}

.guides-table th.sorted[aria-sort='ascending']::after { content: ' ↑'; }
.guides-table th.sorted[aria-sort='descending']::after { content: ' ↓'; }

.guide-name-cell {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

.guide-name {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--accent);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  text-align: left;
}

.guide-name:hover .guide-name-text {
  text-decoration: underline;
}

.guide-name-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}


.guide-avatar {
  flex: none;
  object-fit: cover;
  background: var(--fill);
}

.guide-avatar--sm {
  width: 22px;
  height: 22px;
  border-radius: 50%;
}

.guide-avatar--lg {
  width: 120px;
  height: 120px;
  border-radius: var(--r-md);
}

.guide-avatar--empty {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-2);
  font-weight: 500;
  border: 1px solid var(--border);
}

.guide-avatar--sm.guide-avatar--empty { font-size: 0.6rem; }
.guide-avatar--lg.guide-avatar--empty { font-size: 2rem; }

/* The list's 22px photo, shown large beside the pointer while it rests on it. */
.guide-photo-peek {
  position: fixed;
  z-index: 1000;
  width: 200px;
  height: 200px;
  object-fit: cover;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--fill);
  box-shadow: var(--shadow-pop);
  pointer-events: none;
}

.guide-stars {
  display: inline-flex;
  gap: 1px;
  vertical-align: -2px;
}

.guide-star {
  width: 13px;
  height: 13px;
  fill: none;
  stroke: var(--border-strong);
  stroke-width: 1.2;
  stroke-linejoin: round;
}

.guide-star--on {
  fill: var(--ink-2);
  stroke: var(--ink-2);
}

.guide-from-reviews {
  margin-left: 0.35rem;
  font-size: var(--text-2xs);
}

.guide-standing {
  font-weight: 500;
}

.guide-standing--first_call { color: var(--accent); }
.guide-standing--good { color: var(--ink); }
.guide-standing--backup { color: var(--ink-2); font-weight: 400; }
.guide-standing--none { color: var(--ink-3); font-weight: 400; }
.guide-standing--do_not_hire { color: var(--error); }

.guide-row--excluded td {
  color: var(--ink-3);
}

.guide-row--excluded .guide-name,
.guide-row--excluded .guide-star--on {
  color: var(--ink-2);
  fill: var(--ink-3);
  stroke: var(--ink-3);
}

.guide-muted {
  color: var(--ink-3);
}

.guide-date,
.guide-num,
.guide-phone,
.guide-rank {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.guide-phone {
  color: var(--ink);
  text-decoration: none;
}

.guide-phone:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* The sheet */
.guide-sheet {
  max-width: 44rem;
  width: calc(100vw - 2rem);
  max-height: calc(100vh - 3rem);
  overflow-y: auto;
  padding: 1.25rem 1.5rem 1rem;
  color: var(--ink);
  background: var(--card);
}

.guide-sheet-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 1rem;
  align-items: start;
  margin-bottom: 1rem;
}

.guide-sheet-photo {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
}

.guide-photo-change {
  font-size: var(--text-xs);
}

.guide-sheet-name {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.guide-rank {
  margin-left: 0.4rem;
  font-weight: 500;
  color: var(--ink);
}

.guide-sheet-full,
.guide-sheet-kind,
.guide-sheet-contact {
  margin: 0.15rem 0 0;
}

.guide-sheet-full {
  color: var(--ink-2);
}

.guide-sheet-kind {
  font-size: var(--text-xs);
  color: var(--ink-3);
}

.guide-sheet-contact {
  display: flex;
  gap: 0.75rem;
  align-items: baseline;
  margin-top: 0.4rem;
}

.guide-contact-link {
  font-size: var(--text-xs);
  font-weight: 500;
}

.guide-sheet-close {
  width: 28px;
  height: 28px;
  padding: 6px;
  border: none;
  background: none;
  color: var(--ink-2);
  cursor: pointer;
  border-radius: var(--r-sm);
}

.guide-sheet-close:hover {
  background: var(--fill);
  color: var(--ink);
}

.guide-sheet-close svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.35;
  stroke-linecap: round;
}

.guide-facts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.5rem 1rem;
  margin: 0 0 0.75rem;
  padding: 0.65rem 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

.guide-facts--pair {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border: none;
  padding: 0;
}

.guide-fact dt,
.guide-label,
.guide-form-label {
  display: block;
  margin: 0 0 0.2rem;
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.guide-fact dd {
  margin: 0;
}

.guide-section {
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border);
}

.guide-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.5rem;
}

.guide-section-title {
  margin: 0;
  font-size: var(--text-base);
  font-weight: 600;
}

.guide-count {
  font-weight: 400;
  margin-left: 0.25rem;
}

.guide-edit-btn {
  padding: 0.25rem 0.7rem;
  font-size: var(--text-xs);
}

.guide-text-block {
  margin-top: 0.6rem;
}

.guide-text-block p {
  margin: 0;
  white-space: pre-line;
  line-height: 1.5;
}

.guide-empty-line {
  margin: 0.25rem 0;
  font-size: var(--text-sm);
}

.guide-updated {
  margin: 0.6rem 0 0;
  font-size: var(--text-xs);
  color: var(--ink-3);
}

.guide-form label {
  display: block;
  margin: 0.55rem 0 0.25rem;
  font-size: var(--text-sm);
  font-weight: 500;
}

.guide-form .guide-form-label {
  margin-top: 0.55rem;
}

.guide-form input,
.guide-form select,
.guide-form textarea {
  width: 100%;
  box-sizing: border-box;
}

.guide-form-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 1rem;
}

.guide-form-actions {
  margin-top: 0.75rem;
}

.guide-star-picker {
  display: flex;
  align-items: center;
  gap: 2px;
  min-height: 34px;
}

.guide-star-btn {
  padding: 3px;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: var(--r-sm);
}

.guide-star-btn .guide-star {
  width: 20px;
  height: 20px;
}

.guide-star-btn.is-on .guide-star {
  fill: var(--ink-2);
  stroke: var(--ink-2);
}

.guide-star-btn:hover {
  background: var(--fill);
}

.guide-star-clear {
  margin-left: 0.5rem;
  font-size: var(--text-xs);
}

.guide-reviews {
  list-style: none;
  margin: 0;
  padding: 0;
}

.guide-review {
  padding: 0.5rem 0;
  border-top: 1px solid var(--border);
}

.guide-review:first-child {
  border-top: none;
  padding-top: 0;
}

.guide-review-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.6rem;
}

.guide-review-source {
  font-weight: 500;
}

.guide-review-meta {
  font-size: var(--text-xs);
}

.guide-review-remove {
  margin-left: auto;
  font-size: var(--text-xs);
  color: var(--ink-2);
}

.guide-review-text {
  margin: 0.25rem 0 0;
  white-space: pre-line;
  line-height: 1.5;
}

.guide-review-add {
  margin-top: 0.6rem;
}

.guide-review-add summary {
  cursor: pointer;
  font-weight: 500;
  color: var(--accent);
}

.guide-upcoming {
  margin: 0 0 0.75rem;
  padding: 0;
  list-style: none;
}

.guide-upcoming li {
  padding: 0.1rem 0;
}

.guide-cruises-wrap {
  max-height: 16rem;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}

.guide-cruises {
  width: 100%;
  border-collapse: collapse;
}

.guide-cruises th {
  position: sticky;
  top: 0;
  background: var(--fill);
  text-align: left;
  padding: 0.35rem 0.6rem;
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.guide-cruises td {
  padding: 0.25rem 0.6rem;
  border-top: 1px solid var(--border);
}

.guide-cruises .num-col {
  text-align: right;
  font-family: var(--font-data);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.guide-review-by {
  margin: 0.2rem 0 0;
  font-size: var(--text-xs);
  color: var(--ink-2);
}

.guide-actor {
  font-weight: 500;
  color: var(--ink);
}

.guide-history {
  list-style: none;
  margin: 0;
  padding: 0;
}

.guide-history-item {
  display: grid;
  grid-template-columns: 9.5rem 8rem 1fr;
  gap: 0.75rem;
  padding: 0.3rem 0;
  border-top: 1px solid var(--border);
  font-size: var(--text-sm);
}

.guide-history-item:first-child {
  border-top: none;
}

.guide-history-when {
  color: var(--ink-2);
  font-size: var(--text-xs);
  padding-top: 1px;
}

.guide-history-more {
  margin-top: 0.4rem;
  font-size: var(--text-xs);
}

@media (max-width: 640px) {
  .guide-history-item {
    grid-template-columns: 1fr;
    gap: 0.1rem;
  }
}

.guide-sheet-foot {
  padding-top: 0.75rem;
  font-size: var(--text-sm);
}

@media (max-width: 640px) {
  .guide-sheet {
    padding: 1rem;
  }

  .guide-facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .guide-form-row {
    grid-template-columns: 1fr;
  }
}


/* Freelance guides → Standing filter: looks like the selects beside it,
   opens a list of checkboxes so several standings show at once. */
.guide-standing-filter {
  position: relative;
}

.guide-standing-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  min-width: 14rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.guide-standing-summary::-webkit-details-marker {
  display: none;
}

.guide-standing-summary::after {
  content: '';
  width: 7px;
  height: 7px;
  margin-top: -3px;
  border-right: 1.35px solid var(--ink-2);
  border-bottom: 1.35px solid var(--ink-2);
  transform: rotate(45deg);
}

.guide-standing-filter[open] .guide-standing-summary,
.guide-standing-summary:focus-visible {
  border-color: var(--accent);
  outline: none;
}

/* A narrowed list says so, in the action color, like a sorted column. */
.guide-standing-filter.is-filtered #guide-standing-text {
  color: var(--accent);
  font-weight: 500;
}

.guide-standing-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 30;
  min-width: 100%;
  padding: 0.35rem 0;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow-pop);
}

.guide-standing-option {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.4rem 0.8rem;
  margin: 0;
  font-weight: 400;
  cursor: pointer;
  white-space: nowrap;
}

.guide-standing-option:hover {
  background: var(--surface-raised);
}

.guide-standing-option input {
  width: auto;
  margin: 0;
  accent-color: var(--accent);
}

.guide-standing-presets {
  display: flex;
  gap: 0.9rem;
  padding: 0.45rem 0.8rem 0.2rem;
  margin-top: 0.3rem;
  border-top: 1px solid var(--border);
  font-size: var(--text-xs);
  white-space: nowrap;
}

/* ------------------------------------------------------------------------- */
/* Help chat (bottom right, every signed-in page)                             */
/* A floating panel rather than a band of its own: it is the only shape that   */
/* costs the attendance grid and the cash ledger no rows (DESIGN.md, "one row, */
/* one line"). Quiet instrument rules throughout — hairlines, one accent, no   */
/* chat bubbles, no entrance choreography.                                     */
/* ------------------------------------------------------------------------- */

.help-chat {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 200;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  font-family: var(--font-ui);
}

.help-chat-bubble {
  width: 44px;
  height: 44px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--brand-navy);
  border-radius: 999px;
  background: var(--brand-navy);
  color: #ffffff;
  box-shadow: var(--shadow-card);
  cursor: pointer;
  transition: background 150ms ease-out, box-shadow 150ms ease-out;
}

.help-chat-bubble:hover {
  box-shadow: var(--shadow-pop);
}

.help-chat-bubble:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.help-chat-panel {
  order: -1;
  display: flex;
  flex-direction: column;
  width: min(380px, calc(100vw - 32px));
  max-height: min(560px, calc(100vh - 140px));
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--card);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
  animation: help-chat-in 150ms ease-out;
}

@keyframes help-chat-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.help-chat-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
}

.help-chat-title {
  margin: 0;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
}

.help-chat-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.help-chat-link {
  padding: 2px 4px;
  border: 0;
  background: none;
  color: var(--accent);
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: 500;
  cursor: pointer;
}

.help-chat-link:hover {
  text-decoration: underline;
}

.help-chat-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--ink-3);
  cursor: pointer;
}

.help-chat-icon-btn:hover {
  background: var(--surface-raised);
  color: var(--ink);
}

.help-chat-log {
  flex: 1;
  min-height: 120px;
  overflow-y: auto;
  padding: 12px;
  font-size: var(--text-base);
  line-height: 1.5;
  color: var(--ink);
}

.help-chat-intro {
  color: var(--ink-2);
}

.help-chat-intro p {
  margin: 0 0 8px;
}

.help-chat-note {
  font-size: var(--text-xs);
  color: var(--ink-3);
}

.help-chat-message + .help-chat-message {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.help-chat-who {
  display: block;
  margin-bottom: 4px;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
}

.help-chat-message--user .help-chat-who {
  color: var(--accent);
}

.help-chat-body p {
  margin: 0 0 8px;
}

.help-chat-body p:last-child,
.help-chat-body ul:last-child,
.help-chat-body ol:last-child {
  margin-bottom: 0;
}

.help-chat-body ul,
.help-chat-body ol {
  margin: 0 0 8px;
  padding-left: 20px;
}

.help-chat-body li {
  margin-bottom: 4px;
}

.help-chat-body code {
  padding: 1px 4px;
  border-radius: var(--r-sm);
  background: var(--fill);
  font-family: var(--font-data);
  font-size: var(--text-sm);
}

.help-chat-status {
  margin: 0;
  padding: 8px 12px;
  border-top: 1px solid var(--border);
  font-size: var(--text-xs);
  color: var(--ink-2);
}

.help-chat-status--warn {
  color: var(--warning);
}

.help-chat-status--error {
  color: var(--error);
}

.help-chat-status--ok {
  color: var(--success);
}

.help-chat-form {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 10px 12px;
  border-top: 1px solid var(--border);
}

.help-chat-input {
  flex: 1;
  min-height: 38px;
  max-height: 120px;
  padding: 8px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--card);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: 1.4;
  resize: vertical;
}

.help-chat-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}

.help-chat-send {
  padding: 8px 14px;
  border: 1px solid var(--brand-navy);
  border-radius: var(--r-md);
  background: var(--brand-navy);
  color: #ffffff;
  font-family: var(--font-ui);
  font-size: var(--text-base);
  font-weight: 500;
  cursor: pointer;
}

.help-chat-send:disabled {
  opacity: 0.55;
  cursor: default;
}

.help-chat-panel.is-busy .help-chat-log {
  /* The answer streams in, so there is nothing to show as loading beyond the
     cursor: no skeleton shimmer (DESIGN.md, motion). */
  cursor: progress;
}

@media (max-width: 600px) {
  .help-chat {
    right: 16px;
    bottom: 16px;
  }

  .help-chat-panel {
    width: calc(100vw - 32px);
    max-height: calc(100vh - 120px);
  }
}

@media print {
  .help-chat {
    display: none;
  }
}

/* ------------------------------------------------------------------------- */
/* Help chat log (Staff directory → Help chat, reader list only)              */
/* ------------------------------------------------------------------------- */

.assistant-log-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.assistant-log-meta {
  margin: 0.5rem 0 0.75rem;
  font-family: var(--font-data);
  font-size: var(--text-sm);
  color: var(--ink-2);
}

/* The directory recipe lays its columns out fixed, which divides the width
   evenly and left the question cut after three words with half the row empty.
   Here the question is the column that matters, so the others take what they
   need and it takes the rest. */
.assistant-log-table {
  width: 100%;
  table-layout: auto;
}

.assistant-log-table th:not(.assistant-log-opening):not(:nth-child(4)),
.assistant-log-table td:not(.assistant-log-opening) {
  white-space: nowrap;
  width: 1%;
}

/* One row, one line: the question takes what is left and is cut, never
   wrapped, with the whole of it in the title (DESIGN.md). */
.assistant-log-opening {
  max-width: 0;
  width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-2);
}

.assistant-log-when {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  white-space: nowrap;
}

.assistant-log-num {
  text-align: right;
  font-family: var(--font-data);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.assistant-log-mark {
  white-space: nowrap;
}

/* Not a badge and not red: a forwarded conversation is a fact, not an alarm. */
.assistant-log-sent {
  font-family: var(--font-data);
  font-size: var(--text-2xs);
  color: var(--brass);
}

.assistant-log-table tbody tr {
  cursor: pointer;
}

.assistant-log-table tbody tr:hover {
  background: var(--surface-raised);
}

.assistant-log-table tbody tr:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.assistant-log-empty {
  padding: 0.75rem 0;
  color: var(--ink-3);
  text-align: center;
}

.assistant-log-note {
  margin: 0.75rem 0 0;
  font-size: var(--text-xs);
  color: var(--ink-3);
}

.assistant-log-dialog {
  width: min(680px, calc(100vw - 3rem));
  max-height: min(80vh, 760px);
  padding: 1rem 1.15rem 1.15rem;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--card);
  color: var(--ink);
  box-shadow: var(--shadow-pop);
  overflow-y: auto;
}

.assistant-log-dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.85rem;
  padding-bottom: 0.65rem;
  border-bottom: 1px solid var(--border);
}

.assistant-log-dialog-head h3 {
  margin: 0;
  font-size: var(--text-base);
  font-weight: 600;
}

.assistant-log-message + .assistant-log-message {
  margin-top: 0.9rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--border);
}

.assistant-log-who {
  display: block;
  margin-bottom: 0.25rem;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
}

.assistant-log-message--user .assistant-log-who {
  color: var(--accent);
}

.assistant-log-text {
  font-size: var(--text-base);
  line-height: 1.5;
}

/* ==========================================================================
   Dive commissions (Lot 26, DIVE_COMMISSIONS_SPEC.md)
   One line per sale, grouped by cruise under a quiet group row. Same command
   bar recipe as Immigration and Attendance; figures in Plex Mono; one row,
   one line (DESIGN.md 2026-09-08). Marks are micro-labels in ochre, never red.
   ========================================================================== */

.dive-command-bar {
  padding: 0.4rem 0.65rem;
  margin-bottom: 0.45rem;
}

.dive-command-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.45rem 0.75rem;
}

.dive-command-primary,
.dive-command-secondary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

.dive-command-primary > input[type='search'] {
  width: 14rem;
  min-width: 0;
  max-width: 100%;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 0.82rem;
}

.dive-command-primary > select {
  width: auto;
  padding: 0.35rem 0.55rem;
  font-size: 0.82rem;
  font-weight: 600;
}

.dive-command-secondary > button {
  padding: 0.35rem 0.8rem;
  font-size: 0.82rem;
}

.dive-tabs {
  display: inline-flex;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  overflow: hidden;
}

.dive-tab {
  padding: 0.3rem 0.75rem;
  border-radius: 0;
  background: var(--card);
  color: var(--ink-2);
  font-size: 0.82rem;
  font-weight: 500;
}

.dive-tab + .dive-tab {
  border-left: 1px solid var(--border-strong);
}

.dive-tab.is-active {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

.dive-month-nav {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
}

.dive-month-input {
  width: 9.5rem;
  padding: 0.3rem 0.45rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font: 500 0.82rem var(--font-data);
}

.dive-month-step {
  width: 26px;
  height: 26px;
  padding: 0;
  background: transparent;
  color: var(--ink-2);
  border-radius: 5px;
}

.dive-month-step:hover {
  background: var(--surface-raised);
  color: var(--ink);
}

.dive-totals {
  font-size: 0.82rem;
  color: var(--ink-2);
  white-space: nowrap;
}

.dive-totals strong {
  color: var(--ink);
  font-weight: 500;
}

.dive-sheet {
  padding: 0;
  overflow: hidden;
}

.dive-table {
  table-layout: fixed;
  width: 100%;
  min-width: 860px;
  /* Table cells at the size DESIGN.md gives them (14px), like the petty cash
     and immigration tables: left alone they inherit the page's 16px. */
  font-size: var(--text-base);
}

/* Rows at the Directory's 35px (owner, 2026-09-28): at the 28px of the petty
   cash book the ledger read as cramped, a cruise heading and its lines packed
   together. A row's height is its floor in a table, so a taller cell (the
   vessel chip, the icons) never pushes one row past the others. */
.dive-table tbody tr {
  height: 35px;
}

/* Figures take the width their header and a four-figure amount need; the
   item and the guests, the unsized columns, pay for a narrow window. */
.dive-table col.dive-col-qty { width: 6.5rem; }
.dive-table col.dive-col-money { width: 7.75rem; }
.dive-table col.dive-col-by { width: 7rem; }
.dive-table col.dive-col-actions { width: 64px; }
.dive-table col.dive-col-unit { width: 7rem; }
.dive-table col.dive-col-proof { width: 9rem; }
.dive-table col.dive-col-package { width: 7.5rem; }
.dive-table col.dive-col-from { width: 7.5rem; }

.dive-table th,
.dive-table td {
  padding: 0.35rem 0.75rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dive-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding-top: 0.45rem;
  padding-bottom: 0.45rem;
  border-bottom: 1px solid var(--border-strong);
}

.dive-table .num-col {
  text-align: right;
}

.dive-table td.num,
.dive-table td .num {
  font-family: var(--font-data);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

/* The cruise is a group label, not a data row: uppercase-free, on the fill,
   with the boat chip carrying the vessel identity (DESIGN.md polarity). */
.dive-cruise-row th {
  /* The vessel chip is taller than a line of text: less padding keeps the
     cruise row at the height of the rows under it. */
  padding-top: 0.2rem;
  padding-bottom: 0.2rem;
  background: var(--fill);
  font-size: var(--text-sm);
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink);
  font-weight: 500;
  border-bottom: 1px solid var(--border);
}

.dive-cruise-title {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  min-width: 0;
}

.dive-cruise-name {
  font-weight: 600;
}

.dive-cruise-dates {
  color: var(--ink-2);
  font-family: var(--font-data);
  font-size: var(--text-xs);
}

.dive-cruise-total {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}

.dive-sale-row {
  cursor: pointer;
}

.dive-sale-row:hover {
  background: var(--surface-raised);
}

.dive-sale-row.is-empty {
  cursor: default;
}

/* A cruise with nothing on it yet is information, not a row of data: it says
   so in the small muted size, so a month of empty weeks stays compact. */
.dive-sale-row.is-empty td {
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
  font-size: var(--text-xs);
}

.dive-sale-row.is-empty:hover {
  background: none;
}

.dive-sale-row.is-inactive td {
  color: var(--ink-3);
}

.dive-commission-cell {
  font-weight: 500;
}

.dive-item-name {
  overflow: hidden;
  text-overflow: ellipsis;
}

.dive-muted {
  color: var(--ink-3);
}

.dive-empty {
  padding: 1.25rem 0.75rem !important;
  color: var(--ink-2);
  white-space: normal !important;
}

.dive-mark {
  display: inline-block;
  margin-left: 0.4rem;
  font: 600 var(--text-2xs) / 1 var(--font-ui);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-2);
  vertical-align: 1px;
}

.dive-mark--price,
.dive-mark--review,
.dive-mark--link,
.dive-mark--conflict {
  color: var(--warning);
}

.dive-legend .dive-mark {
  margin-left: 0;
}

.dive-legend {
  margin: 0;
  padding: 0.55rem 0.75rem;
  border-top: 1px solid var(--border);
  font-size: var(--text-xs);
  color: var(--ink-2);
  line-height: 1.6;
}

.dive-legend .dive-mark + * {
  margin-left: 0.2rem;
}

.dive-row-actions {
  text-align: right;
  overflow: visible !important;
}

/* The icons are 22px: with the cell's own padding they would push the rows
   past the 35px the table sets them at. */
.dive-table td.dive-row-actions,
.dive-table th.dive-row-actions {
  padding-top: 0.1rem;
  padding-bottom: 0.1rem;
}

.dive-row-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
  vertical-align: middle;
}

.dive-row-btn + .dive-row-btn { margin-left: 2px; }
.dive-row-btn:hover { color: var(--ink); background: var(--surface-raised); }
.dive-row-btn[data-delete-sale]:hover,
.dive-row-btn[data-delete-price]:hover { color: var(--error); background: var(--error-soft); }
.dive-row-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; color: var(--ink); }
tr:hover .dive-row-btn { color: var(--ink-2); }

/* --- Dialogs --------------------------------------------------------------- */

.dive-dialog {
  width: min(34rem, calc(100vw - 2rem));
  max-width: 34rem;
  max-height: calc(100vh - 2rem);
  overflow: auto;
}

.dive-form {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}

.dive-form label,
.dive-field-label {
  display: block;
  margin-bottom: 0.3rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink-2);
}

.dive-form input[type='text'],
.dive-form input[type='number'],
.dive-form input[type='date'],
.dive-form select {
  width: 100%;
  margin: 0;
  box-sizing: border-box;
}

.dive-form input[type='number'] {
  font-family: var(--font-data);
}

.dive-form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.7rem;
}

.dive-form-row.hidden {
  display: none;
}

.dive-cruise-line {
  margin: -0.2rem 0 0;
  min-height: 1.2em;
  font-size: var(--text-sm);
  color: var(--ink-2);
}

.dive-cruise-line .vessel-chip {
  margin: 0 0.25rem;
}

.dive-cruise-line.is-pending {
  color: var(--warning);
}

.dive-cruise-line.is-refused {
  color: var(--error);
}

.dive-guests-head {
  display: grid;
  grid-template-columns: 1fr 5.5rem 22px;
  gap: 0.45rem;
}

.dive-guests {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.dive-guest-row {
  display: grid;
  grid-template-columns: 1fr 5.5rem 22px;
  gap: 0.45rem;
  align-items: center;
}

.dive-guest-row .dive-guest-dives.hidden {
  display: block !important;
  visibility: hidden;
}

.dive-guests-dives-label.hidden {
  display: block !important;
  visibility: hidden;
}

.dive-add-guest {
  margin-top: 0.4rem;
  font-size: var(--text-sm);
}

.dive-check {
  display: flex !important;
  align-items: center;
  gap: 0.45rem;
  font-weight: 500 !important;
  color: var(--ink) !important;
  cursor: pointer;
}

.dive-check input {
  width: auto;
  margin: 0;
}

.dive-override {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.dive-figures {
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-raised);
  font-size: var(--text-sm);
  color: var(--ink-2);
}

.dive-figures:empty {
  display: none;
}

.dive-figures strong {
  color: var(--ink);
  font-weight: 500;
}

.dive-figures-terms,
.dive-figures-result {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
}

.dive-figures-result {
  margin-top: 0.35rem;
  padding-top: 0.35rem;
  border-top: 1px solid var(--border);
}

.dive-figures-working {
  margin: 0.35rem 0 0;
  padding: 0;
  list-style: none;
}

.dive-figures-working li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}

.dive-figures-warn {
  margin: 0;
  color: var(--warning);
}

.dive-dialog-actions {
  margin-top: 0.9rem;
  align-items: center;
}

.dive-dialog-actions .dive-delete {
  margin-left: auto;
}

.dive-dialog-actions .dive-delete:hover {
  color: var(--error);
  border-color: var(--error);
}

.dive-price-fields {
  margin: 0;
  padding: 0.6rem 0.7rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.dive-price-fields legend {
  padding: 0 0.3rem;
  margin: 0;
}

.dive-price-history ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.dive-price-history li {
  display: grid;
  grid-template-columns: 8.5rem 1fr auto 22px;
  gap: 0.6rem;
  align-items: center;
  padding: 0.2rem 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--text-sm);
}

@media (max-width: 640px) {
  .dive-form-row {
    grid-template-columns: 1fr;
  }
  /* Same step down as the petty cash table on a phone. */
  .dive-table {
    font-size: 0.8rem;
  }
  .dive-command-primary > input[type='search'] {
    width: 100%;
  }
}

/* Dive commissions, who shares a cruise (Lot 27) */
.dive-cruise-row[data-cruise] {
  cursor: pointer;
}

.dive-cruise-row[data-cruise]:hover th {
  background: color-mix(in srgb, var(--fill) 80%, var(--ink-3) 20%);
}

.dive-cruise-guides {
  min-width: 0;
  max-width: 34rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-2);
  font-family: var(--font-data);
  font-size: var(--text-xs);
  font-weight: 400;
}

.dive-cruise-title .dive-cruise-guides::before {
  content: '·';
  margin-right: 0.45rem;
  color: var(--ink-3);
}

/* An exception is a decision somebody took, not a fault: info ink, not ochre. */
.dive-mark--exception {
  color: var(--info);
}

.dive-table col.dive-col-basis { width: 45%; }
.dive-table col.dive-col-actions-wide { width: 6.5rem; }

.dive-guides-total th {
  border-top: 1px solid var(--border-strong);
}

.dive-cruise-dialog {
  width: min(44rem, calc(100vw - 2rem));
  max-width: 44rem;
}

.dive-cruise-dialog .add-staff-month-title .dive-cruise-title {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.dive-cruise-body {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.dive-cruise-guides-table {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

.dive-cruise-guides-table .link-button {
  font-size: var(--text-sm);
}

.dive-notices {
  margin: 0;
  padding-left: 1.1rem;
  font-size: var(--text-sm);
  color: var(--warning);
}

.dive-guide-reason,
.dive-guide-add {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.dive-guide-reason label,
.dive-guide-add label {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink-2);
}

.dive-guide-reason-row {
  display: flex;
  gap: 0.45rem;
  align-items: center;
}

.dive-guide-reason-row input,
.dive-guide-reason-row select {
  flex: 1;
  min-width: 0;
}

.dive-guide-reason-row select {
  flex: 0 0 11rem;
}

.dive-guide-reason-row button {
  flex: none;
  padding: 0.45rem 0.8rem;
}

/* Dive commissions, proof before payment (Lot 28) */
.dive-guest-proof {
  display: none;
  min-width: 0;
  white-space: nowrap;
  font-size: var(--text-sm);
}

.with-proof .dive-guests-head,
.with-proof .dive-guest-row {
  grid-template-columns: 1fr 5.5rem 8.5rem 22px;
}

.with-proof .dive-guest-proof {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}

.dive-proof-link {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  color: var(--success);
  text-decoration: none;
  font-weight: 500;
}

.dive-proof-link:hover {
  text-decoration: underline;
}

.dive-proof-attach {
  padding: 0.3rem 0.6rem;
  font-size: var(--text-xs);
  background: var(--card);
  color: var(--accent);
  border: 1px dashed var(--border-strong);
}

.dive-mark--proof {
  color: var(--warning);
}

/* The boat's cruises ending after the 28th (Month tab): information, not a warning. */
.dive-cutoff {
  margin: 0;
  padding-left: 1.1rem;
  font-size: var(--text-sm);
  color: var(--ink-2);
}

.dive-cutoff strong {
  color: var(--ink);
}

.dive-figures-note {
  margin: 0.35rem 0 0;
  font-size: var(--text-xs);
  color: var(--ink-2);
}

/* Attendance: the dive commissions a finalisation names (Lot 29). A corner
   mark, like an Excel comment: it costs the grid no width and no row. Sea
   teal when the cell holds the finalised total, ochre when it does not. */
#grid-body td.dive-cell {
  position: relative;
}

#grid-body td.dive-cell::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 0 7px 7px 0;
  border-color: transparent var(--leave-vacation) transparent transparent;
  pointer-events: none;
}

#grid-body td.dive-cell.is-differs::after {
  border-color: transparent var(--warning) transparent transparent;
}

/* Deductions (bar) and spa Commission split by boat, for somebody on Yin and
   Yang in the month (2026-10-29). Same corner language as the dive cells, at
   the bottom so the two never collide: ink when split, ochre when the cell
   still holds one figure nobody has split. */
#grid-body td.money-split-cell {
  position: relative;
}

#grid-body td.money-split-cell::before {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 0 0 7px 7px;
  border-color: transparent transparent var(--ink-3) transparent;
  pointer-events: none;
}

#grid-body td.money-split-cell.is-unsplit::before {
  border-bottom-color: var(--warning);
}

#grid-body input.money-split {
  cursor: pointer;
}

.money-split-pop {
  position: fixed;
  z-index: 60;
  width: 13rem;
  padding: 0.6rem 0.7rem 0.55rem;
  background: var(--surface-raised);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  box-shadow: var(--shadow-pop);
  font-size: var(--text-sm);
  color: var(--ink);
}

.money-split-pop[hidden] {
  display: none;
}

.money-split-title {
  margin: 0 0 0.45rem;
  font-weight: 600;
}

.money-split-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0 0 0.3rem;
}

.money-split-row input {
  width: 7rem;
  text-align: right;
  font-family: var(--font-data);
}

.money-split-note {
  margin: 0.2rem 0 0.3rem;
  font-size: var(--text-xs);
  color: var(--warning);
}

.money-split-total {
  display: flex;
  justify-content: space-between;
  margin: 0.35rem 0 0.45rem;
  padding-top: 0.35rem;
  border-top: 1px solid var(--border-strong);
  color: var(--ink-2);
}

.money-split-actions {
  display: flex;
  justify-content: flex-end;
}

/* A holidays balance an admin adjusted, with the reason in the tip; an admin
   clicks the cell to change it (owner, 2026-10-11). */
#grid-body td.cell-z.has-adjustment {
  position: relative;
}

#grid-body td.cell-z.has-adjustment::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 0 7px 7px 0;
  border-color: transparent var(--info) transparent transparent;
  pointer-events: none;
}

html:not(.is-read-only) #grid-body td.cell-z[title] {
  cursor: pointer;
}

.attendance-dive-boats {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0 0.5rem 0.35rem;
}

.attendance-dive-section .attendance-flags-filter[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.attendance-dive-dialog {
  max-width: 30rem;
}

.attendance-dive-table {
  width: 100%;
  margin-bottom: 0.75rem;
}

.attendance-dive-table th,
.attendance-dive-table td {
  padding: 0.3rem 0.5rem;
}

.attendance-dive-table .num-col {
  text-align: right;
}

.attendance-dive-table td.num {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}

/* Dive commissions, the Month tab: one card per boat (Lot 29) */
.dive-boats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: 0.6rem;
  margin-bottom: 0.6rem;
}

.dive-boat-card {
  padding: 0.75rem 0.85rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.dive-boat-head {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
}

.dive-boat-status {
  font-size: var(--text-sm);
  color: var(--ink-2);
  line-height: 1.45;
}

.dive-boat-status.is-warning {
  color: var(--warning);
}

.dive-boat-status.is-done {
  color: var(--ink);
}

.dive-boat-table {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

.dive-boat-table td.num,
.dive-boat-table th.num {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}

.dive-boat-total th {
  border-top: 1px solid var(--border-strong);
  background: var(--card);
  color: var(--ink);
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--text-sm);
}

.dive-boat-actions {
  display: flex;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.dive-summary {
  padding: 0.75rem 0.85rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
  gap: 0.75rem 1.25rem;
}

.dive-summary-section h3 {
  margin: 0 0 0.3rem;
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
}

.dive-summary-section ul {
  margin: 0;
  padding-left: 1rem;
  font-size: var(--text-sm);
  line-height: 1.5;
}

/* Dive commissions, guides who share only some items (Maty, 2026-10-05) */
.dive-limits {
  border-top: 1px solid var(--border-strong);
}

.dive-limits-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0.75rem;
}

.dive-limits-head h3 {
  margin: 0;
  font-size: var(--text-xs);
}

.dive-table col.dive-col-guide { width: 9rem; }
.dive-table col.dive-col-record { width: 12rem; }

.dive-limit-categories {
  margin: 0;
  padding: 0;
  border: 0;
}

.dive-limit-categories #dive-limit-category-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.35rem 1rem;
  margin-top: 0.35rem;
}

.dive-limit-categories[disabled] {
  opacity: 0.5;
}

/* Dive commissions, the Notion import (Lot 30) */
.dive-import-dialog {
  width: min(48rem, calc(100vw - 2rem));
  max-width: 48rem;
}

.dive-import-pick {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.75rem;
}

.dive-import-pick input[type='file'] {
  flex: 1;
  min-width: 0;
}

.dive-import-body {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  font-size: var(--text-sm);
}

.dive-import-summary {
  margin: 0;
}

.dive-import-heading {
  margin: 0;
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-2);
}

.dive-import-list {
  margin: 0;
  padding-left: 1.1rem;
  max-height: 10rem;
  overflow: auto;
}

.dive-import-months {
  min-width: 0;
}

.dive-import-months td {
  white-space: normal;
}

.dive-import-months .dive-check {
  display: inline-flex !important;
  margin-right: 0.5rem;
}

.dive-import-recon > td {
  padding-top: 0;
  border-bottom: 1px solid var(--border-strong);
}

.dive-import-recon summary {
  cursor: pointer;
  color: var(--accent);
  font-size: var(--text-xs);
}

.dive-import-recon .dive-table {
  min-width: 0;
  margin-top: 0.35rem;
}

.dive-import-diff {
  color: var(--warning);
}

/* A course guest's outcome: certified, or a referral sent (half the price). */
.with-outcome .dive-guests-head,
.with-outcome .dive-guest-row {
  /* The dives column is display: none here, so it takes no track at all. */
  grid-template-columns: 1fr 15.5rem 22px;
}

/* As specific as the rule that keeps a hidden dives input in the flow
   (`.dive-guest-row .dive-guest-dives.hidden`), or that one wins. */
.with-outcome .dive-guest-row .dive-guest-dives,
.with-outcome .dive-guest-row .dive-guest-dives.hidden,
.with-outcome .dive-guests-head .dive-guests-dives-label.hidden,
.with-outcome .dive-guests-head .dive-guests-dives-label {
  display: none !important;
}

.dive-guest-outcome {
  width: auto !important;
  padding: 0.3rem 0.4rem;
  font-size: var(--text-xs);
}

/* A long item name gives way to its marks: PROOF or PAID must stay readable. */
.dive-item-wrap {
  display: flex;
  align-items: baseline;
  min-width: 0;
}

.dive-item-wrap .dive-item-name {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dive-item-wrap .dive-mark {
  flex: none;
}

/* Attendance activity: searchable, paged (2026-09-27) */
.attendance-activity-search {
  width: 100%;
  margin: 0 0 0.5rem;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 0.82rem;
}

.attendance-activity-more {
  width: 100%;
  margin-top: 0.5rem;
  padding: 0.35rem;
  font-size: var(--text-xs);
}

.attendance-activity-panel {
  width: min(420px, calc(100vw - 2rem));
  max-height: min(70vh, 640px);
}

/* Small titles in the brand's Presicav Light (DESIGN.md): the uppercase
   heading of a section, a dialog group or a side panel, and the app's name in
   the navbar. Never a table's column headers: Presicav sets about 30% wider
   than Public Sans, which a fixed column cannot give, and its light strokes
   would thin the labels a reader scans a sheet by. Last in the file so it
   wins over each section's own rule. */
.navbar-brand,
.reminders-section-title,
.timeline-plan-section-label,
.finalize-check-group-title,
.staff-profile-section-title,
.attendance-flags-section-head h3,
.staff-leave-section-label,
.dashboard-section-label,
.staff-profile-edit-section,
.immigration-import-heading,
.immigration-section-title,
.pettycash-tenders h3,
.pettycash-count-currency h3,
.help-chat-title,
.dive-summary-section h3,
.dive-import-heading,
.dive-limits-head h3 {
  font-family: var(--font-title);
  font-weight: 300;
  font-synthesis: none;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink);
}

/* The app's name as the brand's wordmark: small, widely spaced capitals,
   like the SCUBASPA logo. */
.navbar-brand {
  font-size: 0.75rem;
  letter-spacing: 0.24em;
}
