/* ==========================================================================
   DEM Workforce — shared design system
   Brand: Deus logo (web/brand/deus-logo.png) + name "DEM Workforce" in each
   page's .topnav__logo block
   ========================================================================== */

:root {
  --color-primary: #5B4CDB;
  --color-primary-dark: #4A3BC4;
  --color-primary-light: #EFECFC;
  --color-bg: #F7F7FB;
  --color-surface: #FFFFFF;
  --color-border: #E6E5F0;
  --color-text: #1E1B33;
  --color-text-muted: #6B6880;
  --color-text-faint: #9694A8;
  --color-success: #1AA870;
  --color-success-bg: #E6F7F0;
  --color-danger: #E0503C;
  --color-danger-bg: #FCEAE7;
  --color-warning: #E0A030;
  --color-warning-bg: #FCF3E2;
  --color-link: #4A3BC4;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --shadow-card: 0 1px 2px rgba(30, 27, 51, 0.06), 0 1px 8px rgba(30, 27, 51, 0.04);
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; }

/* Stop iOS/Android bumping font sizes on rotate, which silently breaks the
   width calculations every media query below depends on. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

/* The `hidden` attribute is only `display: none` in the UA stylesheet, so any
   author rule that sets display — `.stat-grid { display: grid }`, for one —
   silently beats it and the element stays on screen. This makes `hidden`
   behave the way everyone assumes it already does. */
[hidden] { display: none !important; }
html, body {
  margin: 0;
  padding: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.45;
}
a { color: var(--color-link); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { margin: 0; font-weight: 600; }
button { font-family: inherit; cursor: pointer; }
img, svg { display: block; }

/* ---------- Top navigation ---------- */
.topnav {
  height: 60px;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  padding: 0 20px;
  gap: 28px;
  position: sticky;
  top: 0;
  z-index: 50;
}
/* Deus logo + app name. In the header it is a link home; on the login and
   forgot-password cards it is just the brand. The PNG is black ink on a
   transparent background (built by dev-tools/brand/make-logo.ps1 from
   docs/brand/deus-logo-original.png), so it sits on any light surface. */
.topnav__logo {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  font-size: 16px;
  color: var(--color-text);
  white-space: nowrap;
  flex-shrink: 0;
}
.topnav__logo img { height: 34px; width: auto; }
.topnav__logo--auth img { height: 40px; }
a.topnav__logo { border-radius: var(--radius-sm); transition: opacity .12s ease; }
a.topnav__logo:hover { text-decoration: none; opacity: .75; }
a.topnav__logo:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 4px; }
/* Nav row. The history here matters, because two "fixes" fought each other:

   1. Originally this had `overflow-x: auto` so the row could scroll sideways
      on a narrow window. But per the CSS overflow spec, setting EITHER axis
      to something other than "visible" forces the OTHER axis to "auto" too.
      That made this row a scroll container, which clipped the Timesheets
      dropdown panel to the header's height — you had to scroll inside the
      header to see the menu. Declaring `overflow-y: visible` does NOT undo
      that; the browser silently computes it back to "auto".

   2. So the overflow was removed entirely. That fixed the dropdown but broke
      something worse and less obvious: a flex item defaults to
      `min-width: auto`, meaning it will not shrink below its own min-content
      width. Every nav link is `white-space: nowrap`, so this row's floor is
      the full width of all the links laid end to end. Below roughly 1024px
      the row refused to shrink, the header overflowed to the right, and it
      carried `.topnav__right` — the notification bell and the avatar — clean
      off the edge of the screen. The avatar was still "there" in the DOM and
      still had its click handler; it was simply outside the window where no
      pointer could reach it.

   The actual fix is to stop making the popup's visibility depend on this
   element's overflow at all. The dropdown panel is now `position: fixed`
   (positioned under its trigger by app.js), and fixed elements escape an
   ancestor's overflow clipping. That frees this row to scroll horizontally
   again — `min-width: 0` lets it shrink properly — so the header stays one
   60px line at any width and the right-hand controls are never displaced. */
.topnav__links {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: thin;
}
.topnav__links::-webkit-scrollbar { height: 4px; }
.topnav__links::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 2px; }
.topnav__links::-webkit-scrollbar-track { background: transparent; }
.topnav__link {
  color: var(--color-text-muted);
  font-weight: 500;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}
.topnav__link:hover { background: var(--color-bg); text-decoration: none; }
.topnav__link.active { color: var(--color-primary); background: var(--color-primary-light); }

.topnav__dropdown { position: relative; flex-shrink: 0; }
/* Fixed, not absolute: a fixed element's containing block is the viewport, so
   it is not clipped by the scrollable nav row above it. app.js sets top/left
   from the trigger's position each time the menu opens. */
.topnav__dropdown-panel {
  display: none;
  position: fixed;
  top: 0; left: 0;
  z-index: 800;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  min-width: 260px;
  padding: 6px;
}
.topnav__dropdown.open .topnav__dropdown-panel { display: block; }
.topnav__dropdown-item {
  display: block;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  color: var(--color-text);
}
.topnav__dropdown-item:hover { background: var(--color-bg); text-decoration: none; }
.topnav__dropdown-item strong { display: block; font-size: 13.5px; }
.topnav__dropdown-item span { display: block; font-size: 12px; color: var(--color-text-muted); }

/* flex-shrink: 0 is load-bearing — it guarantees the role pill and avatar
   keep their full width and stay inside the viewport no matter how cramped
   the nav row to their left gets. */
.topnav__right {
  display: flex; align-items: center; gap: 14px;
  margin-left: auto; flex-shrink: 0; padding-left: 8px;
}
/* The avatar is a real <button>, not a styled <div>: it gets keyboard focus,
   fires on Enter/Space for free, and announces itself as a menu trigger. It
   used to be a div whose only affordance was a JS click handler — if that
   handler ever failed to attach the control looked completely normal but did
   nothing at all, which is exactly what went wrong. */
.topnav__avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--color-primary); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: 13px;
  border: none; padding: 0; cursor: pointer;
  font-family: inherit; line-height: 1;
  transition: box-shadow .12s ease, filter .12s ease;
}
.topnav__avatar:hover { filter: brightness(1.08); box-shadow: 0 0 0 3px var(--color-primary-light); }
.topnav__avatar:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-primary-light), 0 0 0 4px var(--color-primary); }
.topnav__avatar[aria-expanded="true"] { box-shadow: 0 0 0 3px var(--color-primary-light); }

/* Current-role pill, sits left of the avatar. Always visible once we know who
   is logged in, so "which role am I seeing this as?" never needs a click.
   Clicking it opens the account menu. */
.topnav__role-pill {
  display: inline-flex; align-items: center; gap: 6px;
  height: 26px; padding: 0 10px;
  border-radius: 999px;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-family: inherit; font-size: 11.5px; font-weight: 600;
  letter-spacing: .02em; white-space: nowrap; cursor: pointer;
}
.topnav__role-pill[hidden] { display: none; }
.topnav__role-pill:hover { background: var(--color-bg); color: var(--color-text); }
.topnav__role-pill:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 1px; }

/* Account menu panel (built by app.js, appended to <body>) */
.user-menu {
  position: fixed; z-index: 900;
  /* Bounded, or the panel sizes itself to the longest unwrapped line of hint
     text and ends up spanning half the window. */
  min-width: 248px; max-width: 320px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 10px 30px rgba(30, 27, 51, .18);
  overflow: hidden;
  font-family: inherit;
}
.user-menu[hidden] { display: none; }
.user-menu__head { padding: 12px 14px; border-bottom: 1px solid var(--color-border); }
.user-menu__name { font-weight: 600; font-size: 13.5px; }
.user-menu__sub { font-size: 12px; color: var(--color-text-muted); margin-top: 2px; word-break: break-all; }
.user-menu__action {
  display: block; width: 100%; text-align: left;
  padding: 11px 14px; border: none; background: none;
  font-family: inherit; font-size: 13.5px; color: var(--color-text); cursor: pointer;
}
.user-menu__action:hover { background: var(--color-bg); text-decoration: none; }

/* Narrow windows. The nav row scrolls sideways, but the logo and the
   right-hand controls have intrinsic widths that can't shrink, so past a
   point they'd still push the header wider than the window — which is the
   very failure that put the avatar out of reach. Give back space in stages,
   dropping the least essential things first. The role stays discoverable
   after the pill goes: it's in the account menu. On phones the logo stays
   (it is the way home) but its name is dropped. */
@media (max-width: 880px) {
  .topnav { gap: 14px; padding: 0 12px; }
  .topnav__right { gap: 10px; padding-left: 6px; }
  .topnav__link { padding: 8px 9px; }
}
@media (max-width: 640px) {
  .topnav .topnav__logo-name { display: none; }
  .topnav .topnav__logo img { height: 30px; }
  .topnav__role-pill { display: none; }
}

/* Scheduled-vs-actual variance markers on the timesheet rows. Deliberately
   quieter than a chip: most rows have one, and a table of loud badges stops
   the genuinely wrong ones standing out. */
.var {
  display: inline-block;
  font-size: 11.5px; font-weight: 600;
  white-space: nowrap;
}
.var + .var { margin-left: 6px; }
.var-ok { color: var(--color-text-faint); font-weight: 500; }
.var-bad { color: var(--color-danger); }
.var-note { color: var(--color-text-muted); font-weight: 500; }

/* Inline break editor on the timesheet rows */
.break-input {
  width: 54px;
  padding: 3px 6px;
  font-family: inherit; font-size: 13px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface); color: var(--color-text);
  text-align: right;
}
.break-input:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 2px var(--color-primary-light); }

/* ---------- Page shell ---------- */
.page {
  display: flex;
  min-height: calc(100vh - 60px);
}
.page__left-sidebar {
  width: 230px;
  flex-shrink: 0;
  background: var(--color-surface);
  border-right: 1px solid var(--color-border);
  padding: 18px 14px;
}
.page__main {
  flex: 1;
  min-width: 0;
  padding: 28px 32px;
}
.page__right-sidebar {
  width: 300px;
  flex-shrink: 0;
  background: var(--color-surface);
  border-left: 1px solid var(--color-border);
  padding: 18px 18px;
}

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
  gap: 16px;
  flex-wrap: wrap;
}
.page-header h1 { font-size: 24px; }
.page-header__meta { color: var(--color-text-muted); font-size: 13px; margin-top: 2px; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  font-size: 13.5px;
  font-weight: 600;
  border: 1px solid transparent;
  white-space: nowrap;
}
.btn-primary { background: var(--color-primary); color: #fff; }
.btn-primary:hover { background: var(--color-primary-dark); }
.btn-secondary { background: var(--color-primary-light); color: var(--color-primary-dark); }
.btn-secondary:hover { background: #e2ddfa; }
.btn-outline { background: var(--color-surface); color: var(--color-text); border-color: var(--color-border); }
.btn-outline:hover { background: var(--color-bg); }
.btn-ghost { background: transparent; color: var(--color-text-muted); }
.btn-ghost:hover { background: var(--color-bg); }
.btn-sm { padding: 5px 10px; font-size: 12.5px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* ---------- Inputs ---------- */
.input, .select {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  font-size: 13.5px;
  background: var(--color-surface);
  color: var(--color-text);
}
/* A checkbox list standing in for a multi-select <select multiple> — same
   box look as .input/.select, but each option is its own row with a real
   checkbox rather than a ctrl/cmd-click multi-select, which is easy to use
   by accident (a stray click can silently deselect everything already
   picked) and easy to miss the selection state of at a glance. */
.checkbox-list {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  max-height: 130px;
  overflow-y: auto;
  padding: 4px;
}
.checkbox-list__item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px;
  font-size: 13.5px;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.checkbox-list__item:hover { background: var(--color-bg); }
.checkbox-list__item input { flex-shrink: 0; }
.checkbox-list--disabled { opacity: .5; pointer-events: none; }
.checkbox-list__empty { padding: 8px; font-size: 13px; color: var(--color-text-faint); }

.search-box {
  display: flex; align-items: center; gap: 8px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  background: var(--color-surface);
  flex: 1;
  max-width: 420px;
}
.search-box input { border: none; outline: none; flex: 1; font-size: 13.5px; background: transparent; }
.search-box svg { color: var(--color-text-faint); flex-shrink: 0; }

/* ---------- Cards ---------- */
.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
}
.card-pad { padding: 20px; }

/* ---------- Table ---------- */
.table { width: 100%; border-collapse: collapse; }
.table th {
  text-align: left;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-text-faint);
  padding: 10px 14px;
  border-bottom: 1px solid var(--color-border);
}
.table td {
  padding: 14px;
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}
.table tr:last-child td { border-bottom: none; }
.table tr:hover td { background: #FCFCFF; }
.table-group-header td {
  background: var(--color-bg);
  font-weight: 600;
  padding: 8px 14px;
  color: var(--color-text);
}
.table-group-header:hover td { background: var(--color-bg); }

/* ---------- Chips / badges ---------- */
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  border-radius: 100px;
  padding: 3px 10px;
  font-size: 12px;
  font-weight: 600;
}
.chip .dot { width: 6px; height: 6px; border-radius: 50%; }
.chip-success { background: var(--color-success-bg); color: var(--color-success); }
.chip-success .dot { background: var(--color-success); }
.chip-danger { background: var(--color-danger-bg); color: var(--color-danger); }
.chip-danger .dot { background: var(--color-danger); }
.chip-warning { background: var(--color-warning-bg); color: var(--color-warning); }
.chip-warning .dot { background: var(--color-warning); }
.chip-neutral { background: var(--color-bg); color: var(--color-text-muted); }

/* ---------- Avatars ---------- */
.avatar {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--color-primary-light); color: var(--color-primary-dark);
  display: flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: 12.5px;
  flex-shrink: 0;
}
.avatar-sm { width: 26px; height: 26px; font-size: 11px; }
/* A profile photo laid over the initials (app.js, setAvatarPhoto). Used by
   every round avatar: .avatar, the header's .topnav__avatar, the People
   drawer and the photo dialog. If the image fails, the initials show. */
.has-photo { position: relative; overflow: hidden; }
.avatar-photo {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; border-radius: 50%;
  background: var(--color-surface);
}

/* ---------- Sidebar sections (Locations' "Who's on" groups) ---------- */
.sidebar-section { margin-bottom: 22px; }
.sidebar-section__title {
  font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--color-text-faint); font-weight: 700; margin-bottom: 8px;
  padding: 0 6px;
}

.roster-person, .team-person {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 4px;
}
.roster-person__meta, .team-person__meta { min-width: 0; }
.roster-person__name, .team-person__name { font-weight: 600; font-size: 13px; display: block; }
.roster-person__sub, .team-person__sub {
  font-size: 12px; color: var(--color-text-muted);
  /* display:block is what makes the next three declarations do anything: on
     an inline span, overflow and text-overflow are ignored, so a long line
     ("Due 8:00 am · 168 min late · Retail · Camperdown Retail") pushed the
     sidebar wider than the window instead of being truncated. */
  display: block;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.status-dot {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
}
.status-dot.late { background: var(--color-danger); }
.status-dot.onshift { background: var(--color-success); }

/* ---------- Stat cards (Home) ---------- */
/* minmax(0, 1fr), not 1fr: a grid track defaults to a min-content floor, so a
   long unbreakable label ("Pending timesheet approvals") stops the column
   shrinking and the whole grid pushes past the viewport instead of wrapping
   the text. This is the same min-width:auto trap the nav row hit. */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin-bottom: 28px;
}
.stat-card { padding: 18px; }
.stat-card__label { color: var(--color-text-muted); font-size: 13px; margin-bottom: 6px; }
.stat-card__value { font-size: 28px; font-weight: 700; }
.stat-card__foot { font-size: 12px; color: var(--color-text-faint); margin-top: 6px; }

.link-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}
.link-card {
  padding: 20px;
  display: flex; flex-direction: column; gap: 10px;
  color: var(--color-text);
}
.link-card:hover { text-decoration: none; border-color: var(--color-primary); }
.link-card__icon {
  width: 38px; height: 38px; border-radius: var(--radius-sm);
  background: var(--color-primary-light); color: var(--color-primary-dark);
  display: flex; align-items: center; justify-content: center;
}
.link-card__title { font-weight: 600; font-size: 15px; }
.link-card__desc { font-size: 12.5px; color: var(--color-text-muted); }

/* ---------- Tabs ---------- */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--color-border); margin-bottom: 4px; }
.tab {
  padding: 10px 14px; font-weight: 600; font-size: 13.5px;
  color: var(--color-text-muted); border-bottom: 2px solid transparent;
  display: flex; align-items: center; gap: 6px;
}
.tab .count { color: var(--color-text-faint); font-weight: 500; }
.tab.active { color: var(--color-primary); border-bottom-color: var(--color-primary); }
.tab.active .count { color: var(--color-primary); }
.tab:hover { text-decoration: none; color: var(--color-text); }

/* ---------- Toolbar ---------- */
.toolbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 16px;
}
.toolbar .spacer { flex: 1; }

/* ---------- Schedule grid ---------- */
/* ---------- Roster (Schedule) ---------- */
/* A name column that stays put, then one column per day. Rows are employees,
   with an "Open shifts" row pinned at the top. */
.roster {
  display: grid;
  grid-template-columns: 210px repeat(7, minmax(132px, 1fr));
  min-width: 1050px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-border); /* shows through as 1px gridlines */
  gap: 1px;
  overflow: hidden;
}
.roster__head, .roster__name, .roster__cell { background: var(--color-surface); }
.roster__head {
  padding: 9px 10px;
  font-size: 12px; font-weight: 600;
  color: var(--color-text-muted);
  display: flex; justify-content: space-between; align-items: baseline; gap: 6px;
}
.roster__head.today { color: var(--color-primary); background: var(--color-primary-light); }
.roster__head-total { font-weight: 500; color: var(--color-text-faint); font-size: 11.5px; }
.roster__name {
  padding: 9px 10px;
  display: flex; align-items: center; gap: 9px;
  position: sticky; left: 0; z-index: 2;
}
.roster__name-text { min-width: 0; }
.roster__name-title { font-weight: 600; font-size: 13px; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.roster__name-sub { font-size: 11.5px; color: var(--color-text-muted); }
.roster__name.is-me { background: var(--color-primary-light); }
.roster__name.flash { animation: sched-row-flash 0.9s ease; }
@keyframes sched-row-flash {
  0%, 100% { background: var(--color-surface); }
  30% { background: var(--color-primary-light); }
}
.roster__cell {
  min-height: 52px;
  padding: 5px;
  display: flex; flex-direction: column; gap: 4px;
}
.roster__cell.can-edit { cursor: cell; }
.roster__cell.can-edit:hover { background: var(--color-bg); }
.roster__cell.drag-over { background: var(--color-primary-light); box-shadow: inset 0 0 0 2px var(--color-primary); }

.shift {
  border-radius: var(--radius-sm);
  padding: 5px 7px;
  font-size: 11.5px; line-height: 1.35;
  border-left: 3px solid var(--color-primary);
  background: var(--color-primary-light);
  color: var(--color-text);
  text-align: left; width: 100%;
  font-family: inherit;
  display: block;
}
.shift.can-edit { cursor: pointer; }
.shift__time { font-weight: 600; display: block; }
.shift__meta { color: var(--color-text-muted); display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Draft shifts are visually provisional so an unpublished view is obvious. */
.shift.is-draft { background: repeating-linear-gradient(135deg, var(--color-bg), var(--color-bg) 6px, #fff 6px, #fff 12px); border-left-style: dashed; }
.shift.is-open { border-left-color: var(--color-warning); background: var(--color-warning-bg); }
/* Cosmetic only — a published shift whose start time has passed. It can
   still be edited; this just mirrors how Deputy marks a shift as started. */
.shift.is-locked { background: #EFECFC; }
.shift__lock {
  display: block; margin-top: 1px;
  font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  color: var(--color-text-faint);
}

/* Legend keys. Deliberately NOT .shift — anything counting shifts on the page
   (including tests) would otherwise pick the legend up as real roster data. */
.legend-swatch {
  display: inline-block; width: 15px; height: 12px;
  vertical-align: -2px; border-radius: 3px;
  border-left: 3px solid var(--color-primary);
  background: var(--color-primary-light);
}
.legend-swatch.is-draft {
  border-left-style: dashed;
  background: repeating-linear-gradient(135deg, var(--color-bg), var(--color-bg) 6px, #fff 6px, #fff 12px);
}
.legend-swatch.is-open { border-left-color: var(--color-warning); background: var(--color-warning-bg); }

/* Slide-over editor for a single shift */
.drawer-backdrop {
  position: fixed; inset: 0; background: rgba(30,27,51,.35); z-index: 950;
}
.drawer-backdrop[hidden] { display: none; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 380px; max-width: 100vw;
  background: var(--color-surface); z-index: 960;
  box-shadow: -8px 0 30px rgba(30,27,51,.18);
  display: flex; flex-direction: column;
}
.drawer[hidden] { display: none; }
.drawer__head { padding: 16px 18px; border-bottom: 1px solid var(--color-border); display: flex; justify-content: space-between; align-items: center; }
.drawer__title { font-size: 16px; font-weight: 600; }
.drawer__body { padding: 16px 18px; overflow-y: auto; flex: 1; }
.drawer__foot { padding: 14px 18px; border-top: 1px solid var(--color-border); display: flex; gap: 8px; }
.field { margin-bottom: 14px; }
.field label { display: block; font-size: 12px; font-weight: 600; color: var(--color-text-muted); margin-bottom: 5px; }
.field .input, .field .select { width: 100%; }
.field-row { display: flex; gap: 10px; }
.field-row .field { flex: 1; }

/* A wider variant of .drawer, for a panel that needs room for more than one
   column of fields (Add timesheet / Add leave) rather than a narrow editor
   like the shift drawer. */
.drawer--wide { width: 50vw; min-width: 460px; max-width: 720px; }
.drawer__columns { display: flex; gap: 22px; }
.drawer__col { flex: 1; min-width: 0; }
.drawer__summary {
  background: var(--color-bg); border-radius: var(--radius-sm);
  padding: 12px 14px; margin-top: 4px;
}
.drawer__summary-label { font-size: 12px; font-weight: 600; color: var(--color-text-muted); }
.drawer__summary-value { font-size: 20px; font-weight: 700; margin-top: 2px; }

/* A small generic button dropdown — a button that reveals a panel of plain
   actions below it. Distinct from .topnav__dropdown, which fixed-positions
   its panel from JS to escape a scrolling nav row; this one just needs a
   relatively-positioned wrapper, since it lives in a normal page header. */
.menu { position: relative; display: inline-block; }
.menu__panel {
  display: none;
  position: absolute; top: calc(100% + 6px); right: 0;
  z-index: 500;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  min-width: 220px;
  padding: 6px;
}
.menu.open .menu__panel { display: block; }
.menu__item {
  display: block; width: 100%; text-align: left;
  padding: 8px 10px; border-radius: var(--radius-sm);
  background: none; border: none; font: inherit; color: var(--color-text);
  cursor: pointer;
}
.menu__item:hover { background: var(--color-bg); }
.menu__item:disabled { color: var(--color-text-faint); cursor: not-allowed; }
.menu__item:disabled:hover { background: none; }
.menu__divider { height: 1px; background: var(--color-border); margin: 6px 4px; }

.roster-scroll { overflow-x: auto; }
.roster-grid { display: grid; grid-template-columns: repeat(14, minmax(96px, 1fr)); gap: 6px; min-width: 1400px; }
.roster-day-label {
  font-size: 12px; font-weight: 700; color: var(--color-text-muted);
  text-align: center; padding-bottom: 6px;
}
.roster-day-label.today { color: var(--color-primary); }
.roster-cell { min-height: 34px; }
.roster-unavail {
  background: var(--color-primary-light); color: var(--color-primary-dark);
  border-radius: var(--radius-sm); font-size: 11px; font-weight: 600;
  padding: 6px 6px; text-align: center;
}
.roster-shift {
  background: var(--color-success-bg); border: 1px solid #bfe9d7;
  border-radius: var(--radius-sm); padding: 6px 7px; font-size: 11.5px;
  margin-bottom: 5px; cursor: pointer;
}
.roster-shift strong { display: block; font-size: 11.5px; }
.roster-shift.locked { background: #EFECFC; border-color: #d9d2f7; }
.roster-shift .lock-tag {
  font-size: 9px; font-weight: 700; text-transform: uppercase;
  color: var(--color-text-faint); margin-top: 2px;
}
.roster-add {
  text-align: center; color: var(--color-text-faint); font-size: 16px;
  padding: 4px; border-radius: var(--radius-sm); cursor: pointer;
}
.roster-add:hover { background: var(--color-bg); color: var(--color-primary); }
.roster-area-label {
  font-weight: 700; font-size: 13px;
  grid-column: 1 / -1;
  background: var(--color-surface);
  padding: 10px 10px 4px;
}
.roster-footer {
  display: flex; gap: 18px; flex-wrap: wrap;
  border-top: 1px solid var(--color-border); margin-top: 18px; padding-top: 14px;
  font-size: 12.5px; color: var(--color-text-muted);
}
.roster-footer span { display: inline-flex; align-items: center; gap: 6px; }
.roster-footer .dot { width: 8px; height: 8px; border-radius: 50%; }

/* ---------- Banner / promo ---------- */
.banner {
  display: flex; align-items: center; gap: 16px;
  padding: 16px 20px; margin-bottom: 18px;
}
.banner__icon {
  width: 44px; height: 44px; border-radius: 50%;
  border: 3px solid var(--color-primary-light);
  display: flex; align-items: center; justify-content: center;
  color: var(--color-primary);
  flex-shrink: 0;
}
.banner__title { font-weight: 600; }
.banner__desc { font-size: 12.5px; color: var(--color-text-muted); }

/* ---------- Summary panel (Export timesheets) ---------- */
.summary-panel {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 18px;
  padding: 20px;
  margin-bottom: 18px;
}
.summary-item__label { font-size: 12px; color: var(--color-text-faint); text-transform: uppercase; letter-spacing: .03em; }
.summary-item__row { display: flex; align-items: baseline; gap: 10px; margin-top: 4px; }
.summary-item__value { font-size: 20px; font-weight: 700; }
.summary-item__delta { font-size: 12px; font-weight: 600; }
.summary-item__delta.down { color: var(--color-text-faint); }
.summary-item__prev { font-size: 12px; color: var(--color-text-faint); margin-top: 8px; }

.checklist-item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 6px; border-bottom: 1px solid var(--color-border);
}
.checklist-item:last-child { border-bottom: none; }
/* The "include already exported" switch. Styled like a checklist row but kept
   off .checklist-item, which specifically means a selectable employee. */
.export-toggle {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 4px; margin-bottom: 4px;
  border-bottom: 1px solid var(--color-border);
  cursor: pointer;
}
.export-toggle__name { font-weight: 600; font-size: 13px; }
.export-toggle__sub { font-size: 12px; color: var(--color-text-muted); }

.checklist-item__name { font-weight: 600; font-size: 13px; }
.checklist-item__sub { font-size: 12px; color: var(--color-text-muted); }

/* ---------- Standalone auth card (login, invite, reset) ---------- */
/* Login and the invite page each set a fixed pixel width and no ceiling, so
   on a narrow phone the card was wider than the screen. One class, with the
   ceiling built in. */
.auth-card {
  width: 380px;
  max-width: calc(100vw - 32px);
}

/* ---------- Clock in / off widget (Home) ---------- */
/* The one control every employee uses, so its narrow-screen behaviour needs
   to be expressible in a media query — which an inline style would not be. */
.clock-widget {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  margin-bottom: 22px;
}
.clock-widget__status { flex: 1 1 200px; min-width: 0; }
.clock-widget__title { font-weight: 600; font-size: 14px; margin-bottom: 4px; }
.clock-widget__select { min-width: 170px; }
/* Clock-on failures are full sentences that say what to do ("allow location
   for this site…"), not one-word chips, so the pill shape gives way to a
   readable block on its own line. */
#clock-error {
  flex-basis: 100%;
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  line-height: 1.45;
  font-weight: 500;
}
#clock-in-btn:disabled { opacity: 0.7; cursor: progress; }

/* ---------- "Add to Home Screen" hint (phones, added by app.js) ---------- */
/* z-index sits just under .modal-backdrop (100) so an open dialog covers the
   hint rather than the hint covering the dialog's buttons, and above the
   sticky header (50) and page content. */
.install-hint {
  position: fixed; left: 12px; right: 12px; z-index: 90;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: 12px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 14px;
  box-shadow: 0 8px 28px rgba(30, 27, 51, 0.18);
  padding: 12px 12px 12px 14px;
  font-size: 13px; line-height: 1.45;
}
.install-hint__icon { width: 40px; height: 40px; border-radius: 10px; flex: none; }
.install-hint__body { flex: 1; min-width: 0; }
.install-hint__close {
  flex: none; width: 32px; height: 32px;
  border: none; background: none; border-radius: 8px;
  color: var(--color-text-muted); font-size: 15px; cursor: pointer;
}
.install-hint__close:hover { background: var(--color-bg); }

/* ---------- Clock-on point (Locations › Edit Settings) ---------- */
.clock-point__fields {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  margin-bottom: 10px;
}
.clock-point__actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.clock-point__actions .spacer { flex: 1; }
@media (max-width: 480px) {
  .clock-point__fields { grid-template-columns: 1fr; }
  .clock-point__actions .btn { flex: 1 1 100%; justify-content: center; }
  .clock-point__actions .spacer { display: none; }
}

/* ---------- Period / week navigator ---------- */
/* Was repeated as an inline flex row on four pages, each with its own fixed
   min-width on the label — which is exactly what refused to wrap on a phone.
   One class instead, so the narrow-screen behaviour is defined once. */
.period-nav {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.period-nav__label {
  font-size: 13.5px; font-weight: 600;
  min-width: 170px; text-align: center;
}

/* ---------- Location filter (multi-select) ---------- */
/* Built and positioned entirely in CSS (position:relative/absolute) rather
   than the fixed+JS-positioned pattern .topnav__dropdown-panel uses — this
   one lives inline in the page body, not a scrollable header row, so it
   never needs correcting for scroll position. */
.locfilter { position: relative; }
.locfilter__trigger { display: inline-flex; align-items: center; gap: 6px; min-width: 150px; justify-content: space-between; }
.locfilter__trigger svg { flex-shrink: 0; transition: transform .12s ease; }
.locfilter.open .locfilter__trigger svg { transform: rotate(180deg); }
.locfilter__panel {
  display: none;
  position: absolute; top: calc(100% + 6px); left: 0;
  z-index: 500;
  width: 260px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 10px;
}
.locfilter.open .locfilter__panel { display: block; }
.locfilter__title {
  font-size: 11.5px; font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase; color: var(--color-primary); margin-bottom: 8px;
}
.locfilter__search { width: 100%; margin-bottom: 8px; }
/* Plain checkboxes, label to the right — "All Locations" is a select-all
   convenience, each location below it toggles independently. Nothing here
   forces the selection back to "All" or "None" on its own. */
.locfilter__all {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 6px; border-radius: var(--radius-sm); cursor: pointer;
  font-size: 13.5px; font-weight: 600; color: var(--color-text);
  border-bottom: 1px solid var(--color-border); margin-bottom: 4px;
}
.locfilter__all:hover { background: var(--color-bg); }
.locfilter__list { max-height: 240px; overflow-y: auto; }
.locfilter__option {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 6px; border-radius: var(--radius-sm); cursor: pointer;
  font-size: 13.5px; color: var(--color-text);
}
.locfilter__option:hover { background: var(--color-bg); }
.locfilter__all input, .locfilter__option input { flex-shrink: 0; }
.locfilter__empty { padding: 10px 6px; font-size: 12.5px; color: var(--color-text-faint); line-height: 1.4; }

/* ---------- Date picker (Schedule toolbar) ---------- */
/* Same trigger+panel shape as .locfilter, above. */
.datepick { position: relative; }
.datepick__panel {
  display: none;
  position: absolute; top: calc(100% + 6px); left: 0;
  z-index: 500;
  width: 260px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 12px;
}
.datepick.open .datepick__panel { display: block; }
.datepick__nav {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 13px; margin-bottom: 8px;
}
.datepick__dow {
  display: grid; grid-template-columns: repeat(7, 1fr);
  font-size: 10.5px; font-weight: 700; color: var(--color-text-faint);
  text-align: center; margin-bottom: 4px;
}
.datepick__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.datepick__day {
  border: none; background: none; border-radius: var(--radius-sm);
  padding: 6px 0; font-family: inherit; font-size: 12.5px; color: var(--color-text);
  cursor: pointer;
}
.datepick__day:hover { background: var(--color-bg); }
.datepick__day.is-other-month { color: var(--color-text-faint); }
.datepick__day.is-today { box-shadow: inset 0 0 0 1px var(--color-primary); }
.datepick__day.is-selected { background: var(--color-primary); color: #fff; }

/* ---------- View-by dropdown (Schedule toolbar) ---------- */
.viewby { position: relative; }
.viewby__trigger { display: inline-flex; align-items: center; gap: 6px; min-width: 170px; justify-content: space-between; }
.viewby__trigger svg { flex-shrink: 0; transition: transform .12s ease; }
.viewby.open .viewby__trigger svg { transform: rotate(180deg); }
.viewby__panel {
  display: none;
  position: absolute; top: calc(100% + 6px); left: 0;
  z-index: 500;
  width: 220px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 10px;
}
.viewby.open .viewby__panel { display: block; }
.viewby__group-title {
  font-size: 11.5px; font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase; color: var(--color-primary); margin: 8px 6px 6px;
}
.viewby__group-title:first-child { margin-top: 0; }
.viewby__option {
  padding: 8px 6px; border-radius: var(--radius-sm); cursor: pointer;
  font-size: 13.5px; color: var(--color-text);
}
.viewby__option:hover { background: var(--color-bg); }
.viewby__option.is-active { background: var(--color-primary-light); color: var(--color-primary-dark); font-weight: 600; }
.viewby__divider { border-top: 1px solid var(--color-border); margin: 6px 2px; }
.viewby__toggle-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px; font-size: 12.5px; color: var(--color-text-muted);
  cursor: pointer;
}

/* ---------- Schedule left sidebar (employee shortcuts) ---------- */
.sched-side-list { display: flex; flex-direction: column; gap: 2px; }
.sched-side-row {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 8px; border-radius: var(--radius-sm); cursor: pointer;
}
.sched-side-row:hover { background: var(--color-bg); }
.sched-side-row__text { min-width: 0; }
.sched-side-row__title {
  font-weight: 600; font-size: 13px; display: block;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sched-side-row__sub { font-size: 11px; color: var(--color-text-faint); }

/* ---------- Employee profile drawer ---------- */
/* Opened by clicking a name on the People page (Admin only). Reuses
   .modal-backdrop for the dimmed overlay/centering; this card just swaps in
   its own two-column layout instead of the plain single-column modal card. */
.profile-drawer-card {
  width: 960px; max-width: 100%;
  height: 85vh; max-height: 820px;
  display: flex; padding: 0; overflow: hidden;
  position: relative;
}
.profile-drawer__nav {
  width: 220px; flex-shrink: 0;
  border-right: 1px solid var(--color-border);
  padding: 28px 16px 20px;
  overflow-y: auto;
  display: flex; flex-direction: column; align-items: center; text-align: center;
}
.profile-drawer__avatar {
  width: 60px; height: 60px; border-radius: 50%;
  background: var(--color-primary-light); color: var(--color-primary-dark);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 20px; margin-bottom: 12px; flex-shrink: 0;
}
.profile-drawer__name { font-weight: 700; font-size: 15px; }
.profile-drawer__sub { color: var(--color-text-faint); font-size: 12.5px; margin: 4px 0 22px; }
.profile-drawer__remove-photo { margin: -16px 0 16px -10px; }
.profile-drawer__tabs { width: 100%; display: flex; flex-direction: column; gap: 2px; }
.profile-drawer__tab {
  display: block; width: 100%; text-align: left;
  padding: 9px 10px; border-radius: var(--radius-sm);
  font-size: 13.5px; font-weight: 500; color: var(--color-text);
  cursor: pointer; border: none; background: none; font-family: inherit;
}
.profile-drawer__tab:hover { background: var(--color-bg); }
.profile-drawer__tab.active { background: var(--color-primary-light); color: var(--color-primary-dark); }
.profile-drawer__body { flex: 1; min-width: 0; overflow-y: auto; padding: 26px 34px 30px; }
.profile-drawer__toolbar {
  position: absolute; top: 14px; right: 14px; z-index: 1;
  display: flex; align-items: center; gap: 8px;
}
.profile-drawer__panel { display: none; }
.profile-drawer__panel.active { display: block; }
.profile-drawer__panel h3 { font-size: 15px; margin-bottom: 14px; }
.profile-drawer__panel h3:not(:first-child) { margin-top: 26px; }
.profile-drawer__field-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 18px 22px;
  background: var(--color-bg); border-radius: var(--radius-sm);
  padding: 16px 18px;
}
.profile-drawer__field label {
  display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .03em;
  color: var(--color-text-faint); margin-bottom: 4px;
}
.profile-drawer__field div { font-size: 14px; font-weight: 500; }
.profile-drawer__list-row {
  padding: 12px 2px; border-bottom: 1px solid var(--color-border);
  display: flex; justify-content: space-between; align-items: flex-start; gap: 14px;
}
.profile-drawer__list-row:last-child { border-bottom: none; }
.profile-drawer__empty { padding: 26px 4px; text-align: center; color: var(--color-text-faint); font-size: 13px; }
/* Pay details panel (Employment tab). No media queries here — the field rows
   wrap through the shared .field-row rules in the responsive block. */
.pay-editor { margin-top: 12px; padding: 16px 18px; background: var(--color-bg); border-radius: var(--radius-sm); }
.pay-preview { font-size: 13px; color: var(--color-text-muted); min-height: 18px; line-height: 1.45; }
.pay-note { font-size: 13px; margin-top: 8px; line-height: 1.45; }
.pay-note--warn { color: var(--color-warning); font-weight: 600; }

/* ---------- Modal ---------- */
/* The three modals each carried the same inline position/inset/background.
   Hoisted here so the mobile sizing has somewhere to live. `display` stays
   inline on the element because the page scripts toggle it between
   none and flex. */
.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(30, 27, 51, 0.35);
  align-items: center; justify-content: center;
  z-index: 100;
  padding: 16px;
  overflow-y: auto;
}
.modal-card { width: 480px; max-width: 100%; max-height: 88vh; overflow-y: auto; }
.modal-card--sm { width: 400px; }
.modal-card--md { width: 460px; }

/* ---------- Profile photo dialog (app.js, openPhotoDialog) ---------- */
.photo-dialog__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
.photo-dialog__head h3 { font-size: 17px; }
.photo-dialog__preview {
  width: 140px; height: 140px; margin: 0 auto 12px;
  border-radius: 50%;
  background: var(--color-primary-light); color: var(--color-primary-dark);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 44px;
}
.photo-dialog__hint { text-align: center; color: var(--color-text-muted); font-size: 12.5px; margin: 0 0 14px; }
.photo-dialog__error {
  color: var(--color-danger); background: var(--color-danger-bg);
  border-radius: var(--radius-sm); padding: 8px 10px; font-size: 12.5px; margin-bottom: 12px;
}
.photo-dialog__actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.photo-dialog__choose { position: relative; cursor: pointer; }
.photo-dialog__choose:focus-within { outline: 2px solid var(--color-primary); outline-offset: 2px; }
/* Hidden from view but still focusable and opened by its label. A
   display:none file input doesn't open the picker on some older iPhones. */
.photo-dialog__file {
  position: absolute; width: 1px; height: 1px; opacity: 0;
  overflow: hidden; clip: rect(0 0 0 0); pointer-events: none;
}
/* Phones: a sheet up from the bottom, within thumb reach, with full-width
   44px buttons. "Choose a photo" opens the phone's own picker, which offers
   the camera and the photo library. */
@media (max-width: 640px) {
  .photo-dialog { align-items: flex-end; padding: 0; }
  .photo-dialog .modal-card {
    width: 100%; max-height: 92vh;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }
  .photo-dialog__actions { flex-direction: column; }
  .photo-dialog__actions .btn { justify-content: center; min-height: 44px; font-size: 15px; }
}

/* ---------- Collapsible sidebar toggle (mobile only) ---------- */
/* Inserted by app.js before any aside carrying data-sidebar-label. Hidden
   above the stacking breakpoint, so on a desktop the asides behave exactly as
   they always have and this button never enters the flex row. */
.sidebar-toggle { display: none; }

/* ---------- Day picker (Schedule, phone only) ---------- */
.day-picker {
  display: none;
  gap: 6px;
  margin-bottom: 10px;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
}
.day-picker::-webkit-scrollbar { display: none; }
.day-picker__btn {
  flex: 1 0 auto;
  min-width: 44px;
  padding: 7px 4px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-family: inherit; font-size: 11.5px; font-weight: 600;
  line-height: 1.3; text-align: center;
}
.day-picker__btn span { display: block; font-size: 14px; font-weight: 700; color: var(--color-text); }
.day-picker__btn.is-today { border-color: var(--color-primary); }
.day-picker__btn.is-active {
  background: var(--color-primary); border-color: var(--color-primary); color: #fff;
}
.day-picker__btn.is-active span { color: #fff; }
.day-picker__btn .day-picker__count {
  display: block; font-size: 10px; font-weight: 600; color: var(--color-text-faint);
}
.day-picker__btn.is-active .day-picker__count { color: rgba(255,255,255,.85); }

/* ---------- Misc ---------- */
.text-muted { color: var(--color-text-muted); }
.text-faint { color: var(--color-text-faint); }
.mono { font-variant-numeric: tabular-nums; }
.pin { color: var(--color-primary); }
.placeholder-note {
  background: var(--color-warning-bg); color: #7a5a12;
  border: 1px solid #f2ddac; border-radius: var(--radius-sm);
  padding: 8px 12px; font-size: 12px; margin-bottom: 16px;
}

/* ==========================================================================
   RESPONSIVE LAYER
   --------------------------------------------------------------------------
   Everything above is the desktop design. This block is the only place the
   narrow-window behaviour is defined, so there is one file to read when a
   phone layout misbehaves rather than a media query buried in each section.

   Three breakpoints, each with a single job:

     <= 1024px  give back the generous desktop padding
     <=  980px  stop the page being a three-column flex row; the side panels
                become stacked, collapsible sections
     <=  720px  the phone layout proper — tables become cards, multi-column
                grids collapse, the week roster shows one day at a time
     <=  480px  small phones: single-column grids, tighter still

   A note on !important, which appears a handful of times below and nowhere
   else in this file. Several pages set layout properties inline
   (style="padding:24px 28px", style="width:240px", grid-template-columns on
   the Home "my stats" grid). An inline style beats any selector, however
   specific, so a media query cannot override one without it. Each use below
   is overriding a known inline declaration, and is commented where it is not
   obvious.
   ========================================================================== */

@media (max-width: 1024px) {
  .page__main { padding: 22px 20px; }
  .page__right-sidebar { width: 260px; }
}

/* ---------- Stack the page shell ---------- */
@media (max-width: 980px) {
  .page { display: block; min-height: 0; }

  /* Overrides style="width:240px" / "width:280px" on the Timesheets asides. */
  .page__left-sidebar,
  .page__right-sidebar {
    width: auto !important;
    border-left: none;
    border-right: none;
    border-bottom: 1px solid var(--color-border);
    padding: 14px 16px;
  }
  /* Overrides style="padding:24px 28px" on Schedule / My Timesheets /
     Approve / Export. */
  .page__main { padding: 18px 16px !important; }

  /* The toggle app.js inserts ahead of each collapsible aside. */
  .sidebar-toggle {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    width: 100%;
    padding: 13px 16px;
    background: var(--color-surface);
    border: none;
    border-bottom: 1px solid var(--color-border);
    font-family: inherit; font-size: 13.5px; font-weight: 600;
    color: var(--color-text);
    text-align: left;
  }
  .sidebar-toggle__chev { color: var(--color-text-faint); transition: transform .15s ease; }
  .sidebar-toggle.is-open .sidebar-toggle__chev { transform: rotate(180deg); }
  .sidebar-toggle:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }

  /* Collapsed by default so the page's actual content is what you land on.
     Outside this breakpoint the attribute is simply ignored, so growing the
     window always restores the full sidebar with no JS involved. */
  [data-sidebar-label][data-collapsed="true"] { display: none; }

  /* A sidebar can be a long list (Schedule's employees, the Timesheets
     people filters); cap it so an opened sidebar can't bury the page's
     content under a screenful of entries. */
  .page__left-sidebar[data-collapsed="false"],
  .page__right-sidebar[data-collapsed="false"] {
    max-height: 60vh; overflow-y: auto;
  }
}

/* ---------- Phone layout ---------- */
@media (max-width: 720px) {

  /* --- Header --------------------------------------------------------- */
  .topnav { padding: 0 10px; gap: 8px; }
  .topnav__link { padding: 9px 10px; font-size: 13.5px; }
  .topnav__right { gap: 8px; }
  .topnav__dropdown-panel { min-width: 0; width: calc(100vw - 24px); max-width: 320px; }

  /* --- Page furniture -------------------------------------------------- */
  .page-header { gap: 10px; margin-bottom: 16px; }
  .page-header h1 { font-size: 20px; }
  .card { border-radius: var(--radius-md); }
  .card-pad { padding: 16px; }

  /* Fill the row rather than leaving a stranded 420px box. */
  .search-box { max-width: none; flex-basis: 100%; }
  .toolbar { gap: 8px; }

  .period-nav { width: 100%; gap: 8px; }
  .period-nav > .select { flex: 1 1 100%; width: 100%; }
  .period-nav__label { min-width: 0; flex: 1 1 auto; }
  /* The location filter replaced a plain .select on this row — same
     full-width treatment on a phone, plus its own panel needs to stay on
     screen rather than following the old fixed 260px width. */
  .period-nav > .locfilter { flex: 1 1 100%; }
  .period-nav > .locfilter .locfilter__trigger { width: 100%; }
  .period-nav > .locfilter .locfilter__panel { width: calc(100vw - 24px); max-width: 320px; }
  .period-nav > .viewby { flex: 1 1 100%; }
  .period-nav > .viewby .viewby__trigger { width: 100%; }
  .period-nav > .viewby .viewby__panel,
  .period-nav > .datepick .datepick__panel { width: calc(100vw - 24px); max-width: 320px; }

  /* --- Employee profile drawer ------------------------------------------ */
  /* The two-column layout only works with room to spare. Below 720px the
     nav becomes a horizontal strip (avatar + name inline, tabs in a
     scrollable row) above the content, rather than a column eating a third
     of a narrow screen. */
  .profile-drawer-card { flex-direction: column; width: 100%; height: 92vh; max-height: none; }
  .profile-drawer__nav {
    width: 100%; flex-direction: row; flex-wrap: wrap; align-items: center; text-align: left;
    gap: 10px 14px; padding: 16px 44px 12px 16px; border-right: none;
    border-bottom: 1px solid var(--color-border); overflow: visible; flex-shrink: 0;
  }
  .profile-drawer__avatar { margin-bottom: 0; }
  .profile-drawer__name-block { min-width: 0; }
  .profile-drawer__sub { margin: 2px 0 0; }
  .profile-drawer__remove-photo { margin: 2px 0 0 -10px; }
  .profile-drawer__tabs {
    flex: 1 1 100%; flex-direction: row; gap: 4px;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
  }
  .profile-drawer__tab { white-space: nowrap; }
  .profile-drawer__body { padding: 20px 16px 26px; }

  /* --- Tap targets ----------------------------------------------------- */
  /* 26px-high buttons are a desktop pointer target, not a thumb one. */
  .btn { padding: 10px 14px; min-height: 40px; }
  .btn-sm { padding: 7px 11px; min-height: 34px; }
  /* 24px is the WCAG 2.2 minimum target size, and a tick box is the one
     control here you cannot hit by aiming at surrounding text. */
  input[type="checkbox"] { width: 24px; height: 24px; }
  .stat-card__foot a { display: inline-block; padding: 4px 0; }
  /* Fills the search box so a tap on the box lands on the field, rather than
     on the 8px of padding around it where nothing happens. */
  .search-box input { padding: 6px 0; }
  /* A 26px number field is hard to hit and harder to correct a break on. */
  .break-input { min-height: 36px; }
  /* Names and locations in a table are the row's main link on a phone.
     Inline text stays inline; it just gets a thumb's worth of height. */
  .table td a { display: inline-block; padding: 4px 0; }

  /* 16px is the threshold below which iOS Safari zooms the page in when a
     field takes focus — and never zooms back out. */
  .input, .select, .search-box input, .break-input { font-size: 16px; }
  .input, .select { padding: 9px 12px; }
  .break-input { width: 64px; }

  /* --- Grids ----------------------------------------------------------- */
  /* !important overrides the inline grid-template-columns on Home's
     "my stats" grid (#my-grid), which is set to repeat(2, 1fr). */
  /* auto-fit rather than a fixed count: two columns on a normal phone,
     one on a very narrow one, with no extra breakpoint to maintain. */
  .stat-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)) !important; gap: 12px; margin-bottom: 20px; }
  .link-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
  .stat-card { padding: 14px; }
  .stat-card__value { font-size: 24px; }
  .link-card { padding: 16px; gap: 8px; }
  .summary-panel { grid-template-columns: minmax(0, 1fr); gap: 14px; padding: 16px; }

  /* --- Tabs ------------------------------------------------------------ */
  /* Six tabs will not fit; let the strip scroll rather than wrap into three
     stacked rows that push the table off the first screen. */
  .tabs { overflow-x: auto; scrollbar-width: none; flex-wrap: nowrap; }
  .tabs::-webkit-scrollbar { display: none; }
  .tab { white-space: nowrap; flex-shrink: 0; }
  .tabs .spacer { display: none; }

  /* --- Tables become cards --------------------------------------------- */
  /* A seven-column table cannot be read on a 390px screen, and a sideways
     scroller hides the columns that matter. Each row becomes a card of
     label/value pairs instead. The labels come from the table's own <th>
     text, stamped onto each cell as data-label by app.js — including rows
     added later by a fetch, which a MutationObserver picks up. So this works
     on every table in the app without any page having to opt in. */
  .table, .table thead, .table tbody, .table tr { display: block; width: 100%; }
  .table thead { display: none; }

  .table tr {
    padding: 12px 14px;
    border-bottom: 1px solid var(--color-border);
  }
  .table tr:last-child { border-bottom: none; }
  .table tr:hover td { background: transparent; }

  .table td {
    display: flex;
    align-items: baseline;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 6px 12px;
    padding: 5px 0;
    border-bottom: none;
    text-align: right;
    min-width: 0;
  }
  .table td[data-label]::before {
    content: attr(data-label);
    margin-right: auto;
    flex: 0 1 auto;
    max-width: 45%;
    text-align: left;
    font-size: 11px; font-weight: 700;
    letter-spacing: .04em; text-transform: uppercase;
    color: var(--color-text-faint);
  }
  /* Opt-in wrapper for a cell whose value is several inline pieces (a pin
     icon, the address, a "Verified" chip). Without it each piece is its own
     flex item and a long value wraps them onto separate lines. */
  .table td .cell-value { flex: 1 1 auto; min-width: 0; }

  /* Cells under a blank header — the checkbox column and the row's action
     buttons. No label to show, and the buttons read better ranged left. */
  .table td:not([data-label]) { justify-content: flex-start; text-align: left; }
  .table td:not([data-label]):empty { display: none; }

  /* A cell that spanned the whole table (a loading row, an empty state, or
     the employee band on the Approve screen) is still a full-width block. */
  .table td[colspan] { display: block; text-align: center; }
  .table-group-header td {
    text-align: left;
    margin: 0 -14px; padding: 8px 14px;
  }

  /* --- Roster: one day at a time --------------------------------------- */
  /* The week grid has a 1050px floor, so on a phone it was a long sideways
     scroll with no sense of where you were. Instead the name column stays and
     a single day's column is shown; schedule.html renders a day picker above
     it and sets data-day-view on the grid. Every head/cell carries data-dow,
     so which day shows is pure CSS. */
  .roster {
    grid-template-columns: 116px minmax(0, 1fr);
    min-width: 0;
  }
  .roster[data-day-view="0"] [data-dow]:not([data-dow="0"]),
  .roster[data-day-view="1"] [data-dow]:not([data-dow="1"]),
  .roster[data-day-view="2"] [data-dow]:not([data-dow="2"]),
  .roster[data-day-view="3"] [data-dow]:not([data-dow="3"]),
  .roster[data-day-view="4"] [data-dow]:not([data-dow="4"]),
  .roster[data-day-view="5"] [data-dow]:not([data-dow="5"]),
  .roster[data-day-view="6"] [data-dow]:not([data-dow="6"]) { display: none; }

  .roster__name { padding: 8px; gap: 6px; }
  .roster__name .avatar-sm { display: none; }
  .roster__name-title { font-size: 12.5px; }
  .roster__cell { min-height: 46px; }
  .shift { padding: 7px; font-size: 12px; }

  .day-picker { display: flex; }

  /* --- Drawer ---------------------------------------------------------- */
  .drawer { width: 100%; }
  .drawer__foot { flex-wrap: wrap; }
  .drawer__foot .btn { flex: 1 1 auto; justify-content: center; }
  .drawer__foot #drawer-cancel { margin-left: 0 !important; }

  /* --- Home clock widget ----------------------------------------------- */
  /* The one screen every employee uses, and the reason the phone layout
     matters at all. Full-width controls, thumb-sized primary action.
     !important overrides the inline min-widths on the two selects. */
  .clock-widget { gap: 10px; }
  .clock-widget__status { flex-basis: 100%; }
  .clock-widget__select { width: 100%; min-width: 0; }
  #clock-in-btn, #clock-out-btn {
    width: 100%; justify-content: center;
    min-height: 48px; font-size: 15px;
  }
  #clock-error { width: 100%; justify-content: center; }
}

/* ---------- Wide screens: a wide table scrolls, the page doesn't ---------- */
/* Above the card breakpoint the tables stay tables. The People table needs
   about 1040px of its own and the Approve table about 950px, so on anything
   from a tablet in landscape to a 1280px laptop window they were making the
   whole document wider than the viewport — the page scrolled sideways and
   took the header with it. Confining that scroll to the card keeps the page
   itself fixed. overflow-y computes to auto as a side effect (see the note on
   .topnav__links), which is harmless here: these cards contain only a table,
   and the row menus are modals at body level, not inline popups that would
   get clipped. */
@media (min-width: 721px) {
  .card:has(> .table) { overflow-x: auto; }
}

/* ---------- Small phones ---------- */
@media (max-width: 480px) {
  .page__main { padding: 16px 12px !important; }
  .page-header h1 { font-size: 19px; }
  .table tr { padding: 10px 12px; }
  .table-group-header td { margin: 0 -12px; padding: 8px 12px; }
  .field-row { flex-wrap: wrap; }
  .field-row .field { flex: 1 1 130px; }
  .roster { grid-template-columns: 96px minmax(0, 1fr); }
}

/* ---------- Pointer-coarse touch-ups ---------- */
/* Hover styling that latches on after a tap is worse than no hover styling.
   Scoped to touch devices so the desktop keeps its hover affordances. */
@media (hover: none) {
  .table tr:hover td { background: transparent; }
  .roster__cell.can-edit:hover { background: var(--color-surface); }
  .shift.can-edit { cursor: pointer; }
}

/* ---------- Unavailability / leave markers on the roster ---------- */
/* Deliberately quieter than a shift: this is the absence of work, and it
   must never be mistaken at a glance for something rostered. Same striped
   treatment as a draft shift, so "not solid" already reads as "not real
   work" on this screen. */
.cell-absence {
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-text-muted);
  background: repeating-linear-gradient(135deg, var(--color-bg), var(--color-bg) 4px, #fff 4px, #fff 8px);
  border-left: 3px solid var(--color-text-faint);
  border-radius: var(--radius-sm);
  padding: 4px 6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cell-absence.is-leave {
  border-left-color: var(--color-warning);
  color: #8a5a00;
}
/* A whisper of tint so a blocked day reads across the row without competing
   with the "today" column or a drag target. */
.roster__cell.has-absence { background: #FCFCFE; }
.roster__cell.has-absence.can-edit:hover { background: var(--color-bg); }
