/* Operator console — reuses subscription.css; only console-specific rules here. */
.op-login {
  max-width: 460px;
  width: 100%;
  justify-self: center;
  margin: 40px auto 0;
}
.op-form {
  display: grid;
  gap: 12px;
  margin-top: 12px;
}
.op-form .btn {
  justify-self: start;
}
.op-search {
  max-width: 280px;
}
#op-main,
#op-notice {
  min-width: 0;
}
/* #277 Q71: notice(…, {reveal:true}) scrolls the notice into view; this keeps it clear of
   the sticky topbar (theme.css .app-topbar: 13px padding x2 + 42px icon + 1px border). */
#op-notice {
  scroll-margin-top: 84px;
}
#op-notice:focus {
  outline: 2px solid #3446b8;
  outline-offset: 2px;
}

/* #277 P1: the centre Reference tab lists Kumon-wide tables as links to Static data. */
.op-ref-shared {
  margin-top: 16px;
  padding: 10px 14px;
  border: 1px dashed var(--line, #d7dbe3);
  border-radius: 10px;
}
.op-ref-shared-h {
  margin: 0 0 4px;
  font-size: 13px;
  color: #334155; /* 10:1 */
}
.op-ref-shared-note {
  margin: 0 0 8px;
  font-size: 12px;
  color: #475569; /* 7.6:1 */
}
.op-ref-shared-list {
  margin: 0;
  padding-left: 18px;
  columns: 2 260px;
  font-size: 13px;
  line-height: 1.8;
}
.op-ref-shared-list .op-ref-name {
  font-size: 11px;
  color: #475569;
}
.sub-wrap {
  grid-template-columns: minmax(0, 1fr);
}
@media (max-width: 600px) {
  .app-topbar {
    flex-wrap: wrap;
    gap: 12px;
  }
  .app-topbar .brand {
    min-width: 0;
    flex: 1 1 100%;
  }
  .app-topbar .top-right {
    width: 100%;
    justify-content: flex-end;
  }
}
#op-main > .sub-section {
  min-width: 0;
  overflow-x: auto;
}
@media (max-width: 600px) {
  #op-main .sub-section-head {
    flex-wrap: wrap;
  }
  .op-search {
    width: 100%;
    max-width: 100%;
  }
}
/* Installation-wide settings (#233) — the Amazon Associates tag lives here now. */
.op-setting {
  margin-top: 4px;
}
.op-setting > label {
  display: block;
  font-weight: 700;
  margin-bottom: 4px;
}
.op-setting-row {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 8px;
}
.op-setting-row input {
  flex: 1 1 260px;
  min-width: 0;
  max-width: 380px;
  padding: 9px 11px;
  border: 1px solid var(--line, #d5dce7);
  border-radius: 9px;
  font-size: 14px;
  font-family: inherit;
}
.op-setting-note {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--muted);
}
.op-setting-note.is-error {
  color: var(--danger, #c0392b);
  font-weight: 600;
}

#op-centers tbody tr {
  cursor: pointer;
}
#op-centers tbody tr:hover {
  background: var(--card-2);
}
.op-plan-pill {
  font-size: 11px;
  font-weight: 800;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(91, 110, 225, 0.12);
  color: var(--indigo);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* The centre view was a fixed modal drawer over the long page; since the 2026-09-30
   redesign it is a page of its own (#/centres/<id>/<tab>) inside the console's content
   column, so it flows with the page instead of covering it. */
.op-drawer {
  position: static;
  display: block;
  min-width: 0;
}
.op-drawer[hidden] {
  display: none;
}
.op-drawer-card {
  width: 100%;
  overflow: visible;
  display: flex;
  flex-direction: column;
}
.op-drawer-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  flex-wrap: wrap;
  padding: 18px 22px 10px;
  border-bottom: 1px solid var(--line);
  background: var(--card);
}
.op-drawer-title {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0;
}
.op-drawer-body {
  padding: 16px 22px 40px;
  display: grid;
  gap: 14px;
}
.op-drawer-body > *,
.op-row > *,
.op-grant > *,
.op-plan-row select {
  min-width: 0;
}
.op-table-scroll {
  overflow-x: auto;
}
.op-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
@media (max-width: 760px) {
  .op-row {
    grid-template-columns: 1fr;
  }
}
.op-mini {
  background: var(--card-2);
}
.op-plan-row {
  display: flex;
  gap: 8px;
  margin: 8px 0;
}
.op-plan-row select {
  flex: 1;
}
/*
  The grant row wraps on ITS OWN width, not the viewport's. It used to be a four-column
  grid (110px 120px 1fr auto) with a max-width:760px breakpoint, but this form sits in a
  half-width card inside the drawer: on a wide window the breakpoint never fires and the
  1fr column — the Note field, which is where the invoice reference goes onto the credit
  ledger — collapsed to ~30px, too narrow to read the placeholder or type into.
*/
.op-grant {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}
.op-grant > #d-amount {
  flex: 1 1 110px;
  min-width: 110px;
}
.op-grant > #d-bucket {
  flex: 1 1 120px;
  min-width: 120px;
}
.op-grant > #d-note {
  flex: 1 1 180px;
  min-width: 160px;
}
.op-grant > button {
  flex: 0 0 auto;
}
.op-group-title {
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  margin: 10px 0 6px;
}
.op-addons {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 10px;
}
/* An add-on the operator switched off from the Global feature switches. Same dashed,
   dimmed shape the center's own subscription page uses for the identical state
   (subscription.css `.addon-globally-off`), but WITHOUT that page's `not-allowed`
   cursor: on the center's page the switch really is disabled, whereas here the operator
   may still set what the center is entitled to while the feature is down. */
.op-addons .addon.globally-off {
  border-style: dashed;
  border-color: #d97706;
}
.op-addons .addon.globally-off .addon-meta {
  color: #9a3412;
  font-weight: 600;
}

/* Shared button display rules must not reveal authenticated controls at sign-in. */
#op-logout[hidden] {
  display: none !important;
}
#op-parent-controls {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
  padding: 12px 0;
}
#op-parent-controls .parent-control {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 12px;
  border: 1px solid #e2e8f0;
  border-radius: 10px;
  cursor: pointer;
}
#op-parent-controls .parent-control input {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  margin-top: 3px;
  accent-color: #4f46e5;
}
#op-parent-controls .parent-subscription-badge {
  display: block;
  width: fit-content;
  margin-top: 5px;
  padding: 3px 7px;
  border-radius: 6px;
  background: #fff3d6;
  color: #754a00;
  font-size: 11px;
  font-weight: 700;
}
#op-parent-controls .parent-control-impact {
  display: block;
  margin-top: 6px;
  color: #64748b;
  font-size: 12px;
  line-height: 1.45;
}
/* An off section now reads as off from across the room, the same way a switched-off
   global feature switch does below. Amber, not red: this is a deliberate state an
   operator chose, not a fault — but it is invisible to every parent at every center,
   so it cannot look identical to an on card with the tick removed. */
#op-parent-controls .parent-control.is-off {
  border-color: #d97706;
  background: rgba(217, 119, 6, 0.07);
}
#op-parent-controls .parent-control-off {
  display: block;
  margin-top: 6px;
  color: #9a3412;
  font-size: 12px;
  line-height: 1.45;
}
#op-parent-controls .parent-control-mapped {
  display: block;
  margin-top: 6px;
  color: #475569;
  font-size: 12px;
  line-height: 1.45;
  font-style: italic;
}

/* Global feature switches — same card shape as the parent-portal controls above them. */
#op-global-modules {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 10px;
}
/* The bulk row: a pick box beside the switch, never inside its label. */
#op-global-modules .global-control-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
#op-global-modules .global-control-row .global-control {
  flex: 1 1 auto;
}
/* The standard-reason picker. Four buttons and a text box: the record stays mandatory,
   the typing does not. */
.global-reason-dialog {
  max-width: 560px;
  border: 1px solid var(--border, #d7dbe3);
  border-radius: 12px;
  padding: 18px 20px;
}
.global-reason-dialog h3 {
  margin: 0 0 6px;
}
.global-reason-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 14px;
}
.global-reason-other {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  border-top: 1px solid var(--border, #d7dbe3);
  padding-top: 12px;
}
.global-reason-other .input {
  flex: 1 1 220px;
}
.global-reason-foot {
  margin-top: 12px;
  text-align: right;
}

#op-global-modules .global-control {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border, #d7dbe3);
  border-radius: 10px;
  background: var(--card-bg, #fff);
}
#op-global-modules .global-control input {
  margin-top: 3px;
  flex: 0 0 auto;
}
#op-global-modules .global-control code {
  font-size: 11px;
  opacity: 0.7;
}
#op-global-modules .global-control small {
  display: block;
  margin-top: 3px;
  font-size: 11px;
  line-height: 1.35;
  opacity: 0.85;
}
#op-global-modules .global-control.is-off {
  border-color: #d97706;
  background: rgba(217, 119, 6, 0.07);
}
#op-global-modules .global-control.is-protected {
  opacity: 0.75;
}
#op-global-modules .global-control-reason {
  color: #9a3412;
}
#op-global-modules .global-protected-badge {
  font-weight: 600;
  color: #475569;
}
.op-global-audit {
  margin-top: 12px;
  font-size: 12px;
}
.op-global-audit summary {
  cursor: pointer;
}
.global-audit-list {
  margin: 8px 0 0;
  padding-left: 18px;
  line-height: 1.6;
}

/* AI prompts, per center, inside the drawer (ADMIN_PANEL_TENANCY_AUDIT.md §5).
   One collapsed card per prompt: the inventory is long and an operator opens the drawer
   for a plan or a credit grant far more often than for a prompt, so the prompts must not
   push everything else off the screen. */
.op-prompt {
  margin: 0 0 10px;
}
.op-prompt > summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
}
/* `.field textarea` in theme.css is (0,2,0) and sets font-family: inherit, so the
   monospace asked for here never reached the screen — a prompt with an exact JSON
   contract in it was being edited in a proportional font. Matched specificity, and
   operator.css loads last, so the intended font wins. */
.op-prompt .op-prompt-text {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.op-prompt-text {
  width: 100%;
  min-height: 160px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  resize: vertical;
  /* `pre` kept every line on one row, so reading a 2,400-character prompt meant scrolling
     sideways once per line and the end of every rule was off-screen. `pre-wrap` keeps the
     newlines, indentation and runs of spaces that a prompt depends on, and soft-wraps the
     long lines that were the only thing needing the horizontal scrollbar. */
  white-space: pre-wrap;
  overflow-wrap: break-word;
  overflow-x: auto;
}

/* Reference-data actions in the drawer (ADMIN_PANEL_TENANCY_AUDIT.md §1/F3). */
.op-ref-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin: 0 0 10px;
}

/* "Add a center", collapsed under the center list (ADMIN_PANEL_TENANCY_AUDIT.md §3).
   Collapsed by default because provisioning a center is rare and irreversible, and it
   should not sit open under a list an operator reads every day. */
.op-newcentre {
  margin-top: 14px;
}
.op-newcentre > summary {
  cursor: pointer;
  font-weight: 600;
}
.op-newcentre-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 10px;
  align-items: end;
  margin-top: 10px;
}

/* ---- Contrast (WCAG AA, 4.5:1 for normal text) --------------------------
   The page-local --muted override that used to sit here is GONE. It read the shared token
   at #7b869a (3.67:1 on the white card) and darkened it for this console alone, saying the
   shared token was "not this sweep's to change". It has since been changed: theme.css now
   ships #5b6880, 5.62:1 on the card, above the 5.07:1 this local copy bought. */
/* The plan pill was var(--indigo) (#5b6ee1) on its own 12%-indigo wash: 3.81:1 at 11px.
   #4658c8 on the same wash is 5.19:1. */
.op-plan-pill {
  color: #4658c8;
}

/* ---- Level look-fors table ----------------------------------------------
   Auto table layout gave Section, Kind and Label one third each, so the LABEL — the only
   free-text column, and the thing actually being edited — was cut off mid-word, while a
   0-9 section number sat in 199px. The label takes the leftover width now, and the
   actions cell stops wrapping Save and Delete onto two lines. */
#d-lookfors table {
  width: 100%;
}
#d-lookfors td:nth-child(3) {
  width: 100%;
}
#d-lookfors [data-c='section_order'] {
  width: 72px;
}
#d-lookfors [data-c='kind'] {
  width: 120px;
}
#d-lookfors [data-c='label'] {
  width: 100%;
}
#d-lookfors td:last-child {
  white-space: nowrap;
}

/* The reason dialog answers inside itself. The page-level notice it used to write to
   lives above the modal and under the fixed topbar, so "type a reason" was invisible. */
.global-reason-error {
  margin: 8px 0 0;
  color: #8b1130;
  font-size: 13px;
  font-weight: 600;
}

/* ── Reference data: the card grid ───────────────────────────────────────────
   Modelled on the Admin Panel's Static Data grid (webroot/admin/js/admin.js
   CATEGORIES): an icon, a title, a line saying what the data is for, and a pill
   saying what may be done with it. Clicking a card opens it; a back button
   returns here.

   Every colour pair below was MEASURED against its own background rather than
   eyeballed, and each carries its ratio. The bar is AA 4.5:1 for the text.       */
.op-ref-tools {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin: 8px 0 14px;
}
.op-ref-find {
  flex: 1 1 260px;
  max-width: 360px;
}
.op-ref-count {
  font-size: 12px;
  color: var(--muted); /* #646f83 on --card #fff — 5.07:1 (4.84:1 on --card-2) */
  white-space: nowrap;
  padding-bottom: 8px;
}
.op-ref-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 12px;
}
.op-ref-card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 7px;
  width: 100%;
  text-align: left;
  font: inherit;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--card);
  cursor: pointer;
  transition:
    border-color 0.15s,
    box-shadow 0.15s,
    transform 0.15s;
}
.op-ref-card:hover {
  border-color: #b9c6dc;
  box-shadow: var(--shadow-sm);
  transform: translateY(-1px);
}
/* Keyboard users get the same affordance as the mouse. These are real <button>s,
   so focus-visible is all that is needed — nothing here is a div pretending. */
.op-ref-card:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}
.op-ref-head {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
.op-ref-ic {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  font-size: 13px;
}
.op-ref-title {
  font-weight: 650;
  font-size: 14px;
  color: var(--ink); /* #1e2634 on --card #fff — 15.19:1 */
  line-height: 1.3;
  min-width: 0;
}
.op-ref-purpose {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-soft); /* #43516a on --card #fff — 8.00:1 */
}
/* The "why" line on a center-owned or legacy card. It is the part that stops an
   operator editing something they should not, so it is not fine print: same
   weight of colour as the purpose, set apart by the rule rather than by fading. */
.op-ref-note {
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-soft); /* 8.00:1 */
  border-left: 2px solid var(--line);
  padding-left: 8px;
}
.op-ref-note-block {
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-soft); /* 8.00:1 */
  border-left: 3px solid var(--line);
  padding: 2px 0 2px 10px;
  margin: 8px 0;
}
.op-ref-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 4px;
}
.op-ref-rows {
  font-size: 12px;
  color: var(--muted); /* 5.07:1 */
}
.op-ref-name {
  font-size: 11px;
  color: var(--muted); /* 5.07:1 */
  word-break: break-all;
}
.op-ref-pill {
  display: inline-block;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.01em;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
/* Pill + icon-tile colours. Ratios are the pill TEXT on the pill's own fill. */
.op-ref-pill.is-editable {
  background: #e3f4e8;
  color: #14532d;
} /* 7.97:1 */
.op-ref-pill.is-viewer {
  background: #e8eefb;
  color: #1e3a8a;
} /* 8.90:1 */
.op-ref-pill.is-centre {
  background: #fdf0e3;
  color: #7c3a03;
} /* 7.61:1 */
.op-ref-pill.is-legacy {
  background: #eceff3;
  color: #374151;
} /* 8.94:1 */
.op-ref-ic.is-editable {
  background: #e3f4e8;
  color: #14532d;
}
.op-ref-ic.is-viewer {
  background: #e8eefb;
  color: #1e3a8a;
}
.op-ref-ic.is-centre {
  background: #fdf0e3;
  color: #7c3a03;
}
.op-ref-ic.is-legacy {
  background: #eceff3;
  color: #374151;
}

.op-ref-detail {
  margin: 4px 0 12px;
}
.op-ref-detail-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 12px 0 4px;
}
.op-ref-detail-head h3 {
  margin: 0;
  font-size: 16px;
  color: var(--ink); /* 15.19:1 */
}
.op-ref-acts {
  white-space: nowrap;
}
@media (max-width: 600px) {
  .op-ref-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .op-ref-find {
    max-width: 100%;
  }
}

/* ── Plans editor + trial + per-add-on expiry ─────────────────────────────── */
.op-plan-form {
  margin-top: 12px;
  display: grid;
  gap: 10px;
}
.op-plan-mods {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 4px 12px;
  margin-bottom: 6px;
}
.op-check {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.9rem;
}
.op-check[hidden] {
  display: none;
}
.addon-expiry {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.78rem;
  opacity: 0.85;
  margin-top: 4px;
}
.addon-expiry input {
  padding: 2px 6px;
  font-size: 0.78rem;
  max-width: 150px;
}

/* ══════════════════════════════════════════════════════════════════════════════════
   CONSOLE SHELL (2026-09-30 redesign): left nav + one screen at a time.
   Colour pairs carry their measured contrast; the bar is WCAG AA (4.5:1 text,
   3:1 for focus rings and control borders).
   ══════════════════════════════════════════════════════════════════════════════════ */
.op-sr {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.op-skip {
  position: absolute;
  left: 8px;
  top: -40px;
  z-index: 100;
  padding: 8px 12px;
  border-radius: 8px;
  background: var(--ink); /* #fff on #1e2634 — 15.19:1 */
  color: #fff;
  font-weight: 700;
}
.op-skip:focus {
  top: 8px;
}
.op-shell {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  align-items: start;
  min-height: calc(100vh - 72px);
}
.op-shell > .op-nav[hidden] + .op-content {
  grid-column: 1 / -1;
}
.op-nav {
  position: sticky;
  top: 72px;
  align-self: start;
  padding: 18px 10px;
  max-height: calc(100vh - 72px);
  overflow-y: auto;
}
.op-nav[hidden] {
  display: none;
}
.op-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2px;
}
.op-nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 10px;
  color: var(--ink-soft); /* #43516a on the page background #eef2f7 — 7.1:1 */
  font-weight: 600;
  font-size: 14px;
  text-decoration: none;
}
.op-nav a i {
  width: 18px;
  text-align: center;
}
.op-nav a:hover {
  background: var(--card);
  color: var(--ink);
}
.op-nav a[aria-current='page'] {
  background: var(--card);
  color: #3446b8; /* on #fff — 7.3:1 */
  box-shadow: var(--shadow-sm);
}
.op-nav a:focus-visible,
.op-static-item:focus-visible,
.op-stat:focus-visible,
.op-tabs [role='tab']:focus-visible,
.op-sort:focus-visible {
  outline: 2px solid #3446b8;
  outline-offset: 2px;
}
.op-nav-toggle[hidden] {
  display: none !important;
}
.op-content {
  max-width: 1320px;
  width: 100%;
  margin: 0;
}
.op-content:focus {
  outline: none;
}
/* While a centre page is open the list screens are out of the way (they are also inert). */
#op-drawer:not([hidden]) ~ #op-main {
  display: none;
}
.op-screen {
  display: grid;
  gap: 16px;
  min-width: 0;
}
.op-screen[hidden] {
  display: none;
}
.op-screen-title {
  margin: 0;
  font-size: 20px;
  font-weight: 800;
  color: var(--ink); /* 15.19:1 on #fff; 13.4:1 on #eef2f7 */
}
.op-screen-title:focus {
  outline: none;
}
.op-screen > .sub-section,
.op-screen > .card {
  min-width: 0;
}
.op-banner {
  margin: 0;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  background: #e8eefb;
  color: #1e3a8a; /* 8.90:1 */
  font-size: 14px;
  line-height: 1.5;
}
.op-banner i {
  margin-right: 6px;
}

/* ── Dashboard ─────────────────────────────────────────────────────────────── */
.op-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
}
.op-stat {
  display: grid;
  gap: 2px;
  padding: 16px;
  border-radius: var(--radius-sm);
  background: var(--card);
  border: 1px solid var(--line);
  color: var(--ink);
  text-decoration: none;
  box-shadow: var(--shadow-sm);
}
.op-stat:hover {
  border-color: #b9c6dc;
}
.op-stat i {
  color: #3446b8;
  font-size: 16px;
}
.op-stat-n {
  font-size: 28px;
  font-weight: 800;
  line-height: 1.1;
}
.op-stat-l {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft); /* 8.00:1 */
}
.op-stat-s {
  font-size: 12px;
  color: var(--muted); /* 5.62:1 */
}
.op-list {
  margin: 0;
  padding-left: 18px;
  line-height: 1.7;
  font-size: 14px;
}
.op-links {
  margin: 0;
  padding-left: 18px;
  line-height: 1.8;
}

/* ── Tabs (centre page, grid Rows/Audit) ───────────────────────────────────── */
.op-tabs {
  display: flex;
  gap: 2px;
  overflow-x: auto;
  padding: 0 16px;
  border-bottom: 1px solid var(--line);
  background: var(--card);
}
.op-tabs [role='tab'] {
  flex: 0 0 auto;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 11px 14px;
  border: 0;
  border-bottom: 3px solid transparent;
  background: transparent;
  color: var(--ink-soft); /* 8.00:1 */
  cursor: pointer;
}
.op-tabs [role='tab'][aria-selected='true'] {
  color: #3446b8; /* 7.3:1 */
  border-bottom-color: #3446b8;
}
.op-tabs [role='tab']:disabled {
  cursor: default;
}
.op-tabs-sm {
  padding: 0;
  margin: 10px 0 12px;
  background: transparent;
}
.op-tabpanel[hidden] {
  display: none;
}

/* ── Pager ─────────────────────────────────────────────────────────────────── */
.op-pager {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 10px;
  font-size: 13px;
  color: var(--muted); /* 5.62:1 */
}
.op-pager:empty {
  display: none;
}
.op-pager-count {
  margin-right: auto;
}

/* ── In-page confirmation (no native confirm) ──────────────────────────────── */
.op-confirm {
  margin: 8px 0 12px;
  padding: 12px 14px;
  border: 1px solid #f0b4b4;
  border-left: 4px solid #b42318;
  border-radius: var(--radius-sm);
  background: #fef3f2;
}
.op-confirm p {
  margin: 0 0 6px;
  color: #7a271a; /* on #fef3f2 — 8.5:1 */
  font-weight: 600;
}
.op-btn-danger {
  background: #b42318; /* #fff on #b42318 — 6.5:1 */
  color: #fff;
  border: 1px solid #b42318;
}
.op-btn-danger:hover {
  background: #912018;
}

/* ── Switches: two colour-coded sub-tabs (#277 P7) ─────────────────────────────
   Global features = indigo (#3446b8, 7.3:1 on white), Parent portal = teal (#0f6b5c,
   6.6:1 on white). The tab, its panel's top rule and its section heading share the colour,
   so it is obvious at a glance which half of the screen is open. */
.op-switch-tabs {
  margin: 0 0 14px;
  padding: 0;
  background: transparent;
}
.op-switch-tabs [role='tab'] i {
  margin-right: 4px;
}
.op-switch-tabs [data-swtab='global'][aria-selected='true'] {
  color: #3446b8;
  border-bottom-color: #3446b8;
  background: rgba(52, 70, 184, 0.06);
}
.op-switch-tabs [data-swtab='parent'][aria-selected='true'] {
  color: #0f6b5c;
  border-bottom-color: #0f6b5c;
  background: rgba(15, 107, 92, 0.07);
}
.op-switch-panel > .card {
  border-top: 4px solid transparent;
}
.op-switch-panel.is-global > .card {
  border-top-color: #3446b8;
}
.op-switch-panel.is-parent > .card {
  border-top-color: #0f6b5c;
}
.op-switch-panel.is-global .sub-section-head h3 {
  color: #3446b8;
}
.op-switch-panel.is-parent .sub-section-head h3 {
  color: #0f6b5c;
}
#op-global-modules {
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
/* A card row: the switch (label) on top, its folded Impact below — outside the label, so
   opening Impact never toggles the switch. */
#op-global-modules .global-control-row,
#op-parent-controls .parent-control-row {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
}
.op-impact {
  margin: 0 2px;
  font-size: 12px;
  line-height: 1.45;
  color: #475569; /* 7.6:1 */
}
.op-impact > summary {
  cursor: pointer;
  width: fit-content;
  font-weight: 600;
  color: #334155; /* 10:1 */
}
.op-impact small {
  display: block;
  margin-top: 4px;
  font-size: 12px;
}
.op-bulk {
  margin: 4px 0 12px;
  padding: 10px 12px;
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
}
.op-bulk > summary {
  cursor: pointer;
  font-weight: 600;
}
.op-bulk-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 4px 12px;
  margin: 8px 0;
}
.op-on {
  color: #14532d; /* 9.2:1 on #fff */
}
.op-off {
  color: #9a3412; /* 7.3:1 on #fff */
}

/* ── Static data ───────────────────────────────────────────────────────────── */
.op-static {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}
.op-static-side {
  padding: 12px;
  position: sticky;
  top: 84px;
  max-height: calc(100vh - 100px);
  overflow-y: auto;
}
.op-static-side > .input {
  width: 100%;
  margin-bottom: 8px;
}
.op-static-group {
  margin: 14px 4px 4px;
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-soft); /* 8.00:1 */
}
.op-static-group span {
  display: block;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  color: var(--muted); /* 5.62:1 */
}
.op-static-items {
  list-style: none;
  margin: 0;
  padding: 0;
}
.op-static-item {
  display: grid;
  gap: 1px;
  padding: 7px 9px;
  border-radius: 8px;
  color: var(--ink);
  text-decoration: none;
}
.op-static-item:hover {
  background: var(--card-2);
}
.op-static-item[aria-current='page'] {
  background: #e8eefb;
  color: #1e3a8a; /* 8.90:1 */
}
.op-static-name {
  font-size: 13.5px;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.op-static-meta {
  font-size: 12px;
  color: var(--muted); /* 5.62:1 on #fff, 5.0:1 on #e8eefb */
}
.op-tag-edit {
  color: #14532d;
}
.op-static-main {
  min-width: 0;
}
.op-grid-tools {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  margin: 6px 0 10px;
}
.op-grid-tools[hidden] {
  display: none;
}
.op-grid-find {
  flex: 1 1 240px;
  max-width: 380px;
}
.op-grid-count {
  font-size: 13px;
  color: var(--muted);
  padding-bottom: 8px;
  margin-right: auto;
}
.op-grid th {
  vertical-align: bottom;
  white-space: nowrap;
}
.op-grid td {
  vertical-align: top;
  max-width: 360px;
  overflow-wrap: anywhere;
  font-size: 13px;
}
.op-grid td .input {
  min-width: 90px;
  width: 100%;
  font-size: 13px;
}
.op-grid-text {
  min-width: 240px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  white-space: pre-wrap;
}
.op-grid-new td,
.op-grid-editing td {
  background: #f5f8ff;
}
.op-sort {
  font: inherit;
  font-weight: 700;
  background: none;
  border: 0;
  padding: 0;
  color: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.op-sort i {
  color: var(--muted);
}
.op-col-type {
  display: block;
  font-size: 11px;
  font-weight: 500;
  color: var(--muted); /* 5.62:1 */
}
.op-null {
  color: var(--muted);
}
.op-subhead {
  margin: 14px 0 6px;
  font-size: 15px;
}
.op-inline-form {
  align-items: flex-end;
  flex-wrap: wrap;
}

/* ── #151 P8: static data density ──────────────────────────────────────────── */
/* The static screen uses the full width (the 1320px cap left ~40% of a 1920 screen empty
   and squeezed the grids); every other screen keeps the cap. operator.js markContentScreen. */
.op-content[data-screen='static'] {
  max-width: none;
}
/* Side-list groups fold; only the selected table's group (or a searched one) starts open. */
.op-static-grp > summary {
  cursor: pointer;
  border-radius: 6px;
}
.op-static-grp > summary:focus-visible {
  outline: 2px solid #3446b8;
  outline-offset: 2px;
}
.op-static-grp:not([open]) > summary {
  margin-bottom: 0;
}
/* Compact grid: each cell at most two lines; the full value is in the cell's title and in
   the edit form, which is never clamped. */
.op-grid.is-compact td .op-cell {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.op-grid.is-compact td {
  padding-top: 6px;
  padding-bottom: 6px;
}
.op-grid-compact {
  padding-bottom: 8px;
  font-size: 13px;
  white-space: nowrap;
}

/* ── #151 P9: AI starter prompts as two compact card columns ───────────────── */
.op-ai-viewbar {
  display: flex;
  gap: 8px;
  margin-bottom: 10px;
}
.op-ai-tiers {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  align-items: start;
}
.op-ai-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 6px;
}
.op-ai-card {
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--card);
  min-width: 0;
}
.op-ai-card.is-off {
  background: var(--card-2);
}
.op-ai-card-head {
  font-size: 13.5px;
}
.op-ai-card-text {
  font-size: 13px;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.op-ai-card-meta {
  font-size: 11.5px;
  color: var(--muted); /* 5.62:1 */
  overflow-wrap: anywhere;
}

/* ── Small screens ─────────────────────────────────────────────────────────── */
@media (max-width: 1100px) {
  .op-ai-tiers {
    grid-template-columns: minmax(0, 1fr);
  }
}
@media (max-width: 900px) {
  .op-shell {
    grid-template-columns: minmax(0, 1fr);
  }
  .op-nav {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: 260px;
    max-height: none;
    z-index: 70;
    background: var(--card);
    box-shadow: var(--shadow-lg);
    transform: translateX(-105%);
    transition: transform 0.18s ease;
  }
  .op-nav.is-open {
    transform: none;
  }
  .op-static {
    grid-template-columns: minmax(0, 1fr);
  }
  .op-static-side {
    position: static;
    max-height: 320px;
  }
}
@media (min-width: 901px) {
  .op-nav-toggle {
    display: none !important;
  }
}
@media (prefers-reduced-motion: reduce) {
  .op-nav {
    transition: none;
  }
}

/* ---- forms.css pattern (#205) ------------------------------------------------------------
   Fields and labels come from the theme.css bridge in /shared/styles/forms.css (linked just
   before this sheet). Here: the two forms that sit INSIDE a list card — "Add a center" and
   the subscription-plan editor — get their own bordered panel with an accent edge, so the
   form reads as a separate section and not as more rows of the table above it. */
.op-newcentre,
.op-plan-form {
  margin-top: var(--kf-gap);
  padding: 16px 20px 20px;
  background: var(--kf-card);
  border: 1px solid var(--kf-section-border);
  border-left: 4px solid var(--kf-tone, var(--kf-accent));
  border-radius: var(--kf-radius);
}
/* #277 colour-coded sections: the in-card forms cycle the forms.css tones; the "Add a
   center" / "Add an operator" summary sits on the tone's tint. Title text stays --kf-ink. */
.op-newcentre:nth-of-type(5n + 1),
.op-plan-form:nth-of-type(5n + 1) {
  --kf-tone: var(--kf-tone-indigo);
  --kf-tone-tint: var(--kf-tint-indigo);
}
.op-newcentre:nth-of-type(5n + 2),
.op-plan-form:nth-of-type(5n + 2) {
  --kf-tone: var(--kf-tone-teal);
  --kf-tone-tint: var(--kf-tint-teal);
}
.op-newcentre:nth-of-type(5n + 3),
.op-plan-form:nth-of-type(5n + 3) {
  --kf-tone: var(--kf-tone-green);
  --kf-tone-tint: var(--kf-tint-green);
}
.op-newcentre:nth-of-type(5n + 4),
.op-plan-form:nth-of-type(5n + 4) {
  --kf-tone: var(--kf-tone-orange);
  --kf-tone-tint: var(--kf-tint-orange);
}
.op-newcentre:nth-of-type(5n + 5),
.op-plan-form:nth-of-type(5n + 5) {
  --kf-tone: var(--kf-tone-sky);
  --kf-tone-tint: var(--kf-tint-sky);
}
.op-newcentre > summary {
  background: var(--kf-tone-tint, transparent);
  padding: 8px 12px;
  border-radius: 8px;
}
.op-newcentre > summary {
  font-size: 15px;
  font-weight: 800;
  color: var(--kf-ink);
}
.op-newcentre .sub-plan-desc {
  color: var(--kf-help);
  margin: 8px 0 0;
  max-width: 72ch;
}
.op-newcentre-grid {
  gap: 18px 22px;
  margin-top: 16px;
}
.op-plan-form {
  gap: 18px;
}
.op-plan-form .op-plan-row {
  position: sticky;
  bottom: 0;
  z-index: 5;
  background: #fff;
  padding: 12px 0 4px;
  border-top: 1px solid var(--kf-divider);
}

/* ── Activity: three colour-coded sub-tabs (277 P10) ───────────────────────────
   Same pattern as Switches: the tab, its panel's top rule and its heading share a colour.
   Registrations = indigo #3446b8 (7.3:1 on white), Texting routes = teal #0f6b5c (6.6:1),
   Basic chat use = orange #9a4a00 (6.2:1). */
.op-act-tabs {
  margin: 0 0 14px;
  padding: 0;
  background: transparent;
}
.op-act-tabs [role='tab'] i {
  margin-right: 4px;
}
.op-act-tabs [data-actab='registrations'][aria-selected='true'] {
  color: #3446b8;
  border-bottom-color: #3446b8;
  background: rgba(52, 70, 184, 0.06);
}
.op-act-tabs [data-actab='texting'][aria-selected='true'] {
  color: #0f6b5c;
  border-bottom-color: #0f6b5c;
  background: rgba(15, 107, 92, 0.07);
}
.op-act-tabs [data-actab='chat'][aria-selected='true'] {
  color: #9a4a00;
  border-bottom-color: #9a4a00;
  background: rgba(154, 74, 0, 0.07);
}
.op-act-panel > .card {
  border-top: 4px solid transparent;
}
.op-act-panel.is-registrations > .card {
  border-top-color: #3446b8;
}
.op-act-panel.is-texting > .card {
  border-top-color: #0f6b5c;
}
.op-act-panel.is-chat > .card {
  border-top-color: #9a4a00;
}
.op-act-panel.is-registrations .sub-section-head h3 {
  color: #3446b8;
}
.op-act-panel.is-texting .sub-section-head h3 {
  color: #0f6b5c;
}
.op-act-panel.is-chat .sub-section-head h3 {
  color: #9a4a00;
}
.op-act-sub {
  margin: 14px 0 6px;
  font-size: 14px;
}
.op-act-pager {
  align-items: center;
  gap: 10px;
  margin-top: 8px;
}

/* ── Bugs & requests (#/feedback, owner 2026-10-12; operator/feedback.js) ─────────────── */
.fb-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  background: #eef2f7;
  color: #334155;
}
.fb-bug {
  background: #fef2f2;
  color: #b91c1c;
}
.fb-feature {
  background: #f0fdf4;
  color: #15803d;
}
.fb-st-new {
  background: #dbeafe;
  color: #1d4ed8;
}
.fb-st-in_progress {
  background: #fef3c7;
  color: #92400e;
}
.fb-st-done {
  background: #dcfce7;
  color: #166534;
}
.fb-dl {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 4px 14px;
  margin: 8px 0;
}
.fb-dl dt {
  font-weight: 600;
}
.fb-dl dd {
  margin: 0;
  word-break: break-word;
}
.fb-text {
  white-space: pre-wrap;
}
.fb-notes textarea {
  width: 100%;
}
.fb-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}
/* Bugs & requests: attachments (owner 2026-10-12). */
.fb-atts {
  list-style: none;
  margin: 6px 0 12px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.fb-att {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-width: 180px;
  font-size: 12px;
  word-break: break-all;
}
.fb-att-img img {
  width: 170px;
  height: 120px;
  object-fit: cover;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  background: #f1f5f9;
}
/* ── Centers behind on sync (Dashboard card + nav count; syncBehind.js) ─────── */
.op-sync-behind {
  margin: 14px 0;
  border-left: 4px solid #d64545;
}
.op-sync-behind h3 {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 8px;
}
.op-sync-behind h3 i {
  color: #b42318;
}
.op-sync-count,
.op-nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 7px;
  border-radius: 999px;
  background: #b42318;
  color: #fff;
  font-size: 12px;
  font-weight: 800;
  line-height: 1;
}
.op-sync-count.is-zero {
  background: #1f7a45;
}
.op-sync-count[hidden],
.op-nav-badge[hidden] {
  display: none;
}
.op-nav-badge {
  margin-left: auto;
}
.op-sync-behind-list li {
  overflow-wrap: anywhere;
}
.op-sync-never {
  color: #b42318;
}
.op-sync-runner {
  color: var(--muted);
}

/* ── AI costs (#/ai-costs, aiCosts.js) ─────────────────────────────────────── */
/* Filters, prices and the clear row wrap at phone width instead of widening the page. */
.aic-filters,
#scr-ai-costs .op-plan-row {
  flex-wrap: wrap;
  align-items: flex-end;
}
#scr-ai-costs .op-plan-row .field {
  min-width: 0;
}
.aic-stats {
  margin: 12px 0;
}
.aic-stat-loss {
  border-color: var(--danger, #c0392b);
}
.aic-loss {
  color: var(--danger, #c0392b);
  font-weight: 700;
}
.aic-gain {
  color: #1d7a3e; /* 5.3:1 on #fff */
  font-weight: 600;
}
.aic-sub {
  font-size: 12px;
  color: var(--muted);
}
.aic-table td {
  vertical-align: top;
  white-space: nowrap;
}
.aic-num {
  width: 7.5em;
}

/* Center support: a revealed registration code (owner 2026-10-17, support.js). */
.op-regcode-value {
  font-size: 2rem;
  letter-spacing: 0.2em;
  margin: 0.25rem 0;
}
