/* Self-hosted Inter variable font. No external font calls. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/inter/InterVariable.woff2") format("woff2-variations"),
       url("../fonts/inter/InterVariable.woff2") format("woff2");
}
@font-face {
  font-family: 'Inter';
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/inter/InterVariable-Italic.woff2") format("woff2-variations"),
       url("../fonts/inter/InterVariable-Italic.woff2") format("woff2");
}
/* Self-hosted Fraunces variable font (SIL OFL). Two unicode-range subsets so
   the latin file is fetched first and latin-ext only loads when needed. */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("../fonts/fraunces/Fraunces-Variable-latin.woff2") format("woff2-variations"),
       url("../fonts/fraunces/Fraunces-Variable-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("../fonts/fraunces/Fraunces-Variable-latin-ext.woff2") format("woff2-variations"),
       url("../fonts/fraunces/Fraunces-Variable-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --bg: #f6f7fb;
  --panel: #ffffff;
  --panel-2: #fafbff;
  --text: #1a1d29;
  --muted: #6b7280;
  --border: #e6e8ef;
  --brand: #0b5cff;
  --brand-2: #4a85ff;
  --brand-soft: #dce8ff;
  --access: #0b5cff;
  --access-hover: #0a4ddc;
  --danger: #e5484d;
  --success: #30a46c;
  --warning: #f5a524;
  --shadow: 0 1px 2px rgba(17,24,39,.04), 0 4px 14px rgba(17,24,39,.06);
  --radius: 12px;
  --sidebar-w: 248px;
}
[data-theme="dark"] {
  --bg: #0f1117;
  --panel: #171923;
  --panel-2: #1c1f2b;
  --text: #e6e8f0;
  --muted: #8b90a4;
  --border: #262a38;
  --brand: #3d7dff;
  --brand-2: #78a3ff;
  --brand-soft: #1a2a55;
  --access: #3d7dff;
  --access-hover: #0b5cff;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 4px 18px rgba(0,0,0,.45);
}
[data-theme="neobrutal-light"] {
  --bg: #fef9c3;
  --panel: #ffffff;
  --panel-2: #fef3c7;
  --text: #0a0a0a;
  --muted: #3f3f46;
  --border: #0a0a0a;
  --brand: #ec4899;
  --brand-2: #f97316;
  --brand-soft: #fde68a;
  --access: #2563eb;
  --access-hover: #1d4ed8;
  --danger: #dc2626;
  --success: #16a34a;
  --warning: #eab308;
  --shadow: 4px 4px 0 0 #0a0a0a;
  --radius: 0px;
}
[data-theme="neobrutal-dark"] {
  --bg: #18181b;
  --panel: #27272a;
  --panel-2: #1f1f23;
  --text: #fafafa;
  --muted: #a1a1aa;
  --border: #fafafa;
  --brand: #f472b6;
  --brand-2: #fb923c;
  --brand-soft: #3f3f46;
  --access: #60a5fa;
  --access-hover: #3b82f6;
  --danger: #f87171;
  --success: #4ade80;
  --warning: #facc15;
  --shadow: 4px 4px 0 0 #fafafa;
  --radius: 0px;
}
[data-theme="solarpunk"] {
  --bg: #f5f7e8;
  --panel: #ffffff;
  --panel-2: #eef5d8;
  --text: #1e3a1e;
  --muted: #4e6b4e;
  --border: #b4cba0;
  --brand: #1e9e6a;
  --brand-2: #f2a83b;
  --brand-soft: #d7ebc3;
  --access: #0a8a5a;
  --access-hover: #067349;
  --danger: #c43a3a;
  --success: #2fa862;
  --warning: #e8a11b;
  --shadow: 0 1px 2px rgba(30,58,30,.06), 0 4px 14px rgba(30,110,60,.12);
  --radius: 14px;
}
[data-theme="cyberpunk"] {
  --bg: #05050a;
  --panel: #0f0a1f;
  --panel-2: #15102b;
  --text: #e0f7ff;
  --muted: #8a8ab0;
  --border: #2a1f4a;
  --brand: #ff2bd6;
  --brand-2: #00f0ff;
  --brand-soft: #2a0f3a;
  --access: #00f0ff;
  --access-hover: #00c9d6;
  --danger: #ff3b6b;
  --success: #2bffb3;
  --warning: #ffe100;
  --shadow: 0 0 0 1px #ff2bd6, 0 0 18px rgba(255, 43, 214, .35);
  --radius: 4px;
}

/* Neobrutal accents: hard borders + offset shadows on primary surfaces */
[data-theme^="neobrutal"] * { border-width: 2px !important; }
[data-theme^="neobrutal"] .btn { border: 2px solid var(--border); }
[data-theme^="neobrutal"] .btn-primary { border: 2px solid var(--border); box-shadow: 3px 3px 0 0 var(--border); }
[data-theme^="neobrutal"] .btn-primary:hover { transform: translate(-1px, -1px); box-shadow: 4px 4px 0 0 var(--border); }
[data-theme^="neobrutal"] .card { box-shadow: 4px 4px 0 0 var(--border); }

/* Cyberpunk glow accents */
[data-theme="cyberpunk"] .btn-primary { box-shadow: 0 0 14px rgba(255,43,214,.5); }
[data-theme="cyberpunk"] .sidebar nav a.active { box-shadow: inset 0 0 0 1px var(--brand); }
[data-theme="cyberpunk"] h1, [data-theme="cyberpunk"] h2, [data-theme="cyberpunk"] h3 {
  text-shadow: 0 0 8px rgba(0, 240, 255, .35);
}
[data-theme="solarpunk"] .btn-primary { box-shadow: 0 2px 8px rgba(30,158,106,.25); }
[data-theme="solarpunk"] .sidebar nav a.active { background: var(--brand-soft); color: var(--access); }

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-feature-settings: "cv02", "cv03", "cv04", "cv11";
  background: var(--bg);
  color: var(--text);
  font-size: 1rem;
  line-height: 1.5;
}
a { color: var(--access); text-decoration: none; font-weight: 500; }
a:hover { text-decoration: underline; }
h1,h2,h3 { margin: 0; }
p { margin: .25rem 0; }

.layout { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100vh; }

.sidebar {
  background: var(--panel);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  padding: 18px 14px;
  position: sticky; top: 0; height: 100vh;
  /* Three-zone layout: brand stays pinned at top, the nav middle
     scrolls when its content overflows, and the footer is pinned at
     the bottom. flex-shrink: 0 on brand + footer keeps them out of
     the squeeze; min-height: 0 on the scrolling nav lets the flex
     child shrink below its intrinsic content height (without it
     overflow-y has nothing to clip against). */
}
.sidebar > .brand { flex: 0 0 auto; }
/* Hide the scrollbar visually but keep the scroll functionality. The
   sidebar's middle still scrolls via mouse wheel / trackpad / keyboard;
   we just suppress the gutter so the nav reads as a clean column. */
.sidebar > nav { flex: 1 1 auto; min-height: 0; overflow-y: auto;
  /* Lock horizontal axis. Without an explicit `overflow-x`, the CSS
     spec promotes it to `auto` once the Y axis is non-visible —
     letting any inner element that exceeds the sidebar's width turn
     the nav into a horizontally swipable strip on mobile. Pair with
     `touch-action: pan-y` so iOS Safari can't initiate a horizontal
     pan even if some descendant manages to overflow. */
  overflow-x: hidden; touch-action: pan-y;
  scrollbar-width: none; -ms-overflow-style: none; }
.sidebar > nav::-webkit-scrollbar { width: 0; height: 0; display: none; }
.brand { display: flex; gap: 12px; align-items: flex-start; padding: 4px 6px 18px; }
.brand-mark {
  width: 36px; height: 36px; border-radius: 10px;
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  color: white; display: grid; place-items: center;
  font-weight: 700; letter-spacing: .5px;
}
.brand-mark.lg { width: 54px; height: 54px; font-size: 1.25rem; border-radius: 14px; }
.brand-logo { width: 52px; height: 52px; object-fit: contain; display: block; }
.brand > div { margin-top: 8px; }
.brand-logo-lg { width: 72px; height: 72px; }
.brand-title { font-weight: 700; font-size: 0.9375rem; line-height: 1.1; }
.brand-sub { font-size: 0.9375rem; font-weight: 700; line-height: 1.1; }
.sidebar-footer-img-link { display: flex; justify-content: center; padding: 6px 0 4px; }
.sidebar-footer-img-link img { max-width: 80px; width: 100%; height: auto; display: block; }
.brand-version { display: block; width: fit-content; margin: 4px auto; padding: 2px 8px; text-align: center;
  font-family: inherit; font-size: 0.6875rem;
  color: var(--muted); background: rgba(127, 127, 127, 0.15); border-radius: 6px; }
.sidebar nav { display: flex; flex-direction: column; gap: 2px; margin-top: 8px; }
.sidebar nav a {
  color: var(--text); padding: 9px 12px; border-radius: 8px;
  font-weight: 500; display: block;
  /* Allow long labels (e.g. "Announcements & Events") to wrap to a
     second line instead of overflowing the sidebar. Hyphenation +
     overflow-wrap together handle both spaced phrases and any
     pathologically long single word. */
  line-height: 1.3; overflow-wrap: anywhere; hyphens: auto;
}
.sidebar nav a:hover { background: var(--panel-2); text-decoration: none; }
.sidebar nav a.active { background: var(--brand-soft); color: var(--access); }
.sidebar nav a.sidebar-child { padding-left: 28px; font-size: 0.9125rem; color: var(--muted); }
.sidebar nav a.sidebar-child:hover { color: var(--text); }
.sidebar nav a.sidebar-child.active { color: var(--access); }
/* Action rows (e.g. "+ Add Library" under the Intergroup subsection)
   sit at the bottom of their section as creation entry points. They're
   visually de-emphasised so they don't compete with content rows above. */
.sidebar nav a.sidebar-action { color: var(--muted); font-size: 0.875rem; font-weight: 500; }
.sidebar nav a.sidebar-action:hover { color: var(--text); }

/* Bulletproof: [hidden] should always hide, even on flex/grid children. */
[data-header-panel][hidden] { display: none !important; }

/* ===== Frontend template library picker ===== */
.template-library-grid { display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px; margin: 8px 0 4px; }

/* Compact template-picker pill (top-actions). Tracks the live template
   name and opens the modal for choosing a different one. */
.fe-template-picker {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 4px 4px 4px 12px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--panel-2);
  font-size: 0.875rem;
}
.fe-template-picker-label { font-weight: 500; }
.fe-template-picker-active { font-weight: 600; color: var(--text); }
.fe-template-picker .btn { padding: 4px 12px; font-size: 0.8125rem; border-radius: 999px; }
.fe-template-picker-modal .modal-panel { width: min(820px, 94vw); max-height: 86vh; }
.fe-template-picker-modal .modal-body { overflow-y: auto; }
.fe-layout-picker-modal .modal-panel { width: min(960px, 96vw); max-height: 88vh; }

/* New-page modal: small gap below the title input before the layout
   grid hint, so the two sections of the form read as distinct steps. */
.fe-new-page-layout-hint { margin-top: 18px; }

/* Block-stripe preview rendered inside layout cards (one stripe per
   block in the layout's blocks_json). */
.template-card-preview-blocks {
  display: flex; flex-direction: column; gap: 4px; padding: 10px;
  background: var(--panel-2);
}
.tcp-block { display: block; height: 8px; border-radius: 3px; background: var(--border); }
.tcp-block-hero         { height: 18px; background: var(--brand); }
.tcp-block-quick_links  { background: color-mix(in srgb, var(--brand) 40%, var(--border)); }
.tcp-block-meetings     { background: color-mix(in srgb, var(--brand) 30%, var(--border)); }
.tcp-block-features     { background: color-mix(in srgb, var(--brand) 50%, var(--border)); }
.tcp-block-stats        { height: 6px; background: color-mix(in srgb, var(--text) 25%, var(--border)); }
.tcp-block-testimonials { background: color-mix(in srgb, var(--text) 20%, var(--border)); }
.tcp-block-cta          { height: 14px; background: var(--access); }
.tcp-block-faq          { background: color-mix(in srgb, var(--text) 18%, var(--border)); }
.tcp-block-about        { background: color-mix(in srgb, var(--text) 22%, var(--border)); }
.tcp-block-contact      { height: 12px; background: var(--text); opacity: 0.6; }

.template-card-tag {
  display: inline-block; margin-left: 6px; padding: 1px 6px;
  border-radius: 4px; background: var(--panel-2);
  font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.06em;
  vertical-align: middle;
}
.template-card-new {
  border-style: dashed !important; background: transparent !important;
  text-align: left; cursor: pointer;
}
.template-card-preview-new {
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--text) 5%, transparent);
}
.template-card-preview-new .tcp-plus {
  font-size: 2rem; color: var(--muted); font-weight: 300;
}

/* ============================================================
   DRAG-AND-DROP LAYOUT BUILDER
   ============================================================ */
.fe-layout-builder-modal .modal-panel,
.fe-layout-builder-panel {
  /* Both `width` AND `max-width` are set: the generic `.modal-panel`
     rule at the bottom of this file pins `max-width: 680px`, and CSS
     resolves the rendered width as min(width, max-width). Without an
     explicit `max-width` override here, the builder panel would clamp
     back to 680px even though `width` says 1100px. */
  width: min(1100px, 96vw);
  max-width: min(1100px, 96vw);
  max-height: 92vh;
}
/* Footer builder needs more horizontal real estate so 4 column drop
   zones fit comfortably on desktop. The modifier class is added by
   feFooterLayoutBuilder() — only applied to footer-kind modals. */
.fe-layout-builder-modal--wide .modal-panel,
.fe-layout-builder-modal--wide .fe-layout-builder-panel {
  width: min(1500px, 98vw);
  max-width: min(1500px, 98vw);
}
.fe-layout-builder-body { overflow-y: auto; }
.fe-layout-builder-grid {
  display: grid; grid-template-columns: 280px minmax(0, 1fr);
  gap: 18px; margin-top: 12px;
}
@media (max-width: 720px) {
  .fe-layout-builder-grid { grid-template-columns: 1fr; }
}
.fe-layout-builder-library {
  display: flex; flex-direction: column; gap: 8px;
  max-height: 56vh; overflow-y: auto; padding: 4px;
  border: 1px solid var(--border); border-radius: 10px;
  background: color-mix(in srgb, var(--text) 3%, transparent);
}
.fe-builder-block {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 8px;
  background: var(--panel); border: 1px solid var(--border);
  cursor: grab; user-select: none;
}
.fe-builder-block:active { cursor: grabbing; }
.fe-builder-block:hover { border-color: var(--access); }
.fe-builder-block-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; flex: 0 0 32px;
  background: var(--panel-2); border-radius: 6px; color: var(--muted);
}
.fe-builder-block-icon .icon { width: 16px; height: 16px; }
.fe-builder-block-meta { flex: 1 1 auto; min-width: 0; }
.fe-builder-block-name { font-weight: 600; font-size: 0.9rem; color: var(--text); }
.fe-builder-block-desc { line-height: 1.35; }

.fe-layout-builder-canvas-wrap label {
  display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px;
  font-size: 0.875rem; font-weight: 600; color: var(--text);
}
.fe-layout-builder-canvas-wrap input[type="text"] {
  padding: 8px 12px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel); color: var(--text);
  font: inherit;
}
.fe-layout-builder-canvas {
  min-height: 260px;
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px; border-radius: 10px;
  border: 2px dashed var(--border); background: var(--panel-2);
}
.fe-layout-builder-canvas.is-drop-target {
  border-color: var(--access); background: var(--brand-soft);
}
.fe-builder-empty {
  text-align: center; padding: 32px 0; pointer-events: none;
}
.fe-builder-canvas-block {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 8px;
  background: var(--panel); border: 1px solid var(--border);
  cursor: grab;
}
.fe-builder-canvas-block.dragging { opacity: 0.4; }
.fe-builder-canvas-block .fe-builder-block-icon { background: var(--brand-soft); color: var(--brand); }
.fe-builder-canvas-remove {
  margin-left: auto; padding: 4px 8px; border: 0; background: transparent;
  color: var(--muted); cursor: pointer; border-radius: 6px;
  font-size: 1rem; line-height: 1;
}
.fe-builder-canvas-remove:hover { background: var(--danger); color: #fff; }

/* ---- Footer-builder canvas (rows + columns) ---- */
.fe-footer-builder-canvas {
  background: var(--panel-2);
  padding: 12px;
  gap: 12px !important;
}
.fe-footer-builder-add-row {
  align-self: flex-start;
  margin-top: 12px;
}
.fe-footer-builder-row {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px 12px;
  display: flex; flex-direction: column; gap: 10px;
  transition: border-color 140ms ease, box-shadow 140ms ease;
}
.fe-footer-builder-row.is-dragging {
  opacity: 0.65; box-shadow: 0 12px 28px rgba(0,0,0,0.18);
}
.fe-footer-builder-row-head {
  display: flex; align-items: center; gap: 12px;
  flex-wrap: wrap;
}
.fe-footer-builder-row-handle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  color: var(--muted); cursor: grab; touch-action: none;
  font-size: 0.9rem; line-height: 1;
}
.fe-footer-builder-row-handle:active { cursor: grabbing; }
.fe-footer-builder-row-label {
  font-weight: 700; font-size: 0.78rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted);
}
.fe-footer-builder-row-cols {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.85rem; color: var(--muted);
}
.fe-footer-builder-row-cols select {
  padding: 4px 8px; border-radius: 6px;
  border: 1px solid var(--border); background: var(--panel-2);
  color: var(--text); font: inherit;
}
.fe-footer-builder-row-remove {
  margin-left: auto;
  width: 28px; height: 28px; padding: 0; line-height: 1;
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 6px;
  cursor: pointer; font-size: 1rem;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.fe-footer-builder-row-remove:hover {
  color: var(--danger, #b91c1c); border-color: var(--danger, #b91c1c);
  background: rgba(185, 28, 28, 0.06);
}
.fe-footer-builder-row-cols-wrap {
  display: grid; gap: 10px;
}
.fe-footer-builder-cols-1 { grid-template-columns: 1fr; }
.fe-footer-builder-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.fe-footer-builder-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.fe-footer-builder-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 980px) {
  .fe-footer-builder-cols-3,
  .fe-footer-builder-cols-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 600px) {
  .fe-footer-builder-row-cols-wrap { grid-template-columns: 1fr !important; }
}
.fe-footer-builder-col {
  display: flex; flex-direction: column; gap: 4px;
  min-width: 0;
}
.fe-footer-builder-col-head {
  font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; font-size: 0.7rem;
}
.fe-footer-builder-col-drop {
  flex: 1 1 auto;
  display: flex; flex-direction: column; gap: 6px;
  min-height: 80px; padding: 8px;
  border: 1.5px dashed var(--border); border-radius: 8px;
  background: var(--panel-2);
  transition: border-color 140ms ease, background 140ms ease;
}
.fe-footer-builder-col-drop.is-dragover {
  border-color: var(--brand, var(--access));
  background: var(--brand-soft, var(--panel));
}
.fe-footer-builder-col-drop .fe-builder-empty {
  padding: 18px 0; pointer-events: none;
}
.fe-footer-builder-col-drop .fe-builder-canvas-block {
  cursor: grab;
}
.fe-footer-builder-col-drop .fe-builder-canvas-block.is-dragging { opacity: 0.4; }

/* Two-panel split inside the builder canvas. */
.fe-builder-split { flex-direction: column; padding: 0; gap: 0; cursor: default; }
.fe-builder-split-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-bottom: 1px solid var(--border);
}
.fe-builder-split-cols {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  padding: 10px;
}
.fe-builder-split-col {
  min-height: 80px;
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px; border-radius: 8px;
  background: var(--panel-2); border: 1px dashed var(--border);
}
.fe-builder-split-col.is-drop-target { border-color: var(--access); background: var(--brand-soft); }
.fe-builder-split-col .fe-builder-canvas-block { background: var(--panel); }

/* Container block in the builder canvas — same head + drop-zone
   chrome shape as a split, but a single full-width drop area instead
   of two side-by-side panels. The drop zone reuses the split-col
   styling (dashed border, panel-2 bg, drop-target highlight). */
.fe-builder-container { flex-direction: column; padding: 0; gap: 0; cursor: default; }
.fe-builder-container-drop {
  min-height: 80px;
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px; margin: 10px;
  border-radius: 8px;
  background: var(--panel-2); border: 1px dashed var(--border);
}
.fe-builder-container-drop.is-drop-target {
  border-color: var(--access); background: var(--brand-soft);
}
.fe-builder-container-drop .fe-builder-canvas-block { background: var(--panel); }

/* Per-card visibility toggle pill in the head row. */
.fe-block-vis { margin-left: auto; }

/* Frontend Settings — fonts & icons. */
.fe-font-row {
  display: grid; grid-template-columns: 1fr 220px; gap: 16px 24px;
  align-items: center; padding: 16px 0;
  border-top: 1px solid var(--border);
}
.fe-font-row:first-of-type { border-top: 0; padding-top: 8px; }
.fe-font-row-info .u-name { font-weight: 600; color: var(--text); }
.fe-font-row select { padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel); color: var(--text);
  font: inherit; }
.fe-font-sample {
  grid-column: 1 / -1; padding: 14px 16px; border-radius: 10px;
  background: var(--panel-2); color: var(--text); font-size: 1.0625rem;
  border: 1px solid var(--border);
}
@media (max-width: 720px) {
  .fe-font-row { grid-template-columns: 1fr; }
}

.fe-icon-library {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  margin-top: 6px;
}
.fe-icon-library-tile {
  position: relative; padding: 22px 12px 12px;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 10px;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  overflow: visible;
}
.fe-icon-library-tile img {
  width: 36px; height: 36px; object-fit: contain;
}
.fe-icon-library-name {
  font-size: 0.8rem; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
/* Delete button — always visible, sits in the top-right corner. Solid
   red rectangle with rounded corners so it reads as a "close" action
   without being obtrusive. Slightly translucent until hover. */
.fe-icon-library-tile .fe-icon-library-del,
.fe-icon-library-tile form > .fe-icon-library-del {
  position: absolute; top: 6px; right: 6px; margin: 0;
  min-width: 26px; height: 22px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  background: #dc2626; color: #fff;
  border: 1px solid rgba(0, 0, 0, 0.18);
  border-radius: 6px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
  opacity: 0.9; transition: opacity 140ms ease, background 140ms ease, transform 140ms ease;
  z-index: 2; cursor: pointer; line-height: 1;
}
.fe-icon-library-tile .fe-icon-library-del:hover { opacity: 1; background: #b91c1c; transform: translateY(-1px); }
.fe-icon-library-tile .fe-icon-library-del:focus-visible { outline: 2px solid var(--access); outline-offset: 2px; }
.fe-icon-library-tile .fe-icon-library-del .icon {
  width: 14px; height: 14px; stroke: currentColor; color: #fff;
}

/* Frontend Settings — custom font library: two-column add panel + tiles. */
.fe-font-add-grid {
  display: grid; gap: 14px; margin-top: 4px; margin-bottom: 14px;
  grid-template-columns: 1fr 1fr;
}
@media (max-width: 720px) { .fe-font-add-grid { grid-template-columns: 1fr; } }
.fe-font-add-form {
  display: flex; flex-direction: column; gap: 10px;
  padding: 16px; border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
}
.fe-font-add-head {
  display: flex; align-items: center; gap: 8px;
  font-weight: 700; font-size: 0.95rem; color: var(--text);
}
.fe-font-add-head .icon { width: 16px; height: 16px; }
.fe-font-add-field { display: flex; flex-direction: column; gap: 4px; font-weight: 500; }
.fe-font-add-field input { padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel); color: var(--text);
  font: inherit; }
.fe-font-add-form .btn { align-self: flex-start; }
.fe-font-add-blurb {
  background: rgba(11, 92, 255, 0.06);
  border: 1px solid rgba(11, 92, 255, 0.18);
  border-radius: 8px; padding: 8px 10px; margin: 0;
  line-height: 1.45;
}

.fe-font-library {
  display: grid; gap: 12px; margin-top: 6px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.fe-font-library-tile {
  position: relative; padding: 14px;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 10px;
  display: flex; align-items: center; gap: 14px;
}
.fe-font-library-tile-sample {
  flex: 0 0 auto; width: 56px; height: 56px;
  display: flex; align-items: center; justify-content: center;
  font-size: 2rem; line-height: 1; color: var(--text);
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 8px;
}
.fe-font-library-tile-info { min-width: 0; flex: 1 1 auto; }
.fe-font-library-tile-info .u-name { font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fe-font-library-tile-info .smaller {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fe-font-library-tile form {
  position: absolute; top: 6px; right: 6px; margin: 0;
}
.fe-font-library-tile .fe-font-library-del {
  min-width: 26px; height: 22px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  background: #dc2626; color: #fff;
  border: 1px solid rgba(0, 0, 0, 0.18);
  border-radius: 6px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
  opacity: 0.9; transition: opacity 140ms ease, background 140ms ease, transform 140ms ease;
  cursor: pointer; line-height: 1;
}
.fe-font-library-tile .fe-font-library-del:hover { opacity: 1; background: #b91c1c; transform: translateY(-1px); }
.fe-font-library-tile .fe-font-library-del:focus-visible { outline: 2px solid var(--access); outline-offset: 2px; }
.fe-font-library-tile .fe-font-library-del .icon {
  width: 14px; height: 14px; stroke: currentColor; color: #fff;
}

/* ===== Users tab — top grid + roles/permissions explainer ===== */
.users-top-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 1rem;
}
@media (max-width: 880px) { .users-top-grid { grid-template-columns: 1fr; } }
.users-top-grid > .card { margin: 0; height: 100%; }

.perm-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.perm-row {
  /* Role column auto-sizes to the widest pill across all rows so longer
     labels (e.g. "Intergroup member") don't overflow into the blurb
     column. minmax keeps a 140px floor so short labels still align. */
  display: grid; grid-template-columns: minmax(140px, max-content) minmax(0, 1fr);
  gap: 14px;
  align-items: start; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel-2);
}
@media (max-width: 720px) { .perm-row { grid-template-columns: 1fr; gap: 6px; } }
.perm-role { display: flex; align-items: center; }
.perm-blurb { line-height: 1.45; }
.perm-badge {
  display: inline-block;
  padding: 4px 10px; border-radius: 999px;
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; line-height: 1.2;
  border: 1px solid transparent; white-space: nowrap;
}
/* Per-role accent — matches the post-chip palette so colours read as
   "categorical tags" across the app rather than role-specific. */
.perm-badge-admin  { background: rgba(220, 38, 38, 0.10);  color: #b91c1c; border-color: rgba(220, 38, 38, 0.32); }
.perm-badge-editor { background: rgba(11, 92, 255, 0.10);  color: #1d4ed8; border-color: rgba(11, 92, 255, 0.32); }
.perm-badge-fe     { background: rgba(20, 184, 166, 0.10); color: #0f766e; border-color: rgba(20, 184, 166, 0.32); }
.perm-badge-ig     { background: rgba(168, 85, 247, 0.10); color: #7e22ce; border-color: rgba(168, 85, 247, 0.32); }
.perm-badge-viewer { background: rgba(100, 116, 139, 0.12); color: #475569; border-color: rgba(100, 116, 139, 0.32); }
html[data-theme="dark"] .perm-badge-admin  { background: rgba(220, 38, 38, 0.20);  color: #fca5a5; border-color: rgba(220, 38, 38, 0.45); }
html[data-theme="dark"] .perm-badge-editor { background: rgba(11, 92, 255, 0.22);  color: #93c5fd; border-color: rgba(11, 92, 255, 0.45); }
html[data-theme="dark"] .perm-badge-fe     { background: rgba(20, 184, 166, 0.20); color: #5eead4; border-color: rgba(20, 184, 166, 0.45); }
html[data-theme="dark"] .perm-badge-ig     { background: rgba(168, 85, 247, 0.20); color: #d8b4fe; border-color: rgba(168, 85, 247, 0.45); }
html[data-theme="dark"] .perm-badge-viewer { background: rgba(100, 116, 139, 0.22); color: #cbd5e1; border-color: rgba(100, 116, 139, 0.45); }


/* ===== Sidebar order admin (Settings → Sidebar) ===== */
/* Title row sits at the top of the form with the Save button on the
   right so the primary action is visible without scrolling past the
   manual reorder list. */
.sidebar-order-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
}
/* Scoped to the pane so this beats the generic .u-name rule that
   lives later in the file (cascade resolves ties by source order — my
   shorter selector would lose to .u-name without the pane prefix). */
.settings-pane[data-pane="sidebar"] .sidebar-order-title {
  font-size: 1rem; font-weight: 700; color: var(--text);
}


.sidebar-mode-fieldset {
  display: flex; flex-wrap: wrap; gap: 8px;
  border: 0; padding: 0; margin: 0 0 12px;
}
.sidebar-mode-pill {
  flex: 1 1 auto; display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border: 1.5px solid var(--border); border-radius: 10px;
  background: var(--panel); cursor: pointer; min-width: 0;
  transition: border-color 140ms ease, background 140ms ease;
}
.sidebar-mode-pill:has(input:checked) {
  border-color: var(--brand); background: var(--brand-soft, var(--panel-2));
}
.sidebar-mode-pill input[type="radio"] { flex: 0 0 auto; }
.sidebar-mode-pill-label { font-weight: 600; color: var(--text); }

.sidebar-order-manual {
  display: flex; flex-direction: column; gap: 10px;
  padding: 12px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel-2);
}
.sidebar-order-sections {
  display: flex; flex-direction: column; gap: 8px;
}
.sidebar-order-section {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 8px; padding: 8px 10px;
  transition: opacity 140ms ease, transform 140ms ease;
}
.sidebar-order-section.dragging { opacity: 0.5; }
.sidebar-order-section-head {
  display: flex; align-items: center; gap: 8px;
  font-weight: 700; color: var(--text);
}
.sidebar-order-handle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 22px; flex: 0 0 auto;
  color: var(--muted); cursor: grab; user-select: none;
  font-size: 0.95rem; letter-spacing: -2px;
}
.sidebar-order-handle:active { cursor: grabbing; }
.sidebar-order-section-name { font-size: 0.95rem; }
.sidebar-order-section-note { margin: 6px 0 0 26px; line-height: 1.4; }

.sidebar-order-items {
  list-style: none; padding: 6px 0 0 26px; margin: 0;
  display: flex; flex-direction: column; gap: 4px;
}
.sidebar-order-item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--panel-2); cursor: grab;
  transition: opacity 140ms ease, background 140ms ease;
}
.sidebar-order-item:hover { background: var(--panel); }
.sidebar-order-item.dragging { opacity: 0.5; cursor: grabbing; }
.sidebar-order-item-name { font-size: 0.9rem; color: var(--text); }

/* External-link rows embedded inside the Sidebar tab's manual reorder
   UI. Same drag-handle + row layout as item rows above, but with title
   + URL stacked and inline edit/delete buttons on the right. */
.sidebar-extlink-list {
  list-style: none; padding: 6px 0 0 26px; margin: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.sidebar-extlink-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--panel-2);
}
.sidebar-extlink-row:hover { background: var(--panel); }
.sidebar-extlink-row.dragging { opacity: 0.5; }
.sidebar-extlink-meta { flex: 1 1 auto; min-width: 0; }
.sidebar-extlink-title {
  font-size: 0.9rem; color: var(--text); font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sidebar-extlink-url {
  display: block; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; max-width: 100%;
}
.sidebar-extlink-empty { padding: 6px 0 0 26px; margin: 0; }
.sidebar-extlink-add { margin: 8px 0 0 26px; }


/* ===== 404 page (admin) =====
   The card itself stays a centered ~720px column. The outer .content
   wrapper is widened to the full viewport width via the :has() rule
   below so the card auto-centers between the sidebar and the right
   edge of the screen rather than the narrow normal content column. */
.admin-404 { text-align: center; padding: 3rem 2rem; max-width: 720px; margin: 2rem auto; }
.content:has(.admin-404) { max-width: none; }
.admin-404-art { max-width: 320px; margin: 0 auto 1rem; }
.admin-404-title {
  font-family: var(--fe-font-heading, inherit);
  font-size: 1.75rem; font-weight: 700; margin: 0.5rem 0 0.75rem;
  letter-spacing: -0.01em; color: var(--text);
}
.admin-404-sub { max-width: 540px; margin: 0 auto 1.5rem; line-height: 1.5; }
.admin-404-actions {
  display: flex; flex-wrap: wrap; gap: 8px;
  justify-content: center; margin: 0 auto 1.25rem;
}
.admin-404-foot { line-height: 1.5; }

/* ===== Posts (announcements + events) admin ===== */
.posts-card { padding: 0 !important; overflow: hidden; }
.posts-tbl { width: 100%; border-collapse: collapse; }
.posts-tbl th, .posts-tbl td { padding: 14px 16px; vertical-align: top;
  border-top: 1px solid var(--border); text-align: left; }
.posts-tbl thead th { border-top: 0; font-size: 0.75rem; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--muted); font-weight: 600; }
.posts-tbl tbody tr:hover { background: var(--panel-2); }
.posts-th-thumb, .posts-td-thumb { width: 64px; }
.posts-th-actions, .posts-td-actions { width: 1%; white-space: nowrap; text-align: right; }
.posts-thumb {
  width: 48px; height: 48px; object-fit: cover;
  border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel-2); display: flex; align-items: center;
  justify-content: center; color: var(--muted);
}
.posts-thumb-empty .icon { width: 22px; height: 22px; }
.posts-title { font-weight: 600; color: var(--text); }
.posts-summary { margin-top: 2px; line-height: 1.4; }

/* Type chips. Announcement and event have distinct colours so the
   admin can scan a list quickly. */
.post-chip {
  display: inline-block; margin-right: 4px;
  padding: 2px 8px; border-radius: 999px;
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.03em;
  text-transform: uppercase; line-height: 1.4;
  border: 1px solid transparent;
}
.post-chip-announcement { background: rgba(245, 158, 11, 0.15); color: #b45309; border-color: rgba(245, 158, 11, 0.4); }
.post-chip-event        { background: rgba(11, 92, 255, 0.12);  color: #1d4ed8; border-color: rgba(11, 92, 255, 0.32); }
.post-chip-online       { background: rgba(20, 184, 166, 0.12); color: #0f766e; border-color: rgba(20, 184, 166, 0.32); }
.post-chip-draft        { background: rgba(100, 116, 139, 0.14); color: #475569; border-color: rgba(100, 116, 139, 0.34); }
.post-chip-warning      { background: rgba(245, 158, 11, 0.18);  color: #b45309; border-color: rgba(245, 158, 11, 0.5); }
.post-chip-private      { background: rgba(168, 85, 247, 0.14); color: #6b21a8; border-color: rgba(168, 85, 247, 0.36); }
html[data-theme="dark"] .post-chip-announcement { background: rgba(245, 158, 11, 0.18); color: #fbbf24; border-color: rgba(245, 158, 11, 0.5); }
html[data-theme="dark"] .post-chip-event        { background: rgba(11, 92, 255, 0.22);  color: #93c5fd; border-color: rgba(11, 92, 255, 0.45); }
html[data-theme="dark"] .post-chip-online       { background: rgba(20, 184, 166, 0.20); color: #5eead4; border-color: rgba(20, 184, 166, 0.45); }
html[data-theme="dark"] .post-chip-draft        { background: rgba(100, 116, 139, 0.22); color: #cbd5e1; border-color: rgba(100, 116, 139, 0.45); }
html[data-theme="dark"] .post-chip-warning      { background: rgba(245, 158, 11, 0.25); color: #fbbf24; border-color: rgba(245, 158, 11, 0.55); }
html[data-theme="dark"] .post-chip-private      { background: rgba(168, 85, 247, 0.22); color: #d8b4fe; border-color: rgba(168, 85, 247, 0.5); }
/* Pending-submission banner on the post edit screen — sits above the
   normal edit form so admins see who submitted before they touch
   any field. */
.pending-submission-card {
  border-left: 4px solid #f59e0b;
}
.pending-submission-meta {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 6px 16px;
  margin: 0 0 16px;
}
.pending-submission-meta dt { font-weight: 600; color: var(--muted); }
.pending-submission-meta dd { margin: 0; }
/* Header-row variant of the chip — used in the edit page's top-actions
   bar where the parent is a flex row. Switch to inline-flex with
   centered alignment so the "Draft" text sits visually centered inside
   the pill, and the pill aligns vertically with the adjacent buttons. */
.post-chip-header {
  display: inline-flex; align-items: center; justify-content: center;
  vertical-align: middle; font-size: 0.7rem;
  padding: 4px 10px; line-height: 1;
}

/* Type-tag pills inside the edit form — clickable cards with a checkbox. */
.post-type-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 1rem; }
@media (max-width: 720px) { .post-type-row { grid-template-columns: 1fr; } }
.post-type-pill {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 16px; border: 2px solid var(--border); border-radius: 12px;
  background: var(--panel); cursor: pointer;
  transition: border-color 140ms ease, background 140ms ease;
}
.post-type-pill:has(input:checked) { border-color: var(--brand); background: var(--brand-soft, var(--panel-2)); }
.post-type-pill input[type="checkbox"] { margin-top: 4px; flex: 0 0 auto; }
.post-type-pill-body { display: flex; flex-direction: column; gap: 2px; }
.post-type-pill-title { font-weight: 700; color: var(--text); font-size: 0.95rem; }
.post-type-pill-sub { line-height: 1.4; }

/* Reusable two-column row for short fields (start/end, phone/email, etc.) */
.post-form .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 720px) { .post-form .form-row { grid-template-columns: 1fr; } }

.post-form .post-subhead {
  margin: 1.5rem 0 0.5rem; font-size: 0.85rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted);
}
.post-zoom-block {
  margin-top: 1.25rem; padding: 14px 16px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px;
}
.post-zoom-block .post-subhead { margin-top: 0; }


/* Two-panel split admin card — visualizes the layout builder's split
   block. Each panel hosts the FULL editor cards for the blocks placed
   inside that side of the split, so the admin layout mirrors what the
   visitor sees. The card's outer margin scales with the chosen Outer
   margin setting so the admin spacing matches the public site. */
.fe-split-admin-preview {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
  margin: 8px 0 14px;
}
@media (max-width: 720px) { .fe-split-admin-preview { grid-template-columns: 1fr; } }
.fe-split-admin-panel {
  padding: 14px; border: 1px dashed var(--border);
  border-radius: 10px; background: var(--panel-2);
  min-height: 110px;
  display: flex; flex-direction: column; gap: 12px;
}
.fe-split-admin-panel-label {
  font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  font-size: 0.7rem;
}
.fe-split-admin-empty {
  align-self: center; margin: auto; font-style: italic;
}
/* Editor cards nested inside a split panel — soften their drop shadow,
   slim down the padding, and let them inherit the panel's lighter bg
   so they read as "child of the panel" not "card on the page". */
.fe-split-admin-panel > .card {
  margin: 0; padding: 1.25rem; box-shadow: none;
  background: var(--panel); border-color: var(--border);
}
.fe-split-admin-panel > .card .card-head h2 { font-size: 0.95rem; }

/* Top + bottom gap modifiers — mirror the public-site .fe-split--gt-*
   and .fe-split--gb-* values so the admin shows the chosen spacing in
   place. The universal flex `.fe-admin-main { gap: 1rem }` adds a
   little extra to the floor; the relative scale (none < tight < default
   < loose) is preserved. */
.fe-split-admin-card--gt-none    { margin-top: 0; }
.fe-split-admin-card--gt-tight   { margin-top: 1rem; }
.fe-split-admin-card--gt-default { margin-top: 2.5rem; }
.fe-split-admin-card--gt-loose   { margin-top: 5rem; }
.fe-split-admin-card--gb-none    { margin-bottom: 0; }
.fe-split-admin-card--gb-tight   { margin-bottom: 1rem; }
.fe-split-admin-card--gb-default { margin-bottom: 2.5rem; }
.fe-split-admin-card--gb-loose   { margin-bottom: 5rem; }

/* Background-color row in the split settings — checkbox toggles whether
   the colour is applied; the picker stays mounted so the user's last
   choice is preserved when the toggle flips back on. */
.fe-split-admin-bg-row {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 8px; border: 1px solid var(--border);
  border-radius: 8px; background: var(--panel);
}
.fe-split-admin-bg-row input[type="color"] {
  width: 36px; height: 28px; padding: 0; border: 1px solid var(--border);
  border-radius: 6px; background: transparent; cursor: pointer;
}

/* Settings row under the preview. Three flexible columns that wrap on
   narrow screens; each label-and-select pair stacks vertically. */
.fe-split-admin-settings {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  margin-top: 6px; padding-top: 12px;
  border-top: 1px solid var(--border);
}
.fe-split-admin-setting {
  display: flex; flex-direction: column; gap: 4px;
  font-weight: 500;
}
.fe-split-admin-setting select {
  padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel); color: var(--text);
  font: inherit;
}

/* Frontend Design admin — token override grid. Auto-fit responsive
   grid; each field is a self-contained label + input + reset button.
   Wider min-width than the default form grids because each tile carries
   both a label stack (name + help + default-hex) and a control row
   (gating checkbox, swatch, hex caption, reset). */
.fe-design-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 14px 18px;
  margin-top: 6px;
}
.fe-design-subhead {
  margin: 20px 0 6px; font-size: 0.85rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted);
}
.fe-design-subhead:first-of-type { margin-top: 10px; }

/* Mirrors render the same control set as the canonical field in the
   Colors tab; the dashed border + small badge clue the admin in that
   editing here also updates the matching Colors entry. */
.fe-design-field--mirror {
  border-style: dashed;
  position: relative;
}
.fe-design-field--mirror::after {
  content: "Synced";
  position: absolute; top: 8px; right: 10px;
  font-size: 0.625rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted);
  background: var(--panel); padding: 1px 6px; border-radius: 999px;
  border: 1px solid var(--border);
  pointer-events: none;
}

/* ── Card-style preview pane ─────────────────────────────────────── */
.fe-card-style-preview {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  padding: 18px;
  margin: 6px 0 18px;
  background: linear-gradient(135deg, var(--panel-2), var(--panel));
  border: 1px solid var(--border); border-radius: 14px;
}

/* Two-column layout for the Card styles tab — Primary on the left,
   Secondary on the right. Each column wraps its own preview card +
   settings stack so the visual + the controls that drive it stay
   grouped. Drops to a single column under 900px so the field tiles
   keep enough width to read comfortably on narrower admin views. */
.fe-card-style-cols {
  display: grid; gap: 18px;
  grid-template-columns: 1fr 1fr;
  margin-top: 6px;
}
@media (max-width: 900px) {
  .fe-card-style-cols { grid-template-columns: 1fr; }
}
.fe-card-style-col {
  display: flex; flex-direction: column; gap: 12px;
  padding: 18px;
  background: linear-gradient(135deg, var(--panel-2), var(--panel));
  border: 1px solid var(--border); border-radius: 14px;
}
.fe-card-style-col .fe-card-style-preview-card {
  /* Inside a column the preview reads as the column's "header" — give
     it a touch more presence so it visually pairs with the settings
     beneath it. */
  margin: 0;
}
.fe-card-style-col-head {
  /* Subhead sits in the column flow now, not at the top of a section,
     so reset the first-of-type margin override. */
  margin-top: 4px;
}
.fe-card-style-col-fields {
  /* Field tiles stack vertically inside the column — at half-width
     (each column takes ~440px on a 1100px admin shell) the auto-fit
     300px min would still try to pack two per row but waste space.
     Single column reads as a clear list of knobs. */
  grid-template-columns: 1fr;
}

/* ── Buttons two-column layout (mirrors Card styles) ─────────────── */
.fe-btn-style-cols {
  display: grid; gap: 18px;
  grid-template-columns: 1fr 1fr;
  margin-top: 6px;
}
@media (max-width: 900px) {
  .fe-btn-style-cols { grid-template-columns: 1fr; }
}
.fe-btn-style-col {
  display: flex; flex-direction: column; gap: 12px;
  padding: 18px;
  background: linear-gradient(135deg, var(--panel-2), var(--panel));
  border: 1px solid var(--border); border-radius: 14px;
}
.fe-btn-style-col-head { margin-top: 4px; }
.fe-btn-style-col-fields { grid-template-columns: 1fr; }
/* Preview pad — gives the button some breathing room so the hover lift
   has space to translate without clipping against the column edges. */
.fe-btn-style-preview-wrap {
  display: flex; align-items: center; justify-content: center;
  min-height: 84px;
  padding: 18px;
  background: var(--panel-2);
  border: 1px dashed var(--border); border-radius: 10px;
}
/* Preview button — re-implements just enough of the public `.fe-btn`
   recipe to render here on the admin page (frontend.css isn't loaded
   in admin chrome). Reads the same custom properties so the preview
   JS can update everything live by stamping vars on the element. */
.fe-btn-style-preview-button {
  display: inline-flex; align-items: center; justify-content: center;
  padding: var(--fe-btn-padding-y, 14px) var(--fe-btn-padding-x, 28px);
  border-radius: var(--fe-btn-radius, 999px);
  font-weight: var(--fe-btn-weight, 600);
  font-size: 1rem; font-family: inherit;
  text-transform: var(--fe-btn-text-transform, none);
  text-decoration: var(--fe-btn-decoration, none);
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 150ms ease, box-shadow 150ms ease, background 150ms ease;
}
.fe-btn-style-preview-button--primary {
  background: var(--fe-color-btn-primary-bg, #0b5cff);
  color: var(--fe-color-btn-primary-text, #ffffff);
  border-width: var(--fe-btn-primary-border-width, 1px);
  border-style: solid;
  border-color: var(--fe-color-btn-primary-border, var(--fe-color-btn-primary-bg, transparent));
  box-shadow: var(--fe-btn-shadow, 0 8px 20px rgba(15, 23, 42, 0.18));
}
.fe-btn-style-preview-button--primary:hover {
  transform: var(--fe-btn-hover-transform, translateY(-1px));
  background: var(--fe-color-btn-primary-hover-bg,
                  color-mix(in srgb, var(--fe-color-btn-primary-bg, #0b5cff) 88%, black));
  border-width: var(--fe-btn-primary-hover-border-width, var(--fe-btn-primary-border-width, 1px));
  border-color: var(--fe-color-btn-primary-hover-border,
                    var(--fe-color-btn-primary-border, var(--fe-color-btn-primary-bg, transparent)));
  box-shadow: var(--fe-btn-hover-glow, 0 10px 28px rgba(81, 100, 255, 0.32));
}
.fe-btn-style-preview-button--secondary {
  background: var(--fe-color-btn-secondary-bg, transparent);
  color: var(--fe-color-btn-secondary-text, var(--text));
  border-width: var(--fe-btn-secondary-border-width, 1px);
  border-style: solid;
  border-color: var(--fe-color-btn-secondary-border, var(--border));
}
.fe-btn-style-preview-button--secondary:hover {
  background: var(--fe-color-btn-secondary-hover-bg,
                  color-mix(in srgb,
                            var(--fe-color-btn-secondary-bg, var(--panel)) 92%, black));
  border-width: var(--fe-btn-secondary-hover-border-width, var(--fe-btn-secondary-border-width, 1px));
  border-color: var(--fe-color-btn-secondary-hover-border, var(--fe-color-btn-secondary-text, var(--text)));
}
.fe-card-style-preview-card {
  padding: 18px 20px;
  border-radius: 14px;
  display: flex; flex-direction: column; gap: 8px;
  cursor: default;
  /* Tokens are stamped inline by the preview JS so every adjustment
     in the form below shows up here without a save round-trip. The
     hover rules apply the *-hover-* variants. */
  background: var(--fe-color-card-primary-bg, #ffffff);
  border: var(--fe-card-primary-border-width, 1px) solid var(--fe-color-card-primary-border, #f59e0b);
  box-shadow: var(--fe-card-primary-shadow, none);
  transition:
    background-color var(--fe-card-primary-transition, 200ms ease),
    border-color var(--fe-card-primary-transition, 200ms ease),
    box-shadow var(--fe-card-primary-transition, 200ms ease),
    transform var(--fe-card-primary-transition, 200ms ease);
}
.fe-card-style-preview-card:hover {
  box-shadow: var(--fe-card-primary-hover-shadow, 0 8px 28px rgba(15,23,42,0.10));
  transform: var(--fe-card-primary-hover-transform, translateY(-2px));
  border-color: var(--fe-color-card-primary-hover-border,
                    var(--fe-color-card-primary-border, #f59e0b));
}
.fe-card-style-preview-card--secondary {
  background: var(--fe-color-card-secondary-bg, var(--panel-2));
  border: var(--fe-card-secondary-border-width, 1px) solid var(--fe-color-card-secondary-border, var(--border));
  box-shadow: var(--fe-card-secondary-shadow, none);
  transition:
    background-color var(--fe-card-secondary-transition, 200ms ease),
    border-color var(--fe-card-secondary-transition, 200ms ease),
    box-shadow var(--fe-card-secondary-transition, 200ms ease),
    transform var(--fe-card-secondary-transition, 200ms ease);
}
.fe-card-style-preview-card--secondary:hover {
  box-shadow: var(--fe-card-secondary-hover-shadow, 0 10px 32px rgba(15,23,42,0.08));
  transform: var(--fe-card-secondary-hover-transform, translateY(-3px));
  border-color: var(--fe-color-card-secondary-hover-border,
                    var(--fe-color-card-secondary-border, var(--border)));
}
.fe-card-style-preview-label {
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
}
.fe-card-style-preview-title {
  margin: 0; font-size: 1.0625rem; font-weight: 600;
  color: var(--text);
}
.fe-card-style-preview-body p { margin: 0; }
.fe-design-field {
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px 16px;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 10px;
  transition: border-color 140ms ease, background 140ms ease;
}
.fe-design-field--overridden {
  border-color: var(--brand);
  background: var(--brand-soft, var(--panel-2));
}
.fe-design-field-label { display: flex; flex-direction: column; gap: 3px; }
.fe-design-field-label b { font-size: 0.95rem; color: var(--text); }
.fe-design-field-help { line-height: 1.35; }
.fe-design-field-default { font-size: 0.7rem; }
.fe-design-field-default code {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 4px; padding: 1px 5px; font-size: 0.75rem;
}
.fe-design-field-control {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap;
}
.fe-design-field-control select,
.fe-design-field-control input[type="text"],
.fe-design-field-control input[type="number"] {
  flex: 1 1 auto; min-width: 0;
  padding: 7px 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel); color: var(--text);
  font: inherit;
}
/* Colour-row layout — sits in the same wrap-friendly flex row as
   every other control, but with bigger swatch and a native hex chip
   that reads the picker's value live (the site-wide design-token
   picker is suppressed on this page via `data-no-token-picker` so
   the chip isn't doubled up). The reset button anchors to the right
   on wide rows; on a narrow column it drops to the next line gracefully. */
.fe-design-color-row { align-items: center; gap: 10px; }
.fe-design-color-row .fe-design-reset { margin-left: auto; }
.fe-design-color-on {
  display: inline-flex; align-items: center; gap: 5px;
  flex: 0 0 auto;
  cursor: pointer; user-select: none;
}
.fe-design-color-input {
  width: 48px; height: 32px; padding: 0;
  border: 1px solid var(--border);
  border-radius: 6px; background: transparent; cursor: pointer;
  flex: 0 0 auto;
}
.fe-design-color-toggle { width: 16px; height: 16px; cursor: pointer; margin: 0; }
.fe-design-color-hex {
  display: inline-block;
  padding: 4px 9px;
  width: 9ch;
  border-radius: 6px;
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--muted);
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  text-transform: lowercase;
  white-space: nowrap;
  flex: 0 0 auto;
  cursor: text;
  outline: none;
  text-align: left;
  transition: border-color 120ms ease, background-color 120ms ease, color 120ms ease;
}
.fe-design-color-hex:hover {
  border-color: var(--brand, var(--access));
}
.fe-design-color-hex:focus,
.fe-design-color-hex:focus-visible {
  border-color: var(--brand, var(--access));
  background: var(--panel-2, var(--panel));
  color: var(--text);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand, var(--access)) 18%, transparent);
}
/* Visual cue when the typed hex doesn't parse — the JS commits on
   blur via a value-rollback, but while the admin is correcting their
   input the chip turns red so they know something's off. */
.fe-design-color-hex:invalid:not(:placeholder-shown) {
  border-color: var(--danger, #b91c1c);
  color: var(--danger, #b91c1c);
}
.fe-design-reset {
  width: 28px; height: 28px; padding: 0; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 6px; cursor: pointer;
  transition: color 140ms ease, background 140ms ease;
  font-size: 1rem; line-height: 1;
}
.fe-design-reset:hover { background: var(--panel); color: var(--text); }

/* Built-in pill — marks vendored fonts (Inter / Fraunces) so the admin
   knows the absence of a delete button is intentional. */
.fe-font-builtin-badge {
  display: inline-block; margin-left: 6px;
  font-size: 0.65rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 6px; border-radius: 4px;
  background: var(--panel); color: var(--muted);
  border: 1px solid var(--border);
  vertical-align: middle;
}

/* Branding & SEO: OG image preview row (image left, file input right). */
.og-image-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem;
  align-items: start; margin-top: 12px;
}
@media (max-width: 720px) {
  .og-image-row { grid-template-columns: 1fr; }
}
.og-image-preview img {
  display: block; max-width: 100%; max-height: 220px;
  margin-top: 8px; border-radius: 8px; border: 1px solid var(--border);
}
.og-image-empty {
  margin-top: 8px; padding: 24px; border: 1px dashed var(--border);
  border-radius: 8px; text-align: center; background: var(--panel-2);
}

/* Branding & SEO: two-panel grid inside the Site Identity card —
   Site name + Favicon | Open Graph. Mirrors .fe-header-grid. */
.fe-branding-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem;
  margin-top: 6px;
}
@media (max-width: 820px) { .fe-branding-grid { grid-template-columns: 1fr; } }

/* Favicon sub-block sits inside the Site name panel — preview tile on
   the left, file picker + clear toggle on the right. */
.fe-favicon-block {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  align-items: start; gap: 14px;
  margin-top: 12px; padding-top: 12px;
  border-top: 1px solid var(--border);
}
.fe-favicon-block-fields { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.fe-favicon-current {
  display: block; width: 56px; height: 56px; object-fit: contain;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 8px; padding: 6px;
}
.fe-favicon-current--empty {
  display: flex; align-items: center; justify-content: center;
  padding: 0; border-style: dashed;
}

.fe-og-image-stack {
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  margin-top: 8px;
}
.fe-og-image-current {
  display: block; max-width: 100%; max-height: 140px;
  border: 1px solid var(--border); border-radius: 8px;
}

/* Inline enable-toggle row inside the OG panel — the standalone
   .special-page-row pattern was too tall for a sub-panel. */
.fe-og-toggle-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 8px 10px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 8px; margin-bottom: 6px;
}

/* Header admin: every settings sub-panel sits inside a single card on an
   auto-fit grid (Width & padding | Logo | Under-header alert | Utility
   bar). Each panel keeps its own form so the global save bar can submit
   all dirty ones in one go.

   Column count tracks the *available* space, not the viewport: the Web
   Frontend admin sidebar (248 px) + page padding (28 px × 2) + the
   secondary admin subnav (248 px + 32 px gap) + .card padding (32 px ×
   2) eat ~620 px before the grid even starts, so a viewport-keyed
   3-col rule kicks in long before there's room for three 320-px
   columns. `auto-fit` + `minmax(min(100%, 320px), 1fr)` lets the grid
   render 1, 2, or 3 columns based on the room actually available
   inside the card — and `min(100%, 320px)` keeps the floor from
   exceeding the container width on very narrow shells. */
.fe-header-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: 1.5rem;
  margin-top: 6px;
}
.fe-header-grid-item {
  display: flex; flex-direction: column;
  min-width: 0;  /* allow long inputs/colour rows to shrink, not push */
  padding: 14px 16px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel-2);
  /* Container-type lets sub-rows inside each panel (alert colour row,
     icon row) collapse based on the *card's* width instead of the
     viewport — a viewport-keyed media query on .alert-bar-color-row
     would only kick in below 560 px even though the card itself can
     be ~280 px on a typical desktop with the admin sidebar + subnav
     trimming the page. */
  container-type: inline-size;
  container-name: fe-header-grid-item;
}
.fe-header-grid-title {
  margin: 0 0 4px; font-size: 0.95rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--text);
}
.fe-header-grid-blurb { margin: 0 0 12px; }
.fe-header-grid-foot { margin: 1rem 0 0; }
/* Tighter fieldset padding inside header-grid panels — the global
   `.fieldset` rule pads 2rem all-round, which on a 320-px column
   leaves <250 px for the legend + form controls. Halving the inline
   padding gives controls room to breathe without changing the look
   of fieldsets used elsewhere. */
.fe-header-grid-item .fieldset { padding: 1rem 1.25rem; }
.template-card { display: flex; flex-direction: column; gap: 10px;
  padding: 14px; border: 2px solid var(--border); border-radius: 12px;
  background: var(--panel); cursor: pointer; position: relative;
  transition: border-color 140ms ease, transform 140ms ease, box-shadow 140ms ease; }

/* Edit + Delete buttons that overlay each non-prebuilt layout card. Hidden
   by default, slide in on card hover. Bypass the card's radio-select
   click via stopPropagation in the JS handler. */
.template-card-actions {
  position: absolute; top: 8px; right: 8px;
  display: flex; gap: 4px; z-index: 2;
  opacity: 0; transition: opacity 140ms ease;
}
.template-card:hover .template-card-actions,
.template-card.active .template-card-actions { opacity: 1; }
.template-card-action-btn {
  min-width: 26px; height: 22px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
  cursor: pointer; line-height: 1;
  transition: background 140ms ease, color 140ms ease, transform 140ms ease;
}
.template-card-action-btn:hover { background: var(--panel-2); transform: translateY(-1px); }
.template-card-action-btn:focus-visible { outline: 2px solid var(--access); outline-offset: 2px; }
.template-card-action-btn .icon { width: 14px; height: 14px; }
.template-card-action-del {
  background: #dc2626; color: #fff; border-color: rgba(0, 0, 0, 0.18);
}
.template-card-action-del:hover { background: #b91c1c; color: #fff; }
.template-card-action-del .icon { color: #fff; }
.template-card:hover { border-color: var(--access); transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08); }
.template-card.active { border-color: var(--brand); background: var(--brand-soft); }
/* Badge is rendered on every card so JS can flip the .active class without
   re-rendering; CSS keeps it hidden unless the card is the live selection. */
.template-card .template-card-badge { display: none; }
.template-card.active .template-card-badge { display: inline-flex; }
.template-card input[type="radio"] { position: absolute; width: 0; height: 0;
  opacity: 0; pointer-events: none; }
.template-card-preview { height: 90px; border-radius: 8px; overflow: hidden;
  background: var(--panel-2); border: 1px solid var(--border);
  display: flex; flex-direction: column; }
.template-card-preview-bar { height: 12px; background: var(--brand); }
.template-card-preview-body { flex: 1; padding: 10px 12px;
  display: flex; align-items: center; justify-content: space-between; }
.template-card-preview-logo { width: 26px; height: 26px; border-radius: 6px;
  background: linear-gradient(135deg, var(--brand), var(--brand-2, var(--access))); }
.template-card-preview-nav { display: flex; gap: 6px; }
.template-card-preview-nav span { display: block; width: 28px; height: 5px;
  border-radius: 3px; background: var(--muted); opacity: 0.45; }

/* Footer preview (3 columns + bottom bar) */
.template-card-preview-footer { padding: 10px; background: #fafbfc; }
.template-card-preview-footer-cols { flex: 1; display: grid;
  grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.template-card-preview-footer-cols span { display: block;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 4px;
  height: 100%; }
.template-card-preview-footer-bar { height: 8px; border-radius: 3px;
  background: var(--muted); opacity: 0.25; margin-top: 8px; }

/* Mega menu preview (bar across top + 3-column grid, similar to homepage) */
.template-card-preview-megamenu { padding: 8px; }
.template-card-preview-mm-bar { height: 10px; border-radius: 4px;
  background: var(--brand); margin-bottom: 8px; }
.template-card-preview-mm-grid { display: grid;
  grid-template-columns: 1fr 1fr 1fr; gap: 6px; }
.template-card-preview-mm-grid span { display: block;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 4px;
  height: 34px; }

/* Homepage preview (hero band + 3 cards) */
.template-card-preview-homepage { padding: 8px; }
.template-card-preview-homepage-hero { height: 32px; border-radius: 6px;
  background: linear-gradient(135deg, var(--brand), var(--brand-2, var(--access)));
  margin-bottom: 8px; }
.template-card-preview-homepage-grid { display: grid;
  grid-template-columns: 1fr 1fr 1fr; gap: 6px; }
.template-card-preview-homepage-grid span { display: block;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 4px;
  height: 30px; }
.template-card-info { display: flex; flex-direction: column; gap: 4px; }
.template-card-name { font-size: 0.9375rem; font-weight: 600; color: var(--text);
  display: flex; align-items: center; gap: 8px; }
.template-card-badge { font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; color: #fff; background: var(--brand);
  padding: 2px 7px; border-radius: 999px; }
.template-card-desc { line-height: 1.45; }

.alert-bar-color-row, .alert-bar-icon-row { display: grid;
  grid-template-columns: 1fr 1fr; gap: 16px; }

/* Utility-bar admin editor — repeating-row form with kind-conditional
   fields. Each row collapses on narrow card widths so the layout stays
   adaptive regardless of viewport, sidebar, or surrounding chrome.
   Why container queries instead of @media: on the frontend admin page
   this card lives inside the main app sidebar (248px) + .content
   padding + a secondary fe-admin subnav (248px + gap) + card padding,
   so its actual width is ~viewport−600px. Viewport-keyed breakpoints
   guess wrong and the 5-col row grid overflows by ~1100px viewport. */
.fe-header-grid-item-wide {
  grid-column: 1 / -1;
  container-type: inline-size;
  container-name: utility-bar-card;
}
.utility-bar-side { margin-top: 14px; min-width: 0; }
.utility-bar-side legend { font-weight: 600; padding: 0 6px; }
.utility-bar-items { display: flex; flex-direction: column; gap: 10px;
  min-width: 0; }
/* The shared .fieldset rule pads 2rem all-round, which on narrow cards
   leaves less than 200px for the rows themselves and forces the row
   grids to overflow. Halve the inline padding so row contents have
   room. The mobile-default sub-fieldset gets the same treatment. */
@container utility-bar-card (max-width: 480px) {
  .utility-bar-side, .utility-bar-mobile-default {
    padding: 1rem;
  }
}

/* Each row — leaf or container — has the same outer grid: drag handle |
   row contents | remove button. The handle is the only legitimate drag
   start; clicking elsewhere lets the admin type/select normally. */
.utility-bar-row { display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 10px; padding: 10px;
  border: 1px solid var(--border, #e5e7eb); border-radius: 10px;
  background: var(--card-soft, rgba(0,0,0,0.02));
  align-items: start;
  min-width: 0;
}
.utility-bar-handle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  background: transparent; border: 0; border-radius: 6px;
  color: var(--muted, #6b7280); cursor: grab;
  flex: 0 0 auto;
  margin-top: 2px;
}
.utility-bar-handle:hover { background: rgba(0,0,0,0.05); color: var(--text, inherit); }
.utility-bar-handle .icon { width: 16px; height: 16px; }
.utility-bar-row.is-dragging { opacity: 0.55; }
/* Drop indicators set during dragover. The before / after lines are
   thin brand-tinted bars at the matching edge so the admin sees
   exactly where the row will land on drop; the target ring shows when
   the cursor is over the empty tail of a side or container. */
.utility-bar-row.is-drop-before { box-shadow: 0 -3px 0 0 var(--brand, #0b5cff); }
.utility-bar-row.is-drop-after  { box-shadow: 0 3px 0 0 var(--brand, #0b5cff); }
[data-utility-side].is-drop-target,
[data-utility-container-items].is-drop-target {
  outline: 2px dashed var(--brand, #0b5cff);
  outline-offset: -2px;
}

.utility-bar-row-fields { display: grid;
  grid-template-columns: 140px minmax(0, 1fr) minmax(0, 1fr) 160px auto;
  gap: 10px; align-items: end;
  min-width: 0; }
.utility-bar-row-fields label { display: flex; flex-direction: column;
  gap: 4px; font-size: 0.8125rem;
  min-width: 0; }
.utility-bar-row-fields label.check { flex-direction: row;
  align-items: center; gap: 6px; padding-bottom: 6px; }
/* Inputs/selects inherit `min-width: auto` from the grid, which means
   they refuse to shrink below their intrinsic content width — long
   placeholder text or a wide URL value pushes the whole row past the
   card edge. Force them to fill the column instead. */
.utility-bar-row-fields input,
.utility-bar-row-fields select { width: 100%; min-width: 0;
  box-sizing: border-box; }
/* The kind-visibility JS sets [hidden] on labels that the current kind
   doesn't apply to (e.g. URL + "Open in new tab" hide for text items).
   The .utility-bar-row-fields label rules above land at the same
   specificity as the UA [hidden]{display:none} rule, so without this
   override the labels stay visible. The attribute-scoped rule beats
   them on specificity. */
.utility-bar-row-fields label[hidden] { display: none; }
.utility-bar-add-row { margin-top: 10px; display: flex; gap: 8px; flex-wrap: wrap; }
.utility-bar-remove { align-self: start; }

/* Icon-chooser field — replaces the long flat <select> with the
   shared icon-picker modal trigger, matching the chrome the nav
   mega-menu and homepage feature-card editors already use. The
   wrapper sits in the row grid as if it were a <label>, and its
   has-icon / [hidden] toggles flip the preview, the empty caption,
   and the clear button on or off. */
.utility-bar-row-fields .utility-bar-icon-field {
  display: flex; flex-direction: column;
  gap: 4px; font-size: 0.8125rem;
  min-width: 0;
}
.utility-bar-icon-field[hidden] { display: none; }
.utility-bar-icon-field-lbl { color: inherit; }
.utility-bar-icon-field .icon-picker-trigger {
  width: 100%; min-width: 0;
  justify-content: flex-start;
}
.utility-bar-icon-field.has-icon .icon-picker-preview { display: inline-flex; }
.utility-bar-icon-field.has-icon .icon-picker-trigger-empty { display: none; }
.utility-bar-icon-field.has-icon .icon-picker-clear { display: inline-flex; }

/* Container — labelled group of inner items. Visually distinct from
   leaves: subtle accent border + brand-tinted header strip with the
   group glyph + admin label input + remove button. The inner items
   list is a drop zone (data-utility-container-items) styled the same
   way as the side wrapper so dragging an item over it gives the same
   ring affordance. */
.utility-bar-container {
  /* Reset the grid so the container can stack head / inner / add.
     One brand-tinted background runs across the entire container —
     head, items list, and add-row — so the grouping reads as a
     single panel. The inner rows keep their own card chrome and
     stand out clearly against this backdrop. */
  grid-template-columns: 1fr;
  border-color: var(--brand, #0b5cff);
  background: rgba(11, 92, 255, 0.08);
  padding: 0;
  overflow: hidden;
}
.utility-bar-container-head {
  display: grid;
  /* handle | glyph | label-input | collapsed-icon picker | remove.
     The label input takes the flexible column; the collapsed-icon
     picker sits to its right with intrinsic width so the visible
     "Collapsed icon" caption + select stay readable without
     squashing the label. */
  grid-template-columns: auto auto minmax(0, 1fr) auto auto;
  gap: 8px; align-items: center;
  padding: 10px 12px;
  min-width: 0;
}
.utility-bar-container-glyph {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--brand, #0b5cff);
}
.utility-bar-container-glyph .icon { width: 16px; height: 16px; }
.utility-bar-container-label-input {
  font-weight: 600;
  padding: 6px 10px;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  background: var(--panel, #fff);
  color: inherit; font-family: inherit; font-size: 0.875rem;
  min-width: 0; width: 100%; box-sizing: border-box;
}
.utility-bar-container-items {
  /* Roomier vertical gap so each row reads as its own card against
     the brand-tinted container backdrop — the gap is what visually
     separates one item from the next, since head and body now share
     a single background. */
  display: flex; flex-direction: column; gap: 14px;
  padding: 14px 12px 4px;
  min-height: 60px;
}
.utility-bar-container-items:empty::before {
  content: 'Drop items here, or use the button below';
  color: var(--muted, #6b7280);
  font-size: 0.8125rem; font-style: italic;
  text-align: center;
  padding: 8px 10px;
  display: block;
}
.utility-bar-container-add {
  padding: 10px 12px 12px;
}
/* Collapsed-icon picker — inlined into the container head as a
   compact "Collapsed icon: <select>" pair. Visible caption is
   tight; the long explainer lives on the label's title tooltip so
   the strip stays one line. */
.utility-bar-container-collapsed-label {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.8125rem; font-weight: 600;
  min-width: 0;
  white-space: nowrap;
}
.utility-bar-container-collapsed-label .utility-bar-icon-field-lbl {
  font-size: inherit; font-weight: inherit;
}
.utility-bar-container-collapsed-label .icon-picker-trigger {
  height: 30px; min-width: 90px; padding: 0 10px;
}
/* Inner rows inside a container sit on top of the brand-tinted
   panel — give them a solid white-ish card so the boundary between
   one row and the next is unambiguous. */
.utility-bar-container-items > .utility-bar-row {
  background: var(--panel, #fff);
  border-color: rgba(11, 92, 255, 0.20);
  box-shadow: 0 1px 2px rgba(11, 92, 255, 0.06);
}
/* Containers nested inside a container's items list don't make sense —
   the JS gates against it, but if anything slips through, hide the
   drag handle so it can't be picked up again. */
.utility-bar-container-items .utility-bar-container .utility-bar-handle { display: none; }

/* Theme-toggle row — singleton, can be dragged but has no editable
   fields and no remove button. Visually marked with a sun/moon glyph
   + a short "can't be removed" hint so the admin understands why this
   row looks different from the others. */
.utility-bar-row--theme-toggle {
  background: rgba(15, 118, 110, 0.06);
  border-color: rgba(15, 118, 110, 0.40);
}
.utility-bar-theme-toggle-fields {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap;
  padding: 4px 0;
}
.utility-bar-theme-toggle-glyph {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border-radius: 999px;
  background: rgba(15, 118, 110, 0.18);
  color: rgb(15, 118, 110);
  flex: 0 0 auto;
}
.utility-bar-theme-toggle-glyph .icon { width: 18px; height: 18px; }
.utility-bar-theme-toggle-label {
  font-weight: 600; color: var(--text, inherit);
}
.utility-bar-theme-toggle-help {
  flex: 1 1 200px; min-width: 0;
}
/* GSR singleton glyph carries the literal "GSR" text instead of an
   icon — same teal pill chrome as the theme/search singletons so the
   row reads as the same family. Slightly tighter type so three caps
   fit inside the 32 × 32 chip. */
.utility-bar-gsr-glyph {
  font-weight: 700;
  font-size: 0.7rem;
  letter-spacing: 0.04em;
}

/* Threshold tuned to the row-fields hard column widths (140 + 160 +
   ~150 newtab label + 4 × 10 gap = 490 minimum) plus the row outer
   chrome (handle, remove, gaps, padding, fieldset padding, card
   padding) — totals ~700 of card width before the 5-col grid stops
   fitting. Below that, drop to a flexible 2-col layout. */
@container utility-bar-card (max-width: 700px) {
  .utility-bar-row { grid-template-columns: auto minmax(0, 1fr); }
  .utility-bar-container { grid-template-columns: 1fr; }
  .utility-bar-row-fields { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .utility-bar-row-fields > label.utility-bar-newtab { grid-column: 1 / -1; }
  .utility-bar-remove { grid-column: 2; justify-self: end; }
  .utility-bar-container .utility-bar-remove { justify-self: end; }
}
/* On phones the two-up field grid still overflows (Type select + a long
   URL placeholder don't fit side by side). Stack to a single column so
   each input gets the full row width. The drag handle stays in its own
   column and the remove button parks at the end of the fields block. */
@container utility-bar-card (max-width: 380px) {
  .utility-bar-row-fields { grid-template-columns: minmax(0, 1fr); }
  .utility-bar-row-fields > label.utility-bar-newtab { grid-column: 1; }
  .utility-bar-remove { grid-column: 1; }
  /* Narrow head wraps the collapsed-icon picker and remove button
     onto their own rows so the label input keeps full width. */
  .utility-bar-container-head {
    grid-template-columns: auto auto minmax(0, 1fr);
  }
  .utility-bar-container-head .utility-bar-container-collapsed-label {
    grid-column: 1 / -1; justify-self: start;
  }
  .utility-bar-container-head .utility-bar-remove {
    grid-column: 1 / -1; justify-self: end;
  }
}

/* ===== Mega menu editor (admin) =====
   Columns stack vertically at full container width so each column gets room
   to breathe. Inside a column, link blocks sit in a single stream. #Icon and
   link-option rows keep their 2-up grid on desktop because there's plenty of
   horizontal room in the full-width layout. */
.nav-megamenu-editor { display: flex; flex-direction: column; gap: 22px;
  counter-reset: megacol; }
.nav-megacol { counter-increment: megacol;
  padding: 22px 24px; background: var(--panel-2);
  border: 1px solid var(--border); border-radius: 14px;
  display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.nav-megacol-head { display: flex; align-items: center; gap: 10px; min-width: 0; }
.nav-megacol-head > .drag-handle { flex: 0 0 auto; }
.nav-megacol-label { flex: 1 1 auto; min-width: 0;
  text-transform: uppercase; letter-spacing: .06em; font-weight: 600;
  font-size: 0.8125rem; color: var(--muted); }
.nav-megacol-label::before { content: "Column " counter(megacol); }
.nav-megacol-del-form { flex: 0 0 auto; margin: 0; }
.nav-megacol-addlink-form { margin: 0; }
.nav-megacol-links { list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 14px; }
.nav-megalink { padding: 14px 16px; background: var(--panel);
  border: 1px solid var(--border); border-radius: 10px;
  display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.nav-megalink-top { display: flex; align-items: center; gap: 10px;
  justify-content: space-between; }
.nav-megalink-drag { cursor: grab; color: var(--muted); }
.nav-megalink-drag:active { cursor: grabbing; }
.nav-megalink-del-form { margin: 0; }
.nav-megalink-del-form .btn { padding: 4px 8px; font-size: 0.8125rem; }
.nav-megalink-form { margin: 0; display: flex; flex-direction: column; gap: 12px; }
.nav-megalink.is-dirty { box-shadow: inset 2px 0 0 var(--warning); }
.btn.is-dirty { position: relative; }
.btn.is-dirty::after { content: ""; position: absolute; top: 4px; right: 4px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--warning); }
.nav-megalink-row { display: grid; gap: 14px; min-width: 0; }
.nav-megalink-row-text { grid-template-columns: 1fr 1fr; align-items: center; }
/* Icons row packs icon-before, icon-after, size, override-color, and the
   new-tab checkbox onto one wrap-friendly flex line instead of the old
   2-/3-column grid, so link blocks are noticeably more compact. Fields sit
   at their intrinsic width and pack to the left — no stretching. */
.nav-megalink-row-icons {
  display: flex; flex-wrap: wrap; gap: 1.5rem;
  align-items: flex-start; justify-content: flex-start;
}
.nav-megalink-row-icons .nav-megalink-field { flex: 0 0 auto; }
.nav-megalink-row-icons .nav-megalink-icon-field { flex: 0 0 auto; }
.nav-megalink-row input[type="text"] {
  padding: 9px 12px; font-size: 0.9rem;
  border: 1px solid var(--border); border-radius: 7px;
  background: var(--panel); color: var(--text); min-width: 0;
}
.nav-megalink-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.nav-megalink-field-lbl { font-size: 0.7rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600; }
.nav-megalink-field select { padding: 8px 10px; font-size: 0.875rem; border-radius: 7px;
  border: 1px solid var(--border); background: var(--panel); color: var(--text);
  min-width: 0; width: 100%; }
.nav-megalink-field-newtab .nav-megalink-newtab { height: 36px; padding: 0 2px; }
.nav-megalink-save { align-self: stretch; }
.nav-megalink-row-single { grid-template-columns: 1fr auto; align-items: center; }
@media (max-width: 720px) {
  .nav-megalink-row-text { grid-template-columns: 1fr; }
}
.nav-megalink-seg {
  display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
  background: var(--panel);
}
.nav-megalink-seg-opt {
  display: inline-flex; align-items: center; gap: 0; padding: 6px 10px;
  font-size: 0.75rem; color: var(--muted); cursor: pointer; line-height: 1;
}
.nav-megalink-seg-opt + .nav-megalink-seg-opt { border-left: 1px solid var(--border); }
.nav-megalink-seg-opt input { position: absolute; opacity: 0; pointer-events: none; }
.nav-megalink-seg-opt:has(input:checked) {
  background: var(--brand-soft); color: var(--brand); font-weight: 600;
}
.nav-megalink-color-field .nav-megalink-color-row {
  display: inline-flex; align-items: center; gap: 10px;
}
.nav-megalink-color-input {
  width: 44px; height: 28px; padding: 0; border: 1px solid var(--border);
  border-radius: 6px; background: transparent; cursor: pointer;
}
.nav-megalink-color-input:disabled { opacity: 0.35; cursor: not-allowed; }
/* Per-link size-override row: matches the override-color row's
   layout — toggle on the left, slider + percentage readout on the
   right. Slider dims when the toggle is off so the inactive state
   reads as "off" without needing to hide the control. */
.nav-megalink-size-field .nav-megalink-size-row {
  display: inline-flex; align-items: center; gap: 10px;
}
.nav-megalink-size-slider {
  width: 140px; accent-color: var(--brand);
}
.nav-megalink-size-slider:disabled { opacity: 0.35; cursor: not-allowed; }
.nav-megalink-size-out {
  font-size: 0.75rem; color: var(--muted); font-variant-numeric: tabular-nums;
  min-width: 38px; text-align: right;
}
.nav-megalink-size-field:not(.is-on) .nav-megalink-size-out { opacity: 0.5; }
.nav-megalink-row-footer { grid-template-columns: 1fr auto; align-items: center; }
.nav-megalink-newtab { display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.75rem; color: var(--muted); font-weight: 500; cursor: pointer; }
.nav-megalink-newtab input { accent-color: var(--brand); margin: 0; }
.nav-megalink-kind { font-size: 0.6875rem; text-transform: capitalize;
  background: var(--brand-soft); color: var(--brand); padding: 2px 8px;
  border-radius: 999px; font-weight: 600; letter-spacing: 0.02em;
  margin-right: auto; }
.nav-megalink-title { background: color-mix(in srgb, var(--brand) 4%, var(--panel)); }
.nav-megalink-section { background: color-mix(in srgb, var(--brand) 7%, var(--panel));
  border-color: color-mix(in srgb, var(--brand) 25%, var(--border)); }
.nav-megalink-button { background: color-mix(in srgb, var(--brand) 5%, var(--panel)); }
.nav-megacol-add-row { display: flex; flex-wrap: wrap; gap: 6px; }
.nav-megacol-add-row form { margin: 0; }
@media (max-width: 480px) {
  .nav-megalink-save { grid-column: 1 / -1; }
}
.alert-bar-color-row input[type="color"] { width: 100%; height: 40px; padding: 2px;
  border: 1px solid var(--border); border-radius: 6px; background: transparent;
  cursor: pointer; }
/* Stack the colour + icon rows when the host card is too narrow for
   two side-by-side controls. Container query (vs. viewport) so the
   collapse triggers off the actual card width — important on the
   header admin where the card lives inside the admin sidebar + subnav
   stack and the viewport stays wide. The legacy 560-px viewport rule
   stays as a fallback for browsers that don't support container
   queries. */
@container fe-header-grid-item (max-width: 320px) {
  .alert-bar-color-row, .alert-bar-icon-row { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .alert-bar-color-row, .alert-bar-icon-row { grid-template-columns: 1fr; }
}

.fe-logo-preview-mock { width: 100%; max-width: 248px; min-height: 96px; box-sizing: border-box;
  padding: 18px 14px; background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 8px; display: flex; align-items: center; justify-content: center;
  text-align: center; overflow: hidden; }
.fe-logo-preview-mock img { max-width: 100%; height: auto; display: block; object-fit: contain; }

/* ===== Web Frontend admin area — secondary sidebar layout ===== */
.fe-admin-layout { display: grid; grid-template-columns: 248px minmax(0, 1fr);
  gap: 32px; align-items: start; }
/* Universal 1rem gap between every direct child of the admin main column
   (cards, forms, free sections, etc.) so we never have to remember to
   space stacked panels per-page. .form gets the same gap so cards inside
   a form sit consistently with adjacent stand-alone cards. */
.fe-admin-main {
  min-width: 0;
  display: flex; flex-direction: column; gap: 1rem;
}
.fe-admin-main .form { gap: 1rem; }
.fe-tbl-scroll { max-width: 100%; overflow-x: auto; }
.fe-tbl-scroll .tbl { min-width: 720px; }
.fe-tbl-scroll .tbl .chip { white-space: nowrap; }
.fe-tbl-scroll .tbl td.trunc { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fe-tbl-scroll .tbl .row-actions { flex-wrap: nowrap; justify-content: flex-end; }
.fe-tbl-scroll .tbl .row-actions .btn { white-space: nowrap; }
.fe-subnav { position: sticky; top: 22px; }
/* Save bar fixed to the viewport bottom-left, aligned with the frontend
   admin sidebar column (main app sidebar width + .content padding-left).
   Stays anchored to the viewport bottom regardless of scroll position. */
.fe-save-bar {
  position: fixed;
  left: calc(var(--sidebar-w, 248px) + 28px);
  bottom: 22px;
  width: var(--sidebar-w, 248px);
  /* Stack above any open modal (z-index 100) so the bar — and its
     Save button — stays visible AND clickable while a content-edit
     modal is on focus. Without this the modal backdrop's
     `backdrop-filter: blur(6px)` blurred the bar and intercepted
     clicks intended for the Save button, which made saving the hero
     modal feel broken because the bar was visually muted and dead. */
  z-index: 110;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 12px 14px; border-radius: 12px;
  background: #facc15; color: #422006;
  border: 1px solid #ca8a04;
  box-shadow: 0 8px 22px rgba(202, 138, 4, 0.28);
  animation: fe-save-appear 220ms ease-out both;
}
/* Non-frontend admin pages (library detail, etc.) shift the bar 2rem
   further right of where the frontend admin save bar sits, so it visually
   aligns with the start of the page's content column instead of sitting
   flush against the sidebar gutter. */
.fe-save-bar-content {
  left: calc(var(--sidebar-w, 248px) + 28px + 2rem);
}
@media (max-width: 900px) {
  /* On mobile the .fe-admin-layout collapses to one column and the main
     sidebar usually doesn't reserve a column either; show the bar full-
     width at the screen bottom — applies to both variants. */
  .fe-save-bar,
  .fe-save-bar-content {
    left: 12px; right: 12px; bottom: 12px; width: auto;
  }
}
@keyframes fe-save-appear {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.fe-save-bar.is-leaving {
  animation: fe-save-leave 280ms cubic-bezier(0.55, 0, 0.85, 0.4) forwards;
}
@keyframes fe-save-leave {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(28px); }
}
.fe-save-bar[hidden] { display: none !important; }
/* In-modal variant — reuses the yellow chrome but unfixes the global
   bar's `position: fixed; left: …; bottom: …` so it sits inline
   inside the modal footer. Sized to its content (chip-style); placed
   on the LEFT of the footer with Cancel pushed to the right via the
   bar's `margin-right: auto`. Slides in from below on first appearance
   via the same `fe-save-appear` keyframe. */
.fe-modal-save-bar.fe-save-bar {
  position: relative;
  left: auto; right: auto; bottom: auto;
  width: auto;
  flex: 0 0 auto;
  min-width: 0;
  /* `order: -1` puts the bar before any other flex sibling regardless
     of DOM position; `margin-right: auto` pushes the rest of the
     footer (Cancel) to the right edge. */
  order: -1;
  margin-left: 0;
  margin-right: auto;
}
.fe-modal-save-bar.fe-save-bar .fe-save-bar-msg {
  flex: 0 0 auto;
}
.fe-save-bar-msg {
  font-weight: 700; font-size: 0.875rem;
  /* Single line, ellipsised if it'd wrap — prevents a 1→2 line flash
     when the message changes ("Unsaved changes" → "Saving…" → "Saved")
     since "Saving…" makes the button slightly wider. */
  flex: 1 1 auto; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fe-save-bar-btn.btn { background: #422006; color: #facc15;
  border-color: #422006; padding: 6px 14px;
  flex: 0 0 auto; white-space: nowrap; }
.fe-save-bar-btn.btn:hover { background: #1c0f02; color: #fde047; }
/* Hide the per-card inline save buttons once the global save bar is on
   screen — the bar is the canonical way to commit. The inline form-actions
   are still in the DOM as a no-JS fallback. */
body.has-fe-save-bar .fe-admin-main .form-actions { display: none; }
.fe-subnav-head { padding: 2px 4px 16px; border-bottom: 1px solid var(--border);
  margin-bottom: 12px; }
.fe-subnav-title { font-size: 1.0625rem; font-weight: 700; color: var(--text);
  letter-spacing: -0.01em; line-height: 1.2; }
.fe-subnav-sub { font-size: 0.8125rem; color: var(--muted); margin-top: 4px; }
.fe-subnav-status { font-weight: 600; }
.fe-subnav-status.on { color: #16a34a; }
.fe-subnav-status.off { color: var(--muted); }

.fe-status-row { margin-bottom: 4px; }
.fe-status-pill { display: inline-block; margin-left: 8px; font-size: 0.8125rem;
  font-weight: 600; vertical-align: middle; }
.fe-status-pill.on { color: #16a34a; }
.fe-status-pill.off { color: var(--muted); }
.fe-subnav-nav { display: flex; flex-direction: column; gap: 1px; }
.fe-subnav-group { margin-top: 14px; }
.fe-subnav-group-label { font-size: 0.6875rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted); padding: 0 10px 6px; margin-top: 6px; }
.fe-subnav-link { display: flex; align-items: center; gap: 10px;
  padding: 7px 10px; border-radius: 6px; color: var(--text);
  font-size: 0.9375rem; font-weight: 500; text-decoration: none;
  position: relative; transition: background 120ms ease, color 120ms ease; }
.fe-subnav-link > .icon { width: 16px; height: 16px; flex: 0 0 auto;
  color: var(--muted); transition: color 120ms ease; }
.fe-subnav-link:hover { background: var(--panel-2); text-decoration: none; }
.fe-subnav-link.active { background: var(--panel-2); color: var(--text); font-weight: 600; }
.fe-subnav-link.active::before {
  content: ""; position: absolute; left: -4px; top: 7px; bottom: 7px;
  width: 3px; border-radius: 2px; background: var(--brand);
}
.fe-subnav-link.active > .icon { color: var(--text); }

@media (max-width: 900px) {
  .fe-admin-layout { grid-template-columns: 1fr; gap: 18px; }
  .fe-subnav { position: static; }
  .fe-subnav-head { padding-bottom: 10px; margin-bottom: 8px; }
  .fe-subnav-nav { flex-direction: row; flex-wrap: wrap; gap: 4px; }
  .fe-subnav-group { margin-top: 0; display: contents; }
  .fe-subnav-group-label { display: none; }
  .fe-subnav-link { flex: 0 0 auto; padding: 6px 10px; }
  .fe-subnav-link.active::before { display: none; }
}
.intergroup-grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 20px; align-items: start; }
@media (max-width: 800px) { .intergroup-grid { grid-template-columns: 1fr; } }
.ig-email-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
.ig-email-list li { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.ig-role { font-weight: 500; }
.ig-sep { color: var(--muted); }
.ig-addr { font-weight: 500; }
.ig-webmail { margin-top: 18px; }
.ig-setup .ig-setting { display: flex; gap: 14px; align-items: flex-start; margin: 14px 0; }
.ig-setting-icon {
  width: 44px; height: 44px; border-radius: 10px; display: flex;
  align-items: center; justify-content: center; font-size: 1.25rem;
  color: #fff; flex-shrink: 0;
}
.ig-icon-incoming { background: #2563eb; box-shadow: inset 0 -8px 0 rgba(34,197,94,0.6); }
.ig-icon-outgoing { background: #7c3aed; box-shadow: inset 0 -8px 0 rgba(236,72,153,0.6); }
.ig-setting-title { font-weight: 600; margin-bottom: 2px; }
.ig-learn { color: var(--access); font-weight: 500; }
.alert-banner {
  background: #fef3c7;
  color: #78350f;
  border: 1px solid #f59e0b;
  border-left: 4px solid #d97706;
  padding: 10px 14px;
  border-radius: 8px;
  margin-bottom: 14px;
  white-space: pre-wrap;
  font-weight: 500;
}
.sidebar-nav-divider {
  margin: 10px 4px 4px; padding-top: 10px;
  border-top: 1px solid var(--border);
}
.sidebar-nav-label {
  display: block; font-size: 0.75rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted); padding: 0 8px 4px;
}
/* The divider doubles as a collapse/expand button for its section.
   Strip default button chrome so it visually matches the previous
   plain-div divider, then make the whole row clickable. */
button.sidebar-section-toggle {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: 8px; background: transparent; border: 0; border-top: 1px solid var(--border);
  font: inherit; color: inherit; text-align: left; cursor: pointer;
  border-radius: 0;
}
button.sidebar-section-toggle[hidden] { display: none; }
button.sidebar-section-toggle:hover .sidebar-nav-label { color: var(--text); }
button.sidebar-section-toggle:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.sidebar-section-chevron {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--muted); padding: 0 8px 4px;
  transition: transform 0.18s ease;
}
.sidebar-section-chevron .icon { font-size: 1rem; }
button.sidebar-section-toggle[aria-expanded="false"] .sidebar-section-chevron {
  transform: rotate(-90deg);
}
.sidebar-section-items { display: flex; flex-direction: column; gap: 2px; }
.sidebar-section-items[hidden] { display: none; }
.sidebar-footer { flex: 0 0 auto; padding-top: 14px; border-top: 1px solid var(--border);
  /* The footer lives inside the fixed-width sidebar; ensure long content
     (extra-long usernames in particular) can't push the footer past the
     sidebar edge or escape into the main content column. */
  min-width: 0; overflow: hidden; }
.user-chip { display: flex; gap: 10px; align-items: center; padding: 6px 4px;
  min-width: 0; }
.avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  color: #fff; display: grid; place-items: center; font-weight: 700;
  flex: 0 0 auto;
}
/* Username + role text column. ``min-width: 0`` (declared further
   down on .user-chip-name) lets the flex child shrink below its
   intrinsic content width so ellipsis can engage. The button to the
   right keeps its natural size; long usernames are clipped, not
   wrapped, with the full value surfaced via title= on hover. */
.u-name { font-weight: 600; font-size: 0.8438rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%; }
.u-role { font-size: 0.7188rem; color: var(--muted); text-transform: capitalize;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%; }
.footer-actions { display: flex; gap: 6px; margin-top: 10px; }

.icon { width: 1em; height: 1em; display: inline-block; vertical-align: -0.15em;
  flex: 0 0 auto; }
.icon-btn .icon { font-size: 1.125rem; }
.icon-btn-inline .icon { font-size: 1.35rem; }
.btn-sm .icon { font-size: 1rem; }
.btn .icon + span, .btn span + .icon { margin-left: 4px; }
.link .icon { margin-left: 4px; font-size: 0.95em; }
.icon-btn {
  flex: 1; height: 34px; display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel-2); color: var(--text); cursor: pointer;
  text-decoration: none; font-size: 0.875rem;
}
.icon-btn:hover { background: var(--brand-soft); }
.theme-icon-light, .theme-icon-dark { display: none; }
[data-theme="light"] .theme-icon-dark,
[data-theme="neobrutal-light"] .theme-icon-dark,
[data-theme="solarpunk"] .theme-icon-dark { display: inline; }
[data-theme="dark"] .theme-icon-light,
[data-theme="neobrutal-dark"] .theme-icon-light,
[data-theme="cyberpunk"] .theme-icon-light { display: inline; }

.content { padding: 22px 28px 48px; min-width: 0; max-width: 1400px; }
.content:has(.fe-admin-layout) { max-width: none; }
.topbar {
  display: flex; align-items: center; gap: 14px; margin-bottom: 14px;
}
.topbar h1 { font-size: 1.375rem; font-weight: 700; flex: 1; display: flex; align-items: center; gap: 8px; }
.heading-help { position: relative; display: inline-flex; font-size: 0.875rem; font-weight: 400; }
.help-btn {
  width: 22px; height: 22px; border-radius: 50%; border: 1px solid var(--border);
  background: var(--panel); color: var(--muted); cursor: pointer;
  font-size: 0.8125rem; line-height: 1; padding: 0; display: inline-flex;
  align-items: center; justify-content: center;
}
.help-btn:hover { background: var(--border); color: var(--text); }
.help-tooltip {
  display: none; position: absolute; top: calc(100% + 6px); left: 0; z-index: 50;
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px; font-size: 0.8125rem; font-weight: 400; line-height: 1.45;
  width: max-content; max-width: 360px; color: var(--text);
  box-shadow: 0 4px 16px rgba(0,0,0,.18);
}
.heading-help.open .help-tooltip { display: block; }
.top-actions { display: flex; gap: 8px; }
.menu-btn {
  display: none; background: transparent; border: 0; padding: 0;
  color: var(--text); width: 38px; height: 38px; border-radius: 8px; cursor: pointer;
  align-items: center; justify-content: center;
}
.menu-btn:hover { background: var(--brand-soft); }

.flashes {
  position: fixed; top: 16px; right: 16px; z-index: 1000;
  display: flex; flex-direction: column; gap: 8px;
  margin: 0; pointer-events: none; max-width: calc(100vw - 32px);
}
.flash {
  pointer-events: auto;
  box-shadow: 0 6px 24px rgba(0,0,0,0.18);
  animation: flash-in 180ms ease-out;
}
.flash.flash-hide { animation: flash-out 240ms ease-in forwards; }
@keyframes flash-in {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes flash-out {
  to { opacity: 0; transform: translateY(-8px); }
}
.flash {
  padding: 10px 14px; border-radius: 8px; border: 1px solid var(--border); background: var(--panel);
}
.flash-success { border-color: #b5e5cd; background: #e7f8ee; color: #14532d; }
.flash-danger  { border-color: #f3b9bb; background: #fdecec; color: #7f1d1d; }
.flash-warning { border-color: #fde4b3; background: #fff6e1; color: #7c4a03; }
[data-theme="dark"] .flash-success { background: #15341f; color: #b7f5cf; border-color: #1c5a35; }
[data-theme="dark"] .flash-danger  { background: #381416; color: #fbb; border-color: #642325; }
[data-theme="dark"] .flash-warning { background: #3a2808; color: #ffdc99; border-color: #6b4a17; }

.card {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 2rem; margin-bottom: 16px;
  box-shadow: var(--shadow);
}
.card-head {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 12px; gap: 10px;
}
.card-head h2 { font-size: 1rem; font-weight: 700; }
.card-head-actions { display: flex; align-items: center; gap: 8px; }

/* Collapsible cards (Web Frontend admin only). The JS adds a chevron
   button to each .card-head, makes the head clickable, and toggles
   .is-collapsed on the parent .card. CSS hides everything below the head
   and shrinks padding so the collapsed cards stack tightly. */
.fe-admin-main .card {
  transition: padding 160ms ease; margin-bottom: 0;
  /* Pointer cursor on the card itself so the strip of padding above the
     heading reads as "click to collapse". Everything else inside the card
     (form fields, buttons, body content) explicitly resets so they keep
     their normal cursors. Spacing between cards is owned by the .fe-admin-main
     flex `gap: 1rem` rule above — do not re-introduce per-card margins. */
  cursor: pointer;
}
.fe-admin-main .card > :not(.card-head) { cursor: default; }
.fe-admin-main .card > :not(.card-head) :is(input, textarea, select) { cursor: text; }
.fe-admin-main .card > :not(.card-head) :is(button, a, label) { cursor: pointer; }
.fe-admin-main .card-head {
  cursor: pointer; user-select: none;
  margin-bottom: 0;
}
/* The card-head is a 3-child flex row in FE admin (h2, optional
   .card-head-actions, JS-injected .fe-card-toggle). Default
   `justify-content: space-between` would strand the actions in the
   middle — push them to the right edge so they sit flush against the
   chevron. Cards that use a plain muted-description span instead of
   .card-head-actions are unaffected. */
.fe-admin-main .card-head > .card-head-actions { margin-left: auto; }
.fe-admin-main .card-head:hover h2 { color: var(--access); }
/* Allow the chevron to sit at the far right while the existing actions
   row stays grouped before it. */
.fe-card-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0; flex: 0 0 auto;
  background: transparent; border: 1px solid transparent; border-radius: 6px;
  color: var(--muted); cursor: pointer;
  transition: background 140ms ease, color 140ms ease, transform 220ms ease;
}
.fe-card-toggle:hover { background: var(--panel-2); color: var(--text); }
.fe-card-toggle .icon { width: 16px; height: 16px; }
/* When the card is open the chevron points up; flips down on collapse. */
.fe-admin-main .card:not(.is-collapsed) .fe-card-toggle { transform: rotate(180deg); }

/* When collapsed: hide everything below the head + shrink the card box
   so the stack of titles reads as a tight TOC. The entire card surface
   becomes the click target — JS bails out of any interactive descendant. */
.fe-admin-main .card.is-collapsed { padding: 1rem 1.5rem; cursor: pointer; }
.fe-admin-main .card.is-collapsed:hover { background: var(--panel-2); }
.fe-admin-main .card.is-collapsed > :not(.card-head) { display: none !important; }
/* Re-enable spacing under the head when expanded (we cleared the default
   margin-bottom above so the chevron alignment stays consistent). */
.fe-admin-main .card:not(.is-collapsed) .card-head { margin-bottom: 12px; }
[data-save-reorder-for].is-dirty { background: var(--brand); color: #fff; border-color: var(--brand); }

.tsp-toast-host { position: fixed; bottom: 20px; right: 20px; z-index: 10000;
  display: flex; flex-direction: column; gap: 8px; pointer-events: none; }
.tsp-toast { background: #0f172a; color: #fff; padding: 10px 16px; border-radius: 8px;
  font-size: 0.875rem; font-weight: 500; box-shadow: 0 8px 24px rgba(0,0,0,.22);
  opacity: 0; transform: translateY(8px);
  transition: opacity 140ms ease, transform 140ms ease; }
.tsp-toast.tsp-toast-in { opacity: 1; transform: translateY(0); }
.tsp-toast-error { background: #b91c1c; }
.card-hover { transition: transform .08s ease, box-shadow .12s ease;
  display: flex; flex-direction: column; color: inherit; overflow: hidden; }
.card-hover .tags { margin-top: auto; }
.meeting-card { position: relative; gap: 12px; padding-right: 120px; }
.meeting-card h3 { margin: 0; padding-right: 0; font-weight: 500; }
a.card.meeting-card { font-weight: 500; }
.file-main strong, .file-main a { font-weight: 500; }
.meeting-card .schedule-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.card-type-chip { position: absolute; top: 12px; right: 12px; }
.card-hover:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(17,24,39,.10); text-decoration: none; }

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px;
  grid-auto-rows: 1fr; align-items: stretch; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 16px; }
.stat { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 2rem; box-shadow: var(--shadow); }
.stat-v { font-size: 1.375rem; font-weight: 700; }
.stat-l { color: var(--muted); font-size: 0.7812rem; margin-top: 2px; }
.role-caps { list-style: none; margin: 14px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.role-caps li { position: relative; padding-left: 18px; font-size: 0.8125rem; line-height: 1.35; color: var(--text); }
.role-caps li::before { content: "✓"; position: absolute; left: 0; top: 0; color: var(--brand); font-weight: 700; }
/* Footer "See full access details" link — render without the green
   check so it reads as a separate affordance from the capability
   bullets, with a small top-margin to detach it visually. */
.role-caps li.role-caps-link { padding-left: 0; margin-top: 6px; font-size: 0.75rem; }
.role-caps li.role-caps-link::before { content: none; }
.role-caps li.role-caps-link a { color: var(--brand); text-decoration: none; font-weight: 600; }
.role-caps li.role-caps-link a:hover { text-decoration: underline; }

/* Combined role + server-metrics widget layout */
.server-metrics-body { display: grid; grid-template-columns: minmax(200px, 1fr) 2fr; gap: 24px; align-items: start; }
.server-metrics-role-only .server-metrics-body { grid-template-columns: 1fr; }
.server-metrics-role-only .role-panel { padding-right: 0; border-right: 0; }
.role-panel { display: flex; flex-direction: column; padding-right: 24px; border-right: 1px solid var(--border); }
.role-panel-label { font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
.role-panel-name { font-size: 1.375rem; font-weight: 700; color: var(--text); margin-top: 2px; line-height: 1.2; }
.role-panel .role-caps { margin-top: 12px; }
.server-metrics-column { min-width: 0; }
@media (max-width: 900px) {
  .server-metrics-body { grid-template-columns: 1fr; gap: 18px; }
  .role-panel { padding-right: 0; padding-bottom: 18px; border-right: 0; border-bottom: 1px solid var(--border); }
}

/* ===== Content mode toggle (Upload / Paste) on reading forms ===== */
.content-mode-toggle { display: flex; align-self: flex-start; margin: 2px 0 4px;
  flex: 0 0 auto; }
/* Bump specificity above .form label / .file-add-form label so the labels
   on either side of the switch render in a row, not stacked. */
.form label.content-mode-switch,
.file-add-form label.content-mode-switch,
label.content-mode-switch {
  display: inline-flex; flex-direction: row; align-items: center;
  gap: 12px; font-size: 0.875rem; font-weight: 400; color: var(--text);
  cursor: pointer; user-select: none; margin: 0;
}
.content-mode-switch .mode-track { background: var(--brand); }
.content-mode-switch input:checked ~ .mode-track,
.content-mode-switch input:not(:checked) ~ .mode-track { background: var(--brand); }
.content-mode-label { font-weight: 500; color: var(--muted); transition: color 120ms ease; }
.content-mode-label.active { color: var(--text); font-weight: 600; }

/* ===== Markdown editor (reading body) ===== */
.md-editor { border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
  background: var(--panel); }
.md-editor-tabs { display: flex; align-items: center; gap: 4px; background: var(--panel-2);
  border-bottom: 1px solid var(--border); padding: 4px 6px; }
.md-editor-tab { background: transparent; border: 0; padding: 6px 12px; font-size: 0.8125rem;
  font-weight: 600; color: var(--muted); cursor: pointer; border-radius: 6px 6px 0 0; }
.md-editor-tab.active { background: var(--panel); color: var(--text); border: 1px solid var(--border);
  border-bottom: 1px solid var(--panel); margin-bottom: -5px; padding: 5px 11px; }
.md-editor-tab:hover:not(.active) { color: var(--text); }
.md-editor-hint { margin-left: auto; padding-right: 6px; }
.md-editor-pane { display: none; }
.md-editor-pane.active { display: block; }
.md-editor-pane-write textarea { width: 100%; border: 0; background: var(--panel);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.875rem;
  line-height: 1.5; padding: 10px 12px; resize: vertical; color: var(--text); }
.md-editor-pane-write textarea:focus { outline: 2px solid var(--brand-soft); outline-offset: -2px; }
.md-editor-preview { padding: 14px 16px; min-height: 140px; max-height: 420px; overflow-y: auto;
  font-size: 0.9375rem; line-height: 1.5; }
.md-editor-preview > :first-child { margin-top: 0; }
.md-editor-preview > :last-child { margin-bottom: 0; }
.md-editor-preview h1, .md-editor-preview h2, .md-editor-preview h3 {
  margin: 1em 0 .35em; line-height: 1.25; }
.md-editor-preview p { margin: 0 0 .6em; }
.md-editor-preview ul, .md-editor-preview ol { margin: 0 0 .6em 1.25em; padding: 0; }
.md-editor-preview blockquote { margin: .4em 0; padding: .2em .8em;
  border-left: 3px solid var(--border); color: var(--muted); font-style: italic; }
.md-editor-preview code { font-family: ui-monospace, monospace; background: var(--panel-2);
  padding: 1px 5px; border-radius: 3px; font-size: 0.9em; }
.md-editor-preview pre { background: var(--panel-2); padding: 10px 12px; border-radius: 6px;
  overflow-x: auto; }

/* Side-by-side live mode (used by the inclusion editor + features card
   bodies). The tabs are hidden (no need — both panes are visible at once);
   the two panes sit in a 1fr|1fr grid with a subtle divider. Stacks on
   narrow viewports so each pane keeps a useful width.
   Heights stay locked: each pane is a flex column, the textarea / inner
   preview both `flex: 1` to fill the grid cell, and the grid's default
   align-items: stretch means whichever column is taller (textarea's
   min-height + any user-resize, or content-driven preview) sets the row
   height — and the other column matches. The panel-2 background lives
   on the pane so the preview's coloured area always reaches the
   textarea's bottom edge, even when the rendered preview is short. */
.md-editor-live { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.md-editor-live .md-editor-tabs { display: none; }
.md-editor-live .md-editor-pane {
  display: flex; flex-direction: column;
  min-width: 0; min-height: 0;
}
.md-editor-live .md-editor-pane-write { border-right: 1px solid var(--border); }
.md-editor-live .md-editor-pane-preview { background: var(--panel-2); overflow: hidden; }
.md-editor-live .md-editor-pane-write textarea {
  flex: 1 1 auto; min-height: 180px; box-sizing: border-box;
}
.md-editor-live .md-editor-preview {
  flex: 1 1 auto; min-height: 0; max-height: none; overflow-y: auto;
  background: transparent;
}
@media (max-width: 720px) {
  .md-editor-live { grid-template-columns: 1fr; }
  .md-editor-live .md-editor-pane-write {
    border-right: 0; border-bottom: 1px solid var(--border);
  }
}

/* ===== Reading lightbox (paper-style PDF viewer) ===== */
.reading-lightbox .reading-lightbox-panel {
  max-width: 900px; width: calc(100vw - 32px); height: auto; max-height: 92vh;
  margin: 4vh auto; display: flex; flex-direction: column;
  background: var(--panel); border-radius: 12px; overflow: hidden;
  box-shadow: 0 24px 60px rgba(0,0,0,0.35);
}
.reading-lightbox .reading-lightbox-body { background: #eef1f5; padding: 28px 20px;
  overflow-y: auto; display: block; }
[data-theme="dark"] .reading-lightbox .reading-lightbox-body,
[data-theme="neobrutal-dark"] .reading-lightbox .reading-lightbox-body,
[data-theme="cyberpunk"] .reading-lightbox .reading-lightbox-body { background: #0f0f14; }
.reading-paper { background: #fff; color: #111; max-width: 740px; margin: 0 auto;
  padding: 56px 64px 64px; border-radius: 4px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.22), 0 1px 3px rgba(0,0,0,0.12);
  font-family: Georgia, 'Times New Roman', serif; line-height: 1.6; font-size: 15px; }
.reading-paper-title { font-size: 26px; font-weight: 700; text-align: center;
  margin: 0 0 1.2em; padding-bottom: .6em; border-bottom: 1px solid #ddd; line-height: 1.2; }
.reading-paper-content > :first-child { margin-top: 0; }
.reading-paper-content > :last-child { margin-bottom: 0; }
.reading-paper-content h1 { font-size: 22px; margin: 1.4em 0 .4em; }
.reading-paper-content h2 { font-size: 19px; margin: 1.3em 0 .35em; }
.reading-paper-content h3 { font-size: 17px; margin: 1.1em 0 .3em; }
.reading-paper-content p { margin: 0 0 .9em; }
.reading-paper-content ul, .reading-paper-content ol { margin: 0 0 .9em 1.4em; padding: 0; }
.reading-paper-content li { margin: .15em 0; }
.reading-paper-content blockquote { margin: .8em 1em; padding: .4em 1em;
  border-left: 3px solid #999; color: #444; font-style: italic; }
.reading-paper-content code { font-family: ui-monospace, Consolas, monospace;
  background: #f0f0f0; padding: 1px 5px; border-radius: 3px; font-size: .93em; }
.reading-paper-content pre { background: #f6f6f6; padding: .7em .9em; border-radius: 4px;
  overflow-x: auto; font-size: .92em; }
.reading-paper-content a { color: #0b5cff; text-decoration: underline; }
.reading-paper-content hr { border: 0; border-top: 1px solid #bbb; margin: 1.2em 0; }
.reading-paper-content table { border-collapse: collapse; margin: .5em 0; }
.reading-paper-content th, .reading-paper-content td { border: 1px solid #bbb;
  padding: .35em .7em; }
@media (max-width: 640px) {
  .reading-paper { padding: 32px 24px; font-size: 14px; }
  .reading-paper-title { font-size: 20px; }
}

/* ===== File Browser lightbox ===== */
.file-lightbox .lightbox-panel {
  position: relative; margin: 3vh auto; width: calc(100% - 32px); max-width: 1200px;
  max-height: 94vh; display: flex; flex-direction: column; overflow: hidden;
  background: var(--panel); border: 1px solid var(--border); border-radius: 14px;
  box-shadow: 0 24px 70px rgba(0,0,0,0.35);
  transform: translateY(28px); transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.file-lightbox.open .lightbox-panel { transform: translateY(0); }
.lightbox-head { display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.lightbox-title { flex: 1; font-weight: 600; font-size: 0.9375rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lightbox-head-actions { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.lightbox-head-actions .icon-btn { width: 32px; height: 32px; }
.lightbox-body { flex: 1 1 auto; min-height: 0; display: flex; align-items: center;
  justify-content: center; background: var(--panel-2); overflow: hidden; }
.lightbox-image { max-width: 100%; max-height: 100%; object-fit: contain; display: block; }
.lightbox-pdf { width: 100%; height: 85vh; border: 0; background: #525659; }
@media (max-width: 720px) {
  .file-lightbox .lightbox-panel { margin: 1vh auto; width: calc(100vw - 12px); max-height: 98vh; border-radius: 10px; }
  .lightbox-pdf { height: 80vh; }
}

/* ===== Guided tour overlay ===== */
.tour-overlay { position: fixed; inset: 0; z-index: 2000; pointer-events: none;
  animation: tour-fade-in 200ms ease-out; }
@keyframes tour-fade-in { from { opacity: 0; } to { opacity: 1; } }
.tour-hole { position: fixed; border-radius: 10px; pointer-events: none;
  box-shadow: 0 0 0 9999px rgba(8, 12, 24, 0.72), 0 0 0 2px rgba(255,255,255,0.35) inset;
  transition: left 260ms cubic-bezier(0.2,0.8,0.2,1),
              top 260ms cubic-bezier(0.2,0.8,0.2,1),
              width 260ms cubic-bezier(0.2,0.8,0.2,1),
              height 260ms cubic-bezier(0.2,0.8,0.2,1); }
.tour-hole[hidden] { display: block; left: 50%; top: 50%; width: 0; height: 0;
  box-shadow: 0 0 0 9999px rgba(8, 12, 24, 0.72); }
.tour-card { position: fixed; width: 360px; max-width: calc(100vw - 24px);
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 14px;
  padding: 18px 20px 16px; pointer-events: auto;
  box-shadow: 0 24px 60px rgba(0,0,0,0.35), 0 6px 16px rgba(0,0,0,0.15);
  display: flex; flex-direction: column; gap: 10px;
  transition: left 240ms cubic-bezier(0.2,0.8,0.2,1),
              top 240ms cubic-bezier(0.2,0.8,0.2,1); }
.tour-card-head { display: flex; justify-content: space-between; align-items: center; }
.tour-step-count { font-size: 0.6875rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--brand); }
.tour-close { background: transparent; border: 0; padding: 0; width: 28px; height: 28px;
  font-size: 1.5rem; line-height: 1; color: var(--muted); cursor: pointer; border-radius: 6px; }
.tour-close:hover { background: var(--panel-2); color: var(--text); }
.tour-title { font-size: 1.125rem; font-weight: 700; margin: 0; line-height: 1.3; }
.tour-content { font-size: 0.9375rem; line-height: 1.55; color: var(--text); margin: 0; }
.tour-progress { display: flex; gap: 5px; margin-top: 4px; }
.tour-dot { flex: 1; height: 3px; border-radius: 2px; background: var(--border); transition: background 180ms ease; }
.tour-dot.done { background: var(--brand-2); }
.tour-dot.active { background: var(--brand); }
.tour-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }
.tour-actions .btn { padding: 6px 14px; font-size: 0.875rem; }
.tour-prev:disabled { opacity: 0.4; cursor: not-allowed; }
.tour-skip { background: transparent; border-color: transparent; color: var(--muted); }
.tour-skip:hover { background: var(--panel-2); color: var(--text); }

@media (max-width: 600px) {
  .tour-card { padding: 14px 16px 12px; }
  .tour-title { font-size: 1rem; }
}

/* Help modal: tour row */
.help-tour-row { display: flex; align-items: center; justify-content: space-between;
  gap: 14px; padding: 12px 14px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel-2); }
.help-tour-copy { min-width: 0; }
.help-tour-copy .u-name { font-size: 1rem; margin-bottom: 2px; }
.help-tour-copy p { margin: 0; }
@media (max-width: 520px) {
  .help-tour-row { flex-direction: column; align-items: stretch; }
}

.muted { color: var(--muted); }
.small { font-size: 0.7812rem; }
.smaller { font-size: 0.7188rem; }
.clip { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; color: var(--muted); min-width: 0; }
.trunc { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; max-width: 100%; }

.tags { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
.tag { background: var(--brand-soft); color: var(--brand); padding: 3px 10px; border-radius: 999px; font-size: 0.7188rem; font-weight: 600; }
.chip { background: var(--panel-2); border: 1px solid var(--border); padding: 3px 10px; border-radius: 999px; font-size: 0.75rem; color: var(--text); font-weight: 400; cursor: pointer; }
button.chip { font-family: inherit; }
.chip:hover { border-color: var(--brand); color: var(--brand); }
.chip-active, .chip-active:hover { background: var(--brand); border-color: var(--brand); color: var(--bg); }
/* "Homepage" chip — surfaces which Page is currently bound to
   `SiteSetting.homepage_page_id` in the Pages admin list and the
   page-edit title banner. Brand-tinted background + brand text so it
   reads as a primary affordance against the neutral row backgrounds.
   The `.icon` inline-svg sits flush with the text. */
.chip-homepage {
  background: color-mix(in srgb, var(--brand) 12%, var(--panel));
  border-color: color-mix(in srgb, var(--brand) 40%, var(--border));
  color: var(--brand);
  font-weight: 600;
  display: inline-flex; align-items: center; gap: 4px;
  cursor: default;
}
.chip-homepage:hover {
  background: color-mix(in srgb, var(--brand) 12%, var(--panel));
  border-color: color-mix(in srgb, var(--brand) 40%, var(--border));
  color: var(--brand);
}
.chip-homepage .icon { width: 12px; height: 12px; }
/* "Make homepage" form inside the page-edit title banner — strip the
   default <form> block-level layout so the button sits inline with
   the rest of the meta row's chips. */
.fe-page-edit-make-homepage { display: inline; margin: 0; padding: 0; }
/* Highlight the current-homepage row in the Pages admin list so it's
   easy to spot at a glance. Subtle tint, no border change. */
.tbl tr.is-homepage td {
  background: color-mix(in srgb, var(--brand) 5%, var(--panel));
}
/* Intergroup library detail toolbar: search + sort + category filter
   pills sit above the file list. Wraps on narrow screens. */
.ig-lib-toolbar {
  display: flex; flex-wrap: wrap; gap: 12px 16px;
  align-items: center; padding: 6px 12px 14px;
}
.ig-lib-search { flex: 1 1 240px; min-width: 220px; }
.ig-lib-search input[type="search"] {
  width: 100%; padding: 8px 12px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel-2); color: var(--text);
}
.ig-lib-sort { display: flex; align-items: center; }
.ig-lib-sort label { display: inline-flex; gap: 8px; align-items: center; }
.ig-lib-sort select {
  padding: 6px 10px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--text);
}
.ig-lib-filter { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 100%; }
.ig-lib-filter .chip { font-weight: 500; }
.ig-lib-empty { padding: 12px 14px; }
.ig-cat-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.ig-cat-chip {
  background: var(--brand-soft); color: var(--brand);
  padding: 1px 8px; border-radius: 999px;
  font-size: 0.6875rem; font-weight: 600;
}
/* Category picker on the upload / edit modals: each checkbox sits on
   its own line, left-aligned. Specificity bumps (.ig-cat-picker
   .ig-cat-check) deliberately beat .form label's column direction and
   .form input's text-input restyle, both of which would otherwise
   stack each checkbox over its label and inflate the box itself. */
.ig-cat-picker { display: flex; flex-direction: column; gap: 4px; }
.ig-cat-picker .ig-cat-check {
  flex-direction: row; align-items: center; gap: 10px;
  padding: 6px 10px; margin: 0;
  font-size: 0.9375rem; font-weight: 500;
  background: transparent; border: 1px solid transparent;
  border-radius: 8px;
  align-self: flex-start;
}
.ig-cat-picker .ig-cat-check:hover { background: var(--panel-2); }
.ig-cat-picker .ig-cat-check input[type="checkbox"] {
  width: 16px; height: 16px;
  padding: 0; margin: 0; flex: 0 0 auto;
  accent-color: var(--brand);
  background: transparent; border: 0;
}
.ig-cat-picker .ig-cat-check span { line-height: 1.2; }
/* Toggle switch in the categories editor: small top/bottom margin so
   it has breathing room above the editable rows. */
.ig-cat-required-toggle { margin: 4px 0 12px; }

/* Multi-select bulk-action bar above the file list. Sits inline with
   the section so it visually anchors to the rows below; the action
   buttons cluster on the right. Left padding (6px) matches the
   checkbox position on each row beneath it (li padding-left 2px +
   label padding-left 4px = 6px) so the bar's "Select all" checkbox
   sits in the same column as the per-row checkboxes. */
.lib-bulk-bar {
  display: flex; align-items: center; gap: 16px;
  padding: 8px 14px 8px 6px; border-bottom: 1px solid var(--border);
  background: var(--panel-2);
}
.lib-bulk-bar-actions { margin-left: auto; display: inline-flex; gap: 8px; }
/* Hide the action buttons entirely until at least one row is checked
   — they're enabled-disabled by the JS based on the selection count,
   so disabled === "nothing selected yet" === "don't show". */
.lib-bulk-bar-actions > [data-bulk-action][disabled],
.lib-bulk-bar-actions > [data-bulk-delete][disabled] { display: none; }
.lib-bulk-select-all { display: inline-flex; align-items: center; gap: 8px;
  font-size: 0.875rem; font-weight: 500; cursor: pointer; }
.lib-bulk-select-all input[type="checkbox"] {
  width: 16px; height: 16px; accent-color: var(--brand); margin: 0;
}
/* Per-row checkbox slot. Sits to the left of the drag handle / file
   icon so the row reads "select | drag | type | name | actions". */
.file-list .lib-row-select {
  display: inline-flex; align-items: center; padding: 0 4px;
  cursor: pointer;
}
.file-list .lib-row-select input[type="checkbox"] {
  width: 16px; height: 16px; accent-color: var(--brand); margin: 0;
}
/* Category editor inside the library-edit modal: each row is a name
   input + remove button laid side-by-side. */
.ig-cat-rows { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.ig-cat-row { display: flex; gap: 6px; align-items: center; }
.ig-cat-row input[type="text"] { flex: 1; }

/* === Library import wizard ===
   Modal that stages a batch of files before submission. Drop-zone +
   per-file row pattern: each row exposes a title input pre-filled with
   the derived title, the original filename underneath as muted text,
   and a remove button. The footer shows the queued-file count and
   keeps the Import button disabled until at least one file is staged. */
.lib-import-panel { width: min(720px, 96vw); max-height: 88vh; }
.lib-import-panel .modal-body { display: flex; flex-direction: column; gap: 14px; }
.lib-import-hint { margin: 0; }
.lib-import-drop {
  border: 2px dashed var(--border); border-radius: 12px;
  background: var(--panel-2); padding: 22px 18px; text-align: center;
  transition: background-color 120ms ease, border-color 120ms ease;
  cursor: pointer; outline: none;
}
.lib-import-drop:hover,
.lib-import-drop:focus-visible { border-color: var(--brand); background: var(--brand-soft); }
.lib-import-drop.is-dragging { border-color: var(--brand); background: var(--brand-soft); }
.lib-import-drop-inner { display: inline-flex; flex-direction: column; align-items: center; gap: 8px; }
.lib-import-drop-icon { color: var(--brand); display: inline-flex; }
.lib-import-drop-icon .icon { width: 32px; height: 32px; }
.lib-import-pick-btn { position: relative; overflow: hidden; cursor: pointer; }
.lib-import-pick-btn input[type="file"] {
  position: absolute; inset: 0; opacity: 0; cursor: pointer;
  font-size: 100px;
}
.lib-import-list {
  display: flex; flex-direction: column; gap: 6px;
  max-height: 320px; overflow-y: auto;
}
.lib-import-list:empty { display: none; }
.lib-import-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel-2);
}
.lib-import-row .ftype-sm { flex: 0 0 auto; }
.lib-import-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.lib-import-row-main input[type="text"] {
  width: 100%; padding: 6px 9px; border-radius: 6px;
  border: 1px solid var(--border); background: var(--panel);
  color: var(--text); font-size: 0.9375rem; font-weight: 600;
}
.lib-import-row-meta {
  display: flex; gap: 8px; flex-wrap: wrap;
  font-size: 0.75rem; color: var(--muted);
}
.lib-import-row-meta .lib-import-row-name {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 100%;
}
.lib-import-row-remove {
  flex: 0 0 auto; background: transparent; border: 0; color: var(--muted);
  cursor: pointer; padding: 4px; border-radius: 6px; line-height: 0;
}
.lib-import-row-remove:hover { color: var(--danger); background: var(--brand-soft); }
.lib-import-empty[hidden] { display: none; }
.lib-import-panel .modal-foot { gap: 8px; align-items: center; }
.lib-import-count { margin-right: auto; }
.meta-row { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 14px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--text); cursor: pointer;
  font-weight: 600; font-size: 1rem; line-height: 1.25; text-decoration: none;
  box-sizing: border-box; font-family: inherit;
}
.btn:hover { background: var(--brand-soft); text-decoration: none; }
.btn-primary { background: var(--access); color: white; border-color: transparent; }
.btn-primary:hover { background: var(--access-hover); color: white; }
.btn-danger { background: var(--danger); color: white; border-color: transparent; }
.btn-danger:hover { background: #c73a3f; color: white; }
.btn-sm { padding: 5px 10px; font-size: 0.75rem; }

.form { display: flex; flex-direction: column; gap: 2rem; }
.form label { display: flex; flex-direction: column; gap: 6px; font-size: 1rem; font-weight: 600; color: var(--text); }
.form input, .form select, .form textarea {
  padding: 9px 12px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--text); font-size: 1rem; font-family: inherit;
}
.form textarea { resize: vertical; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.form input:focus, .form select:focus, .form textarea:focus {
  outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft);
}
.form .row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.form-actions { display: flex; gap: 10px; justify-content: flex-end; }

.list { list-style: none; padding: 0; margin: 0; }
.list li { border-bottom: 1px solid var(--border); }
.list li:last-child { border-bottom: none; }
.list li a { display: flex; justify-content: space-between; align-items: center; padding: 10px 2px; color: var(--text); font-weight: 500; }
.list li a:hover { color: var(--brand); text-decoration: none; }

.file-list { list-style: none; padding: 0; margin: 0; }
.file-list li { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 10px; padding: 10px 2px; border-bottom: 1px solid var(--border); }
.file-list li > .file-add-form { flex-basis: 100%; width: 100%; margin-top: 4px; }
.lib-desc { margin: -14px 0 32px; }
.inline-save-msg { display: inline-block; margin-top: 6px; padding: 2px 8px; font-size: 0.75rem; }
.ftype { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 8px; font-size: 0.6875rem; font-weight: 700;
  letter-spacing: 0.5px; background: transparent; border: 1.5px solid currentColor; color: #888; }
.ftype-pdf { color: #e74c3c; }
.ftype-doc { color: #4a9eff; }
.ftype-xls { color: #2ecc71; }
.ftype-ppt { color: #f39c12; }
.ftype-img { color: #b07bd8; }
.ftype-vid { color: #ff7a3d; }
.ftype-aud { color: #1abc9c; }
.ftype-link { color: #90a4ae; }
.ftype-zip { color: #a855f7; }
.ftype-pages { color: #f97316; }
.ftype-file { color: #888; }
.ftype-text { color: #6d7ab0; }
.media-search { display: flex; gap: 8px; margin-bottom: 12px; }
.media-search input { flex: 1; padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel); color: var(--text); }
.picker-upload { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.picker-upload > label.btn { font-size: 1rem; }
.view-controls.picker-controls { display: flex; width: 100%;
  align-items: center; gap: 10px; margin: 0 0 10px;
  justify-content: flex-end; }
#add-library-file .file-input-row > .btn { font-size: 1rem; }

/* ===== Web Frontend status widget toggle ===== */
.frontend-status-card .frontend-status-grid {
  display: flex; align-items: center; gap: 24px;
}
.frontend-status-card .frontend-status-grid > div:first-child { flex: 1 1 auto; }
.frontend-status-msg { margin: 0; display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; font-size: 0.9375rem; color: var(--muted); }
.frontend-status-msg .badge { font-size: 0.75rem; }
.frontend-status-toggle { margin: 0; }
.frontend-toggle-switch { gap: 10px; font-size: 0.9375rem; font-weight: 600; }
.frontend-toggle-label { color: var(--text); }
@media (max-width: 640px) {
  .frontend-status-card .frontend-status-grid { flex-direction: column; align-items: flex-start; gap: 14px; }
}
/* ===== File Browser — list + grid views ===== */
/* Thumbnail button: shared between the list view's leading cell and
   the grid view's card. The button is the click target that opens
   the lightbox when the file is previewable. Non-previewable types
   keep the same visual but render the click as a tab-open via the
   filename link in the row instead. */
.media-thumb-btn {
  display: flex; align-items: center; justify-content: center;
  width: 100%; padding: 0; border: 1px solid var(--border);
  border-radius: 10px; background: var(--panel-2); overflow: hidden;
  cursor: default; color: var(--muted);
}
.media-thumb-btn.is-previewable { cursor: zoom-in; }
.media-thumb-btn.is-previewable:hover {
  border-color: var(--brand); box-shadow: 0 2px 8px rgba(11, 92, 255, 0.15);
}
.media-thumb-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.media-thumb-img {
  display: block; width: 100%; height: 100%; object-fit: cover;
}
.media-thumb-fallback {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; width: 100%; height: 100%;
}
.media-thumb-fallback .icon { font-size: 1.75rem; }
.media-thumb-ext { font-size: 0.6875rem; font-weight: 700; letter-spacing: .06em; }

/* List view: a leading thumbnail column on each row. Sized small so
   the table density stays close to the original. */
.media-tbl .media-thumb-col { width: 56px; padding-right: 0; }
.media-tbl .media-thumb-cell { width: 56px; padding: 6px 8px 6px 0; vertical-align: middle; }
.media-thumb-btn-sm { width: 48px; height: 48px; border-radius: 8px; }
.media-thumb-btn-sm .icon { font-size: 1.25rem; }
.media-thumb-btn-sm .media-thumb-ext { font-size: 0.5625rem; }

/* Grid view: cards with a tall thumbnail surface. */
.media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; }
.media-card { display: flex; flex-direction: column; gap: 10px; padding: 10px;
  border: 1px solid var(--border); border-radius: 12px; background: var(--panel-2);
  transition: border-color 140ms ease, box-shadow 140ms ease, transform 140ms ease; }
.media-card:hover { border-color: var(--brand); box-shadow: 0 6px 16px rgba(0,0,0,0.10); }
.media-card .media-thumb-btn { aspect-ratio: 1 / 1; border-radius: 8px; }
.media-card .media-thumb-fallback .icon { font-size: 2.5rem; }
.media-card .media-thumb-fallback .media-thumb-ext { font-size: 0.8125rem; }
.media-card-meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; padding: 0 2px; }
.media-card-name {
  font-weight: 600; font-size: 0.875rem; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.media-card-name:hover { color: var(--access); }
.media-card-sub { display: flex; align-items: center; gap: 8px; min-width: 0; }
.media-card-actions { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 2px; }
.media-card-actions form { display: inline; margin: 0; }
.media-card-actions .btn { flex: 1 1 auto; min-width: 0; }
.media-card-actions .btn-danger { flex: 0 0 auto; }
@media (max-width: 520px) {
  .media-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
  .media-card { padding: 8px; }
}

/* Pagination footer below the list/grid. */
.media-pagination {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-top: 16px; padding-top: 12px;
  border-top: 1px solid var(--border);
}
.media-pagination-info { flex: 0 0 auto; }
.media-pagination-controls { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.media-pagination-controls .btn { padding: 6px 10px; }
.media-pagination-controls .btn-perm-disabled { opacity: 0.45; cursor: not-allowed; }
.media-pagination-page {
  padding: 0 8px; font-size: 0.8125rem; color: var(--muted); white-space: nowrap;
}
@media (max-width: 520px) {
  .media-pagination { justify-content: center; }
  .media-pagination-controls { width: 100%; justify-content: center; }
}

/* Lightbox prev/next nav buttons inside the body. */
.lightbox-body { position: relative; }
.lightbox-stage { flex: 1 1 auto; min-width: 0; min-height: 0;
  display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }
.lightbox-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 44px; height: 44px; border-radius: 50%;
  border: 0; background: rgba(20, 22, 28, 0.55); color: #fff;
  display: grid; place-items: center; cursor: pointer; z-index: 2;
  transition: background-color 140ms ease, transform 140ms ease;
}
.lightbox-nav:hover { background: rgba(20, 22, 28, 0.85); }
.lightbox-nav:active { transform: translateY(-50%) scale(0.95); }
.lightbox-nav .icon { font-size: 1.5rem; }
.lightbox-nav-prev { left: 12px; }
.lightbox-nav-next { right: 12px; }
.lightbox-nav[hidden] { display: none; }
.lightbox-counter { margin: 0 8px; flex: 0 0 auto; white-space: nowrap; }
@media (max-width: 520px) {
  .lightbox-nav { width: 38px; height: 38px; }
  .lightbox-nav-prev { left: 4px; }
  .lightbox-nav-next { right: 4px; }
}
.file-input-row { display: flex; gap: 8px; align-items: center; }
.file-input-row input[type="file"] { flex: 1; min-width: 0; }
.media-picked-label { padding: 4px 8px; background: var(--brand-soft);
  border-radius: 6px; margin: 4px 0; }
#media-picker-frame { width: 100%; height: 70vh; border: 0; }
.sort-dir { min-width: 32px; text-align: center; font-weight: 700; }
.ftype-sm { width: 36px; height: 22px; font-size: 0.625rem; border-radius: 6px; }
.drag-handle { cursor: grab; color: var(--muted); user-select: none; padding: 0 4px;
  display: inline-flex; align-items: center; }
.drag-handle .icon { font-size: 1.1rem; }
.drag-handle:active { cursor: grabbing; }
.file-list-sortable li { transition: background-color 100ms ease; position: relative; }
.file-list-sortable li.dragging { opacity: 0.4; }
.file-list-sortable > tr { transition: background-color 100ms ease; position: relative; }
/* Precise drop-target indicator: 3px brand-coloured line on the exact edge
   where the dragged row will land. Replaces the full-row tint that used
   to flash on dragover — the line is unambiguous about insertion point. */
.file-list-sortable li.drop-before::before,
.file-list-sortable li.drop-after::after,
.file-list-sortable > tr.drop-before::before,
.file-list-sortable > tr.drop-after::after {
  content: ""; position: absolute; left: 0; right: 0;
  height: 3px; background: var(--brand);
  border-radius: 2px;
  box-shadow: 0 0 0 1px var(--panel), 0 2px 6px rgba(11, 92, 255, 0.35);
  pointer-events: none; z-index: 2;
}
.file-list-sortable li.drop-before::before,
.file-list-sortable > tr.drop-before::before { top: -2px; }
.file-list-sortable li.drop-after::after,
.file-list-sortable > tr.drop-after::after { bottom: -2px; }
/* Back-compat: keep the old .drag-over class working for any sortable that
   hasn't migrated yet. Still a soft tint, just less prominent. */
.file-list-sortable li.drag-over,
.file-list-sortable > tr.drag-over { background-color: var(--brand-soft); }
.file-list-sortable > tr.dragging { opacity: 0.4; }
.file-list-sortable > article { transition: background-color 100ms ease, transform 100ms ease; }
.file-list-sortable > article.drag-over { outline: 2px dashed var(--brand); outline-offset: 2px; }
.file-list-sortable > article.dragging { opacity: 0.4; }
.tbl td.drag-handle-cell { width: 28px; padding-right: 0; color: var(--muted); cursor: grab; }
.tbl td.drag-handle-cell:active { cursor: grabbing; }
.tbl tr[draggable="true"] .drag-handle-cell .icon { font-size: 1rem; }
.file-list li:last-child { border-bottom: none; }
.file-main { min-width: 0; flex: 1; }
.file-actions { display: flex; align-items: center; gap: 6px; }
.file-actions form { margin: 0; display: inline-flex; }

.tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.tab { padding: 6px 12px; border: 1px solid var(--border); border-radius: 999px; background: var(--panel); color: var(--text); font-size: 0.7812rem; font-weight: 600; }
.tab:hover { background: var(--brand-soft); color: var(--brand); text-decoration: none; }
.tab .count { background: var(--brand-soft); color: var(--brand); padding: 1px 7px; border-radius: 999px; margin-left: 4px; font-size: 0.6875rem; }

.empty { text-align: center; padding: 40px 20px; color: var(--muted); }

.checks { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 8px; margin-bottom: 12px; }
.check { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel-2); cursor: pointer; }
.check input { accent-color: var(--brand); }

.lib-block { margin-top: 18px; padding-top: 14px; border-top: 1px dashed var(--border); }

.tbl { width: 100%; border-collapse: collapse; }
.tbl th, .tbl td { text-align: left; padding: 12px 8px; border-bottom: 1px solid var(--border); font-size: 1rem; vertical-align: middle; }
.tbl th { color: var(--muted); font-weight: 600; font-size: 0.75rem; text-transform: uppercase; letter-spacing: .5px; }
.tbl input, .tbl select { padding: 6px 8px; font-size: 0.7812rem; }
.nowrap { white-space: nowrap; }

/* Users table actions cell — Edit / Unlock / Delete buttons.
   Flex layout lives on an inner wrapper so the <td> itself stays a
   normal table-cell; making the td a flex container breaks the
   table's row-height contract and causes its bottom border to land
   above the sibling cells'. */
.tbl td.users-actions { vertical-align: middle; }
.tbl td.users-actions .users-actions-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.tbl td.users-actions form { display: inline-flex; margin: 0; }

.reading-body {
  white-space: pre-wrap; font-family: Georgia, "Times New Roman", serif;
  font-size: 1rem; line-height: 1.7; margin: 0; background: transparent; color: var(--text);
}

.auth-wrap { min-height: 100vh; display: grid; place-items: center; padding: 20px; background: linear-gradient(160deg, var(--bg) 40%, var(--brand-soft)); }
.auth-card { width: 100%; max-width: 380px; background: var(--panel); border: 1px solid var(--border); border-radius: 16px; padding: 28px; box-shadow: var(--shadow); display: flex; flex-direction: column; gap: 12px; }
.auth-brand { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 8px; margin-bottom: 8px; }
.auth-brand h1 { font-size: 1.125rem; }
.auth-brand p { color: var(--muted); font-size: 0.8125rem; }
.auth-card label { display: flex; flex-direction: column; gap: 6px; font-size: 0.8125rem; font-weight: 600; }
.auth-card input { padding: 10px 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--panel-2); color: var(--text); font-size: 0.875rem; }
.auth-card input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }

/* Forgot / reset password screens — full-page centered card with the
   same auth-card visual language as the seeded admin / setup card. */
.auth-card-reset { max-width: 440px; gap: 14px; }
.auth-card-reset .auth-brand h1 { font-size: 1.25rem; line-height: 1.3; }
.auth-card-reset .auth-brand p { font-size: 0.875rem; line-height: 1.5; max-width: 36ch; }
.auth-form { display: flex; flex-direction: column; gap: 12px; }
.auth-form button[type="submit"] { margin-top: 4px; }
.auth-back-link { display: inline-block; margin-top: 6px; text-align: center;
  color: var(--muted); font-size: 0.8125rem; text-decoration: none; }
.auth-back-link:hover { color: var(--brand); text-decoration: underline; }
.auth-actions { display: flex; flex-direction: column; gap: 10px; align-items: center; }
.auth-actions .btn { width: 100%; }
.auth-success { display: flex; flex-direction: column; align-items: center;
  gap: 10px; text-align: center; padding: 8px 0 4px; }
.auth-success-icon { width: 56px; height: 56px; border-radius: 999px;
  background: var(--brand-soft); color: var(--brand);
  display: grid; place-items: center; }
.auth-success-icon .icon { width: 28px; height: 28px; }
.auth-success h2 { font-size: 1.0625rem; font-weight: 700; }
.auth-success p { color: var(--muted); font-size: 0.875rem; line-height: 1.5; max-width: 36ch; }
.auth-invalid { color: var(--muted); font-size: 0.875rem; line-height: 1.55;
  background: var(--panel-2); border: 1px solid var(--border);
  padding: 12px 14px; border-radius: 10px; }

/* Login form: remember-me + forgot-link share a row so the link sits
   at the bottom-right of the form without claiming its own row. */
.login-remember-row { display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px; }
.login-forgot { font-size: 0.8125rem; color: var(--muted); text-decoration: none; }
.login-forgot:hover { color: var(--brand); text-decoration: underline; }

/* ================================================================
   Reset-password modal (admin) + shared password-strength meter +
   policy checklist (also used by the public reset form).
   ================================================================ */
.pwreset-modal .modal-panel { max-width: 520px; }
.pwreset-target { background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 10px; padding: 10px 12px; line-height: 1.5; }
/* Replaces the previous .pwreset-tabs two-tab control: a single
   toggle that flips between Generate (off, default) and Custom
   (on). When off, only the readonly Generated-password readout is
   shown; when on, the readout hides and the New Password field
   reveals with its strength meter. */
.pwreset-mode-toggle { align-self: flex-start; margin: 4px 0; }
.pwreset-mode-label { font-size: 0.875rem; font-weight: 600; }
.pwreset-pane { display: flex; flex-direction: column; gap: 10px; }
/* The author-level ``display: flex`` above outranks the UA stylesheet's
   ``[hidden] { display: none }``, so the New Password pane would stay
   visible even with the ``hidden`` attribute set. Pin it back here so
   the Set-custom-password toggle's off state genuinely hides the pane. */
.pwreset-pane[hidden] { display: none; }
.pwreset-readout-label, .pwreset-custom-label { font-size: 0.8125rem;
  font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; }
.pwreset-readout { display: flex; gap: 8px; align-items: center; }
.pwreset-readout input { flex: 1; padding: 10px 12px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel-2); color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9375rem; letter-spacing: .5px; }
.pwreset-hint { line-height: 1.45; }
.pwreset-custom-input { display: flex; gap: 8px; align-items: stretch; margin-top: 6px; }
.pwreset-custom-input input { flex: 1; padding: 10px 12px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel-2); color: var(--text);
  font-size: 0.9375rem; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.pwreset-custom-input input:focus { outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft); }

.pwreset-strength { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.pwreset-strength-bar { height: 6px; border-radius: 999px; background: var(--panel-2);
  border: 1px solid var(--border); overflow: hidden; }
.pwreset-strength-bar > span { display: block; height: 100%; width: 0;
  background: #ef4444; border-radius: inherit;
  transition: width 180ms ease, background 180ms ease; }
.pwreset-strength-bar > span[data-tier="weak"]   { background: #ef4444; }
.pwreset-strength-bar > span[data-tier="fair"]   { background: #f59e0b; }
.pwreset-strength-bar > span[data-tier="good"]   { background: #10b981; }
.pwreset-strength-bar > span[data-tier="strong"] { background: #059669; }
.pwreset-strength-label { font-size: 0.8125rem; color: var(--muted); }

.pwreset-policy { list-style: none; padding: 0; margin: 4px 0 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px 16px; font-size: 0.8125rem;
  color: var(--muted); }
.pwreset-policy li { position: relative; padding-left: 22px; line-height: 1.5; }
.pwreset-policy li::before { content: ""; position: absolute; left: 0; top: 6px;
  width: 14px; height: 14px; border-radius: 999px;
  border: 1.5px solid currentColor; opacity: .55;
  transition: background 120ms ease, border-color 120ms ease, opacity 120ms ease; }
.pwreset-policy li.is-met { color: #059669; }
.pwreset-policy li.is-met::before { background: #059669; border-color: #059669; opacity: 1; }
.pwreset-policy li.is-met::after { content: ""; position: absolute; left: 4px; top: 8px;
  width: 6px; height: 3px; border-left: 1.5px solid #fff; border-bottom: 1.5px solid #fff;
  transform: rotate(-45deg); }

@media (max-width: 540px) {
  .pwreset-policy { grid-template-columns: 1fr; }
  .pwreset-readout { flex-wrap: wrap; }
  .pwreset-readout input { min-width: 0; flex: 1 1 100%; }
}

/* Public reset page reuses the strength meter + policy checklist —
   tighten spacing to fit the narrower auth card. */
.pwreset-public-form .pwreset-policy { grid-template-columns: 1fr; }
.pwreset-public-form .pwreset-strength { margin-top: 0; }

/* ================================================================
   User Log page — admin-only timeline of write actions, with a
   companion login-sessions table on top. The picker card lives at
   the top so the selected account is always visible while you scroll.
   ================================================================ */
.user-log-picker-form { display: flex; gap: 14px; flex-wrap: wrap; }

/* Account picker card — Account dropdown on the left, summary chip on
   the right. The two carry-forward hidden inputs (days, sdays) keep
   the Activity + Sessions windows intact when the operator changes
   account. */
.user-log-account { display: flex; align-items: center; gap: 18px;
  flex-wrap: wrap; }
.user-log-account .user-log-picker-form { flex: 1 1 240px; }
.user-log-account .user-log-summary { flex: 0 0 auto; padding-top: 0;
  border-top: none; }
.user-log-picker-label { display: flex; flex-direction: column; gap: 4px;
  font-size: 0.75rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .5px; flex: 1 1 220px; }
.user-log-picker-label > span { padding: 0 2px; }
.user-log-picker-label select { padding: 9px 12px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel-2); color: var(--text);
  font-size: 0.9375rem; font-weight: 500; text-transform: none; letter-spacing: 0; }
.user-log-summary { display: flex; align-items: center; gap: 14px; }
.ulog-chip { display: flex; align-items: center; gap: 12px; }
.ulog-chip-name { font-size: 1.0625rem; font-weight: 700; }
.user-log-summary .avatar { width: 44px; height: 44px; font-size: 1.125rem; }

/* Activity + Login sessions cards — each gets its own card with a
   collapse toggle. The whole header is the click target on expanded
   cards; the whole card is the click target when collapsed (handled
   in JS). Cursor signals match: pointer on the head when expanded,
   pointer on the entire card when collapsed. */
.user-log-card { padding: 0; }
.user-log-card-head { display: flex; align-items: center; gap: 12px;
  flex-wrap: wrap; padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  cursor: pointer; user-select: none; }
.user-log-card.is-collapsed { cursor: pointer; }
.user-log-card.is-collapsed .user-log-card-head {
  border-bottom-color: transparent; }
/* Subtle hover affordance — matches the cursor:pointer signal. */
.user-log-card-head:hover h2 { color: var(--brand); }
.user-log-card.is-collapsed:hover .user-log-chevron { color: var(--brand); }
.user-log-card-head:focus-visible { outline: 2px solid var(--brand);
  outline-offset: -2px; border-radius: 8px; }
.user-log-card-body { padding: 16px 18px 18px; }
.user-log-card-head h2 { margin: 0; font-size: 1.0625rem; font-weight: 700;
  transition: color 150ms ease; }
.user-log-chevron { display: inline-flex; align-items: center;
  color: var(--muted); transition: transform 200ms ease, color 150ms ease; }
.user-log-chevron .icon { width: 18px; height: 18px; }
.user-log-card.is-collapsed .user-log-chevron { transform: rotate(-90deg); }
.user-log-card-count { margin-right: auto; }
/* When collapsed, hide the in-header window dropdown — changing the
   window only matters when the body is visible, and the form would
   otherwise be the only "click here doesn't toggle" exception inside
   the card-wide click target. */
.user-log-card.is-collapsed .user-log-card-form { display: none; }
.user-log-card-form { display: inline-flex; align-items: center; gap: 8px;
  margin: 0; }
.user-log-window-label { display: inline-flex; }
.user-log-window-label select { padding: 6px 28px 6px 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel-2); color: var(--text);
  font-size: 0.875rem; font-weight: 500;
  appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat; background-position: right 8px center;
  background-size: 14px 14px; }
.visually-hidden { position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0; }

/* Sessions table can grow up to 7 columns. Wrap it in a horizontal
   scroll container so it keeps its full layout on narrow viewports
   instead of being squished. */
.ulog-sessions-scroll { overflow-x: auto; }
.ulog-sessions-scroll .tbl { width: 100%; }

/* Infinite-scroll sentinel — sits at the end of the feed and
   IntersectionObserver fires when it scrolls into view. */
.ulog-feed-sentinel { padding: 14px 0 4px; text-align: center; }
.ulog-feed-sentinel[hidden] { display: none; }

/* Activity-feed truncation. Hides every row past the 20th until the
   "Show N more" button drops the class, revealing the rest of the
   already-loaded page (and the sentinel beneath it, which then drives
   the infinite-scroll API). */
.ulog-feed--truncated > li:nth-child(n+21) { display: none; }
.ulog-expand-btn {
  margin: 10px 0 0;
  display: inline-flex; align-items: center; gap: 6px;
}
.ulog-expand-btn .muted { color: var(--muted, #64748b); }

.badge-success { background: #d1fae5; color: #065f46; border-color: #10b981; }
[data-theme="dark"] .badge-success,
[data-theme="neobrutal-dark"] .badge-success,
[data-theme="cyberpunk"] .badge-success { background: #064e3b; color: #d1fae5; border-color: #059669; }

.ulog-sessions-tbl { font-size: 0.875rem; }
.ulog-sessions-tbl th { white-space: nowrap; }
.ulog-sessions-tbl .ulog-ua { max-width: 320px; overflow: hidden; text-overflow: ellipsis; }
.ulog-session-active td { background: color-mix(in srgb, #10b981 8%, transparent); }

/* Activity feed — vertical timeline with rail + circular icon nodes.
   Icons are tinted by event family (auth / users / meeting / etc.)
   via the parent ``.ulog-event-<family>`` class derived from the
   first segment of the action verb. Unknown families fall through
   to a neutral muted tint. */
.ulog-feed { list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 0; }
.ulog-event { position: relative; display: grid;
  grid-template-columns: 36px 1fr; gap: 12px;
  padding: 14px 0; border-bottom: 1px dashed var(--border); }
.ulog-event:last-child { border-bottom: none; }
.ulog-event-icon { width: 36px; height: 36px; border-radius: 999px;
  display: grid; place-items: center; flex: 0 0 auto;
  background: var(--panel-2); color: var(--muted);
  border: 1px solid var(--border); }
.ulog-event-icon .icon { width: 18px; height: 18px; }
.ulog-event-title { font-size: 0.9375rem; font-weight: 600; }
.ulog-event-summary { line-height: 1.5; margin-top: 2px; }
.ulog-event-meta { margin-top: 4px; }
.ulog-event-meta .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.ulog-event-login .ulog-event-icon { background: color-mix(in srgb, #10b981 12%, var(--panel-2)); color: #065f46; border-color: #10b981; }
.ulog-event-logout .ulog-event-icon { background: var(--panel-2); }
.ulog-event-password .ulog-event-icon { background: color-mix(in srgb, #f59e0b 12%, var(--panel-2)); color: #78350f; border-color: #f59e0b; }
.ulog-event-user .ulog-event-icon { background: color-mix(in srgb, #6366f1 12%, var(--panel-2)); color: #3730a3; border-color: #6366f1; }
.ulog-event-meeting .ulog-event-icon,
.ulog-event-library .ulog-event-icon,
.ulog-event-reading .ulog-event-icon,
.ulog-event-post .ulog-event-icon,
.ulog-event-file .ulog-event-icon { background: color-mix(in srgb, var(--brand) 12%, var(--panel-2)); color: var(--brand); border-color: var(--brand); }
[data-theme="dark"] .ulog-event-login .ulog-event-icon,
[data-theme="neobrutal-dark"] .ulog-event-login .ulog-event-icon,
[data-theme="cyberpunk"] .ulog-event-login .ulog-event-icon { color: #d1fae5; }
[data-theme="dark"] .ulog-event-password .ulog-event-icon,
[data-theme="neobrutal-dark"] .ulog-event-password .ulog-event-icon,
[data-theme="cyberpunk"] .ulog-event-password .ulog-event-icon { color: #fef3c7; }
[data-theme="dark"] .ulog-event-user .ulog-event-icon,
[data-theme="neobrutal-dark"] .ulog-event-user .ulog-event-icon,
[data-theme="cyberpunk"] .ulog-event-user .ulog-event-icon { color: #c7d2fe; }

/* "Currently online" live widget — header carries a green pulse dot
   so the live aspect is obvious; rows briefly highlight when their
   destination changes between polls. */
.user-log-online .card-head h2 { display: inline-flex; align-items: center; gap: 8px; }
.online-pulse { width: 9px; height: 9px; border-radius: 999px;
  background: #10b981; box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.55);
  animation: online-pulse 2s ease-out infinite; }
@keyframes online-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.55); }
  70%  { box-shadow: 0 0 0 10px rgba(16, 185, 129, 0); }
  100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}
.online-list { display: flex; flex-direction: column; gap: 6px;
  /* Container query context — the row layout reflows based on the
     widget's own width, not the viewport. The "Currently online"
     widget appears both full-width on the User Log page and inside
     a narrower column on the dashboard, so a viewport media query
     would either be too coarse (wide viewport, narrow column) or
     never fire (everything below 720 looks the same regardless of
     widget context). */
  container-type: inline-size; container-name: online-list; }
.online-empty { margin: 0; padding: 8px 0; }
.online-row { display: grid; gap: 12px; align-items: center;
  /* `minmax(0, ...)` instead of `minmax(140px, ...)` lets every
     track shrink past its content width, so children with
     `text-overflow: ellipsis` actually clip instead of forcing the
     row wider than its card. */
  grid-template-columns: 36px minmax(0, 1fr) minmax(0, 1.5fr) auto;
  padding: 10px 12px; border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
  /* Defensive clip: even if a child somehow overflows, it can't push
     past the card's right edge. */
  overflow: hidden;
  transition: background 220ms ease, border-color 220ms ease; }
.online-row > * { min-width: 0; }
.online-row.is-self { border-color: var(--brand); }
.online-row.just-moved { animation: online-flash 1400ms ease-out; }
@keyframes online-flash {
  0%   { background: color-mix(in srgb, #10b981 22%, transparent); }
  100% { background: var(--panel-2); }
}
.online-avatar { width: 36px; height: 36px; border-radius: 999px;
  background: var(--brand); color: #fff; font-weight: 700; font-size: 0.9375rem;
  display: grid; place-items: center; flex: 0 0 auto; }
.online-name { font-weight: 700; font-size: 0.9375rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.online-where { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.online-where-link { color: var(--brand); text-decoration: none; font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.online-where-link:hover { text-decoration: underline; }
.online-path { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.online-seen { white-space: nowrap; text-align: right; flex-shrink: 0; }

/* Mid-width: drop the dedicated location column; tuck the seen stamp
   next to the username and let location wrap to its own row. Keeps
   the time visible at-a-glance without forcing a third column. */
@container online-list (max-width: 540px) {
  .online-row {
    grid-template-columns: 36px minmax(0, 1fr) auto;
    grid-template-areas: "avatar meta seen" "avatar where where";
    row-gap: 2px; column-gap: 10px; }
  .online-avatar { grid-area: avatar; align-self: start; margin-top: 2px; }
  .online-meta   { grid-area: meta; }
  .online-where  { grid-area: where; }
  .online-seen   { grid-area: seen; }
}

/* Narrow: stack everything into a single column. */
@container online-list (max-width: 340px) {
  .online-row {
    grid-template-columns: 36px minmax(0, 1fr);
    grid-template-areas: "avatar meta" "avatar seen" "where where";
    row-gap: 4px; }
  .online-seen { text-align: left; }
}

/* Per-user "Self-reset allowed?" toggle in the Users table.
   Sits below the Reset password button; the mode-track/mode-thumb
   classes piggyback on the existing settings-modal switch styling
   so we don't reinvent the look. */
/* Per-user "Self-reset allowed?" toggle — piggybacks on the standard
   .mode-toggle / .mode-track / .mode-thumb CSS (so the visual flip
   on :checked is inherited) and adds a tiny bit of layout polish:
   sits below the Reset password button with a muted label and the
   12 px font size used elsewhere on the row. The .mode-toggle base
   handles input hiding via width:0/height:0 (NOT pointer-events:none,
   which would break the click that toggles the checkbox via the
   surrounding label). */
.users-reset-allow-toggle { margin-top: 8px; font-size: 0.75rem; color: var(--muted); }
.users-reset-allow-label { white-space: nowrap; }

/* Recent Deletions dashboard widget — a touch tighter than Recent
   Files since each row carries a parent-label sub-line. */
.dash-deletions-list li a { display: flex; flex-direction: column;
  align-items: flex-start; gap: 2px; }
.dash-deletion-name { font-weight: 500; }
.dash-deletion-meta { font-size: 0.75rem; }
.dash-deletions-foot { padding: 8px 0 4px; border-top: 1px dashed var(--border);
  margin-top: 6px; }

/* ================================================================
   Backend-wide search modal — floating popup with live results.
   Pinned toward the top of the viewport so the input is always
   thumb-reachable on mobile while the result list scrolls below.
   ================================================================ */
.search-modal .modal-panel {
  max-width: 640px;
  margin: 7vh auto 0;
  max-height: 80vh;
  overflow: hidden;
  padding: 0;
}
.search-modal-head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}
.search-modal-icon { color: var(--muted); display: inline-flex; }
.search-modal-icon .icon { width: 20px; height: 20px; }
.search-modal-head input {
  flex: 1; min-width: 0;
  padding: 10px 0; border: none; outline: none;
  background: transparent; color: var(--text);
  font-size: 1.0625rem; font-weight: 500;
}
.search-modal-head input::placeholder { color: var(--muted); }
.search-modal-esc {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.6875rem; color: var(--muted);
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 6px; padding: 2px 6px; flex: 0 0 auto;
}
.search-modal-body {
  padding: 8px 8px 14px;
  overflow-y: auto; max-height: calc(80vh - 64px);
}
.search-modal-hint, .search-modal-empty {
  margin: 24px 14px; text-align: center; line-height: 1.5;
}
.search-section + .search-section { margin-top: 6px; }
.search-section-head {
  font-size: 0.6875rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
  padding: 12px 14px 6px;
}
.search-results { list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 2px; }
.search-result {
  display: flex; flex-direction: column; gap: 2px;
  padding: 10px 14px; border-radius: 10px;
  text-decoration: none; color: var(--text);
  outline: none;
  transition: background 120ms ease;
}
.search-result:hover,
.search-result:focus { background: var(--panel-2); }
.search-result:focus { box-shadow: 0 0 0 2px var(--brand-soft); }
.search-result-label { font-weight: 600; font-size: 0.9375rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.search-result-snippet { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.search-modal-body mark {
  background: color-mix(in srgb, var(--brand) 25%, transparent);
  color: inherit; padding: 0 1px; border-radius: 3px;
}

/* Web Frontend quick-jump cluster — two pinned buttons above the
   search bar (admin / view-site) so admins can hop into the public
   frontend without scrolling to the Admin nav section. Visibility is
   gated server-side; this CSS just lays them out. */
.sidebar-quicknav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin: 10px 12px 6px;
}
.sidebar-quicknav-btn {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel-2); color: var(--muted);
  text-decoration: none;
  font-size: 0.82rem; font-weight: 500;
  transition: background 120ms ease, border-color 120ms ease,
              color 120ms ease;
  min-width: 0;
}
.sidebar-quicknav-btn:hover {
  background: var(--panel); color: var(--text);
  border-color: color-mix(in srgb, var(--brand) 35%, var(--border));
}
.sidebar-quicknav-btn.is-active {
  background: color-mix(in srgb, var(--brand) 12%, var(--panel-2));
  border-color: color-mix(in srgb, var(--brand) 50%, var(--border));
  color: var(--text);
}
.sidebar-quicknav-icon { display: inline-flex; flex: 0 0 auto; }
.sidebar-quicknav-icon .icon { width: 14px; height: 14px; display: block; }
.sidebar-quicknav-label {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Live-status dot on the admin button. Green when the frontend is
   publicly enabled, neutral grey when it's in editor-only preview
   mode. Pulsing ring on the live state subtly draws the eye without
   becoming distracting. */
.sidebar-quicknav-status {
  flex: 0 0 auto;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--text) 28%, transparent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--text) 10%, transparent);
}
.sidebar-quicknav-status.is-live {
  background: #16a34a;
  box-shadow: 0 0 0 2px color-mix(in srgb, #16a34a 35%, transparent);
  animation: sidebar-quicknav-pulse 2.4s ease-in-out infinite;
}
@keyframes sidebar-quicknav-pulse {
  0%, 100% { box-shadow: 0 0 0 2px color-mix(in srgb, #16a34a 35%, transparent); }
  50%      { box-shadow: 0 0 0 4px color-mix(in srgb, #16a34a 18%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar-quicknav-status.is-live { animation: none; }
}

/* Sidebar Search button — sits between the brand block and the nav.
   Wide pill that visually lives in the same space as the nav links;
   the kbd hint slides off on narrow viewports where the sidebar is
   tighter. */
.sidebar-search-btn {
  display: flex; align-items: center; gap: 10px;
  margin: 8px 12px 12px; padding: 9px 12px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel-2); color: var(--muted);
  cursor: pointer; font-size: 0.875rem; font-weight: 500;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.sidebar-search-btn:hover {
  background: var(--panel); color: var(--text);
  border-color: color-mix(in srgb, var(--brand) 35%, var(--border));
}
.sidebar-search-icon .icon { width: 16px; height: 16px; display: block; }
.sidebar-search-label { flex: 1; text-align: left; }
.sidebar-search-kbd {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.6875rem; color: var(--muted);
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 6px; padding: 1px 6px; flex: 0 0 auto;
}
@media (max-width: 880px) {
  .sidebar-search-kbd { display: none; }
  .search-modal .modal-panel { margin: 4vh 12px 0; }
}

/* Permission-locked button: editor-tier user has the broad gate but
   fails the per-row check. Renders dim + greyed; cursor flips to
   not-allowed on hover so the disabled state is obvious; the native
   ``title`` attribute still surfaces the explanation tooltip. Used
   on Library detail row actions and the File Browser actions; viewers
   continue to see no button at all (kept hidden upstream). */
.btn-perm-disabled,
.btn-perm-disabled:hover,
.btn-perm-disabled:focus,
.btn-perm-disabled:active {
  opacity: 0.42;
  cursor: not-allowed;
  filter: grayscale(60%);
  box-shadow: none;
  transform: none;
  /* Native ``disabled`` already blocks click handlers, but some
     browsers also kill pointer-events which would suppress the
     tooltip. Force pointer-events back on so hover shows the
     not-allowed cursor + the title attribute renders. */
  pointer-events: auto;
}
.btn-perm-disabled:hover { opacity: 0.42; }

/* Delete Log (recycle bin) */
.dlog-list { list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 12px; }
.dlog-item { padding: 14px 16px; border: 1px solid var(--border);
  border-radius: 12px; background: var(--panel-2); }
.dlog-item-head { display: grid; gap: 14px; align-items: center;
  grid-template-columns: 36px 1fr auto; }
.dlog-icon { width: 36px; height: 36px; border-radius: 999px;
  background: color-mix(in srgb, #ef4444 12%, var(--panel)); color: #b91c1c;
  border: 1px solid color-mix(in srgb, #ef4444 35%, var(--border));
  display: grid; place-items: center; }
.dlog-icon .icon { width: 18px; height: 18px; }
[data-theme="dark"] .dlog-icon,
[data-theme="neobrutal-dark"] .dlog-icon,
[data-theme="cyberpunk"] .dlog-icon { color: #fecaca; }
.dlog-item-main { min-width: 0; }
.dlog-filename { font-weight: 700; font-size: 0.9375rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dlog-meta { margin-top: 2px; }
.dlog-days-left { color: var(--muted); }
.dlog-days-out  { color: #b91c1c; }
.dlog-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Nested tree showing where the file lived. Indent each level
   slightly with a thin connector line so it reads as a hierarchy
   rather than a flat list. */
.dlog-tree { list-style: none; padding: 0; margin: 10px 0 0 8px;
  display: flex; flex-direction: column; gap: 2px;
  font-size: 0.8125rem; }
.dlog-tree-node { position: relative; padding: 4px 0 4px 22px; }
.dlog-tree-node::before { content: ""; position: absolute; left: 6px;
  top: 0; bottom: 0; width: 1px;
  background: color-mix(in srgb, var(--border) 80%, transparent); }
.dlog-tree-node:last-child::before { bottom: 50%; }
.dlog-tree-node::after { content: ""; position: absolute; left: 6px;
  top: 14px; width: 12px; height: 1px;
  background: color-mix(in srgb, var(--border) 80%, transparent); }
.dlog-tree-kind { display: inline-block; min-width: 88px; padding: 1px 8px;
  margin-right: 8px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--border);
  font-size: 0.6875rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted); }
.dlog-tree-label { color: var(--text); font-weight: 500; }
a.dlog-tree-label { color: var(--brand); text-decoration: none; }
a.dlog-tree-label:hover { text-decoration: underline; }
@media (max-width: 640px) {
  .dlog-item-head { grid-template-columns: 36px 1fr; }
  .dlog-actions { grid-column: 1 / -1; }
}

/* Recent password resets table on Access Requests */
.ar-recent-resets-tbl { font-size: 0.875rem; }
.ar-recent-resets-tbl .ar-reset-status-pending  { color: #92400e; }
.ar-recent-resets-tbl .ar-reset-status-used     { color: #065f46; }
.ar-recent-resets-tbl .ar-reset-status-expired  { color: var(--muted); }

/* Split login screen */
.login-split { position: relative; min-height: 100vh; display: grid; grid-template-columns: 1fr 1fr;
  background: var(--bg); perspective: 1400px; perspective-origin: 50% 50%; overflow: hidden; }
.login-split .login-hero,
.login-split .login-form-pane { position: relative; z-index: 2; will-change: transform;
  transition: transform 1500ms cubic-bezier(0.7, 0, 0.3, 1); }
.login-split .login-hero { transform-origin: left center; backface-visibility: hidden; }
.login-split .login-form-pane { transform-origin: right center; backface-visibility: hidden; }
.login-split.logging-in .login-hero { transform: rotateY(-105deg) translateX(-12%); }
.login-split.logging-in .login-form-pane { transform: rotateY(105deg) translateX(12%); }

.login-warp { position: absolute; inset: 0; pointer-events: none; opacity: 0;
  transition: opacity 260ms ease-in; z-index: 0; background: #000; }
.login-split.logging-in .login-warp { opacity: 1; }
.login-warp-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.login-warp-white { position: absolute; inset: 0; background: var(--bg); opacity: 0;
  transition: opacity 400ms ease-in; z-index: 3; }
.login-split.fading-white .login-warp-white { opacity: 1; }

html.login-fade-in body { animation: login-page-fade-in 650ms ease-out both; }
@keyframes login-page-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.login-warp-logo-wrap { position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; z-index: 2; pointer-events: none; }
.login-warp-logo { width: 15vw; max-width: 320px; min-width: 140px; height: auto; display: block;
  filter: brightness(0) invert(1); opacity: 0; transform: scale(0.92);
  transition: opacity 600ms ease-out 200ms, transform 900ms ease-out 200ms; }
.login-split.logging-in .login-warp-logo { opacity: 1; transform: scale(1); }
.login-hero { position: relative; background: linear-gradient(135deg, #0a3eb5 0%, #1153e7 55%, #2e6bff 100%);
  color: #fff; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 48px 32px; overflow: hidden; }
.login-hero-bg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; }
.login-hero-inner { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
.login-hero-logo { width: 100px; max-width: 60vw; height: auto; display: block; }
.login-hero-title { color: #fff; font-weight: 700; font-size: 1.125rem; margin-bottom: 8px; }
.login-request-btn { background: #fff; color: #0b1220; border: 0; border-radius: 999px;
  padding: 10px 22px; font-size: 0.9375rem; font-weight: 600; cursor: pointer;
  box-shadow: 0 4px 14px rgba(0,0,0,0.18); transition: transform 120ms ease, background 120ms ease; }
.login-request-btn:hover { background: #f1f5ff; transform: translateY(-1px); }
.login-hero-footer { position: absolute; bottom: 32px; left: 0; right: 0; display: flex; justify-content: center; z-index: 1; }
.login-hero-brand { width: 100px; height: auto; display: block; }
.login-hero-brand-white { filter: brightness(0) invert(1); }

.login-form-pane { position: relative; display: flex; align-items: center; justify-content: center; padding: 48px 32px; background: var(--panel); }
.login-form { width: 100%; max-width: 300px; display: flex; flex-direction: column; gap: 18px; }
.login-form .flashes:empty { display: none; }
.login-form label { display: flex; flex-direction: column; gap: 6px; font-size: 1rem; color: var(--text); font-weight: 500; }
.login-form label > span { font-weight: 500; }
.login-form .req { color: var(--danger, #e11d48); }
.login-form input[type="text"],
.login-form input[type="password"] { padding: 10px 12px; border-radius: 6px; border: 1px solid var(--border); background: var(--panel); color: var(--text); font-size: 1.2rem; }
.login-form input:focus { outline: none; border-color: var(--access); box-shadow: 0 0 0 3px var(--brand-soft); }
.login-form label.check.login-remember { display: flex; flex-direction: row; align-items: center;
  justify-content: flex-start; gap: 8px; font-size: 0.9375rem; font-weight: 400; color: var(--muted);
  background: transparent; padding: 0; border: 0; cursor: pointer; align-self: flex-start; }
.login-form label.check.login-remember input { margin: 0; width: auto; accent-color: var(--access); }
.login-submit { position: relative; background: var(--access); color: #fff; border: 0; border-radius: 999px;
  padding: 10px 22px; font-size: 1rem; font-weight: 600; cursor: pointer; box-shadow: none; }
.login-submit.is-loading { color: transparent; pointer-events: none; }
.login-submit.is-loading::after {
  content: ""; position: absolute; top: 50%; left: 50%; width: 18px; height: 18px;
  margin: -9px 0 0 -9px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.35); border-top-color: #fff;
  animation: login-spin 0.7s linear infinite;
}
@keyframes login-spin { to { transform: rotate(360deg); } }
.login-submit:hover { background: var(--access-hover); }
.login-form input:-webkit-autofill,
.login-form input:-webkit-autofill:focus { -webkit-text-fill-color: var(--text); box-shadow: 0 0 0 1000px var(--panel) inset; caret-color: var(--text); }
.login-form-footer { position: absolute; bottom: 24px; left: 0; right: 0; display: flex; flex-direction: column;
  align-items: center; gap: 6px; }
.login-form-brand { display: block; width: 32px; height: 32px; background-color: var(--muted);
  -webkit-mask: url("../img/viibeware.svg") center/contain no-repeat;
          mask: url("../img/viibeware.svg") center/contain no-repeat; }
.login-version { font-size: 0.8125rem; color: var(--muted); }
@media (max-width: 800px) {
  .login-split { grid-template-columns: 1fr; }
  .login-hero { min-height: 280px; padding: 48px 24px 80px; }
  .login-hero-footer { bottom: 16px; }
  .login-form-pane { flex-direction: column; justify-content: flex-start; padding-bottom: 96px; }
  .login-form-footer { position: absolute; bottom: 24px; left: 0; right: 0;
    flex-direction: column; align-items: center; margin-top: 0; }
}

/* Request-access modal */
.modal-panel.request-access-panel { max-width: 400px; width: calc(100% - 32px); margin: 5vh auto; position: relative;
  background: var(--panel); border-radius: 18px; padding: 32px 36px 36px; box-shadow: 0 20px 50px rgba(0,0,0,0.25);
  max-height: 90vh; display: flex; flex-direction: column; overflow: hidden; }
.request-access-close { position: absolute; top: 14px; right: 14px; width: 32px; height: 32px;
  color: var(--access); font-size: 1.5rem; background: transparent; border: 0; border-radius: 0;
  display: grid; place-items: center; cursor: pointer; }
.request-access-close:hover { background: transparent; color: var(--access-hover); }
.request-access-title { text-align: center; font-size: 1.5rem; font-weight: 700; color: var(--text);
  margin: 4px 0 24px; line-height: 1.25; }
.request-access-form { display: flex; flex-direction: column; gap: 18px;
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  scrollbar-width: none; -ms-overflow-style: none; }
.request-access-form::-webkit-scrollbar { display: none; }
.request-access-form label { display: flex; flex-direction: column; gap: 6px; font-size: 0.9375rem; color: var(--text); font-weight: 500; }
.request-access-form .req { color: var(--danger, #e11d48); }
.request-access-form input[type="text"],
.request-access-form input[type="tel"],
.request-access-form input[type="email"] { padding: 12px 14px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel); color: var(--text); font-size: 0.9375rem; }
.request-access-form input:focus { outline: none; border-color: var(--access); box-shadow: 0 0 0 3px var(--brand-soft); }
.request-access-roles { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
.request-access-roles legend { font-size: 0.9375rem; font-weight: 500; color: var(--text); padding: 0; margin-bottom: 8px; }
.request-access-roles .check { display: flex; flex-direction: row; align-items: center; gap: 10px;
  font-weight: 400; color: var(--text); font-size: 0.9375rem; }
.request-access-roles .check input { width: 18px; height: 18px; accent-color: var(--access); }
.request-access-meeting .center-label { text-align: center; display: block; color: var(--text); font-weight: 400; font-size: 0.9375rem; }
.request-access-actions { margin-top: 4px; }
.request-access-submit { background: var(--access); color: #fff; border: 0; border-radius: 999px; padding: 12px 28px;
  font-size: 1rem; font-weight: 600; cursor: pointer; }
.request-access-submit:hover { background: var(--access-hover); }

.btn-copy { font-size: 0.75rem; padding: 3px 8px; }

.badge { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 0.75rem;
  font-weight: 600; letter-spacing: 0.02em; line-height: 1.4; text-transform: none;
  background: var(--panel-2); color: var(--muted); border: 1px solid var(--border); }
.badge-warning { background: #fef3c7; color: #78350f; border-color: #f59e0b; }
.badge-muted { background: var(--panel-2); color: var(--muted); border-color: var(--border); }
[data-theme="dark"] .badge-warning,
[data-theme="neobrutal-dark"] .badge-warning,
[data-theme="cyberpunk"] .badge-warning { background: #78350f; color: #fef3c7; border-color: #d97706; }
.user-locked-badge { margin-left: 8px; }

.access-requests-card { display: grid; grid-template-columns: 1fr 1fr; gap: 0;
  align-items: stretch; }
.access-requests-card > .access-requests-block,
.access-requests-card > .locked-accounts-block { min-width: 0; }
.access-requests-card > .access-requests-block { padding-right: 18px; }
.access-requests-card > .locked-accounts-block { padding-left: 18px;
  border-left: 1px solid var(--border); }
.access-requests-card .ar-title,
.access-requests-card .locked-accounts-title {
  font-size: 1rem; font-weight: 700; margin: 0 0 12px; color: var(--text);
  display: flex; align-items: center; gap: 6px; line-height: 1.3; }
.access-requests-block .list { margin: 0; }
.access-requests-foot { display: flex; justify-content: flex-start; margin-top: 12px; }
@media (max-width: 720px) {
  .access-requests-card { grid-template-columns: 1fr; }
  .access-requests-card > .access-requests-block { padding-right: 0; }
  .access-requests-card > .locked-accounts-block {
    padding-left: 0; border-left: 0;
    padding-top: 14px; margin-top: 14px; border-top: 1px solid var(--border);
  }
}
.locked-accounts-list li { display: flex; align-items: center; gap: 10px;
  padding: 6px 0; border-bottom: 1px solid var(--border); }
.locked-accounts-list li:last-child { border-bottom: none; }
.locked-accounts-name { font-weight: 500; }
.locked-accounts-form { margin-left: auto; }
.locked-accounts-empty { margin: 4px 0 0; }
.nav-badge-warn { background: #f59e0b; }

.user-locked-row { background: color-mix(in srgb, #fef3c7 20%, transparent); }
[data-theme="dark"] .user-locked-row,
[data-theme="neobrutal-dark"] .user-locked-row,
[data-theme="cyberpunk"] .user-locked-row { background: color-mix(in srgb, #78350f 25%, transparent); }

/* Disabled accounts get a desaturated tint + slightly muted text so
   they're visually distinct from active rows without screaming. The
   inline role / self-reset controls stay fully readable so an admin
   can still flip them on a disabled row. */
.user-disabled-row { background: color-mix(in srgb, var(--muted) 8%, transparent); }
.user-disabled-row .users-cell-text { color: var(--muted); text-decoration: line-through; }
.user-disabled-badge { margin-left: 6px; }

/* Static text inside the All Users table — same vertical rhythm as
   the inputs they replaced so adjacent cells line up. */
.users-cell-text { display: inline-block; padding: 6px 0; }

/* Edit-user modal — two-column field grid that collapses to one on
   narrow viewports; toggles stack underneath as full-width rows. */
.user-edit-modal .modal-panel { max-width: 560px; }
.user-edit-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 16px; }
.user-edit-form-grid label { display: flex; flex-direction: column; gap: 4px;
  font-size: 0.8125rem; font-weight: 600; }
.user-edit-form-grid input,
.user-edit-form-grid select { padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel-2);
  color: var(--text); font-size: 0.875rem; }
.user-edit-toggles { display: flex; flex-direction: column; gap: 10px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.user-edit-toggle { display: flex; align-items: center; gap: 12px;
  cursor: pointer; padding: 6px 0; }
.user-edit-toggle-label { display: flex; flex-direction: column; gap: 2px;
  line-height: 1.35; }
.user-edit-toggle input:disabled ~ .mode-track { opacity: 0.5; cursor: not-allowed; }
.user-edit-self-warn { margin: 8px 0 0; }
@media (max-width: 560px){
  .user-edit-form-grid { grid-template-columns: 1fr; }
}

/* Row dirty highlight for the per-row save bar — applies to the
   user-table <tr> and to the PIC <form> (it sets ``data-user-row``
   on its own tag too). Soft yellow band that maps to the same
   palette as the save bar. */
[data-user-row].is-dirty,
form[data-savebar-row].is-dirty {
  background: color-mix(in srgb, #facc15 18%, transparent);
  transition: background 200ms ease;
}
form[data-savebar-row].is-dirty {
  border-radius: 8px;
  outline: 1px solid color-mix(in srgb, #facc15 45%, transparent);
}
[data-theme="dark"] [data-user-row].is-dirty,
[data-theme="dark"] form[data-savebar-row].is-dirty,
[data-theme="neobrutal-dark"] [data-user-row].is-dirty,
[data-theme="neobrutal-dark"] form[data-savebar-row].is-dirty,
[data-theme="cyberpunk"] [data-user-row].is-dirty,
[data-theme="cyberpunk"] form[data-savebar-row].is-dirty {
  background: color-mix(in srgb, #422006 35%, transparent);
}

/* Iframe-local save bar lives inside users.html which renders inside
   the settings-frame iframe. Pin to bottom-left of the iframe
   viewport so it stays anchored even as the user scrolls the long
   users list. Use a compound selector that beats ``.settings-save-bar``
   (which sets position: absolute later in this file) on specificity
   without resorting to !important. */
.fe-save-bar.users-save-bar {
  position: fixed;
  left: 16px;
  right: auto;
  bottom: 16px;
  width: auto;
  max-width: calc(100vw - 32px);
  z-index: 60;
}
@media (max-width: 700px) {
  .fe-save-bar.users-save-bar { left: 12px; right: 12px; bottom: 12px; max-width: none; }
}

.nav-badge { display: inline-block; background: var(--brand, #0b5cff); color: #fff; border-radius: 999px;
  font-size: 0.6875rem; font-weight: 700; padding: 1px 7px; margin-left: 6px; vertical-align: middle; }
.nav-badge-muted { background: color-mix(in srgb, var(--text) 20%, transparent); color: var(--muted); }

/* Modal */
.modal { position: fixed; inset: 0; z-index: 100; visibility: hidden; opacity: 0;
  transition: opacity 180ms ease, visibility 0s linear 180ms; }
.modal.open { visibility: visible; opacity: 1;
  transition: opacity 180ms ease, visibility 0s linear 0s; }
.modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(17, 24, 39, 0.45);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.modal-panel {
  position: relative; margin: 5vh auto; max-width: 680px; width: calc(100% - 32px);
  background: var(--panel); border: 1px solid var(--border); border-radius: 14px;
  box-shadow: 0 20px 60px rgba(0,0,0,.25); max-height: 90vh; display: flex; flex-direction: column;
  overflow: hidden;
  transform: translateY(28px);
  transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.modal.open .modal-panel { transform: translateY(0); }
.modal-head { display: flex; justify-content: space-between; align-items: center;
  padding: 14px 18px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
.modal-head h2 { font-size: 1.2rem; font-weight: 700; }

.modal-head .icon-btn { flex: 0 0 auto; width: 32px; height: 32px; }
.modal-panel > form { display: flex; flex-direction: column; min-height: 0; max-height: 90vh; }
.modal-body { padding: 20px 24px; overflow-y: auto; overflow-x: hidden; display: flex;
  flex-direction: column; gap: 12px; flex: 1 1 auto; min-height: 0; }
.modal-body > form.form { flex: 0 0 auto; }
.modal-foot { flex-shrink: 0; }
.modal-foot { padding: 12px 18px; border-top: 1px solid var(--border);
  display: flex; justify-content: flex-end; gap: 10px; }

.fieldset { border: 1px solid var(--border); border-radius: 10px; padding: 2rem; margin: 0;
  display: flex; flex-direction: column; gap: 2rem; }
.fieldset legend { font-size: 1rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .5px; padding: 0 6px; }
.fieldset-inline { padding: 1rem 1.25rem; gap: 0.75rem; }
.checks-row { display: flex; flex-wrap: wrap; gap: 8px; }
.checks-row .check { flex: 1 1 auto; min-width: 0; }
.radio-list { list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.radio-list li { margin: 0; }
.form .radio-list label, .radio-list label {
  display: flex; flex-direction: row; align-items: center; gap: 10px;
  cursor: pointer; font-size: 0.9375rem; font-weight: 400; color: var(--text);
  margin: 0;
}
.radio-list input[type="radio"] {
  flex: 0 0 auto; margin: 0; width: auto; accent-color: var(--brand);
}

.day-list { display: flex; flex-direction: column; gap: 8px; }
.day-row { display: grid;
  grid-template-columns: minmax(120px, 140px) 120px 120px 120px; gap: 8px; align-items: center; }
.day-row > .day-check { grid-column: 1; }
.day-row.hide-opens { grid-template-columns: minmax(120px, 140px) 120px 120px 1fr; }
.day-row-head { align-items: end; padding-bottom: 2px; border-bottom: 1px solid var(--border);
  margin-bottom: 4px; }
.day-col-label { font-size: 0.6875rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .5px; padding: 0 2px; }
.day-row .day-field { padding: 7px 10px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--text); font-size: 0.8125rem; font-family: inherit; }
.day-row .day-field:disabled { opacity: .45; }
.day-row .day-check, .form .day-row .day-check { margin: 0; display: inline-flex;
  flex-direction: row; align-items: center; gap: 10px; }
.form .otp-toggle { display: inline-flex; flex-direction: row; align-items: center;
  gap: 10px; font-size: .9rem; margin: 1rem 0; }
.day-row .day-check .day-label { font-size: 0.875rem; }
.day-row:not(.on) .day-check .day-label { color: var(--muted); }
.chip-sm { padding: 1px 7px; font-size: 0.6875rem; margin-right: 3px; }
.chip-archived { background: var(--panel-2); color: var(--muted); border: 1px solid var(--border); }
.radio-row { display: flex; gap: 10px; flex-wrap: wrap; }
.radio { display: flex; gap: 8px; align-items: center; padding: 8px 12px;
  border: 1px solid var(--border); border-radius: 8px; background: var(--panel-2);
  cursor: pointer; font-weight: 500; }
.radio input { accent-color: var(--brand); }
.row-inline { display: flex; gap: 8px; align-items: center; margin-bottom: 10px; flex-direction: row; }
.row-inline input { flex: 1; padding: 7px 10px; border: 1px solid var(--border);
  border-radius: 8px; background: var(--panel-2); color: var(--text); }
.logo-current { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; }
.logo-current img { max-height: 60px; max-width: 120px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel-2); }
.meeting-logo { max-height: 48px; max-width: 48px; border-radius: 8px;
  margin-right: 10px; vertical-align: middle; }
/* Backend meeting detail page — bigger 100px display, distinct from the
   small inline thumbnails on the admin meeting list. */
.meeting-header .meeting-logo {
  max-height: 100px; max-width: 100px; margin-right: 0;
}
.reading-thumb { width: 56px; height: 56px; object-fit: cover; border-radius: 8px;
  border: 1px solid var(--border); margin-right: 12px; flex: 0 0 auto; }
.reading-hero { max-width: 320px; max-height: 220px; border-radius: 10px;
  border: 1px solid var(--border); margin-bottom: 12px; display: block; }
form.hide-zoom .zoom-only, form.hide-zoom .zoom-only-field { display: none; }

/* Settings modal */
.modal-lg .modal-panel { max-width: 1180px; }
#settings-modal .modal-panel { height: calc(100vh - 10vh); max-width: 1180px; }

/* WordPress importer modal — same full-height treatment as the
   settings modal so the iframe has a tall canvas to render the
   wizard pages without scrolling the wrapper. */
#wp-import-modal .modal-panel { height: calc(100vh - 10vh); max-width: 1180px; }
#wp-import-frame { flex: 1 1 auto; width: 100%; height: 100%; min-height: 0; border: 0; background: var(--panel); }
#settings-modal .settings-body { flex: 1 1 auto; height: auto; min-height: 0; }
.user-chip-name { flex: 1; min-width: 0; }
.icon-btn-inline { width: 40px; height: 40px; flex: 0 0 auto; font-size: 1.35rem; }
.settings-tabs { display: flex; gap: 4px; padding: 0 18px; border-bottom: 1px solid var(--border);
  flex-wrap: nowrap; flex-shrink: 0; overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  -webkit-mask: linear-gradient(90deg, #000 0, #000 calc(100% - 36px), transparent 100%);
          mask: linear-gradient(90deg, #000 0, #000 calc(100% - 36px), transparent 100%); }
.settings-tabs::-webkit-scrollbar { display: none; }
.settings-tab { flex: 0 0 auto; white-space: nowrap; }
.settings-tab { background: none; border: none; padding: 10px 14px; font-size: 1rem;
  font-weight: 600; color: var(--muted); cursor: pointer; border-bottom: 2px solid transparent;
  margin-bottom: -1px; }
.settings-tab:hover { color: var(--text); }
.settings-tab.active { color: var(--brand); border-bottom-color: var(--brand); }
.settings-body { flex: 1 1 auto; min-height: 0; display: flex; height: 70vh; background: var(--panel); }
.settings-pane { display: none; flex: 1 1 auto; min-height: 0; width: 100%; }
/* Global Settings pane defaults — single source of truth so new tabs
   inherit consistent spacing without per-pane CSS:
     · 2rem padding around the outer container
     · 1rem gap between top-level children (cards, forms, etc.)
     · titles (.u-name) sized at 1rem
     · toggle / row containers (.special-page-row) padded at 1rem
   Per-pane overrides win on specificity (e.g. the Appearance pane
   keeps its own internal padding since it scrolls a tall stack of
   sub-sections). Iframe-hosting panes opt out of padding via the
   :has() rule below so the iframe fills edge-to-edge. */
.settings-pane.active {
  display: flex; flex-direction: column;
  padding: 2rem; gap: 1rem;
  overflow-y: auto; overflow-x: hidden; min-width: 0;
}
.settings-pane.active > * { max-width: 100%; min-width: 0; }
.settings-pane.active .u-name { font-size: 1rem; font-weight: 700; line-height: 1.3; }
.settings-pane.active .special-page-row { padding: 1rem; }
.settings-pane.active:has(> iframe.settings-frame),
.settings-pane.active:has(> .settings-frame) {
  padding: 0; gap: 0;
}
.settings-frame { width: 100%; height: 100%; border: 0; background: var(--panel); }
.appearance-pane { display: flex; align-items: flex-start; justify-content: space-between;
  padding: 24px; gap: 16px; width: 100%; font-size: 1rem; }
.appearance-theme { flex-direction: column; align-items: stretch; gap: 12px; }
.theme-picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
.theme-swatch {
  display: flex; flex-direction: column; gap: 8px; padding: 10px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px;
  cursor: pointer; color: var(--text); text-align: left; font: inherit;
  transition: transform .1s ease, border-color .1s ease;
}
.theme-swatch:hover { transform: translateY(-1px); }
.theme-swatch[aria-checked="true"] { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-soft); }
.swatch-preview { display: flex; align-items: stretch; height: 56px; border-radius: 6px; overflow: hidden; border: 1px solid var(--border); }
.sw-panel { width: 40%; }
.sw-accent { width: 14px; align-self: center; height: 60%; margin-left: auto; margin-right: 8px; border-radius: 3px; }
.swatch-label { font-size: 0.875rem; font-weight: 600; }
.settings-pane[data-pane="appearance"] { flex-direction: column; padding: 0; overflow-y: auto; overflow-x: hidden; gap: 0; min-width: 0; }
/* Sidebar tab — flex column with comfortable padding so the form
   doesn't get stretched horizontally and the Save button sits
   naturally at the bottom-right of the form rather than full-height
   on the right edge of the pane. */
.settings-pane[data-pane="sidebar"] {
  flex-direction: column; padding: 2rem;
  overflow-y: auto; overflow-x: hidden; gap: 16px; min-width: 0;
}
.settings-pane[data-pane="sidebar"] > * { max-width: 100%; min-width: 0; }
.settings-pane[data-pane="appearance"] > * { max-width: 100%; min-width: 0; }
.settings-pane[data-pane="appearance"] > .appearance-pane { padding: 20px 24px; }
.settings-pane[data-pane="appearance"] .appearance-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px;
  padding: 20px 24px 24px; align-items: start; }
.settings-pane[data-pane="appearance"] .appearance-grid > * { min-width: 0; }
@media (max-width: 900px) {
  .settings-pane[data-pane="appearance"] .appearance-grid { grid-template-columns: 1fr; }
}
.settings-pane[data-pane="appearance"] .appearance-grid > .form { padding: 0; margin: 0; width: 100%; gap: 10px; }
.settings-pane[data-pane="appearance"] .appearance-grid > .login-appearance-group { display: flex; flex-direction: column; gap: 20px; }
.settings-pane[data-pane="appearance"] .appearance-grid > .login-appearance-group > .form { padding: 0; margin: 0; width: 100%; gap: 10px; }
.settings-pane[data-pane="appearance"] .appearance-grid > .login-appearance-group > .turnstile-form { padding-top: 18px; border-top: 1px solid var(--border); }
.turnstile-form .form-actions { justify-content: flex-start; }
.appearance-branding-form .u-name + p { margin: 0 0 8px; }
.appearance-branding-form label { gap: 6px; font-size: 0.875rem; }
.appearance-branding-form label.check { flex-direction: row; align-items: center; gap: 8px;
  background: transparent; border: 0; padding: 0; font-weight: 400; }
.appearance-branding-form label.check input { width: auto; margin: 0; }
.appearance-branding-form .branding-save-row { margin-top: 4px; }
.settings-pane[data-pane="appearance"] .appearance-grid .login-appearance-form { padding: 0; }
.settings-pane[data-pane="appearance"] .appearance-grid .login-appearance-form .login-fx-controls { max-width: none; }
.settings-pane[data-pane="appearance"] .theme-picker { grid-template-columns: repeat(6, 1fr); }
@media (max-width: 1024px) { .settings-pane[data-pane="appearance"] .theme-picker { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 600px) { .settings-pane[data-pane="appearance"] .theme-picker { grid-template-columns: repeat(2, 1fr); } }
.settings-pane[data-pane="appearance"] > .form { padding: 20px 24px 24px; width: 100%;
  box-sizing: border-box; display: flex; flex-direction: column; gap: 10px; }
.settings-pane[data-pane="appearance"] .u-name { font-size: 1rem; line-height: 1.3; }
.settings-pane[data-pane="appearance"] .u-name + p { margin: 2px 0 2rem; }
.settings-sep { border: 0; border-top: 1px solid var(--border); margin: 0 24px; width: auto; }

/* Daily snapshot list in Settings → Data. Each row shows the file
   name, the formatted date + size, and a Download button. Compact
   layout so 14 days of snapshots stack cleanly. */
.data-snapshots .form-actions { justify-content: flex-start; }
.data-snapshot-list {
  list-style: none; padding: 0; margin: 8px 0 12px;
  display: flex; flex-direction: column; gap: 6px;
}
.data-snapshot-row {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 12px; border: 1px solid var(--border);
  border-radius: 8px; background: var(--panel-2);
}
.data-snapshot-row:hover { background: var(--panel); }
.data-snapshot-name { flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.data-snapshot-name code { font-size: 0.85rem; }
.data-snapshot-row .smaller { flex: 0 0 auto; }
.data-snapshot-row .btn { flex: 0 0 auto; }
.branding-row { display: flex; gap: 16px; align-items: stretch; margin-top: 8px; }
.branding-preview-wrap { flex-shrink: 0; display: flex; flex-direction: column; gap: 6px; width: 248px; max-width: 100%; }
.width-slider-label { margin-top: 4px; font-size: 0.875rem; display: flex; flex-direction: column; gap: 4px; }
.branding-save-row { margin-top: auto; margin-bottom: 1rem; display: flex; justify-content: flex-start; }
.sidebar-footer-mock {
  width: 248px; height: 170px; box-sizing: border-box; padding: 18px 14px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
}
.sidebar-footer-mock .sidebar-footer-img-link { pointer-events: none; }
.sidebar-footer-mock .sidebar-footer-img-link img { max-width: 100%; height: auto; display: block; }
.branding-fields { flex: 1; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.width-slider-head { display: flex; justify-content: space-between; align-items: baseline; }
.width-slider-head output { font-variant-numeric: tabular-nums; color: var(--muted); font-size: .9rem; }
.width-slider-label input[type="range"] { width: 100%; }
.about-head-branded { flex-direction: row; align-items: center; gap: 16px; }
.about-head-branded .u-name { font-size: 1rem; }
.about-logo { width: 120px; height: auto; }
.about-credit { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--border); }
.viibeware-credit { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; color: var(--text); }
.viibeware-credit img { height: 28px; }
.viibeware-name { font-weight: 700; letter-spacing: .08em; font-size: .95rem; }
.viibeware-credit:hover { opacity: .85; }
.about-pane { padding: 0; width: 100%; overflow-y: auto; display: flex; flex-direction: column; gap: 16px; }
.about-head { display: flex; flex-direction: column; gap: 2px; }
.about-sub { font-size: 1rem; font-weight: 700; margin: 4px 0 0; }
/* Release notes + changelog each live in their own <details> block so
   the About tab leads with the friendly summary (open by default) and
   keeps the dense implementation log behind a closed toggle. The
   summary row hosts the existing `.about-sub` heading + a small muted
   subtitle; a custom caret rotates when the section is open. */
.about-rel-notes,
.about-changelog {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-2);
  padding: 4px 16px;
}
.about-rel-notes[open],
.about-changelog[open] {
  padding-bottom: 16px;
}
.about-sub-summary {
  list-style: none; cursor: pointer;
  display: flex; flex-direction: column; gap: 2px;
  padding: 12px 0;
  position: relative; padding-right: 28px;
  user-select: none;
}
.about-sub-summary::-webkit-details-marker { display: none; }
.about-sub-summary::after {
  content: ""; position: absolute; right: 6px; top: 50%;
  width: 8px; height: 8px;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: translateY(-75%) rotate(45deg);
  transition: transform 180ms ease;
}
.about-rel-notes[open] > .about-sub-summary::after,
.about-changelog[open] > .about-sub-summary::after {
  transform: translateY(-25%) rotate(-135deg);
}
.about-sub-summary > .about-sub { margin: 0; }
.about-sub-summary:hover > .about-sub { color: var(--brand, var(--text)); }
.about-sub-summary:focus-visible {
  outline: 2px solid var(--brand, currentColor); outline-offset: 4px;
  border-radius: 6px;
}

.changelog,
.release-notes {
  list-style: none; padding: 0; margin: 8px 0 0;
  display: flex; flex-direction: column; gap: 14px;
}
.changelog > li,
.release-notes > li {
  border: 1px solid var(--border); border-radius: 10px;
  padding: 12px 14px; background: var(--panel);
}
.changelog ul,
.release-notes ul {
  margin: 6px 0 0; padding-left: 18px; color: var(--text); font-size: .95rem;
}
.changelog ul li,
.release-notes ul li { margin: 2px 0; }
.release-notes > li > p {
  margin: 6px 0 0; color: var(--text); font-size: .95rem; line-height: 1.5;
}

.about-tagline { font-size: .875rem; color: var(--muted); margin-top: 8px; max-width: 32ch; line-height: 1.45; }
.about-built-by { margin-top: 10px; font-size: .8125rem; color: var(--muted); display: inline-flex; align-items: center; gap: 6px; }
.about-license { margin-top: 10px; font-size: .75rem; color: var(--muted); line-height: 1.5; max-width: 32ch; }
.viibeware-credit-sm { gap: 6px; color: var(--muted); }
.viibeware-credit-sm img { height: 18px; }
.viibeware-credit-sm .viibeware-name { font-weight: 700; letter-spacing: .08em; font-size: .8125rem; color: var(--muted); }
.about-hero { display: grid; grid-template-columns: minmax(200px, 240px) 1fr; gap: 24px; align-items: start;
  padding: 20px; border: 1px solid var(--border); border-radius: 12px; background: var(--panel-2);
  position: relative; overflow: hidden; isolation: isolate; flex-shrink: 0; }
.about-hero-bg { position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0.16; z-index: 0; pointer-events: none; display: block;
  filter: saturate(0.65); }
[data-theme="dark"] .about-hero-bg,
[data-theme="neobrutal-dark"] .about-hero-bg,
[data-theme="cyberpunk"] .about-hero-bg { opacity: 0.22; filter: saturate(0.55); }
.about-hero > :not(.about-hero-bg) { position: relative; z-index: 1; min-width: 0; }
.about-hero-brand { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.about-hero-brand .about-logo { width: 120px; height: auto; margin-bottom: 10px; }
.about-hero-name { font-size: 1.0625rem; font-weight: 700; color: var(--text); line-height: 1.25; }
.about-hero-version { font-size: .8125rem; color: var(--muted); font-weight: 500; }
.about-hero-stack { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.about-stack-label { font-size: .6875rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); }
.about-hero .tech-stack { margin: 0; }
@media (max-width: 640px) {
  .about-hero { grid-template-columns: 1fr; gap: 16px; padding: 16px; }
  .about-hero-brand { align-items: center; text-align: center; }
  .about-tagline { text-align: center; max-width: 100%; }
}
.tech-stack { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: 10px; }
.tech-tile { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 10px;
  padding: 16px 8px 12px; border: 1px solid var(--border); border-radius: 12px;
  background: color-mix(in srgb, var(--panel-2) 55%, transparent);
  backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
  transition: border-color 140ms ease, transform 140ms ease, background 140ms ease;
  text-decoration: none; color: inherit; }
.tech-tile:hover { border-color: var(--access); transform: translateY(-2px);
  background: color-mix(in srgb, var(--panel) 80%, transparent); }
.tech-icon { width: 32px; height: 32px; flex: 0 0 auto; background-color: var(--text);
  -webkit-mask-size: contain; -webkit-mask-repeat: no-repeat; -webkit-mask-position: center;
  mask-size: contain; mask-repeat: no-repeat; mask-position: center;
  transition: background-color 140ms ease; }
.tech-tile:hover .tech-icon { background-color: var(--access); }
.tech-tile-name { font-size: .75rem; font-weight: 500; color: var(--muted); text-align: center; line-height: 1.2; }

body.embed { background: var(--panel); }
body.embed .embed-content { padding: 20px; }
body.embed .card { background: var(--panel); border: 0; border-radius: 0;
  box-shadow: none; padding: 0 0 20px; margin: 0 0 20px;
  border-bottom: 1px solid var(--border); }
body.embed .card:last-child { margin-bottom: 0; padding-bottom: 2rem; border-bottom: 0; }
.embed-actions { display: flex; justify-content: flex-end; margin-bottom: 12px; }
.view-controls { display: inline-flex; align-items: center; gap: 12px; margin-right: 8px; }
.view-toggle { display: inline-flex; gap: 0; }
.view-toggle .btn { border-radius: 0; border-right-width: 0; }
.view-toggle .btn:first-child { border-top-left-radius: 8px; border-bottom-left-radius: 8px; }
.view-toggle .btn:last-child { border-top-right-radius: 8px; border-bottom-right-radius: 8px;
  border-right-width: 1px; }
.view-toggle .btn.active { background: var(--access); color: white; border-color: var(--access); }
.view-toggle .btn .icon { font-size: 1rem; }
.view-toggle-label { margin-left: 4px; }
@media (max-width: 540px) {
  .view-toggle-label { display: none; }
}
.sort-select { display: inline-flex; align-items: center; gap: 6px; }
.sort-select select { padding: 5px 8px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--text); font-size: 0.8125rem; font-family: inherit; }

.mtype-chip { display: inline-block; margin-left: 12px; padding: 4px 12px; border-radius: 999px; white-space: nowrap;
  font-size: 0.75rem; font-weight: 600; letter-spacing: .3px; vertical-align: middle; }
.mtype-online { background: rgba(11, 92, 255, 0.16); color: #0b5cff; }
.mtype-hybrid { background: rgba(172, 72, 255, 0.18); color: #8b36d9; }
.mtype-in_person { background: rgba(56, 198, 76, 0.2); color: #1f9d3b; }

.meeting-info {
  display: flex; flex-direction: column; gap: 20px;
  /* Anchor for the full-height column divider rendered via ::before. */
  position: relative;
}
/* Vertical hairline between the left/right columns of the details
   grid. Painted on the section card itself so it spans top-padding
   to bottom-padding (the whole height of the container) instead of
   stopping at the grid row's height. Hidden when the grid collapses
   to a single column on narrow viewports — the divider would only
   visually slice through stacked content there. */
.meeting-info::before {
  content: "";
  position: absolute;
  /* Stop 2rem short of the card's top + bottom padding edges so the
     line reads as a column separator rather than a full-bleed
     hairline through the card chrome. */
  top: 2rem; bottom: 2rem;
  left: calc(50% - 0.5px);
  width: 1px;
  background: var(--border);
  pointer-events: none;
}
@media (max-width: 600px) {
  .meeting-info::before { display: none; }
}
.meeting-info .detail-label { font-size: 1rem; font-weight: 700; color: var(--text);
  text-transform: none; letter-spacing: 0; margin-bottom: 1rem; }
.meeting-header { display: flex; gap: 16px; align-items: flex-start; }
.meeting-header-text { display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 0; }
.meeting-header-text .chip { align-self: flex-start; }
.meeting-description { color: var(--text); }
.meeting-description .clamp-body { white-space: pre-wrap; }
.meeting-details-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  column-gap: 2rem; row-gap: 16px;
  /* Cells align to the top of the grid row (rather than stretching
     and centering content), so the right column's first label sits
     at the same Y as the left column's first label regardless of
     how tall the description block grows. */
  align-items: start;
}
.detail-block { display: flex; flex-direction: column; align-self: start; }
/* Right column gets 1rem of inner padding on the left so its content
   sits clear of the vertical divider. Only applied on viewports wide
   enough for the grid to actually have two columns — once it stacks
   below 600px the second block sits flush like the first. */
@media (min-width: 601px) {
  .meeting-details-grid > .detail-block:nth-child(2) { padding-left: 1rem; }
}
/* Divider line between sub-sections inside a detail-block (e.g. the
   right column's Location → Zoom transition). Adds a hairline +
   breathing room in one rule so the inline `margin-top` style on
   the old markup can go away. */
.detail-section-divider {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.detail-label { font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: .5px;
  color: var(--muted); margin-bottom: 1rem; }
.schedule-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 4px; }
.schedule-list li { display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; }
.sched-day { font-weight: 600; min-width: 90px; }
.sched-time { font-weight: 600; color: var(--text); }
.schedule-table { border-collapse: collapse; width: 100%; font-size: 1rem; }
.schedule-table th { text-align: left; padding: 4px 12px 6px 0; color: var(--muted);
  font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; }
.schedule-table td { padding: 4px 12px 4px 0; vertical-align: middle; }
.schedule-table td.sched-day { font-weight: 600; }
.schedule-table td.sched-time { font-weight: 600; color: var(--text); }

.zoom-info { display: grid; grid-template-columns: auto 1fr; gap: 12px 16px; margin: 8px 0 0; align-items: center; }
.otp-login-btn { font-size: 1rem; padding: 10px 18px; font-weight: 600; }
.zoom-section-head { font-size: 1rem !important; color: var(--text) !important;
  margin-top: 12px; padding-top: 12px; padding-bottom: 8px;
  border-top: 1px solid var(--border); }
.zoom-divider-top { margin-top: 16px !important; padding-top: 16px;
  border-top: 1px solid var(--border); }
.zoom-info dt { color: var(--muted); font-weight: 700; font-size: 0.9rem; align-self: center; }
.zoom-info dd { margin: 0; font-size: 1rem; }
.zoom-info dd:has(> .btn-primary) { grid-column: 1 / -1; justify-self: start; }
.zoom-info dt:has(+ dd > .btn-primary) { display: none; }
.pw-row { display: inline-flex; align-items: center; gap: 6px; }

.copy-btn { position: relative; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 6px;
  padding: 4px 8px; cursor: pointer; color: var(--text); font-size: 1rem; }
.copy-btn:hover { border-color: var(--access); color: var(--access); }
.copy-btn::after { content: attr(data-tip); position: absolute; bottom: calc(100% + 6px); left: 50%;
  transform: translateX(-50%); background: var(--text); color: var(--panel); padding: 4px 8px;
  border-radius: 6px; font-family: inherit; font-size: 0.6875rem; white-space: nowrap; opacity: 0;
  pointer-events: none; transition: opacity .15s; }
.copy-btn:hover::after, .copy-btn.copied::after { opacity: 1; }

#library-edit-form label { font-size: 0.8125rem; }
#library-edit-form input,
#library-edit-form textarea { font-size: 0.8125rem; font-family: inherit; }

.file-add-form { display: flex; flex-direction: column; gap: 10px; padding: 14px 16px;
  margin-top: 10px; border: 1px solid var(--border); border-radius: 10px; background: var(--panel-2);
  overflow: hidden; transition: max-height 100ms ease, opacity 100ms ease, margin-top 100ms ease, padding 100ms ease, border-width 100ms ease; }
.file-add-form.collapsed { max-height: 0; opacity: 0; margin-top: 0; padding-top: 0; padding-bottom: 0; border-width: 0; pointer-events: none; }
.file-add-form:not(.collapsed) { max-height: 1500px; opacity: 1; }
.file-add-form label { display: flex; flex-direction: column; gap: 4px; font-size: 0.8125rem;
  font-weight: 600; color: var(--text); }
.file-add-form input[type="text"],
.file-add-form input[type="url"],
.file-add-form input:not([type]),
.file-add-form textarea {
  padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel); color: var(--text); font-size: 0.8125rem; font-family: inherit;
  font-weight: 400; width: 100%; }
.file-add-form textarea { resize: vertical; }
.file-add-form input[type="file"] { font-size: 0.8125rem; font-weight: 400; padding: 4px 0; }
.file-add-form input:focus, .file-add-form textarea:focus {
  outline: none; border-color: var(--access); box-shadow: 0 0 0 3px var(--brand-soft); }
.file-add-form .form-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 4px; }

.library-picker { display: flex; flex-direction: column; gap: 10px; }
.library-picker .library-row { display: flex; flex-direction: column; gap: 8px;
  border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px;
  background: var(--panel-2); }
/* Head row carries the include checkbox + name on the left and the
   whole-library Public toggle on the right. The wrapper is a flex
   container so the toggle sits flush right while the label retains
   its existing pointer-cursor + font-weight treatment. */
.library-picker .library-head-wrap {
  display: flex; flex-direction: row; align-items: center;
  gap: 10px; width: 100%;
}
.library-picker .library-head { display: flex; flex-direction: row; align-items: center;
  gap: 10px; cursor: pointer; padding: 0; margin: 0; font-weight: 600; text-align: left;
  flex: 1 1 auto; min-width: 0; }
.library-picker .library-head input { accent-color: var(--brand); margin: 0; }
.library-picker .library-name { font-weight: 600; flex: 0 1 auto; }
.library-picker .library-public-toggle {
  flex: 0 0 auto;
  margin-left: auto;
}
/* Granular mode hides the whole-library Public toggle — per-item
   toggles below take over. The library-readings block (which holds
   them) is naturally hidden in 'all' mode by the existing JS. */
.library-row.is-granular .library-public-toggle { display: none; }
.library-picker .library-detail { display: flex; flex-direction: column; gap: 8px;
  padding: 0 0 0 26px; }
.library-picker .library-readings { display: flex; flex-direction: column; gap: 4px;
  padding: 4px 0 0 0; max-height: 240px; overflow-y: auto; }
.library-picker .reading-check { display: flex; flex-direction: row; align-items: center;
  gap: 8px; cursor: pointer; padding: 2px 0; margin: 0; font-weight: 400; text-align: left;
  flex: 1 1 auto; min-width: 0; }
.library-picker .reading-check input { accent-color: var(--brand); margin: 0; }
/* Each granular reading row holds the include checkbox on the left
   and a Public toggle on the right (only when the frontend module is
   on). Mirrors the file-row layout: include + Public side-by-side. */
.library-picker .reading-row {
  display: flex; flex-direction: row; align-items: center;
  gap: 10px; padding: 2px 0;
}
.library-picker .reading-public-toggle {
  flex: 0 0 auto;
  margin-left: auto;
}

/* "Show on public meeting page" toggle inside each file's edit form. */
.file-add-form .file-public-toggle {
  flex-direction: row; align-items: center; gap: 10px;
  font-weight: 400; padding: 4px 0;
}

/* Compact "Public" toggle that sits in each file row alongside Edit/Delete.
   Smaller track than the standard mode-toggle so it doesn't dominate the row. */
.file-list .file-public-row-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 0 6px 0 0;
}
/* Disabled state for the "Public" toggle when the user lacks the
   admin / frontend-editor permission. The track + thumb stay visible
   but read as muted; the cursor turns into not-allowed and the title
   attribute provides the tooltip. */
.mode-toggle.is-disabled,
.mode-toggle.is-disabled * { cursor: not-allowed; }
.mode-toggle.is-disabled { opacity: 0.55; }
.mode-toggle.is-disabled .mode-track { background: var(--border); }

/* "/meetings/" static prefix sitting flush against the slug input —
   visually communicates that only the trailing slug is editable. */
.slug-input-row {
  display: flex; align-items: stretch; width: 100%;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--panel); overflow: hidden;
  transition: border-color 140ms ease;
}
.slug-input-row:focus-within { border-color: var(--brand); }
.slug-input-prefix {
  display: inline-flex; align-items: center;
  padding: 0 10px;
  background: var(--panel-2); color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.875rem;
  border-right: 1px solid var(--border);
  user-select: none;
}
.slug-input-row > .slug-input-field {
  flex: 1 1 auto; min-width: 0;
  border: none; outline: none; background: transparent;
  padding: 6px 10px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.875rem; color: var(--text);
  transition: background-color 200ms ease, color 200ms ease;
}
/* Live-sync highlight — added by JS when the slug field is rewritten
   from the title field, removed ~1.4 s later. The transition above
   means the colour fades in/out smoothly. The accent-tinted wash on
   the parent row is the most visible cue at a glance; the input
   itself only lifts to a slightly warmer text colour. */
.slug-input-row:has(> .slug-input-field--synced) {
  border-color: var(--brand, currentColor);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand, currentColor) 22%, transparent);
  background: color-mix(in srgb, var(--brand, currentColor) 8%, var(--panel));
}
.slug-input-field--synced {
  color: var(--brand, var(--text));
}

/* URL change history timeline shown under the slug input on the
   meeting + post edit screens. Collapsed by default; admins click to
   expand and audit which old paths still 301-redirect to the entity. */
.slug-history {
  margin: 12px 0 4px; padding: 10px 14px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel-2);
}
.slug-history > summary {
  cursor: pointer; padding: 4px 0; list-style: none;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-weight: 600; font-size: 0.875rem;
}
.slug-history > summary::-webkit-details-marker { display: none; }
.slug-history > summary::before {
  content: "▸"; color: var(--muted); font-size: 0.75rem;
  transition: transform 140ms ease;
}
.slug-history[open] > summary::before { transform: rotate(90deg); }
.slug-history > summary .icon { width: 14px; height: 14px; color: var(--muted); }
.slug-history > p { margin: 8px 0 6px; }
.slug-history-list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.slug-history-list li {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 0; border-top: 1px solid var(--border);
  font-size: 0.875rem;
}
.slug-history-list li:first-child { border-top: none; }
.slug-history-when { min-width: 90px; font-variant-numeric: tabular-nums; }
.slug-history-old, .slug-history-new {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.8125rem; padding: 2px 6px; border-radius: 4px;
  background: var(--panel); border: 1px solid var(--border);
}
.slug-history-old { text-decoration: line-through; color: var(--muted); }
.slug-history-arrow { font-size: 0.95rem; }
.file-list .file-public-row-toggle .mode-track {
  width: 28px; height: 16px;
}
.file-list .file-public-row-toggle .mode-thumb {
  width: 12px; height: 12px;
}
.file-list .file-public-row-toggle input:checked + .mode-track .mode-thumb {
  transform: translateX(12px);
}

/* Toggle switch for All files / Granular */
.library-picker .mode-toggle { position: relative; display: inline-flex;
  flex-direction: row; align-items: center; gap: 8px; cursor: pointer; font-size: .9rem;
  user-select: none; margin: 0; font-weight: 400; text-align: left; }
.mode-toggle { position: relative; display: inline-flex; align-items: center; gap: 8px;
  cursor: pointer; font-size: .9rem; user-select: none; }
.mode-toggle input { width: 0; height: 0; opacity: 0; margin: 0; padding: 0;
  position: absolute; pointer-events: none; }
.mode-track { position: relative; width: 36px; height: 20px; background: var(--border);
  border-radius: 999px; transition: background .15s; flex-shrink: 0; display: inline-block; }
.mode-thumb { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  background: white; border-radius: 50%; transition: transform .15s;
  box-shadow: 0 1px 2px rgba(0,0,0,.2); }
.mode-toggle input:checked ~ .mode-track { background: var(--access); }
.mode-toggle input:checked ~ .mode-track .mode-thumb { transform: translateX(16px); }
.mode-label-all { color: var(--text); }
.mode-label-granular { color: var(--muted); }
.library-row.is-granular .mode-label-all { color: var(--muted); }
.library-row.is-granular .mode-label-granular { color: var(--text); font-weight: 600; }
.library-row:not(.is-granular) .mode-label-all { font-weight: 600; }
.row-actions { display: flex; align-items: center; justify-content: flex-end; gap: 6px; }
.row-actions form { margin: 0; display: inline-flex; align-items: center; }
.tbl .row-actions .btn { vertical-align: middle; }

.intergroup-toggle-row { display: flex; flex-direction: row; align-items: center;
  justify-content: space-between; gap: 12px; margin-top: 8px; }

.login-appearance-form { padding: 0 24px 24px; display: flex; flex-direction: column; gap: 14px; max-width: none; width: 100%; }
.login-appearance-form .login-fx-controls { width: 100%; max-width: 500px; margin: 0 auto; display: flex; flex-direction: column; gap: 14px; }
.login-appearance-form .login-fx-preview-wrap { width: 100%; }
.login-appearance-form .u-name { font-size: 1rem; }
.login-appearance-form p { margin: 0 0 4px; }
.login-appearance-form label { display: flex; flex-direction: column; gap: 6px; font-size: 0.875rem; font-weight: 600; color: var(--text); }
.login-appearance-form label.check { flex-direction: row; align-items: center; gap: 8px; font-weight: 400; }
.login-appearance-form label.check input { width: auto; margin: 0; }
.login-appearance-form .row { display: grid; grid-template-columns: 2fr 1fr; gap: 14px; }
.login-appearance-form select,
.login-appearance-form input[type="color"] { padding: 6px 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); font-size: 0.875rem; font-weight: 400; min-height: 36px; }
.login-appearance-form input[type="color"] { padding: 2px; height: 36px; cursor: pointer; }
.login-appearance-form .form-actions { margin-top: 6px; justify-content: flex-start; }
.login-appearance-form .login-fx-toggle-row { list-style: none; margin: 4px 0 0;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 16px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel); }
.login-appearance-form .login-fx-toggle-row .special-page-info { flex: 1; min-width: 0; }
.login-appearance-form .login-fx-toggle-row .u-name { font-size: 1rem; margin-bottom: 2px; }
.login-appearance-form .login-fx-toggle-row p { margin: 0; }
.login-appearance-form .login-fx-preview-wrap { margin-bottom: 4px; }
.login-appearance-form .login-fx-preview { position: relative; width: 100%; height: 160px; border-radius: 10px;
  overflow: hidden; border: 1px solid var(--border); }
.login-appearance-form .login-fx-preview canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.login-appearance-form .login-fx-preview-label { position: absolute; top: 8px; left: 10px; color: rgba(255,255,255,0.8);
  font-size: 0.75rem; letter-spacing: 0.04em; text-transform: uppercase; z-index: 1; }
.login-appearance-form .login-fx-speed-row { display: flex; align-items: center; gap: 12px; }
.login-appearance-form .login-fx-speed-row input[type="range"] { flex: 1; min-height: 0; padding: 0; }
.login-appearance-form .login-fx-speed-row output { font-weight: 600; font-size: 0.875rem; min-width: 48px; text-align: right; color: var(--text); }
.login-appearance-form .login-fx-colors { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; }
.login-appearance-form .login-fx-color-slot { flex: 0 0 auto; display: flex; flex-direction: column; gap: 4px;
  font-size: 0.75rem; font-weight: 500; color: var(--muted); }
.login-appearance-form .login-fx-color-slot input[type="color"] { width: 54px; height: 36px; padding: 2px;
  border: 1px solid var(--border); border-radius: 8px; background: var(--panel); cursor: pointer; }
.login-appearance-form #login-fx-random { margin-left: auto; }

/* Save bar variant pinned to the bottom-left of the settings modal panel.
   Reuses the .fe-save-bar yellow styling/animation but anchors to the
   modal-panel (which is `position: relative; overflow: hidden`) instead of
   the viewport. Width fits content so the bar doesn't span the full modal. */
.settings-save-bar {
  position: absolute; left: 20px; bottom: 20px;
  width: auto; max-width: calc(100% - 40px);
  z-index: 11;
}
@media (max-width: 900px) {
  .settings-save-bar {
    left: 12px; right: 12px; bottom: 12px; width: auto; max-width: none;
  }
}
/* JS marks the per-form save buttons (and their wrappers) with this class
   once the bar is wired so the bar becomes the only commit path. */
#settings-modal .savebar-hidden { display: none !important; }

.settings-toast { position: absolute; bottom: 20px; right: 20px; left: auto; transform: translateY(12px);
  min-width: 240px; max-width: 360px; padding: 12px 14px 12px 42px; border-radius: 10px;
  font-size: 0.875rem; font-weight: 500; line-height: 1.35; text-align: left;
  background: #dcfce7; color: #14532d;
  border: 1px solid rgba(22,163,74,0.25); border-left: 3px solid #16a34a;
  box-shadow: 0 12px 32px rgba(15,23,42,0.18), 0 2px 6px rgba(15,23,42,0.08);
  opacity: 0; pointer-events: none; transition: opacity 160ms ease, transform 160ms ease; z-index: 10; }
.settings-toast::before { content: ""; position: absolute; left: 14px; top: 50%; width: 18px; height: 18px;
  margin-top: -9px; border-radius: 50%; background: #16a34a;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%23fff' d='M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/></svg>") center/12px no-repeat #16a34a;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%23fff' d='M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/></svg>") center/12px no-repeat;
  background: #16a34a; }
.settings-toast.show { opacity: 1; transform: translateY(0); }
.settings-toast.flash-danger { background: #fee2e2; color: #7f1d1d; border-color: rgba(220,38,38,0.25); border-left-color: #dc2626; }
.settings-toast.flash-danger::before { background: #dc2626; }
.settings-toast.flash-warning { background: #fef3c7; color: #7c2d12; border-color: rgba(217,119,6,0.25); border-left-color: #d97706; }
.settings-toast.flash-warning::before { background: #d97706; }

.settings-pane[data-pane="security"] { flex-direction: column; padding: 20px 24px; gap: 8px; overflow-y: auto; }
.settings-pane[data-pane="security"] .u-name { font-size: 1rem; }
.settings-pane[data-pane="security"] p { margin: 0 0 8px; max-width: 60ch; }
.settings-pane[data-pane="security"] .security-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0; align-items: stretch; width: 100%;
}
.settings-pane[data-pane="security"] .security-col {
  display: flex; flex-direction: column; min-width: 0; padding: 0 24px;
}
.settings-pane[data-pane="security"] .security-col:first-child { padding-left: 0; border-right: 1px solid var(--border); }
.settings-pane[data-pane="security"] .security-col:last-child { padding-right: 0; }
@media (max-width: 720px) {
  .settings-pane[data-pane="security"] .security-grid { grid-template-columns: 1fr; gap: 20px; }
  .settings-pane[data-pane="security"] .security-col { padding: 0; }
  .settings-pane[data-pane="security"] .security-col:first-child {
    border-right: 0; border-bottom: 1px solid var(--border); padding-bottom: 20px;
  }
}
.settings-pane[data-pane="email"] { flex-direction: column; padding: 20px 24px; gap: 8px; overflow-y: auto; }
.settings-pane[data-pane="email"] .u-name { font-size: 1rem; }
.settings-pane[data-pane="email"] > p { margin: 0 0 12px; max-width: 60ch; }
.settings-pane[data-pane="email"] .settings-sep { margin: 18px 0; width: 100%; }
.settings-pane[data-pane="email"] form.form { display: flex; flex-direction: column; gap: 14px; max-width: 600px; }
.settings-pane[data-pane="email"] form.form .u-name { margin-top: 4px; }
.settings-pane[data-pane="email"] form.form p { margin: 0 0 4px; }
.settings-pane[data-pane="email"] form.form label { display: flex; flex-direction: column; gap: 6px; font-size: 0.875rem; font-weight: 600; color: var(--text); }
.settings-pane[data-pane="email"] form.form label.check { flex-direction: row; align-items: center; gap: 8px; font-weight: 400; }
.settings-pane[data-pane="email"] form.form label.check input { width: auto; margin: 0; }
.settings-pane[data-pane="email"] form.form .row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.settings-pane[data-pane="email"] form.form input,
.settings-pane[data-pane="email"] form.form select { padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); font-size: 0.875rem; font-weight: 400; }
.settings-pane[data-pane="email"] form.form input:focus,
.settings-pane[data-pane="email"] form.form select:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
.settings-pane[data-pane="email"] form.form .form-actions { margin-top: 6px; justify-content: flex-start; }
@media (max-width: 640px) {
  .settings-pane[data-pane="email"] form.form .row { grid-template-columns: 1fr; }
}

.settings-pane[data-pane="data"] { flex-direction: column; padding: 20px 24px; gap: 8px; overflow-y: auto; }
.settings-pane[data-pane="data"] .data-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0;
  align-items: stretch; width: 100%; }
.settings-pane[data-pane="data"] .data-col { display: flex; flex-direction: column; gap: 8px; min-width: 0;
  padding: 0 24px; }
.settings-pane[data-pane="data"] .data-col:first-child { padding-left: 0; border-right: 1px solid var(--border); }
.settings-pane[data-pane="data"] .data-col:last-child { padding-right: 0; }
@media (max-width: 720px) {
  .settings-pane[data-pane="data"] .data-grid { grid-template-columns: 1fr; gap: 20px; }
  .settings-pane[data-pane="data"] .data-col { padding: 0; }
  .settings-pane[data-pane="data"] .data-col:first-child { border-right: 0; border-bottom: 1px solid var(--border); padding-bottom: 20px; }
}
.settings-pane[data-pane="data"] .u-name { font-size: 1rem; }

/* WordPress importer wizard — shared chrome used by every step
   (start / map / dry-run / done). Lives here rather than inline so the
   layout is consistent across pages and embed mode (modal iframe) and
   standalone mode render identically.

   The actionbar + stepper sit inside `.wp-wizard-header` which is
   `position: sticky` so the back/cancel/continue buttons and the
   step indicator stay pinned to the top of the iframe / page while
   the post list or preview table scrolls underneath. */
.wp-wizard-header {
  position: sticky;
  top: 0;
  z-index: 20;
  margin: 0 0 1.25rem;
  padding: 1rem 0 .5rem;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  box-shadow: 0 4px 12px -10px rgba(0, 0, 0, .25);
}
/* Pull the header to the edge of the iframe in embed mode so the
   sticky background covers the whole top strip (otherwise the
   embed-content padding leaves a gap on the sides). */
body.embed .wp-wizard-header {
  margin: -20px -20px 1.25rem;
  padding-left: 20px;
  padding-right: 20px;
  padding-top: 20px;
}
.wp-wizard-header .wp-actionbar { margin-bottom: 1rem; }
.wp-wizard-header .wp-wizard-stepper { margin-bottom: .5rem; }

.wp-actionbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin: 0 0 1.25rem;
}
.wp-actionbar .btn-primary { margin-left: auto; }

/* Loading overlay shown when the wizard kicks off a long-running step
   (REST fetch, CSV parse, dry-run compile, or commit). Lives once in
   the page DOM and is toggled visible via .is-active. */
.wp-fetch-overlay {
  position: fixed; inset: 0;
  z-index: 9999;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(15, 17, 26, .55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.wp-fetch-overlay.is-active { display: flex; }
.wp-fetch-overlay-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.75rem 2.25rem;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .35);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  max-width: min(420px, 90vw);
  text-align: center;
}
.wp-fetch-spinner {
  width: 48px; height: 48px;
  border-radius: 50%;
  border: 3px solid var(--border);
  border-top-color: var(--brand);
  animation: wp-fetch-spin .9s linear infinite;
}
@keyframes wp-fetch-spin { to { transform: rotate(360deg); } }
.wp-fetch-title {
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--text);
}
.wp-fetch-message {
  color: var(--muted);
  font-size: .92rem;
  line-height: 1.5;
  margin: 0;
}
.wp-fetch-host {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: .85rem;
  color: var(--brand);
  word-break: break-all;
}

.wp-wizard-stepper { margin: 0 0 1.5rem; }
.wp-wizard-stepper ol {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  align-items: stretch;
}
.wp-wizard-stepper li {
  flex: 1 1 0;
  min-width: 140px;
  display: flex;
  align-items: center;
  gap: .65rem;
  padding: .65rem .9rem;
  background: var(--panel-2, var(--panel));
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--muted, var(--text));
  font-size: .92rem;
}
.wp-wizard-stepper li.is-active {
  background: var(--brand-soft);
  border-color: var(--brand);
  color: var(--text);
}
.wp-wizard-stepper li.is-done {
  border-color: #1f9d55;
  color: #1f9d55;
}
.wp-step-num {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--panel);
  border: 1px solid currentColor;
  display: inline-grid; place-items: center;
  font-weight: 600;
  font-size: .82rem;
}
.wp-wizard-stepper li.is-active .wp-step-num {
  background: var(--brand);
  color: #fff;
  border-color: var(--brand);
}
.wp-step-label { font-weight: 500; }

/* Feature card chrome — `.data-card` layers a brand-colour left accent
   on the standard `.card` (background, border, radius, padding,
   shadow). Block flow only — no positioning pseudo-elements — so the
   card height always grows naturally with its contents. The header
   row uses a Lucide icon + label; sub-layouts (`.data-card-grid` for
   two-column Import/Export, `.data-card-actions` for trailing CTA
   rows) sit inside the card. Originally for the Data settings tab,
   reused by the WordPress importer wizard. */
.data-card {
  border-left: 4px solid var(--brand);
  margin-bottom: 16px;
}
.data-card:last-child {
  margin-bottom: 0;
}
.data-card-head {
  display: flex;
  align-items: center;
  gap: .6rem;
  font-weight: 700;
  font-size: 1.1rem;
  line-height: 1.3;
  color: var(--text);
  margin: 0 0 .9rem;
}
.data-card-head .icon {
  color: var(--brand);
  width: 22px;
  height: 22px;
  flex-shrink: 0;
}
.data-card-lead,
.data-card-sub {
  margin: 0 0 .9rem;
  line-height: 1.55;
}
.data-card-sub:last-of-type {
  margin-bottom: 0;
}
.data-card-actions {
  margin-top: 1.1rem;
  display: flex;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: 8px;
}
.data-card-actions .btn {
  white-space: nowrap;
}
/* Two-column inner grid (Import / Export, etc.) inside a data-card.
   Mirrors the legacy `.data-grid` shape with the spacing tuned to
   sit inside the card's padding. Collapses to a single column on
   narrow viewports. */
.data-card-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  align-items: stretch;
  width: 100%;
}
.data-card-col {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  padding: 0 24px;
}
.data-card-col:first-child {
  padding-left: 0;
  border-right: 1px solid var(--border);
}
.data-card-col:last-child {
  padding-right: 0;
}
@media (max-width: 720px) {
  .data-card-grid {
    grid-template-columns: 1fr;
    gap: 20px;
  }
  .data-card-col {
    padding: 0;
  }
  .data-card-col:first-child {
    border-right: 0;
    border-bottom: 1px solid var(--border);
    padding-bottom: 20px;
  }
}
.settings-pane[data-pane="data"] p { margin: 0 0 8px; max-width: 60ch; }
.settings-pane[data-pane="data"] .settings-rule { border: 0; border-top: 1px solid var(--border); margin: 22px 0 18px; }
.settings-pane[data-pane="data"] .form-actions { margin-top: 4px; margin-bottom: 4px; justify-content: flex-start; }
.settings-pane[data-pane="data"] .settings-sep { margin: 16px 0; width: 100%; }
.settings-pane[data-pane="data"] form.form { display: flex; flex-direction: column; gap: 12px; max-width: 520px; }
.settings-pane[data-pane="data"] form.form label { display: flex; flex-direction: column; gap: 4px; font-size: 0.875rem; }
.settings-pane[data-pane="data"] form.form input[type="text"],
.settings-pane[data-pane="data"] form.form input[type="file"] { padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); color: var(--text); }

.settings-pane[data-pane="web-frontend"] { flex-direction: column; padding: 2rem; gap: 1rem;
  overflow-y: auto; }

.settings-pane[data-pane="modules"] { flex-direction: column; padding: 20px 24px;
  overflow-y: auto; }

.special-pages-list { list-style: none; margin: 0; padding: 0; display: flex;
  flex-direction: column; gap: 10px; width: 100%; }
.special-page-row { display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 14px 16px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel, var(--bg)); flex-wrap: wrap; }
.special-page-info { min-width: 0; flex: 1; }

/* Per-module role-permission picker — sits between the info column
   and the toggle on each Modules-tab row. */
.module-role-form { display: flex; align-items: center; flex: 0 0 auto; }
.module-role-label { display: flex; flex-direction: column; gap: 2px; }
.module-role-label > .smaller { letter-spacing: 0.04em; text-transform: uppercase;
  font-weight: 600; font-size: 0.65rem; }
.module-role-form select {
  padding: 7px 10px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel-2); color: var(--text);
  font: inherit; font-size: 0.85rem; min-width: 200px;
}
.module-role-form select:focus { outline: 2px solid var(--access); outline-offset: 1px; }
@media (max-width: 720px) {
  .module-role-form select { min-width: 0; width: 100%; }
  .module-role-label { flex: 1 1 100%; }
}
.special-page-info .u-name { margin-bottom: 2px; font-size: 1rem; }
.settings-pane[data-pane="modules"] .u-name { font-size: 1rem; }
.special-page-info p { margin: 0; }
.special-page-toggle-form { margin: 0; display: flex; align-items: center; gap: 8px;
  flex-shrink: 0; }

/* "Your Access" tab inside the Settings modal. Header row pairs the
   user-identity block with their role pill on the right; the body
   uses ya-yes / ya-no bullet rows with circular check / × glyphs so
   the can / can't matrix is scannable at a glance. */
.your-access-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.your-access-head .u-name { margin-bottom: 2px; }
.your-access-list {
  list-style: none; margin: 8px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.your-access-list li {
  display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 10px;
  align-items: start; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel-2); line-height: 1.45;
}
.your-access-list .ya-icon {
  display: inline-grid; place-items: center;
  width: 22px; height: 22px; border-radius: 50%;
  font-weight: 700; font-size: 0.75rem; line-height: 1;
}
.your-access-list .ya-yes .ya-icon {
  background: rgba(22, 163, 74, 0.12); color: #16a34a;
  border: 1px solid rgba(22, 163, 74, 0.30);
}
.your-access-list .ya-no .ya-icon {
  background: rgba(220, 38, 38, 0.10); color: #b91c1c;
  border: 1px solid rgba(220, 38, 38, 0.30);
}
html[data-theme="dark"] .your-access-list .ya-yes .ya-icon {
  background: rgba(22, 163, 74, 0.20); color: #86efac;
  border-color: rgba(22, 163, 74, 0.45);
}
html[data-theme="dark"] .your-access-list .ya-no .ya-icon {
  background: rgba(220, 38, 38, 0.20); color: #fca5a5;
  border-color: rgba(220, 38, 38, 0.45);
}

/* Permission matrix on the Your Access tab. Wrapping div allows
   horizontal scroll on narrow viewports; the table itself uses
   sticky-ish column widths so capability text wraps before the
   role columns shrink. The viewer's own column is highlighted with
   a brand-tinted background so the answer to "what can I do?" is
   the first thing the eye lands on. */
.access-matrix-wrap {
  margin: 8px 0 0; overflow-x: auto;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--panel-2);
  /* Don't let the column-flex pane shrink the wrapper below its
     natural content height — when overflow-x is set the wrap becomes
     a scroll container, whose min-height defaults to 0 in flex
     layouts, so without this flex-shrink: 0 the table consumes the
     whole pane and its inner overflow takes the scroll, hiding the
     "Permission matrix" / "Need a different role?" headings. */
  flex-shrink: 0;
}
.access-matrix {
  width: 100%; border-collapse: collapse; font-size: 0.875rem;
}
.access-matrix th, .access-matrix td {
  padding: 10px 12px; text-align: center; vertical-align: middle;
  border-bottom: 1px solid var(--border);
}
.access-matrix tbody tr:last-child td { border-bottom: 0; }
.access-matrix th.access-matrix-cap,
.access-matrix td.access-matrix-cap {
  text-align: left; min-width: 220px; max-width: 360px;
  font-weight: 500; color: var(--text);
}
.access-matrix thead th { font-weight: 600; background: var(--panel); }
.access-matrix thead th.access-matrix-cap {
  font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.04em; font-size: 0.75rem;
}
.access-matrix .perm-badge { font-size: 0.6875rem; padding: 2px 8px; }
.access-matrix .access-matrix-role { white-space: nowrap; }
/* Highlight the viewer's own role column so they can scan their row
   without re-reading the header. Subtle brand tint, not a hard fill,
   so the column doesn't dominate the page. */
.access-matrix .is-current { background: var(--brand-soft); }
html[data-theme="dark"] .access-matrix .is-current { background: rgba(11, 92, 255, 0.10); }
.access-matrix .access-mark { font-weight: 700; font-size: 1rem; line-height: 1;
  display: inline-block; }
.access-matrix .access-cell-yes .access-mark { color: #16a34a; }
.access-matrix .access-cell-partial .access-mark { color: #ca8a04; }
.access-matrix .access-cell-no .access-mark { color: var(--muted); font-weight: 500; }
.access-matrix .access-foot-mark { color: #ca8a04; font-size: 0.6875rem; margin-left: 1px; }
html[data-theme="dark"] .access-matrix .access-cell-yes .access-mark { color: #4ade80; }
html[data-theme="dark"] .access-matrix .access-cell-partial .access-mark { color: #facc15; }
html[data-theme="dark"] .access-matrix .access-foot-mark { color: #facc15; }
.access-matrix-footnote { margin: 8px 4px 0; line-height: 1.45; }

/* Access Requests Active / Archived view tabs in the card head. Sit
   to the right of the Requests heading, switch between the two views
   via plain page navigation (no JS). Active tab carries the brand
   accent + border; the count chip mirrors the other small badges. */
.ar-card-head { display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 12px; }
.ar-view-tabs { display: inline-flex; gap: 4px; padding: 3px;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 999px; }
.ar-view-tab {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 999px;
  font-size: 0.8125rem; font-weight: 600; color: var(--muted);
  text-decoration: none; line-height: 1.4;
  transition: background 120ms, color 120ms;
}
.ar-view-tab:hover { color: var(--text); }
.ar-view-tab.is-active {
  background: var(--panel); color: var(--brand);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}
.ar-view-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 6px;
  font-size: 0.6875rem; font-weight: 700; line-height: 1;
  border-radius: 999px;
  background: var(--border); color: var(--text);
}
.ar-view-tab.is-active .ar-view-count {
  background: var(--brand); color: #fff;
}

/* Nested sub-rows for module sub-features (e.g. the Intergroup module's
   Email Accounts toggle). The parent row keeps its existing flex layout;
   the nested <ul> drops onto its own line via flex: 0 0 100% and is
   indented to read as a child. Sub-rows reuse the same flex layout as
   the top-level rows but with a softer background and a small connector
   on the left so the parent-child relationship reads at a glance. */
.special-page-row-with-children { align-items: flex-start; }
.special-page-subrows {
  list-style: none; margin: 12px 0 0 0; padding: 0;
  flex: 0 0 100%; min-width: 0;
  display: flex; flex-direction: column; gap: 8px;
  padding-left: 1.75rem; position: relative;
}
.special-page-subrows::before {
  content: ""; position: absolute;
  left: 0.6rem; top: 0; bottom: 0.5rem;
  border-left: 2px solid var(--border);
  border-bottom-left-radius: 8px;
}
.special-page-subrow {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 12px 14px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel-2, var(--panel));
  flex-wrap: wrap; position: relative;
}
.special-page-subrow::before {
  content: ""; position: absolute;
  left: -1.15rem; top: 50%; width: 1.15rem;
  border-top: 2px solid var(--border);
}
.special-page-subrow .u-name { font-size: 0.95rem; display: flex;
  align-items: center; gap: 8px; flex-wrap: wrap; }
/* Inline "Admin-only" / permissions chip rendered next to a sub-row's
   title. Carries the same red palette as the perm-badge-admin pill but
   smaller, and surfaces a native-tooltip on hover via title=. */
.perm-info-badge {
  display: inline-flex; align-items: center;
  padding: 2px 8px; border-radius: 999px;
  font-size: 0.625rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; line-height: 1.4;
  border: 1px solid rgba(220, 38, 38, 0.32);
  background: rgba(220, 38, 38, 0.10); color: #b91c1c;
  cursor: help; white-space: nowrap;
}
.perm-info-badge:focus-visible {
  outline: 2px solid var(--access); outline-offset: 1px;
}
html[data-theme="dark"] .perm-info-badge {
  background: rgba(220, 38, 38, 0.20); color: #fca5a5;
  border-color: rgba(220, 38, 38, 0.45);
}
@media (max-width: 720px) {
  .special-page-subrows { padding-left: 1.25rem; }
  .special-page-subrow::before { left: -0.65rem; width: 0.65rem; }
}
/* Block rendering (public view) */
.block-section { margin: 28px 0; }
.block-section-title { margin: 0 0 12px; font-size: 1rem; font-weight: 700;
  line-height: 1.3; }
h3.block-heading { font-size: 0.95rem; font-weight: 700; margin: 16px 0 6px; }
h4.block-heading { font-size: 0.9rem; font-weight: 600; margin: 14px 0 4px; }
h5.block-heading { font-size: 0.875rem; font-weight: 600; margin: 12px 0 4px; }
/* Vertical breathing room around `.block` elements (containers,
   blog cards, etc.). Reads a CSS custom property so a per-page
   override on `.fe-pp` can zero it out for true edge-to-edge
   layouts. Fallback value preserves the historical 12px so
   nothing changes outside content pages that opt in. */
.block { margin: var(--fe-pp-block-margin-y, 12px) 0; }
.block-image img, .block-video video {
  max-width: 100%; height: auto; display: block;
  /* Image-block corner roundness uses `--img-radius` set inline by
     the renderer. Default of 6px keeps unedited blocks softly
     rounded (pre-existing behaviour); the admin's slider value
     overrides via the inline custom property when set. The mobile
     halving lives in frontend.css's media query so admin previews
     and public renders behave the same. */
  border-radius: var(--img-radius, 6px);
}
.block-image figcaption { color: var(--muted); font-size: .9rem; margin-top: 4px; }
/* Lottie block — the figure is the layout slot (alignment / max-width
   / bg ride inline styles from the renderer); the inner stage is what
   lottie-web injects an SVG/Canvas into. The stage stretches to the
   figure's width and uses an aspect-ratio of 1 by default so admins get
   a square stage even before the animation has loaded its own intrinsic
   ratio (lottie sizes itself to match once the JSON resolves, which
   overrides the placeholder). */
/* Intergroup member card — public render of the `intergroup_member`
   block. Lightweight stack of fields (position / name / phone /
   email); each field gets its own row so the renderer can drop any
   subset based on the block's `show_*` toggles without leaving
   visible gaps. Container layout / background lives on the parent
   container block, so the card itself stays neutral by default. */
.block-officer { margin: 12px 0; }
.block-officer-card {
  display: flex; flex-direction: column; gap: 4px;
}
.block-officer-role {
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted);
}
.block-officer-name { font-size: 1.1rem; font-weight: 700; }
.block-officer-phone, .block-officer-email { font-size: 0.95rem; }

/* ── Container-removal confirm modal ──────────────────────────────
   Two-choice prompt shown when an admin × a container row that
   holds blocks. Each choice is a full-width card-like button so
   admins read the trade-off before clicking — the safe path
   (move to Unplaced) is visually neutral, the destructive path
   (remove everything) tints red on hover. */
.be-container-remove-modal .modal-panel {
  max-width: 540px;
}
.be-container-remove-msg {
  margin: 0 0 12px;
  color: var(--text);
}
.be-container-remove-choices {
  display: flex; flex-direction: column; gap: 10px;
}
.be-container-remove-choice {
  display: flex; flex-direction: column; gap: 4px;
  width: 100%;
  padding: 14px 16px;
  background: var(--panel-2, var(--panel));
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 12px;
  text-align: left; cursor: pointer;
  font: inherit;
  transition: border-color 140ms ease, background 140ms ease,
              transform 140ms ease, box-shadow 140ms ease;
}
.be-container-remove-choice:hover {
  border-color: var(--brand, var(--access));
  background: var(--panel);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(15,23,42,0.08);
}
.be-container-remove-choice-title {
  font-weight: 700; font-size: 0.95rem;
}
.be-container-remove-choice-desc {
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.45;
}
.be-container-remove-all:hover {
  border-color: #b91c1c;
  background: color-mix(in srgb, #ef4444 8%, var(--panel));
  box-shadow: 0 4px 12px rgba(239, 68, 68, 0.15);
}
.be-container-remove-all .be-container-remove-choice-title {
  color: #b91c1c;
}

/* ── Library block ────────────────────────────────────────────────
   Three rendering styles share the same data shape; styles are
   keyed off `.block-library-style-{bulleted|list|cards}` on the
   wrapper. Each style lives in its own block below so adding a
   new style later just means another wrapper class + ruleset. */
.block-library { margin: 12px 0; }
.block-library-title {
  font-size: 1.1rem; font-weight: 700; margin: 0 0 12px;
}
/* Bulleted list — actual <ul> with markers, title-only. The link
   styling rides whatever the page's anchor rule already provides. */
.block-library-bulleted {
  margin: 0; padding-left: 1.5rem;
  list-style-type: disc;
}
.block-library-bulleted li { margin: 4px 0; }

/* Plain list — stacked rows separated by hairline borders, with
   title + optional description + category chips. Reads as a content
   roster rather than a bullet/UL. */
.block-library-list {
  display: flex; flex-direction: column;
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}
.block-library-list-item {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
.block-library-list-item:last-child { border-bottom: 0; }
.block-library-list-title { font-weight: 600; font-size: 1rem; }
.block-library-list-desc {
  margin-top: 4px;
  font-size: 0.9rem;
  color: var(--muted);
  line-height: 1.5;
}

/* Cards — grid layout (column count + gap ride inline styles from
   the renderer). Each card has a thumbnail strip on top (when
   thumbnails are enabled and the item carries one) plus the title /
   description / category chips. Hover lifts to telegraph clickable
   linked items. */
.block-library-card {
  display: flex; flex-direction: column; gap: 0;
  background: var(--panel, #fff);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.06);
  overflow: hidden;
  transition: transform 180ms ease, box-shadow 180ms ease;
}
.block-library-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 2px 4px rgba(0,0,0,0.06), 0 12px 24px rgba(0,0,0,0.10);
}
.block-library-card-thumb {
  aspect-ratio: 16 / 9;
  background: var(--panel-2, var(--panel));
  overflow: hidden;
}
.block-library-card-thumb img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.block-library-card-body {
  display: flex; flex-direction: column; gap: 4px;
  padding: 14px 16px;
}
.block-library-card-title { font-weight: 700; font-size: 1rem; }
.block-library-card-desc {
  font-size: 0.88rem; color: var(--muted); line-height: 1.5;
}

/* Category chips — shared across all three styles. Tinted with the
   active brand colour at low opacity so they read as metadata
   rather than calls-to-action. */
.block-library-cats {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin-top: 6px;
}
.block-library-cat {
  display: inline-block;
  padding: 2px 8px;
  font-size: 0.72rem;
  background: color-mix(in srgb, var(--brand, var(--access)) 12%, transparent);
  color: var(--text);
  border-radius: 999px;
}

@media (max-width: 720px) {
  /* Card grids drop to a single column on narrow viewports so cards
     don't squeeze. The inline grid-template-columns style on the
     wrapper gets overridden via !important since column count is the
     admin's choice on desktop. */
  .block-library-cards {
    grid-template-columns: 1fr !important;
  }
}

/* Items past the configured `max_items` start the page hidden; the
   Load more button progressively reveals them in `data-lib-block-step`-
   sized batches. `display: none !important` beats the inline grid /
   flex declarations the wrapper rules emit. */
.block-library .block-library-hidden {
  display: none !important;
}

/* Load more button — neutral pill that sits below the rendered items
   and is removed from the DOM once nothing's left to reveal. The
   inline "(N more)" count chip gives a hint about how much remains so
   visitors don't feel like they're clicking blindly. */
.block-library-more {
  margin-top: 14px;
  text-align: center;
}
.block-library-more-btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 18px;
  border: 1px solid var(--border);
  background: var(--panel-2, var(--panel));
  color: var(--text);
  border-radius: 999px;
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease, transform 120ms ease;
}
.block-library-more-btn:hover {
  background: color-mix(in srgb, var(--brand, var(--access)) 10%, var(--panel-2, var(--panel)));
  border-color: var(--brand, var(--access));
}
.block-library-more-btn:active { transform: translateY(1px); }
.block-library-more-count {
  font-weight: 500; font-size: 0.78rem; color: var(--muted);
}

/* ── Library block — admin settings panel ───────────────────── */
.be-library-body { gap: 12px; }
.be-library-select { width: 100%; }
.be-library-cards-controls {
  display: flex; flex-direction: column; gap: 8px;
  padding: 8px 10px;
  background: var(--panel-2, var(--panel));
  border: 1px solid var(--border);
  border-radius: 8px;
}
.be-library-granular {
  display: flex; flex-direction: column; gap: 8px;
  padding: 8px 10px;
  background: var(--panel-2, var(--panel));
  border: 1px solid var(--border);
  border-radius: 8px;
  max-height: 280px;
  overflow-y: auto;
}
.be-library-granular-actions {
  display: flex; gap: 6px;
}
.be-library-granular-list {
  display: flex; flex-direction: column; gap: 4px;
}
.be-library-granular-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 4px 6px;
  border-radius: 6px;
}
.be-library-granular-row:hover { background: var(--panel); }
.be-library-granular-title { font-size: 0.92rem; }
.be-library-granular-kind {
  text-transform: uppercase; letter-spacing: 0.04em;
  padding: 1px 6px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--brand, var(--access)) 10%, transparent);
}
.be-library-fields {
  display: flex; flex-direction: column; gap: 4px;
  padding: 8px 10px;
  background: var(--panel-2, var(--panel));
  border: 1px solid var(--border);
  border-radius: 8px;
}

/* Officer roster — each card is a discrete unit with shadow +
   rounded corners + subtle hover lift. The grid layout (column count
   + gap) rides inline styles from the renderer so the same template
   handles 2-col and 3-col without forking CSS. */
.block-officer-roster { margin: 12px 0; }
.block-officer-roster-card {
  display: flex; flex-direction: column; gap: 4px;
  padding: 1.25rem 1.5rem;
  background: var(--panel, #fff);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.06);
  transition: transform 180ms ease, box-shadow 180ms ease;
}
.block-officer-roster-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 2px 4px rgba(0,0,0,0.06), 0 12px 24px rgba(0,0,0,0.10);
}
.block-officer-roster-card .block-officer-role {
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted);
}
.block-officer-roster-card .block-officer-name {
  font-size: 1.1rem; font-weight: 700;
}
.block-officer-roster-card .block-officer-phone,
.block-officer-roster-card .block-officer-email { font-size: 0.95rem; }
@media (max-width: 720px) {
  /* Collapse to a single column on narrow viewports so cards never
     squeeze too tight regardless of the admin's chosen column count. */
  .block-officer-roster {
    grid-template-columns: 1fr !important;
  }
}

.block-lottie { margin: 12px 0; }
/* `--lottie-ratio` is stamped by the public init script after the
   animation's `DOMLoaded` event fires, reading
   `animationData.w / animationData.h` from lottie-web. The `1 / 1`
   fallback covers the brief window before that lands so the stage
   has a definite size during the first paint instead of collapsing
   to zero height. */
.block-lottie-stage {
  width: 100%;
  aspect-ratio: var(--lottie-ratio, 1 / 1);
  display: block;
}
.block-lottie-stage > svg,
.block-lottie-stage > canvas { display: block; width: 100%; height: 100%; }
/* Hover playback mode — the `data-lottie-playback="hover"` attribute
   is the cue. `cursor: pointer` and a subtle scale on hover/tap nudge
   the user that the wrapper is interactive. */
.block-lottie-stage[data-lottie-playback="hover"] {
  cursor: pointer;
  transition: transform 220ms ease;
}
.block-lottie-stage[data-lottie-playback="hover"]:hover { transform: scale(1.02); }
.block-code { background: var(--code-bg, #0f1117); color: #e6e6e6; padding: 12px 14px;
  border-radius: 8px; overflow: auto; font-size: .92rem; }
.block-callout { display: flex; gap: 12px; padding: 12px 14px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel, var(--bg)); }
.block-callout .callout-icon { font-size: 1.4rem; flex-shrink: 0; }
.block-callout .callout-title { font-weight: 600; margin-bottom: 4px; }
.block-callout.callout-info { border-color: #3b82f6; background: rgba(59,130,246,.08); }
.block-callout.callout-warn { border-color: #f59e0b; background: rgba(245,158,11,.08); }
.block-callout.callout-danger { border-color: #ef4444; background: rgba(239,68,68,.08); }
.block-callout.callout-success { border-color: #10b981; background: rgba(16,185,129,.08); }
.block-separator { border: 0; border-top: 1px solid var(--border); margin: 24px 0; }

.wiki-layout { display: grid; grid-template-columns: minmax(0, 1fr) 240px; gap: 32px;
  align-items: start; }
.wiki-main { min-width: 0; }
.wiki-toc { position: sticky; top: 20px; border-left: 2px solid var(--border);
  padding: 4px 0 4px 16px; font-size: .9rem; }
.wiki-toc-label { text-transform: uppercase; letter-spacing: .06em; font-size: .75rem;
  color: var(--muted); margin-bottom: 8px; }
.wiki-toc ul { list-style: none; margin: 0; padding: 0; display: flex;
  flex-direction: column; gap: 4px; }
.wiki-toc a { color: var(--text); text-decoration: none; display: block;
  padding: 4px 0; border-radius: 4px; line-height: 1.3; }
.wiki-toc a:hover { color: var(--access); }
@media (max-width: 900px) {
  .wiki-layout { grid-template-columns: 1fr; }
  .wiki-toc { position: static; border-left: 0; border-top: 1px solid var(--border);
    padding: 12px 0 0; }
}

.template-toggle-row { display: flex; align-items: center; justify-content: space-between;
  gap: 16px; margin: 8px 0 4px; }
.template-toggle-label { display: flex; align-items: center; gap: 6px; font-size: .9rem;
  color: var(--muted); }

/* Block editor — visual hierarchy is modal-panel → section (panel-2,
   slightly tinted) → block (panel, clean elevated card) → block-head
   (panel-2, sub-zone tint). Same logical depth in both light and dark
   mode; the dark theme's panel/panel-2 deltas are subtle but readable. */
.be-root { display: flex; flex-direction: column; gap: 12px; }
.be-sections { display: flex; flex-direction: column; gap: 12px; }
.be-section { border: 1px solid var(--border); border-radius: 10px; padding: 12px;
  background: var(--panel-2); color: var(--text); }
.be-section-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.be-section-drag, .be-block-drag { cursor: grab; color: var(--muted); user-select: none;
  padding: 4px 6px; }
.be-section-title { flex: 1; font-size: 1rem; font-weight: 600;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px; padding: 6px 10px; }
.be-blocks { display: flex; flex-direction: column; gap: 8px; min-height: 8px;
  padding: 4px; border: 1px dashed transparent; border-radius: 6px; }
.be-blocks:empty { border-color: var(--border); padding: 16px; text-align: center;
  color: var(--muted); }
.be-blocks:empty::before { content: "Drop blocks here or use + below"; font-size: .85rem; }
.be-block { border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel); color: var(--text); }
.be-block-head { display: flex; align-items: center; gap: 8px; padding: 6px 8px;
  border-bottom: 1px solid var(--border); background: var(--panel-2); }
.be-block-type { font-size: .8rem; text-transform: uppercase; color: var(--muted);
  letter-spacing: .04em; flex: 1; }
.be-body { padding: 10px; display: flex; flex-direction: column; gap: 8px;
  color: var(--text); }
.be-body textarea, .be-body input[type=text], .be-body input[type=number],
.be-body select { width: 100%;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px; padding: 6px 10px; }
.be-body textarea { font: inherit; }
/* Inside a .be-row (flex container), inputs/selects sit side-by-side.
   The blanket width: 100% above would force every flex child to claim
   the full row, so we override here: select shrinks to content (with
   a sane min for short labels like "H2"), text/number inputs flex to
   fill the remaining space, and any tiny utility buttons keep their
   intrinsic size. */
.be-body .be-row > select { width: auto; flex: 0 0 auto; min-width: 80px; }
.be-body .be-row > input[type=text],
.be-body .be-row > input[type=number] { flex: 1 1 0; min-width: 0; }
.be-body label { display: flex; flex-direction: column; gap: 4px; font-size: .85rem;
  color: var(--muted); }
.be-row { display: flex; gap: 8px; align-items: center; }
.be-row input[type=text] { flex: 1; }
.be-preview { max-width: 200px; max-height: 140px; border-radius: 6px; margin-top: 6px; }
.be-add-block-bar { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.be-add-section { align-self: flex-start; }
.be-remove, .be-root .icon-btn { flex: 0 0 auto; width: 32px; height: 32px; }

.clamp-5 .clamp-body { display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical;
  overflow: hidden; }
.clamp-5.expanded .clamp-body { display: block; }
.clamp-toggle { background: none; border: 0; padding: 4px 0; cursor: pointer;
  font: inherit; color: var(--access); }
.clamp-toggle:hover { text-decoration: underline; }

.rich-content img, .rich-content video { max-width: 100%; height: auto; border-radius: 6px;
  margin: 12px 0; display: block; }
.rich-content figure { margin: 16px 0; }
.rich-content figcaption { color: var(--muted); font-size: .9rem; margin-top: 4px; }
.rich-content h2 { margin-top: 24px; }
.rich-content hr { margin: 24px 0; border: 0; border-top: 1px solid var(--border); }

.pic-contact { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.pic-row { display: flex; align-items: center; gap: 10px; }
.pic-row .pic-icon { width: 20px; display: inline-flex; justify-content: center;
  color: var(--muted); }


.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.pw-reveal { margin-left: 6px; }

.zoom-otp-card { width: 50%; margin-right: auto; }
@media (max-width: 720px) { .zoom-otp-card { width: 100%; } }

.notes-btn { padding: 0; border-radius: 50%; width: 24px; height: 24px; }
.notes-btn .icon { width: 16px; height: 16px; }
.notes-tip .help-tooltip { white-space: pre-wrap; }

.zoom-accounts-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(260px, 320px);
  gap: 24px; align-items: start; }
.zoom-accounts-main { min-width: 0; }
.zoom-accounts-side { min-width: 0; }
.zoom-otp-widget { padding: 14px 16px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel-2); }
.zoom-otp-title { margin: 0 0 4px; font-size: 1rem; font-weight: 600; }
.zoom-otp-widget .zoom-info { margin-top: 10px; }
@media (max-width: 900px) {
  .zoom-accounts-layout { grid-template-columns: 1fr; }
}

.users-new-card .form { gap: 12px; }
.users-new-card .users-new-row { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 12px; align-items: end; }
.users-new-card .users-new-row label { min-width: 0; }
.pic-form-row { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; align-items: end; }
.pic-form-row label { min-width: 0; }
@media (max-width: 720px) { .pic-form-row { grid-template-columns: 1fr; } }
.users-new-card .form-actions { justify-content: flex-end; margin-top: 4px; }
@media (max-width: 720px) {
  .users-new-card .users-new-row { grid-template-columns: 1fr 1fr; }
}

.zoom-cal-wrap { overflow-x: auto; }
.zoom-cal { width: 100%; border-collapse: collapse; min-width: 780px; }
.zoom-cal th, .zoom-cal td { border: 1px solid var(--border); padding: 6px; vertical-align: top;
  font-size: 0.7812rem; }
.zoom-cal thead th { background: var(--panel-2); color: var(--muted); font-size: 0.7188rem;
  text-transform: uppercase; letter-spacing: .4px; }
.zoom-cal .cal-acct { text-align: left; white-space: nowrap; background: var(--panel-2); }
.cal-slot { background: var(--brand-soft); border-left: 3px solid var(--brand);
  border-radius: 6px; padding: 5px 7px; margin-bottom: 4px; }
.cal-time { font-weight: 700; font-size: 0.7188rem; color: var(--brand); }
.cal-link { color: var(--text); font-size: 0.75rem; }
.cal-slot-conflict { background: #fee2e2; border-left-color: #dc2626; }
.cal-slot-conflict .cal-time { color: #b91c1c; }
.cal-slot-conflict .cal-link { color: #7f1d1d; }

@media (max-width: 700px) {
  .day-row { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; }
  .sidebar {
    position: fixed; left: 0; top: 0; width: 260px;
    height: 100dvh;
    transform: translateX(-100%); transition: transform .2s ease; z-index: 30;
    overflow: hidden;
  }
  /* Layout/scroll behavior is set in the base .sidebar rules above and
     applies at every viewport width; nothing extra needed here. */
  .sidebar.open { transform: translateX(0); }
  .menu-btn { display: grid; place-items: center; }
  .grid-2 { grid-template-columns: 1fr; }
  .stats { grid-template-columns: 1fr; }
  .form .row { grid-template-columns: 1fr; }
}

@media (max-width: 720px) {
  .hide-sm { display: none !important; }
  .tbl .mtype-chip { margin-left: 0; padding: 2px 8px; font-size: 0.6875rem; }
  .topbar h1 .mtype-chip { margin-left: auto; }

  .settings-tabs { padding: 0 12px; }
  .settings-tab { padding: 10px 12px; font-size: 0.9375rem; }

  .branding-row { flex-direction: column; align-items: stretch; }
  .branding-preview-wrap { width: 100%; }
  .settings-pane[data-pane="appearance"] .appearance-grid { padding: 16px 14px 20px; gap: 18px; }

  #settings-modal .modal-panel { width: calc(100vw - 2rem); max-width: calc(100vw - 2rem);
    margin: 1rem auto; height: calc(100vh - 2rem); max-height: calc(100vh - 2rem); }
  #settings-modal .settings-body { flex: 1 1 auto; height: auto; min-height: 0; }
  .zoom-info dd:has(> .btn-primary) { grid-column: 1 / -1; }
  .zoom-info dt:has(+ dd > .btn-primary) { display: none; }
  .zoom-info .btn-primary { display: block; width: 100%; text-align: center; }
  .card > .tbl,
  .card .tbl { display: block; overflow-x: auto; max-width: 100%; }
  .tbl th, .tbl td { padding: 10px 6px; font-size: 0.9375rem; white-space: normal; }
  .tbl .row-actions { flex-wrap: wrap; gap: 4px; justify-content: flex-end; }
  .tbl .row-actions .btn { padding: 4px 8px; font-size: 0.75rem; }

  .file-list li { align-items: center; gap: 8px; }
  .file-list li > .row-actions { flex: 1 1 100%; justify-content: flex-start; flex-wrap: wrap; gap: 6px; }
  .file-list li > .row-actions > .btn,
  .file-list li > .row-actions > form { flex: 1 1 0; min-width: 0; }
  .file-list li > .row-actions > form > .btn { width: 100%; }

  body.embed .embed-actions { flex-direction: column; align-items: stretch; }
  body.embed .embed-actions .btn,
  body.embed .embed-actions .btn-primary { width: 100%; justify-content: center; }

  .zoom-accounts-tbl { overflow-x: visible; }
  .zoom-accounts-tbl thead { display: none; }
  .zoom-accounts-tbl tbody, .zoom-accounts-tbl tr { display: block; }
  .zoom-accounts-tbl tr { padding: 12px 0; border-bottom: 2px solid var(--border); }
  .zoom-accounts-tbl td { display: block; border: none; padding: 4px 0; white-space: normal; }
  .zoom-accounts-tbl td[data-label]::before { content: attr(data-label); display: block;
    font-size: 0.75rem; font-weight: 600; color: var(--muted); text-transform: uppercase;
    letter-spacing: 0.04em; margin-bottom: 2px; }
  .zoom-accounts-tbl td.zoom-accounts-actions { padding-top: 10px; }
  .zoom-accounts-tbl td.zoom-accounts-actions .row-actions { justify-content: flex-start; flex-wrap: wrap; }
  .zoom-accounts-tbl td.zoom-accounts-actions .row-actions .btn { flex: 1 1 auto; }

  .locations-tbl { overflow-x: visible; }
  .locations-tbl thead { display: none; }
  .locations-tbl tbody, .locations-tbl tr { display: block; }
  .locations-tbl tr { padding: 12px 0; border-bottom: 2px solid var(--border); }
  .locations-tbl td { display: block; border: none; padding: 4px 0; white-space: normal; }
  .locations-tbl td[data-label]::before { content: attr(data-label); display: block;
    font-size: 0.75rem; font-weight: 600; color: var(--muted); text-transform: uppercase;
    letter-spacing: 0.04em; margin-bottom: 2px; }
  .locations-tbl td.locations-actions { padding-top: 10px; }
  .locations-tbl td.locations-actions .row-actions { justify-content: flex-start; }
  .locations-tbl td.locations-actions .row-actions .btn { flex: 1 1 auto; }
  .loc-csz-row { grid-template-columns: 1fr 1fr 1fr; }
}

/* City / state / ZIP grid inside the Location create / edit modals.
   Three side-by-side fields on desktop; collapses to a single column
   below 480px in the mobile rule above. */
.loc-csz-row {
  display: grid; gap: 8px 12px;
  grid-template-columns: 2fr 1fr 1fr;
  margin-top: 8px;
}
.loc-csz-row label { display: flex; flex-direction: column; }
@media (max-width: 480px) {
  .loc-csz-row { grid-template-columns: 1fr; }

  .users-tbl { overflow-x: visible; }
  .users-tbl thead { display: none; }
  .users-tbl tbody, .users-tbl tr { display: block; }
  .users-tbl tr { padding: 12px 0; border-bottom: 2px solid var(--border); }
  .users-tbl td { display: block; border: none; padding: 4px 0; }
  .users-tbl td[data-label]::before { content: attr(data-label); display: block;
    font-size: 0.75rem; font-weight: 600; color: var(--muted); text-transform: uppercase;
    letter-spacing: 0.04em; margin-bottom: 2px; }
  .users-tbl td select,
  .users-tbl td input { width: 100%; box-sizing: border-box; }
  .users-tbl td.users-actions { padding-top: 10px; }
  .users-tbl td.users-actions .users-actions-row { display: flex; gap: 8px; }
  .users-tbl td.users-actions .users-actions-row > .btn,
  .users-tbl td.users-actions .users-actions-row > form { flex: 1 1 0; }
  .users-tbl td.users-actions .users-actions-row > form .btn { width: 100%; }

  .media-tbl { overflow-x: visible; }
  .media-tbl thead { display: none; }
  .media-tbl tbody, .media-tbl tr { display: block; }
  .media-tbl tr { padding: 10px 4px; border-bottom: 2px solid var(--border); }
  .media-tbl td { display: inline-block; border: none; padding: 2px 8px 2px 0; vertical-align: middle; }
  .media-tbl td.media-thumb-cell { float: left; width: 56px; padding: 0 10px 0 0; }
  .media-tbl td.media-name-cell { display: block; padding: 0 0 6px; font-weight: 500; }
  .media-tbl td.row-actions { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 0 0;
    justify-content: space-between; width: 100%; }
  .media-tbl td.row-actions > .btn,
  .media-tbl td.row-actions > form { flex: 1 1 0; min-width: 0; }
  .media-tbl td.row-actions > form > .btn { width: 100%; }
  .content { padding: 14px 14px 32px; }
  .card { padding: 16px; }
  .stat { padding: 16px; }
  .topbar { flex-wrap: wrap; gap: 10px; }
  .topbar h1 { flex: 1 1 auto; min-width: 0; font-size: 1.125rem; }
  .top-actions { flex: 0 0 100%; order: 2; flex-wrap: wrap; gap: 8px; justify-content: flex-start; }
  .top-actions > .btn,
  .top-actions > .btn-primary { flex: 1 1 auto; min-width: 140px; justify-content: center; }
  .view-controls { width: 100%; margin-right: 0; flex-wrap: wrap; gap: 8px; }
  .view-controls > .view-toggle { flex: 1 1 auto; min-width: 0; }
  .view-toggle .btn { flex: 1 1 0; min-width: 0; padding: 7px 10px; text-align: center; }
  .sort-select { flex: 1 1 140px; min-width: 0; }
  .sort-select select { flex: 1; min-width: 0; }
  .sort-dir { flex: 0 0 auto; }
  .heading-help { display: none; }
  .media-search { flex-wrap: wrap; }
}

.dash-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
.dash-widget { position: relative; min-width: 0; }
.dash-widget > .card, .dash-widget > .stats { margin: 0; }
.dash-widget-wide { grid-column: 1 / -1; }
.dash-widget[draggable="true"] { transition: transform 120ms ease, opacity 120ms ease; }
.dash-widget.dragging { opacity: 0.4; }
.dash-widget.drag-over > .card,
.dash-widget.drag-over > .stats { outline: 2px dashed var(--brand); outline-offset: 4px; }
.dash-drag-handle { position: absolute; top: 10px; right: 12px; z-index: 2;
  cursor: grab; color: var(--muted); line-height: 1;
  user-select: none; padding: 4px 6px; opacity: 0.55; transition: opacity 120ms ease;
  border-radius: 6px; display: inline-flex; align-items: center; }
.dash-widget[draggable="true"]:hover > .dash-drag-handle { opacity: 1; }
.dash-drag-handle .icon { font-size: 1.15rem; }
.dash-drag-handle:hover { background: var(--panel-2); color: var(--text); }
.dash-drag-handle:active { cursor: grabbing; }
@media (max-width: 720px) {
  .dash-grid { grid-template-columns: 1fr; }
  .dash-widget-wide { grid-column: auto; }
  .dash-drag-handle { opacity: 1; }
}

.server-metrics .card-head { align-items: baseline; }
.server-metrics-os { text-align: right; }
.server-metrics-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 4px; }
.server-metrics-grid-5 { grid-template-columns: repeat(5, 1fr); }
.metric-tile { display: flex; flex-direction: column; gap: 4px; padding: 14px 16px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--panel-2); min-width: 0; }
a.metric-tile-link { text-decoration: none; color: inherit; cursor: pointer;
  transition: border-color 140ms ease, background 140ms ease, transform 140ms ease; }
a.metric-tile-link:hover { border-color: var(--brand);
  background: color-mix(in srgb, var(--brand) 8%, var(--panel-2)); }
a.metric-tile-link:active { transform: translateY(1px); }
a.metric-tile-link .metric-value { color: var(--brand); }
.metric-label { font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted); }
.metric-value { font-size: 1.75rem; font-weight: 700; color: var(--text); line-height: 1.1;
  display: flex; align-items: baseline; gap: 2px; }
.metric-value-sm { font-size: 1.125rem; font-weight: 600; }
.metric-unit { font-size: 0.875rem; font-weight: 500; color: var(--muted); margin-left: 2px; }
.metric-sub { margin-top: 2px; }
.metric-spark { width: 100%; height: 40px; margin-top: 6px; display: block; }
.metric-tile-text { justify-content: center; }
@media (max-width: 960px) {
  .server-metrics-grid-5 { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 720px) {
  .server-metrics-grid,
  .server-metrics-grid-5 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 520px) {
  .server-metrics-grid,
  .server-metrics-grid-5 { grid-template-columns: 1fr; }
}

/* ===== First-run setup wizard ===== */
body.setup-body { margin: 0; min-height: 100vh; background: var(--bg);
  background-image: radial-gradient(ellipse at top, var(--brand-soft) 0%, transparent 45%),
                    linear-gradient(160deg, var(--bg) 40%, var(--brand-soft) 120%);
  display: grid; place-items: center; padding: 24px; }
.setup-shell { width: 100%; max-width: 560px; }
.setup-card { background: var(--panel); border: 1px solid var(--border); border-radius: 18px;
  padding: 32px; box-shadow: 0 20px 60px rgba(17,24,39,0.18), 0 4px 12px rgba(17,24,39,0.06);
  display: flex; flex-direction: column; gap: 18px; animation: setup-card-in 360ms cubic-bezier(0.2,0.8,0.2,1) both; }
@keyframes setup-card-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
.setup-head { display: flex; flex-direction: column; gap: 10px; }
.setup-brand { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.setup-logo { height: 38px; width: auto; }
.setup-brand-tag { font-size: 0.7rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted); }
.setup-progress { display: flex; gap: 6px; }
.setup-dot { flex: 1; height: 4px; border-radius: 2px; background: var(--border); transition: background 180ms ease; }
.setup-dot.done { background: var(--brand-2); }
.setup-dot.active { background: var(--brand); }
.setup-step-count { font-size: 0.7rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--brand); margin-top: 6px; }
.setup-title { font-size: 1.5rem; font-weight: 700; line-height: 1.2; margin: 2px 0 0; }
.setup-desc { color: var(--muted); font-size: 0.9375rem; line-height: 1.5; max-width: 52ch; margin: 0; }
.setup-error { background: #fdecec; color: #7f1d1d; border: 1px solid #f3b9bb; border-left: 3px solid #dc2626;
  border-radius: 8px; padding: 10px 14px; font-size: 0.875rem; }
[data-theme="dark"] .setup-error { background: #381416; color: #fbb; border-color: #642325; }

.setup-form { display: flex; flex-direction: column; gap: 14px; }
.setup-form label { display: flex; flex-direction: column; gap: 6px; font-size: 0.875rem; font-weight: 600; color: var(--text); }
.setup-form label.check { flex-direction: row; align-items: center; gap: 8px; font-weight: 400; }
.setup-form label.check input { width: auto; margin: 0; accent-color: var(--brand); }
.setup-form input[type="text"], .setup-form input[type="password"], .setup-form input[type="email"],
.setup-form input[type="tel"], .setup-form input[type="url"], .setup-form input[type="number"],
.setup-form select { padding: 10px 12px; border-radius: 10px; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--text); font-size: 0.9375rem; font-family: inherit;
  transition: border-color 120ms ease, box-shadow 120ms ease; }
.setup-form input[type="file"] { padding: 8px 0; font-size: 0.8125rem; }
.setup-form input:focus, .setup-form select:focus { outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft); }
.setup-form .row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 520px) { .setup-form .row { grid-template-columns: 1fr; } }

/* Password strength */
.setup-pw-meter { display: flex; flex-direction: column; gap: 6px; margin-top: -6px; }
.setup-pw-bar { height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; }
.setup-pw-fill { display: block; height: 100%; width: 0; background: var(--brand); transition: width 160ms ease, background 160ms ease; border-radius: 3px; }
.setup-pw-fill[data-level="1"] { background: #dc2626; }
.setup-pw-fill[data-level="2"] { background: #f59e0b; }
.setup-pw-fill[data-level="3"] { background: #10b981; }
.setup-pw-fill[data-level="4"] { background: #059669; }
.setup-pw-label { font-size: 0.75rem; }
.setup-pw-rules { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 3px; font-size: 0.8125rem; }
.setup-pw-rules li { position: relative; padding-left: 20px; }
.setup-pw-rules li::before { content: "○"; position: absolute; left: 0; color: var(--muted); font-size: 0.875rem; top: -1px; }
.setup-pw-rules li.ok { color: var(--success); }
.setup-pw-rules li.ok::before { content: "✓"; color: var(--success); font-weight: 700; }

/* Theme picker sits a bit denser in the wizard */
.setup-form .theme-picker { grid-template-columns: repeat(3, 1fr); gap: 10px; }
@media (max-width: 520px) { .setup-form .theme-picker { grid-template-columns: repeat(2, 1fr); } }

.setup-logo-preview { display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  padding: 12px; background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px;
  align-self: flex-start; }
.setup-logo-preview img { max-height: 80px; height: auto; border-radius: 6px; }

.setup-actions { display: flex; align-items: center; justify-content: flex-end; gap: 10px; margin-top: 6px; }
.setup-skip { background: transparent; border-color: transparent; color: var(--muted); }
.setup-skip:hover { background: var(--panel-2); color: var(--text); }
.setup-next { padding: 10px 22px; font-size: 0.9375rem; }

.setup-footer { text-align: center; margin-top: 4px; }

@media (max-width: 520px) {
  body.setup-body { padding: 12px; }
  .setup-card { padding: 22px; border-radius: 14px; }
  .setup-title { font-size: 1.25rem; }
}

/* Floating "update available" banner — pinned bottom-right. Shown when the
   version watcher detects the deployed bundle has moved past the one this
   page was loaded with. Persistent until Reload or Later. */
.version-update-banner {
  position: fixed;
  right: 20px; bottom: 20px;
  max-width: calc(100vw - 40px);
  width: 360px;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
  box-shadow: 0 12px 32px -8px rgba(17,24,39,.28), 0 4px 10px -2px rgba(17,24,39,.12);
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 10px;
  /* Pinned to the top of the stacking order — must beat the floating
     block palette (1000), modals (100), wp-fetch overlay (9999), and
     any future floating UI. The "Update available" toast is the
     highest-priority interruption: a stale bundle is now in front of
     the admin and we need them to see it regardless of what else
     they have open. Max signed 32-bit int = the CSS z-index ceiling. */
  z-index: 2147483647;
  animation: tspVersionBannerIn .28s cubic-bezier(.4,0,.2,1);
}
@keyframes tspVersionBannerIn {
  from { opacity: 0; transform: translateY(12px) scale(.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.version-update-banner-title {
  font-size: .9rem; font-weight: 600; margin-bottom: 2px;
}
.version-update-banner-sub {
  font-size: .8rem; color: var(--muted); line-height: 1.4;
}
.version-update-banner-actions {
  display: flex; gap: 6px; justify-content: flex-end;
}
@media (max-width: 640px) {
  .version-update-banner { right: 12px; bottom: 12px; width: calc(100vw - 24px); }
}

/* ── ICON PICKER (mega-menu link fields) ─────────────────────────────── */
.nav-megalink-icon-field { min-width: 0; }
.icon-picker-trigger-wrap {
  display: inline-flex; align-items: stretch; gap: 4px;
}
.icon-picker-trigger {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-width: 72px; height: 36px; padding: 0 12px;
  background: var(--panel-2);
  border: 1px solid var(--border); border-radius: 8px;
  color: var(--text); font: inherit; cursor: pointer;
}
.icon-picker-trigger:hover { background: var(--brand-soft); }
.icon-picker-preview {
  display: none; align-items: center; justify-content: center;
  --icon-size: 20px;
}
.icon-picker-preview .icon { width: var(--icon-size); height: var(--icon-size); }
.icon-picker-preview .icon-custom { object-fit: contain; }
.icon-picker-trigger-empty {
  font-size: .9rem; color: var(--muted);
}
.nav-megalink-icon-field.has-icon .icon-picker-preview { display: inline-flex; }
.nav-megalink-icon-field.has-icon .icon-picker-trigger-empty { display: none; }
.icon-picker-clear {
  display: none; align-items: center; justify-content: center;
  flex: 0 0 auto; width: 32px; height: 36px; border: 1px solid transparent;
  background: transparent; color: var(--muted);
  border-radius: 8px; cursor: pointer;
}
.nav-megalink-icon-field.has-icon .icon-picker-clear { display: inline-flex; }
.icon-picker-clear:hover {
  background: color-mix(in srgb, var(--text) 6%, transparent);
  border-color: var(--border); color: var(--text);
}
.icon-picker-clear .icon { width: 14px; height: 14px; }

/* ── ICON PICKER MODAL ──────────────────────────────────────────────── */
/* The picker is opened from inside other modals (features card editor,
   hero CTA editor, nav megamenu link editor, etc.), so it has to stack
   above the standard `.modal` (z-index 100). Sits below the dynbg
   picker (max-int z-index) and the toast host so important transient
   UI stays visible if both are active. */
.icon-picker-modal { z-index: 200; }
.icon-picker-modal .modal-panel {
  width: min(760px, 94vw); max-height: 86vh; display: flex; flex-direction: column;
}
.icon-picker-body {
  display: flex; flex-direction: column; gap: 12px; min-height: 0;
  padding: 12px 16px 4px;
}
.icon-picker-toolbar {
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
}
.icon-picker-search {
  flex: 1 1 260px; min-width: 0; padding: 8px 12px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel-2); color: var(--text); font: inherit;
}
.icon-picker-size-label {
  display: inline-flex; align-items: center; gap: 8px;
  flex: 0 0 auto;
}
.icon-picker-size-label input[type="range"] {
  width: 140px; accent-color: var(--access, #4f46e5);
}
.mega-animate-speed-row { margin: 10px 0 14px; }
.mega-animate-speed-label { display: block; }
.mega-animate-speed-head {
  display: flex; align-items: baseline; gap: 6px;
  font-weight: 600; font-size: 0.875rem; margin-bottom: 6px;
}
.mega-animate-speed-head output { font-variant-numeric: tabular-nums; color: var(--brand); }
.mega-animate-speed-row input[type="range"] {
  width: 100%; max-width: 420px; accent-color: var(--access, var(--brand));
}
.hero-heading-opts, .hero-bg-grid {
  display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: flex-start;
  justify-content: flex-start; margin-top: 12px;
}

/* Two-column hero builder: text + font on the left, background + CTA buttons
   on the right. The form uses display: contents so its inner cols become
   direct grid items of .hero-section-grid alongside the buttons col. */
.hero-section-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 24px 32px; align-items: start; margin-top: 8px;
}
.hero-grid-form { display: contents; }
.hero-text-col    { grid-column: 1; grid-row: 1 / span 2; min-width: 0; }
.hero-bg-col      { grid-column: 2; grid-row: 1; min-width: 0; }
.hero-buttons-col { grid-column: 2; grid-row: 2; min-width: 0; }
/* The shared .fe-tbl-scroll has a 720px min-width to force horizontal
   scroll on narrow tables. In the hero-builder right column there's no
   room for that, so we let the table fit the column. */
.hero-buttons-col .fe-tbl-scroll { overflow: visible; max-width: 100%; }
.hero-buttons-col .fe-tbl-scroll .tbl { min-width: 0; }
.hero-buttons-col .fe-tbl-scroll .tbl .row-actions { flex-wrap: wrap; gap: 4px; }
@media (max-width: 980px) {
  .hero-section-grid { grid-template-columns: 1fr; gap: 18px; }
  .hero-text-col, .hero-bg-col, .hero-buttons-col {
    grid-column: 1; grid-row: auto;
  }
}

.hero-unified .hero-sub-heading {
  display: flex; align-items: center; gap: 10px;
  font-size: 0.82rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted);
  margin: 22px 0 8px; padding-top: 18px;
  border-top: 1px solid var(--border);
}
.hero-unified > form:first-of-type > .hero-sub-heading:first-of-type,
.hero-unified > .hero-sub-heading:first-of-type {
  margin-top: 8px; padding-top: 0; border-top: 0;
}
.hero-unified .hero-sub-add { margin-left: auto; }
.hero-unified .hero-sub-help { margin: 0 0 10px; }
.hero-unified-actions { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border); }

/* ── Per-page hero edit modal (#page-hero-edit-modal) ──────────────
   The homepage hero modal wraps its inputs in `<form class="form">`
   and inherits `.form label { display: flex; flex-direction: column;
   gap: 6px }` for clean label-above-input stacking. The per-page
   hero modal swaps the form for a plain `<div class="hero-grid-form">`
   (no nested form allowed because the values save with the parent
   page-edit form), so the `.form label` rule never matches and
   labels fall back to inline layout — text and input collide on the
   same baseline. These scoped rules restore the clean stack and
   pin the live-preview's text alignment + max-width so it mirrors
   the public render. Direct-child selector `>` keeps `.mode-toggle`
   labels (rows with a toggle switch) untouched so they keep their
   horizontal layout. */
#page-hero-edit-modal .hero-text-col > label,
#page-hero-edit-modal .hero-bg-col > label,
#page-hero-edit-modal .hero-bg-panel > label,
#page-hero-edit-modal .hero-buttons-col > label {
  display: flex; flex-direction: column; gap: 6px;
  font-size: 0.95rem; font-weight: 600; color: var(--text);
  margin: 0 0 14px;
}
#page-hero-edit-modal .hero-text-col > label > input[type="text"],
#page-hero-edit-modal .hero-text-col > label > input[type="number"],
#page-hero-edit-modal .hero-text-col > label > textarea,
#page-hero-edit-modal .hero-bg-col > label > input[type="text"],
#page-hero-edit-modal .hero-bg-panel > label > input[type="text"],
#page-hero-edit-modal .hero-bg-panel > label > input[type="file"] {
  font-weight: 400;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 12px;
  font: inherit;
}
#page-hero-edit-modal .hero-text-col > label > textarea {
  resize: vertical;
  min-height: 120px;
}
/* Live preview — force the inner content to center horizontally
   and respect the homepage's 820px max so the admin sees the same
   layout the public renderer produces. `!important` defeats any
   admin-context cascade that might otherwise reset text-align. */
#page-hero-edit-modal .hero-full-preview .fe-hero-inner {
  text-align: center !important;
  max-width: 820px !important;
  margin-left: auto !important;
  margin-right: auto !important;
  width: 100%;
}
#page-hero-edit-modal .hero-full-preview .fe-hero-heading,
#page-hero-edit-modal .hero-full-preview .fe-hero-sub,
#page-hero-edit-modal .hero-full-preview .fe-hero-eyebrow {
  text-align: center !important;
}
#page-hero-edit-modal .hero-full-preview .fe-hero-cta {
  justify-content: center !important;
}

/* ── Per-page hero button list editor ─────────────────────────────
   Replaces the inline-styled bordered boxes with a card-style row
   that reads like the rest of the admin UI. The row's header is a
   compact bar (numbered chip + live-updated button name + reorder /
   remove icon-buttons); the body is a 2-column grid with proper
   field labels above each control; advanced icon + custom-colour
   fields live in a collapsed `<details>` so the row stays compact
   for the common case (just Label + URL + Style + new-tab). */
.be-hero-buttons-empty {
  margin: 0; padding: 18px;
  border: 1px dashed var(--border);
  border-radius: 10px;
  text-align: center;
}
.be-hero-button-row {
  display: grid; gap: 12px;
  margin-bottom: 10px; padding: 14px 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.be-hero-button-head {
  display: flex; align-items: center; gap: 10px;
  margin: -2px 0 2px;
}
.be-hero-button-idx {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px;
  border-radius: 999px;
  background: var(--brand-soft, color-mix(in srgb, var(--brand, #5164ff) 14%, transparent));
  color: var(--brand, #5164ff);
  font-size: 0.78rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.be-hero-button-name {
  flex: 1 1 auto; min-width: 0;
  font-weight: 600; font-size: 0.95rem;
  color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.be-hero-button-head-actions {
  flex: 0 0 auto;
  display: inline-flex; gap: 4px;
}
.be-hero-button-head-actions .icon-btn {
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 6px; border: 1px solid transparent;
  background: transparent; color: var(--muted);
  font-size: 0.95rem; line-height: 1;
  cursor: pointer; transition: background 120ms, color 120ms, border-color 120ms;
}
.be-hero-button-head-actions .icon-btn:hover {
  background: var(--panel-2); color: var(--text);
  border-color: var(--border);
}
.be-hero-button-head-actions .be-hero-button-remove:hover {
  background: color-mix(in srgb, #ef4444 10%, transparent);
  color: #b91c1c;
  border-color: color-mix(in srgb, #ef4444 30%, transparent);
}
.be-hero-button-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  gap: 12px;
}
.be-hero-button-grid--opts {
  align-items: end;
}
.be-hero-button-field {
  display: flex; flex-direction: column; gap: 4px;
  min-width: 0;
  font-size: 0.875rem; font-weight: 600; color: var(--text);
}
.be-hero-button-field-lbl {
  font-size: 0.72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted);
}
.be-hero-button-field input[type="text"],
.be-hero-button-field input[type="number"],
.be-hero-button-field select {
  width: 100%;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 7px 10px;
  font: inherit; font-weight: 400;
  color: var(--text);
}
.be-hero-button-field input[type="text"]:focus,
.be-hero-button-field input[type="number"]:focus,
.be-hero-button-field select:focus {
  outline: 0;
  border-color: var(--brand, #5164ff);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand, #5164ff) 18%, transparent);
}
.be-hero-button-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 0.9rem; font-weight: 500; color: var(--text);
  cursor: pointer;
  align-self: end;
  padding-bottom: 4px;
}
.be-hero-button-toggle input[type="checkbox"] {
  width: 16px; height: 16px;
  accent-color: var(--brand, #5164ff);
  cursor: pointer;
}

/* Icon-picker trigger inside the hero button advanced grid. Uses the
   shared `.icon-picker-trigger` markup from the global picker so it
   inherits the same hover state, just with a tighter footprint that
   suits the dense advanced grid (vs the larger feature-card trigger). */
.be-hero-button-icon-field {
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
}
.be-hero-button-icon-row {
  display: inline-flex; align-items: stretch; gap: 6px;
}
.be-hero-button-icon-trigger {
  flex: 1 1 auto;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 36px; padding: 0 12px;
  background: var(--panel-2);
  border: 1px dashed var(--border); border-radius: 8px;
  color: var(--muted); font: inherit; cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}
.be-hero-button-icon-trigger:hover {
  background: var(--panel); border-color: var(--brand, var(--border)); color: var(--text);
}
.be-hero-button-icon-trigger .icon-picker-preview { display: none; }
.be-hero-button-icon-trigger .icon-picker-preview .icon { width: 20px; height: 20px; }
.be-hero-button-icon-field.has-icon .be-hero-button-icon-trigger {
  border-style: solid; color: var(--text);
}
.be-hero-button-icon-field.has-icon .icon-picker-preview { display: inline-flex; }
.be-hero-button-icon-field.has-icon .icon-picker-trigger-empty { display: none; }
.be-hero-button-icon-clear { display: none; }
.be-hero-button-icon-field.has-icon .be-hero-button-icon-clear {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto; width: 32px; min-height: 36px;
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 8px; cursor: pointer;
  font-size: 1rem;
}
.be-hero-button-icon-field.has-icon .be-hero-button-icon-clear:hover {
  background: color-mix(in srgb, var(--text) 6%, transparent);
  color: var(--text);
}

/* Color cluster: editable hex text + native swatch + auto-attached
   🎨 token-palette button + read-only hex caption + matched-token
   chip. The auto-attach (see _design_token_picker.html) inserts its
   chrome immediately after the swatch, so order on screen is
   `hex text` | `swatch` | `🎨` | `caption` | `chip`. */
.be-hero-button-color-field {
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
}
.be-hero-button-color-cluster {
  display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.be-hero-button-color-text {
  flex: 1 1 110px; min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  text-transform: lowercase;
}
.be-hero-button-color-swatch {
  flex: 0 0 auto;
  width: 36px; height: 36px;
  padding: 2px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel); cursor: pointer;
}
/* Native colour swatch: strip the default chrome inside so the swatch
   reads as a clean tile sized by our outer 36px box. */
.be-hero-button-color-swatch::-webkit-color-swatch-wrapper { padding: 0; }
.be-hero-button-color-swatch::-webkit-color-swatch { border: 0; border-radius: 6px; }
.be-hero-button-color-swatch::-moz-color-swatch { border: 0; border-radius: 6px; }
.be-hero-button-advanced {
  border-top: 1px dashed var(--border);
  padding-top: 12px; margin-top: 2px;
}
.be-hero-button-advanced > summary {
  cursor: pointer; padding: 2px 0;
  text-transform: uppercase; letter-spacing: .06em;
  font-size: 0.72rem; font-weight: 700;
}
.be-hero-button-advanced > summary:hover { color: var(--text); }
.be-hero-button-advanced[open] > summary { margin-bottom: 10px; }
.hero-full-preview-clip {
  position: relative;
  height: 400px;
  margin: 6px 0 18px;
  border: 1px dashed var(--border); border-radius: 12px;
  background: var(--panel-2);
  overflow: hidden;
}
.hero-full-preview-label {
  position: absolute; top: 8px; left: 12px; z-index: 2;
  margin: 0; padding: 2px 8px; border-radius: 4px;
  background: color-mix(in srgb, var(--panel) 85%, transparent);
  font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
}
.hero-full-preview {
  /* The outer wrapper fills the clip 1:1 — that's what lets the hero
     background (frosty blobs / solid / gradient / image) span the full
     width of the 320px frame. Only the content inside (.fe-hero-inner)
     gets dynamically scaled to contain-fit, decoupled from the bg. */
  position: absolute; inset: 0;
  pointer-events: none;
  user-select: none;
}
.hero-full-preview.frontend-body {
  background: transparent;
}
/* The inner section fills the wrapper; vertical centering brings the
   .fe-hero-inner content to the middle of the clip regardless of its
   scaled height. Padding is zeroed out because the JS-scaled inner box
   already sets its own visual size relative to the 320px clip. */
.hero-full-preview .fe-hero {
  width: 100%; height: 100%;
  padding: 0 !important;
  display: flex; align-items: center; justify-content: center;
}
.hero-full-preview .fe-hero-inner {
  transform-origin: center center;
}
.hero-slider-field { min-width: 220px; }
.hero-slider-field input[type="range"] {
  width: 100%; accent-color: var(--access, var(--brand));
}
.hero-bg-panel + .hero-bg-panel { margin-top: 12px; }
.hero-bg-panel { margin-top: 16px; }
.hero-bg-image-preview {
  display: flex; align-items: center; gap: 14px; padding: 12px;
  border: 1px solid var(--border); border-radius: 10px; margin-bottom: 8px;
  background: var(--panel-2);
}
.hero-bg-image-preview img {
  max-width: 140px; max-height: 80px; border-radius: 6px; object-fit: cover;
}
.hero-reset-field { min-width: 200px; }
/* Horizontal reset-checkbox row used under the gradient color pickers. */
.hero-reset-row {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 0.85rem; color: var(--muted);
  cursor: pointer; padding-top: 18px;  /* aligns vertically with color pickers */
}
.hero-reset-row input { accent-color: var(--brand); margin: 0; }
.hero-heading-grad-row { margin-top: 12px; }

/* Hero typography card — two side-by-side groups (Heading and
   Subheading) on desktop; stacks into a single column on phones. The
   grid uses `auto-fit` + a min track width so the layout doesn't
   need a media query — when the available width drops below ~340px
   per column, both groups collapse to a single track. Each
   <fieldset> carries its own title via <legend>, indented border
   for visual nesting, and per-row reset checkbox. */
.hero-typo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: 16px;
  margin-top: 16px;
}
.hero-typo-group {
  margin: 0; padding: 14px 16px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2, var(--panel));
  display: flex; flex-direction: column; gap: 12px;
  min-width: 0;
}
.hero-typo-group > legend {
  padding: 0 6px; margin-left: -6px;
  font-size: .78rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted);
}
.hero-typo-color-row {
  display: flex; flex-wrap: wrap; gap: 12px;
  align-items: end;
}
/* The reset row inside a typography group sits flush-left with no
   top padding, parallel to the group's other vertical-rhythm items. */
.hero-typo-group .hero-reset-row {
  padding-top: 0;
}
/* On phones / tight admin embeds the segmented font-family pillgroup
   was overflowing; forcing flex-wrap keeps each pill on its own line
   when there isn't room. */
@media (max-width: 540px) {
  .hero-typo-group .nav-megalink-seg { flex-wrap: wrap; }
  .hero-typo-group .nav-megalink-seg-opt { flex: 1 1 auto; }
}
.icon-picker-upload-btn {
  cursor: pointer; white-space: nowrap;
}
.icon-picker-upload-btn .icon { width: 14px; height: 14px; }
.icon-picker-catalog {
  overflow-y: auto; flex: 1 1 auto;
  padding: 4px; border: 1px solid var(--border); border-radius: 10px;
  background: color-mix(in srgb, var(--text) 3%, transparent);
  max-height: 52vh;
}
.icon-picker-group + .icon-picker-group { margin-top: 12px; }
.icon-picker-group-title {
  font-size: .75rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); padding: 10px 10px 6px;
}
.icon-picker-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(86px, 1fr));
  gap: 6px; padding: 0 6px 6px;
}
.icon-picker-cell {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 10px 6px;
  background: var(--panel-2); border: 1px solid transparent;
  border-radius: 8px; cursor: pointer; min-height: 72px;
  color: inherit; position: relative;
}
.icon-picker-cell:hover {
  border-color: var(--border); background: var(--brand-soft);
}
.icon-picker-cell.is-selected {
  border-color: var(--brand); background: var(--brand-soft);
  box-shadow: inset 0 0 0 1px var(--brand);
}
.icon-picker-cell .icon { width: var(--icon-size, 22px); height: var(--icon-size, 22px); }
.icon-picker-cell .icon-custom { object-fit: contain; }
.icon-picker-cell.is-custom { cursor: pointer; }
.icon-picker-cell-del {
  position: absolute; top: 2px; right: 2px;
  width: 18px; height: 18px; padding: 0; line-height: 16px;
  border: 0; border-radius: 50%;
  background: var(--danger, #dc2626); color: white;
  font-size: 14px; cursor: pointer;
  opacity: 0; transition: opacity 120ms ease;
}
.icon-picker-cell.is-custom:hover .icon-picker-cell-del { opacity: 1; }
.icon-picker-cell-label {
  font-size: .7rem; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 100%;
}
.icon-picker-attribution { padding: 0 4px 4px; margin: 0; }

/* ===========================================================================
   Templates admin — card grid for picking reusable entity-detail templates
   (Meeting Detail, Event Detail). Each card has a CSS-drawn thumbnail
   that hints at the template's character.
   =========================================================================== */
.fe-tplgrid-section { margin-top: 16px; }
.fe-tplgrid-intro { margin: 0; line-height: 1.55; }
.fe-tplgrid-form { display: flex; flex-direction: column; gap: 16px; }
.fe-tplgrid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.fe-tplgrid-card {
  position: relative; display: flex; flex-direction: column; gap: 10px;
  padding: 14px; border: 2px solid var(--border); border-radius: 12px;
  background: var(--panel); cursor: pointer;
  transition: border-color 140ms ease, transform 140ms ease, box-shadow 140ms ease;
}
.fe-tplgrid-card:hover {
  border-color: var(--access); transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08);
}
.fe-tplgrid-card.active { border-color: var(--brand); background: var(--brand-soft); }
.fe-tplgrid-card input[type="radio"] { position: absolute; width: 0; height: 0; opacity: 0; }
.fe-tplgrid-info { display: flex; flex-direction: column; gap: 4px; }
.fe-tplgrid-name {
  display: flex; align-items: center; gap: 8px; font-weight: 600;
  font-size: 0.95rem; color: var(--text);
}
.fe-tplgrid-badge {
  display: none; padding: 1px 8px; border-radius: 999px;
  background: var(--brand); color: #fff; font-size: 0.7rem; font-weight: 600;
  letter-spacing: 0.04em;
}
.fe-tplgrid-card.active .fe-tplgrid-badge { display: inline-flex; }
.fe-tplgrid-desc { line-height: 1.5; }

/* Thumbnail mockups — pure-CSS visual hints, ~140px tall. Each combination
   of (kind + key) is rendered as small layered <span>s positioned to
   suggest the template's structure without literally rendering the
   template. */
.fe-tplgrid-thumb {
  position: relative; height: 140px; border-radius: 8px;
  background: linear-gradient(180deg, #f8fafc 0%, #eef2f7 100%);
  border: 1px solid var(--border); overflow: hidden;
}
.fe-tplgrid-thumb > span {
  position: absolute; background: #cbd5e1; border-radius: 2px;
}
.fe-tplgrid-thumb .t-bar { left: 8px; right: 8px; top: 6px; height: 5px; background: #e2e8f0; border-radius: 999px; }
.fe-tplgrid-thumb .t-h { left: 16px; top: 18px; width: 60%; height: 11px; background: #475569; border-radius: 3px; }
.fe-tplgrid-thumb .t-h-big { left: 50%; transform: translateX(-50%); top: 28px; width: 78%; height: 14px;
  background: #1e293b; border-radius: 3px; }
.fe-tplgrid-thumb .t-h-big.centered { left: 11%; transform: none; }
.fe-tplgrid-thumb .t-rule { left: 16px; right: 16px; top: 36px; height: 1px; background: #94a3b8; border-radius: 0; }
.fe-tplgrid-thumb .t-eyebrow { left: 16px; top: 14px; width: 30%; height: 4px; background: #94a3b8; }
.fe-tplgrid-thumb .t-line { left: 16px; right: 16px; top: 50px; height: 5px; background: #cbd5e1; }
.fe-tplgrid-thumb .t-line.short { width: 50%; right: auto; }
.fe-tplgrid-thumb .t-line.centered { left: 50%; transform: translateX(-50%); width: 70%; }
.fe-tplgrid-thumb .t-line.centered.short { width: 40%; }

/* Classic — title bar + grid of 4 cards */
.fe-tplgrid-thumb .t-grid {
  position: absolute; left: 16px; right: 16px; bottom: 14px; height: 64px;
  display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 6px;
  background: transparent;
}
.fe-tplgrid-thumb .t-grid > span { position: relative; background: #fff;
  border: 1px solid #e2e8f0; border-radius: 4px; }

/* Card stack — gradient hero block + big primary action below */
.fe-tplgrid-thumb-meeting-card-stack { background: linear-gradient(180deg, #eef2ff 0%, #fdf4ff 100%); }
.fe-tplgrid-thumb .t-hero {
  left: 0; right: 0; top: 0; height: 50px; border-radius: 0;
  background: linear-gradient(135deg, #818cf8 0%, #f472b6 100%);
}
.fe-tplgrid-thumb .t-action {
  left: 16px; right: 16px; top: 60px; height: 36px; border-radius: 8px;
  background: #fff; border: 1px solid #e2e8f0;
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.08);
}
.fe-tplgrid-thumb-meeting-card-stack .t-line { top: 108px; }
.fe-tplgrid-thumb-meeting-card-stack .t-line.short { top: 120px; }

/* Magazine — 2-col layout with sidebar */
.fe-tplgrid-thumb .t-cols {
  position: absolute; left: 16px; right: 16px; top: 50px; bottom: 12px;
  display: grid; grid-template-columns: 1.6fr 1fr; gap: 8px; background: transparent;
}
.fe-tplgrid-thumb .t-col-main, .fe-tplgrid-thumb .t-col-side {
  background: transparent; display: flex; flex-direction: column; gap: 4px;
}
.fe-tplgrid-thumb .t-col-main > span { background: #cbd5e1; height: 4px; border-radius: 2px;
  position: relative; left: auto; right: auto; top: auto; }
.fe-tplgrid-thumb .t-col-main > span.short { width: 50%; }
.fe-tplgrid-thumb .t-col-side > span {
  background: #f1f5f9; border: 1px solid #e2e8f0; border-radius: 4px;
  height: 28px; position: relative; left: auto; right: auto; top: auto;
}

/* Minimal — eyebrow + big serif title + body */
.fe-tplgrid-thumb-meeting-minimal,
.fe-tplgrid-thumb-event-minimal { background: #fff; }
.fe-tplgrid-thumb .t-list {
  position: absolute; left: 50%; transform: translateX(-50%); top: 90px;
  width: 70%; display: flex; flex-direction: column; gap: 4px;
  background: transparent;
}
.fe-tplgrid-thumb .t-list > span {
  position: relative; left: auto; top: auto; height: 4px; background: #cbd5e1;
}

/* Event — Classic: cover image + same grid */
.fe-tplgrid-thumb .t-cover {
  left: 8px; right: 8px; top: 8px; height: 36px; border-radius: 6px;
  background: linear-gradient(135deg, #60a5fa 0%, #34d399 100%);
}
.fe-tplgrid-thumb-event-classic .t-h { top: 50px; }
.fe-tplgrid-thumb-event-classic .t-grid { top: 70px; bottom: 10px; height: auto; }

/* Event — Poster: full-bleed dark hero */
.fe-tplgrid-thumb-event-poster { background: #1e293b; }
.fe-tplgrid-thumb .t-poster-hero {
  left: 0; right: 0; top: 0; bottom: 0; border-radius: 0;
  background:
    linear-gradient(180deg, rgba(15,23,42,0.2) 0%, rgba(15,23,42,0.7) 100%),
    linear-gradient(135deg, #f97316 0%, #db2777 50%, #7c3aed 100%);
}
.fe-tplgrid-thumb .t-poster-overlay {
  left: 12px; top: 14px; width: 70%; background: transparent;
}
.fe-tplgrid-thumb .t-poster-title {
  position: relative; left: auto; top: auto; display: block;
  width: 100%; height: 10px; background: #fff; border-radius: 2px;
}
.fe-tplgrid-thumb .t-ticket {
  left: 12px; right: 12px; bottom: 10px; height: 56px; border-radius: 6px;
  background: #fff; border: 1px solid #e2e8f0;
  display: grid; grid-template-columns: 36px 1fr; align-items: center;
  padding: 0 8px; gap: 6px;
}
.fe-tplgrid-thumb .t-ticket-date {
  position: relative; left: auto; top: auto; height: 36px; width: 36px;
  background: #f1f5f9; border-radius: 4px; border: 1px dashed #cbd5e1;
}
.fe-tplgrid-thumb .t-ticket-info {
  position: relative; left: auto; top: auto; background: transparent;
  display: flex; flex-direction: column; gap: 4px;
}
.fe-tplgrid-thumb .t-ticket-info > span {
  position: relative; left: auto; top: auto; height: 4px; background: #cbd5e1;
}

/* Event — Timeline: huge date block on left */
.fe-tplgrid-thumb .t-time-row {
  left: 0; right: 0; top: 0; bottom: 0; padding: 12px;
  display: grid; grid-template-columns: 50px 1fr; gap: 12px;
  background: transparent; border-radius: 0;
}
.fe-tplgrid-thumb .t-time-date {
  position: relative; left: auto; top: auto; background: transparent;
  border-left: 3px solid #6366f1; padding-left: 6px;
  display: flex; flex-direction: column; gap: 4px; align-items: flex-start;
}
.fe-tplgrid-thumb .t-time-date .m {
  position: relative; left: auto; top: auto; width: 26px; height: 4px; background: #6366f1;
}
.fe-tplgrid-thumb .t-time-date .d {
  position: relative; left: auto; top: auto; width: 32px; height: 28px;
  background: #1e293b; border-radius: 3px;
}
.fe-tplgrid-thumb .t-time-main {
  position: relative; left: auto; top: auto; background: transparent;
  display: flex; flex-direction: column; gap: 4px;
}
.fe-tplgrid-thumb .t-time-main .t-h {
  position: relative; left: auto; top: auto; width: 80%; height: 8px;
  background: #475569; margin-bottom: 4px;
}
.fe-tplgrid-thumb .t-time-main > span {
  position: relative; left: auto; top: auto; height: 4px; background: #cbd5e1;
}
.fe-tplgrid-thumb .t-time-main > span.short { width: 60%; }

/* Event — Minimal: thin date line, centered title */
.fe-tplgrid-thumb .t-date-line {
  left: 50%; transform: translateX(-50%); top: 14px; width: 60%; height: 3px;
  background: #94a3b8; border-radius: 2px;
}

@media (max-width: 600px) {
  .fe-tplgrid { grid-template-columns: 1fr; }
}

/* Customize panel — per-template appearance overrides (bg, fonts, sizes)
   for the currently-active template in each section. */
.fe-tplgrid-customize {
  margin-top: 18px;
  border-top: 1px solid var(--border);
  padding-top: 14px;
}
.fe-tplgrid-customize summary {
  cursor: pointer; padding: 6px 0;
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  list-style: none;
}
.fe-tplgrid-customize summary::-webkit-details-marker { display: none; }
.fe-tplgrid-customize summary::before {
  content: "▸"; color: var(--muted); font-size: 0.8rem;
  display: inline-block; transition: transform 140ms ease;
  margin-right: 2px;
}
.fe-tplgrid-customize[open] summary::before { transform: rotate(90deg); }
.fe-tplgrid-customize-title { font-weight: 600; color: var(--text); }
.fe-tplgrid-customize-form { margin-top: 14px; }
.fe-tplgrid-customize-grid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.fe-tplgrid-customize-grid .fieldset {
  display: flex; flex-direction: column; gap: 10px;
}
.fe-tplgrid-bg-toggle { display: flex; align-items: center; gap: 8px; }


/* Features editor — heading/subheading row + draggable card list. The
   row layout fans out to single-column on narrow screens; cards keep
   their icon-trigger / fields / remove button as a flex strip. */
.fe-feat-head-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr);
  gap: 12px 16px; margin: 6px 0 14px;
}
@media (max-width: 720px) { .fe-feat-head-grid { grid-template-columns: 1fr; } }
.fe-feat-head-grid label { display: flex; flex-direction: column; gap: 6px; }

.fe-feat-cards {
  display: flex; flex-direction: column; gap: 12px;
  margin-top: 4px;
}
.fe-feat-cards:empty {
  border: 1px dashed var(--border); border-radius: 10px;
  padding: 24px; text-align: center; color: var(--muted);
  background: var(--panel-2);
}
.fe-feat-cards:empty::before {
  content: "No cards yet — click \201CAdd card\201D below to start.";
  font-style: italic;
}

.fe-feat-card {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  align-items: stretch; gap: 12px;
  padding: 12px 12px 12px 6px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 12px;
  transition: box-shadow 140ms ease, border-color 140ms ease, transform 140ms ease;
}
.fe-feat-card:hover { border-color: var(--brand-soft, var(--border)); }
.fe-feat-card.is-dragging {
  opacity: 0.65; box-shadow: 0 12px 28px rgba(0,0,0,0.18);
  transform: scale(1.005);
}

.fe-feat-card-handle {
  display: flex; align-items: center; justify-content: center;
  width: 22px; color: var(--muted); cursor: grab;
  touch-action: none;
}
.fe-feat-card-handle:active { cursor: grabbing; }
.fe-feat-card-handle .icon { width: 18px; height: 18px; }

.fe-feat-card-icon {
  display: flex; align-items: flex-start; padding-top: 2px;
}
.fe-feat-icon-trigger {
  display: inline-flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px;
  width: 64px; height: 64px;
  padding: 8px; border-radius: 12px;
  background: var(--panel-2); color: var(--text);
  border: 1px dashed var(--border); cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}
.fe-feat-icon-trigger:hover { background: var(--panel); border-color: var(--brand, var(--border)); }
.fe-feat-icon-trigger .icon-picker-preview { display: inline-flex; }
.fe-feat-icon-trigger .icon-picker-preview .icon { width: 26px; height: 26px; }
.fe-feat-icon-trigger .icon-picker-preview:empty { display: none; }
.fe-feat-icon-trigger .icon-picker-trigger-empty {
  display: inline-flex; flex-direction: column; align-items: center; gap: 2px;
  color: var(--muted); font-size: 0.7rem;
}
.fe-feat-icon-trigger .icon-picker-trigger-empty .icon { width: 22px; height: 22px; }
.fe-feat-card-icon.has-icon .fe-feat-icon-trigger { border-style: solid; }
.fe-feat-card-icon.has-icon .icon-picker-trigger-empty { display: none; }

.fe-feat-card-fields {
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
}
.fe-feat-card-title {
  font-weight: 600; font-size: 0.98rem;
}
.fe-feat-card-body { resize: vertical; min-height: 56px; }
/* Compact in-card markdown editor — features cards run side-by-side
   Write/Preview (matches the Inclusion block design) but with a tighter
   min-height than the standalone Inclusion editor since the card row
   itself is already dense. The shared `.md-editor-live` flex layout
   keeps the two panes the same height; we only need to override the
   textarea's min-height (the preview tracks via flex: 1) and the inner
   paddings. Stacks earlier (≤900px) since the field column is narrow
   inside a card. */
.fe-feat-card-md { background: var(--panel); }
.fe-feat-card-md textarea { padding: 8px 10px; font-size: 0.85rem; }
.fe-feat-card-md.md-editor-live .md-editor-pane-write textarea { min-height: 80px; }
.fe-feat-card-md.md-editor-live .md-editor-preview {
  padding: 8px 10px; font-size: 0.85rem;
}
@media (max-width: 900px) {
  .fe-feat-card-md.md-editor-live { grid-template-columns: 1fr; }
  .fe-feat-card-md.md-editor-live .md-editor-pane-write {
    border-right: 0; border-bottom: 1px solid var(--border);
  }
}

.fe-feat-card-link-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 8px; background: var(--panel-2);
  border: 1px solid var(--border); border-radius: 8px;
}
.fe-feat-card-link-icon {
  display: inline-flex; color: var(--muted);
}
.fe-feat-card-link-icon .icon { width: 16px; height: 16px; }
.fe-feat-card-href {
  flex: 1 1 220px; min-width: 0;
  padding: 6px 8px; background: transparent; border: none;
  font: inherit; color: var(--text);
}
.fe-feat-card-href:focus { outline: none; }
.fe-feat-card-newtab {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.82rem; color: var(--muted); white-space: nowrap;
}
.fe-feat-card-newtab input { margin: 0; }

.fe-feat-card-btn-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 8px; background: var(--panel-2);
  border: 1px solid var(--border); border-radius: 8px;
}
.fe-feat-card-btn-label {
  flex: 1 1 220px; min-width: 0;
  padding: 6px 8px; background: transparent; border: none;
  font: inherit; color: var(--text);
}
.fe-feat-card-btn-label:focus { outline: none; }
.fe-feat-card-btn-style {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.82rem; color: var(--muted); white-space: nowrap;
}
.fe-feat-card-btn-style select {
  padding: 4px 6px; font-size: 0.85rem;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
}

.fe-feat-card-remove {
  align-self: start;
  width: 32px; height: 32px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 8px;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.fe-feat-card-remove:hover {
  color: var(--danger, #b91c1c); border-color: var(--danger, #b91c1c);
  background: rgba(185, 28, 28, 0.06);
}
.fe-feat-card-remove .icon { width: 16px; height: 16px; }

.fe-feat-actions {
  display: flex; align-items: center; gap: 12px;
  margin-top: 12px;
}
.fe-feat-actions .btn[disabled],
.fe-feat-actions .btn.is-disabled {
  opacity: 0.5; cursor: not-allowed;
}
.fe-feat-actions .btn .icon { width: 14px; height: 14px; margin-right: 2px; }

/* Section-level CTA fieldset — single bottom button under the cards
   on the public site (.fe-features-foot). Mirrors the chrome of the
   per-card link row so the two button surfaces feel related. */
.fe-feat-section-cta {
  margin: 16px 0 4px;
  padding: 12px 14px;
  background: var(--panel-2);
  border: 1px solid var(--border); border-radius: 10px;
}
.fe-feat-section-cta legend {
  padding: 0 6px; font-size: 0.85rem; font-weight: 600; color: var(--text);
}
.fe-feat-section-cta-grid {
  display: grid; gap: 10px 12px;
  grid-template-columns: 1.4fr 1.4fr 0.8fr auto;
  align-items: end;
}
.fe-feat-section-cta-grid label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 0.82rem; color: var(--muted);
}
.fe-feat-section-cta-grid input[type="text"],
.fe-feat-section-cta-grid select {
  padding: 6px 8px; font-size: 0.9rem;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
}
.fe-feat-section-cta-newtab {
  flex-direction: row !important; align-items: center; gap: 6px;
  white-space: nowrap;
}
.fe-feat-section-cta-newtab input { margin: 0; }
@media (max-width: 720px) {
  .fe-feat-section-cta-grid { grid-template-columns: 1fr 1fr; }
  .fe-feat-section-cta-newtab { grid-column: 1 / -1; }
}

/* FAQ editor — same draggable / add-remove / Markdown-card pattern as
   features. One row per FAQ item: drag handle | icon trigger | fields
   (question + side-by-side Markdown answer) | trash button. */

/* Layout controls (columns / width / pad_x) — three-up grid above the
   item cards in the per-page FAQ modal. Each cell stacks label + input
   + helper microcopy. Collapses to one column on narrow viewports
   so the textareas + selects don't get squashed. */
.fe-faq-layout-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px; margin-top: 12px; padding: 14px; border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
}
@media (max-width: 720px) {
  .fe-faq-layout-grid { grid-template-columns: 1fr; }
}
.fe-faq-layout-cell { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.fe-faq-layout-label {
  font-size: 0.8125rem; font-weight: 600; color: var(--text);
  display: flex; align-items: baseline; gap: 8px;
}
.fe-faq-pad-out {
  margin-left: auto; font-variant-numeric: tabular-nums;
  color: var(--muted); font-weight: 400; font-size: 0.75rem;
}
.fe-faq-layout-select {
  width: 100%; padding: 7px 10px;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  font: inherit;
}
.fe-faq-layout-select:focus { border-color: var(--brand); outline: none; }
.fe-faq-layout-range { width: 100%; }

.fe-faq-cards {
  display: flex; flex-direction: column; gap: 12px;
  margin-top: 4px;
}
.fe-faq-cards:empty {
  border: 1px dashed var(--border); border-radius: 10px;
  padding: 24px; text-align: center; color: var(--muted);
  background: var(--panel-2);
}
.fe-faq-cards:empty::before {
  content: "No items yet — click \201CAdd item\201D below to start.";
  font-style: italic;
}
.fe-faq-card {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  align-items: stretch; gap: 12px;
  padding: 12px 12px 12px 6px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 12px;
  transition: box-shadow 140ms ease, border-color 140ms ease, transform 140ms ease;
}
.fe-faq-card:hover { border-color: var(--brand-soft, var(--border)); }
.fe-faq-card.is-dragging {
  opacity: 0.65; box-shadow: 0 12px 28px rgba(0,0,0,0.18);
  transform: scale(1.005);
}
.fe-faq-card-handle {
  display: flex; align-items: center; justify-content: center;
  width: 22px; color: var(--muted); cursor: grab;
  touch-action: none;
}
.fe-faq-card-handle:active { cursor: grabbing; }
.fe-faq-card-handle .icon { width: 18px; height: 18px; }
.fe-faq-card-icon {
  display: flex; align-items: flex-start; padding-top: 2px;
}
.fe-faq-icon-trigger {
  display: inline-flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px;
  width: 64px; height: 64px;
  padding: 8px; border-radius: 12px;
  background: var(--panel-2); color: var(--text);
  border: 1px dashed var(--border); cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}
.fe-faq-icon-trigger:hover { background: var(--panel); border-color: var(--brand, var(--border)); }
.fe-faq-icon-trigger .icon-picker-preview { display: inline-flex; }
.fe-faq-icon-trigger .icon-picker-preview .icon { width: 26px; height: 26px; }
.fe-faq-icon-trigger .icon-picker-preview:empty { display: none; }
.fe-faq-icon-trigger .icon-picker-trigger-empty {
  display: inline-flex; flex-direction: column; align-items: center; gap: 2px;
  color: var(--muted); font-size: 0.7rem;
}
.fe-faq-icon-trigger .icon-picker-trigger-empty .icon { width: 22px; height: 22px; }
.fe-faq-card-icon.has-icon .fe-faq-icon-trigger { border-style: solid; }
.fe-faq-card-icon.has-icon .icon-picker-trigger-empty { display: none; }
.fe-faq-card-fields {
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
}
.fe-faq-card-question {
  font-weight: 600; font-size: 0.98rem;
}
/* Compact in-card markdown editor — same pattern as the features card.
   Live side-by-side Write/Preview, but tighter min-height since the FAQ
   row is dense. Stacks earlier (≤ 900 px) like features. */
.fe-faq-card-md { background: var(--panel); }
.fe-faq-card-md textarea { padding: 8px 10px; font-size: 0.85rem; }
.fe-faq-card-md.md-editor-live .md-editor-pane-write textarea { min-height: 90px; }
.fe-faq-card-md.md-editor-live .md-editor-preview {
  padding: 8px 10px; font-size: 0.85rem;
}
@media (max-width: 900px) {
  .fe-faq-card-md.md-editor-live { grid-template-columns: 1fr; }
  .fe-faq-card-md.md-editor-live .md-editor-pane-write {
    border-right: 0; border-bottom: 1px solid var(--border);
  }
}
.fe-faq-card-remove {
  align-self: start;
  width: 32px; height: 32px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 8px;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.fe-faq-card-remove:hover {
  color: var(--danger, #b91c1c); border-color: var(--danger, #b91c1c);
  background: rgba(185, 28, 28, 0.06);
}
.fe-faq-card-remove .icon { width: 16px; height: 16px; }
.fe-faq-actions {
  display: flex; align-items: center; gap: 12px;
  margin-top: 12px;
}
.fe-faq-actions .btn[disabled],
.fe-faq-actions .btn.is-disabled {
  opacity: 0.5; cursor: not-allowed;
}
.fe-faq-actions .btn .icon { width: 14px; height: 14px; margin-right: 2px; }

/* Default-appearance picker — three large radio cards (Light / Dark /
   Follow system). The native radio is hidden; the surrounding label is
   the click target. Active card gets a brand-tinted border + soft
   background so the current setting reads at a glance. */
.fe-default-theme-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  margin: 6px 0 14px;
}
.fe-default-theme-opt {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 14px; row-gap: 4px;
  padding: 14px 16px; border-radius: 12px;
  background: var(--panel); border: 1.5px solid var(--border);
  cursor: pointer;
  transition: border-color 140ms ease, background 140ms ease;
}
.fe-default-theme-opt:hover { border-color: var(--brand-soft, var(--border)); }
.fe-default-theme-opt.is-active {
  border-color: var(--brand, var(--access));
  background: var(--brand-soft, var(--panel-2));
}
.fe-default-theme-opt input[type="radio"] {
  position: absolute; left: -9999px; opacity: 0;
}
.fe-default-theme-icon {
  grid-row: 1 / span 2;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 10px;
  background: var(--panel-2); color: var(--text);
}
.fe-default-theme-opt.is-active .fe-default-theme-icon {
  background: var(--brand, var(--access)); color: #fff;
}
.fe-default-theme-icon .icon { width: 22px; height: 22px; }
.fe-default-theme-name { font-weight: 600; align-self: end; }
.fe-default-theme-desc { line-height: 1.35; }

/* ========== Footer admin editor ========== */

/* Container width — reused radio-card pattern from default-theme picker. */
.fe-footer-width-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  margin: 6px 0 14px;
}
.fe-footer-width-opt {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 14px; row-gap: 4px;
  padding: 14px 16px; border-radius: 12px;
  background: var(--panel); border: 1.5px solid var(--border);
  cursor: pointer;
  transition: border-color 140ms ease, background 140ms ease;
}
.fe-footer-width-opt:hover { border-color: var(--brand-soft, var(--border)); }
.fe-footer-width-opt.is-active {
  border-color: var(--brand, var(--access));
  background: var(--brand-soft, var(--panel-2));
}
.fe-footer-width-opt input[type="radio"] {
  position: absolute; left: -9999px; opacity: 0;
}
.fe-footer-width-icon {
  grid-row: 1 / span 2;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 10px;
  background: var(--panel-2); color: var(--text);
}
.fe-footer-width-opt.is-active .fe-footer-width-icon {
  background: var(--brand, var(--access)); color: #fff;
}
.fe-footer-width-icon .icon { width: 22px; height: 22px; }
.fe-footer-width-name { font-weight: 600; align-self: end; }
.fe-footer-width-desc { line-height: 1.35; }
.fe-footer-width-numbers {
  display: grid; gap: 12px 16px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.fe-footer-width-numbers label { display: flex; flex-direction: column; gap: 6px; }

/* Background-mode radio cards — same shape as the width selector. */
.fe-footer-bg-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  margin-top: 14px;
}
.fe-footer-bg-opt {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 14px; row-gap: 4px;
  padding: 14px 16px; border-radius: 12px;
  background: var(--panel); border: 1.5px solid var(--border);
  cursor: pointer;
  transition: border-color 140ms ease, background 140ms ease;
}
.fe-footer-bg-opt:hover { border-color: var(--brand-soft, var(--border)); }
.fe-footer-bg-opt.is-active {
  border-color: var(--brand, var(--access));
  background: var(--brand-soft, var(--panel-2));
}
.fe-footer-bg-opt input[type="radio"] {
  position: absolute; left: -9999px; opacity: 0;
}
.fe-footer-bg-icon {
  grid-row: 1 / span 2;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 10px;
  background: var(--panel-2); color: var(--text);
}
.fe-footer-bg-opt.is-active .fe-footer-bg-icon {
  background: var(--brand, var(--access)); color: #fff;
}
.fe-footer-bg-icon .icon { width: 22px; height: 22px; }
.fe-footer-bg-name { font-weight: 600; align-self: end; }
.fe-footer-bg-desc { line-height: 1.35; }

/* Min-height slider row inside Container width card. */
.fe-footer-minh-row {
  display: flex; align-items: center; gap: 10px;
}
.fe-footer-minh-row input[type="range"] {
  flex: 1 1 auto; min-width: 120px; accent-color: var(--access, #4f46e5);
}
.fe-footer-minh-row output {
  font-variant-numeric: tabular-nums; font-weight: 600;
  min-width: 3ch; text-align: right;
}
/* Inline footer-bg admin section — live preview clip + segmented style
   picker + per-style panels + particle overlay row. Mirrors the hero
   admin's pattern; reuses .hero-bg-panel / .hero-bg-grid for the panel
   internals so per-style controls look identical. */
.fe-footer-bg-section .fe-footer-preview-clip {
  position: relative;
  height: 220px;
  margin: 6px 0 18px;
  border: 1px dashed var(--border); border-radius: 12px;
  background: var(--panel-2);
  overflow: hidden;
}
.fe-footer-preview-label {
  position: absolute; top: 8px; left: 12px; z-index: 2;
  margin: 0; padding: 2px 8px; border-radius: 4px;
  background: color-mix(in srgb, var(--panel) 85%, transparent);
  font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
}
/* Preview wrapper fills the clip 1:1; the inner footer renders edge to
   edge so the bg (solid / gradient / blobs / sinewave) spans the full
   preview width. */
.fe-footer-preview {
  position: absolute; inset: 0;
  pointer-events: none;
  user-select: none;
  background: transparent;
}
.fe-footer-preview .fe-footer {
  width: 100%; height: 100%;
  padding: 0;
  display: flex; align-items: center; justify-content: center;
  margin: 0;
}
.fe-footer-preview-content {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  text-align: center;
}
.fe-footer-preview-brand {
  font-weight: 700; font-size: 1.1rem;
  color: color-mix(in srgb, currentColor 92%, transparent);
}
.fe-footer-preview-copy { font-size: 0.78rem; }
/* Dark-mode preview wrapper — mirrors the public footer's
   `body.fe-footer-force-dark` rule so the preview matches what users
   will actually see when "Dark (always)" is selected. */
.fe-footer-preview.fe-footer-force-dark .fe-footer {
  background: #0b1026; color: #cbd5e1;
}

.fe-footer-bg-style-row { margin: 6px 0 4px; }

.fe-footer-bg-panels { margin-top: 4px; }

/* Sinewave action button row — Random palette / Random wave / Reset. */
.fe-footer-sw-actions {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-top: 12px;
}
.fe-footer-sw-actions .icon { width: 14px; height: 14px; }

.fe-footer-bg-particles {
  margin-top: 16px;
  padding: 12px 14px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px;
  display: flex; flex-direction: column; gap: 10px;
}
.fe-footer-bg-particles-fields {
  display: grid; gap: 10px 14px;
  grid-template-columns: 1fr auto auto;
}
.fe-footer-bg-particles-fields label { display: flex; flex-direction: column; gap: 4px; }
@media (max-width: 540px) {
  .fe-footer-bg-particles-fields { grid-template-columns: 1fr; }
}

/* Brand block toggles. */
.fe-footer-brand-row {
  display: flex; flex-wrap: wrap; gap: 18px;
  margin: 4px 0 10px;
}

/* Brand modal — logo source toggle + preview + upload + width slider. */
.fe-footer-brand-source-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
  margin: 6px 0 14px;
}
.fe-footer-brand-source-label {
  font-size: 0.875rem; font-weight: 600; color: var(--muted);
  white-space: nowrap;
}
.fe-footer-brand-source-toggle { margin: 0; }
.fe-footer-brand-logo-preview {
  display: flex; align-items: center; justify-content: center;
  min-height: 80px; padding: 16px;
  border: 1px dashed var(--border); border-radius: 10px;
  background: var(--panel);
  margin-bottom: 14px;
}
.fe-footer-brand-logo-preview img { max-width: 100%; height: auto; }
.fe-footer-brand-preview-pane.is-hidden { display: none; }
.fe-footer-brand-upload-row {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px 0; border-top: 1px solid var(--border);
  margin-bottom: 8px;
}
.fe-footer-brand-width-label {
  display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px;
}
.fe-footer-brand-width-row {
  display: flex; align-items: center; gap: 10px;
}
.fe-footer-brand-width-row input[type="range"] {
  flex: 1 1 auto; min-width: 140px; accent-color: var(--access, #4f46e5);
}
.fe-footer-brand-width-row output {
  font-variant-numeric: tabular-nums; font-weight: 600;
  min-width: 3ch; text-align: right;
}

/* Link columns editor — list of column cards; each card holds a list
   of link rows. Drag handles on the column header + each link. */
.fe-footer-cols-list {
  display: flex; flex-direction: column; gap: 12px;
  margin-top: 4px;
}
.fe-footer-cols-list:empty {
  border: 1px dashed var(--border); border-radius: 10px;
  padding: 24px; text-align: center; color: var(--muted);
  background: var(--panel-2);
}
.fe-footer-cols-list:empty::before {
  content: "No columns yet — click \201CAdd column\201D below.";
  font-style: italic;
}
.fe-footer-col-card {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 12px; padding: 12px;
  display: flex; flex-direction: column; gap: 10px;
  transition: box-shadow 140ms ease, border-color 140ms ease;
}
.fe-footer-col-card.is-dragging { opacity: 0.65; box-shadow: 0 12px 28px rgba(0,0,0,0.18); }
.fe-footer-col-card-head {
  display: grid; grid-template-columns: auto 1fr auto; gap: 8px;
  align-items: center;
}
.fe-footer-col-handle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0;
  background: transparent; border: 0; color: var(--muted);
  cursor: grab; touch-action: none;
}
.fe-footer-col-handle:active { cursor: grabbing; }
.fe-footer-col-title-input {
  font-weight: 600; font-size: 0.95rem;
}
.fe-footer-col-remove,
.fe-footer-link-remove,
.fe-footer-social-remove,
.fe-footer-secnav-remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0;
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 6px; cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.fe-footer-col-remove:hover,
.fe-footer-link-remove:hover,
.fe-footer-social-remove:hover,
.fe-footer-secnav-remove:hover {
  color: var(--danger, #b91c1c); border-color: var(--danger, #b91c1c);
  background: rgba(185, 28, 28, 0.06);
}
.fe-footer-col-remove .icon,
.fe-footer-link-remove .icon,
.fe-footer-social-remove .icon,
.fe-footer-secnav-remove .icon { width: 14px; height: 14px; }

.fe-footer-link-rows {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.fe-footer-link-row {
  display: grid;
  grid-template-columns: auto minmax(120px, 1fr) minmax(140px, 1.2fr) auto auto;
  gap: 8px; align-items: center;
}
.fe-footer-link-row.is-dragging { opacity: 0.6; }
.fe-footer-link-handle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; padding: 0;
  background: transparent; border: 0; color: var(--muted);
  cursor: grab; touch-action: none;
}
.fe-footer-link-handle:active { cursor: grabbing; }
.fe-footer-link-newtab {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.78rem; color: var(--muted); white-space: nowrap;
}
.fe-footer-link-newtab input { margin: 0; }
.fe-footer-link-add { align-self: flex-start; }
.fe-footer-cols-actions {
  display: flex; align-items: center; gap: 12px; margin-top: 12px;
}
.fe-footer-cols-actions .btn[disabled],
.fe-footer-cols-actions .btn.is-disabled { opacity: 0.5; cursor: not-allowed; }

@media (max-width: 720px) {
  .fe-footer-link-row {
    grid-template-columns: auto 1fr auto;
    grid-template-areas: "handle label  remove"
                          "url    url    url"
                          "newtab newtab newtab";
  }
  .fe-footer-link-row > .fe-footer-link-handle { grid-area: handle; }
  .fe-footer-link-row > input[type="text"]:nth-of-type(1) { grid-area: label; }
  .fe-footer-link-row > input[type="text"]:nth-of-type(2) { grid-area: url; }
  .fe-footer-link-row > .fe-footer-link-newtab { grid-area: newtab; }
  .fe-footer-link-row > .fe-footer-link-remove { grid-area: remove; }
}

/* Social icons editor */
.fe-footer-social-list {
  display: flex; flex-direction: column; gap: 8px; margin-top: 4px;
}
.fe-footer-social-row {
  display: grid;
  grid-template-columns: minmax(140px, 1fr) minmax(140px, 1fr) minmax(180px, 1.5fr) auto;
  gap: 8px; align-items: center;
}
@media (max-width: 720px) {
  .fe-footer-social-row { grid-template-columns: 1fr 1fr auto; }
  .fe-footer-social-row > input:nth-of-type(3) { grid-column: 1 / -2; }
}

/* Secondary nav editor */
.fe-footer-secnav-list {
  display: flex; flex-direction: column; gap: 8px; margin-top: 4px;
}
.fe-footer-secnav-row {
  display: grid;
  grid-template-columns: minmax(140px, 1fr) minmax(180px, 1.5fr) auto;
  gap: 8px; align-items: center;
}

/* ---- Predefined Locations checklist (top of meeting_locations
   modal). Shows a card-list of every in-person Location from
   Settings; the admin ticks the ones to include. Each row links out
   to Settings → Meeting Locations for editing the source data. */
.fe-footer-loc-predefined {
  margin: 14px 0; padding: 12px 14px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px;
}
.fe-footer-loc-predefined-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 6px;
}
.fe-footer-loc-predefined-head .u-name { font-weight: 600; }
.fe-footer-loc-predefined-head .icon { width: 14px; height: 14px; }
.fe-footer-loc-predefined-list {
  list-style: none; padding: 0; margin: 8px 0 0;
  display: flex; flex-direction: column; gap: 6px;
}
.fe-footer-loc-predefined-row {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 8px; border-radius: 8px;
  background: var(--panel);
  border: 1px solid var(--border);
}
.fe-footer-loc-predefined-check {
  display: flex; align-items: center; gap: 8px;
  flex: 1; min-width: 0; cursor: pointer; margin: 0;
}
.fe-footer-loc-predefined-check input[type="checkbox"] {
  margin: 0; flex: 0 0 auto;
}
.fe-footer-loc-predefined-name { font-weight: 600; }
.fe-footer-loc-predefined-addr { margin-left: 4px; }
.fe-footer-loc-predefined-edit { flex: 0 0 auto; }
.fe-footer-loc-predefined-edit .icon { width: 14px; height: 14px; }
.fe-footer-loc-section-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px;
  margin: 18px 0 6px; padding-top: 10px;
  border-top: 1px solid var(--border);
}
.fe-footer-loc-section-head .u-name { font-weight: 600; }

/* ---- Meeting locations editor ----
   Card layout: each location is its own panel with an icon picker +
   name on top, address textarea, dual URL fields (card link + maps),
   and a Markdown editor with side-by-side preview for the note. */
.fe-footer-loc-list {
  display: flex; flex-direction: column; gap: 12px;
  margin: 6px 0 10px;
}
.fe-footer-loc-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: 14px 16px; border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
}
.fe-footer-loc-card-head {
  display: flex; align-items: flex-end; gap: 10px;
}
.fe-footer-loc-icon-cell { flex: 0 0 auto; }
.fe-footer-loc-icon-trigger {
  width: 44px; height: 44px;
}
/* The Name input is wrapped in a `<label>` so it gets the standard
   text-above-input form treatment; the wrapper grows to fill the row
   while the icon picker + remove button hold their fixed sizes. */
.fe-footer-loc-field-grow { flex: 1; min-width: 0; }
.fe-footer-loc-card .fe-footer-loc-name { font-weight: 600; }
.fe-footer-loc-card textarea { resize: vertical; min-height: 56px; }
.fe-footer-loc-urls {
  display: grid; gap: 8px 12px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.fe-footer-loc-url-cell {
  display: flex; flex-direction: column; gap: 4px;
}
.fe-footer-loc-note-label { display: block; }
.fe-footer-loc-note-md { margin-top: 0; }
.fe-footer-loc-remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0; flex: 0 0 auto;
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 6px; cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.fe-footer-loc-remove:hover {
  color: var(--danger, #b91c1c); border-color: var(--danger, #b91c1c);
  background: rgba(185, 28, 28, 0.06);
}
.fe-footer-loc-remove .icon { width: 14px; height: 14px; }

/* ---- Contact section editor ---- */
.fe-footer-contact-list {
  display: flex; flex-direction: column; gap: 8px;
  margin: 6px 0 10px;
}
.fe-footer-contact-row {
  display: grid;
  grid-template-columns: minmax(180px, 1fr) minmax(280px, 2.5fr) auto;
  gap: 8px; align-items: start;
}
.fe-footer-contact-row textarea { resize: vertical; min-height: 72px; }
.fe-footer-contact-remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0;
  background: transparent; color: var(--muted);
  border: 1px solid var(--border); border-radius: 6px; cursor: pointer;
  align-self: start; margin-top: 2px;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.fe-footer-contact-remove:hover {
  color: var(--danger, #b91c1c); border-color: var(--danger, #b91c1c);
  background: rgba(185, 28, 28, 0.06);
}
.fe-footer-contact-remove .icon { width: 14px; height: 14px; }
@media (max-width: 720px) {
  .fe-footer-contact-row { grid-template-columns: 1fr auto; }
  .fe-footer-contact-row > textarea { grid-column: 1 / -2; }
}

/* ---- Active layout structure visualisation ----
   Shared between every frontend admin page that opts into the
   structure-card pattern (footer, homepage, future pages). The footer
   uses the rows × columns shape; the homepage uses a vertical
   sequence with optional 2-panel splits. Both share the same row /
   column / pill styling. Two-column desktop layout per row: a fixed-
   width label gutter on the left (Row #, column count) + the actual
   columns grid on the right. Stacks to label-on-top on narrow
   viewports. */
.fe-page-structure .fe-page-structure-rows {
  display: flex; flex-direction: column; gap: 14px; margin-top: 6px;
}
.fe-page-structure .fe-page-structure-row {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}
@media (min-width: 720px) {
  .fe-page-structure .fe-page-structure-row {
    grid-template-columns: 130px 1fr;
    gap: 18px;
    align-items: start;
  }
}
.fe-page-structure .fe-page-structure-row-label {
  display: flex; flex-direction: column; gap: 4px;
}
.fe-page-structure .fe-page-structure-row-num {
  font-weight: 700; font-size: 0.78rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
}
/* When the admin set a custom container label, render it as a
   normal-cased title rather than the all-caps "CONTAINER" tag, so
   "Officers" reads as the actual subject. The role chip below ("container · single column")
   keeps the structural context. */
.fe-page-structure .fe-page-structure-row-num--labelled {
  font-weight: 700; font-size: 0.95rem; letter-spacing: normal;
  text-transform: none; color: var(--text);
}
/* Inline-editable container label input. Looks like a static title
   by default; gains a subtle border + focus ring on hover/focus to
   telegraph "this is editable." When the field is empty, the
   placeholder reverts to the all-caps muted "CONTAINER"-style label
   so admins still see the structural fallback. */
.fe-page-structure .fe-page-structure-row-label-input {
  width: 100%;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  padding: 4px 6px;
  margin: -4px -6px 0;  /* keep visual position when border appears */
  font-family: inherit;
  font-weight: 700; font-size: 0.78rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
  outline: none;
  cursor: text;
  transition: border-color 120ms ease, background-color 120ms ease;
}
.fe-page-structure .fe-page-structure-row-label-input.is-labelled {
  font-size: 0.95rem; letter-spacing: normal;
  text-transform: none; color: var(--text);
}
.fe-page-structure .fe-page-structure-row-label-input::placeholder {
  color: var(--muted);
  font-weight: 700; font-size: 0.78rem; letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 1;
}
.fe-page-structure .fe-page-structure-row-label-input:hover {
  border-color: var(--border);
  background: var(--panel);
}
.fe-page-structure .fe-page-structure-row-label-input:focus {
  border-color: var(--brand, var(--access));
  background: var(--panel);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand, var(--access)) 18%, transparent);
}
/* Single-block rows (homepage non-split entries) drop the label gutter
   and let the pill span the whole width, since "Row 1 / 1 column" is
   noise when every row is one block. */
@media (min-width: 720px) {
  .fe-page-structure .fe-page-structure-row--single {
    grid-template-columns: 1fr;
    padding: 10px 14px;
  }
  .fe-page-structure .fe-page-structure-row--single .fe-page-structure-col {
    background: transparent;
    border: 0;
    padding: 0;
  }
  .fe-page-structure .fe-page-structure-row--single .fe-page-structure-col-label {
    display: none;
  }
}
/* Per-row action buttons (e.g. "Settings" on the homepage's split rows)
   pin to the bottom of the label gutter on desktop; on mobile they
   wrap below the label text. */
.fe-page-structure .fe-page-structure-row-action {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 4px; align-self: flex-start;
}
.fe-page-structure .fe-page-structure-row-action .icon { width: 14px; height: 14px; }

/* The columns grid honors the row's column count on desktop so the
   admin sees the same shape the public site renders. Below 600 px the
   columns stack to one. */
.fe-page-structure .fe-page-structure-cols {
  display: grid; gap: 10px;
  align-items: stretch;
}
.fe-page-structure .fe-page-structure-cols--1 { grid-template-columns: 1fr; }
.fe-page-structure .fe-page-structure-cols--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.fe-page-structure .fe-page-structure-cols--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.fe-page-structure .fe-page-structure-cols--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 980px) {
  .fe-page-structure .fe-page-structure-cols--4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 600px) {
  .fe-page-structure .fe-page-structure-cols { grid-template-columns: 1fr !important; }
}

.fe-page-structure .fe-page-structure-col {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px 12px;
  display: flex; flex-direction: column; gap: 8px;
  min-width: 0;
}
.fe-page-structure .fe-page-structure-col-label {
  font-weight: 700; font-size: 0.68rem;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted);
}
.fe-page-structure .fe-page-structure-block-list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.fe-page-structure .fe-page-structure-block {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: 8px;
  background: var(--brand-soft, var(--panel-2));
  color: var(--text); font-size: 0.875rem; font-weight: 500;
  border: 1px solid var(--border);
  text-align: left; font-family: inherit;
}
/* Clickable variant — buttons that open the matching content-edit modal.
   Cursor + brand-tint hover affordance + a small "Edit" hint that fades
   in on hover so first-time admins know the pill is a button. */
.fe-page-structure .fe-page-structure-block.is-clickable {
  cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, transform 140ms ease;
}
.fe-page-structure .fe-page-structure-block.is-clickable:hover {
  background: var(--brand, var(--access));
  border-color: var(--brand, var(--access));
  color: #fff;
}
.fe-page-structure .fe-page-structure-block.is-clickable:hover .fe-page-structure-block-icon { color: #fff; }
.fe-page-structure .fe-page-structure-block.is-clickable:focus-visible {
  outline: 2px solid var(--brand, var(--access));
  outline-offset: 2px;
}
.fe-page-structure-block-edit-hint {
  margin-left: auto;
  padding: 2px 8px; border-radius: 999px;
  font-size: 0.65rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  background: rgba(255, 255, 255, 0.18); color: inherit;
  opacity: 0; transition: opacity 140ms ease;
}
.fe-page-structure .fe-page-structure-block.is-clickable:hover .fe-page-structure-block-edit-hint { opacity: 1; }
/* Flat row of pills for prebuilt layouts (no rows × cols structure). */
.fe-page-structure-flat {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding-top: 4px;
}

/* "(Customized)" tag in the structure card heading — shown when the
   page has structurally edited away from its prebuilt layout's stamp.
   Subtle accent so it reads as a status, not a warning. */
.fe-page-customized-tag {
  display: inline-flex; align-items: center;
  margin-left: 4px; padding: 1px 8px;
  font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--brand, var(--access));
  background: var(--brand-soft, var(--panel-2));
  border: 1px solid var(--brand-soft, var(--border));
  border-radius: 999px;
  cursor: help;
}

/* "Change layout" shortcut button on the structure card head — opens
   the picker modal so the admin can swap to a different layout (or
   Custom for free-form). Only rendered for layouts that have an
   active key. */
.fe-page-structure-edit-btn {
  display: inline-flex; align-items: center; gap: 6px;
  margin-left: auto;
}
.fe-page-structure-edit-btn .icon { width: 14px; height: 14px; }
.fe-page-structure .fe-page-structure-block-icon {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--brand, var(--access));
  flex: 0 0 auto;
}
.fe-page-structure .fe-page-structure-block-icon .icon { width: 14px; height: 14px; }
.fe-page-structure .fe-page-structure-empty {
  padding: 12px 0; font-style: italic; text-align: center; color: var(--muted);
}

/* Single-column container row inside the structure tree — keeps the
   row-label gutter (so the admin sees "Container · single column")
   and renders its lone cell with the same panel-card chrome a
   2-column row uses, instead of stripping it like a single-block row
   would. The pills inside stack vertically so a Container holding
   heading + paragraph + list reads as a column of 3 pills, not a
   single opaque "Container" pill. */
.fe-page-structure .fe-page-structure-row--single-container .fe-page-structure-col {
  background: var(--panel);
  border: 1px solid var(--border);
  padding: 10px 12px 12px;
}

/* Nested container rows — any row sitting inside another container's
   column cell. The top-level rows pick up a 130 px label gutter at
   ≥720 px so the row-num / chip / Settings / Remove buttons sit to
   the LEFT of the columns grid. That layout doesn't survive nesting:
   each level of nesting carves another ~130 px off the inner row's
   available width, and three deep the drop zone collapses to nothing
   at typical admin viewports.
   Override: nested rows always stack the label + action buttons
   ABOVE their columns grid, and lay the label out as a single
   horizontal strip (input + chip + Settings + Remove) so the gutter
   stays compact. The full-width drop zone underneath remains usable
   no matter how deep the nest goes. */
.fe-page-structure .fe-page-structure-col .fe-page-structure-row {
  grid-template-columns: 1fr;
  padding: 10px 12px;
  gap: 8px;
}
.fe-page-structure .fe-page-structure-col .fe-page-structure-row-label {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.fe-page-structure .fe-page-structure-col .fe-page-structure-row-label-input {
  flex: 1 1 160px;
  min-width: 0;
}
.fe-page-structure .fe-page-structure-col .fe-page-structure-row-action {
  margin-top: 0;
  align-self: auto;
}

/* Section-title divider in the page admin's structure tree. Renders
   between rows as a low-volume label so the admin can tell which
   section a block belongs to without burying the block pills inside
   nested cards. */
.fe-page-structure .fe-page-structure-section-label {
  font-weight: 700; font-size: 0.7rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted);
  padding: 6px 4px 0; margin-top: 4px;
}
.fe-page-structure .fe-page-structure-section-label:first-child { margin-top: 0; }

/* Page-edit screen title banner — sits above the first card so the
   admin always knows which page they're editing. Uses the same panel
   tokens as a card but with reduced padding and no shadow so it reads
   as a header strip rather than a content card. */
.fe-page-edit-title-banner {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 20px;
  margin-bottom: 12px;
  display: flex; flex-direction: column; gap: 4px;
}
.fe-page-edit-title-banner-eyebrow {
  font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
}
.fe-page-edit-title-banner-title {
  font-size: 1.5rem; font-weight: 700; margin: 0; line-height: 1.2;
  color: var(--text);
}
.fe-page-edit-title-banner-meta {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.fe-page-edit-title-banner-meta code {
  background: var(--panel-2); padding: 1px 8px; border-radius: 6px;
  font-size: 0.8125rem;
}

/* ---- Per-block content-edit modals ----
   Shared between footer and homepage block editors. Each block's
   content-editor lives in its own modal; the modal-panel already
   provides flex-column scroll-aware layout. Default size is the
   global modal-panel max-width (680px); the --wide modifier bumps it
   to 960px for editors with dense rows (link columns, locations,
   features, etc.). Modals stay inside the page's save form so their
   fields submit normally with the yellow save bar's POST. */
.fe-page-edit-modal .modal-panel {
  width: min(680px, calc(100vw - 32px));
  max-width: min(680px, calc(100vw - 32px));
}
.fe-page-edit-modal--wide .modal-panel {
  width: min(960px, calc(100vw - 32px));
  max-width: min(960px, calc(100vw - 32px));
}
/* Per-page hero edit modal sits on its own width bump — the inline
   live-preview + 3-column form (text / background / buttons) need
   more room than the standard wide modal allows, especially with
   the typography + background grid showing all eight panels
   simultaneously. Scoped so other --wide modals stay at 960px. */
#page-hero-edit-modal.fe-page-edit-modal--wide .modal-panel,
#page-hero-edit-modal .modal-panel {
  width: min(1280px, calc(100vw - 32px));
  max-width: min(1280px, calc(100vw - 32px));
}
/* Sticky footer — the modal is tall (preview + Text / Background /
   Buttons columns), so the Done button sat way down past the scroll
   fold. Pinning the form-actions row to the bottom of the modal
   panel's scroll viewport keeps the action button reachable from
   any scroll position. `position: sticky` rides on the panel's own
   `overflow-y: auto`. A frosted-glass background + top hairline +
   slight upward shadow visually separates it from the form content
   sliding behind. */
#page-hero-edit-modal .hero-unified-actions {
  position: sticky;
  bottom: 0;
  z-index: 6;
  /* The host `.card` carries a symmetric `padding: 2rem`. Negative
     horizontal margins pull the footer through the padding so it
     spans edge-to-edge of the panel; matching inner padding restores
     the visual gutter the buttons sit in. The negative bottom margin
     eats the card's `padding-bottom` so sticky pins to the panel's
     true bottom edge (no empty strip below). */
  margin: 24px -2rem -2rem;
  padding: 14px 2rem;
  background: color-mix(in srgb, var(--panel) 94%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-top: 1px solid var(--border);
  box-shadow: 0 -6px 18px -10px rgba(15, 23, 42, 0.15);
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
html[data-theme="dark"] #page-hero-edit-modal .hero-unified-actions {
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  box-shadow: 0 -6px 18px -10px rgba(0, 0, 0, 0.45);
}

/* Wrapper variant for the homepage admin: editor cards live inside a
   modal panel as-is (the existing <section class="card"> becomes the
   panel content). The panel itself scrolls when content overflows; the
   nested card is flushed (no margin/border) so the card+panel reads as
   one surface, not two. The X close button floats top-right inside the
   panel. */
.fe-page-edit-modal-panel {
  padding: 0;
  overflow-y: auto;
  position: relative;
  /* Flex column lets the close button align-self to the right edge as
     a sticky child without wrapping it in extra markup. */
  display: flex;
  flex-direction: column;
}
.fe-page-edit-modal-panel > .card {
  margin: 0;
  border: 0;
  border-radius: 14px;
  box-shadow: none;
  /* Symmetric 2rem horizontal padding (inherited from .card) so the
     form body is centered. The close button is a sticky sibling that
     overlays the top-right; `.card-head` carries its own
     `padding-right: 64px` to clear the toggle from under the button. */
}
/* Sticky title strip. Stays anchored to the top of the scrolling
   panel as the form scrolls so the visitor always knows which block
   they're editing. Side margin negation + matching inner padding
   makes the head span the full panel width even though the card
   itself carries 2rem horizontal padding. The right-padding on the
   head covers the floating close button so the title text never
   slides under it. */
.fe-page-edit-modal-panel > .card > .card-head {
  position: sticky;
  top: 0;
  z-index: 4;
  background: var(--panel);
  margin: 0 -2rem 12px;
  padding: 16px 64px 14px 2rem;
  border-bottom: 1px solid var(--border);
}
/* Close button: switched from `position: absolute` to `position:
   sticky` so it stays pinned to the visible top-right of the panel
   regardless of scroll. Negative margin-bottom pulls the card back
   up so the button doesn't reserve a 44px empty strip above the
   title. z-index 6 layers it above the sticky card-head (z-index 4)
   so the title text passes harmlessly underneath. */
.fe-page-edit-modal-close {
  position: sticky;
  top: 12px;
  align-self: flex-end;
  margin: 12px 12px -44px 0;
  z-index: 6;
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
}

/* Inclusion block admin editor — heading row pairs the icon trigger with
   the heading input, then body / tags / CTA / alignment stack below. */
.fe-inc-editor .fe-inc-head-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px 16px; align-items: end;
  margin: 6px 0 12px;
}
.fe-inc-editor .fe-inc-icon-cell {
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
}
.fe-inc-editor .fe-inc-icon-trigger {
  width: 64px; height: 64px;
  display: inline-flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px;
  padding: 8px; border-radius: 12px;
  background: var(--panel-2); color: var(--text);
  border: 1px dashed var(--border); cursor: pointer;
}
.fe-inc-editor .fe-inc-icon-trigger:hover {
  background: var(--panel); border-color: var(--brand, var(--border));
}
.fe-inc-editor .fe-inc-icon-trigger .icon-picker-preview { display: inline-flex; --icon-size: 26px; }
.fe-inc-editor .fe-inc-icon-trigger .icon-picker-preview:empty { display: none; }
.fe-inc-editor [data-icon-field].has-icon .icon-picker-trigger-empty { display: none; }
.fe-inc-editor [data-icon-field].has-icon .fe-inc-icon-trigger { border-style: solid; }
.fe-inc-editor .fe-inc-heading-cell { display: flex; flex-direction: column; gap: 6px; }
.fe-inc-editor .fe-inc-cta-row {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr);
  gap: 12px 16px; margin-top: 6px;
}
@media (max-width: 720px) {
  .fe-inc-editor .fe-inc-head-row,
  .fe-inc-editor .fe-inc-cta-row { grid-template-columns: 1fr; }
}
.fe-inc-editor .fe-inc-align-row {
  display: flex; align-items: center; gap: 14px; margin-top: 8px;
}
.fe-inc-editor .fe-inc-align-opt {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
}
.fe-inc-editor .fe-inc-align-opt input { margin: 0; }

/* Inclusion icon controls — color toggle + swatch + size slider + reset.
   Sits in a single flex row under the icon trigger / heading row, so the
   admin can tweak appearance without re-opening the icon picker modal. */
.fe-inc-editor .fe-inc-icon-controls {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 14px 18px; margin: 0 0 14px;
  padding: 10px 12px; background: var(--panel-2);
  border: 1px solid var(--border); border-radius: 10px;
}
.fe-inc-editor .fe-inc-icon-color-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.9rem; cursor: pointer;
}
.fe-inc-editor .fe-inc-icon-color-toggle input { margin: 0; }
.fe-inc-editor .fe-inc-icon-color-swatch {
  width: 40px; height: 28px; padding: 0;
  border: 1px solid var(--border); border-radius: 6px; cursor: pointer;
  background: transparent;
}
.fe-inc-editor .fe-inc-icon-color-swatch[disabled] { opacity: 0.45; cursor: not-allowed; }
.fe-inc-editor .fe-inc-icon-size-label {
  display: inline-flex; align-items: center; gap: 8px;
  flex: 1 1 220px; min-width: 200px;
}
.fe-inc-editor .fe-inc-icon-size-label input[type="range"] {
  flex: 1 1 auto; min-width: 120px; accent-color: var(--access, #4f46e5);
}
.fe-inc-editor .fe-inc-icon-size-label output { font-variant-numeric: tabular-nums; }
.fe-inc-editor .fe-inc-icon-size-reset { white-space: nowrap; }

@media (max-width: 640px) {
  .fe-feat-card {
    grid-template-columns: auto auto minmax(0, 1fr);
    grid-template-areas:
      "handle icon fields"
      "remove remove remove";
  }
  .fe-feat-card-handle  { grid-area: handle; }
  .fe-feat-card-icon    { grid-area: icon; }
  .fe-feat-card-fields  { grid-area: fields; }
  .fe-feat-card-remove  { grid-area: remove; justify-self: end; }
}

/* Meetings-list template thumbnails — three suggestive miniatures for
   the picker on /tspro/frontend/templates. Same 140px-tall canvas as
   the meeting/event thumbs, but each shape hints at the layout's
   chrome (sidebar rail, sticky toolbar, week columns). */
.fe-tplgrid-thumb-meetings-list .t-side {
  position: absolute; left: 8px; top: 12px; width: 26%; bottom: 12px;
  background: rgba(99, 102, 241, 0.18);
  border-radius: 6px;
  display: flex; flex-direction: column; gap: 5px; padding: 6px 5px;
}
.fe-tplgrid-thumb-meetings-list .t-side > span {
  display: block; height: 8px; border-radius: 3px;
  background: rgba(255, 255, 255, 0.85);
}
.fe-tplgrid-thumb-meetings-list .t-side > span:first-child {
  background: #6366f1;
}
.fe-tplgrid-thumb-meetings-list .t-main {
  position: absolute; right: 8px; top: 12px; left: 38%; bottom: 12px;
}
.fe-tplgrid-thumb-meetings-list .t-main .t-grid {
  position: absolute; inset: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px;
}
.fe-tplgrid-thumb-meetings-list .t-main .t-grid > span {
  display: block; background: #fff; border-radius: 4px;
  border: 1px solid #e2e8f0;
}
.fe-tplgrid-thumb-meetings-list .t-toolbar {
  position: absolute; left: 8px; right: 8px; top: 10px; height: 24px;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 6px;
}
.fe-tplgrid-thumb-meetings-list .t-toolbar::after {
  content: ""; position: absolute; right: 6px; top: 6px; bottom: 6px;
  width: 70px;
  background: linear-gradient(90deg,
    #818cf8 0 18px, transparent 18px 22px,
    #cbd5e1 22px 38px, transparent 38px 42px,
    #cbd5e1 42px 58px, transparent 58px 62px,
    #cbd5e1 62px 70px);
  border-radius: 4px;
}
.fe-tplgrid-thumb-meetings-list .t-row {
  position: absolute; left: 8px; right: 8px; height: 18px;
  background: #fff; border: 1px solid #e2e8f0; border-radius: 4px;
}
.fe-tplgrid-thumb-meetings-list .t-row:nth-of-type(1) { top: 44px; }
.fe-tplgrid-thumb-meetings-list .t-row:nth-of-type(2) { top: 66px; }
.fe-tplgrid-thumb-meetings-list .t-row:nth-of-type(3) { top: 88px; }
.fe-tplgrid-thumb-meetings-list .t-row:nth-of-type(4) { top: 110px; }
.fe-tplgrid-thumb-meetings-list .t-week {
  position: absolute; inset: 12px;
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px;
}
.fe-tplgrid-thumb-meetings-list .t-week > span {
  background: #fff; border: 1px solid #e2e8f0; border-radius: 3px;
  position: relative;
}
.fe-tplgrid-thumb-meetings-list .t-week > span::before {
  content: ""; position: absolute; left: 3px; right: 3px; top: 4px; height: 4px;
  background: #6366f1; border-radius: 2px; opacity: 0.7;
}
.fe-tplgrid-thumb-meetings-list .t-week > span::after {
  content: ""; position: absolute; left: 3px; right: 3px; top: 12px; height: 3px;
  background: #cbd5e1; border-radius: 2px;
}

/* Events-list template thumbnails — four sketches mirroring each
   layout's defining shape (stacked rows, calendar grid, timeline
   spine, magazine hero + tiles). Same canvas as the meetings-list
   thumbs so the picker reads as a uniform grid. */
.fe-tplgrid-thumb-events-list .t-row {
  position: absolute; left: 8px; right: 8px; height: 22px;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 6px;
}
.fe-tplgrid-thumb-events-list .t-row:nth-of-type(1) { top: 14px; }
.fe-tplgrid-thumb-events-list .t-row:nth-of-type(2) { top: 42px; }
.fe-tplgrid-thumb-events-list .t-row:nth-of-type(3) { top: 70px; }
.fe-tplgrid-thumb-events-list .t-row:nth-of-type(4) { top: 98px; }
.fe-tplgrid-thumb-events-list .t-row::before {
  content: ""; position: absolute; left: 4px; top: 4px; bottom: 4px; width: 14px;
  background: #818cf8; border-radius: 3px;
}

.fe-tplgrid-thumb-events-list .t-cal-toolbar {
  position: absolute; left: 8px; right: 8px; top: 10px; height: 14px;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 4px;
}
.fe-tplgrid-thumb-events-list .t-cal-toolbar::after {
  content: ""; position: absolute; left: 50%; transform: translateX(-50%);
  top: 3px; width: 40px; height: 8px;
  background: #cbd5e1; border-radius: 2px;
}
.fe-tplgrid-thumb-events-list .t-cal-grid {
  position: absolute; inset: 30px 8px 8px;
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px;
  background: #cbd5e1;
}
.fe-tplgrid-thumb-events-list .t-cal-grid > span {
  background: #fff; position: relative;
}
.fe-tplgrid-thumb-events-list .t-cal-grid > span.dot::after {
  content: ""; position: absolute; right: 2px; bottom: 2px;
  width: 4px; height: 4px;
  background: #818cf8; border-radius: 50%;
}

.fe-tplgrid-thumb-events-list .t-tl-spine {
  position: absolute; left: 50%; top: 8px; bottom: 8px; width: 2px;
  background: #818cf8; transform: translateX(-50%);
}
.fe-tplgrid-thumb-events-list .t-tl-row {
  position: absolute; height: 18px;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 4px;
}
.fe-tplgrid-thumb-events-list .t-tl-row-left { left: 14px; right: 56%; }
.fe-tplgrid-thumb-events-list .t-tl-row-right { left: 56%; right: 14px; }
.fe-tplgrid-thumb-events-list .t-tl-row:nth-of-type(2) { top: 18px; }
.fe-tplgrid-thumb-events-list .t-tl-row:nth-of-type(3) { top: 60px; }
.fe-tplgrid-thumb-events-list .t-tl-row:nth-of-type(4) { top: 102px; }

.fe-tplgrid-thumb-events-list .t-mag-hero {
  position: absolute; left: 8px; right: 8px; top: 12px; height: 56px;
  background: linear-gradient(135deg, #818cf8 0%, #c4b5fd 100%);
  border-radius: 6px;
}
.fe-tplgrid-thumb-events-list .t-mag-tile {
  position: absolute; top: 80px; height: 44px;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 4px;
}
.fe-tplgrid-thumb-events-list .t-mag-tile:nth-of-type(2) { left: 8px;  width: 30%; }
.fe-tplgrid-thumb-events-list .t-mag-tile:nth-of-type(3) { left: 36%;  width: 28%; }
.fe-tplgrid-thumb-events-list .t-mag-tile:nth-of-type(4) { right: 8px; width: 30%; }

/* Omni thumb — segmented tab strip on top + a single panel below
   suggesting "all four views, switchable". */
.fe-tplgrid-thumb-events-list .t-omni-tabs {
  position: absolute; left: 50%; top: 14px;
  transform: translateX(-50%);
  display: flex; gap: 2px;
  padding: 3px;
  background: #e2e8f0;
  border-radius: 10px;
}
.fe-tplgrid-thumb-events-list .t-omni-tab {
  display: block; width: 16px; height: 8px;
  background: #cbd5e1; border-radius: 4px;
}
.fe-tplgrid-thumb-events-list .t-omni-tab.is-active {
  background: #6366f1;
}
.fe-tplgrid-thumb-events-list .t-omni-panel {
  position: absolute; left: 8px; right: 8px; top: 42px; bottom: 8px;
  background: #fff; border: 1px solid #cbd5e1;
  border-radius: 6px;
}
.fe-tplgrid-thumb-events-list .t-omni-panel::before {
  content: ""; position: absolute; left: 8px; right: 8px; top: 8px; height: 6px;
  background: linear-gradient(90deg, #818cf8 0 22%, transparent 22% 26%,
                                       #cbd5e1 26% 78%, transparent 78% 82%,
                                       #cbd5e1 82% 100%);
  border-radius: 2px;
}
.fe-tplgrid-thumb-events-list .t-omni-panel::after {
  content: ""; position: absolute; left: 8px; right: 8px; top: 22px; bottom: 8px;
  background:
    linear-gradient(transparent 0, #f1f5f9 0 8px, transparent 8px 12px,
                                    #f1f5f9 12px 20px, transparent 20px 24px,
                                    #f1f5f9 24px 32px);
  border-radius: 2px;
}

/* Archive template thumbnails — four sketches matching each archive
   layout's defining chrome (sidebar rail, timeline spine, dense rows,
   magazine hero). Same canvas as the events-list thumbs so the picker
   reads as a uniform grid. */
.fe-tplgrid-thumb-archive .t-side {
  position: absolute; left: 8px; top: 12px; width: 26%; bottom: 12px;
  background: rgba(99, 102, 241, 0.18);
  border-radius: 6px;
  display: flex; flex-direction: column; gap: 5px; padding: 6px 5px;
}
.fe-tplgrid-thumb-archive .t-side > span {
  display: block; height: 8px; border-radius: 3px;
  background: rgba(255, 255, 255, 0.85);
}
.fe-tplgrid-thumb-archive .t-side > span:first-child { background: #6366f1; }
.fe-tplgrid-thumb-archive .t-main {
  position: absolute; right: 8px; top: 12px; left: 38%; bottom: 12px;
}
.fe-tplgrid-thumb-archive .t-main .t-row {
  position: absolute; left: 0; right: 0; height: 18px;
  background: #fff; border: 1px solid #e2e8f0; border-radius: 4px;
}
.fe-tplgrid-thumb-archive .t-main .t-row:nth-of-type(1) { top: 6px; }
.fe-tplgrid-thumb-archive .t-main .t-row:nth-of-type(2) { top: 30px; }
.fe-tplgrid-thumb-archive .t-main .t-row:nth-of-type(3) { top: 54px; }

.fe-tplgrid-thumb-archive .t-strip {
  position: absolute; left: 8px; right: 8px; top: 10px; height: 18px;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 4px;
}
.fe-tplgrid-thumb-archive .t-strip::after {
  content: ""; position: absolute; right: 6px; top: 5px; bottom: 5px;
  width: 64px;
  background: linear-gradient(90deg,
    #818cf8 0 16px, transparent 16px 20px,
    #cbd5e1 20px 36px, transparent 36px 40px,
    #cbd5e1 40px 56px, transparent 56px 60px,
    #cbd5e1 60px 64px);
  border-radius: 3px;
}
.fe-tplgrid-thumb-archive .t-tl-spine {
  position: absolute; left: 50%; top: 36px; bottom: 8px; width: 2px;
  background: #818cf8; transform: translateX(-50%);
}
.fe-tplgrid-thumb-archive .t-tl-row {
  position: absolute; height: 18px;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 4px;
}
.fe-tplgrid-thumb-archive .t-tl-row-left  { left: 10px; right: 56%; }
.fe-tplgrid-thumb-archive .t-tl-row-right { left: 56%; right: 10px; }
.fe-tplgrid-thumb-archive .t-tl-row:nth-of-type(3) { top: 40px; }
.fe-tplgrid-thumb-archive .t-tl-row:nth-of-type(4) { top: 68px; }
.fe-tplgrid-thumb-archive .t-tl-row:nth-of-type(5) { top: 96px; }

.fe-tplgrid-thumb-archive .t-cl-row {
  position: absolute; left: 8px; right: 8px; height: 16px;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 4px;
}
.fe-tplgrid-thumb-archive .t-cl-row::before {
  content: ""; position: absolute; left: 4px; top: 3px; bottom: 3px; width: 12px;
  background: #818cf8; border-radius: 2px;
}
.fe-tplgrid-thumb-archive .t-cl-row:nth-of-type(2) { top: 36px; }
.fe-tplgrid-thumb-archive .t-cl-row:nth-of-type(3) { top: 56px; }
.fe-tplgrid-thumb-archive .t-cl-row:nth-of-type(4) { top: 76px; }
.fe-tplgrid-thumb-archive .t-cl-row:nth-of-type(5) { top: 96px; }

.fe-tplgrid-thumb-archive .t-mag-hero {
  position: absolute; left: 8px; right: 8px; top: 36px; height: 44px;
  background: linear-gradient(135deg, #818cf8 0%, #c4b5fd 100%);
  border-radius: 6px;
}
.fe-tplgrid-thumb-archive .t-mag-tile {
  position: absolute; top: 90px; height: 30px;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 4px;
}
.fe-tplgrid-thumb-archive .t-mag-tile:nth-of-type(3) { left: 8px;  width: 30%; }
.fe-tplgrid-thumb-archive .t-mag-tile:nth-of-type(4) { left: 36%;  width: 28%; }
.fe-tplgrid-thumb-archive .t-mag-tile:nth-of-type(5) { right: 8px; width: 30%; }

.fe-mlist-width-fieldset {
  margin: 18px 0 4px;
  display: flex; flex-direction: column; gap: 10px;
}
.fe-mlist-width-fieldset legend {
  font-weight: 600; padding: 0 6px;
}
.fe-mlist-width-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 10px;
}
.fe-mlist-width-row .check {
  align-items: flex-start; gap: 10px;
  padding: 12px; border: 1px solid var(--border);
  border-radius: 8px; cursor: pointer;
}
.fe-mlist-width-row .check:hover { background: var(--panel-2); }
.fe-mlist-width-row .check input { margin-top: 3px; }
.fe-mlist-width-controls {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px;
  margin-top: 4px;
}
.fe-mlist-width-pad {
  display: flex; align-items: center; gap: 12px;
  font-size: 0.92rem;
}
.fe-mlist-width-pad input {
  width: 110px; padding: 6px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  font-family: inherit; font-size: 0.95rem;
}

/* Markdown editor with live side-by-side preview. The textarea is the
   real form input; the right-hand pane is rendered HTML from marked.js
   refreshed on every keystroke. Below 720px the panes stack so the
   editor stays usable in narrow modal panels. */
.md-editor {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 4px;
}
.md-editor-input,
.md-editor-preview {
  min-height: 180px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
  font: inherit;
  line-height: 1.5;
  box-sizing: border-box;
}
.md-editor-input {
  resize: vertical;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 0.9rem;
}
.md-editor-preview {
  overflow: auto;
  background: var(--panel-2);
}
.md-editor-preview > *:first-child { margin-top: 0; }
.md-editor-preview > *:last-child { margin-bottom: 0; }
.md-editor-preview p { margin: 0.4em 0; }
.md-editor-preview ul,
.md-editor-preview ol { margin: 0.4em 0; padding-left: 1.4em; }
.md-editor-preview h1,
.md-editor-preview h2,
.md-editor-preview h3 { margin: 0.6em 0 0.3em; line-height: 1.25; }
.md-editor-preview code {
  padding: 1px 5px; border-radius: 3px;
  background: rgba(15, 23, 42, 0.06);
  font-size: 0.92em;
}
.md-editor-preview pre {
  padding: 10px 12px; border-radius: 6px;
  background: rgba(15, 23, 42, 0.06);
  overflow: auto;
}
.md-editor-preview-empty { display: block; padding: 4px 0; }
@media (max-width: 720px) {
  .md-editor { grid-template-columns: 1fr; }
}

/* Backend meeting-detail location block — multi-line address rendering
   when the meeting points at a saved Location row. The name is
   bolder; street + city/state/zip read as quieter follow-up lines. */
.loc-block { line-height: 1.4; }
/* Location name reads as a plain first line — the rest of the address
   carries the same weight, only the value-text colour is muted to
   suggest hierarchy without bolding. */
.loc-name { font-weight: 400; }
.loc-line { color: var(--muted); }
.loc-notes {
  margin-top: 6px;
  padding-left: 10px;
  border-left: 2px solid var(--border, #e2e8f0);
  /* Preserve newlines from the textarea so each line of notes renders
     on its own line without any HTML in the source. */
  white-space: pre-line;
}

/* "Pro Tips" admin fieldset on the Templates page — laid out as a
   responsive 2-up grid so heading + subheading sit side-by-side and
   the icon/colour controls share a row beneath. The JSON textarea
   for items lives in a collapsed <details> below since it's an
   advanced override. */
.fe-mlist-protips-fieldset {
  margin-top: 14px;
  display: flex; flex-direction: column; gap: 10px;
}
.fe-mlist-protips-fieldset legend { font-weight: 600; padding: 0 6px; }
.fe-mlist-protips-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 10px;
}
.fe-mlist-protips-grid label { display: flex; flex-direction: column; gap: 4px; font-size: 0.92rem; }
.fe-mlist-protips-grid input[type="text"] {
  padding: 6px 10px; border: 1px solid var(--border); border-radius: 6px;
  font: inherit;
}
.fe-mlist-protips-grid input[type="color"] {
  width: 80px; height: 36px; padding: 2px;
  border: 1px solid var(--border); border-radius: 6px;
}
/* Extended-content section in the meeting edit modal — toggle gates
   the per-block editor below it; each block is a card with optional
   title input + Markdown body textarea + trash button. Stacked
   vertically; "Add block" appends a fresh row via the cloned
   <template>. */
.fe-meeting-extended-fieldset {
  display: flex; flex-direction: column; gap: 10px;
}
.fe-meeting-extended-toggle {
  align-self: flex-start;
  display: flex; align-items: center; gap: 10px;
  cursor: pointer;
}
.fe-meeting-extended-editor {
  display: flex; flex-direction: column; gap: 10px;
  padding-top: 4px;
}
.fe-meeting-extended-list {
  display: flex; flex-direction: column; gap: 10px;
}
.fe-meeting-extended-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 32px;
  gap: 12px;
  padding: 12px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  align-items: start;
}
.fe-meeting-extended-card-fields { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.fe-meeting-extended-card-fields input[type="text"] {
  padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  font: inherit; font-weight: 500;
}
.fe-meeting-extended-card-fields textarea {
  padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  font: inherit; font-size: 0.92rem; line-height: 1.45;
  resize: vertical;
  min-height: 100px;
}
.fe-meeting-extended-card-remove {
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid transparent;
  border-radius: 6px; color: var(--muted);
  cursor: pointer;
}
.fe-meeting-extended-card-remove:hover {
  background: rgba(220, 38, 38, 0.08);
  color: #dc2626;
  border-color: rgba(220, 38, 38, 0.24);
}
.fe-meeting-extended-card-remove .icon { width: 16px; height: 16px; }
@media (max-width: 600px) {
  .fe-meeting-extended-card {
    grid-template-columns: 1fr;
    grid-template-areas:
      "fields"
      "remove";
  }
  .fe-meeting-extended-card-fields { grid-area: fields; }
  .fe-meeting-extended-card-remove { grid-area: remove; justify-self: end; }
}

/* Pro Tips item editor — vertical stack of per-item cards with an
   icon-picker trigger on the left, fields in the middle, and a
   trash button on the right. Mirrors the homepage FAQ editor's
   geometry but skips the drag handle since reorder isn't wired up
   yet. */
.fe-protips-items-editor { margin-top: 4px; display: flex; flex-direction: column; gap: 10px; }
.fe-protips-items-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px;
}
.fe-protips-items-label { font-weight: 600; }
.fe-protips-items-list { display: flex; flex-direction: column; gap: 10px; }
.fe-protips-item-card {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) 32px;
  gap: 12px;
  padding: 12px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  align-items: start;
}
.fe-protips-item-icon { display: flex; align-items: center; justify-content: center; }
.fe-protips-icon-trigger {
  width: 56px; height: 56px;
  display: flex; align-items: center; justify-content: center;
  background: #fff; border: 1px dashed var(--border); border-radius: 8px;
  cursor: pointer; color: var(--muted);
  font: inherit;
}
.fe-protips-item-icon.has-icon .fe-protips-icon-trigger {
  border-style: solid; color: var(--brand, #6366f1);
}
.fe-protips-item-icon.has-icon .icon-picker-trigger-empty { display: none; }
/* The base .icon-picker-preview rule is `display: none`; flip it to
   inline-flex once the wrapper carries .has-icon so the chosen icon
   actually renders inside the trigger button. Without this the
   trigger reads as an empty white box even after the admin picks an
   icon. Mirrors the same pattern the homepage FAQ + nav-megalink
   editors use. */
.fe-protips-item-icon.has-icon .icon-picker-preview { display: inline-flex; }
.fe-protips-icon-trigger .icon-picker-preview .icon { width: 28px; height: 28px; }

/* Section-level icon field on the Pro Tips fieldset shares the same
   trigger chrome but sits inside a label column so its dimensions
   and `has-icon` selector live on the field wrapper, not the per-
   tip wrapper. */
.fe-protips-section-icon-field {
  display: inline-flex;
  margin-top: 4px;
}
.fe-protips-section-icon-trigger { width: 56px; height: 56px; }
.fe-protips-section-icon-field.has-icon .fe-protips-section-icon-trigger {
  border-style: solid; color: var(--brand, #6366f1);
}
.fe-protips-section-icon-field.has-icon .icon-picker-trigger-empty { display: none; }
.fe-protips-section-icon-field.has-icon .icon-picker-preview { display: inline-flex; }
.fe-protips-section-icon-field:not(.has-icon) .icon-picker-preview { display: none; }
.fe-protips-icon-trigger .icon-picker-trigger-empty {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  font-size: 0.7rem;
}
.fe-protips-item-fields { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.fe-protips-item-question {
  padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  font: inherit; font-weight: 500;
}
.fe-protips-item-answer {
  padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  font: inherit; font-size: 0.92rem; line-height: 1.4;
  resize: vertical;
}
.fe-protips-item-remove {
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid transparent;
  border-radius: 6px; color: var(--muted);
  cursor: pointer;
}
.fe-protips-item-remove:hover { background: rgba(220, 38, 38, 0.08); color: #dc2626; border-color: rgba(220, 38, 38, 0.24); }
.fe-protips-item-remove .icon { width: 16px; height: 16px; }
@media (max-width: 600px) {
  .fe-protips-item-card {
    grid-template-columns: 56px minmax(0, 1fr);
    grid-template-areas:
      "icon fields"
      "remove remove";
  }
  .fe-protips-item-icon { grid-area: icon; }
  .fe-protips-item-fields { grid-area: fields; }
  .fe-protips-item-remove { grid-area: remove; justify-self: end; }
}

/* ── Sidebar custom-links editor (Sidebar template only) ─────────── */
.fe-mlist-links-fieldset {
  border: 1px solid var(--border);
  padding: 12px 14px; border-radius: 10px;
  background: var(--panel);
}
.fe-mlist-links-fieldset legend { font-weight: 600; padding: 0 6px; }
.fe-mlist-links-editor {
  display: flex; flex-direction: column; gap: 10px;
}
.fe-mlist-links-list {
  display: flex; flex-direction: column; gap: 10px;
}
.fe-mlist-link-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 32px;
  gap: 12px;
  padding: 12px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  align-items: start;
}
.fe-mlist-link-fields {
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
}
.fe-mlist-link-label,
.fe-mlist-link-url {
  padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  font: inherit;
  background: var(--panel);
  color: var(--text);
}
.fe-mlist-link-label { font-weight: 500; }
.fe-mlist-link-url { font-size: 0.92rem; }
/* Type radio + new-tab checkbox sit on one row. The radios use
   chip-style buttons so the icon (chevron / external) reads as part
   of the label. Native radio bullet hidden; the chip border conveys
   selection state. */
.fe-mlist-link-options {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 12px;
}
.fe-mlist-link-type {
  display: inline-flex; gap: 4px;
  padding: 3px; background: var(--panel);
  border: 1px solid var(--border); border-radius: 8px;
}
.fe-mlist-link-type-opt {
  position: relative;
  display: inline-flex; align-items: center;
}
.fe-mlist-link-type-opt input[type="radio"] {
  position: absolute; opacity: 0; pointer-events: none;
}
.fe-mlist-link-type-opt > span {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border-radius: 6px;
  font-size: 0.86rem; font-weight: 500; color: var(--muted);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.fe-mlist-link-type-opt > span .icon {
  width: 14px; height: 14px;
}
.fe-mlist-link-type-opt:hover > span { color: var(--text); }
.fe-mlist-link-type-opt input[type="radio"]:checked + span {
  background: var(--brand-soft, color-mix(in srgb, var(--brand, #6366f1) 14%, transparent));
  color: var(--text);
}
.fe-mlist-link-newtab {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.88rem; color: var(--text); cursor: pointer;
}
.fe-mlist-link-remove {
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid transparent;
  border-radius: 6px; color: var(--muted);
  cursor: pointer;
}
.fe-mlist-link-remove:hover {
  background: rgba(220, 38, 38, 0.08); color: #dc2626;
  border-color: rgba(220, 38, 38, 0.24);
}
.fe-mlist-link-remove .icon { width: 16px; height: 16px; }
@media (max-width: 600px) {
  .fe-mlist-link-card {
    grid-template-columns: 1fr;
  }
  .fe-mlist-link-remove { justify-self: end; }
}

/* ===== Forms admin index (/tspro/frontend/forms) =====
   Each registered form renders as one row: icon chip on the left,
   name + description + meta in the middle, Configure button +
   enable toggle on the right. The .mode-toggle base style already
   lives above; we only add a small inline label so the toggle
   reads "On" / "Off" alongside its track. */
.fe-forms-list { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 8px; }
.fe-forms-row {
  display: grid;
  grid-template-columns: 44px 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.fe-forms-row-icon {
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--brand, var(--access)) 12%, transparent);
  color: var(--brand, var(--access));
  flex-shrink: 0;
}
.fe-forms-row-icon .icon { width: 22px; height: 22px; }
.fe-forms-row-text { min-width: 0; }
.fe-forms-row-name { font-weight: 600; font-size: 0.9875rem; color: var(--text); margin: 0 0 2px; }
.fe-forms-row-desc { margin: 0 0 4px; line-height: 1.45; }
.fe-forms-row-meta { margin: 0; display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: baseline; }
.fe-forms-row-meta code { font-size: 0.78rem; padding: 1px 6px; background: var(--panel-2); border-radius: 4px; }
.fe-forms-row-meta-sep { color: var(--muted); }
.fe-forms-row-actions {
  display: flex; align-items: center; gap: 14px; flex-shrink: 0;
}
.fe-forms-row-toggle {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
}
.fe-forms-row-toggle .mode-toggle-label {
  min-width: 22px; text-align: left; font-weight: 500;
}
@media (max-width: 640px) {
  .fe-forms-row { grid-template-columns: 44px 1fr; }
  .fe-forms-row-actions {
    grid-column: 1 / -1; justify-content: space-between;
    border-top: 1px solid var(--border); padding-top: 12px; margin-top: 4px;
  }
}

/* ===== Block editor: Button block ===== */
.be-button-body { display: flex; flex-direction: column; gap: 10px; }
.be-button-body input[type="text"] { width: 100%; }
.be-checkbox-row { display: flex; gap: 8px; align-items: center; }
.be-button-style-row { gap: 12px; align-items: center; flex-wrap: wrap; }
.be-button-style-lbl { font-weight: 600; min-width: 60px; font-size: 0.875rem; }
.be-button-style-toggle { display: inline-flex; gap: 4px; flex-wrap: wrap; }

.be-button-custom-panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 16px;
  margin-top: 8px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2);
  color: var(--text);
}
.be-button-custom-panel[hidden] { display: none; }
.be-button-color-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.be-button-color-lbl {
  flex: 0 0 auto; min-width: 140px;
  font-size: 0.875rem; font-weight: 500;
}
.be-button-color-row input[type="color"] {
  width: 44px; height: 32px; border: 1px solid var(--border);
  border-radius: 6px; padding: 2px; background: var(--panel);
  cursor: pointer;
}
/* Editable hex input next to each picker. Either the visual swatch
   or this text field can drive the colour; the other side mirrors. */
input.be-button-color-val {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.8125rem;
  padding: 4px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  width: 9ch;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
input.be-button-color-val::placeholder {
  text-transform: none; color: var(--muted); letter-spacing: 0;
}
input.be-button-color-val.is-invalid {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  color: var(--danger);
}

/* Page background colour — three labelled rows (light / mode /
   dark hex). The dark-hex row hides when mode != 'manual'. Swatch
   + hex text + Clear sit on a single line for tight horizontal
   composition. */
.fe-page-bg-color-row {
  display: flex; flex-direction: column; gap: 12px;
}
.fe-page-bg-color-label {
  display: flex; flex-direction: column; gap: 6px;
  font-size: 0.875rem; font-weight: 500;
}
.fe-page-bg-color-pair {
  display: flex; gap: 8px; align-items: center;
}
.fe-page-bg-color-pair input[type="color"] {
  width: 44px; height: 36px; padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
}
.fe-page-bg-color-pair input[type="text"] {
  flex: 1 1 auto;
  font-family: ui-monospace, Menlo, monospace;
}
/* Tokens trigger button — Lucide palette icon, sized to match the
   adjacent Clear button so the row reads as a tight pill cluster. */
.fe-page-bg-color-pair .icon { width: 16px; height: 16px; }

/* Block-editor color clusters get the same 🎨 token button via
   `attachTokenButton()`. Sized to align with the existing Clear
   button without dominating the row. */
.be-container-color .be-token-btn {
  flex: 0 0 auto;
  width: 30px;
  padding: 0;
}
.be-container-color .be-token-btn svg { display: block; margin: auto; }

/* Token popover — anchored under whichever Tokens trigger fired
   it. Uses `position: fixed` so its top/left are simple viewport
   coords (matches what `getBoundingClientRect()` returns), avoiding
   the absolute-relative-to-which-ancestor mismatch that caused the
   popover to land off-screen on first build. */
.fe-page-bg-token-popover {
  position: fixed;
  z-index: 1100;
  max-width: 480px;
  min-width: 320px;
  padding: 14px 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 18px 42px rgba(15, 23, 42, 0.18),
              0 4px 12px rgba(15, 23, 42, 0.10);
}
.fe-page-bg-token-popover[hidden] { display: none !important; }
.fe-page-bg-token-popover-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 4px;
}
.fe-page-bg-token-popover-head h4 {
  margin: 0; font-size: 1rem; font-weight: 700;
}
.fe-page-bg-token-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  margin-top: 10px;
  max-height: 360px;
  overflow-y: auto;
}
.fe-page-bg-token-tile {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  background: var(--panel-2, var(--panel));
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
  text-align: left;
  font: inherit; color: var(--text);
  transition: border-color 120ms ease, transform 120ms ease,
              background 120ms ease;
}
.fe-page-bg-token-tile:hover {
  border-color: var(--brand, var(--access));
  background: var(--panel);
  transform: translateY(-1px);
}
.fe-page-bg-token-swatch {
  flex: 0 0 auto;
  width: 28px; height: 28px;
  border-radius: 6px;
  border: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
}
.fe-page-bg-token-meta {
  display: flex; flex-direction: column; gap: 1px;
  min-width: 0;
}
.fe-page-bg-token-label {
  font-size: 0.86rem; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fe-page-bg-token-hex {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.72rem;
}

/* ===== Pages admin: background editor preview ===== */
.page-bg-grid {
  grid-template-columns: minmax(0, 1fr) minmax(260px, 1fr);
  gap: 28px;
  align-items: start;
}
@media (max-width: 720px) {
  .page-bg-grid { grid-template-columns: 1fr; }
}
.page-bg-controls { display: flex; flex-direction: column; gap: 16px; }
.page-bg-scale { display: flex; flex-direction: column; gap: 6px; }
.page-bg-scale > span { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; font-weight: 600; }
.page-bg-scale > span output { color: var(--muted); font-weight: 500; font-variant-numeric: tabular-nums; }
.page-bg-preview-wrap { display: flex; flex-direction: column; gap: 8px; }
.page-bg-preview-label { font-size: 0.8125rem; font-weight: 600; color: var(--muted); }
.page-bg-preview {
  position: relative;
  min-height: 240px;
  border: 1px dashed var(--border);
  border-radius: 12px;
  background-color: var(--panel-2);
  background-image:
    linear-gradient(45deg, rgba(15,23,42,0.05) 25%, transparent 25%),
    linear-gradient(-45deg, rgba(15,23,42,0.05) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, rgba(15,23,42,0.05) 75%),
    linear-gradient(-45deg, transparent 75%, rgba(15,23,42,0.05) 75%);
  background-size: 16px 16px;
  background-position: 0 0, 0 8px, 8px -8px, -8px 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.page-bg-preview.has-bg { background-color: transparent; }
.page-bg-preview.has-bg .page-bg-preview-empty { display: none; }
.page-bg-preview-empty { padding: 20px; text-align: center; }

/* ===== Pages admin: typography editor ===== */
.page-typo-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
}
@media (max-width: 720px) { .page-typo-grid { grid-template-columns: 1fr; } }
.page-typo-col {
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 10px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  background: var(--panel);
}
.page-typo-col legend { font-weight: 600; padding: 0 6px; font-size: 0.875rem; }
.page-typo-color { display: inline-flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.page-typo-color input[type="color"] {
  width: 44px; height: 32px; border: 1px solid var(--border, #e2e8f0);
  border-radius: 6px; padding: 2px; background: var(--panel);
  cursor: pointer;
}
/* Editable hex input. Empty state shows the "Theme default"
   placeholder; invalid hex flags red until the field is fixed or
   blurred (blur snaps back to the last valid value). */
input.page-typo-color-text {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.8125rem;
  padding: 4px 8px;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  width: 12ch;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
input.page-typo-color-text::placeholder {
  text-transform: none; color: var(--muted, #64748b); letter-spacing: 0;
}
input.page-typo-color-text.is-invalid {
  border-color: #ef4444;
  background: rgba(239, 68, 68, 0.08);
  color: #b91c1c;
}
.page-typo-align { gap: 6px; flex-wrap: wrap; }

/* ===== Block editor: Container block ===== */
.be-container-body {
  display: flex; flex-direction: column; gap: 8px;
}
.be-container-panel {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
  color: var(--text);
}
.be-container-panel > summary {
  cursor: pointer;
  padding: 8px 12px;
  font-weight: 600;
  font-size: 0.9375rem;
  list-style: revert;
  color: var(--text);
}
.be-container-panel > summary::-webkit-details-marker { display: revert; }
.be-container-panel[open] > summary { border-bottom: 1px solid var(--border); }
.be-container-panel-body {
  padding: 12px 14px;
  display: flex; flex-direction: column; gap: 12px;
}
.be-container-row {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 10px;
  align-items: center;
}
/* Visual break above mobile-override rows so the admin can scan the
   "desktop value / mobile override" pairs as separate concerns rather
   than blending into the rest of the form. Paired with the existing
   12px panel-body gap, the total whitespace above the row reads as a
   deliberate section start. */
.be-container-row--mobile-section {
  margin-top: 6px;
  padding-top: 14px;
  border-top: 1px dashed var(--border);
}
.be-container-row-lbl { font-size: 0.875rem; font-weight: 500; }

/* Padding box — visual diagram around four numeric inputs so the
   admin can see at-a-glance which input drives which side. Layout
   is a 5-row × 3-col grid: axis labels on the outer rings, the
   four inputs on the inner cross, and a centred "Padding" tag
   inside the rectangle. The bordered centre + axis lines mirror
   the actual padding the box represents. */
.be-container-row--pad-box {
  grid-template-columns: 140px 1fr;
  align-items: start;
}
.be-pad-box {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: auto auto auto auto auto;
  gap: 4px 8px;
  justify-items: center; align-items: center;
  max-width: 360px;
  padding: 4px;
}
.be-pad-box-axis {
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
}
.be-pad-box-axis--top    { grid-row: 1; grid-column: 2; }
.be-pad-box-axis--bottom { grid-row: 5; grid-column: 2; }
.be-pad-box-axis--left   { grid-row: 3; grid-column: 1; justify-self: end; }
.be-pad-box-axis--right  { grid-row: 3; grid-column: 3; justify-self: start; }
.be-pad-box-cell--top    { grid-row: 2; grid-column: 2; }
.be-pad-box-cell--bottom { grid-row: 4; grid-column: 2; }
.be-pad-box-cell--left   { grid-row: 3; grid-column: 1; }
.be-pad-box-cell--right  { grid-row: 3; grid-column: 3; }
.be-pad-box-center {
  grid-row: 3; grid-column: 2;
  min-width: 80px; min-height: 44px;
  display: flex; align-items: center; justify-content: center;
  background: var(--panel-2);
  border: 1px dashed var(--border);
  border-radius: 6px;
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted);
}
.be-pad-cell-wrap {
  display: inline-flex; align-items: center; gap: 2px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 6px; padding: 2px 4px 2px 6px;
  transition: border-color 120ms ease;
}
.be-pad-cell-wrap:focus-within { border-color: var(--brand, var(--access)); }
.be-pad-cell-wrap > input[type="number"] {
  width: 44px; padding: 4px 2px;
  border: 0; background: transparent; outline: none;
  font-family: inherit; font-size: 0.875rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.be-pad-cell-wrap > input[type="number"]::-webkit-outer-spin-button,
.be-pad-cell-wrap > input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}
.be-pad-cell-wrap > input[type="number"] { -moz-appearance: textfield; }
/* Unit selector sits flush against the number; native chevron is
   suppressed to keep the chip compact, the muted colour tells the
   admin it's a secondary control (the number is the focus). */
.be-pad-cell-unit-sel {
  border: 0; background: transparent; outline: none;
  font-family: inherit; font-size: 0.6875rem; font-weight: 600;
  color: var(--muted); cursor: pointer;
  padding: 2px 2px 2px 0;
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  text-align: center; text-transform: lowercase;
}
.be-pad-cell-unit-sel:focus-visible { color: var(--text); }
.be-pad-cell-unit-sel:hover { color: var(--text); }
.be-pad-cell-unit { font-size: 0.6875rem; }

@media (max-width: 600px) {
  .be-container-row--pad-box { grid-template-columns: 1fr; }
  .be-pad-box { margin-left: 0; }
}

/* ── Grid-column GUI controls ───────────────────────────────────
   Replaces the free-form `grid-template-columns` text input with a
   stepper, preset chips, per-track selectors, and a visual preview
   bar. The CSS is structural only — the JS does all the value
   marshalling. */
.be-container-grid-controls {
  display: flex; flex-direction: column; gap: 0.5rem;
}
.be-grid-stepper {
  display: inline-flex; align-items: center; gap: 6px;
}
.be-grid-stepper .btn { width: 30px; padding: 0; font-size: 1.1rem; line-height: 1; }
.be-grid-count {
  display: inline-block; min-width: 92px; text-align: center;
  font-weight: 600; font-size: 0.92rem;
}
.be-grid-presets {
  display: flex; flex-wrap: wrap; gap: 6px;
}
.be-grid-presets .btn { padding: 4px 10px; font-size: 0.82rem; }
.be-grid-presets .btn.active {
  background: var(--brand, var(--access));
  color: #fff;
  border-color: var(--brand, var(--access));
}
.be-grid-tracks {
  display: flex; flex-direction: column; gap: 6px;
}
.be-grid-track-row {
  display: grid;
  grid-template-columns: 56px 1fr;
  align-items: center; gap: 8px;
}
.be-grid-track-row .be-grid-track-custom {
  grid-column: 2 / -1;
  margin-top: 4px;
}
.be-grid-track-label {
  font-size: 0.78rem; font-weight: 700; color: var(--muted);
  letter-spacing: 0.04em; text-transform: uppercase;
}
.be-grid-track-select { width: 100%; }
/* Live proportion preview — flex segments scale to each track's
   relative weight (1fr → 1, 200px → 2, auto → 1, etc. — see
   trackWeight in block_editor.js). Each segment shows its raw value
   in a monospace caption so the admin can verify the mapping. */
.be-grid-preview {
  display: flex; gap: 4px;
  height: 36px;
  padding: 4px;
  background: var(--panel-2, var(--panel));
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
}
.be-grid-preview-seg {
  display: flex; align-items: center; justify-content: center;
  min-width: 0;
  background: color-mix(in srgb, var(--brand, var(--access)) 18%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand, var(--access)) 40%, transparent);
  border-radius: 4px;
  overflow: hidden;
}
.be-grid-preview-label {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.72rem;
  color: var(--text);
  white-space: nowrap;
  padding: 0 6px;
  text-overflow: ellipsis;
  overflow: hidden;
}
.be-grid-advanced-toggle {
  margin-top: 6px;
  font-size: 0.78rem;
  opacity: 0.85;
}
.be-grid-advanced-toggle:hover { opacity: 1; }
.be-container-row-hint {
  grid-column: 2 / -1;
  margin-top: -4px;
}
.be-container-row > select,
.be-container-row > input[type="text"],
.be-container-row > input[type="number"] { width: 100%; }
.be-container-num-wrap { display: inline-flex; align-items: center; gap: 6px; }
.be-container-num-wrap input[type="number"] { width: 80px; }
.be-container-num-suffix { font-variant-numeric: tabular-nums; }
.be-container-checkbox {
  display: inline-flex; align-items: center; gap: 6px; font-weight: 500;
  font-size: 0.875rem;
}

.be-container-color { display: inline-flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.be-container-color input[type="color"] {
  width: 40px; height: 30px; border: 1px solid var(--border);
  border-radius: 6px; padding: 2px; background: var(--panel);
  cursor: pointer;
}
input.be-container-color-text {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.8125rem;
  padding: 4px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  width: 11ch;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
input.be-container-color-text::placeholder {
  text-transform: none; color: var(--muted); letter-spacing: 0;
}
input.be-container-color-text.is-invalid {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  color: var(--danger);
}

.be-container-width-toggle { display: inline-flex; gap: 6px; flex-wrap: wrap; }

/* Children area — visually distinct from the settings panels above
   so the admin reads "this is the nested content" at a glance. */
.be-container-children {
  margin-top: 4px;
  padding-top: 12px;
  border-top: 1px dashed var(--border);
}
.be-container-children-head {
  font-weight: 600;
  font-size: 0.875rem;
  margin-bottom: 8px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.be-container-children .be-blocks {
  background: var(--panel);
  border: 1px dashed var(--border, #e2e8f0);
  border-radius: 8px;
  padding: 8px;
  min-height: 40px;
}
.be-container-children .be-blocks:empty::before {
  content: "Drop blocks here or use + below to nest content.";
  font-size: 0.8125rem;
  color: var(--muted, #64748b);
  display: block;
  text-align: center;
  padding: 12px 8px;
}

/* ===== Pages admin: layout-structure card actions + block-flash ===== */
.fe-page-structure-actions {
  display: flex; gap: 8px; flex-wrap: wrap;
  padding: 12px 0 4px;
}
/* Soft yellow flash applied to a .be-block when the admin clicks its
   structure-card pill. Fades back to the resting state after the
   keyframe runs once. Only used inside the page-edit modal — keeps
   focus visible without a hard outline. */
@keyframes be-block-flash {
  0%   { box-shadow: 0 0 0 0 rgba(250, 204, 21, 0.55); }
  60%  { box-shadow: 0 0 0 6px rgba(250, 204, 21, 0.25); }
  100% { box-shadow: 0 0 0 0 rgba(250, 204, 21, 0); }
}
.be-block-flash {
  animation: be-block-flash 1.4s ease-out;
}

/* Focus mode — set on .fe-page-edit-modal when the admin enters by
   clicking a structure pill (vs clicking "Edit layout"). Hides every
   block + section that isn't on the path to the focused block, so
   the modal reads as a per-block editor instead of the whole tree.
   Closing the modal clears focus so the next open lands fresh. */
.fe-page-edit-modal.is-focus-mode .be-section-head,
.fe-page-edit-modal.is-focus-mode .be-add-section,
.fe-page-edit-modal.is-focus-mode .be-add-block-bar { display: none; }
.fe-page-edit-modal.is-focus-mode .be-section { border: 0; padding: 0; }
.fe-page-edit-modal.is-focus-mode .be-section:not(.be-block-focused-path) { display: none; }
.fe-page-edit-modal.is-focus-mode .be-block:not(.be-block-focused):not(.be-block-focused-path) {
  display: none;
}
/* Path-only blocks (containers wrapping the focused block) keep their
   chrome but drop the drag handle / type label / remove button — the
   admin is editing INSIDE them, not editing them. Container settings
   (layout / spacing / background / hover details panels + the
   "Children" label) also hide so the focused descendant is the only
   thing the admin sees. The child blocks list itself stays visible
   so the focused block keeps rendering through its container chain. */
.fe-page-edit-modal.is-focus-mode .be-block-focused-path > .be-block-head { display: none; }
.fe-page-edit-modal.is-focus-mode .be-block-focused-path > .be-container-body > .be-container-panel,
.fe-page-edit-modal.is-focus-mode .be-block-focused-path .be-container-children-head { display: none; }
.fe-page-edit-modal.is-focus-mode .be-block-focused-path { border: 0; padding: 0; background: transparent; }
/* The focused block IS the modal's subject — its drag handle, type
   label, and × remove button are all redundant once we're in
   per-block edit mode. Hide the head and drop the outline so the
   modal reads as a clean settings sheet for whatever block was
   clicked. The body keeps rendering normally so the actual controls
   (Layout / Spacing / etc.) sit at the top of the modal. */
.fe-page-edit-modal.is-focus-mode .be-block-focused > .be-block-head { display: none; }
.fe-page-edit-modal.is-focus-mode .be-block-focused {
  outline: 0;
  border: 0;
  padding: 0;
  background: transparent;
}

/* Edit-block modal head — push the × close button 1rem away from
   the title so they don't sit visually glued together. The modal-
   head is a flex row whose `space-between` lets the title fill
   middle space; the explicit gap on the close button reserves a
   minimum air-gap regardless of viewport width. */
.fe-page-edit-modal .modal-head { gap: 1rem; }
.fe-page-edit-modal .modal-head > .icon-btn[data-close] { margin-left: 1rem; }

/* Icon block — visual preview card. The visual box renders the
   actual SVG (or <img> for custom icons) at the chosen `font-size`
   so `.icon { width: 1em; height: 1em }` scales it up. A meta row
   below shows the icon ref + size + colour so the admin can reach
   the exact stored values without inspecting the JSON. The card
   uses a checkered background so transparent / tinted icons stay
   visible against the panel. */
.be-icon-picker-trigger { width: auto; align-self: flex-start; }
.be-icon-preview-card {
  display: flex; flex-direction: column; align-items: stretch;
  gap: 10px;
  padding: 14px;
  border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
}
.be-icon-visual {
  display: flex; align-items: center; justify-content: center;
  min-height: 96px;
  padding: 16px;
  border-radius: 8px;
  background: var(--panel);
  background-image:
    linear-gradient(45deg, var(--border) 25%, transparent 25%),
    linear-gradient(-45deg, var(--border) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--border) 75%),
    linear-gradient(-45deg, transparent 75%, var(--border) 75%);
  background-size: 12px 12px;
  background-position: 0 0, 0 6px, 6px -6px, -6px 0px;
  color: var(--text);
  /* SVG inherits font-size from its parent's inline `font-size` (set
     by the editor's renderVisualPreview), and `.icon { 1em }` does
     the rest. Cap height generously so icons up to 256px can render
     without the card growing absurdly tall on small viewports. */
  overflow: hidden;
  max-height: 320px;
}
.be-icon-visual.is-empty {
  font-style: italic; color: var(--muted);
  background-image: none;
  font-size: 0.875rem;
}
.be-icon-visual .icon { display: block; }
.be-icon-visual img.icon-custom { max-width: 100%; max-height: 100%; }
.be-icon-visual-meta {
  font-family: ui-monospace, Menlo, monospace;
  text-align: center;
}

/* Image block — Browse / Upload row + live preview. Buttons sit
   inline so the admin sees both options without scrolling. */
.be-image-source-row {
  display: flex; gap: 8px; flex-wrap: wrap;
  margin-top: 4px;
}
.be-image-source-row .btn { flex: 0 0 auto; }
.be-preview { display: block; max-width: 220px; max-height: 160px;
  border-radius: 8px; margin-top: 6px;
  background: var(--panel-2); border: 1px solid var(--border); }

/* Intergroup member block — admin preview card. Same styling as the
   public render but boxed and tinted so admins can see the result
   inside the editor without it blending into surrounding controls. */
.be-officer-body { gap: 12px; }
.be-officer-select { width: 100%; }
.be-officer-fields {
  display: flex; flex-direction: column; gap: 4px;
  padding: 8px 10px;
  background: var(--panel-2, var(--panel));
  border: 1px solid var(--border);
  border-radius: 8px;
}
.be-officer-fields-label { margin-bottom: 2px; }
.be-officer-preview-wrap {
  display: flex; flex-direction: column; gap: 6px;
}
.be-officer-preview {
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2, var(--panel));
  min-height: 40px;
}
.be-officer-preview.is-empty {
  font-style: italic; color: var(--muted);
  font-size: 0.875rem;
  text-align: center;
}
.be-officer-preview-card {
  display: flex; flex-direction: column; gap: 4px;
}
.be-officer-preview-card .be-officer-role {
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted);
}
.be-officer-preview-card .be-officer-name {
  font-size: 1.1rem; font-weight: 700;
}
.be-officer-preview-card .be-officer-phone,
.be-officer-preview-card .be-officer-email {
  font-size: 0.92rem; color: var(--text);
}

/* Officer roster preview — mirrors the public-side card chrome so
   admins see the same shadow + rounded corners they'll get on the
   live page. The grid template / gap ride inline styles set by JS. */
.be-officer-roster-preview {
  display: grid;
  padding: 4px;
}
.be-officer-roster-card {
  display: flex; flex-direction: column; gap: 4px;
  padding: 1rem 1.25rem;
  background: var(--panel, #fff);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 4px 10px rgba(0,0,0,0.06);
}
.be-officer-roster-card.is-empty {
  font-style: italic; color: var(--muted);
  text-align: center;
  padding: 1rem;
}
.be-officer-roster-card .be-officer-role {
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted);
}
.be-officer-roster-card .be-officer-name {
  font-size: 0.95rem; font-weight: 700;
}
.be-officer-roster-card .be-officer-phone,
.be-officer-roster-card .be-officer-email {
  font-size: 0.82rem; color: var(--text);
}

/* Lottie block — preview card mirrors the icon block's checkered
   stage so admins can see the animation against a non-solid backdrop
   (most lottie files are transparent). The stage is fixed-height so
   tall animations don't push the modal layout around; the SVG
   lottie-web injects scales itself to fit. */
.be-lottie-preview-card {
  display: flex; flex-direction: column; align-items: stretch;
  gap: 10px;
  padding: 14px;
  border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
}
.be-lottie-stage {
  /* Aspect ratio mirrors the public stage — set after the editor
     preview's animation finishes loading. The fallback is 16/9 (a
     reasonable mid-shape for unknown content) which is overridden as
     soon as the JSON resolves. `max-height` clamps tall animations so
     the modal doesn't grow unwieldy; the SVG inside scales itself
     proportionally via lottie-web's preserveAspectRatio. */
  width: 100%;
  aspect-ratio: var(--lottie-ratio, 16 / 9);
  max-height: 280px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px;
  background: var(--panel);
  background-image:
    linear-gradient(45deg, var(--border) 25%, transparent 25%),
    linear-gradient(-45deg, var(--border) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--border) 75%),
    linear-gradient(-45deg, transparent 75%, var(--border) 75%);
  background-size: 12px 12px;
  background-position: 0 0, 0 6px, 6px -6px, -6px 0px;
  overflow: hidden;
}
.be-lottie-stage.is-empty {
  font-style: italic; color: var(--muted);
  background-image: none;
  font-size: 0.875rem;
}
.be-lottie-stage > svg,
.be-lottie-stage > canvas {
  display: block;
  width: 100%; height: 100%; max-height: 240px;
}
.be-lottie-meta {
  font-family: ui-monospace, Menlo, monospace;
  text-align: center;
  word-break: break-all;
}

/* Image library picker modal — thumbnail grid + drop-zone uploader.
   Sized wide so a generous grid fits on desktop; falls back to a
   single column on mobile. */
.fe-image-picker-modal .modal-panel {
  width: min(960px, calc(100vw - 32px));
  max-width: min(960px, calc(100vw - 32px));
  max-height: 90vh;
  display: flex; flex-direction: column;
}
.fe-image-picker-modal .modal-head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 18px; border-bottom: 1px solid var(--border);
}
.fe-image-picker-modal .modal-head h2 { margin: 0; flex: 0 0 auto; }
.be-image-picker-search {
  flex: 1 1 0; min-width: 0; padding: 6px 10px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel); color: var(--text);
}
.fe-image-picker-modal .modal-body {
  padding: 16px 18px; overflow-y: auto;
  display: flex; flex-direction: column; gap: 14px;
}
.be-image-picker-uploader {
  display: flex; flex-direction: column; gap: 6px;
}
.be-image-picker-drop {
  display: block; border: 2px dashed var(--border); border-radius: 12px;
  padding: 22px 16px; text-align: center; cursor: pointer;
  background: var(--panel-2); color: var(--muted);
  transition: border-color 120ms ease, background 120ms ease, color 120ms ease;
}
.be-image-picker-drop:hover,
.be-image-picker-drop.is-drop-target {
  border-color: var(--brand, var(--access));
  background: var(--brand-soft);
  color: var(--text);
}
.be-image-picker-drop input[type=file] { display: none; }
.be-image-picker-drop-label b { color: var(--text); }
.be-image-picker-status { min-height: 1em; }

.be-image-picker-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
.be-image-picker-tile {
  display: flex; flex-direction: column; gap: 6px;
  padding: 8px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--border);
  cursor: pointer; text-align: left; font: inherit; color: var(--text);
  transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;
}
.be-image-picker-tile:hover {
  border-color: var(--brand, var(--access));
  transform: translateY(-1px);
  box-shadow: var(--shadow);
}
.be-image-picker-thumb {
  display: block; aspect-ratio: 4 / 3;
  background: var(--panel-2); border-radius: 6px; overflow: hidden;
}
.be-image-picker-thumb img {
  display: block; width: 100%; height: 100%; object-fit: contain;
}
.be-image-picker-name {
  font-size: 0.78rem; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.be-image-picker-empty { text-align: center; padding: 24px 0; }

/* Color picker with dark-mode mode toggle — used by typography,
   container bg/border, etc. Three rows stacked: light swatch + hex
   + clear; mode toggle [Same | Auto | Manual]; manual dark swatch
   + hex + clear (visible only in Manual mode); auto-derived preview
   chip (visible only in Auto mode). */
.be-color-with-dm {
  display: flex; flex-direction: column; gap: 6px;
  width: 100%;
}
.be-color-dm-mode-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 0.75rem;
}
.be-color-dm-mode-row .be-color-dm-label {
  letter-spacing: 0.04em; text-transform: uppercase;
}
.be-color-dm-row { /* manual hex+swatch row */ }
.be-color-dm-auto-row {
  display: flex; align-items: center; gap: 8px;
  font-size: 0.78rem;
}
.be-color-dm-auto-swatch {
  display: inline-block; width: 14px; height: 14px;
  border-radius: 4px; border: 1px solid var(--border);
  vertical-align: middle;
}
.be-color-dm-auto-preview {
  font-family: ui-monospace, Menlo, monospace;
}

/* Per-block typography panel (heading / paragraph / list). Reuses the
   container-panel chrome so the visual rhythm of "click block →
   collapsible settings panel below the body" stays consistent. */
.be-typo-panel { margin-top: 4px; }
.be-typo-align { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.be-typo-align .btn.active { background: var(--brand); color: #fff; border-color: var(--brand); }

/* Range slider in the image block ("Width  100%") — inline output
   uses the same muted style the bg-scale slider does. */
.be-body label > output { color: var(--muted); font-variant-numeric: tabular-nums; }

/* ── Hover preview popover ──────────────────────────────────────
   Floating card shown when the admin hovers a structure-card pill /
   orphan-bin pill. Body content is JS-rendered from each pill's
   `data-preview` JSON. Pinned to viewport via fixed positioning so
   sticky / scrolled sections don't clip it. */
.fe-pill-preview {
  position: fixed; z-index: 1000;
  max-width: 320px; min-width: 180px;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 10px;
  box-shadow: var(--shadow);
  padding: 12px 14px;
  font-size: 0.875rem; line-height: 1.45;
  pointer-events: none;
  opacity: 0; transform: translateY(-4px);
  transition: opacity 120ms ease, transform 120ms ease;
}
.fe-pill-preview.is-visible { opacity: 1; transform: translateY(0); }
.fe-pill-preview-label {
  font-weight: 700; font-size: 0.7rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
  margin-bottom: 6px;
}
.fe-pill-preview-text {
  white-space: pre-wrap; word-break: break-word;
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical;
  overflow: hidden;
}
.fe-pill-preview-sub { margin-top: 6px; }
.fe-pill-preview-img {
  display: block; max-width: 100%; max-height: 120px;
  border-radius: 6px; margin-bottom: 8px;
  background: var(--panel-2);
}

/* ── Block palette (floating) ───────────────────────────────────
   Anchored to the lower-right corner of the page-edit screen as a
   collapsible floating panel. Two states:
     • Collapsed → only the FAB pill is visible.
     • Expanded → the full panel slides up from the FAB with a scale
       + fade animation; the FAB tucks away.
   The wrapper itself is `position: fixed`, sitting above page content
   but below modal overlays (z-index 1000 vs the page-edit-modal's
   higher stack). Drag-drop wiring keys off `[data-be-palette]` on
   the inner grid, so positioning is purely cosmetic — palette tiles
   stay HTML5-draggable to anywhere a Sortable zone exists. */
.fe-page-palette-floating {
  position: fixed;
  right: clamp(16px, 2vw, 28px);
  bottom: clamp(16px, 2vw, 28px);
  z-index: 1000;
  /* Reserve space so the FAB has somewhere to sit when the panel
     animates out of the way; height is dictated by whichever child
     is showing. The wrapper itself never has a backdrop. */
  pointer-events: none;
}
.fe-page-palette-floating > * { pointer-events: auto; }

/* ── FAB (collapsed state) ─────────────────────────────────────
   A pill-shaped button that reads "+ Add block" — visible whenever
   the panel is closed. Hovers lift slightly for affordance, and on
   the wrapper's `is-open` state the FAB tucks down + fades to clear
   the panel's stage. */
.fe-page-palette-fab {
  display: inline-flex; align-items: center; gap: 8px;
  height: 48px;
  padding: 0 20px 0 16px;
  border-radius: 999px;
  border: 0;
  background: var(--brand, var(--access));
  color: #fff;
  font-weight: 600; font-size: 0.92rem;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18),
              0 2px 6px rgba(15, 23, 42, 0.08);
  transform: translateY(0) scale(1);
  opacity: 1;
  transition: transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1),
              opacity 200ms ease,
              box-shadow 240ms ease;
}
.fe-page-palette-fab:hover {
  transform: translateY(-2px) scale(1.02);
  box-shadow: 0 14px 32px rgba(15, 23, 42, 0.22),
              0 4px 8px rgba(15, 23, 42, 0.1);
}
.fe-page-palette-fab:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--brand, var(--access)) 35%, transparent);
  outline-offset: 3px;
}
.fe-page-palette-fab .fe-page-palette-fab-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 50%;
}
.fe-page-palette-fab .fe-page-palette-fab-icon .icon {
  width: 14px; height: 14px;
}
.fe-page-palette-floating.is-open .fe-page-palette-fab {
  transform: translateY(12px) scale(0.85);
  opacity: 0;
  pointer-events: none;
}

/* ── Panel (expanded state) ────────────────────────────────────
   Rounded card with header + grid. Anchored to the wrapper's
   bottom-right corner (same origin as the FAB) so the open/close
   animation reads as the panel growing OUT of the FAB. The grid
   inside scrolls when the catalog overflows, but the head / hint
   stay pinned at the top. */
.fe-page-palette-panel {
  position: absolute;
  right: 0; bottom: 0;
  width: min(420px, calc(100vw - 32px));
  max-height: min(560px, calc(100vh - 64px));
  display: flex; flex-direction: column; gap: 10px;
  padding: 16px 16px 18px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.20),
              0 6px 14px rgba(15, 23, 42, 0.10);
  transform-origin: bottom right;
  transform: translateY(8px) scale(0.94);
  opacity: 0;
  pointer-events: none;
  transition: transform 280ms cubic-bezier(0.2, 0.8, 0.2, 1),
              opacity 220ms ease;
}
.fe-page-palette-floating.is-open .fe-page-palette-panel {
  transform: translateY(0) scale(1);
  opacity: 1;
  pointer-events: auto;
}
.fe-page-palette-panel-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px;
}
.fe-page-palette-panel-title {
  display: flex; align-items: center; gap: 8px;
}
.fe-page-palette-panel-title h3 {
  margin: 0; font-size: 1rem; font-weight: 700;
}
.fe-page-palette-panel-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  background: var(--brand-soft, var(--panel-2));
  color: var(--brand, var(--access));
  border-radius: 8px;
}
.fe-page-palette-panel-icon .icon { width: 14px; height: 14px; }
.fe-page-palette-close { flex: 0 0 auto; }
.fe-page-palette-hint { margin: 0; }

/* Grid stretches to fill the remaining vertical space and scrolls
   when the catalog grows beyond the panel's max-height. The
   auto-fill column rule keeps tiles tidy whether there are 6 or 16. */
.fe-page-palette-grid {
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  overflow-y: auto;
  padding: 2px;  /* breathing room so focus rings aren't clipped */
}
.fe-page-palette-tile {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
  color: var(--text); cursor: grab; user-select: none;
  transition: border-color 120ms ease, transform 120ms ease, background 120ms ease;
}
.fe-page-palette-tile:hover {
  border-color: var(--brand, var(--access));
  transform: translateY(-1px);
  background: var(--panel);
}
.fe-page-palette-tile:active,
.fe-page-palette-tile.is-dragging { cursor: grabbing; opacity: 0.55; }
.fe-page-palette-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; flex: 0 0 30px;
  background: var(--brand-soft, var(--panel)); border-radius: 6px;
  color: var(--brand, var(--access));
}
.fe-page-palette-icon .icon { width: 16px; height: 16px; }
.fe-page-palette-name { font-weight: 600; font-size: 0.875rem; }

/* ── Orphan-bin card ────────────────────────────────────────────
   Hidden when there are no orphans. Pills inside reuse the structure-
   card pill chrome so they read as the same kind of object — the bin
   is just a parking spot. The drop zone gets a dashed outline so it's
   discoverable as a target. */
/* When the orphan bin is empty, the card stays visible (so drops
   are always possible) but reads as muted + collapsed-ish. Used to
   `display: none` here, but that broke the "drag any unwanted block
   into the bin" workflow because the zone wasn't reachable. */
.fe-page-orphans.is-empty { opacity: 0.6; }
.fe-page-orphans.is-empty .fe-page-orphans-list {
  min-height: 56px;
}
.fe-page-orphans.is-empty .fe-page-orphans-list::before {
  content: 'Drop blocks here to park them — they survive layout switches and saves.';
  display: block;
  text-align: center; padding: 14px 16px;
  color: var(--muted); font-style: italic; font-size: 0.85rem;
}
.fe-page-orphans.is-empty .fe-page-orphans-list:has(> .fe-page-structure-block)::before {
  display: none;
}
.fe-page-orphans-list {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding: 12px; border: 1px dashed var(--border); border-radius: 10px;
  background: var(--panel-2); min-height: 56px;
}
.fe-page-orphans-list .fe-page-structure-block {
  background: var(--panel);
}

/* ── Drag-drop affordances ──────────────────────────────────────
   While dragging, the source pill / palette tile dims, the hovered
   zone gets a brand-tinted outline, and the Sortable ghost shows the
   intended drop position. */
.fe-page-structure .fe-page-structure-block-list[data-be-zone] {
  min-height: 36px; transition: background 120ms ease, border-color 120ms ease;
  border: 1px dashed transparent; border-radius: 8px; padding: 4px;
}

/* Flex-container drop zones flow pills in the same direction the
   public renderer will use, so the admin sees the actual layout shape
   instead of always-stacked columns. Wrap is on so a long horizontal
   row of pills folds onto a second line at narrow widths rather than
   pushing the zone wider than its cell. */
.fe-page-structure .fe-page-structure-block-list--flex {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-start;
}
.fe-page-structure .fe-page-structure-block-list--flex-row { flex-direction: row; }
.fe-page-structure .fe-page-structure-block-list--flex-row-reverse { flex-direction: row-reverse; }
.fe-page-structure .fe-page-structure-block-list--flex-column,
.fe-page-structure .fe-page-structure-block-list--flex-column-reverse {
  flex-direction: column; flex-wrap: nowrap;
  /* Pills in a column-flow zone stretch the full cell width so the
     admin can read long block labels + reach the hover Edit / × at
     the right edge. Cross-axis stretch is what column flexboxes do
     in CSS too, so the editor matches the public render. */
  align-items: stretch;
}
.fe-page-structure .fe-page-structure-block-list--flex-column-reverse { flex-direction: column-reverse; }
.fe-page-structure .fe-page-structure-block-list--flex-column > .fe-page-structure-block,
.fe-page-structure .fe-page-structure-block-list--flex-column-reverse > .fe-page-structure-block {
  width: 100%;
  align-self: stretch;
}
/* In row flow each pill should size to its content (not stretch the
   width of the zone) so multiple pills can sit side-by-side. */
.fe-page-structure .fe-page-structure-block-list--flex-row > .fe-page-structure-block,
.fe-page-structure .fe-page-structure-block-list--flex-row-reverse > .fe-page-structure-block {
  width: auto;
  flex: 0 0 auto;
}

/* Root zone — the rows container itself is a top-level drop target
   for Container / Two-panel / leaf palette tiles. The dashed outline
   only shows during a palette drag-over so it doesn't visually
   compete with normal browsing. */
.fe-page-structure-rows[data-be-zone="root"].is-drop-target {
  outline: 2px dashed var(--brand, var(--access));
  outline-offset: 6px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--brand, var(--access)) 5%, transparent);
}

/* Empty-state placeholder — visible only when the active layout has
   no rows at all. JS removes it on the first drop. */
.fe-page-structure-root-empty {
  border: 1px dashed var(--border);
  border-radius: 12px;
  padding: 28px 20px;
  text-align: center;
  background: var(--panel-2);
}
.fe-page-structure-rows[data-be-zone="root"]:has(> .fe-page-structure-row) > .fe-page-structure-root-empty,
.fe-page-structure-rows[data-be-zone="root"]:has(> .fe-page-structure-section-label) > .fe-page-structure-root-empty {
  display: none;
}

/* Row drag handle — small grip on the left of row-single rows, plus
   a clickable cursor on row-split rows' label gutter so the admin
   knows the whole label is grabbable. */
.fe-page-row-handle {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; min-height: 28px;
  color: var(--muted);
  cursor: grab; user-select: none;
  border-radius: 6px;
  align-self: center;
  font-family: ui-monospace, monospace;
  font-size: 0.85rem; letter-spacing: -2px;
}
.fe-page-row-handle:hover { color: var(--brand, var(--access)); background: var(--panel-2); }
.fe-page-row-handle:active { cursor: grabbing; }

/* Layout-picker — "Custom" radio preview blocks. Three small dashed
   tiles to differentiate from the prebuilt previews (which are typed
   block colour-blocks). */
.template-card-preview-custom {
  display: flex; align-items: center; justify-content: center;
  gap: 8px; padding: 16px;
}
.template-card-preview-custom .tcp-block {
  width: 28px; height: 28px; border-radius: 6px;
  background: var(--panel); border: 1px dashed var(--border);
}
.template-card.template-card-custom-radio.active .template-card-preview-custom .tcp-block {
  border-color: var(--brand, var(--access));
}

/* Build-a-template tools strip — sits below the picker grid as a
   secondary action. Lower visual weight than the radio cards so
   "Custom" reads as the default free-form path. */
.fe-layout-picker-template-tools {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 14px;
  border-top: 1px solid var(--border);
}
.fe-layout-picker-template-tools .btn .icon { width: 14px; height: 14px; }
.fe-page-row-handle .icon { width: 16px; height: 16px; }
.fe-page-structure-row--single { display: flex; align-items: stretch; gap: 8px; }
.fe-page-structure-row--single > .fe-page-structure-cols { flex: 1 1 auto; min-width: 0; }
.fe-page-structure-row-label { cursor: grab; }
.fe-page-structure-row-label:active { cursor: grabbing; }

/* Row drag visual states — a row being moved fades; the gap where
   it'll land gets a brand-tinted hint. */
.fe-page-structure-row.is-row-dragging { opacity: 0.55; }
.fe-page-structure-row.is-row-ghost {
  outline: 2px dashed var(--brand, var(--access));
  outline-offset: 4px;
  background: color-mix(in srgb, var(--brand, var(--access)) 8%, var(--panel-2));
}
.fe-page-structure-row.is-row-chosen {
  box-shadow: 0 0 0 2px var(--brand, var(--access));
}
.fe-page-structure .fe-page-structure-block-list[data-be-zone].is-drop-target,
.fe-page-orphans-list.is-drop-target {
  border-color: var(--brand, var(--access));
  background: var(--brand-soft);
}
.fe-page-structure-block.is-draggable { cursor: grab; }
.fe-page-structure-block.is-draggable:active,
.fe-page-structure-block.is-dragging { cursor: grabbing; opacity: 0.55; }
.fe-page-structure-block.is-drop-ghost {
  background: var(--brand-soft) !important;
  color: var(--brand, var(--access));
  border-color: var(--brand, var(--access));
  opacity: 0.6;
}
.fe-page-structure-block.is-drop-chosen {
  outline: 2px solid var(--brand, var(--access));
  outline-offset: 2px;
}

/* ⧉ duplicate + × delete buttons — small, subtle by default, brighter
   on hover. Both share the same baseline chrome and reveal pattern;
   only the hover colour differs (duplicate goes brand-tinted, remove
   goes danger). Pinned to the right edge of pills via auto margin so
   the existing "Edit" hint stays visible. Keyboard-focusable for
   accessibility. */
.fe-page-structure-block { position: relative; }
.fe-page-structure-block .fe-page-structure-block-remove,
.fe-page-structure-block .fe-page-structure-block-duplicate {
  flex: 0 0 auto;
  width: 22px; height: 22px; padding: 0;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--muted);
  font-size: 0.95rem; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: 4px;
  opacity: 0; transition: opacity 120ms ease, background 120ms ease, color 120ms ease;
}
.fe-page-structure-block .fe-page-structure-block-remove { font-size: 1rem; }
.fe-page-structure-block:hover .fe-page-structure-block-remove,
.fe-page-structure-block:focus-within .fe-page-structure-block-remove,
.fe-page-structure-block:hover .fe-page-structure-block-duplicate,
.fe-page-structure-block:focus-within .fe-page-structure-block-duplicate {
  opacity: 1;
}
.fe-page-structure-block-remove:hover {
  background: var(--danger);
  color: #fff;
}
.fe-page-structure-block-duplicate:hover {
  background: var(--brand, var(--access));
  color: #fff;
}
.fe-page-structure-block-remove:focus-visible,
.fe-page-structure-block-duplicate:focus-visible {
  opacity: 1;
  outline: 2px solid var(--brand, var(--access));
  outline-offset: 1px;
}
/* When hovering the × / ⧉ so the pill turns brand-tinted, keep the
   icons readable against the tinted background. */
.fe-page-structure-block.is-clickable:hover .fe-page-structure-block-remove,
.fe-page-structure-block.is-clickable:hover .fe-page-structure-block-duplicate {
  color: rgba(255, 255, 255, 0.85);
}
.fe-page-structure-block.is-clickable:hover .fe-page-structure-block-remove:hover {
  background: var(--danger); color: #fff;
}
.fe-page-structure-block.is-clickable:hover .fe-page-structure-block-duplicate:hover {
  background: rgba(255, 255, 255, 0.22); color: #fff;
}

/* Hover-expand: when a clickable pill sits inside a narrow nested
   container cell, the "Edit" hint chip + × remove button at the right
   edge can overflow or get clipped against the cell border, making
   them unreachable. On hover (or keyboard focus-within), grow the
   pill to its natural content width and lift it over neighbouring
   cells so every control is visible and clickable. Cells aren't
   `overflow: hidden`, so the pill simply paints beyond its column
   without disturbing the layout of anything else. */
.fe-page-structure .fe-page-structure-block.is-clickable:hover,
.fe-page-structure .fe-page-structure-block.is-clickable:focus-within {
  position: relative;
  z-index: 5;
  min-width: max-content;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
}

/* Row × button — sits in the row label gutter alongside the Settings
   button on container/2-col rows, and as a top-right icon-button on
   row-single rows. Always visible (admin needs explicit affordance
   for destructive action). */
.fe-page-structure-row-remove { color: var(--danger); }
.fe-page-structure-row-remove:hover {
  background: var(--danger); color: #fff;
  border-color: var(--danger);
}
.fe-page-structure-row-remove .icon { width: 14px; height: 14px; }
.fe-page-structure-row-remove--single {
  align-self: center; flex: 0 0 auto;
  width: 32px; height: 32px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel);
  color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
}
.fe-page-structure-row-remove--single:hover {
  color: #fff; background: var(--danger); border-color: var(--danger);
}

/* Merged Page-settings card — three subsections (Title/URL/publish,
   Page width, Background) live inside one `.fe-page-settings-card`,
   separated by hairlines + sub-headings. The sub-heading row pairs
   the title with a muted helper line so the section's purpose stays
   inline with the section break. */
.fe-page-settings-card .fe-page-settings-section {
  padding-top: 18px;
  margin-top: 18px;
  border-top: 1px solid var(--border);
}
.fe-page-settings-card .fe-page-settings-section:first-of-type {
  padding-top: 0; margin-top: 0; border-top: 0;
}
.fe-page-settings-sub {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px;
  font-size: 0.95rem; font-weight: 700;
  margin: 0 0 12px;
  color: var(--text);
}
.fe-page-settings-sub .muted {
  font-weight: 400; flex: 1 1 auto; min-width: 0;
}

/* Page-width card layout — toggle row on top, range labels stacked
   underneath. Matches `page-bg-grid` rhythm. */
.page-width-grid { display: flex; flex-direction: column; gap: 14px; }
.page-width-num { display: flex; flex-direction: column; gap: 6px; }
.page-width-num > span {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; font-weight: 600;
}
.page-width-num > span output {
  color: var(--muted); font-weight: 500; font-variant-numeric: tabular-nums;
}

/* ── Dynamic-background admin picker ─────────────────────────────
   Renders alongside the existing color/image bg controls anywhere
   the admin can configure a frontend background. Each card shows a
   live thumbnail of the actual dynbg recipe (rendered by the
   public partial frontend/_dynbg.html) at small scale, so the
   admin sees exactly what the visitor will see.

   The picker doesn't replace the colour / image fields — it stacks
   alongside them. A site can use a colour OR a dynbg OR both
   (dynbg paints over the colour). */
.fe-dynbg-picker {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 10px;
  margin: 8px 0;
}
.fe-dynbg-picker-card {
  display: flex;
  flex-direction: column;
  cursor: pointer;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  overflow: hidden;
  transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;
}
.fe-dynbg-picker-card:hover {
  border-color: var(--access);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
}
.fe-dynbg-picker-card.active {
  border-color: var(--access);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--access) 30%, transparent);
}
.fe-dynbg-picker-card input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.fe-dynbg-picker-thumb {
  position: relative;
  display: block;
  width: 100%;
  height: 80px;
  overflow: hidden;
  background: var(--card-soft, #f1f5f9);
}
.fe-dynbg-picker-md .fe-dynbg-picker-thumb { height: 110px; }
/* The dynbg children are absolutely positioned with sized
   `width`/`height` (380px blobs, etc.) — far bigger than the
   thumbnail tile. We scale them down with a CSS transform so a
   single recipe drives both the live render and the preview. */
.fe-dynbg-picker-thumb .fe-dynbg {
  transform: scale(0.45);
  transform-origin: center center;
  width: calc(100% / 0.45);
  height: calc(100% / 0.45);
  inset: auto;
  top: 50%;
  left: 50%;
  margin-left: calc(-50% / 0.45);
  margin-top: calc(-50% / 0.45);
}
.fe-dynbg-picker-thumb-none {
  display: grid;
  place-items: center;
  background:
    repeating-linear-gradient(45deg,
      color-mix(in srgb, var(--text) 6%, transparent) 0 6px,
      transparent 6px 12px);
}
.fe-dynbg-picker-none-icon {
  font-size: 1.6rem; color: var(--muted); font-weight: 300;
}
.fe-dynbg-picker-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
}
.fe-dynbg-picker-name {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text);
}
.fe-dynbg-picker-desc {
  line-height: 1.35;
}

/* ── Dynamic-background trigger button ──────────────────────────
   Drop-in form control that opens the global dynbg picker modal.
   Renders like a row-style "what's selected" control: a small
   thumbnail tile + the preset's display name + a chevron. When no
   preset is selected, the thumbnail is an empty hatched tile with
   the ∅ glyph and the name reads "Choose…". */
.fe-dynbg-trigger-wrap { display: block; margin: 8px 0; }
.fe-dynbg-trigger {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 10px 14px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--text);
  transition: border-color 120ms ease, transform 120ms ease,
              box-shadow 120ms ease, background-color 120ms ease;
}
.fe-dynbg-trigger:hover {
  border-color: var(--access);
  background: color-mix(in srgb, var(--access) 4%, var(--card));
  transform: translateY(-1px);
  box-shadow: 0 4px 10px rgba(15, 23, 42, 0.06);
}
.fe-dynbg-trigger:focus-visible {
  outline: 2px solid var(--access);
  outline-offset: 2px;
}
.fe-dynbg-trigger-thumb {
  flex: 0 0 auto;
  width: 64px;
  height: 44px;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--card-soft, #f1f5f9);
  position: relative;
  display: grid;
  place-items: center;
}
/* Reuse the same scaling trick the picker grid uses so the trigger
   thumb is a tiny live preview. */
.fe-dynbg-trigger-thumb .fe-dynbg {
  transform: scale(0.18);
  transform-origin: center center;
  width: calc(100% / 0.18);
  height: calc(100% / 0.18);
  inset: auto;
  top: 50%;
  left: 50%;
  margin-left: calc(-50% / 0.18);
  margin-top: calc(-50% / 0.18);
}
.fe-dynbg-trigger-thumb-none {
  font-size: 1.5rem;
  color: var(--muted);
  font-weight: 300;
}
.fe-dynbg-trigger-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.fe-dynbg-trigger-name {
  font-size: 0.9375rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.fe-dynbg-trigger-status { line-height: 1.3; }
.fe-dynbg-trigger-caret {
  flex: 0 0 auto;
  color: var(--muted);
  display: grid;
  place-items: center;
}
.fe-dynbg-trigger-caret .icon { width: 16px; height: 16px; }

/* Inside the picker modal — give the grid more breathing room than
   the inline picker and let the modal scroll if the catalog grows. */
#dynbg-picker-modal .modal-body {
  max-height: 70vh;
  overflow-y: auto;
}
.dynbg-modal-blurb { margin: 0 0 16px; }

/* ── Dynbg modal — tabs + colour controls ───────────────────────
   The modal grew from a single picker grid into three panels
   (Background / Overlay / Colours). These rules style the tab bar
   at the top and the colour-input fieldset on the third panel. */
.dynbg-modal-tabs {
  display: flex; gap: 4px;
  padding: 4px;
  background: var(--card-soft, color-mix(in srgb, var(--text) 4%, var(--card)));
  border: 1px solid var(--border);
  border-radius: 10px;
  margin: 0 0 16px;
}
.dynbg-modal-tab {
  flex: 1 1 auto;
  padding: 8px 12px;
  background: transparent;
  border: 0;
  border-radius: 6px;
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--muted);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}
.dynbg-modal-tab:hover { color: var(--text); }
.dynbg-modal-tab.is-active {
  background: var(--card);
  color: var(--text);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
}
.dynbg-modal-panel { display: none; }
.dynbg-modal-panel.is-active { display: block; }

.dynbg-modal-colors {
  display: flex; flex-direction: column;
  gap: 12px;
}
.dynbg-modal-color-row {
  display: flex; align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}
.dynbg-modal-color-label {
  flex: 0 0 auto;
  min-width: 80px;
  font-weight: 600;
  font-size: 0.9375rem;
}
.dynbg-modal-color-controls {
  flex: 1 1 auto;
  display: flex; align-items: center;
  gap: 8px;
}
.dynbg-modal-color-controls input[type="color"] {
  width: 44px; height: 44px;
  padding: 0; border: 1px solid var(--border);
  border-radius: 8px; cursor: pointer;
  background: var(--card);
}
.dynbg-modal-color-controls input[type="text"] {
  flex: 1 1 160px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9375rem;
}
.dynbg-modal-color-clear {
  flex: 0 0 auto;
}

/* Overlay-tab thumbnails sit on a soft brand-tinted plate so the
   overlay's translucent texture is visible in isolation. Without
   this, a 3% noise overlay rendered against the white modal bg is
   essentially invisible. */
.fe-dynbg-overlay-thumb { position: relative; overflow: hidden; }
.fe-dynbg-overlay-thumb-plate {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--access) 18%, var(--card)),
    color-mix(in srgb, var(--access) 6%, var(--card)));
}

/* ── Dynbg modal — extra fieldsets (scope / sliders / randomize) */
.dynbg-modal-fieldset {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  margin: 16px 0 0;
  display: flex; flex-direction: column;
  gap: 8px;
}
.dynbg-modal-fieldset legend {
  font-size: 0.875rem;
  font-weight: 600;
  padding: 0 8px;
  color: var(--text);
}
.dynbg-modal-fieldset[hidden] { display: none; }

.dynbg-modal-scope-row {
  display: flex; flex-direction: column;
  gap: 8px;
}
.dynbg-modal-scope-opt {
  display: flex; align-items: flex-start;
  gap: 10px;
  cursor: pointer;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  transition: border-color 120ms ease, background-color 120ms ease;
}
.dynbg-modal-scope-opt:hover { border-color: var(--access); }
.dynbg-modal-scope-opt input[type="radio"] {
  margin-top: 4px;
  accent-color: var(--access);
}

.dynbg-modal-slider-row {
  display: grid;
  grid-template-columns: 120px 1fr auto;
  gap: 12px;
  align-items: center;
}
.dynbg-modal-slider-label {
  font-weight: 600;
  font-size: 0.9375rem;
}
.dynbg-modal-slider-row input[type="range"] {
  width: 100%;
  accent-color: var(--access);
}

.dynbg-modal-randomize {
  display: flex; align-items: flex-start;
  gap: 10px;
  cursor: pointer;
}
.dynbg-modal-randomize input[type="checkbox"] {
  width: 18px; height: 18px;
  margin-top: 2px;
  accent-color: var(--access);
  flex-shrink: 0;
}

/* ── Templates picker · Site Index thumbs ──────────────────────
   Two layouts share the same base palette as other thumbnails;
   the .t-eyebrow span anchors a section label and the .t-row
   spans become content rows. The Alphabet variant centers a
   single title bar then stacks rows tighter to suggest a flat
   directory.  */
.fe-tplgrid-thumb-site-index .t-eyebrow {
  left: 16px; top: 14px; width: 28%; height: 5px; background: #94a3b8;
  border-radius: 2px;
}
.fe-tplgrid-thumb-site-index .t-eyebrow.t-eyebrow-2 { top: 80px; width: 24%; }
.fe-tplgrid-thumb-site-index .t-row {
  left: 16px; right: 16px; height: 8px; border-radius: 3px;
  background: #cbd5e1;
}
.fe-tplgrid-thumb-site-index-grouped .t-row:nth-of-type(1) { top: 30px; }
.fe-tplgrid-thumb-site-index-grouped .t-row:nth-of-type(2) { top: 48px; width: 70%; }
.fe-tplgrid-thumb-site-index-grouped .t-row:nth-of-type(3) { top: 96px; }
.fe-tplgrid-thumb-site-index-grouped .t-row:nth-of-type(4) { top: 114px; width: 80%; }
.fe-tplgrid-thumb-site-index-alphabet .t-h.centered {
  top: 18px; width: 40%; left: 50%; transform: translateX(-50%);
  height: 9px; background: #475569; border-radius: 3px;
}
.fe-tplgrid-thumb-site-index-alphabet .t-row:nth-of-type(1) { top: 44px; }
.fe-tplgrid-thumb-site-index-alphabet .t-row:nth-of-type(2) { top: 62px; width: 86%; }
.fe-tplgrid-thumb-site-index-alphabet .t-row:nth-of-type(3) { top: 80px; width: 92%; }
.fe-tplgrid-thumb-site-index-alphabet .t-row:nth-of-type(4) { top: 98px; width: 78%; }
.fe-tplgrid-thumb-site-index-alphabet .t-row:nth-of-type(5) { top: 116px; width: 88%; }

/* ── Pages list — sortable headers + bulk-action bar ──────────
   Click-to-sort headers carry a small arrow that fills in once
   a direction is set. The bulk bar sits above the table and is
   shown via JS when at least one row is selected. */
.fe-pages-list-card .tbl thead th.sortable {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.fe-pages-list-card .tbl thead th.sortable:hover {
  background: color-mix(in srgb, var(--brand, #0b5cff) 6%, transparent);
}
.fe-pages-list-card .tbl thead th .fe-sort-arrow {
  display: inline-block;
  margin-left: 4px;
  width: 0; height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  vertical-align: middle;
  opacity: 0.35;
}
.fe-pages-list-card .tbl thead th.sortable .fe-sort-arrow {
  border-bottom: 5px solid currentColor;
  border-top: 5px solid currentColor;
  height: 0; width: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 0;
  border-bottom: 0;
}
.fe-pages-list-card .tbl thead th.sort-asc .fe-sort-arrow {
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-bottom: 5px solid currentColor;
  border-top: 0;
  opacity: 1;
}
.fe-pages-list-card .tbl thead th.sort-desc .fe-sort-arrow {
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  border-bottom: 0;
  opacity: 1;
}

.fe-pages-check-col { width: 28px; text-align: center; }
.fe-pages-check { display: inline-flex; align-items: center; cursor: pointer; }
.fe-pages-check input[type="checkbox"] { accent-color: var(--brand, #0b5cff); }

.fe-pages-bulk-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  margin: 0 0 8px;
  background: color-mix(in srgb, var(--brand, #0b5cff) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand, #0b5cff) 24%, transparent);
  border-radius: 8px;
}
.fe-pages-bulk-count {
  font-weight: 600;
  color: var(--brand, #0b5cff);
}
.fe-pages-bulk-actions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Page edit — visibility fieldset (Draft / Published / Private) */
.fe-page-status-fieldset {
  border: 1px solid var(--border, rgba(0, 0, 0, 0.08));
  border-radius: 8px;
  padding: 10px 14px;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.fe-page-status-fieldset legend {
  padding: 0 6px;
  font-weight: 600;
  font-size: 0.875rem;
}
.fe-page-status-fieldset .check {
  align-items: flex-start;
  gap: 8px;
}

/* Page edit — quick-action status pills under the title banner */
.fe-page-edit-status-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
}
.fe-page-edit-status-actions form { margin: 0; }
.fe-page-edit-status-actions .btn.active {
  background: color-mix(in srgb, var(--brand, #0b5cff) 12%, transparent);
  border-color: color-mix(in srgb, var(--brand, #0b5cff) 28%, transparent);
}

/* ── Blog page block ──────────────────────────────────────────────
   Renders inside any custom Page that drops a `blog_list` block.
   Three styles share the same data shape: cards, list, headlines.
   The blog-cat-chip variable rides the category's hex colour so each
   chip tints to its source category. */
.block-blog { margin: 1.4rem 0; }
.block-blog-head { margin-bottom: 1.4rem; }
.block-blog-title {
  font-family: var(--tpl-heading-font, var(--fe-font-heading, inherit));
  font-weight: 700; font-size: 1.6rem; line-height: 1.15;
  margin: 0 0 .35rem; letter-spacing: -.01em;
}
.block-blog-sub {
  margin: 0; color: var(--muted, #6b7280);
  font-size: 1rem; line-height: 1.55;
}
.block-blog-empty {
  padding: 1rem; background: var(--panel-2, #f3f4f6);
  border-radius: 8px; text-align: center;
}
.block-blog-cats { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: .55rem; }
.block-blog-cat-chip {
  --blog-cat-color: var(--accent, #2563eb);
  color: var(--blog-cat-color);
  background: color-mix(in srgb, var(--blog-cat-color) 14%, transparent);
  padding: 2px 9px; border-radius: 6px;
  font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
}
.block-blog-more { margin-top: 1.4rem; text-align: right; }
.block-blog-more-link {
  color: var(--accent, #2563eb); font-weight: 600; text-decoration: none;
  font-size: .92rem;
}
.block-blog-more-link:hover { text-decoration: underline; }

/* ── Cards style ─────────────────────────────────────────────── */
.block-blog-cards { display: grid; }
.block-blog-card {
  background: var(--panel, #fff);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 12px; overflow: hidden;
  transition: transform .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.block-blog-card:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--accent, #2563eb) 30%, var(--border, #e5e7eb));
  box-shadow: 0 12px 30px -12px rgba(15,23,42,.15);
}
.block-blog-card.is-featured {
  box-shadow: inset 3px 0 0 var(--accent, #2563eb);
}
.block-blog-card-link { display: block; color: inherit; text-decoration: none; }
.block-blog-card-art { aspect-ratio: 16 / 10; overflow: hidden; }
.block-blog-card-art img { width: 100%; height: 100%; object-fit: cover; }
.block-blog-card-body { padding: 1rem 1.2rem 1.2rem; }
.block-blog-card-title {
  font-family: var(--tpl-heading-font, var(--fe-font-heading, inherit));
  font-weight: 700; font-size: 1.1rem; line-height: 1.25;
  margin: 0 0 .5rem;
}
.block-blog-card-summary {
  margin: 0 0 .7rem; color: var(--muted, #6b7280);
  font-size: .9rem; line-height: 1.55;
}
.block-blog-card-meta {
  display: flex; flex-wrap: wrap; gap: .5rem;
  color: var(--muted, #6b7280); font-size: .78rem;
}
.block-blog-card-meta > span + span::before { content: "·"; margin-right: .5rem; opacity: .55; }
@media (max-width: 720px) {
  .block-blog-cards { grid-template-columns: 1fr !important; }
}

/* ── List style ──────────────────────────────────────────────── */
.block-blog-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 1.1rem; }
.block-blog-list-item {
  background: var(--panel, #fff);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 10px; overflow: hidden;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.block-blog-list-item:hover {
  border-color: color-mix(in srgb, var(--accent, #2563eb) 30%, var(--border, #e5e7eb));
  box-shadow: 0 6px 18px -8px rgba(15,23,42,.15);
}
.block-blog-list-link {
  display: grid; grid-template-columns: 180px 1fr; gap: 1rem;
  color: inherit; text-decoration: none; align-items: center;
}
.block-blog-list-link:not(:has(.block-blog-list-art)) { grid-template-columns: 1fr; padding: 1rem 1.2rem; }
@media (max-width: 600px) { .block-blog-list-link { grid-template-columns: 1fr; } }
.block-blog-list-art { aspect-ratio: 4 / 3; overflow: hidden; }
.block-blog-list-art img { width: 100%; height: 100%; object-fit: cover; }
.block-blog-list-body { padding: 1rem 1.2rem; }
.block-blog-list-title {
  font-family: var(--tpl-heading-font, var(--fe-font-heading, inherit));
  font-weight: 700; font-size: 1.1rem; line-height: 1.25;
  margin: 0 0 .4rem;
}
.block-blog-list-summary { margin: 0 0 .55rem; color: var(--muted, #6b7280); font-size: .92rem; line-height: 1.55; }
.block-blog-list-meta { display: flex; flex-wrap: wrap; gap: .5rem; color: var(--muted, #6b7280); font-size: .78rem; }
.block-blog-list-meta > span + span::before { content: "·"; margin-right: .5rem; opacity: .55; }

/* ── Headlines style ─────────────────────────────────────────── */
.block-blog-headlines { list-style: none; padding: 0; margin: 0; }
.block-blog-headline {
  border-bottom: 1px solid var(--border, #e5e7eb);
  padding: .9rem 0;
}
.block-blog-headline:last-child { border-bottom: 0; }
.block-blog-headline a {
  color: inherit; text-decoration: none; display: flex; flex-direction: column; gap: 4px;
}
.block-blog-headline-date {
  text-transform: uppercase; letter-spacing: .12em;
  font-size: .72rem; color: var(--muted, #6b7280);
  font-weight: 600;
}
.block-blog-headline-title {
  font-family: var(--tpl-heading-font, var(--fe-font-heading, inherit));
  font-weight: 700; font-size: 1.18rem; line-height: 1.25;
}
.block-blog-headline a:hover .block-blog-headline-title { color: var(--accent, #2563eb); }
.block-blog-headline-summary {
  color: var(--muted, #6b7280); font-size: .95rem; line-height: 1.5;
}

[data-theme="dark"] .block-blog-card,
[data-theme="dark"] .block-blog-list-item {
  background: var(--panel, #1f2937);
  border-color: var(--border, #374151);
}
[data-theme="dark"] .block-blog-empty {
  background: var(--panel-2, #111827);
}

/* ===== Visitor metrics admin page ===== */
.vm-window-form { display: inline-flex; }
.vm-window-label select {
  padding: 7px 28px 7px 12px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--panel); color: var(--text); font: inherit; cursor: pointer;
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 14px) center, calc(100% - 9px) center;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
.vm-window-label select:hover { border-color: var(--brand); }

.vm-summary-card { margin-bottom: 18px; }
.vm-tiles {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; margin-top: 8px;
}
@media (max-width: 1080px) { .vm-tiles { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px)  { .vm-tiles { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 460px)  { .vm-tiles { grid-template-columns: 1fr; } }

.vm-tile {
  position: relative; padding: 16px 18px;
  border: 1px solid var(--border); border-radius: 12px; background: var(--panel-2);
  display: flex; flex-direction: column; gap: 6px; min-width: 0;
  transition: transform 160ms ease, border-color 160ms ease, box-shadow 160ms ease;
}
.vm-tile:hover { transform: translateY(-2px); border-color: var(--brand);
  box-shadow: 0 8px 22px -12px color-mix(in srgb, var(--brand) 60%, transparent); }
.vm-tile-accent {
  background: linear-gradient(135deg,
                color-mix(in srgb, var(--brand) 14%, var(--panel-2)) 0%,
                var(--panel-2) 80%);
  border-color: color-mix(in srgb, var(--brand) 40%, var(--border));
}
.vm-tile-label {
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted);
}
.vm-tile-value {
  font-size: 1.875rem; font-weight: 700; color: var(--text); line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.vm-tile-accent .vm-tile-value { color: var(--brand); }
.vm-tile-sub { display: flex; align-items: center; min-height: 22px; }
.vm-trend-up   { color: #16a34a; font-weight: 700; }
.vm-trend-down { color: #dc2626; font-weight: 700; }
[data-theme="dark"] .vm-trend-up   { color: #4ade80; }
[data-theme="dark"] .vm-trend-down { color: #f87171; }
.vm-spark-inline { display: inline-block; width: 80px; height: 22px; }
.vm-spark-inline svg { display: block; }

/* Time-series chart */
.vm-chart-card { margin-bottom: 18px; }
.vm-chart-wrap { position: relative; width: 100%; }
.vm-chart { width: 100%; height: auto; display: block; max-height: 360px; }
.vm-grid-line { stroke: var(--border); stroke-width: 1; stroke-dasharray: 2 4; opacity: 0.7; }
.vm-axis-tick { fill: var(--muted); font-size: 11px; font-family: inherit; }
.vm-chart-dot {
  fill: var(--brand); stroke: var(--panel); stroke-width: 2;
  cursor: pointer; transition: r 120ms ease;
}
.vm-chart-dot:hover { r: 6; }
.vm-legend { display: inline-flex; gap: 14px; font-size: 0.8125rem; color: var(--muted); }
.vm-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.vm-legend-swatch {
  display: inline-block; width: 10px; height: 10px; border-radius: 3px;
  background: currentColor;
}
.vm-swatch-views   { background: var(--brand); }
.vm-swatch-uniques { background: linear-gradient(90deg, #9333ea, #06b6d4); }

.vm-tooltip {
  position: absolute; z-index: 5; pointer-events: none;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  padding: 8px 10px; font-size: 0.8125rem; min-width: 130px;
  box-shadow: 0 10px 30px -10px rgba(0,0,0,0.25);
}
.vm-tt-day { font-weight: 700; margin-bottom: 4px; }
.vm-tt-row { display: flex; align-items: center; gap: 6px; }
.vm-tt-row b { margin-left: auto; font-variant-numeric: tabular-nums; }

/* Two-column grids for the lower section */
.vm-grid {
  display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 16px; margin-bottom: 18px;
}
.vm-grid-2 { grid-template-columns: 1fr 1fr; }
@media (max-width: 1080px) { .vm-grid    { grid-template-columns: 1fr 1fr; }
                              .vm-grid-2  { grid-template-columns: 1fr; } }
@media (max-width: 640px)  { .vm-grid    { grid-template-columns: 1fr; } }

/* Hourly bars */
.vm-hourly { display: grid; grid-template-columns: repeat(24, 1fr); gap: 4px; height: 220px; align-items: end; }
.vm-hourly-col { display: flex; flex-direction: column; align-items: center; gap: 4px; height: 100%; }
.vm-hourly-bar-track {
  width: 100%; flex: 1; min-height: 4px; display: flex; align-items: flex-end;
  background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--brand) 6%, transparent));
  border-radius: 4px 4px 0 0;
}
.vm-hourly-bar {
  width: 100%;
  background: linear-gradient(180deg,
                color-mix(in srgb, var(--brand) 90%, white),
                var(--brand));
  border-radius: 4px 4px 0 0;
  transition: height 200ms ease, transform 200ms ease;
}
.vm-hourly-col:hover .vm-hourly-bar { transform: scaleX(1.18); }
.vm-hourly-label { font-size: 0.6875rem; color: var(--muted); font-variant-numeric: tabular-nums; height: 14px; }
@media (max-width: 720px) {
  .vm-hourly { gap: 2px; }
}

/* Donut charts */
.vm-donut-wrap {
  display: grid; grid-template-columns: 160px 1fr; gap: 16px; align-items: center;
}
@media (max-width: 480px) { .vm-donut-wrap { grid-template-columns: 1fr; justify-items: center; } }
.vm-donut { width: 160px; height: 160px; transform: rotate(0deg); }
.vm-donut circle { transition: stroke-width 200ms ease; }
.vm-donut:hover circle { stroke-width: 26; }
.vm-donut-total {
  font-size: 1.25rem; font-weight: 700; fill: var(--text);
  font-variant-numeric: tabular-nums;
}
.vm-donut-sublabel { font-size: 0.6875rem; fill: var(--muted);
  letter-spacing: 0.1em; text-transform: uppercase; }
.vm-legend-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.vm-legend-list li {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 8px;
  font-size: 0.875rem;
}
.vm-legend-list .vm-legend-swatch { width: 12px; height: 12px; border-radius: 4px; flex-shrink: 0; }
.vm-legend-label { color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vm-legend-count { font-variant-numeric: tabular-nums; }

/* Top tables */
.vm-top-tbl { width: 100%; }
.vm-top-tbl td, .vm-top-tbl th { vertical-align: middle; }
.vm-num-col { text-align: right; width: 80px; font-variant-numeric: tabular-nums; }
.vm-bar-col { width: 38%; padding-right: 0; }
.vm-bar {
  display: block; width: 100%; height: 7px; border-radius: 999px;
  background: color-mix(in srgb, var(--brand) 10%, transparent);
  overflow: hidden;
}
.vm-bar-fill {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--brand), color-mix(in srgb, var(--brand) 70%, #06b6d4));
}
.vm-bar-fill-alt {
  background: linear-gradient(90deg, #9333ea, #06b6d4);
}
.vm-path-link {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--brand); text-decoration: none; word-break: break-all;
}
.vm-path-link:hover { text-decoration: underline; }
.vm-path-link .icon { width: 14px; height: 14px; flex-shrink: 0; }
.vm-ref-direct {
  display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-weight: 500;
}
.vm-ref-direct .icon { width: 14px; height: 14px; }

.vm-empty { margin: 24px 0; text-align: center; }

/* Dashboard widget — Visitor Metrics card */
.vm-widget-card { display: flex; flex-direction: column; gap: 12px; }
.vm-widget-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.vm-widget-stat {
  padding: 10px 12px; border-radius: 10px; background: var(--panel-2);
  border: 1px solid var(--border); display: flex; flex-direction: column; gap: 2px;
  min-width: 0;
}
.vm-widget-stat-label {
  font-size: 0.625rem; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted);
}
.vm-widget-stat-value {
  font-size: 1.125rem; font-weight: 700; color: var(--text); line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.vm-widget-stat-accent { background:
  linear-gradient(135deg, color-mix(in srgb, var(--brand) 16%, var(--panel-2)), var(--panel-2)); }
.vm-widget-stat-accent .vm-widget-stat-value { color: var(--brand); }
.vm-widget-spark {
  width: 100%; height: 56px; display: block;
  border: 1px solid var(--border); border-radius: 10px;
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  padding: 4px;
}
.vm-widget-spark-empty {
  padding: 16px; text-align: center; color: var(--muted); font-size: 0.8125rem;
}

/* ── Blog post body block editor (.pbe-*) ─────────────────────────
   Visual drag-and-drop editor mounted on `templates/blog_edit.html`.
   The canvas holds an ordered list of "block" cards; each block has
   a left drag handle, a top toolbar (type chip + per-block actions),
   and a type-specific editor body. The floating "Add block" pill
   re-uses the chrome from `.fe-page-palette-floating` (page builder)
   but tile interactions are namespaced to `data-pbe-*` so the two
   editors never cross-wire. */

.pbe-card { position: relative; }
.pbe-pill-inline {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 999px;
  background: var(--brand-soft, var(--panel-2));
  color: var(--brand, var(--access));
  font-weight: 600; font-size: 0.8em;
  vertical-align: middle;
}
.pbe-pill-inline .icon { width: 11px; height: 11px; }
.pbe-handle-inline {
  display: inline-flex; align-items: center;
  padding: 0 2px;
  color: var(--brand, var(--access));
  vertical-align: middle;
}
.pbe-handle-inline .icon { width: 14px; height: 14px; }

/* ── Canvas ──────────────────────────────────────────────────────
   The blocks sit on a softly-tinted rail so the writer can see the
   "compose zone" at a glance. Dashed border on hover / drag-over to
   reinforce the drop affordance without making the resting state
   feel busy. */
.pbe-canvas {
  /* `position: relative` makes the canvas the positioning context
     for the absolutely-positioned insert marker — the marker has
     to overlay the flex column without consuming flex space, or
     dragging causes the canvas to grow / shrink mid-drag and the
     page scroll bounces in sympathy. */
  position: relative;
  display: flex; flex-direction: column; gap: 12px;
  min-height: 220px;
  padding: 14px;
  border-radius: 14px;
  background: var(--panel-2, var(--panel));
  border: 1px dashed var(--border);
  transition: border-color 160ms ease, background 160ms ease;
}
body.pbe-is-dragging .pbe-canvas,
body.pbe-is-palette-dragging .pbe-canvas {
  border-color: var(--brand, var(--access));
  background: color-mix(in srgb, var(--brand, var(--access)) 4%, var(--panel-2, var(--panel)));
}

/* Empty state — visible only when there are no blocks yet. Render
   takes care of show/hide; CSS just polishes the layout. */
.pbe-empty {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  text-align: center;
  padding: 32px 24px;
  border-radius: 12px;
  background: var(--panel);
  border: 1px solid var(--border);
}
.pbe-empty-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; border-radius: 50%;
  background: var(--brand-soft, color-mix(in srgb, var(--brand, var(--access)) 14%, transparent));
  color: var(--brand, var(--access));
}
.pbe-empty-icon .icon { width: 22px; height: 22px; }
.pbe-empty-title { font-size: 1.05rem; font-weight: 600; }
.pbe-empty-help { max-width: 460px; line-height: 1.55; }
.pbe-empty-help .icon { width: 13px; height: 13px; vertical-align: -2px; }

/* Insert marker. A 4px coloured rule that appears between blocks
   while a drag is over the canvas — gives the writer a precise
   "drop here" target. Absolute-positioned within the canvas's
   relative context so it overlays without consuming flex space;
   the JS sets `top` from the surrounding blocks' offsets so the
   marker lands centred in the gap between them. */
.pbe-insert-marker {
  position: absolute;
  left: 14px; right: 14px;
  height: 4px;
  border-radius: 999px;
  background: var(--brand, var(--access));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand, var(--access)) 24%, transparent);
  animation: pbe-pulse 900ms ease-in-out infinite;
  pointer-events: none;
  z-index: 2;
}
@keyframes pbe-pulse {
  0%, 100% { opacity: 0.9; transform: scaleY(1); }
  50%      { opacity: 1;   transform: scaleY(1.4); }
}

/* ── Block card ─────────────────────────────────────────────────
   `position: relative` so the drag handle can sit on the inside
   edge without throwing off the grid. The handle floats outside
   the toolbar so the user can hit it without aiming around the
   buttons. */
.pbe-block {
  position: relative;
  display: grid;
  grid-template-columns: 28px 1fr;
  grid-template-rows: auto auto;
  column-gap: 6px;
  row-gap: 6px;
  padding: 12px 14px 14px 8px;
  border-radius: 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  transition: box-shadow 160ms ease, border-color 160ms ease, transform 160ms ease;
}
.pbe-block:hover {
  border-color: color-mix(in srgb, var(--brand, var(--access)) 35%, var(--border));
  box-shadow: 0 6px 14px rgba(15, 23, 42, 0.08);
}
.pbe-block:focus-within {
  border-color: var(--brand, var(--access));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand, var(--access)) 18%, transparent);
}
.pbe-block.is-dragging {
  opacity: 0.55;
  transform: rotate(-0.4deg);
}

/* Drag handle — vertical column of dots, only the handle itself
   triggers a reorder drag. Inputs / textareas inside the block keep
   their native text-selection drag behaviour. */
.pbe-block-handle {
  grid-row: 1 / span 2;
  display: flex; align-items: flex-start; justify-content: center;
  padding-top: 6px;
  cursor: grab;
  color: var(--muted, #6b7280);
  border-radius: 8px;
  transition: background 120ms ease, color 120ms ease;
}
.pbe-block-handle:hover {
  background: color-mix(in srgb, var(--brand, var(--access)) 10%, transparent);
  color: var(--brand, var(--access));
}
.pbe-block-handle:active { cursor: grabbing; }
.pbe-block-handle .icon { width: 16px; height: 16px; }

/* Toolbar — type chip on the left, per-block actions on the right. */
.pbe-block-toolbar {
  grid-column: 2;
  grid-row: 1;
  display: flex; align-items: center; gap: 4px;
  flex-wrap: wrap;
}
.pbe-block-type-chip {
  margin-right: auto;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: 999px;
  background: var(--brand-soft, color-mix(in srgb, var(--brand, var(--access)) 12%, transparent));
  color: var(--brand, var(--access));
  font-size: 0.78rem; font-weight: 600;
  letter-spacing: 0.02em;
}
.pbe-block-action {
  background: transparent; border: 0; padding: 6px;
  border-radius: 6px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--muted, #6b7280);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.pbe-block-action:hover {
  background: var(--panel-2, color-mix(in srgb, var(--brand, var(--access)) 8%, transparent));
  color: var(--text);
}
.pbe-block-action:disabled {
  opacity: 0.3; cursor: not-allowed; pointer-events: none;
}
.pbe-block-action--danger:hover {
  background: color-mix(in srgb, #dc2626 12%, transparent);
  color: #dc2626;
}
.pbe-block-action .icon { width: 14px; height: 14px; }

.pbe-block-body {
  grid-column: 2;
  grid-row: 2;
  display: flex; flex-direction: column; gap: 10px;
}

/* ── Per-block surfaces ───────────────────────────────────────── */
.pbe-input {
  width: 100%;
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel);
  color: var(--text);
  font-size: 0.95rem; line-height: 1.5;
  font-family: inherit;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.pbe-input:focus {
  outline: none;
  border-color: var(--brand, var(--access));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand, var(--access)) 16%, transparent);
}
.pbe-textarea {
  resize: vertical; min-height: 60px;
}
.pbe-select { cursor: pointer; }

.pbe-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.pbe-mini-label {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 0.78rem; font-weight: 600;
  color: var(--muted, #6b7280);
  text-transform: uppercase; letter-spacing: 0.06em;
}

.pbe-check {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.88rem; color: var(--text);
  cursor: pointer;
}
.pbe-check input { cursor: pointer; }

/* Segmented control — small pill-shaped radio group. */
.pbe-segmented {
  display: inline-flex;
  padding: 3px;
  border-radius: 8px;
  background: var(--panel-2, var(--panel));
  border: 1px solid var(--border);
}
.pbe-segmented-btn {
  border: 0; padding: 5px 12px;
  background: transparent; color: var(--muted);
  font-size: 0.82rem; font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.pbe-segmented-btn:hover { color: var(--text); }
.pbe-segmented-btn.is-active {
  background: var(--brand, var(--access));
  color: #fff;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.10);
}

.pbe-range { width: 120px; accent-color: var(--brand, var(--access)); }
.pbe-range-label { gap: 10px; }
.pbe-range-value { font-variant-numeric: tabular-nums; min-width: 32px; }

/* ── Heading block ──────────────────────────────────────────────
   The heading-text input adapts its typography to the chosen level
   so the writer sees H2 vs H3 vs H4 size in the editor. */
.pbe-heading-body { gap: 8px; }
.pbe-heading-level { width: auto; max-width: 160px; }
.pbe-heading-input { font-weight: 700; }
.pbe-heading-input[data-level="2"] { font-size: 1.45rem; }
.pbe-heading-input[data-level="3"] { font-size: 1.2rem;  }
.pbe-heading-input[data-level="4"] { font-size: 1.05rem; }

/* ── Image block ────────────────────────────────────────────────
   Preview frame sits on top; URL row + alt/caption underneath; an
   align segmented + width slider live in the controls row. */
.pbe-image-preview {
  display: flex; align-items: center; justify-content: center;
  min-height: 80px;
  padding: 6px;
  border-radius: 10px;
  background: var(--panel-2, var(--panel));
  border: 1px dashed var(--border);
}
.pbe-image-preview img {
  max-width: 100%; max-height: 220px;
  border-radius: 6px;
  display: block;
}
.pbe-image-empty {
  font-size: 0.85rem; color: var(--muted);
  padding: 14px;
}
.pbe-image-row { flex-wrap: nowrap; }
.pbe-image-row .pbe-input { flex: 1 1 auto; }
.pbe-upload-btn { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; }
.pbe-upload-btn .icon { width: 14px; height: 14px; }
.pbe-image-controls { gap: 18px; }

/* ── List block ─────────────────────────────────────────────────
   Each list row shows its bullet / number on the left so the writer
   sees the rendered ordering at a glance. */
.pbe-list-items {
  list-style: none;
  margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 4px;
  counter-reset: pbe-list;
}
.pbe-list-item {
  display: flex; align-items: center; gap: 6px;
  position: relative;
  padding-left: 22px;
}
.pbe-list-item::before {
  position: absolute; left: 4px; top: 50%;
  transform: translateY(-50%);
  color: var(--muted);
  font-size: 0.92rem;
}
.pbe-list-items:not(.is-ordered) .pbe-list-item::before { content: '•'; }
.pbe-list-items.is-ordered .pbe-list-item {
  counter-increment: pbe-list;
}
.pbe-list-items.is-ordered .pbe-list-item::before {
  content: counter(pbe-list) '.';
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.pbe-list-item-input { flex: 1 1 auto; }
.pbe-list-item-remove {
  background: transparent; border: 0; padding: 4px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--muted); border-radius: 6px;
  cursor: pointer;
  opacity: 0; transition: opacity 120ms ease, background 120ms ease, color 120ms ease;
}
.pbe-list-item:hover .pbe-list-item-remove,
.pbe-list-item:focus-within .pbe-list-item-remove { opacity: 1; }
.pbe-list-item-remove:hover {
  background: color-mix(in srgb, #dc2626 12%, transparent);
  color: #dc2626;
}
.pbe-list-item-remove .icon { width: 12px; height: 12px; }
.pbe-list-add {
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: 6px;
}
.pbe-list-add .icon { width: 13px; height: 13px; }

/* ── Quote block — italicised border-left preview style ────────── */
.pbe-quote-body .pbe-textarea {
  font-style: italic;
  border-left: 3px solid color-mix(in srgb, var(--brand, var(--access)) 60%, transparent);
  border-radius: 8px;
  padding-left: 14px;
}

/* ── Callout block — variant-tinted border ─────────────────────── */
.pbe-block--callout {
  --pbe-callout: #1f4e79;
  border-left: 4px solid var(--pbe-callout);
}
.pbe-block--callout[data-callout-variant="info"]    { --pbe-callout: var(--brand, var(--access)); }
.pbe-block--callout[data-callout-variant="success"] { --pbe-callout: #047857; }
.pbe-block--callout[data-callout-variant="warn"]    { --pbe-callout: #b45309; }
.pbe-block--callout[data-callout-variant="danger"]  { --pbe-callout: #b91c1c; }

/* ── Separator block — visual placeholder for an <hr>. */
.pbe-separator-body { gap: 6px; }
.pbe-sep-preview hr {
  border: 0; border-top: 1.5px solid var(--border);
  margin: 4px auto;
  max-width: 60%;
}
.pbe-mini-help { font-size: 0.82rem; }

/* ── Video block — iframe preview frame. */
.pbe-video-preview {
  position: relative;
  aspect-ratio: 16 / 9; max-width: 480px;
  margin: 0 auto;
  border-radius: 10px; overflow: hidden;
  background: #000;
  border: 1px solid var(--border);
}
.pbe-video-preview iframe,
.pbe-video-preview video {
  position: absolute; inset: 0;
  width: 100%; height: 100%; border: 0;
}
.pbe-video-preview .pbe-image-empty {
  position: relative;
  background: var(--panel-2, var(--panel)); color: var(--muted);
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%;
}

/* ── Code block — monospaced field. */
.pbe-code-body { gap: 6px; }
.pbe-code-lang { max-width: 280px; }
.pbe-code-input {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.88rem;
  background: var(--panel-2, var(--panel));
}

/* ── Palette specialisation ─────────────────────────────────────
   We re-use `.fe-page-palette-floating` for layout + animation, then
   layer on a few overrides so the blog editor palette doesn't share
   z-index / position with a page-builder palette that might also be
   in the DOM. */
.pbe-palette { z-index: 1200; }
.pbe-palette-grid { max-height: 360px; }
.pbe-palette-tile:focus-visible {
  outline: 2px solid var(--brand, var(--access));
  outline-offset: 2px;
}

/* On narrow screens, collapse the block's grid: handle moves above
   the toolbar (becoming a slim drag bar) and the body uses the full
   width. Keeps the editor usable on phones without sacrificing the
   per-block affordances. */
@media (max-width: 640px) {
  .pbe-block {
    grid-template-columns: 1fr;
  }
  .pbe-block-handle {
    grid-row: 1; grid-column: 1;
    width: 100%; height: 18px;
    padding-top: 0;
    flex-direction: row;
  }
  .pbe-block-handle .icon { transform: rotate(90deg); }
  .pbe-block-toolbar,
  .pbe-block-body { grid-column: 1; }
}

/* ── Section block (container) ────────────────────────────────────
   The blog body's only nested block. Visually distinct so the
   writer sees the wrapped group at a glance, with its own
   margin controls + an inner drop zone that accepts palette tiles
   and reordered children. The inner canvas re-uses the marker
   pulse + drag styling from the top-level canvas. */
.pbe-block--section .pbe-section-body { gap: 14px; }
.pbe-section-controls {
  display: flex; flex-wrap: wrap; gap: 18px 24px;
  padding: 10px 12px; border-radius: 8px;
  background: var(--panel-2, var(--panel));
  border: 1px solid var(--border);
}
.pbe-section-margin-label { gap: 6px; }
.pbe-section-margin-row {
  display: inline-flex; align-items: center; gap: 4px;
}
.pbe-section-margin-input {
  width: 72px;
  padding: 4px 8px;
  font-variant-numeric: tabular-nums;
}
.pbe-section-margin-unit { font-weight: 600; }

.pbe-section-canvas {
  /* Same positioning-context setup as the outer canvas so an
     absolute insert marker can overlay without flex reflow. */
  position: relative;
  display: flex; flex-direction: column; gap: 10px;
  min-height: 80px;
  padding: 12px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--brand, var(--access)) 4%, var(--panel-2, var(--panel)));
  border: 1px dashed color-mix(in srgb, var(--brand, var(--access)) 30%, var(--border));
  transition: border-color 160ms ease, background 160ms ease;
}
body.pbe-is-dragging .pbe-section-canvas,
body.pbe-is-palette-dragging .pbe-section-canvas {
  border-color: var(--brand, var(--access));
  background: color-mix(in srgb, var(--brand, var(--access)) 8%, var(--panel-2, var(--panel)));
}
.pbe-section-empty {
  padding: 14px 12px; text-align: center;
  color: var(--muted, #6b7280); font-size: .88rem;
}
/* Children inside a section get a slightly tighter card so the
   nesting reads visually. */
.pbe-section-canvas .pbe-block { padding: 10px 12px 12px 6px; }

/* ════════════════════════════════════════════════════════════════
   Watchtower — admin security + observability console.

   Five tabs (Overview / Visitors / Access / Deletes / Requests) sit
   under a single sidebar entry. The shared chrome lives here:
     • .wt-tabs           — top-of-page tab strip
     • .wt-kpi-grid       — six-up KPI tile row
     • .wt-system-card    — 4 system-health tiles (CPU / mem / load / uptime)
     • .wt-chart-card     — SVG chart wrapper (consumed by overview + visitors)
     • .wt-anomalies      — banner row for critical / warning callouts
     • .wt-ip-table       — suspicious-IP leaderboard
     • .wt-rank-list      — bar-ranked label/count rows
     • .wt-hourly         — hour-of-day distribution bars

   Everything below scopes under `.wt-*` so it can't collide with
   other admin pages. ============================================ */

/* Tabs strip ─────────────────────────────────────────────────────── */
.wt-tabs {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin: 0 0 18px;
  padding: 4px;
  background: var(--panel, #f8fafc);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 12px;
}
.wt-tab {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px;
  border-radius: 8px;
  color: var(--muted, #475569);
  text-decoration: none;
  font-weight: 600; font-size: 0.92rem;
  transition: background-color 140ms ease, color 140ms ease;
}
.wt-tab:hover { background: rgba(15, 23, 42, 0.05); color: var(--text, #0f172a); }
.wt-tab.is-active {
  background: var(--bg, #ffffff);
  color: var(--text, #0f172a);
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 0 0 1px rgba(15, 23, 42, 0.05);
}
.wt-tab-icon { display: inline-flex; width: 16px; height: 16px; }
.wt-tab-icon svg { width: 16px; height: 16px; }

[data-theme="dark"] .wt-tabs { background: #0f172a; border-color: #1f2937; }
[data-theme="dark"] .wt-tab { color: #94a3b8; }
[data-theme="dark"] .wt-tab:hover { background: rgba(255,255,255,0.04); color: #e5e7eb; }
[data-theme="dark"] .wt-tab.is-active { background: #1f2937; color: #f1f5f9; box-shadow: 0 1px 3px rgba(0,0,0,0.3); }

/* Window selector on the visitors tab ───────────────────────────── */
.wt-window-form select { padding: 6px 28px 6px 10px; }

/* Anomaly banner row ────────────────────────────────────────────── */
.wt-anomalies { display: flex; flex-direction: column; gap: 10px; margin: 0 0 18px; }
.wt-anomaly {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-radius: 10px;
  border: 1px solid;
}
.wt-anomaly-icon { display: inline-flex; flex: none; }
.wt-anomaly-icon svg { width: 22px; height: 22px; }
.wt-anomaly-body { flex: 1; min-width: 0; }
.wt-anomaly-body strong { display: inline-block; margin-right: 6px; }
.wt-anomaly-action {
  flex: none; font-weight: 600; font-size: 0.88rem; text-decoration: none;
}
.wt-anomaly--critical {
  background: rgba(220, 38, 38, 0.08); border-color: rgba(220, 38, 38, 0.35);
  color: #991b1b;
}
.wt-anomaly--critical .wt-anomaly-icon { color: #dc2626; }
.wt-anomaly--critical .wt-anomaly-action { color: #991b1b; }
.wt-anomaly--warn {
  background: rgba(245, 158, 11, 0.10); border-color: rgba(245, 158, 11, 0.35);
  color: #92400e;
}
.wt-anomaly--warn .wt-anomaly-icon { color: #d97706; }
.wt-anomaly--warn .wt-anomaly-action { color: #92400e; }
[data-theme="dark"] .wt-anomaly--critical { background: rgba(220,38,38,0.18); color: #fecaca; }
[data-theme="dark"] .wt-anomaly--warn { background: rgba(245,158,11,0.18); color: #fde68a; }

/* KPI tile grid ─────────────────────────────────────────────────── */
.wt-kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 14px;
  margin: 0 0 22px;
}
.wt-kpi-grid--four { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.wt-kpi {
  padding: 14px 16px;
  background: var(--bg, #ffffff);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04);
  position: relative; overflow: hidden;
}
.wt-kpi-label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em;
  font-weight: 700; color: var(--muted, #64748b); margin-bottom: 8px; }
.wt-kpi-value { font-size: 1.85rem; font-weight: 800; line-height: 1; color: var(--text, #0f172a); }
.wt-kpi-sub { margin-top: 6px; }
.wt-kpi--accent { border-color: rgba(59, 130, 246, 0.45); }
.wt-kpi--accent .wt-kpi-value { color: rgb(37, 99, 235); }
.wt-kpi--warn {
  background: linear-gradient(180deg, rgba(245,158,11,0.08), transparent);
  border-color: rgba(245, 158, 11, 0.45);
}
.wt-kpi--warn .wt-kpi-value { color: #d97706; }
.wt-kpi--crit {
  background: linear-gradient(180deg, rgba(220,38,38,0.10), transparent);
  border-color: rgba(220, 38, 38, 0.45);
}
.wt-kpi--crit .wt-kpi-value { color: #dc2626; }
[data-theme="dark"] .wt-kpi { background: #1e293b; border-color: #334155; }
[data-theme="dark"] .wt-kpi-value { color: #f1f5f9; }
[data-theme="dark"] .wt-kpi-label { color: #94a3b8; }

/* System metrics card ───────────────────────────────────────────── */
.wt-sys-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  padding: 8px 0;
}
.wt-sys-tile { padding: 4px 0; }
.wt-sys-label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em;
  font-weight: 700; color: var(--muted, #64748b); }
.wt-sys-value { font-size: 1.6rem; font-weight: 800; line-height: 1.1; margin: 4px 0; }
.wt-sys-unit { font-size: 0.85rem; font-weight: 600; color: var(--muted, #64748b); margin-left: 2px; }
.wt-sys-bar {
  height: 6px; border-radius: 999px; overflow: hidden;
  background: rgba(148, 163, 184, 0.2);
  margin: 6px 0;
}
.wt-sys-bar > span {
  display: block; height: 100%;
  background: linear-gradient(90deg, rgb(59,130,246), rgb(16,185,129));
  transition: width 200ms ease;
}
.wt-sys-sub { margin-top: 2px; }

/* Chart card ────────────────────────────────────────────────────── */
.wt-chart-card { margin-bottom: 18px; }
.wt-chart-wrap { padding: 8px 0 4px; }
.wt-chart { width: 100%; height: auto; display: block; }
.wt-chart--tall { min-height: 260px; }
.wt-chart-legend {
  display: flex; gap: 14px; align-items: center;
  margin-top: 8px; font-size: 0.86rem;
}
.wt-chart-key { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; }
.wt-chart-key::before {
  content: ""; display: inline-block; width: 12px; height: 3px; border-radius: 2px;
}
.wt-chart-key--views::before { background: rgb(59, 130, 246); }
.wt-chart-key--uniques::before {
  background: linear-gradient(90deg, rgb(16,185,129) 0 6px, transparent 6px 12px);
  background-size: 8px 100%;
}

/* Two-column layout helper (suspicious IPs + recent activity, etc.) */
.wt-two-col {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 18px;
  margin-bottom: 18px;
}

/* Suspicious-IP / blocklist / sessions tables ───────────────────── */
.wt-ip-table-scroll { max-height: 420px; overflow-y: auto; }
.wt-ip-table, .wt-block-table, .wt-session-table { width: 100%; }
.wt-ip-table th, .wt-block-table th, .wt-session-table th {
  text-align: left; font-size: 0.78rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted, #64748b);
}
.wt-ip-table td, .wt-block-table td, .wt-session-table td {
  padding: 8px 10px;
  border-top: 1px solid var(--border, #e5e7eb);
}
.wt-ip-actions { display: flex; gap: 6px; align-items: center; }
.wt-session-active td { background: rgba(16, 185, 129, 0.05); }
[data-theme="dark"] .wt-session-active td { background: rgba(16, 185, 129, 0.10); }

/* Manual ban form ───────────────────────────────────────────────── */
.wt-ban-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px; align-items: end;
  padding: 12px 0 18px;
  border-bottom: 1px solid var(--border, #e5e7eb);
  margin-bottom: 18px;
}
.wt-ban-form label { display: flex; flex-direction: column; gap: 4px; font-size: 0.85rem;
  color: var(--muted, #64748b); font-weight: 600; }
.wt-ban-form input, .wt-ban-form select { padding: 8px 10px; }
.wt-ban-form button { height: 38px; }

.wt-picker-form { display: flex; gap: 14px; align-items: end; }
.wt-picker-form label { display: flex; flex-direction: column; gap: 4px;
  font-size: 0.85rem; color: var(--muted, #64748b); font-weight: 600; }
.wt-card-form { display: inline-flex; align-items: center; gap: 8px; }

/* Recent activity feed ──────────────────────────────────────────── */
.wt-activity-feed { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 10px; }
.wt-activity-item {
  display: flex; gap: 12px; padding: 8px 4px;
  border-bottom: 1px solid var(--border, #e5e7eb);
}
.wt-activity-item:last-child { border-bottom: 0; }
.wt-activity-dot {
  flex: none; margin-top: 6px;
  width: 8px; height: 8px; border-radius: 50%;
  background: rgb(59, 130, 246);
}
.wt-activity-body { flex: 1; min-width: 0; }
.wt-activity-line { font-size: 0.92rem; }
.wt-activity-sum { margin: 2px 0 2px; }

/* Rank lists (top paths, referrers, devices) ─────────────────────── */
.wt-rank-list { list-style: none; margin: 0; padding: 0; }
.wt-rank-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 130px 80px;
  align-items: center; gap: 10px;
  padding: 6px 0; border-bottom: 1px dashed rgba(148, 163, 184, 0.2);
}
.wt-rank-row:last-child { border-bottom: 0; }
.wt-rank-label { font-size: 0.9rem; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wt-rank-bar { height: 6px; background: rgba(148, 163, 184, 0.18); border-radius: 999px; overflow: hidden; }
.wt-rank-bar > span {
  display: block; height: 100%;
  background: linear-gradient(90deg, rgb(59,130,246), rgb(99,102,241));
}
.wt-rank-count { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; font-size: 0.9rem; }
.wt-rank-list--inline .wt-rank-row { grid-template-columns: 100px minmax(0, 1fr) 130px; }

/* Hour-of-day bar strip ────────────────────────────────────────── */
.wt-hourly {
  display: flex; align-items: flex-end; gap: 4px;
  height: 140px;
  padding: 8px 0 6px;
}
.wt-hourly-col { flex: 1; display: flex; flex-direction: column; gap: 4px; align-items: stretch; min-width: 0; }
.wt-hourly-track { flex: 1; background: rgba(148, 163, 184, 0.08); border-radius: 4px;
  display: flex; align-items: flex-end; }
.wt-hourly-bar {
  width: 100%; background: linear-gradient(180deg, rgb(59,130,246), rgb(99,102,241));
  border-radius: 4px 4px 2px 2px;
  min-height: 1px;
}
.wt-hourly-tick { font-size: 0.66rem; color: var(--muted, #64748b); text-align: center; }

/* Badge variants used inside Watchtower tables ───────────────────── */
.badge-danger { background: rgba(220, 38, 38, 0.12); color: #b91c1c; }
.btn-ghost {
  background: transparent;
  border: 1px solid transparent;
  color: var(--muted, #64748b);
}
.btn-ghost:hover { background: rgba(148,163,184,0.10); color: var(--text, #0f172a); }
[data-theme="dark"] .btn-ghost:hover { background: rgba(255,255,255,0.06); color: #f1f5f9; }
