/* ==========================================================================
   crews.css — unified dark theme (black + orange)
   Applies to BOTH Job Board and Job Detail pages.
   ========================================================================== */

:root{
  --bg: #0b0b0c;            /* page background (near-black) */
  --surface: #141518;       /* cards/panels */
  --surface-2: #1a1c20;     /* slightly lighter surface */
  --border: #23252b;        /* subtle borders */
  --muted: #9aa3ae;         /* secondary text */
  --text: #e9edf1;          /* primary text */
  --accent: var(--brand-primary,#ff7a00);        /* orange */
  --accent-2: var(--brand-primary-hover,#ffa24a);      /* hover/soft orange */
  --shadow: rgba(0,0,0,.35);

  /* Role badge colors (kept as requested) */
  --role-super: var(--brand-primary,#ff7a00);    /* orange */
  --role-gf: #ffd54a;       /* yellow */
  --role-foreman: #ff5c5c;  /* strong red (consolidated effective) */
  --role-journeyman: #6c8cff; /* indigo-ish (consistent with blue family) */
  --role-lv: #8ecbff;       /* light blue */
  --role-apprentice: #4caf50;/* green */
  --role-qaqc: #d500f9;     /* magenta */
  --role-operator: #c19a6b; /* light brown */
  --role-safety: #dc2626;   /* red */
  --role-estimator: #1b5e20;          /* dark green */
  --role-project_controls_manager: #5d3a1a; /* dark brown */
  --role-project_coordinator: #00bcd4; /* cyan */
  --role-admin: #ec4899;              /* pink */
}

/* Base ---------------------------------------------------- */
* { box-sizing: border-box; }
html, body { height: 100%; }
/* No sideways drift, ever: stray fixed widgets or wide rows must not widen
   the mobile layout viewport (which also skews fixed-position elements). */
html, body { overflow-x: hidden; overflow-x: clip; }
body{
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-2); }

h1,h2,h3,h4,h5,h6 { color: var(--text); }
.text-muted, .muted, small, .form-text { color: var(--muted) !important; }

/* Cards / containers -------------------------------------- */
.card,
.job-card,
.list-card{
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 6px 20px var(--shadow);
}

.card .card-header{
  background: var(--surface-2);
  color: var(--text);
  border-bottom: 1px solid var(--border);
}
.card .card-header strong,
.card .card-header h1, .card .card-header h2,
.card .card-header h3, .card .card-header h4,
.card .card-header h5, .card .card-header h6 { color: var(--text); }

/* Buttons ------------------------------------------------- */
.btn,
button{
  color: var(--text);
}

.btn-primary{
  background: var(--accent);
  border-color: var(--accent);
  color: #101214;
}
.btn-primary:hover,
.btn-primary:focus{
  background: var(--accent-2);
  border-color: var(--accent-2);
  color: #0b0b0c;
}

.btn-outline-secondary{
  color: var(--accent);
  border-color: var(--accent);
  background: transparent;
}
.btn-outline-secondary:hover{
  color: #0b0b0c;
  background: var(--accent);
  border-color: var(--accent);
}

.btn-outline-danger{
  color: #ff6b6b;
  border-color: #ff6b6b;
  background: transparent;
}
.btn-outline-danger:hover{
  color: #0b0b0c;
  background: #ff6b6b;
  border-color: #ff6b6b;
}

/* Forms --------------------------------------------------- */
.form-control,
.form-select{
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
}
.form-control::placeholder{ color: #8b939c; }
.form-control:focus,
.form-select:focus{
  border-color: var(--accent);
  box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--brand-primary,#ff7a00) 15%, transparent);
}

/* Badges / counters -------------------------------------- */
.badge{
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
}
.badge.bg-secondary{
  background: var(--surface-2) !important;
  border-color: var(--border);
  color: var(--text) !important;
}
.count b,
.badge b{
  color: var(--accent);
  font-weight: 700;
}

/* Navbar (minimal tweaks only) ---------------------------- */
.navbar,
.navbar-dark{
  background: #111214 !important;
  border-bottom: 1px solid var(--accent); /* CHANGED: make divider orange */
}
.navbar .nav-link{ color: var(--text) !important; }
.navbar .nav-link:hover{ color: var(--accent) !important; }

/* brand to orange */
.navbar .navbar-brand,
.navbar-dark .navbar-brand{
  color: var(--accent) !important;   /* NEW */
}
.navbar .navbar-brand:hover,
.navbar-dark .navbar-brand:hover{
  color: var(--accent-2) !important; /* NEW */
}

/* make specifically the Logout link orange (keeps other links as-is) */
.navbar a.nav-link[href$="logout/"],
.navbar a.nav-link[href*="/logout"]{
  color: var(--accent) !important;   /* NEW */
}
.navbar a.nav-link[href$="logout/"]:hover,
.navbar a.nav-link[href*="/logout"]:hover{
  color: var(--accent-2) !important; /* NEW */
}

/* Logout: round brand-orange icon button (all screen sizes) */
.nav-logout {
  display: inline-flex !important; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border: 1px solid var(--accent); border-radius: 50%;
  padding: 0 !important;
  transition: background .12s ease, transform .08s ease;
}
.nav-logout:hover { background: var(--accent); transform: translateY(-1px); }
.nav-logout:hover .logout-ic { color: #0b0b0c; }

/* =========================================================
   JOB BOARD
   ========================================================= */
.job-grid{
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 12px;
}

.job-card{
  display: block;
  padding: 14px 14px 12px;
  transition: transform .12s ease, border-color .12s ease, box-shadow .12s ease;
}
.job-card:hover{
  transform: translateY(-2px);
  border-color: var(--accent);
  box-shadow: 0 10px 28px var(--shadow);
}
.job-card-title{
  font-weight: 600;
  font-size: 1.05rem;
  margin-bottom: 4px;
  color: var(--text);
}
.job-card-address{
  color: var(--muted);
  font-size: .9rem;
  margin-bottom: 8px;
}
.job-card-stats{
  display: flex;
  flex-wrap: wrap;
  gap: 10px 14px;
  font-size: .88rem;
  color: #cfd6dd;
}
.job-card-stats span b{ color: var(--accent); }

/* =========================================================
   JOB BOARD — polished card (v2)
   ========================================================= */
.jc-section{
  display: flex; align-items: center; gap: 10px;
  margin: 26px 0 12px;
}
.jc-section-label{
  text-transform: uppercase; letter-spacing: .18em;
  font-weight: 800; font-size: .8rem; color: var(--text);
}
.jc-section-count{
  font-size: .72rem; font-weight: 700; color: var(--muted);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 999px; padding: 1px 9px;
}
.jc-section-rule{ flex: 1; height: 1px; background: var(--border); }

.job-card--v2{
  padding: 0;
  overflow: hidden;
  border-left: 4px solid var(--accent);
}
.job-card--v2 .jc-body{
  display: flex; flex-direction: column; gap: 12px;
  height: 100%;
  padding: 16px 18px 14px;
}

/* Header: title/address/union on the left, hero headcount on the right */
.jc-head{ display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.jc-head-main{ min-width: 0; flex: 1 1 auto; }   /* long names wrap, hero stays put */
.jc-title{
  font-size: 1.15rem; font-weight: 700; color: var(--text);
  line-height: 1.2;
}
.jc-address{
  display: flex; gap: 6px; align-items: flex-start;
  color: var(--muted); font-size: .86rem; margin-top: 5px;
}
.jc-pin{
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); margin-top: 6px; flex: 0 0 auto;
}
.jc-union{ font-size: .8rem; color: var(--muted); margin-top: 5px; }
.jc-union strong{ color: var(--text); font-weight: 700; }

.jc-hero{ text-align: right; flex: 0 0 auto; }
.jc-hero-num{ font-size: 2rem; font-weight: 800; color: var(--accent); line-height: 1; }
.jc-hero-label{
  font-size: .6rem; font-weight: 700; letter-spacing: .12em;
  color: var(--muted); margin-top: 3px;
}

/* Crew composition bar + legend (colors reuse the .role-<position> classes) */
.jc-bar{
  display: flex; width: 100%; height: 8px;
  border-radius: 999px; overflow: hidden; background: #23262c;
}
.jc-seg{ height: 100%; }
.jc-legend{
  display: flex; flex-wrap: nowrap; justify-content: space-between;
  gap: 6px; font-size: .72rem; color: var(--text);
}
.jc-leg{ display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
.jc-dot{ width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }

/* Per-shift field breakdown, under the composition bar. A row of small pills:
   S1 / S2 / S3 (and "No shift" when some field crew is unassigned). */
.jc-shiftrow{ display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 2px; }
.jc-shift{
  display: inline-flex; align-items: center; gap: 5px; font-size: .68rem;
  line-height: 1; padding: 3px 8px; border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--border));
  color: var(--text);
}
.jc-shift-tag{ font-weight: 700; letter-spacing: .02em; color: var(--muted); }
.jc-shift-n{ font-weight: 800; }
.jc-shift-2{ background: color-mix(in srgb, #3aa0f0 9%, transparent);
  border-color: color-mix(in srgb, #3aa0f0 30%, var(--border)); }
.jc-shift-3{ background: color-mix(in srgb, #9b7cff 9%, transparent);
  border-color: color-mix(in srgb, #9b7cff 30%, var(--border)); }
.jc-shift-0{ background: transparent; border-style: dashed; }

/* Job board: a touch wider than the stock container so the 4-metric
   footer isn't smooshed, but well short of full-bleed — the cards keep
   side breathing room and a sane width. Doubled selector: this must
   outrank crews_consolidated.css's later ".container-fluid{max-width:98vw}",
   which otherwise re-stretches the board on wide monitors. */
.container-fluid.jobs-board-wrap,
.jobs-board-wrap{ padding-left: 2.5rem; padding-right: 2.5rem; max-width: 1520px; margin: 0 auto; }
@media (max-width: 768px){ .jobs-board-wrap{ padding-left: 1rem; padding-right: 1rem; } }

/* Footer metrics: Field | Office | Safety | Trucks. Each column takes
   only the room its number/label needs (centered as a group) rather
   than stretching to fill the card. */
.jc-foot{
  margin-top: auto; display: flex; justify-content: center;
  border-top: 1px solid var(--border); padding-top: 10px;
}
.jc-metric{ flex: 0 1 auto; text-align: center; position: relative; padding: 0 16px; min-width: 70px; }
.jc-metric + .jc-metric::before{
  content: ""; position: absolute; left: 0; top: 50%;
  transform: translateY(-50%); height: 62%; width: 1px; background: var(--border);
}
.jc-metric-num{ display: block; font-size: 1.25rem; font-weight: 800; color: var(--text); }
.jc-metric-num--accent{ color: var(--accent); }
.jc-metric-label{
  display: block; font-size: .62rem; font-weight: 700; letter-spacing: .1em;
  color: var(--muted); margin-top: 2px;
}


/* “Create Job” button on board sits nicely */
.create-job-wrap{
  display:flex; align-items:center; justify-content:flex-end; gap:8px;
}

/* =========================================================
   JOB DETAIL (Crews page)
   ========================================================= */
.list-title{ color: var(--text); }
.people-list{
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 36px;
}

.empty-hint{
  color: var(--muted);
  font-style: italic;
}

.person{
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 10px;
  cursor: grab;
  transition: border-color .12s ease, transform .08s ease;
}
.person:active{ cursor: grabbing; }
.person:hover{ border-color: var(--accent); }

.person .person-top{
  display:flex; align-items:center;
  gap: 5px;
}
.person .name{ color: var(--text); font-weight: 600; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.person .person-bottom{
  margin-top: 4px; display:flex; gap:10px; flex-wrap:wrap; align-items:center;
  color: #cfd6dd;
}
.person .phone{ color: #dfe6ee; opacity: .9; }
.person .truck{ color: var(--accent); }

/* "Absent today" — a persistent, display-only marker for a field employee who
   was checked off as not present on today's roll-call. The card is grayed out
   with a struck-through name and an "Absent" tag. It is purely visual: the
   person is still counted in the field totals and the forecast, and the card is
   still draggable. Cleared automatically when tomorrow's board loads (or when
   attendance is re-taken). */
.person.absent-today{
  position: relative;
  border-style: dashed;
  border-color: var(--muted, #6c757d);
  background: #17191d;
}
.person.absent-today .person-top,
.person.absent-today .person-bottom{ filter: grayscale(1); opacity: .5; }
.person.absent-today .name{ text-decoration: line-through; text-decoration-thickness: 1px; }
.person .absent-flag{
  position: absolute; top: -8px; right: -6px; z-index: 5;
  background: #6c757d; color: #fff; font-size: 10px; font-weight: 700;
  letter-spacing: .03em; text-transform: uppercase;
  padding: 1px 7px; border-radius: 9px; white-space: nowrap;
  box-shadow: 0 1px 3px rgba(0,0,0,.45);
}

/* "On vacation" — a scheduled-time-off marker for a field employee whose
   vacation range covers today. Same display-only rules as the absent marker
   (still counted everywhere); a blue plane tag distinguishes it from absence. */
.person.on-vacation{
  position: relative;
  border-style: dashed;
  border-color: #4c8bf5;
  background: #161b24;
}
.person.on-vacation .person-top,
.person.on-vacation .person-bottom{ opacity: .6; }
.person .vacation-flag{
  position: absolute; top: -8px; right: -6px; z-index: 5;
  background: #4c8bf5; color: #fff; font-size: 10px; font-weight: 700;
  letter-spacing: .03em; text-transform: uppercase;
  padding: 1px 7px 1px 5px; border-radius: 9px; white-space: nowrap;
  box-shadow: 0 1px 3px rgba(0,0,0,.45);
}
/* If someone is both absent and on vacation today, show the vacation tag on the
   left so both are visible. */
.person.absent-today.on-vacation .vacation-flag{ right: auto; left: -6px; }

/* Vacation calendar (job-board Vacation tab) */
.vac-cal{ border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.vac-cal-head{ display: grid; grid-template-columns: repeat(7, 1fr); background: #1a1c20; }
.vac-cal-hcell{ padding: 6px 8px; font-size: .72rem; font-weight: 700; color: var(--muted);
  text-align: center; text-transform: uppercase; letter-spacing: .04em; }
.vac-cal-row{ display: grid; grid-template-columns: repeat(7, 1fr); }
.vac-cal-cell{ min-height: 82px; border-top: 1px solid var(--border); border-left: 1px solid var(--border);
  padding: 4px; display: flex; flex-direction: column; gap: 3px; overflow: hidden; }
.vac-cal-cell:nth-child(7n+1){ border-left: none; }
.vac-out{ background: #131417; }
.vac-out .vac-cal-date{ color: #464b53; }
.vac-today{ background: rgba(76,139,245,.10); }
.vac-today .vac-cal-date{ color: var(--accent); font-weight: 800; }
.vac-cal-date{ font-size: .8rem; color: var(--text); font-weight: 600; }
.vac-chip{ display: block; font-size: .7rem; color: #fff; border-radius: 5px;
  padding: 1px 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Position code shown inside the colored bar so the role is readable regardless
   of the (per-person) chip color. */
.vac-chip-role{ font-weight: 800; letter-spacing: .02em;
  padding: 0 3px; margin-right: 1px; border-radius: 3px;
  background: rgba(0,0,0,.28); }
.vac-swatch{ display: inline-block; width: 12px; height: 12px; border-radius: 3px; vertical-align: middle; }
.vac-summary td, .vac-summary th{ vertical-align: middle; }
@media (max-width: 640px){
  .vac-cal-cell{ min-height: 60px; }
  .vac-chip{ font-size: .62rem; padding: 1px 4px; }
}

/* Role badges — keep the specified colors */
.role-badge{
  padding: 2px 8px;
  font-size: .75rem;
  font-weight: 700;
  border-radius: 999px;
  color: #0b0b0c;
}
.role-superintendent{ background: var(--role-super); }
.role-gf{ background: var(--role-gf); color: #121212; }
.role-foreman{ background: var(--role-foreman); }
.role-journeyman{ background: var(--role-journeyman); }
.role-lv_tech{ background: var(--role-lv); color: #102030; }
.role-apprentice{ background: var(--role-apprentice); }
.role-project_manager{ background: var(--role-project_manager, #805ad5); color: #f2eaff; }
.role-qaqc{ background: var(--role-qaqc); color: #000; }
.role-operator{ background: var(--role-operator); color: #1a1208; }
.role-safety{ background: var(--role-safety); color: #fff; }
.role-estimator{ background: var(--role-estimator); color: #fff; }
.role-project_controls_manager{ background: var(--role-project_controls_manager); color: #fff; }
.role-project_coordinator{ background: var(--role-project_coordinator); color: #001218; }
.role-admin{ background: var(--role-admin); color: #fff; }

/* Senior crown — shown next to the role badge for top PM / Super on a project */
.senior-crown{
  display: inline-block;
  margin-left: 4px;
  font-size: .95rem;
  line-height: 1;
  vertical-align: middle;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,.6));
}

/* ============================================================
   Dynamic count strip — plain text "S: 5 · GF: 2 · F: 3 · 🚚 2"
   followed by an accent-bordered "Total N" chip. When a crew card
   has multiple shift zones, a second .count-shifts line shows
   "Shift 1: N · Shift 2: N · Shift 3: N" beneath.
   ============================================================ */
.dynamic-counts,
.job-card-stats,
#job-totals {
  font-size: .82rem;
  color: var(--text);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}
.dynamic-counts .count-breakdown,
#job-totals .count-breakdown {
  color: var(--muted);
  white-space: normal;
}
.dynamic-counts .count-chips,
#job-totals .count-chips,
.job-card-stats .count-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: 4px;
}
/* Per-shift Field/Trailer/Total rows on crew cards: one line per shift,
   each led by its "Shift N" pill. */
.dynamic-counts .count-shifts {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
}
.dynamic-counts .count-shift-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
}
/* Field / Trailer chips — orange accent pills so the subtotals stand out
   from the muted count breakdown text (which stays as-is). */
.count--field,
.count--trailer {
  display: inline-block;
  padding: 1px 10px;
  border-radius: 999px;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-weight: 700;
  white-space: nowrap;
}
/* Named non-field positions in a crew (Safety, PM, …): boots on the ground,
   counted by name so they never inflate the Field number. Neutral pill so
   the orange Field chip stays the headline. */
.count--pos {
  display: inline-block;
  padding: 1px 10px;
  border-radius: 999px;
  border: 1px solid #5c6470;
  color: #cfd6df;
  font-weight: 700;
  white-space: nowrap;
}
/* Job Totals on the job detail page — Field pill + per-position color-dot
   key (office staff included). No composition bar: the dots are the
   breakdown. */
#job-totals { flex: 1 1 320px; min-width: 280px; }
.jt-legend {
  flex-wrap: wrap; justify-content: flex-start;
  align-items: center; gap: 3px 12px;
}
/* Total pill on Job Totals — full headcount, field + non-field, white. */
.count--total {
  display: inline-block;
  padding: 1px 10px;
  border-radius: 999px;
  border: 1px solid #e8eaee;
  color: #f3f5f7;
  font-weight: 700;
  white-space: nowrap;
}
/* Project GC pill on crew cards — Field-chip format, always white. */
.count--gc {
  display: inline-block;
  padding: 0 8px;
  border-radius: 999px;
  border: 1px solid #e8eaee;
  color: #f3f5f7;
  font-size: .72rem;
  font-weight: 700;
  white-space: nowrap;
}
/* Crew card titles: a touch bigger than the stock h5. */
.list-card .list-title { font-size: 1.4rem; }

/* Side rails (Management/Office + Unassigned bench): sit beside the crew
   grid; collapse to a slim vertical tab so the crew columns get the width
   back. The two rails share one mechanic. */
.crew-board-flex { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; width: 100%; }
/* The crew grid needs room for at least one full crew card (its shift lanes at
   ~200px each). If the rails leave it less than that — e.g. on a narrower window
   or a browser zoom — it WRAPS onto its own full-width row below the rails
   instead of squishing the cards. --crew-cols is the job's shift-lane count. */
.crew-board-flex > .board-grid {
  flex: 1 1 0;                        /* grow from 0 to fill the space beside the
                                        rails; don't let content force a wrap */
  min-width: min(100%, calc(var(--crew-cols, 2) * 240px + 44px));
}
.unassigned-rail, .mgmt-rail {
  flex: 0 0 330px; min-width: 0; position: relative; overflow: hidden;
  transition: flex-basis .28s ease;
}
.unassigned-rail .list-card, .mgmt-rail > .card { transition: opacity .18s ease; min-width: 300px; }
.unassigned-rail.collapsed, .mgmt-rail.collapsed { flex-basis: 36px; }
.unassigned-rail.collapsed .list-card, .mgmt-rail.collapsed > .card { opacity: 0; visibility: hidden; }
/* Collapsed bar: one smooth continuous strip, full column height, with the
   label in upright (unrotated) letters reading downward. */
.bench-tab {
  position: absolute; inset: 0;
  display: flex; align-items: flex-start; justify-content: center;
  padding: 14px 0; border: 1px solid var(--border, #2d2d32);
  border-radius: 10px; background: #15171b; color: #f3f5f7;
  cursor: pointer; opacity: 0; pointer-events: none;
  transition: opacity .18s ease .12s, border-color .12s ease;
}
.unassigned-rail.collapsed .bench-tab, .mgmt-rail.collapsed .bench-tab { opacity: 1; pointer-events: auto; }
.bench-tab:hover { border-color: var(--accent, #ff7a00); }
.bench-tab-text {
  writing-mode: vertical-rl;   /* rotated 90° — letters read sideways */
  font-size: .82rem; font-weight: 700; letter-spacing: .08em;
  white-space: nowrap; user-select: none;
}
@media (max-width: 900px) {
  .crew-board-flex { flex-direction: column; }
  /* Stacked layout: the rails are normal blocks; flex-basis would become
     HEIGHT here, so neutralize it (incl. the collapsed 36px) or a
     collapsed rail leaves a tall empty box behind. */
  .unassigned-rail, .unassigned-rail.collapsed,
  .mgmt-rail, .mgmt-rail.collapsed {
    flex: 0 0 auto; width: 100%; height: auto; min-height: 0;
    transition: none; overflow: visible;
  }
  .unassigned-rail .list-card, .mgmt-rail > .card { min-width: 0; }
  /* !important: must outgun "#pane-crews .list-card { display:flex }" */
  .unassigned-rail.collapsed .list-card,
  .mgmt-rail.collapsed > .card { display: none !important; }
  /* Collapsed rail = one full-width slim bar, horizontal label. */
  .bench-tab {
    position: static; display: none; width: 100%;
    align-items: center; justify-content: center; padding: 9px 0;
    opacity: 1; pointer-events: auto; transition: border-color .12s ease;
  }
  .unassigned-rail.collapsed .bench-tab,
  .mgmt-rail.collapsed .bench-tab { display: flex; }
  .bench-tab-text { writing-mode: horizontal-tb; text-orientation: mixed; }
}

/* Keep the Unassigned/Management collapse (skinny) behavior, but make the
   collapsed rail span the FULL height of the crew columns beside it so the
   skinny bar matches the column length instead of sitting short at the top.
   align-self overrides the row's flex-start just for the collapsed rails. */
.crew-board-flex > .unassigned-rail.collapsed,
.crew-board-flex > .mgmt-rail.collapsed { align-self: stretch; }
@media (max-width: 900px) {
  /* Stacked layout: cross-axis is width; stretch would do nothing useful and
     the rails are already full width — keep natural height. */
  .crew-board-flex > .unassigned-rail.collapsed,
  .crew-board-flex > .mgmt-rail.collapsed { align-self: auto; }
}

/* Crew cards mirror the Tools/Rentals board: each column caps at the viewport
   height and the people area scrolls INTERNALLY when a crew has more people than
   fit, so the board itself never grows the page off-screen. The header (title +
   pills) stays pinned; only the shift lanes scroll. Phones opt out (media query
   below) — there the card grows naturally and the page scrolls. */
.list-card[data-list-type="crew"] {
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 210px);   /* cap → internal scroll kicks in */
}
.list-card[data-list-type="crew"] > .card-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;                  /* the scroll lives on .crew-shifts below */
}
.list-card[data-list-type="crew"] .shift-segment {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1 0 200px;
}
.shift-dropzone,
.shift-segment .people-list.dropzone {
  flex: 1 1 auto;
  min-height: 40px;                  /* always a usable drop target */
  overscroll-behavior: contain;
  scrollbar-width: thin;
}
.shift-dropzone::-webkit-scrollbar,
.shift-segment .people-list.dropzone::-webkit-scrollbar { width: 6px; }
.shift-dropzone::-webkit-scrollbar-thumb,
.shift-segment .people-list.dropzone::-webkit-scrollbar-thumb {
  background: #3a3f47; border-radius: 4px;
}
/* Shifts sit SIDE BY SIDE within a crew, each lane a readable ~200px minimum.
   The lanes area (.crew-shifts) fills the rest of the capped card and scrolls
   vertically as one unit — this is the internal scroll that stays active while
   taking attendance. The lanes NEVER wrap: the grid below guarantees each card
   is wide enough to hold them all in a row, so a card can't warp. On phones
   they stack full-width (media query). */
.crew-shifts {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 10px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  padding-bottom: 4px;
}
.crew-shifts::-webkit-scrollbar { width: 6px; }
.crew-shifts::-webkit-scrollbar-thumb { background: #3a3f47; border-radius: 4px; }
.crew-shifts > .shift-segment {
  flex: 1 1 230px;                     /* readable lanes; grow to fill the card */
  min-width: 230px;
  max-width: 100%;
}
@media (max-width: 768px) {
  /* Stack the shift lanes full-width instead of side by side. The per-segment
     selector matches the specificity of the desktop rule
     `.list-card[data-list-type="crew"] .shift-segment { flex:1 0 200px }`
     (0,3,0) so the stack actually wins — a plain `.crew-shifts > .shift-segment`
     (0,2,0) lost that battle and left the rigid 200px basis, so lane 2 overlapped
     lane 1. The card's max-height cap is already lifted for phones lower in this
     file, so the card grows to content and the page scrolls. */
  .crew-shifts { flex-direction: column; overflow-y: visible; }
  .list-card[data-list-type="crew"] .shift-segment,
  .crew-shifts > .shift-segment {
    flex: 0 0 auto;                    /* natural height per lane; no rigid basis */
    min-width: 0;
    width: 100%;
    max-width: 100%;
  }
}

/* Crews tab: a CSS grid of EQUAL tracks that span the full board width. Each
   track's minimum is sized (--crew-min, from the job's shift-lane count) to hold
   a crew's lanes side by side WITHOUT the card ever having to warp or squish
   them. auto-fit + 1fr means cards expand to the edge of the display when there
   is room, and cleanly drop onto the next row — stacking underneath — when a
   narrower window (or a browser zoom) can't fit another full card. Scoped to
   #pane-crews so other tabs keep their own grids. */
#pane-crews .board-grid {
  /* ~230px per lane + gap + card padding; falls back to 2 lanes. The card is
     always wide enough for its lanes, so names wrap to full text instead of
     forcing the card to shrink. */
  --crew-min: calc(var(--crew-cols, 2) * 240px + 44px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--crew-min)), 1fr));
  gap: 1rem;
  align-items: stretch;               /* cards in a row share one height */
  /* No width:100% — the grid is a flex child of .crew-board-flex and fills the
     space the rails leave (or its own full-width row once it wraps below them). */
}
#pane-crews .board-grid > .grid-item {
  min-width: 0;                        /* let tracks shrink instead of overflowing */
}
#pane-crews .board-grid > .grid-item > .list-card { width: 100%; }
/* Category labels ("Shift 1:", "Totals:") — headings for the row's pills,
   not totals themselves, so plain muted text rather than a pill. */
.dynamic-counts .count-cat {
  color: var(--muted);
  font-weight: 600;
  white-space: nowrap;
  margin-right: 2px;
}

/* ============================================================
   Union-book highlight rings for employee cards on the job board.
   Applied via {{ employee|book_class:job }} (crews/templatetags/book_tags.py).
   - book-1: same local as the job (green)
   - book-2: traveler from another local (blue)
   - book-4: outside-union permit hire (orange)
   - (empty class for salary employees / job without a local set)
   ============================================================ */
.person.book-1 {
  box-shadow: inset 0 0 0 2px var(--book-1,#21c55d), 0 0 8px rgba(33,197,93,.35);
  border-radius: 10px;
}
.person.book-2 {
  box-shadow: inset 0 0 0 2px var(--book-2,#3b82f6), 0 0 8px rgba(59,130,246,.35);
  border-radius: 10px;
}
.person.book-4 {
  box-shadow: inset 0 0 0 2px var(--book-4,#f97316), 0 0 8px rgba(249,115,22,.35);
  border-radius: 10px;
}

/* Legend pills (used in the job board header to explain the rings) */
.book-legend {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-left: 8px;
}
.book-legend .legend-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .72rem;
  font-weight: 600;
  color: #cfd6dd;
  background: rgba(255,255,255,.04);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 3px 10px;
}
.book-legend .legend-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: inline-block;
}
.book-legend .legend-dot.book-1 { background: var(--book-1,#21c55d); box-shadow: 0 0 6px rgba(33,197,93,.6); }
.book-legend .legend-dot.book-2 { background: var(--book-2,#3b82f6); box-shadow: 0 0 6px rgba(59,130,246,.6); }
.book-legend .legend-dot.book-4 { background: var(--book-4,#f97316); box-shadow: 0 0 6px rgba(249,115,22,.6); }

/* Counts row inside crew/unassigned cards */
.list-card .counts{
  display:flex; gap: 10px; flex-wrap: wrap; color: #cfd6dd;
}
.list-card .counts .count b{ color: var(--accent); }

/* Drag & drop affordances */
.list-card.drag-over{
  outline: 2px dashed var(--accent);
  outline-offset: -6px;
}
.person.dragging{
  opacity: .75;
  transform: scale(.98);
}

/* Tables (if any) ---------------------------------------- */
.table{
  --bs-table-bg: var(--surface);
  --bs-table-color: var(--text);
  --bs-table-border-color: var(--border);
  color: var(--text);
  border-color: var(--border);
}
.table thead th{
  color: var(--text);
  border-bottom-color: var(--border);
}
.table tbody td{
  border-top-color: var(--border);
}

/* Toasts / alerts (Bootstrap) ---------------------------- */
.alert{
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
}
.alert-primary{
  background: color-mix(in srgb, var(--brand-primary,#ff7a00) 10%, transparent);
  border-color: color-mix(in srgb, var(--brand-primary,#ff7a00) 40%, transparent);
  color: var(--text);
}

/* Footer / minor UI -------------------------------------- */
hr{ border-color: var(--border); opacity: 1; }
code, pre{ color: #ffe0c2; }

/* Small helpers ------------------------------------------ */
.bg-accent{ background: var(--accent) !important; color: #0b0b0c !important; }
.text-accent{ color: var(--accent) !important; }
.border-accent{ border-color: var(--accent) !important; }

/* Make cards breathe a bit on small screens */
@media (max-width: 480px){
  .job-grid{ grid-template-columns: 1fr; }
  .job-card{ padding: 12px; }
}

/* === Layout for job page: left sidebar + right board === */
.job-layout{
  display:grid;
  grid-template-columns: 320px 1fr;
  gap:16px;
}
@media (max-width: 991.98px){
  .job-layout{ grid-template-columns: 1fr; }
  #leftSidebar{ order: 2; }
}

/* Make entire crew card feel like a drop zone */
.drop-host { position: relative; }
.drop-host.drag-over,
.people-list.dropzone.drag-over{
  outline: 2px dashed var(--accent);
  outline-offset: -6px;
}
.people-list.dropzone{
  min-height: 56px;           /* bigger target */
  padding-bottom: 4px;
}

/* Slight spacing for the counts row */
.list-card .counts { margin-top: 2px; }

/* ======================================================================
   APPENDED: Tools & Rentals item cards + Tabs (kept dark theme)
   ====================================================================== */
.item-card{
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 10px;
  cursor: grab;
  transition: border-color .12s ease, transform .08s ease, box-shadow .08s ease;
}
.item-card:hover{ border-color: var(--accent); }
.item-card.dragging{
  opacity: .8;
  transform: scale(.98);
  box-shadow: 0 8px 18px var(--shadow);
}
.item-card .top{
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.item-card .top .fw-semibold{ color: var(--text); }
.item-card .top .text-muted{ color: var(--muted) !important; }

/* ToolVault-style tool cards on the Job Board live in crews_job_detail.css
   (single canonical definition). The duplicate block that used to be here was
   removed to end the override conflict. */

/* Tabs */
.nav-tabs{
  border-bottom: 1px solid var(--border);
}
.nav-tabs .nav-link{
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
}
.nav-tabs .nav-link:hover{
  color: var(--accent);
  border-color: transparent;
}
.nav-tabs .nav-link.active{
  color: var(--text);
  background: var(--surface);
  border-color: var(--border) var(--border) var(--surface);
}



/* ======================================================================
   APPENDED: Responsive full-width grid for Crews pane (TV-friendly)
   ====================================================================== */
:root{
  /* Adjust this to control min tile width (more columns if smaller) */
  --crew-col-min: 320px;
}

/* Make the crews page span nearly the full viewport width */
#pane-crews .container,
#pane-crews .container-fluid{
  max-width: 98vw !important;
  width: 100% !important;
  padding-left: 8px;
  padding-right: 8px;
}

/* Turn the crews row into a CSS Grid that auto-fills horizontally */
#pane-crews .row.g-3{
  display: grid !important; /* override Bootstrap's flex row */
  grid-template-columns: repeat(auto-fill, minmax(var(--crew-col-min), 1fr)) !important;
  gap: 12px !important;     /* mirrors Bootstrap g-3 spacing */
  margin-left: 0 !important;
  margin-right: 0 !important;
  width: 100% !important;
}

/* Let grid handle sizing instead of Bootstrap's col classes */
#pane-crews .row.g-3 > [class*="col-"]{
  width: 100% !important;
  max-width: none !important;
  flex: 0 0 auto !important;
}

/* Ensure each crew card stretches within its grid cell */
#pane-crews .list-card{
  height: 100%;
  display: flex;
  flex-direction: column;
}
#pane-crews .list-card .card-body{ padding: .75rem; }
#pane-crews .people-list{ min-height: 2.25rem; }

/* Optional: scale tile minimum width on very large displays */
@media (min-width: 1600px){
  :root{ --crew-col-min: 360px; }
}



/* ======================================================================
   OVERRIDES — Responsive, clean expansion for Crew cards (TV-friendly)
   ----------------------------------------------------------------------
   Goals:
   - Cards **expand** as the window grows; never squished.
   - Auto-fit columns with a comfortable minimum width.
   - Use available horizontal space cleanly, with even breathing room.
   - No JS changes; DnD unaffected.
   - Scoped to the Crews pane only.
   ====================================================================== */

/* Use nearly the full viewport width on the crews pane */
#pane-crews .container,
#pane-crews .container-fluid{
  max-width: 100vw !important;
  width: 100% !important;
  padding-left: 8px;
  padding-right: 8px;
}

/* Turn the Bootstrap row into a CSS Grid that expands gracefully.
   - auto-fit chooses how many columns fit without squishing.
   - min 360px keeps each tile comfortable.
   - 1fr lets tiles *grow* to fill negative space (no awkward gaps). */
#pane-crews .row.g-3{
  display: grid !important;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)) !important;
  gap: 16px !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  width: 100% !important;
}

/* Let the grid handle sizing instead of Bootstrap column widths */
#pane-crews .row.g-3 > [class*="col-"]{
  width: 100% !important;
  max-width: none !important;
  flex: 0 0 auto !important;
}

/* Make each crew card stretch and breathe */
#pane-crews .list-card{
  min-height: 120px;
  height: 100%;
  display: flex;
  flex-direction: column;
}
#pane-crews .list-card .card-body{ padding: .9rem; }
#pane-crews .people-list{ min-height: 2.4rem; }

/* On ultra-wide displays, gently increase spacing */
@media (min-width: 1920px){
  #pane-crews .row.g-3{ gap: 20px !important; }
}



/* ======================================================================
   FULL-BLEED CREWS BOARD (use entire viewport width cleanly)
   - #crew-page wrapper breaks out of any parent .container max-width
   - Uses CSS Grid on the crews row to expand cards naturally
   - Keeps DnD intact (layout-only)
   ====================================================================== */

/* Make the page wrapper go full-bleed across the viewport */
#crew-page{
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding-left: 12px;
  padding-right: 12px;
}

/* If any ancestor .container tries to clamp width, squash it under our scope */
#crew-page .container,
#crew-page .container-sm,
#crew-page .container-md,
#crew-page .container-lg,
#crew-page .container-xl,
#crew-page .container-xxl{
  max-width: 100% !important;
  width: 100% !important;
  padding-left: 0;
  padding-right: 0;
}

/* Tabs/content should also stretch */
#crew-page .tab-content,
#crew-page .nav-tabs{
  max-width: 100% !important;
  width: 100% !important;
}

/* Turn the crews row into an expanding grid */
#crew-page #pane-crews .row.g-3{
  display: grid !important;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)) !important;
  gap: 16px !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  width: 100% !important;
}

/* Let the grid own sizing of columns */
#crew-page #pane-crews .row.g-3 > [class*="col-"]{
  width: 100% !important;
  max-width: none !important;
  flex: 0 0 auto !important;
}

/* Make crew cards fill their grid cells and breathe */
#crew-page #pane-crews .list-card{
  height: 100%;
  display: flex;
  flex-direction: column;
}
#crew-page #pane-crews .list-card .card-body{ padding: .9rem; }
#crew-page #pane-crews .people-list{ min-height: 2.25rem; }

/* Slightly larger gap on very wide displays for a clean look */
@media (min-width: 1920px){
  #crew-page #pane-crews .row.g-3{ gap: 20px !important; }
}


/* === Apply same responsive grid to Bus Plugs & Materials panes === */
#pane-busplugs .row.g-3,
#pane-materials .row.g-3,
#pane-tools .row.g-3,
#pane-rentals .row.g-3{
  display: grid !important;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)) !important;
  gap: 16px !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  width: 100% !important;
}
#pane-busplugs .row.g-3 > [class*="col-"],
#pane-materials .row.g-3 > [class*="col-"],
#pane-tools .row.g-3 > [class*="col-"],
#pane-rentals .row.g-3 > [class*="col-"]{
  width: 100% !important;
  max-width: none !important;
  flex: 0 0 auto !important;
}

/* Make board cards stretch and keep internals tidy */
.list-card.card {
  display: flex;
  flex-direction: column;
}
.list-card .card-body {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

/* Reduce extra padding on dense boards (optional) */
.list-card .card-body {
  padding: .75rem .9rem;
}

/* Keep titles from wrapping too wildly */
.list-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Tighten “counts” line on small screens */
@media (max-width: 576px) {
  .counts {
    flex-wrap: wrap;
    gap: .5rem !important;
  }
}
/* Viewport that fills the screen (no scroll). Adjust offset if your header is taller/shorter. */
.fit-wrapper {
  --header-offset: 148px;              /* tweak to match your header area */
  width: 100%;
  height: calc(100vh - var(--header-offset));
  overflow: hidden;                    /* we will scale the strip to avoid scroll */
  position: relative;
}

/* One long horizontal row of fixed-width columns */
.crews-strip {
  display: flex;
  gap: 1rem;
  align-items: stretch;
  flex-wrap: nowrap;                   /* <-- critical: single row, no wrap */
  transform-origin: 0 0;               /* scale from top-left in JS */
  will-change: transform;
}

/* Each column gets a fixed base width; change if you want larger/smaller tiles */
.crew-col {
  flex: 0 0 280px;                     /* width per column; change 280 to taste */
}

/* Make cards fill their column */
.list-card.card { height: 100%; display: flex; flex-direction: column; }
.list-card .card-body { display: flex; flex-direction: column; gap: .5rem; }

/* Keep titles neat */
.list-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.board-grid{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 1rem;
  width: 100%;
}

/* Make Bootstrap .col-* work as grid items even without a .row */
.board-grid > [class*="col-"]{
  width: 100% !important;
  max-width: none !important;
  flex: 0 0 auto; /* stop Bootstrap's flex rules */
}

/* Make sure tab panes themselves don’t constrain width */
.tab-content, 
#pane-tools, #pane-rentals, #pane-busplugs, #pane-materials {
  width: 100%;
}

.tab-pane .list-card{
  height: 100%;
  display: flex;
  flex-direction: column;
}

/* Put counts under the crew title without changing HTML structure */
#pane-crews .card-body > .d-flex.align-items-center.justify-content-between.mb-2 {
  flex-wrap: wrap;
  gap: 4px 8px;
}
#pane-crews .card-body > .d-flex.align-items-center.justify-content-between.mb-2 .list-title {
  flex: 1 1 auto;
}
#pane-crews .card-body > .d-flex.align-items-center.justify-content-between.mb-2 .counts {
  width: 100%;
  order: 2;
  margin-top: 2px;
}

/* Let crew names wrap fully (fixes truncated titles only on Crews tab) */
#pane-crews .list-title {
  white-space: normal;
  overflow: visible;
  text-overflow: initial;
}

/* Transfers: subtle timeline + green completion badge (UI-only) */
.tr-timeline {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 4px 12px;
  color: var(--muted);
}
@media (max-width: 480px) {
  .tr-timeline { grid-template-columns: 1fr; }
}

/* Card outline + checkmark when fully received (status=received) */
.tr-complete {
  box-shadow: 0 0 0 1px #2ecc71 inset;
  border-color: #2ecc71 !important;
}
.tr-complete-badge {
  position: absolute;
  top: 8px;
  right: 10px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #2ecc71;
  color: #0b0b0c;
  display: grid;
  place-items: center;
  font-weight: 900;
  line-height: 1;
}

/* Transfers cards with status styling */
.tr-card{
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: .75rem .9rem;
  box-shadow: 0 6px 20px var(--shadow);
}
.tr-title { font-weight: 600; color: var(--text); }
.tr-meta  { font-size: .875rem; color: var(--muted); }

/* Pending: yellow outline + hourglass */
.tr-card.pending{
  border-color: #f7c948;
  box-shadow: 0 0 0 .15rem rgba(247,201,72,.25);
}
.tr-card.pending::after{
  content: "⌛";
  position: absolute; top: .4rem; right: .5rem;
  font-size: 1rem; opacity: .9;
}

/* Completed: subtle check mark */
.tr-card.completed::after{
  content: "✓";
  position: absolute; top: .4rem; right: .5rem;
  font-weight: 700; opacity: .85;
}

/* Denied: red border + X */
.tr-card.denied{
  border-color: #dc3545;
  box-shadow: 0 0 0 .15rem rgba(220,53,69,.2);
  background: color-mix(in srgb, #dc3545 6%, var(--surface));
}
.tr-card.denied::after{
  content: "✕";
  position: absolute; top: .4rem; right: .5rem;
  font-weight: 700; color: #dc3545; opacity: .9;
}

/* Completed: green outline + ✓ */
.tr-card.completed,
.tr-card.tr-complete,           /* back-compat if old class still present */
.tr-card.border-success {       /* back-compat if Bootstrap class was used */
  border-color: #198754;        /* Bootstrap "success" green */
  box-shadow: 0 0 0 .15rem rgba(25,135,84,.25);
  /* Optional subtle tint; remove if you want pure background */
  background: color-mix(in srgb, #198754 6%, var(--bs-body-bg));
}
.tr-card.completed::after,
.tr-card.tr-complete::after,
.tr-card.border-success::after {
  content: "✓";
  position: absolute;
  top: .4rem;
  right: .5rem;
  font-weight: 700;
  opacity: .85;
}

/* NOTE: PreFab status card visuals now live in crews_job_detail.css (to avoid duplication) */
/* Tab-pane show/hide rules live in crews_job_detail.css (their only page)
   — the identical copy that used to sit here was removed (audit F1a). */

/* Search form cleanup */
.mv-search-form .form-label {
  font-weight: 500;
  color: var(--bs-secondary-color, #888);
}
.mv-search-form input, .mv-search-form select {
  height: 36px;
  font-size: 0.9rem;
}
.mv-search-form .btn {
  height: 36px;
  font-weight: 600;
}

.ring-focus { outline: 3px solid var(--brand-primary,#ff7a00); outline-offset: 2px; border-radius: 8px; }

/* crewhierarchy/static/crewhierarchy/tree.css */

/* Container width and breathing room */
.ch-wrap { padding: 0.75rem; }

/* Rail above the tree for PM (parallel) */
.ch-rail {
  margin-bottom: 1rem;
  border: 1px solid rgba(255,255,255,.08);
  border-radius: .6rem;
  background: rgba(255,255,255,.02);
}
.ch-rail-title {
  font-size: .85rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  opacity: .75;
  padding: .5rem .75rem .25rem;
}
.ch-rail-row {
  padding: .25rem .75rem .75rem;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

/* Generic tree rows */
.ch-row { margin-bottom: 1.25rem; }
.ch-row-title {
  font-size: .85rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  opacity: .75;
  margin: 0 .5rem .25rem;
}
.ch-row-nodes {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  justify-content: center;   /* center like the screenshot */
}

/* Gold-ish connectors between rows, subtle */
.ch-row-connector {
  height: 14px;
  position: relative;
  margin: .25rem auto 0;
  width: clamp(200px, 50%, 540px);
}
.ch-row-connector::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 6px;
  height: 2px;
  background: linear-gradient(90deg, rgba(255,193,7,.15), rgba(255,193,7,.45), rgba(255,193,7,.15));
  border-radius: 2px;
}

/* Crew grid (cards on bottom row) */
.ch-crew-grid {
  display: grid;
  gap: .75rem;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.ch-crew-card {
  border: 1px solid rgba(255,255,255,.08);
  border-radius: .75rem;
  background: rgba(255,255,255,.02);
  padding: .5rem .6rem .65rem;
  position: relative;
}
.ch-crew-head {
  padding-bottom: .35rem;
  border-bottom: 1px dashed rgba(255,255,255,.12);
  margin-bottom: .35rem;
  display: flex;
  align-items: baseline;
  gap: .25rem;
}
.ch-crew-name { font-weight: 600; }
.ch-crew-loc { opacity: .75; }

.ch-crew-rail {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  padding-top: .25rem;
}
.ch-crew-rail--foremen {
  /* light underline separator to echo screenshot “pill rows” */
  padding-bottom: .25rem;
  border-bottom: 1px dashed rgba(255,255,255,.08);
  margin-bottom: .25rem;
}

/* Node wrapper so your employee badge can drop in */
.ch-node {
  display: inline-flex;
  align-items: stretch;
}

/* Optional: small polish if your badge does not span full height */
.ch-node > * {
  border-radius: .75rem; /* soften corners like the screenshot pills */
}

/* Responsive helpers */
@media (max-width: 720px) {
  .ch-row-connector { width: 70%; }
}

/* universal "Previous page" link */
.back-link {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 40px;                       /* gloved-thumb touch floor */
  margin: 4px 0 12px; padding: 6px 14px 6px 10px;
  border-radius: 999px;
  border: 1px solid var(--border, #23252b);
  color: var(--muted, #9aa3ae);
  font-size: .85rem; font-weight: 600;
  transition: color .12s ease, border-color .12s ease, transform .12s ease;
}
.back-link svg { width: 16px; height: 16px; }
.back-link:hover {
  color: var(--brand-primary, #ff7a00);
  border-color: var(--brand-primary, #ff7a00);
  transform: translateY(-1px);
}

/* Weekend availability toggle ------------------------------------------------ */
.wk-toggle-wrap {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-left: auto;
  flex-shrink: 0;
  vertical-align: middle;
}
.wk-toggle-wrap .wk-label {
  font-size: 0.6rem;
  font-weight: 700;
  color: var(--muted);
  user-select: none;
}
.wk-toggle {
  display: inline-block;
  position: relative;
  width: 30px;
  height: 16px;
  border-radius: 8px;
  cursor: pointer;
  background: #3a3d44;
  border: none;
  user-select: none;
  vertical-align: middle;
  transition: background .2s;
  flex-shrink: 0;
}
.wk-toggle::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #888;
  transition: transform .2s, background .2s;
}
.wk-toggle:hover {
  background: #4a4d54;
}
.wk-toggle.wk-on {
  background: #2e7d32;
}
.wk-toggle.wk-on::after {
  transform: translateX(14px);
  background: #81c784;
}

/* Weekend shift badges (weekend board) ---------------------------------------- */
.wk-shift-badge {
  display: inline-block;
  font-size: 0.55rem;
  font-weight: 700;
  padding: 0 4px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--brand-primary,#ff7a00) 20%, transparent);
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--brand-primary,#ff7a00) 35%, transparent);
  vertical-align: middle;
  margin-left: 2px;
}

/* Weekend tier labels --------------------------------------------------------- */
.wk-tier-label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--accent);
  padding: 4px 0 2px;
  margin-top: 6px;
  border-bottom: 1px solid var(--border);
}
.wk-tier-label:first-child {
  margin-top: 0;
}

/* Weekend summary panel ------------------------------------------------------- */
#wk-summary-panel .card-header {
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
#wk-summary-body .row > div {
  border-right: 1px solid var(--border);
}
#wk-summary-body .row > div:last-child {
  border-right: none;
}
/* ======================================================================
   MOBILE / SMALL-SCREEN PASS (applies app-wide via base.html)
   Desktop-size chrome reads "zoomed in" on a phone, so the root font
   steps down (everything rem-based scales with it), the navbar collapses
   to one compact row, tab strips become wrapping chips instead of
   broken half-tabs, and dropdown menus are clamped to the viewport.
   ====================================================================== */
@media (max-width: 991.98px){
  html { font-size: 14px; }

  /* --- Navbar: one tight row; dropdowns can never run off screen --- */
  .navbar { row-gap: 2px; padding-top: .35rem; padding-bottom: .35rem; }
  .navbar .navbar-brand img { height: 28px; width: 28px; }
  .navbar .ms-auto { gap: .5rem !important; }
  .navbar .dropdown-menu {
    max-width: calc(100vw - 16px);
    max-height: 70vh;
    overflow-y: auto;
    overflow-x: hidden;
  }
  .navbar .dropdown-menu .dropdown-item { white-space: normal; }

  /* Apps menu: Bootstrap makes navbar-nav dropdowns position:static below
     the lg breakpoint, which inflates the whole header when opened. Float
     it over the page instead. */
  .navbar .navbar-nav .nav-item.dropdown { position: relative; }
  .navbar .navbar-nav .dropdown-menu {
    position: absolute;
    top: 100%; left: auto; right: 0;   /* the Apps item sits right of the brand */
    z-index: 1050;
    margin-top: .3rem;
    box-shadow: 0 14px 32px rgba(0,0,0,.55);
  }

  /* --- Tab strips (Job page, Forecasting, etc.): the stock underlined
     tabs wrap into ragged rows on a phone, so present them as a tidy
     chip cloud. Active chip = brand accent. --- */
  .nav-tabs { gap: 6px; border-bottom: 0; }
  .nav-tabs .nav-item { margin: 0; }
  .nav-tabs .nav-link {
    padding: .32rem .65rem;
    font-size: .88rem;
    border: 1px solid var(--border) !important;
    border-radius: 999px;
    color: var(--text);
    background: var(--surface-2);
    white-space: nowrap;
  }
  .nav-tabs .nav-link.active {
    background: var(--accent);
    border-color: var(--accent) !important;
    color: #0b0b0c;
    font-weight: 700;
  }

  /* --- Page chrome: reclaim padding the phone can't spare --- */
  main.py-4 { padding-top: .65rem !important; padding-bottom: .75rem !important; }
  .container, .container-fluid { padding-left: .75rem; padding-right: .75rem; }
  .back-link { margin: 2px 0 8px; padding: 4px 8px; font-size: .85rem; }

  /* Job totals header card: tighter, legend wraps below the pills */
  .book-legend { margin-left: 0 !important; width: 100%; }

  /* Crew cards may use the full viewport height on a phone */
  .list-card[data-list-type="crew"] { max-height: none; }
  .list-card .list-title { font-size: 1.2rem; }
}

@media (max-width: 480px){
  html { font-size: 13px; }
  .jc-hero-num { font-size: 1.7rem; }
  .jc-metric-num { font-size: 1.1rem; }
}

/* ======================================================================
   SAFETY — Lock Vault & Equipment card grids (ToolVault/MaterialVault
   pattern: each row is a card; the lock card is the link to the lock
   profile and lights up in brand color on hover). Long lists scroll
   inside the pane instead of stretching the page.
   ====================================================================== */
.saf-scroll {
  max-height: 68vh;
  overflow-y: auto;
  overflow-x: hidden;          /* the row's negative gutters must not scroll */
  overscroll-behavior: contain;
  scrollbar-width: thin;
  /* absorb .row.g-3's -0.5rem side margins so nothing pokes out */
  padding: 0 .5rem 0 .5rem;
}
.saf-scroll::-webkit-scrollbar { width: 6px; }
.saf-scroll::-webkit-scrollbar-thumb { background: #3a3f47; border-radius: 4px; }

.lock-card { cursor: pointer; transition: border-color .12s ease, transform .12s ease; }
.lock-card:hover { border-color: var(--accent, #ff7a00); transform: translateY(-2px); }
/* Let the text column shrink inside the flex card instead of forcing width */
.lock-card .flex-fill { min-width: 0; overflow-wrap: anywhere; }
.lock-qr-img {
  border-radius: 8px; border: 1px solid #2d2d32;
  background: #fff; padding: 4px; flex: 0 0 auto;
}
/* Obscured QR tile: shown in place of the code while the lock is applied */
.lock-qr-hidden {
  width: 96px; height: 96px; flex: 0 0 auto;
  border-radius: 8px; border: 1px dashed #3a3f47; background: #15171b;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; text-align: center; color: var(--muted); font-size: .58rem; padding: 6px;
}
.lock-qr-hidden .lqh-emoji { font-size: 1.35rem; line-height: 1; }

.eq-card { transition: border-color .12s ease; }
.eq-card:hover { border-color: #3f444c; }

/* Round icon actions on cards (view / print …): neutral grey ring that
   lights up brand-orange on hover, with a hover label pill underneath. */
.card-act {
  position: relative;
  width: 30px; height: 30px; border-radius: 50%;
  padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border, #2d2d32);
  background: #1b1e24;
  color: var(--muted, #9aa3ae);
  text-decoration: none;
  transition: border-color .12s ease, color .12s ease, transform .12s ease;
  flex: 0 0 auto;
}
.card-act svg { width: 14px; height: 14px; }
.card-act:hover {
  border-color: var(--accent, #ff7a00);
  color: var(--accent, #ff7a00);
  transform: translateY(-1px);
}
.card-act::after {
  content: attr(data-tip);
  position: absolute; top: calc(100% + 6px); left: 50%;
  transform: translateX(-50%) translateY(-3px);
  background: #1b1e24; color: #f3f5f7;
  border: 1px solid #2d2d32; border-radius: 999px;
  padding: 2px 9px; font-size: .68rem; font-weight: 600;
  white-space: nowrap; pointer-events: none;
  opacity: 0; transition: opacity .14s ease, transform .14s ease;
  z-index: 5;
}
.card-act:hover::after { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Collapsible filter sections: slim pill that toggles the filter form
   (used by MaterialVault and the safety hub panes). Orange when open or
   when filters are active so applied filters are never invisible. */
.filter-toggle {
  border: 1px solid var(--border, #2d2d32);
  border-radius: 999px;
  color: var(--text, #e9edf1);
  background: var(--surface-2, #1a1c20);
  display: inline-flex;
  align-items: center;
  transition: border-color .12s ease, color .12s ease;
}
.filter-toggle:hover,
.filter-toggle.active {
  border-color: var(--accent, #ff7a00);
  color: var(--accent, #ff7a00);
}
.filter-toggle .filter-caret { transition: transform .18s ease; }
.filter-toggle[aria-expanded="true"] .filter-caret { transform: rotate(180deg); }

/* Brand-orange round icon action with a hover label pill (CrewTracker
   primary actions, e.g. New Crew). Same language as .saf-act/.card-act. */
.brand-act {
  position: relative;
  z-index: 5;
  width: 38px; height: 38px; border-radius: 50%; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--accent, #ff7a00);
  background: var(--surface-2, #1a1c20);
  color: var(--accent, #ff7a00);
  cursor: pointer;
  transition: transform .12s ease, box-shadow .18s ease, background .12s ease,
              color .12s ease;
}
.brand-act svg { width: 18px; height: 18px; }
.brand-act i { font-size: 18px; line-height: 1; }
.brand-act--sm i { font-size: 15px; }
.brand-act:disabled, .brand-act[disabled] {
  opacity: .45; cursor: not-allowed; transform: none;
}
.brand-act:disabled:hover { transform: none; background: var(--surface-2, #1a1c20);
  border-color: var(--accent, #ff7a00); color: var(--accent, #ff7a00); box-shadow: none; }
.brand-act:disabled::after { display: none; }
.brand-act:hover, .brand-act:focus-visible {
  z-index: 1100;   /* the hover label bubble must ride over sibling cards */
}
.brand-act:hover {
  transform: translateY(-2px);
  background: var(--accent-2, #ffa24a);
  border-color: var(--accent-2, #ffa24a);
  box-shadow: 0 6px 18px color-mix(in srgb, var(--brand-primary,#ff7a00) 35%, transparent);
  color: #0b0b0c;
}
.brand-act::after {
  content: attr(data-tip);
  position: absolute; top: calc(100% + 7px); left: 50%;
  transform: translateX(-50%) translateY(-3px);
  background: #1b1e24; color: #f3f5f7;
  border: 1px solid #2d2d32; border-radius: 999px;
  padding: 3px 10px; font-size: .72rem; font-weight: 600;
  white-space: nowrap; pointer-events: none;
  opacity: 0; transition: opacity .14s ease, transform .14s ease;
  z-index: 1075;
}
.brand-act:hover::after { opacity: 1; transform: translateX(-50%) translateY(0); }
/* No label pill while the button's dropdown is open — on touch the tap
   leaves the button "hovered", so the pill lingered over the open sheet
   and could clip at the screen edge. */
.brand-act[aria-expanded="true"]::after { opacity: 0 !important; }

/* Compact variant for dense table rows / tiles, and a red "danger" variant
   for destructive actions (delete). Shared by Manpower, Training, etc. */
.brand-act--sm { width: 30px; height: 30px; }
.brand-act--sm svg { width: 15px; height: 15px; }
.brand-act--danger { border-color: #ef4444; color: #ef4444; }
.brand-act--danger:hover {
  background: #ef4444; border-color: #ef4444; color: #fff;
  box-shadow: 0 6px 18px rgba(239, 68, 68, .35);
}
.brand-act--success { border-color: #22c55e; color: #22c55e; }
.brand-act--success:hover {
  background: #22c55e; border-color: #22c55e; color: #06280f;
  box-shadow: 0 6px 18px rgba(34, 197, 94, .35);
}

/* Create Job dropdown panel (job board) */
.job-create-menu { min-width: 340px; max-height: 80vh; overflow-y: auto; }
.job-create-menu .form-label { font-size: .78rem; font-weight: 600; }

/* Apps menu: the active (current app) item follows the brand primary instead
   of Bootstrap's blue, so it re-skins automatically when the theme/branding
   palette changes (Admin → Branding sets --brand-primary). */
.navbar .dropdown-menu .dropdown-item.active,
.navbar .dropdown-menu .dropdown-item:active {
  background-color: var(--brand-primary, #ff7a00);
  color: var(--brand-on-primary, #0b0b0c);
}

/* Segmented toggle (filters / view modes, all tabs): exactly the Labor
   Curve / Forecasting selector — compact outline group whose active segment
   fills with the brand color. One class, used everywhere. */
.seg-toggle { flex-wrap: wrap; row-gap: 4px; }
.seg-toggle .btn {
  font-size: .8rem;
  font-weight: 600;
  flex: 0 0 auto;
}
.seg-toggle .btn.active {
  background: var(--brand-primary, #ff7a00) !important;
  border-color: var(--brand-primary, #ff7a00) !important;
  color: var(--brand-on-primary, #0b0b0c) !important;
  font-weight: 700;
}

/* Dropdown form panels (Add Reel / Add Stock Material / New Crew / Create
   Job): sized for phones — never wider than the screen, scrolls if tall. */
.form-drop {
  min-width: min(92vw, 340px);
  max-width: 96vw;
  max-height: 75vh;
  overflow-y: auto;
  margin-inline-end: 16px;   /* air off the screen edge — native select
                                popups inside don't get clipped */
}
.form-drop .form-select { text-overflow: ellipsis; }
.form-drop--wide { min-width: min(96vw, 560px); }

/* In-panel catalog picker (cat_picker.js): the option list renders inside
   the form-drop panel instead of a native <select> popup, so it can never
   hang off the viewport; long entries wrap, the list scrolls. */
.cat-picker-list {
  max-height: 240px;
  overflow-y: auto;
  margin-top: 6px;
  border: 1px solid var(--border, #2d2d32);
  border-radius: 8px;
  background: var(--surface-2, #1a1c20);
}
.cat-picker-item {
  display: block; width: 100%; text-align: left;
  background: none; border: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border, #2d2d32) 60%, transparent);
  color: var(--text, #e9edf1);
  font-size: .85rem; padding: 6px 10px; cursor: pointer;
  white-space: normal; overflow-wrap: anywhere;  /* nothing gets cut off */
}
.cat-picker-item:last-child { border-bottom: 0; }
.cat-picker-item:hover {
  background: color-mix(in srgb, var(--brand-primary, #ff7a00) 14%, transparent);
}
.cat-picker-item.active {
  background: var(--brand-primary, #ff7a00);
  color: var(--brand-on-primary, #0b0b0c);
  font-weight: 600;
}
.cat-picker-empty { padding: 6px 10px; }

/* Filter toggles use the shared .filter-toggle + Bootstrap collapse
   pattern (see MaterialVault). Area chips keep .reel-chip below. */
.reel-filter-toggle .tog-caret {
  display: inline-block; transition: transform .15s ease;
  transform: rotate(-90deg);
}
.reel-filter-toggle[aria-expanded="true"] .tog-caret { transform: rotate(0deg); }
.reel-search { max-width: 280px; }

/* Reel card feed lists: bold FED FROM / FED TO labels with the equipment
   names stacked beneath — long tags wrap inside the card instead of
   overflowing, lists stay clean, and blocks cap at three names (+N more)
   so every card keeps a professional, bounded size. */
/* Reel card typography (ReelVault board + Materials tab share these):
   big title for fast navigation, a hero "live length", small single-line
   wire type. */
/* Procurement status pill on reel cards (Pending grey / Ordered amber /
   On Site green) — small, no extra card height. */
.reel-proc {
  display: inline-block; padding: 0 7px; border-radius: 999px;
  font-size: .6rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .03em; line-height: 1.5; white-space: nowrap;
}
.reel-proc--pending { background: #6b7280; color: #fff; }
.reel-proc--ordered { background: #f59e0b; color: #0b0b0c; }
.reel-proc--shipped { background: #3b82f6; color: #fff; }
.reel-proc--on_site { background: #22c55e; color: #0b0b0c; }
/* Cable / Wire reel-type badge + filter chips. Shared by ReelVault and the
   job-board Materials tab. Text label always present (never color-only);
   colors are distinct from status/procurement so they don't read as warnings. */
.reel-type-badge {
  text-transform: uppercase; font-weight: 800; letter-spacing: .04em;
}
.reel-type-badge--cable { background: #1f3a5f; color: #9ec5ff; }
.reel-type-badge--wire  { background: #3a2a5f; color: #d6b3ff; }
.reel-type-filter .reel-type-chip--cable.active { background: #5b8def; color: #0b0b0c; }
.reel-type-filter .reel-type-chip--wire.active  { background: #a855f7; color: #0b0b0c; }
.reel-no { font-size: 1.2rem; font-weight: 800; line-height: 1.12; letter-spacing: .01em; }
.reel-len { line-height: 1.05; margin-top: .1rem; }
.reel-len-num { font-size: 1.5rem; font-weight: 800; }
.reel-len-unit { font-size: .8rem; font-weight: 700; }
.reel-len-sub { font-size: .62rem; color: var(--muted, #9aa3ae); }
.reel-type { font-size: .66rem; color: var(--muted, #9aa3ae); text-transform: uppercase; letter-spacing: .03em; }

.feed-label {
  font-size: .58rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--muted, #9aa3ae);
  margin-top: .25rem; line-height: 1.15;
}
.feed-label + .feed-name { margin-top: 0; }
.feed-name {
  font-size: .68rem; color: #cfd6dd; line-height: 1.15;
  overflow-wrap: anywhere;
}
.feed-more { font-size: .62rem; color: var(--muted, #9aa3ae); font-style: italic; line-height: 1.15; }

/* --------------------------------------------------------------------------
   Permit cards — same visual language as the reel cards above (coloured left
   edge by stage, compact body, big identifier, labelled detail rows). Lives in
   crews.css (loaded in <head>) so the Job Board Permits tab — injected via HTMX
   — always gets these styles, not just the server-rendered Manpower tab.
   -------------------------------------------------------------------------- */
.permit-card { border-radius: .6rem; transition: box-shadow .15s ease; }
.permit-card .card-body { padding: .6rem .7rem; }
/* NB: no transform on hover — a transform creates a stacking context on every
   sibling card, which paints over a neighbouring card's OPEN action dropdown
   (the "menu disappears when you move onto it" bug). Lift via shadow only. */
.permit-card:hover { box-shadow: 0 .45rem 1rem rgba(0,0,0,.35); }
/* Card whose action dropdown is open rides above its siblings so the menu is
   never clipped or covered. */
.permit-card:has(.dropdown-menu.show) { position: relative; z-index: 1090; }
.permit-stage-card { border-left: 6px solid var(--stage, #6c757d) !important; }
.permit-clickable { cursor: pointer; }
.permit-clickable:hover { border-color: var(--stage, #6c757d); }

.permit-no { font-size: 1.05rem; font-weight: 800; line-height: 1.12; }
.permit-for { font-size: .9rem; font-weight: 700; color: var(--text, #e9edf1); line-height: 1.2; margin-top: .1rem; }
.permit-sub { font-size: .72rem; color: var(--muted, #9aa3ae); line-height: 1.2; }
.permit-label {
  font-size: .58rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--muted, #9aa3ae);
  margin-top: .35rem; line-height: 1.15;
}
.permit-val { font-size: .72rem; color: #cfd6dd; line-height: 1.25; overflow-wrap: anywhere; }
.stage-badge {
  background: var(--stage, #6c757d); color: #0b0b0c;
  font-weight: 700; white-space: nowrap; font-size: .62rem; padding: .3em .55em;
}
.permit-doc-chip { font-size: .62rem; }
.reel-chip {
  --chip: #9aa3ae;
  border: 1px solid color-mix(in srgb, var(--chip) 55%, transparent);
  color: var(--chip); background: none; border-radius: 999px;
  font-size: .72rem; font-weight: 700; padding: 2px 10px; line-height: 1.4;
  text-transform: uppercase; letter-spacing: .03em; cursor: pointer;
}
.reel-chip.active { background: var(--chip); color: #0b0b0c; }
.reel-chip[data-area="all"] { --chip: var(--brand-primary, #ff7a00); }

/* Desktop: form dropdowns drop inline anchored to their trigger, and stay on
   screen via Popper's flip/shift (the trigger sets data-bs-boundary="viewport").
   They overlay other content (high z-index) and scroll if tall. */
.dropdown-menu.form-drop {
  max-height: 80vh;
  overflow-y: auto;
  z-index: 1085;
}
/* Phones/tablets: become a centered sheet so a finger-sized panel never hangs
   off the edge and native <select> popups stay clear of the screen edge. */
@media (max-width: 991.98px) {
  .dropdown-menu.form-drop.show {
    position: fixed !important;
    left: 50% !important; right: auto !important;
    top: 10vh !important; bottom: auto !important;
    transform: translateX(-50%) !important;
    width: min(92vw, 360px);
    max-height: 78vh;
    box-shadow: 0 12px 40px rgba(0, 0, 0, .6);
    z-index: 1080;
  }
}


/* ==========================================================================
   UI continuity contracts (Phase 1)
   ========================================================================== */
/* Heading contract: every page opens with .page-title; section headers use
   .section-label — one size/weight everywhere regardless of the h-tag. */
.page-title { font-size: 1.4rem; font-weight: 700; letter-spacing: .01em; margin-bottom: 0; }
.section-label {
  font-size: 1.05rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em;
}

/* iOS zooms any focused field under 16px — global rule, not per-page. */
@media (max-width: 991.98px) {
  input, select, textarea { font-size: 16px !important; }
}

/* Keyboard focus: a visible brand ring app-wide. */
:focus-visible { outline: 2px solid var(--brand-primary, #ff7a00); outline-offset: 2px; }

/* Buttons: one modern pill shape product-wide (groups keep their fused
   inner edges via Bootstrap's own group rules). */
.btn { border-radius: 999px; font-weight: 600; }

/* Tables: one dark skin + a scroll container so phones pan instead of
   stretching the layout. */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: 10px; }
.table { color: var(--text, #e9edf1); --bs-table-bg: transparent; }
.table thead th {
  background: var(--surface-2, #1a1c20); color: var(--muted, #9aa3ae);
  font-size: .72rem; text-transform: uppercase; letter-spacing: .06em;
  border-color: var(--border, #23252b) !important;
}
.table td, .table th { border-color: var(--border, #23252b) !important; }
.table tbody tr:hover td { background: color-mix(in srgb, var(--brand-primary, #ff7a00) 7%, transparent); }

/* Pagination: pill chips in the filter-chip language. */
.pagination { gap: 6px; }
.pagination .page-link {
  border-radius: 999px !important; background: transparent;
  border: 1px solid var(--border, #23252b); color: var(--text, #e9edf1);
  font-size: .8rem; padding: 4px 12px;
}
.pagination .page-item.active .page-link,
.pagination .page-link:hover {
  background: var(--brand-primary, #ff7a00);
  border-color: var(--brand-primary, #ff7a00);
  color: var(--brand-on-primary, #0b0b0c);
}


/* Scanner icon buttons (Tool Scan / Material Scan / Safety Scan) — one
   definition shared by all three scanner pages. */
.qr-icon-btn {
  width: 44px; height: 44px; border-radius: 12px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border, #2d2d32);
  background: var(--surface, #141518);
  color: var(--text, #e9edf1); font-size: 1.05rem;
  cursor: pointer; text-decoration: none;
  transition: border-color .12s ease, color .12s ease, background .12s ease;
}
.qr-icon-btn:hover { background: var(--surface-2, #1a1c20); border-color: var(--brand-primary, #ff7a00); }
.qr-icon-btn.is-off { opacity: .45; }
.qr-icon-btn[aria-pressed="true"] { border-color: var(--brand-primary, #ff7a00); color: var(--brand-primary, #ff7a00); }


/* Tab bars with many tabs: one horizontally-scrollable row on phones
   instead of wrapping to 3-4 rows and shoving content down the screen. */
@media (max-width: 991.98px) {
  .nav-tabs-scroll {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .nav-tabs-scroll::-webkit-scrollbar { display: none; }
  .nav-tabs-scroll .nav-item { flex: 0 0 auto; }
  .nav-tabs-scroll .nav-link { white-space: nowrap; }
}

/* ── Reel label multi-select (Materials tab + ReelVault board) ───────── */
.reel-item { position: relative; }
.reel-pick { display: none; position: absolute; top: 8px; left: 8px; z-index: 3;
  width: 22px; height: 22px; border-radius: 6px; border: 2px solid var(--accent, #ff7a00);
  background: rgba(0,0,0,.55); }
body.reel-pick-mode .reel-pick { display: block; }
body.reel-pick-mode .reel-mat-card, body.reel-pick-mode .reel-card { cursor: pointer; }
.reel-item.picked .reel-pick { background: var(--accent, #ff7a00); }
.reel-item.picked .reel-pick::after { content: "✓"; position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center; color: #0b0b0c;
  font-weight: 900; font-size: 14px; }
.reel-item.picked .reel-mat-card, .reel-item.picked .reel-card {
  outline: 3px solid var(--accent, #ff7a00); outline-offset: 1px; }
#reelPrintBar { position: fixed; left: 50%; transform: translateX(-50%); bottom: 18px;
  z-index: 1080; display: none; gap: 10px; align-items: center; background: #15171b;
  border: 1px solid #2d2d32; border-radius: 999px; padding: 8px 14px;
  box-shadow: 0 8px 24px rgba(0,0,0,.45); }
#reelPrintBar.show { display: flex; }

/* =====================================================================
   Reel Families + Progress Dashboard — built from the ReelCard language
   (colored side bar, dark card, same badges/chips). Scoped to reel-* /
   reel-fam-* class names so nothing else is affected.
   ===================================================================== */
/* True top-level ReelVault tabs (not filter pills): underline-accent tab bar. */
.reel-tabs {
  display: flex; gap: .25rem; flex-wrap: wrap; align-items: flex-end;
  margin-bottom: 1.1rem; border-bottom: 2px solid var(--border, #23252b);
}
.reel-tabs a {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .6rem 1.15rem; text-decoration: none;
  font-weight: 700; font-size: .95rem; letter-spacing: .01em;
  color: var(--muted, #9aa3ae);
  border: 0; border-bottom: 3px solid transparent;
  border-radius: 8px 8px 0 0; margin-bottom: -2px;
}
.reel-tabs a:hover { color: var(--accent, #ff7a00); background: rgba(255,255,255,.04); }
.reel-tabs a.active {
  color: var(--accent, #ff7a00);
  border-bottom-color: var(--accent, #ff7a00);
  background: color-mix(in srgb, var(--accent, #ff7a00) 12%, transparent);
}

/* Canonical reel status colors — ONE source of truth for the stacked
   procurement bar, the per-metric progress bars underneath, the legend dots,
   and the hover keys, so every "On Site" is the same green, etc. */
:root {
  --rv-pending: #6b7280;  /* slate  */
  --rv-ordered: #f59e0b;  /* orange */
  --rv-shipped: #3b82f6;  /* blue   */
  --rv-onsite:  #22c55e;  /* green  */
  --rv-cut:     #2dd4bf;  /* teal   — reel install lifecycle */
  --rv-pulled:  #818cf8;  /* indigo — reel install lifecycle */
  --rv-tested:  #c084fc;  /* violet — reel install lifecycle */
  /* Equipment install lifecycle (Set -> Termed -> Torqued). Shares the reel
     install palette so the two Progress sub-tabs read the same way. */
  --rv-set:     #2dd4bf;  /* teal   */
  --rv-termed:  #818cf8;  /* indigo */
  --rv-torqued: #c084fc;  /* violet */
}

/* Stacked procurement bar (area cards). Each segment carries a title=
   breakdown so hovering a color states the count. */
.reel-proc-bar { display: flex; height: 10px; border-radius: 999px; overflow: hidden;
  background: rgba(255,255,255,.06); }
.reel-proc-bar .seg { height: 100%; }
.reel-proc-seg--pending { background: var(--rv-pending); }
.reel-proc-seg--ordered { background: var(--rv-ordered); }
.reel-proc-seg--shipped { background: var(--rv-shipped); }
.reel-proc-seg--on_site { background: var(--rv-onsite); }

/* Status dot — legend key + the marker in front of each progress row, so the
   color language reads even before hovering. */
.reel-dot { display: inline-block; width: .6rem; height: .6rem; border-radius: 50%;
  flex: 0 0 auto; background: var(--rv-onsite); }
.reel-dot--pending { background: var(--rv-pending); }
.reel-dot--ordered { background: var(--rv-ordered); }
.reel-dot--shipped { background: var(--rv-shipped); }
.reel-dot--onsite  { background: var(--rv-onsite); }
.reel-dot--cut     { background: var(--rv-cut); }
.reel-dot--pulled  { background: var(--rv-pulled); }
.reel-dot--tested  { background: var(--rv-tested); }
.reel-dot--set     { background: var(--rv-set); }
.reel-dot--termed  { background: var(--rv-termed); }
.reel-dot--torqued { background: var(--rv-torqued); }

/* Colour legend (one per dashboard) — colored dot + description. */
.reel-legend { display: flex; flex-wrap: wrap; gap: .4rem 1.25rem; align-items: center;
  font-size: .72rem; color: var(--muted, #9aa3ae); margin: -.25rem 0 1rem; }
.reel-legend-group { display: flex; flex-wrap: wrap; gap: .5rem .85rem; align-items: center; }
.reel-legend-label { text-transform: uppercase; letter-spacing: .06em; font-weight: 700;
  color: var(--text, #e9edf1); }
.reel-legend-item { display: inline-flex; align-items: center; gap: .35rem; }

/* Family card — ReelCard with progress inside */
.reel-family-card { border-left: 5px solid var(--fam, #ff7a00); height: 100%; }
.reel-family-card .card-body { padding: .7rem .8rem; }
.reel-fam-title { font-size: 1.02rem; font-weight: 800; letter-spacing: .01em; line-height: 1.15; }
.reel-fam-meta { font-size: .74rem; color: var(--muted, #9aa3ae); }
.reel-fam-icon {
  background: none; border: 0; color: var(--muted, #9aa3ae); cursor: pointer;
  padding: .1rem .25rem; line-height: 1; border-radius: 6px;
}
.reel-fam-icon:hover { color: var(--accent, #ff7a00); background: rgba(255,255,255,.06); }

/* In-card progress rows (text + % always present — never color-only) */
.reel-fam-prog { display: flex; align-items: center; gap: .5rem; margin: .2rem 0; font-size: .72rem; }
.reel-fam-prog .lbl { width: 4.2rem; flex: 0 0 auto; color: var(--muted, #9aa3ae);
  text-transform: uppercase; letter-spacing: .04em; }
.reel-fam-prog .track { flex: 1 1 auto; height: 8px; border-radius: 999px;
  background: rgba(255,255,255,.08); overflow: hidden; }
.reel-fam-prog .fill { display: block; height: 100%; border-radius: 999px; background: var(--rv-onsite); }
/* Per-metric fills match the status color language (see :root --rv-*). */
.reel-fam-prog .fill--onsite  { background: var(--rv-onsite); }
.reel-fam-prog .fill--cut     { background: var(--rv-cut); }
.reel-fam-prog .fill--pulled  { background: var(--rv-pulled); }
.reel-fam-prog .fill--tested  { background: var(--rv-tested); }
.reel-fam-prog .fill--set     { background: var(--rv-set); }
.reel-fam-prog .fill--termed  { background: var(--rv-termed); }
.reel-fam-prog .fill--torqued { background: var(--rv-torqued); }
/* Legacy variant aliases (kept so any other caller keeps working). */
.reel-fam-prog .fill--green { background: var(--rv-onsite); }
.reel-fam-prog .fill--blue  { background: var(--rv-shipped); }
.reel-fam-prog .pct { width: 6rem; flex: 0 0 auto; text-align: right; color: var(--text, #e9edf1);
  font-weight: 600; }

/* Family badge on reel cards / profiles */
.reel-fam-badge {
  display: inline-block; padding: 0 7px; border-radius: 999px;
  font-size: .6rem; font-weight: 800; text-transform: uppercase; letter-spacing: .03em;
  line-height: 1.5; white-space: nowrap; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; vertical-align: middle;
  background: var(--fam, #ff7a00); color: #0b0b0c;
}

/* Dashboard summary stat cards (ReelCard look, accent side bar) */
.reel-sum-card { border-left: 5px solid var(--accent, #ff7a00); }
/* Clickable progress cards drill into the Reel Board (new tab). */
a.reel-sum-link { text-decoration: none; color: inherit; cursor: pointer;
  transition: border-color .12s ease, transform .08s ease, box-shadow .12s ease; }
a.reel-sum-link:hover { border-left-color: var(--brand-primary, #ff7a00);
  box-shadow: 0 2px 10px rgba(0,0,0,.35); transform: translateY(-1px); }
a.reel-sum-link:hover .lbl { color: var(--brand-primary, #ff7a00); }
.reel-sum-card .num { font-size: 1.6rem; font-weight: 800; }
.reel-sum-card .lbl { font-size: .68rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted, #9aa3ae); }

/* Edit Family Mode banner */
.reel-fam-banner {
  position: sticky; top: 0; z-index: 1020; margin-bottom: 1rem;
  border: 1px solid var(--accent, #ff7a00); border-radius: 12px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent,#ff7a00) 22%, #15171b), #15171b);
  padding: .7rem .9rem; display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
}
.reel-fam-banner .ttl { font-weight: 800; }
.reel-fam-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 12px; align-items: stretch;
}

/* Lifecycle chips: Cut / Pulled / Termed / Tested (reel cards, material cards,
   profile). Text + ✓/— always present (never color-only). */
.reel-life { display: inline-flex; flex-wrap: wrap; gap: .25rem; }
.reel-life-chip {
  font-size: .58rem; font-weight: 800; text-transform: uppercase; letter-spacing: .03em;
  padding: .08rem .4rem; border-radius: 999px; white-space: nowrap;
  background: rgba(255,255,255,.06); color: var(--muted, #9aa3ae);
  border: 1px solid var(--border, #23252b);
}
.reel-life-chip.on { background: #14331f; color: #6ee7a0; border-color: #1f7a45; }

/* Single lifecycle progress bar + hover/tap/focus breakdown popover (reel
   cards, material cards). Order shown Cut → Pulled → Tested → Termed. */
.reel-life-bar { position: relative; cursor: pointer; outline: none; }
.reel-life-head { display: flex; justify-content: space-between; align-items: baseline;
  font-size: .62rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted, #9aa3ae); }
.reel-life-head .reel-life-pct { font-weight: 800; color: var(--text, #e9edf1); }
.reel-life-track { height: 8px; border-radius: 999px; background: rgba(255,255,255,.08);
  overflow: hidden; margin-top: 2px; }
.reel-life-fill { display: block; height: 100%; border-radius: 999px; background: var(--accent, #ff7a00); }
.reel-life-pop {
  display: none; position: absolute; z-index: 30; left: 0; bottom: 100%; margin-bottom: 6px;
  min-width: 13rem; padding: .5rem .6rem; border-radius: 10px;
  background: #15171b; border: 1px solid var(--border, #2d2d32);
  box-shadow: 0 8px 24px rgba(0,0,0,.5); color: var(--text, #e9edf1);
}
.reel-life-bar:hover .reel-life-pop,
.reel-life-bar:focus .reel-life-pop,
.reel-life-bar:focus-within .reel-life-pop,
.reel-life-bar.open .reel-life-pop { display: block; }
.reel-life-pop-title { font-size: .62rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted, #9aa3ae); margin-bottom: .25rem; }
.reel-life-row { display: flex; justify-content: space-between; gap: 1rem; font-size: .72rem; padding: .1rem 0; }
.reel-life-row.reel-life-overall { border-top: 1px solid var(--border, #2d2d32); margin-top: .2rem;
  padding-top: .25rem; font-weight: 800; }

/* Standardized reel/material card shell: a flex column whose footer pins the
   single lifecycle bar to the bottom edge. Cards show every feed (no clamping);
   a JS equalizer (see reel_list / job_detail) grows ALL cards on a board to the
   tallest so the grid stays uniform regardless of how much each card needs.
   The !important on display beats the material card's `d-block` utility, which
   would otherwise leave the card-body content-height and strand the footer just
   under the text instead of at the card's bottom edge. */
.reel-card, .reel-mat-card {
  display: flex !important; flex-direction: column; height: 100%;
}
.reel-card > .card-body, .reel-mat-card > .card-body {
  display: flex; flex-direction: column; flex: 1 1 auto;
}
.reel-card-footer, .reel-life-wrap { margin-top: auto; flex: 0 0 auto; }

/* ============================================================================
   Garage / VMR — ReelVault-aligned cards & profile.
   Lives in the global stylesheet (not garage.css) so the shared VMR card renders
   identically in the Garage app AND the Manpower review tab. Mirrors .reel-card:
   a 5px status-colored left edge (--edge), compact body, and the same type scale.
   ========================================================================== */
.gv-card {
  border-left: 5px solid var(--edge, #6c757d);
  height: 100%;
  transition: border-color .12s ease, box-shadow .15s ease, transform .1s ease;
}
.gv-card:hover { box-shadow: 0 6px 20px rgba(0,0,0,.35); transform: translateY(-2px); }
.gv-card .card-body { padding: .6rem .7rem; }
.gv-card .flex-fill { min-width: 0; }           /* let the text column shrink */

/* Title + meta type scale (matches .reel-no / .reel-len / .reel-type) */
.gv-no   { font-size: 1.2rem; font-weight: 800; line-height: 1.12; letter-spacing: .01em; }
.gv-sub  { font-size: .72rem; color: var(--muted, #9aa3ae); }
.gv-meta { font-size: .72rem; color: var(--muted, #9aa3ae); }
.gv-odo  { line-height: 1.05; margin-top: .1rem; }
.gv-odo-num  { font-size: 1.5rem; font-weight: 800; }
.gv-odo-unit { font-size: .8rem; font-weight: 700; }
.gv-odo-sub  { font-size: .62rem; color: var(--muted, #9aa3ae); }

/* Status pill — same shape/weight as .reel-proc, colored by tier. */
.gv-status {
  display: inline-block; font-size: .62rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .03em; padding: .18rem .5rem; border-radius: 999px; white-space: nowrap;
}
/* Single source of truth for color: RED is reserved for out-of-service (down).
   "Needs Attention" (needs_fix) is a service need → YELLOW, same as needs service. */
.gv-status--good, .gv-status--pass, .gv-status--reviewed       { background: #22c55e; color: #0b0b0c; }
.gv-status--service, .gv-status--warn, .gv-status--needs_fix   { background: #f59e0b; color: #0b0b0c; }
.gv-status--down, .gv-status--fail, .gv-status--shop          { background: #ef4444; color: #fff; }
.gv-status--tires, .gv-status--submitted                      { background: #3b82f6; color: #fff; }

/* Symbolic dark-mode action buttons: icon always visible; the label reveals on
   hover/focus (mirrors the .crew-icon-btn look, expanded to a labeled pill). */
.gv-act {
  display: inline-flex; align-items: center; border: 1px solid #2d2d32;
  background: #1b1e24; color: #9aa3ae; border-radius: 999px; height: 34px;
  padding: 0 11px; cursor: pointer;
  transition: color .12s ease, border-color .12s ease, background .12s ease;
}
.gv-act-ic  { font-size: 15px; line-height: 1; display: inline-flex; }
.gv-act-lbl {
  max-width: 0; opacity: 0; overflow: hidden; white-space: nowrap;
  font-size: .82rem; font-weight: 600;
  transition: max-width .2s ease, opacity .2s ease, margin .2s ease;
}
.gv-act:hover .gv-act-lbl, .gv-act:focus-visible .gv-act-lbl {
  max-width: 180px; opacity: 1; margin-left: 7px;
}
.gv-act--ok:hover,     .gv-act--ok:focus-visible     { color: #22c55e; border-color: #22c55e; background: rgba(34,197,94,.08); }
.gv-act--warn:hover,   .gv-act--warn:focus-visible   { color: #f59e0b; border-color: #f59e0b; background: rgba(245,158,11,.08); }
.gv-act--danger:hover, .gv-act--danger:focus-visible { color: #ef4444; border-color: #ef4444; background: rgba(239,68,68,.08); }
.gv-act--brand:hover,  .gv-act--brand:focus-visible  { color: var(--brand-primary, #ff7a00); border-color: var(--brand-primary, #ff7a00); background: rgba(255,122,0,.08); }

/* ReelProfile-style narrow column for the VMR review page. */
.gv-profile { max-width: 760px; }
.gv-checklist { list-style: none; padding: 0; margin: 0; }
.gv-checklist li {
  display: flex; align-items: center; gap: 10px; padding: 7px 12px;
  border-bottom: 1px solid rgba(255,255,255,.06); font-size: .85rem;
}
.gv-checklist li:last-child { border-bottom: none; }
.gv-checklist li.is-fail { background: rgba(239,68,68,.08); }
.gv-chk-ic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%; font-weight: 800;
  font-size: .8rem; flex: 0 0 22px;
}
.gv-chk-ic.is-pass { background: #22c55e; color: #06280f; }
.gv-chk-ic.is-fail { background: #ef4444; color: #2a0808; }
.gv-chk-label  { font-weight: 500; }
.gv-chk-status { margin-left: auto; font-size: .72rem; font-weight: 700; }
.gv-chk-status.is-pass { color: #22c55e; }
.gv-chk-status.is-fail { color: #ef4444; }

/* === Messenger icon badge (folded in from crew_overrides.css — audit F1b) === */
.messenger-icon {
  position: relative;
  display: inline-block;
  margin-right: 0.5rem;
}
.messenger-icon .bi-chat-dots {
  transition: color 0.2s ease;
}
.messenger-icon:hover .bi-chat-dots {
  color: var(--brand-primary,#ff7a00);
}
.messenger-badge {
  position: absolute;
  top: -6px;
  right: -10px;
  font-size: 0.7rem;
  padding: 0.2rem 0.35rem;
  line-height: 1;
}
