/* =============================================================================
   Zeetius Tournaments — Vibrant UI Layer (bold modern enhancement)
   Layers ON TOP of design-system.css. Adds: full-bleed ambient gradients,
   glassmorphic panels, animated gradient borders, motion (scroll-reveal,
   hover, button shine), modernized form fields, and a unified inline
   "mandatory warning" pattern across every validation convention in the app.
   Visual-only + progressive: degrades cleanly if JS/CSS features are absent.
   ========================================================================== */

:root {
    --ds-gradient-mesh-1: #6366F1;
    --ds-gradient-mesh-2: #8B5CF6;
    --ds-gradient-mesh-3: #06B6D4;
    --ds-gradient-mesh-4: #EC4899;
    --ds-glass-bg: rgba(255, 255, 255, .62);
    --ds-glass-border: rgba(255, 255, 255, .55);
    --ds-glass-blur: 16px;
    --ds-warn: #DC2626;
    --ds-warn-bg: #FEF2F2;
    --ds-warn-border: #FCA5A5;
}
/* All former --ds-ease-spring (bounce/elastic) usages below now reference
   design-system.css's existing --ds-ease-out token (cubic-bezier(.22,1,.36,1))
   instead of defining a second, duplicate ease-out token here. */

/* -----------------------------------------------------------------------------
   1. Ambient full-bleed gradient backdrop
   A fixed, low-opacity multi-stop mesh behind everything. Keeps content
   readable (sits under the surface) while giving the whole app a vivid feel.
   -------------------------------------------------------------------------- */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(40vw 40vw at 8% -6%, rgba(99, 102, 241, .16), transparent 60%),
        radial-gradient(38vw 38vw at 102% 4%, rgba(6, 182, 212, .14), transparent 60%),
        radial-gradient(46vw 46vw at 88% 108%, rgba(139, 92, 246, .14), transparent 62%),
        radial-gradient(34vw 34vw at -6% 96%, rgba(236, 72, 153, .10), transparent 60%);
    animation: ds-mesh-drift 22s ease-in-out infinite alternate;
}
/* Same alpha values read as a soft wash on a light surface but a washed-out
   haze on the dark navy surface (more contrast between near-black and any
   tinted overlay, not less) — this was flagged as the cause of low-contrast
   text across dark-mode pages. Cut to roughly a third for dark mode instead
   of removing it outright, so the ambient color still comes through subtly. */
.dark body::before {
    background:
        radial-gradient(40vw 40vw at 8% -6%, rgba(99, 102, 241, .05), transparent 60%),
        radial-gradient(38vw 38vw at 102% 4%, rgba(6, 182, 212, .045), transparent 60%),
        radial-gradient(46vw 46vw at 88% 108%, rgba(139, 92, 246, .045), transparent 62%),
        radial-gradient(34vw 34vw at -6% 96%, rgba(236, 72, 153, .03), transparent 60%);
}

@keyframes ds-mesh-drift {
    0%   { transform: translate3d(0, 0, 0) scale(1); }
    100% { transform: translate3d(0, -1.5%, 0) scale(1.06); }
}

@media (prefers-reduced-motion: reduce) {
    body::before { animation: none; }
}

/* -----------------------------------------------------------------------------
   2. Glassmorphism utilities + applied panels
   -------------------------------------------------------------------------- */
.ds-glass {
    background: var(--ds-glass-bg) !important;
    backdrop-filter: blur(var(--ds-glass-blur)) saturate(160%);
    -webkit-backdrop-filter: blur(var(--ds-glass-blur)) saturate(160%);
    border: 1px solid var(--ds-glass-border) !important;
    box-shadow: 0 8px 32px rgba(15, 23, 42, .12) !important;
}

.glass-card {
    background: linear-gradient(160deg, rgba(255, 255, 255, .82), rgba(255, 255, 255, .55)) !important;
    backdrop-filter: blur(var(--ds-glass-blur)) saturate(150%);
    -webkit-backdrop-filter: blur(var(--ds-glass-blur)) saturate(150%);
    border: 1px solid rgba(255, 255, 255, .6) !important;
}

/* Dropdowns & modals get a subtle frosted treatment (kept high-contrast). */
.dropdown-menu {
    background: rgba(255, 255, 255, .9);
    backdrop-filter: blur(14px) saturate(160%);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
}

/* -----------------------------------------------------------------------------
   3. Animated gradient borders (opt-in via .ds-animated-border)
   Uses a gradient layer behind a same-radius inset surface.
   -------------------------------------------------------------------------- */
.ds-animated-border {
    position: relative;
    border: none !important;
    background-clip: padding-box;
    isolation: isolate;
}
.ds-animated-border::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    padding: 1.5px;
    background: linear-gradient(120deg, #6366F1, #8B5CF6, #06B6D4, #EC4899, #6366F1);
    background-size: 300% 300%;
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
    animation: ds-border-flow 6s linear infinite;
}
@keyframes ds-border-flow {
    0%   { background-position: 0% 50%; }
    100% { background-position: 300% 50%; }
}
@media (prefers-reduced-motion: reduce) {
    .ds-animated-border::before { animation: none; }
}

/* Make the gradient top-accent card (design-system) animate its accent. */
.card-accent::before {
    background-size: 200% 100%;
    animation: ds-accent-slide 5s linear infinite;
}
@keyframes ds-accent-slide {
    0%   { background-position: 0% 0; }
    100% { background-position: 200% 0; }
}
@media (prefers-reduced-motion: reduce) {
    .card-accent::before { animation: none; }
}

/* -----------------------------------------------------------------------------
   4. Motion — hero shimmer, button shine, hover lift
   -------------------------------------------------------------------------- */
.ds-hero {
    background-size: 160% 160%;
    animation: ds-hero-pan 16s ease infinite;
}
@keyframes ds-hero-pan {
    0%   { background-position: 0% 50%; }
    50%  { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
}
@media (prefers-reduced-motion: reduce) {
    .ds-hero { animation: none; }
}

/* Gradient buttons get a sweeping shine on hover. */
.btn-primary, .btn-success, .bg-gradient-primary, .bg-gradient-accent {
    position: relative;
    overflow: hidden;
}
.btn-primary::after, .btn-success::after {
    content: "";
    position: absolute;
    top: 0;
    left: -120%;
    width: 60%;
    height: 100%;
    background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .42), transparent);
    transform: skewX(-18deg);
    transition: left .6s ease;
    pointer-events: none;
}
.btn-primary:hover::after, .btn-success:hover::after { left: 140%; }

/* Cards & stat tiles lift a touch more for the bolder feel. */
.card:hover { transform: translateY(-2px); }
.ds-stat:hover { transform: translateY(-4px); }

/* -----------------------------------------------------------------------------
   5. Scroll-reveal (flash-free; only active when <html class="js"> is set)
   Elements opt in with [data-reveal]; JS adds .ds-in when they enter view.
   -------------------------------------------------------------------------- */
.js [data-reveal] {
    opacity: 0;
    transform: translateY(18px);
    will-change: opacity, transform;
}
.js [data-reveal].ds-in {
    opacity: 1;
    transform: none;
    transition: opacity .55s ease, transform .55s var(--ds-ease-out);
}
@media (prefers-reduced-motion: reduce) {
    .js [data-reveal] { opacity: 1; transform: none; }
}

/* -----------------------------------------------------------------------------
   6. Modernized form fields
   Covers BOTH Bootstrap (.form-control/.form-select) and the custom
   registration field classes (.form-input/.field-label/.required-indicator).
   -------------------------------------------------------------------------- */
.form-control, .form-select, .form-input {
    transition: border-color .18s ease, box-shadow .18s ease, background-color .18s ease;
    background-color: #fff;
}
.form-control:hover:not(:focus):not(:disabled),
.form-select:hover:not(:focus):not(:disabled),
.form-input:hover:not(:focus):not(:disabled) {
    border-color: #C7CBDA;
}
.form-control:focus, .form-select:focus, .form-input:focus {
    border-color: var(--ds-primary);
    box-shadow: 0 0 0 4px rgba(79, 70, 229, .14);
    outline: none;
}

/* Custom registration field classes elevated to the global system. */
.form-input {
    width: 100%;
    min-height: 44px;
    border-radius: 12px;
    border: 1px solid var(--ds-border);
    padding: 10px 14px;
    font-size: 14px;
    color: var(--ds-text);
}
.field-label {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ds-text);
    margin-bottom: 6px;
}
.field-icon { color: var(--ds-primary); opacity: .85; }

/* Required markers — consistent across both conventions. */
.required-indicator, .required-star {
    color: var(--ds-warn);
    font-weight: 700;
    margin-left: 3px;
}

/* Floating-ish label lift for filled/focused inputs in .ds-float groups. */
.ds-float { position: relative; }
.ds-float > label {
    position: absolute;
    top: 12px;
    left: 14px;
    font-size: 14px;
    color: #94A3B8;
    pointer-events: none;
    transition: all .16s var(--ds-ease-out);
    background: #fff;
    padding: 0 4px;
}
.ds-float > .form-control:focus + label,
.ds-float > .form-control:not(:placeholder-shown) + label {
    top: -8px;
    font-size: 11px;
    font-weight: 700;
    color: var(--ds-primary);
}

/* -----------------------------------------------------------------------------
   7. Unified inline MANDATORY WARNING pattern
   Targets every error convention used in the codebase:
     - jQuery unobtrusive: span.field-validation-error / .input-validation-error
     - Custom registration:  .field-error (populated)
     - Bootstrap:            .invalid-feedback (shown via .is-invalid)
     - JS-injected:          .ds-field-warning (from ui-enhance.js)
   Renders a compact, animated, icon-led message with a soft red wash.
   -------------------------------------------------------------------------- */
.field-validation-error:not(:empty),
.field-error:not(:empty),
.ds-field-warning,
.invalid-feedback.d-block:not(:empty),
.is-invalid ~ .invalid-feedback:not(:empty) {
    display: flex !important;
    align-items: flex-start;
    gap: 6px;
    margin-top: 6px;
    padding: 7px 11px;
    font-size: 12.5px;
    font-weight: 600;
    line-height: 1.35;
    color: #991B1B;
    background: var(--ds-warn-bg);
    border: 1px solid var(--ds-warn-border);
    border-radius: 10px;
    animation: ds-warn-in .26s var(--ds-ease-out) both;
}

/* Leading warning icon — CSS-drawn "!" badge (no icon-font version coupling). */
.field-validation-error:not(:empty)::before,
.field-error:not(:empty)::before,
.ds-field-warning::before,
.invalid-feedback.d-block:not(:empty)::before,
.is-invalid ~ .invalid-feedback:not(:empty)::before {
    content: "!";
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin-top: .5px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 800;
    line-height: 1;
    color: #fff;
    background: var(--ds-warn);
    border-radius: 50%;
}

@keyframes ds-warn-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
}

/* Invalid field styling — red border, soft glow, and a one-shot shake. */
.is-invalid,
.input-validation-error,
.form-control.ds-invalid,
.form-select.ds-invalid,
.form-input.ds-invalid {
    border-color: var(--ds-warn) !important;
    box-shadow: 0 0 0 4px rgba(220, 38, 38, .12) !important;
    background-color: #FFFBFB;
}
.ds-shake { animation: ds-shake .4s ease; }
@keyframes ds-shake {
    0%, 100% { transform: translateX(0); }
    20% { transform: translateX(-6px); }
    40% { transform: translateX(5px); }
    60% { transform: translateX(-3px); }
    80% { transform: translateX(2px); }
}
@media (prefers-reduced-motion: reduce) {
    .ds-shake { animation: none; }
}

/* A page-level mandatory banner the JS shows when a submit is blocked. */
.ds-form-warning-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 16px;
    padding: 12px 16px;
    font-size: 13.5px;
    font-weight: 600;
    color: #991B1B;
    background: linear-gradient(135deg, #FEF2F2, #FFE4E6);
    border: 1px solid var(--ds-warn-border);
    border-radius: 14px;
    box-shadow: 0 6px 18px rgba(220, 38, 38, .12);
    animation: ds-warn-in .3s var(--ds-ease-out) both;
}
.ds-form-warning-banner i { font-size: 18px; color: var(--ds-warn); }

/* -----------------------------------------------------------------------------
   8. Navbar — deepen the glass + keep the vibrant accent line crisp
   -------------------------------------------------------------------------- */
.navbar-modern {
    backdrop-filter: saturate(140%) blur(10px);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
}

/* -----------------------------------------------------------------------------
   9. Broad page-hero vivification (applies to every page using these classes)
   -------------------------------------------------------------------------- */
.page-hero {
    background:
        radial-gradient(900px 320px at 8% -20%, rgba(139, 92, 246, .55), transparent 60%),
        radial-gradient(800px 300px at 105% 0%, rgba(6, 182, 212, .45), transparent 60%),
        linear-gradient(120deg, #4F46E5 0%, #6D28D9 55%, #0EA5E9 120%) !important;
    background-size: 160% 160% !important;
    animation: ds-hero-pan 16s ease infinite;
}
.page-hero::before { background: rgba(8, 12, 30, .18) !important; }
@media (prefers-reduced-motion: reduce) {
    .page-hero { animation: none; }
}

/* Section divider with a gradient flourish (opt-in). */
.ds-divider {
    height: 2px;
    border: 0;
    background: linear-gradient(90deg, transparent, var(--ds-accent), var(--ds-accent-2), transparent);
    opacity: .5;
    margin: 24px 0;
}

/* =============================================================================
   FUTURISTIC LAYER — next-gen polish, gamification & feedback components
   (Phase 1 + 2). Additive, opt-in via classes, namespaced ds-/zt-,
   reduced-motion aware. No markup or build changes required.
   ========================================================================== */

:root {
    --ds-glow-primary: 0 0 0 1px rgba(99,102,241,.25), 0 8px 30px rgba(99,102,241,.35);
    --ds-glow-accent: 0 0 0 1px rgba(139,92,246,.25), 0 8px 30px rgba(139,92,246,.38);
    --ds-glow-cyan: 0 0 0 1px rgba(6,182,212,.25), 0 8px 30px rgba(6,182,212,.35);
    /* Soft neumorphism (light surface) */
    --ds-neu-bg: #eef1f8;
    --ds-neu-light: rgba(255,255,255,.9);
    --ds-neu-dark: rgba(174,179,200,.55);
}

/* ---------- Glow utilities (opt-in) ---------- */
.ds-glow        { box-shadow: var(--ds-glow-primary) !important; }
.ds-glow-accent { box-shadow: var(--ds-glow-accent) !important; }
.ds-glow-cyan   { box-shadow: var(--ds-glow-cyan) !important; }
.ds-glow-hover  { transition: box-shadow .25s ease, transform .25s var(--ds-ease-out); }
.ds-glow-hover:hover { box-shadow: var(--ds-glow-accent) !important; transform: translateY(-2px); }

/* Pulsing ambient glow for "live"/featured elements. */
.ds-pulse { animation: ds-pulse 2.4s ease-in-out infinite; }
@keyframes ds-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(99,102,241,.45); }
    50%      { box-shadow: 0 0 0 10px rgba(99,102,241,0); }
}
@media (prefers-reduced-motion: reduce) { .ds-pulse { animation: none; } }

/* ---------- Soft neumorphism (opt-in) ---------- */
.ds-neu {
    background: var(--ds-neu-bg);
    border: none !important;
    border-radius: var(--ds-radius-lg);
    box-shadow: 8px 8px 20px var(--ds-neu-dark), -8px -8px 20px var(--ds-neu-light);
}
.ds-neu-inset {
    background: var(--ds-neu-bg);
    border: none !important;
    border-radius: var(--ds-radius);
    box-shadow: inset 5px 5px 12px var(--ds-neu-dark), inset -5px -5px 12px var(--ds-neu-light);
}

/* ---------- Button: ripple + stronger lift + glow ---------- */
.btn-primary, .btn-success, .btn-danger, .bg-gradient-primary { will-change: transform; }
.btn-primary:hover, .btn-success:hover { transform: translateY(-2px); box-shadow: 0 12px 28px rgba(79,70,229,.45); }
.btn-glow { box-shadow: var(--ds-glow-primary); }
.btn-glow:hover { box-shadow: var(--ds-glow-accent); }
/* JS-injected ripple element */
.ds-ripple-host { position: relative; overflow: hidden; }
.ds-ripple {
    position: absolute; border-radius: 50%; transform: scale(0);
    background: rgba(255,255,255,.5); pointer-events: none;
    animation: ds-ripple .6s ease-out;
}
@keyframes ds-ripple { to { transform: scale(2.6); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .ds-ripple { display: none; } }

/* ---------- Accessibility: crisp focus ring on every interactive control ---------- */
a:focus-visible, button:focus-visible, .btn:focus-visible,
.form-control:focus-visible, .form-select:focus-visible,
[tabindex]:focus-visible, .dropdown-item:focus-visible, .nav-link:focus-visible {
    outline: 2px solid transparent;
    box-shadow: 0 0 0 3px rgba(99,102,241,.45) !important;
    border-radius: 8px;
}

/* ---------- Status pills with animated dot (esports-style) ---------- */
.ds-status {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: 12px; font-weight: 700; line-height: 1;
    padding: 6px 12px 6px 10px; border-radius: var(--ds-radius-pill);
    border: 1px solid transparent;
}
.ds-status::before {
    content: ""; width: 8px; height: 8px; border-radius: 50%;
    background: currentColor; box-shadow: 0 0 0 0 currentColor;
}
.ds-status.is-live::before { animation: ds-dot-pulse 1.6s ease-out infinite; }
@keyframes ds-dot-pulse {
    0%   { box-shadow: 0 0 0 0 currentColor; opacity: 1; }
    70%  { box-shadow: 0 0 0 6px transparent; opacity: .85; }
    100% { box-shadow: 0 0 0 0 transparent; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .ds-status.is-live::before { animation: none; } }
.ds-status-active    { color: #15803D; background: #DCFCE7; }
.ds-status-pending   { color: #B45309; background: #FEF3C7; }
.ds-status-processing{ color: #1D4ED8; background: #DBEAFE; }
.ds-status-rejected  { color: #B91C1C; background: #FEE2E2; }
.ds-status-archived  { color: #475569; background: #E2E8F0; }

/* ---------- Interactive card: scale 1.02 on hover (opt-in) ---------- */
.card-interactive { cursor: pointer; transition: transform .25s var(--ds-ease-out), box-shadow .25s ease, border-color .25s ease; }
.card-interactive:hover { transform: scale(1.02) translateY(-2px); box-shadow: var(--ds-shadow-lg); border-color: rgba(139,92,246,.45); }

/* ---------- SweetAlert2 theming (modals + toasts) ---------- */
.swal2-popup {
    border-radius: var(--ds-radius-lg) !important;
    box-shadow: var(--ds-shadow-lg) !important;
    background: linear-gradient(160deg, rgba(255,255,255,.96), rgba(248,250,252,.96)) !important;
    backdrop-filter: blur(8px);
}
/* Fixed dark color, not the theme-flipping --ds-text: .swal2-popup/.swal2-toast below
   always render on a light/white glass background regardless of site theme, so in dark
   mode --ds-text (near-white, #eef0fb) rendered near-invisible title text on that same
   near-white background — every toast and confirmation dialog looked blank. */
.swal2-title { font-weight: 800 !important; letter-spacing: -.02em; color: #0f172a !important; }
.swal2-styled.swal2-confirm {
    background-image: var(--ds-gradient) !important; border: none !important;
    border-radius: 12px !important; box-shadow: var(--ds-shadow-primary) !important; font-weight: 600 !important;
}
.swal2-styled.swal2-cancel { border-radius: 12px !important; font-weight: 600 !important; }
.swal2-toast {
    border-radius: 14px !important;
    background: rgba(255,255,255,.92) !important;
    backdrop-filter: blur(14px) saturate(160%);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
    box-shadow: 0 10px 30px rgba(15,23,42,.18) !important;
    border: 1px solid rgba(255,255,255,.6) !important;
}
/* Status is already conveyed by SweetAlert2's own icon; a full-border tint
   reinforces it without the side-stripe-accent anti-pattern. */
.swal2-toast.swal2-icon-success { border-color: var(--ds-success) !important; }
.swal2-toast.swal2-icon-error   { border-color: var(--ds-danger) !important; }
.swal2-toast.swal2-icon-warning { border-color: var(--ds-warning) !important; }
.swal2-toast.swal2-icon-info    { border-color: var(--ds-info) !important; }

/* Error modal one-shot shake (add .ds-modal-shake to .swal2-popup via JS). */
.ds-modal-shake { animation: ds-shake .45s ease; }

/* =============================================================================
   GAMIFICATION COMPONENTS
   ========================================================================== */

/* XP / progress bar */
.ds-xp { display: flex; flex-direction: column; gap: 6px; }
.ds-xp-head { display: flex; justify-content: space-between; font-size: 12px; font-weight: 700; color: var(--ds-text-secondary); }
.ds-xp-track {
    height: 12px; border-radius: 999px; background: #E6E8F2; overflow: hidden;
    box-shadow: inset 0 1px 2px rgba(15,23,42,.12);
}
.ds-xp-fill {
    height: 100%; border-radius: 999px; width: 0;
    background: linear-gradient(90deg, #6366F1, #8B5CF6, #06B6D4);
    background-size: 200% 100%;
    box-shadow: 0 0 12px rgba(139,92,246,.6);
    transition: width 1s var(--ds-ease-out);
    animation: ds-xp-flow 3s linear infinite;
}
@keyframes ds-xp-flow { to { background-position: 200% 0; } }
@media (prefers-reduced-motion: reduce) { .ds-xp-fill { animation: none; transition: none; } }

/* Level ring (circular progress; set --p: 0..100) */
.ds-level-ring {
    --p: 0; --size: 64px;
    width: var(--size); height: var(--size); border-radius: 50%;
    display: grid; place-items: center; position: relative;
    background: conic-gradient(#8B5CF6 calc(var(--p) * 1%), #E6E8F2 0);
    box-shadow: 0 6px 18px rgba(139,92,246,.3);
}
.ds-level-ring::before { content: ""; position: absolute; inset: 6px; border-radius: 50%; background: var(--ds-surface); }
.ds-level-ring .ds-level-num { position: relative; font-weight: 800; font-size: 18px; line-height: 1; }
.ds-level-ring .ds-level-cap { position: relative; font-size: 9px; font-weight: 700; color: var(--ds-text-secondary); text-transform: uppercase; letter-spacing: .06em; }

/* Streak counter */
.ds-streak {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 14px; border-radius: var(--ds-radius-pill); font-weight: 800;
    color: #fff; background: linear-gradient(135deg, #F59E0B, #EF4444);
    box-shadow: 0 6px 18px rgba(239,68,68,.35);
}
.ds-streak i { animation: ds-flicker 1.8s ease-in-out infinite; }
@keyframes ds-flicker { 0%,100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.12); opacity: .9; } }
@media (prefers-reduced-motion: reduce) { .ds-streak i { animation: none; } }

/* Achievement / badge */
.ds-achievement {
    display: flex; align-items: center; gap: 14px;
    padding: 16px; border-radius: var(--ds-radius);
    background: linear-gradient(150deg, rgba(255,255,255,.9), rgba(243,232,255,.7));
    border: 1px solid rgba(139,92,246,.25);
    box-shadow: var(--ds-shadow-sm);
}
.dark .ds-achievement {
    background: linear-gradient(150deg, rgba(139,92,246,.14), rgba(255,255,255,.03));
    border-color: rgba(139,92,246,.3);
}
.ds-badge-medal {
    width: 52px; height: 52px; flex: 0 0 52px; border-radius: 16px;
    display: grid; place-items: center; font-size: 24px; color: #fff;
    background: var(--ds-gradient-accent); box-shadow: 0 8px 22px rgba(139,92,246,.4);
    position: relative;
}
.ds-badge-medal.locked { background: #CBD2E0; box-shadow: none; color: #fff; filter: grayscale(1); }
.dark .ds-badge-medal.locked { background: #3a4176; color: #7d84b8; }
/* Explicit color, not inherited — this card sits on a bespoke gradient (above),
   not the --ds-surface token, so it needs its own light/dark text pairing. */
.ds-achievement .ds-ach-title { font-weight: 800; font-size: 15px; color: var(--ds-text); }
.ds-achievement .ds-ach-sub { font-size: 12.5px; color: var(--ds-text-secondary); }

/* Badge unlock animation (add .ds-unlock to trigger) */
.ds-unlock { animation: ds-unlock .7s var(--ds-ease-out) both; }
@keyframes ds-unlock {
    0%   { transform: scale(.4) rotate(-12deg); opacity: 0; }
    60%  { transform: scale(1.12) rotate(4deg); opacity: 1; }
    100% { transform: scale(1) rotate(0); }
}
.ds-badge-medal.ds-unlock::after {
    content: ""; position: absolute; inset: -8px; border-radius: inherit;
    box-shadow: 0 0 0 0 rgba(139,92,246,.6); animation: ds-pulse 1.4s ease-out 2;
}
@media (prefers-reduced-motion: reduce) { .ds-unlock { animation: none; } }

/* Trophy showcase tile */
.ds-trophy {
    text-align: center; padding: 18px; border-radius: var(--ds-radius);
    background: linear-gradient(160deg, #1E293B, #0F172A); color: #fff;
    box-shadow: var(--ds-shadow-md); position: relative; overflow: hidden;
}
.ds-trophy::after {
    content: ""; position: absolute; inset: 0;
    background: radial-gradient(220px 120px at 50% -10%, rgba(245,158,11,.4), transparent 60%);
    pointer-events: none;
}
.ds-trophy .ds-trophy-ico { font-size: 34px; color: #FBBF24; filter: drop-shadow(0 4px 10px rgba(245,158,11,.5)); }

/* =============================================================================
   EMPTY STATES + SKELETON TABLE
   ========================================================================== */
.ds-empty {
    text-align: center; padding: 48px 24px; border-radius: var(--ds-radius-lg);
    background: linear-gradient(160deg, rgba(255,255,255,.7), rgba(248,250,252,.5));
    border: 1px dashed var(--ds-border);
}
.ds-empty-ico {
    width: 88px; height: 88px; margin: 0 auto 16px; border-radius: 26px;
    display: grid; place-items: center; font-size: 40px; color: #fff;
    background: var(--ds-gradient-accent); box-shadow: 0 12px 30px rgba(139,92,246,.35);
    animation: ds-float 4s ease-in-out infinite;
}
@keyframes ds-float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
@media (prefers-reduced-motion: reduce) { .ds-empty-ico { animation: none; } }
.ds-empty-title { font-size: 18px; font-weight: 800; margin-bottom: 6px; }
.ds-empty-sub { font-size: 14px; color: var(--ds-text-secondary); max-width: 420px; margin: 0 auto 18px; }

/* Skeleton table rows: add .ds-skeleton-table to a table; JS/markup fills rows */
.ds-skeleton-line { height: 12px; border-radius: 6px; }
.ds-skeleton-line, .ds-skeleton-cell > span {
    display: block;
    background: linear-gradient(90deg, #eef2f7 25%, #f6f8fb 37%, #eef2f7 63%);
    background-size: 400% 100%; animation: ds-shimmer 1.4s ease infinite; border-radius: 6px; height: 12px;
}
@media (prefers-reduced-motion: reduce) { .ds-skeleton-line, .ds-skeleton-cell > span { animation: none; } }

/* Confetti canvas overlay (created by JS) */
.ds-confetti-canvas { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 20000; }

/* Enhance EXISTING status badges/pills app-wide with an esports-style pulsing
   dot — no markup change, hot-reloads. "pending" breathes amber; live pills pulse. */
.status-badge.pending, .status-pill { position: relative; }
.status-badge.pending::before {
    content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
    background: currentColor; margin-right: 3px; vertical-align: middle;
    animation: ds-dot-pulse 1.6s ease-out infinite;
}
.status-pill::before {
    content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
    background: currentColor; margin-right: 6px; vertical-align: middle;
    animation: ds-dot-pulse 1.4s ease-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .status-badge.pending::before, .status-pill::before { animation: none; }
}

/* =============================================================================
   ACCESSIBILITY PASS — focus visibility (incl. dark surfaces), reduced motion,
   high-contrast & forced-colors support, skip link.
   ========================================================================== */

/* Skip-to-content link (revealed on focus; anchors to #main-content). */
.ds-skip-link {
    position: absolute; left: 12px; top: -64px; z-index: 30000;
    background: var(--ds-primary); color: #fff !important; padding: 10px 16px;
    border-radius: 10px; font-weight: 700; box-shadow: var(--ds-shadow-md);
    transition: top .2s ease;
}
.ds-skip-link:focus { top: 12px; outline: 2px solid #fff; }

/* Focus ring that stays visible on dark / gradient surfaces (white halo + brand ring). */
.navbar-modern a:focus-visible, .navbar-modern button:focus-visible,
.ds-hero a:focus-visible, .page-hero a:focus-visible,
.btn-primary:focus-visible, .btn-success:focus-visible, .bg-gradient-primary:focus-visible {
    box-shadow: 0 0 0 3px rgba(255,255,255,.95), 0 0 0 6px rgba(99,102,241,.65) !important;
    outline: none;
}

/* Reduced-motion safety net — neutralizes any animation/transition we didn't
   individually guard, app-wide. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
    body::before { animation: none !important; }
}

/* Higher-contrast preference — firm up borders + darken muted text to clear AA. */
@media (prefers-contrast: more) {
    :root { --ds-border: #C2C7D6; --ds-text-secondary: #3F4A5C; }
    .text-muted, .text-secondary, .form-text { color: #3F4A5C !important; }
    .card, .form-control, .form-select { border-width: 1.5px; }
}

/* Windows High Contrast / forced-colors — keep structure + focus perceivable. */
@media (forced-colors: active) {
    .btn, .card, .form-control, .form-select, .dropdown-menu, .ds-status, .ds-chip { border: 1px solid; }
    *:focus-visible { outline: 2px solid; outline-offset: 2px; }
    .ds-xp-fill, .ds-level-ring { forced-color-adjust: none; }
}

/* =============================================================================
   SCHEDULE GOLD UX — optimization-goal cards, smart presets, recommendation
   ========================================================================== */
.ds-goal-cards { display: flex; flex-wrap: wrap; gap: 10px; }
.ds-goal-card {
    flex: 1 1 130px; min-width: 120px; max-width: 200px;
    display: flex; flex-direction: column; align-items: center; gap: 4px;
    padding: 12px 10px; border-radius: var(--ds-radius);
    background: var(--ds-surface); border: 1.5px solid var(--ds-border);
    cursor: pointer; font-weight: 700; font-size: 12.5px; color: var(--ds-text);
    transition: transform .18s var(--ds-ease-out), box-shadow .2s ease, border-color .2s ease, background .2s ease;
}
.ds-goal-card .ds-goal-ico { font-size: 22px; line-height: 1; }
.ds-goal-card:hover { transform: translateY(-2px); box-shadow: var(--ds-shadow-md); border-color: rgba(99,102,241,.5); }
.ds-goal-card.active {
    color: #fff; border-color: transparent;
    background-image: var(--ds-gradient); box-shadow: var(--ds-shadow-primary);
}
.ds-goal-card:focus-visible { box-shadow: 0 0 0 3px rgba(99,102,241,.45); outline: none; }

.ds-quick {
    padding: 14px; border-radius: var(--ds-radius);
    background: linear-gradient(150deg, rgba(99,102,241,.06), rgba(6,182,212,.05));
    border: 1px solid rgba(99,102,241,.18);
}
.ds-recommend { background: rgba(255,255,255,.7); border: 1px solid rgba(139,92,246,.22); }
.ds-preset { border-radius: var(--ds-radius-pill); }

/* Animated success check (CSS-drawn; used in custom success modals) */
.ds-check { width: 64px; height: 64px; border-radius: 50%; display: grid; place-items: center; margin: 0 auto;
    background: linear-gradient(135deg,#22C55E,#16A34A); box-shadow: 0 10px 26px rgba(22,163,74,.4); }
.ds-check svg { width: 34px; height: 34px; }
.ds-check path { stroke: #fff; stroke-width: 4; fill: none; stroke-linecap: round; stroke-linejoin: round;
    stroke-dasharray: 48; stroke-dashoffset: 48; animation: ds-check-draw .5s .15s var(--ds-ease-out) forwards; }
@keyframes ds-check-draw { to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) { .ds-check path { animation: none; stroke-dashoffset: 0; } }

/* RTL overrides. */
html[dir="rtl"] .required-indicator, html[dir="rtl"] .required-star { margin-left: 0; margin-right: 3px; }
html[dir="rtl"] .status-badge.pending::before { margin-right: 0; margin-left: 3px; }
html[dir="rtl"] .status-pill::before { margin-right: 0; margin-left: 6px; }
