/* Reusable pieces: cards, tiles, pills, tables, toolbars, modal, forms, toast. */

/* ---------- cards / tiles ---------- */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow); }
.card-h { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.card-h h2 { margin: 0; font-size: 14.5px; }
.card-h .sub { font-size: 12px; color: var(--muted); }
.card-b { padding: 16px 18px; }

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; }
.tile { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 14px 16px; box-shadow: var(--shadow); }
.tile .t-label { font-size: 12px; color: var(--muted); }
.tile .t-value { font-size: 24px; font-weight: 600; margin-top: 2px; }
.tile .t-sub { font-size: 12px; color: var(--ink-2); margin-top: 2px; }
.tile .t-sub .up { color: var(--good-text); font-weight: 600; }

.grid-2 { display: grid; grid-template-columns: 3fr 2fr; gap: 18px; align-items: start; }
@media (max-width: 1100px) { .grid-2 { grid-template-columns: 1fr; } }

/* ---------- dashboard date range bar (one range, every card) ---------- */
.rangebar { row-gap: 6px; }
.rangebar .rb-label { font-size: 12.5px; color: var(--muted); }
.rangebar input[type='date'] { width: auto; }
/* The resolved period, so a preset still says which days it means. */
.rangebar .sub { font-size: 12px; color: var(--muted); margin-left: 2px; }

/* ---------- status pills (label + dot — never color alone) ---------- */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; padding: 2px 9px; border-radius: 999px;
  background: var(--page); border: 1px solid var(--grid); color: var(--ink-2); white-space: nowrap;
}
.pill::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--muted); }
.pill.good::before { background: var(--good); }
.pill.warn::before { background: var(--warning); }
.pill.serious::before { background: var(--serious); }
.pill.crit::before { background: var(--critical); }
.pill.info::before { background: var(--series); }

/* ---------- tables ---------- */
.tablewrap { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: 13px; }
table.data th {
  text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.4px;
  color: var(--muted); font-weight: 600; padding: 8px 12px; border-bottom: 1px solid var(--grid); white-space: nowrap;
}
table.data td { padding: 9px 12px; border-bottom: 1px solid var(--grid); vertical-align: middle; }
table.data tr:last-child td { border-bottom: none; }
table.data tbody tr.rowlink { cursor: pointer; }
table.data tbody tr.rowlink:hover { background: var(--page); }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }
.empty { padding: 28px; text-align: center; color: var(--muted); }
.row-actions { white-space: nowrap; }
.row-actions .btn + .btn { margin-left: 6px; }

/* ---------- sales-history table (Orders / Enrollments) ---------- */
table.data th.sortable { cursor: pointer; user-select: none; }
table.data th.sortable:hover { color: var(--ink); }
table.data th.sortable:focus-visible { outline: 2px solid var(--series); outline-offset: -2px; }
.sortdir { font-size: 11px; }
.sortdir.off { opacity: 0.35; }

/* expander column: fixed width so the first real column doesn't shift */
table.data th.cell-x, table.data td.cell-x { width: 34px; padding-right: 0; }
.iconbtn {
  display: inline-flex; align-items: center; justify-content: center; padding: 2px;
  background: none; border: none; border-radius: 50%; color: var(--series); cursor: pointer;
}
.iconbtn:hover { background: var(--series-wash); }
.iconbtn:focus-visible { outline: 2px solid var(--series); outline-offset: 1px; }

/* the row's own details, opened in place rather than in a modal */
table.data tr.rowdetail > td { background: var(--page); padding: 12px 16px 14px 46px; }
/* Label/value pairs wrap as whole units — never a label on one line and its
   value on the next, which is what a flat dt/dd grid does at narrow widths. */
.kvgrid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 0 28px; margin: 0; font-size: 12.5px;
}
.kvgrid > div { display: flex; gap: 12px; padding: 6px 2px; border-bottom: 1px solid var(--grid); }
.kvgrid dt { flex: none; min-width: 108px; color: var(--muted); }
.kvgrid dd { margin: 0; min-width: 0; word-break: break-word; }

/* table tools row: page size on the left, export/columns on the right */
.tbl-tools { width: 100%; margin-top: 10px; }
.tbl-spacer { flex: 1; }
.pagesize { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--muted); }
.pagesize select { width: auto; padding: 4px 8px; font-size: 12.5px; }

.colvis { position: relative; }
.colvis > summary { list-style: none; }
.colvis > summary::-webkit-details-marker { display: none; }
.colvis-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 20; min-width: 190px;
  display: flex; flex-direction: column; gap: 2px; padding: 8px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow);
}
.colvis-menu label {
  display: flex; align-items: center; gap: 8px; padding: 5px 8px; border-radius: 6px;
  font-size: 12.5px; cursor: pointer; white-space: nowrap;
}
.colvis-menu label:hover { background: var(--page); }
.colvis-menu input { width: auto; flex: none; margin: 0; }

/* the invoice document, shown inside the modal exactly as it prints */
.invoice-frame { width: 100%; height: min(70vh, 900px); border: 1px solid var(--border); border-radius: 8px; background: #fff; }

/* ---------- product tick-picker ---------- */
.field-label { display: block; font-size: 12.5px; color: var(--ink-2); font-weight: 500; margin-bottom: 5px; }
.pp { display: flex; flex-direction: column; gap: 6px; }
/* Platform / Category / SubCategory trio above the search box */
.pp-filters { display: flex; gap: 6px; flex-wrap: wrap; }
.pp-filters select { flex: 1; min-width: 120px; }
.pp-list { border: 1px solid var(--baseline); border-radius: 8px; max-height: 200px; overflow-y: auto; padding: 4px; background: var(--page); }
/* .pp .pp-item outranks .form-grid label (which is a column flex) */
.pp .pp-item {
  display: flex; flex-direction: row; align-items: center; gap: 8px; padding: 5px 8px;
  border-radius: 6px; cursor: pointer; font-size: 12.5px; font-weight: 400; color: var(--ink);
}
.pp .pp-item:hover { background: var(--series-wash); }
.pp .pp-item[hidden] { display: none; }
.pp .pp-item input { width: auto; flex: none; margin: 0; }

/* What is ticked, listed separately above the options (ui/pickers renderTray).
   Deliberately NOT capped in height the way .pp-list is: this is the answer to
   "what is in this bundle?", and a bundle with nine components is a bundle
   whose ninth component must not be behind a second scrollbar. It is bounded
   by how much was ticked, which is bounded by what a bundle sensibly holds. */
.pp-tray { display: flex; flex-direction: column; gap: 5px; }
.pp-tray .field-label { margin-bottom: 0; }
.pp-tray-list { display: flex; flex-wrap: wrap; gap: 5px; list-style: none; margin: 0; padding: 0; }
.pp-tray-item {
  display: flex; align-items: center; gap: 6px; padding: 4px 4px 4px 9px;
  border: 1px solid var(--baseline); border-radius: 999px; background: var(--series-wash);
  font-size: 12.5px; color: var(--ink);
}
.pp-tray-x {
  display: flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; padding: 0; flex: none;
  border: 0; border-radius: 50%; background: transparent;
  color: var(--ink-2); font-size: 11px; line-height: 1; cursor: pointer;
}
.pp-tray-x:hover { background: var(--critical); color: #fff; }

/* ---------- badge editor (ui/tagField.js) ----------
   Credentials and card highlights. The box looks like one input because that
   is what it replaced, and the chips sit INSIDE it so the field reads as one
   control rather than a list with a text box under it. */
.tagf { display: flex; flex-direction: column; }
.tagf-box {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
  border: 1px solid var(--baseline); border-radius: 8px; padding: 5px 6px;
  background: var(--page); cursor: text;
}
.tagf-box:focus-within { outline: 2px solid var(--series); outline-offset: -1px; }
.tagf-chips { display: contents; list-style: none; margin: 0; padding: 0; }
.tagf-chip {
  display: flex; align-items: center; gap: 5px; padding: 3px 3px 3px 8px;
  border-radius: 999px; background: var(--series-wash); color: var(--ink);
  font-size: 12.5px; line-height: 1.5;
}
/* Sized in `em` so the glyph tracks the chip's text rather than a fixed px
   that a browser zoom or a Bengali line-height would leave sitting wrong. */
.tagf-chip .tag-ico { width: 1.15em; height: 1.15em; flex: none; opacity: 0.75; }
.tagf-x {
  display: flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; padding: 0; flex: none;
  border: 0; border-radius: 50%; background: transparent;
  color: var(--ink-2); font-size: 11px; line-height: 1; cursor: pointer;
}
.tagf-x:hover { background: var(--critical); color: #fff; }
/* The typing box is the rest of the row: it grows to fill, and wraps to its
   own line once the chips have taken the width. */
.tagf .tagf-input {
  flex: 1 1 9rem; min-width: 9rem; width: auto; margin: 0;
  border: 0; background: transparent; padding: 3px 2px; font-size: 12.5px;
}
.tagf .tagf-input:focus { outline: none; }
.tagf .tagf-input:disabled { cursor: not-allowed; }
.tagf-note { margin-top: 4px; }

/* ---------- offer field (ui/offerField.js) ----------
   A promotional line and the window it runs in. The note under it states what
   will actually happen — scheduled, showing, or finished — because a pair of
   dates is not something a reader should have to check against today. */
.offerf { display: flex; flex-direction: column; }
.offerf-dates { display: flex; gap: 8px; margin-top: 6px; }
.offerf-dates label { flex: 1; min-width: 0; }
.offerf-note { margin-top: 5px; font-weight: 500; }
.offerf-note[data-tone='good'] { color: var(--good-text); }
.offerf-note[data-tone='warn'] { color: var(--serious); }
.offerf-note[data-tone='bad'] { color: var(--critical); }

/* cycles editor (cycle-based courses): one row per sellable cycle */
.cyc-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 4px 0 8px; }
.cyc-head .btn { flex: none; white-space: nowrap; }
.cyc-rows { display: flex; flex-direction: column; gap: 6px; }
.cyc-row { display: grid; grid-template-columns: 1.1fr 1.4fr 0.8fr 1fr 1fr 0.9fr auto; gap: 6px; align-items: center; }
.cyc-row input, .cyc-row select { width: 100%; min-width: 0; font-size: 12.5px; padding: 6px 8px; }
.cyc-row .cyc-del { padding: 4px 9px; line-height: 1.1; }
/* a row's validation message sits under the whole row, not under one column */
.cyc-row .f-err { grid-column: 1 / -1; }
.cyc-row :is(input, select).invalid { border-color: var(--critical); }
.cyc-row :is(input, select).invalid:focus { outline-color: var(--critical); }
@media (max-width: 760px) {
  /* Seven controls can't share a phone row — each cycle becomes a small card
     on an explicit grid, so nothing is squeezed to an unreadable stub. */
  .cyc-row {
    grid-template-columns: 1fr 1fr; gap: 6px;
    padding: 8px; border: 1px solid var(--grid); border-radius: 8px;
  }
  .cyc-row .cyc-name { grid-area: 1 / 1 / 2 / -1; }
  .cyc-row .cyc-label { grid-area: 2 / 1 / 3 / -1; }
  .cyc-row .cyc-price { grid-area: 3 / 1; }
  .cyc-row .cyc-status { grid-area: 3 / 2; }
  .cyc-row .cyc-start { grid-area: 4 / 1; }
  .cyc-row .cyc-end { grid-area: 4 / 2; }
  .cyc-row .f-err { grid-area: 5 / 1 / 6 / -1; }
  .cyc-row .cyc-del { grid-area: 6 / 1 / 7 / -1; justify-self: end; }
}

/* per-item copies rows (bundle contents) — row layout despite .form-grid label */
#f-qty-rows { display: flex; flex-direction: column; gap: 6px; }
#f-qty-rows .qty-row {
  display: flex; flex-direction: row; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 400; color: var(--ink);
}
#f-qty-rows .qty-row input { width: 64px; flex: none; }

/* ---------- rich text editor (ui/richText.js) ----------
   Product descriptions and instructor bios. The body is styled like the page
   it will be published on rather than like a form control: what a merchant is
   writing is a document, and headings that look like headings while being
   typed are the whole point of a WYSIWYG field. */
.rte { display: flex; flex-direction: column; gap: 0; }
.rte-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 2px;
  padding: 4px 5px; background: var(--page);
  border: 1px solid var(--baseline); border-bottom: 0; border-radius: 8px 8px 0 0;
}
.rte-b {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 28px; height: 28px; padding: 0 6px;
  border: 1px solid transparent; border-radius: 6px; background: none;
  color: var(--ink-2); font: inherit; font-size: 12.5px; line-height: 1; cursor: pointer;
}
.rte-b:hover { background: var(--series-wash); color: var(--ink); }
.rte-b.on { background: var(--series-wash); border-color: var(--series); color: var(--ink); }
.rte-b svg { display: block; }
.rte-sep { width: 1px; height: 18px; background: var(--grid); margin: 0 4px; }
/* the link prompt: part of the field, because the dashboard has ONE <dialog>
   and this editor is already inside it — opening another would close the form */
.rte-link {
  display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
  padding: 6px; background: var(--series-wash);
  border: 1px solid var(--baseline); border-bottom: 0;
}
.rte-link input { flex: 1; min-width: 160px; }
.rte-link .btn { flex: none; }
.rte-body {
  padding: 10px 12px; background: var(--surface); color: var(--ink);
  border: 1px solid var(--baseline); border-radius: 0 0 8px 8px;
  font-size: 13.5px; line-height: 1.6; overflow-y: auto; max-height: 46vh;
}
.rte-body:focus { outline: 2px solid var(--series); outline-offset: -2px; }
.rte-body > :first-child { margin-top: 0; }
.rte-body > :last-child { margin-bottom: 0; }
.rte-body :is(h2, h3, h4) { margin: 14px 0 6px; line-height: 1.3; }
.rte-body h2 { font-size: 17px; }
.rte-body h3 { font-size: 15px; }
.rte-body h4 { font-size: 13.5px; }
.rte-body p { margin: 0 0 10px; }
.rte-body :is(ul, ol) { margin: 0 0 10px; padding-left: 22px; }
.rte-body li { margin: 2px 0; }
.rte-body blockquote {
  margin: 0 0 10px; padding: 2px 0 2px 12px;
  border-left: 3px solid var(--baseline); color: var(--ink-2);
}
.rte-body a { color: var(--series); }
.rte-body img { max-width: 100%; height: auto; border-radius: 6px; }
.rte-body table { border-collapse: collapse; margin: 0 0 10px; }
.rte-body :is(th, td) { border: 1px solid var(--grid); padding: 4px 8px; text-align: left; }
.rte-body pre { background: var(--page); padding: 8px 10px; border-radius: 6px; overflow-x: auto; }
.rte-source {
  width: 100%; min-height: 160px; resize: vertical;
  border: 1px solid var(--baseline); border-radius: 0 0 8px 8px;
  font-family: var(--mono); font-size: 12px; line-height: 1.5;
}
.rte-count { margin-top: 5px; }

/* ---------- promo video (ui/videoField.js) ----------
   A poster and a play badge, not a player: the iframe is only created when
   the poster is clicked, so opening a course editor costs one thumbnail
   instead of loading YouTube on behalf of whoever opened it. */
.vid-preview { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; margin-top: 8px; }
/* The frame keeps its shape whether or not the thumbnail loads: YouTube
   serves none for a private or deleted video, and a collapsed hairline reads
   as a broken preview rather than as the bad link it actually is. */
.vid-poster {
  position: relative; display: block; padding: 0; border: 1px solid var(--baseline);
  border-radius: 10px; overflow: hidden; background: var(--grid); cursor: pointer; line-height: 0;
  width: 260px; max-width: 100%; aspect-ratio: 16 / 9;
}
.vid-poster img { display: block; width: 100%; height: 100%; object-fit: cover; }
.vid-poster:hover { border-color: var(--series); }
.vid-play {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 28px; text-shadow: 0 1px 6px rgba(0, 0, 0, 0.6);
  background: rgba(0, 0, 0, 0.18); line-height: 1;
}
.vid-frame { width: min(480px, 100%); aspect-ratio: 16 / 9; border: 0; border-radius: 10px; }

/* ---------- syllabus / routine link (ui/docField.js) ----------
   The link says what it resolved to and offers to show it. An image previews
   itself; a Drive file or a Sheet is framed only when asked, because the
   question a staff member has ("can anyone outside the office open this?") is
   worth a click and not worth loading on every form open. */
.doc-preview { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; margin-top: 8px; }
.doc-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 12.5px; }
.doc-img {
  max-width: min(420px, 100%); height: auto; border: 1px solid var(--border);
  border-radius: 10px; display: block;
}
.doc-frame {
  width: min(560px, 100%); height: 320px; border: 1px solid var(--baseline);
  border-radius: 10px; background: var(--page);
}

/* ---------- FAQ editor (ui/faqField.js) ----------
   One card per question, each answer its own small rich-text editor. The
   arrows move the ROW element rather than re-rendering the list, so an
   answer's editor keeps its content and its undo history when it is moved. */
.faq-rows { display: flex; flex-direction: column; gap: 10px; }
.faq-row { padding: 10px; border: 1px solid var(--grid); border-radius: 10px; background: var(--page); }
.faq-row-h { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.faq-row-h .faq-q { flex: 1; min-width: 0; font-weight: 500; }
.faq-row-actions { display: flex; gap: 4px; flex: none; }
.faq-row-actions .btn { padding: 4px 9px; line-height: 1.1; }
.faq-row .rte-body { max-height: 30vh; }

/* ---------- toolbar / filters / pager ---------- */
.toolbar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.toolbar input[type='search'], .toolbar input[type='text'] { width: 220px; }
.toolbar select { width: auto; }
.pager { display: flex; gap: 8px; align-items: center; justify-content: flex-end; padding: 10px 14px; font-size: 12.5px; color: var(--muted); }

/* ---------- modal + forms ---------- */
dialog#modal {
  border: none; border-radius: 14px; background: var(--surface); color: var(--ink);
  box-shadow: var(--shadow); padding: 0; width: min(560px, 92vw); max-height: 88vh;
  overflow: hidden; /* the body is the only scroll region — never the dialog itself */
}
/* [open] so the UA's display:none for closed dialogs still applies. Flex column
   lets the body shrink to the 88vh cap while header/footer stay fixed. */
dialog#modal[open] { display: flex; flex-direction: column; }
dialog#modal.modal-wide { width: min(880px, calc(100vw - 16px)); }
dialog#modal::backdrop { background: rgba(0, 0, 0, 0.45); }
.modal-h { flex: none; display: flex; justify-content: space-between; align-items: center; padding: 14px 18px; border-bottom: 1px solid var(--border); }
.modal-h h2 { margin: 0; font-size: 15px; }
.modal-b { padding: 16px 18px; overflow-y: auto; min-height: 0; }
.modal-f { flex: none; display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 8px; padding: 12px 18px; border-top: 1px solid var(--border); }
/* why a save was refused, pinned beside the button that refused it — a long
   server message wraps rather than squeezing the buttons it sits next to */
.modal-f .btn { flex: none; }
.modal-f .f-err { flex: 1 1 auto; min-width: 0; margin-right: auto; text-align: left; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.form-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
.form-grid .full { grid-column: 1 / -1; }
.form-grid label { display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; color: var(--ink-2); font-weight: 500; }
.form-grid label.check { flex-direction: row; align-items: center; gap: 8px; }
.form-grid label.check input { width: auto; }

/* form sections (grouped fields with a small heading) */
.fset { border-top: 1px solid var(--grid); padding-top: 14px; margin-top: 16px; }
.fset:first-child { border-top: none; padding-top: 0; margin-top: 0; }
.fset[hidden] { display: none; }
.fset-t {
  margin: 0 0 10px; font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.6px; color: var(--muted);
}
.hint { font-size: 11.5px; font-weight: 400; color: var(--muted); }

/* toggle switch (styled checkbox) */
label.switch { display: flex; flex-direction: row; align-items: center; gap: 9px; align-self: center; cursor: pointer; }
label.switch input {
  appearance: none; -webkit-appearance: none; flex: none;
  width: 36px; height: 20px; padding: 0; margin: 0; border: none; border-radius: 999px;
  background: var(--baseline); position: relative; cursor: pointer; transition: background 0.15s;
}
label.switch input::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); transition: transform 0.15s;
}
label.switch input:checked { background: var(--series); }
label.switch input:checked::after { transform: translateX(16px); }
label.switch input:focus-visible { outline: 2px solid var(--series); outline-offset: 2px; }

/* thumbnail preview inside forms */
.thumb-prev {
  height: 64px; width: auto; max-width: 100%; align-self: flex-start;
  border-radius: 8px; margin-top: 6px; border: 1px solid var(--border); display: block;
}
.thumb-row { display: flex; align-items: center; gap: 12px; }
.thumb-row .thumb-prev { margin-top: 0; }

/* ---------- settings ---------- */
.settings-t { margin: 0 0 4px; font-size: 16px; }
.settings-d { margin: 4px 0; font-size: 13px; }
/* Qualified with `label.switch` so it outranks that rule's align-self/gap —
   a setting toggle is a full-width row, not a centred inline switch. */
label.switch.setting-toggle {
  justify-content: space-between; gap: 14px; font-size: 13px; align-self: stretch;
  border: 1px solid var(--border); background: var(--page); border-radius: 10px; padding: 12px 14px;
}
.setting-toggle-text { display: flex; flex-direction: column; gap: 2px; }
/* Multi-line settings (origin lists, the Apple Pay domain-association blob):
   monospace so long opaque strings can be checked character by character. */
.form-grid textarea {
  font-family: var(--mono);
  font-size: 12px; line-height: 1.5; resize: vertical; min-height: 72px;
}
.settings-actions { display: flex; gap: 8px; margin: 16px 0 0; flex-wrap: wrap; align-items: center; }
.settings-actions .spacer { flex: 1; }
.diag-row { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.diag-row input { width: 220px; max-width: 100%; }
/* rendered email preview (sandboxed; solid white since emails assume light) */
.email-frame { width: 100%; height: 58vh; border: 1px solid var(--border); border-radius: 10px; background: #fff; }

/* ---- health strip: what is live, what needs a look ---- */
.set-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: 10px; }
.set-stat {
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  padding: 12px 14px; box-shadow: var(--shadow);
}
.set-stat .n { font-size: 22px; font-weight: 600; line-height: 1.2; font-variant-numeric: tabular-nums; }
.set-stat .l { font-size: 12px; color: var(--muted); margin-top: 2px; }

.set-flags { display: flex; flex-direction: column; gap: 8px; }
.set-flag {
  display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; font-size: 13px;
  border: 1px solid var(--border); border-left-width: 3px; border-radius: 10px; background: var(--page);
}
.set-flag .ico { flex: none; display: flex; margin-top: 1px; color: var(--muted); }
.set-flag.crit { border-left-color: var(--critical); }
.set-flag.crit .ico { color: var(--critical); }
.set-flag.warn { border-left-color: var(--warning); }
.set-flag.warn .ico { color: var(--warning); }
.set-flag.info { border-left-color: var(--series); }
.set-flag.info .ico { color: var(--series); }
.set-flag div { flex: 1; min-width: 0; }
.set-flag strong { font-weight: 600; }
.set-flag .btn { flex: none; }

/* ---- toolbar: search + bulk accordion control ---- */
.set-bar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.set-find { position: relative; flex: 1 1 240px; max-width: 380px; }
.set-find > .ico {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  display: flex; color: var(--muted); pointer-events: none;
}
.set-find input { padding-left: 35px; padding-right: 34px; }
/* We draw our own clear button — hide the UA's so there aren't two. */
.set-find input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.set-find .set-find-x {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  border: none; background: none; color: var(--muted); cursor: pointer; font-size: 15px;
  line-height: 1; padding: 4px 6px; border-radius: 6px;
}
.set-find .set-find-x:hover { color: var(--ink); background: var(--page); }
.set-count { font-size: 12.5px; color: var(--muted); margin-left: auto; }

/* ---- rail + groups ---- */
.set-layout { display: grid; grid-template-columns: 208px 1fr; gap: 18px; align-items: start; }
.set-rail { position: sticky; top: 14px; display: flex; flex-direction: column; gap: 2px; }
.set-rail button {
  font: inherit; text-align: left; cursor: pointer; display: flex; align-items: center; gap: 9px;
  padding: 8px 10px; border-radius: 8px; border: 1px solid transparent; background: none;
  color: var(--ink-2); font-size: 13px; font-weight: 500;
}
.set-rail button .ico { width: 18px; flex: none; display: inline-flex; color: var(--muted); }
.set-rail button:hover { background: var(--page); color: var(--ink); }
.set-rail button.active { background: var(--series-wash); color: var(--series); }
.set-rail button.active .ico { color: var(--series); }
.set-rail button .n { margin-left: auto; font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.set-rail button[hidden] { display: none; }

.set-groups { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.set-sec { display: flex; flex-direction: column; gap: 10px; scroll-margin-top: 14px; }
.set-sec[hidden] { display: none; }
.set-sec-h { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; padding: 4px 2px 0; }
.set-sec-h h2 { margin: 0; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.6px; color: var(--muted); }
.set-sec-h span { font-size: 12px; color: var(--muted); }

/* one collapsible card per setting group */
.sgroup {
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: var(--shadow); scroll-margin-top: 14px;
}
.sgroup[hidden] { display: none; }
.sgroup.is-dirty { border-color: var(--warning); }
.sgroup > summary {
  display: flex; align-items: center; gap: 12px; padding: 13px 16px; cursor: pointer;
  list-style: none; border-radius: 12px;
}
.sgroup > summary::-webkit-details-marker { display: none; }
.sgroup > summary:hover { background: var(--page); }
.sgroup > summary:focus-visible { outline: 2px solid var(--series); outline-offset: -2px; }
.sgroup[open] > summary { border-radius: 12px 12px 0 0; }
.sgroup-chev { flex: none; display: flex; color: var(--muted); transition: transform 0.15s; }
.sgroup[open] .sgroup-chev { transform: rotate(90deg); }
.sgroup-id { display: flex; flex-direction: column; min-width: 0; flex: 1; gap: 1px; }
.sgroup-id strong { font-size: 14px; }
.sgroup-id span { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sgroup-tags { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; flex: none; }
.sgroup-b { padding: 14px 16px 16px; border-top: 1px solid var(--grid); }
.sgroup-b > .settings-d:first-child { margin-top: 0; }
.sgroup-meta { font-size: 11.5px; color: var(--muted); margin: 10px 0 0; }

/* ---- fields: chips, inline errors, secret reveal ---- */
.set-toggles { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.set-toggles:empty { display: none; }
.fld-l { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* ⓘ: a label reads as a label, and everything explanatory about the field —
   what it does, its env var, whether it is required — waits behind this. */
.fld-i {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  padding: 2px; margin: 0; border: none; background: none; line-height: 0;
  color: var(--muted); cursor: pointer; border-radius: 50%;
}
.fld-i svg { width: 14px; height: 14px; }
.fld-i:hover { color: var(--ink); background: var(--page); }
.fld-i.on { color: var(--series); background: var(--series-wash); }
.fld-i:focus-visible { outline: 2px solid var(--series); outline-offset: 1px; }
.fld-info {
  display: flex; flex-direction: column; gap: 6px; font-weight: 400;
  border-left: 2px solid var(--grid); padding-left: 9px;
}
.fld-info-chips { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.fchip {
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.3px; text-transform: uppercase;
  color: var(--muted); background: var(--page); border: 1px solid var(--grid);
  border-radius: 5px; padding: 1px 5px; line-height: 1.5;
}
button.fchip { cursor: pointer; font-family: var(--mono); text-transform: none; letter-spacing: 0; }
button.fchip:hover { color: var(--ink); border-color: var(--baseline); }
.fchip.on { color: var(--series); border-color: var(--series); background: var(--series-wash); }
.f-err { font-size: 11.5px; font-weight: 500; color: var(--critical); }
.form-grid label.invalid input, .form-grid label.invalid textarea, .form-grid label.invalid select { border-color: var(--critical); }
/* The focus ring outranks the border, so it has to carry the error too —
   otherwise the field you are typing in is the one that looks fine. */
.form-grid label.invalid :is(input, textarea, select):focus { outline-color: var(--critical); }

.secret-wrap { position: relative; display: block; }
.secret-wrap input { padding-right: 38px; }
.secret-eye {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; border: none; background: none; cursor: pointer;
  color: var(--muted); padding: 6px; border-radius: 6px;
}
.secret-eye:hover { color: var(--ink); background: var(--page); }

/* ---- sticky unsaved-changes bar ---- */
.set-savebar {
  position: sticky; bottom: 14px; z-index: 20; display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; padding: 10px 14px; border-radius: 12px;
  background: var(--surface); border: 1px solid var(--series); box-shadow: var(--shadow);
}
.set-savebar .txt { font-size: 13px; font-weight: 500; flex: 1; min-width: 140px; }

/* ---- read-only environment card ---- */
.env-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.env-row code { font-size: 12px; background: var(--page); border: 1px solid var(--grid); border-radius: 5px; padding: 1px 5px; }
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center; padding: 3px;
  border: none; background: none; color: var(--muted); cursor: pointer; border-radius: 5px;
}
.icon-btn:hover { color: var(--ink); background: var(--page); }

@media (max-width: 1100px) {
  /* Rail becomes a scrollable chip row pinned under the topbar. */
  .set-layout { grid-template-columns: 1fr; gap: 12px; }
  .set-rail {
    flex-direction: row; overflow-x: auto; overscroll-behavior-x: contain; gap: 6px;
    top: 0; z-index: 15; padding: 8px 0; background: var(--page);
    border-bottom: 1px solid var(--border);
  }
  .set-rail button { flex: none; border: 1px solid var(--grid); background: var(--surface); white-space: nowrap; }
  .set-rail button .n { margin-left: 4px; }
}
@media (max-width: 820px) {
  .sgroup > summary { flex-wrap: wrap; row-gap: 8px; }
  .sgroup-tags { justify-content: flex-start; width: 100%; }
  /* Search takes its own row; the two bulk buttons and the count share the next. */
  .set-find { flex: 1 1 100%; max-width: none; }
  .set-count { margin-left: auto; align-self: center; }
  /* Clear the fixed bottom tab bar. */
  .set-savebar { bottom: calc(78px + env(safe-area-inset-bottom)); }
}

/* ---------- image cropper ---------- */
dialog.cropper-dlg {
  border: none; border-radius: 14px; background: var(--surface); color: var(--ink);
  box-shadow: var(--shadow); padding: 0; width: min(640px, calc(100vw - 16px));
  max-height: 92vh; overflow: hidden;
}
dialog.cropper-dlg[open] { display: flex; flex-direction: column; }
dialog.cropper-dlg::backdrop { background: rgba(0, 0, 0, 0.55); }
.cropper-b { padding: 16px 18px; overflow-y: auto; min-height: 0; }
.cropper-b canvas {
  width: 100%; height: auto; display: block; border-radius: 10px;
  background: var(--page); border: 1px solid var(--border);
  touch-action: none; cursor: grab;
}
.cropper-b canvas:active { cursor: grabbing; }
.cropper-zoom { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.cropper-zoom input[type='range'] { flex: 1; width: auto; padding: 0; border: none; background: transparent; }
.cropper-zoom .hint { white-space: nowrap; }
@media (max-width: 560px) { .cropper-zoom .hint:last-child { display: none; } }

.kv { display: grid; grid-template-columns: 140px 1fr; gap: 4px 12px; font-size: 13px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; word-break: break-word; }

/* ---------- notification templates ---------- */
.tpl-layout { display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 18px; align-items: start; margin-top: 16px; }
.tpl-work { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px; align-items: start; }
@media (max-width: 1320px) { .tpl-work { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 900px) { .tpl-layout { grid-template-columns: 1fr; } }

.tpl-rail { position: sticky; top: 14px; display: flex; flex-direction: column; gap: 14px; max-height: calc(100vh - 28px); overflow-y: auto; }
@media (max-width: 900px) { .tpl-rail { position: static; max-height: none; } }
.tpl-rail-c { display: flex; flex-direction: column; gap: 2px; }
.tpl-rail-h {
  display: flex; align-items: center; gap: 8px; padding: 4px 2px; color: var(--muted);
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.6px;
}
.tpl-rail-h .ico { display: inline-flex; }
.tpl-rail-t { font-size: 12.5px; font-weight: 600; color: var(--ink-2); padding: 8px 4px 3px; }
.tpl-rail-v {
  font: inherit; text-align: left; cursor: pointer; display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: 8px; border: 1px solid transparent; background: none;
  color: var(--ink-2); font-size: 12.5px; width: 100%;
}
.tpl-rail-v:hover { background: var(--page); color: var(--ink); }
.tpl-rail-v.active { background: var(--series-wash); color: var(--series); border-color: var(--series); }
.tpl-rail-v .l { flex: 1; min-width: 0; }
.tpl-rail-v .tags { display: flex; gap: 4px; flex: none; }
.tpl-rail-v .pill { font-size: 10.5px; padding: 1px 7px; }

.tpl-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.tpl-head h2 { margin: 0; }
.tpl-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin: 14px 0 4px; }
.tpl-tabs button {
  font: inherit; font-size: 12.5px; cursor: pointer; padding: 6px 11px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--page); color: var(--ink-2);
}
.tpl-tabs button:hover { color: var(--ink); }
.tpl-tabs button.active { background: var(--series-wash); border-color: var(--series); color: var(--series); font-weight: 600; }
.tpl-variant-note { margin: 0 0 12px; }

.tpl-msg {
  display: flex; align-items: flex-start; gap: 10px; margin: 12px 0; padding: 10px 12px; font-size: 12.5px;
  border: 1px solid var(--border); border-left-width: 3px; border-radius: 10px; background: var(--page);
}
.tpl-msg[hidden] { display: none; }
.tpl-msg .ico { flex: none; display: flex; margin-top: 1px; }
.tpl-msg.warn { border-left-color: var(--warning); }
.tpl-msg.warn .ico { color: var(--warning); }
.tpl-msg.crit { border-left-color: var(--critical); }
.tpl-msg.crit .ico { color: var(--critical); }
.tpl-msg code, .tpl-vars code, .hint code {
  font-family: var(--mono);
  font-size: 11.5px; background: var(--surface); border: 1px solid var(--grid); border-radius: 4px; padding: 0 4px;
}

.tpl-vars { margin-top: 14px; }
.tpl-vars-h { font-size: 11.5px; color: var(--muted); margin-bottom: 7px; }
.tpl-vars-l { display: flex; flex-wrap: wrap; gap: 5px; }
.tpl-var {
  font: inherit; cursor: pointer; display: inline-flex; align-items: baseline; gap: 6px; max-width: 100%;
  padding: 3px 9px; border-radius: 999px; border: 1px solid var(--border); background: var(--page); color: var(--ink-2);
}
.tpl-var:hover { border-color: var(--series); color: var(--series); }
.tpl-var code { border: none; background: none; padding: 0; font-size: 11.5px; }
.tpl-var span { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.tpl-preview-card { position: sticky; top: 14px; }
@media (max-width: 1320px) { .tpl-preview-card { position: static; } }
.tpl-prev-ctl { display: flex; align-items: center; gap: 8px; }
.tpl-prev-ctl input { width: 190px; font-size: 12.5px; }
.tpl-subject-line { margin: 0 0 10px; font-size: 13px; }
.tpl-test { border-top: 1px solid var(--border); }
.tpl-test .btn .ico { display: inline-flex; vertical-align: -3px; margin-right: 5px; }
/* An SMS is read on a phone, so preview it shaped like one. */
.sms-bubble {
  white-space: pre-wrap; word-break: break-word; font-size: 13.5px; line-height: 1.5;
  background: var(--series-wash); color: var(--ink); border-radius: 14px 14px 14px 4px;
  padding: 11px 14px; max-width: 340px;
}

/* ---------- toast ---------- */
.toast {
  position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 60;
  background: var(--ink); color: var(--page); padding: 10px 16px; border-radius: 9px;
  font-size: 13px; box-shadow: var(--shadow);
}

/* ---------- mobile ---------- */
@media (max-width: 820px) {
  .form-grid, .form-grid.cols-3 { grid-template-columns: 1fr; }
  .kv { grid-template-columns: 110px 1fr; }
  dialog#modal { width: min(560px, calc(100vw - 16px)); }
  .toolbar input[type='search'], .toolbar input[type='text'] { width: 100%; }
  /* Clear the fixed bottom tab bar. */
  .toast { bottom: calc(72px + env(safe-area-inset-bottom)); width: max-content; max-width: calc(100vw - 24px); }
}
