/* =============================================
   BizOps · CSS Design System
   Font: DM Sans (body) + DM Mono (numbers)
   Theme: Deep forest green · Professional
   ============================================= */

@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500;600&family=DM+Mono:wght@400;500&display=swap');

:root {
  --green-950: #040F09;
  --green-900: #0A2A1F;
  --green-800: #0F3D2C;
  --green-700: #145238;
  --green-600: #1A6647;
  --green-500: #1D9E75;
  --green-400: #2FC08D;
  --green-300: #5DCAA5;
  --green-200: #9FE1CB;
  --green-100: #D0F0E6;
  --green-50:  #E8F8F2;

  --amber-500: #E8A020;
  --amber-100: #FDF3DC;
  --amber-800: #6B4506;

  --coral-500: #D85A30;
  --coral-100: #FAECE7;
  --coral-800: #712B13;

  --red-500:   #C93535;
  --red-100:   #FCEBEB;
  --red-800:   #791F1F;

  --blue-500:  #2471CC;
  --blue-100:  #E6F1FB;
  --blue-800:  #0C447C;

  --bg:        #F5F7F5;
  --surface:   #FFFFFF;
  --surface-2: #F0F4F2;
  --border:    rgba(0,0,0,0.08);
  --border-md: rgba(0,0,0,0.14);

  --text-1: #0D1F18;
  --text-2: #3A5246;
  --text-3: #6B8C7E;
  --text-4: #9DB5AC;

  --font: 'DM Sans', -apple-system, sans-serif;
  --mono: 'DM Mono', 'SF Mono', monospace;

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 20px;

  --header-h: 64px;
  --nav-h: 72px;
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  /* What the bottom bar actually reserves for the home indicator. The full
     inset left a band of empty white under the icons; everything that has to
     clear the nav uses this so the numbers cannot drift apart. */
  --nav-inset: min(env(safe-area-inset-bottom, 0px), 10px);
}

/* Base */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
  /* The canvas — what shows past the end of the app, by the home indicator.
     body stays the header's green for the status bar strip iOS samples, but
     painting the canvas from here keeps the bottom matching the nav. */
  background: var(--surface);
}
body {
  font-family: var(--font);
  /* iOS fills the status bar strip from the DOCUMENT's background colour, not
     from whatever is painted at the top of the page — so a light body put a
     light band above the green header. The page's own light background moved
     onto #app below, which leaves this free to match the header. Nothing on
     screen changes: #app covers the body completely. */
  background: var(--green-900);
  color: var(--text-1);
  overflow: hidden;
  height: 100dvh;
  -webkit-font-smoothing: antialiased;
}

/* =============================================
   APP SHELL
   ============================================= */

#app {
  display: flex;
  flex-direction: column;
  background: var(--bg);        /* the page background, moved off body */
  height: 100dvh;
  max-width: 430px;
  margin: 0 auto;
  position: relative;
}

/* Header */
#app-header {
  /* Height = the bar itself PLUS the iOS status-bar/notch inset, so the inner
     content sits fully below the status bar in standalone (home-screen) mode.
     (With border-box, baking the inset into a fixed height squashed the bar.) */
  /* The inset alone puts the title hard against the status bar, where iOS
     fades its own gradient over the top of it and the name reads as blurred.
     16px of clearance below the inset keeps it clear of the fade. */
  height: calc(var(--header-h) + env(safe-area-inset-top, 0px) + 16px);
  background: var(--green-900);
  flex-shrink: 0;
  padding-top: calc(env(safe-area-inset-top, 0px) + 16px);
  z-index: 10;
}

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  height: var(--header-h);
}

.header-left { display: flex; align-items: center; gap: 10px; }
.header-right { display: flex; align-items: center; gap: 4px; }

.app-logo {
  width: 34px;
  height: 34px;
  background: var(--green-500);
  border-radius: var(--r-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 16px;
  color: #fff;
  letter-spacing: -0.5px;
}

.app-name {
  font-size: 17px;
  font-weight: 600;
  color: #fff;
  letter-spacing: -0.3px;
}

.header-sub {
  display: block;
  font-size: 11px;
  color: var(--green-200);
  margin-top: 1px;
}

.header-titles { display: flex; flex-direction: column; justify-content: center; }
/* The role badge belongs beside the name. Stacked, the three lines overflowed
   the 64px bar and the centred overflow pushed "PCW" up under the status bar. */
.header-name-row { display: flex; align-items: center; gap: 6px; }

.icon-btn {
  width: 38px;
  height: 38px;
  border-radius: var(--r-sm);
  background: rgba(255,255,255,0.08);
  border: none;
  color: rgba(255,255,255,0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.15s;
}
.icon-btn:active { background: rgba(255,255,255,0.16); }
.icon-btn.spinning svg { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Header live-sync indicator */
.sync-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #1D9E75;
  display: inline-block;
  box-shadow: 0 0 0 0 rgba(29,158,117,0.5);
}
.sync-dot.connected { animation: sync-pulse 2s infinite; }
.sync-dot.offline   { background: #8a8f98; animation: none; }
@keyframes sync-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(29,158,117,0.45); }
  70%  { box-shadow: 0 0 0 6px rgba(29,158,117,0); }
  100% { box-shadow: 0 0 0 0 rgba(29,158,117,0); }
}

/* Inline spinner (e.g. invoice OCR status) */
.spinner-dot {
  display: inline-block;
  width: 11px; height: 11px;
  border: 2px solid var(--green-400);
  border-top-color: transparent;
  border-radius: 50%;
  vertical-align: -1px;
  animation: spin 0.7s linear infinite;
}

/* Pages */
#page-container {
  flex: 1;
  overflow: hidden;
  position: relative;
}

.page {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
  transition: opacity 0.2s, transform 0.2s;
}

.page.active {
  opacity: 1;
  pointer-events: all;
  transform: translateY(0);
}

.page-scroll {
  height: 100%;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 16px 16px calc(var(--nav-h) + var(--nav-inset) + 16px);
}

/* Bottom nav */
#bottom-nav {
  /* Clearance for the home indicator, not the whole 34pt inset — the full
     amount left a band of empty white under the icons taller than the labels.
     The icons sit at the top of the bar, so they are well clear either way. */
  height: calc(var(--nav-h) + var(--nav-inset));
  padding-bottom: var(--nav-inset);
  background: var(--surface);
  border-top: 1px solid var(--border);
  display: flex;
  align-items: flex-start;
  flex-shrink: 0;
  z-index: 10;
}

.nav-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 10px 4px;
  background: none;
  border: none;
  color: var(--text-3);
  font-family: var(--font);
  font-size: 10px;
  font-weight: 500;
  cursor: pointer;
  transition: color 0.15s;
  -webkit-tap-highlight-color: transparent;
}

.nav-item.active { color: var(--green-500); }
.nav-item svg { flex-shrink: 0; }

/* =============================================
   PAGE COMPONENTS
   ============================================= */

.page-hero { padding: 4px 0 16px; }
.page-title {
  font-size: 26px;
  font-weight: 600;
  color: var(--text-1);
  letter-spacing: -0.5px;
}
.page-subtitle {
  font-size: 13px;
  color: var(--text-3);
  margin-top: 3px;
}

/* Status bar */
.status-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-3);
  margin-bottom: 14px;
}
.status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green-400);
  flex-shrink: 0;
}
.status-dot.pulse {
  animation: pulse-dot 2s ease-in-out infinite;
}
@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}
.status-time { margin-left: auto; }

/* Hero metrics */
.hero-metrics {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 20px;
}
.hero-card {
  background: var(--green-900);
  border-radius: var(--r-lg);
  padding: 14px;
  color: #fff;
}
/* Threshold alert — tile turns red (wages >32%, COGS >35%, net profit < 0) */
.hero-card.tile-alert { background: #8a1c1c; }
.hero-card.tile-alert .hero-label { color: #f9c9c9; }
.hero-label {
  font-size: 11px;
  color: var(--green-200);
  font-weight: 500;
  letter-spacing: 0.02em;
  margin-bottom: 6px;
}
.hero-value {
  font-family: var(--mono);
  font-size: 22px;
  font-weight: 500;
  color: #fff;
  letter-spacing: -0.5px;
}
.hero-delta {
  font-size: 11px;
  color: var(--green-300);
  margin-top: 4px;
}

/* Cards */
.card {
  background: var(--surface);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  padding: 14px;
  margin-bottom: 10px;
}

/* Section labels */
.section-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin: 16px 0 8px;
}
.section-label:first-of-type { margin-top: 0; }

/* Cost rows */
.cost-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}
.cost-name { font-size: 14px; font-weight: 500; color: var(--text-1); }
.cost-sub { font-size: 11px; color: var(--text-3); margin-top: 1px; }
.cost-right { text-align: right; }
.cost-amount { font-family: var(--mono); font-size: 14px; font-weight: 500; color: var(--text-1); }
.cost-pct { font-size: 11px; color: var(--text-3); }
.cost-bar-wrap {
  height: 4px;
  background: var(--surface-2);
  border-radius: 99px;
  margin-bottom: 12px;
  overflow: hidden;
}
.cost-bar {
  height: 100%;
  border-radius: 99px;
  width: 0;
  transition: width 0.6s cubic-bezier(0.4,0,0.2,1);
}
.cost-bar.labour { background: var(--green-400); }
.cost-bar.cogs { background: var(--amber-500); }
.cost-bar.overhead { background: var(--blue-500); }
.cost-divider { height: 1px; background: var(--border); margin: 8px 0 12px; }
.net-row { margin-bottom: 0; }
.cost-name.net { font-size: 14px; font-weight: 600; color: var(--text-1); }
.cost-amount.net { color: var(--green-600); font-size: 16px; }
.cost-pct.net { color: var(--green-600); font-weight: 500; }

/* Invoice items */
.invoice-item {
  display: flex;
  align-items: center;
  padding: 11px 0;
  border-bottom: 1px solid var(--border);
  gap: 10px;
}
.invoice-item:last-child { border-bottom: none; }
.invoice-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--r-sm);
  background: var(--green-50);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--green-600);
}
.invoice-info { flex: 1; min-width: 0; }
.invoice-supplier { font-size: 13px; font-weight: 500; color: var(--text-1); }
.invoice-meta { font-size: 11px; color: var(--text-3); margin-top: 2px; }
.invoice-right { text-align: right; flex-shrink: 0; }
.invoice-amount { font-family: var(--mono); font-size: 14px; font-weight: 500; color: var(--text-1); }
.invoice-status { font-size: 10px; margin-top: 3px; display: inline-block; padding: 2px 7px; border-radius: 99px; }
.status-draft { background: var(--amber-100); color: var(--amber-800); }
.status-synced { background: var(--green-50); color: var(--green-600); }
.status-overdue { background: var(--red-100); color: var(--red-800); }

/* Quick actions */
.quick-actions {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin-bottom: 16px;
}
.quick-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 12px 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  cursor: pointer;
  font-family: var(--font);
  font-size: 10px;
  font-weight: 500;
  color: var(--text-2);
  transition: background 0.15s, border-color 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.quick-btn:active { background: var(--surface-2); }
.quick-icon {
  width: 40px;
  height: 40px;
  border-radius: var(--r-sm);
  background: var(--green-50);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--green-600);
}

/* Week selector */
.week-selector {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 10px 12px;
  margin-bottom: 14px;
}
.week-nav-btn {
  width: 32px;
  height: 32px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--text-2);
  flex-shrink: 0;
}
.week-nav-btn:active { background: var(--border); }
.week-info {
  flex: 1;
  text-align: center;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-1);
}

/* Staff list */
.staff-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  margin-bottom: 8px;
  overflow: hidden;
  cursor: pointer;
  transition: border-color 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.staff-card:active { border-color: var(--green-300); }
.staff-card-inner {
  display: flex;
  align-items: center;
  padding: 12px 14px;
  gap: 12px;
}
.staff-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--green-100);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--green-800);
  flex-shrink: 0;
}
.staff-card-info { flex: 1; min-width: 0; }
.staff-card-name { font-size: 14px; font-weight: 500; color: var(--text-1); }
.staff-card-meta { font-size: 12px; color: var(--text-3); margin-top: 2px; }
.staff-card-right { text-align: right; flex-shrink: 0; }
.staff-hours-badge {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 500;
  color: var(--text-1);
}

/* Timesheet rows */
.ts-day-row {
  display: flex;
  align-items: center;
  padding: 8px 0;
  gap: 8px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.ts-day-row:last-child { border-bottom: none; }
.ts-day { width: 32px; color: var(--text-3); font-size: 12px; }
.ts-hours { font-family: var(--mono); font-weight: 500; color: var(--text-1); flex-shrink: 0; min-width: 36px; }
.ts-category {
  flex: 1;
  font-size: 11px;
  font-weight: 500;
  padding: 3px 8px;
  border-radius: 99px;
  text-align: center;
}
.cat-weekday { background: var(--green-50); color: var(--green-700); }
.cat-saturday { background: var(--amber-100); color: var(--amber-800); }
.cat-sunday { background: var(--coral-100); color: var(--coral-800); }
.cat-pubhol { background: var(--red-100); color: var(--red-800); }

/* Denomination grid */
.denomination-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 12px;
}
.denom-item { display: flex; flex-direction: column; gap: 4px; }
.denom-label { font-size: 11px; color: var(--text-3); font-weight: 500; }
.denom-row { display: flex; align-items: center; gap: 8px; }
.denom-input {
  flex: 1;
  height: 36px;
  border: 1px solid var(--border-md);
  border-radius: var(--r-sm);
  padding: 0 10px;
  font-family: var(--mono);
  font-size: 14px;
  color: var(--text-1);
  background: var(--surface);
  text-align: center;
}
.denom-input:focus { outline: none; border-color: var(--green-400); }
.denom-value {
  font-size: 12px;
  font-family: var(--mono);
  color: var(--green-600);
  min-width: 44px;
  text-align: right;
}

/* Fields */
.field-group { margin-bottom: 12px; }
.field-group:last-child { margin-bottom: 0; }
.field-label { font-size: 11px; font-weight: 500; color: var(--text-3); margin-bottom: 5px; display: block; }
.field-input {
  width: 100%;
  height: 40px;
  border: 1px solid var(--border-md);
  border-radius: var(--r-sm);
  padding: 0 12px;
  font-family: var(--font);
  font-size: 14px;
  color: var(--text-1);
  background: var(--surface);
}
.field-input:focus { outline: none; border-color: var(--green-400); }
.field-textarea {
  width: 100%;
  border: 1px solid var(--border-md);
  border-radius: var(--r-sm);
  padding: 10px 12px;
  font-family: var(--font);
  font-size: 14px;
  color: var(--text-1);
  background: var(--surface);
  resize: none;
}
.field-textarea:focus { outline: none; border-color: var(--green-400); }
.field-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 12px; }
.read-field {
  height: 40px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 0 12px;
  display: flex;
  align-items: center;
  font-family: var(--mono);
  font-size: 14px;
  color: var(--text-1);
}
.read-field.highlight { color: var(--green-600); font-weight: 500; background: var(--green-50); border-color: var(--green-200); }
.read-field[data-state="ok"] { color: var(--green-600); background: var(--green-50); border-color: var(--green-200); }
.read-field[data-state="warn"] { color: var(--amber-800); background: var(--amber-100); border-color: var(--amber-500); }
.read-field[data-state="error"] { color: var(--red-800); background: var(--red-100); border-color: var(--red-500); }

/* Select */
select.field-input { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236B8C7E' stroke-width='2.5'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; padding-right: 32px; }

/* Buttons */
.primary-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 48px;
  background: var(--green-500);
  color: #fff;
  border: none;
  border-radius: var(--r-lg);
  font-family: var(--font);
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, transform 0.1s;
  -webkit-tap-highlight-color: transparent;
}
.primary-btn:active { background: var(--green-600); transform: scale(0.98); }
.primary-btn:disabled { background: var(--text-4); cursor: not-allowed; }
.full-btn { width: 100%; margin-bottom: 16px; }
.secondary-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  background: var(--surface);
  color: var(--text-2);
  border: 1px solid var(--border-md);
  border-radius: var(--r-lg);
  font-family: var(--font);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}
.secondary-btn:active { background: var(--surface-2); }

/* Alert box */
.alert-box {
  background: var(--amber-100);
  border: 1px solid var(--amber-500);
  border-radius: var(--r-md);
  padding: 12px 14px;
  font-size: 13px;
  color: var(--amber-800);
  margin-bottom: 12px;
  line-height: 1.5;
}

/* Push section */
.push-section { margin: 16px 0; }
.push-status {
  text-align: center;
  font-size: 12px;
  color: var(--text-3);
  margin-bottom: 10px;
}

/* Badges */
.badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 99px;
}
.badge-ok { background: var(--green-50); color: var(--green-700); }
.badge-warn { background: var(--amber-100); color: var(--amber-800); }
.badge-error { background: var(--red-100); color: var(--red-800); }
.badge-info { background: var(--blue-100); color: var(--blue-800); }

/* Empty state */
.empty-state {
  padding: 20px;
  text-align: center;
  font-size: 13px;
  color: var(--text-4);
}

/* =============================================
   MODALS
   ============================================= */

.modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: flex-end;
  background: rgba(0,0,0,0);
  pointer-events: none;
  transition: background 0.25s;
}
.modal.open {
  background: rgba(0,0,0,0.45);
  pointer-events: all;
}
.modal-sheet {
  width: 100%;
  max-width: 430px;
  margin: 0 auto;
  background: var(--surface);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  max-height: 92dvh;
  overflow-y: auto;
  transform: translateY(100%);
  transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
  padding-bottom: calc(var(--safe-bottom) + 16px);
}
.modal.open .modal-sheet { transform: translateY(0); }
.modal-handle {
  width: 40px;
  height: 4px;
  background: var(--border-md);
  border-radius: 99px;
  margin: 10px auto 4px;
}
.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px 12px;
  border-bottom: 1px solid var(--border);
}
.modal-title { font-size: 17px; font-weight: 600; color: var(--text-1); }
.modal-close {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--surface-2);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--text-2);
}
.modal-body { padding: 16px; }

/* Scan steps */
.scan-drop-zone {
  background: var(--surface-2);
  border: 2px dashed var(--border-md);
  border-radius: var(--r-lg);
  min-height: 160px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  cursor: pointer;
  margin-bottom: 16px;
  transition: border-color 0.15s, background 0.15s;
}
.scan-drop-zone:active { border-color: var(--green-400); background: var(--green-50); }
.scan-drop-icon { color: var(--green-500); }
.scan-drop-label { font-size: 14px; font-weight: 500; color: var(--text-2); }
.scan-drop-sub { font-size: 12px; color: var(--text-3); }
.scan-spinner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 32px 0;
}
.spinner-ring {
  width: 40px;
  height: 40px;
  border: 3px solid var(--border);
  border-top-color: var(--green-500);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
.scan-spinner-msg { font-size: 13px; color: var(--text-3); }
.ai-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  font-weight: 500;
  background: var(--green-50);
  color: var(--green-700);
  padding: 4px 10px;
  border-radius: 99px;
  margin-bottom: 14px;
  border: 1px solid var(--green-200);
}
.confidence-tag {
  font-size: 10px;
  color: var(--green-600);
  margin-top: 3px;
}

/* =============================================
   TOASTS
   ============================================= */

#toast-container {
  position: fixed;
  bottom: calc(var(--nav-h) + var(--nav-inset) + 12px);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 200;
  pointer-events: none;
  width: calc(100% - 32px);
  max-width: 400px;
}
.toast {
  background: var(--green-900);
  color: #fff;
  border-radius: var(--r-md);
  padding: 12px 16px;
  font-size: 13px;
  font-weight: 500;
  animation: toast-in 0.25s ease, toast-out 0.25s ease 2.75s forwards;
  display: flex;
  align-items: center;
  gap: 10px;
}
.toast.error { background: var(--red-800); }
.toast.warning { background: var(--amber-800); }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(-8px); } }

/* Settings list */
.settings-group { margin-bottom: 20px; }
.settings-group-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.settings-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 13px 0;
  border-bottom: 1px solid var(--border);
}
.settings-item:last-child { border-bottom: none; }
.settings-item-label { font-size: 14px; color: var(--text-1); }
.settings-item-value { font-size: 13px; color: var(--text-3); }
.settings-item-action { font-size: 13px; color: var(--green-500); font-weight: 500; }

/* =============================================
   DRAWER REPORT ROWS
   ============================================= */

.drawer-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
}
.drawer-row:last-child { border-bottom: none; }
.drawer-label { font-size: 13px; color: var(--text-2); }
.drawer-value { font-family: var(--mono); font-size: 14px; font-weight: 500; color: var(--text-1); }
.drawer-detail-row {
  display: flex;
  justify-content: space-between;
  padding: 5px 0;
  font-size: 12px;
}
.drawer-detail-label { color: var(--text-3); }
.drawer-detail-amount { font-family: var(--mono); font-weight: 500; }

/* GST calc row */
.gst-calc-row {
  background: var(--green-50);
  border: 1px solid var(--green-200);
  border-radius: var(--r-sm);
  padding: 8px 12px;
  font-size: 12px;
  color: var(--green-700);
  margin-bottom: 12px;
}

/* Supplier datalist input */
#inv-supplier::-webkit-calendar-picker-indicator { opacity: 0.5; }

/* =============================================
   v2 ADDITIONS
   ============================================= */

/* Tab bar */
.tab-bar {
  display: flex;
  gap: 4px;
  background: var(--surface-2);
  border-radius: var(--r-lg);
  padding: 4px;
  margin-bottom: 16px;
}
.tab-btn {
  flex: 1;
  height: 36px;
  border: none;
  border-radius: var(--r-md);
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  color: var(--text-3);
  background: none;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.tab-btn.active {
  background: var(--surface);
  color: var(--text-1);
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

/* Drawer rows */
.drawer-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.drawer-row:last-child { border-bottom: none; }
.drawer-label { color: var(--text-2); }
.drawer-val { font-family: var(--mono); font-weight: 500; color: var(--text-1); }

/* Denom section head */
.denom-section-head {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 12px;
}

/* Denom grid — single column list */
.denom-grid {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 10px;
}
.coins-grid { }

.denom-item { display: flex; flex-direction: column; gap: 0; }
.denom-label { font-size: 13px; font-weight: 600; color: var(--text-2); min-width: 40px; }
.denom-row { display: flex; align-items: center; gap: 8px; }
.denom-input {
  width: 72px;
  flex: none;
  height: 38px;
  border: 1px solid var(--border-md);
  border-radius: var(--r-sm);
  padding: 0 8px;
  font-family: var(--mono);
  font-size: 15px;
  color: var(--text-1);
  background: var(--surface);
  text-align: center;
}
.denom-input:focus { outline: none; border-color: var(--green-400); }

/* Cash rec number fields drop the browser's spin buttons — the denomination
   counts already have their own − / + on either side, and on the dollar
   fields the arrows only ever nudge by a cent. Desktop-only clutter; phones
   never draw them. Timesheet hour fields keep theirs, where stepping a
   quarter-hour at a time is the point. */
#petty-amount::-webkit-outer-spin-button,
#petty-amount::-webkit-inner-spin-button,
#wk-recount-input::-webkit-outer-spin-button,
#wk-recount-input::-webkit-inner-spin-button,
.denom-input::-webkit-outer-spin-button,
.denom-input::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
#petty-amount, #wk-recount-input, .denom-input { -moz-appearance: textfield; appearance: textfield; }

.denom-btn {
  width: 34px;
  height: 38px;
  border: 1px solid var(--border-md);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: 18px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.denom-btn:active { background: var(--border); }
.denom-value {
  font-size: 13px;
  font-family: var(--mono);
  color: var(--green-600);
  min-width: 60px;
  text-align: right;
  margin-left: auto;
}
.denom-subtotal {
  font-size: 12px;
  color: var(--text-3);
  text-align: right;
  padding-top: 6px;
  border-top: 1px solid var(--border);
}
.denom-subtotal span { font-weight: 600; color: var(--text-1); font-family: var(--mono); }

/* Photo zone */
.photo-zone {
  background: var(--surface-2);
  border: 2px dashed var(--border-md);
  border-radius: var(--r-lg);
  min-height: 140px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  cursor: pointer;
  margin-bottom: 8px;
  transition: border-color 0.15s;
  overflow: hidden;
  padding: 16px;
  text-align: center;
}
.photo-zone:active { border-color: var(--green-400); }


/* Desktop-only dashboard extras (summary cards + net-profit trend). Hidden by
   default so the phone dashboard is exactly as it was; the desktop block near
   the end of this file switches them on. */
.dash-desk { display: none; }

/* =============================================
   DESKTOP — PANEL DASHBOARD (≥1080px)
   Everything below lives inside the media query, so the phone view is
   completely untouched. Instead of one page at a time, every page renders
   at once as a panel that scrolls inside its own box, and the bottom tab
   bar becomes a left sidebar.
   ============================================= */

@media (min-width: 1080px) {

  /* Shell: drop the 430px phone cap, header across the top, sidebar + main below */
  #app {
    max-width: none;
    display: grid;
    grid-template-columns: 236px 1fr;
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "header  header"
      "sidebar main";
    height: 100dvh;
  }

  #app-header { grid-area: header; }

  /* Bottom tab bar → left sidebar */
  #bottom-nav {
    grid-area: sidebar;
    height: auto;
    padding: 14px 10px;
    border-top: none;
    border-right: 1px solid var(--border);
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 2px;
    overflow-y: auto;
  }
  .nav-item {
    flex: 0 0 auto;
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
    gap: 12px;
    padding: 11px 12px;
    border-radius: var(--r-md);
    font-size: 14px;
    font-weight: 600;
  }
  .nav-item.active { background: var(--green-50); }
  .nav-item:hover:not(.active) { background: var(--surface-2); }

  /* Page container → the panel grid */
  #page-container {
    grid-area: main;
    position: static;
    overflow-y: auto;
    overflow-x: hidden;
    display: grid;
    /* Fixed phone-width left column + a flexible right column. The fixed column
       exists so Cash rec. is EXACTLY the width it is on a phone (430px of
       content + the 16px page-scroll padding each side) and therefore looks
       identical in both views — it is never re-laid-out for desktop. */
    grid-template-columns: 462px minmax(0, 1fr);
    gap: 16px;
    align-content: start;
    padding: 18px 22px 40px;
    background: var(--bg);
  }

  /* Every page is on screen at once, as its own card */
  .page {
    position: static;
    inset: auto;
    opacity: 1;
    pointer-events: all;
    transform: none;
    transition: none;
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    overflow: hidden;
  }

  /* Each panel scrolls inside its own box. Viewport-relative so tall screens
     show more instead of everything being capped at a fixed height. */
  .page-scroll {
    height: auto;
    max-height: clamp(340px, 46vh, 620px);
    padding: 14px 16px 18px;
    scrollbar-gutter: stable;
  }
  /* Make the inner scroll obvious — without a visible bar the panels just look
     cut off mid-content. */
  .page-scroll::-webkit-scrollbar { width: 10px; }
  .page-scroll::-webkit-scrollbar-thumb {
    background: var(--border-md);
    border-radius: 20px;
    border: 3px solid var(--surface);
  }
  .page-scroll::-webkit-scrollbar-track { background: transparent; }

  /* Panel placement — pinned to explicit rows/columns. The DOM order is
     dashboard, invoices, cash, timesheets, staff, so relying on auto-placement
     stranded Invoices on a row of its own with dead space beside it. */
  /* The dashboard is the only thing on the front page now — the other modules
     shown there as panels (see .dpanel) and open as their own pages. */
  #page-dashboard { grid-column: 1 / -1; grid-row: 1; }
  /* :not(.focused) matters — an ID selector outranks .page.focused, so without
     it these rules would keep a focused page hidden. */
  #page-cash:not(.focused),
  #page-invoices:not(.focused),
  #page-timesheets:not(.focused) { display: none; }

  /* The dashboard isn't a bordered panel, so it needs no inner scrollbar */
  #page-dashboard .page-scroll::-webkit-scrollbar { width: 0; }

  /* ── Focus view ───────────────────────────────────────────────────────
     The dashboard is the panel overview. Clicking any other module in the
     sidebar hands it the whole content area as its own working page — App.nav
     puts .focus-view on <body> and .focused on that page — which is where the
     two-column page layouts below apply. Staff is never a panel (it's payroll
     configuration, not weekly numbers), so it only ever appears this way. */
  #page-staff:not(.focused),
  #page-clean:not(.focused) { display: none; }

  body.focus-view .page { display: none; }
  body.focus-view .page.focused {
    display: flex;
    grid-column: 1 / -1;
    grid-row: 1;
  }
  body.focus-view .page.focused .page-scroll { max-height: none; }

  /* Staff: roster in columns rather than one tall list of half-empty rows */
  body.focus-view #staff-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 10px;
  }
  body.focus-view #staff-list .staff-card { margin-bottom: 0; }

  /* ── Invoices page: list | entry form ─────────────────────────────────
     The invoice list takes the width; the entry form is pinned to 430px phone
     width beside it — same rule as the cash rec, data entry stays phone-shaped
     and review gets the room. Placed by grid area because the DOM has the form
     first (which is the right order on a phone). */
  body.focus-view #page-invoices .page-scroll {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 430px;
    grid-template-areas:
      "hero      hero"
      "weeknav   formlabel"
      "listlabel form"
      "list      form";
    /* The form spans the last two rows, and a spanning item's extra height is
       shared out between the auto rows it covers — which pushed the entry list
       half a page down. A flexible last row takes all of it instead, so the
       entries start directly under their label. */
    grid-template-rows: auto auto auto 1fr;
    gap: 0 20px;
    align-content: start;
  }
  body.focus-view #page-invoices .page-hero        { grid-area: hero; }
  body.focus-view #page-invoices #invoice-week-nav { grid-area: weeknav; }
  body.focus-view #page-invoices #inv-list-label   { grid-area: listlabel; }
  body.focus-view #page-invoices #invoice-list     { grid-area: list; align-self: start; }
  body.focus-view #page-invoices #inv-form-label   { grid-area: formlabel; }
  body.focus-view #page-invoices #invoice-form     { grid-area: form; align-self: start; }

  /* ── Cash rec page: Daily Rec | Weekly Banking ────────────────────────
     Both panes side by side, each at phone width, each rendering exactly the
     same markup as the phone — nothing inside either one is re-laid-out. The
     tabs are redundant once both are on screen at once. */
  body.focus-view #page-cash #cash-tabs { display: none; }
  body.focus-view #page-cash .page-scroll {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    align-items: flex-start;
  }
  body.focus-view #page-cash .page-hero,
  body.focus-view #page-cash .week-selector { flex: 0 0 100%; }
  body.focus-view #page-cash #cash-daily-section,
  body.focus-view #page-cash #cash-weekly-section {
    /* !important beats the inline display the tab switcher sets */
    display: block !important;
    flex: 0 0 430px;
    width: 430px;
  }

  /* One week selector, at the top. The panels below follow it (App.setWeek
     broadcasts to every module on desktop), so their own selectors would just
     be duplicate controls fighting each other. */
  /* :not(.focused) again — an ID selector outranks .page.focused, so without
     it these pages lost their week nav the moment they became the focused
     page, leaving a gap where the control should be. */
  #page-cash:not(.focused) .week-selector,
  #page-timesheets:not(.focused) .week-selector,
  #page-invoices:not(.focused) .week-selector { display: none; }

  /* …but on its own page the dashboard's selector isn't on screen, so the
     page's own one comes back. It still drives every other panel through
     App.setWeek, so they stay in step. */
  body.focus-view .page.focused .week-selector { display: flex; }

  /* The dashboard is a KPI strip, not a panel: no card, no clipping. It was
     rendering as a bordered box with overflow:hidden, which sliced the tiles
     off mid-figure and hid their sub-labels. */
  #page-dashboard {
    background: none;
    border: none;
    border-radius: 0;
    overflow: visible;
  }
  #page-dashboard .page-scroll {
    max-height: none;
    overflow: visible;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    align-items: flex-start;
  }
  #page-dashboard .page-scroll > * { flex: 1 1 100%; }   /* week selector etc. stay full width */
  /* Grow each tile group by how many tiles it holds, so all five end up the
     same width across one row. The net-profit group holds a single tile. */
  #page-dashboard .hero-metrics {
    flex: 2 1 240px;
    margin: 0 !important;
  }
  #page-dashboard .hero-metrics.manager-only { flex: 1 1 130px; }

  /* ── Dashboard panels ─────────────────────────────────────────────
     The front page shows the week's working data, not just headline
     figures: the cash week day by day, this week's bills, who worked, and
     the profit trend. Each panel's header opens that module's full page. */
  #dash-panels {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    width: 100%;
    margin-top: 4px;
  }
  .dpanel {
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    padding: 14px 16px 12px;
    min-width: 0;
  }
  .dpanel-head {
    display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
    padding-bottom: 10px; margin-bottom: 4px;
    border-bottom: 1px solid var(--border);
  }
  .dpanel-head[data-open] { cursor: pointer; }
  .dpanel-head[data-open]:hover h2 { color: var(--green-400); }
  .dpanel-head[data-open]:focus-visible { outline: 2px solid var(--green-500); outline-offset: 3px; border-radius: 4px; }
  .dpanel-head h2 { font-size: 14.5px; font-weight: 700; color: var(--text-1); margin: 0; }
  .dpanel-note { font-size: 11px; font-weight: 550; color: var(--text-3); white-space: nowrap; }
  .dpanel-body { flex: 1; min-width: 0; }
  .dpanel-empty { font-size: 12px; color: var(--text-3); padding: 20px 0; text-align: center; }

  /* One line per day / bill / person */
  .drow {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 7px 0; border-bottom: 1px solid var(--border); min-width: 0;
  }
  .drow:last-child { border-bottom: none; }
  .drow-day {
    font-size: 12.5px; font-weight: 650; color: var(--text-1); min-width: 0;
    overflow: hidden; text-overflow: ellipsis;
  }
  .drow-day em {
    display: block; font-style: normal; font-weight: 500;
    font-size: 11px; color: var(--text-3); margin-top: 1px;
  }
  /* The cash rows name the counter on the same line, as the mockup has it */
  #dp-cash .drow-day em { display: inline; margin: 0; }
  .drow-right { display: flex; align-items: center; gap: 12px; white-space: nowrap; }
  .drow-sq { font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
  .drow-var { font-size: 11.5px; font-weight: 650; font-variant-numeric: tabular-nums; }
  .drow-amt { font-size: 13px; font-weight: 700; color: var(--text-1);
    font-variant-numeric: tabular-nums; min-width: 68px; text-align: right; }
  .drow-fill {
    font-family: var(--font); font-size: 11px; font-weight: 650;
    padding: 4px 10px; border-radius: 999px; cursor: pointer;
    border: 1px solid var(--green-500); background: transparent; color: var(--green-400);
  }
  .drow-fill:hover { background: rgba(47,192,141,.12); }

  .dpanel-foot { border-top: 1px solid var(--border); margin-top: 8px; padding-top: 8px; }
  .dpanel-foot:empty { border: none; margin: 0; padding: 0; }
  .dfoot-row {
    display: flex; justify-content: space-between; gap: 12px;
    font-size: 12px; color: var(--text-2); padding: 3px 0;
    font-variant-numeric: tabular-nums;
  }
  .dfoot-row.total { font-size: 13px; font-weight: 700; color: var(--text-1); }

  #dash-panels .ok    { color: var(--green-400); }
  #dash-panels .pos   { color: var(--green-400); }
  #dash-panels .near  { color: var(--text-2); }
  #dash-panels .off   { color: var(--red-500); }
  #dash-panels .muted { color: var(--text-3); }

  .dbadge {
    font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 999px;
    border: 1px solid var(--border-md); color: var(--text-3);
  }
  .dbadge.ok    { border-color: var(--green-500); color: var(--green-400); background: rgba(47,192,141,.10); }
  .dbadge.local { border-color: var(--amber-500); color: var(--amber-500); }
  .dbadge.cogs  { border-color: var(--border-md); }

  .trend-hint { font-size: 11px; font-weight: 500; color: var(--text-3); }
  .trend-bars { display: flex; align-items: flex-end; gap: 14px; height: 150px; margin-top: 12px; }
  .trend-col { flex: 1; display: flex; flex-direction: column; align-items: center;
    justify-content: flex-end; gap: 6px; height: 100%; min-width: 0; }
  .trend-col .fig { font-size: 11.5px; font-weight: 700; color: var(--text-2);
    font-variant-numeric: tabular-nums; white-space: nowrap; }
  .trend-col .bar { width: 68%; min-height: 3px; border-radius: 6px 6px 3px 3px;
    background: linear-gradient(180deg, var(--green-400), var(--green-600)); }
  .trend-col.now .bar { background: linear-gradient(180deg, #3FD59D, var(--green-500));
    box-shadow: 0 0 0 2px rgba(47,192,141,.25); }
  .trend-col.neg .bar { background: linear-gradient(180deg, #e06a6a, var(--red-500)); }
  .trend-col .cap { font-size: 10.5px; color: var(--text-3); white-space: nowrap; }
  .trend-empty { font-size: 12px; color: var(--text-3); padding: 18px 0; text-align: center; }

  /* Panel headings sit tighter than the mobile hero */
  .page-hero { padding: 2px 0 12px; }
  .page-title { font-size: 18px; letter-spacing: -0.2px; }
  .page-subtitle { font-size: 12px; }

  /* ── Timesheets: staff on the left, their week on the right ───────────
     Grid areas rather than auto-placement, because the DOM order is hero →
     week nav → metrics → list → detail → alert → push. */
  body.focus-view #page-timesheets .page-scroll {
    display: grid;
    grid-template-columns: 400px minmax(0, 1fr);
    grid-template-areas:
      "hero    hero"
      "weeknav metrics"
      "listlbl detail"
      "list    detail"
      "alert   detail"
      "push    detail";
    gap: 0 20px;
    align-content: start;
  }
  body.focus-view #page-timesheets .page-hero      { grid-area: hero; }
  body.focus-view #page-timesheets .week-selector  { grid-area: weeknav; align-self: center; }
  /* The two totals sit beside the week nav as a compact strip, not a pair of
     full-width slabs — that kept row 2 short, which is what lifts the staff
     list up level with the detail column. */
  body.focus-view #page-timesheets .hero-metrics {
    grid-area: metrics;
    display: flex; gap: 10px;
    justify-self: end; align-self: center;
    margin: 0;
  }
  body.focus-view #page-timesheets .hero-card {
    display: flex; align-items: baseline; gap: 9px;
    padding: 9px 14px;
  }
  body.focus-view #page-timesheets .hero-label { margin-bottom: 0; }
  body.focus-view #page-timesheets .hero-value { font-size: 17px; letter-spacing: -0.3px; }
  body.focus-view #page-timesheets .hero-delta { margin-top: 0; }
  body.focus-view #page-timesheets #ts-list-label  { grid-area: listlbl; }
  body.focus-view #page-timesheets #ts-staff-list  { grid-area: list; align-self: start; }
  body.focus-view #page-timesheets #ts-detail      { grid-area: detail; display: block; align-self: start; }
  body.focus-view #page-timesheets #ph-alert       { grid-area: alert; }
  body.focus-view #page-timesheets .push-section   { grid-area: push; }

  /* A card opens in the detail column, so it never expands in place */
  body.focus-view #page-timesheets .ts-days { display: none !important; }
  body.focus-view #page-timesheets .staff-card { cursor: pointer; }
  body.focus-view #page-timesheets .staff-card.selected {
    border-color: var(--green-500);
    box-shadow: inset 3px 0 0 var(--green-500);
  }

  /* ── Cleaning on a wide screen ───────────────────────────────────────
     The page was running the full width of a monitor for a list of job
     names. Capped, and in setup the list keeps the left while the open
     job's settings sit beside it. */
  /* One cap, on the page. The day's list had a second one at 720px inside it,
     which left a checklist sitting in a narrow column with half a monitor
     empty beside it. */
  body.focus-view #page-clean .page-scroll { max-width: 1180px; }

  /* This is now the ONLY rule that sets .clean-editor's display anywhere in the
     file. It used to be display:grid here and display:block at base level
     further down — equal weight, later source order, so the grid never applied
     and the detail pane rendered below the whole list instead of beside it.
     Kept id-scoped so nothing added later can quietly outrank it either. */
  #page-clean .clean-editor {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: 20px;
    align-items: start;
  }
  #page-clean .clean-edit-detail {
    position: sticky; top: 0;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--r-lg); padding: 14px 15px;
  }
  #page-clean .clean-edit-detail .clean-detail {
    background: none; border: none; padding: 0; margin: 0;
  }
  #page-clean .clean-edit-detail .clean-repeat { background: var(--surface-2); }

  /* The roster is the point of the Staff page on a big screen */
  #staff-roster-wrap { display: block; }
  body.focus-view #page-staff .page-scroll { display: block; }
}

/* =============================================
   WEEKLY ROSTER
   Styled outside the desktop media query so the print stylesheet —
   which runs at A4 width, not screen width — gets the same rules.
   ============================================= */

.roster-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 14px;
}
.roster-bar .week-selector { margin: 0; flex: 0 1 auto; }
.roster-bar-right { display: flex; align-items: center; gap: 10px; }
.roster-btn { width: auto; padding: 9px 16px; font-size: 12.5px; position: relative; }
.roster-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; margin-left: 7px; padding: 0 5px;
  border-radius: 9px; background: var(--amber-500); color: #24160a;
  font-size: 11px; font-weight: 750;
}
.roster-status { font-size: 11.5px; font-weight: 650; color: var(--text-3); }
.roster-status.ok   { color: var(--green-400); }
.roster-status.warn { color: var(--amber-500); }

.roster-sheet {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 16px 18px 14px;
}
.roster-print-head { display: none; }

.roster-table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  font-size: 12px;
}
.roster-table th, .roster-table td {
  border: 1px solid var(--border);
  padding: 3px;
  vertical-align: middle;
  text-align: center;
}
.roster-table thead th {
  padding: 6px 3px;
  font-weight: 700; color: var(--text-2);
  background: var(--surface-2, rgba(255,255,255,.03));
}
.rc-dow  { display: block; font-size: 12px; }
.rc-date { display: block; font-size: 10.5px; font-weight: 550; color: var(--text-3); }
.roster-table .rc-name {
  width: 15%; text-align: left; padding-left: 9px;
  font-weight: 650; color: var(--text-1); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.roster-table .rc-total {
  width: 8%; font-weight: 700; color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.roster-table tfoot td, .roster-table tfoot th {
  font-weight: 700; color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

/* Every box is the same depth so the rows line up down the page */
.shift-box {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; min-height: 34px; padding: 5px 4px;
  border: 1px solid; border-radius: 5px;
  font-variant-numeric: tabular-nums;
}
.shift-box + .shift-box { margin-top: 3px; }
.sh-time { font-size: 11.5px; font-weight: 700; line-height: 1.15; }
.sh-hrs  { font-size: 10px;   font-weight: 600; opacity: .75; line-height: 1.1; }

/* Dark text on a light fill — reads cleanly on paper */
.sh-blue   { background: #D6E8FA; border-color: #9CC4E8; color: #17456E; }
.sh-orange { background: #FAE0C4; border-color: #EDBB82; color: #74430F; }
.sh-pink   { background: #F9D5E2; border-color: #EDA3BF; color: #78234E; }
.sh-yellow { background: #FAEFBD; border-color: #E5CF71; color: #675103; }
.sh-green  { background: #D2EED6; border-color: #90D19E; color: #1B572E; }

.roster-legend {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  margin-top: 12px; font-size: 11px; color: var(--text-3);
}
.lg-item { display: inline-flex; align-items: center; gap: 6px; }
.lg-chip {
  width: 15px; height: 11px; border-radius: 3px; border: 1px solid; display: inline-block;
}

/* =============================================
   TIMESHEETS — rostered vs actual detail column (desktop)
   ============================================= */
#ts-detail {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 14px 16px 12px;
}
.ts-detail-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; padding-bottom: 10px; margin-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.ts-detail-name { font-size: 15px; font-weight: 700; color: var(--text-1); }
.ts-detail-sub  { font-size: 11.5px; font-weight: 550; color: var(--text-3); margin-top: 3px; }
.ts-detail-total {
  font-size: 22px; font-weight: 750; color: var(--text-1);
  letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.ts-detail-note { font-size: 11.5px; color: var(--text-3); margin-top: 10px; }

.ts-detail-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.ts-detail-table th, .ts-detail-table td {
  text-align: left; padding: 7px 8px; vertical-align: middle;
  border-bottom: 1px solid var(--border);
}
.ts-detail-table thead th {
  font-size: 11px; font-weight: 650; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .04em; padding-bottom: 5px;
}
.ts-detail-table tbody th { font-weight: 650; color: var(--text-1); white-space: nowrap; }
.ts-detail-table tfoot th, .ts-detail-table tfoot td {
  border-bottom: none; padding-top: 10px;
  font-weight: 700; color: var(--text-1); font-variant-numeric: tabular-nums;
}
.ts-detail-table .td-hours, .ts-detail-table .td-diff { text-align: right; white-space: nowrap; }
.ts-detail-table tr.row-flag th, .ts-detail-table tr.row-flag td { background: rgba(232,168,56,.07); }
.td-time { display: block; font-weight: 600; color: var(--text-1); font-variant-numeric: tabular-nums; }
.td-sub  { display: block; font-size: 10.5px; color: var(--text-3); margin-top: 1px;
  font-variant-numeric: tabular-nums; }
.td-flag { font-size: 11.5px; font-weight: 650; color: var(--amber-500); }
.diff-ok    { font-size: 11.5px; font-weight: 600; color: var(--text-3); }
.diff-over  { font-weight: 700; color: var(--amber-500); font-variant-numeric: tabular-nums; }
.diff-under { font-weight: 700; color: var(--green-400); font-variant-numeric: tabular-nums; }
#ts-detail .ts-hours-input {
  width: 66px; text-align: right; font-size: 12.5px; font-weight: 600;
  padding: 4px 6px; border: 1.5px solid var(--border); border-radius: 6px;
  background: var(--surface-2); color: var(--text-1); font-family: var(--font);
}

/* Supervisor tick-box on the staff card (phone and desktop) */
.sup-toggle {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 12px; margin-bottom: 4px;
  border: 1px solid var(--border); border-radius: var(--r-md, 10px);
  cursor: pointer;
}
.sup-toggle input { width: 17px; height: 17px; margin-top: 1px; accent-color: var(--green-500); flex: none; }
.sup-toggle strong { display: block; font-size: 13px; font-weight: 600; color: var(--text-1); }
.sup-toggle em { display: block; font-size: 11.5px; font-style: normal; color: var(--text-3); margin-top: 3px; line-height: 1.4; }

/* =============================================
   PRINT — A4 landscape roster, one page
   Everything but the roster sheet is taken out of the flow, and the
   sheet is re-coloured for paper (the app's dark theme would print
   as a black rectangle).
   ============================================= */
@media print {
  /* margin: 0 is what suppresses the browser's own header and footer — the
     date/time line and the bizapp-v2 URL. With no page margin to print them
     into, Chrome and Safari drop them. The page edge is then held by padding
     on the sheet itself (below) instead. */
  @page { size: A4 landscape; margin: 0; }

  /* The app shell is sized to the viewport (body and #app are both 100dvh).
     On paper a dvh resolves to the page box, so a shell that is exactly one
     page tall spills onto a second, blank one — every height has to be
     released, min-heights included. */
  html, body.print-roster {
    height: auto !important; min-height: 0 !important;
    overflow: visible !important; margin: 0 !important; padding: 0 !important;
  }
  body.print-roster { background: #fff !important; }
  body.print-roster > *:not(#app) { display: none !important; }
  body.print-roster #app {
    display: block !important; max-width: none !important;
    margin: 0 !important; padding: 0 !important;
    height: auto !important; min-height: 0 !important;
  }
  body.print-roster #app > *:not(#page-container) { display: none !important; }
  body.print-roster #page-container {
    display: block !important; padding: 0 !important; overflow: visible !important;
    height: auto !important; min-height: 0 !important; max-height: none !important;
  }
  body.print-roster #page-container > *:not(#page-staff) { display: none !important; }
  body.print-roster #page-staff {
    display: block !important; background: none !important; border: none !important;
    overflow: visible !important;
    height: auto !important; min-height: 0 !important; max-height: none !important;
  }
  body.print-roster #page-staff .page-scroll {
    display: block !important; overflow: visible !important;
    height: auto !important; min-height: 0 !important; max-height: none !important;
    padding: 0 !important;
  }
  body.print-roster #page-staff .page-scroll > *:not(#staff-roster-wrap) { display: none !important; }
  body.print-roster #staff-roster-wrap { display: block !important; }
  body.print-roster .roster-bar { display: none !important; }

  body.print-roster .roster-sheet {
    background: #fff !important; border: none !important;
    border-radius: 0 !important;
    padding: 9mm 10mm !important;   /* stands in for the page margin */
  }
  body.print-roster .roster-print-head {
    display: flex !important; align-items: baseline; justify-content: space-between;
    margin-bottom: 7px; color: #111;
  }
  body.print-roster .roster-print-title { font-size: 13pt; font-weight: 700; }
  body.print-roster .roster-print-week  { font-size: 10pt; font-weight: 600; }

  body.print-roster .roster-table { font-size: 7.5pt; }
  body.print-roster .roster-table th,
  body.print-roster .roster-table td { border-color: #b9b9b9 !important; padding: 2px !important; }
  body.print-roster .roster-table thead th { background: #f1f1f1 !important; color: #111 !important; }
  body.print-roster .roster-table .rc-name,
  body.print-roster .roster-table .rc-total,
  body.print-roster .roster-table tfoot td,
  body.print-roster .roster-table tfoot th { color: #111 !important; }
  body.print-roster .rc-date { color: #555 !important; }

  body.print-roster .shift-box { min-height: 12.5mm; padding: 1.6mm 1mm !important; }
  body.print-roster .sh-time { font-size: 7.5pt; }
  body.print-roster .sh-hrs  { font-size: 6.5pt; }
  body.print-roster .roster-legend { margin-top: 6px; color: #444 !important; font-size: 7pt; }
  body.print-roster tr { break-inside: avoid; page-break-inside: avoid; }

  /* Keep the shift colours — they are what makes the roster readable */
  body.print-roster .shift-box, body.print-roster .lg-chip,
  body.print-roster .roster-table thead th {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }
}

/* =============================================
   CLEANING LIST
   Big tap targets — this gets used at the end of a shift, on a counter
   iPad, by someone in a hurry.
   ============================================= */

.clean-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; margin-bottom: 10px;
}
.clean-day   { font-size: 15px; font-weight: 700; color: var(--text-1); }
.clean-count { font-size: 12px; font-weight: 550; color: var(--text-3); margin-top: 2px; }
.clean-manage { width: auto; padding: 9px 16px; font-size: 12.5px; flex: none; }

.clean-progress {
  height: 6px; border-radius: 999px; background: var(--surface-2);
  overflow: hidden; margin-bottom: 14px;
}
.clean-progress span {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--green-400), var(--green-600));
  transition: width .25s ease;
}

.clean-list { display: flex; flex-direction: column; gap: 8px; }
.clean-empty { font-size: 13px; color: var(--text-3); text-align: center; padding: 28px 0; }

.clean-row {
  display: flex; align-items: center; gap: 13px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 12px 14px;
}
.clean-row.is-done { border-color: var(--green-500); background: rgba(47,192,141,.06); }
.clean-tick {
  flex: none; width: 36px; height: 36px; border-radius: 10px;
  border: 2px solid var(--border-md); background: var(--surface-2);
  color: #fff; font-size: 19px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.clean-row.is-done .clean-tick { background: var(--green-600); border-color: var(--green-600); }
.clean-main  { min-width: 0; flex: 1; }
.clean-title { font-size: 14px; font-weight: 600; color: var(--text-1); }
.clean-row.is-done .clean-title { text-decoration: line-through; color: var(--text-2); }
.clean-sub   { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
.clean-row.is-done .clean-sub { color: var(--green-400); font-weight: 600; }

/* Name picker — opens under the job it belongs to */
.clean-picker {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md, 10px); padding: 11px 12px; margin-top: -4px;
}
.clean-pick-hint { font-size: 11.5px; font-weight: 600; color: var(--text-3); margin-bottom: 8px; }
.clean-pick-names { display: flex; flex-wrap: wrap; gap: 8px; }
.clean-name {
  font-family: var(--font); font-size: 13.5px; font-weight: 600;
  padding: 9px 15px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--green-500); background: transparent; color: var(--green-400);
}
.clean-name:active { background: var(--green-600); color: #fff; }

/* Manager setup */
.clean-edit {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 12px 14px;
}
.clean-edit-top { display: flex; align-items: center; gap: 10px; }
.clean-input {
  flex: 1; min-width: 0; height: 38px; padding: 0 11px;
  border: 1px solid var(--border-md); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text-1);
  font-family: var(--font); font-size: 14px;
}
.clean-input:focus { outline: none; border-color: var(--green-400); }
.clean-del {
  flex: none; width: 32px; height: 32px; border-radius: 50%; border: none;
  background: transparent; color: var(--red-500); font-size: 20px; cursor: pointer;
}
/* Repeat picker — the iOS pattern: a labelled row with the schedule read back
   on the right, then seven round day buttons running Monday to Sunday. */
.clean-repeat {
  background: var(--surface-2); border-radius: var(--r-md, 12px);
  padding: 11px 13px 12px; margin-top: 11px;
}
.clean-repeat-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  font-size: 13.5px; font-weight: 600; color: var(--text-1);
  padding-bottom: 9px; border-bottom: 1px solid var(--border);
}
.clean-repeat-val { font-weight: 550; color: var(--text-3); text-align: right; }
.clean-circles {
  display: flex; justify-content: space-between; gap: 6px; margin: 11px 0 2px;
}
.clean-circle {
  flex: 1 1 0; min-width: 0; aspect-ratio: 1 / 1; max-width: 46px;
  border-radius: 50%; border: none; cursor: pointer;
  background: var(--border); color: var(--text-2);
  font-family: var(--font); font-size: 15px; font-weight: 600;
  display: flex; align-items: center; justify-content: center;
  transition: background .12s, color .12s;
}
.clean-circle.on { background: var(--green-600); color: #fff; }
.clean-repeat-opts { display: flex; gap: 8px; margin-top: 11px; }
.clean-chip {
  font-family: var(--font); font-size: 12.5px; font-weight: 650;
  padding: 8px 15px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--border-md); background: transparent; color: var(--text-3);
}
.clean-chip.on { border-color: var(--green-500); background: rgba(47,192,141,.14); color: var(--green-400); }

/* Full-screen view, opened from the PIN pad */
#clean-overlay {
  position: fixed; inset: 0; z-index: 1000; display: none;
  flex-direction: column; background: var(--bg);
}
.clean-overlay-bar {
  display: flex; align-items: center; justify-content: space-between;
  /* env() directly, as everywhere else in this file — there is no --safe-top
     variable, so var(--safe-top) fell back to zero and put this bar under the
     status bar, where iOS owns the taps. */
  padding: calc(env(safe-area-inset-top, 0px) + 14px) 12px 14px;
  background: var(--green-900); color: #fff;
  font-size: 15px; font-weight: 650;
}
.clean-back {
  /* A real tap target — this is the way out of the full-screen list. */
  min-width: 72px; min-height: 44px; padding: 0 8px;
  display: flex; align-items: center; gap: 2px;
  background: none; border: none; color: #fff;
  font-family: var(--font); font-size: 16px; font-weight: 600; cursor: pointer;
}
/* A second way out, at the end of the list — where someone who has just
   finished the jobs actually is. */
.clean-done-btn {
  width: 100%; margin-top: 22px; padding: 15px;
  border: 1px solid var(--border-md); border-radius: var(--r-lg);
  background: var(--surface); color: var(--text-1);
  font-family: var(--font); font-size: 15px; font-weight: 650; cursor: pointer;
}
.clean-overlay-body {
  flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch;
  padding: 16px 16px calc(var(--safe-bottom, 0px) + 24px);
}

/* Day stepper — the log keeps this week and last, so yesterday is reachable */
.clean-daynav { display: flex; align-items: center; gap: 10px; min-width: 0; }
.clean-step {
  flex: none; width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--border-md); background: var(--surface-2);
  color: var(--text-2); font-size: 18px; line-height: 1; cursor: pointer;
  font-family: var(--font);
}
.clean-step:disabled { opacity: .3; cursor: default; }
.clean-tick.is-past {
  border-style: dashed; background: transparent;
  color: var(--green-400); cursor: default;
}
.clean-row.is-done .clean-tick.is-past { background: var(--green-600); border-style: solid; color: #fff; }
.clean-note { font-size: 11px; color: var(--text-3); text-align: center; margin-top: 14px; }

/* Headings group the day's jobs by whoever is covering them */
.clean-section {
  font-size: 11.5px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-3);
  margin: 14px 0 2px; padding-left: 2px;
}
.clean-list > .clean-section:first-child { margin-top: 0; }
.clean-notes {
  font-size: 12px; color: var(--text-2); margin-top: 3px; line-height: 1.45;
}
.clean-row.is-done .clean-notes { display: none; }

/* ── Setup: a short list you can reorder, settings for one job at a time ── */
.clean-edit-list { display: flex; flex-direction: column; gap: 6px; }

.clean-edit-row {
  display: flex; align-items: center; gap: 9px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md, 12px); padding: 7px 9px;
}
.clean-edit-row.selected { border-color: var(--green-500); box-shadow: inset 3px 0 0 var(--green-500); }

/* Headings carry the header's own colour, so a glance down the list shows
   where each block starts. */
.clean-edit-row.is-heading {
  background: var(--green-900); border-color: var(--green-900);
  margin-top: 10px;
}
.clean-edit-row.is-heading:first-child { margin-top: 0; }
.clean-edit-row.is-heading .clean-arrow {
  background: rgba(255,255,255,.12); border-color: rgba(255,255,255,.2); color: #fff;
}
.clean-edit-row.is-heading .clean-del { color: #F9AAAA; }

.clean-move { display: flex; flex-direction: column; gap: 2px; flex: none; }
.clean-arrow {
  width: 26px; height: 19px; border-radius: 5px; cursor: pointer;
  border: 1px solid var(--border-md); background: var(--surface-2);
  color: var(--text-2); font-size: 11px; line-height: 1; font-family: var(--font);
}
.clean-arrow:disabled { opacity: .25; cursor: default; }

.clean-input {
  flex: 1; min-width: 0; height: 36px; padding: 0 10px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: transparent; color: var(--text-1);
  font-family: var(--font); font-size: 14px;
}
.clean-input:focus { outline: none; border-color: var(--green-400); background: var(--surface-2); }
.clean-input.is-heading-input {
  color: #fff; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; font-size: 12.5px;
}
.clean-input.is-heading-input::placeholder { color: rgba(255,255,255,.45); }

.clean-details-btn {
  flex: none; display: flex; align-items: center; gap: 5px;
  height: 28px; padding: 0 11px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--border-md); background: var(--surface-2);
  color: var(--text-3); font-family: var(--font); font-size: 11.5px; font-weight: 650;
}
.clean-edit-row.selected .clean-details-btn {
  border-color: var(--green-500); background: rgba(47,192,141,.14); color: var(--green-400);
}
.clean-del {
  flex: none; width: 28px; height: 28px; border-radius: 50%; border: none;
  background: transparent; color: var(--red-500); font-size: 19px; cursor: pointer;
}

/* The open job's settings — under its row on a phone, in the pane on a desktop */
.clean-detail {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md, 12px); padding: 12px 13px; margin: -2px 0 4px;
}
.clean-detail-label {
  display: block; font-size: 11px; font-weight: 650; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 6px;
}
.clean-detail-empty {
  font-size: 12.5px; color: var(--text-3); text-align: center;
  padding: 30px 18px; line-height: 1.5;
}
.clean-notes-input {
  width: 100%; padding: 8px 10px; resize: vertical;
  border: 1px solid var(--border-md); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text-2);
  font-family: var(--font); font-size: 12.5px; line-height: 1.45;
}
.clean-notes-input:focus { outline: none; border-color: var(--green-400); }
.clean-detail .clean-repeat { background: var(--surface); margin-top: 12px; }

.clean-add-row { display: flex; gap: 8px; margin-top: 10px; }
.clean-add-row .secondary-btn { flex: 1; }
