/* ops.css — Operations Control Center styles. Reuses frame tokens + pur-* utility
   classes from purchasing.css; only the weekly-trend bar visualization is new. */

.ops-trend { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
.ops-trend-row { display: grid; grid-template-columns: 90px 1fr 160px; align-items: center; gap: 10px; font-size: 12.5px; }
.ops-trend-date { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.ops-trend-bar-wrap { height: 14px; background: var(--surface-2); border-radius: 3px; overflow: hidden; }
.ops-trend-bar { display: block; height: 100%; background: var(--gold); border-radius: 3px; min-width: 2px; }
.ops-trend-bar--warn { background: #b42318; }
.ops-trend-val { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---- Cash Planner: drag a projected payment onto a date ---- */
.ops-plan-tray { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 10px; }
.ops-plan-tray-label { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); margin-top: 8px; }
.ops-chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 9px; border-radius: 14px;
  font-size: 12px; cursor: grab; user-select: none; border: 1px solid var(--border, #d0d5dd);
  background: var(--surface-2); white-space: nowrap; max-width: 300px; overflow: hidden; text-overflow: ellipsis; }
.ops-chip b { font-variant-numeric: tabular-nums; }
.ops-chip-cat { flex: 0 0 auto; min-width: 20px; padding: 1px 4px; border-radius: 5px;
  font-size: 8px; line-height: 1.25; font-weight: 800; text-align: center; letter-spacing: .03em; }
.ops-chip--cat-ap .ops-chip-cat { background: #b4231820; color: #912018; }
.ops-chip--cat-ar .ops-chip-cat { background: #12b76a24; color: #067647; }
.ops-chip--cat-overhead .ops-chip-cat { background: #7f56d924; color: #6941c6; }
.ops-chip--in { border-color: #12b76a55; background: #12b76a14; }
.ops-chip--out { border-color: #b4231855; background: #b4231810; }
.ops-chip--sel { outline: 2px solid var(--gold); }
.ops-chip--planned { cursor: grab; }
.ops-chip--ghost { opacity: .55; cursor: default; }
/* Draft: auto-scheduled off an invoice's printed due date by the email intake,
   not yet committed. Dashed edge = "this one can still move" — these are the
   rows to stretch to 60/90 when the month is tight. */
.ops-chip--draft { border-style: dashed; opacity: .88; }
.ops-chip--draft .ops-chip-lbl { font-style: italic; }
/* Locked: backed by a payment receipt. The money already left the account, so
   the chip is not draggable and carries no edit affordance. */
.ops-chip--locked { cursor: default; background: #6b72801a; border-color: #6b728066; }
.ops-chip .ops-chip-mark { font-size: 10px; opacity: .75; margin-right: 2px; }
.ops-chip .ops-chip-x { cursor: pointer; opacity: .5; padding: 0 2px; }
.ops-chip .ops-chip-x:hover { opacity: 1; }
/* Board: a fit-to-screen grid, never a horizontal scroller. Week = 7 tall
   columns; Month = a 7-wide calendar whose rows share the available height;
   Day = one full-width detail panel. */
.ops-board { display: grid; gap: 4px; padding: 6px 2px 10px; align-content: stretch; }
.ops-board--week  { grid-template-columns: repeat(7, minmax(0, 1fr));
  grid-auto-rows: minmax(190px, 1fr); height: clamp(260px, calc(100vh - 470px), 640px); overflow-y: auto; }
.ops-board--month { grid-template-columns: repeat(7, minmax(0, 1fr));
  grid-auto-rows: minmax(128px, auto); height: auto; overflow: visible; }
.ops-board--day   { grid-template-columns: 1fr; }
.ops-board-wd { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px;
  padding: 0 2px; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); }
.ops-board-wd span { text-align: center; }
.ops-day { min-width: 0; border: 1px solid var(--border, #d0d5dd);
  border-radius: 8px; padding: 6px 6px 8px; background: var(--surface-1, transparent);
  display: flex; flex-direction: column; gap: 4px; overflow: hidden; }
.ops-day-chips { display: flex; flex-direction: column; gap: 4px; overflow-y: auto; min-height: 0; flex: 1 1 auto; }
.ops-day--today { border-color: var(--gold); box-shadow: inset 0 0 0 1px var(--gold); }
.ops-day--offmonth { opacity: .5; }
.ops-day--noproj .ops-day-bal { color: var(--text-muted); font-weight: 400; }

/* ---- View bar: Day / Week / Month + window navigation + intake buttons ---- */
.ops-viewbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 8px 0 4px; }
.ops-viewbar__spacer { flex: 1 1 auto; }
.ops-filterbar { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin: 6px 0 8px;
  font-size: 11px; color: var(--text-muted); }
.ops-filter { display: inline-flex; align-items: center; gap: 5px; border: 1px solid var(--border, #d0d5dd);
  border-radius: 999px; padding: 4px 9px; background: transparent; color: var(--text-muted);
  font: inherit; cursor: pointer; opacity: .58; }
.ops-filter.is-on { color: inherit; background: var(--surface-2); opacity: 1; font-weight: 600; }
.ops-filter-dot { width: 8px; height: 8px; border-radius: 50%; background: #98a2b3; }
.ops-filter-dot--ap { background: #b42318; }
.ops-filter-dot--ar { background: #12b76a; }
.ops-filter-dot--overhead { background: #7f56d9; }
.ops-filter-note { margin-left: auto; }
.ops-seg { display: inline-flex; border: 1px solid var(--border, #d0d5dd); border-radius: 7px; overflow: hidden; }
.ops-seg__b { border: 0; background: transparent; padding: 5px 14px; font-size: 12.5px; cursor: pointer;
  color: var(--text-muted); font-family: inherit; }
.ops-seg__b + .ops-seg__b { border-left: 1px solid var(--border, #d0d5dd); }
.ops-seg__b.is-on { background: var(--gold); color: #17110a; font-weight: 600; }
.ops-nav { display: inline-flex; align-items: center; gap: 6px; }
.ops-nav__b { border: 1px solid var(--border, #d0d5dd); background: transparent; border-radius: 6px;
  padding: 3px 9px; cursor: pointer; color: inherit; font-size: 11px; line-height: 1.4; }
.ops-nav__b:hover { border-color: var(--gold); }
.ops-nav__label { font-size: 13px; font-weight: 600; min-width: 150px; text-align: center; }
.ops-jump { color: var(--gold); text-decoration: underline; cursor: pointer; }

/* ---- Day view ---- */
.ops-dayview { border: 1px solid var(--border, #d0d5dd); border-radius: 10px; padding: 14px 16px;
  display: flex; flex-direction: column; gap: 12px; }
.ops-dayview-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.ops-dayview-head h3 { margin: 0 0 2px; font-size: 16px; }
.ops-dayview-bal { font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; }
.ops-dayview-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; }
.ops-dayview-block h4 { margin: 0 0 6px; font-size: 11.5px; text-transform: uppercase;
  letter-spacing: .04em; color: var(--text-muted); font-weight: 600; }
.ops-dayview-list { display: flex; flex-direction: column; gap: 5px; align-items: flex-start; }
.ops-dayview-list .ops-chip { max-width: 100%; font-size: 12.5px; }
.ops-dayview-pat { display: flex; justify-content: space-between; font-size: 12.5px;
  color: var(--text-muted); font-variant-numeric: tabular-nums; max-width: 380px; }
.ops-dayview-drop { border: 1.5px dashed var(--border, #d0d5dd); border-radius: 8px; padding: 12px;
  text-align: center; font-size: 12px; color: var(--text-muted); }

/* ---- Intake strip: drop a screenshot of a scheduled payment ---- */
.ops-intake { border: 1.5px dashed var(--border, #d0d5dd); border-radius: 8px; padding: 9px 12px;
  margin: 4px 0 8px; font-size: 12px; color: var(--text-muted); line-height: 1.5; }
.ops-intake b { color: inherit; }
.ops-intake--over { border-color: var(--gold); background: var(--surface-2); }
.ops-intake-browse { text-decoration: underline; cursor: pointer; }
.ops-day--weekend { opacity: .75; background: var(--surface-2); }
.ops-day--over { outline: 2px dashed var(--gold); outline-offset: -2px; }
.ops-day-head { font-size: 11px; color: var(--text-muted); display: flex; justify-content: space-between; }
.ops-day-bal { font-size: 12.5px; font-weight: 600; font-variant-numeric: tabular-nums; }
.ops-day-bal--warn { color: #b42318; }
.ops-day-pat { font-size: 10.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.ops-day .ops-chip { max-width: 100%; font-size: 11px; padding: 3px 6px; }
.ops-chip-lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.ops-board--month .ops-day .ops-chip { width: 100%; max-width: 100%; box-sizing: border-box;
  align-items: flex-start; font-size: 10.5px; padding: 3px 4px; gap: 3px; border-radius: 6px; }
.ops-board--month .ops-chip-lbl { flex: 1 1 auto; display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; white-space: normal; line-height: 1.18; overflow: hidden; }
.ops-board--month .ops-chip b { flex: 0 0 auto; font-size: 10px; }
.ops-day-chips--month { gap: 3px; }
.ops-board--month .ops-day-head, .ops-board--month .ops-day-pat { font-size: 10px; }
.ops-board--month .ops-chk-tag { font-size: 8.5px; padding: 0 3px; }
.ops-plan-hint { font-size: 12px; color: var(--text-muted); margin: 4px 0 8px; }
.ops-chk-tag { font-size: 9.5px; text-transform: uppercase; letter-spacing: .03em; padding: 1px 5px;
  border-radius: 8px; font-weight: 700; white-space: nowrap; }
.ops-chk-tag--written   { background: #f7900933; color: #93540a; }
.ops-chk-tag--held      { background: #b4231822; color: #b42318; }
.ops-chk-tag--deposited { background: #175cd333; color: #175cd3; }
.ops-chk-tag--cleared   { background: #12b76a33; color: #067647; }
.ops-plan-editor__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; }
.ops-plan-editor textarea.pur-in { width: 100%; resize: vertical; }
.ops-att-zone { border: 1.5px dashed var(--border, #d0d5dd); border-radius: 8px; padding: 8px 10px; margin-top: 10px; }
.ops-att-zone--over { border-color: var(--gold); background: var(--surface-2); }
.ops-att-item { display: inline-flex; align-items: center; gap: 4px; margin-right: 12px; font-size: 12.5px; }

/* ---- Fit the Operations screen to the window ----------------------------
   .frame-wrap is a grid whose single auto track sizes to the widest card's
   min-content, so one wide table (AR, recurring vendors) dragged the whole
   column — and the planner board with it — past the right edge of the
   screen. shell-frame.css already ships this exact guard, but only under
   the 720px mobile breakpoint. Scoped here to Operations only: the track
   may shrink below its content, and wide tables scroll inside their own
   .fx-table-wrap instead of leaking the page. */
#ops-root .frame-wrap { grid-template-columns: minmax(0, 1fr); }
#ops-root .fx-table-wrap { min-width: 0; max-width: 100%; }
#ops-root .fx-card { min-width: 0; }
/* Long card subtitles sit beside the title on one line; let them wrap. */
#ops-root .fx-card__head { flex-wrap: wrap; }
/* The undated-payables warning lists every vendor on one nowrap line; at the
   real vendor count that badge alone was 2,532px wide and scrolled the page. */
#ops-cash-card .fx-badge { white-space: normal; line-height: 1.45; }

/* ============ payables detail: month cells, detail modal, aging, ============
   facilities, month-end reconciliation.  Added with the invoice-level
   payables work — see ops_center/ap_detail.py. ============================= */

/* Month view compresses to in / out / projected; the transactions themselves
   render in Week and Day where there is room to read them. */
.ops-day--month { min-height: 128px; }
.ops-day--month .ops-day-head { font-size: 12px; font-weight: 700; }
.ops-day-sum { display: flex; flex-direction: column; gap: 1px; margin-top: 2px; }
.ops-day-sum__row { display: flex; justify-content: space-between; font-size: 11px; line-height: 1.35; }
.ops-day-sum__row span { color: var(--muted, #7a8595); }
.ops-day-sum__row--in b { color: #1f8a4c; }
.ops-day-sum__row--out b { color: #b3261e; }
.ops-day-sum__row.is-zero b, .ops-day-sum__row.is-zero span { color: #c2c8d0; }
.ops-day-count { font-size: 10px; color: var(--muted, #7a8595); margin-top: 2px; }

/* detail window */
.ops-modal { position: fixed; inset: 0; background: rgba(16,20,26,.55); display: none;
  align-items: flex-start; justify-content: center; z-index: 120; padding: 32px 16px; overflow-y: auto; }
.ops-modal.is-open { display: flex; }
.ops-modal__panel { background: #fff; border-radius: 12px; max-width: 760px; width: 100%;
  box-shadow: 0 18px 48px rgba(0,0,0,.28); overflow: hidden; }
.ops-modal__head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; padding: 16px 18px 12px; border-bottom: 1px solid var(--line, #e6e9ee); }
.ops-modal__head h3 { margin: 0 0 2px; font-size: 17px; }
.ops-modal__x { background: none; border: 0; font-size: 26px; line-height: 1; cursor: pointer;
  color: var(--muted, #7a8595); padding: 0 4px; }
.ops-modal__body { padding: 16px 18px 20px; }
.ops-modal__amt { font-size: 30px; font-weight: 700; margin-bottom: 12px; }
.ops-modal__amt.is-in { color: #1f8a4c; }
.ops-modal__amt.is-out { color: #b3261e; }
.ops-modal__sec { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line, #e6e9ee); }
.ops-modal__sec h4 { margin: 0 0 8px; font-size: 13px; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted, #7a8595); }
.ops-modal__note { font-size: 12px; color: var(--muted, #56606f); line-height: 1.5;
  background: var(--bg, #f7f8fa); padding: 9px 11px; border-radius: 8px; margin: 10px 0 0; }
.ops-kvs { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 2px 18px; }
.ops-kv { display: flex; justify-content: space-between; gap: 12px; padding: 5px 0;
  border-bottom: 1px dotted var(--line, #e6e9ee); font-size: 13px; }
.ops-kv span { color: var(--muted, #7a8595); }

/* invoice tables */
.ops-inv { width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 12.5px; }
.ops-inv th { text-align: left; font-weight: 600; color: var(--muted, #7a8595);
  border-bottom: 1px solid var(--line, #e6e9ee); padding: 5px 8px 5px 0; }
.ops-inv td { padding: 5px 8px 5px 0; border-bottom: 1px solid #f1f3f6; }
.ops-inv--rem td { color: var(--muted, #7a8595); background: #fbfbfd; }
.ops-tag { font-size: 10px; background: #eef1f5; border-radius: 4px; padding: 1px 5px; color: #56606f; }

/* vendor aging */
.ops-age-pick { display: flex; align-items: center; gap: 10px; margin: 10px 0 12px; flex-wrap: wrap; }
.ops-age-pick select { min-width: 260px; padding: 6px 8px; border: 1px solid var(--line, #d8dde5);
  border-radius: 8px; }
.ops-table-wrap { overflow-x: auto; }
.ops-age { width: 100%; border-collapse: collapse; font-size: 13px; }
.ops-age th { text-align: left; font-weight: 600; color: var(--muted, #7a8595);
  border-bottom: 1px solid var(--line, #e6e9ee); padding: 6px 10px 6px 0; white-space: nowrap; }
.ops-age td { padding: 7px 10px 7px 0; border-bottom: 1px solid #f1f3f6; }
.ops-age-row { cursor: pointer; }
.ops-age-row:hover { background: #f5f8ff; }
.ops-age-90 { color: #b3261e; font-weight: 600; }
.ops-age-tot td { border-top: 2px solid var(--line, #d8dde5); font-weight: 600; background: #fafbfc; }
.ops-age--one { margin-top: 12px; }
.ops-basis { font-size: 10px; border-radius: 4px; padding: 1px 5px; margin-left: 4px; }
.ops-basis--reported { background: #e7f0ff; color: #1a4d9e; }
.ops-basis--computed { background: #e6f6ec; color: #1f8a4c; }
.ops-basis--mixed { background: #fff3e0; color: #9a5b00; }
.ops-basis--unaged { background: #f0f1f4; color: #6b7280; }

/* facilities */
.ops-fac { width: 100%; border-collapse: collapse; font-size: 13px; }
.ops-fac th { text-align: left; font-weight: 600; color: var(--muted, #7a8595);
  border-bottom: 1px solid var(--line, #e6e9ee); padding: 6px 10px 6px 0; white-space: nowrap; }
.ops-fac td { padding: 8px 10px 8px 0; border-bottom: 1px solid #f1f3f6; vertical-align: top; }
.ops-fac--off { opacity: .55; }
.ops-fac-src { font-size: 11px; color: var(--muted, #7a8595); max-width: 320px; }
.ops-unknown { color: #9a5b00; font-style: italic; }
.ops-warn { background: #fff8e6; border: 1px solid #f0d9a0; color: #6b4e00; font-size: 12px;
  padding: 9px 11px; border-radius: 8px; margin: 8px 0 12px; line-height: 1.5; }

/* reconciliation */
.ops-recon__bar { display: flex; align-items: center; gap: 8px; margin: 8px 0 12px; }
.ops-recon__ok { font-size: 12px; color: #1f8a4c; font-weight: 600; margin-left: 8px; }
.ops-recon { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
.ops-recon__col h4 { margin: 0 0 8px; font-size: 12px; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted, #7a8595); }
.ops-recon__row { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px;
  padding: 6px 8px; border-radius: 6px; margin-bottom: 4px; line-height: 1.35; }
.ops-recon__row.is-ok { background: #f0f8f3; }
.ops-recon__row.is-warn { background: #fff6f5; }
.ops-recon__row.is-info { background: #f5f7fb; }
.ops-recon__stmt { margin-top: 14px; font-size: 12px; color: var(--muted, #56606f);
  border-top: 1px solid var(--line, #e6e9ee); padding-top: 10px; }

@media (max-width: 720px) {
  .ops-modal { padding: 12px 8px; }
  .ops-kvs { grid-template-columns: 1fr; }
  .ops-filter-note { flex-basis: 100%; margin-left: 0; }
  .ops-board-wd { display: none; }
  .ops-board--month { display: flex; flex-direction: column; height: auto; overflow: visible; }
  .ops-board--month .ops-day--offmonth { display: none; }
  .ops-day--month { min-height: 72px; }
}


/* ============ conflict log ==================================================
   Where two sources disagree the disagreement is the record — styled to be
   read at a glance and impossible to mistake for settled fact. ============= */
.ops-cf__bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 10px 0 12px; }
.ops-cf__toggle { margin-left: auto; font-size: 12px; color: var(--muted, #7a8595);
  display: flex; align-items: center; gap: 5px; }
.ops-sev { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  border-radius: 4px; padding: 2px 7px; white-space: nowrap; }
.ops-sev--critical { background: #fdeaea; color: #a5150f; }
.ops-sev--high     { background: #fff1e3; color: #9a4b00; }
.ops-sev--medium   { background: #fff8e0; color: #7a5a00; }
.ops-sev--low      { background: #eef1f5; color: #56606f; }
.ops-sev--info     { background: #eef4ff; color: #1a4d9e; }

.ops-cf { border: 1px solid var(--line, #e6e9ee); border-left: 4px solid #d8dde5;
  border-radius: 9px; padding: 11px 13px; margin-bottom: 9px; background: #fff; }
.ops-cf--critical { border-left-color: #d33; }
.ops-cf--high     { border-left-color: #e08a2e; }
.ops-cf--medium   { border-left-color: #e3c04a; }
.ops-cf--low      { border-left-color: #b8c0cc; }
.ops-cf.is-closed { opacity: .6; background: #fafbfc; }
.ops-cf__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; }
.ops-cf__subj { font-weight: 600; font-size: 13px; }
.ops-cf__status { font-size: 10.5px; border-radius: 4px; padding: 1px 6px; background: #eef1f5;
  color: #56606f; text-transform: uppercase; letter-spacing: .03em; }
.ops-cf__status--open { background: #fdeaea; color: #a5150f; }
.ops-cf__status--acknowledged { background: #fff8e0; color: #7a5a00; }
.ops-cf__status--resolved { background: #e6f6ec; color: #1f8a4c; }
.ops-cf__status--accepted { background: #eef4ff; color: #1a4d9e; }
.ops-cf__status--superseded { background: #f0f1f4; color: #6b7280; }
.ops-cf__title { font-size: 13.5px; font-weight: 600; margin-bottom: 3px; }
.ops-cf__detail { font-size: 12.5px; color: var(--muted, #56606f); line-height: 1.5; }
.ops-cf__vals { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 7px; font-size: 12.5px; }
.ops-cf__vals i { color: var(--muted, #7a8595); font-style: normal; }
.ops-cf__delta { color: #b3261e; font-weight: 600; }
.ops-cf__res { margin-top: 7px; font-size: 12.5px; background: #f0f8f3; border-radius: 6px;
  padding: 6px 9px; color: #1f5e3a; }
.ops-cf__acts { display: flex; gap: 6px; margin-top: 9px; flex-wrap: wrap; }

/* ---- email intake: the question queue ---------------------------------- */
/* One row per unreadable FIELD, grouped by the document it came from, so a
   manager answers "what's the amount?" rather than "go read this invoice". */
.ops-intake__sec { padding: 4px 12px 12px; }
.ops-intake__sec--batch { border-top: 1px solid var(--fx-line, #e5e7eb); margin-top: 4px; padding-top: 10px; }
.ops-intake__h { margin: 6px 0 2px; font-size: 13px; }
.ops-intake__grp { border: 1px solid var(--fx-line, #e5e7eb); border-radius: 8px; padding: 8px 10px; margin-bottom: 8px; }
.ops-intake__doc { font-size: 12px; margin-bottom: 6px; }
.ops-intake__cls { display: inline-block; font-size: 10px; text-transform: uppercase;
                   letter-spacing: .04em; padding: 1px 6px; border-radius: 999px;
                   background: #2563eb1a; color: #2563eb; }
.ops-intake__q { padding: 5px 0; }
.ops-intake__q + .ops-intake__q { border-top: 1px dashed var(--fx-line, #e5e7eb); }
.ops-intake__ask { font-size: 13px; margin-bottom: 4px; }
.ops-intake__act { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.ops-intake__act .pur-in { flex: 1 1 180px; min-width: 140px; }
.ops-intake__esc { font-size: 10px; text-transform: uppercase; letter-spacing: .04em;
                   padding: 1px 6px; border-radius: 999px; background: #b4231822; color: #b42318; }

/* ---- collapsible section heads ----
   Grid with equal 1fr side columns so every title is EXACTLY centered no
   matter how wide the caret or subtitle is — the titles line up card to card. */
#ops-root .ops-colhead { display: grid; grid-template-columns: 1fr auto 1fr;
                         align-items: center; gap: 8px;
                         cursor: pointer; user-select: none; }
#ops-root .ops-colhead .ops-col-caret { grid-column: 1; justify-self: start;
                                        font-size: 11px; opacity: .55; }
#ops-root .ops-colhead .fx-card__title { grid-column: 2; text-align: center; }
#ops-root .ops-colhead .pur-dim { grid-column: 3; justify-self: end; text-align: right; }
#ops-root .ops-colhead:hover .ops-col-caret { opacity: 1; }
#ops-root .ops-colhead--closed { margin-bottom: 0; }
#ops-root .ops-colhead--closed ~ * { display: none !important; }

/* ---- drag-to-resize sections ----
   The grip rides the card's bottom edge; a sized card scrolls inside, its head
   stays pinned (full-bleed so content can't slide past in the gutters), and
   the grip stays pinned to the visible bottom edge. Negative margins are
   compensated by equal padding so nothing shifts when sizing kicks in. */
#ops-root .fx-card { position: relative; }
#ops-root .ops-resize { position: absolute; left: 0; right: 0; bottom: 0; height: 12px;
                        cursor: ns-resize; display: flex; align-items: center;
                        justify-content: center; opacity: .35; touch-action: none; }
#ops-root .ops-resize:hover { opacity: 1; }
#ops-root .ops-resize::before { content: ""; width: 44px; height: 4px; border-radius: 2px;
                                background: var(--border, #cbd2dc); }
.ops-resizing, .ops-resizing * { user-select: none !important; cursor: ns-resize !important; }
/* A sticky child can never cover its parent's padding zone, so the sized card
   drops its vertical padding and the head/grip carry it instead. */
#ops-root .ops-card--sized { padding-top: 0 !important; padding-bottom: 0 !important; }
#ops-root .ops-card--sized > .ops-colhead { position: sticky; top: 0; z-index: 2;
                                            background: var(--surface, #fff);
                                            margin: 0 -18px; padding: 14px 18px 6px; }
#ops-root .ops-card--sized > .ops-resize { position: sticky; bottom: 0; z-index: 2;
                                           background: var(--surface, #fff);
                                           margin: 0 -18px; }
