/* ============================================================================
   17 · REACTION ROLES & MODERATION PAGES

   Reaction role panels, the Auto Moderation page and Punishments & Cases.

   Part of the dashboard stylesheet, split out of the former single style.css.
   LOAD ORDER IS LOAD-BEARING (later parts intentionally override earlier
   ones) — the canonical order is dashboard/views/partials/_app_styles.ejs.
   ========================================================================== */

/* ── Reaction Roles ─────────────────────────────────────────────────────────
   The panel modal. Its embed editor and Discord-mock preview are the SHARED
   ones (js/embedBuilder.js), so they reuse the .wz-* rules above verbatim and
   only the reaction-role-specific chrome is defined here. */

.rr-modal { width: min(760px, 96vw); }
.rr-modal-body { padding: 1.25rem; max-height: 72vh; overflow-y: auto; }

.rr-grid2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-bottom: 1rem;
}

/* Setup method — the two methods are a deliberate fork, not a dropdown: which one
   you pick changes what the rest of the modal even asks for, and it is permanent. */
.rr-method { margin-bottom: 1.25rem; }
.rr-method-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.625rem;
}
.rr-method-card {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-sidebar);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.rr-method-card:hover { border-color: rgba(220, 38, 38, 0.4); }
.rr-method-card input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.rr-method-card ion-icon {
  font-size: 1.15rem;
  color: var(--text-muted);
  flex-shrink: 0;
  margin-top: 0.1rem;
}
.rr-method-card b {
  display: block;
  font-size: 0.8125rem;
  color: var(--text-primary);
  font-weight: 600;
  margin-bottom: 0.15rem;
}
.rr-method-card small {
  display: block;
  font-size: 0.72rem;
  color: var(--text-muted);
  line-height: 1.45;
}
.rr-method-card.active {
  border-color: var(--crimson);
  background: rgba(220, 38, 38, 0.08);
}
.rr-method-card.active ion-icon { color: var(--crimson-glow); }

.rr-block {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.875rem;
  margin-bottom: 1rem;
  background: var(--bg-sidebar);
}
.rr-block-head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-secondary);
  margin-bottom: 0.75rem;
}
.rr-block-head ion-icon { font-size: 0.9rem; color: var(--crimson-glow); }

.rr-style { margin: 1rem 0 0.75rem; }
.rr-multi { margin: 0 0 1.25rem; }

.rr-section { margin-top: 0.5rem; }
.rr-section-head {
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 0.5rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* One role row. The grid is what makes the emoji trigger / label / role select
   line up; the row is read back by THIS class, never by a bare `div` selector —
   select-enhance.js wraps each <select> in its own div, and matching those was
   what submitted every role twice. */
.rr-entry {
  display: grid;
  grid-template-columns: auto 1fr 1fr auto;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.5rem;
}

.rr-hint {
  font-size: 0.72rem;
  color: var(--text-muted);
  margin: 0.3rem 0 0;
  line-height: 1.5;
}
.rr-hint-warn { color: var(--yellow); }
.rr-hint a { color: var(--crimson-glow); }

.rr-warn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.625rem 0.875rem;
  border: 1px solid rgba(240, 177, 50, 0.35);
  background: rgba(240, 177, 50, 0.1);
  border-radius: 8px;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.rr-preview { margin-top: 1rem; }
.rr-preview-head {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--green);
  margin-bottom: 0.5rem;
}
.rr-prev-legend {
  margin-top: 0.4rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  line-height: 1.6;
}
.rr-prev-legend b {
  display: block;
  font-size: 0.75rem;
  color: var(--text-primary);
  margin-bottom: 0.2rem;
}
.rr-prev-select {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 0.5rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg-input, var(--bg-sidebar));
  font-size: 0.8125rem;
  color: var(--text-muted);
  flex-direction: row-reverse;
}

@media (max-width: 640px) {
  .rr-grid2,
  .rr-method-grid { grid-template-columns: 1fr; }
  .rr-entry { grid-template-columns: auto 1fr auto; }
  .rr-entry > select { grid-column: 1 / -1; }
}

/* ── Auto Moderation page ───────────────────────────────────────────────────── */
.am-filterbar { display:flex; gap:0.5rem; align-items:center; margin:1.25rem 0 1rem; flex-wrap:wrap; }
.am-filterbar #am-search { flex:1; min-width:180px; }
.am-onlyon { display:flex; align-items:center; gap:0.375rem; font-size:0.8125rem; color:var(--text-muted); white-space:nowrap; cursor:pointer; }
.am-settings-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:0.625rem; margin:0.5rem 0; }
.am-fld { display:flex; flex-direction:column; gap:0.25rem; font-size:0.8125rem; color:var(--text-muted); }
.am-fld > span { font-weight:500; }
.am-fld.am-full { grid-column:1 / -1; }
.am-fld.am-bool, .am-mini { flex-direction:row; align-items:center; gap:0.5rem; }
.am-checks { display:flex; flex-wrap:wrap; gap:0.75rem 1.25rem; margin-top:0.5rem; }
/* `display` is load-bearing, not decoration. `.am-mini` shares the row/gap rule
   above with `.am-fld.am-bool`, but that one is only ever a flex container because
   `.am-fld` makes it one — a bare `<label class="am-mini">` is display:block, which
   makes `flex-direction` and `gap` inert and butted the exception checkboxes
   ("Ignore bots", "Ignore admins", …) straight up against their own labels with no
   space at all. Mirrors `.pn-mini`/`.pn-pick`, which declare it for this reason. */
.am-mini { display:inline-flex; font-size:0.8125rem; color:var(--text-muted); cursor:pointer; }
/* Multi-role exception picker — replaced by the SHARED searchable combobox
   (`js/combo.js`, styles in 12-pickers.css): the full role/channel lists are no
   longer rendered into a drawer; only the selected chips show until searched. */
/* Helper text under a field reads as a note, not as the next field's label. */
.am-hint { display:block; margin-top:0.15rem; line-height:1.35; font-size:0.7rem; }

.am-rules { display:flex; flex-direction:column; gap:0.5rem; }
.am-rule { border:1px solid var(--border); border-radius:10px; background:var(--bg-elev, rgba(255,255,255,0.02)); overflow:hidden; transition:border-color .15s; }
.am-rule.is-on { border-color:color-mix(in srgb, var(--accent, #5865f2) 55%, transparent); }
.am-rule-head { display:flex; align-items:flex-start; gap:0.75rem; padding:0.75rem 0.875rem; }
.am-rule-meta { flex:1; cursor:pointer; min-width:0; }
.am-rule-title { display:flex; align-items:center; gap:0.5rem; flex-wrap:wrap; }
.am-rule-name { font-weight:600; font-size:0.9rem; }
.am-rule-desc { margin:0.25rem 0 0; font-size:0.8rem; color:var(--text-muted); line-height:1.4; }
.am-config-btn { background:none; border:none; color:var(--text-muted); cursor:pointer; padding:0.25rem; font-size:1.1rem; transition:transform .15s; }
.am-rule.am-expanded .am-config-btn { transform:rotate(180deg); }
.am-rule-toggle { flex-shrink:0; margin-top:0.15rem; }

.am-dot { width:9px; height:9px; border-radius:50%; flex-shrink:0; }
.am-sev-critical { background:#992d22; box-shadow:0 0 0 3px rgba(153,45,34,0.2); }
.am-sev-high { background:#e74c3c; }
.am-sev-medium { background:#e67e22; }
.am-sev-low { background:#f1c40f; }

.am-badge { font-size:0.65rem; font-weight:700; padding:0.1rem 0.4rem; border-radius:5px; text-transform:uppercase; letter-spacing:0.03em; }
.am-badge-native { background:rgba(88,101,242,0.18); color:#8f9dff; }
.am-badge-bot { background:rgba(87,242,135,0.15); color:#4fd873; }
.am-badge-both { background:rgba(88,101,242,0.14); color:#a9b4ff; border:1px solid rgba(88,101,242,0.3); }
.am-badge-opt { background:rgba(241,196,15,0.15); color:#f1c40f; }
.am-badge-ok { background:rgba(87,242,135,0.15); color:#4fd873; }
.am-badge-drift { background:rgba(241,196,15,0.18); color:#f1c40f; }
.am-badge-off { background:rgba(237,66,69,0.15); color:#ed4245; }
/* A rule that is switched on and matches nothing. Amber rather than red: it is a
   setup gap the admin can close, not a failure. */
.am-badge-inert { background:rgba(241,196,15,0.18); color:#f1c40f; border:1px solid rgba(241,196,15,0.35); }
.am-rule-warn { margin:0.3rem 0 0; font-size:0.78rem; color:#f1c40f; line-height:1.4; }
.am-hits { font-size:0.7rem; color:var(--text-muted); margin-left:auto; }
.am-group-count { font-size:0.7rem; font-weight:700; color:#4fd873; background:rgba(87,242,135,0.12); padding:0.05rem 0.4rem; border-radius:5px; }

.am-rule-body { border-top:1px solid var(--border); padding:0.875rem; background:rgba(0,0,0,0.12); }
.am-drawer { display:flex; flex-direction:column; gap:0.875rem; }
.am-drawer-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:0.625rem; }
.am-sub-title { font-size:0.75rem; font-weight:700; text-transform:uppercase; letter-spacing:0.04em; color:var(--text-muted); margin-bottom:0.5rem; }
.am-actions { display:flex; flex-wrap:wrap; gap:0.4rem; }
.am-action { display:flex; align-items:center; gap:0.35rem; font-size:0.8rem; padding:0.3rem 0.55rem; border:1px solid var(--border); border-radius:7px; cursor:pointer; transition:all .12s; }
.am-action.on { border-color:var(--accent, #5865f2); background:color-mix(in srgb, var(--accent, #5865f2) 12%, transparent); color:var(--text); }
.am-action input { margin:0; }

.am-stat-row { display:flex; justify-content:space-between; align-items:center; padding:0.4rem 0; border-bottom:1px solid var(--border); font-size:0.85rem; }
.am-stat-row:last-child { border-bottom:none; }
.am-stat-num { font-weight:700; color:var(--accent, #5865f2); }
.am-muted { color:var(--text-muted); font-size:0.85rem; }

/* ── Protection level slider ──────────────────────────────────────────────────
   Four stops — Filters off · Minimum · Medium · Maximum — replacing the three
   preset cards. A slider states the answer as a POSITION, which is why it can
   also show the level a server is already on; three cards could only offer three
   buttons and never say which of them was in effect.

   THE STOPS ARE ABSOLUTELY POSITIONED FROM THEIR STAGE INDEX, and the track is
   inset by half a thumb (`--am-thumb`) on both sides. A native range thumb's
   CENTRE travels from half-a-thumb to width-minus-half, so stops spread with
   flex/space-between drift out of line with the handle at both ends — by exactly
   that half-thumb, which is the amount that makes a 4-stop slider look broken.
   Change the thumb size in one place: every offset here reads that variable.

   COLOURS COME FROM `--blurple`, WHICH IS THIS PALETTE'S CRIMSON (#DC2626 — the
   name is historical, see 01-tokens.css). There is no `--accent` token, so the
   `var(--accent, …)` fallback a few rules below in this file resolves to Discord
   blurple and paints off-brand; do not copy that pattern here. */
.am-lv { --am-thumb:20px; padding:1.35rem 1.5rem 1.25rem; margin-bottom:1rem; }
.am-lv-head { text-align:center; margin-bottom:1.6rem; }
.am-lv-head h3 { margin:0 0 0.3rem; font-size:1rem; font-weight:700; }
.am-lv-head p { margin:0 auto; max-width:52ch; line-height:1.5; }

/* "You are on no preset" — a fact about the SERVER, so it sits with the heading
   rather than beside the Apply button, which states the consequence of pressing it.
   Two different facts, each said once (the Logging page's rule). */
.am-lv-custom {
  display:inline-flex; align-items:center; gap:0.4rem; margin:0.7rem auto 0;
  padding:0.3rem 0.65rem; border-radius:999px; font-size:0.75rem; text-align:left;
  background:rgba(245,158,11,0.10); border:1px solid rgba(245,158,11,0.28); color:var(--yellow);
}
.am-lv-custom ion-icon { font-size:14px; flex-shrink:0; }
.am-lv-custom b { color:var(--yellow); }

/* Which plan this server is on. Sits with the heading because it describes the SERVER,
   like the custom-setup pill above it — the Pro half is named on the individual rules
   and controls, not restated here. */
.am-lv-tier {
  display:inline-flex; align-items:center; gap:0.45rem; margin:0.7rem auto 0;
  padding:0.35rem 0.75rem; border-radius:999px; font-size:0.76rem; text-align:left;
  line-height:1.45;
  background:rgba(46,204,113,0.08); border:1px solid rgba(46,204,113,0.24); color:var(--text);
}
.am-lv-tier ion-icon { font-size:15px; flex-shrink:0; color:#7dcea0; }
.am-lv-tier a { color:var(--blurple, #DC2626); font-weight:600; text-decoration:none; }
.am-lv-tier a:hover { text-decoration:underline; }
/* The one state that really is a lock: an operator switched the free tier off. */
.am-lv-tier.is-off { background:rgba(245,158,11,0.10); border-color:rgba(245,158,11,0.28); color:var(--yellow); }
.am-lv-tier.is-off ion-icon { color:var(--yellow); }

/* "+N with Pro" on a stage that would configure more rules on a paid plan. An anchor,
   so it goes somewhere — a badge that only informs is a dead end on the one control
   whose whole job is choosing a level. */
.am-lv-proextra { margin-left:auto; text-decoration:none; }
.am-lv-title .am-lv-count + .am-lv-proextra { margin-left:0.5rem; }

.am-lv-slider { position:relative; margin:0 calc(var(--am-thumb) / 2) 4.5rem; }

/* The track. `appearance:none` on both the input and the WebKit thumb is what lets
   it be styled at all; without it the browser paints its own control and every rule
   below is ignored with no error. `--am-lv-fill` is set inline per stop, so the
   filled portion follows the handle without a repaint. */
.am-lv-range {
  -webkit-appearance:none; appearance:none;
  display:block; width:100%; height:var(--am-thumb); margin:0;
  background:transparent; cursor:pointer;
}
.am-lv-range::-webkit-slider-runnable-track {
  height:4px; border-radius:999px;
  background:linear-gradient(to right,
    var(--blurple, #DC2626) 0, var(--blurple, #DC2626) var(--am-lv-fill, 0%),
    rgba(255,255,255,0.10) var(--am-lv-fill, 0%), rgba(255,255,255,0.10) 100%);
}
.am-lv-range::-moz-range-track { height:4px; border-radius:999px; background:rgba(255,255,255,0.10); }
.am-lv-range::-moz-range-progress { height:4px; border-radius:999px; background:var(--blurple, #DC2626); }
.am-lv-range::-webkit-slider-thumb {
  -webkit-appearance:none; appearance:none;
  width:var(--am-thumb); height:var(--am-thumb); border-radius:50%;
  background:#fff; border:none; cursor:grab;
  /* Centres the thumb on a 4px track: (thumb - track) / 2, negated. */
  margin-top:calc((4px - var(--am-thumb)) / 2);
  box-shadow:0 1px 4px rgba(0,0,0,0.45);
  transition:transform 0.12s ease, box-shadow 0.12s ease;
}
.am-lv-range::-moz-range-thumb {
  width:var(--am-thumb); height:var(--am-thumb); border-radius:50%;
  background:#fff; border:none; cursor:grab;
  box-shadow:0 1px 4px rgba(0,0,0,0.45);
  transition:transform 0.12s ease, box-shadow 0.12s ease;
}
.am-lv-range:hover::-webkit-slider-thumb { transform:scale(1.12); }
.am-lv-range:hover::-moz-range-thumb { transform:scale(1.12); }
.am-lv-range:focus-visible::-webkit-slider-thumb { box-shadow:var(--ring-blue); }
.am-lv-range:focus-visible::-moz-range-thumb { box-shadow:var(--ring-blue); }
.am-lv-range:focus { outline:none; }

/* The stops sit BELOW the track and are clickable: on a 4-stop slider a label is a
   far easier target than a pixel, and it keeps the stops reachable on touch. */
.am-lv-ticks { position:absolute; left:0; right:0; top:calc(var(--am-thumb) + 0.55rem); height:0; }
.am-lv-tick {
  position:absolute; transform:translateX(-50%);
  display:flex; flex-direction:column; align-items:center; gap:0.3rem;
  background:none; border:none; padding:0.2rem 0.35rem; cursor:pointer;
  color:var(--text-muted); font:inherit; border-radius:8px;
  transition:color 0.15s ease;
}
.am-lv-tick:hover { color:var(--text); }
.am-lv-tick-label { font-size:0.72rem; font-weight:600; white-space:nowrap; }
.am-lv-shield { display:flex; font-size:19px; line-height:1; color:rgba(255,255,255,0.28); transition:color 0.15s ease; }
/* The shield fills up as the level rises — the one decorative thing here, and it
   earns its place: it makes the four stops readable before any label is read. */
.am-lv-shield[data-fill="1"] { color:rgba(220,38,38,0.55); }
.am-lv-shield[data-fill="2"] { color:rgba(220,38,38,0.80); }
.am-lv-shield[data-fill="3"] { color:var(--blurple, #DC2626); }
.am-lv-tick:hover .am-lv-shield { color:var(--blurple, #DC2626); }
/* The stage this server is ON, marked on the track itself — a slider that could not
   say where you already are would be a row of buttons with extra steps. */
/* A stop whose whole difference from the one below it is Pro rules. Marked with a lock
   rather than disabled: it still previews, so somebody can see what the plan buys
   before deciding — the proGate contract (visible and explorable, never activatable). */
/* A literal padlock, not a `\1F512` CSS escape: an escape needs a terminating space or
   a six-digit form, and the five-digit one written next to a closing quote renders as
   the text "\1F512" beside the label. This file is UTF-8 already (its section rules are
   box-drawing characters), so the character itself is the simpler and safer spelling. */
.am-lv-tick.is-pro .am-lv-tick-label::before {
  content:'🔒'; margin-right:0.25rem; font-size:0.62rem; opacity:0.8;
}
.am-lv-tick.is-pro .am-lv-shield { color:rgba(255,255,255,0.22); }
.am-lv-tick.is-pro:hover .am-lv-shield { color:rgba(255,255,255,0.35); }

.am-lv-tick.is-current .am-lv-tick-label { color:var(--text); }
.am-lv-tick.is-current .am-lv-tick-label::after {
  content:''; display:block; height:2px; margin-top:3px; border-radius:2px;
  background:var(--blurple, #DC2626);
}

.am-lv-detail {
  border:1px solid var(--border); border-radius:10px; padding:0.95rem 1rem;
  background:rgba(0,0,0,0.14);
}
.am-lv-title { display:flex; align-items:center; gap:0.5rem; flex-wrap:wrap; margin-bottom:0.35rem; }
.am-lv-name { font-size:1rem; font-weight:700; }
.am-lv-badge {
  font-size:0.66rem; font-weight:600; border-radius:999px; padding:0.12rem 0.45rem;
  background:rgba(46,204,113,0.12); border:1px solid rgba(46,204,113,0.3); color:#7dcea0;
}
.am-lv-count { margin-left:auto; font-size:0.72rem; color:var(--text-muted); }
.am-lv-tag { margin:0 0 0.3rem; font-size:0.85rem; color:var(--text); }
.am-lv-desc { margin:0 0 0.65rem; font-size:0.8rem; color:var(--text-muted); line-height:1.55; }
.am-lv-actions { display:flex; align-items:center; gap:0.75rem; flex-wrap:wrap; margin-top:0.85rem; }
.am-lv-note { flex:1 1 16rem; font-size:0.75rem; color:var(--text-muted); line-height:1.5; }
.am-lv-note b { color:var(--text); }

/* The server-type profiles: the SECOND axis, and deliberately collapsed. A level
   answers "how much", a profile answers "what is normal here" — worth having, but
   asking both up front is what made the old panel three ways to ask one question. */
.am-lv-profiles { margin-top:1rem; border-top:1px solid var(--border); }
.am-lv-profiles > summary {
  display:flex; align-items:center; gap:0.45rem; flex-wrap:wrap;
  padding:0.8rem 0.1rem 0.2rem; cursor:pointer; list-style:none;
  font-size:0.85rem; font-weight:600;
}
.am-lv-profiles > summary::-webkit-details-marker { display:none; }
.am-lv-profiles > summary .am-muted { font-weight:400; flex:1 1 100%; }
.am-lv-profiles > summary:hover { color:var(--blurple, #DC2626); }
.am-lv-profiles .am-setup-body { padding:0.6rem 0 0.2rem; }
.am-setup-lead-p { margin:0 0 0.75rem; line-height:1.5; }

@media (max-width:560px) {
  /* Four labels cannot sit side by side at this width without overlapping, so the
     end stops are pulled inside the track rather than being allowed to collide. */
  .am-lv-tick-label { font-size:0.66rem; }
  .am-lv-tick[style*="left:0%"] { transform:translateX(-30%); }
  .am-lv-tick[style*="left:100%"] { transform:translateX(-70%); }
}

@media (prefers-reduced-motion:reduce) {
  .am-lv-range::-webkit-slider-thumb, .am-lv-range::-moz-range-thumb,
  .am-lv-tick, .am-lv-shield { transition:none; }
}

/* ── Quick Setup cards (the profile grid; the level cards became the slider) ─── */
.am-setup { margin-bottom:1rem; padding:0; }
.am-setup-summary {
  display:flex; flex-direction:column; gap:0.2rem; padding:0.875rem 1rem;
  cursor:pointer; list-style:none; font-weight:600;
}
.am-setup-summary::-webkit-details-marker { display:none; }
.am-setup-summary > span:first-child { display:flex; align-items:center; gap:0.45rem; }
.am-setup-summary .am-muted { font-weight:400; }
.am-setup-body { padding:0 1rem 1rem; }
.am-setup-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:0.75rem; }
.am-setup-card {
  display:flex; flex-direction:column; gap:0.45rem;
  border:1px solid var(--border); border-radius:10px; padding:0.875rem;
  background:rgba(0,0,0,0.12);
}
.am-setup-head { display:flex; align-items:center; justify-content:space-between; gap:0.5rem; }
.am-setup-name { font-weight:700; font-size:0.95rem; }
.am-setup-count { font-size:0.7rem; color:var(--text-muted); }
.am-setup-tag { margin:0; font-size:0.82rem; color:var(--text); }
.am-setup-desc { margin:0; font-size:0.78rem; color:var(--text-muted); line-height:1.45; }
.am-setup-meta { display:flex; flex-wrap:wrap; gap:0.3rem; margin-top:auto; }
.am-setup-meta span {
  font-size:0.68rem; color:var(--text-muted);
  background:rgba(255,255,255,0.04); border-radius:5px; padding:0.1rem 0.4rem;
}
.am-setup-card .btn { margin-top:0.35rem; }
.am-setup-foot { margin:0.875rem 0 0; line-height:1.5; }

/* ── Server-type profiles (the second setup axis) ─────────────────────────────
   A profile card carries one thing a level card does not: WHICH groups it runs
   harder and which it only records. Those two chips are the whole difference
   between "tuned for gaming servers" (unverifiable) and something an owner can
   check against their own server before pressing the button. */
.am-setup-lead { margin:0.25rem 0 0.6rem; }
.am-setup-lead:not(:first-child) { margin-top:1.25rem; padding-top:1rem; border-top:1px solid var(--border); }
.am-setup-lead h4 { margin:0 0 0.2rem; font-size:0.88rem; font-weight:700; }
.am-setup-lead p { margin:0; font-size:0.78rem; line-height:1.45; }
.am-setup-card--profile { min-height:100%; }
.am-setup-icon { font-size:1rem; line-height:1; }
.am-setup-diff { display:flex; flex-wrap:wrap; gap:0.25rem; }
.am-setup-chip {
  font-size:0.66rem; font-weight:600; border-radius:5px; padding:0.1rem 0.38rem;
  border:1px solid transparent; white-space:nowrap;
}
/* Deliberately two colours rather than one neutral: "runs harder" and "only
   records" are opposite promises, and a reader scanning six cards is comparing
   exactly those. */
.am-setup-chip.is-tight { background:rgba(231,76,60,0.12); border-color:rgba(231,76,60,0.3); color:#e88; }
.am-setup-chip.is-relax { background:rgba(46,204,113,0.10); border-color:rgba(46,204,113,0.28); color:#7dcea0; }

/* The Pro half of a rule's punishment list — its own row under the free actions, with
   ONE lock rather than a PRO pill on each of seventeen checkboxes. `lockProControl`
   pins its badge to the top-right corner, so the row needs the padding to sit under it
   and `position:relative` (which the kit sets itself, but stating it here keeps the
   layout readable rather than depending on a side effect). */
.am-actions-pro {
  position:relative; margin-top:0.5rem; padding:0.55rem 0.6rem 0.5rem;
  border:1px dashed var(--border-strong); border-radius:8px;
}
.am-actions-pro::before {
  content:'Pro punishments'; display:block; margin-bottom:0.4rem;
  font-size:0.68rem; font-weight:700; letter-spacing:0.04em; text-transform:uppercase;
  color:var(--text-muted);
}

/* Escalation, read-only. Set by a preset and shown so a configured ladder is not a
   silent behaviour nobody can account for. */
.am-esc-list { margin:0.25rem 0 0; padding-left:1.1rem; font-size:0.78rem; line-height:1.6; color:var(--text-muted); }
.am-esc-list b { color:var(--text); }

/* ── Discord AutoMod sync panel ───────────────────────────────────────────── */
.am-sync-row { padding:0.45rem 0; border-bottom:1px solid var(--border); }
.am-sync-row:last-of-type { border-bottom:none; }
.am-sync-name { display:flex; align-items:center; gap:0.4rem; font-size:0.85rem; font-weight:600; flex-wrap:wrap; }
.am-sync-sub { font-size:0.75rem; margin:0.15rem 0 0; }
.am-sync-warn, .am-sync-note {
  display:flex; gap:0.5rem; align-items:flex-start;
  font-size:0.8rem; line-height:1.5; border-radius:8px;
  padding:0.6rem 0.7rem; margin-bottom:0.75rem;
}
.am-sync-warn { background:rgba(241,196,15,0.1); border:1px solid rgba(241,196,15,0.28); color:#f1c40f; }
.am-sync-note { background:rgba(88,101,242,0.1); border:1px solid rgba(88,101,242,0.28); color:var(--text-muted); }
.am-sync-warn ion-icon, .am-sync-note ion-icon { font-size:16px; flex-shrink:0; margin-top:1px; }
.am-sync-note .btn { margin:0.3rem 0.3rem 0 0; }
.am-sync-budget { margin-top:0.75rem; font-size:0.78rem; color:var(--text-muted); }
.am-sync-actions { display:flex; gap:0.5rem; flex-wrap:wrap; margin-top:0.875rem; }

@media (max-width:640px) {
  .am-settings-grid, .am-drawer-grid { grid-template-columns:1fr; }
  .am-setup-grid { grid-template-columns:1fr; }
}

/* ── Punishments & Cases (pages/punishments.js) ────────────────────────────── */
/* Scoped under the page's own prefix so nothing here can reach another page.   */
.pn-tabs { display:flex; gap:0.4rem; flex-wrap:wrap; margin:0 0 1rem; }
.pn-tab {
  display:inline-flex; align-items:center; gap:0.4rem; padding:0.5rem 0.9rem;
  border:1px solid var(--border); border-radius:8px; background:transparent;
  color:var(--text-muted); font-size:0.85rem; cursor:pointer; transition:all .15s;
}
.pn-tab:hover { color:var(--text); border-color:var(--crimson-glow, #dc2626); }
.pn-tab.active { color:#fff; background:rgba(220,38,38,.15); border-color:rgba(220,38,38,.5); }

.pn-note {
  display:flex; gap:0.6rem; align-items:flex-start; padding:0.75rem 0.9rem; margin-bottom:1rem;
  border:1px solid rgba(88,101,242,.35); background:rgba(88,101,242,.08);
  border-radius:10px; font-size:0.82rem; color:var(--text-muted); line-height:1.5;
}
.pn-note ion-icon { font-size:18px; color:#5865F2; flex:0 0 auto; }

/* ── Escalation guide (Escalation tab) ───────────────────────────────────────
   The collapsible "How escalation works" explainer. Same blue accent family as
   .pn-note, full-width above the two columns, collapsible like the automod
   setup <details>. */
.pn-guide {
  border:1px solid rgba(88,101,242,.35); background:rgba(88,101,242,.06);
  border-radius:10px; margin-bottom:1rem; overflow:hidden;
}
.pn-guide summary {
  display:flex; align-items:center; gap:0.5rem; padding:0.7rem 0.9rem;
  cursor:pointer; font-size:0.85rem; font-weight:600; color:var(--text);
  list-style:none; user-select:none;
}
.pn-guide summary::-webkit-details-marker { display:none; }
.pn-guide summary ion-icon { font-size:16px; color:#5865F2; flex:0 0 auto; }
.pn-guide-hint { font-weight:400; font-size:0.78rem; color:var(--text-muted); }
.pn-guide summary::after { content:'−'; margin-left:auto; color:var(--text-muted); font-weight:400; }
.pn-guide:not([open]) summary::after { content:'+'; }
.pn-guide-body {
  padding:0.2rem 0.9rem 0.9rem; font-size:0.82rem; line-height:1.6;
  color:var(--text-muted); border-top:1px solid rgba(88,101,242,.2);
}
.pn-guide-body p { margin:0.6rem 0; }
.pn-guide-body b { color:var(--text); }
.pn-guide-body ol { margin:0.5rem 0; padding-left:1.2rem; }
.pn-guide-body li { margin:0.45rem 0; }
.pn-guide-body li::marker { color:#5865F2; font-weight:600; }
.pn-guide-body code {
  background:rgba(255,255,255,.06); border-radius:4px; padding:0.05rem 0.35rem;
  font-size:0.78rem; color:var(--text);
}
.pn-guide-ladder { display:flex; align-items:center; flex-wrap:wrap; gap:0.4rem; margin:0.6rem 0; }
.pn-guide-ladder .pn-rung { background:rgba(255,255,255,.03); }
.pn-guide-more { margin-bottom:0 !important; }
.pn-guide-more a { color:#A8B1FF; }

.pn-ladder-actions { display:flex; gap:0.5rem; margin-bottom:0.9rem; flex-wrap:wrap; }

.pn-ladder {
  border:1px solid var(--border); border-radius:10px; margin-bottom:0.75rem;
  background:var(--bg-elev, rgba(255,255,255,0.02)); overflow:hidden;
}
.pn-ladder-head {
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:0.8rem 1rem; cursor:pointer;
}
.pn-ladder-head:hover { background:rgba(255,255,255,.02); }
.pn-ladder-title { font-weight:600; font-size:0.95rem; display:flex; align-items:center; gap:0.45rem; flex-wrap:wrap; }
.pn-ladder-sub { font-size:0.76rem; color:var(--text-muted); margin-top:0.2rem; }
.pn-ladder-summary {
  display:flex; align-items:center; gap:0.35rem; flex-wrap:wrap;
  padding:0 1rem 0.8rem; font-size:0.75rem; color:var(--text-muted);
}
.pn-rung { padding:0.2rem 0.5rem; border:1px solid var(--border); border-radius:20px; white-space:nowrap; }
.pn-rung b { color:var(--text); margin-right:0.25rem; }
.pn-arrow { opacity:.4; }
.pn-ladder-body { border-top:1px solid var(--border); padding:1rem; }

.pn-badge { font-size:0.65rem; padding:0.1rem 0.4rem; border-radius:4px; font-weight:600; text-transform:uppercase; letter-spacing:.03em; }
.pn-badge-builtin { background:rgba(88,101,242,.2); color:#A8B1FF; }
.pn-badge-test { background:rgba(59,130,246,.2); color:#93C5FD; }
.pn-badge-off { background:rgba(148,163,184,.2); color:#CBD5E1; }
.pn-badge-on { background:rgba(34,197,94,.18); color:#86EFAC; }

.pn-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr)); gap:0.75rem; }
.pn-fld { display:flex; flex-direction:column; gap:0.3rem; font-size:0.78rem; color:var(--text-muted); }
.pn-fld.pn-full { grid-column:1/-1; margin-top:0.6rem; }
.pn-fld.pn-narrow { max-width:120px; }
.pn-fld small { font-size:0.7rem; }
/* Settings-tab fields are stacked straight into a panel with no wrapper to carry a
   gap, so consecutive ones sat flush at 0px: each field's muted helper text ran
   directly into the NEXT field's label and the two read as one paragraph ("…the
   fallback if no channel is picked above." / "Blacklisted users are removed by").
   Only siblings are spaced — `* +` leaves the first field tight under the panel
   head, which already carries its own margin — and 0.6rem matches the spacing
   `.pn-full` had already set for itself, so nothing that looked right moves. */
.punishments-page .ga-panel > * + .pn-fld { margin-top:0.6rem; }
.pn-muted { color:var(--text-muted); font-size:0.78rem; }

.pn-checks { display:flex; gap:1rem; flex-wrap:wrap; margin:0.8rem 0; }
.pn-mini, .pn-pick { display:inline-flex; align-items:center; gap:0.4rem; font-size:0.8rem; cursor:pointer; }
.pn-picklist {
  display:flex; flex-wrap:wrap; gap:0.5rem 1rem; max-height:170px; overflow-y:auto;
  padding:0.6rem; border:1px solid var(--border); border-radius:8px;
}
.pn-sub-title { font-size:0.8rem; font-weight:600; margin:1rem 0 0.5rem; color:var(--text); }

.pn-levels { display:flex; flex-direction:column; gap:0.5rem; margin-bottom:0.7rem; }
.pn-level {
  display:flex; align-items:flex-end; gap:0.6rem; flex-wrap:wrap;
  padding:0.65rem; border:1px solid var(--border); border-radius:9px;
  background:rgba(255,255,255,.015);
}
.pn-level.dragging { opacity:.45; }
.pn-level.dragover { border-color:var(--crimson-glow, #dc2626); }
.pn-drag { cursor:grab; color:var(--text-muted); padding-bottom:0.4rem; }
.pn-level-msgs { flex:1 1 100%; display:grid; gap:0.5rem; margin-top:0.4rem; }
.pn-level-more, .pn-level-del { margin-bottom:0.15rem; }

/* ── Level editor comprehension (Escalation tab) ─────────────────────────────
   The picker gets room to breathe, a plain-language description of the selected
   punishment sits under it, a rung whose punishment needs a configured role says
   so INLINE, the duration input carries a live human hint, and the messages
   toggle is a labelled button rather than a bare icon. */
.pn-fld.pn-punish { flex:1 1 210px; min-width:180px; }
.pn-punish-desc, .pn-dur-hint { font-size:0.7rem; line-height:1.45; min-height:1.1em; }
.pn-needswarn { font-size:0.7rem; line-height:1.45; color:#FCA5A5; }
.pn-level-more.on { color:#fff; border-color:rgba(88,101,242,.55); background:rgba(88,101,242,.16); }
.pn-msgs-title { font-size:0.75rem; font-weight:600; color:var(--text); display:flex; align-items:center; gap:0.4rem; }

.pn-editor-actions { display:flex; gap:0.5rem; flex-wrap:wrap; margin-top:0.9rem; }
.pn-editor-msg { font-size:0.78rem; margin-top:0.5rem; min-height:1em; color:var(--text-muted); }
.pn-editor-msg.is-ok { color:#86EFAC; }
.pn-editor-msg.is-err { color:var(--red); }

.pn-roleline { display:flex; justify-content:space-between; gap:1rem; font-size:0.8rem; padding:0.35rem 0; border-bottom:1px solid var(--border); }
.pn-roleline:last-of-type { border-bottom:0; }
.pn-preview-out { margin-top:0.7rem; font-size:0.8rem; }
.pn-preview-card { padding:0.7rem; border:1px solid var(--border); border-radius:8px; line-height:1.6; }

.pn-filterbar { display:flex; gap:0.5rem; align-items:center; flex-wrap:wrap; margin-bottom:0.9rem; }
.pn-filterbar .input { max-width:200px; }
.pn-cases { display:flex; flex-direction:column; gap:0.5rem; }
.pn-case {
  display:flex; align-items:center; gap:0.9rem;
  padding:0.65rem 0.8rem; border:1px solid var(--border); border-radius:9px;
}
.pn-case-num { font-family:var(--font-mono); color:var(--text-muted); font-size:0.8rem; flex:0 0 auto; }
.pn-case-main { flex:1; min-width:0; }
.pn-case-title { font-size:0.87rem; font-weight:600; display:flex; align-items:center; gap:0.4rem; flex-wrap:wrap; }
.pn-case-sub { font-size:0.72rem; color:var(--text-muted); margin-top:0.15rem; }
.pn-case-reason { font-size:0.78rem; margin-top:0.25rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pn-pager { display:flex; align-items:center; justify-content:space-between; gap:1rem; margin-top:0.9rem; font-size:0.78rem; color:var(--text-muted); }
.pn-empty { padding:1.5rem; text-align:center; color:var(--text-muted); font-size:0.85rem; }

.pn-case-detail { display:flex; flex-direction:column; gap:0.5rem; text-align:left; }
.pn-kv { display:grid; grid-template-columns:130px 1fr; gap:0.75rem; font-size:0.82rem; }
.pn-kv > span { color:var(--text-muted); }
.pn-note-row { padding:0.2rem 0; font-size:0.8rem; }

.pn-reasons { display:flex; flex-direction:column; gap:0.5rem; }
.pn-reason { display:flex; gap:0.5rem; align-items:center; }
.pn-reason .input:first-child { max-width:180px; }
.pn-reason .input:nth-child(2) { flex:1; }

@media (max-width:640px) {
  .pn-grid { grid-template-columns:1fr; }
  .pn-level { align-items:stretch; }
  .pn-kv { grid-template-columns:1fr; gap:0.15rem; }
  .pn-reason { flex-wrap:wrap; }
  .pn-reason .input:first-child { max-width:none; }
}
.pn-case-actions { display:flex; gap:0.3rem; align-items:center; flex:0 0 auto; }

/* ── Moderators tab ──────────────────────────────────────────────────────────
   The roster of who may moderate, read off the Permissions Manager's grants. The
   per-capability editor inside its modal deliberately reuses the Permissions
   Manager's OWN classes (.pm-cmd / .pm-seg / .pm-user-row / .pm-search /
   .pm-subj-ic / .pm-count-pill from 15-permissions-payment.css) rather than
   restyling them here: it is the same control editing the same rows, and a second
   look for it is how the two pages start disagreeing about what "Deny" means. */
.pn-note-warn { border-color:rgba(245,158,11,.35); background:rgba(245,158,11,.08); }
.pn-note-warn ion-icon { color:var(--yellow); }

.pn-mod-add { display:flex; flex-direction:column; gap:0.5rem; margin-bottom:0.9rem; }
.pn-mod-add .pm-userlist { max-height:210px; overflow-y:auto; }

.pn-mod-list { display:flex; flex-direction:column; gap:0.4rem; }
.pn-mod-row {
  display:flex; align-items:center; gap:0.65rem; padding:0.55rem 0.7rem;
  border:1px solid var(--border); border-radius:10px; background:var(--bg-tertiary);
  transition:border-color .16s var(--ease);
}
.pn-mod-row:hover { border-color:var(--border-strong); }
.pn-mod-av { width:28px; height:28px; border-radius:50%; object-fit:cover; flex:0 0 auto; }
.pn-mod-main { flex:1; min-width:0; }
.pn-mod-name { font-size:0.86rem; font-weight:600; display:flex; align-items:center; gap:0.4rem; flex-wrap:wrap; }
.pn-mod-sub { font-size:0.73rem; color:var(--text-muted); margin-top:0.15rem; }
.pn-mod-actions { display:flex; align-items:center; gap:0.3rem; flex:0 0 auto; font-size:0.73rem; }

/* Master switch inside the capability editor — the module grant every capability
   below inherits from, so it sits apart from them rather than in the same list. */
.pn-mod-master {
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:0.7rem 0.85rem; border:1px solid rgba(220,38,38,.3); border-radius:10px;
  background:rgba(220,38,38,.06);
}
.pn-cap-group + .pn-cap-group { margin-top:0.4rem; }
.pn-cap-group .pn-sub-title { display:flex; align-items:center; gap:0.4rem; }
.pn-cap-group .pn-sub-title ion-icon { color:var(--crimson-glow); font-size:15px; }

@media (max-width:640px) {
  .pn-mod-row { flex-wrap:wrap; }
  .pn-mod-actions { width:100%; justify-content:flex-end; }
}

/* ── Commands tab ────────────────────────────────────────────────────────────
   Every moderation command, what it does and who may run it — the capability-first
   view of the same grants the Moderators tab shows subject-first. The access editor
   inside its modal reuses the Permissions Manager's own .pm-seg / .pm-search /
   .pm-user-row / .pm-subj-ic classes for the same reason the per-subject editor
   does: it is the same control editing the same rows, and a second look for it is
   how two pages start disagreeing about what "Deny" means. */
.pn-cmd-toolbar { display:flex; gap:0.5rem; align-items:center; flex-wrap:wrap; margin-bottom:1rem; }
.pn-cmd-toolbar .input { max-width:190px; }
.pn-cmd-search { flex:1 1 220px; max-width:320px; }

.pn-cmd-group + .pn-cmd-group { margin-top:1.4rem; }
.pn-cmd-group .pn-sub-title { display:flex; align-items:center; gap:0.4rem; margin-top:0; }
.pn-cmd-group .pn-sub-title ion-icon { color:var(--crimson-glow); font-size:15px; }

.pn-cmd-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(330px,1fr)); gap:0.7rem; }

.pn-cmd-card {
  display:flex; flex-direction:column; gap:0.5rem;
  padding:0.8rem 0.9rem; border:1px solid var(--border); border-radius:11px;
  background:var(--bg-tertiary); transition:border-color .16s var(--ease);
}
.pn-cmd-card:hover { border-color:var(--border-strong); }
/* The filter hides cards with the `hidden` attribute, and a flex display would beat
   the UA's [hidden] rule outright — without this, narrowing the list does nothing. */
.pn-cmd-card[hidden], .pn-cmd-group[hidden] { display:none !important; }

.pn-cmd-head { display:flex; align-items:center; justify-content:space-between; gap:0.6rem; }
.pn-cmd-title { display:flex; align-items:center; gap:0.4rem; flex-wrap:wrap; min-width:0; }
.pn-cmd-name { font-size:0.9rem; font-weight:650; }
/* Which engine performs the command. Blurple for Discord's own API, crimson for
   Azra's own feature, and a muted mix for the ones Discord applies and Azra keeps
   maintaining — the same honest-badge convention the Auto Moderation rule list uses,
   so a reader who has learnt one recognises the other. */
.pn-cmd-engine {
  font-size:0.62rem; text-transform:uppercase; letter-spacing:.04em; font-weight:700;
  padding:0.1rem 0.38rem; border-radius:4px; white-space:nowrap;
}
.pn-cmd-engine-discord { background:rgba(88,101,242,.18); color:#A8B1FF; }
.pn-cmd-engine-hybrid  { background:rgba(148,163,184,.18); color:#CBD5E1; }
.pn-cmd-engine-azra    { background:rgba(220,38,38,.16); color:#FCA5A5; }
.pn-cmd-desc { font-size:0.78rem; color:var(--text-muted); line-height:1.5; margin:0; }

.pn-cmd-usages { display:flex; flex-direction:column; gap:0.3rem; }
.pn-cmd-usage { display:flex; align-items:baseline; gap:0.4rem; flex-wrap:wrap; font-size:0.75rem; }
.pn-cmd-usage code {
  font-family:var(--font-mono); font-size:0.74rem; padding:0.12rem 0.36rem;
  border:1px solid var(--border); border-radius:5px; background:rgba(255,255,255,.03); color:var(--text);
}
.pn-cmd-usage code i { color:var(--text-muted); font-style:normal; }
.pn-cmd-surface {
  font-size:0.62rem; text-transform:uppercase; letter-spacing:.04em; font-weight:600;
  padding:0.08rem 0.32rem; border-radius:4px; background:rgba(148,163,184,.16); color:#CBD5E1;
}
.pn-cmd-usage-desc { flex:1 1 100%; color:var(--text-muted); line-height:1.45; }

.pn-cmd-perms { display:flex; align-items:center; gap:0.4rem; font-size:0.73rem; color:var(--text-muted); }
.pn-cmd-perms ion-icon { font-size:14px; color:var(--yellow); flex:0 0 auto; }
.pn-cmd-perms b { color:var(--text); font-weight:600; }

.pn-cmd-access { border-top:1px solid var(--border); padding-top:0.55rem; margin-top:auto; display:flex; flex-direction:column; gap:0.4rem; }
.pn-cmd-access-row { display:flex; gap:0.5rem; align-items:flex-start; }
.pn-cmd-access-label {
  flex:0 0 auto; font-size:0.68rem; text-transform:uppercase; letter-spacing:.04em;
  color:var(--text-muted); padding-top:0.18rem; min-width:52px;
}
.pn-cmd-access-deny .pn-cmd-access-label { color:var(--red); }
.pn-cmd-chips { display:flex; flex-wrap:wrap; gap:0.3rem; }
.pn-cmd-chip {
  display:inline-flex; align-items:center; gap:0.25rem; font-size:0.71rem;
  padding:0.15rem 0.45rem; border-radius:20px; border:1px solid var(--border);
  background:rgba(255,255,255,.03); color:var(--text); max-width:100%;
}
.pn-cmd-chip ion-icon { font-size:12px; opacity:.7; flex:0 0 auto; }
.pn-cmd-chip-allow { border-color:rgba(34,197,94,.4); background:rgba(34,197,94,.1); }
.pn-cmd-chip-deny  { border-color:rgba(239,68,68,.4); background:rgba(239,68,68,.1); }
.pn-cmd-chip-administrator { border-color:rgba(88,101,242,.4); background:rgba(88,101,242,.1); }
.pn-cmd-none { font-size:0.73rem; color:var(--text-muted); }

/* Per-command ON/OFF switch (Punishments → Commands). The shared .toggle-btn, scaled
   down and pushed to the row's right edge; a disabled command's line is dimmed with
   its command name struck through so the state reads without reading the switch. */
.pn-cmd-toggle { flex:0 0 auto; margin-left:auto; transform:scale(.68); transform-origin:right center; }
.pn-cmd-usage-off code { opacity:.45; text-decoration:line-through; }
.pn-cmd-usage-off .pn-cmd-usage-desc,
.pn-cmd-usage-off .pn-cmd-surface { opacity:.6; }

/* Command category tabs (the MEE6-plugins pattern): the full capability list is one
   long scroll, so categories are picked from a text tab strip rather than scrolled
   to. Text tabs over a shared hairline, the active one lifted by a crimson underline
   — the same palette the page's main tab strip uses, in underline form. */
.pn-cmd-tabs {
  display:flex; gap:0.25rem; align-items:center; flex-wrap:wrap;
  border-bottom:1px solid var(--border); margin:0 0 1rem; overflow-x:auto;
}
.pn-cmd-tab {
  display:inline-flex; align-items:center; gap:0.35rem; padding:0.55rem 0.8rem;
  background:transparent; border:none; border-bottom:2px solid transparent;
  margin-bottom:-1px; color:var(--text-muted); font-size:0.82rem; cursor:pointer;
  white-space:nowrap; transition:color .15s, border-color .15s;
}
.pn-cmd-tab ion-icon { font-size:14px; flex:0 0 auto; }
.pn-cmd-tab:hover { color:var(--text); }
.pn-cmd-tab.active { color:#fff; border-bottom-color:rgba(220,38,38,.8); }

/* A subject list longer than three chips collapses behind "Show more" (native
   <details>, so no wiring and the one-shot render just works): the summary holds
   the preview chips plus the toggle, and opening it swaps the preview for the
   full list — so a busy capability cannot stretch its whole grid row. */
.pn-cmd-chips-more summary {
  display:flex; flex-wrap:wrap; gap:0.3rem; align-items:center;
  cursor:pointer; list-style:none;
}
.pn-cmd-chips-more summary::-webkit-details-marker { display:none; }
.pn-cmd-chips-more .pn-cmd-more-toggle {
  display:inline-flex; align-items:center; gap:0.25rem; font-size:0.71rem;
  padding:0.15rem 0.45rem; border-radius:20px; border:1px dashed var(--border-strong);
  color:var(--text-muted); white-space:nowrap; user-select:none;
}
.pn-cmd-chips-more .pn-cmd-more-toggle ion-icon { font-size:12px; flex:0 0 auto; }
.pn-cmd-chips-more summary:hover .pn-cmd-more-toggle { color:var(--text); }
.pn-cmd-chips-more .pn-cmd-more-less { display:none; }
.pn-cmd-chips-more[open] summary { margin-bottom:0.3rem; }
.pn-cmd-chips-more[open] summary > .pn-cmd-chips { display:none; }
.pn-cmd-chips-more[open] summary > .pn-cmd-more-toggle:not(.pn-cmd-more-less) { display:none; }
.pn-cmd-chips-more[open] summary > .pn-cmd-more-less { display:inline-flex; }

/* Access editor (modal) */
.pn-cmd-add { display:flex; flex-direction:column; gap:0.5rem; margin-bottom:0.9rem; }
.pn-cmd-add .pm-userlist { max-height:190px; overflow-y:auto; }
.pn-ca-row {
  display:flex; align-items:center; gap:0.6rem; padding:0.5rem 0.6rem;
  border:1px solid var(--border); border-radius:10px; margin-bottom:0.4rem;
}
.pn-ca-row .pn-mod-main { flex:1; min-width:0; }

@media (max-width:640px) {
  .pn-cmd-grid { grid-template-columns:1fr; }
  .pn-cmd-toolbar .input, .pn-cmd-search { max-width:none; width:100%; }
  .pn-ca-row { flex-wrap:wrap; }
  .pn-ca-row .pm-seg { width:100%; }
}
