/* bulbulatorCRM — app shell stylesheet (ported from the mockup; mockup.css remains the reference)
   Two themes via CSS custom properties; [data-theme] on <html>.
   Palettes from realtimecolors.com:
   light: bg f6d8fd / text 210128 / primary e380fa / secondary a70659 / accent f72662
   dark:  bg 200227 / text f7d7fe / primary 69057f / secondary f958ab / accent d90843
*/

:root, [data-theme="light"] {
    --bg: #f6d8fd;
    --text: #210128;
    --primary: #e380fa;
    --secondary: #a70659;
    --accent: #f72662;

    --surface: #fdf2ff;
    --surface-2: #efcbfc;
    --border: #dcaeee;
    --muted: #6b4a75;
    --on-primary: #210128;
    --sidebar-bg: rgba(253, 242, 255, .55); /* translucent — the aurora shows through */
    --sidebar-text: #210128;
    --sidebar-hover: rgba(33, 1, 40, .05);
    --sidebar-active-bg: rgba(33, 1, 40, .08);
    --shadow: 0 2px 10px rgba(33, 1, 40, .12);

    --login-surface: rgba(253, 242, 255, .5);
    --login-border: rgba(167, 6, 89, .25);
    --login-field-bg: rgba(255, 255, 255, .55);
    --login-shadow: 0 24px 60px rgba(33, 1, 40, .18), 0 0 90px rgba(227, 128, 250, .35);
}

[data-theme="dark"] {
    --bg: #200227;
    --text: #f7d7fe;
    --primary: #69057f;
    --secondary: #f958ab;
    --accent: #d90843;

    --surface: #2b0536;
    --surface-2: #3a0a49;
    --border: #4a1060;
    --_border: #600d80;
    --muted: #b98cc9;
    --on-primary: #f7d7fe;
    --sidebar-bg: rgba(22, 1, 27, .5); /* translucent — the aurora shows through */
    --sidebar-text: #f7d7fe;
    --sidebar-hover: rgba(255, 255, 255, .06);
    --sidebar-active-bg: rgba(255, 255, 255, .08);
    --shadow: 0 2px 12px rgba(0, 0, 0, .45);

    --login-surface: rgba(59, 10, 73, .35);
    --login-border: rgba(249, 88, 171, .28);
    --login-field-bg: rgba(32, 2, 39, .55);
    --login-shadow: 0 24px 60px rgba(0, 0, 0, .5), 0 0 90px rgba(105, 5, 127, .35);
}

* { box-sizing: border-box; }

/* global quiet scrollbars (owner 2026-09-25): thin + translucent thumb on a
   transparent track, both engines; the translucent tone works on both themes */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
    background: rgba(140, 120, 150, .35);
    border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover { background: rgba(140, 120, 150, .55); }
* {
    scrollbar-width: thin;
    scrollbar-color: rgba(140, 120, 150, .35) transparent;
}

body {
    margin: 0;
    font-family: "Saira Condensed", sans-serif;
    background: var(--bg);
    color: var(--text);
    font-size: 15px;
}

/* the QCubed form wraps the whole layout */
form { margin: 0; }

/* override qcubed.css's off-palette link colors (#1d7596 / #d90d0d) */
a:link, a:visited { color: var(--secondary); }
a:hover, a:active { color: var(--accent); }

.layout { display: flex; height: 100vh; overflow: hidden; }

/* ---------- sidebar ---------- */
.sidebar {
    flex: 0 0 200px; /* fixed width: no grow, no shrink, 200px basis */
    min-width: 0; /* otherwise flex's min-width:auto lets long menu entries push it wider than the basis */
    background: var(--sidebar-bg);
    backdrop-filter: blur(7px); /* frost the aurora/content showing through */
    -webkit-backdrop-filter: blur(7px);
    border-right: 1px solid var(--border);
    color: var(--sidebar-text);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
}
.sidebar-logo {
    display: flex; align-items: center; gap: .5em;
    padding: .7em .7em .7em .35em; /* text centered on the topbar title; left edge aligned with the menu texts below */
    font-family: "Saira", sans-serif;
    font-size: 1.35em; font-weight: 600;
    color: var(--sidebar-text); text-decoration: none;
    transition: color .15s ease;
}
/* qcubed.css styles a:link/a:visited with (0,1,1) specificity — the link states
   below must match that to keep the sidebar colors */
.sidebar-logo:link, .sidebar-logo:visited { color: var(--sidebar-text); text-decoration: none; }
.logo-crm { color: var(--accent); transition: color .15s ease; }
/* hover: "bulbulator" and "CRM" swap colors */
.sidebar-logo:hover { color: var(--accent); }
.sidebar-logo:hover .logo-crm { color: var(--sidebar-text); }
.logo-mark {
    background: var(--primary); color: var(--on-primary);
    border-radius: .35em; padding: 0 .35em;
}
.menu { list-style: none; margin: 0; padding: 0; }
.menu-item a {
    display: flex; align-items: center; gap: .7em;
    padding: .65em 1.2em;
    font-family: "Saira", sans-serif;
    color: var(--sidebar-text); text-decoration: none;
    border-left: 3px solid transparent;
}
.menu-item a:hover { background: var(--sidebar-hover); }
/* the watcher-driven Messages badge panel renders a wrapper div inside the
   flex anchor - display:contents keeps the flex layout untouched */
.menu-badge-wrap { display: contents; }
.menu-item.active a {
    border-left-color: var(--secondary);
    background: var(--sidebar-active-bg);
    font-weight: 600;
}
.menu-section {
    margin: 1em 1.2em .3em;
    font-size: .75em; text-transform: uppercase;
    letter-spacing: .08em; color: var(--muted);
}
.mi { width: 1.2em; text-align: center; opacity: .8; }

/* sidebar harvest-queue glance (owner 2026-09-13) */
.harvest-queue { margin: 1.2em 1.2em 0; padding-top: .8em; border-top: 1px solid var(--border); font-size: .82em; }
/* the queue can run long (20+ visits) - cap it with its own scrollbar so it
   never stretches the sidebar (owner 2026-09-13) */
.hq-block { max-height: 40vh; overflow-y: auto; }
/* empty queue: fractional line-height rounding leaves a 1-2px "overflow" and
   Chrome draws a phantom scrollbar (FF does not) - nothing scrolls when empty */
.hq-block:not(:has(.hq-row)) { overflow-y: hidden; }
.hq-title { font-size: .75em; text-transform: uppercase; letter-spacing: .08em; margin-bottom: .3em; }
.hq-row { display: flex; align-items: center; gap: .4em; padding: .18em 0; min-width: 0; }
.hq-st { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; box-sizing: border-box; }
.hq-st.is-pending { border: 1.5px solid var(--muted); }
.hq-st.is-running { background: #2ecc71; }
.hq-bot { flex: 0 0 auto; }
.hq-nicks { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.hq-remove { margin-left: auto; flex: 0 0 auto; cursor: pointer; color: var(--muted); padding: 0 .3em; line-height: 1; }
.hq-remove:hover { color: var(--accent); }
.hq-empty { font-size: .9em; }
.hq-actions { margin: .2em 0 .5em; }
.hq-actions button { font-size: .85em; padding: .2em .8em; cursor: pointer; }

/* ---------- main column ---------- */
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; height: 100vh; }

.topbar {
    display: flex; align-items: center; gap: 1em;
    padding: .6em 1.2em;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    position: sticky; top: 0; z-index: 10;
}
.topbar-title {
    font-family: "Saira", sans-serif;
    font-size: 1.25em; font-weight: 600;
}
.topbar-title .crumb-sep { color: var(--muted); font-weight: 300; margin: 0 .1em; }
.topbar-title .crumb-parent { font-size: 0.65em; font-weight: 400; }
.topbar-title a { color: inherit; text-decoration: none; }
.topbar-title a:hover { text-decoration: underline; }
.topbar-search { flex: 1; max-width: 420px; }
.topbar-search input {
    width: 100%; padding: .45em .8em;
    border: 1px solid var(--border); border-radius: .5em;
    background: var(--bg); color: var(--text);
    font-family: inherit;
}
.topbar-actions { margin-left: auto; display: flex; align-items: center; gap: .8em; }
.theme-toggle {
    border: 1px solid var(--border); background: var(--surface-2);
    color: var(--text); border-radius: .3em;
    width: 2.2em; height: 2.2em; cursor: pointer;
    font-size: 1em; /* button box stays 2.2em; only the glyph is enlarged below */
    display: inline-flex; align-items: center; justify-content: center;
    line-height: 1;
}
/* CSS-drawn half-filled circle instead of the "◐" text glyph: glyph metrics
   (size AND baseline) come from each browser's fallback font, so Chrome and
   Firefox rendered it differently (owner, 2026-10-04) */
.theme-toggle::before {
    content: "";
    width: 0.8em; height: 0.8em;
    border: 2px solid currentColor; border-radius: 50%;
    background: linear-gradient(90deg, currentColor 50%, transparent 50%);
}
/* same hover as the neighboring Sign out (.btn-logout) */
.theme-toggle:hover, .theme-toggle:active { border-color: var(--secondary); color: var(--secondary); }
.user-chip {
    display: flex; align-items: center; gap: .8em;
    font-size: .95em;
}
.user-avatar {
    width: 2em; height: 2em; border-radius: 50%;
    background: var(--surface-2); border: 1px solid var(--border);
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 600; text-transform: uppercase;
    overflow: hidden; /* ready for an <img> */
}
.user-avatar img { width: 100%; height: 100%; object-fit: cover; }
.user-name {
    font-family: "Saira", sans-serif;
    font-size: 1.05em; font-weight: 500;
}
.btn-logout {
    display: inline-flex; align-items: center; gap: .5em;
    padding: .45em 1em; border-radius: .3em;
    background: var(--surface-2); border: 1px solid var(--border);
    text-decoration: none;
    font-size: .95em;
}
/* qcubed.css's a:link/a:visited and our global link colors carry (0,1,1) specificity — match it */
.btn-logout:link, .btn-logout:visited { color: var(--text); }
.btn-logout:hover, .btn-logout:active { border-color: var(--secondary); color: var(--secondary); }
.btn-logout svg { width: 1.1em; height: 1.1em; }
.hamburger {
    display: none;
    border: 0; background: none; color: var(--text);
    font-size: 1.4em; cursor: pointer;
}

/* ---------- content ---------- */
.content { flex: 1; padding: 0.5em; overflow-y: auto; overflow-x: auto; /* narrow screens: wide QCubed grids scroll inside the content area */ }
.content-head {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 1.1em;
}
h1 {
    font-family: "Saira", sans-serif;
    font-size: 1.9em; margin: 0; font-weight: 600;
}
h2 {
    font-family: "Saira", sans-serif;
    font-size: 1.25em; margin: 0 0 .6em; font-weight: 600;
}

.btn {
    font-family: inherit; font-size: .95em;
    padding: .5em 1.1em; border-radius: .5em; cursor: pointer;
    border: 1px solid transparent;
}
.btn-primary {
    background: var(--secondary); color: #fff;
}
.btn-primary:hover { filter: brightness(1.12); }

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: .7em;
    box-shadow: var(--shadow);
    padding: 0 10px;
    overflow-x: auto; /* narrow screens: wide tables scroll inside the card instead of being clipped */
}
.card-pad { padding: 1.1em 1.3em; }

/* M11 bot identity (variant A: read-only cards + modal editors) */
.identity-card { max-width: 720px; margin-top: 1em; padding: 0 1em 0.5em 1em; border-color: var(--bot-c-v); box-shadow: 0 2px 12px color-mix(in srgb, var(--bot-c-d) 65%, transparent); }
[data-theme="light"] .identity-card { border-color: var(--bot-c-vd); }
.identity-card h3 { margin: .7em 0 .4em; }
.identity-info-row { display: flex; gap: .8em; align-items: center; margin: .45em 0; }
.identity-info-top { align-items: flex-start; }
.identity-info-row .identity-label { min-width: 8.5em; font-size: .9em; color: var(--muted); text-align: right; }
.identity-info-row .identity-value { flex: 1; overflow-wrap: anywhere; }
.identity-info-row .identity-value strong { font-size: 1.1em; font-weight: 500; }
.identity-info-row .identity-pre { white-space: pre-wrap; }
.identity-info-row .identity-actions { display: flex; gap: .4em; }
/* page-scoped button sizing (owner 2026-10-04) - the global .button stays */
.bot-identity .button { font-size: .8em; padding: .3em 1em; }
.bot-identity .button:hover { border-color: var(--secondary); }
.identity-row { display: flex; gap: .6em; align-items: center; margin: .5em 0 .2em; }
.bmodal-hint { display: block; font-size: .85em; margin-top: .4em; }
.bmodal-card textarea { width: 100%; }
.bmodal-card input[type=text] { width: 100%; }
.bmodal-overlay.bi-hidden { display: none; }
/* identity modals: fixed width from the start, so expanding the emoji panel
   no longer stretches the card; two-line title with breathing room below */
#bi-status-modal .bmodal-card, #bi-welcome-modal .bmodal-card { width: 48em; max-width: 100%; }
.bmodal-title-main { display: block; margin-bottom: .15em; }
.bmodal-title-sub { display: block; font-size: .9em; color: var(--muted); margin-bottom: 1.1em; }
.identity-progress { font-size: .85em; color: var(--muted); display: inline-flex; align-items: center; gap: .4em; }
.identity-progress .bi-ok { color: var(--primary); }
.bi-spinner { display: inline-block; width: .8em; height: .8em; border: 2px solid var(--border); border-top-color: var(--primary); border-radius: 50%; animation: bi-spin .8s linear infinite; }
@keyframes bi-spin { to { transform: rotate(360deg); } }

/* ---------- emoji picker (reusable: any .emoji-toggle + data-emoji-target) ---------- */
/* the toggle is a wide button sitting in the panel's slot; it only OPENS the
   picker (no on/off) and hands the slot to the panel until the modal reopens */
.emoji-toggle {
    display: block; width: 100%; margin: .5em 0; padding: .3em;
    background: var(--surface); border: 1px solid var(--border); border-radius: .4em;
    cursor: pointer; font-size: 1.1em; line-height: 1.4;
}
.emoji-toggle:hover { border-color: var(--primary); }
.emoji-toggle.bi-hidden { display: none; }
.emoji-panel.bi-hidden { display: none; }
.emoji-panel {
    /* floats above its toggle (owner 2026-10-09) - out of flow, anchored
       by the module from the toggle's rect */
    position: fixed; z-index: 100;
    max-height: 16.5em; overflow-y: auto;
    margin: 0; padding: .4em;
    border: 1px solid var(--border); border-radius: .5em; background: var(--surface);
    display: flex; flex-wrap: wrap; gap: 2px;
}
.emoji-group { flex-basis: 100%; font-size: .7em; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; margin-top: .3em; text-align: left; }
/* corpus | extras separator inside the emoji grid (not clickable) */
.emoji-sep { color: var(--muted); opacity: .6; align-self: center; pointer-events: none; }
.emoji-item { background: none; border: none; font-size: 1.2em; padding: .1em .15em; cursor: pointer; border-radius: .3em; line-height: 1.3; }
.emoji-item:hover { background: var(--border); }
.bi-delete-wall { display: flex; align-items: center; gap: .5em; font-size: .9em; color: var(--muted); margin: .6em 0; cursor: pointer; }
.cards-2col {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: 1.2em; margin-top: 1.2em;
}

.table { width: 100%; border-collapse: collapse; }
.table th, .table td {
    text-align: left; padding: .6em .9em;
    border-bottom: 1px solid var(--border);
}
.table th {
    font-family: "Saira", sans-serif;
    font-size: .9em; text-transform: uppercase; letter-spacing: .05em;
    color: var(--muted);
    background: var(--surface-2);
}
.table tbody tr:hover { background: var(--surface-2); }
.badge {
    background: transparent;
    color: var(--text);
    border: 1px solid var(--secondary);
    border-radius: .35em; padding: .1em .7em; font-size: .8em;
    box-shadow: 0 0 .45em color-mix(in srgb, var(--secondary) 45%, transparent);
}
.accent { color: var(--accent); }
.muted { color: var(--muted); }
.row-actions a { color: var(--secondary); text-decoration: none; }
.row-actions a:hover { text-decoration: underline; }

.stat-row {
    display: flex; justify-content: space-between; gap: 1em;
    padding: .35em 0; border-bottom: 1px dashed var(--border);
}
.stat-row:last-child { border-bottom: 0; }
.stat-row > span { flex: 0 0 auto; }
.stat-row > strong { min-width: 0; text-align: right; word-break: break-word; }

/* bot card: short label:value pairs pack two per row; .stat-row-wide (task,
   current url) spans both columns */
.stat-rows { display: grid; grid-template-columns: 1fr 1fr; column-gap: 1.4em; }
.stat-row-wide { grid-column: 1 / -1; }
.stat-row-stack { flex-direction: column; align-items: stretch; gap: 0; }
.stat-row-stack > strong { text-align: left; }

/* ---------- status bar ---------- */
.statusbar {
    display: flex; align-items: center; gap: .6em;
    padding: .3em 1.2em;
    font-size: .8em; color: var(--muted);
    background: var(--surface);
    border-top: 1px solid var(--border);
}
.dot { width: .6em; height: .6em; border-radius: 50%; display: inline-block; }
.dot.ok { background: #2ecc71; }
.sep { width: 1px; height: 1em; background: var(--border); }
.spacer { flex: 1; }

/* ---------- aurora background (from the login mockup) ----------
   Fixed full-viewport layer at z-index:-1 — visible only under .content,
   since sidebar/topbar/statusbar have opaque backgrounds. */
.aurora {
    position: fixed; inset: 0; z-index: -1;
    overflow: hidden;
    pointer-events: none;
}
.blob {
    position: absolute;
    border-radius: 50%;
    filter: blur(90px);
    will-change: transform;
}
.b1 {
    width: 55vmax; height: 55vmax;
    left: -15vmax; top: -15vmax;
    animation: drift1 26s ease-in-out infinite alternate;
}
.b2 {
    width: 45vmax; height: 45vmax;
    right: -12vmax; top: 15%;
    animation: drift2 32s ease-in-out infinite alternate;
}
.b3 {
    width: 40vmax; height: 40vmax;
    left: 25%; bottom: -22vmax;
    animation: drift3 38s ease-in-out infinite alternate;
}
@keyframes drift1 {
    0%   { transform: translate(0, 0) scale(1); }
    50%  { transform: translate(9vmax, 6vmax) scale(1.15); }
    100% { transform: translate(-4vmax, 12vmax) scale(.95); }
}
@keyframes drift2 {
    0%   { transform: translate(0, 0) scale(1); }
    50%  { transform: translate(-10vmax, 8vmax) scale(1.1); }
    100% { transform: translate(-3vmax, -6vmax) scale(1.2); }
}
@keyframes drift3 {
    0%   { transform: translate(0, 0) scale(1); }
    50%  { transform: translate(8vmax, -7vmax) scale(1.12); }
    100% { transform: translate(-8vmax, -3vmax) scale(.9); }
}

/* faint tech grid over the aurora, fading out towards the bottom */
.grid-overlay {
    position: absolute; inset: 0;
    background-size: 44px 44px;
    mask-image: radial-gradient(ellipse 75% 65% at 50% 40%, black 30%, transparent 75%);
    -webkit-mask-image: radial-gradient(ellipse 75% 65% at 50% 40%, black 30%, transparent 75%);
}

/* aurora colors — dark (dimmed login mockup values) */
[data-theme="dark"] .aurora {
    background:
        radial-gradient(ellipse 80% 55% at 50% -10%, rgba(105, 5, 127, .2), transparent 60%),
        var(--bg);
}
[data-theme="dark"] .b1 {
    background: radial-gradient(circle at 35% 35%, #a706ff, #69057f 60%, transparent 75%);
    opacity: .3;
}
[data-theme="dark"] .b2 {
    background: radial-gradient(circle at 60% 40%, #f958ab, #a70659 55%, transparent 72%);
    opacity: .3;
}
[data-theme="dark"] .b3 {
    background: radial-gradient(circle at 50% 50%, #d90843, #69057f 55%, transparent 70%);
    opacity: .22;
}
[data-theme="dark"] .grid-overlay {
    background-image:
        linear-gradient(rgba(247, 215, 254, .05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(247, 215, 254, .05) 1px, transparent 1px);
}

/* aurora colors — light: softer, pastel variants of the same palette */
[data-theme="light"] .aurora {
    background:
        radial-gradient(ellipse 80% 55% at 50% -10%, rgba(227, 128, 250, .45), transparent 60%),
        var(--bg);
}
[data-theme="light"] .b1 {
    background: radial-gradient(circle at 35% 35%, #f0c2ff, #e380fa 60%, transparent 75%);
    opacity: .5;
}
[data-theme="light"] .b2 {
    background: radial-gradient(circle at 60% 40%, #f9a1cd, #f72662 55%, transparent 72%);
    opacity: .35;
}
[data-theme="light"] .b3 {
    background: radial-gradient(circle at 50% 50%, #f72662, #e380fa 55%, transparent 70%);
    opacity: .3;
}
[data-theme="light"] .grid-overlay {
    background-image:
        linear-gradient(rgba(33, 1, 40, .04) 1px, transparent 1px),
        linear-gradient(90deg, rgba(33, 1, 40, .04) 1px, transparent 1px);
}

/* ---------- login (from the login mockup, on theme variables) ---------- */
.login-wrap {
    position: relative;
    min-height: 100vh;
    display: flex; flex-direction: column;
    justify-content: center;
    padding: 1em;
}
.login-card {
    position: relative;
    width: min(400px, 92vw);
    margin: 0 auto;
    padding: 2.6em 2.4em 2.2em;
    background: var(--login-surface);
    border: 1px solid var(--login-border);
    border-radius: 1.1em;
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    box-shadow:
        0 0 0 1px rgba(255,255,255,.04) inset,
        var(--login-shadow);
    animation: card-in .7s cubic-bezier(.2, .9, .25, 1.2) both;
}

/* rotating glow ring around the card */
@property --ang { syntax: "<angle>"; initial-value: 0deg; inherits: false; }
.login-card::before {
    content: "";
    position: absolute;
    inset: -2px;
    border-radius: 1.2em;
    padding: 2px;
    background: conic-gradient(from var(--ang),
        transparent 0%, rgba(249, 88, 171, .95) 10%, rgba(217, 8, 67, .7) 16%, transparent 32%);
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
            mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
            mask-composite: exclude;
    animation: ring 6s linear infinite;
    pointer-events: none;
}
@keyframes ring { to { --ang: 360deg; } }

@keyframes card-in {
    from { opacity: 0; transform: translateY(26px) scale(.97); }
    to   { opacity: 1; transform: none; }
}

.login-logo {
    display: flex; align-items: center; justify-content: center; gap: .55em;
    font-family: "Saira", sans-serif;
    font-size: 1.9em; font-weight: 700;
    color: var(--text);
}
.login-logo .logo-mark {
    background: linear-gradient(135deg, var(--secondary), var(--accent));
    color: #fff;
    box-shadow: 0 0 22px color-mix(in srgb, var(--secondary) 55%, transparent);
}
.login-sub {
    display: block;
    text-align: center;
    color: var(--muted);
    margin: .4em 0 1.8em;
    font-size: 1.05em;
}

.field { display: block; margin-bottom: 1.15em; }
.field-label {
    display: block;
    font-size: .8em; text-transform: uppercase; letter-spacing: .1em;
    color: var(--muted);
    margin-bottom: .35em;
}
.field input {
    width: 100%;
    padding: .65em .9em;
    font-family: inherit; font-size: 1.15em;
    color: var(--text);
    background: var(--login-field-bg);
    border: 1px solid var(--login-border);
    border-radius: .5em;
    outline: none;
    transition: border-color .18s, box-shadow .18s;
}
.field input::placeholder { color: color-mix(in srgb, var(--muted) 50%, transparent); }
.field input:focus {
    border-color: var(--secondary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--secondary) 18%, transparent),
        0 0 18px color-mix(in srgb, var(--secondary) 28%, transparent);
}

/* QCubed renders the Button as .button; on the login card and the bmodal card it gets the gradient look */
.login-card .button, .bmodal-card .button {
    width: 100%;
    margin-top: .5em;
    padding: .7em;
    font-family: "Saira", sans-serif;
    font-size: 1.05em; font-weight: 600; letter-spacing: .04em;
    color: #fff;
    background: linear-gradient(135deg, var(--primary), var(--secondary) 65%, var(--accent));
    background-size: 180% 180%;
    background-position: 0% 50%;
    border: 0; border-radius: .55em;
    cursor: pointer;
    transition: background-position .35s ease, box-shadow .25s ease, transform .12s ease;
    box-shadow: 0 6px 22px color-mix(in srgb, var(--accent) 25%, transparent);
}
.login-card .button:hover, .bmodal-card .button:hover {
    background-position: 100% 50%;
    box-shadow: 0 6px 30px color-mix(in srgb, var(--secondary) 45%, transparent);
    filter: none;
}
.login-card .button:active, .bmodal-card .button:active { transform: translateY(1px) scale(.99); }
.login-card .button del { opacity: .75; font-weight: 100; }
.login-card .button ins { text-decoration: none; }

.login-note {
    text-align: center;
    color: color-mix(in srgb, var(--muted) 55%, transparent);
    font-size: .85em; letter-spacing: .08em;
    margin: 1.6em 0 0;
    animation: note-in 1s .35s ease both;
}
@keyframes note-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* ---------- own modal (login error etc.) ---------- */
.bmodal-overlay {
    position: fixed; inset: 0; z-index: 100;
    background: color-mix(in srgb, var(--bg) 55%, transparent);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    display: flex; align-items: center; justify-content: center;
}
.bmodal-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: .7em;
    box-shadow: var(--shadow);
    padding: 2.2em 2.8em 2em;
    max-width: 30em;
    text-align: center;
}
.bmodal-text { display: block; font-size: 1.3em; }
.bmodal-card .button { margin-top: 1em; }

/* respect users who prefer no motion (last in the file, so it wins on equal specificity) */
@media (prefers-reduced-motion: reduce) {
    .blob, .login-card::before { animation: none; }
    .login-card, .login-note { animation: none; }
}

/* ---------- responsive ---------- */
@media (max-width: 900px) {
    .sidebar {
        position: fixed; left: 0; top: 0; z-index: 20;
        transform: translateX(-100%);
        transition: transform .2s ease;
    }
    .sidebar.open { transform: translateX(0); box-shadow: var(--shadow); }
    .hamburger { display: block; }
    .cards-2col { grid-template-columns: 1fr; }
    .topbar-search { max-width: none; }
}

/* ---------- QCubed controls on the app theme ----------
   QCubed renders semantic classes (.datagrid, .paginator, .button, .textbox,
   .listbox); mapped onto the theme variables here so the generated panels
   (grids, dialogs, filters) follow the active theme. */
.datagrid { background: var(--surface); border: 1px solid var(--border); border-radius: .1em; border-spacing: 0; box-shadow: var(--shadow); }
.datagrid th { background: var(--surface-2); color: var(--muted); font-family: "Saira", sans-serif; font-size: .8em; padding: 0.4em 0.6em; border-bottom: 1px solid var(--border); font-weight: 500; }
.datagrid th a { color: inherit; }
.panel-mailing-list .datagrid th { text-align: left; }
.datagrid td { padding: .3em .8em; border-bottom: 1px solid var(--border); font-size: 0.9em;}
.datagrid tbody tr:hover td { background: var(--surface-2); }
/* cell links: underline only on hover (owner 2026-10-19) */
.datagrid td a { text-decoration: none; }
.datagrid td a:hover { text-decoration: underline; }
/* the campaigns grid: hard column widths (owner 2026-10-19) - fixed layout,
   long nowrap cell content must clip, never stretch a column */
.datagrid.dg-fixed { table-layout: fixed; }
.datagrid.dg-fixed td { overflow: hidden; }
/* a past event in the campaigns grid (owner 2026-10-19) */
.datagrid .ev-past { color: var(--muted); font-style: italic; }
/* contents cells (campaigns + mailings grids, owner 2026-10-19): edit/preview
   as small buttons; a hairline above the nav links */
.datagrid .cc-btn { display: inline-block; padding: 0 .5em; border: 1px solid var(--border); border-radius: .3em; background: var(--surface-2); font-size: .8em; margin-left: .3em; }
.datagrid td a.cc-btn:hover { text-decoration: none; border-color: var(--secondary); }
.datagrid .cc-sep { border: 0; border-top: 1px solid var(--border); margin: .3em 0; }
.datagrid .ml-content-links { display: block; font-family: "Saira", sans-serif; font-size: .8em; white-space: nowrap; }
/* the mailings column in the campaigns grid: the name ellipsizes, the full
   name rides the tooltip (owner 2026-10-19) - no fixed cap: the flex line
   (.cc-line) gives it all the space the cell has */
.datagrid .cc-name { display: inline-block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
/* a contents/mailings cell line: the name left, the buttons pushed right
   (owner 2026-10-19) */
.datagrid .cc-line { display: flex; justify-content: space-between; align-items: baseline; gap: .4em; }
/* the campaign mailings list: the state icon keeps ONE width for every
   state, a small margin off the name (owner 2026-10-21) */
.datagrid .cc-stateicon { display: inline-flex; flex: 0 0 20px; justify-content: center; align-self: center; }
.datagrid .cc-stateicon .ml-sc-icon { vertical-align: middle; }
.datagrid .cc-line .cc-name { flex: 1 1 auto; min-width: 0; }
.datagrid .cc-btns { flex: 0 0 auto; }
/* the mailings grid Audience column (owner 2026-10-19): the member count in
   muted parens, "no audience" as a small grey italic note */
.datagrid .ml-aud-cell { color: var(--muted); font-size: .8em; }
.datagrid .ml-aud-count { color: var(--muted); font-size: .85em; }
.datagrid .ml-noaud { color: var(--muted); font-size: .85em; font-style: italic; }
/* the mailings grid Bots column: the tag-bot pill fills the fixed-width
   column, the nick ellipsizes (owner 2026-10-19) */
.datagrid .ml-bot-tag { display: flex; width: 100%; box-sizing: border-box; margin: .15em 0; text-align: center; justify-content: center; }
.datagrid .ml-bot-tag .botid-v { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.datagrid .ml-botcell { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px .4em; align-items: center; margin: .15em 0; }
.datagrid .ml-botcell .ml-bot-top { display: contents; }
.datagrid .ml-botcell .ml-bot-tag { min-width: 0; margin: 0; }
.datagrid .ml-botcell .ml-sc-bar { display: block; grid-column: 1; width: 100%; height: 5px; background: var(--border); border-radius: 3px; overflow: hidden; border: 1px solid var(--primary); margin: 1px 0 3px; }
.datagrid .ml-botcell .ml-sc-fill { display: block; height: 100%; background: var(--secondary); }
.datagrid .ml-botcell .ml-sc-label { grid-column: 2; grid-row: 1; width: 80px; font-size: .8em; color: var(--muted); text-align: center; white-space: nowrap; }
.datagrid tr.ml-group-start { position: relative; }
.datagrid tr.ml-group-start > td:first-child::before { content: "campaign: "; display: block; position: absolute; top: 0; right: 0; left: 0; padding: 1.2em .6em .6em; border-top: 1em solid var(--bg); background: var(--sidebar-hover); color: var(--muted); font-family: "Saira", sans-serif; font-size: .8em; font-weight: 400; white-space: nowrap;}
.datagrid tr.ml-group-start > td:first-child::after { content: var(--ml-campaign-name); display: block; position: absolute; top: 0; right: 0; left: 5.2em; padding: 1.7em .6em .4em 0; color: var(--secondary); font-family: "Saira", sans-serif; font-size: .9em; font-weight: 400;}
.datagrid tr.ml-group-start > td { padding-top: 3.5em; }

/* the mailings grid State cell (owner 2026-10-21): icon + name, a progress
   bar labeled with the percent and sendingIndex/recipientsCount */
.datagrid .ml-statecell { display: flex; flex-direction: column; gap: 2px; }
.datagrid .ml-statecell .ml-sc-top { display: flex; align-items: center; justify-content: space-between; gap: .4em; }
.datagrid .ml-statecell .ml-sc-state { white-space: nowrap; }
.datagrid .ml-statecell .ml-sc-icon { width: 16px; height: 16px; object-fit: contain; vertical-align: -3px; }
.datagrid .ml-statecell .ml-sc-bar { display: block; width: 100%; height: 5px; background: var(--border); border-radius: 3px; overflow: hidden; border: 1px solid var(--primary); }
.datagrid .ml-statecell .ml-sc-fill { display: block; height: 100%; background: var(--secondary); }
.datagrid .ml-statecell .ml-sc-label { font-size: .8em; color: var(--muted); white-space: nowrap; }

.paginator .arrow, .paginator .break, .paginator .page { color: var(--muted); }
.paginator a { color: var(--secondary); text-decoration: none; }
.paginator .selected { background: var(--secondary); border-color: transparent; }

.button {
    font-family: inherit; font-size: .95em;
    padding: .5em 1.1em; border-radius: .3em; cursor: pointer;
    border: 1px solid var(--border);
    background: var(--surface-2); color: var(--text);
}
.button:hover { filter: brightness(1.05); }
/* tighter buttons in the datagrid toolbar (owner 2026-10-19); the dialog
   buttons are jQuery UI buttonpane widgets - styled in their own rule below */
.lst-toolbar .button { padding: 0.2em 0.8em; }
.lst-toolbar .button:hover { border-color: var(--secondary); }

/* every input speaks the body font (Saira Condensed), everywhere (owner
   2026-10-19) - bare inputs included; buttons keep their own. The doubled
   .ui-widget beats jQuery UI's own .ui-widget select/textarea font rules
   regardless of stylesheet order */
input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]), select, select option, textarea { font-family: "Saira Condensed", sans-serif; }
.ui-widget.ui-widget input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]), .ui-widget.ui-widget select, .ui-widget.ui-widget select option, .ui-widget.ui-widget textarea { font-family: "Saira Condensed", sans-serif; }

.textbox, .listbox {
    padding: 0.2em 0.6em;
    border: 1px solid var(--border); border-radius: .3em;
    background: var(--bg); color: var(--text);
    font-family: "Saira Condensed", sans-serif;
}
/* a gentler focus marker (owner 2026-10-19): a tinted border + a small soft
   glow replace the aggressive native focus ring */
.textbox:focus, .listbox:focus,
input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]):focus, select:focus, textarea:focus {
    outline: none;
    border-color: color-mix(in srgb, var(--secondary) 65%, var(--border));
    box-shadow: 0 0 5px color-mix(in srgb, var(--secondary) 30%, transparent);
}
/* disabled inputs read as locked values, not just dimmed (owner 2026-10-19):
   the browser's native dimming is overridden on purpose */
.textbox:disabled, .listbox:disabled, input:disabled, select:disabled, textarea:disabled {
    opacity: 1;
    color: var(--muted);
    background: var(--surface-2);
    border-style: dashed;
    cursor: not-allowed;
    -webkit-text-fill-color: var(--muted);
}

/* jQuery UI dialogs (edit/new) follow the theme instead of the stock gray */
.ui-dialog {
    background: var(--surface); color: var(--text);
    border: 1px solid var(--border); border-radius: 0.3em;
    box-shadow: var(--shadow);
    font-family: "Saira Condensed", sans-serif;
}
.ui-dialog .ui-dialog-titlebar {
    background: var(--surface-2); color: var(--text);
    border: 0; border-bottom: 1px solid var(--border);
    border-radius: 0.3em 0.3em 0 0;
    font-family: "Saira", sans-serif;
    font-weight: 500;
}
.ui-dialog .ui-dialog-titlebar .ui-button { background: transparent; border: 0; color: var(--muted); }
/* edit dialogs: the RenderWithName label/field pair as two columns
   (owner 2026-10-19) - the label column right-aligned */
.ui-dialog div:has(> .form-name) { display: flex; gap: .8em; align-items: flex-start; margin-bottom: .5em; }
.ui-dialog .form-name { flex: 0 0 8em; text-align: right; padding-top: .3em; color: var(--muted); }
.ui-dialog .form-field { flex: 1; min-width: 0; }
/* the mailing dialog's bot picks as color toggle chips (owner 2026-10-19):
   the per-item --bot-c* identity vars ride the label (ListItem styles);
   dimmed until picked, the bot's own color when checked */
.bot-pick-chips { display: grid; grid-template-columns: repeat(3, auto); gap: .3em; justify-content: start; }
.bot-pick-chips input.qc-tableCell { display: none; }
.bot-pick-chips label.qc-tableCell { display: inline-block; width: 10em; padding: .3em .8em; border: 1px solid var(--border); border-radius: .3em; background: var(--surface-2); font-size: .9em; cursor: pointer; opacity: .4; box-sizing: border-box; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bot-pick-chips label.qc-tableCell:hover { opacity: 1; }
.bot-pick-chips input:checked + label { opacity: 1; color: var(--bot-c-v); border-color: var(--bot-c-v); box-shadow: 0 0 7px color-mix(in srgb, var(--bot-c-v) 55%, transparent); }
[data-theme="light"] .bot-pick-chips input:checked + label { color: var(--bot-c-vd); border-color: var(--bot-c-vd); box-shadow: 0 0 7px color-mix(in srgb, var(--bot-c-vd) 55%, transparent); }
.ui-dialog .ui-dialog-content { background: transparent; color: var(--text); }
.ui-dialog .ui-dialog-buttonpane { background: transparent; border-top: 1px solid var(--border); }
.ui-dialog .ui-dialog-buttonpane .ui-button {
    background: var(--surface-2); color: var(--text);
    border: 1px solid var(--border); border-radius: .3em;
    font-family: inherit;
    padding: 0.2em 0.8em;
}
/* same hover language as the rest of the UI (owner 2026-10-19) - the bg
   pin overrides jQuery UI's .ui-state-hover skin */
.ui-dialog .ui-dialog-buttonpane .ui-button:hover { background: var(--surface-2); border-color: var(--secondary); color: var(--text); }

/* Bot API live log (dashboard) */
.bot-log {
    margin: 0;
    max-height: 280px;
    overflow: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    line-height: 1.45;
    white-space: pre-wrap;
    word-break: break-all;
    color: var(--muted);
}

/* Bot status staleness lamp */
.lamp {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-right: 6px;
}
.lamp-green { background: #2ecc71; box-shadow: 0 0 6px #2ecc71; }
.lamp-yellow { background: #f1c40f; box-shadow: 0 0 6px #f1c40f; }
.lamp-red { background: var(--accent); box-shadow: 0 0 6px var(--accent); }
.lamp-gray { background: var(--muted); }
.lamp-blue { background: #3498db; box-shadow: 0 0 6px #3498db; }
.lamp-red-blink { background: var(--accent); box-shadow: 0 0 6px var(--accent); animation: proxy-lamp-blink 1s steps(2, end) infinite; }
@keyframes proxy-lamp-blink {
    0%, 49% { opacity: 1; }
    50%, 100% { opacity: .25; }
}
@media (prefers-reduced-motion: reduce) {
    .lamp-red-blink { animation: none; }
}

.btn-row {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.stat-row strong.url {
    font-weight: 400;
    word-break: break-all;
}

/* Live botbox tiles (/live) and bot page snapshot */
.live-layout {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    flex-wrap: wrap;
}
.live-tiles {
    display: flex;
    flex-direction: column;
    gap: 12px;
    width: 300px;
    flex: 0 0 auto;
    /* the column scrolls inside itself (owner 2026-09-25): the page stays
       put, the scrollbar sits between the tiles and the 100% view; the
       column width is JS-compensated for the scrollbar gutter, so the
       tiles themselves never shrink */
    max-height: calc(100vh - 92px);
    overflow-y: auto;
}
/* the HD full view stays pinned in the viewport while the tiles column
   scrolls under it (owner 2026-09-25) */
.live-hd {
    position: sticky;
    top: 8px;
}
.live-tile-head { display: flex; align-items: center; gap: 4px; padding: 8px 0 8px 4px; font-weight: 300; }
/* never let the column's overflow shrink a card (flex-shrink would squeeze
   the card until its own theme overflow-y:auto opens a scrollbar inside it
   and eats the canvas width - the 2026-09-25 tile-shrink incident) */
.live-tile-card { flex: 0 0 auto; padding: 0 10px 8px;}
.live-tile-head .spacer { flex: 1 1 auto; }
/* the small tile whose full view is open (owner 2026-09-11): thin border in
   the secondary color, like the active thread row - zero layout shift */
.live-tile-card.expanded { border-color: var(--secondary); }
.live-expand, .live-power button, .live-takecontrol, #live-hd-close {
    font: inherit;
    font-size: 11px;
    padding: 2px 8px;
    border: 1px solid var(--border);
    border-radius: .3em;
    background: var(--surface-2);
    color: var(--text);
    cursor: pointer;
    text-decoration: none;
}
.live-expand:hover, .live-power button:hover, .live-takecontrol:hover, #live-hd-close:hover { border-color: var(--secondary); }
/* power toggle sits inline in the tile head (M6) */
.live-power { display: flex; align-items: center; gap: 6px; }
.live-power .lamp { margin-right: 0; cursor: help; }
/* interactive takeover mode in the HD full view (M6-C) */
.live-hd.interactive .guac-hd { outline: 2px solid #2ecc71; }
.live-hd.interactive #live-hd-mode { color: #6cff9e; font-weight: 500; }
/* HD full view: the header row is an overlay ON the canvas (owner 2026-09-11) -
   reclaims its ~40px for short windows; the covered pixels are the botbox
   desktop's unused corners (the BulbulaPanel titlebar buttons, the window seam) */
.live-hd-overlay {
    position: absolute; top: 6px; left: 0; right: 0; z-index: 2;
    display: flex; align-items: flex-start; pointer-events: none;
}
.live-hd-overlay > * { pointer-events: auto; }
.live-hd-status {
    margin: 0 auto; padding: 3px 12px; border-radius: 1em;
    background: rgba(0, 0, 0, .88); border: 1px solid rgba(247, 215, 254, .25);
    color: #f7d7fe; font-size: 13px; font-weight: 300;
}
.live-hd-status .muted { color: inherit; opacity: .75; }
.live-hd-actions { position: absolute; top: 2px; right: 8px; display: flex; gap: 3px; }
.live-hd.interactive .live-hd-status { background: rgba(20, 60, 35, .92); border-color: rgba(46, 204, 113, .5); }
.guac-tile { position: relative; }
.guac-canvas {
    aspect-ratio: 1024 / 768;
    background: #000;
    overflow: hidden;
}
.guac-canvas > div { width: 100% !important; height: 100% !important; }
.guac-hd .guac-canvas {
    width: 1024px;
    height: 768px;
    aspect-ratio: auto;
}
.guac-state {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, .55);
    color: var(--muted);
    font-weight: 300;
    letter-spacing: .08em;
}
.guac-offline .guac-canvas > div { visibility: hidden; }
.bot-snapshot {
    display: block;
    max-width: 100%;
    border: 1px solid var(--border);
    border-radius: .5em;
    background: #000;
}
.bot-snapshot.snapshot-offline { opacity: .35; }

/* Bot accounts: one card per bot on a single page (2026-09-11 cleanup -
   replaces the stock datagrid list + the separate bot detail page) */
.bot-cards {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 16px;
    align-items: start;
}
@media (max-width: 1400px) { .bot-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 900px) { .bot-cards { grid-template-columns: 1fr; } }
.bot-card-head { display: flex; align-items: center; gap: 8px; }
.bot-card-head h2 { margin: 0; }
.bot-card-head .spacer { flex: 1 1 auto; }
.bot-card-actions { margin-top: .9em; gap: 6px; }
.bot-card-actions .button { padding: .3em .6em; font-size: .85em; }

/* Bot account proxy editor: QCubed ListBox + toggle-tag checkbox */
.proxy-config { display: flex; align-items: center; gap: .5em; flex-wrap: wrap; margin-top: .8em; }
.proxy-config .listbox { max-width: 100%; background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .35em; padding: .25em .45em; font-family: inherit; font-size: .85em; }
.proxy-toggle {
    display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; width: 8em; cursor: pointer; user-select: none;
    font-size: .75em; font-weight: 600; padding: .3em .6em; border-radius: .35em;
    background: var(--surface-2); border: 1px solid color-mix(in srgb, var(--border) 30%, #000); color: var(--muted);
    box-shadow: 0 0 4px color-mix(in srgb, #fff 40%, transparent);
}
.proxy-toggle, .proxy-toggle * { cursor: pointer; }
.proxy-toggle input { display: none; }
.proxy-toggle:has(input:checked) { border-color: var(--secondary); color: var(--text); box-shadow: 0 0 7px color-mix(in srgb, var(--secondary) 55%, transparent); }

/* Bot proxy: health cards reuse the bot-account grid and stat rows */
.proxy-inactive { opacity: .6; }
.proxy-health { display: flex; align-items: center; gap: 4px; white-space: nowrap; font-size: .85em; }
.proxy-health .lamp { margin-right: 0; }
.proxy-log {
    width: 100%;
    max-height: 14em;
    overflow: auto;
    margin: .35em 0 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font: inherit;
    font-size: .8em;
    font-weight: 400;
}

/* fleet-wide command history below the cards */
.bot-history-card { margin-top: 24px; }
.bot-history-card .datagrid { width: 100%; table-layout: fixed; font-size: .85em; }
.bot-history-card .datagrid th, .bot-history-card .datagrid td { text-align: center; }
.bot-history-card .datagrid .col-payload, .bot-history-card .datagrid .col-result { text-align: left; }
.bot-history-card .col-id { width: 50px; }
.bot-history-card .col-bot { width: 46px; }
.bot-history-card .col-command { width: 112px; }
.bot-history-card .col-status { width: 72px; }
.bot-history-card .col-time { width: 76px; }
/* col-payload + col-result share whatever width is left (50/50) */
.cell-wrap {
    overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
    cursor: help; /* full text rides the tooltip */
}

/* M5 UI pass: slim stat values (Saira 100-400 convention) + vertical card gap */
.stat-row strong { font-weight: 400; }
.cards-2col { margin-bottom: 16px; }

/* snapshot pipeline is kept but currently unused (see DECISIONS 2026-09-11) */
.bot-snapshot { margin-left: auto; margin-right: auto; }
/* M7: profile tiles (DataRepeater on /profiles) */
.profiles-head { display: flex; align-items: center; gap: .8em; flex-wrap: wrap; }
.profile-tiles, .aud-preview-tiles, .aud-members-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 10px; margin-top: .8em; }
/* M10-UI: full-height card with an internal scroller (same shell trick as
   messages) - the InfiniteRepeater grid itself scrolls */
.content:has(.panel-profiles) { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.content:has(.panel-profiles) div:has(.panel-profiles) { display: flex; flex-direction: column; flex: 1; min-height: 0; } /* QCubed _ctl wrappers */
.panel-profiles { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.profiles-card { flex: 1; display: flex; flex-direction: column; min-height: 0; margin: 1em; }
/* tiles + docked profile side panel; the split animates the tile reflow */
.profiles-split { position: relative; flex: 1; display: grid; grid-template-columns: 100% 0%; min-height: 0; transition: grid-template-columns .4s ease; }
.profiles-split.open { grid-template-columns: 66.67% 33.33%; }
.profiles-split > div:not([class]), .profiles-split > div:not([class]) > div:not([class]) { display: contents; } /* QCubed _ctl wrappers must not become grid items */
.profiles-tiles-col { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.profiles-head { display: flex; align-items: center; gap: .8em; flex-wrap: wrap; }
.profiles-head h2 { margin: 0; white-space: nowrap; }
.profiles-head .sort-strip { margin-left: auto; }
.profiles-head .textbox { max-width: 110px; }
/* region filter dropdown (owner 2026-09-12): plain select in the head (the
   panel root is never redrawn, so it survives watcher pings); an active
   filter gets a glow + a reset link. 2026-09-21: the type/orientation
   dropdowns share the same styling (.ps-filter-*) */
.ps-region-wrap, .ps-filter-wrap { display: inline-flex; align-items: center; gap: .5em; }
.ps-region-select, .ps-filter-select { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .4em; padding: .25em .45em; font-family: inherit; font-size: .85em; cursor: pointer; width: 7em;}
.ps-region-wrap.active .ps-region-select, .ps-filter-wrap.active .ps-filter-select { border-color: var(--secondary); box-shadow: 0 0 7px color-mix(in srgb, var(--secondary) 55%, transparent); }
.ps-region-reset, .ps-filter-reset { background: none; border: 0; padding: 0; color: var(--muted); font-family: inherit; font-size: .82em; text-decoration: underline; cursor: pointer; }
.ps-region-reset:hover, .ps-filter-reset:hover { color: var(--text); }
/* friend/favorite toggle tags (owner 2026-10-04): the /events tag-filter
   look (.ev-tagfilter .ev-filter-tag), separate classes - those carry
   events-page JS bindings */
.ps-reltags { display: inline-flex; align-items: center; gap: .3em; }
.ps-reltag {
    display: inline-flex; align-items: center; gap: .3em;
    cursor: pointer; user-select: none;
    font-size: .75em; font-weight: 600; padding: .3em .6em; border-radius: .35em;
    background: var(--surface-2); border: 1px solid color-mix(in srgb, var(--border) 30%, #000); color: var(--muted);
    box-shadow: 0 0 4px color-mix(in srgb, #fff 40%, transparent);
}
.ps-reltag svg { width: 13px; height: 13px; }
.ps-reltag.active { border-color: var(--secondary); color: var(--text); box-shadow: 0 0 7px color-mix(in srgb, var(--secondary) 55%, transparent); }
/* /stats (2026-09-22): snapshot tables rendered from stats.json */
.stats-head-row { display: flex; align-items: center; justify-content: space-between; }
.stats-head-row .button { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .4em; padding: .3em .9em; font-family: inherit; font-size: .85em; cursor: pointer; }
.stats-head-row .button:hover:not(:disabled) { border-color: var(--primary); }
.stats-head-row .button:disabled { opacity: .5; cursor: default; }
.stats-computing { animation: stats-pulse 1.2s ease-in-out infinite; }
@keyframes stats-pulse { 50% { opacity: .35; } }
.stats-card h3 { margin: 1.1em 0 .4em; font-size: .95em; }
.stats-hint { font-weight: normal; font-size: .85em; margin-left: .5em; }
.stats-table { border-collapse: collapse; min-width: 340px; }
.stats-table th { text-align: left; font-weight: normal; color: var(--muted); padding: .3em 1.4em .3em 0; }
.stats-table td { padding: .3em 0; font-variant-numeric: tabular-nums; }
.stats-table td + td { padding-left: 1em; text-align: right; }
/* freshness donut beside the numbers; age chart with the mode radios aside */
.stats-fresh-split { display: flex; align-items: flex-start; gap: 2em; }
.stats-donut { flex: 1 1 auto; min-height: 300px; }
.stats-fresh-split .stats-table { flex: 0 0 auto; margin-top: 1.2em; }
.stats-age-split { display: flex; gap: 1.5em; }
.stats-age-side { flex: 0 0 170px; display: flex; flex-direction: column; gap: .3em; padding-top: .4em; }
.stats-age-side label { display: flex; align-items: center; gap: .45em; font-size: .88em; color: var(--text); cursor: pointer; }
.stats-age-note { font-size: .78em; margin-top: .8em; }
.stats-age-region { width: 100%; margin-bottom: .8em; }
.stats-age-norm { margin-top: .8em; padding-top: .6em; border-top: 1px solid var(--border); font-size: .82em; color: var(--muted); display: flex; flex-direction: column; gap: .25em; }
.stats-age-chart { flex: 1 1 auto; height: 420px; }
.stats-region-chart { height: 500px; }
.profiles-tiles-col > div:not([class]) { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.profiles-tiles-col .profile-tiles { flex: 1 1 auto; min-height: 0; overflow-y: auto; align-content: start; }
.ir-loading { flex: 0 0 auto; text-align: center; padding: .5em; font-size: .85em; }
/* on phones the open panel takes over the whole width (drill-in) */
@media (max-width: 900px) {
    .profiles-split.open { grid-template-columns: 0% 100%; }
}

/* the docked profile side view: compact typography, a lot of content */
.profile-side { min-width: 0; overflow: hidden; background: var(--surface); border-left: 1px solid transparent; display: flex; flex-direction: column; min-height: 0; }
.profiles-split.open .profile-side { border-left-color: var(--border); }
.profile-side .ps-inner { flex: 1; min-height: 0; overflow-y: auto; padding: .9em 1em; font-size: .86em; line-height: 1.35; font-weight: 300; }
.ps-head { display: grid; grid-template-columns: 15% 1fr; gap: 0 .8em; align-items: center; text-align: left; margin-bottom: .7em; }
.ps-head-text { min-width: 0; }
/* the close X: DRAWN bars (box = ink, no font-metric dependence). Lives in
   the split chrome, NOT inside the side panel (.profile-side has
   overflow:hidden and would clip it); sticks out of the panel's top-right
   corner (-8px) and clears the update-NOW pill completely at this offset.
   Rendered always, shown only when the split is open (owner 2026-09-12) */
.ps-close { display: none; }
.profiles-split.open .ps-close { display: block; position: absolute; top: -15px; right: -15px; width: 36px; height: 36px; border: 0; border-radius: 50%; background: var(--surface); cursor: pointer; padding: 0; z-index: 2; }
.ps-close::before, .ps-close::after { content: ''; position: absolute; left: 50%; top: 50%; width: 22px; height: 3px; border-radius: 2px; background: var(--muted); }
.ps-close::before { transform: translate(-50%, -50%) rotate(45deg); }
.ps-close::after { transform: translate(-50%, -50%) rotate(-45deg); }
.ps-close:hover::before, .ps-close:hover::after { background: var(--text); }
.ps-head .avatar { margin: 0; justify-self: end; }
.ps-nick { font-family: "Saira", sans-serif; font-weight: 500; font-size: 1.5em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the bot-name prefix on our bots' own tiles (owner 2026-10-04): smaller and
   lighter so it reads as a tag, not as part of the nick */
.pt-nick .botid { font-size: 1em; font-weight: 700; margin-right: .35em;}
.ps-sub { font-size: .85em; }
.ps-row { display: flex; justify-content: space-between; gap: .7em; padding: .22em 0; border-bottom: 1px dashed var(--border); font-size: .92em; }
.ps-row:last-child { border-bottom: 0; }
.ps-row span { color: var(--muted); flex: 0 0 auto; }
.ps-row strong { font-weight: 400; text-align: right; overflow-wrap: break-word; min-width: 0; }
.ps-text { margin: .15em 0 .45em; overflow-wrap: break-word; }
.ps-subhead { text-transform: uppercase; font-size: .78em; letter-spacing: .05em; color: var(--muted); margin: .55em 0 .15em; }
/* FOUR-column info grid (owner 2026-09-12): the facts block (Location /
   Last active / Registered / Last harvested) and People (He/She pairs) ride
   [label 15%][value][label 15%][value], label columns on the panel's axis */
.ps-grid4 { display: grid; grid-template-columns: 15% 1fr 15% 1fr; gap: 0 .8em; margin-bottom: .6em; }
.ps-grid4 .ps-subhead { grid-column: span 2; margin-top: 0; }
.ps-cell-label, .ps-cell-value { padding: .22em 0; border-bottom: 1px dashed var(--border); overflow-wrap: break-word; min-width: 0; }
.ps-cell-label { text-align: right; color: var(--muted); }
.ps-cell-value { font-weight: 400; text-align: left; }
.ps-grid4 > :nth-last-child(-n+4) { border-bottom: 0; }
/* gallery strip (M10-UI): pinned at the side panel's bottom (a flex child
   after the scrolling .ps-inner); thumbs square-cropped and width-fluid, the
   counter at the right; a click anywhere opens the gallery modal */
.ps-galstrip { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; align-self: stretch; margin: 0; padding: 6px; border: 0; border-top: 1px solid var(--border); background: var(--surface); cursor: pointer; font: inherit; color: inherit; }
.ps-galstrip img { flex: 1 1 0; min-width: 0; aspect-ratio: 1; height: auto; object-fit: cover; border-radius: .4em; display: block; }
.ps-galfill { flex: 0 1 0; min-width: 0; }
.ps-galcount { flex: 0 0 auto; color: var(--muted); font-size: .82em; padding: 0 .2em; white-space: nowrap; }
.ps-galstrip:hover img { filter: brightness(1.15); }

/* gallery modal (M10-UI): ~85%-window overlay on a blurred backdrop; the grid
   scrolls internally; fixed-height rows, natural aspect ratios */
.gal-modal { position: fixed; inset: 0; z-index: 1000; }
.gal-backdrop { position: absolute; inset: 0; background: rgba(8, 0, 12, .55); backdrop-filter: blur(6px); }
.gal-box { position: absolute; inset: 7.5%; display: flex; flex-direction: column; background: var(--surface); border: 1px solid var(--border); border-radius: .8em; box-shadow: var(--shadow); overflow: hidden; }
.gal-head { display: flex; align-items: center; gap: .8em; padding: .55em 1em; border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.gal-title { font-family: "Saira", sans-serif; text-transform: uppercase; letter-spacing: .06em; font-size: .82em; color: var(--muted); }
.gal-count { margin-left: auto; font-size: .85em; }
.gal-close { position: relative; width: 22px; height: 22px; border: 0; background: none; cursor: pointer; padding: 0; flex: 0 0 auto; }
.gal-close::before, .gal-close::after { content: ''; position: absolute; left: 50%; top: 50%; width: 15px; height: 2px; border-radius: 1px; background: var(--muted); }
.gal-close::before { transform: translate(-50%, -50%) rotate(45deg); }
.gal-close::after { transform: translate(-50%, -50%) rotate(-45deg); }
.gal-close:hover::before, .gal-close:hover::after { background: var(--text); }
.gal-body { flex: 1; min-height: 0; overflow-y: auto; padding: .8em 1em; }
.gal-grid { display: flex; flex-wrap: wrap; gap: 8px; align-content: flex-start; justify-content: center; }
.gal-grid img { height: 220px; width: auto; display: block; border-radius: .35em; background: var(--surface-2); }
.gal-sentinel { padding: 1em; text-align: center; font-size: .85em; }
.ps-note { font-size: .85em; line-height: 1.4; }
/* operator visit controls (M10-UI): ONE loose row along the panel's top edge
   (owner 2026-09-13, was a stacked column in the head's right cell). The
   auto-update checkbox rides AFTER its label (owner 2026-09-12).
   In the /profiles split the row is ABSOLUTE against the split chrome
   (.profile-side stays static on purpose) - the only way onto the close X's
   line, which pokes out of the panel; top -8px centers a 21px row on the X
   (center +3px from the panel top). margin-right clears the X's circle.
   The contact card has no X - there the row stays a plain in-flow top bar. */
.ps-update { display: flex; align-items: center; justify-content: flex-end; gap: 1em; font-size: .85em; flex: 0 0 auto; align-self: stretch; padding: 0 1em; }
.profiles-split.open .ps-update { position: absolute; top: -8px; right: 0; margin-right: 26px; z-index: 2; }
/* sticky fade at the scroller's top edge: content scrolling under the pinned
   controls dissolves instead of colliding (owner's construction 2026-09-13:
   sticks 12px ABOVE the scroller edge - it backs the absolute controls row,
   which pokes out at -8px; the padding inflates the strip to 60px so the
   gradient can run solid first, then dissolve) */
.ps-fadetop { position: sticky; z-index: 1; height: 20px; margin: -11px -1em -5px; background: linear-gradient(var(--surface), var(--surface), transparent); pointer-events: none; top: -12px; padding-top: 40px; }
.contact-card .ps-fadetop { margin: -17px -1.1em -5px; }
.ps-auto { display: inline-flex; align-items: center; gap: .35em; cursor: pointer; color: var(--muted); }
.ps-autoupdate-cb { transform: scale(1.25); transform-origin: right center; margin-left: .15em; cursor: pointer; }
.ps-visitnow { font-size: .9em; padding: .2em .7em; border-radius: 2em; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); cursor: pointer; font-family: inherit; }
.ps-visitnow:hover { border-color: var(--primary); }
.ps-sep { border: none; border-top: 1px solid var(--border); margin: 0; flex: 0 0 auto; }
/* the enemy row follows the panel's 2-column convention (15% label + value);
   the text is deliberately inert (no label/for) - only the square toggles
   (touch-misclick guard near the gallery below, owner 2026-09-15) */
.ps-enemy-row { display: grid; grid-template-columns: 15% 1fr; gap: 0 .8em; align-items: center; padding: .35em 1em; font-size: .86em; flex: 0 0 auto; }
.contact-card .ps-enemy-row { padding-left: 1.1em; padding-right: 1.1em; }
.ps-enemy-row .ps-cell-label { border-bottom: none; }
.ps-enemy-text { color: var(--muted); }
.ps-enemy-row.is-enemy .ps-enemy-text { color: rgb(255, 95, 95); }
.ps-enemy-cb { transform: scale(1.25); cursor: pointer; }
/* idle spinner slot: box kept, ink hidden - its appearance must not shift the row */
.ps-spin.off { visibility: hidden; }

/* bio sections (M10-UI, flat since 2026-09-12): section headers like the old
   accordion's, no collapsing - the only long-form content (About) clamps at
   150px with a Show more/less toggle, 600ms height animation (the JS measures
   and unhides it) */
.ps-sections h3 { font-family: "Saira", sans-serif; font-size: .82em; font-weight: 400; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); padding: .35em .2em; margin: .6em 0 0; border-bottom: 1px solid var(--border); }
.ps-sections h3:first-child { margin-top: 0; }
.ps-clamp { position: relative; padding: .35em 0 0; }
/* owner 2026-09-12: the whole side panel rides ONE 2-column table look -
   labels in the left column (15% of the section width, so the layout survives
   window resizes; long labels may wrap, accepted) aligned RIGHT, values
   left-aligned. Covers the facts block (.ps-rows) and the bio sections' rows
   (direct children only - the People's He/She half-columns keep their own
   compact split) */
.ps-sections > .ps-row, .ps-clamp .ps-row { display: grid; grid-template-columns: 15% 1fr; gap: 0 .8em; }
.ps-sections > .ps-row span, .ps-clamp .ps-row span { text-align: right; }
.ps-sections > .ps-row strong, .ps-clamp .ps-row strong { text-align: left; }
/* free-text paragraphs (status, about, meetInfo) ride the value column (empty
   label cell) - the section header above acts as the name; the about font
   stays a touch larger than the rows (owner); About's dashed separator spans
   BOTH columns (it hangs on the first field row, not on the indented text) */
.ps-sections > .ps-text, .ps-sections > .ps-stats { margin-left: calc(15% + .8em); }
.ps-clamp .ps-text { margin-left: calc(15% + .8em); }
.ps-clamp .ps-text + .ps-row { border-top: 1px dashed var(--border); padding-top: .45em; }
.ps-clamp.is-clamped { max-height: 150px; overflow: hidden; transition: max-height .6s ease; }
.ps-clamp.is-clamped::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 5em; background: linear-gradient(transparent, var(--surface)); pointer-events: none; transition: opacity .6s ease; }
.ps-clamp.is-clamped.is-open { max-height: none; }
.ps-clamp.is-clamped.is-open::after { opacity: 0; }
/* big soft square chip (owner 2026-09-12): pinned under the section header at
   the text's first line, in the label column - SAME spot in both states, so
   collapse needs no mouse move; the "Show more/less" label is back, the
   chevron above it rotates with state */
.ps-clamp-toggle { position: absolute; top: .35em; left: 0; width: 5em; height: 3.5em; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0; border: 1px solid rgba(46, 204, 113, .4); border-radius: .6em; background: rgba(46, 204, 113, .12); color: #2ecc71; font-size: .9em; cursor: pointer; font-family: inherit; }
.ps-clamp-toggle[hidden] { display: none; }
.ps-clamp-toggle::before { content: '\25BE'; font-size: 2.1em; line-height: .8; transition: transform .3s; }
.ps-clamp.is-open .ps-clamp-toggle::before { transform: rotate(180deg); }
.ps-clamp-toggle:hover { background: rgba(46, 204, 113, .22); border-color: rgba(46, 204, 113, .65); }
/* rows-only tall content (no about text): make room for the pinned toggle,
   else it would cover the first row's label */
.ps-clamp:not(:has(.ps-text)) { padding-top: 6em; }
.profile-tile { background: var(--surface-2); border: 1px solid var(--border); border-radius: .5em; padding: .2em .5em; }
/* tiles of our bots' own profiles: the bot hue nearly washed out (owner
   2026-10-04) - dark tint on the dark theme, light tint on the light one */
.pt-own-bot { background: var(--bot-bg); }
[data-theme="light"] .pt-own-bot { background: var(--bot-bg-l); }
/* M10-UI: the tile is an <a> opening the docked profile panel */
a.profile-tile { display: block; color: inherit; text-decoration: none; cursor: pointer; }
a.profile-tile:hover { border-color: var(--primary); }
a.profile-tile.active { border-color: var(--on-primary); box-shadow: 0px 0px 10px 0px var(--on-primary);}
/* no min-height: tiles hug their content (owner 2026-09-13; was 8em reserved
   for planned content); grid still equalizes each row to its tallest tile */
.pt-head { display: flex; align-items: center; gap: .6em; }
/* min-width: 0 lets the text lines shrink inside the flex row so ellipsis can kick in */
.pt-id { flex: 1 1 auto; min-width: 0; }
.pt-nick { font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 40px wide thumb like the service's own avatars; real files are 120px wide
   with varying aspect ratios, so the height floats within 40..55px and
   object-fit: cover does the rest (uniform scale only - wide-and-low images
   get cropped left/right, tall ones top/bottom; never distorted).
   The placeholder PNG is 180x180 and lands as a 40x40 square */
.pt-avatar { width: 40px; height: auto; min-height: 40px; max-height: 55px; object-fit: cover; object-position: center; flex: 0 0 auto; border-radius: 4px; }
.pt-sub { font-size: .8em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pt-foot { font-size: .8em; margin-top: .1em; }
.pt-flags { display: flex; flex-direction: column; gap: 0; flex: 0 0 auto; }
/* tile footer strip (owner 2026-09-13): the planned home for state/relation
   info - left: the profile state dot + visit spinner, right: friend/fan/mail
   icons (inactive ones ride the .badge-off fade convention) */
a.profile-tile { display: flex; flex-direction: column; }
/* our-enemy marker (owner 2026-09-15): red translucent overlay over the tile;
   pointer-events none - the operator still opens the profile (e.g. to unflag) */
a.profile-tile { position: relative; }
.pt-enemy-overlay { position: absolute; inset: 0; z-index: 1; background: rgba(255, 45, 45, .28); border: 1px solid rgba(255, 45, 45, .6); border-radius: inherit; pointer-events: none; }
.pt-head { flex: 1 0 auto; }
.pt-strip { display: flex; align-items: center; gap: .5em; margin-top: auto; padding-top: 0; }
.pt-strip-left { display: inline-flex; align-items: center; gap: 2.5px; }
.pt-strip-right { margin-left: auto; display: inline-flex; align-items: center; gap: .45em; color: var(--muted); }
/* the 4-state profile dot: filled = bio, hollow = stub; green = fresh, pale = stale */
.pt-state { width: 9px; height: 9px; border-radius: 50%; box-sizing: border-box; flex: 0 0 auto; }
/* the queued-visit spinner overlays the profile-state dot exactly (owner
   2026-09-15) - the spinning ring's hub IS the dot it reports on, and the
   absolute placement never pushes the strip icons sideways. Centered via
   negative margins (transform would fight the rotate keyframes) */
.pt-state-wrap { position: relative; display: inline-flex; flex: 0 0 auto; }
.pt-state-wrap .pt-spin { position: absolute; left: 50%; top: 50%; margin: -6px 0 0 -6px; }
.pt-state.is-bio-fresh { background: #2ecc71; }
.pt-state.is-bio-stale { background: color-mix(in srgb, #2ecc71 35%, var(--muted)); }
.pt-state.is-stub-fresh { border: 1.5px solid #2ecc71; }
.pt-state.is-stub-stale { border: 1.5px solid var(--muted); }
.pt-spin, .ps-spin { display: inline-block; width: 12px; height: 12px; border: 2px solid color-mix(in srgb, var(--secondary) 32%, transparent); border-top-color: var(--secondary); border-radius: 50%; animation: ptspin .8s linear infinite; flex: 0 0 auto; }
@keyframes ptspin { to { transform: rotate(360deg); } }
/* the hydration dot is clickable (queues a profile visit, owner 2026-10-06) */
.pt-state.pt-state-click { cursor: pointer; }
.pt-ico { display: inline-flex; width: 13px; height: 13px; }
.pt-ico svg { width: 100%; height: 100%; }
.pt-ico.on { color: var(--text); }
.pt-mail { display: inline-flex; align-items: center; gap: .15em; }
.pt-mail svg { width: 13px; height: 13px; }
.pt-mail-count { font-size: .85em; }
.pt-mail.on { color: var(--text); }
.pt-flags .ml4 { margin-left: 0; }
.badge-off { opacity: .2; filter: grayscale(1); }
/* zbiornik badges: white disc + glyph in the theme fill (markup captured from
   the live DOM, M7) */
.nicon { display: inline-block; width: 15px; height: 15px; background: #fff; border-radius: 50%; }
.nicon svg { display: block; width: 100%; height: 100%; }
.badge-vip { fill: rgb(255, 64, 129); }
.badge-verified { fill: rgb(76, 175, 80); }
.badge-monetizing { fill: rgb(3, 169, 244); }
.badge-paid { fill: rgb(239, 108, 0); }
/* the rare $ sits in the tile's bottom strip but visually continues the
   vertical badge column: tops of the column steps are 19.3px apart, the
   strip lands 5.2px lower - pull it up to the next even step (measured);
   relative+top, not margin (flex centering would re-center the margin away) */
.pt-strip-right .badge-paid { position: relative; top: -5.2px; }
.ml4 { margin-left: 4px; }

/* ---------- Messages / zbiornik (M8) ---------- */
/* the panel needs the full content height with per-column scrolling */
.content:has(.panel-messages) { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.content:has(.panel-messages) div:has(.panel-messages) { display: flex; flex-direction: column; flex: 1; min-height: 0; } /* QCubed _ctl wrappers and the panel-content control */
.panel-messages { flex: 1; min-height: 0; }
.panel-messages { flex: 1; display: flex; min-height: 0; }
/* Activity (M13): the same full-height chain as messages - without it the
   repeater grows unbounded, .content scrolls instead of it and the JS
   loadmore trigger (bound to the repeater's own scroll) never fires */
.content:has(.panel-activity) { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.content:has(.panel-activity) div:has(.panel-activity) { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.panel-activity { flex: 1; display: flex; min-height: 0; }
.panel-activity-list { flex: 1; min-height: 0; }
/* the activity split mirrors .msg-split: feed | profile events | side panel;
   the child's QCubed wrappers pass their grid items through (display:contents) */
.act-split { flex: 1; display: grid; grid-template-columns: 1fr 1fr 1fr; min-height: 0; min-width: 0; }
.act-split > div:not([class]), .act-split > div:not([class]) > div:not([class]) { display: contents; }
.act-empty { grid-column: 2 / 4; }
.act-profile-repeater { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
/* activity-only override of the global img.avatar max-height: 55px (the
   .mini-row precedent) - taller crops would inflate every feed row */
.activity-row img.avatar { max-height: 40px; }
.msg-split { flex: 1; display: grid; grid-template-columns: 1fr 1fr 1fr; min-height: 0; min-width: 0; }
/* ThreadViewPanel's QCubed wrappers must not become grid items of their own -
   display:contents passes the child's columns (thread view + card) through */
.msg-split > div:not([class]), .msg-split > div:not([class]) > div:not([class]) { display: contents; }
.thread-view.thread-empty { grid-column: 2 / 4; }

/* thread list */
.thread-list { border-right: 1px solid var(--border); background: var(--surface); display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
/* the repeater div itself scrolls (the section keeps head + loading label fixed) */
/* QCubed render() wraps the control in an anonymous div - constrain that
   wrapper, the repeater inside just fills it */
.thread-list > div:not([class]) { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.thread-repeater { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.thread-loading { flex: 0 0 auto; text-align: center; padding: .5em; font-size: .85em; }
.thread-list-head { display: flex; align-items: center; gap: .5em .7em; padding: .6em .9em; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.thread-list-head .ir-count { flex: 0 0 auto; }
/* the URL-state filter bar (2026-10): bot / month / search / sort dropdowns
   with reset links + highlight, the unread toggle-tag - the .ps-filter /
   .ev-filter pattern localized to the messages page */
.mf-wrap { display: inline-flex; align-items: center; gap: .4em; flex: 0 0 auto; min-width: 0; }
.mf-wrap select, .mf-wrap input { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .4em; padding: .25em .45em; font-family: inherit; font-size: .85em; cursor: pointer; width: 7em;}
.mf-wrap input { cursor: text; width: 8em; }
/* charset-guard flash: a refused/converted character was just dropped (app.js) */
.mf-search.denied { border-color: var(--accent); box-shadow: 0 0 7px color-mix(in srgb, var(--accent) 55%, transparent); }
.mf-wrap.active select, .mf-wrap.active input { border-color: var(--secondary); box-shadow: 0 0 7px color-mix(in srgb, var(--secondary) 55%, transparent); }
.mf-reset { background: none; border: 0; padding: 0; color: var(--muted); font-family: inherit; font-size: .82em; text-decoration: underline; cursor: pointer; }
.mf-reset:hover { color: var(--text); }
.mf-unread-tag { cursor: pointer; user-select: none; padding: .3em .6em; font-weight: 600; font-size: .85em; border: 1px solid var(--border); border-radius: .4em; color: var(--muted); }
.mf-unread-tag.active { color: var(--text); border-color: var(--secondary); box-shadow: 0 0 7px color-mix(in srgb, var(--secondary) 55%, transparent); }
/* the filter strip's QCubed wrappers (panel + its child strip panel): both
   must be flex lines that may shrink, so the chips inside actually compress
   (2026-09-25; inline buttons just wrapped inside the wrappers) */
.thread-list-head > div:first-child,
.thread-list-head > div:first-child > div:first-child { display: flex; align-items: center; gap: .4em; flex: 0 1 auto; min-width: 0; flex-wrap: nowrap; }
.bot-filter { padding: .3em .6em; border-radius: .5em; border: 1px solid var(--border); background: var(--bg); color: var(--text); font-family: inherit; font-size: .85em; }
a.thread-row {
    display: flex; gap: .7em; align-items: center;
    padding: .5em .9em;
    border-bottom: 1px solid var(--border);
    color: inherit; text-decoration: none;
}
a.thread-row.last-in { background: linear-gradient(90deg, color-mix(in srgb, var(--primary) 12%, transparent), transparent 62%); }
a.thread-row.last-out { background: linear-gradient(270deg, color-mix(in srgb, var(--secondary) 12%, transparent), transparent 62%); }
a.thread-row:hover { background: var(--surface-2); }
a.thread-row.active { background: var(--surface-2); box-shadow: inset 3px 0 0 var(--secondary); }
a.thread-row.unread .thread-nick,
a.thread-row.unread .thread-preview { font-weight: 400; }

/* avatars in the messages UI: ONE rule, exactly the profile tiles'
   (pt-avatar) - 40px wide, portrait grows to max 55px tall, landscape crops
   its sides to the square. (18px bubble-side avatar stays - owner's spec.) */
.avatar {
    flex: 0 0 auto; width: 40px; height: 40px; border-radius: 4px;
    display: flex; align-items: center; justify-content: center;
    background: var(--primary); color: var(--on-primary);
    font-family: "Saira", sans-serif; font-weight: 400;
    text-transform: uppercase; font-size: .9em;
}
img.avatar { display: block; width: 40px; height: auto; min-height: 40px; max-height: 55px; object-fit: cover; object-position: center; }
.avatar-deleted { opacity: .12; filter: grayscale(1); } /* like the service: default man placeholder, heavily faded */
.cc-head .avatar { margin: 0 auto .6em; }

.thread-main { flex: 1; min-width: 0; }
.thread-top { display: flex; justify-content: space-between; gap: .6em; align-items: baseline; }
.thread-nick { font-family: "Saira", sans-serif; font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.thread-time { flex: 0 0 auto; font-size: .78em; color: var(--muted); white-space: nowrap; }
.thread-preview { color: var(--muted); font-size: .92em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.thread-foot { display: flex; gap: .5em; margin-top: .25em; align-items: center; min-height: 1.2em; }

.tag { display: inline-block; font-size: .72em; line-height: 1.5; padding: 0 .6em; border-radius: 0.5em; border: 1px solid var(--border); color: var(--muted); vertical-align: middle; }
.tag-deleted { border-color: var(--accent); color: var(--accent); }
.tag-partial { border-color: var(--secondary); color: var(--secondary); }
.tag-ok { border-color: #2ecc71; color: #2ecc71; }
.tag-invite { border-color: var(--secondary); color: var(--secondary); }
.tag-bot { font-size: .7em; border-color: var(--bot-c-v); background: var(--bot-bg); }
[data-theme="light"] .tag-bot { border-color: var(--bot-c-vd); background: var(--bot-bg-l); }

.unread-badge {
    margin-left: auto;
    background: var(--accent); color: #fff;
    min-width: 1.6em; height: 1.6em; border-radius: 1em;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: .8em; font-weight: 400; padding: 0 .45em;
}

/* open thread */
.thread-view { display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--bg); }
.thread-view.thread-empty { align-items: center; justify-content: center; display: flex; }
.thread-head { display: flex; align-items: center; gap: .8em; padding: .8em 1.2em; background: var(--surface); border-bottom: 1px solid var(--border); }
.thread-head-main { flex: 1; min-width: 0; }
.thread-head-nick { font-family: "Saira", sans-serif; font-weight: 400; font-size: 1.15em; }
.thread-head-sub { font-size: .85em; }
.thread-head-tags { display: flex; flex-direction: column; gap: .25em; align-items: flex-end; }
.thread-head-tags .tag { font-size: .8em; }

.msg-scroll { flex: 1; overflow-y: auto; padding: 1em .1em; }
.msg-col { width: 100%; display: flex; flex-direction: column; gap: .5em; }
.msg-row { display: flex; }
.msg-row.out { justify-content: flex-end; }
.msg-row.in { justify-content: flex-start; }
.bubble {
    position: relative;
    max-width: 85%; /* of the conversation column */
    padding: .55em .9em .9em;
    border-radius: 0.6em;
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
    font-size: .98em;
    overflow-wrap: break-word;
    min-width: 9em; /* room for the corner timestamp even in a one-char bubble */
		font-weight: 300;
}
.msg-row.out .bubble { background: var(--primary); border-color: transparent; color: #fff; border-bottom-right-radius: 0; max-width: 87%; margin-right: 0.5em;}
.msg-row.in .bubble { border-bottom-left-radius: 0; }
.msg-unseen .bubble { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 55%, transparent), var(--shadow); }
.bubble-deleted { border-style: dashed; border-color: var(--accent); opacity: .82; }
.attach-ph { display: inline-block; padding: .5em 1.2em; border: 1px dashed var(--border); border-radius: .5em; color: var(--muted); font-style: italic; }
.attach-link { display: inline-block; margin: .1em .2em .1em 0; }
.attach-thumb { display: block; max-width: 240px; max-height: 320px; width: auto; height: auto; border-radius: .5em; }
.msg-tag { display: block; margin-top: .35em; font-size: .75em; }
.msg-row.out .msg-tag { color: rgba(255,255,255,.75); }
.msg-row.in .tag-deleted { color: var(--accent); }
.msg-time { position: absolute; right: .8em; bottom: calc(.2em - 1px); font-size: .7em; opacity: .65; }
.msg-text { position: relative; top: -3px; } /* layout-neutral nudge: the bubble's size stays put */
.thread-empty-note { text-align: center; padding: 1em; }
.thread-foot-bar { padding: .55em 1.2em; background: var(--surface); border-top: 1px solid var(--border); font-size: .82em; text-align: center; }
.thread-foot-bar .composer { display: flex; gap: .5em; align-items: stretch; }
.thread-foot-bar .composer textarea { flex: 1; resize: none; font: inherit; font-size: 1.05em; padding: .45em .6em; border: 1px solid var(--border); border-radius: .5em; background: var(--bg); color: var(--text); }
.thread-foot-bar .composer .button { align-self: center; }
.thread-foot-bar .composer-meta { margin-top: .3em; font-size: .85em; }
.thread-foot-bar .composer-block { padding: .5em; }
.thread-foot-bar .composer-status { margin-top: .3em; font-size: .85em; }
.thread-foot-bar .send-error { color: var(--accent); }

/* contact card */
.contact-card { border-left: 1px solid var(--border); background: var(--surface); padding: 0; overflow-y: auto; }
.contact-card .ps-fadetop { margin: -17px -1.1em -5px; }
/* M10-UI: the shared ProfileSidePanel fills the card; its ps-inner owns the
   padding, the Thread block keeps the old side margins */
.contact-card .ps-inner { padding: 1.2em 1.1em .4em; }
.contact-card .cc-section { margin: .8em 1.1em .4em; }
.contact-card .cc-rows { margin: 0 1.1em 1em; }
.cc-head { text-align: center; margin-bottom: 1.2em; }
.cc-nick { font-family: "Saira", sans-serif; font-weight: 400; font-size: 1.3em; }
.cc-sub { margin-top: .1em; }
.cc-rows { margin-bottom: 1.1em; }
.cc-row { display: flex; justify-content: space-between; gap: .8em; padding: .4em 0; border-bottom: 1px dashed var(--border); font-size: .92em; }
.cc-row:last-child { border-bottom: 0; }
.cc-row span { color: var(--muted); }
.cc-row strong { font-weight: 400; text-align: right; }
.cc-section { font-family: "Saira", sans-serif; font-size: .95em; font-weight: 400; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 1.2em 0 .4em; }
.cc-note { font-size: .82em; line-height: 1.4; }

@media (max-width: 1280px) {
    .msg-split { grid-template-columns: 1fr 1fr; }
    .contact-card { display: none; }
}
@media (max-width: 900px) {
    .msg-split { grid-template-columns: 1fr; }
    .thread-list { border-right: 0; }
    .thread-view { display: none; } /* drill-in state would toggle this */
    .bubble { max-width: 82%; }
}

/* sidebar subitem (Messages > zbiornik) */
.menu-subitem a { display: block; padding: .4em 1.2em .4em 3.1em; color: var(--sidebar-text); text-decoration: none; border-left: 3px solid var(--secondary); background: rgba(255,255,255,.05); font-size: .92em; }

/* thread row: nick + badges + meta share one line, meta truncates first */
.thread-id { display: flex; align-items: center; gap: .35em; min-width: 0; overflow: hidden; flex: 1; }
.thread-id .thread-nick { flex: 0 1 auto; }
.thread-meta { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: .82em; flex: 0 1 auto; min-width: 0; }
.thread-id .nicon { width: 13px; height: 13px; }

/* bubble-side avatar (incoming messages) */
.msg-row.in .avatar { margin: 0 .45em 0 0; align-self: flex-end; }

/* instant feedback on thread open (M8): cover + spinner until the ajax redraw lands */
.thread-view, .contact-card { position: relative; }
.msg-cover {
    position: absolute; inset: 0; z-index: 5;
    background: color-mix(in srgb, var(--bg) 65%, transparent);
    display: flex; align-items: center; justify-content: center;
}
.msg-cover::after {
    content: ''; width: 2em; height: 2em; border-radius: 50%;
    border: 3px solid var(--border); border-top-color: var(--accent);
    animation: msgspin .8s linear infinite;
}
@keyframes msgspin { to { transform: rotate(360deg); } }
.tag-count { font-variant-numeric: tabular-nums; }

/* bot filter as chips (a native <select> dropdown collapses on every watcher
   redraw - chips have no open state to kill). Label-tag look, not pills
   (owner 2026-09-25): the head never wraps - the chips flex-shrink below
   their natural width and the longest names ellipsis, so the whole strip +
   the counter always fits one line, even at 5 bots */
.bot-filter-btn, .type-filter-btn { font-size: .82em; padding: .25em .45em; border-radius: .35em; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); cursor: pointer; font-family: inherit; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bot-filter-btn.active, .type-filter-btn.active { border-color: var(--primary); background: var(--primary); color: #fff; }
/* the 'all' chip never shrinks (its 3 letters must survive the flex squeeze) */
.bot-filter-btn[data-value="all"], .type-filter-btn[data-value="all"] { flex: 0 0 auto; }

/* profiles sort chips (M10-UI): same chip look, the strip sits in the head */
.sort-strip { display: inline-flex; gap: .4em; flex-wrap: wrap; }
.profile-sort-btn { font-size: .82em; padding: .3em .8em; border-radius: .35em; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); cursor: pointer; font-family: inherit; }
.profile-sort-btn.active { border-color: var(--primary); background: var(--primary); color: #fff; }

/* landing dashboard (M9 demo): per-bot live guac tile + mini inbox; all
   bots must fit one screen (owner, 2026-09-10) */
.dash-bots { display: flex; flex-flow: row wrap; gap: .8em; align-items: flex-start; }
.dash-bot { max-width: 100%; }
/* two tiles per row at the 1695px panel width: gaps 0.6em + 430px inbox
   column keep a tile at ~825px (owner, 2026-10-04) */
.dash-bot-body { display: grid; grid-template-columns: auto 320px minmax(0, 430px); gap: 0.6em; align-items: start; padding: 0.5em 0; }
/* side strip = the original one-line head rotated 90deg counterclockwise:
   vertical-rl lays the line top-to-bottom, the 180deg flip makes it read
   bottom-to-top with the bot name at the bottom (owner, 2026-10-04).
   Stretched to the tile height with space-between: the button keeps the
   top edge, the name+nick group hugs the bottom one */
.dash-bot-side {
    display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: .8em;
    align-self: stretch;
    writing-mode: vertical-rl; transform: rotate(180deg);
    white-space: nowrap;
    font-family: "Saira", sans-serif; /* the body default is Saira Condensed */
    cursor: default;
}
.dash-bot-ids { display: flex; flex-direction: row; align-items: center; gap: .8em; }
/* straight into the /live HD view from the dashboard tile (owner 2026-09-13) */
.dash-fullview { display: inline-block; padding: 5px 5px; font-weight: 500; font-size: 0.8em; }
/* neutral light gray text (owner 2026-10-04) - the bot-name colors bring
   enough chroma here; (0,1,1) specificity to beat the global a:link rule */
a.dash-fullview:link, a.dash-fullview:visited { color: #c8c8c8; }
[data-theme="light"] a.dash-fullview:link, [data-theme="light"] a.dash-fullview:visited { color: #595959; }
.dash-fullview:hover { border-color: var(--primary); }
.mini-inbox { display: flex; flex-direction: column; min-width: 0; max-height: 240px; overflow-y: auto; }
.mini-row { display: flex; align-items: center; gap: .55em; padding: .12em .3em; border-bottom: 1px solid var(--border); color: inherit; text-decoration: none; border-radius: .35em; }
/* last-message direction hint, exactly the messages list's (thread-row):
   theirs = left glow (primary), ours = right glow (secondary) */
.mini-row.last-in { background: linear-gradient(90deg, color-mix(in srgb, var(--primary) 12%, transparent), transparent 62%); }
.mini-row.last-out { background: linear-gradient(270deg, color-mix(in srgb, var(--secondary) 12%, transparent), transparent 62%); }
/* hover AFTER the direction gradients so it actually wins (same specificity,
   source order decides) - the thread-row rules use the same order */
.mini-row:hover { background: var(--surface-2); }
.mini-row img.avatar { min-height: 33px; max-height: 33px; }
.mini-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.mini-preview { font-size: .9em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mini-top { display: flex; align-items: baseline; gap: .35em; min-width: 0; }
.mini-top .mini-nick { flex: 0 0 auto; color: var(--text); }
/* bot color identity (BotAccount::color*): the element carries --bot-c /
   --bot-c-d inline; dark theme reads the base shade, light theme the dark one */
.botid { color: var(--bot-c); }
[data-theme="light"] .botid { color: var(--bot-c-d); }
/* the saturated variant (BotAccount::colorVivid) - same on both themes */
.botid-v { color: var(--bot-c-v); }
[data-theme="light"] .botid-v { color: var(--bot-c-vd); }
.mini-top .nicon { width: 12px; height: 12px; }
.mini-top .ml4 { flex: 0 0 auto; margin-left: 0; }
.mini-meta { font-size: .78em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.mini-time { flex: 0 0 auto; font-size: .78em; white-space: nowrap; }
.mini-more { justify-content: center; font-size: .85em; min-height: 40px; }
.mini-empty { padding: 1em .4em; }
@media (max-width: 1100px) {
    .dash-bot-body { grid-template-columns: 1fr; }
    /* the rotated strip would eat vertical space on the stacked layout */
    .dash-bot-side { writing-mode: horizontal-tb; transform: none; }
}

/* ajax-resilience.js: transient connectivity badge (replaces QCubed's white error box) */
#ajax-conn-badge {
    position: fixed; top: 8px; left: 50%; /* centered on the viewport, above everything */
    z-index: 10001;
    display: flex; align-items: center; gap: .6em;
    padding: .45em 1em; border-radius: 999px;
    background: var(--surface); border: 1px solid var(--border);
    color: var(--text); font-size: .85em;
    box-shadow: var(--shadow);
    opacity: 0; transform: translateX(-50%) translateY(-8px);
    pointer-events: none;
    transition: opacity .25s, transform .25s;
}
#ajax-conn-badge.visible { opacity: 1; transform: translateX(-50%); }
#ajax-conn-badge .acb-dot {
    width: .6em; height: .6em; border-radius: 50%;
    background: var(--accent);
    animation: acb-pulse 1.2s ease-in-out infinite;
}
@keyframes acb-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

/* /system page (M10 side task): status text colors reusing the lamp palette */
.sys-ok { color: #2ecc71; }
.sys-warn { color: #f1c40f; }
.sys-bad { color: var(--accent); font-weight: 600; }
tr.sys-bad td { color: var(--accent); }

/* /system: narrow columns centered; the long-text (cell-wrap) cells stay left */
.system-page .datagrid th, .system-page .datagrid td { text-align: center; }
.system-page .datagrid td:has(.cell-wrap) { text-align: left; }

/* /system: vertical separation between the cards, and between the two
   tables inside the containers & disk card (owner, 2026-09-12) */
.system-page { display: flex; flex-direction: column; gap: 1.4em; }
.system-page .datagrid + .datagrid { margin-top: 1.1em; }
.system-page .card > h2 { margin-top: 0; }
.system-page .sys-disks { margin-top: 1.1em; }

/* ---------- M12 /calendar (FullCalendar 6.1.21 on the app theme) ----------
   FC's default styling is light-only; its CSS variables (names verified
   against the vendored index.global.min.js) are mapped onto the theme vars
   here so the calendar follows BOTH [data-theme]s. */
#bulb-calendar {
    --fc-border-color: var(--border);
    --fc-page-bg-color: transparent; /* the .card wrapper carries the surface */
    --fc-neutral-bg-color: var(--surface-2);
    --fc-neutral-text-color: var(--text);
    --fc-today-bg-color: transparent; /* today = normal bg + white frame (owner 2026-09-24) */
    --fc-highlight-color: color-mix(in srgb, var(--primary) 22%, transparent);
    --fc-event-bg-color: var(--primary);   /* the scheduled_task layer color */
    --fc-event-border-color: var(--primary);
    --fc-event-text-color: var(--on-primary);
    --fc-button-bg-color: var(--surface-2);
    --fc-button-text-color: var(--text);
    --fc-button-border-color: var(--border);
    --fc-button-hover-bg-color: var(--surface);
    --fc-button-hover-border-color: var(--primary);
    --fc-button-active-bg-color: var(--primary);
    --fc-button-active-border-color: var(--primary);
    --fc-list-event-hover-bg-color: var(--surface-2);
    --fc-more-link-text-color: var(--secondary);
    --fc-non-business-color: color-mix(in srgb, var(--muted) 12%, transparent);
    --fc-now-indicator-color: var(--accent);
    color: var(--text);
}
#bulb-calendar.fc { font-family: inherit; }
/* the today button: already on today = disabled = hidden entirely (owner 2026-10-19) */
#bulb-calendar .fc-today-button:disabled { display: none; }
/* no lingering focus halo on the prev/next buttons after a click (owner 2026-10-19) */
#bulb-calendar .fc-button:focus { outline: none; box-shadow: none; }
/* the calendar buttons hover like every other button: only the border flips
   (owner 2026-10-19) - beats FC's own hover vars by the id specificity */
#bulb-calendar .fc-button:not(:disabled):hover { border-color: var(--secondary); background: var(--surface-2); }
/* day numbers / weekday headers / list-day captions are <a> in FC; keep them
   on-theme instead of the generic link colors. NOTE: the mount div IS the .fc
   root, so "#bulb-calendar .fc x" would never match - no .fc in the chain. */
#bulb-calendar a { color: inherit; }
#bulb-calendar .fc-col-header-cell { background: var(--surface-2); }
#bulb-calendar .fc-col-header-cell-cushion { color: var(--muted); text-decoration: none; }
#bulb-calendar .fc-daygrid-day-number { color: var(--text); text-decoration: none; }
#bulb-calendar .fc-list-day-text, #bulb-calendar .fc-list-day-side { color: var(--text); text-decoration: none; }
#bulb-calendar .fc-list-empty { background: transparent; color: var(--muted); }
#bulb-calendar .fc-toolbar-title { font-family: "Saira", sans-serif; font-size: 1.35em; }

/* filters row: layer checkbox + bot chips (the .bot-filter-btn look, but a
   separate class - app.js's messages-page chip handler binds .bot-filter-btn
   globally and would fight over the active class) */
/* filters bar hidden for now (owner 2026-09-27) - the elements stay in the
   DOM (calendar.js reads the layer checkboxes), only invisible */
.cal-filters { display: none; }
.cal-layer { display: inline-flex; align-items: center; gap: .4em; cursor: pointer; }
.cal-layer-swatch { display: inline-block; width: .8em; height: .8em; border-radius: .2em; background: var(--primary); }
.cal-bot-chips { display: inline-flex; gap: .4em; flex-wrap: wrap; }
.cal-bot-chip, .cal-pick-chip { font-size: .8em; padding: .3em; border-radius: .3em; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); cursor: pointer; font-family: inherit;}
.cal-bot-chip.active { border-color: var(--primary); background: var(--primary); color: #fff; }
/* the modal bot picks ride the events tag-filter look (owner 2026-10-19):
   dimmed until picked; ACTIVE = the bot's own color identity (the /live
   tiles' --bot-c* vars ride the chip inline): colored label + border/glow */
.cal-pick-chip { display: inline-flex; gap: .2em; opacity: .4; max-width: 11em; min-width: 0; overflow: hidden; white-space: nowrap; }
.cal-pick-chip:hover { opacity: 1; }
.cal-pick-chip:not(.active):hover { border-color: var(--secondary); }
.cal-pick-chip .cpc-nick { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.cal-pick-chip.active { opacity: 1; border-color: var(--bot-c-v); color: var(--text); box-shadow: 0 0 7px color-mix(in srgb, var(--bot-c-v) 55%, transparent); }
.cal-pick-chip.active .cpc-id { color: var(--bot-c); }
.cal-pick-chip.active .cpc-nick { color: var(--bot-c-v); }
[data-theme="light"] .cal-pick-chip.active { border-color: var(--bot-c-vd); box-shadow: 0 0 7px color-mix(in srgb, var(--bot-c-vd) 55%, transparent); }
[data-theme="light"] .cal-pick-chip.active .cpc-id { color: var(--bot-c-d); }
[data-theme="light"] .cal-pick-chip.active .cpc-nick { color: var(--bot-c-vd); }

/* event chip: state dot + title + aggregate ("done 2/3") */
.cal-ev { display: inline-flex; align-items: center; gap: .3em; max-width: 100%; overflow: hidden; }
.cal-ev-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-ev-agg { font-size: .85em; opacity: .85; white-space: nowrap; }
.cal-dot { display: inline-block; width: .55em; height: .55em; border-radius: 50%; flex: 0 0 auto; }
/* fixed semantic hues, readable on both themes' surfaces */
.cal-dot-pending { background: #4f9cf4; }
.cal-dot-enqueued { background: #9b6df2; }
.cal-dot-executing { background: #e8a13d; }
.cal-dot-done { background: #46b56a; }
.cal-dot-failed { background: #e04a5a; }
.cal-dot-expired { background: #8d8d99; }
.cal-dot-cancelled { background: #63636e; }
.cal-ev-cancelled .cal-ev-title { text-decoration: line-through; opacity: .7; }
#bulb-calendar .fc-list-event-dot { border-color: var(--fc-event-bg-color); }
/* M15 events layer: own color (secondary; the calendar-level FC vars stay the
   scheduled_task primary), proposed events dimmed as drafts, same-venue
   date-range conflicts get the loud red (fixed semantic hue, both themes) */
.cal-layer-swatch.cal-swatch-events { background: var(--secondary); }
#bulb-calendar .fc-event.cal-layer-events { --fc-event-bg-color: var(--secondary); --fc-event-border-color: var(--secondary); --fc-event-text-color: var(--bg); font-weight: 600; padding: 2px 4px; }
/* two-line events chips (owner 2026-09-27): title line, then where + tag
   icons right-aligned */
.cal-ev-event { display: flex; flex-direction: column; align-items: stretch; gap: 0; width: 100%; }
.cal-ev-line1 { display: inline-flex; align-items: center; gap: .3em; min-width: 0; }
.cal-ev-sub { display: flex; align-items: baseline; gap: .4em; font-weight: 400; font-size: .92em; opacity: .92; min-width: 0; }
.cal-ev-where { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.cal-ev-icons { margin-left: auto; white-space: nowrap; font-size: 1.5em; text-shadow: 0 1px 3px rgba(0, 0, 0, .85); }
#bulb-calendar .fc-event.cal-ev-proposed { opacity: .72; }
#bulb-calendar .fc-event.cal-ev-conflict { --fc-event-bg-color: #e04a5a; --fc-event-border-color: #e04a5a; --fc-event-text-color: #fff; }
#bulb-calendar .cal-ev-warn { color: #fff; background: #e04a5a; border-radius: .25em; padding: 0 .3em; font-weight: 600; flex: 0 0 auto; }
#bulb-calendar .fc-event.cal-ev-conflict .cal-ev-warn { background: #fff; color: #e04a5a; }
/* the calendar page's scroller always reserves the scrollbar gutter, so the
   inner width never jumps AFTER FC measured the grid (FF, maximized window,
   full refresh → the Sunday column's day number got clipped, 2026-09-24).
   Scoped to the calendar page only - a reserved gutter elsewhere would just
   be dead space on non-scrolling pages */
.content:has(.panel-calendar) { scrollbar-gutter: stable; }
/* other-month cells recede ONLY when past (the previous-month fragment);
   next-month days are future and keep the normal background. Day numbers:
   past = grey + thin, today/future = full color + weight (owner 2026-09-24;
   Saira stays within the 100-400 weight convention) */
#bulb-calendar .fc-day-other.fc-day-past { background: color-mix(in srgb, var(--surface-2) 35%, transparent); }
#bulb-calendar .fc-day-past .fc-daygrid-day-number { color: var(--muted); font-weight: 200; }
#bulb-calendar .fc-day-future .fc-daygrid-day-number,
#bulb-calendar .fc-day-today .fc-daygrid-day-number { color: var(--text); font-weight: 400; }
/* next-month fragment: day numbers almost-white for extra contrast (owner
   2026-09-24); light theme mirrors to almost-black */
#bulb-calendar .fc-day-other.fc-day-future .fc-daygrid-day-number { color: #fff; }
[data-theme="light"] #bulb-calendar .fc-day-other.fc-day-future .fc-daygrid-day-number { color: #000; }
/* today: normal background + a white frame (outline - zero layout shift in
   the collapsed-borders scrollgrid) */
#bulb-calendar .fc-day-today { outline: 1px solid #fff; outline-offset: -1px; }
[data-theme="light"] #bulb-calendar .fc-day-today { outline-color: #000; }
/* tighter event lines in day cells (owner 2026-09-24): 21px harness -> ~16px */
#bulb-calendar .fc-daygrid-event-harness { margin-top: 0; }
#bulb-calendar .fc-daygrid-event { padding: 0 2px; font-size: .82em; line-height: 1.25; }

/* calendar modals (bmodal look; content is plain DOM filled by calendar.js) */
.cal-modal {
	max-width: 52em;
	width: 52em;
	text-align: left;
}
.cal-modal .bmodal-text { margin-bottom: .6em; }
.cal-form-row { display: flex; gap: .8em; align-items: center; flex-wrap: wrap; margin: .55em 0; }
.cal-form-col { flex-direction: column; align-items: stretch; gap: .25em; }
.cal-modal input[type=date], .cal-modal input[type=time], .cal-modal textarea {
    padding: .45em .8em;
    border: 1px solid var(--border); border-radius: .5em;
    background: var(--bg); color: var(--text);
    font-family: inherit;
}
.cal-bot-picks { gap: .4em; flex-wrap: nowrap; justify-content: space-between;}
.cal-counter { align-self: flex-end; font-size: .8em; }
.cal-error { color: var(--accent); margin: .55em 0; }
.cal-error.bi-hidden { display: none; }
.cal-modal-actions { display: flex; gap: .6em; justify-content: flex-end; margin-top: .8em; }
.cal-modal-actions > * { flex: 1 1 0; }
.cal-modal-actions .button { margin-top: 0; width: 100%; }
.cal-danger { filter: saturate(1.4) hue-rotate(-25deg); }
.cal-det-meta { margin: .2em 0 .6em; }
.cal-det-meta > div { display: flex; gap: .6em; padding: .1em 0; }
.cal-meta-k { min-width: 4.5em; color: var(--muted); font-size: .85em; }
.cal-det-text { white-space: pre-wrap; overflow-wrap: anywhere; margin: .4em 0 .8em; }
.cal-pairs { width: 100%; border-collapse: collapse; margin-bottom: .4em; }
.cal-pairs td { padding: .25em .5em; border-top: 1px solid var(--border); font-size: .92em; }
.cal-pairs td:last-child { color: var(--muted); overflow-wrap: anywhere; }
.cal-drop-info { margin: .4em 0; }
.cal-drop-title { font-weight: 600; overflow-wrap: anywhere; }
#cal-det-edit { border-top: 1px solid var(--border); margin-top: .8em; padding-top: .4em; }
#cal-det-edit.bi-hidden, #cal-det-cancel-task.bi-hidden, #cal-det-restore.bi-hidden { display: none; }

/* ---------- M15 /events (the events work layer) ---------- */
.ev-filters { display: flex; gap: .6em; margin: .4em 0 .8em; align-items: baseline; flex-wrap: wrap; }
.ev-filters select { background: var(--surface-2); color: var(--text); border: 1px solid color-mix(in srgb, var(--border) 30%, #000); border-radius: .35em; padding: 0 .5em; font-family: inherit; box-shadow: 0 0 4px color-mix(in srgb, #fff 40%, transparent); }
/* tag filter chips (owner 2026-09-27): click filters; the active chip gets
   the secondary border + glow, the rest fade hard; reset link only then */
.ev-tagfilter { display: inline-flex; align-items: baseline; flex-wrap: wrap; }
.ev-tagfilter .ev-filter-tag { cursor: pointer; user-select: none; padding: 0.3em 0.6em; margin: 0 0.3em; font-weight: 600; border-color: color-mix(in srgb, var(--border) 30%, #000); box-shadow: 0 0 4px color-mix(in srgb, #fff 40%, transparent); }
.ev-tagfilter.has-active .ev-filter-tag { opacity: .3; }
.ev-tagfilter.has-active .ev-filter-tag.active { opacity: 1; border-color: var(--secondary); color: var(--text); box-shadow: 0 0 7px color-mix(in srgb, var(--secondary) 55%, transparent); }
.ev-cityfilter.has-active select { border-color: var(--secondary); box-shadow: 0 0 7px color-mix(in srgb, var(--secondary) 55%, transparent); }
.ev-filter-reset { margin-left: .5em; font-size: .85em; color: var(--secondary); }
/* independent column scrolling (owner 2026-09-27): the page itself never
   scrolls - the list and the card own their scrollbars (the profiles/
   messages full-height pattern) */
.content:has(.panel-events) { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.content:has(.panel-events) div:has(.panel-events) { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.panel-events { display: flex; flex-direction: column; flex: 1; min-height: 0; padding: .5em; }
.events-page { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.ev-split { display: flex; gap: .8em; align-items: flex-start; flex: 1; min-height: 0; }
.ev-list { flex: 1 1 55%; min-width: 0; padding: 1.2em 0; max-height: 100%; overflow-y: auto; }
.ev-card-col { flex: 1 1 45%; min-width: 0; max-height: 100%; overflow-y: auto; }
/* the today separator (owner 2026-09-27): one unified newest-first list,
   split by a wide banner - upcoming above (arrows up), past below */
.ev-today-sep { display: flex; flex-direction: column; align-items: center; gap: .1em; margin: .8em 0; padding: .8em 0; border-top: 2px solid var(--border); border-bottom: 2px solid var(--border); text-align: center; }
.ev-today-cap { font-family: "Saira", sans-serif; font-weight: 600; color: var(--muted); text-transform: uppercase; font-size: .72em; letter-spacing: .14em; }
.ev-today-arr { font-size: 1.5em; line-height: 1; vertical-align: -.08em; }
.ev-today-now { font-family: "Saira", sans-serif; font-weight: 600; font-size: 1.25em; letter-spacing: .05em; color: var(--secondary); text-transform: uppercase; }
a.event-row.ev-past .ev-title { opacity: .5; }
/* weekend grouping (variant C): gap + a delicate inset hairline on the
   first row of a new weekend; rows themselves carry no vertical padding */
a.event-row.ev-wk-start { margin-top: .9em; position: relative; }
a.event-row.ev-wk-start::before { content: ''; position: absolute; top: -.5em; left: .8em; right: .8em; height: 0; border-top: 1px solid color-mix(in srgb, var(--border) 45%, transparent); }
/* immovable holidays (NYE, Easter Monday): accent glyph before the title */
.ev-holiday { color: var(--accent); }
.ev-empty { padding: .3em .8em .8em; }
a.event-row { display: flex; align-items: baseline; gap: .6em; padding: 0 0 0 .4em; color: inherit; text-decoration: none; border-left: 3px solid transparent; }
a.event-row:hover { background: var(--surface-2); }
a.event-row.active { border-left-color: var(--secondary); background: color-mix(in srgb, var(--secondary) 22%, transparent); }
a.event-row .ev-dow { flex: 0 0 2.2em; min-width: 3em; white-space: nowrap; text-align: center; color: var(--muted); font-size: .78em; text-transform: uppercase; }
a.event-row .ev-when { flex: 0 0 auto; min-width: 5em; text-align: right; white-space: nowrap; color: var(--muted); font-size: .85em; }
a.event-row .ev-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
a.event-row .ev-where { flex: 0 1 auto; min-width: 0; color: var(--muted); font-size: .85em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* one line per row, always (owner 2026-09-27): chips/badges never wrap or
   shrink - the title and venue take the ellipsis instead */
a.event-row .ev-tags { flex: 0 0 auto; white-space: nowrap; }
a.event-row .ev-tags .ev-tag { position: relative; top: -1px; }
a.event-row .ev-row-tag { cursor: pointer; }
a.event-row .ev-row-tag:hover { border-color: var(--secondary); }
a.event-row .ev-badges { flex: 0 0 auto; white-space: nowrap; }
a.event-row.ev-proposed .ev-title { opacity: .72; }
a.event-row.ev-cancelled .ev-title { text-decoration: line-through; opacity: .7; }
a.event-row.ev-conflict { background: color-mix(in srgb, #e04a5a 14%, transparent); }
.ev-tag { display: inline-block; font-size: .75em; padding: .05em .45em; border-radius: .35em; background: var(--surface-2); border: 1px solid var(--border); color: var(--muted); margin-right: .25em; }
/* card cells are .86em - compensate so card chips match the list's (owner 2026-09-27) */
.evc-v .ev-tag { font-size: .87em; font-weight: 500; }
.ev-tag-proposed { border-style: dashed; opacity: .8; }
.ev-badge { display: inline-block; font-size: .72em; padding: .08em .5em; border-radius: .35em; background: var(--surface-2); border: 1px solid var(--border); color: var(--muted); margin-left: .3em; }
.ev-badge-proposed { background: var(--secondary); border-color: var(--secondary); color: var(--bg); }
.ev-badge-confirmed { background: #46b56a; border-color: #46b56a; color: #10281a; }
.ev-badge-rejected { background: #63636e; border-color: #63636e; color: #fff; }
.ev-badge-conflict { background: #e04a5a; border-color: #e04a5a; color: #fff; }

/* review queue */
.ev-queue { margin-bottom: .8em; border: 1px solid var(--secondary); }
.ev-queue h3 { margin: 0 0 .4em; font-size: 1em; }
.ev-queue-row { display: flex; align-items: center; gap: .6em; padding: .25em 0; }
.ev-queue-row .button { flex: 0 0 auto; }
.ev-queue-row select { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .35em; padding: .25em .4em; font-family: inherit; }
a.event-row.ev-queue-link { flex: 1 1 auto; min-width: 0; padding: .15em .4em; }
.ev-queue-venue .ev-venue-name { font-weight: 600; }

/* event card */
.event-card-inner { min-width: 0; }
.event-card-empty { flex: 1 1 45%; }
.evc-head { display: flex; align-items: flex-start; gap: .6em; }
.evc-title { font-family: "Saira", sans-serif; font-weight: 600; font-size: 1.15em; flex: 1 1 auto; overflow-wrap: anywhere; }
.event-card-close { flex: 0 0 auto; color: var(--muted); text-decoration: none; font-size: 1.2em; padding: 0 .3em; }
.event-card-close:hover { color: var(--accent); }
/* payload details follow the profile-side-panel convention (owner 2026-09-27):
   right-aligned muted labels | left values, dashed row separators */
.evc-grid { display: grid; grid-template-columns: 12% 1fr; margin-top: .4em; }
/* the top fact block mirrors the profile's ps-grid4: two label+value pairs
   per row (when | organizers, venue | city). NOTE: no nth-last-child border
   removal here - the last row's dashed line separates this block from the
   two-column grid below */
.evc-grid4 { display: grid; grid-template-columns: 12% 1fr 12% 1fr; margin-top: .4em; }
.evc-grid4 .evc-v-when { font-family: "Saira", sans-serif; font-size: 1em; font-weight: 700; padding-top: 0; }
.evc-k, .evc-v { padding: .22em 0; border-bottom: 1px dashed var(--border); overflow-wrap: break-word; min-width: 0; font-size: .86em; }
.evc-k { text-align: right; color: var(--muted); }
.evc-v { text-align: left; padding-left: .8em; font-weight: 300; }
.evc-grid > :nth-last-child(-n+2) { border-bottom: 0; }
.evc-list { margin: 1em 0 0; padding-left: .9em; }
.evc-list li::marker { color: var(--muted); font-size: .75em; }
.evc-actions { display: flex; gap: .5em; margin-top: .8em; border-top: 1px solid var(--border); padding-top: .6em; align-items: baseline; }
.evc-lastai { margin-left: auto; font-size: .78em; }
.evc-lastai.running { color: var(--secondary); }
.evc-edit { margin-top: .8em; border-top: 1px solid var(--border); padding-top: .6em; }
.evc-edit label { display: inline-block; margin: 0 .8em .5em 0; color: var(--muted); font-size: .85em; }
.evc-edit input, .evc-edit select { display: block; background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .35em; padding: .3em .5em; font-family: inherit; }
.evc-edit-tags { margin: 1.6em 0 .5em; }
.evc-edit-tags-cap { color: var(--muted); font-size: .85em; }
.evc-edit-tags-row { display: flex; flex-wrap: wrap; gap: .3em; margin-top: .3em; }
.evc-edit-tags-row .evc-tag-pick { display: inline-flex; align-items: center; gap: .3em; margin: 0; padding: .2em .5em; border: 1px solid var(--border); border-radius: .35em; background: var(--surface-2); color: var(--text); cursor: pointer; }
.evc-edit-tags-row .evf-tag { display: inline-block; margin: 0; padding: 0; width: auto; }
.evc-tag-pick:has(.evf-tag:checked) { border-color: var(--secondary); }
.evc-tag-pick.evc-tag-proposed { border-style: dashed; opacity: .85; }
.evc-why { margin: .3em 0 .5em; padding: .5em .7em; border: 1px solid var(--secondary); border-radius: .5em; background: color-mix(in srgb, var(--secondary) 8%, transparent); }
.evc-edit .evc-payload { display: block; margin: 1.6em 0 .3em; color: var(--muted); font-size: .85em; }
.evc-payload textarea { display: block; width: 100%; box-sizing: border-box; margin-top: .3em; background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .35em; padding: .5em; font-family: monospace; font-size: .85em; }

/* ---------- M16 /audiences ---------- */
.panel-audiences .aud-create { display: flex; gap: .5em; align-items: baseline; margin-bottom: 1em; }
.panel-audiences .aud-new-btn { display: inline-block; padding: .3em .9em; border: 1px solid var(--border); border-radius: .35em; background: var(--surface-2); color: var(--text); text-decoration: none; }
.panel-audiences .aud-new-btn:hover { border-color: var(--secondary); }
.panel-audiences .aud-row { display: flex; gap: 1em; align-items: baseline; padding: .45em .6em; border: 1px solid var(--border); border-radius: .5em; margin-bottom: .4em; color: var(--text); text-decoration: none; }
.panel-audiences .aud-row:hover { border-color: var(--secondary); }
.panel-audiences .aud-name { font-weight: 400; }
.panel-audiences .aud-count { font-weight: 700; color: var(--secondary); min-width: 3em; text-align: right; }
.panel-audiences .aud-note { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel-audiences .aud-detail h3 { margin: .3em 0; }
.panel-audiences .aud-head { display: flex; gap: .5em .8em; align-items: center; margin: .5em 0 1em; flex-wrap: wrap; }
.panel-audiences .aud-head input { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .35em; padding: .3em .5em; font-family: inherit; max-width: 100%; }
/* the name caption, the input and the auto-generate hint ride ONE line
   (owner 2026-10-19); the QCubed _ctl wrapper span (no class) is the
   flexible part */
.panel-audiences .aud-name-wrap { flex: 1 1 22em; min-width: 0; display: flex; align-items: center; gap: .5em; }
.panel-audiences .aud-name-wrap > span:not([class]) { flex: 1 1 auto; min-width: 0; }
.panel-audiences .aud-name-wrap input { width: 100%; box-sizing: border-box; }
.panel-audiences .aud-name-wrap input::placeholder { color: var(--muted); font-style: italic; }
.panel-audiences .aud-name-cap { font-size: .8em; color: var(--muted); flex: 0 0 auto; }
.panel-audiences .aud-name-hint { font-size: .78em; font-style: italic; white-space: nowrap; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }
.panel-audiences .aud-filter-row.aud-off .aud-checks, .panel-audiences .aud-filter-row.aud-off select, .panel-audiences .aud-filter-row.aud-off input:not(.aud-enable) { opacity: .35; }
.panel-audiences .aud-row-label { color: var(--muted); font-size: .9em; }
.panel-audiences .aud-hidden { display: none; }
/* the geo panel (owner 2026-10-08): region + city in one rectangle -
   centered chips on top, the lock hint in a reserved line, city at the
   bottom */
.panel-audiences .aud-geo { float: right; width: 270px; margin: 0 0 .35em .9em; display: flex; flex-direction: column; gap: .5em; align-items: center; }
.panel-audiences .aud-geo .aud-checks { justify-content: center; }
.panel-audiences .aud-region-hint { margin: 0; min-height: 1.1em; color: var(--muted); font-size: .82em; font-style: italic; text-align: center; }
.panel-audiences .aud-region-hint.aud-hidden { display: block; visibility: hidden; }
.panel-audiences .aud-geo.aud-geo-locked .aud-checks { opacity: .35; }
.panel-audiences .aud-geo .aud-city-wrap { width: 90%; }
.panel-audiences .aud-geo .aud-city-wrap .aud-val-city { width: 100%; box-sizing: border-box; }
.panel-audiences .aud-city-wrap { position: relative; display: inline-block; }
.panel-audiences .aud-city-wrap .aud-val-city { padding-right: 1.4em; }
.panel-audiences .aud-city-clear { position: absolute; right: .1em; top: 50%; transform: translateY(-50%); border: 0; background: none; color: var(--muted); cursor: pointer; padding: 0 .3em; font-size: 1.05em; line-height: 1; }
.panel-audiences .aud-city-clear:hover { color: var(--accent); }
.panel-audiences .aud-val-city::placeholder { color: var(--muted); font-style: italic; }
.panel-audiences .aud-relation { display: inline-flex; gap: .5em; }
.panel-audiences .aud-val-relation-bot,
.panel-audiences .aud-val-messages-bot { width: 115px;}
.panel-audiences .aud-val-relation { width: 175px;}
.panel-audiences .aud-builder { display: block; margin: .2em 0; }
.panel-audiences .aud-builder::after { content: ""; display: block; clear: both; }
.panel-audiences .aud-filter-row { display: inline-flex; gap: .2em; align-items: center; flex-wrap: wrap; padding: .3em; border: 1px solid var(--border); border-radius: .3em; background: var(--surface-2); margin: 0 .35em .35em 0; vertical-align: top; }
.panel-audiences .aud-filter-row select, .panel-audiences .aud-filter-row input { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .35em; padding: 0em 0.6em; font-family: inherit; }
.panel-audiences .aud-checks { display: inline-flex; gap: .3em; flex-wrap: wrap; align-items: center; }
/* the /events tag-filter / /profiles relation-tag look (owner 2026-10-08),
   values verbatim from .ps-reltag */
.panel-audiences .aud-check {
    display: inline-flex; align-items: center;
    cursor: pointer; user-select: none;
    font-size: .75em; font-weight: 600; padding: .3em .4em; border-radius: .3em;
    background: var(--surface-2); border: 1px solid color-mix(in srgb, var(--border) 30%, #000); color: var(--muted);
    box-shadow: 0 0 4px color-mix(in srgb, #fff 40%, transparent);
}
.panel-audiences .aud-check input { display: none; }
.panel-audiences .aud-check:has(input:checked) { border-color: var(--secondary); color: var(--text); box-shadow: 0 0 7px color-mix(in srgb, var(--secondary) 55%, transparent); }
/* the negative pair chips (without image / no-vip / not-verified): the ICON
   reads faded while unchecked (owner 2026-10-08); the label stays full,
   a checked chip gets the full active look */
.panel-audiences .aud-check:has(.aud-pair-b:not(:checked)) .aud-ico { opacity: .4; }
.panel-audiences .aud-ico { display: inline-flex; width: 13px; height: 13px; margin-right: .35em; align-items: center; justify-content: center; }
.panel-audiences .aud-ico svg { width: 13px; height: 13px; }
.panel-audiences .aud-ico-glyph { font-size: 1.15em; line-height: 1; }
.panel-audiences .aud-age input { width: 4.5em; }
.panel-audiences .aud-val-days { width: 5em; }
.panel-audiences .aud-row-remove { margin-left: auto; border: 0; background: none; color: var(--muted); cursor: pointer; font-size: 1.1em; }
.panel-audiences .aud-row-remove:hover { color: var(--accent); }
.panel-audiences .aud-spin { display: inline-block; width: 14px; height: 14px; border: 2px solid var(--muted); border-top-color: var(--secondary); border-radius: 50%; animation: audSpinRot .7s linear infinite; }
.panel-audiences .aud-spin[hidden] { display: none; }
@keyframes audSpinRot { to { transform: rotate(360deg); } }
.panel-audiences .aud-save-btn { padding: .3em .9em; border: 1px solid var(--border); border-radius: .35em; background: var(--surface-2); color: var(--text); cursor: pointer; font-family: inherit; }
.panel-audiences .aud-save-btn:hover { border-color: var(--secondary); }
.panel-audiences .aud-preview { margin-top: -0.6em; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; position: relative; }
.panel-audiences .aud-preview-head { display: flex; gap: .7em; align-items: baseline; flex-wrap: wrap; }
/* the loading overlay (owner 2026-10-08): covers the result list while the
   auto-preview reloads */
.panel-audiences .aud-loading { position: absolute; inset: 0; z-index: 3; display: flex; align-items: flex-start; justify-content: center; padding-top: 3em; background: color-mix(in srgb, var(--surface) 55%, transparent); }
.panel-audiences .aud-loading[hidden] { display: none; }
/* the two-column detail (owner 2026-10-08): left = filters + what they
   produce, middle = the materialize action, right = the current members */
.panel-audiences .aud-cols { display: flex; gap: .8em; align-items: stretch; height: calc(100vh - 146px); min-height: 320px; }
.panel-audiences .aud-col { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
/* light card chrome on the two columns (owner 2026-10-08, the profiles
   surface look) */
.panel-audiences .aud-col-left, .panel-audiences .aud-members { background: var(--surface); border: 1px solid var(--border); border-radius: .6em; padding: .6em .8em; }
.panel-audiences .aud-col-left { flex: 1 1 56%; }
.panel-audiences .aud-col-right { flex: 1 1 44%; }
.panel-audiences .aud-members-hint { font-size: .82em; }
.panel-audiences .aud-cols-mid { align-self: center; flex: 0 0 auto; display: flex; flex-direction: column; gap: .4em; }
.panel-audiences .aud-cols-mid button { display: flex; flex-direction: column; align-items: center; gap: .1em; padding: .55em .8em; border: 1px solid var(--border); border-radius: .35em; background: var(--surface-2); color: var(--text); cursor: pointer; font-family: inherit; }
.panel-audiences .aud-cols-mid button:hover { border-color: var(--secondary); }
.panel-audiences .aud-btn-ico { font-size: 1.75em; line-height: 1.1; }
.panel-audiences .aud-btn-ico .aud-btn-trash { width: 1em; height: 1em; }
.panel-audiences .aud-btn-label { font-size: .78em; color: var(--muted); }
.panel-audiences .aud-preview-tiles { flex: 1 1 auto; min-height: 0; overflow-y: auto; align-content: start; }
@media (max-width: 900px) {
	.panel-audiences .aud-cols { flex-direction: column; height: auto; }
	.panel-audiences .aud-cols-mid { align-self: start; }
	.panel-audiences .aud-geo { float: none; width: 100%; margin-left: 0; }
	.panel-audiences .aud-preview-tiles, .panel-audiences .aud-members-tiles { max-height: 50vh; }
}
/* members (M16 4c): the snapshot grid scrolls internally so the bottomless
   module can track it; the per-tile remove is a JS-injected overlay */
.panel-audiences .aud-members { margin-top: 0; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.panel-audiences .aud-members-head { display: flex; gap: .7em; align-items: baseline; flex-wrap: wrap; }
.panel-audiences .aud-members-head input { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .35em; padding: .25em .5em; font-family: inherit; }
.panel-audiences .aud-members-tiles { flex: 1 1 auto; min-height: 0; overflow-y: auto; align-content: start; }
.panel-audiences .aud-preview-tiles .profile-tile, .panel-audiences .aud-members-tiles .profile-tile { position: relative; }
.panel-audiences .aud-preview-tiles .profile-tile { padding-right: 2em; }
/* the preview tile's add strip (owner 2026-10-08): full-height button on
   the right edge - green = add to members, grey inert = already a member */
.panel-audiences .aud-tile-add { position: absolute; top: 0; right: 0; bottom: 0; width: 1.2em; border: 0; border-radius: 0 .5em .5em 0; background: #27ae60; color: #fff; font-size: 1.15em; font-weight: 700; cursor: pointer; padding: 0; }
.panel-audiences .aud-tile-add:hover { background: #2ecc71; }
.panel-audiences .aud-tile-add-in { background: var(--surface-2); color: var(--muted); cursor: default; border-left: 1px solid var(--border); }
.panel-audiences .aud-tile-add-in:hover { background: var(--surface-2); }
.panel-audiences .aud-members-tiles .profile-tile { padding-left: 2em; }
/* the members tile's remove strip (owner 2026-10-08): full-height button
   on the LEFT edge - mirrors the preview tile's add strip */
.panel-audiences .aud-tile-remove { position: absolute; top: 0; left: 0; bottom: 0; width: 1.2em; border: 0; border-radius: .3em 0 0 .3em; background: var(--surface-2); color: #e74c3c; border-right: 1px solid #c0392b; font-size: 1.05em; font-weight: 700; cursor: pointer; padding: 0; opacity: 0.6; }
.panel-audiences .aud-tile-remove:hover { background: #c0392b; color: #fff; opacity: 1; }
/* add/remove motion (owner 2026-10-08): the ghost flight, the removed
   tile's fade-out, the new member's landing pulse */
.panel-audiences .aud-tile-out { transition: opacity .22s ease, transform .22s ease; opacity: 0; transform: scale(.85); }
.panel-audiences .aud-pulse { animation: audPulse 1.1s ease-out; }
@keyframes audPulse {
	0% { box-shadow: 0 0 0 2px rgba(46,204,113,.95), 0 0 12px rgba(46,204,113,.8); }
	100% { box-shadow: 0 0 0 0 rgba(46,204,113,0), 0 0 0 rgba(46,204,113,0); }
}
/* NB: a.profile-tile sets position:relative at (0,1,1) - this selector must
   match that specificity to win */
a.aud-ghost { position: fixed; z-index: 1; margin: 0; pointer-events: none; transition: transform .85s cubic-bezier(.3,.7,.4,1), opacity .85s ease-in; }
/* the ghost slides UNDER the members list (owner 2026-10-08): the grid
   stacks above it */
.panel-audiences .aud-members-tiles { position: relative; z-index: 2; }

/* ---------- M16 generated lists (campaigns / mailings / contents): the
   search + New ride a toolbar ABOVE the grid (owner 2026-10-19) ---------- */
.lst-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 1em; margin-bottom: .6em; }
.lst-toolbar .camp-back { margin-bottom: 0; }
.panel-content-list .datagrid th { position: sticky; top: 0; z-index: 2; text-align: left; }
.content:has(.panel-content-list) { display: flex; flex-direction: column; overflow: hidden; }
.content:has(.panel-content-list) > div,
.content:has(.panel-content-list) > div > div,
.content:has(.panel-content-list) > div > div > div { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.panel-content-list { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.panel-content-list .mcl-split { flex: 1; min-height: 0; display: flex; gap: 1em; align-items: stretch; }
.panel-content-list .mcl-pane { min-width: 0; min-height: 0; display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: .5em; padding: .6em .7em; background: var(--surface); }
.panel-content-list .mcl-pane-contents { flex: 2 1 0; }
.panel-content-list .mcl-pane-media { flex: 1 1 0; }
.panel-content-list .mcl-pane-head { font-weight: 400; margin-bottom: .5em; }
.panel-content-list .mcl-pane-scroll { flex: 1; min-height: 0; overflow-y: auto; }
.panel-content-list .mcl-pane-media .mcl-pane-scroll { display: flex; flex-direction: column; overflow: hidden; }
.panel-media-items { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
.panel-media-items .mi-table-scroll { position: relative; top: -30px; flex: 1; min-height: 0; margin-bottom: -30px; overflow-y: auto; }
.panel-media-items .lst-toolbar { position: relative; z-index: 4; }
.panel-media-items .datagrid caption { position: sticky; top: 0; z-index: 3; background: var(--surface); }
.datagrid .mcl-attach-thumb { width: auto; height: 64px; object-fit: cover; border: 1px solid var(--border); border-radius: .25em; margin: .1em; box-shadow: 0 0 6px color-mix(in srgb, var(--primary) 25%, transparent); transition: border-color .15s ease, box-shadow .15s ease; }
.datagrid .mcl-attach-thumb:hover { border-color: var(--primary); box-shadow: 0 0 10px color-mix(in srgb, var(--primary) 40%, transparent); }
/* the contents list: the Body cell is a scrollable box (owner 2026-10-19) */
.datagrid .mcl-body { max-height: 120px; overflow-y: auto; font-size: .8em; background-color: var(--bg); padding: 5px; border: 1px solid var(--primary); }

/* ---------- M16 /mailings (the generated lists ride the global datagrid
   theming; this is the custom work page only) ---------- */
.panel-mailings .ml-state { display: inline-flex;	align-items: center; justify-content: center; gap: .3em; min-width: 6em; height: 1.7em; box-sizing: border-box; border: 1px solid var(--login-border); border-radius: .3em; font-size: .85em; color: var(--muted); box-shadow: 0 0 .45em color-mix(in srgb, currentColor 35%, transparent); padding: 0;}
.panel-mailings .ml-state .ml-sc-icon { width: 14px; height: 14px; object-fit: contain; }
/* the emoji fallback glyph is TEXT on a baseline - give it the same fixed,
  flex-centered box as the images or it hangs low (owner's catch 2026-10-21) */
.ml-sc-emoji { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; line-height: 1; }
/* cancelled: the emoji GLYPH hangs low no matter how its box is centered
   (emoji font metrics) - it is drawn in pure CSS instead (owner 2026-10-21) */
.ml-sc-emoji-cancelled { font-size: 0; position: relative; }
.ml-sc-emoji-cancelled::before { content: ""; width: 10px; height: 10px; border: 2px solid var(--accent); border-radius: 50%; }
.ml-sc-emoji-cancelled::after { content: ""; position: absolute; left: 50%; top: 50%; width: 8px; height: 2px; background: var(--accent); transform: translate(-50%, -50%) rotate(-45deg); }

.panel-mailings .ml-head { display: flex; gap: .8em; align-items: baseline; margin: .5em 0 .8em; flex-wrap: wrap; }
.panel-mailings .ml-progress { font-weight: 700; }
/* the head's progress bar: the list cell's bar/fill pair, inline-sized here
   (owner 2026-10-21) */
.panel-mailings .ml-head .ml-head-bar { display: inline-block; width: 90px; height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; vertical-align: middle; margin-right: .4em; font-weight: 400; }
.panel-mailings .ml-head .ml-head-bar .ml-sc-fill { display: block; height: 100%; background: var(--secondary); }
.panel-mailings .ml-actions { display: flex; gap: .6em; align-items: center; margin-bottom: .8em; flex-wrap: wrap; }
.panel-mailings .ml-actions .button:hover:not(:disabled) { border-color: var(--secondary); }
.panel-mailings .ml-actions .button:disabled { opacity: .45; cursor: default; }
/* Re-stage rides far right - it must never catch a stray click (owner
   2026-10-20); the QCubed _ctl wrapper around the button is invisible to
   flex, so the push sits on our own span */
.panel-mailings .ml-actions .ml-restage-wrap { margin-left: auto; }
.panel-mailings .ml-inflight { color: #eab308; }
.panel-mailings .ml-recipients { display: block; }
.panel-mailings .mlr { display: flex; gap: .7em; align-items: center; padding: .3em .5em; border: 1px solid transparent; border-radius: .4em; }
.panel-mailings .mlr + .mlr { border-top-color: var(--border); border-radius: 0; }
.panel-mailings .mlr-avatar { width: 32px; height: 32px; border-radius: .3em; object-fit: cover; }
.panel-mailings .mlr-nick { color: var(--text); min-width: 12em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel-mailings .mlr-state { min-width: 4.5em; font-size: .9em; color: var(--muted); }
.panel-mailings .mlr-st-queued .mlr-state, .panel-mailings .mlr-st-pending .mlr-state { color: #eab308; }
.panel-mailings .mlr-st-sent .mlr-state { color: #2ecc71; }
.panel-mailings .mlr-st-failed .mlr-state { color: #e74c3c; }
.panel-mailings .mlr-reason { font-size: .85em; }
.panel-mailings .mlr-content { font-size: .85em; }
.panel-mailings .mlr-time { margin-left: auto; font-size: .85em; }
/* the in-progress markers go YELLOW, red/pink is reserved for errors
   (owner 2026-10-20) */
.panel-mailings .mlr-current { background: color-mix(in srgb, #eab308 8%, transparent); border: 1px solid #eab308; border-radius: .4em; }
.panel-mailings .mlr-current::after { content: 'next up'; color: #eab308; font-size: .8em; }

/* the work page scrolls ONLY the recipient list (owner 2026-10-19): header +
   buttons stay put - the content-editor flex-chain pattern, the repeater is
   the scroller (UseWrapper=false, rides TRACKED/LOADMORE in app.js) */
.content:has(.panel-mailings) { display: flex; flex-direction: column; overflow: hidden; }
.content:has(.panel-mailings) > div,
.content:has(.panel-mailings) > div > div,
.content:has(.panel-mailings) > div > div > div { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.panel-mailings, .panel-mailings .ml-detail { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.panel-mailings .ml-recipients { flex: 1; min-height: 0; overflow-y: auto; }

/* the scoped lists' back link */
.camp-back { display: inline-block; margin-bottom: .5em; padding: .25em .8em; border: 1px solid var(--border); border-radius: .35em; background: var(--surface-2); color: var(--text); text-decoration: none; font-size: .9em; }
.camp-back:hover { border-color: var(--secondary); }

/* M16 modal dialogs (owner 2026-10-08): a real scrim - dimmed + blurred
   page behind the dialog (applies to every jQuery UI modal overlay) */
.ui-widget-overlay { background: rgba(0,0,0,.35); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); opacity: 1; }

/* ---------- M16 content editor (preview | source | inspirations) ----------
   The whole page is a flex chain that NEVER scrolls as a page: .content
   stops scrolling, the three anonymous form wrappers and the panel grow to
   fill it, and each column scrolls its own body (owner 2026-10-08). The
   QCubed _ctl wrappers are off on the stretched controls (UseWrapper=false)
   - they break the flex chain (the audiences gotcha). */
.content:has(.panel-content-edit) { display: flex; flex-direction: column; overflow: hidden; }
.content:has(.panel-content-edit) > div,
.content:has(.panel-content-edit) > div > div,
.content:has(.panel-content-edit) > div > div > div { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.panel-content-edit { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.panel-content-edit .mce-cols { flex: 1; min-height: 0; display: flex; gap: 1em; align-items: stretch; }
.panel-content-edit .mce-col { flex: 1 1 0; min-width: 0; min-height: 0; display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: .5em; padding: .6em .7em; background: var(--surface); }
.panel-content-edit .mce-col-head { font-weight: 400; margin-bottom: .5em; }
.panel-content-edit .mce-col-editor { flex: 1 1 0; }
/* buttons on this page ride the .camp-back look (owner 2026-10-08); the
   emoji grid items keep their own plain style (owner 2026-10-09) */
.panel-content-edit button:not(.emoji-item), .panel-content-edit input[type=button], .panel-content-edit input[type=submit] { display: inline-block; padding: .25em .8em; border: 1px solid var(--border); border-radius: .3em; background: var(--surface-2); color: var(--text); font: inherit; font-size: .9em; cursor: pointer; }
.panel-content-edit button:not(.emoji-item):not(:disabled):hover, .panel-content-edit input[type=button]:not(:disabled):hover, .panel-content-edit input[type=submit]:not(:disabled):hover { border-color: var(--secondary); }
.panel-content-edit .mce-head-row { display: flex; justify-content: space-between; align-items: center; }
.panel-content-edit .mce-head-actions { display: inline-flex; gap: .6em; align-items: center; }
.panel-content-edit .mce-auto { display: inline-flex; gap: .3em; align-items: center; margin: 0; color: var(--muted); font-size: .9em; }
.panel-content-edit .mce-preview-body, .panel-content-edit .mce-insp-body { display: block; flex: 1; min-height: 0; overflow-y: auto; border: 1px solid var(--border); border-radius: .35em; background: var(--surface-2); padding: .5em .6em; white-space: normal; color: var(--muted); }
/* one text setup across all three columns (owner 2026-10-08) */
.panel-content-edit .mce-preview-body, .panel-content-edit .mce-insp-body, .panel-content-edit .mce-col-editor textarea { font-family: inherit; font-size: .92em; line-height: 1.35; }
.panel-content-edit .mce-lbl { display: block; color: var(--muted); font-size: .85em; margin: .4em 0 .2em; }
.panel-content-edit .mce-col-editor textarea { display: block; width: 100%; box-sizing: border-box; flex: 1; min-height: 0; resize: none; background: var(--surface-2); color: var(--text); border: 1px solid var(--border); border-radius: .35em; padding: .5em; font-family: inherit; }
.panel-content-edit .mce-editor-actions { display: flex; gap: .5em; align-items: center; margin-top: .5em; flex-wrap: wrap; }
.panel-content-edit .mce-editor-actions .mce-delete { margin-left: auto; }
.panel-content-edit .mce-editor-actions .camp-back { margin-bottom: 0; }
@keyframes mce-save-pulse { 0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, #eab308 0%, transparent); } 50% { box-shadow: 0 0 0 4px color-mix(in srgb, #eab308 35%, transparent); } }
.panel-content-edit.mce-save-dirty .mce-save-main { animation: mce-save-pulse 1.8s ease-in-out infinite; border-color: #eab308; }
.panel-content-edit .mce-save-main:disabled { animation: none; }
/* the emoji toggle rides inside Label/_ctl spans - let them vanish from
   the flex layout so the button itself aligns with the rest */
.panel-content-edit .mce-editor-actions > span, .panel-content-edit .mce-editor-actions > span > span { display: contents; }
.panel-content-edit .mce-insp-item { padding: 4em 0; }
.panel-content-edit .mce-insp-item + .mce-insp-item { border-top: 1px solid var(--secondary); }
.panel-content-edit .mce-emoji-cheatsheet { flex: 0 0 auto; margin-bottom: .5em; border: 1px solid var(--border); border-radius: .35em; background: var(--surface-2); }
.panel-content-edit .mce-emoji-cheatsheet[open] { position: relative; flex: 0 0 30%; min-height: 0; }
.panel-content-edit .mce-emoji-cheatsheet summary { height: 2.2em; box-sizing: border-box; padding: .45em .6em; cursor: pointer; }
.panel-content-edit .mce-emoji-list { display: block; position: absolute; top: 2.2em; right: 0; bottom: 0; left: 0; min-height: 0; box-sizing: border-box; overflow-y: auto; padding: .5em .6em; border-top: 1px solid var(--border); user-select: text; }
.panel-content-edit .mce-emoji-group + .mce-emoji-group { margin-top: .7em; }
.panel-content-edit .mce-emoji-group-name { margin-bottom: .2em; color: var(--muted); font-size: .85em; }
.panel-content-edit .mce-emoji-group-items { font-size: 1.2em; line-height: 1.6; word-spacing: .15em; }
/* the global /contents/new campaign pick (owner 2026-10-19) - a row above
   the three columns; the columns keep their flex:1 below it */
.panel-content-edit .mce-campaign-pick { display: flex; align-items: center; gap: .7em; margin-bottom: .8em; padding: .5em .7em; border: 1px solid var(--border); border-radius: .5em; background: var(--surface); }

/* ---------- M16 content preview popup (/content-preview/{id}, owner
   2026-10-19) - a bare window over the shared theme ---------- */
.cpv-page { background: var(--bg); color: var(--text); padding: 1em 1.2em; }
.cpv-head { margin-bottom: .2em; }
/* the mode switch always on its own line under the header, over a subtle
   separator (owner 2026-10-19) */
.cpv-modes {
	display: flex;
	gap: .9em;
	border-top: 1px solid var(--border);
	margin-top: 0.3em;
	padding: 0.2em 0;
	margin-bottom: 0.1em;
}
.cpv-modes a { color: var(--muted); text-decoration: none; }
.cpv-modes a:hover { text-decoration: underline; }
.cpv-modes .on { color: var(--text); font-weight: 600; }
.cpv-auto { display: inline-flex; gap: .3em; align-items: center; color: var(--muted); font-size: .9em; cursor: pointer; }
.cpv-esc { margin: 0 0 .4em; font-size: .8em; font-style: italic; }
.cpv-body { background: var(--surface); border: 1px solid var(--border); border-radius: .3em; padding: .7em .9em; font-size: .92em; line-height: 1.35; }
.mpv-body { display: flex; justify-content: center; align-items: flex-start; }
.mpv-body img { max-width: 100%; max-height: calc(100vh - 7em); object-fit: contain; border-radius: .3em; }
/* no campaign picked yet: the dropdown flashes to draw the eye, the saves
   stay disabled (owner 2026-10-19) */
.panel-content-edit .mce-campaign-pick select { animation: mce-pickblink .9s ease-in-out 4; }
@keyframes mce-pickblink { 0%, 100% { outline: 2px solid transparent; } 50% { outline: 2px solid #eab308; } }
.panel-content-edit .mce-editor-actions button:disabled { opacity: .45; cursor: default; }

/* M17: the media base grid (/contents) + the content editor's attach bar */
.mcl-media-head { font-weight: 400; margin: 1.2em 0 .5em; }
.panel-media-items .mi-upload { display: flex; align-items: center; gap: .6em; }
.panel-media-items .mi-upload .mi-error { color: var(--accent); }
.panel-media-items .mi-info { display: flex; flex-direction: column; gap: .2em; min-width: 0; }
.panel-media-items .mi-info-row { display: grid; grid-template-columns: 4em minmax(0, 1fr); gap: .3em; align-items: baseline; }
.panel-media-items .mi-info-label { color: var(--muted); text-align: right; }
.panel-media-items .mi-info-value { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel-media-items .mi-info-actions { display: flex; gap: .3em; }
.panel-media-items .mcl-attach-link { display: flex; justify-content: center; }
.datagrid .mi-thumb { max-width: 96px; max-height: 96px; width: auto; height: auto; border: 1px solid var(--border); border-radius: .35em; display: block; box-shadow: 0 0 6px color-mix(in srgb, var(--primary) 25%, transparent); transition: border-color .15s ease, box-shadow .15s ease; }
.datagrid .mi-thumb:hover { border-color: var(--primary); box-shadow: 0 0 10px color-mix(in srgb, var(--primary) 40%, transparent); }
.mce-attached-body, .mce-picker-body { display: flex; flex-wrap: wrap; gap: .5em; margin-bottom: .5em; }
.mce-media { display: block; border: 2px solid transparent; border-radius: .4em; line-height: 0; }
.mce-media img { max-width: 72px; max-height: 72px; width: auto; height: auto; border-radius: .3em; }
.mce-media.on { border-color: var(--secondary); }
.mce-media:hover { border-color: var(--primary); }
.mlr-media img { max-width: 26px; max-height: 26px; width: auto; height: auto; border-radius: .25em; display: block; }
