/* ==========================================================================
   amethyst mailer — web panel
   design language: dark-first, dot-grid backdrop, DM Sans + Geist Mono,
   purple only as a functional accent (active nav, focused input, primary CTA).
   inspired by 2fa.best.
   ========================================================================== */

/* ------------------------------------------------------------------ tokens */
:root {
    /* surfaces — warm near-black (not pitch), reads softer on OLED */
    --bg:           #0b0b0c;
    --surface:      #121214;
    --surface-2:    #17171a;
    --surface-3:    #1c1c21;

    /* lines */
    --border:       #1f1f23;
    --border-hi:    #2a2a30;

    /* text */
    --text:         #f4f4f5;
    --text-2:       #a1a1aa;
    --text-3:       #71717a;
    --text-ghost:   #3f3f46;

    /* brand — amethyst used sparingly */
    --amy:          #a78bfa;
    --amy-hi:       #c4b5fd;
    --amy-lo:       #7c5cf0;
    --amy-dim:      rgba(167, 139, 250, 0.10);
    --amy-ring:     rgba(167, 139, 250, 0.25);
    /* primary CTAs: deep base (amy-lo). hover/active are small hex nudges
       between amy-lo and amy — full --amy on hover felt cheap + too pastel. */
    --btn-primary-bg:         var(--amy-lo);
    --btn-primary-bg-hover:   #8366f2;
    --btn-primary-bg-active:  #6a4fd4;
    --btn-primary-border:     rgba(124, 92, 240, 0.55);
    --btn-primary-border-hi:  rgba(139, 110, 245, 0.5);
    --btn-primary-border-down: rgba(98, 72, 200, 0.65);

    /* semantic */
    --ok:           #22c55e;
    --ok-dim:       rgba(34, 197, 94, 0.12);
    --warn:         #f59e0b;
    --warn-dim:     rgba(245, 158, 11, 0.12);
    --err:          #ef4444;
    --err-dim:      rgba(239, 68, 68, 0.12);
    /* team owner (panel) — distinct from admin / product “owner” */
    --cyan:         #22d3ee;
    --cyan-dim:     rgba(34, 211, 238, 0.12);
    --cyan-ring:    rgba(34, 211, 238, 0.32);

    /* radii, motion */
    --r-xs: 6px;
    --r-s:  8px;
    --r-m:  12px;
    --r-l:  16px;
    --r-xl: 20px;
    /* alias — several pages were authored against --r-md. keeping them in
       sync here so we don't have to chase individual files. */
    --r-md: var(--r-m);

    --dur-fast: 120ms;
    --dur-med:  180ms;
    --dur-slow: 300ms;
    --easing:   cubic-bezier(0.16, 1, 0.3, 1);
    /* aliases for pages that reference the shorter names — same values. */
    --d-1: var(--dur-fast);
    --d-2: var(--dur-med);
    --d-3: var(--dur-slow);
    --e-out: var(--easing);

    /* 4px-scale spacing tokens — a bunch of admin templates were written
       against --space-1 through --space-6 but the tokens had never been
       defined, so every padding/margin/gap that referenced them was
       silently dropped by the browser and the whole admin surface
       looked like it had no spacing at all. these match the cadence
       already used elsewhere in the file (concrete 4/8/12/16/20/24 px). */
    --space-1:  4px;
    --space-2:  8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    --space-6: 24px;
    --space-7: 32px;
    --space-8: 40px;

    /* semantic color aliases — several pages reference --accent / --text-1
       expecting the amethyst accent and primary text colours. point them
       at the real tokens so the aliases resolve instead of collapsing. */
    --accent:     var(--amy);
    --accent-dim: var(--amy-dim);
    --accent-hi:  var(--amy-hi);
    --text-1:     var(--text);
    /* background-depth aliases — several admin pages expect --bg-2 / --bg-3
       instead of --surface-* so the backdrop colours never showed up. */
    --bg-2:       var(--surface-2);
    --bg-3:       var(--surface-3);

    /* layout */
    --sidebar-w: 240px;
    --topbar-h:  60px;

    /* fonts */
    --font:  'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --mono:  'Geist Mono', 'JetBrains Mono', 'SF Mono', Consolas, monospace;
}

/* ---------------------------------------------------------- reset + base */
*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

/* do not set `height: 100%` on both html and body — that locks the body box
   to the initial viewport while children (.app) still use vh/svh, which
   routinely produces scrollHeight = innerHeight + 1..3px and a permanent
   vertical scrollbar on short pages (chrome/edge). html supplies the pct
   root; body uses min-height only so it can grow with overflow content. */
html {
    height: 100%;
    /* htmx / async height changes above the fold can trigger scroll anchoring
       and leave the page scrolled down a few dozen px on first paint — reads
       as a “gap” under the chrome until the user scrolls manually. */
    overflow-anchor: none;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}
body {
    font-family: var(--font);
    font-size: 13px;
    line-height: 1.5;
    letter-spacing: -0.005em;
    color: var(--text);
    background: var(--bg);
    min-height: 100%;
    /* 100vh alone is often a few px taller than the *layout* viewport once a
       scrollbar exists (windows chrome/edge) → permanent ~20–40px overflow.
       100svh tracks the *small* viewport and matches clientHeight much more
       reliably; keep vh as fallback for older engines. */
    min-height: 100vh;
    min-height: 100svh;
    overflow-x: hidden;
    overflow-anchor: none;
}

/* signature dot-grid behind everything */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 0;
    background-image: radial-gradient(circle, #1a1a1f 1px, transparent 1px);
    background-size: 24px 24px;
    opacity: 0.55;
    pointer-events: none;
}

/* falling-crystals canvas. fixed full-viewport, sits between the dot-grid
   pseudo-element and the .app shell, so particles drift behind every page
   but the dot pattern still shows above them. pointer-events:none keeps it
   purely decorative — clicks pass through to whatever's underneath. */
#bg-canvas {
    position: fixed;
    inset: 0;
    /* global `img, video, canvas { height: auto }` (below) must not zero
       the full-viewport canvas on mobile webkit. */
    width: 100% !important;
    max-width: none !important;
    min-height: 100vh !important;
    min-height: 100svh !important;
    height: 100vh !important;
    height: 100svh !important;
    z-index: 0;
    pointer-events: none;
    /* note: previously used mix-blend-mode: screen for a softer glow, but
       blend-modes at viewport scale force the compositor to re-blend every
       pixel beneath the canvas on each paint — biggest single perf hit on
       this page. the per-particle halos already give the glow effect, so
       we render as a normal layer (own compositor surface, no recompose). */
    will-change: transform;
    -webkit-transform: translateZ(0);
    transform: translateZ(0);
}

a {
    color: inherit;
    text-decoration: none;
}
a:hover { color: var(--text); }

h1, h2, h3, h4, h5, h6 {
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--text);
}

h1 { font-size: 24px; line-height: 1.2; letter-spacing: -0.03em; }
h2 { font-size: 18px; line-height: 1.3; }
h3 { font-size: 15px; line-height: 1.4; }

p   { color: var(--text-2); }
hr  { border: 0; border-top: 1px solid var(--border); margin: 20px 0; }
.mono { font-family: var(--mono); letter-spacing: 0; }

::selection {
    background: var(--amy-dim);
    color: var(--text);
}

/* custom scrollbar */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 6px;
    border: 2px solid var(--bg);
}
::-webkit-scrollbar-thumb:hover { background: var(--border-hi); }
/* the gap where vertical + horizontal scrollbars meet defaults to white in
   webkit, which looks awful on dark surfaces (visible at the bottom-right
   of the preview/template list when long filenames force a horizontal
   scrollbar). transparent makes it blend with whichever surface owns the
   scrolling container. */
::-webkit-scrollbar-corner { background: transparent; }

/* ---------------------------------------------------------------- layout */
.app {
    position: relative;
    z-index: 1;
    overflow-anchor: none;
    /* min-height here duplicated body + vh and fought the html/body pct
       chain — let content + sidebar height define grid block size. */
    display: grid;
    grid-template-columns: var(--sidebar-w) 1fr;
    /* second row must not flex-grow past content: 1fr + indefinite grid height
       can overshoot on blink; auto + minmax keeps the document height honest. */
    grid-template-rows: var(--topbar-h) minmax(0, auto);
    grid-template-areas:
        "sidebar topbar"
        "sidebar main";
}

@media (min-width: 901px) {
    .app {
        transition: grid-template-columns var(--dur-med) var(--easing);
    }

    .sidebar {
        transition:
            transform var(--dur-med) var(--easing),
            opacity var(--dur-med) var(--easing);
        min-width: 0;
    }

    .app.is-sidebar-collapsed {
        grid-template-columns: 0 minmax(0, 1fr);
    }

    .app.is-sidebar-collapsed .sidebar {
        opacity: 0;
        transform: translateX(-16px);
        pointer-events: none;
        border-right-color: transparent;
    }

    .app.sidebar-skip-transition,
    .app.sidebar-skip-transition .sidebar {
        transition: none !important;
    }
}

.topbar { grid-area: topbar; }
.sidebar { grid-area: sidebar; }
.main {
    grid-area: main;
    padding: 24px 32px 36px;
    min-width: 0;
    min-height: 0;
    /* without this, blink stretches main to the full row track height; on
       short compose/preview pages that reads as a huge empty band under the
       topbar even though the headings sit at the normal padding offset. */
    align-self: start;
    overflow-anchor: none;
}

@media (max-width: 900px) {
    .app {
        grid-template-columns: 1fr;
        grid-template-rows: var(--topbar-h) minmax(0, auto) minmax(0, auto);
        grid-template-areas:
            "topbar"
            "sidebar"
            "main";
    }
    .main { padding: 20px 16px 40px; }
    /* on mobile the sidebar collapses below the topbar and shouldn't
       reserve a full viewport height — that would cover the page. */
    .sidebar {
        position: static;
        height: auto;
        max-height: none;
        overflow: visible;
    }
    .sidebar-scroll {
        flex: 0 1 auto;
        min-height: 0;
        overflow: visible;
    }
}

/* ---------------------------------------------------------------- topbar */
.topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 24px 0 28px;
    border-bottom: 1px solid var(--border);
    background: rgba(11, 11, 12, 0.75);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    position: sticky;
    top: 0;
    z-index: 10;
}

.topbar .crumb {
    font-size: 12px;
    color: var(--text-3);
    display: flex;
    align-items: center;
    gap: 8px;
}
.topbar .crumb .sep { color: var(--text-ghost); }
.topbar .crumb .now { color: var(--text-2); }

.topbar-right {
    display: flex;
    align-items: center;
    gap: 10px;
}

.theme-toggle {
    color: var(--text);
    flex-shrink: 0;
    opacity: 0.92;
}

.theme-toggle:hover {
    color: var(--text);
}

.theme-toggle .theme-icon {
    width: 18px;
    height: 18px;
    display: block;
}

.topbar-start {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--text-2);
}

.nav-toggle:hover {
    color: var(--text);
    background: var(--surface);
}

.nav-toggle svg {
    width: 18px;
    height: 18px;
}

@media (min-width: 901px) {
    /* topbar menu only when sidebar is hidden — use sidebar chevron to collapse */
    .topbar .nav-toggle {
        display: none;
    }

    .app.is-sidebar-collapsed .topbar .nav-toggle {
        display: inline-flex;
    }
}

/* user chip */
.user-chip {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 6px 10px 6px 6px;
    border-radius: 100px;
    border: 1px solid var(--border);
    background: var(--surface);
    transition: border-color var(--dur-med) var(--easing), background var(--dur-med) var(--easing);
    cursor: default;
}
.user-chip:hover { border-color: var(--border-hi); }

.avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--surface-2);
    object-fit: cover;
    flex-shrink: 0;
    border: 1px solid var(--border);
}
.avatar.lg { width: 40px; height: 40px; }
.avatar.sm { width: 22px; height: 22px; }
.avatar-fallback {
    width: 28px; height: 28px;
    border-radius: 50%;
    background: var(--amy-dim);
    color: var(--amy);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 600;
    flex-shrink: 0;
    text-transform: uppercase;
}
.user-avatar-wrap {
    position: relative;
    width: 28px;
    height: 28px;
    flex-shrink: 0;
}
.user-avatar-wrap .avatar-fallback { display: none; }
.user-avatar-wrap.no-photo .avatar { display: none; }
.user-avatar-wrap.no-photo .avatar-fallback { display: inline-flex; }

.user-chip .name {
    font-size: 12px;
    font-weight: 500;
    color: var(--text);
}
.user-chip .role {
    font-size: 10px;
    color: var(--text-3);
    text-transform: lowercase;
    letter-spacing: 0.04em;
    padding-right: 6px;
}

/* ---------------------------------------------------------------- sidebar */
/* outer shell: no vertical scroll here — flex + min-height:0 child handles
   overflow so scrollbar-hiding applies to one real scrollport (see
   .sidebar-scroll). fixes cases where the gutter stayed visible on the
   aside even with ::-webkit-scrollbar { display:none }. */
.sidebar {
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--border);
    background: rgba(11, 11, 12, 0.6);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    padding: 16px 14px 16px;
    align-self: start;
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100svh;
    max-height: 100vh;
    max-height: 100svh;
    overflow: hidden;
    min-height: 0;
}
.sidebar > .sidebar-head,
.sidebar > .sidebar-foot {
    flex-shrink: 0;
}

.sidebar-head {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0;
    margin-bottom: 0;
    padding: 4px 8px 8px;
    border-bottom: 0;
}

.sidebar-head .sidebar-collapse {
    position: absolute;
    top: 0;
    right: 0;
}

.sidebar-head .brand-stack {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    padding: 0;
    text-align: center;
}

.brand-mark-logo {
    width: 58px;
    height: 58px;
    border-radius: 50%;
    object-fit: cover;
    object-position: center;
    display: block;
    box-shadow: 0 0 0 2px rgba(34, 211, 238, 0.22), 0 0 18px rgba(34, 211, 238, 0.12);
}

.sidebar-head .brand {
    flex: none;
    min-width: 0;
    padding: 0;
}

.sidebar-collapse {
    display: none;
    flex-shrink: 0;
    color: var(--text-3);
}

@media (min-width: 901px) {
    .sidebar-collapse {
        display: inline-flex;
    }
}

.sidebar > .sidebar-foot {
    flex-shrink: 0;
}
/* inner region: all nav sections; sole vertical scrollport + hidden bar */
.sidebar-scroll {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow-x: hidden;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    -ms-overflow-style: none;
    scrollbar-width: none;
    scrollbar-color: transparent transparent;
    padding-top: 0;
}
.sidebar-scroll > .nav-section:first-child {
    margin-top: 0;
}
.sidebar-scroll::-webkit-scrollbar {
    display: none;
    width: 0;
    height: 0;
}
.sidebar-scroll::-webkit-scrollbar-track,
.sidebar-scroll::-webkit-scrollbar-thumb,
.sidebar-scroll::-webkit-scrollbar-button {
    display: none;
}

.brand {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    text-decoration: none;
    border: 0;
    background: transparent;
    user-select: none;
    -webkit-user-drag: none;
}
.brand-logo {
    display: block;
    height: 26px;
    width: auto;
    max-width: 100%;
    object-fit: contain;
    filter: none;
    transition: transform 180ms ease;
    -webkit-user-drag: none;
}
.brand:hover .brand-logo {
    filter: none;
}
.brand:active .brand-logo {
    transform: translateY(1px);
}

.nav-section {
    /* compact section spacing — admins have ~20 nav items so we want them
       to all fit inside a single viewport at 1080p without an internal
       scrollbar. members/regular users have ~10 items and look the same. */
    margin-top: 10px;
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.nav-section-foot {
    margin-top: auto;
    padding-top: 8px;
}
.nav-label {
    padding: 6px 10px 4px;
    font-size: 10px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--text-ghost);
}

.nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 10px;
    border-radius: var(--r-s);
    font-size: 13px;
    color: var(--text-2);
    position: relative;
    transition: background var(--dur-fast) var(--easing), color var(--dur-fast) var(--easing);
}
.nav-item:hover {
    color: var(--text);
    background: rgba(255, 255, 255, 0.025);
}
.nav-item.active {
    color: var(--text);
    background: var(--amy-dim);
}
.nav-item.active::before {
    content: "";
    position: absolute;
    left: -14px;
    top: 50%;
    transform: translateY(-50%);
    height: 18px;
    width: 2px;
    border-radius: 2px;
    background: var(--amy);
    box-shadow: none;
}
.nav-item.active .nav-icon { color: var(--amy); }

.nav-icon {
    width: 16px; height: 16px;
    flex-shrink: 0;
    color: var(--text-3);
    transition: color var(--dur-fast) var(--easing);
}
.nav-item:hover .nav-icon { color: var(--text-2); }

.sidebar-foot {
    margin-top: auto;
    padding: 12px 10px 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    border-top: 0;
}

.sidebar-action-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    min-height: 44px;
    padding: 11px 16px;
    border-radius: 14px;
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 0.01em;
    text-decoration: none;
    border: 0;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
    transition: transform 0.15s ease, filter 0.15s ease, box-shadow 0.15s ease;
    cursor: pointer;
    font-family: inherit;
}

.sidebar-action-icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    stroke: #fff;
}

.telegram-btn {
    background: #3b9cff;
    color: #fff;
}

.telegram-btn:hover {
    background: #4aa5ff;
    filter: brightness(1.03);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(59, 156, 255, 0.35);
}

.telegram-btn:active {
    transform: translateY(0);
}

.sidebar-logout-form {
    margin: 0;
    padding: 0;
}

.logout-btn {
    background: #ef4444;
    color: #fff;
}

.logout-btn:hover {
    background: #f25555;
    filter: brightness(1.03);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(239, 68, 68, 0.35);
}

.logout-btn:active {
    transform: translateY(0);
}

/* ---------------------------------------------------------------- cards */
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-l);
    padding: 20px;
    animation: slideUp 0.35s var(--easing);
}
.card.flush { padding: 0; overflow: hidden; }
.card.tight { padding: 14px 16px; }

.card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--border);
}
.card-head h2 { font-size: 14px; font-weight: 600; }
.card-head .card-title { font-size: 14px; font-weight: 600; color: var(--text); }
.card-head .sub { font-size: 11px; color: var(--text-3); }
.card-head .sub.is-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.card-head-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

/* /send live-preview fetch indicator only — /preview keeps its own
   #tpl-render-frame + loading styles in preview.html so that page
   is never affected by send-page tweaks. */
#send-preview-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    position: relative;
}
#send-preview-card.is-loading::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: linear-gradient(90deg,
        rgba(168, 85, 247, 0) 0%,
        rgba(168, 85, 247, 0.85) 50%,
        rgba(168, 85, 247, 0) 100%);
    background-size: 200% 100%;
    animation: send-preview-loading 0.9s linear infinite;
    pointer-events: none;
    z-index: 2;
}
@keyframes send-preview-loading {
    from { background-position: 100% 0; }
    to   { background-position: -100% 0; }
}

.card-body { padding: 18px; }

/* generic "scrollable region inside a card" — used by list-heavy pages
   (sender / history / admin tables) so they don't grow the page height
   past the viewport. the container scrolls; the page does not. height
   is roughly tuned so the surrounding card chrome (head/foot, page
   title, filter bar) leaves a comfortable gap above the v0.1 footer at
   1024px+ heights, while still showing 6+ rows at the bare minimum. */
.scroll-region {
    /* dynamic max-height so the surrounding chrome (page title, filters,
       card head, footer, sidebar foot) always has room to breathe. the
       fallback fixed value covers very small viewports where the
       calc could go negative. */
    max-height: max(320px, calc(100vh - 380px));
    overflow-y: auto;
    /* always reserve room for a vertical scrollbar so toggling between
       short and long lists doesn't shift the table column widths. */
    scrollbar-gutter: stable;
}
.scroll-region.tall {
    /* subtract chrome + page-head + filter card + card-head +
       card body padding so the table's scroll region fits inside
       the viewport without pushing the body into its own scrollbar.
       bumped from 440px to 520px because the history filter bar
       (labels + 40px inputs + card padding) is taller than the
       bare-table pages this rule was originally tuned for. */
    max-height: max(320px, calc(100vh - 520px));
}
/* sticky header row stays visible while scrolling the body */
.scroll-region table.table thead th {
    position: sticky;
    top: 0;
    background: var(--surface);
    z-index: 1;
    /* a thin bottom rule keeps the head visually separated from rows
       that scroll underneath it. */
    box-shadow: inset 0 -1px 0 var(--border);
}
.card-foot {
    padding: 12px 18px;
    border-top: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    background: rgba(255, 255, 255, 0.01);
}

.section-title {
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--text-3);
    margin-bottom: 12px;
}

.page-title {
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.03em;
    margin-bottom: 4px;
}
.page-sub {
    color: var(--text-3);
    font-size: 13px;
    margin-bottom: 20px;
}

/* dashboard grid — 3 col with recent sends weighted wider, collapses gracefully */
.dash-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(260px, 1fr) minmax(240px, 1fr);
    gap: 14px;
    align-items: stretch;
}
.dash-grid > .card {
    height: 100%;
    min-height: 0;
}
.dash-grid > .card.flush {
    display: flex;
    flex-direction: column;
}
.dash-grid > .card.flush .dash-table-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
}
.dash-grid > * { min-width: 0; }
@media (max-width: 1400px) {
    .dash-grid { grid-template-columns: minmax(0, 1.4fr) minmax(260px, 1fr); }
    .dash-grid > :nth-child(3) { grid-column: 1 / -1; }
}
@media (max-width: 900px) {
    .dash-grid { grid-template-columns: 1fr; }
    .dash-grid > :nth-child(3) { grid-column: auto; }
}

/* a stacked column of checkbox rows (fixes the cramped inline layout) */
.check-col {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.check-col .check-row { padding: 2px 0; }

/* two-column page layout for settings-style pages (form left, meta right) */
.split-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(280px, 1fr);
    gap: 14px;
    align-items: flex-start;
}
@media (max-width: 900px) {
    .split-grid { grid-template-columns: 1fr; }
}

/* key/value meta rows shared across team, settings, dashboard */
.kv-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    font-size: 12px;
}
.kv-row .k { color: var(--text-3); font-size: 11px; text-transform: lowercase; }
.kv-row .v { color: var(--text); font-family: var(--mono); font-size: 12px; }
.kv-stack { display: grid; gap: 8px; }

/* ---------------------------------------------------------------- buttons */
.btn[hidden] { display: none !important; }
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 9px 14px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-2);
    font-family: var(--font);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: -0.005em;
    cursor: pointer;
    transition: all var(--dur-fast) var(--easing);
    user-select: none;
    text-decoration: none;
    line-height: 1;
    text-shadow: none;
    filter: none;
}
.btn:hover {
    color: var(--text);
    border-color: var(--border-hi);
    background: rgba(255, 255, 255, 0.025);
}
.btn:active { transform: translateY(0.5px); }
.btn:disabled, .btn.disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}
.btn svg { width: 14px; height: 14px; }

.btn.primary {
    /* flat fill — deeper amethyst (amy-lo) to align with brand / nav accent;
       no gradient, glow, or micro-translate (reads as jittery on dark UIs). */
    background: var(--btn-primary-bg);
    border: 1px solid var(--btn-primary-border);
    color: #fff;
    box-shadow: none;
    font-weight: 600;
    text-shadow: none;
    transform: none;
    transition:
        background var(--dur-fast) var(--easing),
        border-color var(--dur-fast) var(--easing),
        color var(--dur-fast) var(--easing);
}
.btn.primary:hover {
    color: #fff;
    background: var(--btn-primary-bg-hover);
    border-color: var(--btn-primary-border-hi);
    transform: none;
    box-shadow: none;
    filter: none;
}
.btn.primary:active {
    /* override global .btn:active translateY — primary stays visually stable */
    background: var(--btn-primary-bg-active);
    border-color: var(--btn-primary-border-down);
    transform: none;
}
.btn.primary svg {
    filter: none;
}
.btn.ghost { border-color: transparent; }
.btn.ghost:hover { border-color: var(--border); }

.btn.danger { color: var(--err); border-color: rgba(239, 68, 68, 0.25); }
.btn.danger:hover { background: var(--err-dim); border-color: rgba(239, 68, 68, 0.45); }

.btn.lg { padding: 11px 18px; font-size: 13px; }
.btn.sm { padding: 6px 10px; font-size: 11px; }
.btn.icon { padding: 8px; width: 32px; height: 32px; }

/* ---------------------------------------------------------------- inputs */
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.field[hidden],
.quick-field[hidden],
#spoof-slot[hidden] {
    display: none !important;
}
#spoof-custom-fields[hidden] {
    display: none !important;
}
.spoof-custom-grid {
    display: grid;
    gap: 10px;
    margin-top: 10px;
}
.spoof-custom-field {
    margin-bottom: 0;
}
.field label, .label {
    font-size: 11px;
    font-weight: 500;
    color: var(--text-2);
    letter-spacing: 0.01em;
}

.input, .select, .textarea {
    width: 100%;
    padding: 10px 12px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background-color: var(--surface-2);
    color: var(--text);
    font-family: var(--font);
    font-size: 13px;
    line-height: 1.4;
    transition: border-color var(--dur-fast) var(--easing), box-shadow var(--dur-fast) var(--easing), background-color var(--dur-fast) var(--easing);
    outline: none;
}
.input:focus, .select:focus, .textarea:focus {
    border-color: var(--amy);
    box-shadow: 0 0 0 3px var(--amy-ring);
    background-color: var(--surface-3);
}
.input::placeholder, .textarea::placeholder { color: var(--text-ghost); }

.textarea { min-height: 88px; resize: vertical; font-family: var(--mono); font-size: 12px; }

.relay-custom-input {
    width: 100%;
    max-width: 100%;
    resize: vertical;
    overflow-x: hidden;
    box-sizing: border-box;
}

.select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 12px;
    padding-right: 36px;
}

/* error flash on inputs */
.input.flash-err { animation: flashErr 0.6s var(--easing); }
@keyframes flashErr {
    0%   { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); border-color: var(--border); }
    25%  { box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.15); border-color: rgba(239, 68, 68, 0.5); }
    100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); border-color: var(--border); }
}

/* ── custom client-side validation (replaces native popups) ────────
   amyValidateForm() paints `.is-invalid` on the offending control and
   appends a `.field-error` message beneath it. we set `novalidate` on
   the <form> to suppress the browser's own tooltip — it looked wildly
   out of place against the rest of the panel's dark surface. */
.input.is-invalid,
.select.is-invalid,
.textarea.is-invalid {
    border-color: rgba(239, 68, 68, 0.55);
    background: color-mix(in oklab, var(--err) 5%, var(--surface-2));
}
.input.is-invalid:focus,
.select.is-invalid:focus,
.textarea.is-invalid:focus {
    border-color: var(--err);
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.18);
}
/* comboboxes: the validated node is a <input type=hidden>, so the
   JS pastes the marker on the wrapper so the button face reflects it. */
.fc-combobox.is-invalid .fc-button {
    border-color: rgba(239, 68, 68, 0.55);
    background: color-mix(in oklab, var(--err) 5%, var(--surface-2));
}
.fc-combobox.is-invalid .fc-button:focus-visible {
    border-color: var(--err);
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.18);
}
/* dropzones (hidden file inputs): paint the dashed border red. */
.dropzone.is-invalid {
    border-color: rgba(239, 68, 68, 0.6);
    background: color-mix(in oklab, var(--err) 4%, var(--surface-2));
}

.field-error {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin-top: 6px;
    font-size: 11.5px;
    line-height: 1.4;
    color: #fca5a5;
    animation: fieldErrorIn 0.18s var(--easing);
}
.field-error svg {
    flex: 0 0 auto;
    width: 12px;
    height: 12px;
    margin-top: 1px;
    color: var(--err);
}
@keyframes fieldErrorIn {
    from { opacity: 0; transform: translateY(-2px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ── confirm / alert dialogs (replace native confirm/alert) ────────
   used by amyConfirm() + amyAlert() in /static/js/ui-dialog.js and by
   /send + /quick's "missing placeholders" inline modal. sits above the
   panel via a blurred backdrop; the card scales in for a less abrupt
   reveal than a hard-cut display:flex. */
.confirm-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(8, 8, 14, 0.58);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    padding: 20px;
}
/* [hidden] alone can lose to other display rules in some engines — never let
   a closed backdrop participate in layout (was inside /send's css grid). */
.confirm-backdrop[hidden]:not(.open) {
    display: none !important;
}
.confirm-backdrop.open { display: flex; animation: confirmBackdropIn 0.12s var(--easing); }
.confirm-backdrop.open .confirm-dialog { animation: confirmDialogIn 0.16s var(--easing); }
@keyframes confirmBackdropIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes confirmDialogIn {
    from { opacity: 0; transform: translateY(6px) scale(0.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

.confirm-dialog {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-l);
    padding: 22px 22px 18px;
    width: 100%;
    max-width: 460px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.confirm-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}
.confirm-icon {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--warn-dim);
    border: 1px solid rgba(245, 158, 11, 0.35);
    color: #fbbf24;
}
.confirm-icon svg { width: 18px; height: 18px; }
/* danger variant — matches .btn.danger tone so delete/destroy
   actions read as "hot" the instant the modal opens. */
.confirm-icon.danger {
    background: var(--err-dim);
    border-color: rgba(239, 68, 68, 0.35);
    color: #fca5a5;
}
.confirm-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
    letter-spacing: -0.01em;
}
.confirm-body { font-size: 13px; color: var(--text-2); line-height: 1.5; }
.confirm-body p { margin: 0; }
.confirm-body p + p { margin-top: 8px; }
.confirm-list {
    margin: 10px 0 0;
    padding: 10px 12px;
    list-style: none;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.confirm-list li {
    font-family: var(--mono);
    font-size: 11.5px;
    padding: 3px 8px;
    border-radius: 999px;
    background: var(--warn-dim);
    border: 1px solid rgba(245, 158, 11, 0.3);
    color: #fde68a;
}
.confirm-actions {
    display: flex;
    gap: 10px;
    margin-top: 16px;
}
.confirm-actions .btn { flex: 1; }

/* checkbox */
.check {
    appearance: none;
    width: 16px; height: 16px;
    border-radius: 4px;
    border: 1px solid var(--border-hi);
    background: var(--surface-2);
    cursor: pointer;
    position: relative;
    transition: all var(--dur-fast) var(--easing);
    flex-shrink: 0;
}
.check:checked {
    background: var(--amy);
    border-color: var(--amy);
}
.check:checked::after {
    content: "";
    position: absolute;
    top: 2px; left: 5px;
    width: 4px; height: 8px;
    border: solid #0b0b0c;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}
.check-row {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: var(--text-2);
    cursor: pointer;
    user-select: none;
}
.check-row:hover { color: var(--text); }

/* file input */
.file {
    display: block;
    padding: 9px 12px;
    border-radius: var(--r-s);
    border: 1px dashed var(--border-hi);
    background: var(--surface-2);
    color: var(--text-3);
    font-size: 12px;
    cursor: pointer;
    transition: all var(--dur-fast) var(--easing);
}
.file:hover { border-color: var(--amy); color: var(--text-2); }
.file input { display: none; }

/* uploaded-file thumbnail rendered next to a file input by send.js. small,
   square, with the same border treatment as inputs so it reads as part of
   the field rather than free-floating. */
.file-thumb {
    display: block;
    margin-top: 8px;
    width: 96px;
    height: 96px;
    object-fit: cover;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: var(--surface-2);
}

/* ---------------------------------------------------------------- pills */
.pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 9px;
    border-radius: 100px;
    border: 1px solid var(--border);
    background: var(--surface);
    font-size: 10px;
    font-weight: 500;
    color: var(--text-3);
    letter-spacing: 0.02em;
    text-transform: lowercase;
}
.pill .dot {
    width: 6px; height: 6px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.6;
}
.pill.ok      { color: var(--ok); border-color: rgba(34, 197, 94, 0.25); background: var(--ok-dim); }
.pill.warn    { color: var(--warn); border-color: rgba(245, 158, 11, 0.25); background: var(--warn-dim); }
.pill.err     { color: var(--err); border-color: rgba(239, 68, 68, 0.25); background: var(--err-dim); }
.pill.amy     { color: var(--amy); border-color: rgba(167, 139, 250, 0.3); background: var(--amy-dim); }
.pill.live .dot { animation: pulse 2s infinite; }

@keyframes pulse {
    0%, 100% { opacity: 0.9; transform: scale(1); }
    50%      { opacity: 0.35; transform: scale(0.85); }
}

/* ---------------------------------------------------------------- tables */
.table {
    width: 100%;
    border-collapse: collapse;
}
.table th, .table td {
    padding: 10px 16px;
    text-align: left;
    vertical-align: middle;
    font-size: 12px;
    border-bottom: 1px solid var(--border);
}
.table th {
    font-weight: 500;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 10px;
    background: rgba(255, 255, 255, 0.01);
}
.table tr:last-child td { border-bottom: 0; }
.table tr { transition: background var(--dur-fast) var(--easing); }
.table tbody tr:hover { background: rgba(255, 255, 255, 0.015); }
.table td .mono { font-size: 11px; color: var(--text-2); }

/* ---------------------------------------------------------------- stat tiles */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 12px;
    margin-bottom: 18px;
}
.stat-tile {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-m);
    padding: 14px 16px;
    transition: border-color var(--dur-med) var(--easing), transform var(--dur-med) var(--easing);
    animation: slideUp 0.35s var(--easing) backwards;
}
.stat-tile:hover {
    border-color: var(--border-hi);
    transform: translateY(-1px);
}
.stat-tile .stat-label {
    font-size: 10px;
    font-weight: 500;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    gap: 6px;
}
.stat-tile .stat-label svg { width: 12px; height: 12px; }
.stat-tile .stat-value {
    font-family: var(--mono);
    font-size: 24px;
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1;
    color: var(--text);
    text-shadow: none;
}
.stat-tile .stat-delta {
    margin-top: 6px;
    font-size: 10px;
    color: var(--text-3);
    display: flex;
    align-items: center;
    gap: 4px;
}
.stat-tile .stat-delta.up   { color: var(--ok); }
.stat-tile .stat-delta.down { color: var(--err); }

/* ---------------------------------------------------------------- grids + rows */
.row { display: flex; align-items: center; gap: 10px; }
.row.spread { justify-content: space-between; }
.row.end    { justify-content: flex-end; }
.row.start  { justify-content: flex-start; }
.row.wrap   { flex-wrap: wrap; }

.grid { display: grid; gap: 14px; }
.grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 720px) {
    .grid.cols-2, .grid.cols-3, .grid.cols-4 { grid-template-columns: 1fr; }
}

.gap-xs { gap: 6px; }
.gap-sm { gap: 10px; }
.gap-md { gap: 14px; }
.gap-lg { gap: 20px; }

.muted { color: var(--text-3); }
.muted-2 { color: var(--text-2); }
.faint { color: var(--text-ghost); }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* -------------------------------------------------- cell-scroll utility
   single-line content that may outrun its cell gets truncated with a
   clean ellipsis by default. ONLY when that specific cell is directly
   hovered AND its content actually overflows does the cell become
   horizontally scrollable. the cell's width and text position do not
   change between states — the scrollbar always occupies the same 4px
   strip at the bottom of the cell, invisible when idle.

   tweaks that were needed to feel right:
     - padding-bottom: 4px always, so when overflow-x flips to auto on
       hover the scrollbar has a pre-allocated home; text never shifts.
     - text-overflow: ellipsis -> clip on hover, so scrolling actually
       reveals hidden characters instead of re-showing the ellipsis.
     - ::-webkit-scrollbar-button { display: none } kills the tiny
       < > arrow caps chromium renders on thin horizontal scrollbars.
     - scrollbar color is subtle white-alpha to match the neutral
       grayscale UI chrome, not the violet accent. */
.cell-scroll {
    display: block;
    max-width: 100%;
    width: max-content;
    white-space: nowrap;
    line-height: 1.4;
    /* both axes locked so the browser never implicitly promotes
       overflow-y to auto (which was silently growing the element
       by another scrollbar's worth of space on hover). */
    overflow: hidden;
    text-overflow: ellipsis;
    /* a little right-padding so when the user scrolls all the way
       to the end, the last glyph isn't clipped against the container
       edge. the browser's advance-width can be ~1px short of the
       ink bounds (kerning, italic tails, numeric tabular digits),
       which manifested as a half-cut last character. */
    padding-right: 6px;
    /* reserve the full text-line + scrollbar height up front so the
       element occupies the same vertical space in both resting and
       hover states. the scrollbar just materialises inside the
       already-allocated 4px at the bottom instead of pushing the
       element taller (which would re-center it and shift the text). */
    min-height: calc(1.4em + 6px);
    /* NOTE: deliberately NOT using scrollbar-width: thin — chromium
       disables the ::-webkit-scrollbar pseudo-element whenever
       scrollbar-width is set, which forces a fat 10-12px scrollbar.
       the webkit rules below give us a real 4px bar. */
}
.cell-scroll::-webkit-scrollbar { height: 6px; width: 6px; background: transparent; }
.cell-scroll::-webkit-scrollbar-track { background: transparent; }
.cell-scroll::-webkit-scrollbar-thumb {
    background: transparent;
    border-radius: 8px;
    /* transparent border acts as an inset padding so the rounded pill
       reads as ~6px inside the 8px slot, giving the bar breathing room
       while still being an easy target for the mouse. */
    border: 1px solid transparent;
    background-clip: padding-box;
}
.cell-scroll::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
.cell-scroll::-webkit-scrollbar-corner { display: none; }

/* hover trigger — ONLY when this exact element is hovered, and the
   scrollbar only actually appears when the content overflows. short
   names that fit don't show a scrollbar at all. overflow-y stays
   hidden so the element height doesn't change.

   thumb color is a neutral slate-gray pill, clearly visible on the
   dark card without leaning into the violet accent; the inner hover
   state brightens toward near-white to confirm grab-ability. */
.cell-scroll:hover {
    overflow-x: auto;
    overflow-y: hidden;
    text-overflow: clip;
}
.cell-scroll:hover::-webkit-scrollbar-thumb {
    background: #4a4a54;
    background-clip: padding-box;
}
.cell-scroll:hover::-webkit-scrollbar-thumb:hover {
    background: #7e7e8a;
    background-clip: padding-box;
}

/* ---------------------------------------------------------------- alerts */
.alert {
    padding: 12px 14px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: var(--surface);
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 12px;
    color: var(--text-2);
    line-height: 1.5;
}
.alert svg { width: 14px; height: 14px; flex-shrink: 0; margin-top: 2px; color: var(--text-3); }
.alert.ok   { border-color: rgba(34, 197, 94, 0.3);  background: var(--ok-dim);  color: var(--text); }
.alert.ok svg   { color: var(--ok); }
.alert.warn { border-color: rgba(245, 158, 11, 0.3); background: var(--warn-dim); color: var(--text); }
.alert.warn svg { color: var(--warn); }
.alert.err  { border-color: rgba(239, 68, 68, 0.3);  background: var(--err-dim); color: var(--text); }
.alert.err svg  { color: var(--err); }
.alert.info { border-color: rgba(167, 139, 250, 0.3); background: var(--amy-dim); color: #e9e5ff; }
.alert.info svg { color: var(--amy); }
.alert.is-hiding {
    opacity: 0;
    margin-bottom: 0 !important;
    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    overflow: hidden;
    transition:
        opacity 0.35s var(--easing),
        margin 0.35s var(--easing),
        max-height 0.35s var(--easing),
        padding 0.35s var(--easing);
}

/* ---------------------------------------------------------------- toast */
.toast {
    position: fixed;
    left: 50%;
    bottom: 28px;
    transform: translateX(-50%) translateY(18px);
    padding: 10px 16px;
    border-radius: var(--r-m);
    border: 1px solid var(--border);
    background: rgba(23, 23, 26, 0.9);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 12px;
    color: var(--text);
    opacity: 0;
    pointer-events: none;
    transition: all var(--dur-slow) var(--easing);
    z-index: 100;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.35);
}
.toast.show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
    pointer-events: auto;
}
.toast .toast-icon {
    width: 22px; height: 22px;
    border-radius: 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.toast.ok   .toast-icon { background: var(--ok-dim); color: var(--ok); }
.toast.err  .toast-icon { background: var(--err-dim); color: var(--err); }
.toast.warn .toast-icon { background: var(--warn-dim); color: var(--warn); }
.toast svg { width: 12px; height: 12px; }

/* ---------------------------------------------------------------- empty state */
.empty {
    padding: 40px 20px;
    text-align: center;
    color: var(--text-3);
    font-size: 13px;
}
.empty .empty-icon {
    width: 38px; height: 38px;
    margin: 0 auto 14px;
    border-radius: 10px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-ghost);
}
.empty h3 { font-size: 14px; font-weight: 600; margin-bottom: 6px; color: var(--text-2); }
.empty p  { font-size: 12px; color: var(--text-3); }

/* ---------------------------------------------------------------- divider */
.divider { height: 1px; background: var(--border); margin: 16px 0; }

/* ----------------------------------------------- iframe preview + zoom
   shared by /preview and /send. the iframe sits inside .preview-frame
   and we drive zoom by setting the css custom property `--scale` on the
   frame. the iframe is sized as `100% / scale` and visually scaled back
   down (or up) by `transform: scale(scale)`, so visually it always fills
   the wrapper at any zoom level — overflow becomes the iframe's own
   internal scroll. zoom range is clamped to 25%..200% by the toolbar. */
.preview-frame { --scale: 1; }

/* /preview historically inlined this; /send uses the same card shape — keep
   one definition so the preview column is a flex column everywhere. */
.rendered-card {
    display: flex;
    flex-direction: column;
    min-height: 0;
    position: relative;
}
.rendered-card .card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    flex-shrink: 0;
}
.rendered-card .card-head-actions {
    display: flex;
    align-items: center;
    gap: 10px;
}

.preview-frame > iframe.preview-iframe {
    flex: none;
    width: calc(100% / var(--scale, 1));
    height: calc(100% / var(--scale, 1));
    min-width: 100%;
    min-height: 100%;
    border: 0;
    display: block;
    transform: scale(var(--scale, 1));
    transform-origin: top left;
    background: #fff;
}

.zoom-toolbar {
    display: inline-flex;
    align-items: center;
    gap: 0;
    height: 26px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    background: var(--surface-2);
    overflow: hidden;
    user-select: none;
}
.zoom-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 100%;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--text-3);
    cursor: pointer;
    transition: background var(--dur-fast) var(--easing),
                color var(--dur-fast) var(--easing);
}
.zoom-btn:hover { background: rgba(255, 255, 255, 0.04); color: var(--text); }
.zoom-btn:active { background: rgba(255, 255, 255, 0.08); }
.zoom-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.zoom-btn svg { width: 12px; height: 12px; }
.zoom-value {
    display: inline-flex;
    align-items: baseline;
    height: 100%;
    padding: 0 4px;
    border-left: 1px solid var(--border);
    border-right: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-2);
    font-family: var(--mono);
    font-size: 11px;
}
.zoom-input {
    width: 32px;
    height: 100%;
    padding: 0 2px;
    border: 0;
    outline: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: right;
    -moz-appearance: textfield;
    appearance: textfield;
}
.zoom-input::-webkit-outer-spin-button,
.zoom-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.zoom-input:focus { color: var(--text); }
.zoom-suffix { color: var(--text-3); padding-left: 1px; }
.zoom-reset {
    height: 100%;
    padding: 0 8px;
    border: 0;
    border-left: 1px solid var(--border);
    background: transparent;
    color: var(--text-3);
    font-family: var(--mono);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    cursor: pointer;
    transition: background var(--dur-fast) var(--easing),
                color var(--dur-fast) var(--easing);
}
.zoom-reset:hover { background: rgba(255, 255, 255, 0.04); color: var(--text); }

/* native <details> styled to match the rest of the panel: a tight clickable
   header with a chevron that rotates on open. used to hide low-frequency
   form sections (sender/subject/spoof on /send) so the page fits in a
   single viewport without scrolling. */
.collapsible { display: block; }
.collapsible > summary { list-style: none; cursor: pointer; }
.collapsible > summary::-webkit-details-marker { display: none; }
.collapsible-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    background: var(--surface-2);
    transition: border-color var(--dur-fast) var(--easing),
                background var(--dur-fast) var(--easing);
}
.collapsible-head:hover { border-color: var(--border-hi); }
.collapsible-title {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-2);
    text-transform: uppercase;
    letter-spacing: 0.09em;
}
.collapsible-meta {
    font-size: 11px;
    flex: 1;
    color: var(--text-3);
}
.collapsible-chev {
    color: var(--text-3);
    transition: transform var(--dur-fast) var(--easing);
    flex-shrink: 0;
}
.collapsible[open] > summary .collapsible-chev { transform: rotate(180deg); }
.collapsible[open] > summary .collapsible-head {
    border-color: var(--border-hi);
    background: var(--surface);
}
.collapsible-body {
    margin-top: 12px;
    padding: 0 2px;  /* hairline so focus rings inside don't kiss the card edge */
    animation: collapsible-fade-in 160ms var(--easing);
}
@keyframes collapsible-fade-in {
    from { opacity: 0; transform: translateY(-2px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ---------------------------------------------------------------- tabs */
.tabs {
    display: flex;
    gap: 2px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 18px;
}
.tab {
    padding: 10px 14px;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-3);
    border-bottom: 2px solid transparent;
    cursor: pointer;
    transition: color var(--dur-fast) var(--easing), border-color var(--dur-fast) var(--easing);
    background: none;
    border-top: 0; border-left: 0; border-right: 0;
    font-family: inherit;
}
.tab:hover { color: var(--text-2); }
.tab.active {
    color: var(--text);
    border-bottom-color: var(--amy);
}

/* ---------------------------------------------------------------- animations */
@keyframes slideUp {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}
.animate-fade   { animation: fadeIn  0.35s var(--easing) backwards; }
.animate-slide  { animation: slideUp 0.35s var(--easing) backwards; }
.delay-1  { animation-delay: 0.05s; }
.delay-2  { animation-delay: 0.10s; }
.delay-3  { animation-delay: 0.15s; }
.delay-4  { animation-delay: 0.20s; }
.delay-5  { animation-delay: 0.25s; }

/* ---------------------------------------------------------------- login */
.login-shell {
    min-height: 100vh;
    min-height: 100svh;
    /* never use 100dvh / -webkit-fill-available here: on desktop edge they
       often resolve *above* innerHeight and both force a body scrollbar and
       kill vertical margin:auto centering (card pins to the top). */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 16px;
    padding-top: max(16px, env(safe-area-inset-top, 0px));
    padding-left: max(16px, env(safe-area-inset-left, 0px));
    padding-right: max(16px, env(safe-area-inset-right, 0px));
    padding-bottom: max(16px, env(safe-area-inset-bottom, 0px));
    position: relative;
    z-index: 1;
    overflow-y: auto;
}
/* tall login flows — pure vertical center would clip the top of the card */
@media (max-height: 720px) {
    .login-shell {
        justify-content: flex-start;
    }
}
.login-card {
    width: 100%;
    max-width: 440px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-xl);
    /* slightly roomier than the original, but no forced min-height (avoids a
       huge empty band on step 1 before a code is generated). */
    padding: 24px 26px 20px;
    animation: slideUp 0.5s var(--easing);
    position: relative;
    flex-shrink: 0;
    overflow: hidden;
}
.login-card::before {
    content: "";
    position: absolute;
    top: -40%; right: -30%;
    width: 300px; height: 300px;
    background: radial-gradient(circle, rgba(167, 139, 250, 0.12), transparent 60%);
    pointer-events: none;
}
.login-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
}
.login-brand {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    border: 0;
    background: transparent;
    user-select: none;
    -webkit-user-drag: none;
    cursor: pointer;
}
.login-brand-logo {
    display: block;
    height: 32px;
    width: auto;
    max-width: 78%;
    object-fit: contain;
    filter: none;
    transition: transform 220ms cubic-bezier(.2,.7,.2,1);
    -webkit-user-drag: none;
}
.login-brand:hover .login-brand-logo {
    filter: none;
    transform: translateY(-1px) scale(1.03);
}
.login-brand:active .login-brand-logo {
    transform: translateY(1px) scale(0.99);
    transition-duration: 80ms;
}
.login-brand:focus-visible {
    outline: 2px solid var(--amy);
    outline-offset: 4px;
    border-radius: 6px;
}
.login-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 8px;
    border-radius: 6px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    font-size: 9.5px;
    font-weight: 500;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-bottom: 8px;
}
.login-h1 {
    font-size: 20px;
    font-weight: 700;
    line-height: 1.12;
    letter-spacing: -0.04em;
    margin-bottom: 4px;
}
.login-h1 em { font-style: normal; color: inherit; }
.login-sub {
    font-size: 12.5px;
    color: var(--text-3);
    line-height: 1.45;
    margin-bottom: 14px;
}

/* large login code display */
.code-display {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin: 18px 0 14px;
}
.code-digit {
    width: 44px;
    height: 56px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--mono);
    font-size: 24px;
    font-weight: 700;
    color: var(--text);
    letter-spacing: 0;
}

/* timer ring (login code expiry) */
.timer-ring-wrap {
    position: relative;
    width: 48px; height: 48px;
    flex-shrink: 0;
}
.timer-ring-bg {
    fill: none;
    stroke: var(--border);
    stroke-width: 2;
}
.timer-ring-fill {
    fill: none;
    stroke: var(--amy);
    stroke-width: 2;
    stroke-linecap: round;
    opacity: 0.8;
    transform: rotate(-90deg);
    transform-origin: 50% 50%;
    transition: stroke-dashoffset 1s linear;
}
.timer-ring-value {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    font-family: var(--mono);
    font-size: 13px;
    font-weight: 600;
    color: var(--text-2);
}

/* ---------------------------------------------------------------- misc */
kbd {
    font-family: var(--mono);
    font-size: 10px;
    padding: 2px 6px;
    border-radius: 4px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--text-2);
}

.copy-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: none;
    border: none;
    color: var(--text-3);
    cursor: pointer;
    font-size: 11px;
    padding: 2px 4px;
    border-radius: 4px;
    transition: color var(--dur-fast) var(--easing), background var(--dur-fast) var(--easing);
}
.copy-btn:hover { color: var(--text); background: rgba(255, 255, 255, 0.03); }

/* badge for role/status inline with text */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 10px;
    font-weight: 500;
    text-transform: lowercase;
    letter-spacing: 0.02em;
    background: var(--surface-2);
    color: var(--text-3);
    border: 1px solid var(--border);
}
.badge.amy { background: var(--amy-dim); color: var(--amy); border-color: rgba(167, 139, 250, 0.25); }
.badge.ok  { background: var(--ok-dim);  color: var(--ok);  border-color: rgba(34, 197, 94, 0.25); }
.badge.warn{ background: var(--warn-dim);color: var(--warn);border-color: rgba(245, 158, 11, 0.25); }
.badge.err { background: var(--err-dim); color: var(--err); border-color: rgba(239, 68, 68, 0.25); }
.badge.team-owner {
    background: var(--cyan-dim);
    color: var(--cyan);
    border-color: var(--cyan-ring);
}

/* ==================================================================
   notifications system: bell, popover, page rows, dashboard card,
   admin announce flow (chooser, telegram, panel).
   ================================================================== */

/* ---- topbar bell + popover ---------------------------------------- */
.notif-wrap {
    position: relative;
}

.bell-btn {
    position: relative;
    width: 34px;
    height: 34px;
    border-radius: var(--r-s);
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-3);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color var(--dur-fast) var(--easing),
                border-color var(--dur-fast) var(--easing),
                background var(--dur-fast) var(--easing);
}
.bell-btn svg { width: 16px; height: 16px; }
.bell-btn:hover {
    color: var(--text);
    border-color: var(--border-hi);
    background: rgba(255, 255, 255, 0.025);
}
.bell-btn.has-unread { color: var(--amy); border-color: var(--amy-ring); }
.notif-wrap.is-open .bell-btn {
    color: var(--text);
    border-color: var(--amy-ring);
    background: var(--amy-dim);
}

.bell-dot {
    position: absolute;
    top: -4px;
    right: -4px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background: linear-gradient(135deg, var(--amy-lo), var(--amy));
    color: #fff;
    font-size: 9px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    box-shadow: 0 0 0 2px var(--bg);
    pointer-events: none;
}

.notif-popover {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    width: 360px;
    max-width: calc(100vw - 24px);
    background: var(--surface);
    border: 1px solid var(--border-hi);
    border-radius: var(--r-m);
    box-shadow: 0 14px 40px rgba(0, 0, 0, 0.55), 0 2px 6px rgba(0, 0, 0, 0.3);
    z-index: 50;
    overflow: hidden;
    animation: notif-pop-in var(--dur-fast) var(--easing);
}
.notif-popover[hidden] { display: none; }

@keyframes notif-pop-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

.notif-pop-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    border-bottom: 1px solid var(--border);
}
.notif-pop-title {
    font-size: 12px;
    font-weight: 600;
    color: var(--text);
}
.notif-unread-tag {
    font-size: 10px;
    color: var(--amy);
    background: var(--amy-dim);
    border: 1px solid var(--amy-ring);
    padding: 2px 6px;
    border-radius: 4px;
    text-transform: lowercase;
}

/* carded list — each notification gets its own framed pill so the severity
   left-bar never bleeds to the popover edges. mirrors the dashboard's
   .dash-notif-list look so both views feel like the same component. */
.notif-list {
    list-style: none;
    margin: 0;
    padding: 8px 8px;
    max-height: min(380px, 55vh);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
    /* auto: no gutter when content fits (OS may still overlay when overflowing). */
    scrollbar-gutter: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border-hi) transparent;
    /* same soft top/bottom fade as .dash-notif-list — partial cards
       dissolve into the popover chrome on scroll instead of looking
       abruptly clipped. */
    mask-image: linear-gradient(
        to bottom,
        transparent 0,
        black 10px,
        black calc(100% - 10px),
        transparent 100%
    );
    -webkit-mask-image: linear-gradient(
        to bottom,
        transparent 0,
        black 10px,
        black calc(100% - 10px),
        transparent 100%
    );
}
.notif-list::-webkit-scrollbar {
    width: 6px;
}
.notif-list::-webkit-scrollbar-track {
    background: transparent;
}
.notif-list::-webkit-scrollbar-thumb {
    background: var(--border-hi);
    border: 0;
    border-radius: 3px;
}

/* bell popover: on mouse, keep a fixed 6px scrollbar *lane* always so hover
   only reveals the thumb — toggling width 0→6px reflowed cards/text. */
@media (hover: hover) and (pointer: fine) {
    .notif-popover-inner .notif-list {
        scrollbar-width: thin;
        scrollbar-color: transparent transparent;
    }
    .notif-popover-inner .notif-list::-webkit-scrollbar {
        width: 6px;
    }
    .notif-popover-inner .notif-list::-webkit-scrollbar-track {
        background: transparent;
    }
    .notif-popover-inner .notif-list::-webkit-scrollbar-thumb {
        background: transparent;
        border-radius: 3px;
    }
    .notif-popover-inner:hover .notif-list {
        scrollbar-color: var(--border-hi) transparent;
    }
    .notif-popover-inner:hover .notif-list::-webkit-scrollbar-thumb {
        background: var(--border-hi);
    }
}
.notif-row {
    display: flex;
    gap: 10px;
    padding: 9px 11px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    transition: background var(--dur-fast) var(--easing),
                border-color var(--dur-fast) var(--easing);
}
.notif-row:hover { background: rgba(255, 255, 255, 0.035); }

.notif-dot {
    flex: 0 0 6px;
    width: 6px;
    height: 6px;
    margin-top: 7px;
    border-radius: 50%;
    background: var(--text-ghost);
}
.notif-row.notif-unread .notif-dot { background: var(--amy); box-shadow: 0 0 0 3px var(--amy-dim); }
.notif-row.sev-success .notif-dot { background: var(--ok); }
.notif-row.sev-warn    .notif-dot { background: var(--warn); }
.notif-row.sev-critical .notif-dot { background: var(--err); }
.notif-row.notif-unread.sev-success .notif-dot { box-shadow: 0 0 0 3px var(--ok-dim); }
.notif-row.notif-unread.sev-warn    .notif-dot { box-shadow: 0 0 0 3px var(--warn-dim); }
.notif-row.notif-unread.sev-critical .notif-dot { box-shadow: 0 0 0 3px var(--err-dim); }
/* purple outline + faint tint on unread popover rows. now that each row is a
   real bordered card we just swap the border-color (no more inset ring hack)
   and keep the right-falloff gradient anchored to the left accent bar. */
.notif-row.notif-unread {
    background: linear-gradient(to right,
        rgba(167, 139, 250, 0.10),
        rgba(167, 139, 250, 0.02) 70%,
        var(--surface-2));
    border-color: var(--amy-ring);
}
.notif-row.notif-unread:hover {
    background: linear-gradient(to right,
        rgba(167, 139, 250, 0.14),
        rgba(167, 139, 250, 0.04) 70%,
        var(--surface-2));
}

.notif-body { flex: 1 1 auto; min-width: 0; }
.notif-row-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
}
.notif-row-title {
    font-weight: 600;
    font-size: 12px;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.notif-row.notif-unread .notif-row-title { color: var(--text); }
.notif-row:not(.notif-unread) .notif-row-title { color: var(--text-2); font-weight: 500; }
.notif-row-time {
    font-size: 10px;
    color: var(--text-3);
    white-space: nowrap;
    flex-shrink: 0;
}
.notif-row-text {
    font-size: 11px;
    color: var(--text-2);
    line-height: 1.45;
    margin: 4px 0 6px;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.notif-row-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 10px;
    color: var(--text-3);
}
.notif-mark {
    margin-left: auto;
    background: none;
    border: none;
    color: var(--amy);
    font-size: 10px;
    cursor: pointer;
    padding: 0;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.notif-mark:hover { color: var(--amy-hi); }

.notif-pop-foot {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    border-top: 1px solid var(--border);
    background: var(--surface-2);
}

.notif-empty {
    text-align: center;
    padding: 36px 16px;
    color: var(--text-3);
}
.notif-empty p { font-size: 12px; color: var(--text-2); margin: 8px 0 4px; }
.notif-empty-icon { color: var(--text-ghost); margin-bottom: 4px; }

/* ---- brand icons -------------------------------------------------- */
/* small folder logo tile shown next to a folder name across the panel
   (dashboard recent sends, /history rows, /preview folder badge,
   /stats top folders, etc). files live under /static/icons/brands/:
     - {folder}.png  full-color official brand logo (apple-touch-icon
       or google favicon, downscaled to 64px — see fetch_brand_logos.ps1)
     - {folder}.svg  colored monogram fallback for non-brand folders
       (banking, independent, mobile, etc) — see gen_monograms.ps1
   the macro in partials/brand_icon.html tries .png first, falls back
   to .svg via onerror, then hides on second failure. */
.brand-icon {
    display: inline-block;
    width: 16px;
    height: 16px;
    border-radius: 4px;
    vertical-align: middle;
    flex-shrink: 0;
    object-fit: contain;
    /* force crisp scaling from the 64px source even when downsized on
       low-dpi screens. pairs well with PNGs that have transparent bg. */
    image-rendering: -webkit-optimize-contrast;
}
.brand-icon.sm { width: 14px; height: 14px; border-radius: 3px; }
.brand-icon.md { width: 18px; height: 18px; }
.brand-icon.lg { width: 22px; height: 22px; border-radius: 5px; }
.brand-icon.xl { width: 28px; height: 28px; border-radius: 6px; }
/* tight wrapper used when we want the icon to sit inline with text without
   the text baseline shifting. gap matches the panel's typical 14px row
   rhythm so rows don't feel crowded. */
.brand-cell {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    /* match the combobox option's vertical geometry. in .fc-option the
       text runs at 13px / 1.5 ≈ 19.5px line-box, TALLER than the 18px
       icon — flex then parks the icon inside the text's line-box and
       the glyphs' natural middle lands next to the icon's geometric
       middle. history/dashboard rows are 12px / 1.4 (= 16.8px line-box)
       which is SHORTER than the icon, so flex centres two mismatched
       boxes and the glyphs read as "high". bumping line-height to
       1.625 keeps the 12px font (so the row's font-size stays
       consistent with the rest of the table) but produces a 19.5px
       line-box that mirrors the combobox's icon-fits-inside-text-box
       relationship exactly. */
    line-height: 1.625;
}
/* the `.cell-scroll` child carries its own `line-height: 1.4` from the
   generic table-row scroller, which would override the cell's setting
   and put us back in the mismatched-box case. force it to inherit. bare
   <span> children (team top-folder card) are included for symmetry. */
.brand-cell > .cell-scroll,
.brand-cell > span:not(.brand-cell-label) {
    line-height: inherit;
}
/* final optical nudge — even after matching the combobox's line-box
   geometry, DM Sans renders mixed-case glyphs with a visible middle
   that sits ~2px above the em-box centre (the font reserves more space
   above the baseline for ascenders than below for descenders). a
   solid-filled brand png/svg centres on its geometric middle, so flex
   alone can't compensate — pulling the icon up 2px with a balanced
   top/bottom margin (so row height is unchanged) brings the icon's
   centre onto the glyphs' optical centre. margin is used instead of
   transform so the icon doesn't sub-pixel blur on non-hidpi screens. */
.brand-cell > .brand-icon {
    margin-top: -2px;
    margin-bottom: 2px;
}
.brand-cell-label { min-width: 0; }

/* ---- folder combobox (custom <select> replacement) ---------------- */
/* native <select> can't render icons next to option labels, so folder
   pickers (send / preview / history / sender) use this custom button +
   popover. the button is styled to match .select so surrounding form
   layouts don't need changes; the popover is a lightweight, JS-driven
   listbox that shows the brand icon alongside each folder name and
   supports typeahead filtering + keyboard navigation.
   behaviour + aria wiring live in /static/js/combobox.js. */
.fc-combobox {
    position: relative;
    width: 100%;
}
.fc-button {
    /* mirrors .input/.select exactly so it sits flush next to other
       form controls without layout drift. */
    width: 100%;
    padding: 10px 36px 10px 12px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text);
    font-family: var(--font);
    font-size: 13px;
    line-height: 1.4;
    text-align: left;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;
    transition: border-color var(--dur-fast) var(--easing),
                box-shadow var(--dur-fast) var(--easing),
                background var(--dur-fast) var(--easing);
    /* embed the same chevron as .select so the control reads as a
       dropdown at a glance. stroke color matches --text-3 (#71717a). */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 12px;
}
.fc-button:focus,
.fc-combobox.is-open > .fc-button {
    outline: none;
    border-color: var(--amy);
    box-shadow: 0 0 0 3px var(--amy-ring);
    background-color: var(--surface-3);
}
.fc-value {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    flex: 1;
}
/* placeholder state paints the button face + its listbox row with the
   same --text color as real values — this matches how native <select>s
   render their first "— pick … —" option (no dimming) and avoids the
   button text looking grey-washed against a white selected-folder name. */
/* the button face is painted by cloning the active option's html, and the
   placeholder option would otherwise carry an empty icon span that eats a
   ~30px gutter. collapse it so the text sits flush-left like a plain
   <select> placeholder, and do the same inside the listbox row so the
   two "— pick folder —" lines line up across the button and the menu. */
.fc-value.is-placeholder .brand-icon,
.fc-option[data-placeholder] .brand-icon { display: none; }
.fc-value-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* combobox icons need more pixels than the 14px .brand-icon.sm default —
   at that size, dense svgs (coinbase's open C, apple's silhouette) blur
   into a solid blob because the 48-unit viewBox is downsampled below one
   stroke width. 20px in the button face + 18px in the options preserves
   brand detail without inflating control height. */
.fc-button .brand-icon {
    width: 20px;
    height: 20px;
    border-radius: 5px;
    margin-top: -1px;
}
.fc-option .brand-icon {
    width: 18px;
    height: 18px;
    border-radius: 4px;
}

.fc-menu {
    position: absolute;
    z-index: 40;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    background: var(--surface-2);
    border: 1px solid var(--border-hi);
    border-radius: var(--r-s);
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.45);
    padding: 6px;
    /* cap at ~560px on tall screens, but always leave ~160px of chrome
       (topbar + breathing room) so the popover doesn't clip the bottom
       of the viewport on smaller displays. at 560px we get ~15 option
       rows visible before scrolling, which was what "make it roughly
       double" worked out to in practice. */
    max-height: min(560px, calc(100vh - 160px));
    display: flex;
    flex-direction: column;
    gap: 6px;
}
/* `display: flex` above silently overrides the browser's UA rule for the
   [hidden] attribute (both live at the same specificity; author wins), so
   without this explicit override the popover is always visible and can
   never be closed. keep this immediately after the `.fc-menu` block so
   anyone reading the rules sees the pair together. */
.fc-menu[hidden] { display: none; }

/* FA mailer folder picker — open above the button, escape scroll clipping. */
.fc-combobox--dropup.is-open .fc-menu {
    top: auto;
    bottom: auto;
}

#fa-compose-panel .send-layout > .card {
    overflow: visible;
}

.fc-combobox--dropup > .fc-button {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='18 15 12 9 6 15'/%3E%3C/svg%3E");
}

.fc-search {
    width: 100%;
    padding: 7px 10px;
    border-radius: var(--r-xs);
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-family: var(--font);
    font-size: 12px;
    outline: none;
}
.fc-search:focus {
    border-color: var(--amy);
    box-shadow: 0 0 0 2px var(--amy-ring);
}
.fc-options {
    list-style: none;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    /* let .fc-menu cap the height; options fill whatever vertical room
       is left after the search input + gap. flex:1 + min-height:0 is the
       standard incantation for a scrolling flex child inside a capped
       parent, otherwise the ul ignores the parent's max-height. */
    flex: 1;
    min-height: 0;
}
.fc-option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border-radius: var(--r-xs);
    font-size: 13px;
    color: var(--text);
    cursor: pointer;
    user-select: none;
    min-width: 0;
}
.fc-option[hidden] { display: none; }
.fc-option.is-active { background: rgba(255, 255, 255, 0.05); }
.fc-option.is-selected {
    /* highlight the currently-chosen value so users can spot it when
       the popover is long — matches the amethyst accent used elsewhere
       (sidebar active row, .tpl.active, etc). */
    background: var(--amy-dim);
    color: var(--amy);
}
.fc-option.is-selected.is-active { background: color-mix(in oklab, var(--amy) 22%, transparent); }
.fc-option-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* the placeholder row reads as "nothing picked" thanks to the em-dash
   label ("— pick folder —"). the /history filter reuses the same slot
   for a legitimate "all folders" pick, so we keep the row styled like
   any other option instead of muting/italicising it. */
.fc-option[data-placeholder] .brand-icon { visibility: hidden; }

/* ---- /notifications full page ------------------------------------- */
/* the notifications page has almost no surrounding chrome (just the
   page title), so allow the card to grow naturally with its content
   and only cap + scroll once it would exceed the viewport. this
   avoids the generic .scroll-region.tall sizing (tuned for list pages
   with filter bars + card heads + footers) which leaves awkward
   empty space below the last row when there are only a few rows. */
.notif-page-card .scroll-region.notif-page-scroll {
    /* ~page-head (≈76px) + main padding (28+48) + breathing room */
    max-height: calc(100vh - 200px);
}
.notif-page-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.notif-page-row {
    display: flex;
    gap: 14px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--border);
}
.notif-page-row:last-child { border-bottom: 0; }
.notif-page-left { flex: 0 0 auto; padding-top: 7px; }
.notif-page-body { flex: 1 1 auto; min-width: 0; }
.notif-page-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 4px;
}
.notif-page-title { font-size: 13px; color: var(--text); }
.notif-page-row:not(.notif-unread) .notif-page-title {
    color: var(--text-2);
    font-weight: 500;
}
.notif-page-text {
    font-size: 12px;
    color: var(--text-2);
    line-height: 1.55;
    margin: 0 0 8px;
    white-space: pre-wrap;
}
.notif-page-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11px;
    color: var(--text-3);
}

/* ---- /sender inline-edit grid ------------------------------------- */
/* replaces the old <table> + bottom "add or update" form combo with
   one grid where every folder is an always-editable row. each row is
   its own <form> so Enter submits just that row; clear reuses the row
   form via `formaction` on the clear button. */
.sender-list {
    display: flex;
    flex-direction: column;
}
.sender-row {
    /* folder name | sender name | sender email | subject | actions.
       the three editable fields get identical `1fr` tracks so each
       input renders at the same visible width — even though emails
       and subjects tend to hold longer values, equal tracks read as
       a cleaner grid. min-width:0 on children (set per-class below)
       lets the inputs actually shrink inside their grid cells
       instead of pushing the row wider than the scroll region. */
    display: grid;
    grid-template-columns:
        minmax(140px, 0.8fr)
        minmax(180px, 1fr)
        minmax(180px, 1fr)
        minmax(180px, 1fr)
        auto;
    align-items: center;
    gap: 12px;
    padding: 8px 16px;
    border-bottom: 1px solid var(--border);
}
.sender-row:last-child { border-bottom: 0; }
/* sticky header row — mirrors the generic .table thead look so users
   who know the panel's list pages read it the same way. positioned
   sticky so long folder lists don't scroll the column names away. */
.sender-row-head {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--surface);
    padding: 10px 16px;
    font-weight: 500;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 10px;
    box-shadow: inset 0 -1px 0 var(--border);
    border-bottom: 0;
}
.sender-folder {
    font-size: 12px;
    color: var(--text);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* compact input styling — the generic .input is tuned for form pages
   (13px font, 10/12 padding, 88px min-height on textarea) which is
   way too chunky for a list of 30+ rows. tighten everything to match
   the table row rhythm so rows stay near 40px tall. */
.sender-input {
    padding: 6px 10px;
    font-size: 12px;
    line-height: 1.35;
    min-width: 0;
    /* .input sets width:100% already, but grid track can still be
       narrow so make sure the input respects its grid cell's width
       instead of its own intrinsic content width. */
    width: 100%;
}
.sender-input.mono { font-family: var(--mono); letter-spacing: 0; }
.sender-actions {
    display: inline-flex;
    gap: 6px;
    justify-self: end;
    white-space: nowrap;
}
.sender-actions .btn {
    padding: 6px 10px;
    font-size: 11px;
}
.sender-actions .btn[disabled] {
    opacity: 0.4;
    cursor: not-allowed;
    /* keep hover styles from flashing when the button is inert, and
       stop accidental click-through from firing a redundant clear. */
    pointer-events: none;
}
/* the /sender list is the only card on the page now (no bottom
   add/update form eating ~240px), so let the scroll region take
   most of the viewport height. the subtraction covers topbar (60)
   + main padding top/bottom (76) + page-head (~100) + card-head (50)
   + ~30px breathing room so the card always ends cleanly above the
   fold instead of spawning a page-level scrollbar on short viewports. */
.sender-scroll {
    max-height: max(340px, calc(100vh - 320px));
}

/* hover-reveal scrollbar — mirrors .dash-notif-list on the dashboard.
   on mouse devices the track stays transparent (no visual noise while
   the user's focus is elsewhere on the page) and only the thumb
   appears once the pointer is inside the sender card. the 6px gutter
   is reserved at all times so revealing the thumb doesn't reflow the
   sender rows. touch/coarse-pointer devices keep the default native
   bar since "hover" isn't meaningful there. */
@media (hover: hover) and (pointer: fine) {
    .sender-scroll {
        scrollbar-width: thin;
        scrollbar-color: transparent transparent;
        transition: scrollbar-color var(--dur-fast) var(--easing);
    }
    .sender-scroll::-webkit-scrollbar {
        width: 6px;
    }
    .sender-scroll::-webkit-scrollbar-track {
        background: transparent;
    }
    .sender-scroll::-webkit-scrollbar-thumb {
        background: transparent;
        border-radius: 3px;
        transition: background var(--dur-fast) var(--easing);
    }
    /* :has() scopes the reveal to the card containing .sender-scroll
       so we don't accidentally change scrollbar behaviour on other
       .card elements elsewhere in the panel. */
    .card:has(.sender-scroll):hover .sender-scroll {
        scrollbar-color: var(--border-hi) transparent;
    }
    .card:has(.sender-scroll):hover .sender-scroll::-webkit-scrollbar-thumb {
        background: var(--border-hi);
    }
}

/* ---- dashboard notifications card --------------------------------- */
.dash-notif-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    /* cap the list so the "view all" button stays visible even when the
       feed is long. the user can scroll inside the list to reach older
       items instead of being forced through /notifications. matches the
       bell popover's UX. small right padding keeps the unread left-bar
       from kissing the scrollbar gutter. */
    max-height: min(360px, 50vh);
    overflow-y: auto;
    padding-right: 4px;
    scrollbar-gutter: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border-hi) transparent;
    /* soft fade only at the *top* edge so a half-scrolled card dissolves
       into the card chrome on scroll. no bottom fade — the last visible
       card meets the "view all" button cleanly with a crisp border. */
    mask-image: linear-gradient(
        to bottom,
        transparent 0,
        black 10px,
        black 100%
    );
    -webkit-mask-image: linear-gradient(
        to bottom,
        transparent 0,
        black 10px,
        black 100%
    );
}

/* full-width CTA used by both team and notif cards on the dashboard. */
.dash-card-cta {
    width: 100%;
    justify-content: center;
    margin-top: 14px;
}
/* pin the CTA to the bottom edge of its card so "view all" lines up
   with "manage team" when the two cards share a grid row height.
   without this the notifications card (which has less content than
   the team card's activity-tiles + top-folder) ends up with "view
   all" floating mid-card while team's button sits at the bottom. */
#dash-team-card,
#dash-notif-card {
    display: flex;
    flex-direction: column;
}
#dash-team-card > .dash-card-cta,
#dash-notif-card > .dash-card-cta,
#dash-notif-card > .dash-notif-actions {
    margin-top: auto;
}
#dash-team-card > *:has(+ .dash-card-cta),
#dash-notif-card > *:has(+ .dash-card-cta),
#dash-notif-card > .dash-notif-list:has(+ .dash-notif-actions) {
    margin-bottom: 14px;
}
#dash-notif-card .dash-notif-list {
    flex: 1 1 0;
    min-height: 0;
    max-height: none;
}
.dash-notif-list::-webkit-scrollbar {
    width: 6px;
}
.dash-notif-list::-webkit-scrollbar-track {
    background: transparent;
}
.dash-notif-list::-webkit-scrollbar-thumb {
    background: var(--border-hi);
    border: 0;
    border-radius: 3px;
}

@media (hover: hover) and (pointer: fine) {
    #dash-notif-card .dash-notif-list {
        scrollbar-width: thin;
        scrollbar-color: transparent transparent;
    }
    #dash-notif-card .dash-notif-list::-webkit-scrollbar {
        width: 6px;
    }
    #dash-notif-card .dash-notif-list::-webkit-scrollbar-track {
        background: transparent;
    }
    #dash-notif-card .dash-notif-list::-webkit-scrollbar-thumb {
        background: transparent;
        border-radius: 3px;
    }
    #dash-notif-card:hover .dash-notif-list {
        scrollbar-color: var(--border-hi) transparent;
    }
    #dash-notif-card:hover .dash-notif-list::-webkit-scrollbar-thumb {
        background: var(--border-hi);
    }
}
.dash-notif-row {
    display: flex;
    gap: 8px;
    padding: 10px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
}
.dash-notif-row.notif-unread { border-color: var(--amy-ring); }
.dash-notif-row .notif-dot { margin-top: 6px; }
.dash-notif-row.sev-success .notif-dot { background: var(--ok); }
.dash-notif-row.sev-warn    .notif-dot { background: var(--warn); }
.dash-notif-row.sev-critical .notif-dot { background: var(--err); }
/* purple "unread" dot — mirrors the bell popover so both views match. */
.dash-notif-row.notif-unread .notif-dot {
    background: var(--amy);
    box-shadow: 0 0 0 3px var(--amy-dim);
}
.dash-notif-row.notif-unread.sev-success  .notif-dot { box-shadow: 0 0 0 3px var(--ok-dim); background: var(--ok); }
.dash-notif-row.notif-unread.sev-warn     .notif-dot { box-shadow: 0 0 0 3px var(--warn-dim); background: var(--warn); }
.dash-notif-row.notif-unread.sev-critical .notif-dot { box-shadow: 0 0 0 3px var(--err-dim); background: var(--err); }
.dash-notif-body { flex: 1 1 auto; min-width: 0; }
.dash-notif-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
}
.dash-notif-head strong {
    font-size: 12px;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dash-notif-row:not(.notif-unread) .dash-notif-head strong { color: var(--text-2); font-weight: 500; }
.dash-notif-text {
    font-size: 11px;
    line-height: 1.4;
    color: var(--text-3);
    margin: 4px 0 0;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.dash-notif-meta {
    display: flex;
    justify-content: flex-end;
    margin-top: 6px;
}

/* ---- team mini-stats inside the team card ------------------------- */
.team-mini-stats {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px dashed var(--border);
}
.team-mini-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}
.team-mini-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-3);
    font-weight: 600;
}
.team-mini-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
}
.team-mini-tile {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    padding: 8px 6px;
    text-align: center;
}
.team-mini-value {
    font-family: var(--mono);
    font-size: 16px;
    font-weight: 700;
    color: var(--text);
    line-height: 1.1;
    text-shadow: none;
}
.team-mini-cap {
    font-size: 9px;
    color: var(--text-3);
    text-transform: lowercase;
    margin-top: 2px;
}
.team-mini-rows {
    margin-top: 10px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.team-mini-line {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    line-height: 1.3;
    color: var(--text-2);
}
.team-mini-line .mono { font-family: var(--mono); color: var(--text); }

/* featured "top folder" tile — sits below the 3-up activity grid and gets
   more breathing room so it reads as the headline takeaway of the section.
   intentionally clean dark surface (no gradient/glow) to match the other
   stat tiles in this card. */
.team-top-folder {
    margin-top: 10px;
    padding: 10px 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
}
.team-top-folder-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 6px;
}
.team-top-folder-icon {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 9.5px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-3);
    font-weight: 600;
    text-shadow: none;
}
.team-top-folder-icon svg {
    color: var(--amy);
    filter: none;
}
.team-top-folder-count {
    font-size: 10px;
    color: var(--text-3);
    white-space: nowrap;
}
.team-top-folder-name {
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
    line-height: 1.2;
    letter-spacing: -0.01em;
    word-break: break-word;
    text-shadow: none;
}

/* ---- admin announce: choose page two-col grid --------------------- */
.dash-grid.two {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}
@media (max-width: 900px) {
    .dash-grid.two { grid-template-columns: 1fr; }
    .dash-grid.two > :nth-child(3) { grid-column: auto; }
}

.choice-card {
    cursor: pointer;
    transition: border-color var(--dur-fast) var(--easing),
                transform var(--dur-fast) var(--easing),
                background var(--dur-fast) var(--easing);
    color: var(--text);
}
.choice-card:hover {
    border-color: var(--amy-ring);
    transform: translateY(-1px);
    background: var(--amy-dim);
}
.choice-icon {
    width: 48px;
    height: 48px;
    border-radius: var(--r-s);
    background: var(--surface-2);
    border: 1px solid var(--border);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 12px;
}
.choice-tags { display: flex; flex-wrap: wrap; gap: 6px; }

/* ---- admin announce: shared form bits ----------------------------- */
.audience-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}
.audience-grid.four {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 720px) {
    .audience-grid,
    .audience-grid.four { grid-template-columns: 1fr; }
}
.audience-opt {
    cursor: pointer;
    position: relative;
    display: block;
}
.audience-opt input { position: absolute; opacity: 0; pointer-events: none; }
.audience-card {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 10px 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    transition: border-color var(--dur-fast) var(--easing),
                background var(--dur-fast) var(--easing);
}
.audience-card strong { font-size: 12px; color: var(--text); font-weight: 600; }
.audience-opt:hover .audience-card { border-color: var(--border-hi); }
.audience-opt input:checked ~ .audience-card {
    border-color: var(--amy);
    background: var(--amy-dim);
    box-shadow: inset 0 0 0 1px var(--amy-ring);
}
.audience-opt.sev-success input:checked ~ .audience-card { border-color: var(--ok); background: var(--ok-dim); box-shadow: inset 0 0 0 1px rgba(34,197,94,0.25); }
.audience-opt.sev-warn    input:checked ~ .audience-card { border-color: var(--warn); background: var(--warn-dim); box-shadow: inset 0 0 0 1px rgba(245,158,11,0.25); }
.audience-opt.sev-critical input:checked ~ .audience-card { border-color: var(--err); background: var(--err-dim); box-shadow: inset 0 0 0 1px rgba(239,68,68,0.25); }

.recipient-count {
    padding: 10px 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    font-size: 12px;
    min-height: 38px;
    display: flex;
    align-items: center;
}

.reason-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.reason-list li {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    font-size: 11px;
}
.reason-count {
    font-family: var(--mono);
    font-weight: 700;
    color: var(--err);
    min-width: 24px;
    text-align: right;
}
.reason-label { color: var(--text-2); }

.failure-log {
    max-height: 260px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
}
.failure-log .table { margin: 0; }
.failure-log .table th { position: sticky; top: 0; background: var(--surface-2); z-index: 1; }

.recent-notif-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 480px;
    overflow-y: auto;
}
.recent-notif {
    padding: 10px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
}

/* severity row tinting (subtle left border accent) */
.sev-row {
    border-left: 3px solid var(--text-ghost);
    padding-left: 8px;
}
.sev-row.sev-info     { border-left-color: var(--text-ghost); }
.sev-row.sev-success  { border-left-color: var(--ok); }
.sev-row.sev-warn     { border-left-color: var(--warn); }
.sev-row.sev-critical { border-left-color: var(--err); }
/* unread always wins the left accent — purple thick bar regardless of severity,
   so unread rows read as "new" everywhere (dashboard card + bell popover). */
.sev-row.notif-unread { border-left-color: var(--amy); }
/* dash-notif-row already has its own padding/border, only override the accent */
.dash-notif-row.sev-row { padding-left: 10px; }
.recent-notif.sev-row   { padding-left: 10px; }
.notif-page-row.sev-row { padding-left: 13px; }
/* popover rows are carded too — keep the left accent flush to the inner edge */
.notif-row.sev-row      { padding-left: 9px; }

/* ===== dev-mode login card (PANEL_DEV_LOGIN_UID(S)) ===== */
.dev-mode-card {
    margin-top: 12px;
    padding: 10px 12px 11px;
    border: 1px dashed var(--border);
    border-radius: var(--r-m);
    background: var(--surface-2);
}
.dev-mode-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}
.dev-mode-tag {
    display: inline-block;
    font-size: 9px;
    font-weight: 600;
    color: var(--warn);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    padding: 2px 7px;
    border: 1px solid var(--warn);
    border-radius: 999px;
    flex-shrink: 0;
}
.dev-mode-hint {
    flex: 1;
    font-size: 10px;
    line-height: 1.4;
    color: var(--text-3);
}
.dev-mode-list {
    display: grid;
    gap: 6px;
}
.dev-mode-btn {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    background: var(--surface-1);
    color: var(--text);
    text-decoration: none;
    font-size: 12px;
    transition: border-color .15s, background .15s, transform .05s;
}
.dev-mode-btn:hover {
    border-color: var(--amy);
    background: var(--surface-3, var(--surface-1));
}
.dev-mode-btn:active { transform: translateY(1px); }
.dev-mode-role {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 9px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 3px 7px;
    border-radius: 999px;
}
.dev-mode-btn.is-admin .dev-mode-role {
    color: var(--amy);
    background: rgba(155, 81, 224, 0.12);
}
.dev-mode-btn.is-user .dev-mode-role {
    color: var(--ok);
    background: rgba(46, 196, 132, 0.12);
}
.dev-mode-meta {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
}
.dev-mode-meta strong {
    font-size: 12px;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex-shrink: 1;
}
.dev-mode-uid {
    font-size: 10px;
    color: var(--text-3);
    white-space: nowrap;
}
.dev-mode-team {
    font-size: 10px;
    color: var(--text-3);
    padding: 2px 7px;
    border: 1px solid var(--border);
    border-radius: 999px;
    white-space: nowrap;
}

/* ── /send auto-fill banner + per-field tag ─────────────────────── */
.autofill-banner {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    margin-bottom: 12px;
    border-radius: var(--r-s);
    background: var(--amy-dim);
    border: 1px solid var(--amy-ring);
    color: var(--amy);
    font-size: 11.5px;
}
.autofill-banner svg { width: 13px; height: 13px; flex: 0 0 auto; }
.autofill-banner strong { color: var(--text); font-weight: 600; }
.autofill-tag {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--amy);
    background: var(--amy-dim);
    border: 1px solid var(--amy-ring);
    border-radius: 999px;
    vertical-align: middle;
    font-weight: 600;
}

/* ── /send image dropzone ────────────────────────────────────────────
   replaces the old `.file` label-style file input with a roomy,
   drag-and-droppable / click / ctrl+v paste zone. the actual file
   input is visually hidden (opacity:0 + sized 1px) so its native
   click/keyboard behavior still works inside the zone label without
   intercepting drag events. */
.dropzone {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 130px;
    padding: 18px 16px;
    border: 1.5px dashed var(--border-hi);
    border-radius: var(--r-m);
    background: var(--surface-2);
    color: var(--text-3);
    cursor: pointer;
    text-align: center;
    transition: border-color var(--d-1) var(--e-out),
                background var(--d-1) var(--e-out),
                color var(--d-1) var(--e-out);
    outline: none;
}
.dropzone:hover,
.dropzone:focus-visible {
    border-color: var(--amy);
    background: color-mix(in oklab, var(--amy) 6%, var(--surface-2));
    color: var(--text-2);
}
.dropzone.is-dragover {
    border-color: var(--amy);
    background: color-mix(in oklab, var(--amy) 14%, var(--surface-2));
    color: var(--text);
}
.dropzone.is-filled {
    cursor: default;
    text-align: left;
    align-items: stretch;
    border-style: solid;
    background: var(--surface-2);
}
/* the file input is a transparent overlay that sits on top of the
   visual dropzone content. clicking anywhere on the dashed area is
   literally clicking the <input type="file">, so the os file picker
   opens without any js / label-association indirection. */
.dz-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
    z-index: 3;
    border: 0;
    padding: 0;
    margin: 0;
    /* hide the actual file input chrome (e.g. "no file selected" text)
       in browsers that still render it under opacity:0 in some edge cases */
    font-size: 0;
    color: transparent;
}
.dropzone.is-filled .dz-input { cursor: pointer; }
/* the visual layers in both states must NOT capture pointer events —
   they sit beneath the transparent file input overlay (z-index:3) and
   must let clicks pass through to it (which opens the os picker).
   we deliberately do NOT set z-index on .dz-empty / .dz-filled, because
   doing so creates a local stacking context that would trap the remove
   button's z-index inside it (preventing it from rising above the input
   in the parent stacking context). */
.dz-empty,
.dz-filled,
.dz-preview,
.dz-meta { pointer-events: none; }
.dz-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    width: 100%;
}
.dz-icon {
    width: 28px;
    height: 28px;
    color: var(--text-3);
    opacity: 0.85;
}
.dropzone:hover .dz-icon,
.dropzone:focus-visible .dz-icon,
.dropzone.is-dragover .dz-icon {
    color: var(--amy);
    opacity: 1;
}
.dz-title {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-2);
}
.dz-hint {
    font-size: 11px;
    color: var(--text-3);
}
.dz-filled[hidden],
.dz-empty[hidden] { display: none !important; }
.dz-filled {
    display: grid;
    grid-template-columns: 88px minmax(0, 1fr) auto;
    grid-template-rows: auto;
    align-items: center;
    gap: 14px;
    width: 100%;
}
.dz-preview {
    width: 88px;
    height: 88px;
    object-fit: cover;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: #ffffff;
    display: block;
}
.dz-meta {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.dz-name {
    font-size: 13px;
    color: var(--text);
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.dz-size {
    font-size: 11px;
    color: var(--text-3);
    font-family: var(--mono, monospace);
}
/* "click to replace" lives inside the meta column as a subtle hint —
   the entire dropzone is the click target, so we don't need a button. */
.dz-replace-hint {
    font-size: 11px;
    color: var(--text-3);
    font-style: italic;
    margin-top: 2px;
}
/* remove is the only real button inside the filled state. it must:
   - opt back into pointer events (parent .dz-filled has them off)
   - paint AND hit-test above the transparent input overlay (z-index:3)
     so the click lands on the button rather than passing through to
     the input (which would open the picker). z-index:5 + position:
     relative puts it directly in the .dropzone stacking context. */
.dz-remove-btn {
    pointer-events: auto;
    position: relative;
    z-index: 5;
    align-self: center;
    cursor: pointer;
}
@media (max-width: 480px) {
    .dz-filled {
        grid-template-columns: 64px minmax(0, 1fr);
    }
    .dz-preview { width: 64px; height: 64px; }
    .dz-remove-btn {
        grid-column: 1 / -1;
        justify-self: stretch;
    }
}

/* ==================================================================
   /team page — owner-only members table, subscription side panel,
   per-row sparklines. kept in one block so future tweaks don't have
   to hunt through page-specific <style> tags.
   ================================================================== */

/* reusable 28x28 square button for row-level icon actions (remove,
   edit, etc.). intentionally sized for table rows so it sits inline
   with text without ballooning row height. */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border-radius: var(--r-s);
    border: 1px solid transparent;
    background: transparent;
    color: var(--text-3);
    cursor: pointer;
    transition: background var(--dur-fast) var(--easing),
                border-color var(--dur-fast) var(--easing),
                color var(--dur-fast) var(--easing);
}
.icon-btn:hover {
    background: var(--surface-2);
    border-color: var(--border);
    color: var(--text);
}
.icon-btn svg { width: 14px; height: 14px; }
.icon-btn.danger { color: var(--text-3); }
.icon-btn.danger:hover {
    background: var(--err-dim);
    border-color: rgba(239, 68, 68, 0.35);
    color: #fca5a5;
}

/* subscription summary card: big days-left readout + progress bar. the
   progress bar shows how much of the *current* 30-day window remains.
   without a start date we approximate a 30-day cycle from expiration
   so the bar always has something sensible to draw. */
.sub-card { padding: 20px 22px; }
.sub-card .sub-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 14px;
}
.sub-card .sub-card-head h2 {
    font-size: 13px;
    color: var(--text);
    margin: 0;
    text-transform: lowercase;
    font-weight: 600;
    letter-spacing: 0.01em;
}
.sub-days {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 4px;
}
.sub-days .n {
    font-family: var(--mono);
    font-size: 32px;
    font-weight: 600;
    color: var(--text);
    line-height: 1;
    letter-spacing: -0.02em;
}
.sub-days .unit { font-size: 12px; color: var(--text-3); }
.sub-expires {
    font-size: 11px;
    color: var(--text-3);
    margin: 0 0 14px;
    font-family: var(--mono);
}
.sub-card .quota-bar { height: 6px; }

/* members table overrides. only two tweaks vs the global .table: the
   header row gets a slightly muted background to separate from body
   rows in a long list, and the first column takes the remaining space
   while stats/spark columns sit at their natural widths. */
.members-table { table-layout: auto; }
.members-table th { font-size: 10px; }
.members-table th.num,
.members-table td.num {
    text-align: right;
    font-family: var(--mono);
    font-size: 12px;
    white-space: nowrap;
}
.members-table td.num.good { color: var(--ok); }
.members-table td.num.bad  { color: var(--err); }
.members-table th.actions-col,
.members-table td.actions-col {
    width: 44px;
    text-align: right;
    padding-right: 16px;
}

/* member identity cell: square-ish avatar with a rounded radius (not a
   full circle — the brand icons we render as pfps in other places use
   rounded squares too, keeps the panel consistent). */
.member-cell {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}
.member-avatar-lg {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-2);
    flex-shrink: 0;
    overflow: hidden;
    text-transform: uppercase;
}
.member-avatar-lg img { width: 100%; height: 100%; object-fit: cover; }
.member-identity {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.member-identity .name-row {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12.5px;
    color: var(--text);
    font-weight: 500;
}
.member-identity .name-row .truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 180px;
}
.member-identity .tg-id {
    font-family: var(--mono);
    font-size: 10.5px;
    color: var(--text-3);
}

/* add-member footer row. a little more breathing room than the default
   card-foot plus an inline help text that appears on focus so the
   input doesn't lose its placeholder-as-label pattern. */
.team-add-foot {
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: stretch;
}
.team-add-foot form {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 10px;
    align-items: center;
    margin: 0;
}
.team-add-foot .help {
    font-size: 11px;
    color: var(--text-3);
    line-height: 1.45;
    margin: 0;
}

/* empty-roster banner — shows when the owner is the only member in
   the team. nudges them toward adding someone without shouting. */
.team-empty-row {
    padding: 28px 18px;
    text-align: center;
    color: var(--text-3);
    font-size: 12.5px;
}
.team-empty-row strong { color: var(--text-2); font-weight: 600; }

/* "top folder" stat tile: the brand icon + folder name can exceed the
   tile width when a long folder is active. cap the text so it truncates
   gracefully instead of pushing the tile out. */
.team-top-folder-tile .stat-value.brand-cell { align-items: center; }
.team-top-folder-tile .stat-value .truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* regular-member view (not owner): soft badge over an avatar-sized box
   so the page doesn't feel empty when the user can't see the roster. */
.team-public-card {
    padding: 22px;
}
.team-public-head {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 16px;
}
.team-public-head .member-avatar-lg {
    width: 44px;
    height: 44px;
    border-radius: 12px;
}
.team-public-head h2 {
    font-size: 16px;
    color: var(--text);
    margin: 0;
    letter-spacing: -0.01em;
}
.team-public-head .sub {
    font-size: 11.5px;
    color: var(--text-3);
    margin: 2px 0 0;
}

/* ------------------------------------------------------------ number-input
   strip the native up/down spinner on inputs tagged `.no-spinner`. we
   keep `type="number"` (so inputmode keyboards + browser validation
   still apply) but render as a plain text field — the tiny chromium
   arrows looked out of place next to the custom combobox / select and
   the user asked for the field to read as "just a text box they can
   type in". applied opt-in (not globally) in case other pages want
   the native controls back. */
.input.no-spinner::-webkit-outer-spin-button,
.input.no-spinner::-webkit-inner-spin-button {
    -webkit-appearance: none;
    appearance: none;
    margin: 0;
}
.input.no-spinner { -moz-appearance: textfield; appearance: textfield; }

/* ------------------------------------------------------------ history page
   filter bar + table chrome.

   the old layout used inline flex with `btn.sm` for the submit button,
   which painted a tiny pill next to full-height inputs and read as a
   layout mistake. rebuilt around a gap token, an explicit submit
   wrapper, and a button that matches the input height.

   the scroll region also gets a wider, more visible scrollbar here
   (10px → 12px w/ a stronger thumb) so the long history table reads
   as scrollable on first glance — the page-wide 10px gutter felt
   invisible when the user was specifically looking for it. */
.history-filter-card { margin-bottom: 18px; }
.history-filter-row {
    display: flex;
    gap: 14px;
    align-items: flex-end;
    flex-wrap: wrap;
}
.history-filter-field {
    margin: 0;
    flex: 1 1 200px;
    min-width: 160px;
    /* anchor for the absolutely-positioned .field-error below */
    position: relative;
}
.history-filter-limit {
    margin: 0;
    width: 130px;
    flex: 0 0 130px;
    position: relative;
}
/* keep validation messages from resizing the field + bumping the
   input upward inside the flex-end row. sitting them just below the
   input in absolute flow preserves row alignment when the user
   submits an out-of-range value. */
.history-filter-row .field-error {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    margin-top: 0;
}
.history-filter-submit {
    /* the label above the inputs adds ~18px — reserve an equivalent
       top offset on the button row so everything baselines on the
       input bottom edge, not the label. */
    display: flex;
    align-items: flex-end;
}
.history-filter-submit .btn {
    /* match the input's box: 10+10 padding + 1+1 border + ~17px line-height
       lands at ~40px which is what `.input` renders at. keep the button
       visually the same height, with comfortable horizontal breathing
       room so "filter" doesn't read as a crammed chip. */
    height: 40px;
    padding: 0 22px;
    font-size: 12.5px;
    min-width: 104px;
}

/* hover-reveal scrollbar for scroll regions that opt in via
   `.scroll-region.tall` (history table) or `.scroll-region.hover-fade`
   (stats page top-N lists, any future card with an internal scroll).
   the thumb keeps its full min-height: 80px footprint at all times —
   we only toggle its `background` between transparent and
   var(--border-hi) to control visibility. this matters because the
   moment either `scrollbar-width` OR `scrollbar-color` is set on the
   element, chromium 121+ switches to the standard scrollbar renderer
   and silently throws away our ::-webkit-scrollbar pseudo-elements
   (including the min-height), which squashed the thumb back to a
   ratio-sized sliver in previous attempts. touch devices hit the
   native bar because "hover" isn't meaningful there. */
@media (hover: hover) and (pointer: fine) {
    .scroll-region.tall::-webkit-scrollbar,
    .scroll-region.hover-fade::-webkit-scrollbar {
        width: 10px;
        height: 10px;
    }
    .scroll-region.tall::-webkit-scrollbar-track,
    .scroll-region.hover-fade::-webkit-scrollbar-track {
        background: transparent;
    }
    .scroll-region.tall::-webkit-scrollbar-thumb,
    .scroll-region.hover-fade::-webkit-scrollbar-thumb {
        background: transparent;
        /* zero the border the global ::-webkit-scrollbar-thumb rule
           applies (2px solid var(--bg)); otherwise it draws a visible
           thumb-shaped outline on the transparent state — the "darker
           hanger" the user was seeing when not hovering. re-applied on
           hover so the thumb picks up the inset breathing room once
           the background fades in. */
        border: 0;
        border-radius: 5px;
        min-height: 80px;
        transition: background var(--dur-fast) var(--easing);
    }
    /* :has() scopes the reveal to the card wrapping this scroll
       region so other .card elements elsewhere in the panel aren't
       affected. */
    .card:has(.scroll-region.tall):hover .scroll-region.tall::-webkit-scrollbar-thumb,
    .card:has(.scroll-region.hover-fade):hover .scroll-region.hover-fade::-webkit-scrollbar-thumb {
        background: var(--border-hi);
        border: 2px solid var(--surface);
    }
    .card:has(.scroll-region.tall):hover .scroll-region.tall::-webkit-scrollbar-thumb:hover,
    .card:has(.scroll-region.hover-fade):hover .scroll-region.hover-fade::-webkit-scrollbar-thumb:hover {
        background: var(--text-2);
    }

    /* firefox has no ::-webkit-scrollbar support — feature-detect and
       give it the scrollbar-color hover-reveal in a dedicated block so
       we don't regress chromium's webkit renderer. */
    @supports not selector(::-webkit-scrollbar-thumb) {
        .scroll-region.tall,
        .scroll-region.hover-fade {
            scrollbar-color: transparent transparent;
            transition: scrollbar-color var(--dur-fast) var(--easing);
        }
        .card:has(.scroll-region.tall):hover .scroll-region.tall,
        .card:has(.scroll-region.hover-fade):hover .scroll-region.hover-fade {
            scrollbar-color: var(--border-hi) transparent;
        }
    }
}

/* stats page layout.
   - .stats-split: two equal columns on desktop, single column below
     900px so the top-N lists don't get squashed on narrow viewports.
     stretched by default so both cards render the same height even
     when one has many fewer rows than the other (the user reported
     the "top folders" card looking short next to "top templates").
   - .stats-scroll: fixed height per card body (not max-height), so
     cards always match regardless of how many rows they hold. the
     calc subtracts the app bar, page head, 4-tile stat row, card
     head, and breathing room so the page itself never scrolls.
     falls back to 260px on very small screens.
   - gap above the split is separate from the grid's own gap so we
     can tune the "space between the summary tiles and the lists"
     independently — the user wanted a bigger gap there. */
.stats-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    /* concrete px because the `--space-*` design tokens aren't defined
       anywhere in this stylesheet — using them silently invalidated
       the declaration, which is why the two cards were touching. */
    gap: 20px;
    /* stretch (grid default) — keeps both columns at the same height
       regardless of dataset size. */
    margin-top: 24px;
}
@media (max-width: 900px) {
    .stats-split {
        grid-template-columns: 1fr;
    }
}
.stats-card {
    display: flex;
    flex-direction: column;
    /* the header is fixed-height; the body is stats-scroll and takes
       the remainder. min-height:0 lets the inner scroll area actually
       shrink to the card's bounds in a flex child (without this the
       scroll region would push the card taller than our calc). */
    min-height: 0;
}
.stats-card .card-body.stats-scroll {
    /* fixed height keeps both cards pixel-identical even when one
       list is shorter than the other.
       subtract: app bar (~56) + page head (~80) + summary tiles row
       (~96) + 24px gap + card head (~60) + card footer breathing
       room (~28) + scrollbar gutter — comfortably under one
       viewport height so the body never gains its own scrollbar. */
    height: min(520px, calc(100vh - 440px));
    min-height: 220px;
    overflow-y: auto;
}

/* give history table rows a touch more vertical breathing room so
   entries don't read as cramped against each other. tightened on the
   page-level override — doesn't affect the other .table usages. */
.scroll-region.tall table.table tbody td {
    padding-top: 13px;
    padding-bottom: 13px;
}

/* ---------------------------------------------------------- settings
   page-specific scaffolding. mirrors sender.html's visual language but
   layouts each "setting" as a row with a label/description on the left
   and the control on the right, so the grid reads top-to-bottom without
   the old checkbox-stack look. */
.settings-list { display: flex; flex-direction: column; }
.settings-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 24px;
    padding: 14px 0;
    border-bottom: 1px solid var(--border);
}
.settings-row:last-child { border-bottom: 0; }
.settings-row .setting-body { min-width: 0; }
.settings-row .setting-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 2px;
}
.settings-row .setting-desc {
    font-size: 11px;
    color: var(--text-3);
    line-height: 1.5;
}
.settings-row .setting-control {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 10px;
}
.settings-row-nested {
    padding-left: 18px;
    border-left: 2px solid var(--border);
    margin-left: 4px;
}
.settings-row-nested .setting-title {
    font-weight: 500;
    color: var(--text-2);
}

/* compact pill-style switch so each row terminates cleanly. uses a
   native checkbox for a11y, then hides it + paints a custom pill via
   the sibling span. */
.switch { position: relative; display: inline-block; width: 36px; height: 20px; flex-shrink: 0; }
.switch input { opacity: 0; width: 0; height: 0; position: absolute; }
.switch .slider {
    position: absolute; inset: 0;
    cursor: pointer;
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: 999px;
    transition: background var(--dur-fast) var(--easing),
                border-color var(--dur-fast) var(--easing);
}
.switch .slider::before {
    content: "";
    position: absolute;
    top: 2px; left: 2px;
    width: 14px; height: 14px;
    background: var(--text-2);
    border-radius: 50%;
    transition: transform var(--dur-fast) var(--easing),
                background var(--dur-fast) var(--easing);
}
.switch input:checked + .slider {
    background: var(--amy-dim);
    border-color: rgba(167, 139, 250, 0.45);
}
.switch input:checked + .slider::before {
    transform: translateX(16px);
    background: var(--amy);
}
.switch input:focus-visible + .slider {
    box-shadow: 0 0 0 2px rgba(167, 139, 250, 0.35);
}

/* danger-zone row: same layout as settings-row but wraps nicely when
   the button group gets long, and tints the title. */
.danger-zone .setting-title { color: var(--text); }
.danger-zone .setting-meta {
    display: inline-block;
    margin-left: 8px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    font-family: var(--mono);
    font-size: 10px;
    color: var(--text-3);
    vertical-align: middle;
}

/* inline flash banner used at the top of settings after a redirect. */
.flash-banner {
    margin-bottom: 16px;
    padding: 10px 14px;
    border-radius: var(--r-s);
    border: 1px solid rgba(74, 222, 128, 0.3);
    background: var(--ok-dim);
    color: #bbf7d0;
    font-size: 12px;
    display: flex;
    align-items: center;
    gap: 10px;
}
.flash-banner.err {
    border-color: rgba(239, 68, 68, 0.3);
    background: var(--err-dim);
    color: #fecaca;
}
.flash-banner svg { width: 14px; height: 14px; flex-shrink: 0; }
.flash-banner.ok { border-color: rgba(74, 222, 128, 0.3); background: var(--ok-dim); color: var(--text); }
.flash-banner.warn {
    border-color: rgba(245, 158, 11, 0.3);
    background: var(--warn-dim);
    color: #fde68a;
}
.flash-banner.danger {
    border-color: rgba(239, 68, 68, 0.3);
    background: var(--err-dim);
    color: #fecaca;
}

/* team page */
.team-page { max-width: 820px; }
.team-stack { display: flex; flex-direction: column; gap: 14px; }
.team-you {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 18px 20px;
}
.team-you-copy { min-width: 0; flex: 1; }
.team-you-name {
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 6px;
}
.team-you-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.team-you-logout { margin-left: auto; flex-shrink: 0; }
.members-table tr.is-self td { background: rgba(167, 139, 250, 0.04); }

/* settings page layout (legacy) */
.settings-page { max-width: 680px; }
.settings-stack {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.settings-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding-top: 2px;
}
.settings-select {
    min-width: 168px;
    max-width: 220px;
}
.settings-row .setting-desc .link {
    color: var(--amy);
    text-decoration: none;
}
.settings-row .setting-desc .link:hover {
    text-decoration: underline;
}
body.is-bg-static #bg-canvas { display: none; }

.settings-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(280px, 0.85fr);
    gap: 14px;
    align-items: start;
}
@media (max-width: 960px) {
    .settings-layout { grid-template-columns: 1fr; }
}
.settings-main,
.settings-rail {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}
.settings-profile-card .card-body,
.settings-profile-card { padding: 0; }
.settings-profile-head {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 20px 22px;
}
.settings-profile-avatar {
    width: 56px;
    height: 56px;
    border-radius: 14px;
}
.settings-profile-avatar.no-photo .avatar-fallback {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    font-size: 20px;
    font-weight: 700;
    color: var(--text-2);
}
.settings-profile-avatar .avatar-fallback { display: none; }
.settings-profile-avatar.no-photo img { display: none; }
.settings-profile-copy { min-width: 0; flex: 1; }
.settings-profile-copy h2 {
    margin: 0;
    font-size: 18px;
    letter-spacing: -0.02em;
    color: var(--text);
}
.settings-profile-copy .sub {
    margin: 4px 0 0;
    font-size: 12px;
    color: var(--text-3);
}
.settings-profile-logout { margin-left: auto; flex-shrink: 0; }
.settings-id-chip {
    font-family: var(--mono);
    font-size: 12px;
    padding: 6px 10px;
    border-radius: var(--r-s);
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--text);
}
.settings-link-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 0;
    border-bottom: 1px solid var(--border);
    text-decoration: none;
    color: inherit;
    transition: opacity var(--dur-fast) var(--easing);
}
.settings-link-row:last-child { border-bottom: 0; }
.settings-link-row:hover { opacity: 0.88; }
.settings-link-arrow {
    color: var(--text-3);
    font-size: 16px;
    flex-shrink: 0;
}
.badge.sm {
    font-size: 10px;
    padding: 2px 7px;
}

.flash-banner strong { font-weight: 600; }
.flash-banner code, .flash-banner .mono { color: inherit; }

/* ───────────────────────── admin /edit surface ─────────────────────────
   the admin edit pages mirror the telegram bot's /edit command (categories /
   folders / templates). these styles cover:
   - the tab bar at the top (edit-tabs)
   - dense inline edit forms inside table rows (inline-rename, defaults-grid)
   - the folder grid on the templates landing page (folder-grid)
   - chip lists for commands/folders
   - breadcrumb + kv + bulk edit scaffolding
   naming is kept simple so these can be reused on future admin pages. */

.edit-tabs {
    display: flex;
    gap: 2px;
    margin-bottom: 20px;
    padding: 3px;
    background: var(--bg-2);
    border: 1px solid var(--border);
    border-radius: var(--r-m);
    width: fit-content;
}
.edit-tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 14px;
    border-radius: calc(var(--r-m) - 3px);
    font-size: 12px;
    color: var(--text-2);
    text-decoration: none;
    transition: background 0.15s, color 0.15s;
    cursor: pointer;
}
.edit-tab:hover { color: var(--text); background: rgba(255, 255, 255, 0.03); }
.edit-tab.active {
    background: var(--amy-dim);
    color: var(--amy);
    border: 1px solid rgba(167, 139, 250, 0.25);
    padding: 6px 13px;
}
.edit-tab-ico { width: 14px; height: 14px; }

/* breadcrumb (folder > template) */
.breadcrumb-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 16px;
    font-size: 12px;
    color: var(--text-2);
}
.breadcrumb-row .btn.xs { padding: 4px 8px; font-size: 11px; }
.breadcrumb-row .btn-ico { width: 12px; height: 12px; margin-right: 2px; }

/* xs button size: smaller than .sm, for cramped table cells */
.btn.xs {
    padding: 4px 9px;
    font-size: 10.5px;
    border-radius: var(--r-s);
}
.btn.xs svg { width: 11px; height: 11px; }

/* ── two-column row for side-by-side cards ── */
.row-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
@media (max-width: 900px) {
    .row-2 { grid-template-columns: 1fr; }
}

/* ── form-grid: vertical stack with optional 2-column layout for big forms ── */
.form-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
}
.form-grid.cols-2 {
    grid-template-columns: 1fr 1fr;
    column-gap: 16px;
}
.form-grid.cols-2 .form-row.span-2 { grid-column: 1 / -1; }
.form-grid .form-row { display: flex; flex-direction: column; gap: 4px; }
.form-grid .form-label {
    font-size: 11px;
    color: var(--text-3);
    text-transform: lowercase;
    letter-spacing: 0.02em;
}
.form-grid .form-hint {
    font-size: 11px;
    color: var(--text-3);
    margin-top: 2px;
}

/* ── inline rename forms inside table cells ── */
.inline-rename {
    display: flex;
    gap: 4px;
    align-items: center;
}
.inline-rename .input.sm { flex: 1 1 auto; min-width: 0; }

/* ── grid of three inputs + button for folder-defaults row ── */
.defaults-grid {
    display: grid;
    grid-template-columns: 1fr 1.2fr 1.2fr auto;
    gap: 4px;
    align-items: center;
    max-width: 560px;
}
.defaults-grid .input.sm { min-width: 0; }

/* ── chip lists (commands, folder badges) ── */
.chip-list {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
}
.chip {
    display: inline-flex;
    align-items: center;
    padding: 3px 8px;
    background: var(--bg-3);
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 11px;
    color: var(--text-2);
    line-height: 1.3;
}

/* ── folder-grid on the templates landing page ── */
.folder-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 12px;
}
.folder-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 18px;
    background: var(--bg-2);
    border: 1px solid var(--border);
    border-radius: var(--r-m);
    text-decoration: none;
    color: var(--text);
    transition: border-color 0.15s, background 0.15s, transform 0.1s;
    cursor: pointer;
}
.folder-card:hover {
    border-color: var(--amy);
    background: rgba(167, 139, 250, 0.04);
}
.folder-card:active { transform: translateY(1px); }
.folder-card-ico {
    width: 24px;
    height: 24px;
    color: var(--amy);
}
.folder-card-name {
    font-size: 13px;
    color: var(--text);
    font-weight: 500;
}
.folder-card-count {
    font-size: 11px;
    color: var(--text-3);
}

/* ── bulk-grid: the three "apply to all" forms stacked on one row ── */
.bulk-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
}
@media (max-width: 900px) {
    .bulk-grid { grid-template-columns: 1fr; }
}
.bulk-form { display: flex; flex-direction: column; gap: 4px; }
.bulk-form .field-row { display: flex; gap: 4px; }
.bulk-form .input.sm { flex: 1 1 auto; min-width: 0; }

/* ── pill faint variant (used for "inherits folder" / "dynamic") ── */
.pill.faint {
    background: transparent;
    color: var(--text-3);
    border-color: var(--border);
}

/* ==========================================================================
   cross-browser + responsive layer
   appended 2026-04. covers the full desktop ladder (4k down to 320px) and
   the long tail of browser quirks without rewriting any of the above rules.
   ordered: primitives → breakpoints → browser fallbacks → a11y / print.
   ========================================================================== */

/* ---------- primitives: keep elements inside their container ---------- */

/* flex/grid children overflow when their content is wider than the cell
   (long email addresses, monospace templates). min-width: 0 on the
   common layout children fixes this without affecting their normal
   sizing. */
.split-grid > *,
.dash-grid > *,
.row-2 > *,
.form-grid > *,
.stats-grid > *,
.bulk-grid > *,
.folder-grid > *,
.grid > * { min-width: 0; }

/* images, video and canvases should never escape their parent. svg keeps
   its explicit width/height so icon sizes stay predictable. */
img, video, canvas { max-width: 100%; height: auto; }
#bg-canvas {
    max-width: none !important;
    width: 100% !important;
    min-height: 100vh !important;
    min-height: 100svh !important;
    height: 100vh !important;
    height: 100svh !important;
}

/* unbreakable tokens wrap so a 60-char monospace id doesn't blow the
   layout sideways on narrow viewports. */
.mono, code, pre { overflow-wrap: anywhere; word-break: break-word; }
/* …except inputs / select / textarea, where typing a long value should
   scroll inside the control rather than wrap. */
.input, .select, .textarea, input, select, textarea {
    overflow-wrap: normal;
    word-break: normal;
}

/* ---------- tables: horizontal scroll on overflow ---------- */
/* tables inside .scroll-region already scroll vertically; add horizontal
   overflow so a 6-column table doesn't blow the card out on narrow
   screens. on wide screens no scrollbar appears — overflow: auto only
   paints one when content actually overflows.
   NOTE: we never set `display: block` on the table itself — that breaks
   the table layout algorithm (cells lose alignment). scrolling has to
   happen on the *container*, not the table. */
.scroll-region { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* card-body wrapping a raw table (no scroll-region) gets the same
   horizontal-scroll treatment on narrow viewports. targeted via :has()
   where supported; legacy browsers just keep the existing table look. */
@supports selector(:has(*)) {
    .card-body:has(> .table):not(.settings-list) {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
}

/* ---------- number inputs: hide native spinners cross-browser ---------- */
.no-spinner::-webkit-outer-spin-button,
.no-spinner::-webkit-inner-spin-button {
    -webkit-appearance: none;
    appearance: none;
    margin: 0;
}
.no-spinner { -moz-appearance: textfield; appearance: textfield; }

/* ==========================================================================
   breakpoints — desktop ladder
   1920+ (big desktop) : full layout, no caps
   1440  (standard)    : full layout (default)
   1280  (mid desktop) : narrow the sidebar slightly to reclaim content
   1100  (small laptop): narrower sidebar + tighter padding
    900  (tablet)      : sidebar stacks under topbar (existing rule)
    600  (phone)       : dense spacing, 1-col grids, tap-friendly controls
    420  (small phone) : absolute tightest layout
   ========================================================================== */

@media (min-width: 1441px) {
    /* defaults already tuned for 1440px+ — nothing to adjust */
}

@media (max-width: 1280px) {
    :root { --sidebar-w: 212px; }
    .main { padding: 24px 24px 40px; }
    .topbar { padding: 0 20px; }
}

@media (max-width: 1100px) {
    :root { --sidebar-w: 188px; }
    .main { padding: 22px 20px 36px; }
    .nav-item { padding: 7px 9px; font-size: 12.5px; }
    .nav-icon { width: 15px; height: 15px; }
    /* dash-grid tightening: below 1100 we effectively have ~900px of
       content width, 2-col still works but with tighter min cols */
    .dash-grid { grid-template-columns: minmax(0, 1.4fr) minmax(240px, 1fr); }
    .dash-grid > :nth-child(3) { grid-column: 1 / -1; }
}

@media (max-width: 900px) {
    /* base layout already collapses sidebar below topbar (line 223).
       these rules tighten the rest of the page for tablet-portrait. */
    .page-title { font-size: 20px; }
    .page-sub   { font-size: 12px; margin-bottom: 16px; }
    .topbar { padding: 0 14px; }

    /* collapse any still-multi-column grids to single-column so cards
       don't end up half-width on a 700px-wide viewport. */
    .grid.cols-2,
    .grid.cols-3,
    .grid.cols-4,
    .form-grid.cols-2,
    .row-2,
    .defaults-grid,
    .history-filter-row { grid-template-columns: 1fr !important; }
    .defaults-grid { max-width: 100%; }

    /* user chip: truncate long usernames instead of pushing the bell and
       logout off the right edge. */
    .user-chip .name {
        max-width: 140px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* confirm + alert dialogs: fit inside the viewport with some gutter */
    .confirm-dialog { max-width: calc(100vw - 24px); padding: 18px 16px 14px; }

    /* tap-friendly sidebar on mobile */
    .sidebar { padding: 14px 12px 12px; }
    .nav-item {
        padding: 9px 10px;
        font-size: 13px;
        /* 36px min height is enough for finger targeting without making
           the whole sidebar feel loose. */
        min-height: 36px;
    }

    /* stats split: single column on tablet */
    .stats-split { grid-template-columns: 1fr !important; }
}

@media (max-width: 600px) {
    body { font-size: 12.5px; }
    .main { padding: 16px 12px 28px; }
    h1 { font-size: 20px; }
    h2 { font-size: 16px; }
    .page-title { font-size: 18px; }
    .card { padding: 14px; border-radius: var(--r-m); }
    .card.tight { padding: 12px 14px; }
    .card-head { padding: 12px 14px; }
    .card-body { padding: 14px; }
    .card-foot { padding: 10px 14px; }

    .btn { padding: 8px 12px; font-size: 11.5px; }
    .btn.lg { padding: 10px 14px; font-size: 12px; }
    .btn.sm { padding: 6px 9px; font-size: 10.5px; }

    .table th, .table td { padding: 8px 10px; font-size: 11.5px; }
    .table th { font-size: 9.5px; }

    /* stats grid: 2 columns on small phones, 1 at very small */
    .stats-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
    .folder-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }

    /* user chip on phone: role/badge tends to crowd the row; hide the
       trailing role badge if present, keep name + avatar */
    .user-chip .role { display: none; }
    .user-chip .name { max-width: 90px; }

    /* bigger tap targets for form controls — also prevents ios auto-zoom
       which kicks in whenever a focused input is <16px. */
    .input, .select, .textarea,
    input:not([type="checkbox"]):not([type="radio"]),
    select, textarea { font-size: 16px; }
}

@media (max-width: 420px) {
    .stats-grid { grid-template-columns: 1fr; }
    .folder-grid { grid-template-columns: 1fr; }
    .brand-logo { height: 22px; }
    .confirm-dialog { max-width: calc(100vw - 16px); padding: 16px 14px 12px; }
}

/* ==========================================================================
   cross-browser fallbacks
   ========================================================================== */

/* color-mix() landed in chrome 111 / safari 16.2 / firefox 113. on older
   renderers the input-error tint silently collapses to plain surface-2;
   the fallback below paints a mild red wash so validation still reads. */
@supports not (color: color-mix(in oklab, red, blue)) {
    .input.is-invalid,
    .select.is-invalid,
    .textarea.is-invalid,
    .fc-combobox.is-invalid .fc-button,
    .dropzone.is-invalid {
        background: rgba(239, 68, 68, 0.08);
    }
    .fc-option.is-selected.is-active { background: rgba(167, 139, 250, 0.22); }
}

/* :has() landed chrome 105 / safari 15.4 / firefox 121. on older
   browsers the hover-reveal scrollbars inside the sender card and
   scroll-regions would never appear. restore always-visible thin
   scrollbars as a graceful fallback. */
@supports not selector(:has(*)) {
    .sender-scroll,
    .scroll-region.tall,
    .scroll-region.hover-fade {
        scrollbar-width: thin;
        scrollbar-color: var(--border) transparent;
    }
}

/* firefox doesn't support ::-webkit-scrollbar. expose the same thin look
   via the standard scrollbar-* properties wherever we customize the
   webkit variant. */
@supports (scrollbar-width: thin) {
    body, html,
    .scroll-region,
    .textarea,
    .notif-list,
    .dash-notif-list,
    .sender-scroll {
        scrollbar-color: var(--border) transparent;
    }
    /* .sidebar omitted: it uses scrollbar-width: none + hidden webkit bar */
}

/* safari: give brand icon <img> a pixel-art friendly filter so small
   brand marks don't blur when cached at 2x. harmless elsewhere. */
img[data-brand] { image-rendering: -webkit-optimize-contrast; }

/* ==========================================================================
   accessibility
   ========================================================================== */

/* os-level "reduce motion": flatten css animations/transitions. the canvas
   uses requestAnimationFrame (not css keyframes) — we no longer `display:none`
   it here so the field stays visible; amethyst-bg.js already dials down
   particles and disables pointer-driven motion when matchMedia(reduce) is
   on. to hide the canvas fully, the user can use forced-colors or turn off
   "show animations" in the browser chrome flags — but win10/edge often maps
   "show animations" off to prefers-reduce, and hiding the only backdrop made
   the app look "broken" vs "calm". */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* forced-colors (windows high-contrast): keep ui borders legible. canvas
   stays visible at low opacity so the field never "disappears" on edge/safari. */
@media (forced-colors: active) {
    .card, .btn, .input, .select, .textarea { border: 1px solid CanvasText; }
    .nav-item.active { outline: 1px solid Highlight; }
    body::before { opacity: 0.35; }
    #bg-canvas { opacity: 0.35; }
}

/* keyboard focus ring — every focusable element gets a visible ring,
   but only for keyboard navigation (focus-visible), so mouse-clicks
   don't draw an outline. controls that already style their own focus
   (inputs, buttons, nav items) opt out. */
:focus { outline: none; }
:focus-visible {
    outline: 2px solid var(--amy);
    outline-offset: 2px;
    border-radius: 4px;
}
.btn:focus-visible,
.input:focus-visible,
.select:focus-visible,
.textarea:focus-visible,
.nav-item:focus-visible,
.switch input:focus-visible + .slider,
.fc-button:focus-visible { outline: none; }

/* ------------------------------------------------------------------ /send
   (moved out of templates/pages/send.html head_extra so the document head
   stays tiny — avoids BOM/stray-bytes next to <style> in some deploy paths,
   and keeps all layout chrome in one cacheable sheet.) */
.main.page--send .send-layout {
    display: grid;
    grid-template-columns: minmax(380px, 440px) minmax(0, 1fr);
    gap: 18px;
    align-items: start;
}
@media (max-width: 1100px) {
    .main.page--send .send-layout { grid-template-columns: 1fr; }
}
.main.page--send #send-preview-card .preview-frame,
.main.page--send #relay-preview-card .preview-frame,
.main.page--send #lis-preview-card .preview-frame {
    position: relative;
    height: clamp(500px, calc(100vh - 280px), 620px);
    height: clamp(500px, calc(100svh - 280px), 620px);
    background: var(--surface);
    border-radius: 0 0 var(--r-l) var(--r-l);
    overflow: hidden;
    display: block;
}
.main.page--send #send-result,
.main.page--send #quick-send-result { margin-top: 14px; }
.main.page--send #send-result:empty,
.main.page--send #quick-send-result:empty {
    display: none;
    margin: 0;
    padding: 0;
    border: none;
}
.main.page--send .send-result:not(:empty) {
    padding: 12px 14px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: var(--surface-2);
    font-size: 12px;
}
.main.page--send .send-result.ok {
    border-color: rgba(34, 197, 94, 0.3);
    background: var(--ok-dim);
    color: var(--text);
}
.main.page--send .send-result.warn {
    border-color: rgba(245, 158, 11, 0.3);
    background: var(--warn-dim);
    color: var(--text);
}
.main.page--send .send-result.error {
    border-color: rgba(239, 68, 68, 0.3);
    background: var(--err-dim);
    color: var(--text);
}

.relay-progress-wrap {
    padding: 4px 0;
}

.relay-progress {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.relay-progress-step {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    color: var(--muted, #6b7280);
    transition: color 0.2s ease;
}

.relay-progress-step.is-active {
    color: #d1fae5;
    font-weight: 600;
}

.relay-progress-step.is-done {
    color: #d1fae5;
}

.relay-progress-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.35;
    flex-shrink: 0;
}

.relay-progress-step.is-active .relay-progress-dot,
.relay-progress-step.is-done .relay-progress-dot {
    opacity: 1;
}

.relay-progress-step.is-done .relay-progress-dot {
    box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.35);
}

.main.page--send .subject-preview {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    margin-bottom: 12px;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    background: var(--surface-2);
    font-size: 12px;
    line-height: 1.4;
    cursor: text;
}
.main.page--send .subject-preview-label {
    flex: 0 0 auto;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 10.5px;
    font-weight: 600;
}
.main.page--send .subject-preview-value {
    flex: 1 1 auto;
    color: var(--text);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.main.page--send .subject-preview-input {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    padding: 2px 6px;
    font-size: 12px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--text);
    border: 1px solid transparent;
    border-radius: var(--r-xs);
    background: transparent;
    box-shadow: none;
}
.main.page--send .subject-preview-input:hover {
    border-color: var(--border-hi);
    cursor: text;
}
.main.page--send .subject-preview-input:focus {
    border-color: var(--amy);
    background: var(--surface);
    outline: none;
}
.main.page--send .subject-preview-tag {
    flex: 0 0 auto;
    font-size: 9.5px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
    padding: 2px 7px;
    border-radius: 999px;
    background: var(--surface);
    border: 1px solid var(--border-hi);
    color: var(--text-2);
}
.main.page--send .subject-preview-tag.amy {
    background: var(--amy-dim);
    border-color: var(--amy-ring);
    color: var(--amy);
}
.main.page--send .subject-preview-tag-slot:empty {
    display: none !important;
    width: 0;
    min-width: 0;
    flex: 0 0 0;
    margin: 0;
    padding: 0;
    overflow: hidden;
}
.main.page--send .subject-preview-tag.static {
    background: var(--ok-dim);
    border: 1px solid rgba(34, 197, 94, 0.38);
    color: var(--ok);
}

/* ------------------------------------------------------------------ /preview */
.main.page--preview .preview-layout {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 14px;
    /* stretch both columns to same row height, then let the rendered frame
       grow to fill the card so extra height shows more template content
       instead of a dark dead area. */
    align-items: stretch;
}
@media (max-width: 1100px) {
    .main.page--preview .preview-layout { grid-template-columns: 1fr; }
}
.main.page--preview .tpl-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-height: 520px;
    overflow-y: auto;
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    background: var(--surface-2);
}
.main.page--preview .tpl-list .tpl {
    display: block;
    padding: 8px 10px;
    border-radius: var(--r-xs);
    font-size: 12px;
    color: var(--text-2);
    font-family: var(--mono);
    text-decoration: none;
    transition: background var(--dur-fast) var(--easing), color var(--dur-fast) var(--easing);
    cursor: pointer;
}
.main.page--preview .tpl-list .tpl:hover {
    background: rgba(255, 255, 255, 0.03);
    color: var(--text);
}
.main.page--preview .tpl-list .tpl.active {
    background: var(--amy-dim);
    color: var(--amy);
}
.main.page--preview .rendered-card {
    display: flex;
    flex-direction: column;
    position: relative;
    min-height: 0;
    height: 100%;
}
.main.page--preview .rendered-card .card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
}
.main.page--preview .rendered-card .card-head-actions {
    display: flex;
    align-items: center;
    gap: 10px;
}
.main.page--preview #tpl-render-frame {
    position: relative;
    flex: 1 1 auto;
    min-height: clamp(420px, calc(100vh - 360px), 520px);
    min-height: clamp(420px, calc(100svh - 360px), 520px);
    background: var(--surface);
    border-radius: 0 0 var(--r-l) var(--r-l);
    overflow: hidden;
    display: block;
}
.main.page--preview #tpl-render-frame > .preview-iframe {
    border: 0;
    display: block;
}
.main.page--preview .rendered-card.is-loading::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: linear-gradient(
        90deg,
        rgba(168, 85, 247, 0) 0%,
        rgba(168, 85, 247, 0.85) 50%,
        rgba(168, 85, 247, 0) 100%
    );
    background-size: 200% 100%;
    animation: tpl-loading-bar 0.9s linear infinite;
    pointer-events: none;
    z-index: 2;
}
@keyframes tpl-loading-bar {
    from { background-position: 100% 0; }
    to   { background-position: -100% 0; }
}

/* ==========================================================================
   print
   ========================================================================== */

@media print {
    body { background: #fff; color: #000; }
    body::before, #bg-canvas, .sidebar, .topbar, .toast,
    .confirm-backdrop, .notif-popover { display: none !important; }
    .app {
        grid-template-columns: 1fr;
        grid-template-rows: 1fr;
        grid-template-areas: "main";
    }
    .main { padding: 0; }
    .card {
        break-inside: avoid;
        border: 1px solid #bbb;
        background: #fff;
        color: #000;
        box-shadow: none;
    }
    a { color: #000; text-decoration: underline; }
}

.fa-account-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.fa-account-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(1, minmax(0, 1fr));
    gap: 12px;
}
@media (min-width: 720px) {
    .fa-account-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1100px) {
    .fa-account-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.fa-account-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px;
    border: 1px solid var(--border);
    border-radius: var(--r-m);
    background: var(--surface-2);
}
.fa-account-card.is-active {
    border-color: color-mix(in srgb, #3b82f6 70%, var(--border));
}
.fa-account-card-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
}
.fa-account-select-btn {
    flex: 1;
    min-width: 0;
    text-align: left;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    color: inherit;
}
.fa-account-card-title {
    margin: 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.fa-account-card-email {
    margin: 4px 0 0;
    font-size: 12px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.fa-account-card-meta {
    margin: 6px 0 0;
    font-size: 11px;
}
.fa-account-card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.fa-acct-act {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    border: 0;
    border-radius: var(--r-s);
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    background: rgba(16, 185, 129, 0.14);
    color: #34d399;
}
.fa-acct-act:hover { filter: brightness(1.08); }
.fa-acct-totp {
    background: rgba(168, 85, 247, 0.14);
    color: #c4b5fd;
}
.fa-account-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    background: var(--surface-2);
    font-size: 12px;
}
.fa-account-empty {
    padding: 10px 0;
    font-size: 12px;
}
.fa-account-label {
    flex: 1;
    min-width: 0;
}
.fa-account-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    min-width: 0;
}
.fa-account-provider {
    display: inline-block;
    flex-shrink: 0;
    padding: 3px 10px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--amy-hi);
    background: var(--amy-dim);
    border: 1px solid var(--amy-ring);
}
.fa-account-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    flex-shrink: 0;
}
.fa-account-sep {
    flex-shrink: 0;
    font-size: 12px;
}
.fa-account-email {
    font-size: 12px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.page-head-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 4px;
}
.page-head-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
}
.domain-preview-link {
    margin-left: 10px;
    vertical-align: middle;
}
.fa-page-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
    flex-wrap: wrap;
    justify-content: flex-end;
}
.fa-page-actions .fa-head-btn {
    padding: 10px 16px;
    font-size: 13px;
    font-weight: 500;
    border-radius: 999px;
    gap: 8px;
    white-space: nowrap;
    background: var(--surface-2);
    border: 1px solid var(--border-hi);
    color: var(--text);
    box-shadow: none;
    transform: none;
    line-height: 1.2;
}
.fa-page-actions .fa-head-btn svg {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
}
.fa-page-actions .fa-head-btn:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: var(--border-hi);
    color: var(--text);
    transform: none;
}
.fa-page-actions .fa-head-btn-add {
    background: rgba(59, 130, 246, 0.12);
    border-color: rgba(96, 165, 250, 0.35);
    color: #93c5fd;
}
.fa-page-actions .fa-head-btn-add:hover {
    background: rgba(59, 130, 246, 0.18);
    border-color: rgba(96, 165, 250, 0.5);
    color: #bfdbfe;
    transform: none;
}
.fa-page-actions .fa-head-btn:active {
    transform: none;
}
.fa-source-tabs {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}
.fa-source-tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    background: var(--surface-2);
    font-size: 12px;
    cursor: pointer;
    user-select: none;
}
.fa-source-tab:has(input:checked) {
    border-color: var(--amy);
    background: rgba(167, 139, 250, 0.08);
}
.fa-source-tab input {
    accent-color: var(--amy);
}
.fa-html-editor {
    min-height: 220px;
    resize: vertical;
    line-height: 1.45;
    font-size: 11px;
}
.fa-auth-dialog .field {
    margin-bottom: 12px;
}
#fa-auth-modal.confirm-backdrop {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}
.fa-auth-dialog {
    overflow: visible;
    max-width: 520px;
}
.fa-auth-tabs {
    display: flex;
    gap: 8px;
    margin-bottom: 14px;
}
.fa-auth-tab {
    flex: 1;
    padding: 8px 10px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--muted);
    font-family: var(--font);
    font-size: 12px;
    cursor: pointer;
    text-transform: lowercase;
}
.fa-auth-tab.is-active {
    color: var(--text);
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 12%, var(--surface-2));
}
.fa-oauth-steps {
    margin-bottom: 12px;
    padding: 12px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: var(--surface-2);
}
.fa-oauth-title {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 600;
}
.fa-oauth-list {
    margin: 0 0 8px 18px;
    padding: 0;
    font-size: 11px;
    line-height: 1.5;
}
.fa-oauth-list a {
    color: var(--accent);
}
.fa-oauth-note {
    margin: 0;
    font-size: 11px;
}
.fa-oauth-paste {
    min-height: 72px;
    resize: vertical;
    font-family: var(--mono, monospace);
    font-size: 11px;
    line-height: 1.4;
}
.fa-oauth-card {
    /* shared with fa-tab-card */
}
.fa-tab-card {
    margin-bottom: 18px;
}
.fa-tab-card-sub {
    margin: -6px 0 16px;
    font-size: 13px;
    line-height: 1.5;
}
.fa-picker {
    position: relative;
    width: 100%;
}
.fa-picker-btn {
    width: 100%;
    padding: 10px 36px 10px 12px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text);
    font-family: var(--font);
    font-size: 13px;
    line-height: 1.4;
    text-align: left;
    cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 12px;
    transition: border-color var(--dur-fast) var(--easing), box-shadow var(--dur-fast) var(--easing), background-color var(--dur-fast) var(--easing);
}
.fa-picker-btn:hover {
    background-color: var(--surface-3);
}
.fa-picker.is-open > .fa-picker-btn,
.fa-picker-btn:focus-visible {
    outline: none;
    border-color: var(--amy);
    box-shadow: 0 0 0 3px var(--amy-ring);
    background-color: var(--surface-3);
}
.fa-picker-menu {
    position: absolute;
    z-index: 20;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    margin: 0;
    padding: 4px;
    list-style: none;
    border-radius: var(--r-s);
    border: 1px solid var(--border-hi);
    background: var(--surface-2);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
    max-height: 220px;
    overflow-y: auto;
}
.fa-picker-menu[hidden] {
    display: none;
}
.fa-picker-option {
    padding: 9px 10px;
    border-radius: 6px;
    color: var(--text);
    font-size: 13px;
    cursor: pointer;
}
.fa-picker-option:hover,
.fa-picker-option.is-selected {
    background: rgba(34, 211, 238, 0.12);
    color: var(--text);
}
.fa-auth-dialog .confirm-actions {
    justify-content: flex-end;
}
.fa-upload-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    margin: 0;
}

/* FA mode tabs (Compose / Inbox) */
.fa-mode-tabs {
    display: inline-flex;
    gap: 6px;
    margin: 0 0 18px;
    padding: 4px;
    border-radius: 999px;
    background: var(--surface-2);
    border: 1px solid var(--border);
}
.fa-mode-tab {
    padding: 8px 18px;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--text-3);
    font-family: var(--font);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background var(--dur-fast) var(--easing), color var(--dur-fast) var(--easing);
}
.fa-mode-tab:hover {
    color: var(--text);
}
.fa-mode-tab.is-active {
    background: rgba(59, 130, 246, 0.18);
    color: #93c5fd;
    box-shadow: inset 0 0 0 1px rgba(96, 165, 250, 0.35);
}

.fa-section-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    margin: 0 0 14px;
    font-weight: 600;
}
.fa-section-title svg {
    flex-shrink: 0;
    opacity: 0.7;
}

/* Mail viewer — Noot Panel style */
.fa-viewer-card {
    padding: 20px;
    background: var(--surface);
    border-color: var(--border);
}
.fa-viewer-card.is-idle .fa-mail-list-wrap {
    opacity: 0.5;
    pointer-events: none;
}
.fa-viewer-top {
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin-bottom: 16px;
}
.fa-viewer-title-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}
.fa-viewer-title-group {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}
.fa-viewer-title {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0;
    font-size: 18px;
    font-weight: 600;
    color: var(--text);
    text-transform: none;
    letter-spacing: normal;
}
.fa-viewer-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.fa-viewer-select {
    min-width: 220px;
    font-size: 13px;
    color: var(--text);
    background-color: var(--surface-2);
    border-color: var(--border);
}
.fa-viewer-select option {
    color: var(--text);
    background-color: var(--surface);
}
.fa-viewer-select option[value=""] {
    color: var(--text-3);
}
.fa-viewer-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    font-size: 13px;
    border-radius: 8px;
    background-color: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--text-2);
    white-space: nowrap;
}
.fa-viewer-btn svg { flex-shrink: 0; }
.fa-viewer-btn:hover:not(:disabled) {
    background-color: var(--surface-3);
    border-color: var(--border-hi);
    color: var(--text);
}
.fa-viewer-btn:disabled,
.fa-folder-tab:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    pointer-events: none;
}
.fa-viewer-trash-btn { color: var(--err); }
.fa-viewer-trash-btn:hover:not(:disabled) { background-color: var(--err-dim); }

.fa-folder-tabs {
    display: inline-flex;
    gap: 2px;
    padding: 4px;
    border-radius: 8px;
    background: var(--surface-2);
    border: 1px solid var(--border);
}
.fa-folder-tab {
    padding: 6px 14px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--text-3);
    font-family: var(--font);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
}
.fa-folder-tab:hover:not(:disabled) {
    background: var(--surface-3);
    color: var(--text);
}
.fa-folder-tab.is-active {
    background: #2563eb;
    color: #fff;
}

.fa-mail-source-tabs {
    display: inline-flex;
    gap: 4px;
    padding: 3px;
    border-radius: 8px;
    background: var(--surface-2);
    border: 1px solid var(--border);
}
.fa-mail-source-tab {
    border: none;
    background: transparent;
    color: var(--text-3);
    font-size: 12px;
    font-weight: 500;
    padding: 6px 12px;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.fa-mail-source-tab:hover:not(:disabled) {
    color: var(--text);
    background: var(--surface-3);
}
.fa-mail-source-tab.is-active {
    background: var(--ok-dim);
    color: var(--text);
}
.fa-mail-source-tab:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.fa-mail-cache-banner {
    margin-bottom: 12px;
    padding: 10px 14px;
    border-radius: 8px;
    font-size: 13px;
    line-height: 1.45;
    border: 1px solid rgba(59, 130, 246, 0.35);
    background: rgba(59, 130, 246, 0.1);
    color: var(--text);
}
.fa-mail-cache-banner.is-archive-mode {
    border-color: rgba(16, 185, 129, 0.35);
    background: var(--ok-dim);
    color: var(--text);
}
.fa-mail-cache-banner.is-empty {
    border-color: var(--border);
    background: var(--surface-2);
    color: var(--text-3);
}

.fa-mail-search-row { margin-bottom: 14px; }
.fa-mail-search {
    display: flex;
    gap: 8px;
    align-items: center;
    position: relative;
    flex: 1;
}
.fa-mail-search-icon {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-ghost);
    pointer-events: none;
    z-index: 1;
}
.fa-mail-search-input {
    flex: 1;
    font-size: 13px;
    padding-left: 38px;
    background-color: var(--surface-2);
    border-color: var(--border);
    color: var(--text);
}
.fa-mail-search-btn { flex-shrink: 0; }

.fa-mail-status-block { margin-bottom: 10px; }
.fa-mail-status-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}
.fa-mail-count {
    margin: 0;
    font-size: 13px;
    color: var(--text-3);
}
.fa-mail-hint {
    margin: 0;
    font-size: 12px;
    color: var(--text-3);
}
.fa-mail-pager {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}
.fa-mail-page-input {
    width: 52px;
    padding: 6px 8px;
    text-align: center;
    font-size: 12px;
}
.fa-mail-page-label {
    font-size: 12px;
    color: var(--text-3);
}

.fa-mail-list-wrap {
    position: relative;
    min-height: 280px;
    max-height: min(560px, calc(100vh - 420px));
    overflow-y: auto;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--surface-2);
}
.fa-mail-list-wrap.is-loading::after,
.fa-mail-modal-body.is-loading::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--amy) 50%,
        transparent 100%
    );
    background-size: 200% 100%;
    animation: fa-mail-loading 0.9s linear infinite;
    pointer-events: none;
    z-index: 2;
}
@keyframes fa-mail-loading {
    from { background-position: 100% 0; }
    to   { background-position: -100% 0; }
}
.fa-mail-empty {
    padding: 48px 24px;
    text-align: center;
    color: var(--text-3);
    font-size: 13px;
}
.fa-mail-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
    transition: background var(--dur-fast) var(--easing);
}
.fa-mail-row:last-child { border-bottom: none; }
.fa-mail-row:hover { background: var(--surface-3); }
.fa-mail-row-main { flex: 1; min-width: 0; }
.fa-mail-row-subject {
    margin: 0 0 4px;
    font-size: 14px;
    font-weight: 500;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.fa-mail-row.is-unread .fa-mail-row-subject { font-weight: 600; }
.fa-mail-row-from {
    margin: 0 0 2px;
    font-size: 13px;
    color: var(--text-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.fa-mail-row-to {
    margin: 0;
    font-size: 12px;
    color: var(--text-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.fa-mail-row-side {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}
.fa-mail-row-date {
    font-size: 12px;
    color: var(--text-3);
    white-space: nowrap;
}
.fa-mail-row-actions { display: flex; gap: 4px; }
.fa-mail-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--text-3);
    cursor: pointer;
    padding: 0;
}
.fa-mail-spam-btn:hover {
    background: rgba(249, 115, 22, 0.15);
    color: #fdba74;
}
.fa-mail-del-btn:hover {
    background: rgba(239, 68, 68, 0.15);
    color: #fca5a5;
}
.fa-mail-error {
    padding: 24px;
    color: var(--err);
    font-size: 13px;
    text-align: center;
}
#fa-compose-panel[hidden],
#fa-inbox-panel[hidden],
#fa-drive-panel[hidden],
#fa-photos-panel[hidden],
#fa-scanner-panel[hidden],
#fa-logos-panel[hidden] {
  display: none !important;
}

#fa-drive-panel:not([hidden]),
#fa-photos-panel:not([hidden]) {
  display: block;
  width: 100%;
}

.fa-mail-modal {
    position: fixed;
    inset: 0;
    z-index: 1200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.fa-mail-modal[hidden] { display: none !important; }
.fa-mail-modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(8, 8, 14, 0.62);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.fa-mail-modal-dialog {
    position: relative;
    z-index: 1;
    width: min(1024px, 100%);
    height: min(85vh, 900px);
    display: flex;
    flex-direction: column;
    border-radius: var(--r-l);
    border: 1px solid var(--border-hi);
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), transparent 35%), var(--surface);
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.55);
    overflow: hidden;
    animation: confirmDialogIn 0.16s var(--easing);
}
.fa-mail-modal-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 18px 20px;
    border-bottom: 1px solid var(--border);
    background: var(--surface-2);
    flex-shrink: 0;
}
.fa-mail-modal-meta { flex: 1; min-width: 0; }
.fa-mail-modal-subject {
    margin: 0 0 10px;
    font-size: 17px;
    font-weight: 600;
    color: var(--text);
    letter-spacing: -0.01em;
    word-break: break-word;
}
.fa-mail-modal-fields {
    margin: 0;
    font-size: 12px;
    color: var(--text-2);
    line-height: 1.55;
}
.fa-mail-modal-fields p { margin: 0 0 3px; }
.fa-mail-modal-fields .label {
    font-weight: 600;
    color: var(--text-3);
    text-transform: uppercase;
    font-size: 10px;
    letter-spacing: 0.06em;
    margin-right: 4px;
}
.fa-mail-modal-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    flex-wrap: wrap;
}
.fa-mail-act {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 13px;
    border: 1px solid transparent;
    border-radius: var(--r-s);
    font-family: var(--font);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: background var(--dur-fast) var(--easing), border-color var(--dur-fast) var(--easing);
}
.fa-mail-act-reply {
    background: var(--amy-dim);
    border-color: rgba(34, 211, 238, 0.28);
    color: var(--amy-hi);
}
.fa-mail-act-reply:hover {
    background: rgba(34, 211, 238, 0.16);
    border-color: rgba(34, 211, 238, 0.4);
}
.fa-mail-act-spam {
    background: var(--warn-dim);
    border-color: rgba(245, 158, 11, 0.28);
    color: #fcd34d;
}
.fa-mail-act-spam:hover {
    background: rgba(245, 158, 11, 0.16);
    border-color: rgba(245, 158, 11, 0.4);
}
.fa-mail-act-del {
    background: var(--err-dim);
    border-color: rgba(239, 68, 68, 0.28);
    color: #fca5a5;
}
.fa-mail-act-del:hover {
    background: rgba(239, 68, 68, 0.16);
    border-color: rgba(239, 68, 68, 0.4);
}
.fa-mail-act-close {
    background: var(--surface-3);
    border-color: var(--border);
    color: var(--text-2);
    font-size: 18px;
    line-height: 1;
    padding: 4px 11px;
}
.fa-mail-act-close:hover {
    background: var(--border-hi);
    color: var(--text);
}
.fa-mail-modal-body {
    flex: 1;
    overflow: auto;
    background: var(--surface-3);
    min-height: 0;
    padding: 16px;
    position: relative;
}
.fa-mail-modal-body iframe {
    width: 100%;
    min-height: calc(100% - 8px);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    display: block;
    background: #fff;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}
.fa-mail-modal-body .fa-mail-empty,
.fa-mail-modal-body .fa-mail-error {
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    background: var(--surface-2);
}
.fa-mail-detail-text {
    padding: 18px 20px;
    font-size: 13px;
    line-height: 1.6;
    white-space: pre-wrap;
    word-break: break-word;
    color: var(--text);
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-s);
}

/* ------------------------------------------------------------------ /values */
.values-layout {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 28px;
    align-items: start;
}
@media (max-width: 960px) {
    .values-layout {
        grid-template-columns: 1fr;
        gap: 18px;
    }
}
.section-title {
    font-size: 12px;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    font-weight: 600;
}
.profile-rail .card-head {
    padding: 14px 16px 10px;
    border-bottom: none;
}
.profile-rail .card-body { padding: 6px; }
.profile-rail .card-foot {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    padding: 10px 12px 12px;
    border-top: 1px solid var(--border);
}
.profile-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.profile-card {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: var(--r-s);
    border: 1px solid transparent;
    background: transparent;
    color: var(--text-2);
    text-decoration: none;
    font-size: 13px;
    line-height: 1.2;
    transition: background var(--d-1) var(--e-out), color var(--d-1) var(--e-out), border-color var(--d-1) var(--e-out);
    cursor: pointer;
    min-width: 0;
}
.profile-card:hover {
    background: var(--surface-2);
    color: var(--text);
}
.profile-card.is-selected {
    background: color-mix(in oklab, var(--amy) 12%, transparent);
    border-color: var(--amy-ring);
    color: var(--text);
}
.profile-card.is-selected .pf-name { font-weight: 600; }
.pf-icon {
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--text-3);
}
.profile-card.is-selected .pf-icon {
    background: var(--amy-dim);
    border-color: var(--amy-ring);
    color: var(--amy);
}
.pf-icon svg { width: 14px; height: 14px; }
.pf-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.pf-name {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.pf-meta {
    font-size: 10.5px;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.pf-active {
    flex: 0 0 auto;
    font-size: 9.5px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--amy);
    font-weight: 600;
    padding: 2px 7px;
    border-radius: 999px;
    background: var(--amy-dim);
    border: 1px solid var(--amy-ring);
}
.editor-pane .card-head { padding: 12px 16px; }
.editor-head {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    width: 100%;
}
.editor-head .title {
    font-size: 16px;
    font-weight: 600;
    color: var(--text);
    letter-spacing: -0.01em;
    margin-right: 4px;
}
.field-grid {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.field-row {
    display: grid;
    grid-template-columns: 180px minmax(0, 1fr);
    align-items: center;
    gap: 14px;
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    background: var(--surface-2);
    transition: border-color var(--d-1) var(--e-out);
}
.field-row:focus-within { border-color: var(--amy-ring); }
.field-row .label {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.field-row .label .name {
    color: var(--text);
    font-size: 13px;
    font-weight: 500;
}
.field-row .label .hint {
    color: var(--text-3);
    font-size: 11px;
    line-height: 1.3;
}
.field-row .input {
    background: var(--surface);
    border-color: var(--border-hi);
}
@media (max-width: 720px) {
    .field-row { grid-template-columns: 1fr; gap: 6px; }
}
.editor-pane .card-foot {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
}
.values-layout > .card .card-foot {
    background: var(--surface);
}

/* ------------------------------------------------------------------ /quick */
.quick-layout {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 28px;
    align-items: start;
}
@media (max-width: 960px) {
    .quick-layout { grid-template-columns: 1fr; gap: 18px; }
}
.quick-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 14px;
}
.quick-field > label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-3);
    font-weight: 600;
}
.quick-two-col {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
}
@media (max-width: 720px) {
    .quick-two-col { grid-template-columns: 1fr; }
}
.quick-summary {
    border: 1px solid var(--border);
    border-radius: var(--r-s);
    background: var(--surface-2);
    padding: 12px 14px;
    margin-bottom: 14px;
}
.quick-summary dl {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 6px 14px;
    margin: 0;
    font-size: 12.5px;
}
.quick-summary dt {
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 10.5px;
    font-weight: 600;
    padding-top: 2px;
}
.quick-summary dd { margin: 0; color: var(--text); min-width: 0; }
.values-profile-chip {
    display: inline-block;
    font-size: 11px;
    padding: 1px 8px;
    border-radius: 999px;
    background: color-mix(in oklab, var(--amy) 10%, transparent);
    border: 1px solid var(--amy-ring);
    color: var(--amy);
    text-transform: lowercase;
    letter-spacing: 0.02em;
}
.values-preview-grid {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    column-gap: 14px;
    row-gap: 3px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--border);
    font-size: 12px;
}
.values-preview-grid .k {
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-size: 10px;
    font-weight: 600;
    padding-top: 1px;
}
.values-preview-grid .v {
    color: var(--text);
    overflow-wrap: anywhere;
    min-width: 0;
}
.missing-values-card {
    margin-bottom: 14px;
    padding: 14px 16px;
    border-radius: var(--r-m);
    border: 1px solid color-mix(in oklab, orange 28%, var(--border));
    background: color-mix(in oklab, orange 6%, var(--surface));
}
.missing-values-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
    font-size: 12px;
    font-weight: 600;
    color: color-mix(in oklab, orange 70%, var(--text));
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.missing-values-head svg { width: 14px; height: 14px; flex: 0 0 auto; }
.missing-values-hint {
    font-size: 11.5px;
    color: var(--text-3);
    margin: 0 0 12px;
    line-height: 1.45;
    text-transform: none;
    letter-spacing: 0;
}
.empty-card {
    background: var(--surface);
    border: 1px dashed var(--border-hi);
    border-radius: var(--r-m);
    padding: 40px 24px;
    text-align: center;
    color: var(--text-2);
}
.empty-card h3 { margin: 0 0 6px; color: var(--text); font-size: 16px; }
.empty-card p { margin: 0 0 18px; font-size: 13px; color: var(--text-3); }
.send-result:not(:empty) { margin-top: 14px; }
.send-result.error { color: var(--err, #e24f4f); }
.send-result.ok { color: var(--amy); }
.quick-footer {
    display: flex;
    align-items: center;
    gap: 10px;
    justify-content: flex-end;
    margin-top: 18px;
}
.editor-head .actions { margin-left: auto; display: flex; gap: 8px; }
.pf-icon .brand-icon { width: 20px; height: 20px; }

/* FA Crypto Scanner */
.fa-scanner-hero {
    margin-bottom: 16px;
    padding: 0;
    overflow: hidden;
    background: linear-gradient(135deg, rgba(59, 130, 246, 0.12) 0%, rgba(139, 92, 246, 0.08) 50%, rgba(17, 19, 24, 0.95) 100%);
    border-color: rgba(96, 165, 250, 0.25);
}
.fa-scanner-hero-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 22px 24px;
    flex-wrap: wrap;
}
.fa-scanner-title {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 6px;
    font-size: 18px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--text);
}
.fa-scanner-title svg {
    color: #93c5fd;
}
.fa-scanner-sub {
    margin: 0;
    font-size: 13px;
    color: var(--text-3);
    max-width: 520px;
    line-height: 1.5;
}
.fa-scanner-controls {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.fa-scanner-select {
    min-width: 240px;
}
.fa-scanner-run {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
}
.fa-scanner-idle {
    text-align: center;
    padding: 48px 24px;
    margin-bottom: 16px;
}
.fa-scanner-idle-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 72px;
    height: 72px;
    border-radius: 50%;
    background: rgba(59, 130, 246, 0.1);
    border: 1px solid rgba(96, 165, 250, 0.2);
    color: #93c5fd;
    margin-bottom: 16px;
}
.fa-scanner-idle-title {
    margin: 0 0 8px;
    font-size: 16px;
    font-weight: 600;
}
.fa-scanner-idle-sub {
    margin: 0;
    font-size: 13px;
    max-width: 360px;
    margin-inline: auto;
    line-height: 1.5;
}
.fa-scanner-loading {
    position: relative;
    padding: 28px 24px 24px;
    margin-bottom: 16px;
}
.fa-scanner-progress-wrap {
    margin-bottom: 12px;
}
.fa-scanner-progress-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}
.fa-scanner-progress-pct {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.03em;
    color: #93c5fd;
    font-variant-numeric: tabular-nums;
}
.fa-scanner-progress-status {
    font-size: 12px;
    text-align: right;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fa-scanner-progress-track {
    height: 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.06);
    overflow: hidden;
    border: 1px solid rgba(96, 165, 250, 0.15);
}
.fa-scanner-progress-fill {
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, #3b82f6, #8b5cf6);
    transition: width 0.35s var(--easing);
    box-shadow: 0 0 12px rgba(96, 165, 250, 0.45);
}
.fa-scanner-loading-note {
    margin: 0;
    font-size: 12px;
    text-align: center;
}
.fa-scanner-stats {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
    margin-bottom: 16px;
}
@media (max-width: 900px) {
    .fa-scanner-stats { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
    .fa-scanner-stats { grid-template-columns: 1fr; }
}
.fa-scanner-stat {
    padding: 18px 20px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: rgba(17, 19, 24, 0.7);
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.fa-scanner-stat--blue { border-color: rgba(96, 165, 250, 0.3); background: rgba(59, 130, 246, 0.08); }
.fa-scanner-stat--purple { border-color: rgba(167, 139, 250, 0.3); background: rgba(139, 92, 246, 0.08); }
.fa-scanner-stat--amber { border-color: rgba(251, 191, 36, 0.3); background: rgba(245, 158, 11, 0.08); }
.fa-scanner-stat--red { border-color: rgba(248, 113, 113, 0.35); background: rgba(239, 68, 68, 0.08); }
.fa-scanner-stat-val {
    font-size: 28px;
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1;
    color: var(--text);
}
.fa-scanner-stat-label {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-3);
}
.fa-scanner-stat-sub {
    font-size: 11px;
}
.fa-scanner-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
    margin-bottom: 14px;
}
@media (max-width: 768px) {
    .fa-scanner-grid { grid-template-columns: 1fr; }
}
.fa-scanner-panel-card {
    padding: 18px 20px;
}
.fa-scanner-card-title {
    margin: 0 0 4px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: -0.01em;
}
.fa-scanner-card-sub {
    margin: 0 0 14px;
    font-size: 11px;
}
.fa-scanner-bars {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.fa-scanner-bar-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.fa-scanner-bar-meta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    font-size: 12px;
}
.fa-scanner-bar-label {
    color: var(--text);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fa-scanner-bar-val {
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}
.fa-scanner-bar-track {
    height: 6px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.06);
    overflow: hidden;
}
.fa-scanner-bar-fill {
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, #3b82f6, #8b5cf6);
    transition: width 0.5s var(--easing);
}
.fa-scanner-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.fa-scanner-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 500;
    background: rgba(59, 130, 246, 0.12);
    border: 1px solid rgba(96, 165, 250, 0.25);
    color: #bfdbfe;
}
.fa-scanner-tag em {
    font-style: normal;
    font-size: 11px;
    font-weight: 700;
    color: #93c5fd;
    background: rgba(59, 130, 246, 0.2);
    padding: 1px 7px;
    border-radius: 999px;
}
.fa-scanner-empty {
    margin: 0;
    font-size: 12px;
    padding: 8px 0;
}
.fa-scanner-findings-card {
    padding: 18px 20px;
}
.fa-scanner-findings-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}
.fa-scanner-findings {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.fa-scanner-finding {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 14px 16px 14px 18px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: rgba(17, 19, 24, 0.6);
    border-left-width: 3px;
}
.fa-scanner-finding-body {
    flex: 1;
    min-width: 0;
}
.fa-scanner-goto-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    white-space: nowrap;
    font-size: 12px;
    padding: 8px 14px;
    border-color: rgba(96, 165, 250, 0.35);
    color: #93c5fd;
    background: rgba(59, 130, 246, 0.1);
}
.fa-scanner-goto-btn:hover {
    background: rgba(59, 130, 246, 0.18);
    border-color: rgba(96, 165, 250, 0.55);
    color: #bfdbfe;
}
.fa-scanner-goto-btn svg {
    flex-shrink: 0;
}
@media (max-width: 640px) {
    .fa-scanner-finding {
        flex-direction: column;
        align-items: stretch;
    }
    .fa-scanner-goto-btn {
        justify-content: center;
        width: 100%;
    }
}
.fa-scanner-finding--critical { border-left-color: #ef4444; }
.fa-scanner-finding--high { border-left-color: #f97316; }
.fa-scanner-finding--medium { border-left-color: #eab308; }
.fa-scanner-finding--low { border-left-color: #64748b; }
.fa-scanner-finding-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 6px;
}
.fa-scanner-sev {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 2px 8px;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.06);
    color: var(--text-3);
}
.fa-scanner-finding--critical .fa-scanner-sev { background: rgba(239, 68, 68, 0.2); color: #fca5a5; }
.fa-scanner-finding--high .fa-scanner-sev { background: rgba(249, 115, 22, 0.2); color: #fdba74; }
.fa-scanner-finding--medium .fa-scanner-sev { background: rgba(234, 179, 8, 0.2); color: #fde047; }
.fa-scanner-folder {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-3);
    padding: 2px 8px;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.04);
}
.fa-scanner-finding-subject {
    margin: 0 0 4px;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
}
.fa-scanner-finding-from {
    margin: 0 0 8px;
    font-size: 12px;
}
.fa-scanner-finding-acct {
    color: #93c5fd;
}
.fa-scanner-finding-snippet {
    margin: 0 0 10px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-3);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.fa-scanner-finding-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.fa-scanner-hit-tag {
    font-size: 10px;
    font-weight: 600;
    padding: 3px 8px;
    border-radius: 999px;
    text-transform: lowercase;
    background: rgba(255, 255, 255, 0.06);
    color: var(--text-3);
}
.fa-scanner-hit-tag--critical { background: rgba(239, 68, 68, 0.15); color: #fca5a5; }
.fa-scanner-hit-tag--high { background: rgba(249, 115, 22, 0.15); color: #fdba74; }
.fa-scanner-hit-tag--medium { background: rgba(234, 179, 8, 0.15); color: #fde047; }
.fa-scanner-no-hits {
    text-align: center;
    padding: 36px 20px;
    color: var(--text-3);
}
.fa-scanner-no-hits svg {
    color: #4ade80;
    margin-bottom: 12px;
}
.fa-scanner-no-hits p {
    margin: 0 0 4px;
    font-size: 14px;
    font-weight: 500;
    color: var(--text);
}
.fa-scanner-error {
    padding: 12px 0;
}

.fa-findings-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.fa-findings-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.fa-findings-group-label {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-3);
    padding: 0 4px 4px;
}
.fa-finding-row {
    display: grid;
    grid-template-columns: minmax(72px, 0.7fr) minmax(0, 2fr) minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: rgba(17, 19, 24, 0.5);
    border-left: 3px solid var(--border);
    font-size: 12px;
}
.fa-finding-row--critical { border-left-color: #ef4444; }
.fa-finding-row--high { border-left-color: #f97316; }
.fa-finding-row--medium { border-left-color: #eab308; }
.fa-finding-row--low { border-left-color: #64748b; }
.fa-finding-reason {
    font-size: 10px;
    font-weight: 600;
    text-transform: lowercase;
    color: #93c5fd;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fa-finding-subj {
    font-weight: 500;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fa-finding-meta {
    font-size: 10px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fa-scanner-goto-btn--sm {
    padding: 5px 10px;
    font-size: 11px;
}
@media (max-width: 720px) {
    .fa-finding-row {
        grid-template-columns: 1fr auto;
        grid-template-rows: auto auto;
    }
    .fa-finding-reason { grid-column: 1; }
    .fa-finding-subj { grid-column: 1 / -1; }
    .fa-finding-meta { grid-column: 1; }
    .fa-scanner-goto-btn--sm { grid-column: 2; grid-row: 1; }
}

/* FA Logos manager */
.fa-logos-hero {
    margin-bottom: 18px;
    padding: 22px 24px;
}
.fa-logos-hero-inner {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 18px;
    flex-wrap: wrap;
}
.fa-logos-title {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 8px;
    font-size: 18px;
    font-weight: 600;
}
.fa-logos-title svg { color: var(--amy); }
.fa-logos-sub {
    margin: 0;
    max-width: 560px;
    font-size: 13px;
    line-height: 1.5;
}
.fa-logos-search-wrap { min-width: 220px; flex: 0 1 280px; }
.fa-logos-search { width: 100%; }
.fa-logos-status {
    margin: 0 0 14px;
    font-size: 12px;
}
.fa-logos-status.ok { color: var(--ok); }
.fa-logos-status.err { color: var(--err); }
.fa-logos-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 14px;
}
.fa-logo-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px;
    border-radius: var(--r-m);
    background: var(--surface);
    border: 1px solid var(--border);
}
.fa-logo-preview {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 88px;
    border-radius: var(--r-s);
    background: var(--surface-2);
    border: 1px dashed var(--border-hi);
    overflow: hidden;
}
.fa-logo-preview img {
    max-width: 72px;
    max-height: 72px;
    object-fit: contain;
}
.fa-logo-meta { min-height: 42px; }
.fa-logo-name {
    margin: 0;
    font-size: 13px;
    font-weight: 600;
}
.fa-logo-id {
    margin: 4px 0 0;
    font-size: 11px;
}
.fa-logo-badge {
    align-self: flex-start;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 3px 8px;
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--text-3);
    border: 1px solid var(--border);
}
.fa-logo-badge.is-custom {
    color: var(--amy);
    border-color: color-mix(in srgb, var(--amy) 35%, var(--border));
    background: color-mix(in srgb, var(--amy) 10%, transparent);
}
.fa-logo-actions {
    display: flex;
    gap: 8px;
    margin-top: auto;
}
.fa-logo-upload-btn {
    flex: 1;
    justify-content: center;
    cursor: pointer;
}
.fa-logo-upload-btn.is-busy { opacity: 0.6; pointer-events: none; }
.fa-logos-loading,
.fa-logos-empty {
    grid-column: 1 / -1;
    padding: 48px 20px;
    text-align: center;
}

/* ------------------------------------------------------------------ /mass */
.mass-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(280px, 0.8fr);
    gap: 28px;
    align-items: start;
}
@media (max-width: 960px) {
    .mass-layout { grid-template-columns: 1fr; gap: 18px; }
}
.mass-section-label {
    margin: 0 0 12px;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-3);
    font-weight: 600;
}
.mass-lines {
    min-height: 160px;
    font-family: var(--mono, ui-monospace, monospace);
    font-size: 12.5px;
    line-height: 1.5;
}
.mass-line-count {
    margin: 6px 0 0;
    font-size: 12px;
}
.mass-delay-row {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
}
.mass-delay-row .input {
    width: 100px;
    flex: 0 0 auto;
}
.mass-delay-presets {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.mass-actions {
    margin-top: 8px;
}
.mass-status-card {
    position: sticky;
    top: 24px;
}
.mass-progress-bar-wrap {
    height: 8px;
    border-radius: 999px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    overflow: hidden;
    margin-bottom: 12px;
}
.mass-progress-bar {
    height: 100%;
    width: 0;
    background: linear-gradient(90deg, var(--accent), var(--accent-2, var(--accent)));
    transition: width 0.35s ease;
}
.mass-status-line {
    margin: 0 0 6px;
    font-size: 13px;
    font-weight: 600;
}
.mass-status-current {
    margin: 0 0 10px;
    font-size: 12px;
}
.mass-error-list {
    margin: 0;
    padding-left: 18px;
    font-size: 12px;
    color: var(--err);
    max-height: 220px;
    overflow: auto;
}
.mass-fields-empty {
    padding: 12px 0;
    font-size: 12px;
}

/* ==================================================================
   sessions panel — list + session details modal
   ================================================================== */

.session-table .session-row {
    cursor: pointer;
    transition: background var(--dur-fast) var(--easing);
}
.session-table-cards .session-row td {
    padding: 16px 14px;
    vertical-align: middle;
}
.session-table-cards .session-row {
    min-height: 84px;
}
.session-cell-stack {
    display: grid;
    gap: 4px;
}
.session-cell-primary {
    font-size: 13px;
    line-height: 1.35;
    word-break: break-word;
}
.session-cell-secondary {
    font-size: 12px;
    line-height: 1.35;
    word-break: break-all;
}
.session-cell-meta {
    margin-top: 2px;
}
.session-cell-info {
    min-width: 180px;
    max-width: 260px;
}
.session-cell-creds {
    min-width: 200px;
    max-width: 320px;
}
.session-cred-line {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    max-width: 100%;
    flex-wrap: nowrap;
}
.session-cred-text {
    flex: 0 1 auto;
    min-width: 0;
    font-size: 13px;
    line-height: 1.35;
    word-break: break-all;
}
.session-cred-line .session-cred-text.muted {
    font-size: 12px;
    color: var(--text-3);
}
.session-copy-btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    margin: 0;
    padding: 0;
    border: none;
    border-radius: 0;
    background: transparent;
    color: var(--text-3);
    cursor: pointer;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: color var(--dur-fast) var(--easing);
}
.session-copy-btn svg {
    width: 13px;
    height: 13px;
    display: block;
}
.session-copy-btn:hover,
.session-copy-btn:focus-visible {
    color: var(--text);
    background: transparent;
    outline: none;
}
.session-copy-btn.copied {
    color: var(--ok);
    background: transparent;
}
.session-cell-creds .session-cell-secondary {
    user-select: all;
}
.session-cell-location {
    min-width: 180px;
    max-width: 280px;
}
.session-cell-started {
    min-width: 120px;
    white-space: nowrap;
}
.session-table-cards thead th {
    font-size: 11px;
    letter-spacing: 0.04em;
    text-transform: lowercase;
    color: var(--muted);
    padding: 10px 14px;
}
.session-table .session-row:hover,
.session-table .session-row:focus-visible {
    background: rgba(255, 255, 255, 0.03);
    outline: none;
}
.session-table .session-actions-col {
    width: auto;
    min-width: 120px;
    text-align: right;
    white-space: nowrap;
    padding-right: 10px;
}
.session-row-actions {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
}
.session-table .icon-btn {
    width: 36px;
    height: 36px;
    border-radius: 8px;
}
.session-table .icon-btn svg {
    width: 17px;
    height: 17px;
}
.session-table .session-row-delete {
    padding: 4px 10px;
    font-size: 11px;
    line-height: 1.2;
    opacity: 0.72;
}
.session-table .session-row:hover .icon-btn,
.session-table .session-row:focus-within .icon-btn {
    opacity: 1;
}
.session-table .icon-btn[disabled] {
    opacity: 0.28;
    cursor: not-allowed;
    pointer-events: none;
}
.session-captured-value {
    word-break: break-all;
    user-select: all;
}
.session-logs-dialog {
    max-width: 720px;
}
.session-logs-pre {
    margin: 0;
    max-height: 52vh;
    overflow: auto;
    padding: 14px 16px;
    border-radius: var(--r-m);
    border: 1px solid var(--border);
    background: rgba(0, 0, 0, 0.28);
    font-size: 12px;
    line-height: 1.55;
    white-space: pre-wrap;
    word-break: break-word;
    user-select: all;
}

.auth-codes-dialog {
    width: min(920px, 100%);
}
.auth-codes-body {
    display: grid;
    gap: 14px;
}
.auth-codes-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}
.auth-codes-toolbar-actions {
    display: inline-flex;
    gap: 8px;
    flex-wrap: wrap;
}
.auth-codes-count-pill {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: rgba(255, 255, 255, 0.04);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: lowercase;
    color: var(--text-3);
}
.auth-codes-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 14px;
}
.auth-code-card {
    display: grid;
    gap: 12px;
    padding: 14px;
    border-radius: var(--r-m);
    border: 1px solid var(--border);
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0.02));
}
.auth-code-card-head {
    min-width: 0;
}
.auth-code-issuer {
    font-size: 14px;
    font-weight: 700;
    line-height: 1.25;
    word-break: break-word;
}
.auth-code-account {
    margin-top: 4px;
    font-size: 11px;
    line-height: 1.35;
    word-break: break-all;
}
.auth-code-dial {
    position: relative;
    width: 148px;
    height: 148px;
    margin: 0 auto;
}
.auth-code-ring {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
}
.auth-code-ring-track {
    fill: none;
    stroke: rgba(255, 255, 255, 0.08);
    stroke-width: 5;
}
.auth-code-ring-progress {
    fill: none;
    stroke: var(--accent);
    stroke-width: 5;
    stroke-linecap: round;
    transition: stroke-dasharray 0.35s linear;
}
.auth-code-value {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 28px;
    font-weight: 700;
    letter-spacing: 0.08em;
}
.auth-code-remaining {
    position: absolute;
    left: 50%;
    bottom: 18px;
    transform: translateX(-50%);
    font-size: 11px;
    font-weight: 600;
    color: var(--text-3);
}
.auth-codes-empty,
.auth-codes-status {
    margin: 0;
    font-size: 12px;
}

.recovery-data-dialog {
    width: min(560px, 100%);
}
.recovery-data-body {
    display: flex;
    flex-direction: column;
    gap: 18px;
}
.recovery-data-section {
    margin: 0;
}
.recovery-backup-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 8px;
}
.recovery-backup-item {
    padding: 10px 12px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: var(--surface-2);
    font-size: 14px;
    letter-spacing: 0.08em;
    color: var(--text);
}
.recovery-contacts-list {
    display: grid;
    gap: 10px;
}
.recovery-contact-card {
    padding: 12px 14px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: var(--surface-2);
}
.recovery-contact-primary {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 4px;
}
.recovery-contact-line {
    font-size: 13px;
    line-height: 1.45;
}
.recovery-data-empty {
    margin: 0;
    font-size: 13px;
}

.session-modal {
    position: fixed;
    inset: 0;
    z-index: 1200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.session-modal[hidden] { display: none !important; }
.session-modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(8, 8, 14, 0.62);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.session-modal-dialog {
    position: relative;
    z-index: 1;
    width: min(520px, 100%);
    max-height: min(90vh, 860px);
    display: flex;
    flex-direction: column;
    min-height: 0;
    border-radius: var(--r-l);
    border: 1px solid var(--border-hi);
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), transparent 28%), var(--surface);
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.55);
    overflow: hidden;
    animation: confirmDialogIn 0.16s var(--easing);
}
.session-modal-head {
    padding: 20px 22px 14px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}
.session-modal-head h2 {
    margin: 0 0 4px;
    font-size: 18px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--text);
}
.session-modal-sub {
    margin: 0;
    font-size: 12px;
    line-height: 1.45;
}
.session-modal-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding: 0 22px 18px;
}
.session-kv {
    margin: 0;
    padding: 0;
}
.session-kv-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 11px 0;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
}
.session-kv-row dt {
    margin: 0;
    color: var(--text-2);
    font-weight: 400;
    flex: 0 1 42%;
    min-width: 0;
    word-break: break-word;
}
.session-kv-row dd {
    margin: 0;
    color: var(--text);
    text-align: right;
    word-break: break-word;
}
.session-section {
    margin-top: 18px;
}
.session-section-label {
    margin: 0 0 12px;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-3);
}
.session-timeline {
    list-style: none;
    margin: 0;
    padding: 0;
}
.session-timeline-item {
    display: flex;
    gap: 12px;
    padding: 0 0 14px;
    position: relative;
}
.session-timeline-item:not(:last-child)::before {
    content: "";
    position: absolute;
    left: 5px;
    top: 14px;
    bottom: 0;
    width: 1px;
    background: var(--border);
}
.session-timeline-dot {
    width: 11px;
    height: 11px;
    border-radius: 50%;
    flex-shrink: 0;
    margin-top: 3px;
    border: 2px solid var(--surface);
    box-shadow: 0 0 0 1px var(--border);
}
.session-timeline-dot.dot-blue  { background: #3b82f6; box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.35); }
.session-timeline-dot.dot-grey  { background: var(--text-3); }
.session-timeline-dot.dot-yellow{ background: #eab308; box-shadow: 0 0 0 1px rgba(234, 179, 8, 0.35); }
.session-timeline-dot.dot-green { background: var(--ok); box-shadow: 0 0 0 1px rgba(34, 197, 94, 0.35); }
.session-timeline-main {
    flex: 1;
    min-width: 0;
}
.session-timeline-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}
.session-timeline-label {
    font-size: 13px;
    color: var(--text);
}
.session-timeline-time {
    font-size: 11px;
    color: var(--text-3);
    flex-shrink: 0;
}
.session-timeline-detail {
    margin-top: 4px;
    font-size: 12px;
    color: #f87171;
    word-break: break-all;
}
.session-ua {
    margin: 0;
    padding: 12px 14px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    background: var(--surface-2);
    font-size: 11px;
    line-height: 1.55;
    color: var(--text-2);
    white-space: pre-wrap;
    word-break: break-word;
}
.session-modal-foot {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px 22px 18px;
    border-top: 1px solid var(--border);
    flex-shrink: 0;
}
.session-foot-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
.session-foot-row-main {
    justify-content: space-between;
}
.session-foot-row-tools {
    justify-content: flex-start;
}
.session-foot-row-tools:not(:has(.session-foot-btn:not([hidden]))) {
    display: none;
}
.session-foot-row-close {
    justify-content: flex-end;
    padding-top: 4px;
    border-top: 1px solid var(--border);
}
.session-modal-foot .session-foot-btn {
    font-size: 13px;
    padding: 8px 14px;
    white-space: nowrap;
}
.session-modal-foot .btn.err.ghost {
    color: var(--err);
    border-color: rgba(239, 68, 68, 0.35);
}
.session-modal-foot .btn.err.ghost:hover {
    background: var(--err-dim);
    border-color: rgba(239, 68, 68, 0.45);
}
.session-modal-foot .btn.ghost.session-foot-btn:not(.err) {
    color: var(--text);
    border-color: var(--border-hi);
    background: rgba(255, 255, 255, 0.02);
}
.session-modal-foot .btn.ghost.session-foot-btn:not(.err):hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: var(--border-hi);
}

/* panel pages (domains, settings, anti-bot stubs) */
.sessions-card { min-height: 360px; }
.sessions-card .table-wrap {
    overflow-x: auto;
}

.panel-form-card {
    padding: 24px;
    display: grid;
    gap: 18px;
}

.grid-2 {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
}

.card-head-inline {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
}

.toggle {
    width: 44px;
    height: 24px;
    border-radius: 999px;
    background: var(--surface-3);
    border: 1px solid var(--border);
    position: relative;
    flex-shrink: 0;
}

.toggle::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--text-3);
    transition: transform 0.15s ease, background 0.15s ease;
}

.toggle.on {
    background: var(--blue-dim);
    border-color: var(--blue-ring);
}

.toggle.on::after {
    transform: translateX(20px);
    background: var(--blue);
}

button.toggle {
    cursor: pointer;
    padding: 0;
    appearance: none;
}

.panel-modal-dialog { width: min(480px, 100%); }

.panel-modal-form {
    display: grid;
    gap: 16px;
    padding-top: 4px;
}

.domain-add-error {
    font-size: 13px;
    color: var(--err);
}

.count-pill {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--surface-3);
    border: 1px solid var(--border);
    font-size: 12px;
    color: var(--text-2);
}

.avatar-dot {
    display: inline-block;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--surface-3);
    border: 1px solid var(--border);
}

.panel-role {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--blue-dim);
    color: var(--blue);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
}

.checkbox {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 13px;
    color: var(--text-2);
    cursor: pointer;
}

.checkbox input { accent-color: var(--blue); }

.domain-adder-input {
    resize: vertical;
    min-height: 140px;
    line-height: 1.5;
}

.domain-adder-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
}

.domain-adder-result {
    padding: 14px 16px;
    border-radius: var(--r-s);
    border: 1px solid var(--border);
    font-size: 13px;
    line-height: 1.5;
}

.domain-adder-result.ok {
    background: var(--ok-dim);
    border-color: rgba(52, 211, 153, 0.25);
    color: var(--ok);
}

.domain-adder-result.err {
    background: var(--err-dim);
    border-color: rgba(239, 68, 68, 0.25);
    color: var(--err);
}

.domain-adder-result pre {
    margin-top: 10px;
    padding: 10px 12px;
    border-radius: var(--r-s);
    background: rgba(0, 0, 0, 0.2);
    color: var(--text-2);
    white-space: pre-wrap;
    word-break: break-word;
}

@media (max-width: 720px) {
    .grid-2 { grid-template-columns: 1fr; }
}
.session-modal-head-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
}
.session-row-actions .btn.sm.session-row-launchBat {
  font-size: 0.72rem;
  padding: 0.35rem 0.55rem;
  white-space: nowrap;
}

.browser-watch-modal {
  position: fixed;
  inset: 0;
  z-index: 1400;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.browser-watch-modal.is-open {
  display: flex !important;
}
.browser-watch-modal[hidden]:not(.is-open) { display: none !important; }
.browser-watch-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(8, 8, 14, 0.78);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.browser-watch-dialog {
  position: relative;
  z-index: 1;
  width: min(1100px, 96vw);
  max-height: min(92vh, 900px);
  display: flex;
  flex-direction: column;
  border-radius: var(--r-l);
  border: 1px solid var(--border-hi);
  background: var(--surface);
  box-shadow: 0 28px 80px rgba(0, 0, 0, 0.65);
  overflow: hidden;
}
.browser-watch-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px 10px;
  border-bottom: 1px solid var(--border);
}
.browser-watch-head h2 {
  margin: 0 0 4px;
  font-size: 18px;
  font-weight: 600;
}
.browser-watch-sub {
  margin: 0;
  font-size: 12px;
}
.browser-watch-close {
  font-size: 22px;
  line-height: 1;
  flex-shrink: 0;
}
.browser-watch-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px;
  font-size: 12px;
  color: var(--text-2);
  border-bottom: 1px solid var(--border);
}
.browser-watch-slug {
  margin-left: auto;
  color: var(--text-3);
}
.browser-watch-frame {
  position: relative;
  flex: 1;
  min-height: 420px;
  max-height: min(68vh, 720px);
  background: #08080e;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.browser-watch-stream {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.browser-watch-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  text-align: center;
  color: var(--text-3);
  font-size: 13px;
  line-height: 1.5;
}
.browser-watch-frame.has-frame .browser-watch-empty,
.session-watch-frame.has-frame .browser-watch-empty {
  display: none;
}
.browser-watch-url {
  padding: 10px 18px 14px;
  font-size: 11px;
  line-height: 1.45;
  color: var(--text-3);
  word-break: break-all;
  border-top: 1px solid var(--border);
  max-height: 72px;
  overflow: auto;
}

.session-watch-live-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #e24;
  box-shadow: 0 0 8px rgba(226, 68, 68, 0.65);
  animation: watchPulse 1.2s ease-in-out infinite;
}
@keyframes watchPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

.session-watch-card {
  padding: 0;
  overflow: hidden;
  max-width: 1100px;
  margin: 0 auto;
}
.session-watch-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  color: var(--text-2);
}
.session-watch-slug {
  margin-left: auto;
  color: var(--text-3);
}
.session-watch-frame {
  position: relative;
  background: #08080e;
  min-height: min(60vh, 640px);
  display: flex;
  align-items: center;
  justify-content: center;
}
.session-watch-url {
  padding: 10px 16px 14px;
  font-size: 11px;
  line-height: 1.45;
  color: var(--text-3);
  word-break: break-all;
  border-top: 1px solid var(--border);
}

/* settings page — desktop-first, matches sessions/domains layout */
.settings-panel-card {
  margin-top: 18px;
}

.settings-panel-card:first-of-type {
  margin-top: 14px;
}

.settings-panel-body {
  padding: 20px 24px 24px;
  display: grid;
  gap: 8px;
}

.settings-fields-grid {
  display: grid;
  grid-template-columns: minmax(280px, 1fr) minmax(280px, 1fr);
  gap: 20px 28px;
  margin-bottom: 8px;
}

.settings-fields-grid .field {
  margin-bottom: 0;
}

.settings-fields-grid .input-row {
  display: flex;
  gap: 10px;
}

.settings-fields-grid .input-row .input {
  flex: 1;
  min-width: 0;
}

.settings-after-login {
  margin-top: 10px;
  margin-bottom: 0;
}

.settings-after-login .select {
  max-width: 360px;
}

.after-login-custom {
  margin-top: 12px;
}

.after-login-custom.is-hidden {
  display: none;
}

.settings-row-nested.after-login-custom {
  padding-top: 0;
}

.settings-row-nested.after-login-custom .input {
  margin-top: 8px;
  max-width: 420px;
}

.settings-save-status {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-3);
}

.settings-save-status.is-ok { color: var(--ok); }
.settings-save-status.is-err { color: var(--err); }

.settings-row-disabled {
  opacity: 0.45;
  pointer-events: none;
}

@media (max-width: 900px) {
  .settings-fields-grid {
    grid-template-columns: 1fr;
  }
}

/* ------------------------------------------------------------------ domains hub */
.domains-hub {
  display: flex;
  flex-direction: column;
  gap: 20px;
  width: 100%;
}

.domains-add-card {
  padding: 22px 24px 20px;
  border-radius: 14px;
}

.domains-add-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 16px;
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
}

.domains-add-plus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #1a73e8;
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
}

.domains-add-toolbar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}

.domains-add-row {
  display: flex;
  gap: 8px;
  align-items: center;
  width: 100%;
}

.domains-add-input {
  width: 100%;
  min-width: 0;
  height: 40px;
  max-height: 44px;
}

.domains-add-select {
  flex: 1 1 140px;
  min-width: 120px;
  height: 40px;
  max-height: 44px;
}

.domains-add-btn {
  flex: 0 0 auto;
  height: 40px;
  padding: 0 16px;
  border-radius: 10px;
  white-space: nowrap;
}

.domains-edit-select {
  width: 100%;
  max-width: 220px;
  height: 36px;
  margin-top: 4px;
}

@media (min-width: 721px) {
  .domains-add-toolbar {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    gap: 10px;
    align-items: center;
  }

  .domains-add-row {
    display: contents;
  }

  .domains-add-input {
    width: 100%;
  }

  .domains-add-select {
    flex: none;
    width: 150px;
  }
}

.domains-list-card {
  overflow: hidden;
  border-radius: 14px;
}

.domains-list-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 18px 22px;
  border-bottom: 1px solid var(--border);
}

.domains-list-head h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
}

.domains-globe {
  display: inline-flex;
  color: #1a73e8;
}

.domains-globe svg {
  width: 22px;
  height: 22px;
}

.domains-list {
  display: flex;
  flex-direction: column;
}

.domain-item {
  padding: 18px 22px;
  border-bottom: 1px solid var(--border);
}

.domain-item:last-child {
  border-bottom: none;
}

.domain-item-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.domain-item-host-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.domain-item-host {
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
}

.domain-badge {
  border: none;
  cursor: pointer;
  font: inherit;
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}

.domain-badge-ok {
  background: rgba(19, 115, 51, 0.22);
  color: #81c995;
}

.domain-badge-ok.is-off {
  background: var(--surface-3);
  color: var(--text-3);
}

.domain-item-meta {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--text-3);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
}

.domain-status {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.domain-status.is-active {
  background: rgba(19, 115, 51, 0.22);
  color: #81c995;
}

.domain-status.is-pending {
  background: rgba(251, 188, 4, 0.18);
  color: #fbbc04;
}

.domain-item-actions {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.domain-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
}

.domain-icon-btn:hover {
  background: var(--surface-2);
  color: var(--text);
}

.domain-icon-btn svg {
  width: 18px;
  height: 18px;
}

.domain-item-detail {
  margin-top: 14px;
  padding: 14px 16px;
  border-radius: 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px 20px;
}

.domain-ns-copy {
  border: none;
  background: transparent;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-align: left;
  display: block;
  width: 100%;
}

.domain-ns-copy:hover {
  color: #8ab4f8;
  text-decoration: underline;
}

.domain-ns-copy.is-copied {
  color: #81c995;
  text-decoration: none;
}

.domain-detail-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-3);
  margin-bottom: 4px;
}

.domain-detail-value {
  font-size: 13px;
  color: var(--text);
  line-height: 1.5;
}

.domain-detail-value + .domain-detail-value {
  margin-top: 2px;
}

.domains-edit-select {
  margin-top: 4px;
  max-width: 220px;
}

.domains-empty-state {
  padding: 32px 22px;
  text-align: center;
  font-size: 14px;
}

@media (max-width: 720px) {
  .domains-add-toolbar {
    flex-direction: column;
  }

  .domains-add-select,
  .domains-add-btn {
    width: 100%;
    flex: 1 1 auto;
  }

  .domain-item {
    padding: 14px 16px;
  }

  .domain-item-top {
    flex-wrap: wrap;
    gap: 10px;
  }

  .domain-item-main {
    flex: 1 1 100%;
    min-width: 0;
  }

  .domain-item-actions {
    margin-left: auto;
  }

  .domain-item-detail {
    grid-template-columns: 1fr;
    padding: 12px 14px;
  }

  .domains-edit-select {
    max-width: 100%;
    width: 100%;
  }
}

/* lockdown queue */
.setting-title-icon {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.setting-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}
.setting-icon-shield { color: #a78bfa; }
.setting-icon-shield-gold { color: #fbbf24; }
.setting-icon-bolt { color: #fbbf24; }
.setting-icon-lock { color: #f87171; }

.sessions-controls-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 14px;
}
.sessions-control-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px 18px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.02);
}
.sessions-control-copy {
  min-width: 0;
}
.sessions-control-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.sessions-control-desc {
  margin-top: 3px;
  font-size: 11px;
  color: var(--text-3);
}
.sessions-lockdown-queue {
  margin-bottom: 14px;
}
.sessions-lockdown-queue.is-hidden {
  display: none;
}
.lockdown-queue-head-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.lockdown-queue-card.is-hidden {
  display: none;
}

.strength-segment {
  display: inline-flex;
  gap: 0;
  margin-top: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.02);
}
.strength-segment-btn {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-2);
  font-size: 11px;
  font-weight: 600;
  padding: 8px 14px;
  cursor: pointer;
  border-right: 1px solid var(--border);
  text-transform: lowercase;
}
.strength-segment-btn:last-child {
  border-right: 0;
}
.strength-segment-btn:hover {
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
}
.strength-segment-btn.is-active {
  background: rgba(239, 68, 68, 0.18);
  color: #fca5a5;
}
.antibot-strength-row .setting-desc {
  margin-top: 8px;
}

.lockdown-queue-card {
  overflow: hidden;
}
.lockdown-queue-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 20px;
  border-bottom: 1px solid var(--border);
}
.lockdown-queue-body {
  padding: 16px 20px 18px;
}
.lockdown-queue-empty {
  margin: 0;
  font-size: 12px;
}
.lockdown-queue-foot {
  margin-top: 12px;
  font-size: 12px;
}
.lockdown-queue-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.lockdown-queue-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.02);
}
.lockdown-queue-item-main {
  min-width: 0;
  flex: 1;
}
.lockdown-queue-ip {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 4px;
}
.lockdown-queue-loc {
  font-size: 12px;
  color: var(--text-2);
  margin-bottom: 4px;
}
.lockdown-queue-ua {
  font-size: 11px;
  color: var(--text-3);
  line-height: 1.45;
  word-break: break-word;
}
.lockdown-queue-actions {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
}
.lockdown-approve {
  color: #86efac;
  border-color: rgba(134, 239, 172, 0.22);
}
.lockdown-approve:hover {
  background: rgba(134, 239, 172, 0.08);
  border-color: rgba(134, 239, 172, 0.4);
  color: #bbf7d0;
}
.lockdown-deny {
  color: var(--err);
  border-color: rgba(239, 68, 68, 0.25);
}
.lockdown-deny:hover {
  background: var(--err-dim);
  border-color: rgba(239, 68, 68, 0.45);
}
.lockdown-queue-item.is-leaving {
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
  transition: opacity 0.16s ease, transform 0.16s ease;
}
.lockdown-queue-page-card {
  padding: 0;
  overflow: hidden;
}
.lockdown-queue-list-page {
  padding: 8px;
}
.lockdown-queue-list-page .lockdown-queue-item {
  border-radius: 0;
  border-left: 0;
  border-right: 0;
  border-top: 0;
}
.lockdown-queue-list-page .lockdown-queue-item:last-child {
  border-bottom: 0;
}
.lockdown-queue-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 14px;
}
.lockdown-queue-page-label {
  font-size: 12px;
  color: var(--text-2);
}
@media (max-width: 720px) {
  .sessions-controls-grid {
    grid-template-columns: 1fr;
  }
  .lockdown-queue-head,
  .lockdown-queue-item {
    flex-direction: column;
  }
  .lockdown-queue-actions {
    width: 100%;
  }
  .lockdown-queue-actions .btn {
    flex: 1;
  }
}

/* ------------------------------------------------------------------ drive viewer */
.drive-viewer-dialog {
  max-width: min(1100px, calc(100vw - 24px));
  width: 100%;
}

.drive-viewer-body {
  padding-top: 0;
}

.drive-viewer-layout {
  display: grid;
  grid-template-columns: minmax(220px, 320px) minmax(0, 1fr);
  gap: 14px;
  min-height: 420px;
}

.drive-viewer-list-pane {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-2);
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.drive-viewer-list-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
}

.drive-viewer-count {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
}

.drive-viewer-files {
  list-style: none;
  margin: 0;
  padding: 6px;
  overflow: auto;
  flex: 1 1 auto;
  max-height: 52vh;
}

.drive-viewer-file-btn {
  width: 100%;
  border: none;
  background: transparent;
  text-align: left;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  color: var(--text);
}

.drive-viewer-file.is-active .drive-viewer-file-btn,
.drive-viewer-file-btn:hover {
  background: var(--surface);
}

.drive-viewer-file-name {
  display: block;
  font-size: 13px;
  line-height: 1.35;
  word-break: break-word;
}

.drive-viewer-file-meta {
  display: block;
  font-size: 11px;
  margin-top: 2px;
}

.drive-viewer-preview-pane {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-2);
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.drive-viewer-preview-head {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
}

.drive-viewer-preview-name {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  word-break: break-word;
}

.drive-viewer-preview-meta {
  display: block;
  font-size: 11px;
  margin-top: 4px;
}

.drive-viewer-preview-stage {
  flex: 1 1 auto;
  overflow: auto;
  padding: 12px;
  min-height: 280px;
}

.drive-viewer-preview-placeholder {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
}

.drive-viewer-text {
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 12px;
  line-height: 1.45;
  max-height: 52vh;
  overflow: auto;
}

.drive-viewer-image,
.drive-viewer-video {
  max-width: 100%;
  max-height: 52vh;
  display: block;
  margin: 0 auto;
}

.drive-viewer-iframe {
  width: 100%;
  min-height: 52vh;
  border: none;
  border-radius: 8px;
  background: #fff;
}

.drive-viewer-status {
  margin: 10px 0 0;
  font-size: 12px;
}

.fa-drive-sub {
  margin: 6px 0 0;
  font-size: 12px;
  line-height: 1.45;
}

.fa-drive-layout {
  margin-top: 14px;
  min-height: 460px;
}

.fa-photos-controls {
  flex-wrap: wrap;
  justify-content: flex-end;
}

.fa-photos-search-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: min(100%, 320px);
}

.fa-photos-search-input {
  min-width: 220px;
  flex: 1 1 auto;
}

.photos-viewer-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: 14px;
  margin-top: 14px;
  min-height: 460px;
}

.photos-viewer-grid-pane {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: rgba(15, 23, 42, 0.35);
  padding: 10px;
}

.photos-viewer-grid-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.photos-viewer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(108px, 1fr));
  gap: 8px;
  max-height: 520px;
  overflow: auto;
  padding-right: 2px;
}

.photos-viewer-tile {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 6px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: rgba(2, 6, 23, 0.45);
  cursor: pointer;
  text-align: left;
  color: inherit;
}

.photos-viewer-tile:hover,
.photos-viewer-tile.is-active {
  border-color: rgba(96, 165, 250, 0.55);
  background: rgba(30, 41, 59, 0.75);
}

.photos-viewer-thumb-wrap {
  position: relative;
  display: block;
  aspect-ratio: 1;
  border-radius: 8px;
  overflow: hidden;
  background: rgba(15, 23, 42, 0.8);
}

.photos-viewer-thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.photos-viewer-badge {
  position: absolute;
  right: 6px;
  bottom: 6px;
  padding: 2px 6px;
  border-radius: 999px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: rgba(15, 23, 42, 0.85);
  color: var(--text-2);
}

.photos-viewer-tile-name {
  font-size: 11px;
  line-height: 1.3;
  color: var(--text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.photos-viewer-preview-pane {
  min-height: 460px;
}

.photos-viewer-preview-stage {
  min-height: 380px;
}

.photos-viewer-full,
.photos-viewer-video {
  max-height: 420px;
}

@media (max-width: 820px) {
  .drive-viewer-layout {
    grid-template-columns: 1fr;
    min-height: 0;
  }

  .drive-viewer-files {
    max-height: 220px;
  }

  .drive-viewer-preview-stage {
    min-height: 240px;
  }

  .photos-viewer-layout {
    grid-template-columns: 1fr;
    min-height: 0;
  }

  .photos-viewer-grid {
    max-height: 280px;
  }

  .photos-viewer-preview-stage {
    min-height: 240px;
  }
}

/* FA Tokens / OAuth tools */
.fa-tokens-hero { margin-bottom: 16px; }
.fa-tokens-title {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 600;
}
.fa-tokens-title svg { color: #60a5fa; }
.fa-tokens-sub { margin: 0; font-size: 13px; line-height: 1.5; max-width: 640px; }
.fa-tokens-card-title {
  margin: 0 0 6px;
  font-size: 14px;
  font-weight: 600;
}
.fa-tokens-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.fa-tools-check {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--text-2);
  cursor: pointer;
}
.fa-oauth-paste {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  resize: vertical;
}
.fa-tools-out {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: var(--r-s);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 11px;
  white-space: pre-wrap;
  word-break: break-all;
  max-height: 220px;
  overflow: auto;
}
.fa-tools-out.is-error { color: #fca5a5; border-color: rgba(239, 68, 68, 0.35); }
.fa-tools-codes {
  margin-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.fa-tools-code-row {
  padding: 10px 12px;
  border-radius: var(--r-s);
  border: 1px solid var(--border);
  background: var(--surface-2);
}
.fa-tools-code-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: 6px;
}
.fa-tools-code-label { font-size: 12px; font-weight: 600; }
.fa-tools-code-account { font-size: 11px; }
.fa-tools-code-main {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.fa-tools-code-value {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.12em;
}
.fa-tools-code-timer { font-size: 11px; }
.fa-tools-code-track {
  margin-top: 8px;
  height: 4px;
  border-radius: 999px;
  background: rgba(148, 163, 184, 0.25);
  overflow: hidden;
}
.fa-tools-code-fill {
  height: 100%;
  background: #34d399;
  transition: width 0.4s linear;
}
@media (max-width: 820px) {
  .fa-tokens-grid { grid-template-columns: 1fr !important; }
}

/* FA account scan modal (Noot-style overlay) */
.fa-scan-modal {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.fa-scan-modal[hidden] { display: none !important; }
.fa-scan-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
}
.fa-scan-modal-dialog {
  position: relative;
  z-index: 1;
  width: min(720px, 100%);
  max-height: 90vh;
  overflow-y: auto;
  padding: 20px;
  border-radius: var(--r-m, 12px);
  background: var(--surface, #1e293b);
  border: 1px solid var(--border, rgba(148,163,184,0.25));
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.fa-scan-modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}
.fa-scan-modal-title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
}
.fa-scan-modal-email {
  margin: 4px 0 0;
  font-size: 13px;
}
.fa-scan-modal-sub {
  margin: 4px 0 0;
  font-size: 11px;
}
.fa-scan-modal-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.fa-scan-modal-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border: 0;
  border-radius: var(--r-s, 8px);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  background: rgba(16, 185, 129, 0.9);
  color: #fff;
}
.fa-scan-modal-btn:disabled {
  opacity: 0.55;
  cursor: default;
}
.fa-scan-modal-btn.is-spinning svg {
  animation: fa-scan-spin 0.9s linear infinite;
}
@keyframes fa-scan-spin {
  to { transform: rotate(360deg); }
}
.fa-scan-modal-close {
  border: 0;
  background: transparent;
  color: var(--text-3, #94a3b8);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 6px;
}
.fa-scan-modal-close:hover { color: var(--text, #fff); }
.fa-scan-modal-progress-track {
  height: 8px;
  border-radius: 999px;
  background: var(--surface-2, #0f172a);
  overflow: hidden;
}
.fa-scan-modal-progress-fill {
  height: 100%;
  background: #10b981;
  transition: width 0.25s ease;
}
.fa-scan-modal-progress-status {
  margin: 6px 0 0;
  font-size: 12px;
}
.fa-scan-modal-quick {
  padding: 12px 14px;
}
.fa-scan-modal-quick-title {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 600;
}
.fa-scan-modal-quick-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
@media (max-width: 560px) {
  .fa-scan-modal-quick-grid { grid-template-columns: 1fr; }
}
.fa-scan-modal-quick-label {
  margin: 0 0 6px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.fa-scan-modal-folder-list,
.fa-scan-modal-brand-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 12px;
  display: grid;
  gap: 2px;
}
.fa-scan-modal-folder-list {
  grid-template-columns: 1fr 1fr;
  gap: 2px 12px;
}
.fa-scan-modal-hits {
  margin-top: 10px;
  font-size: 12px;
}
.fa-scan-modal-findings-wrap {
  min-height: 80px;
}
.fa-scan-modal-findings-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}
.fa-scan-modal-findings {
  max-height: 40vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.fa-scan-modal-error { color: #f87171; margin: 0; }
body.fa-scan-modal-open { overflow: hidden; }
