:root {
  --bg: #f6f7f9;
  --card: #ffffff;
  --ink: #1c2733;
  --muted: #5b6b7c;
  --brand: #0f5c8a;
  --line: #dfe3ea;
  --green: #2e7d32;
  --amber: #b26a00;
  --danger: #c0392b;
}
* { box-sizing: border-box; }
body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  margin: 0; background: var(--bg); color: var(--ink); line-height: 1.45;
}
.topbar {
  background: #0d3a54; color: #fff; padding: 12px 20px;
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
}
.topbar .brand { font-weight: 700; font-size: 1.05rem; color: #fff; text-decoration: none; }
.topbar nav { display: flex; gap: 14px; align-items: center; margin-left: auto; }
/* The log-out control is a POST form (Django 5 refuses GET logout), so its button has to carry the
   same look as the links beside it: a bare <button> arrives with a border, a background and the
   browser's own font. */
.topbar a, .topbar button { color: #e4eef6; text-decoration: none; padding: 4px 8px; border-radius: 4px; }
.topbar a:hover, .topbar button:hover { background: #1c5578; }
.topbar form { margin: 0; }
.topbar button { background: none; border: 0; font: inherit; cursor: pointer; }

/* The label on the map point for the record the page is about. Dark on light so it reads over any
   basemap, and it carries no arrow — it names the marker, it does not point at anything else. */
.map-current-label { background: #111827; color: #fff; border: 0; border-radius: 4px;
  padding: 2px 7px; font: 600 12px system-ui, sans-serif; box-shadow: 0 1px 4px rgba(0,0,0,.4); }
.map-current-label::before { display: none; }

/* A map popup is how a record gets opened in the field, so its name is a real tap target. Leaflet
   paints anchors inside a map its own blue, so the app's link colour is stated here; underlined
   because a phone has no hover to discover a link with; 44px tall for a gloved thumb, the same
   minimum the markup tools use. */
.leaflet-popup-content a.map-popup-link {
  color: var(--brand); text-decoration: underline;
  display: inline-block; min-height: 44px; line-height: 44px;
}
main { max-width: 1100px; margin: 0 auto; padding: 20px 16px; padding-bottom: 48px; }
.flash { background: #e8f4ec; border-left: 4px solid var(--green);
  padding: 10px 14px; margin-bottom: 14px; border-radius: 4px; }

.card { background: var(--card); border: 1px solid var(--line); border-radius: 8px;
  padding: 18px; box-shadow: 0 1px 2px rgba(20,30,50,.06); }
.page-head { display: flex; justify-content: space-between; align-items: center;
  gap: 12px; margin-bottom: 18px; flex-wrap: wrap; }
h1 { font-size: 1.45rem; }
h2 { font-size: 1.15rem; }

.pill { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: .78rem;
  background: #eef1f5; color: var(--muted); }
.pill.ok { background: var(--green); color: #fff; }
.pill.brand { background: var(--brand); color: #fff; }
.pill.warn { background: var(--amber); color: #fff; }
.pill.danger { background: var(--danger); color: #fff; }

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--line); }
th { font-size: .82rem; color: var(--muted); }
a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }

.btn { display: inline-block; background: var(--brand); color: #fff; border: 0;
  padding: 8px 14px; border-radius: 6px; font-size: .9rem; cursor: pointer; }
.btn:hover { background: #0a4a70; }
.btn.ghost { background: transparent; border: 1px solid var(--line); color: var(--ink); }
.btn.ghost:hover { background: #eef1f5; }

.grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.stat { font-size: 1.7rem; font-weight: 700; color: var(--brand); }
label { font-size: .85rem; font-weight: 600; color: var(--muted); display: block; margin-bottom: 4px; }
input, textarea, select { width: 100%; padding: 8px 10px; border: 1px solid var(--line);
  border-radius: 6px; font: inherit; font-size: .9rem; }
input[type=file] { padding: 8px; }
input[type=checkbox], input[type=radio] { width: auto; margin-right: 6px; }
form.filters { display: flex; gap: 12px; align-items: end; flex-wrap: wrap; }

.media { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.media img, .media .file { max-width: 100%; border: 1px solid var(--line); border-radius: 6px; }

.timeline { border-left: 2px solid var(--line); padding-left: 14px; }
.timeline .item { margin-bottom: 14px; }
.timeline .meta { font-size: .8rem; color: var(--muted); }

/* Sub-header tab bar. Wraps rather than scrolls on a wide screen: a tab that needs a sideways
   scroll to find is a tab nobody finds — the project bar is twelve tabs long now. The phone
   layout below puts it back to a single scrolling row, where wrapping would cost too much height. */
.tabs { display: flex; gap: 4px; border-bottom: 2px solid var(--line);
  margin: 4px 0 18px; overflow-x: auto; flex-wrap: wrap; }
.tab { padding: 9px 14px; text-decoration: none; color: var(--muted);
  border-bottom: 2px solid transparent; margin-bottom: -2px; white-space: nowrap; font-weight: 600; }
.tab:hover { color: var(--brand); }
.tab.active { color: var(--brand); border-bottom-color: var(--brand); }

.page-subhead { display: flex; justify-content: space-between; align-items: center;
  gap: 12px; margin-bottom: 12px; }
.page-subhead h2 { margin: 0; }

/* Clickable stat cards on the summary tab */
.stat-card { display: block; text-decoration: none; color: var(--ink); }
.stat-card .stat { font-size: 1.9rem; }
.stat-card .view-all { color: var(--brand); font-size: .85rem; margin-top: 4px; }
.stat-card:hover { border-color: var(--brand); }

/* Milestone substep rows */
.substep-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 8px 0; border-top: 1px solid var(--line); }
.substep-row:first-of-type { border-top: 0; }
.substep-name { min-width: 200px; flex: 1; }
.substep-field { display: flex; flex-direction: column; }
.substep-field input, .substep-field select { width: 130px; }
.substep-check label.noline { font-weight: 400; display: flex; align-items: center; gap: 4px; }
.done-check { display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%; background: var(--green);
  color: #fff; font-weight: 700; font-size: .95rem; }
.done-check.empty { background: var(--line); }

/* Unit codes are contract shorthand (P58D) — always shown next to the work
   description, since crews recognise the work, not the code. */
.unit-code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 600; font-size: .95em; letter-spacing: .01em; }
.unit-uom { font-size: .68rem; font-weight: 600; color: var(--muted); background: #eef1f5;
  border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; margin-left: 6px;
  vertical-align: middle; letter-spacing: .02em; }
.unit-desc { margin: 2px 0 6px; font-size: .85rem; color: var(--ink); opacity: .82; }
td .unit-desc { margin: 2px 0 0; font-size: .8rem; }

/* Job screen: units planned vs actually logged, per unit line. */
.unit-summary { display: flex; gap: 10px; flex-wrap: wrap; margin: 10px 0 4px; }
.unit-metric { flex: 1 1 150px; border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 12px; background: #fbfcfd; }
.unit-metric-value { display: block; font-size: 1.5rem; font-weight: 700; color: var(--brand);
  line-height: 1.15; }
.unit-metric-value.ok { color: var(--green); }
.unit-metric-value.pending { color: var(--amber); }
.unit-metric-label { font-size: .78rem; color: var(--muted); }
.unit-line { border-top: 1px solid var(--line); padding-top: 12px; margin-top: 12px; }
.unit-line-head { display: flex; flex-direction: column; gap: 2px; }
.unit-line-title { margin: 0; font-size: 1.05rem; display: flex; align-items: center;
  gap: 8px; flex-wrap: wrap; }
.unit-bar { height: 8px; border-radius: 999px; background: var(--line); overflow: hidden;
  margin: 8px 0 6px; }
.unit-bar-fill { height: 100%; background: var(--green); border-radius: 999px; }
.unit-figures { display: flex; gap: 18px; flex-wrap: wrap; font-size: .86rem; margin-bottom: 10px; }
.unit-figures .fig-label { color: var(--muted); font-size: .78rem; }
.unit-figures strong.ok, strong.ok { color: var(--green); }
.unit-figures strong.pending, strong.pending { color: var(--amber); }
.unit-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 14px; }
.unit-col { border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; background: #fff; }
.unit-col-title { margin: 0 0 6px; font-size: .82rem; text-transform: uppercase;
  letter-spacing: .03em; color: var(--muted); font-weight: 600; }
.unit-table { font-size: .86rem; }
.unit-table th { font-size: .74rem; }
.unit-empty { margin: 0; font-size: .84rem; color: var(--muted); }
.wl-ref { font-weight: 600; font-size: .84rem; }
tr:target { background: #fff8d9; }
.wl-ref + .meta { margin-top: 1px; }
.ok-strong { color: var(--green); font-weight: 600; }
.bad-strong { color: var(--danger); font-weight: 600; }

/* Cross-project lists: make the source project unmistakable in every row. */
.project-tag { display: inline-block; padding: 1px 9px; border-radius: 999px;
  background: #eef4fb; border: 1px solid #cddff0; color: var(--brand);
  font-size: .8rem; font-weight: 600; text-decoration: none; white-space: nowrap; }
.project-tag:hover { background: #e2edf9; border-color: var(--brand); }

/* Dashboard "needs attention" cards — every one is a link into the work. */
.attention-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 12px; }
.attention-card { display: block; text-decoration: none; color: var(--ink);
  background: var(--card); border: 1px solid var(--line); border-left: 4px solid var(--line);
  border-radius: 8px; padding: 12px 14px; transition: border-color .12s, box-shadow .12s; }
.attention-card:hover { box-shadow: 0 2px 8px rgba(0, 0, 0, .07); border-color: var(--brand); }
.attention-card.warn { border-left-color: var(--amber); }
.attention-card.danger { border-left-color: var(--danger); }
.attention-card.clear { opacity: .62; }
.attention-card.clear .attention-count { color: var(--muted); }
.attention-head { display: flex; align-items: baseline; gap: 10px; }
.attention-count { font-size: 1.8rem; font-weight: 700; color: var(--brand); line-height: 1.1; }
.attention-card.warn .attention-count { color: var(--amber); }
.attention-card.danger .attention-count { color: var(--danger); }
.attention-label { font-weight: 600; font-size: .92rem; }
.attention-detail { margin-top: 4px; font-size: .84rem; color: var(--ink); opacity: .85;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attention-hint { margin-top: 6px; font-size: .78rem; color: var(--muted); }

/* ---- Mobile: field crews on phones ---- */
@media (max-width: 640px) {
  .topbar { padding: 10px 12px; gap: 10px; }
  .topbar nav { gap: 6px; margin-left: 0; width: 100%; overflow-x: auto; }
  .topbar nav a, .topbar nav button { padding: 8px 10px; white-space: nowrap; }
  main { padding: 14px 10px; }
  .btn { width: 100%; padding: 12px 14px; font-size: 1rem; text-align: center; }
  .btn.ghost { width: 100%; }
  /* minimize vertical space for on-site forms */
  input, textarea, select { font-size: 16px; padding: 10px; }
  .pill { font-size: .72rem; }
  .grid { grid-template-columns: 1fr; }
  table { display: block; overflow-x: auto; white-space: nowrap; }
  .tabs { flex-wrap: nowrap; }
  .tab { padding: 10px 12px; }
  /* keep the mini-map usable */
  #project-map, #job-detail-map, #job-list-map, #asset-minimap, #asset-map { height: 220px !important; }
}

/* ---- Job scheduler calendar ---- */
.cal-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 10px 0 8px; }
.cal-title { margin-left: 6px; font-size: 1.25rem; font-weight: 600; }
.cal-filters { margin-left: auto; display: flex; gap: 6px; }
.cal { background: var(--card); border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }

/* Supporting text that should not compete with the record it describes. The mention list, the
   comment thread and the segment list all ask for this class, and it was never defined. */
.muted { color: var(--muted); }

/* The markup page's line picker: which line is picked, and where its units belong. */
.pick-status { margin: 8px 0 0; font-size: .82rem; color: var(--muted); }

/* The units row waiting for the picked line's units. sheet-markup.js toggles this on a row and the
   picker's own text tells the user to enter units "in the armed row" — so the row has to be visible.
   Styled on the cells rather than the row, because a background on a <tr> does not paint reliably. */
tr.armed > td { background: #eef5fa; }
tr.armed > td:first-child { box-shadow: inset 3px 0 0 var(--brand); }

.cal-head { display: grid; grid-template-columns: repeat(7, 1fr); background: #fff;
  border-bottom: 1px solid var(--line); }
.cal-head div { padding: 8px 10px; font-size: .82rem; font-weight: 400; color: var(--muted); }
.cal-head div.wknd { color: #9aa7b4; }

/* Each week is one row: day cells behind, event bars absolutely placed on top. */
.cal-week { position: relative; border-bottom: 1px solid var(--line);
  min-height: max(150px, calc(var(--lanes) * 30px + 40px)); }
.cal-week:last-child { border-bottom: 0; }
.cal-days { display: grid; grid-template-columns: repeat(7, 1fr); position: absolute; inset: 0; }
.cal-day { border-right: 1px solid var(--line); padding: 8px 10px 0; }
.cal-day:last-child { border-right: 0; }
.cal-day.wknd { background: #fbfcfd; }
.cal-day.out-of-month { background: #f7f8fa; }
.cal-day.today { background: #f3efff; box-shadow: inset 0 0 0 2px #7c5cff; }
.cal-day.drop-target { background: #e7f1fd; box-shadow: inset 0 0 0 2px var(--brand); }
.cal-daynum { font-size: .82rem; color: var(--muted); line-height: 1.2; }
.cal-day.today .cal-daynum { color: #5b3fa0; }
.daychip { display: inline-block; }
.cal-daystrip { height: 1px; }

/* Event bars: pastel fill + dark text (crew colour), stacked one lane every 30px. */
.cal-bars { position: absolute; inset: 34px 0 0 0; pointer-events: none; }
.cal-bar { position: absolute; height: 24px; border-radius: 3px; font-size: .78rem;
  text-decoration: none; padding: 3px 8px; overflow: hidden; white-space: nowrap;
  text-overflow: ellipsis; pointer-events: auto; cursor: grab;
  border: 1px solid transparent; border-left-width: 4px; line-height: 17px; }
.cal-bar:hover { filter: brightness(0.97); }
.cal-bar.cont-left { border-left-width: 1px; border-top-left-radius: 0; border-bottom-left-radius: 0; }
.cal-bar.cont-right { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.cal-bar.dragging { opacity: .45; }
.cal-bar.selected { outline: 2px solid #7c5cff; outline-offset: 1px; }
.cal-bar-label { pointer-events: none; font-weight: 500; }

.cal-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
  margin: 10px 0 4px; font-size: .82rem; color: var(--ink); }
.cal-legend span { display: inline-flex; align-items: center; gap: 6px; }
.cal-legend i { width: 16px; height: 12px; border-radius: 3px; display: inline-block;
  border: 1px solid var(--line); }
.cal-legend-note { color: var(--muted); font-size: .8rem; }
.unscheduled-list { display: flex; flex-wrap: wrap; gap: 8px; }
.chip { background: #eef1f5; border: 1px solid var(--line); border-radius: 999px;
  padding: 6px 12px; font-size: .84rem; cursor: grab; }
.chip .meta { color: var(--muted); font-size: .76rem; }

@media (max-width: 640px) {
  .cal-head div { font-size: .68rem; padding: 6px 3px; text-align: center; }
  .cal-week { min-height: max(110px, calc(var(--lanes) * 26px + 34px)); }
  .cal-day { padding: 6px 5px 0; }
  .cal-bar { font-size: .7rem; height: 22px; padding: 2px 5px; line-height: 16px; }
  .cal-bars { inset: 28px 0 0 0; }
  .cal-filters { width: 100%; margin-left: 0; }
  .cal-filters select { flex: 1; }
}
/* ------------------------------------------------------------------ workprints & markup */
/* The plan set on a job screen, and the phone screen the crew draws on. */

.notice { border-radius: 8px; padding: 10px 12px; margin: 10px 0; font-size: .9rem;
  background: #eef4fb; border: 1px solid var(--line); }
.notice.success { background: #e8f5e9; border-color: #a5d6a7; }
.notice.warning { background: #fff8e1; border-color: #ffe082; }
.notice.error { background: #fdecea; border-color: #f5c6cb; }

.linkbtn { display: inline-block; padding: 5px 10px; border-radius: 6px; font-size: .85rem;
  border: 1px solid var(--line); background: #fff; color: var(--fg); cursor: pointer;
  text-decoration: none; }
.linkbtn:hover { background: #f4f6f9; }
.linkbtn.danger { color: #b3261e; border-color: #f0c3bf; }

/* sheets attached to a job */
.sheet-strip { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 10px; }
.sheet-card { width: 320px; max-width: 100%; border: 1px solid var(--line); border-radius: 10px;
  overflow: hidden; background: #fff; }
.sheet-card > a { display: block; background: #f2f4f7; }
.sheet-card img { width: 100%; height: 190px; object-fit: contain; display: block;
  background: #fff; }
.sheet-card-body { padding: 10px; }
.sheet-card-body .meta { color: var(--muted); font-size: .78rem; margin: 3px 0; }
.sheet-actions { display: flex; gap: 8px; align-items: center; margin-top: 8px; flex-wrap: wrap; }

/* page picker */
.sheet-picker { display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.pick-cell { border: 1px solid var(--line); border-radius: 8px; padding: 6px; cursor: pointer;
  background: #fff; display: flex; flex-direction: column; gap: 6px; position: relative; }
.pick-cell.picked { border-color: #1565c0; box-shadow: 0 0 0 2px rgba(21,101,192,.18); }
.pick-cell input { position: absolute; top: 8px; left: 8px; width: 20px; height: 20px; }
.pick-cell img { width: 100%; height: 96px; object-fit: contain; background: #fff;
  border: 1px solid var(--line); border-radius: 4px; }
.pick-placeholder { height: 96px; display: flex; align-items: center; justify-content: center;
  background: #f2f4f7; border-radius: 4px; color: var(--muted); font-size: .8rem; }
.pick-label { font-size: .8rem; line-height: 1.35; }
.pick-label strong { display: inline-block; min-width: 16px; }
.pick-label em { display: block; color: var(--muted); font-style: normal; font-size: .74rem; }

/* one sheet on its own screen */
.sheet-frame { background: #f2f4f7; border: 1px solid var(--line); border-radius: 8px;
  padding: 8px; overflow: auto; max-height: 74vh; }
.sheet-image { width: 100%; height: auto; display: block; background: #fff; }
.over { color: #b3261e; font-weight: 600; }

/* the markup screen */
.markup-head { display: flex; justify-content: space-between; align-items: flex-start;
  gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.markup-head-right { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.markup-stage { position: relative; background: #fff; border: 1px solid var(--line);
  border-radius: 8px; overflow: auto; max-height: 62vh; touch-action: pan-x pan-y pinch-zoom; }
.markup-stage img { display: block; width: 100%; height: auto; }
#sheet-canvas { position: absolute; top: 0; left: 0; touch-action: none; }
.markup-tools { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0; }
.tool { display: inline-flex; align-items: center; gap: 6px; padding: 11px 14px;
  border: 1px solid var(--line); border-radius: 8px; background: #fff; font-size: .9rem;
  cursor: pointer; min-height: 44px; }
.tool.active { background: #1565c0; color: #fff; border-color: #1565c0; }
.tool-icon { font-size: 1rem; line-height: 1; }
.markup-note-row { margin-bottom: 8px; }
.markup-note-row input { width: 100%; padding: 12px; font-size: 16px; border-radius: 8px;
  border: 1px solid var(--line); }
.markup-hint { color: var(--muted); font-size: .84rem; margin: 4px 0 12px; }
.markup-units .units-table { width: 100%; }
.qty-input { width: 90px; padding: 10px; font-size: 16px; border: 1px solid var(--line);
  border-radius: 6px; text-align: right; }
.markup-save { display: flex; align-items: center; gap: 12px; margin: 14px 0 30px; }
.btn.big { padding: 15px 22px; font-size: 1.02rem; }
.markup-status { color: var(--muted); font-size: .88rem; }

@media (max-width: 640px) {
  .markup-stage { max-height: none; }
  .sheet-card { width: 100%; }
  .sheet-card img { height: 150px; }
}

/* "Not allocated to this job" block on the markup screen: the crew can report units the plan
   has not allocated yet, and it has to read as a deliberate, secondary option. */
.markup-other { margin-top: 14px; border-top: 1px dashed var(--line); padding-top: 10px; }
.markup-other summary { cursor: pointer; font-weight: 600; font-size: .92rem; padding: 6px 0;
  min-height: 40px; }
.markup-other .units-table { margin-top: 8px; }
.warn-note { color: #b26a00; font-weight: 600; font-size: .78rem; text-transform: uppercase;
  letter-spacing: .02em; }

/* FW-2: work that could not reach the server, kept on the phone. Shown on every page (the base
   template), because a queued drawing has to be visible from wherever the crew is standing — it
   sends itself on a timer, with or without an "online" event, since a LAN-only server and a phone
   with wifi off looks perfectly online to the browser. */
.offline-queue-note {
  background: #b26a00; color: #fff; padding: 9px 12px; border-radius: 8px;
  font-size: .88rem; margin: 10px 0;
}

/* The unit log is the one form a crew member fills in standing up, in gloves, on a phone. Everything
   here is for that: 16px inputs (anything smaller makes iOS Safari zoom in the moment the field is
   tapped), 44px targets, and a full-width button a thumb can find without looking. */
.unit-entry label { display: block; font-weight: 600; margin-top: 12px; }
.unit-entry input, .unit-entry select { width: 100%; min-height: 44px; font-size: 16px; }
.unit-entry input[type="file"] { min-height: 0; padding: 8px 0; font-size: 14px; }
.unit-entry input[type="checkbox"] { width: auto; min-height: 0; }
.unit-entry .btn { width: 100%; padding: 13px; font-size: 1rem; margin-top: 14px; }
#unit-line-filter { margin-bottom: 2px; }
