/* CFSI Field Forms - mobile first. Brand: navy #262261, orange #F6921E, grey #808184 */
:root {
  --navy: #262261;
  --navy-dark: #1b1848;
  --orange: #F6921E;
  --grey: #808184;
  --ink: #1d1d26;
  --muted: #5f6070;
  --line: #d9dae2;
  --bg: #f4f5f9;
  --panel: #ffffff;
  /* A shade behind a heading or a count, darker than the page so it still reads as
     a band when it sits on the page background rather than on a white panel. */
  --tint: #eceef6;
  --good: #17794a;
  --bad: #b3261e;
  --radius: 10px;
  --tap: 48px;
}

* { box-sizing: border-box; }

/* Author rules that set `display` override the browser's own [hidden] rule, which
   is how the site search came to hide nothing at all. Keep this above everything. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: "Segoe UI", Roboto, -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  padding-bottom: env(safe-area-inset-bottom);
}

a { color: var(--navy); }

/* ---------- chrome ---------- */
.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 10px 16px;
  background: var(--navy); color: #fff;
  padding-top: calc(10px + env(safe-area-inset-top));
}
.topbar__brand img { display: block; height: 34px; width: auto; }
.topbar__nav { display: flex; align-items: center; gap: 14px; flex-wrap: nowrap; }
/* A button that reads as a link. The white belongs to the top bar it was written
   for - inherited anywhere else it renders white on white, which is how the
   "open this device" link on the test run came to be invisible. Colour comes from
   whatever it sits in unless the top bar says otherwise. */
.topbar__nav a, .linkish {
  color: inherit; text-decoration: none; font-weight: 600; font-size: 15px;
  background: none; border: 0; padding: 6px 2px; cursor: pointer; font-family: inherit;
  /* Five links and a logo do not fit across a phone. Without this each one wraps
     onto two lines and the bar doubles in height on the screen with least of it
     to spare. */
  white-space: nowrap;
}
@media (max-width: 560px) {
  .topbar { gap: 8px; padding-left: 12px; padding-right: 12px; }
  .topbar__brand img { height: 26px; }
  .topbar__nav { gap: 10px; }
  .topbar__nav a, .linkish { font-size: 13.5px; padding: 6px 0; }
}
@media (max-width: 400px) {
  .topbar__nav { gap: 8px; }
  .topbar__nav a, .linkish { font-size: 13px; }
}
.topbar { color: #fff; }
.topbar__nav a, .topbar .linkish { color: #fff; }
/* Outside the bar it is a link and should look like one. */
.linkish { color: var(--navy); text-decoration: underline; text-underline-offset: 3px; }
.topbar__nav a, .topbar .linkish { text-decoration: none; }
.topbar__nav a:hover, .linkish:hover { color: var(--orange); }
.inline { display: inline; margin: 0; }

.wrap { max-width: 860px; margin: 0 auto; padding: 18px 16px 120px; }
.wrap--wide { max-width: 1180px; }

.footer { padding: 18px 16px 28px; text-align: center; color: var(--muted); font-size: 13px; }

/* ---------- typography ---------- */
h1 { font-size: 24px; margin: 0 0 4px; color: var(--navy); }
h2 { font-size: 19px; margin: 28px 0 10px; color: var(--navy); }
h3 { font-size: 16px; margin: 0 0 8px; }
.lede { color: var(--muted); margin: 0 0 20px; }
.eyebrow { text-transform: uppercase; letter-spacing: .08em; font-size: 12px;
  font-weight: 700; color: var(--orange); margin: 0 0 2px; }

/* ---------- panels ---------- */
.panel {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px; margin-bottom: 14px;
}
.panel--flush { padding: 0; overflow: hidden; }
/* A panel sitting inside a table row: no border or margin of its own, because the row
   already provides both and a second frame inside a table reads as a mistake. */
.panel--bare { border: 0; background: transparent; margin: 0; padding: 8px 12px; }
/* The running yearly figure beside the continuing extras. Quiet, but not a hint: it is
   the number a client is deciding on. */
.opt__running { margin: 10px 0 0; font-size: 14px; }
.lineedit > td { background: var(--panel); border-top: 0; }
.panel__head { padding: 12px 16px; background: #fbfbfd; border-bottom: 1px solid var(--line); }
.panel__head h2 { margin: 0; font-size: 17px; }
.panel__body { padding: 16px; }
.section-intro { color: var(--muted); font-size: 14px; margin: 0 0 14px; }

.notice { border-left: 4px solid var(--orange); background: #fff8ee; padding: 12px 14px;
  border-radius: 6px; margin-bottom: 16px; font-size: 14px; }
.notice--warn { border-left-color: #b8860b; background: #fffaf0; }
.is-muted td { opacity: 0.62; }
.alert { border-left: 4px solid var(--bad); background: #fdf1f0; padding: 12px 14px;
  border-radius: 6px; margin-bottom: 16px; }
.alert ul { margin: 8px 0 0; padding-left: 20px; }
.success { border-left: 4px solid var(--good); background: #eef7f2; padding: 12px 14px;
  border-radius: 6px; margin-bottom: 16px; }

/* ---------- forms ---------- */
.grid { display: grid; gap: 14px; grid-template-columns: 1fr; }
@media (min-width: 720px) {
  .grid { grid-template-columns: repeat(6, 1fr); }
  .f--half { grid-column: span 3; }
  .f--third { grid-column: span 2; }
  .f--two-thirds { grid-column: span 4; }
  .f--full { grid-column: span 6; }
}
.field { display: flex; flex-direction: column; gap: 6px; grid-column: 1 / -1; }
@media (min-width: 720px) { .field { grid-column: span 6; } }
label { font-weight: 600; font-size: 14px; }
.req { color: var(--bad); }
.hint { font-size: 13px; color: var(--muted); }

input[type=text], input[type=email], input[type=password], input[type=number],
input[type=date], input[type=time], input[type=search], select, textarea {
  width: 100%; font: inherit; color: var(--ink);
  padding: 12px; min-height: var(--tap);
  border: 1px solid var(--line); border-radius: 8px; background: #fff;
}
textarea { min-height: 96px; resize: vertical; }
input:focus, select:focus, textarea:focus, button:focus-visible {
  outline: 3px solid rgba(38,34,97,.35); outline-offset: 1px; border-color: var(--navy);
}
.prefilled { background: #f7f8fc; }

/* segmented yes/no/na - large touch targets */
.seg { display: flex; gap: 8px; flex-wrap: wrap; }
.seg input { position: absolute; opacity: 0; width: 0; height: 0; }
.seg label {
  flex: 1 1 0; min-width: 78px; min-height: var(--tap);
  display: flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--line); border-radius: 8px; background: #fff;
  font-weight: 700; cursor: pointer; user-select: none;
}
.seg input:checked + label { color: #fff; }
/* Every value that can be checked needs a background. The rule above turns the label's
   text white the moment it is selected, so a value with no background of its own
   renders white on white and the button appears blank - which is exactly what the Pass
   button on the device page did. This catch-all makes that impossible; the named
   colours below beat it on specificity. */
.seg input:checked + label { background: var(--navy); border-color: var(--navy); }
.seg input[value=yes]:checked + label,
.seg input[value=pass]:checked + label { background: var(--good); border-color: var(--good); }
.seg input[value=no]:checked + label,
.seg input[value=fail]:checked + label { background: var(--bad); border-color: var(--bad); }
.seg input[value=na]:checked + label,
.seg input[value=not_tested]:checked + label,
.seg input[value=skip]:checked + label { background: var(--grey); border-color: var(--grey); }
.seg input:focus-visible + label { outline: 3px solid rgba(38,34,97,.35); }

/* checklist */
.check { border-bottom: 1px solid var(--line); padding: 14px 16px; }
.check:last-child { border-bottom: 0; }
.check__ref { font-weight: 700; color: var(--orange); font-size: 13px; }
.check__label { margin: 2px 0 10px; }
.check__note { margin-top: 10px; }
.check[data-flag="no"] { background: #fdf5f4; }

/* count / grid tables */
/* `position: relative` is not decoration. An absolutely positioned descendant is only
   clipped by an ancestor that is its containing block, so a `.visually-hidden` label
   inside a wide table escaped this box entirely and stretched the whole page sideways -
   a phone that scrolled 900px to the right and showed nothing. Making this the
   containing block keeps everything inside the scroller where it belongs. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; position: relative; }
.table-scroll table { min-width: 560px; }
table.data td.ref, table.data th.ref { width: 1%; white-space: nowrap; }
table.data td.result, table.data th.result { width: 1%; white-space: nowrap; text-align: center; }
table.data td.flag-no { background: #fdeceb; color: var(--bad); }
table.data { width: 100%; border-collapse: collapse; font-size: 15px; }
table.data th, table.data td { border: 1px solid var(--line); padding: 8px; text-align: left; vertical-align: middle; }
table.data th { background: #fbfbfd; font-size: 13px; }
table.data input { min-height: 42px; padding: 8px; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: var(--tap); padding: 12px 20px; border-radius: 8px;
  font: inherit; font-weight: 700; text-decoration: none; cursor: pointer;
  border: 1.5px solid transparent; background: var(--navy); color: #fff;
}
.btn:hover { background: var(--navy-dark); }
.btn--accent { background: var(--orange); color: #23180a; }
.btn--accent:hover { background: #e0820f; }
.btn--ghost { background: #fff; color: var(--navy); border-color: var(--navy); }
/* These need the :hover specificity to beat .btn:hover, or a ghost button
   turns solid navy the moment it is touched. */
.btn--ghost:hover, .btn--ghost:focus { background: #eef0f7; color: var(--navy); }
.btn--danger { background: #fff; color: var(--bad); border-color: var(--bad); }
.btn--danger:hover, .btn--danger:focus { background: #fdf1f0; color: var(--bad); }
.btn[disabled] { opacity: .55; cursor: progress; }
.btn--block { width: 100%; }
.btn--sm { min-height: 38px; padding: 6px 12px; font-size: 14px; }

/* The bar pinned to the bottom of a form. Most pages put two buttons in it and
   it behaves like any other row. The form-filling page puts four controls and a
   save indicator in it, which will not fit across a 390px phone on one line, so
   that variant stacks the indicator above the buttons and shrinks them. */
.actionbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  display: flex; gap: 10px; align-items: center;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  background: rgba(255,255,255,.97); border-top: 1px solid var(--line);
  box-sizing: border-box;
}
.actionbar .btn { flex: 1 1 auto; min-width: 0; white-space: nowrap; }
.actionbar__status { font-size: 13px; color: var(--muted); flex: 0 0 auto; min-width: 84px; }

.actionbar--form { display: block; }
.actionbar--form .actionbar__status {
  display: block; min-width: 0; margin: 0 0 6px;
  font-size: 12px; text-align: center; line-height: 1.2;
}
.actionbar__actions { display: flex; gap: 8px; align-items: center; }
/* Nothing in here may overflow the screen: the sign-off button is the one control
   an engineer must always be able to reach. */
.actionbar__actions .btn {
  /* Sized by their own labels, not by an equal share: an equal share is what
     clipped "Devices" on a 320px handset. The sign-off button takes whatever is
     left over, so it is always the largest target on the bar. */
  flex: 0 1 auto; min-width: 0; padding: 12px 8px; font-size: 14px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block;
  line-height: 24px;
}
.actionbar__actions .actionbar__primary { flex: 1 1 auto; }

@media (max-width: 360px) {
  .actionbar { padding-left: 8px; padding-right: 8px; }
  .actionbar__actions { gap: 6px; }
  .actionbar__actions .btn { padding-left: 6px; padding-right: 6px; }
}

.scanner {
  position: fixed; inset: 0; z-index: 90; background: #000;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  padding: 20px calc(20px + env(safe-area-inset-right)) calc(20px + env(safe-area-inset-bottom))
           calc(20px + env(safe-area-inset-left));
}
.scanner video { width: 100%; max-width: 520px; border-radius: var(--radius); background: #111; }
.scanner__hint { color: #fff; margin: 0; font-size: 15px; text-align: center; }

.tickbox { display: flex; align-items: center; gap: 10px; font-weight: 600;
  min-height: var(--tap); cursor: pointer; }
.tickbox input[type=checkbox] { width: 24px; height: 24px; flex: 0 0 auto; }
.tickbox input[type=radio] { width: 22px; height: 22px; flex: 0 0 auto; }
.tickbox--block { align-items: flex-start; border: 1px solid var(--line); border-radius: 8px;
  padding: 10px 12px; margin-bottom: 8px; background: #fff; font-weight: 400; }
.tickbox--block span strong { font-weight: 600; }
.scan-row { display: flex; gap: 8px; align-items: stretch; }
.scan-row input { flex: 1 1 auto; }
.scan-row .btn { flex: 0 0 auto; }

/* ---------- the point-of-work check: eight rows, two taps each ---------- */
.riskcheck { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.riskcheck__row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 12px; border-bottom: 1px solid var(--line);
}
.riskcheck__row:last-child { border-bottom: 0; }
.riskcheck__label { flex: 1 1 180px; min-width: 0; font-size: 15px; }
.seg--tight { flex: 0 0 auto; gap: 6px; }
.seg--tight label { min-width: 58px; min-height: 42px; font-size: 15px; }

/* ---------- line items: parts used, and anything else counted ---------- */
.lines { list-style: none; margin: 0; padding: 0; }
.lines li {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--line);
}
.lines li:last-child { border-bottom: 0; }
.lines__qty {
  flex: 0 0 auto; min-width: 44px; font-weight: 700; color: var(--navy);
  background: #eef0f7; border-radius: 6px; padding: 4px 8px; text-align: center;
}
.lines__what { flex: 1 1 auto; min-width: 0; }
.lines form { flex: 0 0 auto; }
.empty { color: var(--muted); margin: 0; }

/* ---------- a radio that is a whole readable choice, not a dot ---------- */
.choice {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 12px; border: 1.5px solid var(--line); border-radius: 8px;
  margin-bottom: 8px; cursor: pointer; font-weight: 400;
}
.choice input { width: 24px; height: 24px; flex: 0 0 auto; margin-top: 2px; }
.choice:has(input:checked) { border-color: var(--navy); background: #f7f8fc; }
.choice .hint { display: block; }

.btn-row { display: flex; flex-wrap: wrap; gap: 10px; }
.btn-row .btn { flex: 1 1 auto; }

/* ---------- a device's life, tests and changes interleaved ---------- */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { border-bottom: 1px solid var(--line); padding: 12px 16px; }
.timeline li:last-child { border-bottom: 0; }
.timeline__when { font-size: 13px; color: var(--muted); }
.timeline__what { font-weight: 700; margin: 2px 0; }
.timeline__what .tag { margin-left: 6px; }
.timeline--event { background: #fbfaff; }
.tag {
  display: inline-block; font-size: 12px; font-weight: 700; padding: 2px 8px;
  border-radius: 999px; background: #eef0f7; color: var(--navy); vertical-align: middle;
}
.tag--pass { background: #e6f4ec; color: var(--good); }
.tag--fail { background: #fdeceb; color: var(--bad); }
.tag--change { background: #fff1de; color: #8a5300; }
.tag--muted { background: #f1f1f4; color: var(--muted); }
.tag--warn { background: #fff1de; color: #8a5300; }

/* ---------- lists ---------- */
.cards { display: grid; gap: 10px; }
.card {
  display: block; background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px 16px; text-decoration: none; color: inherit;
}
.card:hover { border-color: var(--navy); }
.card__title { display: block; font-weight: 700; color: var(--navy); }
.card__meta { display: block; font-size: 14px; color: var(--muted); margin-top: 2px; }
label.card { cursor: pointer; }
/* A card that is itself the button - used where choosing it does something rather
   than selecting something. Reset the browser's own button styling first. */
.card--button {
  width: 100%; text-align: left; cursor: pointer; font: inherit;
  appearance: none; -webkit-appearance: none;
}
label.card:has(input:checked) { border-color: var(--navy); box-shadow: inset 0 0 0 2px var(--navy); }
label.card input[type=radio] { margin-right: 8px; transform: scale(1.3); accent-color: var(--navy); }
.badge {
  display: inline-block; font-size: 12px; font-weight: 700; padding: 2px 8px;
  border-radius: 999px; background: #eceef6; color: var(--navy); margin-left: 6px;
}
.badge--draft { background: #fff2df; color: #8a5200; }
.badge--done { background: #e6f3ec; color: var(--good); }

.progress { height: 8px; background: #e7e8f0; border-radius: 999px; overflow: hidden; margin-top: 8px; }
.progress span { display: block; height: 100%; background: var(--orange); }

/* ---------- signature ---------- */
.sigpad {
  width: 100%; height: 220px; background: #fff; border: 2px dashed var(--line);
  border-radius: 8px; touch-action: none; display: block;
}
.sigpad--signed { border-style: solid; border-color: var(--good); }
.sig-proof { border: 1px solid var(--line); border-radius: 8px; padding: 10px; background: #fff; }
.sig-proof img { max-height: 110px; }

/* ---------- photos ---------- */
.thumbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
.thumb { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; background: #fff; }
.thumb img { width: 100%; height: 120px; object-fit: cover; display: block; }
.thumb figcaption { padding: 8px; font-size: 13px; }

/* ---------- misc ---------- */
.kv { display: grid; grid-template-columns: 1fr; gap: 2px 16px; margin: 0; }
@media (min-width: 620px) { .kv { grid-template-columns: 200px 1fr; } }
.kv dt { font-weight: 600; color: var(--muted); font-size: 14px; }
.kv dd { margin: 0 0 8px; }
.kv--tight dd { margin: 0 0 2px; }
.kv--tight dt { font-size: 13px; }
@media (min-width: 620px) { .kv--tight { grid-template-columns: 160px 1fr; } }

/* ---------- the job timeline ---------- */
.story { list-style: none; margin: 0; padding: 0; }
.story li { position: relative; padding: 0 0 18px 26px; border-left: 2px solid var(--line); }
.story li:last-child { border-left-color: transparent; padding-bottom: 0; }
.story li::before { content: ""; position: absolute; left: -7px; top: 3px; width: 12px;
  height: 12px; border-radius: 50%; background: var(--line); border: 2px solid #fff; }
.story li.is-good::before { background: #1f8b4c; }
.story li.is-bad::before { background: #c0392b; }
.story li.is-warn::before { background: #d38b00; }
.story__when { font-size: 13px; color: var(--muted); margin: 0; }
.story__what { margin: 2px 0 0; font-weight: 600; }
.story__detail { margin: 2px 0 0; font-size: 14px; }
.story__who { font-size: 13px; color: var(--muted); }

/* ---------- the morning list ---------- */
.digest { margin-bottom: 20px; }
.digest__head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.digest__count { background: var(--line); border-radius: 20px; padding: 1px 10px;
  font-size: 13px; font-weight: 600; }
.digest--bad .digest__count { background: #f6d7d3; color: #8c2d20; }
.stat-row { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
.stat { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 14px; }
.stat b { display: block; font-size: 26px; color: var(--navy); line-height: 1.1; }
.stat span { font-size: 13px; color: var(--muted); }
.toolbar { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 14px; }
.toolbar input, .toolbar select { flex: 1 1 200px; width: auto; max-width: 320px; }
.empty { text-align: center; color: var(--muted); padding: 28px 12px; }

/* ---------- permissions editor ---------- */
.perms { display: grid; gap: 8px; grid-template-columns: 1fr; }
@media (min-width: 780px) { .perms { grid-template-columns: 1fr 1fr; } }
.perm {
  display: flex; gap: 10px; align-items: flex-start;
  border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px;
  background: #fff; font-weight: 400; cursor: pointer;
}
.perm:hover { border-color: var(--navy); }
.perm input { margin-top: 3px; width: 20px; height: 20px; accent-color: var(--navy); flex: 0 0 auto; }
.perm strong { font-size: 14px; }
.perm:has(input:checked) { border-color: var(--navy); background: #f7f8fc; }

/* ---------- repeating tables ---------- */
.repeat { margin: 0; }
.repeat__table th.narrow, .repeat__table td.narrow { width: 90px; }
.repeat [data-add-row] { margin-top: 10px; }
.repeat table.data input, .repeat table.data select { min-height: 44px; }

/* ---------- photo attachment from the action bar ---------- */
.actionbar__photo { position: relative; }
.actionbar__photo .count {
  position: absolute; top: 2px; right: 2px; min-width: 18px; height: 18px;
  line-height: 18px !important;
  border-radius: 999px; background: var(--orange); color: #23180a;
  font-size: 12px; line-height: 20px; text-align: center; font-weight: 700;
}
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
.photo-status { font-size: 13px; color: var(--muted); margin: 8px 0 0; }
.search-count { font-size: 14px; color: var(--muted); margin: 0 0 10px; }

/* ---------- floor plans and device pins ---------- */
.planwrap { position: relative; display: block; overflow: auto; background: #f0f1f6; }
.planwrap img { display: block; width: 100%; height: auto; }
.planwrap--edit { cursor: crosshair; }
.pin {
  position: absolute; transform: translate(-50%, -50%);
  min-width: 30px; height: 30px; padding: 0 6px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px; border: 2px solid #fff;
  background: var(--grey); color: #fff;
  font-size: 12px; font-weight: 800; text-decoration: none;
  box-shadow: 0 1px 4px rgba(0,0,0,.35); cursor: pointer; user-select: none;
}
.pin--pass { background: var(--good); }
.pin--fail { background: var(--bad); }
.pin--na, .pin--not_tested { background: var(--navy); }
.pin--placed { background: var(--navy); }
.pin--selected { outline: 3px solid var(--orange); }
.place-target { text-align: left; font: inherit; cursor: pointer; width: 100%; }
.place-target.is-active { border-color: var(--orange); box-shadow: inset 0 0 0 2px var(--orange); }

/* ---------- the device round ---------- */
.device {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px 16px;
}
.device__head { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.device__ref { font-weight: 800; color: var(--navy); font-size: 17px; text-decoration: none; }
.device__meta { font-size: 14px; color: var(--muted); margin-top: 2px; }
.device__last { font-size: 13px; color: var(--muted); text-align: right; flex: 0 0 auto; }
.device__actions { display: flex; gap: 8px; margin-top: 12px; }
.device__actions .btn { flex: 1 1 0; }
.device[data-done="pass"] { border-left: 4px solid var(--good); }
.device[data-done="fail"] { border-left: 4px solid var(--bad); }

/* ---------- navigation ---------- */
.topbar__search { flex: 1 1 200px; max-width: 340px; margin: 0 4px; }
.topbar__search input {
  width: 100%; min-height: 38px; padding: 6px 12px; font-size: 15px;
  border-radius: 999px; border: 1px solid rgba(255,255,255,.35);
  background: rgba(255,255,255,.12); color: #fff;
}
.topbar__search input::placeholder { color: rgba(255,255,255,.65); }
.topbar__search input:focus {
  background: #fff; color: var(--ink); border-color: var(--orange); outline: none;
}
@media (max-width: 560px) { .topbar__search { display: none; } }

.crumbs {
  max-width: 1180px; margin: 0 auto; padding: 10px 16px 0;
  font-size: 13px; color: var(--muted);
}
.crumbs a { color: var(--muted); }
.crumbs span { margin: 0 6px; color: var(--line); }

/* ---------- quick action tiles ---------- */
.quick { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.quick__tile {
  display: flex; flex-direction: column; gap: 2px; justify-content: center;
  min-height: 72px; padding: 14px 16px; border-radius: var(--radius);
  background: #fff; border: 1px solid var(--line); text-decoration: none; color: var(--navy);
  font-weight: 700;
}
.quick__tile span { font-weight: 400; font-size: 13px; color: var(--muted); }
.quick__tile:hover { border-color: var(--navy); }
.quick__tile--primary { background: var(--orange); border-color: var(--orange); color: #23180a; }
.quick__tile--primary span { color: #4a3a17; }
.quick__tile--primary:hover { background: #e0820f; border-color: #e0820f; }

/* ---------- last visit's reading, shown but never filled in ---------- */
.hint--was { margin: 2px 0 0; color: var(--muted); }
.was { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }

.ref-code {
  font-family: ui-monospace, Menlo, Consolas, monospace; letter-spacing: .08em;
  background: #eef0f7; padding: 2px 8px; border-radius: 6px;
}

.code {
  background: #1d1d26; color: #eef0f7; padding: 14px; border-radius: 8px;
  overflow-x: auto; font-size: 12.5px; line-height: 1.5; margin: 0;
  font-family: ui-monospace, Menlo, Consolas, monospace;
}
code { background: #eef0f7; padding: 1px 5px; border-radius: 4px; font-size: 92%; }
.code code { background: none; padding: 0; }

.card--flat {
  border: 0; border-top: 1px solid var(--line); border-radius: 0; margin: 0;
  padding: 12px 14px;
}
.picklist .card--flat:first-of-type { border-top: 1px solid var(--line); }

/* ---------- the standby battery calculation ---------- */
.battery { }
.battery__result {
  margin-top: 12px; padding: 14px 16px; border-radius: var(--radius);
  border: 1.5px solid var(--line); background: #fbfbfd;
}
.battery__result--pass { border-color: var(--good); background: #eef7f2; }
.battery__result--fail { border-color: var(--bad); background: #fdf1f0; }
.battery__verdict { margin: 0; font-weight: 700; font-size: 17px; color: var(--navy); }
.battery__result--pass .battery__verdict { color: var(--good); }
.battery__result--fail .battery__verdict { color: var(--bad); }
.battery__figures { margin: 4px 0 0; }
.battery__figures:empty { display: none; }
.battery__working {
  margin: 8px 0 0; font-size: 13px; color: var(--muted); line-height: 1.5;
}
.battery__working:empty { display: none; }

/* ---------- tick-box groups: more than one answer is the point ---------- */
.opts { display: grid; gap: 8px; grid-template-columns: 1fr; }
@media (min-width: 620px) { .opts { grid-template-columns: repeat(2, 1fr); } }
.opt {
  display: flex; flex-direction: column;
  border: 1.5px solid var(--line); border-radius: 8px; background: #fff;
  padding: 4px 0;
}
.opt__box {
  display: flex; align-items: center; gap: 12px; padding: 8px 12px;
  min-height: var(--tap); cursor: pointer; font-weight: 700; margin: 0;
}
.opt__box input { width: 24px; height: 24px; flex: 0 0 auto; }
.opt:has(input:checked) { border-color: var(--navy); background: #f7f8fc; }
/* The note only matters once the box is ticked. Where :has() is unsupported it
   simply stays visible, which is untidy rather than broken. */
.opt > .opt__note {
  /* the type selector on inputs sets width:100%, which with side margins pushed the
     note past its own card; two classes outrank it, and the calc subtracts them */
  display: none; margin: 0 12px 8px; width: calc(100% - 24px);
}
.opt:has(input:checked) > .opt__note { display: block; }

/* ---------- switching between the dashboards ---------- */
.viewswitch {
  display: flex; gap: 4px; padding: 4px; margin-bottom: 16px;
  background: #eef0f7; border-radius: 10px;
}
.viewswitch__tab {
  flex: 1 1 0; min-width: 0; text-align: center; padding: 10px 8px;
  border-radius: 7px; text-decoration: none; color: var(--navy); font-weight: 700;
  font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-height: 42px; display: flex; align-items: center; justify-content: center;
}
.viewswitch__tab--on { background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.08); }
.viewswitch__tab:hover { color: var(--navy-dark); }

/* ---------- the day list ---------- */
.daynav { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.daynav .btn { flex: 0 1 auto; }

.job { display: flex; gap: 12px; align-items: flex-start; }
.job__when {
  flex: 0 0 auto; min-width: 58px; font-weight: 700; color: var(--navy);
  background: #eef0f7; border-radius: 8px; padding: 8px 6px; text-align: center;
  font-size: 14px; line-height: 1.2;
}
.job__body { flex: 1 1 auto; min-width: 0; }
.job__note { display: block; margin-top: 6px; font-size: 13px; color: var(--muted); }

.badge--planned { background: #eef0f7; color: var(--navy); }
.badge--in_progress { background: #fff1de; color: #8a5300; }
.badge--done { background: #e6f4ec; color: var(--good); }
.badge--cancelled { background: #f1f1f4; color: var(--muted); }

/* A fortnight at a glance, so the office can see where the week is filling up. */
.strip { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 6px; margin-bottom: 16px;
  -webkit-overflow-scrolling: touch; }
.strip__day {
  flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 1px;
  min-width: 56px; padding: 8px 6px; border: 1px solid var(--line); border-radius: 8px;
  background: #fff; text-decoration: none; color: var(--ink);
}
.strip__day--on { border-color: var(--navy); background: #f7f8fc; }
.strip__dow { font-size: 12px; color: var(--muted); text-transform: uppercase; }
.strip__num { font-size: 18px; font-weight: 700; color: var(--navy); }
.strip__count { font-size: 12px; color: var(--muted); }

/* A long list of forms to tick, grouped so it is not one scroll of fifty. */
.picklist details {
  border: 1px solid var(--line); border-radius: 8px; margin-bottom: 8px; background: #fff;
}
.picklist summary {
  padding: 12px 14px; font-weight: 700; cursor: pointer; min-height: var(--tap);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.picklist .tickbox { padding: 10px 14px; border-top: 1px solid var(--line); font-weight: 400; }
.picklist .tickbox span { font-weight: 600; }

.card--static { cursor: default; }

/* ---------- counted tiles: what came out of a visit ---------- */
.tiles { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  margin-bottom: 18px; }
.tile {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; padding: 14px 10px; background: #fff; border: 1px solid var(--line);
  border-radius: var(--radius); text-align: center;
}
.tile__number { font-size: 26px; font-weight: 700; color: var(--navy); line-height: 1.1; }
.tile__label { font-size: 13px; color: var(--muted); }

/* ---------- the bin ---------- */
.danger-zone { border: 1px solid var(--bad); border-radius: var(--radius); padding: 16px; background: #fffafa; }
.danger-zone h2 { color: var(--bad); margin-top: 0; }


/* ---------- what is waiting to send ----------
   Sits above the action bar, out of the way of the buttons, and disappears entirely
   once the queue is empty. An engineer should never have to wonder where their work
   went. */
.outbox {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
  background: #3a3320; color: #ffe9b8; font-size: 13.5px; font-weight: 600;
  box-shadow: 0 -2px 10px rgba(0,0,0,.18);
}
.outbox[data-online="1"] { background: #1f3326; color: #d7f2e0; }
.outbox__what { flex: 1 1 auto; min-width: 0; }
.outbox__send {
  flex: 0 0 auto; font: inherit; padding: 6px 12px; border-radius: 6px;
  border: 1px solid currentColor; background: transparent; color: inherit; cursor: pointer;
}
/* The action bar is also fixed to the bottom; lift it clear so neither hides the other. */
body:has(.outbox:not([hidden])) .actionbar { bottom: 46px; }
.badge--queued { background: #fff1de; color: #8a5300; }


/* ---------- the test run ----------
   One device filling the screen, and two buttons big enough to hit with a gloved
   thumb without looking. Everything here is sized for somebody holding a test pole
   in the other hand. */
.run__top {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  margin-bottom: 8px;
}
.run__count { margin: 2px 0 0; font-size: 15px; color: var(--muted); }
.run__count strong { color: var(--navy); font-size: 20px; }
.run__zones { display: flex; gap: 8px; overflow-x: auto; padding: 10px 0 4px; }
.chip {
  flex: 0 0 auto; padding: 7px 14px; border-radius: 999px; font-size: 14px;
  font-weight: 700; background: #eef0f7; color: var(--navy); text-decoration: none;
  border: 1.5px solid transparent; white-space: nowrap;
}
.chip--on { background: var(--navy); color: #fff; }

.run__card { margin: 14px 0 0; }
.run__device {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 22px 18px; min-height: 240px;
  display: flex; flex-direction: column; justify-content: center; text-align: center;
}
.run__ref {
  margin: 0; font-size: 14px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--orange);
}
.run__where { margin: 6px 0 4px; font-size: 30px; line-height: 1.15; color: var(--navy); }
.run__what { margin: 0; font-size: 16px; color: var(--ink); }
.run__last { margin: 10px 0 0; font-size: 14px; color: var(--muted); }
.run__state { margin: 12px 0 0; min-height: 26px; }
.run__more { margin-top: 14px; font-size: 14px; color: var(--navy); }

.run__buttons { display: flex; gap: 10px; margin-top: 16px; }
.run__btn {
  flex: 1 1 0; min-height: 74px; font-size: 20px; font-weight: 800; border-radius: 12px;
}
.run__btn--skip { flex: 0 0 88px; font-size: 16px; font-weight: 700; }
.btn--good { background: var(--good); border-color: var(--good); color: #fff; }
.btn--good:hover, .btn--good:focus { background: #135f3a; border-color: #135f3a; color: #fff; }

.run__nav {
  display: flex; align-items: center; justify-content: space-between;
  margin: 14px 0 96px; font-size: 15px; color: var(--muted);
}
.run__nav .linkish { color: var(--navy); }
/* The card fills what is left of the screen rather than leaving a hole under it. */
.run__device { min-height: min(46vh, 340px); }

/* On a wider screen the card can breathe rather than stretching to fill a desktop. */
@media (min-width: 700px) {
  .run__device { min-height: 300px; }
  .run__where { font-size: 38px; }
}


/* ---------- before you go ----------
   The two or three things that change what an engineer takes or expects, above the
   fold, with everything else folded away behind a summary. A briefing nobody reads
   is worse than no briefing, because it looks like the information was given. */
.brief {
  border: 1.5px solid var(--navy); border-radius: var(--radius); background: #fbfbfe;
  padding: 14px 16px; margin-bottom: 16px;
}
.brief__head {
  margin: 0 0 8px; font-size: 15px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--orange);
}
.brief__list { margin: 0; padding-left: 20px; }
.brief__list li { margin-bottom: 6px; font-size: 15.5px; line-height: 1.45; }
.brief__more { margin-top: 12px; }
.brief__more summary {
  cursor: pointer; font-weight: 700; color: var(--navy); padding: 6px 0;
  min-height: var(--tap); display: flex; align-items: center;
}
.brief__body h3 {
  margin: 16px 0 6px; font-size: 15px; color: var(--navy);
}
.brief__body h3:first-child { margin-top: 6px; }


/* ---------- reading it on site ----------
   Two problems, both real and neither solved by a dark mode: bright sunlight on a
   phone, and gloves. "Bigger" raises the type and the tap targets across the whole
   application; "Sharper" raises the contrast for a screen being read at arm's length
   in daylight. Both are per device and remembered, because it is a property of the
   person and their phone rather than of their account. */
body.reading--big {
  font-size: 18.5px;
  --tap: 56px;
}
body.reading--big .btn { font-size: 17.5px; padding: 14px 18px; }
body.reading--big input, body.reading--big select, body.reading--big textarea {
  font-size: 18px; min-height: 54px;
}
body.reading--big .card__title { font-size: 18px; }
body.reading--big .card__meta, body.reading--big .hint { font-size: 15.5px; }
body.reading--big table.data { font-size: 16.5px; }
body.reading--big .check__label { font-size: 17.5px; }

body.reading--sharp {
  --line: #6f7186;
  --muted: #3a3b48;
  --bg: #ffffff;
}
body.reading--sharp .panel, body.reading--sharp .card, body.reading--sharp .opt {
  border-width: 2px;
}
body.reading--sharp .hint { color: #3a3b48; }
body.reading--sharp .btn { border-width: 2px; font-weight: 800; }

.reading {
  display: flex; gap: 6px; align-items: center;
  margin: 0 0 14px; flex-wrap: wrap;
}
.reading__label { font-size: 13px; color: var(--muted); margin-right: 4px; }

/* ---------- speaking instead of typing ---------- */
.dictate {
  position: absolute; right: 8px; bottom: 8px;
  width: 40px; height: 40px; border-radius: 50%;
  border: 1.5px solid var(--line); background: #fff; cursor: pointer;
  font-size: 18px; line-height: 1; display: flex; align-items: center;
  justify-content: center; color: var(--navy);
}
.dictate[data-on="1"] { background: var(--bad); border-color: var(--bad); color: #fff; }
/* 2.22.4. Whether this browser transcribes on the device or streams the audio to its
   vendor's speech service. Said on the control rather than buried in a policy nobody
   reads: an engineer about to describe a client's server room is entitled to know
   where their voice is going before they press it, and the answer differs by browser
   rather than by anything we control. */
.dictate[data-local="0"] { border-style: dashed; }
.field { position: relative; }
.field:has(> textarea) > .dictate { display: flex; }

/* ---------- the next thing still to answer ---------- */
.jumper {
  position: fixed; right: 12px; bottom: 78px; z-index: 40;
  padding: 10px 14px; border-radius: 999px; border: 0;
  background: var(--navy); color: #fff; font: inherit; font-weight: 700;
  font-size: 14px; box-shadow: 0 3px 12px rgba(0,0,0,.22); cursor: pointer;
}
.jumper[hidden] { display: none !important; }
.field--wanted, .check--wanted {
  outline: 3px solid var(--orange); outline-offset: 4px; border-radius: 6px;
}

.verifycode {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 24px; font-weight: 700; letter-spacing: 2px; color: var(--navy);
  margin: 0 0 8px;
}

/* A retired catalogue item is still shown - it is on old quotations - but it should
   not read as something you can sell today. */
.row--muted td { opacity: .6; }

/* ---------- the week board ----------
   A grid of engineers by days. It has to survive being read on an office monitor and
   glanced at on a phone, so the table scrolls sideways rather than reflowing into
   something unreadable, and every cell says its state in words as well as colour -
   a board that only uses colour tells a colour-blind planner nothing. */
.board { min-width: 900px; width: 100%; border-collapse: collapse; }
.board th, .board td { border: 1px solid var(--line); vertical-align: top; padding: 8px; }
.board thead th { background: #f0f1f6; text-align: center; font-size: 13px; }
.board__who { background: #f8f8fb; text-align: left; min-width: 150px; font-size: 14px; }
.board__today { background: #e9e7f5; }
.cell { min-width: 190px; }
.cell__why { margin: 0 0 6px; font-size: 12px; color: var(--muted); font-weight: 700; }
.cell--free { background: #ffffff; }
.cell--tight { background: #fff8ec; }
.cell--full { background: #fdeceb; }
.cell--part { background: #f7f4ff; }
.cell--off, .cell--away { background: #f1f1f4; }
.cell--off .cell__why, .cell--away .cell__why { color: #6a6b78; }
.cell__drop { display: flex; gap: 4px; margin-top: 6px; }
.cell__pick { flex: 1 1 auto; min-width: 0; font-size: 12px; padding: 4px; }

.jobchip {
  display: block; text-decoration: none; color: var(--ink); background: #fff;
  border: 1px solid var(--line); border-left: 4px solid var(--navy);
  border-radius: 6px; padding: 6px 8px; margin-bottom: 6px; font-size: 13px;
}
.jobchip b { display: block; }
.jobchip span { display: block; color: var(--muted); font-size: 12px; }
.jobchip__meta { font-size: 11px; }
.jobchip--in_progress { border-left-color: var(--orange); }
.jobchip--done { border-left-color: var(--good); opacity: .7; }

.inline-form { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.opts--inline { display: flex; flex-wrap: wrap; gap: 10px; }
.label-ish { font-weight: 600; font-size: 14px; }

/* ---------- the map ---------- */
.map { height: 62vh; min-height: 380px; border: 1px solid var(--line);
  border-radius: var(--radius); }
@media (max-width: 720px) { .map { height: 55vh; } }

/* A quantity box beside a suggested line. Narrow on purpose - it holds "3", not a
   sentence - and it must not inherit the full-width rule that input[type=text] carries
   everywhere else, which is exactly the bug the note fields hit in 1.0.0. */
.qty-box { width: 5em; }
.opt__note-wrap { display: inline-block; margin: 0 0 8px 26px; }

/* ---------- the office navigation ----------
   A column beside every office page on a desktop, a disclosure at the top of the page
   on a phone. Same markup either way: the phone version is not a second navigation,
   it is this one with the list collapsed, because two navigations disagree eventually.

   Deliberately no `hidden` attribute and no `!important`. An earlier draft hid the
   list with `hidden` and then had to fight the global `[hidden] { display: none }`
   rule to show it again on a desktop, which is the sort of thing that works until
   somebody adds a stylesheet. Class and media query only. */
.shell { display: block; }

.officenav__toggle {
  display: block; text-align: left; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px;
  font: inherit; font-weight: 700; color: var(--navy); min-height: var(--tap);
  margin: 14px 16px 0; width: calc(100% - 32px); cursor: pointer;
}
.officenav__toggle::after { content: " ▾"; color: var(--muted); }
.officenav--open .officenav__toggle::after { content: " ▴"; }
.officenav__body { display: none; padding: 6px 16px 0; }
.officenav--open .officenav__body { display: block; }

.officenav__title {
  margin: 14px 0 4px; font-size: 12px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
}
.officenav__list { list-style: none; margin: 0; padding: 0; }
.officenav__link {
  display: block; padding: 9px 10px; border-radius: 6px; text-decoration: none;
  color: var(--ink); font-size: 15px; line-height: 1.3; min-height: var(--tap);
}
.officenav__link:hover { background: #eceef6; }
.officenav__link--here {
  background: var(--navy); color: #fff; font-weight: 700;
}
.officenav__link--here:hover { background: var(--navy-dark); color: #fff; }

@media (min-width: 980px) {
  .shell--office { display: flex; align-items: flex-start; gap: 0; }
  .shell--office > .wrap { max-width: none; flex: 1 1 auto; min-width: 0; }
  .officenav {
    flex: 0 0 236px; align-self: stretch; background: #fbfbfd;
    border-right: 1px solid var(--line); padding: 8px 10px 60px;
    position: sticky; top: 0; max-height: 100vh; min-height: 100vh; overflow-y: auto;
  }
  .officenav__toggle { display: none; }
  .officenav__body { display: block; padding: 0; }
  .officenav__title:first-child { margin-top: 10px; }
}

/* A filter button that is currently on. Used on the contracts and quotations lists,
   where "which filter am I looking at" is otherwise guesswork. */
.btn--on { background: var(--navy); color: #fff; border-color: var(--navy); }
.btn--on:hover { background: var(--navy-dark); color: #fff; }

/* ---------- the Office front door ----------
   It used to be twenty-six identical cards in one column: everything equally
   prominent, which is another way of saying nothing was. It now opens with the
   handful of things somebody can act on today, and the pages sit underneath in
   groups. */
.attention__head { margin-top: 4px; }
.attention { list-style: none; margin: 0 0 24px; padding: 0; display: grid; gap: 8px; }
.attention__row { border: 1px solid var(--line); border-left: 4px solid var(--muted);
  border-radius: var(--radius); background: var(--panel); }
.attention__row--bad { border-left-color: var(--bad); }
.attention__row--warn { border-left-color: var(--orange); }
.attention__row--info { border-left-color: var(--grey); }
.attention__link {
  display: flex; gap: 14px; align-items: center; padding: 12px 14px;
  text-decoration: none; color: var(--ink); min-height: var(--tap);
}
.attention__link:hover { background: #f6f7fb; }
.attention__count {
  flex: 0 0 auto; min-width: 46px; text-align: center; font-size: 22px;
  font-weight: 700; color: var(--navy);
}
.attention__what { display: block; min-width: 0; }
.attention__what b { display: block; font-size: 15px; }
.attention__what span { display: block; font-size: 13px; color: var(--muted); }

.officesec { margin-bottom: 26px; }
.officesec__title { margin: 0 0 2px; }
.officesec__blurb { margin: 0 0 12px; color: var(--muted); font-size: 14px; }
.officesec__title--all { margin-top: 30px; padding-top: 20px; border-top: 2px solid var(--line); }

/* ---------- the office, folded ----------
   details/summary, so the folding is the browser's own and works with the script
   absent. The script only remembers which ones were left open. */
.officefold {
  border: 1px solid var(--line); border-radius: var(--radius); background: #fff;
  margin-bottom: 10px;
}
.officefold__head {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; align-items: center;
  padding: 14px 16px; cursor: pointer; list-style: none; min-height: var(--tap);
  border-radius: var(--radius);
}
.officefold__head::-webkit-details-marker { display: none; }
.officefold__title { font-weight: 700; font-size: 17px; color: var(--navy); }
.officefold__count {
  grid-row: 1; justify-self: end; font-size: 13px; font-weight: 700; color: var(--muted);
  background: var(--tint); border-radius: 999px; padding: 2px 10px; min-width: 28px;
  text-align: center;
}
.officefold__blurb { grid-column: 1 / -1; font-size: 14px; color: var(--muted); }
.officefold[open] > .officefold__head {
  border-bottom: 1px solid var(--line); border-radius: var(--radius) var(--radius) 0 0;
  background: var(--tint);
}
.officefold__head:hover .officefold__title { text-decoration: underline; }
.officefold__head:focus-visible { outline: 3px solid var(--orange); outline-offset: -3px; }
.officefold__body { padding: 14px 16px; }

/* Jump straight to a group without reading the others. */
.jumpbar { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; }
.jumpbar__link {
  font-size: 14px; font-weight: 600; text-decoration: none; color: var(--navy);
  border: 1px solid var(--line); border-radius: 999px; padding: 6px 12px; background: #fff;
}
.jumpbar__link:hover { border-color: var(--navy); background: var(--tint); }

/* ---------- pinning a page ----------
   The card is a link and the star is a button, so they cannot be nested. The card
   becomes the positioning context and the star sits in its corner. */
.card { position: relative; }
.card__body { display: block; text-decoration: none; color: inherit; padding-right: 30px; }
.card__pinform { position: absolute; top: 8px; right: 8px; margin: 0; }
.pin {
  appearance: none; -webkit-appearance: none; background: none; border: 0; cursor: pointer;
  font-size: 20px; line-height: 1; color: var(--muted); padding: 4px 6px; border-radius: 6px;
}
.pin:hover { color: var(--orange); background: var(--tint); }
.pin--on { color: var(--orange); }
.pin:focus-visible { outline: 3px solid var(--orange); outline-offset: 1px; }
.card--pinned { border-color: var(--orange); }
.officesec--pinned .cards { margin-bottom: 4px; }
.officenav__title--pinned { color: var(--orange); }
@media (min-width: 760px) {
  .cards--two { grid-template-columns: 1fr 1fr; }
}

.panel--news { border-left: 4px solid var(--orange); margin-bottom: 22px; }
.news__body { font-size: 14px; }
.news__body h3 { font-size: 15px; margin: 14px 0 4px; }
.news__body ul { margin: 6px 0 0; padding-left: 20px; }

/* The map on the Office page. Shorter than the full one - it is there to answer "where
   is everybody" at a glance, not to be worked in, and it must not push the rest of the
   page below the fold. */
.map--dash { height: 320px; min-height: 260px; }
@media (max-width: 720px) { .map--dash { height: 240px; min-height: 200px; } }

/* A photograph the engineer took, chosen for a quotation line. Small, because the
   point is to recognise it rather than to study it - the client sees it full size on
   the quotation itself. */
.photopick { display: flex; flex-wrap: wrap; gap: 8px; }
.photopick__one { display: block; cursor: pointer; }
.photopick__one img, .photopick__none {
  display: block; width: 92px; height: 70px; object-fit: cover;
  border: 3px solid var(--line); border-radius: 6px;
}
.photopick__none {
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; color: var(--muted); background: #f4f5f9;
}
.photopick__one input { position: absolute; opacity: 0; width: 0; height: 0; }
.photopick__one input:checked + img,
.photopick__one input:checked + .photopick__none { border-color: var(--navy); }
.photopick__one input:focus-visible + img,
.photopick__one input:focus-visible + .photopick__none { outline: 3px solid var(--orange); }
.linethumb { max-width: 120px; border-radius: 4px; margin-top: 6px; }

/* A photograph on a quotation. Wide enough for a facilities manager to recognise their
   own damaged equipment on a phone, which is the entire point of putting it there. */
.quotephoto { max-width: 260px; width: 100%; border-radius: 6px; margin-top: 8px;
  border: 1px solid var(--line); }

/* ---------- moving a job on the week board ----------
   The chip is two things: a link that opens the job, and a handle that picks it up to
   move. Both need to be obviously themselves, because getting the wrong one on a busy
   Monday means losing your place. */
.jobchip { position: relative; }
.jobchip__open { display: block; text-decoration: none; color: inherit; }
.jobchip__move {
  position: absolute; top: 4px; right: 4px; font: inherit; font-size: 11px;
  font-weight: 700; line-height: 1; padding: 4px 7px; cursor: grab;
  background: #eef0f7; color: var(--navy); border: 1px solid var(--line);
  border-radius: 999px;
}
.jobchip__move:hover { background: var(--navy); color: #fff; }
.jobchip__move[aria-pressed="true"] { background: var(--orange); color: #1d1d26;
  border-color: var(--orange); }
.jobchip[draggable="true"] { cursor: grab; }

/* While something is being carried, every day is a target and says so. */
.board--moving .cell { outline: 1px dashed var(--line); outline-offset: -3px; }
.board--moving .cell:hover, .cell--over {
  background: #fff6e8; outline: 2px solid var(--orange); outline-offset: -3px;
}
.board--moving .cell--off, .board--moving .cell--away { opacity: .75; }

.moving {
  position: sticky; top: 0; z-index: 5; display: flex; gap: 12px; align-items: center;
  flex-wrap: wrap; background: var(--navy); color: #fff; padding: 10px 14px;
  border-radius: var(--radius); margin-bottom: 10px;
}
.moving__what { font-weight: 700; }
.moving__how { color: #cfd0e4; font-size: 14px; }
.moving .btn { margin-left: auto; background: #fff; }

/* ---------- type-to-search on a long list ----------
   Wrapped around the real select, which stays in the form and stays what is
   submitted. With the JavaScript absent the select is simply visible and works. */
.combo { position: relative; }
.combo__native { display: none; }
.combo__input { width: 100%; }
.combo__list {
  position: absolute; z-index: 20; left: 0; right: 0; top: 100%;
  margin: 2px 0 0; padding: 4px; list-style: none; max-height: 260px;
  overflow-y: auto; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: 0 6px 20px rgba(29, 29, 38, .14);
}
.combo__item {
  padding: 9px 10px; border-radius: 6px; cursor: pointer; font-size: 15px;
  min-height: var(--tap); display: flex; align-items: center;
}
.combo__item--on, .combo__item:hover { background: var(--navy); color: #fff; }
.combo__none { padding: 9px 10px; color: var(--muted); font-size: 14px; }
.combo__chosen { margin: 6px 0 0; font-size: 13px; color: var(--muted); font-weight: 600; }
.combo__input--wrong { border-color: var(--bad); box-shadow: 0 0 0 3px rgba(180, 35, 45, .12); }
.combo__input--wrong + .combo__list + .combo__chosen { color: var(--bad); }
/* 2.15.0. The search box that reloads the page, for a browser with the script off.
   It is a real control, not a placeholder: it stays visible and stays working if the
   script never arrives, and app.js hides it only once the live picker has actually
   attached. Two boxes doing the same job is worse than one. */
.combo-fallback { margin-bottom: 14px; padding-bottom: 14px;
                  border-bottom: 1px dashed var(--line); }
.combo-fallback .f--actions { display: flex; align-items: flex-end; gap: 8px; }
/* A search that is showing every match it has says nothing; one that has more to give
   says so here rather than leaving somebody to wonder. */
.combo__more { padding: 8px 10px; font-size: 13px; color: var(--muted);
               border-top: 1px solid var(--line); margin-top: 4px; }
/* ---------- a panel lifted into a pop-up ----------
   The panel is in the page first and only becomes this if the script runs, so with
   the script blocked these rules simply never apply to anything. */
.sheet {
  border: 0; border-radius: var(--radius); padding: 0; width: min(760px, 94vw);
  max-height: 88vh; box-shadow: 0 18px 50px rgba(29, 29, 38, .28);
  background: var(--panel); color: inherit;
}
.sheet::backdrop { background: rgba(29, 29, 38, .45); }
.sheet__head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 18px; border-bottom: 1px solid var(--line);
  position: sticky; top: 0; background: var(--panel); z-index: 1;
}
.sheet__title { margin: 0; font-size: 18px; }
.sheet__body { padding: 18px; overflow-y: auto; max-height: calc(88vh - 60px); }
.dialog__open { margin-bottom: 12px; }

/* ---------- the number you are working against, in the bar that already exists ----
   NOT a second fixed bar. This page already has an .actionbar pinned to the bottom and
   a page may only have one: a second lands directly on top of the first. That is a
   lesson this codebase has already learned once, written in a comment in the template,
   and it was learned again here - the browser suite caught two bars stacked. So the
   totals went into the bar that was there. */
.summarybar__row {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px;
  flex: 1 1 auto; min-width: 0;
}
.summarybar__item { display: flex; align-items: baseline; gap: 5px; font-size: 13px; }
.summarybar__item b { font-size: 16px; }
.summarybar__item span { color: var(--muted); }
.actionbar--under { border-top: 3px solid var(--bad); }
.actionbar--under .summarybar__flag { color: var(--bad); font-weight: 700; }
@media (max-width: 700px) {
  /* On a phone the figures wrap onto their own line above the buttons rather than
     squeezing them off the edge, which is the fault that cost a release once. */
  .actionbar { flex-wrap: wrap; }
  .summarybar__row { flex: 1 0 100%; }
}

/* The commonest items, as one-press buttons. Deliberately NOT called .chip - that
   class already exists as a filter link on the portfolio and quotations pages, and
   these rules would have quietly restyled both. Found by the browser suite's contrast
   check, which is the only thing that would have found it. */
.quickpick { display: flex; flex-wrap: wrap; gap: 6px; }
.quickpick__item {
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  border-radius: 999px; padding: 8px 12px; font: inherit; font-size: 13px;
  cursor: pointer; min-height: var(--tap);
}
.quickpick__item:hover, .quickpick__item:focus {
  background: var(--navy); color: #fff; border-color: var(--navy);
}
.pricemoved { font-weight: 600; }
.gp__note { margin-top: 4px; font-weight: 600; color: var(--muted); min-height: 1em; }
.pager { display: flex; align-items: center; gap: 12px; margin: 0 0 18px; }
.pager .hint { margin: 0; }

/* The margin line in a quotation's totals. Under the floor it says so in colour as
   well as in words, because the number is the whole point of the row. */
.marginrow th, .marginrow td { background: var(--tint); }
.marginrow--under th, .marginrow--under td { background: #fdeceb; color: var(--bad); }

/* ---------- getting out of where you are ----------
   One row under the top bar carrying Back and Home. Back's href is "up", worked out
   on the server, and the script turns it into browser history where there is any -
   so it is a working link before any script runs, which is the point. */
.pagenav {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 16px; background: var(--panel); border-bottom: 1px solid var(--line);
}
.backlink {
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px;
  color: var(--navy); font-weight: 600; font-size: 15px; text-decoration: none;
  padding: 4px 2px;
}
.backlink:hover { text-decoration: underline; text-underline-offset: 3px; }
.backlink:focus-visible { outline: 3px solid var(--orange); outline-offset: 2px; }
.backlink--home { color: var(--muted); }
@media (max-width: 460px) {
  .pagenav { padding-left: 12px; padding-right: 12px; }
  /* "Back to the quotations list" is useful on a desktop and is the thing that
     wraps the row on a phone. The arrow and the word carry it there. */
  .backlink__where { display: none; }
}

/* A row of secondary page actions. Deliberately not `.actionbar`, which is the fixed
   bar at the foot of the screen and of which there may only ever be one per page -
   a second one lands on top of the first and makes both unusable. */
.toolbar--actions { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line); }
.toolbar--actions form { margin: 0; }

/* ---------- sections on a quotation ---------- */
.grouphead {
  display: flex; gap: 12px; align-items: flex-start; justify-content: space-between;
  padding: 12px 14px; background: var(--tint); border-bottom: 1px solid var(--line);
  border-radius: var(--radius) var(--radius) 0 0;
}
.grouphead__title { margin: 0; font-size: 17px; color: var(--navy); }
.grouphead__blurb { margin: 4px 0 0; font-size: 14px; color: var(--muted); }
.grouphead__tools { display: flex; gap: 6px; align-items: flex-start; flex: 0 0 auto; }
.groupedit summary { list-style: none; cursor: pointer; }
.groupedit summary::-webkit-details-marker { display: none; }
.groupedit[open] { display: block; width: 100%; }
.linetools { white-space: nowrap; }
.linetools .inline-form { display: inline-flex; gap: 4px; margin: 0 4px 0 0; }
.tiny-select { width: auto; min-width: 110px; display: inline-block; padding: 6px 8px; }
/* The drag handle. It is a decoration on top of buttons that already work, so it is
   drawn only where dragging is possible and never carries the behaviour alone. */
.grip { cursor: grab; color: var(--muted); margin-right: 6px; user-select: none; }
tr.dragging { opacity: .45; }
tr.dropinto td { box-shadow: inset 0 2px 0 var(--orange); }

/* The price of a whole section, on the client's copy. Large, because on a section
   sold as one piece of work it is the only price there is. */
.grouphead__price {
  font-size: 20px; font-weight: 700; color: var(--navy); white-space: nowrap;
  flex: 0 0 auto;
}

/* ---------- the engineer's day ---------- */
.leg { margin: 2px 0 2px 4px; font-size: 13px; color: var(--muted); }
.brief { margin: -4px 0 10px; border-color: var(--line); }
.brief summary { cursor: pointer; font-size: 14px; }
.brief p { margin: 8px 0 0; font-size: 14px; }
.brief__why { color: var(--navy); }
.brief__list { margin: 6px 0 0 18px; font-size: 14px; }

/* ---------- plain text we are showing verbatim (an order, a letter) ---------- */
pre.plain { white-space: pre-wrap; word-wrap: break-word; font: inherit;
  background: var(--wash, #f7f7fa); border: 1px solid var(--line); border-radius: 8px;
  padding: 14px; margin: 10px 0 0; }
.row--flag > td { background: #fdf3f1; }
.btn.is-on { background: var(--navy); color: #fff; border-color: var(--navy); }

/* A multiple-answer question is a group of controls, not one control. */
fieldset.field { border: 0; margin: 0; padding: 0; }
fieldset.field > legend { font-weight: 600; font-size: 14px; padding: 0; margin-bottom: 6px; }

/* ---------- the jump bar on a long working page ---------- */
.jump { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 16px;
  padding: 8px; background: #fff; border: 1px solid var(--line);
  border-radius: var(--radius); position: sticky; top: 0; z-index: 5; }
.jump a { display: inline-block; padding: 6px 10px; border-radius: 6px;
  font-size: 14px; font-weight: 600; text-decoration: none; color: var(--navy);
  background: var(--wash, #f6f7fb); }
.jump a:hover, .jump a:focus { background: var(--navy); color: #fff; }
/* An anchored heading must not land under the sticky bar. */
[id] { scroll-margin-top: 64px; }
@media (max-width: 620px) { .jump { position: static; } }

/* ---------- the engineer's own day, drawn ---------- */
.map--day { height: 260px; border: 1px solid var(--line); border-radius: var(--radius);
  margin-bottom: 14px; }
@media (min-width: 720px) { .map--day { height: 340px; } }
.daypin span { display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%; background: var(--navy);
  color: #fff; font-weight: 700; font-size: 14px; border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.35); }
.stops { list-style: none; margin: 0; padding: 0; }
.stops li { display: flex; gap: 12px; padding: 10px 0; border-top: 1px solid var(--line); }
.stops li:first-child { border-top: 0; }
.stops__n { flex: 0 0 28px; height: 28px; border-radius: 50%; background: var(--navy);
  color: #fff; font-weight: 700; display: flex; align-items: center;
  justify-content: center; font-size: 14px; }
.stops__what { flex: 1 1 auto; }
.stops__what a.btn { margin-top: 6px; }

/* 2.22.0. A visit shown in an assistant's cell on the week board. Faded and without a
   move handle, because the chip belongs to somebody else's column: the job is theirs
   to move, and this person's part in it is changed on the job itself. */
.jobchip--helping { opacity: 0.78; border-style: dashed; }
