/* =========================================================================
   ShanksGames Dashboard — Design System
   Official Fluent 2 (Windows 11) dark/light tokens. Untinted Mica: flat,
   opaque, neutral card surfaces — NOT blurred glassmorphism. Blur is
   reserved for Acrylic (nav-on-scroll, toasts) only, per Fluent's own
   Mica-vs-Acrylic distinction.

   All class names below are load-bearing — they are referenced from
   dashboard.py and dashboard/modules/*.py. Renaming any of them breaks
   the dashboard. Only visual properties (color, radius, motion) changed;
   layout/structure kept intact.
   ========================================================================= */

:root {
    color-scheme: dark;

    /* --- Brand (official Fluent 2 brand blue) --- */
    --accent: #0078d4;
    --accent-rgb: 0, 120, 212;
    --accent-hover: #1084d8;
    --accent-2: #8764b8;
    --accent-2-rgb: 135, 100, 184;
    --success: #10b981;
    --success-rgb: 16, 185, 129;
    --danger: #f43f5e;
    --danger-rgb: 244, 63, 94;
    --warning: #facc15;

    /* --- Mica canvas + surfaces --- */
    --mica-tint-rgb: 24, 24, 24;
    /* Border ring on Mica/Acrylic blocks tints the SAME blurred wallpaper
       the OPPOSITE way from the block's own fill — light on dark, dark on
       light — like a Fluent 2 stroke reacting to the OS theme. */
    --mica-border-tint-rgb: 255, 255, 255;
    --bg-gradient: #181818;
    --surface-2: #242424;
    --surface-3: #2f2f2f;
    --mica-border: rgba(255, 255, 255, 0.08);
    --mica-border-hover: rgba(255, 255, 255, 0.14);
    --mica-highlight: rgba(255, 255, 255, 0.06);

    /* Back-compat aliases: original variable names used inline in dashboard.py */
    --mica: var(--surface-2);
    --mica-strong: var(--surface-3);
    --glass: rgba(255, 255, 255, 0.03);
    --glass-border: var(--mica-border);

    /* Acrylic: translucent, blurred — nav-on-scroll / toasts / flyouts ONLY */
    --acrylic: rgba(41, 41, 41, 0.7);
    --acrylic-border: rgba(255, 255, 255, 0.12);

    --text: #ffffff;
    --text-muted: rgba(255, 255, 255, 0.65);

    /* --- Radius (Fluent standard 8px / bento-outer 16px) --- */
    --radius-sm: 8px;
    --radius-lg: 16px;
    --radius-pill: 999px;

    /* --- Motion tokens (Emil Kowalski's animate skill — extend, never fork) --- */
    --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
    --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
    --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
    --ease-spring: var(--ease-out);

    --font-sans: "Segoe UI Variable", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, system-ui, sans-serif;

    /* Shared grain: the material texture both Mica (canvas) and Acrylic
       (surfaces) use, per Microsoft's own material recipes. */
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90' height='90'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.05'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Light mode — system preference */
@media (prefers-color-scheme: light) {
    :root:not([data-theme="dark"]) {
        color-scheme: light;
        --mica-tint-rgb: 245, 245, 245;
        --mica-border-tint-rgb: 0, 0, 0;
        --bg-gradient: #f5f5f5;
        --surface-2: #ffffff;
        --surface-3: #f0f0f0;
        --mica-border: rgba(0, 0, 0, 0.08);
        --mica-border-hover: rgba(0, 0, 0, 0.14);
        --mica-highlight: rgba(0, 0, 0, 0.05);
        --mica: var(--surface-2);
        --mica-strong: var(--surface-3);
        --glass: rgba(255, 255, 255, 0.5);
        --glass-border: var(--mica-border);
        --acrylic: rgba(255, 255, 255, 0.7);
        --acrylic-border: rgba(0, 0, 0, 0.1);
        --text: #1b1b1b;
        --text-muted: rgba(27, 27, 27, 0.65);
    }
}
/* Explicit override (for a future manual theme toggle) */
:root[data-theme="light"] {
    color-scheme: light;
    --mica-tint-rgb: 245, 245, 245;
    --mica-border-tint-rgb: 0, 0, 0;
    --bg-gradient: #f5f5f5;
    --surface-2: #ffffff;
    --surface-3: #f0f0f0;
    --mica-border: rgba(0, 0, 0, 0.08);
    --mica-border-hover: rgba(0, 0, 0, 0.14);
    --mica-highlight: rgba(0, 0, 0, 0.05);
    --mica: var(--surface-2);
    --mica-strong: var(--surface-3);
    --glass: rgba(255, 255, 255, 0.5);
    --glass-border: var(--mica-border);
    --acrylic: rgba(255, 255, 255, 0.7);
    --acrylic-border: rgba(0, 0, 0, 0.1);
    --text: #1b1b1b;
    --text-muted: rgba(27, 27, 27, 0.65);
}
:root[data-theme="dark"] {
    color-scheme: dark;
    --mica-tint-rgb: 24, 24, 24;
    --mica-border-tint-rgb: 255, 255, 255;
    --bg-gradient: #181818;
    --surface-2: #242424;
    --surface-3: #2f2f2f;
    --mica-border: rgba(255, 255, 255, 0.08);
    --mica-border-hover: rgba(255, 255, 255, 0.14);
    --mica-highlight: rgba(255, 255, 255, 0.06);
    --mica: var(--surface-2);
    --mica-strong: var(--surface-3);
    --glass: rgba(255, 255, 255, 0.03);
    --glass-border: var(--mica-border);
    --acrylic: rgba(41, 41, 41, 0.7);
    --acrylic-border: rgba(255, 255, 255, 0.12);
    --text: #ffffff;
    --text-muted: rgba(255, 255, 255, 0.65);
}

* { box-sizing: border-box; }

/* body's own overflow-x:hidden can't stop the ROOT scrollbar from
   appearing — a child with a bleed past its container (e.g. the landing
   carousel's -32px edge-fade margin) still widens what <html> itself
   scrolls, since that's a separate box from body. Belt-and-suspenders on
   both elements is the standard fix for stray horizontal scroll. */
html { overflow-x: hidden; }

/* ---------------------------------------------------------------------
   Mica material — the window/canvas backdrop. Plain, dark, opaque. It does
   NOT show the uploaded wallpaper — the wallpaper only ever appears through
   the Acrylic surfaces above it (see .glass, .acrylic below), as if they
   were windows looking through this dark canvas at an image behind it.
   --------------------------------------------------------------------- */
body {
    margin: 0;
    font-family: var(--font-sans);
    background-color: var(--bg-gradient);
    color: var(--text);
    height: 100vh;
    display: flex;
    overflow: hidden;
}
/* Sidebar + main-wrapper live inside this wrapper (not directly on body)
   specifically so the mobile slide-panel transform below never lands on
   <body> itself — a transformed ancestor becomes the containing block for
   ALL its position:fixed descendants (the announcement popup, the floating
   save bar), which would silently reposition them relative to this panel
   instead of the real viewport the moment body itself got transformed. */
.mobile-shell { display: flex; flex: 1; gap: 24px; min-width: 0; }

/* ---------------------------------------------------------------------
   Acrylic material — a sharp, viewport-fixed slice of the uploaded
   wallpaper (::before) seen through a blurred, tinted, grained pane
   (::after) sitting on top of it. Split into two layers on purpose: the
   moment `filter` touches the SAME element as `background-attachment:
   fixed`, engines quietly break that fixed attachment and it starts
   scrolling with the element instead of staying pinned to the viewport.
   Blurring via `backdrop-filter` on a separate sibling avoids that quirk
   entirely — ::after has no fixed background of its own for the quirk to
   break, and backdrop-filter reaches straight through to ::before's sharp
   image sitting right behind it.
   `isolation: isolate` plus negative z-index on both pseudo layers keeps
   them behind the card's real content — position:absolute with z-index:
   auto still paints ABOVE static content per the CSS stacking spec
   regardless of source order, which used to sit these layers on top of
   text/inputs/buttons and swallow clicks (e.g. Embed Studio's textareas).
   `pointer-events: none` on both is the other half of that fix. */
.glass, .acrylic {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    background-color: var(--acrylic);
    transition: background-color 160ms var(--ease-out);
}
.glass::before, .acrylic::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -2;
    border-radius: inherit;
    pointer-events: none;
    background-image: var(--wallpaper, none);
    background-size: cover;
    background-position: center;
    background-attachment: fixed;
}
.glass::after, .acrylic::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    border-radius: inherit;
    /* translateZ(0) forces this onto its own compositing layer — without
       it, Chromium's backdrop-filter blur (110px is large relative to a
       pill's tight corner radius) can bleed a faint square sliver past the
       rounded clip at corners instead of respecting border-radius exactly. */
    transform: translateZ(0);
    backdrop-filter: blur(110px) saturate(85%) brightness(0.65);
    -webkit-backdrop-filter: blur(110px) saturate(85%) brightness(0.65);
    background-image:
        linear-gradient(rgba(var(--mica-tint-rgb), 0.78), rgba(var(--mica-tint-rgb), 0.78)),
        var(--grain);
    background-size: cover, 128px 128px;
    /* The border ring: same blurred wallpaper (backdrop-filter above already
       blurs it for the whole element), just tinted the OPPOSITE way from
       the fill — light ring on a dark OS theme, dark ring on a light one.
       An inset box-shadow paints a solid band inward from the edge; since
       its color is translucent, the shared blur still shows through it. */
    box-shadow: inset 0 0 3px 1px rgba(var(--mica-border-tint-rgb), 0.7);
}
/* Firefox needs layout.css.backdrop-filter.enabled flipped on manually to
   support backdrop-filter at all (older/default builds don't). Fall back
   to a fully opaque surface there instead of a broken, unblurred, see-
   through panel with illegible text. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .glass, .acrylic { background-color: var(--surface-2); }
    .glass::before, .glass::after, .acrylic::before, .acrylic::after { display: none; }
}

/* Cards combine .glass/.acrylic with .fluent-reveal below, and both rules
   target the same ::before — same specificity means whichever is later in
   the file wins outright (no per-property merge), which silently deleted
   the wallpaper reveal from every card. Re-declaring it here on the
   compound selector (higher specificity than .fluent-reveal alone) makes
   the wallpaper win on those shared elements; .fluent-reveal-only elements
   (no glass/acrylic) keep their plain cursor highlight untouched below.
   opacity: 1 is the other half of that override — .fluent-reveal::before
   defaults to opacity:0 (only flipping to 1 on hover, for its own cursor
   highlight) and that default was quietly winning too, since nothing else
   here touched opacity, leaving the wallpaper invisible at rest and only
   flashing in on hover. */
.glass.fluent-reveal::before, .acrylic.fluent-reveal::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -2;
    border-radius: inherit;
    opacity: 1;
    pointer-events: none;
    background-image: var(--wallpaper, none);
    background-size: cover;
    background-position: center;
    background-attachment: fixed;
}

/* Fluent "Reveal" highlight: a soft light that tracks the cursor on
   interactive surfaces. Shared site-wide — theme.js writes --mx/--my. */
.fluent-reveal { position: relative; }
.fluent-reveal::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    opacity: 0;
    background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 50%), rgba(255, 255, 255, 0.06), transparent 65%);
    transition: opacity 200ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
    .fluent-reveal:hover::before { opacity: 1; }
}

/* Scrollbars */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.15); border-radius: 10px; }
::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.12); border-radius: 10px; border: 2px solid transparent; background-clip: content-box; transition: background-color 160ms var(--ease-out); }
::-webkit-scrollbar-thumb:hover { background: var(--accent); }
* { scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, 0.12) rgba(0, 0, 0, 0.15); }

/* Icons (Lucide) */
svg.lucide { width: 1em; height: 1em; stroke-width: 2; vertical-align: -0.15em; }

/* Form controls */
select, input[type="text"], input[type="file"], textarea, .glass-input {
    width: 100%;
    padding: 14px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--glass-border);
    background: var(--surface-3) !important;
    color: var(--text) !important;
    outline: none;
    font-family: var(--font-sans);
    transition: border-color 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
}
textarea { resize: vertical; min-height: 80px; }
select option { background: var(--surface-3); color: var(--text); }
.glass-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.25); }

/* Server picker cards */
.server-card {
    padding: 30px;
    border-radius: var(--radius-lg);
    text-align: center;
    text-decoration: none;
    color: inherit;
    display: block;
    transition: background-color 160ms var(--ease-out), border-color 160ms var(--ease-out), transform 160ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
    .server-card:hover { background-color: var(--surface-3); border-color: var(--mica-border-hover); }
    .server-card:hover img { transform: scale(1.04); }
}
.server-card:active { transform: scale(0.98); transition-duration: 100ms; }
.server-card img { border-radius: var(--radius-sm); transition: transform 200ms var(--ease-out); }

/* App shell */
.sidebar { width: 280px; margin: 24px 0 24px 24px; border-radius: var(--radius-lg); display: flex; flex-direction: column; z-index: 10; }
/* No background here on purpose — the parent .sidebar is itself .glass, and
   an opaque fill on this child would paint over (hide) its Mica reveal in
   this one spot, since normal static content always paints above a
   parent's ::before/::after. Leaving it transparent lets the sidebar's
   Mica effect read continuously behind the logo/name too. */
.sidebar-header { padding: 25px; display: flex; align-items: center; gap: 12px; font-weight: 700; border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
.sidebar-header img { width: 40px; border-radius: var(--radius-sm); }

.menu-item { padding: 12px 20px; margin: 5px 15px; border-radius: var(--radius-sm); color: var(--text-muted); text-decoration: none; display: flex; align-items: center; gap: 10px; transition: background-color 160ms var(--ease-out), color 160ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
    .menu-item:hover { background: var(--mica-highlight); color: var(--text); }
}
.menu-item.active { background: var(--accent); color: white; }

.main-wrapper { flex: 1; display: flex; flex-direction: column; padding: 24px 24px 24px 0; overflow: hidden; }
.content { flex: 1; overflow-y: auto; scrollbar-width: none; }
.content-inner { padding: 0 20px 20px; }

/* Sticky Acrylic topbar: it's the first child of the scroll container, so it
   pins to the top while content-inner scrolls up and visibly blurs behind it
   — Acrylic (translucent, blurred), not Mica (opaque), because it floats. */
.top-bar {
    position: sticky;
    top: 0;
    z-index: 50;
    height: 70px;
    flex-shrink: 0;
    border-radius: var(--radius-lg);
    margin: 0 20px 15px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 0 20px;
}
.top-bar-server { display: flex; align-items: center; gap: 12px; min-width: 0; font-weight: 600; color: var(--text); }
.top-bar-server-icon { width: 34px; height: 34px; border-radius: var(--radius-sm); flex-shrink: 0; }
.top-bar-server span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.user-pill { display: flex; align-items: center; gap: 10px; padding: 6px 8px 6px 14px; background: var(--mica-highlight); border-radius: var(--radius-pill); border: 1px solid var(--glass-border); flex-shrink: 0; }
.user-pill-name { font-weight: 600; font-size: 14px; color: var(--text); }
.user-avatar { width: 32px; height: 32px; border-radius: 50%; border: 2px solid var(--accent); }
.logout-btn {
    display: flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; border-radius: 50%;
    background: transparent; border: none; color: var(--text-muted);
    cursor: pointer;
    transition: background-color 120ms var(--ease-out), color 120ms var(--ease-out);
}
.logout-btn:hover { background: rgba(var(--danger-rgb), 0.15); color: var(--danger); }
.logout-btn:active { transform: scale(0.92); transition-duration: 80ms; }

/* Hidden on desktop; only shown (see the mobile media query below) once a
   phone-width viewport is actually viewing the content panel, as the way
   back to the sidebar/menu panel. */
.mobile-back-btn {
    display: none;
    align-items: center; justify-content: center;
    width: 36px; height: 36px; border-radius: 50%;
    background: transparent; border: none; color: var(--text);
    cursor: pointer; flex-shrink: 0;
    transition: background-color 120ms var(--ease-out);
}
.mobile-back-btn:hover { background: var(--mica-highlight); }
.mobile-back-btn:active { transform: scale(0.92); transition-duration: 80ms; }

/* ---------------------------------------------------------------------
   Mobile layout: the sidebar (menu + server widget) and the main content
   can't sit side by side below ~768px, so instead of squeezing both into
   one cramped row, each becomes its own full-width "page" and .mobile-shell
   slides between them — tapping a tab in the sidebar reveals the content
   panel from the right, swiping left (or the back arrow) returns to the
   sidebar. Plain CSS transform + one small, self-contained script (see
   theme.js) — showTab()/TAB_FORM_MAP/the rest of the existing tab logic
   are untouched, this only layers a slide on top of the same clicks.
   --------------------------------------------------------------------- */
@media (max-width: 768px) {
    /* flex: 0 0 <size> (not just width) — .mobile-shell and .main-wrapper
       both start from flex:1 (flex-basis:0%) elsewhere, and flex-basis
       wins over width whenever it isn't auto, which silently ignored a
       plain `width: 200vw`/`width: 100vw` here. */
    /* `left`, not `transform` — same lesson as the landing page carousel
       elsewhere in this file: a `transform` on an ancestor becomes the
       containing block for every position:fixed descendant, which pulled
       the floating save bar's `left:50%` centering off the real viewport
       and onto this 200vw-wide shell instead (it rendered pinned to the
       left edge). `left` slides identically without that side effect. */
    .mobile-shell {
        position: relative;
        left: 0;
        flex: 0 0 200vw;
        gap: 0;
        transition: left 320ms var(--ease-drawer);
    }
    body.mobile-show-content .mobile-shell { left: -100vw; }
    .mobile-shell .sidebar { flex: 0 0 100vw; width: 100vw; margin: 0; border-radius: 0; }
    .mobile-shell .main-wrapper { flex: 0 0 100vw; width: 100vw; padding: 0; }
    /* Pages rendered with show_sidebar=False (the "Choose a server" page)
       have no .sidebar panel at all — the 200vw shell + -100vw shift above
       assumes one always exists to occupy the first 100vw, so with only the
       content panel present, that same shift pushed it clean off the left
       edge of the screen (nothing but the dark background was visible). A
       single panel needs no slide at all. */
    .mobile-shell.no-sidebar { flex: 0 0 100vw; }
    body.mobile-show-content .mobile-shell.no-sidebar { left: 0; }
    .mobile-shell.no-sidebar .mobile-back-btn { display: none !important; }
    .top-bar { margin: 12px; }
    .content-inner { padding: 0 16px 20px; }
    body.mobile-show-content .mobile-back-btn { display: inline-flex; }
    /* The widget's fixed height="500" attribute was eating most of the
       screen, leaving almost no room for the scrollable tab list above it
       to actually scroll in. CSS height beats the HTML attribute. */
    .sidebar-widget { padding: 10px; }
    .sidebar-widget iframe { height: 220px; }
    /* Embed Studio's own 280px + 1fr grid is an inline style (needs
       !important to win) — at 375px wide, that fixed 280px left column
       for My Saves/My Forms left nothing for the actual builder on the
       right, which was completely unreachable since horizontal scroll is
       disabled. Stack them instead: saves/forms first, builder below. */
    .embed-studio-grid { grid-template-columns: 1fr !important; }
    /* Stacking the grid to 1 column (above) wasn't enough on its own — the
       builder's two inner columns (form fields, live preview) each carry
       their own inline min-width (350px/320px, 670px combined) so they'd
       still refuse to shrink below that and overflow the now-single,
       ~340px-wide column. min-width:0 alone still let both squeeze into the
       same row since their parent keeps flex-wrap available room; flex:0 0
       100% forces each fully onto its own row instead. */
    .embed-studio-fields, .embed-studio-preview { min-width: 0 !important; flex: 0 0 100% !important; }
    /* Author Name / Author URL (and the rest of that 2-up grid inside each
       embed block) — same 1fr 1fr overflow as the outer studio grid. Several
       fields inside (Author Icon, Title, Description, Image, Timestamp) have
       their own inline grid-column:span 2 — with only 1 explicit column left,
       Grid doesn't clamp that span down, it silently adds an implicit 2nd
       column to fit it instead, which is exactly the overflow this was meant
       to fix. Forcing every child back to span 1 avoids that implicit column. */
    .embed-fields-grid { grid-template-columns: 1fr !important; }
    .embed-fields-grid > div { grid-column: span 1 !important; }
    /* Field rows (drag handle / name / value / inline / delete) — the two
       60px+35px fixed columns alongside 1fr 1fr left almost nothing for the
       actual text inputs. Two rows instead of five squeezed columns. */
    .field-row {
        grid-template-columns: 1fr 1fr !important;
        grid-template-areas: "name value" "inline delete" !important;
    }
    .field-row .drag-handle { display: none; }
    .field-row > div:nth-child(2) { grid-area: name; }
    .field-row > div:nth-child(3) { grid-area: value; }
    .field-row > div:nth-child(4) { grid-area: inline; }
    .field-row > button { grid-area: delete; }
    /* The header's Save name / channel picker are 200px + 220px fixed —
       stack them under the title and let each take the full width instead
       of forcing 420px+ into a ~340px row. */
    .embed-studio-header { flex-direction: column; align-items: stretch !important; gap: 12px; }
    .embed-studio-header > div { flex-direction: column; width: 100%; }
    .embed-studio-header input, .embed-studio-header select { width: 100% !important; }
    /* Button row (emoji code / label / style) crams 3 fields into one flex
       row — fine on desktop, but on a 375px screen the label field was
       squeezed down to ~55px (barely a few characters) since it shares the
       row with a 50px emoji box and an equally-flexed style dropdown. Stack
       them instead, same pattern as the header above. */
    .btn-row-top { flex-direction: column; }
    @media (prefers-reduced-motion: reduce) {
        .mobile-shell { transition: none; }
    }
}

/* Controls */
.control-row { display: flex; align-items: center; gap: 15px; margin-top: 8px; }
input[type=range] { flex: 1; -webkit-appearance: none; background: transparent; cursor: pointer; }
input[type=range]::-webkit-slider-runnable-track { height: 8px; background: rgba(255, 255, 255, 0.1); border-radius: 10px; }
input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; height: 20px; width: 20px; border-radius: 50%; background: var(--accent); margin-top: -6px; transition: transform 120ms var(--ease-out); }
input[type=range]::-webkit-slider-thumb:active { transform: scale(1.15); }
.num-input { width: 75px; background: var(--surface-3); border: 1px solid var(--glass-border); color: var(--text); padding: 8px; border-radius: var(--radius-sm); text-align: center; }
.checkbox-container { display: flex; align-items: center; padding: 12px; background: var(--mica-highlight); border-radius: var(--radius-sm); border: 1px solid var(--glass-border); cursor: pointer; }
/* Same flat look as .checkbox-container/.switch-row, for other small,
   secondary rows nested inside a bigger .glass panel (list rows, small
   form sub-groups) — .glass/.acrylic's full wallpaper reveal is meant for
   the main surfaces (topbar, sidebar, cards), not these; stacking it on a
   nested element on top of its own parent's Mica reads as inconsistent
   duplication rather than one coherent effect. */
.searchable-item, .sub-panel { background: var(--mica-highlight); border: 1px solid var(--glass-border); border-radius: var(--radius-sm); }

/* Toggle switch — replaces tiny native checkboxes wherever the hit target
   needs to be the whole row, not a 13px box. */
.switch-row {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    background: var(--mica-highlight);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    user-select: none;
    transition: border-color 160ms var(--ease-out);
}
.switch-row:hover { border-color: var(--mica-border-hover); }
.switch-row input[type="checkbox"] { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
.switch-track {
    flex-shrink: 0;
    width: 38px;
    height: 22px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.18);
    position: relative;
    transition: background-color 160ms var(--ease-out);
}
.switch-thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: white;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
    transition: transform 160ms var(--ease-out);
}
.switch-row input:checked ~ .switch-track { background: var(--accent); }
.switch-row input:checked ~ .switch-track .switch-thumb { transform: translateX(16px); }
.switch-row input:focus-visible ~ .switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch-label { font-size: 13px; color: var(--text); flex: 1; }
@media (prefers-reduced-motion: reduce) {
    .switch-thumb { transition-duration: 1ms; }
}

/* Floating "unsaved changes" action bar — hidden until a tracked form is
   dirty, then pinned to the bottom of the viewport (Acrylic: it floats). */
.form-actions {
    display: none;
    gap: 12px;
    justify-content: flex-end;
    margin-top: 30px;
}
.form-actions .btn-save { margin: 0; display: inline-flex; align-items: center; gap: 8px; }
.btn-reset {
    background: transparent;
    border: 1px solid var(--glass-border);
    color: var(--text-muted);
    padding: 14px 22px;
    border-radius: var(--radius-sm);
    font-weight: 700;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    transition: background-color 120ms var(--ease-out), color 120ms var(--ease-out), border-color 120ms var(--ease-out);
}
.btn-reset:hover { background: var(--mica-highlight); color: var(--text); border-color: var(--mica-border-hover); }
.btn-reset:active { transform: scale(0.97); }

.form-actions.is-dirty {
    display: flex;
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    z-index: 200;
    background-color: var(--acrylic);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border: 1px solid var(--acrylic-border);
    border-radius: var(--radius-lg);
    padding: 14px 16px;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4);
    animation: form-actions-in 220ms var(--ease-out);
}
@keyframes form-actions-in {
    from { opacity: 0; transform: translateX(-50%) translateY(16px); }
    to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
@keyframes shake-bar {
    10%, 90% { transform: translateX(-50%) translateX(-1px); }
    20%, 80% { transform: translateX(-50%) translateX(2px); }
    30%, 50%, 70% { transform: translateX(-50%) translateX(-4px); }
    40%, 60% { transform: translateX(-50%) translateX(4px); }
}
.form-actions.shake { animation: shake-bar 400ms; }
@media (prefers-reduced-motion: reduce) {
    .form-actions.is-dirty { animation: none; }
    .form-actions.shake { animation: none; }
}

select, input[type="text"], input[type="file"], .btn-save {
    width: 100%; padding: 14px; border-radius: var(--radius-sm);
    border: 1px solid var(--glass-border); background: var(--surface-3); color: var(--text); outline: none;
}
.btn-save {
    background: var(--accent);
    font-weight: 700;
    margin-top: 30px;
    border: none;
    cursor: pointer;
    transition: background-color 160ms var(--ease-out), transform 160ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
    .btn-save:hover { background: var(--accent-hover); }
}
.btn-save:active { transform: scale(0.97); transition-duration: 100ms; }

.preview-img { max-width: 100%; border-radius: var(--radius-sm); margin-top: 15px; border: 2px solid var(--accent); }

.delete-btn {
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 15px;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    opacity: 0.6;
    transition: opacity 120ms var(--ease-out), background-color 120ms var(--ease-out), color 120ms var(--ease-out);
}
.delete-btn:hover { opacity: 1; background: rgba(var(--danger-rgb), 0.12); color: var(--danger); }
.delete-btn:active { transform: scale(0.92); transition-duration: 80ms; }

.sidebar-label { margin: 20px 20px 10px; font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; opacity: 0.7; }
.sidebar-label:first-child { margin-top: 10px; }

/* Announcement toast — Acrylic, not Mica: it floats, it's transient. */
.popup-box {
    position: fixed;
    bottom: 20px;
    right: 20px;
    width: 350px;
    background-color: var(--acrylic);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border: 1px solid var(--accent);
    border-radius: var(--radius-lg);
    padding: 20px;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4);
    transform: translateY(150%);
    transition: transform 400ms var(--ease-drawer);
    z-index: 9999;
}
.popup-box.active { transform: translateY(0); }
.popup-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; border-bottom: 1px solid var(--glass-border); padding-bottom: 10px; }
.popup-title { margin: 0; color: var(--accent); font-size: 16px; display: flex; align-items: center; gap: 8px; font-weight: bold; }
.popup-close { background: none; border: none; color: var(--text); font-size: 20px; cursor: pointer; opacity: 0.5; padding: 0; transition: opacity 120ms var(--ease-out), color 120ms var(--ease-out); }
.popup-close:hover { opacity: 1; color: var(--danger); }
.popup-body { color: var(--text-muted); line-height: 1.5; font-size: 13px; max-height: 200px; overflow-y: auto; }

/* Respect the user's motion preference everywhere: gentler, not zero. */
@media (prefers-reduced-motion: reduce) {
    .server-card, .server-card img, .menu-item, .btn-save, input[type=range]::-webkit-slider-thumb {
        transition-duration: 1ms !important;
    }
    .server-card:hover img { transform: none !important; }
}
