/* ALC Internal System - Direction A in the store palette (spec section 10).
   Primary teal, accent lime, warm beige background, saturated status colours.
   Form stays quiet and slick: hairline dividers, photo-first rows, small pills.
   Red is reserved for exceptions and corrections. */

:root {
  --teal: #b45309;
  --teal-dark: #92400e;
  --lime: #bcc31d;
  --beige: #f4f1ec;
  --ink: #1c1a17;
  --muted: #6f675c;
  --line: #ddd6c9;

  /* Stage colours, carried over from the approved prototype. */
  --st-to_test: #2563eb;
  --st-in_repair: #d97706;
  --st-waiting_part: #7c3aed;
  --st-to_price: #be123c;
  --st-ready: #15803d;
  --st-escalated: #c1272d;
  --st-sold: #6f675c;
  --st-neutral: #6f675c;

  --tap: 48px; /* No interactive element under 48px for floor roles (spec 5.7). */
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; }

/* With viewport-fit cover, the phone paints the strip above the
   header (the status bar zone) from the page background: beige
   there read as a blurry pale band over the app. The html
   background is teal so any overscroll above the frame stays
   teal; the band itself is painted by the header since Nov 5,
   2026 (black-translucent plus the header's safe-area
   padding), because with the "default" status bar style the
   phone owned that zone and frosted it pale regardless of
   this colour. */
html { background: var(--teal); }

/* Staging banner (T-160, staging build only): an amber band across
   the top of every screen, in a colour live never uses, so a
   screenshot alone tells which world it came from. The shell is a
   flex column and screens scroll inside .view, so an in-flow band
   with flex 0 0 auto stays pinned above the header for good. */
.staging-banner {
  flex: 0 0 auto;
  background: #f59e0b; color: #1c1a17;
  font-size: 14px; font-weight: 800; letter-spacing: .02em;
  text-align: center; padding: 10px 12px;
}

/* The no-sticker choice on the intake photo step: a big box
   and a full row tap target, right under the sticker photo. */
.no-sticker-check {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 4px; margin: 2px 0 6px;
  font-size: 17px; font-weight: 700; cursor: pointer;
}
/* Workshop view (Nov 2, 2026): the unit photo on the
   contractor-only screen. */
.wk-photo { width: 100%; border-radius: 12px; margin-top: 8px; }

/* Testing assignments (Nov 2, 2026): the assign row under a
   unit waiting to be tested. */
.assign-row { display: flex; gap: 8px; align-items: center; margin: 0 0 12px; }
.assign-row select { flex: 1 1 0; min-width: 0; }

/* Units filters (Nov 2, 2026): the Filters heading is a
   dropdown row; the block under it starts shut. */
.filters-toggle {
  display: flex; justify-content: space-between; align-items: center;
  width: 100%; background: none; border: none; padding: 0;
  margin: 18px 0 8px; font: inherit; font-size: 16px; font-weight: 800;
  color: var(--ink); cursor: pointer; text-align: left;
}

/* Unit screen lightening (Nov 4, 2026): a card section that does
   not need immediate action starts shut behind its title row, the
   same shape as the Units filters above. The title row is the
   toggle; the body under it carries the hidden class while shut.
   The shut row keeps the useful state (a count, an open count) in
   its hint span, so nothing urgent hides invisibly. */
.section-toggle {
  display: flex; justify-content: space-between; align-items: center;
  width: 100%; background: none; border: none; padding: 0;
  margin: 0 0 8px; font: inherit; font-size: 16px; font-weight: 800;
  color: var(--ink); cursor: pointer; text-align: left;
}
.section-toggle .section-hint { font-size: 13px; font-weight: 600; color: var(--muted, #6f675c); }
.section-chev { flex: 0 0 auto; margin-left: 10px; }

/* The finish requirements checklist (Nov 4, 2026): one short line
   per requirement at the top of the finish step, done or missing
   at a glance. */
.finish-check-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 0; border-top: 1px solid var(--line);
}
.finish-check-row:first-of-type { border-top: none; }
.finish-check-mark { font-weight: 800; width: 18px; flex: 0 0 auto; text-align: center; }
.finish-check-row[data-check-state="done"] .finish-check-mark { color: var(--teal); }
.finish-check-row[data-check-state="missing"] .finish-check-mark { color: var(--st-in_repair); }
.finish-check-state { margin-left: auto; font-weight: 700; font-size: 13px; }
.finish-check-row[data-check-state="missing"] .finish-check-state { color: var(--st-in_repair); }

/* Marketing tile actions (Nov 4, 2026): under a marketing
   thumbnail, the main-picture choice and the remove sit in the
   open, one tap each, never behind the viewer. */
.mkt-tile-actions { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; width: 96px; }
.mkt-tile-actions .btn { min-height: 32px; font-size: 12px; padding: 4px 6px; }
.mkt-main-marker { font-size: 11px; font-weight: 800; color: var(--teal); padding: 2px 0; }

/* Administration (Nov 2, 2026): one section at a time behind
   tabs, and people as compact rows that open one editor. */
.admin-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 14px; }
.admin-tab {
  border: 2px solid var(--teal); background: #fff; color: var(--teal);
  border-radius: 999px; padding: 8px 14px; font-weight: 700; cursor: pointer;
}
.admin-tab.on { background: var(--teal); color: #fff; }
.admin-person-row {
  display: flex; justify-content: space-between; align-items: center;
  gap: 10px; width: 100%; text-align: left; margin: 6px 0;
}
.admin-person-row .meta { display: block; }

.no-sticker-check input[type="checkbox"] {
  width: 30px; height: 30px; flex: 0 0 auto; margin: 0;
  accent-color: var(--teal);
}

/* App frame (Nov 1, 2026, Christian's screen report: the bottom nav
   floated up mid-scroll and list rows painted underneath it). The
   shell used to be a document-scrolling page with the nav pinned by
   position: fixed; on iOS a fixed element anchors to the visual
   viewport, which grows and shrinks as the browser chrome retracts,
   so the nav rode up with the chrome and the page showed through
   below it. The frame is now a flex column sized to the DYNAMIC
   viewport (100vh first for older browsers, then 100dvh): header,
   back bar and bottom nav are in-flow children, and #view is the
   one scroll container, ending exactly at the nav's top edge, so
   nothing can render below the nav. The fixed layers that share the
   bottom edge (confirm bar, update banner, reporter pill) keep
   their viewport-relative offsets, which still clear the in-flow
   nav exactly as they cleared the fixed one. */
body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--beige);
  color: var(--ink);
  display: flex; flex-direction: column;
  height: 100vh;
  height: 100%;
  overflow: hidden;
}

.app-header {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: nowrap;
  background: var(--teal); color: #fff;
  /* The header paints the status bar zone (Nov 5, 2026): the
     status bar style is black-translucent, so the page extends
     under the phone's clock and icons, and this top padding,
     exactly the system's own safe-area inset, extends the teal
     through that zone as one solid band. The header is in-flow
     at the frame's top and never scrolls, so the band holds at
     rest and mid-scroll alike. Where the inset is 0 (browser
     tabs, Android, the test browser) the bar keeps its exact
     44 px shape: the content row does not grow, the band only
     ever gains the phone's own status zone. */
  padding: calc(26px + env(safe-area-inset-top, 0px)) 12px 6px;
}
.app-title { font-weight: 800; font-size: 17px; letter-spacing: .01em; white-space: nowrap; }
.app-title span { font-weight: 400; opacity: .85; font-size: 12px; }

/* The one scroll container of the app frame: it fills the space
   between the back bar and the bottom nav and scrolls alone. */
.view {
  flex: 1 1 auto; min-height: 0; width: 100%;
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  max-width: 720px; margin: 0 auto; padding: 14px 14px 24px;
}
.view h1 { font-size: 21px; margin: 6px 0 10px; }
.view h2 { font-size: 16px; margin: 18px 0 8px; }

/* In-flow last child of the app frame (Nov 1, 2026): the nav sits
   at the true bottom of the dynamic viewport on every phone, and
   its safe-area padding keeps the links clear of the home
   indicator on notched iPhones. */
.bottom-nav {
  flex: 0 0 auto;
  display: flex; background: #fff; border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}
.bottom-nav a {
  flex: 1; text-align: center; text-decoration: none; color: var(--muted);
  font-size: 13px; font-weight: 600; padding: 12px 0 10px; min-height: var(--tap);
}
.bottom-nav a.active { color: var(--teal-dark); box-shadow: inset 0 3px 0 var(--lime); }
.bottom-nav a.hidden { display: none; }

/* Boards (spec 6.14): one card per stage, count, oldest age. */
.board-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

/* Quick actions (Nov 1, 2026): the common doors on the person's own
   dashboard, above the pipeline counts. Full-width stacked, like the
   Intake door choice, so either language's label fits, and taller
   than the 48px tap floor (56px): these are the buttons a person
   reaches for all day. */
.quick-actions { display: grid; gap: 8px; margin-bottom: 12px; }
.quick-actions .btn { width: 100%; min-height: 56px; }

/* Units add action (Nov 1, 2026): intake holders get the same
   full-width, 56px primary action at the top of the Units screen,
   above the Stock and Sold tabs, so it stays in reach on both views. */
.units-add-unit { width: 100%; min-height: 56px; margin: 4px 0 12px; }
.stage-card {
  background: #fff; border: 1px solid var(--line); border-left: 8px solid var(--st-neutral);
  border-radius: 10px; padding: 10px 12px; text-decoration: none; color: var(--ink);
  min-height: var(--tap);
}
.stage-card .count { font-size: 24px; font-weight: 800; }
.stage-card .label { font-size: 14px; font-weight: 700; }
.stage-card .age { font-size: 12px; color: var(--muted); }
.stage-card[data-stage="to_test"] { border-left-color: var(--st-to_test); }
.stage-card[data-stage="in_repair"] { border-left-color: var(--st-in_repair); }
.stage-card[data-stage="waiting_part"] { border-left-color: var(--st-waiting_part); }
.stage-card[data-stage="to_price"] { border-left-color: var(--st-to_price); }
.stage-card[data-stage="ready"] { border-left-color: var(--st-ready); }
.stage-card[data-stage="escalated"] { border-left-color: var(--st-escalated); }

/* Small status pill, used on unit rows everywhere. */
.pill {
  display: inline-block; font-size: 11.5px; font-weight: 700; color: #fff;
  border-radius: 999px; padding: 2px 9px; background: var(--st-neutral);
}
.pill[data-stage="to_test"] { background: var(--st-to_test); }
.pill[data-stage="in_repair"] { background: var(--st-in_repair); }
.pill[data-stage="waiting_part"] { background: var(--st-waiting_part); }
.pill[data-stage="to_price"] { background: var(--st-to_price); }
.pill[data-stage="ready"] { background: var(--st-ready); }
.pill[data-stage="escalated"] { background: var(--st-escalated); }
.pill[data-stage="sold"], .pill[data-stage="donor"], .pill[data-stage="scrapped"] { background: var(--st-sold); }

/* Photo-first rows (unit lists, contractor view). */
.unit-row {
  display: flex; gap: 12px; align-items: center; background: #fff;
  border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; margin-bottom: 8px;
  text-decoration: none; color: var(--ink); min-height: 64px;
}
.unit-row img { width: 64px; height: 64px; object-fit: contain; border-radius: 8px; background: var(--beige); }
.unit-row .num { font-size: 20px; font-weight: 800; }
.unit-row .meta { font-size: 13px; color: var(--muted); }

/* Back bar (Oct 31, 2026): one consistent way back at the top of
   every non-root screen; the button clears the 48px tap floor. */
.back-bar { flex: 0 0 auto; width: 100%; max-width: 720px; margin: 0 auto; padding: 10px 14px 0; }
.back-button {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--tap); min-width: var(--tap); padding: 10px 12px 10px 4px;
  background: none; border: 0; border-radius: 10px; cursor: pointer;
  color: var(--teal-dark); font-size: 16px; font-weight: 700;
}
.back-button .back-chevron { font-size: 22px; line-height: 1; }

/* Buttons: verb plus object, self-explanatory (review standard, Oct 29 2026). */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tap); padding: 10px 16px; border-radius: 10px; border: 0;
  background: var(--teal); color: #fff; font-size: 15px; font-weight: 700; cursor: pointer;
}
.btn.secondary { background: #fff; color: var(--teal-dark); border: 1.5px solid var(--teal); }
.btn.danger { background: var(--st-escalated); }
.btn.block { display: flex; width: 100%; margin-top: 10px; }

/* Two-step confirm bar (spec 6.3): state changes never fire on one abrupt tap. */
.confirm-bar {
  background: #fff7ed; border: 1.5px solid var(--st-in_repair); border-radius: 10px;
  padding: 12px; margin-top: 10px; font-size: 14px;
}
.confirm-bar .row { display: flex; gap: 10px; margin-top: 10px; }
.confirm-bar .row .btn { flex: 1; }

/* The router's discard prompt and the new-version banner (Nov 1, 2026):
   fixed above the bottom nav so they are on screen wherever the person
   has scrolled to. In flow, the discard bar landed at the bottom of
   long screens, out of sight, and the navigation tap that opened it
   looked dead. */
.confirm-bar-fixed {
  position: fixed; left: 10px; right: 10px; z-index: 60;
  bottom: calc(60px + env(safe-area-inset-bottom, 0px));
  margin-top: 0; box-shadow: 0 6px 24px rgba(28, 26, 23, 0.28);
}

.notice {
  background: #fff; border: 1px solid var(--line); border-left: 8px solid var(--lime);
  border-radius: 10px; padding: 12px; font-size: 14px; line-height: 1.45;
}
input[type="text"], input[type="number"], input[type="tel"], select, textarea {
  width: 100%; min-height: var(--tap); font-size: 16px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 8px; background: #fff; color: var(--ink);
}
label.field { display: block; font-size: 13px; font-weight: 700; margin: 12px 0 4px; }

/* Desktop density (spec 5.7): same data, wider boards. */
@media (min-width: 1100px) {
  .view { max-width: 1100px; }
  .back-bar { max-width: 1100px; }
  .board-grid { grid-template-columns: repeat(4, 1fr); }
}


/* Authentication and live Slice 1 forms. */
.hidden { display: none !important; }
.header-actions { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }
.header-button {
  min-height: 32px; border: 1px solid rgba(255, 255, 255, .65); border-radius: 999px;
  background: transparent; color: #fff; font-weight: 700; cursor: pointer; padding: 4px 10px;
  font-size: 13px; white-space: nowrap;
}
/* Top bar redesign (Nov 5, 2026): one slim row. The language
   toggle and the mode selector are compact pills in the bar's
   own style; the mode chip is the same select element with the
   same behaviour, only restyled. The profile picture is a
   round button at the right edge; with no photo field on
   profiles it shows the person's initials until one lands. */
.header-chip {
  min-height: 32px; border: 1px solid rgba(255, 255, 255, .65); border-radius: 999px;
  background: transparent; color: #fff; font-weight: 700; cursor: pointer; padding: 4px 10px;
  font-size: 13px;
}
.mode-chip {
  width: auto; min-height: 32px; font-size: 13px; padding: 4px 8px;
  border: 1px solid rgba(255, 255, 255, .65); border-radius: 999px;
  background: transparent; color: #fff; cursor: pointer;
}
.mode-chip option { color: #111; }
.profile-avatar {
  width: 32px; height: 32px; border-radius: 50%; flex: 0 0 auto;
  border: 1px solid rgba(255, 255, 255, .65); background: rgba(255, 255, 255, .16);
  color: #fff; font-weight: 700; font-size: 13px; cursor: pointer; padding: 0;
  display: inline-grid; place-items: center; overflow: hidden;
}
.profile-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.auth-card, .profile-card, .test-card {
  background: #fff; border: 1px solid var(--line); border-radius: 12px;
  padding: 16px; margin-bottom: 12px;
}
.auth-card { max-width: 520px; margin: 20px auto; }
.auth-card h1 { margin-top: 0; }
.auth-switch { margin-top: 16px; font-size: 14px; }
/* A text-only button that reads as a link (the sign-in
   screen's Forgot password toggle). */
.linklike {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--teal-dark); font-weight: 700; font-size: 14px;
}
.auth-forgot { margin-top: 14px; }
/* The My information profile photo: a 72 px circle preview
   (the stored photo, or initials on the teal disc) with its
   actions beside it. */
.profile-photo-row { display: flex; align-items: center; gap: 14px; }
.profile-photo-preview {
  width: 72px; height: 72px; border-radius: 999px; object-fit: cover;
  flex: 0 0 auto; background: var(--teal);
}
.profile-photo-initials {
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 800; font-size: 24px;
}
.profile-photo-actions { display: flex; flex-direction: column; gap: 8px; }
.profile-photo-actions .btn { text-align: center; }
.auth-switch a, .admin-alert { color: var(--teal-dark); font-weight: 700; }
.error { color: var(--st-escalated); font-size: 14px; font-weight: 700; margin-top: 10px; }
.success { color: var(--st-ready); font-size: 14px; font-weight: 700; margin-top: 10px; }
.form-row { display: flex; gap: 8px; align-items: stretch; }
.form-row > * { flex: 1; }
.form-row.spaced { margin-top: 6px; }
.grow { flex: 1; min-width: 0; }
.results { margin-top: 12px; }
.admin-alert {
  display: block; background: #fff; border: 1px solid var(--line);
  border-left: 8px solid var(--st-escalated); border-radius: 10px;
  padding: 12px; margin-bottom: 12px; text-decoration: none;
}
.unit-row.flat { border: 0; padding: 0; margin: 0; }
.meta.strong { color: var(--ink); font-weight: 700; }
fieldset { border: 1px solid var(--line); border-radius: 10px; margin: 14px 0; padding: 10px; }
legend { font-size: 13px; font-weight: 800; padding: 0 5px; }
.check-grid, .pay-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.check-item {
  display: flex; gap: 8px; align-items: center; min-height: var(--tap);
  border: 1px solid var(--line); border-radius: 8px; padding: 8px; font-size: 14px;
}
.check-item input { width: 20px; height: 20px; flex: 0 0 auto; }
.pay-grid label span { display: block; font-size: 13px; font-weight: 700; margin-bottom: 4px; }
.assigned-number {
  background: #fff; border: 2px solid var(--st-ready); border-radius: 12px;
  padding: 18px; text-align: center; margin-top: 14px;
}
.assigned-number strong { display: block; font-size: 52px; line-height: 1.1; color: var(--teal-dark); }
.module-list { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.module-link {
  display: flex; align-items: center; min-height: 64px; background: #fff;
  border: 1px solid var(--line); border-radius: 10px; padding: 12px;
  color: var(--teal-dark); font-weight: 800; text-decoration: none;
}
input[type="email"], input[type="password"], input[type="date"] {
  width: 100%; min-height: var(--tap); font-size: 16px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 8px; background: #fff; color: var(--ink);
}
button:disabled { opacity: .55; cursor: wait; }

@media (max-width: 520px) {
  .app-header { align-items: center; gap: 8px; }
  .header-actions { flex-wrap: nowrap; justify-content: flex-end; }
  /* The bar stays one row on a phone even before the app is
     installed (when the Download app pill still shows): the
     wordmark shortens to ALC alone so the language chip, the
     mode chip, and the profile picture all stay on screen. */
  .app-title span { display: none; }
  /* The mode chip sizes to its longest option ("Operations
     Manager"); capped on a phone so the avatar keeps its
     place at the right edge. The dropdown itself is native
     and still shows every mode in full. */
  .mode-chip { max-width: 112px; }
  .check-grid, .pay-grid { grid-template-columns: 1fr; }
  .load-row { align-items: stretch; flex-direction: column; }
}


/* ------------------------------------------------------------------
   Slices 2 to 7 components. Direction A stays: teal primary, lime on
   the primary action, saturated stage colours, red only for exceptions.
   ------------------------------------------------------------------ */

.card {
  background: #fff; border: 1px solid var(--line); border-radius: 12px;
  padding: 14px; margin-bottom: 12px;
}
.card h2, .card h3 { margin-top: 0; }
a.card { display: block; text-decoration: none; color: var(--ink); }
.muted { color: var(--muted); }
.strong { font-weight: 700; }
.small { font-size: 13px; }
.mt { margin-top: 10px; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
a.unit-row { cursor: pointer; }
button.unit-row { width: 100%; text-align: left; font: inherit; cursor: pointer; }

/* Key-value detail rows on unit, sale, claim, and stop cards. */
.kv { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border-bottom: 1px solid var(--line); font-size: 14px; }
.kv:last-child { border-bottom: 0; }
.kv .k { color: var(--muted); font-weight: 600; }
.kv .v { font-weight: 700; text-align: right; }
.kv .v.big { font-size: 19px; }

/* Tappable identity fields (F10, F11): the field itself is the target,
   a small pencil mark shows it can be tapped. */
.tappable { cursor: pointer; }
.tappable::after { content: " \270E"; color: var(--muted); font-size: 12px; }
.inline-edit { display: flex; gap: 8px; align-items: stretch; margin-top: 6px; }
.inline-edit > * { flex: 1; }

/* Fault chips (F12): multi-select at testing, tap again to clear. */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0; }
.chip {
  min-height: var(--tap); padding: 8px 14px; border-radius: 999px; cursor: pointer;
  border: 1.5px solid var(--teal); background: #fff; color: var(--teal-dark);
  font-size: 14px; font-weight: 700;
}
.chip.selected { background: var(--teal); color: #fff; }
.fault-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 15px; }
.fault-row:last-child { border-bottom: 0; }

/* Floor tasks: photo-led rows, before-delivery chip, load flags. */
.floor-task-row { display: flex; gap: 10px; align-items: flex-start; padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 15px; }
.floor-task-row:last-child { border-bottom: 0; }
.floor-task-row .thumb { width: 56px; height: 56px; border-radius: 8px; background: var(--beige); display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--muted); flex: 0 0 auto; overflow: hidden; text-align: center; }
.thumb img { width: 100%; height: 100%; object-fit: contain; background: var(--beige); }
.pill.warn { background: var(--st-in_repair); }
.load-flag { background: #fdf3e3; border: 1px solid var(--st-in_repair); color: var(--ink); border-radius: 8px; padding: 6px 9px; font-size: 14px; font-weight: 600; margin-top: 6px; }

/* Timeline (spec 6.5): the unit's whole life, newest first. */
.timeline { margin-top: 6px; }
.timeline-entry { padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 14px; }
.timeline-entry:last-child { border-bottom: 0; }
.timeline-entry .when { color: var(--muted); font-size: 12.5px; }
.timeline-entry.correction { border-left: 4px solid var(--st-escalated); padding-left: 8px; }
.timeline-entry.reply-highlight { background: #fdf6d8; border-left: 4px solid var(--lime); padding-left: 8px; border-radius: 4px; }

/* Stepper (F27): one step at a time, progress header, live gates (F28). */
.stepper-head { margin-bottom: 10px; }
.stepper-title { font-size: 16px; font-weight: 800; margin-bottom: 6px; }
.progress { height: 8px; background: var(--line); border-radius: 999px; overflow: hidden; }
.progress span { display: block; height: 100%; background: var(--lime); }
.stepper-bar { display: flex; gap: 10px; margin-top: 14px; }
.stepper-bar .btn { flex: 1; }
.review-row { display: flex; gap: 10px; align-items: center; padding: 10px 0; border-bottom: 1px solid var(--line); }
.review-row:last-child { border-bottom: 0; }

/* Quiet sticky action bar on stop screens (P2): details carry the
   screen, completion sits secondary at the bottom. It sticks to the
   bottom of the #view scroll container, which already ends at the
   bottom nav's top edge, so the offset is simply 0. */
.stopbar {
  position: sticky; bottom: 0;
  display: flex; gap: 10px; background: var(--beige); padding: 10px 0; z-index: 5;
}
.stopbar .btn { flex: 1; }
.btn.ghost { background: transparent; color: var(--st-escalated); border: 1.5px solid var(--st-escalated); }

/* Photo-led rows (P4): big thumbnail space, big number, short labels. */
.bigrow { display: flex; gap: 12px; align-items: center; background: #fff; border: 1px solid var(--line); border-radius: 10px; padding: 10px; margin-bottom: 8px; text-decoration: none; color: var(--ink); min-height: 84px; }
.bigrow .thumb { width: 64px; height: 64px; border-radius: 8px; background: var(--beige); display: flex; align-items: center; justify-content: center; font-size: 26px; flex: 0 0 auto; }
.bigrow .num { font-size: 21px; font-weight: 800; }
.bigrow .meta { font-size: 13px; color: var(--muted); }

/* Review queue rows (Nov 1, 2026 layout fix): a stacked card, not
   one flex line. The open target is the head (thumbnail plus title,
   title free to wrap at readable width) and the meta lines; the
   assignee pill, the assignment row, and Mark resolved stack below
   as siblings, so nothing overlaps or clips at phone width. Named
   queue-row, never review-row: .review-row is the stepper's own
   summary row (display:flex), and the first version of this fix
   shared that name, which laid these cards out as one flex line
   and reproduced the very collapse it was fixing. */
.queue-row { background: #fff; border: 1px solid var(--line); border-radius: 10px; padding: 10px; margin-bottom: 8px; }
.queue-row-open { display: block; text-decoration: none; color: inherit; }
.queue-row-head { display: flex; gap: 12px; align-items: center; }
.queue-row-title { font-size: 16px; overflow-wrap: anywhere; }
.queue-row-open .meta { display: block; margin-top: 6px; font-size: 13px; color: var(--muted); }
.queue-row-assignee { margin-top: 8px; }
.queue-row-assign { margin-top: 10px; }
.queue-row-assign select { flex: 1.6 1 0; min-width: 0; }
.queue-row .btn.block { margin-top: 10px; }

/* Parked photo tiles (Nov 1, 2026): the "photo unavailable" label
   sits behind the image; a tile whose image is missing or failed
   shows the label instead of a silent grey box. */
.parked-thumb { position: relative; overflow: hidden; }
.parked-thumb-label { display: none; font-size: 11px; line-height: 1.25; color: var(--muted); text-align: center; padding: 2px; }
.parked-thumb.photo-failed .parked-thumb-label { display: block; }

/* Unit thumbnails (Mayssa's rule, Oct 30, 2026): one small square
   beside the number on every unit row, card, and picker option. The
   box is fixed before any photo loads, so rows never jump; a unit
   with no stored photo shows its type on a neutral tile instead. */
.unit-thumb {
  width: 46px; height: 46px; border-radius: 8px; background: var(--beige);
  display: flex; align-items: center; justify-content: center;
  flex: 0 0 auto; overflow: hidden;
}
.unit-thumb img { width: 100%; height: 100%; object-fit: contain; display: block; background: var(--beige); }
/* Nov 1, 2026: no type word on the tile (long names clipped at this
   size); one muted image glyph, centred, same box as the photo. */
.unit-thumb-none { color: var(--muted); }
.unit-thumb-none svg { width: 22px; height: 22px; display: block; }

/* Warranty visit identity (P4): violet band everywhere a visit appears,
   so a visit is never mistaken for a repair assignment. */
.visit-band { border-left: 8px solid #7c3aed !important; }
.visit-chip { background: #7c3aed; color: #fff; font-size: 11.5px; font-weight: 800; border-radius: 999px; padding: 2px 9px; display: inline-block; }
.visit-banner { background: #7c3aed; color: #fff; border-radius: 10px; padding: 10px 12px; font-weight: 800; margin-bottom: 10px; }

/* Operations Manager task board (B2): each task type reads differently
   at a glance, own colour band, count, and deadline line. */
.task-card {
  display: flex; gap: 12px; align-items: center; background: #fff; text-decoration: none; color: var(--ink);
  border: 1px solid var(--line); border-left: 8px solid var(--st-neutral);
  border-radius: 10px; padding: 12px; margin-bottom: 8px; min-height: 64px;
}
.task-card .count { font-size: 24px; font-weight: 800; min-width: 40px; text-align: center; }
.task-card .label { font-size: 15px; font-weight: 800; }
.task-card .sub { font-size: 13px; color: var(--muted); }
.task-card[data-kind="plan"] { border-left-color: var(--teal); }
.task-card[data-kind="pricing"] { border-left-color: var(--st-to_price); }
.task-card[data-kind="approvals"] { border-left-color: var(--st-in_repair); }
.task-card[data-kind="exceptions"] { border-left-color: var(--st-escalated); }
.task-card[data-kind="claims"] { border-left-color: #7c3aed; }
.task-card[data-kind="requests"] { border-left-color: #2563eb; }
.task-card.overdue { background: #fdf2f2; border-color: var(--st-escalated); }

/* Exceptions strip (spec 6.14). */
.exception-strip { background: #fdf2f2; border: 1px solid var(--st-escalated); border-radius: 10px; padding: 10px 12px; margin-bottom: 12px; font-size: 14px; }
.exception-strip .item { padding: 4px 0; }
.exception-strip a.reply-open { color: inherit; text-decoration: none; }
.exception-strip a.reply-open .who { text-decoration: underline; }
.banner { border-radius: 10px; padding: 10px 12px; font-size: 14px; margin-bottom: 10px; border: 1px solid var(--line); background: #fff; }
.banner.amber { border-left: 8px solid var(--st-in_repair); }
.banner.red { border-left: 8px solid var(--st-escalated); background: #fdf2f2; }
.banner.violet { border-left: 8px solid #7c3aed; }
.banner.teal { border-left: 8px solid var(--teal); }

/* Smart unit field identity card. */
.smart-card { border: 1.5px solid var(--line); border-radius: 10px; padding: 10px 12px; margin-top: 8px; background: #fff; }
.smart-card .num { font-size: 20px; font-weight: 800; }
.smart-card.ok { border-color: var(--st-ready); }
.smart-card.warn { border-color: var(--st-in_repair); }
.smart-card.bad { border-color: var(--st-escalated); background: #fdf2f2; }
.flag-line { color: var(--st-escalated); font-weight: 700; font-size: 13.5px; margin-top: 3px; }

/* Guidance pinned from the Operations Manager (B19). */
.guidance-card { background: #fff7ed; border: 1.5px solid var(--st-in_repair); border-radius: 10px; padding: 12px; margin-bottom: 12px; font-size: 14.5px; }

/* Planning map panel (N4 stand-in until live maps): pins in order, the
   line runs out of the warehouse and back (P1). */
.map-panel { position: relative; background: #eef3f1; border: 1px solid var(--line); border-radius: 12px; min-height: 220px; margin-bottom: 12px; overflow: hidden; }
.map-pin {
  position: absolute; width: 30px; height: 30px; border-radius: 50%; transform: translate(-50%, -50%);
  background: var(--teal); color: #fff; font-weight: 800; font-size: 14px;
  display: flex; align-items: center; justify-content: center; border: 2px solid #fff;
}
.map-pin.warehouse { background: var(--ink); border-radius: 8px; }
.map-pin.done { background: var(--st-ready); }
.map-pin.attempted { background: var(--st-escalated); }
.map-pin.visit { background: #7c3aed; }

/* Live truck map (Leaflet, OpenStreetMap): active routes in the
   planning view. Numbered stop pins match the drawn panel's look;
   the truck marker is a dark label that cannot be mistaken for a
   stop. The map sits under the app header in stacking order. */
.live-map { height: 260px; border: 1px solid var(--line); border-radius: 12px; margin-bottom: 8px; z-index: 0; }
.leaflet-pin-wrap { background: transparent; border: 0; }
.leaflet-stop-pin {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--teal); color: #fff; font-weight: 800; font-size: 14px;
  display: flex; align-items: center; justify-content: center; border: 2px solid #fff;
}
.leaflet-truck-pin {
  background: var(--ink); color: #fff; font-weight: 800; font-size: 11px;
  letter-spacing: .04em; border-radius: 8px; border: 2px solid var(--lime);
  display: flex; align-items: center; justify-content: center; height: 26px;
}

/* Plan the day, Circuit-style map (Christian's surfaces, Nov 5,
   2026): exchange pins in the calm rust of the stop edges, the
   warehouse as a dark W square, a tapped pin carrying a ring, and
   the stop rows' kind edges in the list. The rust is the exchange
   colour wherever a stop's kind is drawn. */
:root { --rust: #b3502e; }
.leaflet-stop-pin.exchange { background: var(--rust); }
.leaflet-stop-pin.visit { background: #7c3aed; }
.leaflet-stop-pin.ring { box-shadow: 0 0 0 5px rgba(14, 107, 122, .45); }
.leaflet-warehouse-pin {
  width: 30px; height: 30px; border-radius: 8px;
  background: var(--ink); color: #fff; font-weight: 800; font-size: 14px;
  display: flex; align-items: center; justify-content: center; border: 2px solid #fff;
}
.plan-map { height: 300px; border: 1px solid var(--line); border-radius: 12px; margin-bottom: 8px; z-index: 0; }
.stop-edge { border-left: 5px solid var(--line); }
.stop-edge-delivery { border-left-color: var(--teal); }
.stop-edge-exchange { border-left-color: var(--rust); }
.stop-edge-pickup, .stop-edge-load_pickup { border-left-color: #5b7a72; }
.stop-edge-warranty_visit { border-left-color: #7c3aed; }
.stop-edge.flash { background: #fdf3e3; }
.unit-row .grow[data-open-stop] { cursor: pointer; }
.unit-row[draggable="true"] { cursor: grab; }
.unit-row.drag-over { outline: 2px dashed var(--teal); outline-offset: -2px; }
/* Pointer Events plan drag (Nov 7, 2026): the handle never
   scrolls, a lifted row floats over the list, and its slot is
   held by the placeholder the list makes room around. */
[data-drag-handle] { touch-action: none; cursor: grab; padding: 10px 6px; margin: -10px -6px; }
[data-stop-row] { -webkit-touch-callout: none; }
.plan-drag-placeholder { border: 2px dashed var(--line); border-radius: 12px; background: rgba(20, 25, 30, 0.04); }
.plan-drag-lift { position: fixed; z-index: 80; margin: 0; box-shadow: 0 10px 28px rgba(20, 25, 30, 0.28); opacity: 0.97; }
body.plan-dragging { overflow: hidden; }
body.plan-dragging, body.plan-dragging * { user-select: none; -webkit-user-select: none; }

/* Segmented choices and tables. */
.seg { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0; }
.seg button { flex: 1; min-height: var(--tap); }
.table { width: 100%; border-collapse: collapse; font-size: 14px; background: #fff; }
.table th, .table td { text-align: left; padding: 8px; border-bottom: 1px solid var(--line); }
.table th { font-size: 12.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; }
.tabs { display: flex; gap: 6px; margin-bottom: 12px; overflow-x: auto; }
.tabs a, .tabs button {
  flex: 0 0 auto; min-height: 44px; padding: 8px 14px; border-radius: 999px; border: 1.5px solid var(--teal);
  background: #fff; color: var(--teal-dark); font-weight: 700; font-size: 14px; text-decoration: none;
  display: inline-flex; align-items: center; cursor: pointer;
}
.tabs a.active, .tabs button.active { background: var(--teal); color: #fff; }
input[type="time"] {
  width: 100%; min-height: var(--tap); font-size: 16px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 8px; background: #fff; color: var(--ink);
}
.photo-check-rules { background: #fff; border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; font-size: 13.5px; margin-bottom: 10px; }
.photo-check-rules li { margin: 3px 0; }

/* Download app help sheet (bottom sheet over a dimmed backdrop). */
.install-help {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(28, 26, 23, 0.55);
  display: flex; align-items: flex-end; justify-content: center;
}
.install-card {
  background: #fff; width: 100%; max-width: 480px;
  border-radius: 14px 14px 0 0; padding: 18px;
}
.install-card ol { margin: 8px 0 14px 20px; }
.install-card li { margin-bottom: 6px; }

/* Screen modification request (Nov 1, 2026): the quiet shell button
   on every screen, its bottom sheet, and the sent confirmation. The
   button sits just above the bottom nav at the right, small and
   secondary; the fixed confirm bar and the new-version banner ride
   at z-index 60 and cover it while they are up, never the reverse. */
.screen-report-button {
  position: fixed; right: 12px; z-index: 40;
  bottom: calc(68px + env(safe-area-inset-bottom, 0px));
  min-height: 40px; padding: 8px 14px; border-radius: 999px;
  background: #fff; color: var(--teal-dark);
  border: 1.5px solid var(--teal);
  font-size: 13px; font-weight: 700; cursor: pointer;
  box-shadow: 0 4px 14px rgba(28, 26, 23, 0.22);
}
.screen-report-sheet {
  position: fixed; inset: 0; z-index: 70;
  background: rgba(28, 26, 23, 0.55);
  display: flex; align-items: flex-end; justify-content: center;
}
.screen-report-card {
  background: #fff; width: 100%; max-width: 480px;
  border-radius: 14px 14px 0 0; padding: 18px;
  /* Attachments (Nov 1, 2026) made the sheet taller: a previewed
     photo or video must never push Send off a small phone. The
     card is a flex column whose BODY scrolls and whose action row
     is a permanent footer, and while the sheet is open the
     component also fits the sheet to the visual viewport, so Send
     stays at the bottom of what is visible with the on-screen
     keyboard up (the .23 card could not scroll at all, and its
     buttons sat below the visible area: Christian, Nov 1, 2026). */
  max-height: 92vh; max-height: 92dvh;
  display: flex; flex-direction: column;
}
.screen-report-body { overflow-y: auto; min-height: 0; }
.screen-report-card h2 { margin: 0 0 6px; font-size: 17px; }
.screen-report-screen { margin: 0 0 4px; font-size: 13.5px; color: var(--muted); }
.screen-report-card .row { display: flex; gap: 10px; margin-top: 12px; flex: 0 0 auto; }
.screen-report-card .row .btn { flex: 1; }
.screen-report-toast {
  position: fixed; left: 50%; transform: translateX(-50%); z-index: 80;
  bottom: calc(124px + env(safe-area-inset-bottom, 0px));
  background: var(--teal-dark); color: #fff;
  border-radius: 999px; padding: 10px 18px;
  font-size: 14px; font-weight: 700;
  box-shadow: 0 6px 24px rgba(28, 26, 23, 0.28);
}

/* First-run language pick: two big buttons, English and Français, before
   anything else in the app (the person's own choice, never preset). */
.language-pick { display: grid; gap: 12px; margin-top: 14px; }
.language-choice { min-height: 64px; font-size: 20px; }

/* Photo strip on the unit screen: stored photos render from their
   durable reference; waiting photos show their state in words. */
.photo-strip { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
/* Photos grouped by kind on the unit screen (Nov 4, 2026): one
   compact heading line per kind, its strip tight under it, so a
   long set reads as short named groups instead of one grid. */
.photo-group { margin-top: 12px; }
.photo-group-head { font-size: 13px; font-weight: 700; }
/* Photo groups start shut behind their heading (Nov 4, 2026),
   except the group holding the cover: the heading is the toggle,
   in the same family as .section-toggle. */
button.photo-group-head {
  display: flex; justify-content: space-between; align-items: center;
  width: 100%; background: none; border: none; padding: 0;
  font: inherit; color: var(--ink); cursor: pointer; text-align: left;
}
.photo-group .photo-strip { margin-top: 6px; }
/* Pictures to sort (Nov 4, 2026): a stored photo whose kind is
   the catch-all carries an amber outline until a person moves
   it into a real category. */
.photo-tile.to-sort img,
.photo-tile.to-sort .tile-note { outline: 2px solid var(--st-in_repair); outline-offset: -2px; }
.photo-tile { width: 96px; margin: 0; }
.photo-tile img { width: 96px; height: 96px; object-fit: contain; border-radius: 10px; display: block; background: var(--beige); }
.photo-tile video { width: 96px; height: 96px; object-fit: cover; border-radius: 10px; display: block; background: #1c1a17; }
.photo-tile figcaption { font-size: 11px; color: var(--muted, #6f675c); margin-top: 4px; }
.photo-tile .tile-note { width: 96px; height: 96px; border-radius: 10px; display: flex; align-items: center; justify-content: center; text-align: center; font-size: 11px; padding: 6px; background: #f4f1ec; color: #6f675c; border: 1px dashed #c9c2b4; box-sizing: border-box; }
.photo-tile[data-photo-open] { cursor: pointer; }
.photo-view { margin: 0; }
.photo-view img { width: 100%; max-height: 420px; object-fit: contain; border-radius: 12px; display: block; background: #f4f1ec; }
.photo-view video { width: 100%; max-height: 420px; border-radius: 12px; display: block; background: #1c1a17; }
.photo-view figcaption { font-size: 12px; color: var(--muted, #6f675c); margin-top: 4px; }

/* Batch photo fixing (Nov 1, 2026): in Fix photos mode every stored
   tile is a large selectable target with a check badge; the sticky
   bar rides above the bottom nav like the confirm bar so the count
   and the remove action stay on screen while he scrolls the set. */
.photo-tile { position: relative; }
.photo-check {
  display: none; position: absolute; top: 6px; right: 6px; z-index: 2;
  width: 28px; height: 28px; border-radius: 50%;
  background: #fff; border: 2px solid var(--teal); color: transparent;
  font-size: 16px; font-weight: 800; line-height: 24px; text-align: center;
}
.photo-strip.fixing .photo-tile { cursor: pointer; }
.photo-strip.fixing .photo-check { display: block; }
.photo-strip.fixing .photo-tile.selected img,
.photo-strip.fixing .photo-tile.selected .tile-note { outline: 3px solid var(--teal); outline-offset: -3px; }
.photo-tile.selected .photo-check { background: var(--teal); color: #fff; }
.photo-fix-bar {
  position: fixed; left: 10px; right: 10px; z-index: 60;
  bottom: calc(60px + env(safe-area-inset-bottom, 0px));
  background: #fff; border: 1px solid var(--line); border-radius: 12px;
  padding: 12px; box-shadow: 0 6px 24px rgba(28, 26, 23, 0.28);
}
.photo-fix-bar .row { display: flex; gap: 10px; margin-top: 10px; }
.photo-fix-bar .row .btn { flex: 1; min-height: var(--tap); }

/* Work panels (Tier 2, Flow 2, Nov 2, 2026): the sticky outcome bar
   on the repair and test panels, the part request sheet, its
   quantity stepper and urgency cards, and the compact temperature
   round lines on the Testing home. */
.work-bar {
  position: sticky; bottom: 8px; z-index: 30; display: flex; gap: 8px;
  background: #fff; border: 1px solid var(--line); border-radius: 12px;
  padding: 10px; margin: 10px 0; box-shadow: 0 6px 24px rgba(28, 26, 23, 0.18);
}
.work-bar .btn { flex: 1; min-height: 56px; }
.part-sheet {
  border: 1.5px solid var(--teal); border-radius: 12px; padding: 12px;
  margin-top: 10px; background: #fbfaf7;
}
.qty-stepper { display: flex; gap: 8px; align-items: stretch; }
.qty-stepper .btn { min-width: 52px; min-height: 52px; font-size: 20px; }
.qty-stepper input { text-align: center; font-size: 18px; font-weight: 700; }
.urgency-cards { display: flex; gap: 8px; }
.urgency-card {
  flex: 1; min-height: 56px; border: 1.5px solid var(--teal); border-radius: 12px;
  background: #fff; color: var(--teal-dark); font-size: 14.5px; font-weight: 700;
  padding: 10px; cursor: pointer;
}
.urgency-card.selected { background: var(--teal); color: #fff; }
.round-line { display: flex; gap: 10px; align-items: center; width: 100%; }
.round-detail { margin-top: 10px; }

/* Day planning (Oct 30, 2026): the day switcher strip in the planning
   view. A confirmed delivery day carries the teal outline; the day
   being planned is filled. Tap targets stay at least 48px. */
.day-chips { display: flex; gap: 6px; margin: 0 0 12px; overflow-x: auto; padding-bottom: 2px; }
.day-chip {
  flex: 0 0 auto; min-height: 48px; padding: 8px 12px; border-radius: 999px;
  border: 1.5px solid var(--line); background: #fff; color: var(--ink);
  font-weight: 700; font-size: 13.5px; cursor: pointer;
}
.day-chip.confirmed { border-color: var(--teal); color: var(--teal-dark); }
.day-chip.active { background: var(--teal); border-color: var(--teal); color: #fff; }
.task-card[data-kind="delivery-days"] { border-left-color: var(--lime); }

/* Accounting, Option A (Oct 31, 2026): the module home is a tile
   dashboard, one screen per kind of work behind it. Tiles reuse the
   board grid; an exception tile carries the red exception edge the
   palette reserves for exceptions. The period bar sits at the top
   of every accounting screen and stays reachable while scrolling. */
.acc-period-bar {
  position: sticky; top: 0; z-index: 5; background: var(--beige);
  padding: 6px 0 8px; margin-bottom: 6px;
}
.acc-tile {
  background: #fff; border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; text-decoration: none; color: var(--ink);
  min-height: var(--tap); display: block;
}
.acc-tile .tile-num { font-size: 22px; font-weight: 800; }
.acc-tile .tile-label { font-size: 14px; font-weight: 700; }
.acc-tile .tile-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.acc-tile.exception { border-left: 8px solid var(--st-escalated); }
.acc-doors { display: grid; gap: 10px; }
.acc-doors a {
  background: #fff; border: 1px solid var(--line); border-radius: 10px;
  padding: 14px 12px; text-decoration: none; color: var(--ink);
  font-weight: 700; min-height: var(--tap); display: flex; align-items: center;
}
.acc-manual { border-left: 8px solid var(--lime); }
.acc-locked { border-left: 8px solid var(--st-escalated); }

/* Customer signature pad (Nov 1, 2026): the customer signs on the
   driver's phone at the door. The canvas is a white box with the ink
   color; touch-action none keeps the page from scrolling while a
   finger draws. The office read-back image sits on white too. */
.sig-pad { margin: 6px 0 10px; }
.sig-canvas {
  display: block; width: 100%; height: 180px;
  background: #fff; border: 2px solid var(--ink, #1c1a17);
  border-radius: 10px; touch-action: none;
}
.sig-actions { margin-top: 6px; }
/* Photo slot pair (Nov 1, 2026): the take-a-photo button and the
   quieter choose-from-library button stacked as one slot. */
.photo-slot-pair { display: block; }

/* Tier 1 batch (Nov 2, 2026): driver presence and load rows stack
   identity over a full-width button row (Flow 1, item 3). */
.bigrow.dlv-row { flex-direction: column; align-items: stretch; }
.dlv-row-id { display: flex; gap: 12px; align-items: center; }
.dlv-row-btns { display: flex; gap: 10px; }
.dlv-row-btns .btn { flex: 1; min-height: 48px; }

/* Tier 1 (Flow 4, item 2): intake steps clear the reporter pill. */
#step-photos, #step-details { padding-bottom: 72px; }

/* Tier 1 (Flow 4, item 4): intake photo slot buttons side by side. */
#slots .photo-slot-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }

/* Intake Tier 2 (Flow 4, Nov 2, 2026): numbered slot cards on the
   photo step, a sticky Continue, and the check step's identity
   strip and read rows. */
.slot-card {
  background: #fff; border: 1px solid var(--line); border-radius: 14px;
  padding: 12px; margin-bottom: 12px;
}
.slot-card-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.slot-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--teal); color: #fff; font-weight: 700; flex: 0 0 auto;
}
.slot-name { font-weight: 700; font-size: 17px; }
.slot-card .slot-status { margin-top: 8px; }
.sticky-action {
  position: sticky; bottom: 8px; z-index: 30;
  background: #fff; border: 1px solid var(--line); border-radius: 14px;
  padding: 10px; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
}
.identity-strip { display: flex; gap: 10px; margin: 10px 0; }
.identity-strip figure { flex: 1; margin: 0; }
.identity-strip img {
  width: 100%; height: 150px; object-fit: contain; background: #f4f1ec;
  border-radius: 10px; border: 1px solid var(--line); display: block;
}
.identity-strip figcaption { font-size: 13px; color: var(--muted); margin-top: 4px; text-align: center; }
.strip-viewer { margin: 8px 0; }
.strip-viewer img { width: 100%; border-radius: 10px; border: 1px solid var(--line); display: block; }
.read-summary-head { margin: 12px 0 4px; }
.read-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  width: 100%; text-align: left; background: #fff;
  border: 1px solid var(--line); border-radius: 10px;
  padding: 12px 14px; margin: 6px 0; min-height: 56px; cursor: pointer;
}
.read-row-label { color: var(--muted); font-size: 14px; flex: 0 0 auto; }
.read-row-value { font-size: 19px; font-weight: 700; text-align: right; overflow-wrap: anywhere; }

/* Tier 1 (Flow 6, item 1): customer view chips on one scrollable rail. */
#cust-chips { flex-wrap: nowrap; overflow-x: auto; }
#cust-chips .chip { flex: 0 0 auto; }

/* Tier 1 (Flow 6, item 4): the customers search row sticks. */
.cust-search-sticky { position: sticky; top: 0; background: var(--beige); z-index: 6; padding: 4px 0 6px; }

/* Tier 1 (Flow 6, item 5): slim empty profile cards. */
.slim-card { display: flex; align-items: baseline; gap: 10px; padding: 10px 14px; }
.slim-card h3 { margin: 0; }

/* Tier 1 (Flow 3, item 1): Board floor task cards stack, with
   Mark done on its own full-width row. */
.bigrow.ft-row { flex-direction: column; align-items: stretch; }
.ft-row-main { display: flex; gap: 12px; align-items: center; }
.ft-row .btn { min-height: 48px; }

/* Tier 2 (Flow 3): the staff Board tail sits behind its own door
   line. The summary is a full-width tappable row; the content
   under it is the unchanged form or list. */
.board-tail { margin: 12px 0; }
.board-tail-summary {
  cursor: pointer; font-weight: 700; font-size: 17px;
  padding: 12px 2px; min-height: 48px;
}
.photo-slot-pair .photo-library { border-style: dashed; }
.sig-img {
  max-width: 260px; max-height: 110px; margin-top: 4px;
  background: #fff; border: 1px solid #ccc; border-radius: 6px;
}
/* Pricing queue rows (Nov 1, 2026 simplification): the linked identity
   block keeps the shared bigrow look; a manager's in-place price form
   sits directly under it inside the same row wrapper. Grep-checked:
   no earlier pricing-queue classes existed in this stylesheet. */
.pricing-queue-row { margin-bottom: 10px; }
.pricing-queue-row .bigrow { margin-bottom: 0; }
.pricing-queue-controls {
  background: #fff; border: 1px solid var(--line); border-top: 0;
  border-radius: 0 0 10px 10px; padding: 4px 12px 12px;
}

/* Pricing Tier 2 (Flow 5, Nov 2, 2026): summary strip, sticky
   queue header, one-card queue rows, reference strip. */
.summary-strip .strip-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  width: 100%; text-align: left; background: transparent; border: 0;
  border-top: 1px solid var(--line); padding: 10px 2px; min-height: 48px;
  font: inherit; font-weight: 600; color: inherit; cursor: pointer;
  text-decoration: none;
}
.queue-sticky {
  position: sticky; top: 0; z-index: 20;
  background: var(--beige); padding: 8px 0 6px;
}
.queue-sticky h2 { margin: 0; }
.queue-card .pricing-queue-controls {
  background: transparent; border: 0; border-radius: 0;
  padding: 0; margin-top: 8px;
}
.queue-facts {
  display: flex; justify-content: space-between; align-items: center;
  gap: 10px; margin-top: 8px; color: var(--muted); font-size: 14px;
}
.ref-strip {
  border-top: 1px dashed var(--line); margin-top: 10px; padding-top: 8px;
}
.batch-pick {
  display: flex; align-items: center; gap: 10px;
  min-height: 48px; font-weight: 600; cursor: pointer;
}
.batch-pick input { width: 24px; height: 24px; flex: 0 0 auto; }
.batch-bar { margin-top: 12px; }
.suggest-line { margin-top: 8px; }
.pricing-queue-controls .field { margin-top: 6px; }
.pricing-queue-controls input { flex: 1; min-width: 0; }

/* Intake slot preview (Nov 1, 2026): the picked picture itself,
   shown under its capture buttons so the person adding a unit can
   see that the photo took. Best effort only: a format this browser
   cannot decode stays hidden and the status line reports instead. */
.slot-preview {
  display: block;
  width: 100%;
  max-height: 340px;
  object-fit: contain;
  background: #f4f1ec;
  border-radius: 10px;
  margin-top: 8px;
}
.slot-preview.hidden { display: none; }

/* Bottom clearance for the reporter pill (sweep fix, Nov 1, 2026;
   made GLOBAL the same night after live verification of .34 caught
   the Pricing home's "Open promotions" door under the pill): the
   fixed "Request a modification" pill rides in a band just above
   the bottom nav, exactly where a screen's last action lands at
   full scroll; a thumb tap on that action's centre hit the pill
   instead. The clearance therefore lives in the shell, once: #view
   ends with an in-flow pseudo-element spacer on EVERY screen, so
   the last element of any screen can always scroll fully clear of
   the pill's band and no screen can forget it. A pseudo-element is
   a real layout box, so it counts toward the scrollable overflow
   in every engine (the scroll container's own bottom padding does
   not reliably), and it is not a DOM node, so no module's child
   queries can see it or trip over it. The height clears the pill's
   worst-case intrusion: the pill is 40px tall sitting on the nav's
   top edge, and on a notched phone its safe-area offset lifts it
   about 62px into the view; 76px clears both with room to spare,
   and the view's own 24px bottom padding stacks on top wherever
   the engine honours it. Intake's per-screen .pill-clear spacer,
   the first version of this fix, is removed as redundant: the
   shell spacer now gives intake the same clearance it had. */
.view::after { content: ""; display: block; height: 76px; }

/* Scroll margin for buttons (sweep fix, Nov 1, 2026, companion to
   the shell spacer above): scrollIntoView parks a button at the
   scroll port's bottom edge, inside the reporter pill's band, no
   matter how much clearance follows it in the content. A bottom
   scroll margin makes every programmatic scroll stop this far
   early, so a save button's centre lands above the band; the
   .view::after spacer covers the human max-scroll case. */
.view .btn { scroll-margin-bottom: 124px; }

/* Sale form 3-step layout (rebuild, Nov 2, 2026): the step strip,
   the sticky bill bar, the fulfilment and money toggle cards, the
   day and method chips, and the removal stepper. All classes are
   sal3- prefixed; nothing here touches another module's rules.
   The bill bar sticks to the bottom of the #view scroll container
   like .stopbar does, so it rides above the bottom nav. */
.sal3-steps { display: flex; gap: 6px; margin: 10px 0 4px; }
.sal3-stepbtn {
  flex: 1; min-height: var(--tap); border-radius: 10px; cursor: pointer;
  border: 1.5px solid var(--line); background: #fff; color: var(--muted);
  font-size: 14px; font-weight: 700; padding: 8px 4px;
}
.sal3-stepbtn .sal3-stepnum {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 999px; margin-right: 4px;
  border: 1.5px solid currentColor; font-size: 13px;
}
.sal3-stepbtn.active { border-color: var(--teal); color: var(--teal-dark); background: var(--beige); }
.sal3-stepbtn.done { color: var(--teal-dark); }
.sal3-stepbtn:disabled { opacity: 0.45; cursor: default; }
/* The bill bar sits in the normal flow right after the step
   panels (the hidden panels take no space, so it lands at the
   end of whichever step is showing). It was sticky until
   Nov 6, 2026: on Christian's phone the sticky bar floated over
   the form fields mid-scroll and ghosted into two Continue
   labels over the sale source field. In flow it can never
   cover a field. */
.sal3-billbar {
  display: flex; align-items: center; gap: 10px;
  background: var(--beige); border-top: 1px solid var(--line);
  padding: 10px 2px; margin-top: 12px;
}
.sal3-billbar .grow { flex: 1; font-weight: 700; overflow-wrap: anywhere; }
.sal3-billbar .btn { flex: 0 0 auto; }
.sal3-toggle { display: flex; gap: 8px; margin: 8px 0; }
.sal3-tcard {
  flex: 1; min-height: 56px; border-radius: 12px; cursor: pointer;
  border: 1.5px solid var(--line); background: #fff; color: var(--ink);
  font-size: 16px; font-weight: 700; padding: 10px 6px;
}
.sal3-tcard.active { border-color: var(--teal); background: var(--teal); color: #fff; }
/* Dropdown bars (sell corrections, Nov 9, 2026): one slim bar,
   thumb sized, with the big chevron in its soft circle; the
   chevron turns when the bar is open. */
.sal-bigbar {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 56px; padding: 8px 10px 8px 14px; margin-top: 12px;
  background: #fff; border: 1.5px solid var(--line); border-radius: 14px;
  color: var(--ink); font-size: 16px; font-weight: 700; cursor: pointer;
  text-align: left;
}
.sal-bigbar .grow { flex: 1; }
.chev-circle {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 50%;
  background: #e7f2f3; display: flex; align-items: center; justify-content: center;
}
.chev {
  display: block; width: 13px; height: 13px;
  border-right: 2.5px solid var(--teal); border-bottom: 2.5px solid var(--teal);
  transform: rotate(45deg); transition: transform 0.15s ease;
}
.chev.right { transform: rotate(-45deg); }
.sal-bigbar[aria-expanded="true"] .chev { transform: rotate(225deg); }
/* The quiet by-hand row under a failed distance lookup. */
.sal-manual-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 48px; padding: 6px 6px 6px 14px; margin-top: 8px;
  background: #fff; border: 1.5px solid var(--line); border-radius: 12px;
  color: var(--ink); font-size: 15px; font-weight: 600; cursor: pointer;
  text-align: left;
}
.sal-manual-row .grow { flex: 1; }

.sal3-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0; }
.sal3-chips .chip.active { background: var(--teal); color: #fff; }
.sal3-stepper { display: flex; align-items: center; gap: 8px; }
.sal3-stepper input { flex: 1; text-align: center; }
.sal3-stepper .btn { flex: 0 0 56px; }

/* Board decision tap-through landing (Nov 2, 2026): the People
   requests card flashes once when the approver arrives from the
   Board, so the eye lands on the decision itself. */
.decision-flash { animation: decision-flash-pulse 1.2s ease-in-out 2; }
@keyframes decision-flash-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(13, 94, 104, 0); }
  50% { box-shadow: 0 0 0 3px rgba(13, 94, 104, 0.55); }
}

/* Flag strips (Nov 2, 2026): a flagged field's check line and its
   actions sit directly under the field's own row, never in a box
   at the top of the step the employee has to scroll back to. */
.flag-strip { margin: 6px 0 10px; border-left: 4px solid var(--st-in_repair); padding-left: 10px; font-size: 14px; }
.flag-strip > div + div { margin-top: 6px; }
.flag-strip.resolved { border-left-color: var(--teal); color: var(--muted); }

/* Mayssa's Home (visual pass, Nov 5, 2026): the kind bands
   and status chips. Bands follow the app's colour language:
   visits keep the violet visit band, draft claims take the
   amber, customer replies the blue the Board's requests use,
   and exception rows take the Needs attention treatment
   (escalated red band on the pale red ground, the same
   pairing as the exceptions strip). Stat tiles reuse the
   Board's stage-card; money tiles take the teal band. */
.home-band-draft { border-left: 8px solid var(--st-in_repair) !important; }
.home-band-reply { border-left: 8px solid #2563eb !important; }
.home-band-alert { border-left: 8px solid var(--st-escalated) !important; background: #fdf2f2; }
.home-stat-money { border-left-color: var(--teal); }
.home-stat-span { grid-column: span 2; }

/* At a glance bars (hybrid, Nov 5, 2026): week and month
   money fill toward their sales goal when one is set, and
   against each other when none is; conversion fills its
   own fraction in the requests blue. Units and average
   price sit under the bars as mini figures. */
.home-bar-row { margin-top: 10px; }
.home-bar-row:first-child { margin-top: 0; }
.home-bar { height: 10px; background: var(--line); border-radius: 999px; overflow: hidden; margin-top: 4px; }
.home-bar > i { display: block; height: 100%; background: var(--teal); border-radius: 999px; }
.home-bar.home-bar-blue > i { background: #2563eb; }
.home-mini-num { font-size: 20px; font-weight: 800; }

/* The no-goal call to action inside the At a glance card:
   amber, plain, and gone the moment the goal is set. */
.home-nogoal { color: var(--st-in_repair); font-weight: 700; font-size: 13.5px; margin-top: 4px; }

/* Christian's Home Board tiles and the Decisions queue
   (Nov 5, 2026, decisions of record): the Board on Home is the
   stage-card shape compressed into four columns by two rows;
   the queue rows are calm: a small colour square on the group
   title and a thin colour edge on each row, both in the
   Board's own stage colours, counts and ages as plain text. */
.chome-board-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.chome-tile { border-left-width: 4px; padding: 6px 7px; min-height: 0;
  display: flex; flex-direction: column; gap: 1px; }
.chome-tile .count { font-size: 17px; }
.chome-tile .label { font-size: 11px; line-height: 1.25; }
.chome-tile .age { font-size: 10px; }
.dec-group { margin-top: 18px; }
.dec-group-title { display: flex; align-items: baseline; gap: 8px; font-size: 16px; }
.dec-square { width: 10px; height: 10px; border-radius: 2px;
  background: var(--dec-color); align-self: center; flex: none; }
.dec-oldest { font-size: 12px; font-weight: 400; color: var(--muted); }
.dec-row { display: flex; align-items: center; gap: 10px; margin-top: 6px;
  background: #fff; border: 1px solid var(--line);
  border-left: 3px solid var(--dec-color); border-radius: 8px;
  padding: 8px 10px; text-decoration: none; color: var(--ink); }
.dec-photo { width: 44px; height: 44px; object-fit: cover; border-radius: 6px; flex: none; }
.dec-title { display: block; font-weight: 600; }
.dec-meta { display: block; font-size: 12px; color: var(--muted); }
.dec-age { font-size: 12px; color: var(--muted); white-space: nowrap; }

/* Christian's Home, mockup fidelity (Nov 5, 2026 correction
   round): small grey section headings, the pale amber
   decisions alert, the Today summary rows, the Team plan
   people rows with initial avatars and its calendar control. */
.chome-h { font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 6px; }
.chome-alert { background: #fdf3e0; border-color: #f0dfba; }
.chome-alert-title { font-size: 17px; font-weight: 800; color: #8a5a00; }
.chome-summary .chome-sum-row { display: flex; justify-content: space-between;
  align-items: baseline; gap: 10px; padding: 7px 0; }
.chome-summary .chome-sum-row + .chome-sum-row { border-top: 1px solid var(--line); }
.chome-cal { display: flex; gap: 8px; align-items: center; }
.chome-cal input[type="date"] { flex: 1; min-height: 38px; }
.chome-person-row { display: flex; align-items: center; gap: 10px;
  padding: 9px 0; color: inherit; text-decoration: none; }
.chome-person-row + .chome-person-row { border-top: 1px solid var(--line); }
.chome-person-row .grow { flex: 1; }
.chome-avatar { width: 32px; height: 32px; border-radius: 50%; flex: none;
  background: var(--teal); color: #fff; font-size: 12px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; }
.chome-planner-link { display: block; margin-top: 8px; padding-top: 9px;
  border-top: 1px solid var(--line); color: var(--teal); font-weight: 600;
  text-decoration: none; }

/* Loading presentation standard (Nov 6, 2026): while a screen
   holds, each slotted section's box is its skeleton (muted bars
   in the layout's own shells), and the section itself is
   height-0 and invisible so progressive paints move nothing
   anyone can see. At the reveal the wrapper becomes
   display:contents, which removes it from the layout entirely:
   the settled screen is byte-for-byte the layout it always
   was. The pulse is slow and shallow, a calm state, not a
   spinner; reduced-motion turns it off. */
.rv-skel { display: none; }
.rv-hold .rv-skel { display: block; animation: skpulse 1.8s ease-in-out infinite alternate; }
.rv-hold .rv-wrap > :not(.rv-skel) { visibility: hidden; height: 0; overflow: hidden; margin-top: 0; margin-bottom: 0; }
.rv-done .rv-skel { display: none; }
/* A section still unpainted at the reveal keeps its skeleton
   and stays held (Nov 6, 2026): the reveal unwraps painted
   sections outright, so a wrapped section under rv-done is
   exactly a pending one. */
.rv-wrap.rv-pending > :not(.rv-skel) { visibility: hidden; height: 0; overflow: hidden; margin-top: 0; margin-bottom: 0; }
.rv-done .rv-wrap.rv-pending .rv-skel { display: block; animation: skpulse 1.8s ease-in-out infinite alternate; }
@keyframes skpulse { from { opacity: 0.6; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .rv-hold .rv-skel { animation: none; }
  .rv-done .rv-wrap.rv-pending .rv-skel { animation: none; }
}
.sk-card { background: #fff; border: 1px solid var(--line); border-radius: 14px; padding: 14px; }
.rv-skel .sk-card + .sk-card, .skel-stack .sk-card + .sk-card { margin-top: 10px; }
.sk-line { height: 12px; border-radius: 6px; background: #e8e2d4; margin: 9px 0; }
.sk-line:first-child { margin-top: 2px; }
.sk-line:last-child { margin-bottom: 2px; }
.sk-heading { width: 38%; height: 14px; margin: 4px 0 10px; }
.sk-bare { padding: 4px 2px; }
.sk-tile { height: 74px; border-radius: 12px; background: #efe9db; border: 1px solid var(--line); }
.sk-alert { height: 52px; border-radius: 12px; background: #f6efdd; border: 1px solid var(--line); }
