/* ============================================================================
   19 · LOGGING PAGE

   `er-*` — the event-routing card grid. `lcp-*` — the logging control panel.

   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.
   ========================================================================== */

/* ═══════════════════════════════════════════════════════════════════════════════
   LOGGING PAGE — event-routing card grid (`er-*`) + logging control panel (`lcp-*`)

   The Logging page is a searchable/filterable GRID OF EVENT CARDS beside a sticky
   settings sidebar, not a list of accordion rows. Two namespaces, deliberately
   separate because they are two different things: `er-*` is the routing surface
   (header, toolbar, sections, cards, configure modal) and `lcp-*` is the control
   panel down the right-hand side (master switch card, quick setup, overview,
   health, quick actions, recommendations, session activity).

   Everything here is layout on top of the existing theme — every colour, radius,
   font and easing resolves to a token already defined at the top of this file,
   and the cards reuse `.gw-card`'s glass language and `.gw-status`'s badge
   language rather than restating them. The page's functional hooks are unchanged
   from the old list layout (`.log-row[data-key]`, `.toggle-btn[data-rowtoggle]`,
   `select.log-row-channel`, `#log-master`, `#log-default-channel`,
   `#log-mod-channel`, `#log-quick-btn`), so `pages/logging.js`'s save contract
   sits on top of this untouched.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* ── Page layout — 3fr/1fr split; the sidebar reflows ABOVE the grid on tablet ──
   align-items:start so each column is only as tall as its own content. The sidebar
   is a plain flow column (see `.lcp-stack`), so there is no sticky child needing a
   full-height box to travel within — stretch would just leave dead space under the
   shorter column. */
.er-page-layout { display:grid; grid-template-columns:3fr 1fr; gap:1.75rem; margin-top:1.5rem;
  align-items:start; }
.er-main { min-width:0; }
.er-main .er-root { margin-top:0; }
.er-page-layout .lcp-sidebar { order:2; }
@media (max-width:1180px) {
  .er-page-layout { grid-template-columns:1fr; }
  .er-page-layout .lcp-sidebar { order:-1; }
}

.er-root { display:flex; flex-direction:column; gap:1.75rem; margin-top:1.5rem; }

/* ── 1. Header — title/subtitle, master card, Total/Enabled/Disabled stats ── */
.er-head { display:flex; align-items:flex-start; justify-content:space-between; gap:1.5rem; flex-wrap:wrap; }
.er-head-text { min-width:0; }
.er-eyebrow { display:inline-flex; align-items:center; gap:.4rem; font-size:.7rem; font-weight:800;
  text-transform:uppercase; letter-spacing:.1em; color:var(--crimson-glow); margin-bottom:.5rem; }
.er-eyebrow ion-icon { font-size:.95rem; }
.er-title { font-family:var(--font-display); font-size:1.85rem; font-weight:800; letter-spacing:-.02em;
  color:var(--text-primary); line-height:1.15; }
.er-subtitle { font-size:.925rem; color:var(--text-secondary); margin-top:.5rem; max-width:52ch; line-height:1.55; }

/* There is deliberately no header health/last-edited badge row here. Both pills
   restated what the sidebar's health and Recent Changes cards say (the health card
   with the fix, the activity card with the timestamps), so the row was dropped
   along with its `.er-badge*` rules rather than kept as dead CSS. */

.er-stats { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:1rem; flex-shrink:0; width:min(30rem,100%); }
@media (max-width:640px) { .er-stats { gap:.6rem; } }

/* Master switch — its own glass card in the header row (label + description left,
   status pill + toggle right), because the switch for the whole page belongs where
   it is seen first, not buried in the sidebar. */
.er-master-card { display:flex; align-items:center; justify-content:space-between; gap:1.25rem;
  background:linear-gradient(160deg, rgba(255,255,255,.05), transparent 45%), var(--glass);
  border:1px solid var(--border); border-radius:20px; padding:.9rem 1.25rem;
  backdrop-filter:blur(18px) saturate(150%); -webkit-backdrop-filter:blur(18px) saturate(150%);
  box-shadow:0 14px 34px -16px rgba(0,0,0,.5); flex-shrink:0; min-width:19rem;
  transition:transform .3s var(--ease), box-shadow .3s var(--ease), border-color .3s; }
.er-master-card:hover { transform:translateY(-3px); border-color:rgba(220,38,38,.35); box-shadow:0 22px 46px -18px rgba(0,0,0,.55); }
.er-master-card-text { display:flex; flex-direction:column; gap:.2rem; min-width:0; }
.er-master-card-label { font-family:var(--font-display); font-size:.92rem; font-weight:800; letter-spacing:-.01em; color:var(--text-primary); }
.er-master-card-desc { font-size:.72rem; color:var(--text-muted); line-height:1.4; max-width:15rem; }
.er-master-card-actions { display:flex; align-items:center; gap:.85rem; flex-shrink:0; }

.lcp-master-status { display:inline-flex; align-items:center; gap:.4rem; white-space:nowrap;
  font-size:.66rem; font-weight:800; text-transform:uppercase; letter-spacing:.04em;
  padding:.3rem .65rem; border-radius:999px;
  background:rgba(255,255,255,.05); border:1px solid var(--border-strong); color:var(--text-muted);
  transition:background .3s, border-color .3s, color .3s; }
.lcp-master-status.is-on { color:var(--pistachio-light); background:rgba(147,197,114,.14); border-color:rgba(147,197,114,.4); }
.lcp-master-dot { width:.4rem; height:.4rem; border-radius:50%; background:var(--text-muted); transition:background .3s, box-shadow .3s; }
.lcp-master-status.is-on .lcp-master-dot { background:var(--pistachio); box-shadow:0 0 8px 1px rgba(147,197,114,.7); }

/* Same #log-master button/id/aria-pressed contract as before, sized to sit inside
   a compact header card. */
button.lcp-master-toggle { width:3.35rem; height:1.85rem; border-radius:999px; position:relative; flex-shrink:0;
  background:var(--surface-hover); border:1px solid var(--border-strong); padding:0; cursor:pointer;
  transition:background .4s var(--ease), box-shadow .4s var(--ease), border-color .3s, transform .2s var(--ease); }
button.lcp-master-toggle:hover { transform:scale(1.05); }
button.lcp-master-toggle .toggle-thumb { position:absolute; top:2px; left:2px; width:1.55rem; height:1.55rem; border-radius:50%;
  background:#fff; box-shadow:0 2px 6px rgba(0,0,0,.4); transition:transform .45s var(--spring); }
button.lcp-master-toggle.on { background:linear-gradient(135deg, var(--pistachio), var(--pistachio-dark)); border-color:transparent;
  box-shadow:0 0 0 4px rgba(147,197,114,.16), 0 6px 18px -6px rgba(147,197,114,.65);
  animation:lcp-pulse 2.4s ease-in-out infinite; }
button.lcp-master-toggle.on .toggle-thumb { transform:translateX(1.5rem); box-shadow:0 2px 6px rgba(0,0,0,.4), 0 0 10px 1px rgba(255,255,255,.65); }
@keyframes lcp-pulse {
  0%,100% { box-shadow:0 0 0 4px rgba(147,197,114,.16), 0 6px 18px -6px rgba(147,197,114,.65); }
  50%     { box-shadow:0 0 0 7px rgba(147,197,114,.08), 0 6px 22px -4px rgba(147,197,114,.8); }
}
/* The .on animation rewrites box-shadow every frame and would mask any focus ring
   however specific — so the on+focused combination gets its own keyframes with the
   ring baked in, rather than a rule the animation immediately paints over. */
button.lcp-master-toggle.on:focus-visible { outline:none; animation:lcp-pulse-focus 2.4s ease-in-out infinite; }
@keyframes lcp-pulse-focus {
  0%,100% { box-shadow:0 0 0 4px rgba(147,197,114,.16), 0 6px 18px -6px rgba(147,197,114,.65), 0 0 0 7px rgba(220,38,38,.55); }
  50%     { box-shadow:0 0 0 7px rgba(147,197,114,.08), 0 6px 22px -4px rgba(147,197,114,.8), 0 0 0 7px rgba(220,38,38,.55); }
}
@media (prefers-reduced-motion:reduce) {
  button.lcp-master-toggle.on, .er-master-card { animation:none; transition:none; }
  button.lcp-master-toggle.on:focus-visible { animation:none; box-shadow:0 0 0 4px rgba(147,197,114,.16), 0 0 0 7px rgba(220,38,38,.55); }
}
@media (max-width:1180px) {
  .er-master-card { flex-basis:100%; order:2; min-width:0; }
  .er-head-text { order:1; }
  .er-stats { order:3; }
}
@media (max-width:640px) {
  .er-master-card { width:100%; padding:1rem 1.1rem; }
  .er-master-card-desc { max-width:none; }
  /* Bigger switch on touch so the tappable box clears the 44x44px minimum. Sized
     against a 15px root — style.css drops html to 93.75% under 900px, not 16px —
     so 3rem/4.8rem is what actually lands on ~45x72px there. */
  button.lcp-master-toggle { width:4.8rem; height:3rem; }
  button.lcp-master-toggle .toggle-thumb { width:2.6rem; height:2.6rem; top:3px; left:3px; }
  button.lcp-master-toggle.on .toggle-thumb { transform:translateX(1.8rem); }
}

/* ── 2. Toolbar — search / category / status / enabled-only / sort ── */
.er-toolbar { display:flex; align-items:center; gap:.75rem; flex-wrap:wrap; padding:.9rem 1rem; border-radius:18px;
  background:var(--glass); border:1px solid var(--border);
  backdrop-filter:blur(16px) saturate(150%); -webkit-backdrop-filter:blur(16px) saturate(150%); }
.er-search { position:relative; flex:1 1 15rem; min-width:11rem; }
.er-search > ion-icon { position:absolute; left:.85rem; top:50%; transform:translateY(-50%);
  color:var(--text-muted); font-size:1rem; pointer-events:none; }
.er-search input { width:100%; padding-left:2.35rem; }
.er-search .er-clear { position:absolute; right:.5rem; top:50%; transform:translateY(-50%);
  width:1.5rem; height:1.5rem; border-radius:50%; display:none; align-items:center; justify-content:center;
  color:var(--text-muted); background:transparent; border:none; cursor:pointer; font-size:1rem; }
.er-search.has-value .er-clear { display:flex; }
.er-search .er-clear:hover { background:rgba(255,255,255,.08); color:#fff; }
/* select-enhance.js replaces each <select> with a `.cs-wrap` (display:block,
   width:100%) that becomes the flex item, so sizing only the <select> would leave
   three full-width dropdowns stacked down the toolbar. Both are targeted, and the
   wrap is pinned to its content width so `.er-toolbar-count`'s margin-left:auto
   still pushes the count to the far end. */
.er-toolbar select.select, .er-toolbar .cs-wrap { min-width:9.5rem; width:auto; flex:0 0 auto; }
.er-toolbar-divider { width:1px; align-self:stretch; background:var(--border); margin:0 .1rem; }
.er-enabled-only { display:inline-flex; align-items:center; gap:.55rem; font-size:.8125rem; font-weight:600;
  color:var(--text-secondary); white-space:nowrap; cursor:pointer; }
.er-toolbar-count { font-size:.78rem; color:var(--text-muted); white-space:nowrap; margin-left:auto; padding-left:.25rem; }
.er-toolbar-count b { color:var(--text-secondary); font-weight:700; }

/* Checkbox skinned as a switch — same <input type="checkbox">, ids/attrs untouched. */
input.er-switch[type="checkbox"] { -webkit-appearance:none; appearance:none; width:2.65rem; height:1.5rem;
  border-radius:999px; background:var(--surface-hover); border:1px solid var(--border-strong);
  position:relative; flex-shrink:0; cursor:pointer; margin:0;
  transition:background .35s var(--ease), border-color .3s, box-shadow .35s var(--ease); }
input.er-switch[type="checkbox"]::before { content:""; position:absolute; top:2px; left:2px;
  width:1.1rem; height:1.1rem; border-radius:50%; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.4);
  transition:transform .45s var(--spring), box-shadow .3s; }
input.er-switch[type="checkbox"]:hover { filter:brightness(1.08); }
input.er-switch[type="checkbox"]:checked { background:linear-gradient(135deg, var(--crimson), var(--crimson-dark));
  border-color:transparent; box-shadow:0 0 0 3px rgba(220,38,38,.15), 0 4px 16px -4px rgba(220,38,38,.6); }
input.er-switch[type="checkbox"]:checked::before { transform:translateX(1.13rem);
  box-shadow:0 1px 3px rgba(0,0,0,.4), 0 0 8px 1px rgba(255,255,255,.6); }
input.er-switch[type="checkbox"]:focus-visible { outline:none; box-shadow:var(--ring-blue); }

/* ── 3. Sections — a collapsible heading above each card grid ── */
.er-section { display:flex; flex-direction:column; gap:1rem; }
.er-section-head { display:flex; align-items:center; gap:.8rem; cursor:pointer; user-select:none;
  padding:.5rem .6rem; margin:-.5rem -.6rem; border-radius:14px; transition:background .2s var(--ease); }
.er-section-head:hover { background:rgba(255,255,255,.03); }
.er-section-head:hover .er-section-icon { transform:scale(1.06) rotate(-4deg); }
.er-section-icon { width:2.35rem; height:2.35rem; border-radius:12px; display:flex; align-items:center; justify-content:center;
  font-size:1.05rem; flex-shrink:0; background:var(--er-accent-bg, rgba(220,38,38,.13)); color:var(--er-accent, var(--crimson-glow));
  box-shadow:inset 0 0 0 1px var(--er-accent-bd, rgba(220,38,38,.3)); transition:transform .3s var(--spring); }
.er-section-title { font-family:var(--font-display); font-size:1.05rem; font-weight:800; letter-spacing:-.01em;
  display:flex; align-items:center; gap:.55rem; flex-wrap:wrap; }
.er-section-count { font-size:.72rem; font-weight:700; color:var(--text-muted); background:rgba(255,255,255,.05);
  border:1px solid var(--border); border-radius:999px; padding:.15rem .55rem; }
.er-section-desc { font-size:.78rem; color:var(--text-muted); margin-top:.15rem; }
.er-section-chevron { margin-left:auto; flex-shrink:0; display:flex; color:var(--text-muted); font-size:1.15rem;
  transform:rotate(180deg); transition:transform .3s var(--ease); }
.er-section.collapsed .er-section-chevron { transform:rotate(0deg); }
.er-section.collapsed .er-section-head { background:rgba(255,255,255,.02); }
.er-section-body { overflow:visible; transition:max-height .4s var(--ease); }
.er-section.collapsed .er-section-body { overflow:hidden; max-height:0 !important; }

.er-subgroup { display:flex; flex-direction:column; gap:.75rem; margin-top:.25rem; }
.er-subgroup + .er-subgroup { margin-top:1rem; }
.er-subgroup-title { font-size:.7rem; font-weight:700; text-transform:uppercase; letter-spacing:.08em;
  color:var(--text-muted); opacity:.8; padding-left:.1rem; }
/* Integrations holds one card per subgroup, so stacking them just repeats
   "label + one card" three times — lay them side by side instead. Each subgroup's
   own grid still only has to fit its single card, so it fills the narrower column. */
#acc-integr .er-section-body { display:flex; gap:1.1rem; }
#acc-integr .er-subgroup { flex:1; margin-top:0; }
@media (max-width:900px) { #acc-integr .er-section-body { flex-direction:column; } }

/* ── 4. Card grid ──
   Flexbox, not CSS Grid, on purpose: grid shares one column template across every
   row, so a trailing partial row (7 cards -> 4+3) or a section with fewer cards
   than the column count leaves dead equal-width tracks. Flex distributes leftover
   space per LINE, so a sparse section or a short last row fills out cleanly. */
.er-grid { display:flex; flex-wrap:wrap; gap:1.1rem; }
.er-card { flex:1 1 260px; max-width:340px; }
@media (max-width:1400px) { .er-card { flex-basis:240px; max-width:320px; } }
@media (max-width:1024px) { .er-card { flex-basis:220px; max-width:300px; } }
@media (max-width:620px)  { .er-card { flex-basis:100%; max-width:none; } }

/* ── 5. Event card ── */
.er-card { --ga-accent:var(--er-accent, var(--crimson-glow)); position:relative;
  display:flex; flex-direction:column; gap:.85rem; border-radius:20px !important;
  padding:1.25rem 1.25rem 1.1rem; animation:er-card-in .45s var(--ease) backwards; }
.er-card.er-hidden { display:none !important; }
@keyframes er-card-in { from { opacity:0; transform:translateY(10px) scale(.98); } to { opacity:1; transform:none; } }
@media (prefers-reduced-motion:reduce) { .er-card { animation:none; } }

.er-card-top { display:flex; align-items:flex-start; justify-content:space-between; gap:.5rem; }
.er-card-icon { width:2.75rem; height:2.75rem; border-radius:14px; display:flex; align-items:center; justify-content:center;
  font-size:1.3rem; flex-shrink:0; background:var(--er-accent-bg, rgba(220,38,38,.14)); color:var(--er-accent, var(--crimson-glow));
  box-shadow:inset 0 0 0 1px var(--er-accent-bd, rgba(220,38,38,.32));
  transition:transform .35s var(--spring), box-shadow .35s var(--ease); }
.er-card:hover .er-card-icon { transform:scale(1.1) rotate(-4deg);
  box-shadow:inset 0 0 0 1px var(--er-accent-bd, rgba(220,38,38,.45)), 0 8px 20px -6px var(--er-accent, rgba(220,38,38,.5)); }
.er-card-icon ion-icon { font-size:1.35rem; }

.er-kebab-wrap { position:relative; flex-shrink:0; }
.er-kebab-btn { width:2rem; height:2rem; border-radius:9px; display:flex; align-items:center; justify-content:center;
  background:transparent; border:1px solid transparent; color:var(--text-muted); cursor:pointer; font-size:1.05rem;
  transition:background .2s var(--ease), color .2s var(--ease), border-color .2s var(--ease); }
.er-kebab-btn:hover, .er-kebab-btn.open { background:rgba(255,255,255,.06); border-color:var(--border-strong); color:#fff; }
.er-kebab-menu { position:absolute; top:calc(100% + 6px); right:0; min-width:12rem; z-index:40;
  background:var(--glass-strong); border:1px solid var(--border-strong); border-radius:12px;
  box-shadow:0 20px 44px -14px rgba(0,0,0,.6); backdrop-filter:blur(18px) saturate(160%);
  -webkit-backdrop-filter:blur(18px) saturate(160%); padding:.35rem; display:none;
  animation:er-menu-in .18s var(--ease); }
.er-kebab-menu.open { display:block; }
@keyframes er-menu-in { from { opacity:0; transform:translateY(-4px) scale(.97); } to { opacity:1; transform:none; } }
/* An OPEN menu is portaled to <body>, so it is no longer inside `.er-kebab-wrap` and
   the `absolute` / `top` / `right` above have nothing left to resolve against — every
   edge is set from JS instead. `right:auto` is load-bearing: with `position:fixed`,
   a JS-set `left` PLUS the inherited `right:0` would stretch the menu across the
   whole viewport rather than sizing it to its content.

   This exists because a menu drawn inside the card cannot be made to work. `.gw-card`
   (13-giveaways.css) sets `overflow:hidden`, which literally cut the menu off at the
   card's edge; and `transform-style:preserve-3d` plus the hover `translateY` make
   every card BOTH its own stacking context — so no z-index inside it could lift the
   menu over a neighbouring card — and a containing block, so even `position:fixed`
   would have resolved against the card instead of the viewport. That file documents
   the same trap for `.cs-open` two rules below the one that causes it.

   Portaling is the fix `select-enhance.js` already uses for its own dropdowns, so
   this mirrors `.cs-menu.cs-portal` — but at 8500 rather than 10050: a kebab is page
   chrome and is never opened inside a modal, so it must stay BELOW `.modal-overlay`
   (9000) while still clearing the savebar (60) and every card. */
.er-kebab-menu.er-kebab-portal { position:fixed; top:auto; right:auto; z-index:8500; }
/* Flipped upward (not enough room below). The entrance animation has to come from
   the other direction, or a menu opening ABOVE its button appears to slide downward
   out of it. */
.er-kebab-menu.er-kebab-up { animation-name:er-menu-in-up; }
@keyframes er-menu-in-up { from { opacity:0; transform:translateY(4px) scale(.97); } to { opacity:1; transform:none; } }
.er-kebab-item { display:flex; align-items:center; gap:.55rem; width:100%; padding:.5rem .6rem; border-radius:8px;
  background:none; border:none; color:var(--text-secondary); font-size:.8125rem; font-weight:600; text-align:left; cursor:pointer;
  transition:background .15s var(--ease), color .15s var(--ease); }
.er-kebab-item:hover { background:rgba(220,38,38,.12); color:#fff; }
.er-kebab-item ion-icon { font-size:.95rem; opacity:.85; flex-shrink:0; }

.er-card-name { font-size:.925rem; font-weight:700; color:var(--text); line-height:1.35; }
.er-card-desc { font-size:.78rem; color:var(--text-muted); line-height:1.5; margin-top:.3rem; }
.er-card-badges { display:flex; flex-wrap:wrap; gap:.4rem; margin-top:.1rem; }
.er-cat-badge { display:inline-flex; align-items:center; font-size:.66rem; font-weight:700; letter-spacing:.02em;
  padding:.22rem .55rem; border-radius:999px; background:rgba(255,255,255,.05); border:1px solid var(--border-strong);
  color:var(--text-secondary); white-space:nowrap; }
/* "Detected by Azra" — the event's information does not come from Discord's audit log.
   Tinted so it reads as a property of the event rather than as another category chip,
   and carrying `help` so the title attribute is discoverable as an explanation. */
.er-src-badge { background:rgba(88,101,242,.13); border-color:rgba(88,101,242,.34);
  color:#A5B0F5; cursor:help; }
/* The card's picker is scaled down to card size. The inline font-size on the
   <select> is not one of the properties select-enhance carries onto the wrap, so
   the visible trigger has to be sized here. */
.er-card-channel { margin-top:.1rem; }
.er-card-channel .cs-trigger, .er-card-channel select.select { font-size:.8rem; }
.er-card-footer { margin-top:auto; padding-top:.9rem; border-top:1px solid var(--border);
  display:flex; align-items:center; justify-content:space-between; gap:.6rem; }
/* A card whose event has nothing to configure carries only its toggle. `gap` and
   `space-between` both no-op on a single child, so the modifier is about SAYING the
   footer holds one control rather than about moving anything — without it the rule
   above reads as though a second child were merely missing. `margin-top:auto` still
   pins the row to the bottom, so a card with no button lines up with one that has
   it and the grid keeps a single baseline. */
.er-card-footer--solo { justify-content:flex-start; gap:0; }
.er-card-footer .toggle-btn, .er-configure-btn { flex-shrink:0; }

/* ── 6. Empty state (every card filtered out) ── */
.er-empty { display:none; }
.er-empty.show { display:flex; }
.er-empty .empty-state-icon { font-size:3.25rem; }

/* ── 7. Configure modal ── */
#modal-er-configure .modal { width:min(620px,95vw); }
.er-modal-title-wrap { display:flex; align-items:center; gap:.7rem; min-width:0; }
.er-modal-icon { width:2.35rem; height:2.35rem; border-radius:12px; display:flex; align-items:center; justify-content:center;
  font-size:1.05rem; flex-shrink:0; background:rgba(220,38,38,.14); color:var(--crimson-glow); }
.er-modal-title { font-weight:700; font-size:.95rem; }
.er-modal-sub { font-size:.74rem; color:var(--text-muted); margin-top:1px; }
.er-modal-body { padding:1.25rem 1.35rem; display:flex; flex-direction:column; gap:1.3rem; max-height:70vh; overflow-y:auto; }
.er-modal-section-title { font-size:.68rem; font-weight:800; text-transform:uppercase; letter-spacing:.09em;
  color:var(--text-muted); margin-bottom:.65rem; display:flex; align-items:center; gap:.4rem; }
.er-modal-section-title ion-icon { font-size:.9rem; }
.er-modal-row { display:flex; align-items:center; justify-content:space-between; gap:.75rem; padding:.55rem 0; }
.er-modal-row:not(:last-child) { border-bottom:1px solid var(--border); }
.er-modal-row-text strong { font-size:.8125rem; font-weight:700; color:var(--text); display:block; }
.er-modal-row-text span { font-size:.74rem; color:var(--text-muted); }
.er-modal-note { font-size:.76rem; color:var(--text-secondary); line-height:1.6; }
.er-modal-note code { font-family:var(--font-mono); font-size:.72rem; color:var(--text); }
@media (max-width:560px) { #modal-er-configure .modal { width:100vw; } }

/* ── 7b. Routing preview modal (`rp-*`) ──
   Answers "where do my logs go" as a structure rather than a sentence: the
   fallback chain, one collapsible block per destination channel, and inside it
   the events grouped by HOW they arrived (own channel / mod sink / default sink).
   Everything resolves to existing tokens — this is layout, not a second theme. */
#log-route-dialog { width:min(760px,95vw); }
@media (max-width:560px) { #log-route-dialog { width:100vw; } }

.rp-banner { display:flex; gap:.7rem; align-items:flex-start; padding:.8rem .9rem; border-radius:12px;
  background:rgba(255,255,255,.04); border:1px solid var(--border); font-size:.8rem; line-height:1.55;
  color:var(--text-secondary); }
.rp-banner ion-icon { font-size:1.1rem; flex-shrink:0; margin-top:.05rem; color:var(--text-muted); }
.rp-banner strong { color:var(--text); }
.rp-banner--off { background:rgba(var(--red-rgb),.09); border-color:rgba(var(--red-rgb),.32); }
.rp-banner--off ion-icon { color:var(--red); }
.rp-banner--bad { background:rgba(245,158,11,.09); border-color:rgba(245,158,11,.32); }
.rp-banner--bad ion-icon { color:var(--yellow); }

.rp-stats { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:.55rem; }
@media (max-width:560px) { .rp-stats { grid-template-columns:repeat(2,minmax(0,1fr)); } }
.rp-stat { padding:.65rem .7rem; border-radius:12px; background:rgba(255,255,255,.04);
  border:1px solid var(--border); text-align:center; }
.rp-stat b { display:block; font-size:1.25rem; font-weight:800; color:var(--text); line-height:1.15; }
.rp-stat span { font-size:.66rem; font-weight:700; text-transform:uppercase; letter-spacing:.06em;
  color:var(--text-muted); }
.rp-stat--bad { background:rgba(var(--red-rgb),.1); border-color:rgba(var(--red-rgb),.3); }
.rp-stat--bad b { color:var(--red); }
.rp-stat--muted b { color:var(--text-muted); }

.rp-chain { display:flex; flex-wrap:wrap; align-items:center; gap:.4rem; }
.rp-chain > ion-icon { font-size:.85rem; color:var(--text-muted); flex-shrink:0; }
.rp-chain-step { display:inline-flex; align-items:center; gap:.4rem; padding:.35rem .6rem; border-radius:999px;
  background:rgba(255,255,255,.05); border:1px solid var(--border-strong); font-size:.74rem;
  font-weight:600; color:var(--text-secondary); }
.rp-chain-step b { display:inline-flex; align-items:center; justify-content:center; width:1.05rem; height:1.05rem;
  border-radius:50%; background:rgba(220,38,38,.18); color:var(--crimson-glow); font-size:.62rem; font-weight:800; }
.rp-chain-step em { font-style:normal; font-family:var(--font-mono); font-size:.7rem; color:var(--text); }
.rp-chain-step--unset { opacity:.6; }
.rp-chain-step--unset em { color:var(--text-muted); }
.rp-title--bad { color:var(--red); }

/* A destination. `<details>` because the disclosure is native — no JS state to
   keep in step with the arrow, and Expand all just writes `.open`. */
.rp-dest { border:1px solid var(--border); border-radius:12px; background:rgba(255,255,255,.025);
  overflow:hidden; }
.rp-dest + .rp-dest { margin-top:.5rem; }
.rp-dest > summary { list-style:none; cursor:pointer; display:flex; align-items:center; gap:.5rem;
  padding:.65rem .8rem; transition:background .15s var(--ease); }
.rp-dest > summary::-webkit-details-marker { display:none; }
.rp-dest > summary:hover { background:rgba(255,255,255,.045); }
.rp-chev { font-size:.9rem; color:var(--text-muted); flex-shrink:0;
  transition:transform .18s var(--ease); }
.rp-dest[open] > summary .rp-chev { transform:rotate(90deg); }
.rp-dest-name { font-family:var(--font-mono); font-size:.8rem; font-weight:700; color:var(--text);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rp-dest-count { margin-left:auto; flex-shrink:0; font-size:.7rem; font-weight:700; color:var(--text-muted);
  white-space:nowrap; }
.rp-dest-body { padding:.2rem .8rem .85rem; display:flex; flex-direction:column; gap:.85rem; }
.rp-dest--muted .rp-dest-name { font-family:inherit; color:var(--text-secondary); }
.rp-tag { display:inline-flex; align-items:center; gap:.25rem; flex-shrink:0; padding:.16rem .45rem;
  border-radius:999px; font-size:.63rem; font-weight:700; letter-spacing:.02em; white-space:nowrap;
  background:rgba(255,255,255,.06); border:1px solid var(--border-strong); color:var(--text-secondary); }
.rp-tag ion-icon { font-size:.72rem; }
.rp-tag--mod { background:rgba(var(--red-rgb),.14); border-color:rgba(var(--red-rgb),.35); color:var(--red); }

.rp-via-head { display:flex; align-items:center; gap:.4rem; flex-wrap:wrap; margin-bottom:.5rem; }
.rp-via-head ion-icon { font-size:.85rem; color:var(--text-muted); }
.rp-via-head strong { font-size:.74rem; font-weight:700; color:var(--text-secondary); }
.rp-via-count { display:inline-flex; align-items:center; justify-content:center; min-width:1.25rem; height:1.25rem;
  padding:0 .35rem; border-radius:999px; background:rgba(255,255,255,.07); border:1px solid var(--border-strong);
  font-size:.65rem; font-weight:800; color:var(--text); }
.rp-via-hint { font-size:.7rem; color:var(--text-muted); }

.rp-events { display:flex; flex-wrap:wrap; gap:.35rem; }
.rp-event { display:inline-flex; align-items:baseline; gap:.4rem; max-width:100%; padding:.28rem .55rem;
  border-radius:8px; background:rgba(255,255,255,.045); border:1px solid var(--border);
  border-left:3px solid var(--rp-accent,var(--crimson)); font-size:.75rem; font-weight:600; color:var(--text); }
.rp-event code { font-family:var(--font-mono); font-size:.63rem; color:var(--text-muted);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* ── 8. Sidebar shell ── */
.lcp-sidebar { min-width:0; }
/* ONE scrollbar on this page, and it is the page's own. This panel is a plain flow
   column — no `position:sticky`, no `max-height`, no `overflow-y` — so it scrolls
   with everything else instead of trapping a second scrollport inside the first.
   It was sticky-with-its-own-scroll, which is what produced the nested bar: the
   panel is taller than the viewport (destinations, Quick Setup, health, quick
   actions, the checklist and the change feed), so pinning it forces a cap, the cap
   forces an inner scroller, and the inner scroller then has to fight the 56px topbar
   and the sticky savebar for the last card to stay reachable at all. Dropping the
   pin deletes that whole class of problem rather than tuning it.
   DO NOT re-add `position:sticky` here without also capping the panel's CONTENT —
   a pinned column taller than the viewport simply cannot scroll to its own end. */
.lcp-stack { display:flex; flex-direction:column; gap:1.1rem; }

.lcp-card { position:relative;
  background:linear-gradient(160deg, rgba(255,255,255,.05), transparent 40%), var(--glass);
  border:1px solid var(--border); border-radius:20px; padding:1.35rem 1.35rem 1.25rem;
  backdrop-filter:blur(18px) saturate(150%); -webkit-backdrop-filter:blur(18px) saturate(150%);
  box-shadow:0 14px 34px -16px rgba(0,0,0,.5); flex-shrink:0;
  transition:transform .35s var(--ease), box-shadow .35s var(--ease), border-color .3s; }
.lcp-card:hover { transform:translateY(-3px); border-color:rgba(220,38,38,.35); box-shadow:0 22px 46px -18px rgba(0,0,0,.55); }
.lcp-card-title { font-family:var(--font-display); font-size:.85rem; font-weight:800; letter-spacing:-.01em;
  display:flex; align-items:center; gap:.45rem; margin-bottom:.9rem; }
.lcp-card-title ion-icon { color:var(--crimson-glow); font-size:1rem; }

/* ── 9. Hero — the two destination channels ── */
.lcp-hero { text-align:center; padding-top:1.6rem; }
.lcp-hero-icon { width:3.25rem; height:3.25rem; margin:0 auto .9rem; border-radius:16px;
  display:flex; align-items:center; justify-content:center; font-size:1.5rem;
  background:rgba(220,38,38,.14); color:var(--crimson-glow);
  box-shadow:inset 0 0 0 1px rgba(220,38,38,.32), 0 8px 20px -8px rgba(220,38,38,.45); }
.lcp-hero-title { font-family:var(--font-display); font-size:1.15rem; font-weight:800; letter-spacing:-.01em; }
.lcp-hero-desc { font-size:.78rem; color:var(--text-muted); line-height:1.55; margin:.4rem auto 0; max-width:22rem; }
.lcp-channels { display:flex; flex-direction:column; gap:.9rem; margin-top:1.3rem; text-align:left;
  border-top:1px solid var(--border); padding-top:1.1rem; }
/* The title row and its "· mod, automod & security" annotation are separate
   block-level lines rather than one nowrap flex line — crammed together they
   collapsed into garbled two-column wrapping once this column narrowed (which it
   does at ordinary 1280px laptop widths, where it is only ~230px wide). */
.lcp-field-label { display:flex; align-items:center; flex-wrap:wrap; gap:.3rem; font-size:.72rem; font-weight:700;
  color:var(--text-secondary); margin-bottom:.2rem; }
.lcp-field-label ion-icon { color:var(--red); flex-shrink:0; }
.lcp-field-hint { display:block; font-size:.68rem; font-weight:400; color:var(--text-muted); margin-bottom:.35rem; }

/* ── 10. Quick setup ── */
.lcp-quicksetup { background:linear-gradient(160deg, rgba(220,38,38,.12), rgba(147,197,114,.05) 60%, transparent), var(--glass); }
.lcp-quicksetup-head { font-family:var(--font-display); font-size:.95rem; font-weight:800; display:flex; align-items:center; gap:.4rem; }
.lcp-sparkle { display:inline-block; animation:lcp-sparkle-spin 3.5s ease-in-out infinite; }
@keyframes lcp-sparkle-spin { 0%,100% { transform:rotate(0deg) scale(1); } 50% { transform:rotate(14deg) scale(1.15); } }
.lcp-quicksetup-desc { font-size:.78rem; color:var(--text-secondary); line-height:1.55; margin:.5rem 0 1rem; }
.lcp-quicksetup-btn { width:100%; justify-content:center; }
.lcp-quicksetup-time { display:flex; align-items:center; gap:.4rem; font-size:.72rem; color:var(--text-muted); margin-top:.8rem; }
.lcp-quicksetup-time strong { color:var(--text-secondary); }

/* There is deliberately no sidebar stat grid. Its Enabled/Disabled tiles were the
   header `.er-stats` cards restated, and Coverage was those two as a percentage, so
   the block went rather than being left here unused. The header stat row is the one
   home for the counts. */

/* ── 11. Health ── */
.lcp-health { border-left:3px solid var(--text-muted); }
.lcp-health-body { display:flex; align-items:flex-start; gap:.7rem; }
.lcp-health-dot { width:.65rem; height:.65rem; border-radius:50%; margin-top:.3rem; flex-shrink:0;
  background:var(--text-muted); box-shadow:0 0 8px 1px currentColor; }
.lcp-health-state { font-size:.85rem; font-weight:800; }
.lcp-health-msg { font-size:.76rem; color:var(--text-muted); margin-top:.15rem; line-height:1.5; }
.lcp-health.state-excellent { border-left-color:var(--pistachio); }
.lcp-health.state-excellent .lcp-health-dot { background:var(--pistachio); color:var(--pistachio); }
.lcp-health.state-excellent .lcp-health-state { color:var(--pistachio-light); }
.lcp-health.state-attention { border-left-color:#F59E0B; }
.lcp-health.state-attention .lcp-health-dot { background:#F59E0B; color:#F59E0B; }
.lcp-health.state-attention .lcp-health-state { color:#F59E0B; }
.lcp-health.state-incomplete { border-left-color:#EF4444; }
.lcp-health.state-incomplete .lcp-health-dot { background:#EF4444; color:#EF4444; }
.lcp-health.state-incomplete .lcp-health-state { color:#FCA5A5; }

/* ── 12. Quick actions ── */
.lcp-actions { display:flex; flex-direction:column; gap:.55rem; }
.lcp-action { display:flex; align-items:center; gap:.75rem; text-align:left; width:100%;
  padding:.7rem .8rem; border-radius:13px; background:rgba(255,255,255,.025); border:1px solid var(--border);
  color:var(--text); cursor:pointer;
  transition:background .25s var(--ease), border-color .25s, transform .2s var(--ease); }
.lcp-action:hover { background:rgba(220,38,38,.08); border-color:rgba(220,38,38,.4); transform:translateX(3px); }
.lcp-action ion-icon { font-size:1.15rem; color:var(--crimson-glow); flex-shrink:0; }
.lcp-action strong { display:block; font-size:.8rem; font-weight:700; }
.lcp-action span { display:block; font-size:.7rem; color:var(--text-muted); margin-top:1px; }

/* ── 13. Recommended setup ── */
.lcp-recs { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:.6rem; }
.lcp-rec { display:flex; align-items:center; gap:.6rem; font-size:.8rem; color:var(--text-secondary); }
.lcp-rec-check { width:1.2rem; height:1.2rem; border-radius:50%; flex-shrink:0; display:flex; align-items:center; justify-content:center;
  border:1.5px solid var(--border-strong); color:transparent; transition:background .3s, border-color .3s, color .3s; }
.lcp-rec-check ion-icon { font-size:.8rem; }
.lcp-rec.done { color:var(--text); }
.lcp-rec.done .lcp-rec-check { background:var(--pistachio); border-color:var(--pistachio); color:#0A0A0F; }

/* ── 14. Session activity ── */
.lcp-activity { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:.55rem; }
.lcp-activity-item { display:flex; align-items:flex-start; gap:.5rem; font-size:.78rem; color:var(--text-secondary);
  line-height:1.45; animation:er-card-in .35s var(--ease); }
.lcp-activity-item ion-icon { color:var(--pistachio); font-size:.95rem; margin-top:.15rem; flex-shrink:0; }
.lcp-activity-time { display:block; font-size:.66rem; color:var(--text-muted); margin-top:1px; }
.lcp-activity-empty { font-size:.78rem; color:var(--text-muted); }

/* ── 15. Compact info cards ── */
.lcp-compact-text { font-size:.76rem; color:var(--text-secondary); line-height:1.6; }
.lcp-compact-list { margin:0; padding-left:1.05rem; color:var(--text-secondary); font-size:.76rem; line-height:1.65;
  display:flex; flex-direction:column; gap:.25rem; }

/* ── 16. Focus rings for the custom controls that suppress the native outline ── */
.toggle-btn:focus-visible { outline:none; box-shadow:var(--ring-blue), 0 0 0 1px var(--border-strong); }
.er-section-head:focus-visible, .er-kebab-btn:focus-visible, .lcp-action:focus-visible,
.er-configure-btn:focus-visible { outline:none; box-shadow:var(--ring-blue); }
.lcp-action:focus-visible { border-color:var(--crimson); }
