@import url('https://fonts.googleapis.com/css2?family=Chakra+Petch:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap');

:root {
    --void: #0a0b10;
    --panel: #13151c;
    --panel-raised: #1a1d2a;
    --line: rgba(148, 163, 220, 0.15);
    --indigo: #6d6af6;
    --cyan: #2dd9e8;
    --rose: #fb6f92;
    --emerald: #34e2a1;
    --amber: #f5b74d;
    --text-hi: #f8fafc;
    --text-mid: #cbd5e1;
    --text-low: #64748b;
}

* { box-sizing: border-box; }

body {
    font-family: 'Inter', sans-serif;
    background: linear-gradient(180deg, var(--void) 0%, #0d0e12 100%);
    color: var(--text-hi);
    position: relative;
    min-height: 100vh;
    overflow-x: hidden;
}

.font-display { font-family: 'Chakra Petch', sans-serif; }
.font-mono { font-family: 'JetBrains Mono', monospace; }

/* Wrapper for the four decorative background layers below (grid-field +
   three glow-orbs). They used to be position:fixed each, which caused the
   GPU-compositor black-screen bug fixed elsewhere in this file (see the
   .app-sidebar comment for the original diagnosis) - switching them to
   position:absolute fixed THAT, but introduced a different bug: glow-orb-2
   and glow-orb-3 deliberately sit partly off-screen (right:-5%/left:-10%)
   for an edge-bleed look, and as absolute (in-flow-for-sizing) elements
   that actually extends the document's real scrollable width past the
   viewport, even though body's overflow-x:hidden visually hides it at
   rest. iOS Safari (and some Chrome mobile builds) don't reliably keep
   honoring a ROOT element's overflow:hidden once a pinch-zoom gesture
   changes the visual viewport, which is exactly the "zoom out and the
   layout breaks" report this fixes - the hidden overflow becomes reachable
   again mid-zoom. A nested, non-root overflow:hidden container doesn't
   have that quirk, so this wrapper (not body) is what actually clips them,
   regardless of zoom level. height is generous enough to contain all three
   orbs' vertical extent (tallest reaches ~900px down) without clipping the
   glow effect itself. */
.bg-decor-layer {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 1000px;
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
}

.grid-field {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: 
        linear-gradient(rgba(45, 217, 232, 0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(45, 217, 232, 0.05) 1px, transparent 1px),
        linear-gradient(rgba(109, 106, 246, 0.02) 1px, transparent 1px),
        linear-gradient(90deg, rgba(109, 106, 246, 0.02) 1px, transparent 1px);
    background-size: 50px 50px, 50px 50px, 100px 100px, 100px 100px;
    opacity: 0.7;
    animation: gridPulse 8s ease-in-out infinite;
}

@keyframes gridPulse {
    0%, 100% { opacity: 0.5; }
    50% { opacity: 0.8; }
}

/* AMBIENT NEON GLOW ORB BACKGROUND */
.glow-orb {
    position: absolute;
    top: -120px;
    left: 50%;
    transform: translateX(-50%);
    width: 1000px;
    height: 600px;
    background: radial-gradient(circle, rgba(109, 106, 246, 0.3) 0%, rgba(45, 217, 232, 0.15) 45%, transparent 75%);
    filter: blur(60px);
    animation: orbFloat 12s ease-in-out infinite;
    z-index: 1;
    pointer-events: none;
}

@keyframes orbFloat {
    0%, 100% { transform: translateX(-50%) translateY(0); }
    50% { transform: translateX(-50%) translateY(20px); }
}

/* ADDITIONAL GLOW ORBS FOR MORE VIBRANCY */
.glow-orb-2 {
    position: absolute;
    top: 500px;
    right: -5%;
    width: 600px;
    height: 400px;
    background: radial-gradient(circle, rgba(251, 111, 146, 0.2) 0%, rgba(109, 106, 246, 0.1) 40%, transparent 70%);
    filter: blur(50px);
    animation: orbFloat2 15s ease-in-out infinite;
    z-index: 1;
    pointer-events: none;
}

@keyframes orbFloat2 {
    0%, 100% { transform: translate(0, 0); }
    50% { transform: translate(-30px, -20px); }
}

/* THIRD GLOW ORB FOR BALANCE */
.glow-orb-3 {
    position: absolute;
    top: 160px;
    left: -10%;
    width: 500px;
    height: 500px;
    background: radial-gradient(circle, rgba(52, 226, 161, 0.12) 0%, rgba(45, 217, 232, 0.06) 50%, transparent 70%);
    filter: blur(60px);
    animation: orbFloat3 18s ease-in-out infinite;
    z-index: 1;
    pointer-events: none;
}

@keyframes orbFloat3 {
    0%, 100% { transform: translate(0, 0); }
    50% { transform: translate(25px, 15px); }
}

/* ORB AMBIENT RESPONSIVE MOTION */
@keyframes pulse-orb {
    0% {
        transform: translateX(-50%) scale(1);
        opacity: 0.8;
    }
    100% {
        transform: translateX(-48%) scale(1.1);
        opacity: 1;
    }
}

/* ADDITIONAL PARTICLE EFFECTS */
.particle-field {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: 
        radial-gradient(circle at 20% 30%, rgba(45, 217, 232, 0.1) 0%, transparent 50%),
        radial-gradient(circle at 80% 70%, rgba(109, 106, 246, 0.08) 0%, transparent 50%),
        radial-gradient(circle at 40% 80%, rgba(251, 111, 146, 0.06) 0%, transparent 40%);
    animation: particleFloat 20s ease-in-out infinite;
}

@keyframes particleFloat {
    0%, 100% { transform: translate(0, 0); }
    25% { transform: translate(10px, -5px); }
    50% { transform: translate(-5px, 10px); }
    75% { transform: translate(-10px, -5px); }
}

/* SCANLINE / CRT FILTER TO ENHANCE SCIFI VIBES */
body::after {
    content: " ";
    display: block;
    position: fixed;
    top: 0; left: 0; bottom: 0; right: 0;
    background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.15) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.04), rgba(0, 255, 0, 0.01), rgba(0, 0, 255, 0.04));
    z-index: 9999;
    background-size: 100% 4px, 6px 100%;
    pointer-events: none;
    opacity: 0.08;
}

/* SCIFI PANEL CONTAINER */
.panel {
    background: linear-gradient(135deg, rgba(19, 21, 28, 0.9) 0%, rgba(10, 11, 16, 0.95) 100%);
    -webkit-backdrop-filter: blur(16px) saturate(140%);
    backdrop-filter: blur(16px) saturate(140%);
    border: 1px solid rgba(148, 163, 220, 0.15);
    transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.panel::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(45, 217, 232, 0.4), transparent);
    opacity: 0.6;
}

.panel:hover {
    border-color: rgba(45, 217, 232, 0.4);
    box-shadow: 0 0 30px rgba(45, 217, 232, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.1);
}

/* ADVANCED CYBERNETIC BRACKET CORNERS DESIGN */
.bracket-frame {
    position: relative;
    overflow: visible;
}

/* Several modals/dropdowns pair `bracket-frame` with a Tailwind
   `max-h-[...] overflow-y-auto` so long content scrolls inside a capped
   box (profile modal, notification dropdowns, template pickers, ticket
   replies, etc). `.bracket-frame`'s own `overflow: visible` above has the
   same specificity as Tailwind's single-class `.overflow-y-auto`, and this
   stylesheet loads after tailwind.css, so it was silently winning and
   cancelling the scroll - the box just grew past the viewport with no
   scrollbar, forcing a page zoom-out to see the rest. This compound
   selector (two classes = higher specificity) wins regardless of load
   order and restores the intended scroll, without touching the separate
   `bracket-frame` + `overflow-hidden` panels elsewhere that rely on the
   visible corners showing through. */
.bracket-frame.overflow-y-auto {
    overflow-y: auto;
}

/* Same specificity trap as above, but for `position`: `.bracket-frame`'s
   own `position: relative` (single class) has equal specificity to
   Tailwind's single-class `.absolute { position: absolute }`, and this
   stylesheet loads after tailwind.css, so it was silently winning on any
   dropdown that pairs `absolute` with `bracket-frame` for the corner
   decoration (notification bell panel, account menu, survey/analytics
   action menus, etc). With `position` cancelled back to `relative`, the
   panel stayed in normal document flow instead of floating over the page,
   inflating the whole nav bar's height to match the open panel's content
   and shoving the other header icons down to its vertical center - the
   "clunky notification tab" bug. This compound selector wins regardless
   of load order and restores the intended floating behavior. */
.bracket-frame.absolute {
    position: absolute;
}

.bracket-frame::before,
.bracket-frame::after {
    content: '';
    position: absolute;
    width: 16px;
    height: 16px;
    pointer-events: none;
    z-index: 5;
    transition: all 0.3s ease;
}

/* Top-Left & Bottom-Right Corner styling */
.bracket-frame::before {
    top: -1px;
    left: -1px;
    border-top: 2px solid #2dd9e8;
    border-left: 2px solid #2dd9e8;
    box-shadow: 0 0 8px rgba(45, 217, 232, 0.4);
}

.bracket-frame::after {
    bottom: -1px;
    right: -1px;
    border-bottom: 2px solid #6d6af6;
    border-right: 2px solid #6d6af6;
    box-shadow: 0 0 8px rgba(109, 106, 246, 0.4);
}

/* Hover-activated cybernetic corner expansion */
.bracket-frame:hover::before {
    width: 22px;
    height: 22px;
    border-top-color: #2dd9e8;
    border-left-color: #2dd9e8;
    filter: drop-shadow(0 0 6px rgba(45, 217, 232, 0.8));
}

.bracket-frame:hover::after {
    width: 22px;
    height: 22px;
    border-bottom-color: #fb6f92;
    border-right-color: #fb6f92;
    filter: drop-shadow(0 0 6px rgba(251, 111, 146, 0.8));
}

/* HIGH-TECH PULSING DOTS */
.pulse-dot {
    position: relative;
    display: inline-block;
    animation: pulseGlow 2s ease-in-out infinite;
}

@keyframes pulseGlow {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.7; transform: scale(1.1); }
}

.pulse-dot::after {
    content: '';
    position: absolute;
    inset: -4px;
    border-radius: 9999px;
    border: 1px solid currentColor;
    opacity: 0.8;
    animation: pulse-ring 2s cubic-bezier(0.215, 0.610, 0.355, 1) infinite;
}

@keyframes pulse-ring {
    0% {
        transform: scale(0.6);
        opacity: 0.8;
    }
    100% {
        transform: scale(2.2);
        opacity: 0;
    }
}

/* PREMIUM SCIFI INPUTS */
.input-style {
    background: rgba(8, 9, 13, 0.8);
    border: 1px solid rgba(148, 163, 220, 0.16);
    color: #eef0f7;
    font-family: "JetBrains Mono", monospace;
    transition: all 0.25s ease;
}

.input-style:focus {
    outline: none;
    border-color: #2dd9e8;
    box-shadow: 0 0 12px rgba(45, 217, 232, 0.15);
    background: rgba(16, 18, 25, 0.95);
}

/* NEO-PULSING PRIMARY BUTTONS */
.btn-primary {
    position: relative;
    background: linear-gradient(135deg, #6d6af6 0%, #2dd9e8 100%);
    color: #08090d;
    font-weight: 700;
    font-family: "Chakra Petch", sans-serif;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    border: none;
    overflow: hidden;
    box-shadow: 0 4px 15px rgba(45, 217, 232, 0.25);
    cursor: pointer;
    transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.btn-primary::before {
    content: '';
    position: absolute;
    top: 0; left: -100%;
    width: 100%; height: 100%;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
    transition: all 0.6s ease;
}

.btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 22px rgba(45, 217, 232, 0.45);
    color: #08090d;
}

.btn-primary:hover::before {
    left: 100%;
}

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

/* ENTRANCE ANIMATIONS */
@keyframes fadeInUp {
    from {
        opacity: 0;
        transform: translateY(30px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes fadeInScale {
    from {
        opacity: 0;
        transform: scale(0.9);
    }
    to {
        opacity: 1;
        transform: scale(1);
    }
}

@keyframes slideInLeft {
    from {
        opacity: 0;
        transform: translateX(-30px);
    }
    to {
        opacity: 1;
        transform: translateX(0);
    }
}

@keyframes slideInRight {
    from {
        opacity: 0;
        transform: translateX(30px);
    }
    to {
        opacity: 1;
        transform: translateX(0);
    }
}

.animate-fade-in-up {
    animation: fadeInUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
    opacity: 0;
}

.animate-fade-in-scale {
    animation: fadeInScale 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards;
    opacity: 0;
}

.animate-slide-in-left {
    animation: slideInLeft 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
    opacity: 0;
}

.animate-slide-in-right {
    animation: slideInRight 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
    opacity: 0;
}

/* Staggered animation delays */
.delay-100 { animation-delay: 0.1s; }
.delay-200 { animation-delay: 0.2s; }
.delay-300 { animation-delay: 0.3s; }
.delay-400 { animation-delay: 0.4s; }
.delay-500 { animation-delay: 0.5s; }
.delay-600 { animation-delay: 0.6s; }

/* GLITCH EFFECT */
@keyframes glitch {
    0% {
        transform: translate(0);
    }
    20% {
        transform: translate(-2px, 2px);
    }
    40% {
        transform: translate(-2px, -2px);
    }
    60% {
        transform: translate(2px, 2px);
    }
    80% {
        transform: translate(2px, -2px);
    }
    100% {
        transform: translate(0);
    }
}

@keyframes glitch-skew {
    0% {
        transform: skew(0deg);
    }
    20% {
        transform: skew(2deg);
    }
    40% {
        transform: skew(-2deg);
    }
    60% {
        transform: skew(1deg);
    }
    80% {
        transform: skew(-1deg);
    }
    100% {
        transform: skew(0deg);
    }
}

.glitch-effect {
    position: relative;
    display: inline-block;
}

.glitch-effect:hover {
    animation: glitch 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) both infinite;
}

.glitch-effect::before,
.glitch-effect::after {
    content: attr(data-text);
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    pointer-events: none;
}

.glitch-effect:hover::before {
    opacity: 0.8;
    color: #2dd9e8;
    animation: glitch-skew 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) both infinite;
    clip-path: polygon(0 0, 100% 0, 100% 45%, 0 45%);
    transform: translate(-2px);
}

.glitch-effect:hover::after {
    opacity: 0.8;
    color: #fb6f92;
    animation: glitch-skew 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) reverse both infinite;
    clip-path: polygon(0 55%, 100% 55%, 100% 100%, 0 100%);
    transform: translate(2px);
}

/* PREMIUM UPGRADE BUTTON WITH SHINE EFFECT */
.btn-upgrade {
    position: relative;
    background: linear-gradient(135deg, #6d6af6 0%, #fb6f92 100%);
    color: white;
    font-weight: 700;
    font-family: "Chakra Petch", sans-serif;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    border: 1px solid rgba(255, 255, 255, 0.2);
    overflow: hidden;
    box-shadow: 0 0 15px rgba(109, 106, 246, 0.35);
    cursor: pointer;
    transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.btn-upgrade::before {
    content: '';
    position: absolute;
    top: 0; left: -100%;
    width: 100%; height: 100%;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
    transition: transform 1s ease-out;
}

.btn-upgrade:hover {
    filter: brightness(1.1);
    box-shadow: 0 0 22px rgba(251, 111, 146, 0.5);
    transform: translateY(-1px);
}

.btn-upgrade:hover::before {
    transform: translateX(100%);
}

.btn-upgrade:active {
    transform: scale(0.95);
}

/* STATUS INDICATOR WITH PULSE */
.status-indicator {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    background: rgba(14, 16, 23, 0.85);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border: 1px solid rgba(45, 217, 232, 0.3);
    border-radius: 9999px;
    box-shadow: 0 0 15px rgba(45, 217, 232, 0.06);
    transition: all 0.3s ease;
}

.status-indicator:hover {
    border-color: rgba(45, 217, 232, 0.5);
    box-shadow: 0 0 20px rgba(45, 217, 232, 0.15);
}

.status-dot {
    position: relative;
    display: inline-flex;
}

.status-dot::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 9999px;
    background: currentColor;
    animation: ping 1.5s cubic-bezier(0, 0, 0.2, 1) infinite;
}

@keyframes ping {
    75%, 100% {
        transform: scale(2);
        opacity: 0;
    }
}

/* WELCOME HERO CARD */
.welcome-card {
    position: relative;
    overflow: hidden;
    border-radius: 1rem;
    padding: 1.5rem 2rem;
    border: 1px solid rgba(148, 163, 220, 0.1);
    background: linear-gradient(135deg, #161925 0%, #12141e 50%, #0a0b10 100%);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}

.welcome-card::before {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 20rem;
    height: 20rem;
    background: rgba(109, 106, 246, 0.05);
    border-radius: 50%;
    filter: blur(3rem);
    pointer-events: none;
}

.system-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-family: "JetBrains Mono", monospace;
    font-size: 0.5625rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: #2dd9e8;
    background: rgba(45, 217, 232, 0.15);
    padding: 0.25rem 0.75rem;
    border-radius: 9999px;
    border: 1px solid rgba(45, 217, 232, 0.25);
    margin-bottom: 0.25rem;
}

.system-badge .dot {
    width: 0.375rem;
    height: 0.375rem;
    border-radius: 9999px;
    background: #2dd9e8;
    box-shadow: 0 0 8px #2dd9e8;
    animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

@keyframes pulse {
    0%, 100% {
        opacity: 1;
    }
    50% {
        opacity: 0.5;
    }
}

/* METRIC CARDS WITH HOVER EFFECTS */
.metric-card {
    padding: 1.25rem;
    border-radius: 0.75rem;
    border: 1px solid rgba(148, 163, 220, 0.08);
    background: #11131c;
    transition: all 0.3s ease;
}

.metric-card:hover {
    border-color: rgba(45, 217, 232, 0.3);
}

.metric-card.hover-cyan:hover {
    border-color: rgba(45, 217, 232, 0.3);
}

.metric-card.hover-emerald:hover {
    border-color: rgba(52, 226, 161, 0.3);
}

.metric-card.hover-indigo:hover {
    border-color: rgba(109, 106, 246, 0.3);
}

.metric-card.hover-rose:hover {
    border-color: rgba(251, 111, 146, 0.3);
}

/* LIVE TELEMETRY FEED */
.telemetry-feed {
    padding: 1.25rem;
    border-radius: 0.75rem;
    background: #0d0f15;
    border: 1px solid rgba(148, 163, 220, 0.08);
    border-left: 4px solid #6d6af6;
}

.telemetry-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-bottom: 0.625rem;
    border-bottom: 1px solid rgba(148, 163, 220, 0.05);
}

.telemetry-indicator {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 9999px;
    background: #fb6f92;
    animation: ping 1.5s cubic-bezier(0, 0, 0.2, 1) infinite;
}

/* GRADIENT BUTTONS */
.btn-gradient-cyan {
    background: linear-gradient(135deg, #2dd9e8 0%, #6d6af6 100%);
    color: black;
    font-weight: 700;
    font-family: "Chakra Petch", sans-serif;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    border: none;
    border-radius: 0.75rem;
    padding: 0.5rem 1rem;
    cursor: pointer;
    transition: all 0.3s ease;
}

.btn-gradient-cyan:hover {
    transform: scale(1.02);
}

.btn-glass {
    background: rgba(255, 255, 255, 0.05);
    color: white;
    border: 1px solid rgba(255, 255, 255, 0.15);
    font-weight: 700;
    font-family: "Chakra Petch", sans-serif;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    border-radius: 0.75rem;
    padding: 0.5rem 1rem;
    cursor: pointer;
    transition: all 0.3s ease;
}

.btn-glass:hover {
    background: rgba(255, 255, 255, 0.1);
}

/* SERVER CARDS WITH ACTIVE/OFFLINE STATES */
.server-card {
    padding: 1.5rem;
    border-radius: 1rem;
    border: 1px solid rgba(148, 163, 220, 0.1);
    transition: all 0.3s ease;
}

.server-card.active {
    background: #11131c;
    border-color: rgba(148, 163, 220, 0.1);
}

.server-card.active:hover {
    border-color: rgba(109, 106, 246, 0.4);
    box-shadow: 0 4px 25px rgba(109, 106, 246, 0.08);
}

.server-card.inactive {
    background: #0d0e14;
    border-color: rgba(148, 163, 220, 0.05);
    opacity: 0.8;
}

.server-icon {
    width: 3rem;
    height: 3rem;
    border-radius: 0.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid rgba(148, 163, 220, 0.1);
    background: #181a26;
    font-size: 1.5rem;
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);
}

.server-status-light {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 9999px;
}

.server-status-light.online {
    background: #2dd9e8;
    animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
    box-shadow: 0 0 8px #2dd9e8;
}

.server-status-light.offline {
    background: #475569;
}

/* SERVER STATS PANEL */
.server-stats {
    padding: 1rem;
    border-radius: 0.75rem;
    background: rgba(23, 26, 38, 0.8);
    border: 1px solid rgba(148, 163, 220, 0.06);
}

/* PROGRESS BARS */
.progress-bar {
    width: 100%;
    height: 0.375rem;
    background: rgba(0, 0, 0, 0.4);
    border-radius: 9999px;
    overflow: hidden;
}

.progress-fill {
    height: 100%;
    border-radius: 9999px;
    transition: all 0.5s ease;
}

.progress-fill.success {
    background: #34e2a1;
}

.progress-fill.warning {
    background: #fb6f92;
}

/* LOG ENTRY STYLING */
.log-entry {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    color: #cbd5e1;
}

.log-timestamp {
    color: #6d6af6;
    font-weight: 500;
    flex-shrink: 0;
}

.log-badge {
    padding: 0.125rem 0.375rem;
    border-radius: 0.25rem;
    font-size: 0.5rem;
    font-weight: 700;
    text-transform: uppercase;
    flex-shrink: 0;
}

.log-badge.success {
    background: rgba(52, 226, 161, 0.1);
    color: #34e2a1;
}

.log-badge.ticket {
    background: rgba(45, 217, 232, 0.1);
    color: #2dd9e8;
}

.log-badge.security {
    background: rgba(251, 111, 146, 0.1);
    color: #fb6f92;
}

/* CUSTOM SCROLLBAR FOR LOGS */
.custom-scrollbar::-webkit-scrollbar {
    width: 6px;
}

.custom-scrollbar::-webkit-scrollbar-track {
    background: rgba(0, 0, 0, 0.2);
    border-radius: 3px;
}

.custom-scrollbar::-webkit-scrollbar-thumb {
    background: rgba(148, 163, 220, 0.2);
    border-radius: 3px;
}

.custom-scrollbar::-webkit-scrollbar-thumb:hover {
    background: rgba(148, 163, 220, 0.4);
}

/* OFFLINE SERVER STATE */
.server-offline-state {
    padding: 1.5rem;
    text-align: center;
    border: 1px dashed rgba(148, 163, 220, 0.08);
    border-radius: 0.75rem;
    background: rgba(0, 0, 0, 0.2);
}

/* SECTION DIVIDER */
.section-divider {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.section-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: linear-gradient(to right, rgba(148, 163, 220, 0.1), transparent);
}

/* SECONDRY BUTTONS WITH GLASS OVERLAY */
.btn-secondary {
    background: rgba(22, 25, 37, 0.6);
    border: 1px solid rgba(148, 163, 220, 0.2);
    color: #9ba0b8;
    font-family: "Chakra Petch", sans-serif;
    letter-spacing: 0.05em;
    transition: all 0.25s ease;
    cursor: pointer;
}

.btn-secondary:hover {
    background: rgba(109, 106, 246, 0.1);
    color: #eef0f7;
    border-color: rgba(109, 106, 246, 0.4);
}

/* CUSTOM HIGH TECH SCROLLBARS */
::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

::-webkit-scrollbar-track {
    background: #08090d;
}

::-webkit-scrollbar-thumb {
    background: #161925;
    border: 1px solid rgba(148, 163, 220, 0.08);
    border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
    background: #6d6af6;
    border-color: #2dd9e8;
}

/* CHROME/GLOW TRANSITIONS FOR EMBEDS */
.glow-border {
    animation: glow-pulse 4s infinite alternate;
}

@keyframes glow-pulse {
    0% {
        box-shadow: 0 0 10px rgba(109, 106, 246, 0.1);
    }
    100% {
        box-shadow: 0 0 20px rgba(45, 217, 232, 0.2);
    }
}

/* LOGO SWIRL SPINNING AND PULSING ANIMATIONS */
@keyframes spin-slow {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

@keyframes spin-reverse-slower {
    from {
        transform: rotate(360deg);
    }
    to {
        transform: rotate(0deg);
    }
}

.animate-spin-slow {
    animation: spin-slow 20s linear infinite;
    transform-origin: center;
}

.animate-spin-reverse-slower {
    animation: spin-reverse-slower 30s linear infinite;
    transform-origin: center;
}

/* Hide scrollbars but keep functionality */
.no-scrollbar::-webkit-scrollbar { display: none; }
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }

::selection { background: rgba(109,106,246,0.35); }

html { scroll-behavior: smooth; }

/* ============================================================
   TOAST NOTIFICATIONS
   Replaces native alert()/confirm() popups, which block the whole
   tab and look nothing like the rest of the UI, with an in-theme
   stack that appears/dismisses without interrupting the user.
   ============================================================ */
#toast-stack {
    position: fixed;
    top: 1.5rem;
    right: 1.5rem;
    z-index: 9998;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    width: min(360px, calc(100vw - 3rem));
    pointer-events: none;
}

.toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.875rem 1rem;
    border-radius: 0.875rem;
    background: linear-gradient(135deg, rgba(19, 21, 28, 0.97) 0%, rgba(10, 11, 16, 0.98) 100%);
    -webkit-backdrop-filter: blur(16px) saturate(140%);
    backdrop-filter: blur(16px) saturate(140%);
    border: 1px solid rgba(148, 163, 220, 0.15);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
    font-size: 0.8125rem;
    color: var(--text-mid);
    transform: translateX(calc(100% + 1.5rem));
    opacity: 0;
    transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.35s ease;
}

.toast.toast-visible {
    transform: translateX(0);
    opacity: 1;
}

.toast-icon {
    flex-shrink: 0;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 9999px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
}

.toast-success .toast-icon { background: rgba(52, 226, 161, 0.15); color: var(--emerald); }
.toast-error .toast-icon { background: rgba(251, 111, 146, 0.15); color: var(--rose); }
.toast-warning .toast-icon { background: rgba(245, 183, 77, 0.15); color: var(--amber); }
.toast-info .toast-icon { background: rgba(45, 217, 232, 0.15); color: var(--cyan); }

.toast-success { border-color: rgba(52, 226, 161, 0.25); }
.toast-error { border-color: rgba(251, 111, 146, 0.25); }
.toast-warning { border-color: rgba(245, 183, 77, 0.25); }
.toast-info { border-color: rgba(45, 217, 232, 0.25); }

.toast-message { flex: 1; line-height: 1.4; padding-top: 0.1rem; }

.toast-close {
    flex-shrink: 0;
    background: none;
    border: none;
    color: var(--text-low);
    cursor: pointer;
    padding: 0;
    font-size: 0.75rem;
    line-height: 1;
    transition: color 0.2s ease;
}

.toast-close:hover { color: var(--text-hi); }

/* ============================================================
   MODAL TRANSITIONS
   The old approach toggled `hidden`/`flex` directly, so modals
   just snapped into existence. This fades the backdrop in and
   scales the panel up, and reverses it on the way out so JS can
   wait for the transition before actually hiding the element.
   ============================================================ */
.modal-overlay {
    transition: opacity 0.25s ease;
    opacity: 0;
}

.modal-overlay.modal-open {
    opacity: 1;
}

.modal-overlay .modal-panel {
    transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease;
    transform: scale(0.94) translateY(8px);
    opacity: 0;
}

.modal-overlay.modal-open .modal-panel {
    transform: scale(1) translateY(0);
    opacity: 1;
}

/* ============================================================
   SKELETON LOADING STATES
   A plain "Loading..." string causes a layout-shifting text swap
   the instant data arrives. A shimmer bar sized like the eventual
   content reads as "this is loading" at a glance and swaps out
   without the jump.
   ============================================================ */
.skeleton-bar {
    display: inline-block;
    height: 1.5rem;
    width: 4.5rem;
    border-radius: 0.375rem;
    background: linear-gradient(90deg, rgba(148, 163, 220, 0.08) 25%, rgba(148, 163, 220, 0.18) 37%, rgba(148, 163, 220, 0.08) 63%);
    background-size: 400% 100%;
    animation: skeletonShimmer 1.6s ease-in-out infinite;
    vertical-align: middle;
}

@keyframes skeletonShimmer {
    0% { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
}

/* ============================================================
   ACCESSIBLE KEYBOARD FOCUS
   Buttons/links only had hover treatment - a keyboard user tabbing
   through the dashboard had no way to see where focus was. This
   restores a visible ring on keyboard focus only (not on mouse
   click) so pointer users see no visual change.
   ============================================================ */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
.btn-primary:focus-visible,
.btn-secondary:focus-visible,
.btn-glass:focus-visible,
.btn-gradient-cyan:focus-visible,
.btn-upgrade:focus-visible,
.nav-link:focus-visible,
.util-icon-btn:focus-visible,
.avatar-btn:focus-visible,
.app-nav-link:focus-visible,
.app-sidebar-toggle:focus-visible {
    outline: 2px solid var(--cyan);
    outline-offset: 2px;
    border-radius: 0.375rem;
}

/* ============================================================
   REDUCED MOTION
   Respect the OS-level "reduce motion" preference: keep the
   overall dark theme intact but stop the ambient grid pulse, orb
   drift, and glitch/scanline effects, which are exactly the kind
   of continuous motion that setting exists to opt out of.
   ============================================================ */
/* ============================================================
   PRIMARY NAVIGATION
   Bigger, clearer wayfinding for the top nav bar. Previously every
   link looked identical whether or not it was the current page, so
   there was no way to tell where you were in the app - .nav-link
   now gets an explicit .active state (filled gradient + glow) so
   the current section is unmistakable at a glance.
   ============================================================ */
.nav-bar {
    padding: 0.5rem;
    border-radius: 1rem;
    position: relative;
}

.nav-bar::after {
    content: '';
    position: absolute;
    left: 1rem;
    right: 1rem;
    bottom: -1px;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(45, 217, 232, 0.35), rgba(109, 106, 246, 0.35), transparent);
}

.nav-link {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.7rem 1.125rem;
    border-radius: 0.75rem;
    font-family: "JetBrains Mono", monospace;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-mid);
    border: 1px solid transparent;
    transition: all 0.25s ease;
    white-space: nowrap;
}

.nav-link:hover {
    color: var(--text-hi);
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(148, 163, 220, 0.15);
}

.nav-link .nav-link-icon {
    width: 1.125rem;
    height: 1.125rem;
    flex-shrink: 0;
    transition: filter 0.25s ease;
}

.nav-link.active {
    color: #08090d;
    background: linear-gradient(135deg, var(--indigo) 0%, var(--cyan) 100%);
    border-color: transparent;
    box-shadow: 0 0 18px rgba(45, 217, 232, 0.35), 0 2px 8px rgba(0, 0, 0, 0.3);
}

.nav-link.active .nav-link-icon {
    filter: brightness(0) saturate(100%);
    opacity: 0.85;
}

/* ============================================================
   UTILITY CLUSTER (status / language / notifications / avatar)
   Bumped to a consistent 40px control height so this row reads
   as one deliberate row of controls instead of a cluster of
   mismatched pill sizes.
   ============================================================ */
.util-pill {
    height: 2.5rem;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0 1rem;
    border-radius: 9999px;
    background: rgba(14, 16, 23, 0.85);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border: 1px solid rgba(148, 163, 220, 0.15);
    font-family: "JetBrains Mono", monospace;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-mid);
    transition: all 0.25s ease;
}

.util-icon-btn {
    height: 2.5rem;
    width: 2.5rem;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    background: rgba(14, 16, 23, 0.85);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border: 1px solid rgba(148, 163, 220, 0.15);
    color: var(--text-mid);
    cursor: pointer;
    transition: all 0.25s ease;
    position: relative;
}

.util-icon-btn:hover {
    color: var(--text-hi);
    border-color: rgba(45, 217, 232, 0.4);
    box-shadow: 0 0 15px rgba(45, 217, 232, 0.15);
}

.util-icon-btn .util-badge {
    position: absolute;
    top: 0.35rem;
    right: 0.35rem;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 9999px;
    background: var(--rose);
    box-shadow: 0 0 6px var(--rose);
}

/* Avatar / profile menu trigger - replaces the plain text "MORE"
   hamburger with something that reads as "this is you", the way
   Discord/Linear/Vercel all put account-level nav behind an
   avatar rather than a loose text link. */
.avatar-btn {
    height: 2.5rem;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0.75rem 0.25rem 0.25rem;
    border-radius: 9999px;
    background: rgba(14, 16, 23, 0.85);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border: 1px solid rgba(148, 163, 220, 0.15);
    cursor: pointer;
    transition: all 0.25s ease;
}

.avatar-btn:hover {
    border-color: rgba(109, 106, 246, 0.5);
    box-shadow: 0 0 15px rgba(109, 106, 246, 0.2);
}

.avatar-btn img,
.avatar-btn .avatar-fallback {
    width: 2rem;
    height: 2rem;
    border-radius: 9999px;
    object-fit: cover;
    flex-shrink: 0;
}

.avatar-btn .avatar-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, var(--indigo) 0%, var(--cyan) 100%);
    color: #08090d;
    font-family: "Chakra Petch", sans-serif;
    font-weight: 700;
    font-size: 0.75rem;
}

.avatar-btn .avatar-name {
    font-family: "JetBrains Mono", monospace;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-mid);
    max-width: 6rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.avatar-btn:hover .avatar-name {
    color: var(--text-hi);
}

/* ============================================================
   APP SHELL
   Persistent left sidebar + slim topbar, replacing the old
   per-page top nav row that had to cram brand, primary nav, and
   the whole utility cluster into one horizontal strip. Rendered
   once in base.html instead of copy-pasted (with drifting markup)
   into six separate page templates.
   ============================================================ */
.app-shell {
    display: flex;
    min-height: 100vh;
    position: relative;
    z-index: 1;
}

.app-sidebar {
    width: 17rem;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    background: linear-gradient(180deg, rgba(13, 15, 23, 0.97) 0%, rgba(8, 9, 13, 0.98) 100%);
    border-right: 1px solid rgba(148, 163, 220, 0.1);
    /* Was position:fixed - a full-height, always-mounted, high-z-index
       layer with continuously-animating children (spinning logo, pulse-dot,
       status ping) inside it. That combination is a known GPU compositor
       trigger: the browser keeps it on its own layer permanently and would
       periodically re-promote/mis-scale it, blowing up whichever icon it
       was rendering at that moment to fill the viewport for a frame or two.
       Removing backdrop-filter alone (see git history) didn't stop it, so
       this removes position:fixed itself on desktop, where the sidebar is
       visible essentially 100% of the time. sticky keeps the exact same
       pinned-while-scrolling look, but the element is a normal flex child
       instead of a floating always-on compositor layer - .app-main no
       longer needs its old margin-left:17rem offset hack because of this.
       Mobile keeps position:fixed (see the max-width:1023px block below)
       since there it's a short-lived, user-toggled overlay drawer rather
       than something permanently mounted, so it isn't the same risk. */
    position: sticky;
    top: 0;
    height: 100vh;
    z-index: 50;
    transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.app-sidebar-brand {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1.75rem 1.5rem 1.5rem;
    border-bottom: 1px solid rgba(148, 163, 220, 0.08);
}

.app-sidebar-nav {
    flex: 1;
    overflow-y: auto;
    padding: 1.25rem 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.app-nav-link {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    padding: 0.8rem 1rem;
    border-radius: 0.75rem;
    font-family: "Chakra Petch", sans-serif;
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--text-mid);
    border-left: 2px solid transparent;
    transition: all 0.2s ease;
    position: relative;
}

.app-nav-link .app-nav-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex-shrink: 0;
}

.app-nav-link:hover {
    color: var(--text-hi);
    background: rgba(255, 255, 255, 0.04);
}

.app-nav-link.active {
    color: var(--text-hi);
    background: linear-gradient(90deg, rgba(45, 217, 232, 0.14) 0%, rgba(109, 106, 246, 0.05) 100%);
    border-left-color: var(--cyan);
    box-shadow: inset 0 0 20px rgba(45, 217, 232, 0.06);
}

.app-nav-link.active::after {
    content: '';
    position: absolute;
    right: 1rem;
    top: 50%;
    transform: translateY(-50%);
    width: 0.375rem;
    height: 0.375rem;
    border-radius: 9999px;
    background: var(--cyan);
    box-shadow: 0 0 8px var(--cyan);
}

.app-sidebar-footer {
    padding: 1rem 1.5rem 1.5rem;
    border-top: 1px solid rgba(148, 163, 220, 0.08);
}

.app-sidebar-collapse-btn {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    padding: 0.7rem 1rem;
    border-radius: 0.75rem;
    background: transparent;
    border: 1px solid rgba(148, 163, 220, 0.12);
    color: var(--text-mid);
    font-family: "Chakra Petch", sans-serif;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    cursor: pointer;
    transition: all 0.2s ease;
}

.app-sidebar-collapse-btn:hover {
    color: var(--text-hi);
    border-color: var(--cyan);
    background: rgba(255, 255, 255, 0.03);
}

.app-sidebar-collapse-icon {
    width: 1.1rem;
    height: 1.1rem;
    flex-shrink: 0;
    transition: transform 0.3s ease;
}

/* Collapsed state - desktop only (see the max-width:1023px block below,
   which never adds this class; the mobile drawer already has its own
   fully-hidden/fully-shown behavior and doesn't need an icon-only middle
   state). Shrinks the sidebar to just enough room for the icons, hides
   every text label via .app-nav-label/.app-sidebar-brand-text, and
   flips the collapse icon to point the other way. */
@media (min-width: 1024px) {
    .app-sidebar.collapsed {
        width: 5.25rem;
    }

    .app-sidebar.collapsed .app-sidebar-brand-text,
    .app-sidebar.collapsed .app-nav-label {
        display: none;
    }

    .app-sidebar.collapsed .app-sidebar-brand {
        justify-content: center;
        padding-left: 0.75rem;
        padding-right: 0.75rem;
    }

    .app-sidebar.collapsed .app-nav-link {
        justify-content: center;
        padding-left: 0;
        padding-right: 0;
    }

    .app-sidebar.collapsed .app-nav-link.active::after {
        display: none;
    }

    .app-sidebar.collapsed .app-sidebar-footer {
        padding-left: 0.75rem;
        padding-right: 0.75rem;
    }

    .app-sidebar.collapsed .app-sidebar-collapse-btn {
        justify-content: center;
        padding-left: 0;
        padding-right: 0;
    }

    .app-sidebar.collapsed .app-sidebar-collapse-icon {
        transform: rotate(180deg);
    }
}

.app-sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(3, 3, 5, 0.7);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    z-index: 40;
}

.app-sidebar-backdrop.open {
    display: block;
}

.app-main {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    /* No margin-left offset needed anymore - the sidebar is a real flex
       child now (position:sticky, not fixed), so it already takes up its
       own 17rem in the row instead of being pulled out of flow. */
}

.app-topbar {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.5rem;
    background: rgba(10, 11, 16, 0.85);
    -webkit-backdrop-filter: blur(16px) saturate(140%);
    backdrop-filter: blur(16px) saturate(140%);
    border-bottom: 1px solid rgba(148, 163, 220, 0.08);
}

/* partials/nav_controls.html renders every page's utility cluster
   (upgrade pill, status pill, language select, theme toggle,
   notification bell, avatar menu - now up to 6 items) as one
   flex-nowrap row. On a narrow phone that row doesn't fit and, being
   nowrap, was pushing wider than the viewport instead of shrinking -
   the whole topbar (and the page under it) forced horizontal scroll.
   overflow-x:auto was the first instinct here, but the notification
   and avatar dropdowns are position:absolute DESCENDANTS of this same
   row, and per the CSS overflow spec, setting overflow-x to anything
   but visible silently forces the paired overflow-y to auto too - that
   would have clipped both dropdowns the moment they extended below
   this row's own height. Letting the row wrap onto a second line
   instead avoids that clipping entirely. Overrides the Tailwind
   flex-nowrap utility already on the element (same specificity, this
   file loads after tailwind.css so it wins). */
@media (max-width: 640px) {
    .app-topbar {
        padding: 0.75rem 1rem;
        gap: 0.5rem;
        flex-wrap: wrap;
    }

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

.app-sidebar-toggle {
    display: none;
    height: 2.5rem;
    width: 2.5rem;
    align-items: center;
    justify-content: center;
    border-radius: 0.75rem;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(148, 163, 220, 0.15);
    color: var(--text-hi);
    flex-shrink: 0;
    cursor: pointer;
}

.app-content {
    flex: 1;
    padding: 1.75rem 1.5rem 3rem;
}

/* Global scroll affordance for every Tailwind `overflow-x-auto` region
   site-wide (wide tables, tab bars, header button clusters, etc). These
   were never actually broken - confirmed via document.documentElement
   .scrollWidth on a real phone-width test, the page itself never
   overflows - each region already scrolls internally exactly as
   intended. The bug was that a bare overflow-x-auto container looks
   IDENTICAL whether its content is fully visible or clipped, so on a
   touchscreen (or a mouse, where horizontal drag/swipe isn't obvious at
   all) it just looks cut off/broken instead of "swipe for more."
   owner_panel.html's tab bar already had a one-off local fix for this
   exact problem; this makes that same fade-hint + momentum-scroll
   treatment apply everywhere automatically instead of requiring every
   page to redo it. Mask-based (not a background-gradient "scroll
   shadow") specifically because it doesn't need to match each
   container's own background color - a mask just fades opacity, so it
   works identically over --panel, --void, or anything else without any
   risk of a mismatched-color seam. */
.overflow-x-auto {
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
}
@media (max-width: 767px) {
    .overflow-x-auto {
        mask-image: linear-gradient(to right, black calc(100% - 28px), transparent 100%);
        -webkit-mask-image: linear-gradient(to right, black calc(100% - 28px), transparent 100%);
    }
}

@media (max-width: 1023px) {
    .app-sidebar {
        /* Back to position:fixed here specifically - on mobile this is a
           short-lived, user-toggled overlay drawer (closed most of the
           time), not something permanently mounted, so it needs to be
           pulled out of flow entirely rather than reserving 17rem of a
           row nobody sees, and needs fixed's full-viewport top/bottom
           to slide in as an overlay instead of pushing content. */
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        height: auto;
        transform: translateX(-100%);
    }

    .app-sidebar.open {
        transform: translateX(0);
        box-shadow: 0 0 40px rgba(0, 0, 0, 0.6);
    }

    .app-sidebar-toggle {
        display: inline-flex;
    }
}

@media (min-width: 1024px) {
    .app-sidebar-backdrop {
        display: none !important;
    }
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    .grid-field,
    .glow-orb,
    .glow-orb-2,
    .glow-orb-3,
    .particle-field,
    .pulse-dot::after,
    .status-dot::before,
    .system-badge .dot,
    .server-status-light.online,
    .animate-spin-slow,
    .animate-spin-reverse-slower,
    .skeleton-bar {
        animation: none !important;
    }

    .animate-fade-in-up,
    .animate-fade-in-scale,
    .animate-slide-in-left,
    .animate-slide-in-right {
        animation-duration: 0.01ms !important;
        opacity: 1 !important;
    }

    .toast,
    .modal-overlay,
    .modal-overlay .modal-panel,
    .btn-primary,
    .btn-upgrade,
    .panel,
    .bracket-frame::before,
    .bracket-frame::after,
    .nav-link,
    .util-icon-btn,
    .avatar-btn,
    .app-sidebar,
    .app-nav-link {
        transition: none !important;
    }
}

/* ============================================================
   LIGHT THEME
   Toggled by setting data-theme="light" on <html> (see
   setTheme()/initTheme() in nav-controls.js, persisted to
   localStorage and applied before first paint to avoid a flash of
   the wrong theme).

   Selector choice matters here: `html[data-theme="light"]` (an
   element + attribute selector) is MORE specific than a bare
   `:root { ... }` block, even though many individual page templates
   redeclare their own `:root { --void: #0a0b10; ... }` with the same
   variable names in a local <style> block that loads after this
   file. A bare :root has the same specificity as another bare
   :root, so source order would decide (page-local one wins, light
   mode would silently do nothing on those pages) - the attribute
   selector wins on specificity instead, regardless of load order,
   so this correctly overrides every page's local dark :root block
   without having to touch each of those files individually.

   Palette is deliberately the same one already proven out for the
   light-themed transactional emails (see the _CYAN/_ROSE/_AMBER/
   _EMERALD/_TEXT_* constants in email_service.py) - cyan, rose and
   amber in particular needed deepening from their dark-theme values
   to stay legible on a white background, and that contrast work is
   reused here rather than redone from scratch.

   Scope: this covers the shared design system (variables + every
   component in this file) plus the app shell (sidebar/topbar/toasts/
   modals in base.html), which is everything under {% extends
   "base.html" %} - the dashboard, Support Center + chat, Vault, API
   Docs, Owner Panel, Survey/Quiz Builder, Analytics, Account,
   Settings, Templates, Giveaway Builder. Standalone pages that don't
   extend base.html (staff kanban, status page, public leaderboard,
   error pages, marketing/legal pages, etc.) still render dark-only
   for now - each would need the toggle script and this stylesheet
   wired in individually, which is a separate follow-up.
   ============================================================ */
html[data-theme="light"] {
    --void: #eef0f6;
    --panel: #ffffff;
    --panel-raised: #f4f5f9;
    --line: #e3e5ef;
    --indigo: #5750e8;
    --cyan: #1fb8c9;
    --rose: #e5477a;
    --emerald: #1f9d6f;
    --amber: #c98a1f;
    --text-hi: #161822;
    --text-mid: #565a6e;
    --text-low: #7b7f92;
}

html[data-theme="light"] body {
    background: var(--void);
}

/* Scanline/CRT overlay and the ambient neon grid+orbs were built to
   glow on top of a near-black page - on white they just read as a
   faint smudge or, in the scanline's case, visible grey banding, so
   both are switched off rather than reskinned. */
html[data-theme="light"] body::after {
    opacity: 0;
}

html[data-theme="light"] .grid-field,
html[data-theme="light"] .glow-orb,
html[data-theme="light"] .glow-orb-2,
html[data-theme="light"] .glow-orb-3,
html[data-theme="light"] .particle-field {
    opacity: 0;
}

html[data-theme="light"] .panel {
    background: linear-gradient(135deg, #ffffff 0%, #fbfbfd 100%);
    border-color: var(--line);
    box-shadow: 0 1px 3px rgba(20, 21, 30, 0.06), inset 0 1px 0 rgba(255, 255, 255, 0.6);
}

html[data-theme="light"] .input-style {
    background: #ffffff;
    border-color: var(--line);
    color: var(--text-hi);
}

html[data-theme="light"] .input-style:focus {
    background: #ffffff;
}

html[data-theme="light"] .btn-glass {
    background: rgba(22, 24, 34, 0.04);
    color: var(--text-hi);
    border-color: rgba(22, 24, 34, 0.14);
}

html[data-theme="light"] .btn-glass:hover {
    background: rgba(22, 24, 34, 0.08);
}

html[data-theme="light"] .btn-secondary {
    background: var(--panel-raised);
    border-color: var(--line);
    color: var(--text-mid);
}

html[data-theme="light"] .btn-secondary:hover {
    color: var(--text-hi);
}

html[data-theme="light"] .status-indicator {
    background: rgba(255, 255, 255, 0.8);
}

html[data-theme="light"] .welcome-card {
    background: linear-gradient(135deg, #ffffff 0%, #f7f8fb 50%, #f0f1f7 100%);
    border-color: var(--line);
    box-shadow: 0 4px 20px rgba(20, 21, 30, 0.06);
}

html[data-theme="light"] .system-badge {
    color: var(--cyan);
    background: rgba(31, 184, 201, 0.12);
    border-color: rgba(31, 184, 201, 0.3);
}

html[data-theme="light"] .system-badge .dot {
    background: var(--cyan);
    box-shadow: 0 0 8px var(--cyan);
}

html[data-theme="light"] .metric-card {
    background: var(--panel-raised);
    border-color: var(--line);
}

html[data-theme="light"] .telemetry-feed {
    background: var(--panel-raised);
    border-color: var(--line);
}

html[data-theme="light"] .log-entry {
    color: var(--text-mid);
}

html[data-theme="light"] .log-timestamp {
    color: var(--indigo);
}

html[data-theme="light"] .server-card.active {
    background: var(--panel-raised);
}

html[data-theme="light"] .server-card.inactive {
    background: #f1f2f6;
}

html[data-theme="light"] .server-icon {
    background: #eceef4;
    box-shadow: inset 0 2px 4px rgba(20, 21, 30, 0.06);
}

html[data-theme="light"] .server-stats {
    background: rgba(20, 21, 30, 0.03);
}

html[data-theme="light"] .progress-bar {
    background: rgba(20, 21, 30, 0.08);
}

html[data-theme="light"] .server-offline-state {
    background: rgba(20, 21, 30, 0.03);
    border-color: var(--line);
}

html[data-theme="light"] ::-webkit-scrollbar-track {
    background: var(--void);
}

html[data-theme="light"] ::-webkit-scrollbar-thumb {
    background: #d5d8e3;
    border-color: var(--line);
}

html[data-theme="light"] .custom-scrollbar::-webkit-scrollbar-track {
    background: rgba(20, 21, 30, 0.04);
}

html[data-theme="light"] .toast {
    background: linear-gradient(135deg, #ffffff 0%, #fbfbfd 100%);
    border-color: var(--line);
    box-shadow: 0 8px 30px rgba(20, 21, 30, 0.12);
}

html[data-theme="light"] .nav-link:hover {
    background: rgba(20, 21, 30, 0.04);
    border-color: var(--line);
}

html[data-theme="light"] .util-pill,
html[data-theme="light"] .util-icon-btn,
html[data-theme="light"] .avatar-btn {
    background: rgba(255, 255, 255, 0.75);
    border-color: var(--line);
}

html[data-theme="light"] .app-sidebar {
    background: linear-gradient(180deg, #ffffff 0%, #f7f8fb 100%);
    border-right-color: var(--line);
}

html[data-theme="light"] .app-topbar {
    background: rgba(255, 255, 255, 0.85);
    border-bottom-color: var(--line);
}

html[data-theme="light"] .app-sidebar-toggle {
    background: rgba(20, 21, 30, 0.04);
    border-color: var(--line);
}

/* Notification bell + account menu dropdowns (partials/nav_controls.html)
   are hand-built with literal Tailwind arbitrary hex classes
   (bg-[#101219]/95, text-[#9ba0b8], hover:bg-[#161925], etc.) rather
   than the .panel/var() pattern the rest of the shell uses, so the
   variable swap above doesn't reach them - these need direct
   overrides. The ID selector gives this enough specificity to beat
   those single-class Tailwind utilities without !important. */
html[data-theme="light"] #notification-dropdown,
html[data-theme="light"] #menu-dropdown {
    background-color: rgba(255, 255, 255, 0.97);
    border-color: var(--line);
}

html[data-theme="light"] #notification-dropdown > div:first-child {
    background-color: var(--panel-raised);
    border-color: var(--line);
}

html[data-theme="light"] #notification-dropdown,
html[data-theme="light"] #menu-dropdown a,
html[data-theme="light"] #notification-list {
    color: var(--text-mid);
}

html[data-theme="light"] #notification-dropdown a:hover,
html[data-theme="light"] #menu-dropdown a:hover {
    color: var(--text-hi);
}

html[data-theme="light"] #menu-dropdown a[href="/account"]:hover,
html[data-theme="light"] #menu-dropdown a[href="/logout"]:hover,
html[data-theme="light"] #menu-dropdown a[href="/about"]:hover {
    background-color: var(--panel-raised);
}

html[data-theme="light"] #notification-dropdown .border-b,
html[data-theme="light"] #menu-dropdown .border-t {
    border-color: var(--line) !important;
}

/* Theme toggle switch itself - lives in the topbar utility cluster
   (partials/nav_controls.html), styled like the other .util-icon-btn
   pills but with a sliding sun/moon indicator instead of an icon. */
.theme-toggle-btn {
    position: relative;
}

.theme-toggle-btn .theme-icon {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 1.125rem;
    height: 1.125rem;
    transition: opacity 0.2s ease, transform 0.3s ease;
}

.theme-toggle-btn .theme-icon-sun {
    opacity: 0;
    transform: rotate(-90deg) scale(0.5);
}

.theme-toggle-btn .theme-icon-moon {
    opacity: 1;
    transform: rotate(0) scale(1);
}

html[data-theme="light"] .theme-toggle-btn .theme-icon-sun {
    opacity: 1;
    transform: rotate(0) scale(1);
}

html[data-theme="light"] .theme-toggle-btn .theme-icon-moon {
    opacity: 0;
    transform: rotate(90deg) scale(0.5);
}

/* ==========================================================================
   Builder floating action bar (Survey/Quiz/Giveaway builders)
   -------------------------------------------------------------------------
   The real Save/Deploy buttons live in each builder's own in-page header,
   which scrolls away with the rest of the page - after adding a dozen
   questions/tasks a user has to scroll all the way back to the top just to
   save. This bar duplicates those same buttons (same onclick handlers, so
   there's exactly one source of truth for what they do) pinned to the
   bottom of the viewport, so saving/deploying never requires scrolling.
   Hidden until the page has scrolled past its own header once, so it
   doesn't just look like a second, redundant button bar on page load.
   ========================================================================== */
.builder-float-actions {
    position: fixed;
    left: 50%;
    bottom: 20px;
    transform: translate(-50%, 12px);
    z-index: 400;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 16px;
    box-shadow: 0 16px 40px -10px rgba(0,0,0,0.55);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    backdrop-filter: blur(14px) saturate(140%);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.2s ease;
}
.builder-float-actions.bfa-visible {
    opacity: 1;
    pointer-events: auto;
    transform: translate(-50%, 0);
}
.builder-float-actions .bfa-label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-low);
    padding: 0 4px;
    white-space: nowrap;
}
@media (max-width: 640px) {
    .builder-float-actions {
        left: 12px;
        right: 12px;
        bottom: 12px;
        transform: translateY(12px);
        justify-content: stretch;
    }
    .builder-float-actions.bfa-visible { transform: translateY(0); }
    .builder-float-actions .bfa-label { display: none; }
    .builder-float-actions button { flex: 1; }

    /* site-tour.js's "?" help launcher (.st-help-btn) is a separate fixed
       bottom-right circle that knows nothing about this bar - on desktop
       they don't collide, but on mobile this bar stretches full-width and
       sits right under it, so the help bubble was overlapping the Deploy
       button. Push it up above the bar instead. */
    .st-help-btn {
        bottom: 76px !important;
    }
}

/* Small "?" hint next to a tab button (Survey Builder's Content/
   Branding/Settings, Quiz Builder's Questions/Results/Deployment/
   Preview) - shows a plain-language description of that tab's fields
   on click. Each page defines its own text map + toggle function
   (toggleTabHelp/qbToggleTabHelp) but shares this same visual style. */
.tab-help-dot {
    position: absolute;
    top: 3px;
    right: 3px;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: var(--panel-raised);
    border: 1px solid var(--line);
    color: var(--text-low);
    font-size: 9px;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.15s ease;
}
.tab-help-dot:hover { color: #fff; border-color: var(--indigo); }
.tab-help-popover {
    max-width: 300px;
    background: var(--panel);
    border: 1px solid var(--indigo);
    border-radius: 12px;
    padding: 14px 16px;
    font-size: 12px;
    line-height: 1.6;
    color: var(--text-mid);
    box-shadow: 0 16px 34px -10px rgba(0,0,0,0.55);
}

/* ==========================================================================
   Guild workspace nav bar - see partials/guild_workspace_nav.html.
   One horizontal bar, not a second sidebar: identity chip on the left,
   grouped links (Engage/Moderation/Configure) on the right, deliberately
   quieter than the main sidebar/topbar so it doesn't compete with them -
   flat background instead of a heavy panel, small uppercase group labels
   instead of icons, no active box-shadow glow.
   ========================================================================== */
.gwn-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem 1.5rem;
    padding: 0.875rem 1.125rem;
    border-radius: 14px;
    background: var(--panel);
    border: 1px solid var(--line);
}
.gwn-identity {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding-right: 1.125rem;
    margin-right: 0.25rem;
    border-right: 1px solid var(--line);
    shrink: 0;
}
.gwn-icon {
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 0.7rem;
    object-fit: cover;
    flex-shrink: 0;
    border: 1px solid var(--line);
    box-shadow: 0 2px 8px -2px rgba(0,0,0,0.4);
}
.gwn-icon-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(109,106,246,0.15);
    color: var(--indigo);
    font-family: 'Chakra Petch', sans-serif;
    font-weight: 700;
    font-size: 1rem;
}
.gwn-identity-text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}
.gwn-name {
    font-family: 'Chakra Petch', sans-serif;
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--text-hi);
    white-space: nowrap;
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.2;
}
.gwn-switch {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    letter-spacing: 0.03em;
    color: var(--text-low);
    white-space: nowrap;
    transition: color 0.15s ease;
}
.gwn-switch:hover { color: var(--indigo); }

.gwn-groups {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem 1.25rem;
    flex: 1;
}
.gwn-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.375rem;
}
.gwn-group-label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 9px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-low);
    background: var(--panel-raised);
    border-radius: 5px;
    padding: 0.2rem 0.45rem;
    margin-right: 0.25rem;
}
.gwn-divider {
    width: 1px;
    height: 1.5rem;
    background: var(--line);
    flex-shrink: 0;
}
.gwn-link {
    position: relative;
    font-family: 'Inter', sans-serif;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--text-mid);
    padding: 0.4rem 0.75rem;
    border-radius: 8px;
    white-space: nowrap;
    transition: color 0.15s ease, background 0.15s ease;
}
.gwn-link:hover { color: var(--text-hi); background: var(--panel-raised); }
.gwn-link.active {
    color: var(--indigo);
    background: rgba(109,106,246,0.14);
    font-weight: 600;
    box-shadow: inset 0 0 0 1px rgba(109,106,246,0.25);
}
.gwn-soon {
    font-family: 'JetBrains Mono', monospace;
    font-size: 8px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-low);
    background: var(--panel-raised);
    border: 1px solid var(--line);
    border-radius: 5px;
    padding: 1px 4px;
    margin-left: 0.375rem;
    vertical-align: middle;
}

@media (max-width: 767px) {
    .gwn-bar { padding: 0.75rem 0.875rem; }
    .gwn-identity { border-right: none; padding-right: 0; margin-right: 0; width: 100%; padding-bottom: 0.75rem; border-bottom: 1px solid var(--line); margin-bottom: 0.375rem; }
    .gwn-groups { gap: 0.625rem 0.75rem; }
    .gwn-divider { display: none; }
    .gwn-group { width: 100%; }
    .gwn-name { max-width: none; }
}

html[data-theme="light"] .gwn-bar { background: #ffffff; border-color: var(--line); }
html[data-theme="light"] .gwn-link.active { background: rgba(87,80,232,0.1); }
html[data-theme="light"] .gwn-icon-fallback { background: rgba(87,80,232,0.12); }
html[data-theme="light"] .gwn-group-label { background: rgba(0,0,0,0.04); }

/* --- Info Tooltip: hover (desktop) / tap (mobile+touch) popover,
   see nav-controls.js for the tap-toggle handler. Markup:
   <span class="info-tip" tabindex="0">ⓘ<span class="info-tip-panel">
     <span class="info-tip-title">Title</span>
     <span class="info-tip-desc">Explanation text.</span>
   </span></span> --- */
.info-tip {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border-radius: 999px;
    background: var(--panel-raised);
    border: 1px solid var(--line);
    color: var(--text-low);
    font-size: 11px;
    font-family: 'JetBrains Mono', monospace;
    cursor: help;
    vertical-align: middle;
    margin-left: 6px;
}
.info-tip-panel {
    position: absolute;
    z-index: 60;
    bottom: calc(100% + 10px);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    width: 260px;
    max-width: min(80vw, 300px);
    background: var(--panel-raised);
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 12px 14px;
    box-shadow: 0 12px 30px -12px rgba(0,0,0,0.5);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease;
    text-align: left;
    white-space: normal;
}
.info-tip-panel::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 6px solid transparent;
    border-top-color: var(--panel-raised);
}
.info-tip:hover .info-tip-panel,
.info-tip:focus .info-tip-panel,
.info-tip:focus-within .info-tip-panel,
.info-tip.open .info-tip-panel {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
    pointer-events: auto;
}
.info-tip-title {
    font-family: 'Chakra Petch', sans-serif;
    font-weight: 700;
    font-size: 12px;
    color: var(--text-hi);
    margin-bottom: 4px;
    display: flex;
    align-items: center;
    gap: 6px;
}
.info-tip-desc {
    font-size: 11.5px;
    line-height: 1.5;
    color: var(--text-mid);
    display: block;
}
@media (max-width: 767px) {
    /* Near the left edge of a narrow screen, a centered popover clips off
       the viewport - shift the anchor point instead of centering. */
    .info-tip-panel { width: 220px; left: 0; transform: translateX(0) translateY(4px); }
    .info-tip:hover .info-tip-panel, .info-tip:focus .info-tip-panel,
    .info-tip:focus-within .info-tip-panel, .info-tip.open .info-tip-panel {
        transform: translateX(0) translateY(0);
    }
    .info-tip-panel::after { left: 8px; transform: translateX(0); }
}
