:root {
  color-scheme: light dark;
  --bg: #e8eef1;
  --surface: #fbfcfc;
  --surface-raised: #ffffff;
  --surface-muted: #e0e8ec;
  --line: #cbd6dc;
  --text: #17262f;
  --muted: #647782;
  --accent: #315f79;
  --accent-soft: #d6e5ed;
  --claim: #b17b12;
  --claim-soft: #fff4d5;
  --issue: #bd4f50;
  --issue-soft: #fde2e0;
  --buy: #187c78;
  --buy-soft: #d9f3ee;
  --open: #667789;
  --open-soft: #e8edf1;
  --shadow: 0 8px 24px rgba(23, 38, 47, 0.075);
  --radius: 14px;
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  background: var(--bg);
  color: var(--text);
}

:root[data-color-scheme="dark"] {
  --bg: #142128;
  --surface: #1b2a32;
  --surface-raised: #202b33;
  --surface-muted: #25323c;
  --line: #3b4954;
  --text: #edf4f5;
  --muted: #a7b5bb;
  --accent: #7cb7d2;
  --accent-soft: #213e4d;
  --claim: #e0ad3d;
  --claim-soft: #3c321d;
  --issue: #ef8582;
  --issue-soft: #452a2b;
  --buy: #62c7bd;
  --buy-soft: #173b39;
  --open: #a8b7c3;
  --open-soft: #2d3a44;
  --shadow: 0 12px 30px rgba(0, 0, 0, 0.22);
}

* {
  box-sizing: border-box;
}

html {
  min-width: 320px;
  background: var(--bg);
}

body {
  position: relative;
  margin: 0;
  min-width: 320px;
  min-height: 100vh;
  background:
    radial-gradient(circle at 85% -10%, color-mix(in srgb, var(--accent-soft) 80%, transparent), transparent 34%),
    linear-gradient(180deg, color-mix(in srgb, var(--surface-muted) 60%, var(--bg)) 0, var(--bg) 300px);
  color: var(--text);
}

body::before {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  content: "";
  background-image:
    linear-gradient(color-mix(in srgb, var(--accent) 10%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--accent) 10%, transparent) 1px, transparent 1px);
  background-size: 48px 48px;
  opacity: 0.28;
  mask-image: linear-gradient(to bottom, black, transparent 58%);
}

button,
select {
  font: inherit;
}

button,
select,
input {
  -webkit-tap-highlight-color: transparent;
}

button:focus-visible,
select:focus-visible,
input:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--accent) 55%, transparent);
  outline-offset: 2px;
}

.app-shell {
  position: relative;
  z-index: 1;
  width: min(100%, 760px);
  margin: 0 auto;
  padding: 18px 16px calc(28px + var(--safe-bottom));
}

.topbar,
.project-strip,
.controls,
.secondary-controls,
.app-footer,
.brand-lockup,
.filter-row,
.record-heading,
.record-meta,
.record-footer {
  display: flex;
  align-items: center;
}

.topbar {
  justify-content: space-between;
  min-height: 52px;
  padding-bottom: 14px;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 78%, transparent);
}

.brand-lockup {
  gap: 10px;
}

.brand-mark {
  position: relative;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--accent);
  border-radius: 8px;
  background: var(--accent);
  color: var(--surface);
  font: 700 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.08em;
}

.brand-mark::after {
  position: absolute;
  right: -5px;
  bottom: -5px;
  width: 8px;
  height: 8px;
  border-right: 1px solid var(--accent);
  border-bottom: 1px solid var(--accent);
  content: "";
}

.eyebrow {
  margin: 0 0 3px;
  color: var(--muted);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.14em;
}

h1,
p {
  margin-top: 0;
}

h1 {
  margin-bottom: 0;
  font-size: 20px;
  line-height: 1;
  letter-spacing: -0.03em;
}

.icon-button {
  border: 0;
  background: transparent;
  color: var(--muted-strong);
  cursor: pointer;
}

.icon-button {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  font-size: 24px;
  line-height: 1;
}

.icon-button:hover,
.icon-button:active {
  background: var(--surface-muted);
  color: var(--text);
}

.project-strip {
  justify-content: space-between;
  gap: 18px;
  margin: 20px 0 13px;
  padding: 18px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.project-label {
  display: block;
}

.project-label select,
.select-wrap select {
  max-width: 100%;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  cursor: pointer;
  font-weight: 750;
}

.project-label select {
  margin-left: -5px;
  padding: 2px 23px 2px 4px;
  font-size: 18px;
}

.project-day {
  margin: 5px 0 0;
  color: var(--muted);
  font-size: 12px;
}

.count-number {
  display: block;
  font: 750 25px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: -0.07em;
}

.count-label {
  display: block;
  margin-top: 5px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.count-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
}

.count-card {
  min-width: 0;
  width: 100%;
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color .12s ease, border-color .12s ease, box-shadow .12s ease;
  padding: 13px 11px 12px;
  /* RESTING: no colour at all. Colour is reserved for the selected tab, so "which one am
     I in" never depends on telling two tints apart - a distinction that disappears in
     light mode, where the soft fills sit a couple of percent off the surface. */
  border: 1px solid var(--line);
  border-top: 3px solid var(--line);
  border-radius: 10px;
  background: transparent;
}

.count-card .count-number { color: var(--muted); }
.count-card .count-label { color: var(--muted-strong); }


/* SELECTED. The signal is COLOUR ITSELF, not a tint: at rest every card is neutral -
   grey rule, grey number, no fill. Only the selected one carries colour, on three
   surfaces at once (a 4px top bar, a 2px ring, and the number). That reads on any
   ground, in either theme, and it does not rely on telling two near-identical
   background washes apart - which is exactly what failed in light mode. */
.count-card.is-active {
  border-width: 2px;
  border-top-width: 4px;
  background: var(--accent-soft);
}
.count-card.is-active .count-label {
  color: var(--text);
  font-weight: 800;
}

.count-claim.is-active { border-color: var(--claim); }
.count-open.is-active  { border-color: var(--open); }
.count-buy.is-active   { border-color: var(--buy); }

.count-claim.is-active .count-number { color: var(--claim); }
.count-open.is-active  .count-number { color: var(--open); }
.count-buy.is-active   .count-number { color: var(--buy); }

/* the 2px ring must not shift the row: pull the extra border back out of the padding */
.count-card.is-active { padding: 12px 10px 11px; }

.controls {
  align-items: flex-start;
  flex-direction: column;
  gap: 10px;
  margin: 19px 0 13px;
}

.filter-row {
  width: 100%;
  gap: 7px;
  overflow-x: auto;
  padding: 2px 1px 5px;
  scrollbar-width: none;
}

.filter-row::-webkit-scrollbar { display: none; }

.filter-chip {
  flex: 0 0 auto;
  padding: 8px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  font-size: 12px;
  font-weight: 750;
}

.filter-chip:hover,
.filter-chip.is-active {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--surface);
}

.secondary-controls {
  width: 100%;
  gap: 8px;
}

.select-wrap {
  min-width: 0;
  flex: 1;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
}

.select-wrap select {
  width: 100%;
  padding-right: 8px;
  color: var(--muted);
  font-size: 12px;
}

.record-list {
  display: grid;
  gap: 10px;
}

.record-card {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 11px;
  width: 100%;
  padding: 15px 14px 14px;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  border: 1px solid var(--line);
  border-left: 5px solid var(--open);
  border-radius: 12px;
  background: var(--surface);
  box-shadow: 0 3px 12px rgba(23, 38, 47, 0.04);
  transition: border-color 160ms ease, background 160ms ease, transform 160ms ease;
}

.record-card.state-claim { border-left-color: var(--claim); }
.record-card.state-issue { border-left-color: var(--issue); }
.record-card.state-buy { border-left-color: var(--buy); }


.record-card:focus-within {
  transform: translateY(-1px);
}

.record-group {
  display: grid;
  gap: 0;
}

.nested-records {
  position: relative;
  display: grid;
  gap: 8px;
  margin: -2px 0 0 17px;
  padding: 10px 0 0 13px;
  border-left: 2px solid color-mix(in srgb, var(--accent) 34%, var(--line));
}

.nested-records::before {
  position: absolute;
  top: 22px;
  left: -2px;
  width: 12px;
  border-top: 2px solid color-mix(in srgb, var(--accent) 34%, var(--line));
  content: "";
}

.record-card.is-child {
  border-left-color: var(--open);
  background: color-mix(in srgb, var(--accent-soft) 22%, var(--surface));
  box-shadow: none;
}

.record-card.is-child .record-title {
  font-size: 14px;
}



.record-heading {
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
}

.record-id {
  flex: 0 0 auto;
  margin: 0;
  color: var(--accent);
  font: 800 13px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: -0.03em;
}

.state-badge {
  flex: 0 0 auto;
  padding: 4px 7px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.01em;
}

.state-claim .state-badge { background: var(--claim-soft); color: var(--claim-ink); }
.state-issue .state-badge { background: var(--issue-soft); color: var(--issue-ink); }
.state-buy .state-badge { background: var(--buy-soft); color: var(--buy-ink); }
.state-open .state-badge { background: var(--open-soft); color: var(--open-ink); }

.record-title {
  margin: 8px 0 11px;
  color: var(--text);
  font-size: 15px;
  font-weight: 650;
  line-height: 1.38;
  overflow-wrap: anywhere;
}

.record-meta {
  flex-wrap: wrap;
  gap: 6px 10px;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.3;
}

.owner {
  min-width: 0;
  overflow-wrap: anywhere;
}

.owner::before {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin: 0 6px 2px 0;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.7;
}

.record-footer {
  gap: 8px;
  margin-top: 10px;
  color: var(--muted);
  font-size: 11px;
}

.nested-label {
  padding: 3px 6px;
  border: 1px solid var(--line);
  border-radius: 5px;
  color: var(--muted);
  font: 700 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
}

.related-label {
  padding: 4px 7px;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.01em;
}

.notice {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 12px;
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text);
  font-size: 12px;
  line-height: 1.4;
}

.notice-copy {
  min-width: 0;
}

.undo-button {
  flex: 0 0 auto;
  padding: 5px 8px;
  border: 1px solid currentColor;
  border-radius: 7px;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 11px;
  font-weight: 800;
}

.notice[data-tone="warning"] {
  border-color: color-mix(in srgb, var(--claim) 48%, var(--line));
  background: var(--claim-soft);
}

.notice[data-tone="error"] {
  border-color: color-mix(in srgb, var(--issue) 48%, var(--line));
  background: var(--issue-soft);
}

.message-state {
  padding: 34px 20px;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  text-align: center;
}

.message-state h2 {
  margin: 0 0 7px;
  font-size: 17px;
  letter-spacing: -0.02em;
}

.message-state p {
  max-width: 330px;
  margin: 0 auto 15px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
}

.retry-button {
  border: 0;
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  font-weight: 800;
}

.retry-button {
  padding: 9px 14px;
  font-size: 12px;
}

.loading-state {
  display: grid;
  gap: 10px;
}

.skeleton-card {
  height: 137px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: linear-gradient(100deg, var(--surface) 35%, var(--surface-muted) 50%, var(--surface) 65%);
  background-size: 300% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
}

@keyframes shimmer {
  from { background-position: 100% 0; }
  to { background-position: -100% 0; }
}



.secondary-action,
.primary-action,
.danger-action {
  /* 34px is a desktop button. Every one of these is pressed with a thumb on a
     phone held in one hand, so the floor is the platform's, not the mouse's. */
  min-height: 44px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
  font-size: 11px;
  font-weight: 800;
}

.secondary-action {
  background: var(--surface-muted);
  color: var(--text);
}

.danger-action {
  border-color: color-mix(in srgb, var(--issue) 38%, var(--line));
  background: var(--issue-soft);
  color: var(--issue);
}

.primary-action {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--surface);
}

.secondary-action:disabled,
.primary-action:disabled,
.danger-action:disabled {
  cursor: wait;
  opacity: 0.55;
}

.secondary-action:hover {
  border-color: var(--accent);
}

.modal {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 16px;
}

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--text) 32%, transparent);
  backdrop-filter: blur(3px);
}

.modal-card {
  position: relative;
  width: min(100%, 560px);
  max-height: min(92vh, 680px);
  overflow: auto;
  padding: 20px;
  border: 1px solid var(--line);
  border-top: 4px solid var(--accent);
  border-radius: 18px 18px 10px 10px;
  background: var(--surface-raised);
  box-shadow: 0 20px 55px rgba(23, 38, 47, 0.24);
}

.confirm-card {
  border-top-color: var(--issue);
}

.modal-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}

.modal-heading h2 {
  margin: 0;
  font-size: 19px;
  letter-spacing: -0.03em;
}

.modal-close {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface-muted);
  color: var(--muted-strong);
  cursor: pointer;
  font-size: 20px;
  line-height: 1;
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 13px;
}

.form-field {
  display: grid;
  gap: 6px;
  min-width: 0;
  color: var(--muted);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.form-field-wide {
  grid-column: 1 / -1;
}

.form-field input,
.form-field textarea,
.form-field select {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 550;
  letter-spacing: normal;
  text-transform: none;
}

.form-field input,
.form-field select {
  min-height: 38px;
  padding: 8px 10px;
}

.form-field textarea {
  min-height: 94px;
  padding: 10px;
  resize: vertical;
}

.form-field small {
  color: var(--muted);
  font-size: 10px;
  font-weight: 550;
  letter-spacing: normal;
  text-transform: none;
}

.modal-message {
  margin: 0 0 20px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding-top: 7px;
}





.retry-button:disabled {
  cursor: wait;
  opacity: 0.55;
}

.app-footer {
  justify-content: center;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: 20px;
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.02em;
  text-align: center;
}

.footer-dot {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--muted);
}

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

[hidden] {
  display: none !important;
}

@media (min-width: 600px) {
  .app-shell {
    padding-right: 24px;
    padding-left: 24px;
  }

  .controls {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }

  .secondary-controls {
    width: auto;
    flex: 0 0 auto;
  }

  .select-wrap {
    width: 150px;
    flex: 0 0 auto;
  }

  .modal {
    align-items: center;
  }

  .modal-card {
    border-radius: 18px;
  }
}

@media (max-width: 480px) {
  .form-grid {
    grid-template-columns: 1fr;
  }

  .form-field-wide {
    grid-column: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* A record nobody owns is the quietest way work dies, and a third of the pilot board is
   in this state. It reads as a flag, not as somebody's name. */
.owner-none {
  color: var(--issue);
  font-weight: 750;
}

/* A claim is a request, not a status: somebody has said the work is done and is waiting
   on the manager to accept it. Yellow because that is the colour the board already uses
   for "needs confirmation", and a left rule so it reads as a callout rather than a label. */
.claim-banner {
  margin: 9px 0 0;
  padding: 8px 10px;
  border-left: 3px solid var(--claim);
  border-radius: 8px;
  background: var(--claim-soft);
  color: var(--claim);
  font-size: 12.5px;
  font-weight: 750;
  line-height: 1.35;
}

.count-mine.is-active { border-color: var(--accent); }
.count-mine.is-active .count-number { color: var(--accent); }

.topbar-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

/* A checkbox reads as a control, not as a paragraph: the box and its sentence sit on one
   baseline and the whole row is the target. */
.check-field {
  flex-direction: row;
  align-items: flex-start;
  gap: 9px;
  cursor: pointer;
}
.check-field input {
  width: 18px;
  height: 18px;
  margin-top: 2px;
  flex: 0 0 auto;
  accent-color: var(--accent);
}
.check-field span {
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  line-height: 1.4;
}

/* A ticket heading, for a parent whose own row lives in another tab. Quiet on purpose:
   it is context, not something you can act on from here. */
.group-heading {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  padding: 12px 2px 6px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 8px;
}
.group-title {
  font-size: 13px;
  font-weight: 750;
  color: var(--text);
}
.group-sub {
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --- where a record came from -------------------------------------------
   Two kinds of line: the ones the record was actually read from, and the talk
   around them. Only the first kind can be wrong, so only the first kind is
   marked and only the first kind can be rejected. Context is deliberately
   quiet - it is here to make the evidence readable, not to be judged. */
.thread-card {
  max-width: 40rem;
  width: 100%;
}

.thread-body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-height: 55vh;
  overflow-y: auto;
  margin: 0.25rem 0 0.75rem;
  padding-right: 0.25rem;
}

.thread-msg {
  border: 1px solid var(--line);
  border-radius: 0.6rem;
  padding: 0.5rem 0.65rem;
  background: var(--surface);
}

.thread-msg-evidence {
  border-color: var(--accent-soft);
  border-left: 3px solid var(--accent);
  background: var(--surface-raised);
}

.thread-msg-rejected {
  opacity: 0.55;
}

.thread-msg-rejected .thread-text {
  text-decoration: line-through;
}

.thread-meta {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  font-size: 0.75rem;
  color: var(--muted);
  margin-bottom: 0.2rem;
}

.thread-who {
  font-weight: 600;
  color: var(--text);
}

.thread-reply {
  font-style: italic;
}

.thread-text {
  font-size: 0.9rem;
  line-height: 1.4;
  color: var(--text);
  overflow-wrap: anywhere;
}

.thread-media {
  display: inline-block;
  margin-top: 0.3rem;
  font-size: 0.72rem;
  color: var(--muted);
}

.thread-reject {
  margin-top: 0.4rem;
  font-size: 0.72rem;
  background: none;
  border: none;
  padding: 0;
  color: var(--muted);
  cursor: pointer;
  text-decoration: underline;
}

.thread-reject:hover:not(:disabled) {
  color: var(--text);
}

.thread-empty {
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.5;
  padding: 0.5rem 0;
}

.thread-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
}

.thread-open {
  text-decoration: none;
  display: inline-flex;
  align-items: center;
}

.thread-photo {
  display: block;
  margin-top: 0.4rem;
  max-width: 100%;
  max-height: 60vh;
  border-radius: 0.45rem;
  border: 1px solid var(--line);
  object-fit: contain;
}

.photos-body {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
  gap: 0.3rem;
  max-height: 62vh;
  overflow-y: auto;
  padding-right: 0.25rem;
}

.photo-cell {
  border: 1px solid var(--line);
  border-radius: 0.5rem;
  overflow: hidden;
  background: var(--surface);
  display: flex;
  flex-direction: column;
}

.photo-cell img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
  background: var(--surface-muted);
  cursor: zoom-in;
}

.photo-cell figcaption {
  padding: 0.35rem 0.4rem;
  font-size: 0.68rem;
  line-height: 1.35;
  color: var(--muted);
}

.photo-who {
  display: block;
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}

.timeline-body {
  max-height: 62vh;
  overflow-y: auto;
  padding-right: 0.25rem;
}

.timeline-day {
  position: sticky;
  top: 0;
  background: var(--surface-raised);
  padding: 0.4rem 0 0.3rem;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  z-index: 1;
}

.timeline-row {
  display: flex;
  gap: 0.55rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--surface-muted);
}

.timeline-time {
  flex: 0 0 2.7rem;
  font-size: 0.72rem;
  color: var(--muted);
  padding-top: 0.1rem;
}

.timeline-main {
  flex: 1 1 auto;
  min-width: 0;
}

.timeline-what {
  font-size: 0.85rem;
  line-height: 1.35;
  color: var(--text);
  overflow-wrap: anywhere;
}

.timeline-num {
  font-weight: 800;
  font-size: 0.72rem;
  margin-right: 0.35rem;
  color: var(--accent);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}

.timeline-meta {
  font-size: 0.7rem;
  color: var(--muted);
  margin-top: 0.1rem;
}

.timeline-closed .timeline-what {
  color: var(--muted);
}

.timeline-photos {
  margin-top: 0.3rem;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  background: none;
  border: 1px solid var(--line);
  border-radius: 0.45rem;
  padding: 0.3rem 0.45rem;
  cursor: pointer;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--text);
}

.timeline-photos:hover {
  border-color: var(--accent);
}

.timeline-thumbs {
  display: flex;
  gap: 0.2rem;
}

.timeline-thumbs img {
  width: 2rem;
  height: 2rem;
  object-fit: cover;
  border-radius: 0.25rem;
  background: var(--surface-muted);
}

/* A burst is ONE moment - same person, same minute, same division - so its
   details belong in the heading once. Repeating them under every frame made the
   caption taller than the photograph it described. */
.photo-cell {
  border: none;
  border-radius: 0.4rem;
}

.photo-cell figcaption {
  padding: 0.25rem 0.1rem 0;
  font-size: 0.66rem;
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, 0.92);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1rem;
  cursor: zoom-out;
}

.lightbox img {
  max-width: 100%;
  max-height: 82vh;
  object-fit: contain;
  border-radius: 0.3rem;
}

.lightbox-caption {
  color: #f2f5f6;
  font-size: 0.78rem;
  text-align: center;
  max-width: 34rem;
  line-height: 1.4;
}

/* A milestone is a fact about the work, so it reads as a statement rather than as
   another row of admin. */
.timeline-event .timeline-what {
  font-weight: 700;
}

.timeline-event {
  border-left: 3px solid var(--accent);
  padding-left: 0.5rem;
  margin-left: -0.5rem;
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}

.timeline-log {
  width: 100%;
  margin: 0.5rem 0 0.2rem;
  background: none;
  border: 1px dashed var(--line);
  border-radius: 0.5rem;
  padding: 0.5rem;
  cursor: pointer;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--muted);
}

.timeline-log:hover {
  border-color: var(--accent);
  color: var(--text);
}

.timeline-promote {
  margin-left: 0.4rem;
  background: none;
  border: none;
  padding: 0;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline;
}

.photo-cell.picking img {
  cursor: pointer;
  outline: 2px solid transparent;
  outline-offset: -2px;
}

.photo-cell.picked img {
  outline-color: var(--accent);
  opacity: 0.72;
}

#add-photos-note {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.72rem;
  color: var(--muted);
}

/* Everything is shown until somebody chooses otherwise. A filter that defaults to
   ON quietly answers a different question than the reader thinks they asked. */
.timeline-filters {
  display: flex;
  margin: 0 0 0.4rem;
}

.timeline-assigned .timeline-what,
.timeline-claimed .timeline-what {
  color: var(--muted);
}

.timeline-claimed {
  border-left: 2px solid var(--accent-soft);
  padding-left: 0.4rem;
  margin-left: -0.4rem;
}

/* ---------------------------------------------------------------- crew ---
   A different screen, not the manager's console with things taken out. It
   answers one question - what do I owe, and let me knock it off - and it is
   read one-handed, in daylight, sometimes through gloves.

   The whole colour budget goes on ONE state: finished. That green appears
   nowhere else in the app, so seeing it means exactly one thing. No confetti,
   no ring, no streak: on a site those read as toy, and the tally IS the
   reward. */
:root {
  --done: #1f9d55;
  --done-soft: #e3f6ea;
}

:root[data-color-scheme="dark"] {
  --done: #45c07a;
  --done-soft: #17321f;
}

.today {
  padding: 4px 2px 14px;
}

.today-day {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-strong);
}

.today-score {
  display: flex;
  align-items: baseline;
  gap: 9px;
  margin-top: 2px;
}

.today-count {
  /* tabular so the number does not jump sideways when it counts up */
  font-variant-numeric: tabular-nums;
  font-size: 40px;
  line-height: 1;
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--text);
}

.today-count.is-scored { color: var(--done-ink); }

.today-label {
  font-size: 15px;
  font-weight: 600;
  color: var(--muted-strong);
}

.today-week {
  margin-top: 7px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
}

/* One row, one job, one tap. Big enough for a thumb with the phone in the
   other hand. */
/* the row is a container now: the tick is a button inside it, and so is the
   camera. A button inside a button is invalid and swallows the inner tap. */
/* ONE surface, ONE gesture. It was a container with three controls competing
   inside it; it is a single button that opens the job's card. */
.job {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  min-height: 60px;
  padding: 13px 12px;
  border: none;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  background: none;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: background 140ms ease, opacity 140ms ease;
}

.job:last-child { border-bottom: none; }
.job:hover { background: var(--surface-muted); }
.job:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.job:active { transform: scale(0.995); }

/* A MARK, not a control. Nothing happens when it is pressed - the row is what
   is being pressed - so it no longer wears the 44px target of a button. */
.job-box {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border: 2px solid var(--line);
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: transparent;
}

.job-what {
  font-size: 15px;
  line-height: 1.35;
  color: var(--text);
  overflow-wrap: anywhere;
}

.job-meta {
  margin-top: 3px;
  font-size: 12px;
  font-weight: 700;
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
}

/* Somebody has reported this finished and it is waiting on the manager to accept.
   Same position and size as every other mark on the board - what changes is that
   this one is addressed to the person reading it. */
.job-box.is-claimed {
  border-color: var(--claim);
  background: var(--claim-soft);
  color: var(--claim);
}

.job.is-done { background: var(--done-soft); }

.job.is-done .job-box {
  background: var(--done);
  border-color: var(--done);
  color: #fff;
}

.job.is-done .job-what {
  color: var(--muted-strong);
  text-decoration: line-through;
  text-decoration-color: color-mix(in srgb, var(--done) 55%, transparent);
}

.job.is-busy { opacity: 0.5; pointer-events: none; }

.job-urgent {
  display: inline-block;
  margin-right: 5px;
}

/* --- the problem, and the jobs that belong to it ------------------------- */
/* A heading with loose rows drifting after it never said "these three are the
   same matter" - it left that to the numbering, TH-2.1 against TH-2.2, which is
   a scheme nobody should have to decode to understand what they are doing. The
   jobs are INSIDE the problem now. */
.issue-group {
  margin: 0 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.issue-group.is-loose {
  border: none;
  background: none;
  overflow: visible;
}

.issue-jobs { display: flex; flex-direction: column; }

/* Railed to the header above them, and set in from it, so the nesting is legible
   at a glance rather than inferred from the border. */
.issue-group:not(.is-loose) .issue-jobs {
  padding-left: 12px;
  border-left: 3px solid color-mix(in srgb, var(--accent) 38%, var(--line));
  margin-left: 12px;
}

.issue-group.is-loose .issue-jobs {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

/* proof you can see without opening anything */
.job-thumbs {
  display: flex;
  gap: 4px;
  margin-top: 7px;
}

.job-thumbs:empty { display: none; }

.job-thumbs img {
  width: 38px;
  height: 38px;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--surface-muted);
}

.job-hasproof {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: var(--done);
}

.crew-heading {
  margin: 16px 2px 8px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-strong);
}

.crew-empty {
  padding: 30px 16px;
  text-align: center;
  font-size: 15px;
  line-height: 1.5;
  color: var(--muted);
}

@media (prefers-reduced-motion: reduce) {
  .job, .job-box { transition: none; }
  .job:active { transform: none; }
}

/* The moment. A tick already changed the row and the tally; what was missing was
   the beat between them that says the two are connected. It is information, not
   decoration: the number tells you whether the photograph counted, which is how
   somebody discovers the multiplier without anyone explaining it. */
.pop {
  position: absolute;
  left: 50%;
  translate: -50% 0;
  pointer-events: none;
  font-size: 19px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--done);
  animation: pop-rise 900ms cubic-bezier(0.22, 0.8, 0.3, 1) forwards;
}

@keyframes pop-rise {
  0%   { opacity: 0; translate: -50% 6px;   scale: 0.85; }
  22%  { opacity: 1; translate: -50% -6px;  scale: 1.06; }
  70%  { opacity: 1; translate: -50% -24px; scale: 1; }
  100% { opacity: 0; translate: -50% -42px; scale: 1; }
}

.today-count.is-bumped { animation: count-bump 420ms ease-out; }

@keyframes count-bump {
  0%   { scale: 1; }
  38%  { scale: 1.13; }
  100% { scale: 1; }
}

.job { position: relative; }

@media (prefers-reduced-motion: reduce) {
  .pop { animation: none; opacity: 0; }
  .today-count.is-bumped { animation: none; }
}

/* Who you are and what you have earned. It read as "no points system" because a
   man on his first day sees nothing but a zero - so the profile is always there,
   with his name on it. */
.me {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 2px 2px 10px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 12px;
}

.me-name {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--text);
  overflow-wrap: anywhere;
}

.me-total {
  flex: 0 0 auto;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.me-total b {
  display: block;
  font-size: 22px;
  font-weight: 800;
  line-height: 1;
  color: var(--done);
}

.me-total span {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* the camera sits on the row, so proof is one tap from the job it proves */
/* Bottom right, and small. The job is what the row is for; the camera is a tool
   sitting beside it, and it should not compete with the words for attention. Still
   a 34px target, because it is pressed with a thumb. */




















.job-body { flex: 1 1 auto; min-width: 0; }

.job-chev {
  flex: 0 0 auto;
  font-size: 18px;
  line-height: 1;
  color: var(--muted-strong);
}




@media (prefers-reduced-motion: reduce) {
  .job:active { transform: none; }
}

/* Proof you can look at. A tick in the corner saying "photo added" is an assertion
   about an assertion - the whole point is that somebody can SEE the work, including
   the man who took it, before he says the job is done. */
.job-proof {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 8px;
}

.job-proof img {
  width: 54px;
  height: 54px;
  object-fit: cover;
  border-radius: 7px;
  border: 1px solid var(--line);
  background: var(--surface-muted);
  cursor: zoom-in;
}

.job.is-done .job-proof img { border-color: color-mix(in srgb, var(--done) 40%, var(--line)); }

.job-proof-more {
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  border-radius: 7px;
  border: 1px dashed var(--line);
  font-size: 12px;
  font-weight: 800;
  color: var(--muted);
}

/* Nothing is inferred, so the rule is stated - once, at the top, in the place
   somebody opening this for the first time will actually look. */
.today-rule {
  margin-top: 8px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--muted-strong);
}

/* A delivery receipt cannot be a thumbnail, so it is a chip that says what it is.
   Same footprint as a photo so the strip stays a strip. */
.proof-file {
  display: grid;
  place-items: center;
  gap: 2px;
  width: 54px;
  height: 54px;
  padding: 4px;
  border-radius: 7px;
  border: 1px solid var(--line);
  background: var(--surface-muted);
  text-align: center;
  font: inherit;
  color: var(--muted);
  cursor: pointer;
  overflow: hidden;
}

.proof-file b { font-size: 15px; line-height: 1; }

.proof-file span {
  font-size: 8px;
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: 0.02em;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* A gallery, not a single frame. Photographs of a job come in sets and flicking
   between them must not mean closing and reopening four times. */
.lightbox {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-rows: auto 1fr auto;
  align-items: center;
  gap: 6px;
  padding: 10px;
}

.lightbox-bar {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.lightbox-count {
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, 0.72);
}

.lightbox-close {
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  font-size: 21px;
  line-height: 1;
  cursor: pointer;
}

.lightbox img {
  grid-column: 2;
  grid-row: 2;
  justify-self: center;
  max-width: 100%;
  max-height: 74vh;
}

.lightbox-step {
  grid-row: 2;
  width: 38px;
  height: 64px;
  border: none;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
}

.lightbox-step[hidden] { visibility: hidden; display: block; }
.lightbox-step:first-of-type { grid-column: 1; }
.lightbox-next { grid-column: 3; }

.lightbox-caption { grid-column: 1 / -1; }









/* Something on screen saying the phone is still working. Without it a slow
   connection gets the button pressed again and the photograph arrives twice. */
/* Pinned to the bottom edge of the row. The row no longer wraps, so a bar that
   asks for its own line inside it simply never gets one. This is the fallback
   path anyway - the picker is opened from the card, and the bar goes there. */
.job-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: block;
  height: 4px;
  border-radius: 3px;
  background: var(--surface-muted);
  overflow: hidden;
}

.job-bar span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--done);
  transition: width 120ms linear;
}

/* A picture filed on the wrong job is worse than none - it is evidence pointing at
   work it does not show. Taking it off happens where you are looking at it. */
.lightbox-drop {
  grid-column: 1 / -1;
  justify-self: center;
  min-height: 34px;
  padding: 0 16px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 999px;
  background: transparent;
  color: rgba(255, 255, 255, 0.9);
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}

.lightbox-drop:disabled { opacity: 0.55; cursor: wait; }

/* A delivery receipt has no frame to show, so the viewer gives it a panel - same
   place, same controls, so there is one way to inspect and remove any attachment
   rather than one for pictures and another for paperwork. */
.lightbox-file {
  grid-column: 2;
  grid-row: 2;
  justify-self: center;
  display: grid;
  justify-items: center;
  gap: 12px;
  padding: 28px 24px;
  max-width: 20rem;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.08);
  text-align: center;
}

.lightbox-file b { font-size: 40px; line-height: 1; }

.lightbox-file p {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  color: #f2f5f6;
  overflow-wrap: anywhere;
}

/* The problem a job belongs to. Reads as a heading rather than another row,
   because it is context for the work beneath it, not more work. */
/* The group's own top bar. It leads - the problem is the thing, and the jobs
   are what is being done about it. */
.issue-head {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 0;
  padding: 13px 12px;
  border: none;
  background: var(--surface-muted);
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.issue-head:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* COLOUR CARRIES THE KIND, said once: the stripe down the card and the fill of
   its header are the same decision, so the eye picks a purchase out of a column
   of problems without reading a word. A claim waiting on the manager outranks
   what the matter is - he is being asked a question. */
.issue-group.kind-issue > .issue-head { background: var(--issue-soft); }
.issue-group.kind-purchase > .issue-head { background: var(--buy-soft); }
.issue-group.kind-claim > .issue-head { background: var(--claim-soft); }

.issue-group.kind-issue { border-left: 3px solid var(--issue); }
.issue-group.kind-purchase { border-left: 3px solid var(--buy); }
.issue-group.kind-claim { border-left: 3px solid var(--claim); }

/* The parent is filtered out of this tab - its work is "mine", the matter is not -
   so the card stands for context and says so by receding, rather than by claiming
   to be a result of the filter the way a full-strength card would. */
.issue-group.is-context > .issue-head { background: var(--surface-muted); }



.issue-head > span:first-child { flex: 1 1 auto; min-width: 0; }

.issue-head-what {
  display: block;
  font-size: 14px;
  font-weight: 800;
  line-height: 1.3;
  color: var(--text);
  overflow-wrap: anywhere;
}

.issue-head-meta {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  font-weight: 700;
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
}

.issue-head-flag { flex: 0 0 auto; font-size: 14px; }

/* WHICH RECORD the question is about, in the words the board uses for it, so
   the thing he taps here is the thing he can find when he lands there. */
.issue-head-on {
  display: block;
  margin-top: 3px;
  font-size: 12.5px;
  line-height: 1.3;
  color: var(--text);
  overflow-wrap: anywhere;
}

/* The card at the top: face, name, score. It is the first thing on the screen
   because the score is the reason to open the thing at all. */
/* In its own slot above the project strip now, so it carries the card treatment
   itself rather than a divider borrowed from the list it used to sit in. */
#me-slot:empty { display: none; }

.me {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 11px 12px;
  margin: 14px 0 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.me-face {
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-muted);
  display: grid;
  place-items: center;
  font-size: 15px;
  font-weight: 800;
  color: var(--muted-strong);
  overflow: hidden;
}

.me-body { flex: 1 1 auto; min-width: 0; }

.me-sub {
  display: block;
  margin-top: 1px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.me-chev { flex: 0 0 auto; font-size: 17px; color: var(--muted); }

.me-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin: 4px 0 16px;
}

.me-stat {
  padding: 11px 8px;
  border: 1px solid var(--line);
  border-radius: 10px;
  text-align: center;
}

.me-stat b {
  display: block;
  font-size: 21px;
  font-weight: 800;
  line-height: 1.1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.me-stat span {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}

.me-history { max-height: 46vh; overflow-y: auto; }

.me-day {
  display: grid;
  grid-template-columns: 5.5rem 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 9px 2px;
  border-bottom: 1px solid var(--surface-muted);
  font-size: 13px;
}

.me-day-when { font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.me-day-jobs { font-size: 12px; color: var(--muted); }

.me-day-pts {
  font-weight: 800;
  color: var(--done);
  font-variant-numeric: tabular-nums;
}

.me-bar {
  grid-column: 2;
  height: 5px;
  border-radius: 3px;
  background: var(--surface-muted);
  overflow: hidden;
}

.me-bar span { display: block; height: 100%; background: var(--done); }

/* Said once, plainly, and gone on its own - a man finishing six jobs should not
   have to dismiss six things. It sits over the board rather than pushing it. */
.cheer {
  position: fixed;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: min(23rem, calc(100vw - 28px));
  padding: 12px 16px;
  border-radius: 14px;
  border: 1px solid color-mix(in srgb, var(--done) 45%, var(--line));
  background: var(--done-soft);
  box-shadow: 0 12px 30px rgba(10, 20, 26, 0.18);
  animation: cheer-in 220ms cubic-bezier(0.2, 0.9, 0.3, 1);
}

.cheer.going {
  opacity: 0;
  scale: 0.96;
  transition: opacity 300ms ease, scale 300ms ease;
}

.cheer b {
  flex: 0 0 auto;
  font-size: 24px;
  font-weight: 800;
  line-height: 1;
  color: var(--done);
  font-variant-numeric: tabular-nums;
}

.cheer span { display: block; }

.cheer strong {
  display: block;
  font-size: 14px;
  font-weight: 800;
  color: var(--text);
}

.cheer span span {
  font-size: 12px;
  line-height: 1.35;
  color: var(--muted);
}

/* Grows into the middle rather than sliding up from the edge - it is the answer
   to the tap, and the eye is already on the row that was tapped. */
@keyframes cheer-in {
  from { opacity: 0; translate: -50% -50%; scale: 0.9; }
  to   { opacity: 1; translate: -50% -50%; scale: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .cheer { animation: none; }
  .cheer.going { transition: none; }
}

.me-sound {
  display: block;
  width: 100%;
  margin: 0 0 16px;
  padding: 11px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
}

/* ------------------------------------------------------------------ gold ---
   The score is the metric this whole thing runs on, so it is the biggest thing
   on the card and the only gold anywhere. Two golds, chosen per theme rather
   than one lightened: on a light ground gold has to go dark to stay legible. */
/* #a4750a read better but measured 3.98:1, which is fine for the 30px score and
   fails for the 13px day totals that use the same token. One token, one bar: the
   smallest text it touches decides it. */
:root { --gold: #8a6008; --gold-soft: #fdf3dc; }

/* --muted is right for 12px+ on white and wrong for 11px uppercase on a tinted
   panel, where it measures 3.76:1. This is the same grey carried far enough to
   clear 4.5:1 on every surface the small type actually lands on. */
:root {
  --muted-strong: #4f606b;
  /* 10-12px type on a tinted chip needs more than the fill colour carries */
  --done-ink: #147038; --issue-ink: #a3302f;
  --claim-ink: #7a5209; --buy-ink: #0f5c59; --open-ink: #4a5a68;
}
:root[data-color-scheme="dark"] {
  --muted-strong: #b3c2cc; --done-ink: #5fd08c; --issue-ink: #ff9d9b;
  --claim-ink: #f0c04b; --buy-ink: #5ad6cd; --open-ink: #b0c0cd;
}
:root[data-color-scheme="dark"] { --gold: #f0c04b; --gold-soft: #33291045; }

.me-score {
  flex: 0 0 auto;
  text-align: right;
  line-height: 1;
}

.me-score b {
  display: block;
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}

.me-score span {
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --- the same card, read as a filter -------------------------------------
   The crew card is a portrait and its number is a score, which is why the score
   is the only gold on the screen. The manager's is the same component saying
   WHO the board is showing, and its number is a count of what is underneath -
   so it takes the ink colour. Gold would have promised a reward for filtering. */
.me.is-filter { margin-top: 0; }
.me-score.is-plain b { color: var(--text); }

/* Three faces mean "a list of people, and you may pick one" without a sentence
   having to say it. They are a mark, not a roster - the roster is behind the tap. */
.me-stack { display: flex; flex: 0 0 auto; }
.me-stack > * {
  margin-right: -12px;
  border: 2px solid var(--surface);
}
.me-stack > *:last-child { margin-right: 0; }

/* The roster is the people filter now, so its rows are pressable and the one in
   force is marked. */
/* A pressable row is a CARD, not a line in a list. The divider that separates
   read-only names would sit under a tappable one as a seam, and a <button>
   brings its own border from the browser - together they drew every person in
   a box of their own, all butted against each other. */
.person.is-pick {
  width: 100%;
  /* The same edge the dashboard's site rows carry, so a tappable row looks the
     same wherever it appears. */
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 11px 10px;
  background: var(--surface);
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: background 140ms ease;
}
.person.is-pick:hover { background: var(--surface-muted); }
.person.is-pick:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* The one in force, said with the border rather than only a wash - on a bright
   screen outdoors a pale fill is the first thing that stops being visible. */
.person.is-on {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}

.me-stat:first-child b { color: var(--gold); }
.me-day-pts { color: var(--gold); }
.me-bar span { background: var(--gold); }












/* Icons take the colour of whatever they sit in, so a clip in a muted button is
   muted and the same clip in the done state is green - one asset, no variants. */
.ic {
  flex: 0 0 auto;
  display: block;
}

.me-sound .ic,
.job-urgent .ic,
.issue-head-flag .ic { display: inline-block; vertical-align: -2px; }

.me-sound { display: flex; align-items: center; justify-content: center; gap: 8px; }

.job-urgent,
.issue-head-flag { color: var(--issue); }

.proof-file .ic { margin-bottom: 2px; }
.lightbox-file b .ic { width: 38px; height: 38px; }

.job:active .job-box { scale: 0.9; }

@media (prefers-reduced-motion: reduce) {
  .job:active .job-box { scale: 1; }
}

/* An issue's words are a way in, so they read like one: weightier than the meta
   under them, and they take the accent while pressed. */
.issue-head-what { text-decoration: none; }
.issue-head:active .issue-head-what { color: var(--accent); }

.issue-head-chev {
  flex: 0 0 auto;
  font-size: 18px;
  line-height: 1;
  color: var(--muted-strong);
}



/* --------------------------------------------------------- the detail card ---
   Everything a row used to do at a tap happens here instead, named and spaced.
   The facts first, because the first question is always "where does this stand",
   and then the two or three things you can do about it. */
.detail-card { max-width: 460px; }

/* A RECORD THAT CAME OUT OF A QUESTION, SHOWN AS THE QUESTION.

   The register's summary of a question is a fair summary and not what anybody
   said, so the words go back at the top, attributed and in quotes. Set as a
   quotation rather than as another fact row: the point is that a person said
   this, and a dt/dd pair would file it alongside "Due" and "Created" as one
   more piece of provenance to skim past. */
.detail-question {
  margin: 4px 0 0;
  padding: 9px 12px;
  border-left: 3px solid var(--accent);
  background: var(--accent-soft);
  border-radius: 0 6px 6px 0;
}

.detail-question-who {
  margin: 0;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--accent);
}

.detail-question-text {
  margin: 3px 0 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--text);
}

.detail-facts {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 5px 12px;
  margin: 4px 0 0;
  padding: 10px 0 0;
  border-top: 1px solid var(--line);
}

/* THE MATTER ITSELF IS THE HEADLINE. On a detail sheet the description is the
   only thing he came to read, and it was set 19px against 14px provenance -
   near enough the same weight of voice for the eye to have to choose. */
.detail-card .modal-heading h2 {
  font-size: 23px;
  line-height: 1.22;
  font-weight: 700;
}

/* PROVENANCE IS SMALL PRINT. What is left in this list - when it appeared, what
   last happened to it - is worth having and worth nobody's attention until they
   go looking. It used to be set at nearly the size of the thing it describes. */
.detail-facts dt {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
  padding-top: 1px;
}

.detail-facts dd {
  margin: 0;
  font-size: 12px;
  line-height: 1.35;
  color: var(--muted-strong);
  overflow-wrap: anywhere;
}

.detail-extra:empty { display: none; }

.detail-flag {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 14px 0 0;
  font-size: 13px;
  font-weight: 700;
  color: var(--issue);
}

.detail-warn {
  margin: 14px 0 0;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 13px;
  line-height: 1.45;
}

.detail-warn { background: var(--issue-soft); color: var(--text); }

.detail-extra .job-proof { margin-top: 14px; }

/* One column, full width, biggest first. A footer that wraps three buttons onto
   two lines on a narrow phone puts the destructive one wherever it lands. */
.detail-footer {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 18px;
}

.detail-footer > * {
  width: 100%;
  min-height: 46px;
  justify-content: center;
  border-radius: 11px;
  font-size: 14px;
}

.detail-attach {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  cursor: pointer;
}

.detail-attach input { display: none; }

.detail-progress {
  height: 4px;
  margin-top: 14px;
  border-radius: 999px;
  background: var(--surface-muted);
  overflow: hidden;
}

.detail-progress > span {
  display: block;
  height: 100%;
  width: 6%;
  border-radius: 999px;
  background: var(--accent);
  transition: width 120ms linear;
}

/* --- what a PIC has that a crew member does not --------------------------- */
/* Assignment is the PIC's whole job, so it is a control on the card rather than
   a trip through an editor built for auditing a register. */
.detail-assign {
  display: block;
  margin-top: 14px;
}

.detail-assign-label {
  display: block;
  margin-bottom: 6px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted-strong);
}

.detail-assign select {
  width: 100%;
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 14px;
}

.detail-assign select:disabled { opacity: 0.5; }

/* The row a PIC is actually hunting for. Colour cannot carry it alone, so the
   words say it too - "nobody on it" is the meta line, not a swatch. */
.job-unowned .job-meta { color: var(--issue-ink); font-weight: 800; }

/* Looking at your own site as somebody under you. A downgraded board is
   indistinguishable from a broken one unless something on screen admits it. */
.preview-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  margin-bottom: 12px;
  padding: 10px 12px;
  border-radius: var(--radius);
  background: var(--claim-soft);
  border: 1px solid color-mix(in srgb, var(--claim) 34%, var(--line));
}

.preview-bar strong {
  font-size: 13px;
  font-weight: 800;
  color: var(--text);
}

.preview-bar > span {
  flex: 1 1 160px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--muted-strong);
}

.preview-out {
  flex: 0 0 auto;
  min-height: 32px;
  padding: 0 14px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--claim) 45%, var(--line));
  background: var(--surface);
  font: inherit;
  font-size: 12px;
  font-weight: 800;
  color: var(--text);
  cursor: pointer;
}

/* The receipt for handing work to somebody. */
.moved-hand {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
  padding: 14px 12px;
  border-radius: 12px;
  background: var(--surface-muted);
}

.moved-leg {
  flex: 1 1 0;
  min-width: 0;
}

.moved-leg-label {
  display: block;
  margin-bottom: 3px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-strong);
}

.moved-leg strong {
  font-size: 15px;
  font-weight: 800;
  color: var(--text);
  overflow-wrap: anywhere;
}

.moved-arrow {
  flex: 0 0 auto;
  font-size: 20px;
  line-height: 1;
  color: var(--muted-strong);
}

.moved-told {
  margin: 14px 0 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--muted-strong);
}

/* it did NOT reach a phone, which is the thing worth noticing */
.moved-told.is-quiet {
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--claim-soft);
  color: var(--text);
  font-weight: 600;
}

/* 34px is a desktop button. This is pressed with a thumb, in gloves, outdoors. */
#moved-modal .modal-footer { margin-top: 18px; }

#moved-modal .modal-footer .primary-action {
  width: 100%;
  min-height: 46px;
  border-radius: 11px;
  font-size: 14px;
}

/* ---------------------------------------------- the sites he is running ---
   A Telegram group is one project and he runs four. This is the view the chat
   cannot give him, so it is the first thing he sees rather than a dropdown. */
.home { padding: 4px 0 8px; }

/* Drawn inside the list now, after the Waiting block, so it needs room above
   it as well as below - it is a divider between two sections rather than the
   first thing on the screen. */
.home-title {
  margin: 6px 2px 3px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-strong);
}

.home-list { display: flex; flex-direction: column; gap: 9px; }

.site {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 68px;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: background 140ms ease;
}

.site:hover { background: var(--surface-muted); }
.site:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.site:active { transform: scale(0.995); }

.site-mark {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 11px;
  background: var(--accent);
  color: var(--surface);
  font-size: 17px;
  font-weight: 800;
}

/* The group's own photo in the same 42px slot as the letter it replaces, so a
   row with a picture and a row without still line up. */
.site-mark-photo {
  object-fit: cover;
  padding: 0;
  background: var(--surface-muted);
}

.site-body { flex: 1 1 auto; min-width: 0; }

.site-name {
  display: block;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
  overflow-wrap: anywhere;
}

.site-meta {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  font-weight: 700;
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
}

.site-chev {
  flex: 0 0 auto;
  font-size: 20px;
  line-height: 1;
  color: var(--muted-strong);
}

/* --- who you are on this site, not what it holds -------------------------
   Manager on one group, crew on the next - the same person, and a list of
   several sites has to say which one this row is. */
.site-role {
  flex: 0 0 auto;
  font: 650 9.5px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 7px;
  border-radius: 6px;
  background: var(--surface-muted);
  color: var(--muted-strong);
  white-space: nowrap;
}
.site-role.is-manager { background: var(--accent-soft); color: var(--accent); }

/* ------------------------------------------------- who is on this site ---- */
.people-button {
  min-height: 38px;
  white-space: nowrap;
}

/* Spacing between the rows lives here rather than as a margin on each, so the
   read-only list keeps its flush dividers and the pressable one gets air. */
.people-body { margin-top: 8px; display: flex; flex-direction: column; gap: 8px; }

.person {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 2px;
  border-bottom: 1px solid var(--line);
}

.person:last-child { border-bottom: none; }

.person-who { flex: 1 1 auto; min-width: 0; }

.person-name {
  display: block;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  overflow-wrap: anywhere;
}

.person-role {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-strong);
}

.person-tally {
  flex: 0 0 auto;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.person-tally b {
  display: block;
  font-size: 20px;
  font-weight: 800;
  line-height: 1;
  color: var(--gold);
}

.person-tally span {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-strong);
}

/* the Closed tab wears the finished colour, like a done row does */
.count-card.count-done .count-number { color: var(--done-ink); }

/* a row that opens something says so */
.record-chev {
  position: absolute;
  top: 15px;
  right: 12px;
  font-size: 18px;
  line-height: 1;
  color: var(--muted-strong);
}

.record-card:hover { background: var(--surface-muted); }
.record-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.record-card:active { transform: scale(0.997); }

.record-heading { padding-right: 18px; }

/* Two selects and a button in one row. The row was built for one select, so the
   third control pushed it 6px past the viewport - which on a phone is a page that
   slides sideways under the thumb. It wraps now, and nothing has a fixed width. */
.secondary-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

.secondary-controls .select-wrap {
  flex: 1 1 132px;
  min-width: 0;
  max-width: 100%;
}

.secondary-controls .people-button { flex: 1 1 100%; }

/* Small type on the manager's rows sat at 3.9-4.32:1 - the same --muted problem
   already fixed everywhere else, on the one board that had not been touched. */
.record-meta .owner,
.record-meta .age,
.nested-label,
.related-label { color: var(--muted-strong); }

/* Delete reads as a warning, and a warning nobody can read is decoration. */
.danger-action { color: var(--issue-ink); }

/* --------------------------------------------------- what happened since ---
   Read when somebody is arguing about what was agreed: rarely, and then very
   carefully. So it is quiet, dense, and dated. */
.thread-history { margin-top: 4px; }

.change {
  display: flex;
  gap: 10px;
  padding: 10px 2px;
  border-bottom: 1px solid var(--line);
}

.change:last-child { border-bottom: none; }

.change-dot {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  margin-top: 6px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 55%, var(--line));
}

.change-body { flex: 1 1 auto; min-width: 0; }

.change-what {
  display: block;
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
}

.change-who {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
}

.change-was {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--muted-strong);
  overflow-wrap: anywhere;
}

/* ------------------------------------------------- waiting on somebody ----
   The work has not moved. Somebody's attention has. */
/* What actually turned up. A part load is the normal case and has to read as
   unfinished, or a shortage looks like a completed order. */
.deliveries {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 12px 0 4px;
}

.deliveries-head {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.delivery {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--surface-muted);
  border-left: 3px solid var(--muted);
}

.delivery.is-complete {
  border-left-color: var(--done);
}

.delivery-what { font-size: 14px; }
.delivery-note { font-size: 13px; color: var(--buy); }
.delivery-who { font-size: 12px; color: var(--muted); }

.form-check {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 4px 0 8px;
  font-size: 14px;
}

.form-check input { width: 18px; height: 18px; }

.waiting {
  margin-top: 14px;
  padding: 12px;
  border-radius: 11px;
  border: 1px solid color-mix(in srgb, var(--claim) 34%, var(--line));
  background: var(--claim-soft);
}

/* waiting on YOU is a different sentence, and gets a different colour */
.waiting.is-mine {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: var(--accent-soft);
}

.waiting-head {
  display: block;
  font-size: 13px;
  font-weight: 800;
  color: var(--text);
}

.waiting-what {
  margin: 6px 0 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--text);
  overflow-wrap: anywhere;
}

.waiting-who {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-strong);
}

.settled {
  margin: 14px 0 0;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--surface-muted);
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
  overflow-wrap: anywhere;
}

.settled.is-approved { background: var(--done-soft); }
.settled.is-declined { background: var(--issue-soft); }
.settled-when { color: var(--muted-strong); }

.meta-waiting { color: var(--claim-ink); font-weight: 800; }

/* an approval and a question are two different things behind one button */
.ask-kinds {
  display: flex;
  flex-wrap: wrap;              /* four kinds since 15 Oct: two per row on a phone */
  gap: 8px;
  margin: 4px 0 14px;
}
.ask-kinds .ask-kind { flex: 1 1 45%; min-width: 45%; }

/* RFA / RFI are what a site calls these. The gloss under each is for whoever is
   new, and it stops being read the day they are not. */
.ask-kind {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  flex: 1 1 0;
  min-height: 52px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--surface);
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  color: var(--muted-strong);
  cursor: pointer;
}

.ask-kind.is-active {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--text);
}

/* A heading that is also a record opens like one. The day headings in Closed and
   the "Others" label are not records, and stay inert. */
.group-heading.is-open {
  width: 100%;
  /* it is a button now, so it is sized like one - 37px was a label's height */
  min-height: 44px;
  align-items: center;
  border: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  border-radius: 8px;
}

.group-heading.is-open:hover { background: var(--surface-muted); }
.group-heading.is-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.group-heading.is-open:active { transform: scale(0.997); }

.group-chev {
  flex: 0 0 auto;
  margin-left: auto;
  font-size: 18px;
  line-height: 1;
  color: var(--muted-strong);
}

.ask-kind > span {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  opacity: 0.85;
}

/* --------------------------------------------------------- thumb-sized ----
   The CPM board was built before the touch pass the crew screen went through:
   the header icons were 38px, the filters 39, the roster button 38. Every one
   of them is pressed with a thumb, outdoors, in gloves. */
.icon-button { min-width: 44px; min-height: 44px; }

.controls .select-wrap {
  min-height: 44px;
  display: flex;
  align-items: center;
}

.controls .select-wrap select { width: 100%; }

.people-button { min-height: 44px; }

/* Four cards in a row read as a row when the number and the word share an axis.
   Left-aligned, a two-word label wraps under a one-word neighbour and the whole
   strip looks knocked out of true. */
.count-card {
  text-align: center;
  align-items: center;
}

.count-number,
.count-label { text-align: center; }

.count-label {
  display: block;
  line-height: 1.15;
  overflow-wrap: anywhere;
}

/* The select IS the control - the wrapper only draws the box round it, so a
   44px wrapper with an 18px select inside is a 44px target you can miss. */
.select-wrap { padding: 0 10px; }
.select-wrap select { min-height: 42px; width: 100%; }
#project-select { min-height: 42px; }
#ask-of, #edit-owner, #edit-status, #edit-parent, #edit-due { min-height: 44px; }

.modal-close {
  display: grid;
  place-items: center;
  min-width: 44px;
  min-height: 44px;
}

/* --------------------------------------------- more than one pair of hands ---
   A wall gets poured by three men. Ticks rather than a dropdown, and one Update
   at the end - applying on each tick would send three requests and three rounds
   of notifications to put three men on one job. */
.picks {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-bottom: 10px;
}

.pick {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 44px;
  padding: 0 13px 0 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
}

.pick.is-on {
  border-color: var(--accent);
  background: var(--accent-soft);
  font-weight: 700;
}

.pick input {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--accent);
}

.picks-apply[hidden] { display: none; }
/* It commits the change, so it is a real button and it spans the sheet like
   every other decision on it - not a chip tucked under the names. */
.picks-apply { width: 100%; margin-top: 10px; }

/* ═══════════════════════════════════════════════════════════════════════════
   REDESIGN · stage 1 — presentation only.
   Appended, never rewritten in place: an earlier pass in this codebase removed
   a selector from a ten-selector list with a regex and silently broke .topbar,
   .project-strip and .controls at once. Additive rules cannot do that.
   Everything here rides classes the JS already emits.
   ═══════════════════════════════════════════════════════════════════════════ */

/* --- the CPM list: a coloured edge per kind ------------------------------
   A scan down the register should say what KIND each row is without reading
   it. The fill stays neutral because colour is spoken for by the selected
   tab; an edge is loud enough to sort by and quiet enough to sit under it. */
.record-card {
  border-left: 3px solid var(--line);
  border-radius: 12px;
}
.record-card.state-issue { border-left-color: var(--issue); }
.record-card.state-buy   { border-left-color: var(--buy); }
.record-card.state-claim { border-left-color: var(--claim); }
.record-card.state-done  { border-left-color: var(--done); }
.record-card.state-open  { border-left-color: var(--open); }
/* A child sits under its parent, so it says so by inset rather than by colour. */
.record-card.is-child { border-left-color: transparent; }

/* --- the crew/PIC list: the same idea, and room to tap ------------------- */
.job { min-height: 64px; }
.job-what { line-height: 1.32; }
.job-meta { margin-top: 3px; }

/* --- section captions ---------------------------------------------------
   ONLY the ones that are labels. .group-title does double duty: over a group of
   jobs it carries "TH-#2 - Water pooling at the back of the slab", which is a
   RECORD's number and title and opens like any other record. Styling the class
   flat turned every parent into a small grey uppercase caption while its own
   children stayed full cards - which is exactly the inconsistency it caused.
   .is-open is the marker the heading already sets when it IS a record. */
.group-heading:not(.is-open) > .group-title {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted-strong);
}

/* --- the four counts ----------------------------------------------------
   Tabular numerals so 4 / 14 / 31 / 3 sit on one baseline grid instead of
   drifting, which is what made the row read as decoration. */
.count-number {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

/* --- what the app says back ---------------------------------------------
   The toast carries the undo, because that is where the regret is: a tick
   reversed here costs one tap, found an hour later it costs a hunt. */
.notice {
  border-radius: 13px;
  box-shadow: 0 10px 28px rgba(23, 38, 47, 0.28);
}

/* --- the three states nobody designs ------------------------------------
   An empty board is usually GOOD NEWS on a site, and an error should name
   what did not happen rather than announce that something occurred. */
.empty-state,
.error-state {
  padding: 34px 24px;
  text-align: center;
}

/* --- one primary action per surface -------------------------------------
   Eight full-width buttons read as eight decisions. The primary keeps its
   weight; everything beside it steps back rather than competing. */
.detail-footer .secondary-action {
  font-weight: 600;
  color: var(--muted-strong);
}
.detail-footer .primary-action { font-weight: 670; }

/* --- destructive actions stand apart ------------------------------------
   Delete and re-open are one thumb-width apart today and only one of them
   can be undone. */
.detail-footer .danger-action { margin-top: 6px; }

/* --- what each crew/PIC row IS ------------------------------------------
   The manager's list has carried state-* since it was written; this one had
   nothing, so a crew board was a column of identical grey rows and telling a
   problem from a delivery meant reading every line. */
.job {
  border-left: 3px solid transparent;
  padding-left: 9px;
}
.job.kind-issue    { border-left-color: var(--issue); }
.job.kind-purchase { border-left-color: var(--buy); }
.job.job-receive   { border-left-color: var(--buy); }
.job.job-release   { border-left-color: var(--claim); }
.job.is-done       { border-left-color: var(--done); }

/* --- a site's numbers, as chips -----------------------------------------
   Three counts joined by dots read as one sentence nobody parses. Waiting
   means somebody is blocked, so it does not look like the two that are just
   counts. */
.site-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 5px;
}
.site-chip {
  font-size: 11px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  padding: 2px 7px;
  border-radius: 6px;
  background: var(--surface-muted);
  color: var(--muted-strong);
  white-space: nowrap;
}
.site-chip.is-waiting  { background: var(--issue-soft); color: var(--issue-ink); }
.site-chip.is-critical { background: var(--claim-soft); color: var(--claim-ink); }

/* --- one decision, then tools, then the rest ----------------------------
   Eight stacked full-width buttons read as eight decisions. The tools are a
   ROW of equals because none of them is the decision; putting them at full
   width is what made them compete with it. */
.detail-tools {
  display: flex;
  gap: 8px;
  margin-top: 4px;
}
.detail-tool {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 48px;
  margin: 0;
  padding: 0 8px;
  font-size: 13px;
  font-weight: 600;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.detail-more {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}
.detail-more[hidden] { display: none; }
.detail-more-toggle {
  margin-top: 4px;
  font-weight: 600;
  color: var(--muted-strong);
}
/* Destructive last, and never adjacent to the thing above it: delete and
   re-open sit one thumb-width apart and only one can be undone. */
.detail-more .danger-action { margin-top: 4px; }

/* --- waiting on you -----------------------------------------------------
   The three numbers this screen used to lead with all read zero on real data:
   nothing has ever been flagged urgent and no claim has ever been open. These
   are the items with a PERSON on the other end, oldest first. When there is
   nothing waiting the band is absent rather than a zero. */
.home-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: 2px 2px 9px;
}
.home-head-title {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted-strong);
}
.home-head-count {
  font-size: 11px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--issue-ink);
}
/* The "Waiting on you" list uses the ordinary card now (issue-group kind-claim),
   so the bespoke row that used to live here is gone rather than left behind as a
   second way of drawing the same thing. */

/* ═══════════════════════════════════════════════════════════════════════════
   REDESIGN · stage 3 — the part you can actually see.
   Stages 1 and 2 changed structure and left the button system alone, so the
   board still read as the old one: every action was 11px at weight 800 in a
   44px pill, which is a dense admin-tool label, not something a man presses
   standing on a site.
   ═══════════════════════════════════════════════════════════════════════════ */

/* --- the actions -------------------------------------------------------- */
.secondary-action,
.primary-action,
.danger-action {
  min-height: 48px;
  padding: 12px 16px;
  border-radius: 12px;
  /* 11px/800 is a label. This is a button, and it is pressed with a thumb, in
     the sun, by somebody who is not looking for it. */
  font-size: 14.5px;
  font-weight: 620;
  letter-spacing: 0;
}
.primary-action {
  min-height: 50px;
  font-size: 15.5px;
  font-weight: 670;
}
/* A SECONDARY BUTTON WAS WHITE ON WHITE. --surface against the sheet it sits
   on, separated by one hairline - so Send for RFI/RFA, Attach a photo and More
   read as labels somebody had drawn a box around rather than things to press.
   They are filled now, with an edge that survives daylight and a shadow thin
   enough not to compete with the green one that ends the job. */
.secondary-action {
  background: var(--surface-muted);
  border-color: color-mix(in srgb, var(--line) 70%, var(--text) 12%);
  color: var(--text);
  box-shadow: 0 1px 1px rgba(23, 38, 47, 0.06);
}
.secondary-action:hover {
  background: color-mix(in srgb, var(--surface-muted) 84%, var(--text) 6%);
}
.danger-action {
  background: var(--issue-soft);
  border-color: #e0a9a7;
  color: var(--issue-ink);
}

/* A button that moves when pressed is the cheapest confirmation there is, and
   on a site the tap is often made without looking at the screen afterwards. */
.secondary-action,
.primary-action,
.danger-action {
  transition: background 120ms ease, transform 60ms ease, box-shadow 120ms ease;
}
.secondary-action:active,
.primary-action:active,
.danger-action:active {
  transform: translateY(1px);
  box-shadow: none;
}
.primary-action { box-shadow: 0 1px 2px rgba(23, 38, 47, 0.16); }

/* FINISHING work is green, and nothing else is.
   Blue is "go somewhere / commit to something"; green means the job is over.
   One colour, one meaning - a board where the ordering button and the done
   button look identical is one where the difference has to be read. */
.primary-action.is-finish {
  background: var(--done);
  border-color: var(--done);
  color: #ffffff;
}

/* --- the tool row -------------------------------------------------------- */
/* The tools are a rung below the decision above them, and they say so with SIZE
   and weight - 13px/600 against 14.5px/620. They used to say it by being white
   on a white sheet, which is not a quieter button, it is a missing one. */
.detail-tool {
  min-height: 48px;
  padding: 0 8px;
  font-size: 13px;
  font-weight: 600;
  background: var(--surface-muted);
  color: var(--muted-strong);
}

/* --- room to read -------------------------------------------------------- */
.detail-footer { gap: 9px; margin-top: 20px; }
.record-card { padding: 14px 14px 13px; }
.job { padding-top: 14px; padding-bottom: 14px; }
.job-what { font-size: 14px; font-weight: 600; }

/* --- a parent heading is a record, so it says what a record says ---------
   Every child under it carried a status, an owner and an age while the problem
   they belong to said nothing about itself. The sub-line is uppercase where it
   is a LABEL's caption; under a record it is a person's name and a number of
   days, and shouting those reads as a heading rather than a fact. */
.group-heading.is-open > .group-sub {
  font-size: 12px;
  font-weight: 550;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted-strong);
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE CREW BOARD — the screen with the most users and the least room.
   Tapped standing up, in the sun, with a glove on, by somebody who opens it
   because there is something in it for him.
   ═══════════════════════════════════════════════════════════════════════════ */

/* --- the day, as a band -------------------------------------------------
   The one gold thing on the screen. It is the reason he opened this, so it
   reads as a reward rather than a status line. */
.today {
  padding: 15px 16px;
  border: 1px solid #e2c98a;
  border-radius: 14px;
  background: linear-gradient(180deg, var(--gold-soft) 0%, var(--surface) 82%);
}
.today-count {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.today-week {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--gold);
  margin-top: 4px;
}
/* The rule, once, quietly. It has to be here for a man opening this the first
   time and must not compete with the number every day after that. */
.today-rule {
  font-size: 12px;
  line-height: 1.45;
  color: var(--muted-strong);
  margin-top: 8px;
}

/* --- what this job is worth ---------------------------------------------
   On the row, where the decision is made. */
.job-worth {
  display: inline-flex;
  align-items: center;
  margin-top: 5px;
  padding: 2px 7px;
  border-radius: 6px;
  background: var(--gold-soft);
  color: var(--gold);
  font-size: 11px;
  font-weight: 650;
  white-space: nowrap;
}

/* --- finished work stays, and looks finished ---------------------------- */
.issue-group.is-done-today .issue-jobs { background: var(--done-soft); }
.job.is-done .job-what { color: var(--done-ink); }

/* --- room to press ------------------------------------------------------
   44px is the floor, not the target. This is the one list in the app tapped
   with a glove on. */
.job { min-height: 66px; }


/* ===========================================================================
   THE FIELD FRAME - the mockup was mostly about what is NOT on the screen.
   A crew man was handed the manager's chrome: an app title, an identity card,
   a project card, a sort control, and then the band. Five stacked blocks
   before his first job. The mockup opens on one identity bar and goes
   straight to the work.
   =========================================================================== */

/* Inside Telegram the chat header already says which app this is. Repeating
   it in our own topbar spends the top of the screen saying nothing. The
   ACTIONS stay - he can still raise something, and still refresh. */
/* THE DASHBOARD HAS NO TITLE BAR. Every control in it names something about one
   site - add a record TO it, ITS timeline - and this is the screen where he has
   not chosen one yet. With the brand-lockup already hidden in the field view,
   what was left was an empty strip with three buttons that could not act. The
   person card below is the header now, which is what the plan drew. */
.on-home .topbar { display: none; }
.on-home #me-slot { margin-top: 4px; }

/* THE TITLE STAYS, for crew too. It was hidden on the reasoning that Telegram
   already shows the app's name above it - but Telegram shows the BOT's name
   ("Tagusao Project Bot"), not the board's, so what the header actually said
   was nothing, and the row was three buttons floating against blank space.
   Smaller than the manager's, because a crew screen is read one-handed and the
   jobs below it are what he came for. */
.as-field .brand-lockup { gap: 8px; }
.as-field .brand-mark { width: 30px; height: 30px; font-size: 14px; }
.as-field .brand-lockup .eyebrow { display: none; }
.as-field .brand-lockup h1 { font-size: 17px; }
.as-field .topbar {
  justify-content: space-between;
  min-height: 0;
  padding-bottom: 8px;
  border-bottom: none;
}

/* The identity bar IS the header now, so it is built like one: a square tile
   rather than a floating avatar, sitting flush under the actions. */
.as-field .me { margin-top: 4px; }
.as-field .me-face { border-radius: 12px; }

/* One site is the normal case on site, and its name is on the bar above. A
   selector holding one option is a control that cannot be used. */
.as-field.one-site .project-strip { display: none; }
.as-field .project-strip {
  margin: 12px 0 12px;
  padding: 11px 13px;
  border-left-width: 3px;
  box-shadow: none;
}
.as-field .project-strip .eyebrow,
.as-field .project-strip .project-day { display: none; }

/* Sorting three jobs is not something anybody needs a control for. */
.view-crew .controls { display: none; }

/* --- the day, as the mockup drew it -------------------------------------
   Icon, one sentence, the run on the right, then the bar. The 40px numeral
   this replaces was the largest thing on the screen, and on most days it
   reads nought - a lot of gold spent telling a man he has done nothing yet. */
.today-line {
  display: flex;
  align-items: center;
  gap: 11px;
}
.today-bolt { flex: 0 0 auto; color: var(--gold); }
.today-said {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 650;
  line-height: 1.35;
  color: var(--text);
}
/* two classes, so it beats the 40px .today-count the manager's screen uses */
.today-said .today-count {
  font-size: 15px;
  font-weight: 800;
  color: var(--text);
}
.today-said .today-count.is-scored { color: var(--done-ink); }
.today-run {
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 700;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}
/* The progress bar went with the denominator it measured: the count now goes
   up with no ceiling, and a bar needs something to be full of. */
.today .today-week { margin-top: 9px; }

/* --- the row stacks ------------------------------------------------------
   what / who / what it is worth were three inline spans running together on
   one line, so "Photo = 2 points" landed in the middle of a wrapped title. */
.job-body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
/* A mark, and it should look like the tick box it is rather than a radio. */
.job-box { width: 24px; height: 24px; border-radius: 7px; }
.job-what { font-size: 15px; font-weight: 600; }
.job-worth { gap: 5px; padding: 3px 8px; font-size: 11.5px; }

/* One tool is not a toolbar. Stretched full width it is indistinguishable
   from a stacked decision, which is the thing the tier exists to stop. */
.detail-tools.is-alone { justify-content: flex-start; }
.detail-tools.is-alone .detail-tool { flex: 0 1 auto; padding: 0 18px; }


/* --- the group is one card, and its head says what kind of thing it is ----
   The mockup railed and tinted the PROBLEM, then let its jobs sit plainly
   inside the same card. What we shipped was a grey caption bar with a second
   blue rail down the jobs - two containers where the design has one, and the
   colour saying nothing about what the record is. */
.as-field .issue-group {
  background: var(--surface-raised);
  box-shadow: var(--shadow);
}
.as-field .issue-head {
  padding: 12px 14px 12px 11px;
  border-left: 3px solid var(--issue);
  background: color-mix(in srgb, var(--issue) 4%, var(--surface-raised));
}
.as-field .issue-head-what { color: var(--issue-ink); }
.as-field .issue-group:not(.is-loose) .issue-jobs {
  margin-left: 0;
  padding-left: 0;
  border-left: none;
}

/* A trade and a site are a name and a place, not a label. Shouting them in
   uppercase made the one human line on the screen read like a form field. */
.as-field .me-sub {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted-strong);
}

/* One gold thing at a time: the run and the bar. This is a footnote. */
.today .today-week { color: var(--muted-strong); font-weight: 600; }

.as-field .issue-head-what { font-weight: 700; }

/* The band is its own thing, not stuck to the identity bar above it. */
.as-field .today { margin-top: 14px; }

/* A tile, in the site colour, the way the mockup drew it - a grey circle with a
   letter in it reads as a missing photo rather than a person. */
.as-field .me-face:not(img) { background: var(--accent); color: var(--surface); }


/* --- what was taken off the boards --------------------------------------
   The manager's sight of everybody else's curation. A PIC still clears the
   bot's duplicates off his own site; this is the record that he did, and the
   one button that undoes it. */
.gone {
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--muted);
  border-radius: 12px;
  background: var(--surface);
  margin-bottom: 10px;
}
.gone-what {
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text);
  overflow-wrap: anywhere;
}
.gone-n {
  display: inline-block;
  margin-right: 7px;
  padding: 2px 6px;
  border-radius: 5px;
  background: var(--surface-muted);
  color: var(--muted-strong);
  font-size: 11px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.gone-meta {
  margin-top: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-strong);
  font-variant-numeric: tabular-nums;
}
/* Deliberately quiet. Undoing somebody's tidying is a considered act, not the
   thing the eye lands on first. */
.gone-back {
  width: 100%;
  margin: 11px 0 0;
  min-height: 42px;
  font-size: 13px;
}

/* --- the day band, tightened ---------------------------------------------
   THE DATE IS THE HEADLINE. It was 13px uppercase in muted grey - smaller and
   fainter than the sentence under it - so the one thing that says which day
   this is was the quietest thing in the box. It reads first now.

   The weekly total is gone from the markup: this band is about TODAY, and a
   third number nobody acts on was competing with the two that matter.

   And the rule at the bottom is instruction, not score, so a hairline separates
   it rather than the reader having to work out that it changed subject. */
.today { padding: 16px 16px 14px; }

.today-day {
  font-size: 15.5px;
  font-weight: 800;
  letter-spacing: 0.05em;
  color: var(--text);
  margin-bottom: 9px;
}

.today-line { gap: 10px; }
.today-week { margin-top: 7px; }

.today-rule {
  margin-top: 12px;
  padding-top: 11px;
  border-top: 1px solid color-mix(in srgb, var(--gold) 26%, transparent);
}

/* --- where a purchase has got to -----------------------------------------
   Seven chips in the order the job actually happens, so the next step is the
   one to the right and the whole journey is on screen. The current one is lit
   the way a chosen person is; the ones he may not set are dimmed rather than
   hidden, because a stage you cannot reach is still a stage this thing has. */
.pr-status .picks { gap: 6px; }
.pr-status .pick {
  min-height: 36px;
  padding: 0 11px;
  font-size: 12.5px;
  font-weight: 600;
}
.pr-status .pick:disabled { cursor: default; }
.pr-status .pick:disabled:not(.is-on) { opacity: 0.45; }
/* Something went wrong with this one, and it is not a step forward. */
.pr-status .pick.is-bad.is-on {
  border-color: var(--issue);
  background: var(--issue-soft);
  color: var(--issue-ink);
}

/* ── A PROBLEM AND A JOB SHOULD NOT LOOK ALIKE (Arjo, 2026-09-04) ────────────
   Both opened as the same card, so telling them apart meant reading the number
   and knowing that # is one and T the other. The kind is spelled out in the
   eyebrow and the card is coloured by it - on the top edge, the ring, and the
   PRIMARY ACTION, because the action is what gets pressed in a hurry. */
.detail-card { border-top: 3px solid var(--accent); }
.detail-card.is-issue { border-top-color: var(--issue); }
.detail-card.is-purchase { border-top-color: var(--buy); }
.detail-card .modal-eyebrow {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
}
.detail-card.is-issue .modal-eyebrow { background: var(--issue-soft); color: var(--issue-ink); }
.detail-card.is-purchase .modal-eyebrow { background: var(--buy-soft); color: var(--buy); }
/* NOT the primary action. Colouring it by kind turned two identical "this is
   finished" buttons into red on an issue and green on a task, and red on a button
   labelled Resolve reads as danger when resolving is the good outcome. Finish stays
   green everywhere; the kind is carried by the eyebrow, the top edge and the ring. */
.detail-card.is-issue { box-shadow: var(--shadow), 0 0 0 3px var(--issue-soft); }
.detail-card.is-task { box-shadow: var(--shadow), 0 0 0 3px var(--accent-soft); }
.detail-card.is-purchase { box-shadow: var(--shadow), 0 0 0 3px var(--buy-soft); }

/* ── WHO OWNS THIS, IN ONE ROW ───────────────────────────────────────────────
   Was a checkbox per person, always expanded. Office Works has 24 members, so
   the control naming the owner pushed the record off the screen. */
.assign-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 10px 12px; margin-top: 4px;
  background: var(--surface-raised); border: 1px solid var(--line);
  border-radius: 10px; font: inherit; color: var(--text); cursor: pointer;
}
.assign-row:active { transform: scale(.995); }
.assign-who { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.assign-name { font-size: 15px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.assign-name.is-none { color: var(--issue-ink); }
.assign-more { font-size: 13px; color: var(--muted); flex: none; }
.assign-change { font-size: 13px; color: var(--accent); flex: none; }

/* The picker itself. position:fixed is correct here - it is a real overlay in a
   real webview, not a mockup that has to contribute layout height. */
.sheet-backdrop {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(12, 22, 28, .45);
  display: flex; align-items: flex-end; justify-content: center;
}
.sheet {
  width: 100%; max-width: 460px; max-height: 82vh;
  display: flex; flex-direction: column;
  background: var(--surface); border-radius: 16px 16px 0 0;
  padding: 14px 14px calc(14px + env(safe-area-inset-bottom, 0px));
}
.sheet-title { margin: 0 0 10px; font-size: 16px; font-weight: 700; }
.sheet-find {
  width: 100%; padding: 9px 11px; font: inherit; font-size: 15px;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--surface-raised); color: var(--text);
}
.sheet-list { flex: 1; overflow-y: auto; margin: 10px 0 4px; }
.sheet-group {
  margin: 10px 0 4px; font-size: 11px; font-weight: 700;
  letter-spacing: .07em; color: var(--muted);
}
.sheet-group:first-child { margin-top: 0; }
.sheet-person {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 6px; border: 0; background: none; font: inherit;
  color: var(--text); text-align: left; cursor: pointer; border-radius: 8px;
}
.sheet-person:active { background: var(--surface-muted); }
.sheet-face {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700;
  background: var(--surface-muted); color: var(--muted-strong);
}
.sheet-person.is-on .sheet-face { background: var(--accent); color: #fff; }
.sheet-person-name { flex: 1; font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sheet-tick { color: var(--accent); font-weight: 700; }
/* the tick sheet (2 Oct): several answers, one Send under the list */
.sheet-hint { margin: -6px 0 6px; font-size: 13px; color: var(--muted); }
.sheet-send { width: 100%; margin-top: 8px; }
.sheet-send:disabled { opacity: .45; }
.sheet-empty { color: var(--muted); font-size: 14px; padding: 12px 6px; }
.sheet-foot { display: flex; gap: 8px; padding-top: 10px; border-top: 1px solid var(--line); }
.sheet-apply { flex: 1; }
.sheet-apply[disabled] { opacity: .4; }

/* ── WAS THE BOT WRONG, OR DID IT CHANGE? ────────────────────────────────────
   A bar, not a modal. He has just finished an edit and is on his way somewhere;
   a dialog demanding an answer gets dismissed, and a dismissed question teaches
   nothing while training him to dismiss the next one. */
.learn-bar {
  position: fixed; left: 12px; right: 12px; z-index: 70;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 12px; border-radius: 12px;
  background: var(--surface-raised); border: 1px solid var(--line);
  box-shadow: var(--shadow);
}
.learn-ask { flex: 1 1 100%; font-size: 14px; font-weight: 600; }
.learn-bar button {
  flex: 1; padding: 8px 10px; border-radius: 9px; font: inherit; font-size: 13px;
  border: 1px solid var(--line); background: var(--surface); color: var(--text);
}
.learn-yes { border-color: var(--issue) !important; color: var(--issue-ink) !important; }

/* =====================================================================
   POLISH LAYER - 2026-09-05
   CSS only. Same markup, same class names, same behaviour, same dark mode.
   Everything sits here at the end so the whole pass reads (and reverts) as
   one block. What changed and why:
     - Tokens: cleaner neutrals, true-white surfaces, a slightly deeper
       accent, one 16px radius, and a two-part shadow that replaces hairline
       borders as the thing that separates a card from the ground.
     - Texture: the 48px drafting grid becomes a fine grain that fades out
       below the fold - present, never competing with a record.
     - Chips, tags and counts become pills; the count tiles lose the thick
       top border and select with a tint instead.
   Palette variants (`:root[data-palette]`) are a DEV-ONLY comparison
   switch - dev-stub.js sets it from ?palette=; production never sets it.
   ===================================================================== */
:root {
  --bg: #f1f4f6;
  --surface: #ffffff;
  --surface-raised: #ffffff;
  --surface-muted: #e9eef1;
  --line: #dde4e9;
  --text: #16232b;
  --muted: #687985;
  --muted-strong: #4b5d68;
  --accent: #2f5e78;
  --accent-soft: #dde9f0;
  --shadow: 0 1px 2px rgba(23, 38, 47, 0.05), 0 6px 18px rgba(23, 38, 47, 0.06);
  --shadow-raised: 0 2px 4px rgba(23, 38, 47, 0.06), 0 16px 36px rgba(23, 38, 47, 0.12);
  --radius: 16px;
  --radius-sm: 10px;
}
:root[data-color-scheme="dark"] {
  --bg: #10191f;
  --surface: #182430;
  --surface-raised: #1e2c37;
  --surface-muted: #233340;
  --line: #31424d;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 10px 28px rgba(0, 0, 0, 0.32);
  --shadow-raised: 0 2px 4px rgba(0, 0, 0, 0.4), 0 20px 48px rgba(0, 0, 0, 0.45);
}
/* Dev comparison palettes. Navy: cooler, higher contrast. Graphite: near-mono
   with the record colours doing all the talking. */
:root[data-palette="navy"] {
  --bg: #eef2f7; --surface-muted: #e5ebf3; --line: #d8e0ea;
  --text: #101b2a; --muted: #66768b; --muted-strong: #475a72;
  --accent: #2a4c7c; --accent-soft: #dfe8f6;
}
:root[data-palette="navy"][data-color-scheme="dark"] {
  --bg: #0f151e; --surface: #171f2c; --surface-raised: #1c2635; --surface-muted: #212d3d;
  --line: #2f3d50; --accent: #8db4e6; --accent-soft: #203348;
  --text: #edf2f8; --muted: #a3b1c4; --muted-strong: #b8c5d6;
}
:root[data-palette="graphite"] {
  --bg: #f3f4f5; --surface-muted: #e9ebed; --line: #dfe2e5;
  --text: #171c20; --muted: #6b747b; --muted-strong: #4d565e;
  --accent: #38454f; --accent-soft: #e2e6e9;
}
:root[data-palette="graphite"][data-color-scheme="dark"] {
  --bg: #121517; --surface: #1b1f23; --surface-raised: #21262b; --surface-muted: #272d33;
  --line: #363d44; --accent: #b6c2cc; --accent-soft: #2b343b;
  --text: #eef1f3; --muted: #a5adb4; --muted-strong: #bcc4ca;
}

/* Hardhat: construction colours. Dark blue is the brand, hi-vis yellow is the
   highlight (score, primary action, the active tab's stripe), and the record
   kinds move to a clear red / green / blue. "Waiting" shifts from amber to
   orange-amber so it never reads as the brand yellow. */
:root[data-palette="hardhat"] {
  --bg: #eef2f6; --surface-muted: #e6ecf2; --line: #d9e1ea;
  --text: #0f1f33; --muted: #5f7085; --muted-strong: #40536a;
  --accent: #1b3a5c; --accent-soft: #dbe6f2;
  --yellow: #f5c400; --yellow-soft: #fff3bf; --yellow-ink: #7a5b00;
  --gold: #7a5b00; --gold-soft: #fff3bf;
  --issue: #c8352f; --issue-soft: #fde3e1; --issue-ink: #a12a25;
  --buy: #1f8a4c; --buy-soft: #ddf3e4; --buy-ink: #146336;
  --open: #2e6fd6; --open-soft: #e0ebfb; --open-ink: #1f52a3;
  --claim: #d97706; --claim-soft: #fff1dc; --claim-ink: #8a4b04;
  --done: #1f8a4c; --done-soft: #ddf3e4; --done-ink: #146336;
}
:root[data-palette="hardhat"][data-color-scheme="dark"] {
  --bg: #0c1624; --surface: #132133; --surface-raised: #182a40; --surface-muted: #1c3047;
  --line: #2b4058; --text: #eaf0f7; --muted: #9fb0c4; --muted-strong: #b7c6d6;
  --accent: #7fb0e8; --accent-soft: #1e3651;
  --yellow: #f5c400; --yellow-soft: #3d3410; --yellow-ink: #f5d35a;
  --gold: #f5d35a; --gold-soft: #3d3410;
  --issue: #f08a85; --issue-soft: #42262a; --issue-ink: #ff9d9b;
  --buy: #5fcf8a; --buy-soft: #173826; --buy-ink: #6fe0a0;
  --open: #6ea8f5; --open-soft: #1b2f4a; --open-ink: #9cc4ff;
  --claim: #f0a83a; --claim-soft: #3f2f18; --claim-ink: #f5c56a;
  --done: #5fcf8a; --done-soft: #173826; --done-ink: #6fe0a0;
}
/* Where the yellow goes. Sparingly: it is a highlight, not a fill. */
:root[data-palette="hardhat"] .brand-mark { background: var(--accent); border-color: var(--accent); color: var(--yellow); }
:root[data-palette="hardhat"] .me-score { padding: 6px 10px 5px; border-radius: 10px; background: var(--yellow); }
:root[data-palette="hardhat"] .me-score b { color: #0f1f33; }
:root[data-palette="hardhat"] .me-score span { color: #4a3d0a; }
:root[data-palette="hardhat"] .me-score.is-plain { background: var(--surface-muted); }
:root[data-palette="hardhat"] .me-score.is-plain b { color: var(--text); }
:root[data-palette="hardhat"] .me-score.is-plain span { color: var(--muted); }
:root[data-palette="hardhat"] .count-card.is-active {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: inset 0 -3px 0 var(--yellow);
}
:root[data-palette="hardhat"] .count-card.is-active .count-number,
:root[data-palette="hardhat"] .count-card.is-active .count-label { color: #fff; }
:root[data-palette="hardhat"] .primary-action { background: var(--yellow); border-color: var(--yellow); color: #0f1f33; box-shadow: 0 4px 12px rgba(245, 196, 0, 0.35); }
:root[data-palette="hardhat"] .site-role.is-manager { background: var(--yellow-soft); color: var(--yellow-ink); }
/* Red / green / blue for the kinds: a plain task row gets the blue rail the
   other kinds already have. Delivery and release jobs keep their own colours. */
:root[data-palette="hardhat"] .job.kind-task:not(.job-receive):not(.job-release) { border-left-color: var(--open); }
:root[data-palette="hardhat"][data-color-scheme="dark"] .count-card.is-active { background: var(--accent-soft); }
:root[data-palette="hardhat"][data-color-scheme="dark"] .count-card.is-active .count-number,
:root[data-palette="hardhat"][data-color-scheme="dark"] .count-card.is-active .count-label { color: var(--text); }

/* ---- ground & texture ---------------------------------------------- */
body {
  background:
    radial-gradient(circle at 80% -20%, color-mix(in srgb, var(--accent-soft) 70%, transparent), transparent 40%),
    var(--bg);
}
body::before {
  background-image: radial-gradient(color-mix(in srgb, var(--text) 9%, transparent) 0.7px, transparent 0.8px);
  background-size: 5px 5px;
  opacity: 0.32;
  mask-image: linear-gradient(to bottom, black, transparent 70%);
}
.app-shell { padding-top: 16px; }

/* ---- header ---------------------------------------------------------- */
.topbar { border-bottom: 0; padding-bottom: 10px; }
.brand-mark { border-radius: 10px; }
.brand-mark::after { display: none; }
.icon-button {
  width: 40px; height: 40px;
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}
.icon-button:hover, .icon-button:active { background: var(--surface-muted); }

/* ---- person card ------------------------------------------------------ */
.me {
  align-items: center;
  padding: 13px 14px;
  margin-bottom: 16px;
  border: 0;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.me-face { background: var(--accent-soft); color: var(--accent); }
.me-name { font-size: 17px; }
.me-sub { margin-top: 2px; letter-spacing: 0.05em; }
.me-score b { font-size: 26px; }
.me-chev { color: color-mix(in srgb, var(--muted) 60%, transparent); }
.on-home #me-slot { margin-top: 0; }

/* ---- dashboard --------------------------------------------------------- */
.home-head { margin: 2px 2px 10px; }
.home-head-count {
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--issue-soft);
  color: var(--issue-ink);
  font-weight: 800;
}
.home-title { margin-top: 20px; }
.site {
  min-height: 70px;
  padding: 12px 14px;
  border: 0;
  box-shadow: var(--shadow);
  margin-bottom: 8px;
}
.site-mark { border-radius: 12px; width: 44px; height: 44px; }
.site-mark-photo { box-shadow: inset 0 0 0 1px rgba(23, 38, 47, 0.06); }
.site-chip {
  padding: 3px 8px;
  border-radius: 999px;
  font-weight: 700;
  line-height: 1.3;
}
.site-role { border-radius: 999px; padding: 4px 8px; }
.site-chev { color: color-mix(in srgb, var(--muted) 60%, transparent); }

/* ---- board chrome ------------------------------------------------------- */
.project-strip {
  margin: 14px 0 12px;
  padding: 14px 16px;
  border: 0;
  border-left: 0;
  box-shadow: var(--shadow);
}
.count-grid { gap: 6px; }
.count-card {
  padding: 12px 10px 11px;
  border: 1px solid var(--line);
  border-top-width: 1px;
  border-radius: 12px;
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(23, 38, 47, 0.04);
}
.count-card.is-active {
  padding: 12px 10px 11px;
  border-width: 1px;
  border-top-width: 1px;
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  background: var(--accent-soft);
  box-shadow: 0 1px 2px rgba(23, 38, 47, 0.04), inset 0 0 0 1px color-mix(in srgb, var(--accent) 25%, transparent);
}
.count-number { font-size: 23px; }
.count-label { font-weight: 700; }
.select-wrap select, .secondary-action, .people-button {
  border-radius: 999px;
}
.secondary-action { background: var(--surface); box-shadow: var(--shadow); border-color: transparent; }
.notice { border: 0; border-radius: 12px; box-shadow: var(--shadow); }
.message-state { border-style: solid; border-color: var(--line); }
.skeleton-card { border: 0; border-radius: var(--radius); }

/* ---- records ------------------------------------------------------------- */
.issue-group {
  margin-bottom: 10px;
  border: 0;
  box-shadow: var(--shadow);
}
.issue-group.is-loose { box-shadow: none; }
.issue-group.kind-issue, .issue-group.kind-purchase, .issue-group.kind-claim { border-left-width: 4px; }
.issue-head { padding: 13px 14px; }
.issue-head-what { font-size: 14.5px; font-weight: 750; line-height: 1.35; }
.issue-head-on { color: var(--muted-strong); }
.issue-head-meta { margin-top: 3px; font-weight: 650; color: var(--muted); }
.issue-head-chev { color: color-mix(in srgb, var(--muted) 60%, transparent); }
.issue-group:not(.is-loose) .issue-jobs {
  margin-left: 0;
  padding-left: 0;
  border-left: 0;
  border-top: 1px solid var(--line);
}
.issue-group.is-loose .issue-jobs {
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.job { padding: 12px 14px; border-bottom-color: color-mix(in srgb, var(--line) 70%, transparent); }
.job-box { border-color: color-mix(in srgb, var(--muted) 45%, var(--line)); }
.job-what { font-size: 14.5px; }
.job-meta { font-weight: 650; color: var(--muted); }
.job-chev { color: color-mix(in srgb, var(--muted) 45%, transparent); }
.job-thumbs img { border-radius: 8px; border: 0; box-shadow: inset 0 0 0 1px rgba(23, 38, 47, 0.08); }
.record-card { border-left-width: 4px; border-radius: 12px; box-shadow: var(--shadow); }
.state-badge { font-weight: 750; }
.group-heading { border-bottom: 0; padding-top: 14px; }
.group-sub { padding: 2px 7px; border-radius: 999px; background: var(--surface-muted); }
.crew-heading { margin-top: 18px; }

/* ---- the detail sheet takes its record's colour ---------------------------- */
/* Open a task and the sheet is blue, an issue red, a purchase green - you know
   what you opened before you read a word. Tint, not fill: the controls inside
   stay white so they still read as things to press. The card already carries
   is-task / is-issue / is-purchase from renderDetail. */
.detail-card.is-task, .detail-card.is-issue, .detail-card.is-purchase { box-shadow: var(--shadow-raised); }
.detail-card.is-task { background: var(--open-soft); border-top-color: var(--open); }
.detail-card.is-issue { background: var(--issue-soft); }
.detail-card.is-purchase { background: var(--buy-soft); }
.detail-card.is-task .modal-eyebrow { background: var(--open); color: #fff; }
.detail-card.is-issue .modal-eyebrow { background: var(--issue); color: #fff; }
.detail-card.is-purchase .modal-eyebrow { background: var(--buy); color: #fff; }
.detail-card .detail-facts dd { color: color-mix(in srgb, var(--text) 80%, transparent); }
/* A purchase opens its order form rather than the sheet, so the form is the
   green one. */
#buy-modal .modal-card { background: var(--buy-soft); border-top-color: var(--buy); }
#buy-modal .modal-eyebrow { display: inline-block; padding: 3px 8px; border-radius: 999px; background: var(--buy); color: #fff; }
#buy-modal .form-field input, #buy-modal .form-field textarea, #buy-modal .secondary-action, #buy-modal .modal-close {
  background: var(--surface-raised);
  border-color: transparent;
  box-shadow: 0 1px 2px rgba(23, 38, 47, 0.06), 0 3px 10px rgba(23, 38, 47, 0.05);
}
:root[data-color-scheme="dark"] #buy-modal .form-field input,
:root[data-color-scheme="dark"] #buy-modal .form-field textarea,
:root[data-color-scheme="dark"] #buy-modal .secondary-action,
:root[data-color-scheme="dark"] #buy-modal .modal-close { background: color-mix(in srgb, #fff 8%, transparent); box-shadow: none; }
.detail-card .assign-row,
.detail-card .secondary-action,
.detail-card .modal-close {
  background: var(--surface-raised);
  border-color: transparent;
  box-shadow: 0 1px 2px rgba(23, 38, 47, 0.06), 0 3px 10px rgba(23, 38, 47, 0.05);
}
:root[data-color-scheme="dark"] .detail-card .assign-row,
:root[data-color-scheme="dark"] .detail-card .secondary-action,
:root[data-color-scheme="dark"] .detail-card .modal-close {
  background: color-mix(in srgb, #fff 8%, transparent);
  box-shadow: none;
}

/* ---- modals & controls ---------------------------------------------------- */
.modal-card {
  border: 0;
  border-top: 4px solid var(--accent);
  border-radius: 20px;
  box-shadow: var(--shadow-raised);
}
.modal-close { border: 0; }
.primary-action, .secondary-action, .danger-action { border-radius: 10px; }
.primary-action { box-shadow: 0 4px 12px color-mix(in srgb, var(--accent) 30%, transparent); }
.person.is-pick { border: 0; box-shadow: var(--shadow); }
.form-field input, .form-field select, .form-field textarea { border-radius: 10px; }
.app-footer { margin-top: 24px; color: color-mix(in srgb, var(--muted) 75%, transparent); }

/* ── ASSIGNED TO IS A FACT, AND A WRONG RECORD CAN SAY SO (Arjo, 2026-09-07) ──
   The owner row moves into the facts list - same label column, same value
   column, Change as a link on the right. And a task sheet ends with one small
   link to report that the record is wrong; tapping it opens a short form in
   place, and sending it leaves a receipt with a number. */
.detail-facts dd.fact-assign {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.fact-who {
  font-size: 13px;
  font-weight: 650;
  color: var(--text);
  overflow-wrap: anywhere;
}
.fact-who.is-none { color: var(--issue-ink); }
.fact-change {
  flex: 0 0 auto;
  margin: -6px -6px -6px 0;
  padding: 6px;
  border: 0;
  background: none;
  font: inherit;
  font-size: 12px;
  font-weight: 650;
  color: var(--accent);
  cursor: pointer;
  white-space: nowrap;
}

.detail-footer .report-error {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  margin-top: 2px;
}
.report-error-link {
  border: 0;
  background: none;
  padding: 8px 10px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--muted) 45%, transparent);
  cursor: pointer;
}
.detail-footer .report-form {
  display: grid;
  gap: 8px;
  margin-top: 4px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-muted);
  text-align: left;
}
.report-label {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted-strong);
}
.report-what {
  width: 100%;
  min-height: 76px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-raised);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  line-height: 1.4;
  resize: vertical;
}
.report-note {
  font-size: 11px;
  line-height: 1.4;
  color: var(--muted);
}
.report-actions { display: flex; gap: 8px; }
.report-actions > * { flex: 1; min-height: 44px; }
.detail-footer .report-done {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--done-soft);
  color: var(--done-ink);
  font-size: 13px;
  font-weight: 650;
  text-align: center;
}

/* ── OPEN IN TELEGRAM, IN TELEGRAM'S BLUE (Arjo, 2026-09-08) ──────────────────
   On the task sheet the conversation comes first: this button sits at the top
   of the footer, tall, in the colour of the app it opens, so the one action
   that leaves the board looks like where it goes. Not primary-action - that
   class is the job's own finish button, and only one of those per sheet. */
.telegram-action {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 46px;
  padding: 7px 12px;
  border: 1px solid #2aabee;
  border-radius: 11px;
  background: #2aabee;
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 670;
  cursor: pointer;
}
.telegram-action:hover, .telegram-action:active { background: #229ed9; border-color: #229ed9; }
.telegram-action .ic { flex: none; }

/* ── "N YOURS" (Arjo, 2026-09-09) ─────────────────────────────────────────────
   The one dashboard number that is about the reader. Accent, not amber or red:
   information, not a warning. Same chip in the summary row, on its own ground. */
.site-chip.is-mine { background: var(--accent-soft); color: var(--accent); }

/* ── THE SITE PICKER IS OURS (Arjo, 2026-09-09) ───────────────────────────────
   A native <select> cannot carry the dashboard's chip. The strip shows a
   button in the select's place; tapping it opens a sheet of sites, each with
   the same accent number. Same sheet as the owner picker. */
.project-label select[hidden] { display: none; }
.project-pick {
  display: inline-flex; align-items: center; gap: 9px; max-width: 100%;
  margin-left: -5px; padding: 2px 4px; border: 0; background: none;
  font: inherit; font-size: 18px; font-weight: 750; color: var(--text); cursor: pointer;
}
.project-pick-name { flex: 0 1 auto; min-width: 0; white-space: nowrap; }
.project-pick .site-chip, .project-pick-chev { flex: none; }
.project-pick .site-chip { font-size: 12px; padding: 3px 9px; }
.project-pick-chev { color: var(--muted); font-size: 15px; line-height: 1; margin-top: -4px; }
.project-pick[disabled] { cursor: default; }
.project-pick[disabled] .project-pick-chev { display: none; }
.sheet-site {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 52px;
  padding: 8px 6px; border: 0; background: none; font: inherit; color: var(--text);
  text-align: left; border-radius: 10px; cursor: pointer;
}
.sheet-site:active { background: var(--surface-muted); }
.sheet-site-mark {
  flex: none; width: 34px; height: 34px; border-radius: 9px; object-fit: cover;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 800; background: var(--accent-soft); color: var(--accent);
}
.sheet-site-name { flex: 1; font-size: 15px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sheet-site.is-on .sheet-site-name { font-weight: 800; }
.sheet-site .site-chip { font-size: 12px; padding: 4px 9px; }
.sheet-site .sheet-tick { width: 22px; text-align: right; }


/* ---- Photos & files: the site's media in one place ---------------------- */
.media-filters { margin-bottom: 0.5rem; }

.media-body {
  max-height: 62vh;
  overflow-y: auto;
  padding-right: 0.25rem;
}

.media-day {
  margin: 0.6rem 0 0.3rem;
  font-size: 0.72rem;
  font-weight: 750;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.media-day:first-child { margin-top: 0; }

.media-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: 0.35rem;
}

.media-cell {
  margin: 0;                 /* a figure carries a 40px margin by default */
  border: 1px solid var(--line);
  border-radius: 0.5rem;
  overflow: hidden;
  background: var(--surface);
  display: flex;
  flex-direction: column;
}

.media-cell img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
  background: var(--surface-muted);
  cursor: zoom-in;
}

/* a PDF has no picture; the tile is the file's name on a plain face */
.media-file {
  width: 100%;
  aspect-ratio: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  padding: 0.5rem;
  border: 0;
  background: var(--surface-muted);
  color: var(--text);
  cursor: pointer;
  font: inherit;
}

.media-file .media-file-mark { font-size: 1.6rem; line-height: 1; }

.media-file .media-file-name {
  font-size: 0.7rem;
  font-weight: 650;
  text-align: center;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.media-cell figcaption {
  padding: 0.35rem 0.4rem 0.4rem;
  font-size: 0.68rem;
  line-height: 1.35;
  color: var(--muted);
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.media-caption {
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.media-link {
  align-self: flex-start;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}

.media-room {
  align-self: flex-start;
  font-size: 0.62rem;
  font-weight: 700;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: var(--surface-muted);
  color: var(--muted);
}

/* ---- Roll call: the check-in card ---------------------------------------- */
.checkin-card { padding: 0; overflow: hidden; text-align: center; }
.checkin-head { background: linear-gradient(135deg, #2f5e78, #3f7f9e); color: #fff; padding: 1.1rem 1rem 2.6rem; position: relative; }
.checkin-kicker { font-size: 0.72rem; letter-spacing: 0.14em; font-weight: 800; opacity: 0.85; margin: 0; }
.checkin-title { font-size: 1.25rem; font-weight: 800; margin: 0.15rem 0 0; color: #fff; }
.checkin-date { font-size: 0.85rem; opacity: 0.9; margin: 0.1rem 0 0; }
.checkin-head .modal-close { position: absolute; top: 0.7rem; right: 0.7rem; background: rgba(255, 255, 255, 0.18); color: #fff; }
.checkin-body { padding: 0 1.2rem 1.2rem; }
.checkin-face { position: relative; z-index: 2; width: 5rem; height: 5rem; border-radius: 50%; margin: -2.5rem auto 0.5rem;
  border: 4px solid var(--surface); background: linear-gradient(135deg, #dbe9f1, #b9d3e2); color: #2f5e78; display: flex;
  align-items: center; justify-content: center; font-size: 1.6rem; font-weight: 800; box-shadow: 0 4px 14px rgba(23, 38, 47, 0.18);
  overflow: hidden; }
.checkin-face img { width: 100%; height: 100%; object-fit: cover; display: block; }
.checkin-name { font-size: 1.2rem; font-weight: 800; margin: 0; }
.checkin-points { display: inline-block; margin: 0.35rem 0 0.2rem; padding: 0.3rem 0.85rem; border-radius: 999px;
  background: #fff3d6; color: #8a5a00; font-weight: 800; font-size: 0.9rem; }
.checkin-points.is-up { background: #e3f4ea; color: #1d6b3c; }
.checkin-note { color: var(--muted); font-size: 0.92rem; line-height: 1.45; margin: 0.7rem 0 1rem; }
.checkin-log { margin: 0 auto 1rem; max-width: 17rem; text-align: left; border: 1px solid var(--line); border-radius: 0.8rem;
  background: var(--surface-muted); padding: 0.2rem 0.9rem; }
.checkin-row { display: flex; align-items: center; gap: 0.6rem; padding: 0.55rem 0; font-size: 0.98rem; font-weight: 650; color: var(--muted); }
.checkin-row + .checkin-row { border-top: 1px solid var(--line); }
.checkin-row.is-on { color: var(--text); }
.checkin-box { width: 1.25rem; height: 1.25rem; border-radius: 0.35rem; border: 2px solid var(--line); background: var(--surface);
  display: inline-flex; align-items: center; justify-content: center; font-size: 0.85rem; color: #fff; flex: 0 0 auto; }
.checkin-row.is-on .checkin-box { background: #2e9e5b; border-color: #2e9e5b; }
.checkin-time { margin-left: auto; font-variant-numeric: tabular-nums; }
.checkin-go { width: 100%; font-size: 1.05rem; padding: 0.95rem; }

/* today's roll call under each name on "Who is on this site" */
.rollcall-head { margin: 0 0 0.6rem; font-size: 0.78rem; font-weight: 700; color: var(--muted); }
.rollcall-line { display: block; margin-top: 0.2rem; font-size: 0.74rem; font-weight: 650; color: var(--muted); }
.rollcall-line b { color: #1d6b3c; font-weight: 750; }
.rollcall-box { display: inline-flex; width: 0.95rem; height: 0.95rem; border-radius: 0.25rem; border: 1.5px solid var(--line);
  align-items: center; justify-content: center; font-size: 0.62rem; color: #fff; margin-right: 0.2rem; vertical-align: -0.12rem; }
.rollcall-box.is-on { background: #2e9e5b; border-color: #2e9e5b; }

/* the home-screen shortcut offer on the dashboard */
.homescreen-button { display: block; width: 100%; margin: 0.2rem 0 0.7rem; padding: 0.8rem; border: 1px dashed var(--line);
  border-radius: 0.9rem; background: transparent; color: var(--accent); font: inherit; font-weight: 700; cursor: pointer; }
.homescreen-hint { margin: 0.1rem 0 0.8rem; font-size: 0.8rem; color: var(--muted); text-align: center; }

/* ---- Select several: a mode entered on purpose ---------------------------- */
.is-selecting .record-card { position: relative; padding-left: 2.6rem; }
.is-selecting .record-card::before {
  content: ""; position: absolute; left: 0.8rem; top: 50%; width: 1.25rem; height: 1.25rem; margin-top: -0.625rem;
  border-radius: 50%; border: 2px solid var(--line); background: var(--surface); }
.is-selecting .is-selected { outline: 2px solid var(--accent); outline-offset: -2px; }
.is-selecting .record-card.is-selected::before { background: var(--accent); border-color: var(--accent);
  box-shadow: inset 0 0 0 3px var(--surface); }
/* a job row already has a box on its left: while selecting, THAT box is the tick */
.is-selecting .job .job-box { position: relative; border-color: var(--accent); }
.is-selecting .job .job-box > * { visibility: hidden; }
.is-selecting .job.is-selected .job-box { background: var(--accent); }
.is-selecting .job.is-selected .job-box::after { content: ""; position: absolute; left: 50%; top: 46%;
  width: 0.34rem; height: 0.68rem; border: solid #fff; border-width: 0 2.5px 2.5px 0;
  transform: translate(-50%, -50%) rotate(45deg); }
.select-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 15; display: flex; align-items: center; gap: 0.5rem;
  padding: 0.7rem 0.8rem calc(0.7rem + env(safe-area-inset-bottom)); background: var(--surface);
  border-top: 1px solid var(--line); box-shadow: 0 -6px 18px rgba(23, 38, 47, 0.12); }
.select-bar[hidden] { display: none; }
.select-count { font-weight: 750; font-size: 0.9rem; margin-right: auto; white-space: nowrap; }
.select-bar button { flex: 0 0 auto; padding: 0.6rem 0.8rem; font-size: 0.85rem; }
.is-selecting .board-region { padding-bottom: 5rem; }

/* ---- What a bulk action did: the card after Mark done / Assign to ---------- */
.bulk-head { padding-bottom: 1.1rem; }
/* room for the close button: the longest title must not run under it */
.bulk-head .checkin-title, .bulk-head .checkin-kicker { padding: 0 2.6rem; }
.bulk-head .checkin-title { font-size: 1.12rem; line-height: 1.2; }
.bulk-head.is-partial { background: linear-gradient(135deg, #8a5a12, #b9822a); }
.bulk-head.is-nothing { background: linear-gradient(135deg, #8c3a36, #b4524c); }
.bulk-body { padding: 1rem 1.1rem 1.1rem; text-align: left; }
.bulk-points { text-align: center; margin: 0 0 0.9rem; padding: 0.75rem 0.8rem; border-radius: 0.9rem;
  background: #e3f4ea; color: #1d6b3c; }
.bulk-points.is-none { background: var(--surface-2, #eef2f5); color: var(--muted); }
/* a late job: the box turns amber and says why the number is below zero (1 Oct) */
.bulk-points.is-late { background: var(--warn-bg, #fff4dc); color: var(--warn-ink, #7a4b00); }
.bulk-points b { display: block; font-size: 1.5rem; font-weight: 850; line-height: 1.1; }
.bulk-points span { display: block; font-size: 0.86rem; margin-top: 0.2rem; line-height: 1.4; }
.bulk-list { border: 1px solid var(--line); border-radius: 0.8rem; overflow: hidden; }
.bulk-row { display: flex; align-items: flex-start; gap: 0.6rem; padding: 0.55rem 0.7rem; font-size: 0.9rem; }
.bulk-row + .bulk-row { border-top: 1px solid var(--line); }
.bulk-row-main { flex: 1 1 auto; min-width: 0; }
.bulk-row-what { display: block; font-weight: 650; line-height: 1.3; }
.bulk-row-meta { display: block; font-size: 0.76rem; color: var(--muted); margin-top: 0.1rem; }
.bulk-row-worth { flex: 0 0 auto; font-weight: 800; color: #1d6b3c; white-space: nowrap; }
.bulk-row-worth.is-none { color: var(--muted); font-weight: 650; }
.bulk-more { display: block; width: 100%; padding: 0.55rem; border: 0; border-top: 1px solid var(--line);
  background: transparent; color: var(--accent); font: inherit; font-weight: 700; font-size: 0.86rem; cursor: pointer; }
.bulk-refused { margin-top: 0.8rem; padding: 0.7rem 0.8rem; border-radius: 0.8rem; background: #fdf1e1; color: #6e4508;
  font-size: 0.88rem; }
.bulk-refused[hidden] { display: none; }
.bulk-refused strong { display: block; margin-bottom: 0.3rem; }
.bulk-refused ul { margin: 0; padding: 0 0 0 1.1rem; }
.bulk-refused li { margin: 0.2rem 0 0; line-height: 1.35; }
.bulk-actions { display: flex; gap: 0.6rem; margin-top: 1rem; }
.bulk-actions button { flex: 1 1 0; padding: 0.75rem; }
.bulk-actions button[hidden] { display: none; }

/* ---- Leaderboard: who has the most points, across every site ------------- */
.site.is-board .site-mark { background: var(--gold); color: #fff; }
.leaderboard-filters { margin: 2px 0 8px; }
.lb-facts { margin: 0; }
.leaderboard-note { margin: 0.2rem 0 0.4rem; font-size: 0.82rem; color: var(--muted); }
.leaderboard-note b { color: var(--text); }
.lb-person { display: flex; align-items: center; gap: 10px; padding: 10px 2px; border-bottom: 1px solid var(--line); }
.lb-person:last-child { border-bottom: none; }
.lb-rank { flex: 0 0 1.7rem; text-align: center; font-weight: 850; font-size: 0.95rem; color: var(--muted-strong);
  font-variant-numeric: tabular-nums; }
.lb-rank.is-medal { font-size: 1.25rem; }
.lb-person.is-me { background: var(--surface-muted); border-radius: 0.6rem; padding-left: 6px; padding-right: 6px; }
.lb-sub { display: block; margin-top: 2px; font-size: 12px; font-weight: 600; color: var(--muted-strong); }
.lb-tally { flex: 0 0 auto; text-align: right; font-variant-numeric: tabular-nums; }
.lb-tally b { display: block; font-size: 20px; font-weight: 800; line-height: 1; color: var(--gold); }
.lb-tally span { font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted-strong); }
.leaderboard-foot { margin: 0.6rem 0 0; font-size: 0.76rem; color: var(--muted); }
.leaderboard-manage { display: flex; gap: 0.6rem; margin-top: 0.9rem; }
.leaderboard-manage button { flex: 1 1 0; padding: 0.7rem; }
.leaderboard-manage[hidden] { display: none; }
.reset-text { margin: 0 0 0.8rem; font-size: 0.95rem; line-height: 1.45; text-align: left; }
.round-row { padding: 10px 2px; border-bottom: 1px solid var(--line); }
.round-row:last-child { border-bottom: none; }
.round-title { display: block; font-weight: 800; }
.round-meta { display: block; font-size: 12px; color: var(--muted-strong); margin-top: 2px; }
.round-top { display: block; margin-top: 4px; font-size: 0.9rem; }
.lb-undo { margin-left: 0.4rem; color: var(--accent); font-weight: 800; background: none; border: 0; font: inherit; cursor: pointer; }

/* ---- the Odoo PR on a purchase: a fact that is also a door ------------------ */
.fact-link { border: 0; background: none; padding: 0; font: inherit; font-size: 13px; font-weight: 650;
  color: var(--accent); text-align: left; cursor: pointer; overflow-wrap: anywhere; }
.fact-link.is-none { color: var(--muted-strong); font-weight: 600; }
.odoo-form { display: flex; gap: 6px; width: 100%; }
.odoo-form input { flex: 1 1 auto; min-width: 0; padding: 0.5rem 0.6rem; border: 1px solid var(--line);
  border-radius: 10px; font: inherit; font-size: 13px; background: var(--surface); color: var(--text); }
.odoo-form button { flex: 0 0 auto; padding: 0.5rem 0.8rem; }

/* ---- Purchasing view and notification history ------------------------------ */
.site.is-buying .site-mark { background: #2f6f6a; }
.buy-row { display: flex; align-items: flex-start; gap: 10px; padding: 10px 2px; border-bottom: 1px solid var(--line); }
.buy-row:last-child { border-bottom: none; }
.buy-main { flex: 1 1 auto; min-width: 0; border: 0; background: none; padding: 0; text-align: left; font: inherit;
  color: inherit; cursor: pointer; }
.buy-what { display: block; font-size: 15px; font-weight: 700; color: var(--text); overflow-wrap: anywhere; }
.buy-meta { display: block; margin-top: 2px; font-size: 12px; font-weight: 600; color: var(--muted-strong); }
.buy-side { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 5px; }
.buy-stage { padding: 0.18rem 0.55rem; border-radius: 999px; font-size: 11px; font-weight: 800;
  background: var(--surface-muted); color: var(--muted-strong); white-space: nowrap; }
.buy-stage.stage-delivered { background: #e3f4ea; color: #1d6b3c; }
.buy-stage.stage-issue { background: #fde4e1; color: #8c2f2a; }
.buy-stage.stage-waiting-delivery, .buy-stage.stage-po-sent { background: #fdf1e1; color: #6e4508; }
.buy-odoo { font-size: 12px; }
.note-day { margin: 0.7rem 0 0.1rem; font-size: 11px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted-strong); }
.note-row { display: flex; gap: 10px; padding: 8px 2px; border-bottom: 1px solid var(--line); }
.note-row:last-child { border-bottom: none; }
.note-time { flex: 0 0 2.8rem; font-size: 12px; font-weight: 700; color: var(--muted-strong); font-variant-numeric: tabular-nums;
  padding-top: 2px; }
.note-main { flex: 1 1 auto; min-width: 0; }
.note-label { display: block; font-size: 14px; font-weight: 700; color: var(--text); }
.note-meta { display: block; margin-top: 1px; font-size: 12px; font-weight: 600; color: var(--muted-strong); overflow-wrap: anywhere; }

/* ── WAITING ON YOU: one card on the dashboard, a page behind it (Arjo, 2026-09-30) ─ */
  display: flex; align-items: center; gap: 12px; width: 100%; margin: 0 0 18px;
  padding: 14px; border: 0; border-left: 4px solid var(--claim); border-radius: var(--radius);
  background: var(--claim-soft); box-shadow: var(--shadow);
  text-align: left; font: inherit; color: var(--text); cursor: pointer;
}
  flex: none; width: 46px; height: 46px; border-radius: 12px;
  background: var(--claim); color: #fff; display: grid; place-items: center;
  font-size: 20px; font-weight: 800; font-variant-numeric: tabular-nums;
}

.wq-empty { padding: 34px 20px; text-align: center; color: var(--muted); border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }

/* ── MY JOBS, EVERY SITE (Arjo, 2026-09-30) - shares the waiting page's frame ── */
.home-head-count.is-plain { background: var(--surface-muted); color: var(--muted-strong); }
.wq-page .issue-group.is-loose { margin-bottom: 10px; }
.wq-page .issue-group.is-loose .issue-jobs { border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow); overflow: hidden; }

/* ── RFI / RFA ON THE CARD (Arjo, 2026-10-01) ─────────────────────────────────
   Gold for an open RFA, steel for an open RFI, green once settled, a red rail
   past WAITING_TOO_LONG. Under the meta line on whichever record carries it. */
.ask-band {
  display: flex; gap: 10px; align-items: flex-start;
  margin: 8px 0 2px; padding: 9px 11px; border-radius: 10px;
  background: var(--claim-soft); border-left: 3px solid var(--claim);
  text-align: left;
}
.ask-band.is-rfi { background: var(--accent-soft); border-left-color: var(--accent); }
.ask-band.is-settled { background: var(--done-soft); border-left-color: var(--done); }
.ask-band.is-old { border-left-color: var(--issue); }
.ask-band-kind {
  flex: none; margin-top: 1px; padding: 2px 7px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.7); color: var(--claim-ink);
  font-size: 10px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
}
:root[data-color-scheme="dark"] .ask-band-kind { background: rgba(255, 255, 255, 0.12); }
.ask-band.is-rfi .ask-band-kind { color: var(--accent); }
.ask-band.is-settled .ask-band-kind { color: var(--done-ink); }
.ask-band-body { flex: 1; min-width: 0; }
.ask-band-what { display: block; font-size: 13px; font-weight: 650; line-height: 1.35; color: var(--text); overflow-wrap: anywhere; }
.ask-band-meta { display: block; margin-top: 3px; font-size: 11px; font-weight: 650; color: var(--muted-strong); }
.ask-band.is-old .ask-band-meta b { color: var(--issue-ink); }
.job .ask-band { margin: 6px 0 0; padding: 7px 10px; }

/* ---- THE MANAGEMENT PAGE (2 Oct): Project / Person facts, five tiles, two pickers,
   one big card per project with the records inside -------------------------------- */
.mg-facts { margin-bottom: 12px; }
/* crew locked to themselves: the Person chip is a label, not a picker (7 Oct) */
.mg-pick.is-locked { opacity: 0.55; }
.mg-tiles { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; margin: 0 0 12px; }
.mg-tile { grid-column: span 2; min-height: 78px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; border: 0; border-radius: 12px; background: var(--surface); box-shadow: var(--shadow); border-top: 4px solid var(--line); font: inherit; cursor: pointer; color: var(--text); }
.mg-tile:nth-child(4) { grid-column: 2 / span 2; }
.mg-tile b { font-size: 22px; line-height: 1; }
.mg-tile span { font-size: 11px; font-weight: 700; color: var(--muted); text-align: center; }
.mg-tile.is-rfa { border-top-color: var(--claim); }
.mg-tile.is-rfi { border-top-color: var(--accent); }
.mg-tile.is-on { background: var(--text); color: var(--surface); border-top-color: var(--text); }
.mg-tile.is-on span { color: var(--surface); opacity: .8; }
.mg-two { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 0 0 14px; }
.mg-pick { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; padding: 8px 12px; border: 0; border-radius: 12px; background: var(--surface); box-shadow: var(--shadow); font: inherit; text-align: left; cursor: pointer; color: var(--text); }
.mg-pick small { font-size: 11px; color: var(--muted); }
.mg-pick b { font-size: 14px; }
.mg-project { background: var(--surface); border-radius: 16px; box-shadow: var(--shadow); margin: 0 0 16px; overflow: hidden; }
.mg-project-head { display: flex; justify-content: space-between; align-items: center; margin: 0; padding: 11px 14px; font-size: 15px; font-weight: 800; background: var(--text); color: var(--surface); }
.mg-project-n { background: rgba(255,255,255,.18); border-radius: 999px; padding: 1px 9px; font-size: 13px; font-weight: 700; }
.mg-row { position: relative; padding: 12px 14px; border-top: 1px solid var(--line); border-left: 4px solid var(--claim); }
.mg-row:first-of-type { border-top: 0; }
.mg-row.is-rfi { border-left-color: var(--accent); }
.mg-row.is-task { border-left-color: var(--muted); }
.mg-row.is-issue, .mg-row.is-overdue { border-left-color: var(--issue); }
.mg-row.is-purchase { border-left-color: #6b4fbb; }
.mg-row.is-equipment { border-left-color: #2a7f8f; }
.mg-row.is-done { border-left-color: var(--done, #1e8e5a); }
.mg-pill { float: right; margin-left: 8px; font-size: 12px; font-weight: 700; padding: 4px 9px; border-radius: 999px; background: var(--surface-muted); color: var(--muted); font-variant-numeric: tabular-nums; }
.mg-pill.is-old { background: var(--issue-soft); color: var(--issue-ink); }
.mg-pill.is-due { background: var(--claim-soft); color: var(--claim-ink); }
.mg-pill.is-today { background: var(--claim); color: #fff; }
.mg-pill.is-done { background: var(--done-soft, #e2f5ea); color: var(--done-ink, #145f3c); }
.mg-kind { display: block; font-size: 10px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--claim-ink); }
.mg-row.is-rfi .mg-kind { color: var(--accent); }
.mg-row.is-task .mg-kind { color: var(--muted); }
.mg-row.is-issue .mg-kind, .mg-row.is-overdue .mg-kind { color: var(--issue-ink); }
.mg-row.is-done .mg-kind { color: var(--done-ink, #145f3c); }
.mg-what { margin: 4px 0 4px; font-size: 15px; font-weight: 750; line-height: 1.35; overflow-wrap: anywhere; }
.mg-what small { font-weight: 500; color: var(--muted); font-size: 12px; }
.mg-who { font-size: 12px; font-weight: 650; color: var(--muted); }
.mg-outcome { margin-top: 6px; font-size: 13px; padding: 6px 8px; border-radius: 8px; background: var(--done-soft, #e2f5ea); color: var(--done-ink, #145f3c); }
.mg-outcome.is-no { background: var(--issue-soft); color: var(--issue-ink); }
.mg-act { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.mg-act button { min-height: 36px; padding: 6px 12px; font-size: 13px; }
.mg-under { margin: 10px 0 0 6px; padding-left: 12px; border-left: 3px solid var(--line); }
.mg-row.is-nested { border-left: 0; padding: 8px 0; border-top: 1px dashed var(--line); }
.mg-row.is-nested:first-of-type { border-top: 0; padding-top: 2px; }
.mg-row.is-nested .mg-what { font-size: 14px; }
.mg-row.is-nested .mg-pill { font-size: 11px; padding: 3px 8px; }
