/* Channel Scanner — hand-written CSS, no build step, no external fonts.
 *
 * Everything is driven by the token block below, which is redefined once for
 * dark mode. Dark is not an inversion: surfaces get their own values so the
 * sidebar stays the darkest layer and cards still read as lifted.
 */

:root {
    color-scheme: light dark;

    --bg: #f4f5f7;            /* content pane */
    --bg-veil: rgba(244, 245, 247, 0.86);
    --surface: #ffffff;       /* cards, inputs */
    --surface-2: #eceef2;     /* sidebar */
    --surface-3: #e6e9ee;     /* chips, media backdrop */
    --hover: rgba(0, 0, 0, 0.05);

    --text: #14161a;
    --text-2: #43474e;
    /* Dark enough to clear 4.5:1 on the sidebar, the lightest surface it lands on. */
    --muted: #626873;

    --separator: rgba(0, 0, 0, 0.09);
    --separator-strong: rgba(0, 0, 0, 0.16);

    --accent: #0071e3;        /* links and accented text */
    --accent-solid: #0071e3;  /* filled controls */
    --on-accent: #ffffff;
    --accent-tint: rgba(0, 113, 227, 0.10);
    --ring: rgba(0, 113, 227, 0.35);

    --danger: #d1002a;
    --danger-tint: rgba(209, 0, 42, 0.08);
    --ok: #1a7f37;

    --shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.07);

    --r-sm: 8px;
    --r-md: 12px;
    --r-lg: 14px;
    --r-pill: 980px;

    --pane-x: clamp(16px, 3vw, 36px);

    --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto,
            "Helvetica Neue", Helvetica, Arial, sans-serif;
}

@media (prefers-color-scheme: dark) {
    :root {
        --bg: #0f1216;
        --bg-veil: rgba(15, 18, 22, 0.86);
        --surface: #181c22;
        --surface-2: #0a0c0f;
        --surface-3: #232830;
        --hover: rgba(255, 255, 255, 0.06);

        --text: #e9ecf1;
        --text-2: #b8bfc9;
        --muted: #8b93a0;

        --separator: rgba(255, 255, 255, 0.09);
        --separator-strong: rgba(255, 255, 255, 0.18);

        --accent: #6ab0ff;
        --accent-solid: #2f6fd0;
        --on-accent: #ffffff;
        --accent-tint: rgba(106, 176, 255, 0.14);
        --ring: rgba(106, 176, 255, 0.45);

        --danger: #ff7b7b;
        --danger-tint: rgba(255, 123, 123, 0.12);
        --ok: #4ade80;

        --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 10px 30px rgba(0, 0, 0, 0.5);
    }
}

/* ---------- Base ---------- */
* { box-sizing: border-box; }
html { overflow-x: clip; -webkit-text-size-adjust: 100%; }
html, body { height: 100%; }

body {
    margin: 0;
    font-family: var(--font);
    font-size: 14px;
    line-height: 1.5;
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
}

img, svg { max-inline-size: 100%; }
a { color: var(--accent); text-decoration: none; }
h1, h2, h3 { letter-spacing: -0.022em; font-weight: 600; }
p { margin: 0; }

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb {
    background: var(--separator-strong);
    border-radius: var(--r-pill);
    border: 3px solid transparent;
    background-clip: content-box;
}

/* ---------- Utilities ---------- */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
.skip-link {
    position: fixed;
    top: 8px; left: 8px;
    z-index: 200;
    padding: 10px 16px;
    border-radius: var(--r-md);
    background: var(--surface);
    box-shadow: var(--shadow);
    font-weight: 600;
    transform: translateY(-200%);
}
.skip-link:focus { transform: none; }
.sep { margin: 0 6px; opacity: 0.55; }
.dim { color: var(--muted); }

/* ---------- Toasts ---------- */
/* Bottom-right, not top-right: the top-right corner is where the channel's
   action buttons live, and a toast that covers "Удалить" is a trap. */
.messages {
    position: fixed;
    bottom: 16px; right: 16px;
    z-index: 100;
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: min(360px, calc(100vw - 32px));
    margin: 0; padding: 0;
    list-style: none;
}
.msg {
    padding: 11px 15px;
    border-radius: var(--r-md);
    background: var(--surface);
    border: 1px solid var(--separator-strong);
    box-shadow: var(--shadow);
    font-size: 13.5px;
    /* Self-dismissing without JS: a toast that never leaves covers the feed. */
    animation: toast-in 0.22s ease both, toast-out 0.4s ease 7s forwards;
}
.msg.success { color: var(--ok); }
.msg.error { color: var(--danger); }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } }
@keyframes toast-out { to { opacity: 0; visibility: hidden; } }

/* ---------- Buttons ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 7px 15px;
    border: 1px solid var(--separator-strong);
    border-radius: var(--r-pill);
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}
.btn.primary { background: var(--accent-solid); color: var(--on-accent); border-color: transparent; }
.btn.danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, transparent); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--text-2); }
.btn.sm { padding: 5px 12px; font-size: 12.5px; }
.btn[disabled] { opacity: 0.5; cursor: default; }

/* ---------- Two-pane layout ---------- */
.layout {
    display: grid;
    grid-template-columns: clamp(248px, 22vw, 320px) 1fr;
    height: 100vh;
    height: 100dvh;
}
/* Grid tracks are min-content-sized by default; without this a wide <select>
   inside the pane pushes the whole page sideways on a 320px phone. */
.layout > * { min-width: 0; }

/* ---------- Sidebar ---------- */
.sidebar {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--surface-2);
    border-right: 1px solid var(--separator);
}
.sidebar-head { padding: 14px 12px 10px; }
.brand { display: flex; align-items: center; gap: 9px; padding: 0 4px 12px; }
.brand-mark {
    width: 24px; height: 24px;
    flex: none;
    border-radius: 7px;
    background: var(--accent-solid) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23fff' d='M7 15.6l17-6.4-3 15.2-5.4-3.6-2.6 2.8-.5-4.6z'/%3E%3C/svg%3E") center / 17px no-repeat;
}
.brand-mark.lg { width: 34px; height: 34px; border-radius: 10px; background-size: 24px; }
.brand-name { font-weight: 600; font-size: 15px; letter-spacing: -0.01em; }

.add-form { display: flex; gap: 8px; }
.add-form input {
    flex: 1;
    min-width: 0;
    padding: 8px 13px;
    border: 1px solid var(--separator-strong);
    border-radius: var(--r-pill);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 13px;
}
.channel-nav { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 4px 8px 8px; }
.channel-list { margin: 0; padding: 0; list-style: none; }
.channel-item a {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 8px 10px;
    margin: 2px 0;
    border-radius: var(--r-md);
    color: var(--text);
}
.channel-item.active a { background: var(--accent-solid); color: var(--on-accent); }
.channel-item.active .ch-sub { color: rgba(255, 255, 255, 0.82); }
.channel-empty { color: var(--muted); padding: 24px 12px; font-size: 13px; text-align: center; line-height: 1.6; }

.avatar {
    width: 40px; height: 40px;
    flex: none;
    border-radius: 50%;
    object-fit: cover;
    background: var(--surface-3);
    box-shadow: inset 0 0 0 1px var(--separator);
}
.avatar.lg { width: 56px; height: 56px; }
.avatar.placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(140deg, #7d8794, #59616d);
    color: #fff;
    font-weight: 600;
    font-size: 16px;
}
.avatar.lg.placeholder { font-size: 22px; }
.channel-item.active .avatar.placeholder { background: rgba(255, 255, 255, 0.22); }

.ch-meta { display: flex; flex-direction: column; min-width: 0; }
.ch-title { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ch-sub { display: flex; align-items: center; gap: 5px; font-size: 12px; color: var(--muted); }
.ch-sub--parsing { color: var(--accent); }
.ch-sub--error { color: var(--danger); }
.channel-item.active .ch-sub--error { color: #ffd7d7; }
.dot {
    width: 6px; height: 6px;
    flex: none;
    border-radius: 50%;
    background: currentColor;
    animation: pulse 1.4s ease-in-out infinite;
}
@keyframes pulse { 50% { opacity: 0.25; } }

.sidebar-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 8px 12px;
    border-top: 1px solid var(--separator);
}
.account {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12.5px;
    color: var(--muted);
}

/* ---------- Content pane ---------- */
.content { overflow-y: auto; padding: 0 var(--pane-x) 56px; }
/* One reading column for the whole pane. Wider than this and post text runs
   past the ~90 characters a line can be scanned comfortably. */
.channel-header, .posts, .notice, .empty-pane, .pagination, .toolbar { max-width: 920px; }

.empty-pane { padding: clamp(48px, 14vh, 120px) 8px; text-align: center; }
.empty-title { margin: 0; font-size: 16px; font-weight: 600; letter-spacing: normal; }
.empty-hint { margin-top: 6px; color: var(--muted); max-width: 42ch; margin-inline: auto; }

/* Sticky top: identity + filters travel together while the feed scrolls. */
.sticky-head {
    position: sticky;
    top: 0;
    z-index: 10;
    margin: 0 calc(var(--pane-x) * -1) 16px;
    padding: 16px var(--pane-x) 12px;
    border-bottom: 1px solid var(--separator);
    background: var(--bg-veil);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
}
@supports not (backdrop-filter: blur(1px)) {
    .sticky-head { background: var(--bg); }
}

.channel-header {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 14px;
}
.ch-head-meta { flex: 1 1 220px; min-width: 0; }
.ch-head-meta h1 { margin: 0 0 2px; font-size: clamp(1.15rem, 1rem + 0.8vw, 1.4rem); }
.ch-head-sub { color: var(--muted); font-size: 13px; }
.ch-head-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Two rows by construction: counts + filters, then the top-% chips. Letting
   the chips wrap wherever they fit made the toolbar read as one long sentence. */
.toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 20px;
    margin-top: 14px;
}
/* The stats block grows, so the filters sit hard right when they share the row
   and fall back to the left edge when they wrap onto their own. */
.feed-stats { flex: 1 1 auto; font-size: 13px; color: var(--text-2); }
.pct-row { flex: 1 0 100%; }
.feed-stats b { color: var(--text); font-weight: 600; }

.controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ctl {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12.5px;
    color: var(--muted);
    font-weight: 500;
}
.controls select, .controls input {
    padding: 6px 10px;
    border: 1px solid var(--separator-strong);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 13px;
}
.controls select {
    appearance: none;
    padding-right: 26px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='%23888f9a' d='M5 6 0 1 1 0l4 4 4-4 1 1z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 9px center;
}
.controls input[type=number] { width: 78px; }
.controls select { max-width: 100%; }
.ctl { min-width: 0; }

/* Inputs share one focus treatment; the ring is the only affordance that moves. */
.add-form input:focus, .controls select:focus, .controls input:focus, .login-card input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--ring);
}

.pct-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.pct-label { color: var(--muted); font-size: 12.5px; font-weight: 500; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
    padding: 4px 11px;
    border: 1px solid var(--separator-strong);
    border-radius: var(--r-pill);
    background: var(--surface);
    color: var(--text-2);
    font-size: 12.5px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}
.chip.active { background: var(--accent-solid); color: var(--on-accent); border-color: transparent; }

/* ---------- Notices ---------- */
.notice {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    padding: 13px 16px;
    border-radius: var(--r-md);
    background: var(--accent-tint);
    color: var(--accent);
    font-size: 13.5px;
}
.notice .notice-hint { color: var(--muted); }
.notice.error { background: var(--danger-tint); color: var(--danger); }
.notice.error .notice-hint { color: var(--text-2); }

/* ---------- Post cards ---------- */
.posts { display: flex; flex-direction: column; gap: 14px; }
.post-card {
    padding: 16px 18px;
    border: 1px solid var(--separator);
    border-radius: var(--r-lg);
    background: var(--surface);
}

/* Fixed aspect boxes: images arrive lazily, and without a reserved box every
   arrival would shove the rest of the feed down under the reader's cursor. */
.post-gallery {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4px;
    max-width: 420px;
    margin-bottom: 12px;
    border-radius: var(--r-md);
    overflow: hidden;
}
.post-gallery .media {
    position: relative;
    display: block;
    aspect-ratio: 1 / 1;
    background: var(--surface-3);
}
.post-gallery.single { grid-template-columns: 1fr; }
.post-gallery.single .media { aspect-ratio: 16 / 10; }
/* A lone trailing image spans the row instead of leaving a hole. */
.post-gallery:not(.single) .media:last-child:nth-child(odd) { grid-column: span 2; aspect-ratio: 16 / 9; }
.post-gallery .media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.post-gallery.single .media img { object-fit: contain; }

.play {
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: 46px; height: 46px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
}
.play::after {
    content: "";
    border-style: solid;
    border-width: 8px 0 8px 14px;
    border-color: transparent transparent transparent #fff;
    margin-left: 3px;
}

/* A video whose cover thumbnail could not be downloaded: say what it is instead
   of rendering a text-only card for something that is really a video. */
.video-placeholder {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    border: 1px solid var(--separator);
    border-radius: var(--r-md);
    background: var(--surface-3);
    color: var(--text-2);
    text-decoration: none;
    transition: background var(--dur, 120ms) ease, border-color var(--dur, 120ms) ease;
}
.video-placeholder:hover { background: var(--hover); border-color: var(--separator-strong); }
.video-placeholder .play {
    position: static;
    transform: none;
    flex: none;
    width: 34px;
    height: 34px;
}

.post-text { max-width: 72ch; line-height: 1.55; color: var(--text-2); white-space: pre-wrap; overflow-wrap: anywhere; }

.reactions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 13px; }
.reaction {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: var(--r-pill);
    background: var(--surface-3);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.reaction .r-emoji {
    font-size: 14px;
    line-height: 1;
    font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
    font-variant-emoji: emoji;
}

.post-footer {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 14px;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--separator);
    font-size: 12.5px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}
.stat { display: inline-flex; align-items: center; gap: 5px; }
.stat .ic { width: 15px; height: 15px; fill: currentColor; opacity: 0.75; }
.stat.er {
    padding: 1px 8px;
    border: 1px solid var(--separator);
    border-radius: var(--r-pill);
    color: var(--text-2);
}
.post-date { margin-left: auto; }
.tg-open { font-weight: 500; white-space: nowrap; }

/* ---------- Pagination ---------- */
.pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 20px;
}
.page-range { color: var(--muted); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.page-btns { display: flex; align-items: center; gap: 6px; }
.page-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    height: 34px;
    padding: 0 9px;
    border: 1px solid var(--separator-strong);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text);
    font-size: 13px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}
.page-btn.active { background: var(--accent-solid); color: var(--on-accent); border-color: transparent; }
.page-btn.disabled { color: var(--muted); opacity: 0.45; }
.page-status { padding: 0 8px; color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }

/* Mobile-only "back to the channel list" link. */
.back-link { display: none; align-items: center; gap: 6px; padding: 12px 0 2px; font-weight: 500; }
.back-link span { font-size: 19px; line-height: 1; }

/* ---------- Login ---------- */
.login-wrap {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    padding: clamp(48px, 12vh, 140px) 16px 32px;
    min-height: 100vh;
    min-height: 100dvh;
}
.card { background: var(--surface); border: 1px solid var(--separator); border-radius: var(--r-lg); box-shadow: var(--shadow); }
.login-card {
    width: 100%;
    max-width: 340px;
    padding: clamp(24px, 5vw, 32px);
    display: flex;
    flex-direction: column;
    gap: 15px;
}
.login-brand { display: flex; flex-direction: column; align-items: center; gap: 10px; margin-bottom: 4px; }
.login-brand h1 { margin: 0; font-size: 1.4rem; }
.login-card label { display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--text-2); font-weight: 500; }
.login-card input {
    padding: 10px 13px;
    border: 1px solid var(--separator-strong);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 14px;
}
.login-card .msg { animation: none; box-shadow: none; }
.login-card .btn { margin-top: 4px; padding: 11px; font-size: 15px; }

/* ---------- Hover, only where a real pointer exists ---------- */
@media (hover: hover) {
    .btn:hover:not([disabled]) { background: var(--hover); }
    .btn.primary:hover { background: var(--accent-solid); filter: brightness(1.08); }
    .btn.danger:hover { background: var(--danger-tint); }
    .btn.ghost:hover { background: var(--hover); color: var(--text); }
    .channel-item a:hover { background: var(--hover); }
    .channel-item.active a:hover { background: var(--accent-solid); filter: brightness(1.06); }
    .chip:hover { background: var(--hover); color: var(--text); }
    .chip.active:hover { background: var(--accent-solid); filter: brightness(1.08); }
    .page-btn:hover:not(.disabled):not(.active) { background: var(--hover); }
    .tg-open:hover, .ch-head-sub a:hover { text-decoration: underline; }
    .post-gallery .media:hover img { filter: brightness(1.05); }
}

/* ---------- Tablet: give the feed the room the sidebar was hoarding ---------- */
@media (max-width: 1100px) {
    .layout { grid-template-columns: 250px 1fr; }
    .ch-head-actions { gap: 6px; }
}

/* ---------- Mobile: one pane at a time ---------- */
@media (max-width: 860px) {
    .layout { grid-template-columns: 1fr; height: auto; min-height: 100dvh; }
    .sidebar, .content { overflow: visible; }
    .sidebar { border-right: none; }
    .channel-nav { overflow: visible; }
    /* Only one pane is ever on screen: the list, or the channel you opened. */
    .layout.has-selection .sidebar { display: none; }
    .layout:not(.has-selection) .content { display: none; }
    .back-link { display: inline-flex; }

    /* Not sticky here: pinned, this block would eat most of a phone screen. */
    .sticky-head { position: static; margin-bottom: 14px; padding-top: 10px; }
    .sidebar-foot { position: sticky; bottom: 0; background: var(--surface-2); }
    /* Clear the pinned account row — a toast landing on "Выйти" is a mis-tap waiting to happen. */
    .messages { bottom: 72px; }

    /* Touch targets: 44px is the smallest reliably tappable box. */
    .btn { min-height: 44px; }
    .btn.sm { min-height: 38px; }
    .page-btn { min-width: 44px; height: 44px; }
    .add-form input, .controls select, .controls input, .login-card input {
        min-height: 44px;
        font-size: 16px; /* below 16px iOS Safari zooms the whole page on focus */
    }
}

/* ---------- Small phones: stack everything that was a row ---------- */
@media (max-width: 560px) {
    .channel-header { gap: 12px; }
    .avatar.lg { width: 44px; height: 44px; }
    .ch-head-actions { width: 100%; }
    .ch-head-actions form, .ch-head-actions .btn { flex: 1 1 auto; }
    .toolbar { flex-direction: column; align-items: stretch; gap: 12px; }
    .controls { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
    .controls .ctl { flex-direction: column; align-items: flex-start; gap: 3px; }
    /* :first-of-type, not :first-child — the form's first child is a hidden input. */
    .controls .ctl:first-of-type { grid-column: 1 / -1; }
    .controls select, .controls input[type=number] { width: 100%; }
    .controls .btn { grid-column: 1 / -1; }
    .post-card { padding: 14px; }
    .post-footer { gap: 10px 14px; }
    .post-date { margin-left: 0; }
    .pagination { justify-content: center; }
    .page-range { width: 100%; text-align: center; }
    .messages { left: 12px; right: 12px; max-width: none; }
}

/* ---------- Motion is optional ---------- */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
    }
    /* Durations collapse but delays do not, so the toast still clears itself
       after its 7s — it just stops sliding and fading to do it. */
}

/* ==========================================================================
   Settings (apps.appsettings) — appended section, self-contained.
   Everything here is prefixed `app-nav`/`settings-`/`set-` so it cannot reach
   into the dashboard, and every colour comes from the tokens at the top of the
   file, so both themes follow for free.
   ========================================================================== */

:root { --app-nav-h: 38px; }

/* ---------- Staff-only global nav ---------- */
/* A bar above <main>, not a floating pill: the free corners of the dashboard are
   the channel actions (top-right) and the toasts (bottom-right), and a link that
   lands on "Удалить" is a trap. The sibling rules hand the full-height grid back
   the height the bar takes — without them the app grows a second scrollbar. */
.app-nav {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    height: var(--app-nav-h);
    padding: 0 var(--pane-x);
    border-bottom: 1px solid var(--separator);
    background: var(--surface-2);
}
.app-nav-link {
    padding: 4px 12px;
    border-radius: var(--r-pill);
    color: var(--text-2);
    font-size: 12.5px;
    font-weight: 500;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.app-nav-link.current { background: var(--accent-tint); color: var(--accent); }
.app-nav ~ #main .layout {
    height: calc(100vh - var(--app-nav-h));
    height: calc(100dvh - var(--app-nav-h));
}

/* ---------- Settings page shell ---------- */
.settings-wrap {
    display: flex;
    flex-direction: column;
    gap: 18px;
    max-width: 760px;
    margin: 0 auto;
    padding: clamp(18px, 4vw, 36px) var(--pane-x) 72px;
}
.settings-back { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 500; }
.settings-back span { font-size: 19px; line-height: 1; }
.settings-head h1 { margin: 8px 0 0; font-size: clamp(1.3rem, 1.1rem + 1vw, 1.65rem); }
.settings-sub { margin-top: 8px; max-width: 62ch; color: var(--muted); }
/* Scoped to this page rather than a bare `code` rule: the dashboard has no
   monospace anywhere, and a global element rule would be a surprise waiting. */
.settings-wrap code {
    padding: 1px 5px;
    border-radius: 5px;
    background: var(--surface-3);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.92em;
}

/* ---------- Cards ---------- */
.set-card { display: flex; flex-direction: column; gap: 16px; padding: clamp(18px, 3.4vw, 26px); }
.set-card-head { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.set-card-head h2 { margin: 0; font-size: 1.05rem; }

/* The badge is the state machine made visible: a half-finished login that looks
   like a fresh form is how a second code gets requested and the first dies. */
.set-badge {
    padding: 3px 10px;
    border-radius: var(--r-pill);
    background: var(--surface-3);
    color: var(--text-2);
    font-size: 12px;
    font-weight: 600;
}
.set-badge--on { background: color-mix(in srgb, var(--ok) 15%, transparent); color: var(--ok); }
.set-badge--wait { background: var(--accent-tint); color: var(--accent); }

.set-note, .set-error {
    padding: 11px 14px;
    border-radius: var(--r-md);
    font-size: 13px;
    line-height: 1.5;
}
.set-note { background: var(--accent-tint); color: var(--accent); }
.set-note code { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.set-error { background: var(--danger-tint); color: var(--danger); }

/* ---------- Fields ---------- */
.set-form { display: flex; flex-direction: column; gap: 18px; }
.set-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.set-label { font-size: 13px; font-weight: 600; color: var(--text); }
.set-field input, .set-field select {
    width: 100%;
    padding: 9px 12px;
    border: 1px solid var(--separator-strong);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 14px;
}
/* Same focus treatment as every other input in the app: border plus ring. */
.set-field input:focus, .set-field select:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--ring);
}
.set-field input[aria-invalid="true"] { border-color: var(--danger); }
.set-help { max-width: 62ch; color: var(--muted); font-size: 12.5px; line-height: 1.5; }
.set-help b { color: var(--text-2); font-weight: 600; }
.set-default { color: var(--text-2); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.set-err { color: var(--danger); font-size: 12.5px; font-weight: 500; }

/* ---------- A secret that is shown as absent, not as blank ---------- */
/* Baseline, not centre: opening <details> makes the right-hand column two rows
   tall, and centring would leave the dots floating beside the new input. */
.set-masked { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px 12px; }
.set-dots { letter-spacing: 0.16em; color: var(--text-2); font-size: 15px; }
/* <details> so "заменить" needs no JavaScript; the input inside submits either
   way, and an empty one means "keep what is stored". */
.set-replace { flex: 1 1 200px; min-width: 0; }
.set-replace summary { list-style: none; }
.set-replace summary::-webkit-details-marker { display: none; }
.set-replace summary::marker { content: ""; }
.set-replace input { margin-top: 8px; }

/* ---------- Connected account ---------- */
.set-facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 14px 18px;
    margin: 0;
}
.set-facts > div { min-width: 0; }
.set-facts dt { color: var(--muted); font-size: 12px; font-weight: 500; }
.set-facts dd { margin: 2px 0 0; font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }

.set-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
/* Sibling of the login form, never nested inside it: forms do not nest. */
.set-cancel { margin-top: -6px; }

/* ---------- Config groups ---------- */
.set-group { margin: 0; padding: 0; border: 0; min-width: 0; }
.set-group + .set-group { padding-top: 18px; border-top: 1px solid var(--separator); }
.set-legend {
    padding: 0 0 14px;
    color: var(--muted);
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
}
.set-grid { display: grid; gap: 20px; }
.set-submit { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; }
.set-submit .set-help { flex: 1 1 260px; }

/* ---------- Hover, only where a real pointer exists ---------- */
@media (hover: hover) {
    .app-nav-link:hover { background: var(--hover); color: var(--text); }
    .settings-back:hover { text-decoration: underline; }
    .set-help a:hover, .set-note a:hover { text-decoration: underline; }
}

/* ---------- Mobile ---------- */
@media (max-width: 860px) {
    /* Restores the mobile layout rule above, minus the bar's height. */
    .app-nav ~ #main .layout { height: auto; min-height: calc(100dvh - var(--app-nav-h)); }
    .app-nav { padding: 0 16px; }
    /* 44px targets, and 16px so iOS Safari does not zoom the page on focus. */
    .set-field input, .set-field select { min-height: 44px; font-size: 16px; }
}

@media (max-width: 560px) {
    .settings-wrap { gap: 14px; padding-bottom: 48px; }
    .set-dots { flex: 1 1 100%; }
    .set-replace { flex: 1 1 100%; }
    .set-actions .btn, .set-submit .btn { width: 100%; }
    .set-submit { flex-direction: column; align-items: stretch; gap: 10px; }
}
