/* FRRS design system — palette is authoritative (see PRD / docs/START.md). */

/* Self-hosted Geist Variable (latin). No external font request. */
@font-face {
  font-family: "Geist Variable";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url("/static/fonts/geist-variable.woff2") format("woff2-variations");
}

/* Neutral shadcn palette (ported from the sales demo). FRRS red stays the
   primary action color; surfaces are white cards on a subtle slate canvas.
   Theme-varying tokens live per-theme so the data-theme toggle swaps them. */
:root[data-theme="light"] {
  --text: oklch(0.27 0.03 260);
  --text-muted: oklch(0.56 0.02 258);
  --background: oklch(0.97 0.004 258);
  --surface: oklch(1 0 0);
  --surface-2: oklch(0.97 0.004 258);
  --border: oklch(0.92 0.01 255);
  --border-strong: oklch(0.87 0.012 255);
  --primary: #ed1d23;
  --primary-foreground: oklch(0.985 0 0);
  --secondary: oklch(0.97 0.004 258);
  --accent: oklch(0.97 0.004 258);
  --success: oklch(0.6 0.13 163);
  --warning: oklch(0.68 0.16 65);
  --warning-strong: oklch(0.5 0.13 65);
  --info: oklch(0.55 0.22 262);
  --shadow: 0 1px 2px oklch(0.27 0.03 260 / 0.08), 0 1px 3px oklch(0.27 0.03 260 / 0.05);
  --shadow-lg: 0 8px 24px oklch(0.27 0.03 260 / 0.18);
  --shadow-overlay: 0 0 2rem oklch(0.27 0.03 260 / 0.4);
}

:root[data-theme="dark"] {
  --text: oklch(0.97 0.01 255);
  --text-muted: oklch(0.73 0.02 255);
  --background: oklch(0.18 0.02 260);
  --surface: oklch(0.21 0.02 260);
  --surface-2: oklch(0.25 0.03 260);
  --border: oklch(0.3 0.02 260);
  --border-strong: oklch(0.37 0.02 260);
  --primary: #ed1d23;
  --primary-foreground: oklch(0.985 0 0);
  --secondary: oklch(0.25 0.03 260);
  --accent: oklch(0.25 0.03 260);
  --success: oklch(0.72 0.15 162);
  --warning: oklch(0.82 0.15 75);
  --warning-strong: oklch(0.82 0.15 75);
  --info: oklch(0.7 0.15 258);
  --shadow: 0 1px 2px oklch(0 0 0 / 0.4), 0 1px 3px oklch(0 0 0 / 0.3);
  --shadow-lg: 0 8px 24px oklch(0 0 0 / 0.5);
  --shadow-overlay: 0 0 2rem oklch(0 0 0 / 0.6);
}

/* Theme-independent tokens */
:root {
  --radius: 8px;
  --radius-sm: 6px;
  --space: 1rem;
  --card-gap: 1.25rem;
  --sidebar-w: 16rem;
  --font: "Geist Variable", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

* {
  box-sizing: border-box;
}

.completed-calendar { overflow: hidden; }
.completed-calendar__header, .completed-calendar__weekdays, .completed-calendar__grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.completed-calendar__header { grid-template-columns: auto 1fr auto; align-items: center; gap: 1rem; padding: 1rem; border-bottom: 1px solid var(--border); }
.completed-calendar__header h2 { margin: 0; text-align: center; font-size: 1.2rem; }
.completed-calendar__weekdays { padding: .65rem 1rem; color: var(--text-muted); font-size: .75rem; font-weight: 700; text-align: center; }
.completed-calendar__grid { border-top: 1px solid var(--border); }
.completed-calendar__day { min-height: 8rem; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.completed-calendar__day a { display: block; height: 100%; min-height: 8rem; padding: .65rem; text-decoration: none; }
.completed-calendar__day a:hover, .completed-calendar__day.is-selected a { background: var(--surface-2); }
.completed-calendar__day.is-outside { color: var(--text-muted); background: var(--surface-2); }
.completed-calendar__number { display: block; font-weight: 700; }
.completed-calendar__count { display: block; margin-top: .4rem; color: var(--primary); font-size: .75rem; font-weight: 700; }
.completed-calendar__day ul { margin: .3rem 0 0; padding: 0; list-style: none; font-size: .75rem; overflow: hidden; }
.completed-calendar__day li { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.completed-calendar__detail { margin-top: 1.25rem; padding: 1rem; }
.completed-calendar__detail h2 { margin-top: 0; }
.completed-calendar__date-picker, .completed-calendar__detail--empty { display: none; }
.completed-calendar__list { margin: 0; padding: 0; list-style: none; }
.completed-calendar__list li { padding: .7rem 0; border-bottom: 1px solid var(--border); }
.completed-calendar__list a { display: flex; justify-content: space-between; gap: 1rem; }
.completed-calendar__drawer { width: 100%; height: 80vh; height: 80dvh; max-width: 48rem; max-height: 80vh; max-height: 80dvh; margin: auto auto 0; padding: 0; border: 1px solid var(--border); border-bottom: 0; border-radius: var(--radius) var(--radius) 0 0; background: var(--surface); color: var(--text); box-shadow: var(--shadow-lg); }
.completed-calendar__drawer::backdrop { background: oklch(0 0 0 / .45); }
.completed-calendar__drawer-panel { display: flex; height: 100%; max-height: 80vh; max-height: 80dvh; flex-direction: column; }
.completed-calendar__drawer-header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem; border-bottom: 1px solid var(--border); }
.completed-calendar__drawer-header h2 { margin: 0; font-size: 1.1rem; }
.completed-calendar__drawer-content { min-height: 0; overflow-y: auto; padding: 1rem; }
.completed-calendar__drawer-content h2 { display: none; }
.completed-calendar__drawer-content > p { margin: 0; color: var(--text-muted); }
@media (max-width: 640px) {
  .completed-calendar__day, .completed-calendar__day a { min-height: 5.5rem; }
  .completed-calendar__day a { padding: .4rem; }
  .completed-calendar__day li { display: none; }
  .completed-calendar__count { font-size: .65rem; }
  .completed-calendar__header { gap: .4rem; }
  .completed-calendar__header .button { padding: .4rem .55rem; }
  .completed-calendar__date-picker { display: flex; gap: .35rem; overflow-x: auto; padding: .65rem; border-bottom: 1px solid var(--border); }
  .completed-calendar__date-picker a { display: flex; min-width: 2.35rem; height: 2.35rem; align-items: center; justify-content: center; flex-direction: column; border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); font-weight: 700; text-decoration: none; }
  .completed-calendar__date-picker a.is-selected { background: var(--primary); border-color: var(--primary); color: var(--surface); }
  .completed-calendar__date-picker small { color: var(--primary); font-size: .65rem; line-height: 1; }
  .completed-calendar__date-picker a.is-selected small { color: inherit; }
  .completed-calendar__weekdays, .completed-calendar__grid { display: none; }
  .completed-calendar__detail { margin-top: .75rem; }
  .completed-calendar__detail--empty { display: block; }
}

html,
body {
  margin: 0;
}

body {
  background: var(--background);
  color: var(--text);
  font-family: var(--font);
  line-height: 1.5;
  min-height: 100vh;
}

a {
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* ---------- App shell: left sidebar + main content ---------- */
.app-shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  min-height: 100vh;
}

.app-sidebar {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1rem 0.75rem;
  border-right: 1px solid var(--border);
  background: var(--surface-2);
  position: sticky;
  top: 0;
  height: 100vh;
  /* The aside itself never scrolls: the brand pins to the top and the profile
     footer to the bottom. Only .app-nav scrolls (with a hidden scrollbar), so
     the desktop sidebar never shows an ugly vertical scrollbar. */
  overflow: hidden;
}

.app-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.35rem 0.5rem 0.9rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.5rem;
}

/* The logo renders as a bare mark (no tile/radius) so it reads as the brand
   glyph rather than a badge, matching the shadcn-style reskin. */
.app-brand__logo {
  width: 2.5rem;
  height: 2.5rem;
  flex: none;
  object-fit: contain;
}

.app-brand__lockup {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.15;
}

.app-brand__sub {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-muted);
}

.app-brand-text {
  font-weight: 800;
  font-size: 1.4rem;
  letter-spacing: 0.04em;
  color: var(--primary);
}

/* Inline Lucide icons that inherit text colour and track the theme. */
.app-icon {
  width: 1.15rem;
  height: 1.15rem;
  flex: none;
}

/* Theme toggle: show the sun in dark mode (switch to light) and the moon in
   light mode (switch to dark). One icon is always hidden via the data-theme
   attribute, no JS swap needed. */
.app-icon--light,
.app-icon--dark {
  display: none;
}

:root[data-theme="light"] .app-icon--dark {
  display: block;
}

:root[data-theme="dark"] .app-icon--light {
  display: block;
}

.app-nav {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  flex: 1 1 auto;
  /* The nav list is the sole scroll region, and its scrollbar is hidden so a
     tall nav (many permissions / short viewport) never shows chrome. */
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.app-nav::-webkit-scrollbar {
  display: none;
}

.app-nav__group {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.app-nav__heading {
  margin: 0 0 0.25rem;
  padding: 0 0.5rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  font-weight: 700;
}

/* Collapsible groups: the heading is a <details>/<summary>, so the sidebar can
   fold everything but the active section. Strip the native disclosure marker
   and lay the label + caret out as a clickable row. */
details.app-nav__group > summary.app-nav__heading {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
  border-radius: var(--radius-sm);
  padding-block: 0.25rem;
}

details.app-nav__group > summary.app-nav__heading::-webkit-details-marker {
  display: none;
}

details.app-nav__group > summary.app-nav__heading:hover {
  background: color-mix(in srgb, var(--text) 6%, transparent);
}

details.app-nav__group > summary:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Disclosure caret: points right when collapsed, rotates down when open. Used
   by both the nav groups and the profile menu. */
.app-caret {
  width: 0.85rem;
  height: 0.85rem;
  flex: none;
  color: var(--text-muted);
  transition: transform 0.15s ease;
}

details.app-nav__group[open] > summary .app-caret,
.app-profile[open] .app-caret,
details.filters[open] > summary .app-caret {
  transform: rotate(90deg);
}

.app-nav__link {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.45rem 0.6rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--text);
  font-weight: 600;
}

/* Per-item nav glyph: inherits the link colour and tracks the theme. */
.app-nav__icon {
  width: 1.05rem;
  height: 1.05rem;
  flex: none;
  color: var(--text-muted);
}

/* The label takes the remaining width so any trailing badge (e.g. "Soon")
   is pushed to the far edge. */
.app-nav__label {
  flex: 1 1 auto;
  min-width: 0;
}

.app-nav__link:hover {
  background: color-mix(in srgb, var(--text) 7%, transparent);
}

.app-nav__link.is-active {
  background: color-mix(in srgb, var(--text) 8%, transparent);
  color: var(--text);
  font-weight: 700;
}

.app-nav__link.is-active .app-nav__icon {
  color: var(--text);
}

.app-nav__link.is-disabled {
  color: var(--text-muted);
  cursor: not-allowed;
  font-weight: 500;
}

.app-nav__link.is-disabled em {
  font-style: normal;
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 0.4rem;
  color: var(--text-muted);
}

.app-sidebar__footer {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.4rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
  margin-top: 0.5rem;
}

.app-sidebar__footer form {
  display: block;
}

/* Signed-in user identity block at the top of the sidebar footer. */
.app-user {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.35rem 0.5rem 0.6rem;
  min-width: 0;
}

.app-user__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.app-user__name {
  font-weight: 600;
  font-size: 0.9rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.app-user__role {
  font-size: 0.72rem;
  color: var(--text-muted);
  text-transform: capitalize;
}

.app-icon-button {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  width: 100%;
  padding: 0.5rem 0.7rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  justify-content: flex-start;
}

.app-icon-button:hover {
  background: color-mix(in srgb, var(--text) 7%, transparent);
}

/* Profile menu: the footer identity is a <details> whose summary is the trigger
   and whose content is a popover opening upward with the theme + logout actions. */
.app-profile {
  position: relative;
}

.app-profile__trigger {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.5rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.app-profile__trigger::-webkit-details-marker {
  display: none;
}

.app-profile__trigger:hover {
  background: color-mix(in srgb, var(--text) 7%, transparent);
}

.app-profile__trigger:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* The identity block fills the trigger so the caret sits at the far edge; drop
   the standalone .app-user padding since the trigger owns spacing now. */
.app-profile__trigger .app-user {
  flex: 1 1 auto;
  padding: 0;
}

.app-profile__menu {
  position: absolute;
  bottom: calc(100% + 0.4rem);
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.3rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  z-index: 20;
}

.app-profile__menu form {
  display: block;
}

.app-main {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding: 1.5rem clamp(1rem, 3vw, 2.5rem);
  max-width: 100%;
  min-width: 0;
}

.app-main--centered {
  max-width: 60rem;
  margin: clamp(2rem, 9vh, 6rem) auto;
}

/* Login page centered chrome: a neutral card (the red accent lives only on the
   submit button). .app-login-card owns its own sizing (max-width / margins) so
   the generic .card rule doesn't constrain it. */
.app-login-card {
  max-width: 52rem;
  margin: 0 auto;
  padding: 2.25rem;
  text-align: center;
}

.app-login-brand {
  margin-bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Centered logo tile atop the login card. */
.app-login-logo {
  width: 4rem;
  height: 4rem;
  border-radius: var(--radius);
  object-fit: contain;
  margin-bottom: 0.6rem;
}

.app-login-wordmark {
  font-weight: 800;
  font-size: 2.75rem;
  letter-spacing: 0.06em;
  color: var(--primary);
  margin: 0 0 0.2rem;
  line-height: 1;
}

.app-login-tagline {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.app-login-card h1 {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 700;
}

.app-login-card .alert {
  text-align: left;
}

.app-login-card form {
  text-align: left;
}

.app-login-submit {
  width: 100%;
  margin-top: 0.25rem;
  padding: 0.7rem 1rem;
  font-size: 1rem;
}

/* Mobile top bar (authenticated pages, below the sidebar breakpoint). The bar
   sits above the open sidebar overlay (z-index: 50) so the toggle button
   remains tappable to dismiss the menu. */
.app-mobile-bar {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 0.9rem 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  position: sticky;
  top: 0;
  z-index: 60;
}

.app-menu-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  position: absolute;
  left: 0.6rem;
}

.app-mobile-bar .app-brand-text {
  font-size: 1.45rem;
}

/* The mobile bar reuses the sidebar lockup at a smaller scale. */
.app-mobile-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
}

.app-mobile-brand .app-brand__logo {
  width: 2rem;
  height: 2rem;
}

/* Menu toggle shows the open (hamburger) icon by default and the close (x)
   icon while the menu is open. Both icons are explicit so neither relies on
   the SVG default display. */
.app-menu-toggle .app-icon--open {
  display: inline-flex;
}

.app-menu-toggle .app-icon--close {
  display: none;
}

body.app-nav-open .app-menu-toggle .app-icon--open {
  display: none;
}

body.app-nav-open .app-menu-toggle .app-icon--close {
  display: inline-flex;
}

/* Card — a column flex container whose gap is the single ruler of internal
   spacing. Direct children drop their own block margins (see the scoped reset
   below) so the gap is consistent across every card instead of doubling up
   with per-component margin rules. */
.card {
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.5rem;
  box-shadow: var(--shadow);
}

/* Scoped under .card (higher specificity than the component base rules) so
   non-card layouts that reuse these classes — e.g. the dashboard places
   .page-heading and .dash-stats directly in <main>, not in a card — keep their
   own spacing. Forms keep 0 outer margins here; their inner .form-field
   margins are untouched for internal field rhythm. */
.card > .page-heading,
.card > .card__heading,
.card > .inline-form,
.card > .row-action,
.card > .alert,
.card > .empty-state,
.card > .inspection-list,
.card > .reference-images,
.card > .line-items,
.card > .pagination,
.card > .segmented,
.card > h2,
.card > form,
.card > p {
  margin-top: 0;
  margin-bottom: 0;
}

/* A lone direct-child button (e.g. the dashboard's "Open review queue" link)
   should keep its natural width and left alignment rather than stretching across
   the full card width as a column flex item. */
.card > .button {
  align-self: flex-start;
}

/* List card — the standard layout for every paginated list page. The card
   stretches to fill the remaining viewport height (`.app-main` is a flex
   column inside the `.app-shell` grid, whose row tracks the sticky 100vh
   sidebar), the heading/filters stay pinned at the top, the table region
   scrolls internally, and the pagination control sits at the bottom. Applied
   opt-in via `card card--list` so dashboard multi-card pages and the bounded
   reference-data tables keep their natural height. */
.card--list {
  flex: 1 1 auto;
  min-height: 0;
}

/* The table region grows to absorb leftover height and scrolls internally so
   the heading and pagination stay visible even with few/many rows. */
.card--list > .table-wrap {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
}

/* The shared pagination control (see `_pagination.html`). A flat row anchored
   at the foot of a list card: Previous / "Page N" / Next. */
.pagination {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.pagination__page {
  color: var(--text-muted);
  font-size: 0.9rem;
}



.page-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space);
  margin-bottom: 1.25rem;
}

.page-heading h1 {
  margin: 0 0 0.2rem;
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.page-heading p {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.9rem;
}

/* Inline segmented group: a lightweight, borderless wrapper for a small set of
   toggle links (e.g. the Repairs list's Open / Done / All status filter). It is
   intentionally NOT the heavyweight `.filters` disclosure card — just enough
   flex layout to hold a label + a row of buttons that wraps on narrow screens. */
.segmented {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0 0 var(--card-gap);
}

/* Button + variants — shadcn shape (rounded, medium weight) translated to the
   FRRS token layer. Default is the neutral secondary; modifiers layer on the
   variant surface/colour. A subtle press-down (translateY) mirrors the demo's
   active feedback without a per-variant rule. */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  white-space: nowrap;
  vertical-align: middle;
  padding: 0.5rem 1rem;
  border-radius: var(--radius);
  border: 1px solid transparent;
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
  background: var(--secondary);
  color: var(--text);
  transition: background-color 0.12s, border-color 0.12s, filter 0.12s;
}

.button:hover {
  filter: brightness(0.96);
}

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

.button--primary {
  background: var(--primary);
  color: var(--primary-foreground);
}

.button--success {
  background: var(--success);
  color: var(--primary-foreground);
}

.page-heading p.text-danger {
  margin-top: 0.75rem;
  color: var(--primary);
}

.button--secondary {
  background: var(--secondary);
  color: var(--text);
}

.button--accent {
  background: var(--accent);
  color: var(--text);
}

/* Ghost: no chrome until hover, matching the demo's quiet tertiary action. */
.button--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--text);
}

.button--ghost:hover {
  filter: none;
  background: color-mix(in srgb, var(--text) 7%, transparent);
}

/* Outline: a bordered surface button — the demo's default "quiet but present"
   action (e.g. Edit / secondary CTAs). */
.button--outline {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text);
}

.button--outline:hover {
  filter: none;
  background: color-mix(in srgb, var(--text) 6%, var(--surface));
}

/* Destructive: soft red tint (not solid) so the primary red CTA stays the loud
   one. The legacy .button--danger alias resolves here. */
.button--destructive,
.button--danger {
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  border-color: transparent;
  color: var(--primary);
}

.button--destructive:hover,
.button--danger:hover {
  filter: none;
  background: color-mix(in srgb, var(--primary) 20%, transparent);
}

.danger-zone {
  display: grid;
  gap: 0.5rem;
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
}

.danger-zone > h2,
.danger-zone > p {
  margin: 0;
}

.danger-zone form {
  display: grid;
  gap: 0.75rem;
}

.danger-zone > .button,
.danger-zone form > .button {
  width: fit-content;
}

.danger-zone > .button {
  margin-top: 0.5rem;
}

.container-delete-dialog {
  max-width: 32rem;
  padding: 1.5rem;
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  background: var(--surface);
  color: var(--text);
}

.container-delete-dialog::backdrop {
  background: rgb(0 0 0 / 45%);
}

.share-form {
  display: grid;
  grid-template-columns: minmax(10rem, 14rem) auto;
  align-items: end;
  gap: 0.75rem;
}

.share-form__field {
  display: grid;
  gap: 0.35rem;
}

.share-form__submit {
  grid-column: 1 / -1;
  justify-self: start;
}

.share-form__field label {
  font-weight: 700;
}

.input {
  width: 100%;
  min-height: 2.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--background);
  color: var(--text);
  font: inherit;
  padding: 0.5rem 0.75rem;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--text) 5%, transparent);
}

.input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 30%, transparent);
}

.share-link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}

.share-link a {
  min-width: 0;
  overflow-wrap: anywhere;
}

.share-link__actions {
  display: flex;
  justify-content: flex-start;
}

.button--icon {
  flex: none;
  padding: 0.55rem;
}

/* Bulk-add container form: one row per rail can number, with the input
   sized to leave the remove ("x") button sitting directly beside it rather
   than stretched to the full row width. Errors (duplicate warning) render
   full-width beneath the row. */
.bulk-rail-rows {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.bulk-rail-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.bulk-rail-row [data-bulk-rail-input] {
  flex: 0 1 22rem;
  width: auto;
}

.bulk-rail-row [data-bulk-rail-remove] {
  min-height: 2.5rem;
  box-sizing: border-box;
}

.bulk-rail-row [data-bulk-rail-error] {
  flex: 1 0 100%;
  margin: 0;
}

[data-bulk-rail-rows] > [data-bulk-rail-add] {
  margin-top: 0.65rem;
}

/* Duplicate-rail-can-number confirmation modal (bulk-add form), mirroring
   the photo-viewer's hand-built dialog pattern since there is no native
   <dialog> precedent in this codebase. */
.bulk-duplicate-modal-open {
  overflow: hidden;
}

.bulk-duplicate-modal[hidden] {
  display: none;
}

.bulk-duplicate-modal {
  position: fixed;
  z-index: 1000;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 1rem;
}

.bulk-duplicate-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 0.6);
}

.bulk-duplicate-modal__panel {
  position: relative;
  width: min(92vw, 480px);
  display: grid;
  gap: 0.75rem;
  padding: 1.5rem;
  border-radius: var(--radius-md);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
}

.customer-report-picker {
  display: grid;
  gap: 0.65rem;
}

.customer-report-picker__item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: border-color 0.12s, background-color 0.12s;
}

.customer-report-picker__item:hover {
  border-color: var(--border-strong);
  background: var(--surface-2);
}

.customer-report-picker__item strong,
.customer-report-picker__item small {
  display: block;
}

.customer-report-picker__item small {
  color: var(--text-muted);
  font-size: 0.85rem;
}

.customer-report-picker__initial {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  flex: none;
  border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  color: var(--primary);
  font-weight: 700;
}

.customer-report-picker__arrow {
  margin-left: auto;
  color: var(--text-muted);
  font-size: 1.2rem;
}

@media (max-width: 38rem) {
  .share-form {
    grid-template-columns: 1fr;
  }
}

/* Forms */
.form-field {
  display: grid;
  gap: 0.35rem;
  margin-bottom: 1rem;
}

/* Field-level validation feedback. Errored fields get a red ring via
   `aria-invalid` (set by the _forms.html macros) plus an inline message, so the
   user never needs to scroll to find what broke. Uses the primary/danger token
   so the look matches the existing `.alert--danger` banner. */
.form-field--error label,
.form-field__error {
  color: var(--primary);
}

.form-field__error {
  font-size: 0.85rem;
  margin: 0;
}

.form-field__required {
  color: var(--primary);
}

.form-field
  input[aria-invalid="true"],
.form-field
  select[aria-invalid="true"],
.form-field
  textarea[aria-invalid="true"] {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 25%, transparent);
}

/* Top-of-form validation summary banner emitted by the `error_summary` macro.
   Sits inside the `.alert--danger` chip; the inner `<ul>` lists whole-form
   messages, so reset browser list styling so it reads as a tight stack of
   lines rather than an indented bullet list. */
.form-errors {
  margin-bottom: 1rem;
}

.form-errors__list {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.25rem;
}

.form-errors__list li {
  font-size: 0.9rem;
}

/* Small helper-text line under a form (e.g. "A new container starts at…"). */
.form-help {
  margin: 0.5rem 0 1rem;
  color: var(--text-muted);
  font-size: 0.9rem;
}

.form-field label {
  font-weight: 700;
}

.form-field input,
.form-field select,
.form-field textarea {
  width: 100%;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--background);
  color: var(--text);
  font: inherit;
  padding: 0.55rem 0.65rem;
  transition: border-color 0.12s, box-shadow 0.12s;
}

.form-field input:focus,
.form-field select:focus,
.form-field textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 30%, transparent);
}

/* File inputs: don't stretch to full width (filename row reads better sized
   to content) and restyle the native choose-file button to match .button. */
.form-field input[type="file"] {
  width: auto;
  max-width: min(100%, 28rem);
}

.form-field input[type="file"]::file-selector-button {
  padding: 0.45rem 0.9rem;
  margin-right: 0.6rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  background: var(--secondary);
  color: var(--text);
  transition: filter 0.12s;
}

.form-field input[type="file"]::file-selector-button:hover {
  filter: brightness(0.96);
}

.csv-example {
  width: fit-content;
  max-width: 100%;
  margin: 0 0 1rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
}

.csv-example pre {
  max-width: 100%;
  margin: 0.4rem 0 0;
  overflow-x: auto;
  font: 0.85rem/1.6 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

.csv-example code {
  font: inherit;
}

/* Style the native select consistently across browsers; a custom chevron keeps
   the control on-palette without losing native keyboard behaviour. */
.form-field select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: linear-gradient(
      45deg, transparent 50%, var(--text-muted) 50% 62%, transparent 62% 78%, var(--text-muted) 78%
    );
  background-repeat: no-repeat;
  background-size: 0.5rem 0.5rem;
  background-position: right 0.7rem center;
  padding-right: 2rem;
}

.form-field textarea {
  resize: vertical;
  min-height: 5rem;
}

/* Password field with a trailing show/hide toggle button (password-toggle.js).
   The input keeps its normal `.form-field input` styling; the wrapper only
   adds the relative positioning the absolutely-placed button needs, plus
   right padding so typed text never sits under the icon. */
.form-field__password-wrap {
  position: relative;
  display: flex;
}

.form-field__password-wrap input {
  padding-right: 2.5rem;
}

.form-field__password-toggle {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  padding: 0;
}

.form-field__password-toggle:hover {
  color: var(--text);
}

.form-field__password-toggle:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 30%, transparent);
  border-radius: var(--radius-sm);
}

.app-icon--eye,
.app-icon--eye-off {
  width: 1.1rem;
  height: 1.1rem;
}

.inline-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  align-items: end;
  gap: 0.75rem;
  margin-top: 1.25rem;
  margin-bottom: 2rem;
}

/* Filter card: the container tracking list's collapsible filter panel. A
   native <details>/<summary> styled as a shadcn-style card so the user gets a
   clear clickable bar (icon + label + caret + an "Active" hint when filters
   are applied) and a responsive field grid with room to breathe. No JS: the
   disclosure state is the `open` attribute, auto-set by the template when any
   filter is active. */
.filters {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  margin: 0 0 var(--card-gap);
}

.filters__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
  padding: 0.75rem 1rem;
  font-weight: 700;
}

.filters__summary::-webkit-details-marker {
  display: none;
}

.filters__summary-text {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.filters__summary-meta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--text-muted);
}

.filters__summary:hover {
  background: color-mix(in srgb, var(--text) 6%, transparent);
}

.filters__summary:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* The field grid owns the inner spacing so the open panel has generous top &
   bottom breathing room; reset .form-field's own bottom margin here so the
   grid gap is the single source of vertical rhythm. */
.filters__form {
  padding: 1.25rem 1rem;
}

.filters__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: 1rem 1.25rem;
}

.filters__grid .form-field {
  margin-bottom: 0;
}

.filters__actions {
  margin-top: 1.25rem;
}

/* Bottom-aligning fields (`align-items: end` above) only works while every
   field is the same height. An inline error `<p>` is a 3rd grid row of
   `.form-field`, so one errored field is taller than its siblings and the
   clean fields' inputs sink to the errored field's error line. Take the
   error out of flow here so each field keeps a label+input height and the
   shared input baseline holds; the reserved `margin-bottom` on the row
   gives the overlay room so it doesn't clip into the next content. */
.inline-form .form-field {
  position: relative;
  margin-bottom: 0;
  min-width: 0;
}

.inline-form .form-field__error {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin: 0.35rem 0 0;
}

.inline-form .button,
.inline-form .checkbox-field {
  justify-self: start;
  align-self: end;
}

/* A lean inline form for a single control inside a table cell, e.g. the Remove
   button on a container's Assignments row. Unlike .inline-form this carries no
   grid spans or page-level margins, so an active row stays the same height as
   its inactive ("—") siblings instead of inflating from a 1.25rem grid. */
.row-action {
  display: inline-grid;
  margin: 0;
}

/* Compact multi-checkbox fieldsets (e.g. Users Site/Station access). The
   templates use <label class="checkbox"> for each row; <label class="checkbox-field">
   is the single-inline variant used in add forms. Both render an input + label
   in a flex row. */
.checkbox-field,
.checkbox {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  white-space: nowrap;
}

fieldset {
  border: 0;
  padding: 0;
  margin: 0 0 1rem;
  min-width: 0;
}

fieldset.form-field {
  margin-bottom: 1rem;
}

/* Slightly denser styling for the fieldset row variant. */
.checkbox {
  padding: 0.2rem 0;
  font-weight: 500;
}

input[type="checkbox"],
input[type="radio"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--primary);
  cursor: pointer;
}

/* Submit row for stacked forms (e.g. repair-catalog new/edit): breathing room so
   the action isn't flush against the last checkbox above it. */
.form-actions {
  margin-top: 1.25rem;
}

/* Inspection form: flat section headers over stacks of expandable item cards.
   Each item collapses to a single header row; its fields are revealed only when
   the include checkbox is checked, via a pure-CSS `:checked ~` sibling selector
   (no JS). This keeps a ~35-item form short and scannable, and stops every input
   from rendering at once. */
.inspection-section {
  margin: 0 0 var(--card-gap);
}

.inspection-section:last-of-type {
  margin-bottom: 0;
}

.inspection-section__title {
  margin: 0 0 0.75rem;
  font-size: 1.05rem;
  font-weight: 600;
}

.inspection-items {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.inspection-item {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 0.85rem 1rem;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.inspection-item:hover {
  border-color: var(--border-strong);
}

/* Checkpoint status control: a two-option Approved/Repair radio group. */
.inspection-item__status {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0;
  border: 0;
  padding: 0;
}

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

.inspection-item__status-opt {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.3rem 0.6rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  cursor: pointer;
  font-size: 0.8rem;
  color: var(--text-muted);
  user-select: none;
}

.inspection-item__status-opt--repair:has(input:checked) {
  border-color: var(--primary);
  background: color-mix(in oklab, var(--primary) 8%, var(--surface-2));
  color: var(--text);
  font-weight: 600;
}

.inspection-item__status-opt:not(.inspection-item__status-opt--repair):has(input:checked) {
  border-color: var(--success);
  color: var(--text);
  font-weight: 600;
}

.inspection-item__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.inspection-item__ident {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  min-width: 0;
}

/* The demo's code chip: a compact square anchoring each row. */
.inspection-item__code {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.5rem;
  height: 2.5rem;
  padding: 0 0.4rem;
  border-radius: var(--radius-sm);
  background: var(--text);
  color: var(--surface);
  font-weight: 700;
  font-size: 0.8rem;
}

.inspection-item__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.inspection-item__name {
  font-weight: 600;
  color: var(--text);
}

.inspection-item__meta {
  font-size: 0.8rem;
  color: var(--text-muted);
}

/* Progressive disclosure: repair fields stay hidden until the checkpoint is
   marked Repair. */
.inspection-item__fields {
  display: none;
  grid-template-columns: 1fr;
  gap: 0.75rem 1rem;
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--border);
}

.inspection-item:has(.inspection-item__status-opt--repair input:checked) .inspection-item__fields {
  display: grid;
}

.inspection-progress {
  margin: 0.5rem 0 1rem;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.inspection-item__lock-note {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 0.75rem;
  color: var(--text-muted);
}

.inspection-photo-thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin: 0.5rem 0;
}

.inspection-photo-thumb {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin: 0;
  width: 8rem;
}

.inspection-photo-thumb img {
  width: 8rem;
  height: 6rem;
  object-fit: cover;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}

.inspection-photo-thumb a {
  display: block;
  border-radius: var(--radius-sm);
}

.inspection-photo-thumb a:focus-visible,
.inspection-photo-thumb a:hover {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.photo-gallery-button {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  align-self: flex-start;
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: 0.78rem;
  cursor: pointer;
}

.inspection-photo-panel__head .photo-gallery-button {
  order: 0;
}

.photo-gallery-title {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.photo-gallery-button svg {
  width: 1rem;
  height: 1rem;
}

.photo-gallery-button:hover {
  border-color: var(--primary);
  color: var(--primary);
}

.photo-viewer-open {
  overflow: hidden;
}

.photo-viewer[hidden] {
  display: none;
}

.photo-viewer {
  position: fixed;
  z-index: 1000;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 1rem;
}

.photo-viewer__backdrop {
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 0.84);
}

.photo-viewer__panel {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-rows: minmax(0, 1fr) auto;
  align-items: center;
  width: min(96vw, 1100px);
  height: min(94vh, 900px);
  gap: 1rem;
}

.photo-viewer__image {
  grid-column: 2;
  grid-row: 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.photo-viewer__close,
.photo-viewer__previous,
.photo-viewer__next {
  z-index: 1;
  border: 1px solid rgb(255 255 255 / 0.35);
  border-radius: 999px;
  background: rgb(0 0 0 / 0.55);
  color: white;
  font: inherit;
  cursor: pointer;
}

.photo-viewer__close {
  position: absolute;
  top: -0.4rem;
  right: -0.4rem;
  width: 2.25rem;
  height: 2.25rem;
  font-size: 1.6rem;
  line-height: 1;
}

.photo-viewer__previous,
.photo-viewer__next {
  width: 2.75rem;
  height: 2.75rem;
  font-size: 2rem;
  line-height: 1;
}

.photo-viewer__status {
  grid-column: 1 / -1;
  grid-row: 2;
  justify-self: center;
  color: white;
  font-size: 0.85rem;
}

.photo-viewer__close:hover,
.photo-viewer__previous:hover,
.photo-viewer__next:hover,
.photo-viewer__close:focus-visible,
.photo-viewer__previous:focus-visible,
.photo-viewer__next:focus-visible {
  border-color: white;
  background: rgb(255 255 255 / 0.2);
  outline: 2px solid white;
  outline-offset: 2px;
}

@media (max-width: 560px) {
  .photo-viewer__panel {
    grid-template-columns: auto minmax(0, 1fr) auto;
    width: 100%;
    height: min(88vh, 700px);
    gap: 0.4rem;
  }

  .photo-viewer__previous,
  .photo-viewer__next {
    width: 2.25rem;
    height: 2.25rem;
  }
}

.button--sm {
  padding: 0.3rem 0.6rem;
  font-size: 0.8rem;
}

.inspection-item__fields .form-field {
  position: relative;
  margin-bottom: 0;
  min-width: 0;
}

.inspection-item__fields .form-field__error {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin: 0.3rem 0 0;
  z-index: 1;
}

.inspection-item__fields .form-field--error {
  margin-bottom: 1.35rem;
}

/* Field labels sit below the item name in the visual hierarchy: small, muted,
   uppercase — never bolder than the item they describe. */
.inspection-item__fields .form-field label {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0;
  color: var(--text-muted);
}

.inspection-photo-panel {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  min-width: 0;
  margin-top: 0.1rem;
  padding-top: 0.85rem;
  border-top: 1px dashed var(--border);
}

.inspection-photo-panel__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.inspection-photo-panel__title {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text);
}

.inspection-photo-panel__meta {
  font-size: 0.75rem;
  color: var(--text-muted);
}

.photo-gallery-meta {
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--text-muted);
}

@media (min-width: 560px) {
  .inspection-item__fields {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .inspection-item__fields .form-field--wide {
    grid-column: 1 / -1;
  }
}

@media (min-width: 900px) {
  .inspection-item__fields {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .inspection-item__fields .form-field--wide {
    grid-column: span 2;
  }
}

/* Feedback */
.alert {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  margin: 0 0 1rem;
}

.alert--danger {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 14%, var(--background));
}

.alert--success {
  border-color: color-mix(in srgb, var(--success) 45%, transparent);
  background: color-mix(in srgb, var(--success) 12%, var(--background));
  color: var(--success);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.alert--info {
  border-color: color-mix(in srgb, var(--info) 45%, transparent);
  background: color-mix(in srgb, var(--info) 12%, var(--background));
  color: var(--info);
}

.alert--warning {
  border-color: color-mix(in srgb, var(--warning-strong) 45%, transparent);
  background: color-mix(in srgb, var(--warning) 14%, var(--background));
  color: var(--warning-strong);
  font-weight: 700;
}

/* Repair-created confirmation: subtle green-accented ticket summary. */
.repair-created__summary {
  border: 1px solid var(--border);
  border-left: 3px solid var(--success);
  border-radius: var(--radius);
  padding: 1rem;
  margin: 0 0 1rem;
  background: var(--surface);
}

.repair-created__can {
  font-weight: 600;
  margin: 0 0 0.25rem;
}

.repair-created__station {
  margin: 0;
  color: var(--text-muted);
}

/* Tables */
.table-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.table-wrap .table {
  min-width: max-content;
}

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

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

.table th {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
}

/* Flat rows (no zebra striping) with a subtle hover, matching the demo. */
.table tbody tr:hover {
  background: color-mix(in srgb, var(--text) 4%, var(--surface));
}

/* Badge — pill chips. The default (no modifier) is a muted neutral chip
   matching the demo's `bg-muted text-muted-foreground`; semantic variants tint
   a soft fill from the status tokens. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 0.15rem 0.55rem;
  font-size: 0.78rem;
  font-weight: 500;
  white-space: nowrap;
  background: var(--surface-2);
  color: var(--text-muted);
}

/* Neutral: an explicit alias for the unmodified `.badge` styling, for callers
   that pass a "neutral" status variant name (e.g. a revenue target of $0). */
.badge--neutral {
  background: var(--surface-2);
  color: var(--text-muted);
}

.badge--success {
  background: color-mix(in srgb, var(--success) 16%, var(--surface));
  color: var(--success);
}

.badge--warning {
  background: color-mix(in srgb, var(--warning) 18%, var(--surface));
  color: var(--warning-strong);
  font-weight: 600;
}

.badge--destructive,
.badge--danger {
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  color: var(--primary);
}

.badge--info {
  background: color-mix(in srgb, var(--info) 14%, var(--surface));
  color: var(--info);
}

/* Outline: bordered, transparent-fill chip for quiet metadata. */
.badge--outline {
  background: transparent;
  border-color: var(--border);
  color: var(--text);
}

/* Avatar — a round initials chip on the muted surface. Used by the Users table
   and the sidebar identity block. --lg is the larger footer/identity size. */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1;
  overflow: hidden;
}

.avatar--lg {
  width: 2.5rem;
  height: 2.5rem;
  font-size: 0.95rem;
}

/* Rounded-square avatar used in the sidebar footer identity row (matches the
   demo's rounded-lg avatar rather than the default circle). */
.avatar--square {
  border-radius: var(--radius);
}

/* An avatar + label row, e.g. a Users table name cell. */
.identity {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  min-width: 0;
}

/* Two-line identity label: the display name over a muted login-username
   subline. Each line stays on a single line (no wrapping); the ellipsis
   properties guard against overflow if the column is ever width-constrained.
   Today the table sizes to `max-content` and scrolls, so long names widen the
   column rather than truncate. */
.identity__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.identity__name {
  color: var(--text);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.identity__sub {
  color: var(--text-muted);
  font-size: 0.8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Inspection review queue — a list of cards (thumbnail + body + Review CTA)
   replacing the old table. Reuses the shadcn badge/button primitives; wraps to
   a stacked layout on narrow viewports. */
.inspection-list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.inspection-card {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.inspection-card:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow);
}

.inspection-card__thumb {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: var(--radius);
  color: var(--text-muted);
  background: var(--surface-2);
}

.inspection-card__main {
  display: flex;
  align-items: center;
  flex: 1 1 12rem;
  min-width: 0;
  gap: 1rem;
  color: inherit;
  text-decoration: none;
}

.inspection-card__thumb .app-icon {
  width: 1.6rem;
  height: 1.6rem;
}

.inspection-card__body {
  flex: 1 1 12rem;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.inspection-card__title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.inspection-card__ref {
  font-weight: 600;
  color: var(--text);
}

.inspection-card__meta {
  margin: 0;
  font-size: 0.85rem;
  color: var(--text);
}

.inspection-card__meta--muted {
  color: var(--text-muted);
  font-size: 0.8rem;
}

.inspection-card__action {
  flex: none;
  margin-left: auto;
}

/* Approve/Deny inline row actions on the inspection queue and my-work lists. */
.inspection-card__action--row {
  display: flex;
  gap: 0.5rem;
}

/* The per-row Deny reason form is initially hidden. deny-modal.js moves the
   selected form into a shared native <dialog> and reveals it only after the
   corresponding Deny button is clicked. */
.deny-form {
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px dashed var(--border);
}

.deny-form .form-field {
  margin-bottom: 0.5rem;
}

/* The shared deny-reason popup. A single native <dialog> element is reused
   across every row; deny-modal.js relocates the triggering row's form into it
   on open and returns the form to its original position on close. */
.deny-modal {
  width: min(28rem, calc(100vw - 2rem));
  padding: 1.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.deny-modal::backdrop {
  background: rgb(0 0 0 / 0.45);
}

.deny-modal__heading {
  margin: 0 0 0.75rem;
  font-size: 1.05rem;
}

.deny-modal .deny-form {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

.forklift-move-dialog {
  width: min(32rem, calc(100vw - 2rem));
  padding: 1.75rem;
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) + 2px);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-lg);
}

.forklift-move-dialog::backdrop {
  background: rgb(0 0 0 / 0.55);
}

.forklift-move-dialog__title,
.forklift-move-dialog__question {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 650;
  line-height: 1.35;
}

.forklift-move-dialog__question {
  margin-top: 0.5rem;
  color: var(--text-muted);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.5;
}

.forklift-move-dialog__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: flex-start;
  margin-top: 1.5rem;
}

.forklift-move-dialog__actions .button {
  flex: 1 1 8rem;
  max-width: 12rem;
  min-height: 3.25rem;
  padding: 0.75rem 1rem;
  font-size: 1rem;
  font-weight: 650;
}

/* The stage-move prompt is used in the field workflow, so it gets more room
   and larger controls than the compact forklift queue confirmation. */
.forklift-alert-dialog {
  width: min(32rem, calc(100vw - 2rem));
  padding: 1.75rem;
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) + 2px);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-lg);
}

.forklift-alert-dialog::backdrop {
  background: rgb(0 0 0 / 0.55);
}

.forklift-alert-dialog__question {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 650;
  line-height: 1.35;
}

.forklift-alert-dialog__hint {
  margin: 0.5rem 0 0;
  color: var(--text-muted);
  font-size: 1rem;
  line-height: 1.5;
}

.forklift-alert-dialog__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.5rem;
  justify-content: center;
}

.forklift-alert-dialog__actions .button {
  flex: 1 1 8rem;
  max-width: 12rem;
  min-height: 3.25rem;
  padding: 0.75rem 1rem;
  font-size: 1rem;
  font-weight: 650;
}

.forklift-alert-dialog__cancel {
  color: var(--text-muted);
}

@media (max-width: 30rem) {
  .forklift-alert-dialog,
  .forklift-move-dialog {
    padding: 1.25rem;
  }

  .forklift-alert-dialog__question,
  .forklift-move-dialog__title {
    font-size: 1.2rem;
  }

  .forklift-alert-dialog__hint,
  .forklift-move-dialog__question {
    font-size: 0.95rem;
  }

  .forklift-alert-dialog__actions,
  .forklift-move-dialog__actions {
    flex-direction: column;
    align-items: stretch;
  }

  .forklift-alert-dialog__actions .button,
  .forklift-move-dialog__actions .button {
    max-width: none;
  }
}

/* Container reference: two illustrative reference photos in a responsive 2-up
   grid (shown on the review detail and the inspection form). Not a per-inspection
   capture. */
.reference-images {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.75rem;
}

/* Each photo lives in a figure that clips the hover zoom. object-contain keeps
   the whole container art visible (no cropping); a 16:9 letterbox gives the
   photos real presence on desktop rather than a thin strip. */
.reference-image {
  position: relative;
  margin: 0;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
}

/* Side by side, the two photos shrink fast as the viewport narrows, so stack
   them early — well before phone widths — and flatten each to a full-row
   letterbox once it spans the whole card. */
@media (max-width: 1400px) {
  .reference-images {
    grid-template-columns: 1fr;
  }
  .reference-image {
    aspect-ratio: 16 / 7;
  }
}

.reference-image img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: transform 0.5s ease;
}

.reference-image:hover img {
  transform: scale(1.05);
}

/* Demo-style caption pill naming the view (e.g. "Left / Rear"). */
.reference-image__label {
  position: absolute;
  left: 0.6rem;
  bottom: 0.6rem;
  padding: 0.2rem 0.55rem;
  border-radius: var(--radius-sm);
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Review-detail line-items rendered as demo-style rows: a check glyph marks an
   included repair, with a title line and a muted detail line. */
.line-items {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.line-item {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.line-item__check {
  display: inline-flex;
  flex: none;
  color: var(--success);
  margin-top: 0.1rem;
}

.line-item__body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.line-item__title {
  font-weight: 600;
  color: var(--text);
}

.line-item__detail {
  margin: 0;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Submit/Save-draft row at the foot of the inspection form: separate it from
   the last item section, which otherwise butts right up against the buttons. */
.actions--form-footer {
  margin-top: var(--card-gap);
}

/* Right-aligned actions (e.g. the Approve/Reopen buttons on the repair review
   page, which sit in the bottom-right corner per the customer's request). */
.actions--end {
  justify-content: flex-end;
}

/* The "Stuck / unbilled" badge sits beneath the stage badge inside a Stage
   table cell; give it a hair of breathing room from the badge above. */
.stuck-unbilled-badge {
  margin-top: 0.25rem;
}

/* ---------- Dashboard ---------- */
.card__heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

.card__heading h2 {
  margin: 0 0 0.15rem;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.card__heading p {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.9rem;
}

.dash-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 0.85rem;
  margin-bottom: 1.25rem;
}

/* Clean white KPI card (shadcn "operational" style): a muted icon chip, an
   uppercase muted label, and a large bold value. No accent left border — the
   soft shadow and 1px border do the lifting, keeping red for actions only. */
.stat-card {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 1.1rem 1.15rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.stat-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  margin-bottom: 0.15rem;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-muted);
}

.stat-card__icon svg {
  width: 1.15rem;
  height: 1.15rem;
}

.stat-card__label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  font-weight: 700;
}

.stat-card__value {
  font-size: 1.9rem;
  font-weight: 800;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.dash-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
  margin-bottom: 1.25rem;
}

.dash-grid--money {
  margin-top: 1.25rem;
}

.dash-grid--content {
  grid-template-columns: 1fr;
}

@media (min-width: 1100px) {
  .dash-grid--content {
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  }
}

.dash-finance-card {
  gap: 1rem;
}

.dash-review-list {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.dash-review-list li {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--border);
}

.dash-review-list li:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.dash-review-list a {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  color: var(--text);
  text-decoration: none;
}

.dash-review-list a:hover {
  color: var(--primary);
}

.dash-review-list a span,
.dash-review-list small {
  color: var(--text-muted);
  font-size: 0.82rem;
}

.dash-review-list a span {
  text-align: right;
}

.dash-empty {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.35rem;
  padding: 1.25rem;
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}

.dash-empty p {
  margin: 0 0 0.35rem;
  color: var(--text-muted);
  font-size: 0.9rem;
}

.dash-empty--compact {
  padding: 0.9rem;
}

.dash-finance-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.7rem;
}

.dash-finance-row .stat-card {
  padding: 0.85rem;
  box-shadow: none;
}

.dash-finance-row .stat-card__value {
  font-size: 1.45rem;
}

.dash-finance-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  color: var(--text-muted);
  font-size: 0.88rem;
}

.dash-card-link {
  align-self: flex-start;
  font-size: 0.9rem;
  font-weight: 600;
}

.dash-chart-card {
  overflow-x: auto;
}

/* Inline SVG workflow-stage chart. Uses currentColor + palette vars so it
   follows the theme without per-theme rules. */
.stage-chart {
  width: 100%;
  height: auto;
  max-height: 20rem;
  color: var(--text);
}

.stage-chart__label {
  fill: var(--text);
  font-size: 13px;
  font-weight: 600;
}

.stage-chart__track {
  fill: color-mix(in srgb, var(--text) 8%, transparent);
}

/* Neutral slate bars keep the chart calm and reserve red for primary actions,
   while staying legible on the white surface in both themes. */
.stage-chart__bar {
  fill: color-mix(in srgb, var(--text) 45%, transparent);
}

.stage-chart__value {
  fill: var(--text);
  font-size: 13px;
  font-weight: 700;
}

.empty-state {
  margin: 0.25rem 0 0;
  color: var(--text-muted);
  font-style: italic;
}

/* Stage-event history timeline on the container detail page. Rendered as a
   bordered <ol> with one row per stage change; the .badge next to a row marks
   a "did not need" skip, and .stage-timeline__meta carries the source +
   timestamp. */
.stage-timeline {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin: 0;
  padding: 0;
}

.stage-timeline__item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}

.stage-timeline__name {
  font-weight: 600;
  color: var(--text);
}

.stage-timeline__meta {
  margin-left: auto;
  color: var(--text-muted);
  font-size: 0.85rem;
  white-space: nowrap;
}

/* "Did not need" checklist on the inspection approve form: a fieldset of
   per-stage checkboxes a rebuild reviewer may tick to jump the container
   past those stages on approval. */
.checklist {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0 0 1rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}

.checklist > legend {
  padding: 0;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--text-muted);
  margin-bottom: 0.4rem;
}

.checklist__item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
}

.dash-coming-soon {
  border-style: dashed;
}

/* ---------- Board / Container Schedule ---------- */

/* Visually-hidden but available to assistive tech. Used by the move-bar's
   implicit "Move selected to" label (the visible affordance is the live
   count + adjacent select). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.site-selector {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 0.75rem;
  margin-top: 0;
}

.site-selector .form-field {
  margin-bottom: 0;
}

.board__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  margin-top: 0.5rem;
}

.board-move-enhanced .board__move-target {
  display: none;
}

.board-page-header {
  flex: none;
  gap: 0.75rem;
  padding: 1rem 1.25rem;
}

.board-page-header .page-heading {
  align-items: center;
  margin-bottom: 0;
}

.board-page-header .page-heading h1 {
  margin: 0;
}

.board__form {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
}

.app-main:has(.board__form) {
  min-height: 0;
}

.board {
  display: flex;
  gap: 1rem;
  min-height: 100%;
  min-width: max-content;
  padding-bottom: 0.5rem;
}

.board__column {
  width: 19rem;
  flex-shrink: 0;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.board__column-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.65rem 0.85rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  border-radius: var(--radius) var(--radius) 0 0;
}

.board__column-title {
  margin: 0;
  font-size: 0.8rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.board__column-body {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.6rem;
  flex: 1 1 auto;
}

.board__empty {
  padding: 1.25rem 0.5rem;
  text-align: center;
  font-size: 0.85rem;
  color: var(--text-muted);
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
}

/* A card is a flex row: a checkbox "grip" + a navigable card body.
   The left accent bar signals priority; the strong primary ring signals
   selection (works even without JS via :has). */
.board__card {
  position: relative;
  display: flex;
  gap: 0.5rem;
  align-items: stretch;
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
  transition: border-color 0.12s, box-shadow 0.12s;
}

.board__card:hover {
  border-color: color-mix(in srgb, var(--primary) 35%, var(--border));
  box-shadow: 0 1px 4px color-mix(in srgb, var(--text) 8%, transparent);
}

.board__card:has(.board__card-check:checked) {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 24%, transparent);
}

.board__card--priority-high {
  border-left-color: var(--primary);
}
.board__card--priority-medium {
  border-left-color: var(--warning-strong);
}
.board__card--priority-low {
  border-left-color: var(--success);
}
.board__card--priority-none {
  border-left-color: var(--border);
}

.board__card-check-wrap {
  display: flex;
  align-items: flex-start;
  padding: 0.6rem 0 0.6rem 0.55rem;
  cursor: pointer;
}

.board__card-check {
  flex-shrink: 0;
  width: 1.1rem;
  height: 1.1rem;
  margin: 0;
  accent-color: var(--primary);
}

.board__card-main {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
  flex: 1;
  padding: 0.6rem;
  text-decoration: none;
  color: inherit;
}

.board__card-main:visited {
  color: inherit;
}

.board__card-main:hover {
  background: color-mix(in srgb, var(--primary) 4%, var(--surface));
}

.board__card-id {
  font-weight: 800;
  font-size: 0.95rem;
  word-break: break-all;
  color: var(--text);
}

.board__card-customer {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.board__card-customer .app-icon {
  width: 0.85rem;
  height: 0.85rem;
  flex-shrink: 0;
}

.board__card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.2rem;
}

.board__cell {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0.3rem 0.45rem;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  min-width: 0;
  flex: 1 1 4rem;
}

.board__cell-label {
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}

.board__cell-value {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Priority badges. Red/amber/emerald mirrors the demo's `priorityClasses`. */
.badge--priority {
  align-self: flex-start;
  font-weight: 600;
  text-transform: capitalize;
}
.badge--priority-high {
  background: color-mix(in srgb, var(--primary) 14%, var(--surface));
  color: var(--primary);
  border: 1px solid color-mix(in srgb, var(--primary) 30%, transparent);
}
.badge--priority-medium {
  background: color-mix(in srgb, var(--warning-strong) 16%, var(--surface));
  color: var(--warning-strong);
  border: 1px solid color-mix(in srgb, var(--warning-strong) 30%, transparent);
}
.badge--priority-low {
  background: color-mix(in srgb, var(--success) 14%, var(--surface));
  color: var(--success);
  border: 1px solid color-mix(in srgb, var(--success) 30%, transparent);
}

.board__move-bar {
  position: sticky;
  bottom: 0;
  margin-top: 0.75rem;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 -2px 8px color-mix(in srgb, var(--text) 6%, transparent);
}

.board__move-bar-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

.board__move-count {
  font-size: 0.85rem;
  color: var(--text-muted);
  font-weight: 500;
}

.board__move-count strong {
  color: var(--text);
  font-weight: 800;
}

.board__move-bar .form-field {
  flex: 1 1 14rem;
  margin-bottom: 0;
}

.board-move-dialog__field {
  margin: 1rem 0 0;
}

.board__move-bar [data-board-move-submit] {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.board__move-bar [data-board-move-submit]:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.board__move-bar [data-board-move-submit] .app-icon {
  width: 1rem;
  height: 1rem;
}

/* ---------- Finances ---------- */

/* Period tabs (Day / Week / Month / Year) and prev/next navigation. Kept
   lightweight: the tabs are simple pill-shaped links, not a heavy client-side
   tab component. */
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}

.tabs__tab {
  display: inline-flex;
  align-items: center;
  padding: 0.4rem 0.75rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  font-size: 0.9rem;
  font-weight: 500;
  text-decoration: none;
  line-height: 1;
}

.tabs__tab:hover {
  background: color-mix(in srgb, var(--text) 8%, transparent);
}

.tabs__tab.is-active {
  background: var(--text);
  color: var(--surface);
  border-color: var(--text);
}

.period-nav {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.period-nav__label {
  font-weight: 600;
  font-size: 0.95rem;
  padding: 0 0.25rem;
}

/* Definition list grid used for the payroll-detail card. */
.dl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: 0.75rem 1.25rem;
}

.dl-grid dt {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  font-weight: 700;
  margin: 0;
}

.dl-grid dd {
  margin: 0.2rem 0 0;
  font-size: 0.95rem;
  font-weight: 600;
}

/* ---------- Responsive ---------- */
@media (max-width: 720px) {
  .page-heading {
    align-items: stretch;
    flex-direction: column;
  }

  .inline-form {
    grid-template-columns: 1fr;
    align-items: stretch;
  }

  .inline-form .button,
  .inline-form .checkbox-field {
    justify-self: stretch;
    align-self: stretch;
  }

}

/* Below the sidebar breakpoint the panel becomes a full-screen overlay menu
   summoned from a mobile top bar. */
@media (max-width: 1023px) {
  .app-shell {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr;
  }

  .app-mobile-bar {
    display: flex;
  }

  .app-sidebar {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    height: 100dvh;
    transform: translateX(-100%);
    transition: transform 0.18s ease;
    z-index: 50;
    box-shadow: var(--shadow-overlay);
    /* The mobile bar (z-index: 60) stays on top so its close (x) toggle stays
       tappable. Push the menu content down below the bar so the first items
       (Overview, Dashboard) aren't overlapped by it. */
    padding-top: 4.5rem;
  }

body.app-nav-open .app-sidebar {
    transform: translateX(0);
  }

  /* Lock the page background once the overlay menu opens so only the menu
     scrolls, not the screen behind it. Inside the sidebar, .app-nav is the
     scroll container (the aside itself is overflow: hidden). */
  body.app-nav-open {
    overflow: hidden;
  }

  /* The FRRS wordmark already lives in the mobile bar, so the sidebar's
     brand block is redundant inside the full-screen menu and looks cramped
     against the bar's FRRS. Hide it here; desktop keeps the sidebar brand. */
  .app-brand {
    display: none;
  }

  /* The grid's `auto 1fr` row track already pushes main below the sticky
      mobile top bar, so no extra margin is needed here. */
}

@media (min-width: 1024px) {
  .app-mobile-bar {
    display: none;
  }
}

/* ---------- Phone (≤ 559px) ----------
   Below the smallest tablet breakpoint. List pages swap their wide
   scroll-only table for a stacked card layout (no horizontal scroll for
   common fields), the login card sheds its generous padding, and remaining
   tables compact their cells. The mobile-card list is hidden on wider
   screens and shown here; the desktop table is hidden here and shown wider. */

/* Hidden on desktop, revealed at the phone breakpoint. Paired with
   .table-wrap--desktop which is visible by default and hidden at the
   breakpoint, so each list page renders both markups and CSS toggles them. */
.mobile-cards {
  display: none;
}

@media (max-width: 559px) {
  /* Reveal the stacked card list and hide the desktop table. */
  .mobile-cards {
    display: block;
  }
  .table-wrap--desktop {
    display: none;
  }

  .dash-stats { gap: .5rem; margin-bottom: .75rem; }
  .stat-card { gap: .15rem; padding: .55rem .65rem; }
  .stat-card__icon { width: 1.5rem; height: 1.5rem; margin-bottom: 0; }
  .stat-card__icon svg { width: .8rem; height: .8rem; }
  .stat-card__value { font-size: 1.2rem; }

  /* The card list fills the remaining card height and scrolls internally,
     mirroring the .card--list > .table-wrap flex/scroll contract. */
  .card--list > .mobile-cards {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* Each row becomes a mini-card separated by a border. */
  .mobile-cards__item {
    padding: 0.85rem 0.25rem;
    border-bottom: 1px solid var(--border);
  }
  .mobile-cards__item:last-child {
    border-bottom: none;
  }

  /* The primary line: rail-can number (often a link) sits prominently. */
  .mobile-cards__title {
    font-weight: 700;
    font-size: 1rem;
    margin-bottom: 0.4rem;
  }

  /* Label:value pairs stack vertically, full width, no horizontal scroll. */
  .mobile-cards__field {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.18rem 0;
  }
  .mobile-cards__label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    font-weight: 600;
    white-space: nowrap;
    flex-shrink: 0;
  }
  .mobile-cards__value {
    text-align: right;
    font-size: 0.9rem;
    word-break: break-word;
    min-width: 0;
  }

  /* Per-row action row (e.g. the "Mark moved" button) sits full-width. */
  .mobile-cards__actions {
    margin-top: 0.5rem;
  }

  /* Login card: shed the 2.25rem padding that squeezes a 375px viewport. */
  .app-login-card {
    padding: 1.25rem;
  }
  .app-login-wordmark {
    font-size: 2rem;
  }
  .app-login-logo {
    width: 3rem;
    height: 3rem;
  }

  /* Reduce main + card padding so content gets more of the narrow viewport. */
  .app-main {
    padding: 1rem 0.75rem;
  }
  .card {
    padding: 1rem;
  }

  /* Compact table cells for tables that remain (reference data, repair
     completion summary, etc.). */
  .table th,
  .table td {
    padding: 0.5rem 0.35rem;
    font-size: 0.82rem;
  }

  /* Scale down page headings and stat values that are oversized on phones. */
  .page-heading h1 {
    font-size: 1.25rem;
  }
  .stat-card__value {
    font-size: 1.5rem;
  }

  /* Board: add a gradient fade on the right edge so users see there is more
     content to scroll to. The fade lives on .board__form (the scroll
     container's parent, which is not itself a scroll container) so it stays
     pinned to the visible right edge rather than scrolling with the content.
     pointer-events: none keeps touch scrolling unblocked. */
  .board__form {
    position: relative;
  }
  .board__form::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 1.5rem;
    background: linear-gradient(
      to right,
      transparent,
      var(--surface)
    );
    pointer-events: none;
    z-index: 1;
  }

  /* The move bar wraps on phones; give the select and button full width. */
  .board__move-bar-inner {
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
  }
  .board__move-bar .form-field--inline {
    flex-direction: column;
    align-items: stretch;
  }
  .board__move-bar [data-board-move-submit] {
    width: 100%;
  }

  /* Site selector wraps cleanly on phones. */
  .site-selector {
    flex-direction: column;
    align-items: stretch;
  }

  /* Filter card: tighter form padding and full-width action buttons. */
  .filters__form {
    padding: 1rem 0.5rem;
  }
  .filters__summary {
    padding: 0.65rem 0.75rem;
  }
  .filters__actions .button {
    width: 100%;
  }
}

/* ---------- Photo compression ---------- */
/* While the client-side photo compressor is resizing/re-encoding a selection,
   the owning form carries `.is-compressing` (and aria-busy). Submit controls
   are disabled by the script; an appended ellipsis + progress cursor signals
   that work is in flight so a slow encode on a phone doesn't read as a frozen
   page. `input[type="submit"]` can't host a pseudo-element (void element), so
   it only gets the cursor; the visible ellipsis renders on <button>. */
.is-compressing button[type="submit"],
.is-compressing input[type="submit"],
.is-compressing button:not([type]) {
  cursor: progress;
}

.is-compressing button[type="submit"]::after,
.is-compressing button:not([type])::after {
  content: " …";
}
@media print {
  .app-nav, .app-header, form, button, .button { display: none !important; }
  .card { box-shadow: none; border: 1px solid #ddd; break-inside: avoid; }
}
