/* Seattle Reconomy — shared stylesheet.
   Extracted from MOCKUP.html so prod pages match the design. */

:root {
  --sr-blue: #1E64A5;
  --sr-blue-dark: #144A7E;
  --sr-green: #4F9E3D;
  --sr-green-dark: #3A7A2C;
  --bg: #F7F9FB;
  --panel: #FFFFFF;
  --text: #1F2A37;
  --text-muted: #5B6B7C;
  --border: #E3E8EE;
  --warn: #C58A1E;
  --danger: #B83A3A;
  --row-alt: #F2F5F8;   /* zebra stripe on table rows */
}

* { box-sizing: border-box; }
html, body {
  margin: 0; padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}
a { color: var(--sr-blue); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---------- Beta-testing 2FA bypass banner ---------- */
.beta-2fa-banner {
  background: var(--danger); color: white;
  padding: 10px 24px;
  font-size: 14px; text-align: center;
}

/* ---------- Top bar ---------- */
.topbar {
  background: white;
  border-bottom: 1px solid var(--border);
  padding: 12px 24px;
  display: flex; align-items: center; justify-content: space-between;
  box-shadow: 0 1px 2px rgba(0,0,0,0.03);
}
.topbar .brand { display: flex; align-items: center; gap: 12px; }
.topbar .brand img { height: 36px; }
.topbar .user-chip {
  display: flex; align-items: center; gap: 10px;
  font-size: 14px; color: var(--text-muted);
}
.topbar .user-chip .avatar {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--sr-green); color: white;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: 13px;
}
.topbar .user-chip a { color: var(--text-muted); }

.role-pill {
  background: var(--sr-blue); color: white;
  padding: 2px 10px; border-radius: 12px;
  font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.5px;
}
.role-pill.role-staff { background: var(--sr-green); }
.role-pill.role-volunteer { background: var(--warn); }
.role-pill.role-member { background: var(--text-muted); }

/* ---------- Tab nav ---------- */
.tabnav {
  background: white;
  border-bottom: 1px solid var(--border);
  padding: 0 24px;
  display: flex; gap: 4px;
  overflow-x: auto;
}
.tabnav a, .tabnav button {
  background: none; border: none;
  padding: 14px 18px;
  font-size: 14px; font-weight: 500;
  color: var(--text-muted);
  cursor: pointer; text-decoration: none;
  border-bottom: 3px solid transparent;
  white-space: nowrap;
  transition: color 0.15s, border-color 0.15s;
}
.tabnav a:hover { color: var(--text); text-decoration: none; }
.tabnav a.active {
  color: var(--sr-blue);
  border-bottom-color: var(--sr-blue);
}

/* ---------- Layout ---------- */
.main { padding: 24px; max-width: 1400px; margin: 0 auto; }
.page-header {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 20px;
}
.page-header h1 { margin: 0; font-size: 24px; font-weight: 600; }
.page-header .subtitle { color: var(--text-muted); font-size: 14px; margin-top: 4px; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px; border-radius: 6px;
  font-size: 14px; font-weight: 500;
  cursor: pointer; border: 1px solid transparent;
  text-decoration: none;
  transition: background 0.15s;
}
.btn-primary { background: var(--sr-blue); color: white; }
.btn-primary:hover { background: var(--sr-blue-dark); text-decoration: none; color: white; }
.btn-secondary { background: white; color: var(--text); border-color: var(--border); }
.btn-secondary:hover { background: var(--bg); text-decoration: none; }
.btn-green { background: var(--sr-green); color: white; }
.btn-green:hover { background: var(--sr-green-dark); text-decoration: none; color: white; }
/* The hidden attribute must beat any class that sets display (e.g. a .btn
   that a data-reveal toggle has retired) — the UA default alone loses. */
[hidden] { display: none !important; }
/* A <summary> styled as a button (inline edit affordances, e.g. Rename board). */
details.inline-edit > summary { list-style: none; cursor: pointer; }
details.inline-edit > summary::-webkit-details-marker { display: none; }

/* ---------- Panels ---------- */
.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 16px;
}
.panel h2 { margin: 0 0 12px 0; font-size: 16px; font-weight: 600; }

/* ---------- Tool photo ----------
   The photo lives INSIDE the details panel, beside the field list — not as a
   sibling panel in .two-col. As a sibling it dropped below Loan policy and
   Loan history the moment that grid collapsed at 900px, which is most tablets
   and every phone. Here it stays welded to the details at every width.

   Source order is photo-then-fields, so narrow screens stack the photo on top
   with no reordering; wide screens flip to row-reverse to sit it on the right.

   Imported photos are wildly inconsistent — portrait phone shots next to tiny
   square thumbnails. `contain` in a fixed frame keeps every tool page the same
   shape without cropping or stretching anyone's picture. */
.detail-with-photo {
  display: flex; flex-direction: row-reverse;
  align-items: flex-start; gap: 20px;
}
.detail-with-photo .field-list { flex: 1 1 auto; min-width: 0; }
.tool-photo { flex: 0 0 240px; }

.tool-photo-frame {
  display: flex; align-items: center; justify-content: center;
  height: 240px; padding: 8px;
  background: var(--bg);
  border: 1px solid var(--border); border-radius: 6px;
  overflow: hidden;
}
.tool-photo-frame img {
  max-width: 100%; max-height: 100%;
  object-fit: contain;
}
.tool-photo-empty {
  display: flex; align-items: center; justify-content: center;
  height: 120px; padding: 8px; text-align: center;
  background: var(--bg); color: var(--text-muted); font-size: 13px;
  border: 1px dashed var(--border); border-radius: 6px;
}
.tool-photo-caption {
  margin: 6px 0 0; text-align: center;
  font-size: 12px; color: var(--text-muted);
}

/* Narrow: photo above the details, so it's still the first thing you see. */
@media (max-width: 760px) {
  .detail-with-photo { flex-direction: column; }
  .tool-photo { flex: 1 1 auto; width: 100%; }
  .tool-photo-frame { height: 220px; }
}

/* ---------- Project card images ---------- */
.card-image { padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid var(--border); }
.card-image:last-of-type { border-bottom: 0; }
.card-image .tool-photo-frame { height: 180px; }
.card-image-caption { font-size: 14px; margin-top: 6px; }
.card-image-meta { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.card-image-actions { margin-top: 8px; display: flex; gap: 6px; }
.card-image-actions .btn { padding: 4px 10px; font-size: 13px; }

/* ---------- Forms ---------- */
.form-row { margin-bottom: 14px; }
.form-row label {
  display: block; font-size: 13px; font-weight: 500;
  margin-bottom: 4px; color: var(--text);
}
.form-row input, .form-row select, .form-row textarea {
  width: 100%; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  font-size: 14px; font-family: inherit; background: white;
}
.form-row input:focus, .form-row select:focus, .form-row textarea:focus {
  outline: none; border-color: var(--sr-blue);
  box-shadow: 0 0 0 3px rgba(30, 100, 165, 0.15);
}
/* Checkboxes: opt OUT of the full-width text-input styling above, or the box
   stretches into a bordered strip and shoves its label to the far right. */
.form-row input[type="checkbox"] {
  width: 16px; height: 16px; padding: 0; margin: 0;
  flex: 0 0 auto; accent-color: var(--sr-blue);
}
.form-row .errorlist {
  color: var(--danger); font-size: 12px; margin: 4px 0 0; padding: 0;
  list-style: none;
}
.form-row .helptext { color: var(--text-muted); font-size: 12px; margin-top: 4px; }

/* ---------- Messages (flash) ---------- */
.messages {
  list-style: none; padding: 0; margin: 0 0 16px 0;
}
.messages li {
  padding: 10px 14px; border-radius: 6px; margin-bottom: 8px;
  font-size: 14px;
}
.messages li.success { background: #E3F4DD; color: var(--sr-green-dark); }
.messages li.error { background: #F3D8D8; color: var(--danger); }
.messages li.warning { background: #FFF8E1; color: #7A5A0E; }
.messages li.info { background: #D8E5F4; color: var(--sr-blue-dark); }

/* ---------- Auth (login/signup) ---------- */
.auth-wrap {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #F0F6FB 0%, #EAF4E5 100%);
  padding: 24px;
}
.auth-card {
  background: white; width: 100%; max-width: 400px;
  padding: 32px; border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0,0,0,0.06);
}
.auth-card img { display: block; margin: 0 auto 20px auto; height: 56px; }
.auth-card h1 { font-size: 20px; margin: 0 0 4px 0; text-align: center; }
.auth-card .sub {
  color: var(--text-muted); text-align: center;
  font-size: 14px; margin-bottom: 24px;
}
.auth-card .btn { width: 100%; justify-content: center; padding: 10px; }
.auth-card .alt {
  text-align: center; margin-top: 16px;
  font-size: 13px; color: var(--text-muted);
}

/* ---------- Module-hint banner ---------- */
.module-hint {
  background: #FFF8E1; border-left: 3px solid var(--warn);
  padding: 10px 14px; font-size: 13px; color: #7A5A0E;
  border-radius: 4px; margin-bottom: 16px;
}

/* ---------- Tables ---------- */
table { width: 100%; border-collapse: collapse; }
th, td {
  padding: 10px 12px; text-align: left;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
}
th {
  font-weight: 600; color: var(--text-muted);
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px;
  background: var(--bg);
}
tbody tr { transition: background 0.1s; }
/* Zebra stripes. :where() keeps specificity at zero-class level so any
   row-level styling (unread tint, .row-conflict, inline styles) still wins. */
tbody :where(tr:nth-child(even)) { background: var(--row-alt); }
tbody tr:hover { background: #E9EEF4; cursor: pointer; }
.table-link { color: inherit; text-decoration: none; display: block; }
.table-link:hover { text-decoration: none; }

/* Sortable column headers ({% sort_th %} — apps/core/templatetags/sr_tables.py).
   The link fills the whole cell so the click target is the full header. */
th.sortable { padding: 0; }
th.sortable a {
  display: block; padding: 10px 12px;
  color: inherit; text-decoration: none; white-space: nowrap;
}
th.sortable a:hover { background: #EDF1F6; color: var(--text); text-decoration: none; }
th.sortable .sort-arrow { font-size: 9px; }
th.sortable.sorted a { color: var(--sr-blue); }

/* Library header chip — cycles the branch filter ({% library_cycle_th %}). */
th .th-toggle {
  display: inline-block; margin-left: 6px; padding: 1px 8px;
  border: 1px solid var(--border); border-radius: 10px;
  background: white; color: var(--sr-blue);
  font-size: 11px; font-weight: 600;
  text-transform: none; letter-spacing: 0;
  white-space: nowrap; text-decoration: none;
}
th .th-toggle:hover { border-color: var(--sr-blue); text-decoration: none; }
th .th-toggle.active { background: var(--sr-blue); border-color: var(--sr-blue); color: white; }

/* ---------- Status / tier badges ---------- */
.badge {
  display: inline-block;
  padding: 2px 8px; border-radius: 10px;
  font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.4px;
  white-space: nowrap;
}
.badge-available    { background: #E3F4DD; color: var(--sr-green-dark); }
.badge-on_loan      { background: #FFEBC2; color: var(--warn); }
.badge-reserved     { background: #D8E5F4; color: var(--sr-blue-dark); }
.badge-maintenance  { background: #F3D8D8; color: var(--danger); }
.badge-retired      { background: #E3E8EE; color: var(--text-muted); }
.badge-tier-1       { background: #E3F4DD; color: var(--sr-green-dark); }
.badge-tier-2       { background: #D8E5F4; color: var(--sr-blue-dark); }

/* ---------- Filterbar ---------- */
.filterbar {
  display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap;
}
.filterbar input, .filterbar select {
  padding: 7px 10px; border: 1px solid var(--border); border-radius: 6px;
  font-size: 13px; background: white;
}
.filterbar input[type=search] { flex: 1; min-width: 200px; }

/* ---------- Detail field list ---------- */
.field-list { display: grid; grid-template-columns: 180px 1fr; gap: 10px 16px; }
.field-list .key { font-size: 13px; color: var(--text-muted); font-weight: 500; }
.field-list .val { font-size: 14px; color: var(--text); }

/* ---------- Two-column layout ---------- */
.two-col { display: grid; grid-template-columns: 2fr 1fr; gap: 16px; }
@media (max-width: 900px) { .two-col { grid-template-columns: 1fr; } }
/* When the wide column has nothing in it — a dashboard whose modules are
   switched off for the current test round — collapse rather than leave a
   2fr hole beside the panels that did survive. */
.two-col.solo { grid-template-columns: 1fr; }

/* ---------- Empty state ---------- */
.empty {
  text-align: center; padding: 40px 20px;
  color: var(--text-muted); font-size: 14px;
}

/* ---------- Pagination bar ---------- */
.pagination-bar {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px;
  padding: 12px 16px; margin-top: 14px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
  font-size: 13px; color: var(--text-muted);
}
.pagination-controls { display: flex; align-items: center; gap: 10px; }
.pagination-controls .btn { padding: 5px 12px; font-size: 13px; }
.pagination-page { color: var(--text); font-weight: 500; }
.pagination-perpage a { margin: 0 3px; }
.pagination-perpage strong { margin: 0 3px; color: var(--sr-blue); }
.pagination-bar-top { margin: 0 0 14px; }   /* the duplicate bar above the table */

/* ---------- Stat cards (dashboards) ---------- */
.panel-grid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.stat {
  background: white; border: 1px solid var(--border); border-radius: 8px;
  padding: 16px;
}
.stat .label { font-size: 12px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
.stat .value { font-size: 28px; font-weight: 600; color: var(--text); margin-top: 4px; }

/* ---------- Horizontal bars (analytics) ---------- */
.hbar {
  height: 16px; min-width: 2px;
  background: var(--sr-blue); border-radius: 3px;
}
.hbar-green { background: var(--sr-green); }

/* ---------- Kanban (projects) ---------- */
.kanban { display: grid; gap: 12px; grid-template-columns: repeat(4, 1fr); align-items: start; }
@media (max-width: 1000px) { .kanban { grid-template-columns: repeat(2, 1fr); } }
.kanban-col {
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 10px;
}
.kanban-col h3 {
  margin: 0 0 10px 0; font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted);
}
.kanban-card {
  background: white; border: 1px solid var(--border); border-radius: 6px;
  padding: 10px 12px; margin-bottom: 8px; font-size: 14px;
}
.kanban-card .meta { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.priority-high { border-left: 3px solid var(--danger); }
.priority-medium { border-left: 3px solid var(--warn); }
.priority-low { border-left: 3px solid var(--border); }

/* ---------- Clickable table rows (see static/js/sr.js) ---------- */
tr[data-href] { cursor: pointer; }
tr[data-href]:hover td { background: var(--bg); }

/* ---------- Kanban extras (projects) ---------- */
.kanban-card { cursor: grab; }
.kanban-card.dragging { opacity: 0.4; cursor: grabbing; }
.kanban-card.drag-error { outline: 2px solid var(--danger); }
.kanban-col.dropover { background: #E8F0F8; border-color: var(--sr-blue); }
.kanban-card.nest-target { outline: 2px dashed var(--sr-blue); outline-offset: 2px; }

/* Sub-tasks (2026-09-23): indented under the parent with a line-and-elbow
   per child; the line runs down to the last elbow. */
.subtasks { margin: 10px 0 0 14px; }
.kanban-card.subtask {
  position: relative; margin-bottom: 6px; padding: 8px 10px; font-size: 13px;
  background: var(--bg);
}
.kanban-card.subtask::before {           /* the elbow */
  content: ""; position: absolute; left: -14px; top: 16px; width: 11px;
  border-top: 2px solid var(--border);
}
.kanban-card.subtask::after {            /* the trunk, down to the next elbow */
  content: ""; position: absolute; left: -14px; top: -8px; bottom: -8px;
  border-left: 2px solid var(--border);
}
.kanban-card.subtask:last-child::after { bottom: auto; height: 24px; }
.kanban-card.subtask.is-done > a { text-decoration: line-through; color: var(--text-muted); }

.quickadd-grid {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
}
.quickadd-grid .qa-title { flex: 1 1 240px; }
.quickadd-grid input, .quickadd-grid select {
  padding: 8px 10px; border: 1px solid var(--border); border-radius: 4px; font: inherit;
}
.quickadd-grid .qa-label {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--text-muted);
}
/* The quick-add's timing inputs (shown per timing mode) join the flex row
   as if the wrapper weren't there. */
.quickadd-grid .qa-timing:not([hidden]) { display: contents; }
.quickadd-grid .qa-label select[multiple] { font-size: 12px; padding: 4px 6px; }

/* ---------- Task timing (projects/task.html) ---------- */
.timing-fieldset {
  border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 14px 12px; margin: 0 0 12px;
}
.timing-fieldset > legend { font-weight: 600; font-size: 14px; padding: 0 6px; }

/* ---------- Required-field feedback (PM lead, 2026-09-23) ----------
   Required-but-empty: thin red border → yellow while focused. Filled:
   green for a few seconds, then fades back to the neutral border. Pure
   CSS transitions/animations — nothing here is newer than 2012 browsers. */
.field-req { border-color: var(--danger) !important; }
.field-req:focus { border-color: #D9A400 !important; box-shadow: 0 0 0 3px rgba(217, 164, 0, 0.2) !important; }
.field-ok { animation: field-ok-fade 4s ease forwards; }
@keyframes field-ok-fade {
  0%, 55% { border-color: var(--sr-green); box-shadow: 0 0 0 3px rgba(79, 158, 61, 0.18); }
  100%    { border-color: var(--border); box-shadow: none; }
}
.required-msg { color: var(--danger); font-size: 12px; margin-top: 6px; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }
/* The little red ✕ that removes an optional duration. */
.qa-x {
  background: none; border: none; color: var(--danger); font-size: 14px;
  cursor: pointer; padding: 0 4px; line-height: 1;
}
.qa-x:hover { color: #8B1E1E; }

/* The Done column's link to the archive — deliberately quiet. */
.kanban-col h3 .col-archive-link {
  float: right; font-weight: 400; text-transform: none; letter-spacing: 0;
  font-size: 11px; color: var(--text-muted); text-decoration: underline dotted;
}
.kanban-col h3 .col-archive-link:hover { color: var(--sr-blue); }

/* ---------- Gantt timeline (projects) ----------
   Server-rendered like the analytics .hbar rows: the view hands the template
   left/width percentages, the bars are absolutely-positioned divs. Gridlines
   and the today line repeat inside every row's track — rows stack flush, so
   the segments read as one continuous vertical. Phones scroll it sideways
   (the tables decision), so no responsive collapse here. */
.gantt-wrap { overflow-x: auto; }
.gantt { min-width: 780px; }
.gantt-row { display: grid; grid-template-columns: 240px 1fr; align-items: center; }
.gantt-head { border-bottom: 1px solid var(--border); margin-bottom: 2px; }
.gantt-label {
  padding: 3px 12px 3px 0; font-size: 13px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.gantt-label a { color: inherit; }
.gantt-label .who { color: var(--text-muted); font-size: 11px; }
.gantt-months { position: relative; height: 24px; }
.gantt-month {
  position: absolute; top: 0; bottom: 0;
  padding: 5px 0 0 6px; border-left: 1px solid var(--border);
  font-size: 11px; font-weight: 600; letter-spacing: 0.4px;
  text-transform: uppercase; color: var(--text-muted);
  white-space: nowrap; overflow: hidden;
}
.gantt-lane-h {
  margin: 12px 0 2px; font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted);
}
.gantt-track { position: relative; height: 26px; }
.gantt-gridline { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--border); }
.gantt-today { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--warn); z-index: 1; }
.gantt-bar {
  position: absolute; top: 4px; height: 18px; min-width: 8px;
  border-radius: 4px; z-index: 2;
  background: var(--bg); border: 1px solid var(--border);   /* to do */
}
.gantt-bar.st-in_progress { background: var(--sr-blue); border-color: var(--sr-blue); }
.gantt-bar.st-blocked { background: var(--danger); border-color: var(--danger); }
.gantt-bar.st-done { background: var(--sr-green); border-color: var(--sr-green); }
.gantt-diamond {
  position: absolute; top: 7px; width: 13px; height: 13px; margin-left: -7px;
  transform: rotate(45deg); border-radius: 2px; z-index: 2;
  background: var(--bg); border: 1px solid var(--text-muted);
}
.gantt-diamond.st-in_progress { background: var(--sr-blue); border-color: var(--sr-blue); }
.gantt-diamond.st-blocked { background: var(--danger); border-color: var(--danger); }
.gantt-diamond.st-done { background: var(--sr-green); border-color: var(--sr-green); }
.gantt-bar.overdue, .gantt-diamond.overdue { box-shadow: 0 0 0 2px var(--danger); }
.gantt-bar:hover, .gantt-diamond:hover { filter: brightness(0.92); }
/* M23 projection ghost: the computed schedule, drawn under the planned bar.
   Hollow + hatched so it reads as "pencil", never competing with the plan. */
.gantt-ghost {
  position: absolute; top: 17px; height: 7px; min-width: 8px;
  border-radius: 3px; z-index: 1;
  background: repeating-linear-gradient(
    -45deg, var(--text-muted) 0 3px, transparent 3px 6px);
  opacity: 0.55;
}
.gantt-ghost.proj-late { background: repeating-linear-gradient(
    -45deg, var(--danger) 0 3px, transparent 3px 6px); opacity: 0.75; }
/* Dependency layer (2026-09-23): SVG connectors drawn by gantt-deps.js over
   the chart; badges in the label column; a summary strip above. */
.gantt { position: relative; }
svg.gantt-deps { position: absolute; left: 0; top: 0; pointer-events: none; z-index: 3; overflow: visible; }
svg.gantt-deps .dep { fill: none; stroke: #8A97A6; stroke-width: 1.5; }
svg.gantt-deps .dep.critical { stroke: var(--danger); stroke-width: 2; }
svg.gantt-deps .dep.child { stroke-dasharray: 2 3; }
svg.gantt-deps .merge { fill: var(--sr-blue); stroke: #fff; stroke-width: 1.5; }
svg.gantt-deps .merge.critical { fill: var(--danger); }
.gantt-bar.hanging { border-style: dashed; border-color: var(--text-muted); }
.dep-badge {
  font-size: 10px; font-weight: 600; border-radius: 8px; padding: 0 6px; margin-right: 4px;
  color: var(--sr-blue); background: #E8F0F8; white-space: nowrap; vertical-align: middle;
}
.dep-badge.hanging { color: var(--text-muted); background: var(--bg); border: 1px dashed var(--border); }
.dep-summary {
  display: flex; flex-wrap: wrap; gap: 6px 22px; font-size: 13px;
  margin: 0 0 10px; color: var(--text);
}
.dep-summary .who { color: var(--text-muted); font-size: 12px; }
.dep-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: var(--sr-blue); border: 1.5px solid #fff; box-shadow: 0 0 0 1px var(--sr-blue); }
.hang-flag { color: var(--text-muted); }
.crit-swatch { display: inline-block; width: 18px; height: 0; border-top: 2px solid var(--danger); vertical-align: middle; }

/* ---------- Nodes view (2026-09-30) ----------
   A pannable/zoomable canvas: .nodes-world carries the transform, edges
   are one SVG in world space, cards are absolutely positioned HTML.
   Charcoal ground on purpose (Peter): it must never read as the Gantt. */
.nodes-panel { padding: 10px 14px 14px; }
.nodes-toolbar { display: flex; align-items: center; gap: 14px; font-size: 13px; margin-bottom: 8px; min-height: 26px; }
.nodes-status { color: var(--text-muted); }
.nodes-selection { display: inline-flex; align-items: center; gap: 8px; }
.nodes-viewport {
  position: relative; height: 70vh; min-height: 420px; overflow: hidden;
  background: #2B2F36; border: 1px solid #1E2126; border-radius: 8px;
  background-image: radial-gradient(#3A3F47 1px, transparent 1px); background-size: 24px 24px;
  cursor: grab; user-select: none; touch-action: none; outline: none;
}
.nodes-viewport.panning { cursor: grabbing; }
.nodes-viewport:focus-visible { box-shadow: 0 0 0 3px rgba(30, 100, 165, 0.35); }
.nodes-world { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
.nodes-edges { position: absolute; left: 0; top: 0; overflow: visible; }
.nodes-edges .edge { fill: none; stroke: #AEB8C4; stroke-width: 2; cursor: pointer; }
.nodes-edges .edge.critical { stroke: #FF6B61; stroke-width: 2.5; }
.nodes-edges .edge.child { stroke-dasharray: 3 4; pointer-events: none; }
.nodes-edges .edge.selected { stroke: #7FB3FF; stroke-width: 3.5; }
.nodes-edges .edge-hit { fill: none; stroke: transparent; stroke-width: 16; cursor: pointer; }
.nodes-edges .edge-temp { fill: none; stroke: #7FB3FF; stroke-width: 2; stroke-dasharray: 5 4; pointer-events: none; }
.nodes-edges .edge-delete { cursor: pointer; }
.nodes-edges .edge-delete circle { fill: #7FB3FF; stroke: #2B2F36; stroke-width: 2; }
.nodes-edges .edge-delete text { fill: #1B1F24; font-size: 13px; font-weight: 700; text-anchor: middle; dominant-baseline: central; pointer-events: none; }
.nodes-edges .edge-delete:hover circle { fill: #FF6B61; }
/* The cards layer must not swallow clicks meant for the lines beneath it. */
.nodes-cards { position: absolute; left: 0; top: 0; pointer-events: none; }
.node {
  position: absolute; box-sizing: border-box; width: 200px; height: 74px; pointer-events: auto;
  background: white; border: 1px solid #C9D1DA; border-left-width: 5px;
  border-radius: 8px; padding: 9px 18px 8px 14px; font-size: 13px; line-height: 1.25;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35); cursor: grab;
}
.node.moving { cursor: grabbing; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5); z-index: 5; }
.node.st-todo { border-left-color: #B7C2CE; }
.node.st-in_progress { border-left-color: var(--sr-blue); }
.node.st-blocked { border-left-color: var(--danger); }
.node.st-done { border-left-color: var(--sr-green); background: #F4FAF3; }
.node.critical { box-shadow: 0 0 0 2px rgba(255, 107, 97, 0.8), 0 2px 6px rgba(0, 0, 0, 0.35); }
.node.in-cycle { border-style: dashed; }
.node.milestone { border-radius: 8px 22px 22px 8px; }
.node.no-drop { opacity: 0.35; filter: grayscale(1); }
.node .node-title { font-weight: 600; color: var(--text); display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; }
.node .node-title:hover { color: var(--sr-blue); text-decoration: none; }
.node .node-meta { font-size: 11px; color: var(--text-muted); margin-top: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.node .node-dates { font-size: 11px; color: var(--text-muted); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.node .handle {
  position: absolute; top: 50%; width: 16px; height: 16px; margin-top: -8px;
  border-radius: 50%; background: white; border: 2px solid #6B7785; box-sizing: border-box;
}
.node .handle.in { left: -9px; cursor: crosshair; }
.node .handle.out { right: -9px; cursor: grab; }
.node .handle:hover, .node .handle.armed { border-color: var(--sr-blue); background: #E8F0F8; transform: scale(1.25); }
.node.link-target { box-shadow: 0 0 0 3px rgba(79, 158, 61, 0.9), 0 2px 6px rgba(0, 0, 0, 0.35); }
.node.link-target .handle.in { border-color: var(--sr-green); background: #E6F4E2; transform: scale(1.35); }
.node.link-source { box-shadow: 0 0 0 3px rgba(127, 179, 255, 0.9), 0 2px 6px rgba(0, 0, 0, 0.35); }
.nodes-toast {
  position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%);
  background: var(--text); color: white; padding: 8px 14px; border-radius: 6px;
  font-size: 13px; z-index: 50; max-width: 80vw; box-shadow: 0 4px 16px rgba(0,0,0,0.2);
}
.nodes-toast.error { background: var(--danger); }

/* ---------- Project charter (2026-10-06) ---------- */
.charter-section h2 { margin-bottom: 8px; }
.charter-row { display: grid; grid-template-columns: 220px 1fr; gap: 12px; padding: 7px 0; border-bottom: 1px solid var(--border); font-size: 14px; }
.charter-row:last-child { border-bottom: none; }
.charter-label { font-weight: 600; color: var(--text); }
.charter-value ul { margin: 0; padding-left: 18px; }
.charter-value li { margin: 2px 0; }
.charter-empty { color: var(--text-muted); }
.charter-table { width: 100%; font-size: 13px; }
.charter-table th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--text-muted); }
.charter-table td { vertical-align: top; }
.charter-edit-rows input, .charter-edit-rows select { width: 100%; padding: 5px 8px; border: 1px solid var(--border); border-radius: 4px; font: inherit; font-size: 13px; }
.charter-form .form-row textarea { min-height: 70px; }
@media (max-width: 700px) { .charter-row { grid-template-columns: 1fr; gap: 2px; } }

/* Gantt legend (2026-09-23): four columns of symbols to scan down. */
.gantt-legend {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px 28px; margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--border);
}
.gantt-legend .lg-h {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--text-muted); margin-bottom: 6px;
}
.gantt-legend .lg-row { display: flex; align-items: center; gap: 10px; font-size: 12px; padding: 3px 0; }
.gantt-legend .lg-sym { flex: 0 0 44px; display: flex; align-items: center; justify-content: center; }
.lg-bar { display: inline-block; width: 36px; height: 12px; border-radius: 3px; background: var(--bg); border: 1px solid var(--border); }
.lg-bar.st-in_progress { background: var(--sr-blue); border-color: var(--sr-blue); }
.lg-bar.st-blocked { background: var(--danger); border-color: var(--danger); }
.lg-bar.st-done { background: var(--sr-green); border-color: var(--sr-green); }
.lg-bar.overdue { box-shadow: 0 0 0 2px var(--danger); }
.lg-bar.hanging { border-style: dashed; border-color: var(--text-muted); }
.lg-bar.chip { width: 10px; }
.lg-bar.critical-path { outline: 2px dashed var(--danger); outline-offset: 1px; }
.lg-diamond { display: inline-block; width: 11px; height: 11px; transform: rotate(45deg); border-radius: 2px; background: var(--bg); border: 1px solid var(--text-muted); }
.lg-today { display: inline-block; width: 2px; height: 16px; background: var(--warn); }
.lg-ghost { display: inline-block; width: 36px; height: 7px; border-radius: 3px;
  background: repeating-linear-gradient(-45deg, var(--text-muted) 0 3px, transparent 3px 6px); }
.lg-ghost.late { background: repeating-linear-gradient(-45deg, var(--danger) 0 3px, transparent 3px 6px); }
.lg-line { display: inline-block; width: 36px; height: 0; border-top: 1.5px solid #8A97A6; position: relative; }
.lg-line::after { content: ""; position: absolute; right: -1px; top: -4px; border: 4px solid transparent; border-left: 6px solid #8A97A6; }
.lg-line.crit { border-top: 2px solid var(--danger); }
.lg-line.crit::after { border-left-color: var(--danger); }
.lg-line.child { border-top-style: dotted; }

.drift-badge {
  font-size: 11px; font-weight: 600; border-radius: 8px; padding: 0 6px;
  color: #fff; background: var(--danger); white-space: nowrap;
}
.drift-badge.early { background: var(--sr-green); }
/* M23 P2 critical path: dashed red route — distinct from the solid overdue
   ring. Applies to gantt bars/diamonds and pipeline chips alike. */
.critical-path { outline: 2px dashed var(--danger); outline-offset: 2px; }
.sched-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; padding: 5px 11px; border-radius: 8px;
  background: var(--bg); border: 1px solid var(--border); white-space: nowrap;
}
.sched-chip .crit { color: var(--danger); font-weight: 600; }

/* ---------- Email block composer (campaigns) ---------- */
.composer-block {
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px; margin-bottom: 10px;
}
.composer-block-bar {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 8px;
}
.composer-block-label {
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.5px; color: var(--text-muted);
}
.composer-ctl {
  background: white; border: 1px solid var(--border); border-radius: 4px;
  padding: 2px 8px; margin-left: 4px; font-size: 13px; line-height: 1.4;
  color: var(--text-muted); cursor: pointer;
}
.composer-ctl:hover { color: var(--text); background: var(--bg); }
.composer-block-body input[type="text"],
.composer-block-body input[type="url"],
.composer-block-body textarea {
  width: 100%; padding: 8px 12px; border: 1px solid var(--border);
  border-radius: 4px; font: inherit; background: white;
}
.composer-block-body textarea { resize: vertical; }
.composer-block-body .cb-alt-row { margin-top: 8px; }
.composer-block-body .cb-alt-row label {
  display: block; font-size: 12px; color: var(--text-muted); margin-bottom: 4px;
}
.composer-block-body .cb-preview {
  display: block; max-width: 100%; max-height: 220px;
  border-radius: 6px; margin-bottom: 8px;
}
.composer-block-body .cb-error { color: var(--danger); font-size: 13px; margin-top: 6px; }
.composer-block-body .cb-divider-note {
  text-align: center; color: var(--text-muted); font-size: 12px; padding: 2px 0;
}
.composer-add-row {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding-top: 10px; border-top: 1px dashed var(--border); margin-top: 4px;
}
.composer-add-row .btn { padding: 5px 12px; font-size: 13px; }

/* ---------- Campaign preview iframe ---------- */
.email-preview-frame {
  width: 100%; height: 640px; border: 1px solid var(--border);
  border-radius: 8px; background: var(--bg);
}

/* ---------- Email templates (campaign form) ---------- */
.template-picker { display: flex; flex-wrap: wrap; gap: 8px; }
.template-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 16px;
  padding: 4px 6px 4px 12px; font-size: 13px;
}
.template-chip a { text-decoration: none; font-weight: 500; }
.template-chip form { display: inline; margin: 0; }
.template-chip-active { border-color: var(--sr-blue); background: #EAF2FA; }
.campaign-actions {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin: 16px 0 6px 0;
}
.template-save-group {
  display: inline-flex; align-items: center; gap: 6px; margin-left: auto;
  padding-left: 12px; border-left: 1px solid var(--border);
}
.template-save-group input {
  padding: 7px 10px; border: 1px solid var(--border); border-radius: 4px;
  font: inherit; width: 170px;
}

/* ---------- Campaign editor: form left, live preview right ---------- */
.campaign-editor-layout {
  display: flex; gap: 20px; align-items: flex-start;
}
.campaign-editor-main { flex: 1 1 480px; min-width: 0; max-width: 760px; }
.campaign-preview-pane {
  flex: 1 1 460px; min-width: 0; max-width: 700px;
  position: sticky; top: 16px;
}
.campaign-preview-panel .preview-meta {
  font-size: 13px; color: var(--text); line-height: 1.7;
  padding: 8px 12px; margin-bottom: 10px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
}
.campaign-preview-panel .preview-meta-label {
  color: var(--text-muted); font-weight: 600; margin-right: 4px;
}
.campaign-preview-iframe { height: 70vh; min-height: 420px; background: white; }
@media (max-width: 1100px) {
  .campaign-editor-layout { flex-direction: column; }
  .campaign-preview-pane { position: static; width: 100%; max-width: 760px; }
  .campaign-preview-iframe { height: 560px; }
}
