/* Self-hosted Oxygen fonts (replaces the design book's Google Fonts @import). */
@font-face { font-family: 'Oxygen'; font-style: normal; font-weight: 300; font-display: swap; src: url('/fonts/oxygen-300.woff2') format('woff2'); }
@font-face { font-family: 'Oxygen'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/oxygen-400.woff2') format('woff2'); }
@font-face { font-family: 'Oxygen'; font-style: normal; font-weight: 700; font-display: swap; src: url('/fonts/oxygen-700.woff2') format('woff2'); }
@font-face { font-family: 'Oxygen Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('/fonts/oxygen-mono-400.woff2') format('woff2'); }
/* ============================================================
   AEGIS tokens and components.
   Ported verbatim from the design book (aegis-design-system.html
   and aegis-dashboard.html). One material, form from light and
   shadow only, teal as a spotlight. The React components are thin
   wrappers over these classes, so this file stays the single
   source of truth.
   ============================================================ */
:root {
    /* The design book's material: a lighter base with a brighter highlight and a deeper shadow, so raised
       edges catch more light and pressed wells sink further. The relief reads soft and physical. */
    --base: #2a2e38;
    --shadow-d: #1f222a;
    --shadow-l: #343844;
    /* A softer, lighter dark for raised edges only, so a bump hugs the surface instead of floating.
       The wells keep the firmer --shadow-d so recesses still read as clearly cut in. */
    --shadow-d-soft: #23262e;

    --text-main: #ffffff;
    --text-muted: #a0a4b8;
    --text-darker: #6b7085;

    --font-sans: 'Oxygen', system-ui, sans-serif;
    --font-mono: 'Oxygen Mono', ui-monospace, monospace;

    /* Motion easings from the design book: a spring with overshoot for arrivals, a soft ease for the rest. */
    --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

    --accent: #4f9da2;
    --accent-deep: #316064;
    /* Alias used by several older rules (picker checkmark, the enabled pill, reference examples). It was
       referenced but never defined, so those rendered without their teal. Points at the accent. */
    --teal: var(--accent);
    --green: #5e9d70;
    --red: #c25b5b;
    --yellow: #c99a52;

    /* Raised: the dark side is pulled in and spread wide (a soft, hugging bump), the highlight is unchanged. */
    --raised: 3px 3px 17px var(--shadow-d-soft), -4px -4px 12px var(--shadow-l);
    --raised-hover: 4px 4px 22px var(--shadow-d-soft), -5px -5px 15px var(--shadow-l);
    --raised-sm: 2px 2px 12px var(--shadow-d-soft), -3px -3px 8px var(--shadow-l);
    /* Blank round buttons (server icons, avatars) get a firmer, more defined edge, since a plain disc with no
       glyph relies entirely on its shadow to read as raised. Other circles keep the soft bump. */
    --raised-blank: 4px 4px 12px #1d2027, -3px -3px 8px var(--shadow-l);
    --pressed: inset 4px 4px 12px var(--shadow-d), inset -4px -4px 12px var(--shadow-l);
    --pressed-sm: inset 3px 3px 8px var(--shadow-d), inset -3px -3px 8px var(--shadow-l);
    --pressed-key: inset 4px 4px 10px var(--shadow-d), inset -4px -4px 10px var(--shadow-l);

    /* The room a raised shadow needs around an item, so a clipping container (overflow) can widen its clip box
       by this much on every side and never slice an item's shadow. Covers the raised shadows' reach
       (--raised-sm ~11px, --raised ~14px) while staying inside the sidebar's own 16px padding. */
    --shadow-gutter: 14px;

    --flat: rgba(255, 255, 255, 0.04);
    --focus-ring: 0 0 0 2px var(--base), 0 0 0 4px rgba(79, 157, 162, 0.55);
}

*, *::before, *::after { box-sizing: border-box; }
/* Reset the default body margin: without this the .app (100vh) plus the browser's 8px body margins
   overflows the viewport by ~16px, leaving the page permanently scrollable by a small amount. */
html, body { margin: 0; padding: 0; }
.aegis, .aegis * { font-family: var(--font-sans); }
.aegis {
    background: var(--base);
    color: var(--text-main);
    font-size: 14px;
    line-height: 1.5;
    -webkit-tap-highlight-color: transparent;
}
.aegis h1, .aegis h2, .aegis h3, .aegis h4 { margin: 0; font-weight: 700; color: var(--text-main); letter-spacing: -0.01em; }
.aegis p { margin: 0; }
.aegis :focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* Show the focus ring only for real keyboard focus. Suppress the browser's default outline on mouse
   click (a plain :focus that is not :focus-visible), and keep the heading that FocusOnNavigate focuses
   after each navigation silent, since it is a screen-reader target, not a control the user chose. */
.aegis :focus:not(:focus-visible) { outline: none; }
.aegis h1:focus { outline: none; box-shadow: none; }

/* Every glyph is carved into the surface: a dark edge upper-left, a light edge lower-right, so it reads
   as pressed in rather than sitting on top. This is the default for all icons, container contexts only
   reset the box around the glyph, they do not add the carve. */
.ic { width: 1.2em; height: 1.2em; display: inline-block; vertical-align: -0.225em; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; filter: drop-shadow(1px 1px 0.4px rgba(255, 255, 255, 0.13)) drop-shadow(-1px -1px 0.4px rgba(0, 0, 0, 0.28)); }

/* the design book builds controls from <div>. These components use real <button>
   elements for accessibility, so strip the native OS chrome that would otherwise
   paint its own background over the material (this is why an on toggle looked dark). */
.aegis button { -webkit-appearance: none; appearance: none; }

/* ---------- surfaces ---------- */
.card { background: var(--base); box-shadow: var(--raised); border-radius: 20px; transition: transform 0.2s var(--ease-out), box-shadow 0.22s var(--ease-out); }
/* A small, smooth lift, matching the buttons: no overshoot, the lift and shadow move together. */
.card--interactive:hover { box-shadow: var(--raised-hover); transform: translateY(-2px); }
.well { background: var(--base); box-shadow: var(--pressed); border-radius: 12px; }
.well--sm { box-shadow: var(--pressed-sm); }
.chip { background: var(--flat); border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; }
.chip--raised { box-shadow: var(--raised-sm); }

/* ---------- inputs ---------- */
.input { width: 100%; background: var(--base); box-shadow: var(--pressed); border: none; border-radius: 12px; color: var(--text-main); font-family: inherit; font-size: 14px; padding: 0.75rem 1rem; transition: box-shadow 0.25s ease; }
.input::placeholder { color: var(--text-darker); }
.input:focus { outline: none; box-shadow: var(--pressed), inset 0 0 0 1px rgba(79, 157, 162, 0.45); }

.select-wrap { position: relative; display: inline-block; }
.select { appearance: none; cursor: pointer; font-weight: 400; padding-right: 2.5rem; box-shadow: var(--raised-sm); }
.select:hover { box-shadow: var(--raised); }
/* A select is a raised "press me" control, not a text well, so it must NOT recess on focus the way .input
   does (which read as the trigger pushing in while the menu was open, then popping out on blur). It stays
   raised while open. Keyboard focus still shows the focus ring via the .aegis :focus-visible rule. */
.select:focus { box-shadow: var(--raised-sm); }
.select:hover:focus { box-shadow: var(--raised); }
.select-chevron { position: absolute; right: 1.1rem; top: 50%; transform: translateY(-50%); color: var(--text-darker); pointer-events: none; }
/* The trigger is our raised pill, but the opened list is the browser's native menu. We can at least bring
   its options onto the surface colour so the popup is dark and on-brand instead of a white system list. */
.select option, .aegis select option { background: var(--base); color: var(--text-main); }
.select option:checked { color: var(--accent); }
/* Timeout duration picker (057): the preset dropdown, and on the custom path an amount plus a unit dropdown. */
.duration { display: inline-flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.duration__amount { width: 6rem; }

/* kill the browser's generic number spinner everywhere */
.input[type="number"]::-webkit-outer-spin-button,
.input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.input[type="number"] { -moz-appearance: textfield; appearance: textfield; }

/* a number field with real steppers: an inset track holding the value between two raised keys */
.stepper { display: inline-flex; align-items: center; gap: 3px; padding: 3px; background: var(--base); box-shadow: var(--pressed-sm); border-radius: 12px; }
.stepper__input { width: 2.75rem; text-align: center; background: transparent; border: none; color: var(--text-main); font-family: inherit; font-size: 14px; padding: 0.4rem 0; -moz-appearance: textfield; }
.stepper__input:focus { outline: none; }
.stepper__btn { width: 30px; height: 30px; border-radius: 8px; background: var(--base); box-shadow: var(--raised-sm); border: none; color: var(--text-muted); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; transition: color 0.2s ease, box-shadow 0.2s ease; }
.stepper__btn .ic { width: 13px; height: 13px; }
.stepper__btn:hover { color: var(--text-main); box-shadow: var(--raised); }
.stepper__btn:active { box-shadow: var(--pressed-key); }
.stepper__btn:disabled { color: var(--shadow-l); cursor: default; box-shadow: var(--raised-sm); }

/* ---------- buttons ---------- */
.btn { background: var(--base); box-shadow: var(--raised-sm); border: none; border-radius: 12px; color: var(--text-muted); font-family: inherit; font-weight: 400; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 0.6rem; padding: 0.75rem 1.5rem; margin-top: 1rem; transition: color 0.18s ease, box-shadow 0.2s var(--ease-out); }
/* Feedback is carried by depth alone (the design book's depth law): raised, brighter on hover, inset when
   pressed. No transform on the button, so its text never re-rasterizes and tears as it settles. */
.btn:hover { color: var(--text-main); box-shadow: var(--raised); }
.btn:active { color: var(--text-main); box-shadow: var(--pressed-key); }
.btn--primary { color: var(--accent); box-shadow: var(--raised); font-size: 15px; font-weight: 700; padding: 0.85rem 2rem; }
.btn--primary:hover { box-shadow: var(--raised-hover); }
.btn--primary:active { box-shadow: var(--pressed-key); }
.btn--danger { color: var(--red); }
.btn--block { width: 100%; }

.icon-btn { width: 48px; height: 48px; border-radius: 50%; background: var(--base); box-shadow: var(--raised-sm); border: none; color: var(--text-muted); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; font-size: 18px; transition: color 0.2s ease, box-shadow 0.2s var(--ease-out); flex-shrink: 0; }
.icon-btn:hover { color: var(--text-main); box-shadow: var(--raised); }
.icon-btn:active { color: var(--text-main); box-shadow: var(--pressed-key); }
.icon-btn--danger:hover { color: var(--red); }
.icon-btn--sm { width: 32px; height: 32px; font-size: 14px; }

/* quiet full-width add-a-row button */
.add-row { width: 100%; padding: 1.1rem; border: none; border-radius: 12px; background: var(--base); box-shadow: var(--raised-sm); color: var(--text-muted); font-family: inherit; font-size: 15px; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 0.75rem; transition: color 0.2s ease, box-shadow 0.2s ease; }
.add-row:hover { color: var(--text-main); box-shadow: var(--raised); }
.add-row:active { color: var(--text-main); box-shadow: var(--pressed-key); }

/* ---------- toggle (hardware) ---------- */
.toggle { width: 52px; height: 28px; background: var(--base); box-shadow: var(--pressed-sm); border-radius: 14px; position: relative; cursor: pointer; flex-shrink: 0; border: none; padding: 0; transition: background 0.3s ease, box-shadow 0.3s ease; }
/* A plump raised knob that overhangs the recessed track by 1px all round. Off, it carries the full
   neumorphic raise, on, it slides onto the teal and swaps to a plain drop shadow so the raise's light
   patch never reads as a dark blob on the accent. It springs across with a little overshoot. */
.toggle-knob { width: 30px; height: 30px; border-radius: 50%; position: absolute; top: -1px; left: -1px; background: var(--base); box-shadow: var(--raised-sm); transition: transform 0.45s var(--spring), background 0.3s ease, box-shadow 0.3s ease; }
.toggle.is-on { background: var(--accent); box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.25); }
.toggle.is-on .toggle-knob { transform: translateX(24px); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35); }
.toggle--lg { transform: scale(1.1); transform-origin: left; }

/* Back the switch with a real, visually-hidden checkbox so it is keyboard- and label-driven. The track
   and knob mirror the checkbox state, and the focus ring lands on the track for keyboard users. */
.toggle-input { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; pointer-events: none; }
.toggle-input:checked + .toggle { background: var(--accent); box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.25); }
.toggle-input:checked + .toggle .toggle-knob { transform: translateX(24px); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35); }
.toggle-input:focus-visible + .toggle { box-shadow: var(--focus-ring); }

/* ---------- segmented match toggle (any | all), the inset-active control ---------- */
.segmented { display: inline-flex; gap: 4px; padding: 4px; border-radius: 10px; }
.segmented__opt { padding: 5px 14px; border-radius: 8px; font-family: inherit; font-size: 13px; font-weight: 400; color: var(--text-darker); background: transparent; border: none; cursor: pointer; transition: color 0.2s ease, box-shadow 0.2s ease; }
.segmented__opt.is-active { box-shadow: var(--pressed-sm); color: var(--accent); font-weight: 700; }

/* ---------- tags ----------
   Sentence case, quiet. Not uppercase letter-spaced pills. Severity stays subtle,
   role and entity color is data and is carried by a swatch plus the real name. */
.tag { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 8px; font-size: 12px; font-weight: 400; }
.tag .ic { width: 0.85em; height: 0.85em; }
.tag--red { background: rgba(194, 91, 91, 0.16); color: var(--red); }
.tag--yellow { background: rgba(201, 154, 82, 0.16); color: var(--yellow); }
.tag--neutral { background: var(--flat); color: var(--text-muted); }
/* a role tag carries its Discord color as a leading swatch, the label stays readable */
.tag--role { background: var(--flat); color: var(--text-main); font-weight: 700; }
.tag--role .swatch-dot { width: 10px; height: 10px; border-radius: 50%; box-shadow: inset 0 1px 2px rgba(0,0,0,0.4); }

/* ---------- entity chips and chip field ---------- */
.chipfield { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; padding: 0.6rem; background: var(--base); box-shadow: var(--pressed-sm); border-radius: 12px; }
/* no grey pill: the swatch carries the color and the name carries the label */
.chip-entity { display: inline-flex; align-items: center; gap: 0.45rem; padding: 0.2rem 0.15rem; color: var(--text-main); font-size: 14px; }
.chip-entity__disc { width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.4); }
/* the remove is a real little key pressed into the chip, not a bare white glyph */
.chip-entity__x { width: 18px; height: 18px; border-radius: 50%; background: var(--base); box-shadow: var(--raised-sm); border: none; color: var(--text-darker); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; padding: 0; transition: color 0.2s ease, box-shadow 0.2s ease; }
.chip-entity__x .ic { width: 9px; height: 9px; stroke-width: 2.5; }
.chip-entity__x:hover { color: var(--red); box-shadow: var(--raised); }
.chip-entity__x:active { box-shadow: var(--pressed-key); }
.chip-add { width: 30px; height: 30px; border-radius: 50%; background: var(--base); box-shadow: var(--raised-sm); border: none; color: var(--text-muted); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.chip-add:hover { color: var(--text-main); box-shadow: var(--raised); }

/* ---------- small bits ---------- */
.eyebrow { display: inline-flex; align-items: center; gap: 0.75rem; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-darker); }
.eyebrow .crumb-current { color: var(--text-muted); }
.label { display: block; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-darker); }
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); flex-shrink: 0; }
.status-dot--glow { box-shadow: 0 0 8px rgba(79, 157, 162, 0.8); }
.mono { font-family: var(--font-mono); }

/* ---------- meter ---------- */
.meter { flex: 1; height: 12px; background: var(--base); box-shadow: var(--pressed); border-radius: 999px; overflow: hidden; }
.meter__fill { height: 100%; background: var(--accent); border-radius: 999px; }

/* ---------- toast ---------- */
.toast { background: var(--base); box-shadow: var(--raised), 0 10px 30px rgba(0, 0, 0, 0.5); color: var(--text-main); padding: 16px 24px; border-radius: 16px; display: inline-flex; align-items: center; gap: 16px; font-weight: 400; }
/* The Blazor error toast floats at the bottom-right and is hidden until Blazor shows it (then dismissable),
   so it never sits in the page flow and gets buried under the fixed side panel. */
#blazor-error-ui { position: fixed; right: 24px; bottom: 24px; left: auto; top: auto; z-index: 1000; max-width: min(92vw, 30rem); display: none; }
#blazor-error-ui .dismiss { cursor: pointer; margin-left: 4px; }

/* ---------- rule row (the contextual builder row) ---------- */
/* Top-align so every control's label sits on the top line (the kind dropdown, which now carries its own
   label, lines up with the field inputs, and a tall control's label stays readable at the top). */
.rule-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0.75rem; padding: 0.5rem 0; }
.rule-row__fields { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0.75rem; flex: 1; min-width: 0; }
.rule-row__remove { margin-left: auto; align-self: center; }
/* Nested condition groups (071): each group is a bordered card, its body inset with a left accent so a
   nested group reads as contained inside its parent. The AND/OR join and the add controls live in the card. */
.cond-group { border: 1px solid var(--accent); border-radius: 12px; padding: 0.6rem 0.85rem; margin: 0.5rem 0; }
.cond-group__head { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.cond-group__label { font-size: 13px; color: var(--text-muted); font-weight: 600; }
.cond-group__remove { margin-left: auto; }
.cond-group__body { margin-top: 0.5rem; padding-left: 0.85rem; border-left: 2px solid var(--accent); }
.cond-group__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.4rem; }
/* A trigger's label (073) as a small id chip at the bottom of the row: click to copy, hover to reveal a
   rename control. Kept quiet so it reads as metadata, not a primary field. */
.trigger-id { flex: 1 1 100%; display: flex; align-items: center; gap: 0.35rem; margin-top: 0.1rem; min-height: 1.4rem; }
.trigger-id__chip { display: inline-flex; align-items: center; gap: 0.3rem; font: 600 11px/1 var(--font-mono, ui-monospace, monospace); color: var(--text-muted); background: var(--flat); border: 0; border-radius: 6px; padding: 0.22rem 0.45rem; cursor: pointer; }
.trigger-id__chip:hover { color: var(--text-main); }
.trigger-id__edit { opacity: 0; border: 0; background: none; color: var(--text-muted); cursor: pointer; display: inline-flex; align-items: center; transition: opacity 0.12s; }
.trigger-id:hover .trigger-id__edit { opacity: 1; }
.trigger-id__edit:hover { color: var(--accent); }
.trigger-id__add { opacity: 0.7; border: 0; background: none; color: var(--text-muted); cursor: pointer; font-size: 12px; display: inline-flex; align-items: center; gap: 0.25rem; }
.trigger-id__add:hover { opacity: 1; color: var(--text-main); }
.trigger-id__input { max-width: 12rem; font-size: 12px; padding: 0.2rem 0.45rem; }
.trigger-id__go { border: 0; background: none; color: var(--accent); cursor: pointer; display: inline-flex; align-items: center; }
.trigger-id__copied { font-size: 11px; color: var(--accent); }
/* Word-list management (074): a create bar and one card per list with an inline name, a terms textarea, and
   save/rename/delete controls. */
.wl-new { display: flex; gap: 0.5rem; align-items: center; }
.wl-card { margin-bottom: 1rem; }
.wl-card__head { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; }
.wl-card__name { font-weight: 600; flex: 1 1 12rem; min-width: 0; }
.wl-card__actions { display: flex; gap: 0.5rem; margin-left: auto; }
.wl-card__entries { width: 100%; font-family: var(--font-mono, ui-monospace, monospace); }
.wl-card__foot { display: flex; justify-content: space-between; align-items: center; margin-top: 0.6rem; }
/* Live regex tester in the builder (076): a sample input plus a match/no-match result with the matched span
   highlighted, using the trigger's own matcher so it agrees with save and runtime. */
.regex-tester { margin-top: 0.5rem; padding: 0.6rem 0.75rem; border: 1px solid var(--flat); border-radius: 10px; }
.regex-tester__msg { font-size: 12px; display: inline-flex; align-items: center; gap: 0.3rem; margin-top: 0.35rem; }
.regex-tester__msg--bad { color: var(--red); }
.regex-tester__result { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.4rem; font-size: 13px; flex-wrap: wrap; }
.regex-tester__result--hit { color: #43b581; }
.regex-tester__result--miss { color: var(--text-muted); }
.regex-tester__text { color: var(--text-main); background: var(--flat); padding: 0.15rem 0.4rem; border-radius: 6px; overflow-wrap: anywhere; }
.regex-tester__text mark { background: var(--accent); color: #fff; border-radius: 3px; padding: 0 1px; }
/* Branch effect editor (073): an ordered list of branch cards (each fires on a trigger label and runs its
   effects) plus an optional default, first-match-wins so the visual order is the run order. */
.branch-editor { display: flex; flex-direction: column; gap: 0.5rem; width: 100%; }
.branch { border: 1px solid var(--accent); border-radius: 12px; padding: 0.6rem 0.85rem; }
.branch--default { border-style: dashed; }
.branch__head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.branch__num { display: inline-flex; align-items: center; justify-content: center; width: 1.4rem; height: 1.4rem; border-radius: 50%; background: var(--accent); color: #fff; font-size: 12px; font-weight: 700; flex: none; }
.branch__trigger { max-width: 14rem; }
.branch__remove { margin-left: auto; }
.branch__effects { margin-top: 0.5rem; padding-left: 0.85rem; border-left: 2px solid var(--accent); }
.branch__note { font-size: 12px; opacity: 0.7; margin-top: 0.3rem; }
/* Send-buttons editor (078): one row per button (label, id, style, remove), then the restrict toggle. */
.buttons-editor { display: flex; flex-direction: column; gap: 0.5rem; width: 100%; }
.btn-spec { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.btn-spec__label { flex: 1 1 12rem; min-width: 8rem; }
.btn-spec__id { flex: 0 1 9rem; min-width: 6rem; }
.btn-spec__style { flex: none; width: auto; }
.btn-restrict { display: flex; align-items: center; gap: 0.5rem; font-size: 13px; }
.buttons-editor__note { font-size: 12px; opacity: 0.7; margin-top: 0.3rem; }
.field { display: inline-flex; flex-direction: column; gap: 0.3rem; }
.field .input { width: auto; min-width: 4rem; }
/* Hug the select so its chevron sits at the select's own right edge. Without this the wrap stretches to
   the field width (a long label widens the field), and the chevron floats past the narrower select. */
.field .select-wrap { align-self: flex-start; }
.field--num .input { width: 6rem; }
/* Tall controls (the entity picker, a message textarea) take a full line, so on wide screens they do not
   share a row with small controls like the self-delete toggle (which must stay below, with its timer). */
.field--grow { flex: 1 1 100%; min-width: 0; }
.field--grow .input, .field--grow .picker { width: 100%; min-width: 0; }

@media (prefers-reduced-motion: reduce) {
    .aegis *, .aegis *::before, .aegis *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

/* Rule categories (058): a flat tab bar above the rule list. Each tab is a category, plus All and Main.
   Rules render flat under the active tab, no nested embossed containers. Tabs are plain links (static SSR). */
.rules-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.25rem; }

/* Rules list toolbar (060): a flat row of list-wide controls, search then the sort field and direction.
   The depth lives on the controls (inset search, raised selects and Apply), not a wrapping box, per the
   neumorphic rule. */
.rules-toolbar { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 1.25rem; }
.rules-toolbar .btn { margin-top: 0; }
.rules-toolbar__search { position: relative; display: inline-flex; align-items: center; flex: 1 1 14rem; min-width: 12rem; }
.rules-toolbar__icon { position: absolute; left: 1rem; width: 15px; height: 15px; color: var(--text-darker); pointer-events: none; }
.rules-toolbar__q { padding-left: 2.6rem; }
.rules-toolbar .select { width: auto; min-width: 9rem; margin: 0; }

/* A flat tab row: no wrapping embossed box. The depth lives on the tabs (raised buttons that press in when
   active) and the category input (inset), per the neumorphic rule that controls carry depth, not containers. */
.cat-tabs { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1.75rem; }
.cat-tab { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.6rem 1rem; border-radius: 12px; background: var(--base); box-shadow: var(--raised-sm); color: var(--text-muted); font-size: 14px; text-decoration: none; transition: color 0.2s ease, box-shadow 0.2s ease; }
.cat-tab:hover { color: var(--text-main); box-shadow: var(--raised); }
.cat-tab.is-active { box-shadow: var(--pressed-sm); color: var(--accent); font-weight: 700; }
.cat-tab__count { min-width: 1.4rem; height: 1.4rem; padding: 0 0.4rem; border-radius: 8px; background: var(--flat); display: inline-flex; align-items: center; justify-content: center; font-size: 11px; color: var(--text-darker); }
.cat-tab.is-active .cat-tab__count { color: var(--accent); }
.cat-tabs__new { display: inline-flex; align-items: center; gap: 0.4rem; margin-left: auto; }
.cat-tabs__new-name { width: 10rem; padding: 0.5rem 0.75rem; margin: 0; }
.cat-tabs__new .btn { margin-top: 0; }

/* Contextual category toolbar: shown under the tabs when a real category is active. Rename, reorder, delete. */
.cat-toolbar { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.cat-toolbar form { margin: 0; }
.cat-toolbar .btn { margin-top: 0; }
.cat-toolbar__rename { display: inline-flex; align-items: center; gap: 0.4rem; }
.cat-toolbar__name { width: 12rem; padding: 0.5rem 0.75rem; margin: 0; }
.cat-toolbar__spacer { flex: 1 1 auto; }

/* Category default reason (059): a labelled inset field under the category toolbar, with a quiet hint. */
.cat-default { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.cat-default .btn { margin-top: 0; }
.cat-default__label { font-size: 13px; color: var(--text-muted); }
.cat-default__input { flex: 1 1 20rem; min-width: 14rem; }
.cat-default__hint { flex-basis: 100%; margin: 0.25rem 0 0; font-size: 12px; color: var(--text-darker); }
/* Category default channel scope and role condition (059 inc. 2): two pickers side by side. */
.cat-scope { display: grid; grid-template-columns: 1fr; gap: 1.75rem; margin: 0 0 1.5rem; }
@media (min-width: 900px) { .cat-scope { grid-template-columns: 1fr 1fr; } }
.cat-scope__col { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; }
.cat-scope__mode { align-self: flex-start; max-width: 100%; }
.cat-scope__actions { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.cat-scope__actions .btn { margin-top: 0; }
.cat-scope__count { font-size: 13px; color: var(--text-darker); }
.cat-scope__msg { grid-column: 1 / -1; display: flex; align-items: center; gap: 0.6rem; color: var(--accent); font-size: 14px; }
.picker--compact .picker__list { height: auto; max-height: 220px; }

/* An inherited value shown under a rule field (059): a quiet note that a blank field uses the category default. */
.field-inherited { display: block; margin-top: 0.4rem; font-size: 12px; color: var(--text-darker); }
.field-inherited strong { color: var(--text-muted); font-weight: 700; }
/* The Preferences page (068): consistent spacing per setting, and the searchable timezone picker. */
.prefs { max-width: 42rem; margin-top: 1.5rem; display: flex; flex-direction: column; gap: 1.5rem; }
.pref-card { padding: 1.75rem 1.9rem; }
.pref-card__title { margin: 0 0 0.5rem; }
.pref-card__desc { margin: 0 0 1.25rem; max-width: 34rem; }
.pref-card .segmented { display: inline-flex; }
.pref-hint { font-size: 13px; color: var(--text-darker); margin: 0.9rem 0 0; }
.pref-tz { margin-top: 1.1rem; display: flex; flex-direction: column; gap: 0.75rem; max-width: 30rem; }
.pref-tz__list { display: flex; flex-direction: column; gap: 0.2rem; max-height: 280px; overflow-y: auto; padding: 0.4rem; background: var(--base); box-shadow: var(--pressed-sm); border-radius: 12px; }
.pref-tz__opt { text-align: left; background: none; border: none; font: inherit; font-size: 14px; color: var(--text-muted); padding: 0.45rem 0.65rem; border-radius: 8px; cursor: pointer; transition: color 0.15s ease; }
.pref-tz__opt:hover { color: var(--accent); }
.pref-tz__opt.is-picked { color: var(--accent); font-weight: 600; box-shadow: var(--pressed-sm); }
.pref-tz__more { font-size: 12px; color: var(--text-darker); margin: 0.3rem 0.6rem; }
.pref-save { margin-top: 0.5rem; }
/* Author-time preview of a Send message action (067): the composed message with variables filled in. */
.msg-preview { margin-top: 0.5rem; padding: 0.7rem 0.9rem; background: var(--base); box-shadow: var(--pressed-sm); border-radius: 12px; font-size: 14px; color: var(--text-main); white-space: pre-wrap; overflow-wrap: anywhere; }
.msg-preview__unknown { color: var(--red); font-weight: 700; box-shadow: var(--pressed-sm); border-radius: 6px; padding: 0 0.25rem; }
.msg-preview__empty { color: var(--text-darker); font-style: italic; }
.msg-preview__note { display: block; margin-top: 0.5rem; font-size: 12px; color: var(--text-darker); white-space: normal; }
/* Inherited-versus-overridden panel in the rule builder (059 inc. 3): what a rule inherits from its category. */
.inherit-panel { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; background: var(--flat); border-radius: 12px; padding: 0.8rem 1.1rem; margin-bottom: 0.75rem; }
.inherit-panel__body { display: flex; align-items: center; gap: 0.6rem; min-width: 0; font-size: 14px; color: var(--text-muted); overflow-wrap: anywhere; }
.inherit-panel__body strong { color: var(--text-main); font-weight: 700; }
.inherit-panel .btn { margin-top: 0; flex-shrink: 0; }
.inherit-panel--own .inherit-panel__body { color: var(--text-darker); }
/* Variable autocomplete popup (062): a floating suggestion list under a `{`-typed field. */
.var-ac { position: fixed; z-index: 200; max-height: 280px; overflow-y: auto; max-width: 460px; display: flex; flex-direction: column; gap: 2px; padding: 0.4rem; background: var(--base); box-shadow: var(--raised); border-radius: 12px; }
.var-ac__opt { display: flex; align-items: center; gap: 0.6rem; padding: 0.5rem 0.6rem; border-radius: 8px; cursor: pointer; }
.var-ac__opt.is-active { background: var(--flat); }
.var-ac__token { font-family: var(--font-mono); font-size: 13px; color: var(--accent); white-space: nowrap; flex-shrink: 0; }
.var-ac__tag { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-darker); box-shadow: var(--raised-sm); border-radius: 6px; padding: 1px 5px; flex-shrink: 0; }
.var-ac__meaning { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto; min-width: 0; }
.var-ac__more { margin-left: auto; color: var(--text-darker); text-decoration: none; font-size: 14px; flex-shrink: 0; padding: 0 0.2rem; }
.var-ac__more:hover { color: var(--accent); }

/* ---------- embed builder (066) ---------- */
.field-hint { font-size: 12px; color: var(--text-darker); margin: 0.3rem 0 0; }
.toggle-row { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 14px; color: var(--text-muted); cursor: pointer; }

/* The builder: a form column and a sticky live preview column, stacking on narrow screens. */
.embed-builder { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 30rem); gap: 2rem; align-items: start; }
.embed-builder__form { display: flex; flex-direction: column; gap: 0.75rem; min-width: 0; }
.embed-builder__group { margin: 1.25rem 0 0.25rem; font-size: 1rem; }
.embed-builder__row { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
/* Custom colour picker (066): a swatch that opens a popover with a saturation/value square, a hue slider,
   and synced HEX / RGB / HSL fields. */
.cpick { position: relative; display: inline-flex; align-items: center; gap: 0.5rem; }
.cpick__swatch { width: 2.6rem; height: 2.6rem; border-radius: 10px; border: none; box-shadow: var(--raised-sm); cursor: pointer; padding: 0; }
.cpick__swatch:hover { box-shadow: var(--raised); }
.cpick__hex { width: 9rem; font-family: var(--font-mono); }
.cpick__pop { position: absolute; top: calc(100% + 0.5rem); left: 0; z-index: 60; width: 240px; padding: 0.85rem; background: var(--base); box-shadow: var(--raised), 0 14px 34px rgba(0, 0, 0, 0.4); border-radius: 14px; display: flex; flex-direction: column; gap: 0.7rem; }
.cpick__sv { position: relative; width: 100%; height: 132px; border-radius: 8px; cursor: crosshair; touch-action: none; }
.cpick__sv-cursor { position: absolute; width: 12px; height: 12px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45); transform: translate(-50%, -50%); pointer-events: none; }
.cpick__hue { position: relative; width: 100%; height: 14px; border-radius: 7px; cursor: pointer; touch-action: none; background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%); }
.cpick__hue-cursor { position: absolute; top: 50%; width: 14px; height: 14px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45); transform: translate(-50%, -50%); pointer-events: none; }
.cpick__fields { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.4rem; }
.cpick__fld { display: flex; flex-direction: column; gap: 0.2rem; }
.cpick__fld:first-child { grid-column: span 3; }
.cpick__fld span { font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-darker); }
.cpick__fld .input { width: 100%; padding: 0.4rem 0.4rem; font-size: 13px; font-family: var(--font-mono); text-align: center; }
/* The swatch's no-colour state: a diagonal line, the standard "none" indicator. */
.cpick__swatch--none { position: relative; background: var(--base); box-shadow: var(--pressed-sm); }
.cpick__swatch--none::after { content: ''; position: absolute; inset: 5px; background: linear-gradient(to top right, transparent 44%, var(--red) 45%, var(--red) 55%, transparent 56%); }
.cpick__foot { display: flex; gap: 0.5rem; }
.cpick__none { padding: 0.5rem 0.85rem; border: none; border-radius: 10px; background: var(--base); box-shadow: var(--raised-sm); color: var(--text-muted); font-family: inherit; font-size: 13px; cursor: pointer; transition: color 0.2s ease, box-shadow 0.2s ease; }
.cpick__none:hover { color: var(--red); box-shadow: var(--raised); }
.cpick__done { flex: 1; padding: 0.5rem; border: none; border-radius: 10px; background: var(--accent); box-shadow: var(--raised-sm); color: var(--base); font-family: inherit; font-size: 13px; font-weight: 600; cursor: pointer; transition: filter 0.2s ease, box-shadow 0.2s ease; }
.cpick__done:hover { filter: brightness(1.08); box-shadow: var(--raised); }
.embed-builder__actions { display: flex; gap: 1rem; margin-top: 1.5rem; align-items: center; }
.embed-builder__preview { position: sticky; top: 1rem; display: flex; flex-direction: column; gap: 0.6rem; }

/* One field's editor row. */
.embed-field-edit { display: flex; flex-direction: column; gap: 0.5rem; padding: 0.85rem; border-radius: 12px; box-shadow: var(--pressed-sm); }
.embed-field-edit__head { display: flex; align-items: center; gap: 0.75rem; }
.embed-field-edit__name { flex: 1 1 auto; }
.embed-field-edit__remove { margin-top: 0; padding: 0.5rem 0.75rem; }

/* The preview card, in the platform's embed shape: a coloured left bar, content, and a thumbnail top-right. */
/* Capped to a real embed's width (Discord tops out around here) so the preview never stretches to fill a
   wide card. It still shrinks on narrow screens. */
.embed-card { display: flex; gap: 1rem; width: 100%; max-width: 520px; background: var(--flat); border-radius: 8px; border-left: 4px solid var(--text-darker); padding: 1rem 1.1rem; overflow: hidden; }
.embed-card__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.embed-card__author { display: flex; align-items: center; gap: 0.5rem; font-size: 13px; font-weight: 700; color: var(--text-main); min-width: 0; overflow-wrap: anywhere; }
.embed-card__author-icon { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.embed-card__title { font-size: 16px; font-weight: 700; color: var(--text-main); overflow-wrap: anywhere; }
.embed-card__title--link { color: var(--accent); text-decoration: none; }
.embed-card__title--link:hover { text-decoration: underline; }
.embed-card__desc { font-size: 15px; line-height: 1.4; color: var(--text-muted); white-space: pre-wrap; overflow-wrap: anywhere; }
.embed-card__author a { color: inherit; text-decoration: none; }
.embed-card__author a:hover { text-decoration: underline; }
.embed-card__fields { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.embed-card__field { flex: 1 1 100%; min-width: 0; }
.embed-card__field.is-inline { flex: 1 1 30%; }
.embed-card__field-name { font-size: 13px; font-weight: 700; color: var(--text-main); overflow-wrap: anywhere; }
.embed-card__field-value { font-size: 13px; color: var(--text-muted); white-space: pre-wrap; overflow-wrap: anywhere; }
.embed-card__image { max-width: 100%; border-radius: 6px; margin-top: 0.25rem; }
.embed-card__thumb { width: 72px; height: 72px; border-radius: 6px; object-fit: cover; flex-shrink: 0; }
.embed-card__footer { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; min-width: 0; font-size: 12px; color: var(--text-darker); margin-top: 0.25rem; }
.embed-card__footer span { overflow-wrap: anywhere; min-width: 0; }
.embed-card__footer-icon { width: 18px; height: 18px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.embed-card__ts { color: var(--text-darker); }
.embed-card__empty { font-size: 13px; color: var(--text-darker); font-style: italic; }

/* Library rows. */
.embed-list { display: flex; flex-direction: column; gap: 1rem; margin: 1.5rem 0 2.5rem; }
/* A library entry is a collapsed card that expands to preview the embed and reveal its actions (066). */
.embed-row { padding: 0; overflow: hidden; }
.embed-row__summary { display: flex; align-items: center; gap: 1rem; padding: 1.1rem 1.25rem; cursor: pointer; list-style: none; min-width: 0; }
.embed-row__summary::-webkit-details-marker { display: none; }
/* The leading glyph is carved into the surface (no tile), matching the app's engraved icon language. */
.embed-row__icon { width: 44px; height: 44px; font-size: 22px; color: var(--accent); flex-shrink: 0; }
.embed-row__id { min-width: 0; flex: 1 1 auto; }
.embed-row__name { margin: 0; font-size: 16px; }
.embed-row__chevron { color: var(--text-darker); flex-shrink: 0; transition: transform 0.2s ease; }
.embed-row[open] .embed-row__chevron { transform: rotate(180deg); }
.embed-row__body { padding: 0 1.25rem 1.25rem; display: flex; flex-direction: column; gap: 1rem; }
/* Actions sit quiet under the preview and come forward on hover or keyboard focus. */
.embed-row__controls { display: flex; align-items: flex-start; gap: 0.6rem; flex-wrap: wrap; opacity: 0.5; transition: opacity 0.2s ease; }
.embed-row:hover .embed-row__controls, .embed-row__body:focus-within .embed-row__controls { opacity: 1; }
.embed-row__controls .btn { margin-top: 0; }
.embed-row__controls form { margin: 0; }
/* Rename edits the name in place: pressing Rename turns the title into a field, not a separate box (066). */
.embed-row__name { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.embed-row__name-edit { font: inherit; font-weight: 700; padding: 0.3rem 0.55rem; width: 15rem; max-width: 100%; margin: 0; }
.embed-row__rename { display: inline-flex; align-items: center; gap: 0.5rem; }

/* Stack the form and preview once the content box is too narrow for both side by side (the form needs about 24rem
   beside the 30rem preview). The preview un-stickies and drops below the form instead of staying pinned and forcing
   the form to wrap and clip around it. Two breakpoints make it sidebar-aware: the expanded 240px bar stacks about
   150px sooner than the collapsed 88px bar (the app auto-collapses the bar below 1180px, so these ranges line up). */
@media (max-width: 1080px) {
    .embed-builder { grid-template-columns: 1fr; }
    .embed-builder__preview { position: static; }
}
@media (max-width: 1240px) {
    .app.nav-expanded .embed-builder { grid-template-columns: 1fr; }
    .app.nav-expanded .embed-builder__preview { position: static; }
}

/* Action log local time and locale date pickers (064). Each From/To is a single inset pill with a small
   uppercase label prefix, so the native date input reads as one neumorphic control matching the other
   inputs, not a stray browser box. The date input itself is transparent inside the pill. */
.log-date { position: relative; display: inline-flex; align-items: center; gap: 0.6rem; background: var(--base); box-shadow: var(--pressed); border-radius: 12px; padding: 0 1rem; transition: box-shadow 0.25s ease; cursor: pointer; }
.log-date:focus-within { box-shadow: var(--pressed), inset 0 0 0 1px rgba(79, 157, 162, 0.45); }
.log-date__lbl { font-size: 11px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-darker); }
.log-date__input { width: 7.5rem; background: transparent; box-shadow: none; border: none; border-radius: 0; padding: 0.75rem 0; color: var(--text-main); font-family: inherit; font-size: 14px; cursor: pointer; }
.log-date__input:focus { outline: none; box-shadow: none; }
.log-date__input::placeholder { color: var(--text-darker); }
/* Under the Time header: the viewer's timezone display name in small mono (064, refined). Proper case,
   never uppercased, set by script from the browser's long timezone name. */
.th-tz { display: block; font-family: var(--font-mono); font-weight: 400; color: var(--text-darker); font-size: 10px; text-transform: none; letter-spacing: 0; margin-top: 2px; }

/* Custom calendar popover (064), matching the neumorphic language: a raised card, raised nav keys, day
   cells that lift on hover and press in with the accent when selected. */
.cal { position: absolute; top: calc(100% + 0.5rem); left: 0; z-index: 60; width: 17rem; padding: 0.85rem; background: var(--base); box-shadow: var(--raised); border-radius: 16px; }
.cal__head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.6rem; }
.cal__title { font-weight: 600; font-size: 14px; color: var(--text-main); }
.cal__nav { width: 2rem; height: 2rem; border-radius: 8px; background: var(--base); box-shadow: var(--raised-sm); border: none; color: var(--text-muted); cursor: pointer; font-size: 17px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; transition: box-shadow 0.2s ease, color 0.2s ease; }
.cal__nav:hover { box-shadow: var(--raised); color: var(--text-main); }
.cal__nav:active { box-shadow: var(--pressed-key); }
.cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.cal__dow { text-align: center; font-size: 10px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-darker); padding: 0.25rem 0 0.4rem; }
.cal__day { aspect-ratio: 1; border: none; border-radius: 8px; background: transparent; color: var(--text-muted); font-family: inherit; font-size: 13px; cursor: pointer; transition: box-shadow 0.15s ease, color 0.15s ease; }
.cal__day:hover { box-shadow: var(--raised-sm); color: var(--text-main); }
.cal__day.is-other { color: var(--text-darker); opacity: 0.45; }
.cal__day.is-selected { box-shadow: var(--pressed-sm); color: var(--accent); font-weight: 700; }
.cal__foot { display: flex; justify-content: flex-end; margin-top: 0.6rem; }
.cal__clear { background: none; border: none; color: var(--text-darker); font-size: 12px; cursor: pointer; padding: 0.25rem 0.4rem; }
.cal__clear:hover { color: var(--text-main); }

/* Unsaved-rule leave pop-up (063): an in-app modal resolving an attempted navigation with unsaved work. */
.modal-overlay { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; padding: 1.5rem; background: rgba(15, 17, 21, 0.55); }
/* The site-styled unsaved-changes leave guard (shown by the layout's navigation interceptor), hidden by default. */
.leave-guard { position: fixed; inset: 0; z-index: 200; display: none; align-items: center; justify-content: center; padding: 1.5rem; background: rgba(15, 17, 21, 0.55); }
.leave-guard.is-open { display: flex; }
.modal { width: 100%; max-width: 26rem; padding: 1.75rem; background: var(--base); box-shadow: var(--raised); border-radius: 20px; }
.modal__title { display: flex; align-items: center; gap: 0.6rem; margin: 0 0 0.75rem; font-size: 18px; color: var(--text-main); }
.modal__body { margin: 0; color: var(--text-muted); font-size: 14px; }
.modal__actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.6rem; margin-top: 1.5rem; }
.modal__actions .btn { margin-top: 0; }
