/* =========================================================================
   AI-MODUS  -  two lanes, one CTFd
   Injected into CTFd's theme_header by ctf.sh (see platform/theme/README.md).

   The lane control in the navbar sets html[data-ai-mode="on"|"off"]:
     - Classic (off): a calm, cool blue skin. No effects.
     - AI-modus (on): the loud one. Fire, glitches, CRT scanlines, matrix rain,
       a boot sequence and a random screen flicker, so it feels hard.
   Both share the same layout and tile shape; only the atmosphere changes.
   Classic rules use html:not([data-ai-mode="on"]) so they apply before the
   footer script runs (no flash). Animation stops under reduced motion.
   ========================================================================= */

:root {
  /* Classic */
  --cl-ground:     #0f1720;
  --cl-deep:       #0b121a;
  --cl-panel:      #16212c;
  --cl-line:       #2a3c4e;
  --cl-ink:        #e6eef5;
  --cl-soft:       #c3d1de;
  --cl-muted:      #9db0c2;
  --cl-accent:     #5ab0ff;
  --cl-accent-ink: #07213d;
  --cl-solved:     #1b3a5c;

  /* AI-modus */
  --ai-bg:     #060403;
  --ai-panel:  #120a06;
  --ai-line:   #4a2412;
  --ai-fg:     #ffe9d6;
  --ai-soft:   #f2d2b6;
  --ai-muted:  #c79a7a;
  --ai-red:    #ff2e00;
  --ai-orange: #ff7a00;
  --ai-amber:  #ffc400;
  --ai-hot:    #ff5a2a;
  --ai-neon:   #39ff14;
  --ai-cyan:   #00e5ff;
  --ai-fire:   linear-gradient(0deg, #ff2e00 0%, #ff7a00 38%, #ffc400 68%, #fff3b0 100%);
  --ai-mono:   ui-monospace, SFMono-Regular, Menlo, Consolas, "Courier New", monospace;
}

/* ---- lane control in the navbar (both lanes) ---------------------------- */
/* Compact on purpose: CTFd pads <main> by 3.5rem for the fixed navbar, so the
   control must stay no taller than a nav link (~40px) and narrow enough that
   the navbar doesn't wrap onto a second row. */
.ai-lane-item { display:flex; align-items:center; padding:0 .25rem; }
.ai-lane { display:inline-flex; gap:2px; padding:2px; border-radius:9px;
  background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.16); }
.ai-lane button { min-height:30px; padding:0 .55rem; border:0; border-radius:7px;
  background:transparent; color:#b7c5d3; font-size:.82rem; font-weight:600;
  line-height:1; white-space:nowrap; cursor:pointer; transition:background .15s, color .15s; }
.ai-lane button[data-lane="ai"] { font-family:var(--ai-mono); font-weight:700;
  letter-spacing:.04em; font-size:.76rem; color:#ffc24d; }
.ai-lane button:hover { color:#fff; }
.ai-lane button:focus-visible { outline:2px solid #fff; outline-offset:2px; }
.ai-lane button[data-lane="classic"][aria-checked="true"] {
  background:var(--cl-accent); color:var(--cl-accent-ink); }
.ai-lane button[data-lane="ai"][aria-checked="true"] {
  background:linear-gradient(90deg, #ff2e00, #ff7a00 55%, #ffc400); color:#1a0600;
  box-shadow:0 0 14px rgba(255,90,0,.6); }

/* ---- bracket filter: ai-mode.js tags each category block (or tile) with
        data-ai-bracket; show only the bracket matching the lane. A preview has
        no lane control, so it shows whatever challenges it was given ------- */
html:not([data-ai-mode="on"]):not([data-ctf-preview]) [data-ai-bracket="ai"],
html[data-ai-mode="on"] [data-ai-bracket="normal"] { display:none !important; }

/* ---- preview (ctf.sh up --preview): nobody needs an account, so no Login link;
        the admin goes to /login directly ------------------------------------ */
html[data-ctf-preview] .navbar .nav-item:has(> a.nav-link[href$="/login"]) { display:none; }

/* ---- trimmed CTFd chrome (both lanes): no "Powered by CTFd" footer, and
        none of CTFd's own language choices (its navbar menu and the Language
        field in Settings): the theme's NO | EN switch (i18n.js) replaces them,
        and it needs CTFd to render English underneath ---------------------- */
.navbar .nav-item:has(.fa-language), footer.footer,
form :is(div, p):has(> select#language) { display:none !important; }

/* ---- the language switch (i18n.js): NO | EN at the far end of the navbar,
        small and quiet on purpose; the lane control is the loud one -------- */
.ctf-lang-item { display:flex; align-items:center; padding:0 .15rem; }
.ctf-lang-switch { display:inline-flex; align-items:center; gap:1px; }
/* padding sized for a >=24px tap target; colour contrast kept >=4.5:1 (the
   underline, not brightness, marks the selected one) */
.ctf-lang-switch button { padding:.35rem .4rem; border:0; border-radius:4px; background:transparent;
  color:rgba(255,255,255,.7); font-size:.7rem; font-weight:600; letter-spacing:.08em; line-height:1;
  cursor:pointer; transition:color .15s; }
.ctf-lang-switch button:hover { color:#fff; }
.ctf-lang-switch button[aria-checked="true"] { color:#fff;
  text-decoration:underline; text-underline-offset:3px; }
.ctf-lang-switch button:focus-visible { outline:2px solid #fff; outline-offset:1px; }
html[data-ai-mode="on"] .ctf-lang-switch button { font-family:var(--ai-mono); color:rgba(255,196,0,.72); }
html[data-ai-mode="on"] .ctf-lang-switch button:hover,
html[data-ai-mode="on"] .ctf-lang-switch button[aria-checked="true"] { color:var(--ai-amber); }

/* One look only: hide CTFd's light/dark toggle. ai-mode.head.js pins the dark
   palette, so there is nothing for it to switch. */
.theme-switch { display:none !important; }

/* ---- bilingual content: a challenge description, hint or page holds a block
        per language (<div class="ctf-lang" lang="no">, written by ctfd_admin.py
        from metadata.yml), and the one in the page's language shows. A block
        with no sibling in that language stays, so text in one language only is
        never hidden. Two rules per language: :has (for a block before the
        current language's) can't take the first one down with it ----------- */
html[data-ctf-lang="no"] .ctf-lang[lang="no"] ~ .ctf-lang:not([lang="no"]),
html[data-ctf-lang="en"] .ctf-lang[lang="en"] ~ .ctf-lang:not([lang="en"]) { display:none !important; }
html[data-ctf-lang="no"] .ctf-lang:not([lang="no"]):has(~ .ctf-lang[lang="no"]),
html[data-ctf-lang="en"] .ctf-lang:not([lang="en"]):has(~ .ctf-lang[lang="en"]) { display:none !important; }

/* ---- the event's logo (both lanes): ctfd_admin.py sets it from
        platform/theme/brand/. Square, so a bit taller than CTFd's 25px; the
        negative margin keeps the navbar as tall as before (CTFd pads <main> by
        3.5rem for it) ------------------------------------------------------- */
.navbar-brand img.ctf_logo { height:32px; width:auto; margin:-4px 0; vertical-align:middle; }

/* ---- after a correct flag, every challenge window offers Close where CTFd
        offers "Next Challenge" only when one is set (ai-mode.js relabels it).
        Only on a correct (alert-success) or already-solved (alert-info) answer,
        whatever CTFd's own x-show around it does --------------------------- */
#challenge-window .notification-row .alert:is(.alert-success, .alert-info) div:has(> button.btn-info) { display:block !important; }

/* ---- a wrong flag says to try again; from the second in a row it counts them
        and the alert shakes (ai-mode.js sets data-ctf-fails and replays
        .ctf-refail). Classic here; AI-modus and a preview have their own. The
        words are --ctf-t-* variables, from i18n.strings.js ("css.") -------- */
.notification-row .alert-danger::after { content:var(--ctf-t-try-again); display:block;
  margin-top:.25rem; font-size:.9rem; font-weight:400; opacity:.85; }
.notification-row .alert-danger:not([data-ctf-fails="1"])[data-ctf-fails]::after {
  content:var(--ctf-t-try-again-n-a) attr(data-ctf-fails) var(--ctf-t-try-again-n-b); }
.notification-row .alert-danger.ctf-refail { animation:ctf-refail .45s ease-out 1; }
/* an answer CTFd has no colour for: the theme's "error" (ai-mode.head.js: an
   expired session, a refused request), and CTFd's own "too fast" */
.notification-row .alert:not(.alert-success):not(.alert-info):not(.alert-danger):not(.alert-warning) {
  color:#ffd27a; background:rgba(255,196,0,.08); border:1px solid rgba(255,196,0,.45); }
/* AI-modus: every alert glows on the dark panel instead of Bootstrap's pastels:
   red for a wrong flag or an error, neon green for a correct (or already solved)
   answer, amber for the rest: the CTF paused, CTFd's unclassed "too fast", and the
   page notices above the board ("... is paused", "... has ended", alert-info) */
html[data-ai-mode="on"] .alert { font-family:var(--ai-mono);
  --ai-alert:var(--ai-amber); --ai-alert-head:#ffe08a; --ai-alert-line:var(--ai-amber); --ai-alert-rgb:255,196,0;
  background:linear-gradient(180deg, rgba(var(--ai-alert-rgb),.16), rgba(var(--ai-alert-rgb),.04)), #0d0604;
  border:1px solid; border-color:var(--ai-alert-line) !important; /* over the lane's brown borders */
  color:var(--ai-alert);
  text-shadow:0 0 8px rgba(var(--ai-alert-rgb),.55);
  box-shadow:0 0 18px rgba(var(--ai-alert-rgb),.25), inset 0 0 24px rgba(var(--ai-alert-rgb),.12); }
html[data-ai-mode="on"] .alert strong { color:var(--ai-alert-head);
  text-transform:uppercase; letter-spacing:.14em; }
html[data-ai-mode="on"] .alert-danger {
  --ai-alert:var(--ai-hot); --ai-alert-head:#ff6a3d; --ai-alert-line:var(--ai-red); --ai-alert-rgb:255,46,0; }
html[data-ai-mode="on"] .alert-success {
  --ai-alert:var(--ai-neon); --ai-alert-head:#b8ffa3; --ai-alert-line:var(--ai-neon); --ai-alert-rgb:57,255,20; }
html[data-ai-mode="on"] .notification-row .alert-info {
  --ai-alert:var(--ai-neon); --ai-alert-head:#b8ffa3; --ai-alert-line:rgba(57,255,20,.55); --ai-alert-rgb:57,255,20; }
html[data-ai-mode="on"] .notification-row .alert-danger::after { content:var(--ctf-t-ai-try-again);
  color:var(--ai-amber); text-shadow:0 0 6px rgba(255,122,0,.5); }
html[data-ai-mode="on"] .notification-row .alert-danger:not([data-ctf-fails="1"])[data-ctf-fails]::after {
  content:var(--ctf-t-ai-try-again-n-a) attr(data-ctf-fails) var(--ctf-t-ai-try-again-n-b); }
html[data-ai-mode="on"] .notification-row .alert-danger.ctf-refail { animation:ai-refail .6s ease-out 1; }

/* ---- per-bracket scores: the scoreboard's bracket label and the team page's
        score per bracket (the selected bracket in bold) --------------------- */
#ai-board-label { margin:.25rem 0 0; font-family:var(--ai-mono);
  font-weight:700; letter-spacing:.14em; text-transform:uppercase; opacity:.8; }
#ai-bracket-scores { margin-top:.25rem; opacity:.85; }
#ai-bracket-scores[data-active="normal"] [data-bracket="normal"],
#ai-bracket-scores[data-active="ai"] [data-bracket="ai"] { font-weight:700; opacity:1; }
html[data-ai-mode="on"] #ai-board-label { color:var(--ai-amber);
  text-shadow:0 0 8px var(--ai-red); opacity:1; }

/* ---- scoreboard tabs: All | Classic | AI-MODUS (ai-mode.js), where CTFd puts
        its own bracket tabs; the picked one in the skin's accent ------------- */
#ai-board-tabs .nav-link { font-weight:600; }
#ai-board-tabs .nav-link:focus-visible { outline:2px solid #fff; outline-offset:2px; }
html:not([data-ai-mode="on"]) #ai-board-tabs .nav-link { color:var(--cl-soft); }
html:not([data-ai-mode="on"]) #ai-board-tabs .nav-link:hover { color:#fff; }
html:not([data-ai-mode="on"]) #ai-board-tabs .nav-link.active {
  background:var(--cl-accent); color:var(--cl-accent-ink); }
html[data-ai-mode="on"] #ai-board-tabs .nav-link { font-family:var(--ai-mono);
  font-weight:700; letter-spacing:.04em; }
html[data-ai-mode="on"] #ai-board-tabs .nav-link.active {
  background:linear-gradient(90deg, #ff2e00, #ff7a00 55%, #ffc400); color:#1a0600 !important;
  box-shadow:0 0 14px rgba(255,90,0,.6); text-shadow:none; }

/* ---- lane banner on the Challenges page: a quiet rule strip under the title
        in Classic. In AI-modus a line above the title (the lane, its rule, its
        threat level) and, beside the title, how much of the bracket you have
        rooted: a count and a thin bar. ai-mode.js puts both in the title's
        container (.ai-banner-host), which lays them out here -------------- */
.ai-banner { max-width:1000px; margin:1.5rem auto 0; text-align:left;
  font-family:"Lato", system-ui, sans-serif; }
.ai-rule { display:flex; align-items:center; gap:.75rem; padding:.8rem 1rem;
  border-radius:12px; font-size:1rem; line-height:1.45; }
.ai-rule svg { flex:0 0 auto; width:22px; height:22px; fill:none; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round; }
.ai-rule-classic { background:var(--cl-panel); border:1px solid var(--cl-line); color:var(--cl-soft); }
.ai-rule-classic strong { color:var(--cl-ink); }
.ai-rule-classic svg { stroke:var(--cl-accent); }
.ai-kicker, .ai-hud { display:none; }
html[data-ai-mode="on"] .ai-rule-classic { display:none; }
html[data-ai-mode="on"] .ai-banner-host { display:grid; grid-template-columns:minmax(0, 1fr) auto;
  column-gap:2rem; align-items:end; text-align:left; }
html[data-ai-mode="on"] .ai-banner-host > .ai-kicker { grid-area:1 / 1; display:block; margin:0 0 .75rem;
  font:.75rem/1.5 var(--ai-mono); letter-spacing:.3em; text-transform:uppercase; color:var(--ai-muted); }
html[data-ai-mode="on"] .ai-banner-host > h1 { grid-area:2 / 1; justify-self:start; margin:0; }
html[data-ai-mode="on"] .ai-banner-host > .ai-banner { grid-area:2 / 2; max-width:none; margin:0 0 .7rem; }
html[data-ai-mode="on"] .ai-hud { display:flex; flex-direction:column; align-items:flex-end; gap:.65rem;
  font:.82rem var(--ai-mono); color:var(--ai-muted); white-space:nowrap; }
.ai-hud-bar { display:block; width:220px; height:2px; background:rgba(255,110,40,.18); }
.ai-hud-bar i { display:block; width:0; height:100%; background:linear-gradient(90deg, #ff2e00, #ffc400);
  box-shadow:0 0 10px rgba(255,90,0,.8); transition:width .6s ease; }
@media (max-width: 720px) {
  html[data-ai-mode="on"] .ai-banner-host { grid-template-columns:minmax(0, 1fr); }
  html[data-ai-mode="on"] .ai-banner-host > .ai-banner { grid-area:3 / 1; margin:1rem 0 0; }
  html[data-ai-mode="on"] .ai-hud { align-items:flex-start; }
  .ai-hud-bar { width:min(220px, 100%); }
}
.ai-caret { display:inline-block; width:.55em; height:1.05em; margin-left:2px;
  vertical-align:-.15em; background:var(--ai-neon); animation:ai-blink 1s steps(1) infinite; }

/* ---- siblings, in the pop-up only: an AI challenge's chips ("← builds on
        mono", each name a link) and, once a normal challenge is solved, one
        quiet line under its description that links its AI sibling ---------- */
.ai-modal-chips { display:flex; flex-wrap:wrap; justify-content:center; gap:.5rem; margin:.25rem 0 1rem; }
.ai-chip { display:inline-flex; align-items:center; padding:.3rem .65rem; border-radius:8px;
  font:.78rem/1.3 var(--ai-mono); }
.ai-chip-back { display:inline-block; } /* a flex box would drop the spaces between the names */
html[data-ai-mode="on"] .ai-chip-back { background:var(--cl-ground) !important;
  border:1px solid var(--cl-line) !important; color:#8fc6ff !important; }
html[data-ai-mode="on"] .ai-chip-rule { background:#2a1e10 !important; border:1px solid #8a6320 !important;
  color:#ffd066 !important; font-weight:700; letter-spacing:.08em; }
html[data-ai-mode="on"] .ai-chip-threat { background:#1a0806 !important; border:1px solid var(--ai-red) !important;
  color:var(--ai-hot) !important; font-weight:700; letter-spacing:.08em; }
.ai-link { padding:0; border:0; background:none; color:inherit; font:inherit; cursor:pointer;
  text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:.2em; }
.ai-link:hover { text-decoration-thickness:2px; }
.ai-link:focus-visible { outline:2px solid currentColor; outline-offset:2px; border-radius:2px; }
html[data-ai-mode="on"] .ai-chip-back .ai-link { color:#cfe6ff; }
.ai-next { margin:.5rem 0 1rem; font-size:.85rem; color:var(--cl-muted); }
.ai-next .ai-link { color:#ffc24d; font-family:var(--ai-mono); }
.ai-next .ai-link::after { content:"\00a0\2192"; content:"\00a0\2192" / ""; }
html[data-ai-mode="on"] .ai-next { color:var(--ai-muted); }

/* =========================================================================
   CLASSIC  -  calm, cool, guided. The content is the attraction.
   ========================================================================= */
/* The Classic skin deliberately wins over Admin > Config > Theme > Theme Color
   (CTFd writes that into theme_header as .navbar/.jumbotron !important): the
   lane's look is set here. To change it, edit --cl-deep / --cl-ground above. */
html:not([data-ai-mode="on"]) .navbar { background-color:var(--cl-deep) !important;
  box-shadow:inset 0 -1px 0 #22303d; }
html:not([data-ai-mode="on"]) .jumbotron { background-color:var(--cl-ground) !important;
  color:var(--cl-ink); }
/* Bootstrap paints inputs, tabs and table cells from --bs-body-bg, so it
   changes with the page background (else they stay #212529 blocks). */
html:not([data-ai-mode="on"])[data-bs-theme="dark"] { --bs-body-bg:var(--cl-ground); --bs-body-bg-rgb:15,23,32; }
html:not([data-ai-mode="on"])[data-bs-theme="dark"] body { background-color:var(--cl-ground); }
html:not([data-ai-mode="on"])[data-bs-theme="dark"] .modal-content { background-color:var(--cl-panel); }
html:not([data-ai-mode="on"]) .challenge-button { background-color:var(--cl-panel) !important;
  color:var(--cl-ink) !important; border:1px solid var(--cl-line) !important;
  border-radius:10px; box-shadow:none !important;
  transition:transform .12s ease, border-color .12s ease; }
html:not([data-ai-mode="on"]) .challenge-button:hover { transform:translateY(-2px);
  border-color:var(--cl-accent) !important; }
html:not([data-ai-mode="on"]) .challenge-button:focus-visible { outline:3px solid var(--cl-accent);
  outline-offset:2px; }
html:not([data-ai-mode="on"]) .challenge-button.challenge-solved {
  background-color:var(--cl-solved) !important; border-color:var(--cl-accent) !important; }
html:not([data-ai-mode="on"]) .challenge-button.challenge-solved .challenge-inner p::before {
  content:"\2713\00a0"; color:var(--cl-accent); font-weight:700; }

/* =========================================================================
   AI-MODUS  -  loud, burning, hostile. Everything below needs data-ai-mode=on.
   ========================================================================= */
html[data-ai-mode="on"] { background:var(--ai-bg); color-scheme:dark; }
html[data-ai-mode="on"] body { background:transparent !important; color:var(--ai-fg) !important; }
html[data-ai-mode="on"] * { border-color:var(--ai-line) !important; }

html[data-ai-mode="on"] a,
html[data-ai-mode="on"] .nav-link { color:var(--ai-amber) !important; }
html[data-ai-mode="on"] a:hover { color:#ffe27a !important; text-shadow:0 0 8px var(--ai-orange); }

html[data-ai-mode="on"] h1,
html[data-ai-mode="on"] h2,
html[data-ai-mode="on"] h3 { font-family:var(--ai-mono); color:var(--ai-amber) !important;
  text-shadow:0 0 10px rgba(255,120,0,.45); letter-spacing:.03em; }

/* burning text: the page title, the brand, the final boss's name and the
   challenge window's title */
html[data-ai-mode="on"] .jumbotron h1,
html[data-ai-mode="on"] .navbar-brand,
html[data-ai-mode="on"] [data-ai-boss] .challenge-inner > p,
html[data-ai-mode="on"] #challenge-window .challenge-name {
  background:var(--ai-fire); background-size:100% 220%;
  -webkit-background-clip:text; background-clip:text;
  -webkit-text-fill-color:transparent; color:var(--ai-orange) !important;
  text-shadow:none; filter:drop-shadow(0 0 14px rgba(255,90,0,.55));
  animation:ai-fire-shift 1.3s ease-in-out infinite alternate; }
/* sized to take no more room than Classic's brand: the full player navbar only
   just fits one row at 1280px */
html[data-ai-mode="on"] .navbar-brand { font-family:var(--ai-mono); font-weight:700;
  font-size:1.1rem; letter-spacing:.02em; text-transform:uppercase; }
/* category names: small and quiet, so the tiles carry the board */
html[data-ai-mode="on"] .category-header h3 { display:inline-block; max-width:100%; overflow-wrap:anywhere;
  margin:0; font-size:.82rem; font-weight:700; letter-spacing:.3em; text-transform:uppercase;
  color:#ff9a4a !important; text-shadow:0 0 10px rgba(255,90,0,.35); }
html[data-ai-mode="on"] .jumbotron h1 { display:inline-block; max-width:100%; overflow-wrap:anywhere;
  font-weight:700; font-size:clamp(1.9rem, 7vw, 4.6rem); letter-spacing:.02em; text-transform:uppercase; }

/* glitch: RGB-split copies of the title (ai-mode.js sets data-text) */
html[data-ai-mode="on"] .ai-glitch { position:relative; }
html[data-ai-mode="on"] .ai-glitch::before,
html[data-ai-mode="on"] .ai-glitch::after { content:attr(data-text); position:absolute; left:0; top:0;
  width:100%; -webkit-text-fill-color:currentColor; background:none;
  clip-path:inset(0 0 100% 0); pointer-events:none; }
html[data-ai-mode="on"] .ai-glitch::before { color:var(--ai-cyan); animation:ai-glitch-a 3.1s steps(1) infinite; }
html[data-ai-mode="on"] .ai-glitch::after { color:var(--ai-red); animation:ai-glitch-b 3.1s steps(1) infinite; }

/* navbar / jumbotron */
html[data-ai-mode="on"] .navbar { background:rgba(6,4,3,.94) !important;
  box-shadow:inset 0 -1px 0 var(--ai-line), 0 0 24px rgba(255,90,0,.18); }
html[data-ai-mode="on"] .jumbotron { background:transparent !important;
  border-bottom:1px solid var(--ai-line); }

/* cards, modals, tables, code */
html[data-ai-mode="on"] .card,
html[data-ai-mode="on"] .modal-content,
html[data-ai-mode="on"] .list-group-item,
html[data-ai-mode="on"] .table,
html[data-ai-mode="on"] .dropdown-menu,
html[data-ai-mode="on"] pre,
html[data-ai-mode="on"] code { background:var(--ai-panel) !important; color:var(--ai-fg) !important; }
html[data-ai-mode="on"] .dropdown-menu { --bs-dropdown-color:var(--ai-fg); --bs-dropdown-link-color:var(--ai-soft);
  --bs-dropdown-link-hover-color:#1a0600; --bs-dropdown-link-hover-bg:var(--ai-orange);
  --bs-dropdown-link-active-color:#1a0600; --bs-dropdown-link-active-bg:var(--ai-amber); }
html[data-ai-mode="on"] .modal-content { border:1px solid rgba(255,110,40,.35) !important; border-radius:16px;
  box-shadow:0 0 60px rgba(255,50,0,.18), 0 30px 80px rgba(0,0,0,.7); }
html[data-ai-mode="on"] .challenge-desc { font-family:"Lato", system-ui, sans-serif; color:var(--ai-soft); }
html[data-ai-mode="on"] .btn-close { filter:invert(1) sepia(1) saturate(4) hue-rotate(-20deg); }
html[data-ai-mode="on"] .nav-tabs .nav-link.active { background:var(--ai-panel) !important;
  color:var(--ai-amber) !important; }
html[data-ai-mode="on"] .table, html[data-ai-mode="on"] .table * { color:var(--ai-fg) !important; }
/* Bootstrap 5 paints table cells from these variables (white by default). */
html[data-ai-mode="on"] .table { --bs-table-bg:transparent; --bs-table-color:var(--ai-fg);
  --bs-table-striped-bg:rgba(255,122,0,.07); --bs-table-striped-color:var(--ai-fg);
  --bs-table-hover-bg:rgba(255,122,0,.14); --bs-table-hover-color:var(--ai-fg); }
html[data-ai-mode="on"] .footer, html[data-ai-mode="on"] .text-muted { color:var(--ai-muted) !important; }

/* inputs. background-color, not the background shorthand, and exclude checkbox and
   radio so Bootstrap's checked background-image (the tick/dot) still shows. */
html[data-ai-mode="on"] .form-control,
html[data-ai-mode="on"] .form-select,
html[data-ai-mode="on"] input:not([type=checkbox]):not([type=radio]),
html[data-ai-mode="on"] textarea, html[data-ai-mode="on"] select {
  background-color:#0a0604 !important; color:var(--ai-fg) !important;
  border:1px solid var(--ai-line) !important; caret-color:var(--ai-amber); font-family:var(--ai-mono); }
html[data-ai-mode="on"] .form-control:focus,
html[data-ai-mode="on"] input:focus, html[data-ai-mode="on"] textarea:focus {
  border-color:var(--ai-orange) !important; box-shadow:0 0 0 .2rem rgba(255,122,0,.3) !important; }

/* buttons */
html[data-ai-mode="on"] .btn:not(.challenge-button):not(.btn-close) {
  background:#0a0604 !important; color:var(--ai-amber) !important;
  border:1px solid var(--ai-orange) !important; font-family:var(--ai-mono); font-weight:700;
  transition:all .12s; }
html[data-ai-mode="on"] .btn:not(.challenge-button):not(.btn-close):hover {
  background:linear-gradient(90deg, #ff2e00, #ff7a00 55%, #ffc400) !important; color:#1a0600 !important;
  box-shadow:0 0 16px rgba(255,90,0,.6); text-shadow:none; }

/* challenge tiles: dark glass that burns on hover. The name on top; below it
   the points and the threat rating (ai-mode.js, .ai-heat). A solved tile says
   "rooted" in green where its points were, and its flames go grey. CTFd's tile
   is .challenge-inner > p (the name) + span (the points). */
html[data-ai-mode="on"] .challenge-button { position:relative; overflow:hidden;
  padding:1.1rem 1.15rem 1rem; text-align:left;
  background:rgba(14,8,5,.82) !important; color:var(--ai-fg) !important;
  border:1px solid rgba(255,110,40,.16) !important; border-radius:12px; box-shadow:none !important;
  font-family:var(--ai-mono); transition:transform .15s ease, box-shadow .15s ease, border-color .15s ease; }
html[data-ai-mode="on"] .challenge-button .challenge-inner { margin:0 !important; min-height:4.4rem;
  display:grid; grid-template-columns:minmax(0, 1fr) auto; grid-template-rows:1fr auto;
  row-gap:1.1rem; align-items:end; }
html[data-ai-mode="on"] .challenge-button .challenge-inner > p { grid-column:1 / -1; align-self:start;
  margin:0; font-size:1.05rem; font-weight:700; overflow-wrap:anywhere; }
html[data-ai-mode="on"] .challenge-button .challenge-inner > p + span { grid-column:1;
  font-size:.88rem; color:var(--ai-muted); }
html[data-ai-mode="on"] .challenge-button:hover,
html[data-ai-mode="on"] .challenge-button:focus-visible { transform:translateY(-3px);
  border-color:rgba(255,122,0,.75) !important;
  box-shadow:0 10px 40px rgba(255,60,0,.28), inset 0 -30px 40px -30px rgba(255,90,0,.55) !important; }
html[data-ai-mode="on"] .challenge-button:focus-visible { outline:2px solid var(--ai-amber); outline-offset:2px; }
html[data-ai-mode="on"] .challenge-button.challenge-solved { border-color:rgba(57,255,20,.35) !important; }
html[data-ai-mode="on"] .challenge-button.challenge-solved .challenge-inner > p + span { font-size:0; }
html[data-ai-mode="on"] .challenge-button.challenge-solved .challenge-inner > p + span::after {
  content:var(--ctf-t-rooted); font-size:.72rem; letter-spacing:.2em; color:#5cff3a;
  text-shadow:0 0 8px rgba(57,255,20,.6); }
.ai-heat { display:none; }
html[data-ai-mode="on"] .ai-heat { grid-column:2; display:flex; gap:1px;
  filter:drop-shadow(0 0 3px rgba(255,90,0,.7)); }
.ai-heat svg { width:15px; height:15px; }
html[data-ai-mode="on"] .challenge-solved .ai-heat { opacity:.35; filter:grayscale(1); }
html[data-ai-mode="on"] .challenge-button:hover .ai-heat svg { animation:ai-heat .35s ease-in-out infinite alternate; }

/* the final boss (ai-mode.js marks the ai-llm block): at the top of the AI board,
   its category name hidden, each challenge one wide row with "FINAL BOSS", its
   burning name, the boss's sanity and its points */
html[data-ai-mode="on"] [data-ai-board] { display:flex; flex-direction:column; }
html[data-ai-mode="on"] [data-ai-boss] { order:-1; }
html[data-ai-mode="on"] [data-ai-boss] .category-header { display:none; }
html[data-ai-mode="on"] [data-ai-boss] .challenges-row > * { flex:0 0 100%; width:100%; max-width:100%; }
html[data-ai-mode="on"] [data-ai-boss] .challenge-button { padding:1.35rem 1.6rem;
  background:linear-gradient(100deg, rgba(255,30,0,.16), rgba(14,8,5,.85) 45%) !important;
  border-color:rgba(255,46,0,.45) !important; }
html[data-ai-mode="on"] [data-ai-boss] .challenge-button:hover,
html[data-ai-mode="on"] [data-ai-boss] .challenge-button:focus-visible { transform:none;
  border-color:var(--ai-red) !important; box-shadow:0 0 40px rgba(255,30,0,.3) !important; }
html[data-ai-mode="on"] [data-ai-boss] .challenge-inner { min-height:0; column-gap:2rem; row-gap:.45rem;
  grid-template-columns:minmax(0, 1fr) minmax(0, 260px) auto; grid-template-rows:auto auto; }
html[data-ai-mode="on"] [data-ai-boss] .challenge-inner > p { grid-column:1; grid-row:2;
  font-size:clamp(1.5rem, 3.4vw, 2.4rem); font-weight:800; line-height:1.05; }
html[data-ai-mode="on"] [data-ai-boss] .challenge-inner > p + span { grid-column:3; grid-row:1 / 3;
  align-self:center; font-size:1.4rem; font-weight:700; color:var(--ai-amber); }
html[data-ai-mode="on"] [data-ai-boss] .ai-heat { display:none; }
.ai-boss-kicker, .ai-boss-sanity { display:none; }
html[data-ai-mode="on"] .ai-boss-kicker { display:block; grid-column:1; grid-row:1;
  font-size:.7rem; letter-spacing:.3em; color:var(--ai-hot); }
html[data-ai-mode="on"] .ai-boss-sanity { display:flex; grid-column:2; grid-row:1 / 3; align-self:center;
  flex-direction:column; align-items:flex-end; gap:.6rem; font-size:.78rem; color:var(--ai-muted); }
.ai-boss-sanity-bar { display:block; width:100%; height:3px; background:rgba(255,46,0,.18); }
.ai-boss-sanity-bar i { display:block; width:0; height:100%; background:var(--ai-red);
  box-shadow:0 0 10px var(--ai-red); transition:width .6s ease; }
@media (max-width: 720px) {
  html[data-ai-mode="on"] [data-ai-boss] .challenge-inner { grid-template-columns:minmax(0, 1fr) auto; }
  html[data-ai-mode="on"] [data-ai-boss] .challenge-inner > p + span { grid-column:2; }
  html[data-ai-mode="on"] .ai-boss-sanity { grid-column:1 / -1; grid-row:3; align-items:stretch; }
}

/* ---- effect layers (created by ai-mode.js). Rain and flames sit BEHIND the
        content; scanlines, the rolling bar and the flicker sit on top but never
        take clicks. ------------------------------------------------------- */
#ai-rain, #ai-flames, #ai-scanlines, #ai-rollbar, #ai-flicker-msg { display:none; }
/* the fire's gradients (ai-mode.js): a 0x0 SVG, never display:none */
#ai-defs { position:absolute; width:0; height:0; overflow:hidden; pointer-events:none; }
/* faint, and gone before it reaches the flames */
html[data-ai-mode="on"] #ai-rain { display:block; position:fixed; inset:0; z-index:-2;
  opacity:.28; pointer-events:none;
  -webkit-mask-image:linear-gradient(180deg, #000 0%, #000 40%, transparent 78%);
  mask-image:linear-gradient(180deg, #000 0%, #000 40%, transparent 78%); }
html[data-ai-mode="on"] #ai-flames { display:block; position:fixed; left:0; right:0; bottom:0;
  height:320px; z-index:-1; pointer-events:none; overflow:hidden; }
#ai-flames::before { content:""; position:absolute; left:0; right:0; bottom:0; height:240px;
  background:radial-gradient(ellipse 70% 100% at 50% 100%, rgba(255,60,0,.32), rgba(255,60,0,0)); }
/* four rows of drawn flames (ai-mode.js places and sizes each one), each
   licking on its own loop: the back row slow and wide, the front ones quick */
.ai-fl-row { position:absolute; inset:0; }
.ai-fl { position:absolute; bottom:-18px; transform-origin:50% 100%;
  animation:ai-lick-a 1.2s ease-in-out infinite; }
.ai-fl svg { display:block; width:100%; height:100%; }
.ai-fl-back .ai-fl { animation-name:ai-lick-b; }
.ai-fl-front .ai-fl { animation-name:ai-lick-c; }
.ai-fl-bed { position:absolute; left:0; right:0; bottom:0; height:24px;
  background:linear-gradient(0deg, #ffd040, #ff7a00 55%, rgba(255,90,0,0)); }
.ai-ember { position:absolute; bottom:24px; border-radius:50%; background:#ffd04d;
  box-shadow:0 0 6px #ff9a00, 0 0 12px #ff3a00; opacity:0; animation:ai-ember 4s ease-out infinite; }

html[data-ai-mode="on"] #ai-scanlines { display:block; position:fixed; inset:0; z-index:9998;
  pointer-events:none; background:repeating-linear-gradient(0deg,
    rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,0,0,.16) 3px, rgba(0,0,0,0) 4px); }
html[data-ai-mode="on"] #ai-rollbar { display:block; position:fixed; left:0; right:0; top:-160px;
  height:160px; z-index:9998; pointer-events:none;
  background:linear-gradient(180deg, rgba(255,200,120,0), rgba(255,200,120,.05) 50%, rgba(255,200,120,0));
  animation:ai-roll 7s linear infinite; }

/* the random flicker: two dips in 0.8 s and nothing else that flashes (no
   brightness, contrast, invert or colour spikes; the warning fades in and out),
   so it stays under the three-flashes-a-second limit. The warning never takes
   clicks. */
/* the page parts shake, not <body>: a transformed body would drag the fixed
   warning along with it, off-centre on long pages */
html.ai-flickering[data-ai-mode="on"] body > .navbar,
html.ai-flickering[data-ai-mode="on"] body > main,
html.ai-flickering[data-ai-mode="on"] body > .footer { animation:ai-crt .8s linear 1; }
html.ai-flickering[data-ai-mode="on"] #ai-flicker-msg { display:flex; position:fixed; inset:0;
  z-index:9999; align-items:center; justify-content:center; pointer-events:none;
  background:rgba(255,20,0,.10); animation:ai-warn .8s linear 1 both; }
#ai-flicker-msg span { padding:.9rem 1.6rem; background:var(--ai-bg); border:2px solid var(--ai-red) !important;
  font:700 clamp(1.1rem, 3vw, 1.9rem)/1.2 var(--ai-mono); letter-spacing:.1em;
  color:var(--ai-hot); text-shadow:0 0 14px rgba(255,46,0,.9); }

/* ---- the Effects button (ai-mode.js), bottom left in AI-modus only. Off
        (html[data-ai-fx="off"], set before paint by ai-mode.head.js): no
        flames, rain, scanlines, rolling bar, flicker or boot sequence. Under
        the pop-ups' backdrop (1050), over the page ------------------------- */
#ai-fx-toggle { display:none; }
html[data-ai-mode="on"] #ai-fx-toggle { display:inline-flex; align-items:center; gap:.45rem;
  position:fixed; left:1rem; bottom:1rem; z-index:1030; min-height:32px; padding:0 .7rem;
  border:1px solid var(--ai-line) !important; border-radius:8px; background:rgba(6,4,3,.9);
  color:var(--ai-soft); font:700 .72rem/1 var(--ai-mono); letter-spacing:.08em;
  text-transform:uppercase; cursor:pointer; }
html[data-ai-mode="on"] #ai-fx-toggle:hover { color:#fff; border-color:var(--ai-orange) !important; }
html[data-ai-mode="on"] #ai-fx-toggle:focus-visible { outline:2px solid var(--ai-amber); outline-offset:2px; }
#ai-fx-toggle .ai-fx-state { color:var(--ai-neon); }
#ai-fx-toggle[aria-pressed="false"] .ai-fx-state { color:var(--ai-muted); }
html[data-ai-fx="off"] :is(#ai-rain, #ai-flames, #ai-scanlines, #ai-rollbar, #ai-flicker-msg, #ai-boot) {
  display:none !important; }
html.ai-flickering[data-ai-fx="off"] :is(body > .navbar, body > main, body > .footer) { animation:none !important; }

/* the boot sequence, played when you enter the lane (click or Esc skips it) */
#ai-boot { position:fixed; inset:0; z-index:10000; display:flex; flex-direction:column;
  justify-content:center; gap:.4rem; padding:10vh 10vw; background:#030201; cursor:pointer;
  font:clamp(.95rem, 2vw, 1.25rem)/1.5 var(--ai-mono); color:var(--ai-neon);
  text-shadow:0 0 8px rgba(57,255,20,.6); }
#ai-boot.ai-boot-out { animation:ai-boot-out .45s ease-in forwards; }
#ai-boot .ai-boot-skip { position:absolute; right:2rem; bottom:1.5rem; font-size:.8rem;
  color:#6fcf5a; text-shadow:none; }

/* ---- first-visit lane chooser (both lanes) ------------------------------ */
/* margin:auto (not align-items:center) keeps the panel centred when it fits
   and scrollable from its top when it doesn't, e.g. on phones */
#ai-chooser { position:fixed; inset:0; z-index:10001; display:flex;
  padding:1rem; background:rgba(5,7,10,.94); overflow:auto; }
.ai-chooser-panel { margin:auto; width:100%; max-width:1000px; border-radius:16px; overflow:hidden;
  background:#0b0e12; color:var(--cl-ink); border:1px solid #22303d !important;
  box-shadow:0 30px 80px rgba(0,0,0,.6); font-family:"Lato", system-ui, sans-serif; }
.ai-chooser-head { padding:2rem 2rem 1.5rem; text-align:center; }
.ai-chooser-head h2 { margin:0 0 .4rem; font-size:2rem; font-weight:700; color:var(--cl-ink) !important;
  font-family:inherit; text-shadow:none; }
.ai-chooser-head p { margin:0; color:#b7c5d3; }
.ai-chooser-lanes { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); }
.ai-chooser-lane { position:relative; overflow:hidden; display:flex; flex-direction:column; gap:1rem;
  padding:2rem 2.25rem 2.25rem; }
.ai-chooser-lane ul { margin:0; padding-left:1.2rem; line-height:1.55; }
.ai-chooser-lane button { align-self:flex-start; min-height:48px; padding:0 1.5rem; border:0;
  border-radius:10px; font-size:1.05rem; font-weight:700; cursor:pointer; position:relative; }
.ai-chooser-lane button:focus-visible { outline:3px solid #fff; outline-offset:3px; }
.ai-chooser-kicker { font:.8rem var(--ai-mono); letter-spacing:.14em; }
.ai-chooser-classic { background:var(--cl-ground); border-top:3px solid var(--cl-accent) !important; }
.ai-chooser-classic .ai-chooser-kicker { color:var(--cl-accent); }
.ai-chooser-classic .ai-chooser-name { font-size:2.2rem; font-weight:700; line-height:1.1; }
.ai-chooser-classic ul { color:var(--cl-soft); }
.ai-chooser-classic button { background:var(--cl-accent); color:var(--cl-accent-ink); }
.ai-chooser-ai { background:var(--ai-bg); color:var(--ai-fg);
  border-top:3px solid var(--ai-hot) !important; }
.ai-chooser-ai::before { content:""; position:absolute; left:0; right:0; bottom:0; height:120px;
  background:linear-gradient(0deg, rgba(255,60,0,.45), rgba(255,60,0,0)); pointer-events:none; }
.ai-chooser-ai .ai-chooser-kicker { color:var(--ai-amber); }
.ai-chooser-ai .ai-chooser-name { align-self:flex-start; font:700 2.4rem/1.1 var(--ai-mono);
  background:var(--ai-fire); background-size:100% 220%; -webkit-background-clip:text; background-clip:text;
  -webkit-text-fill-color:transparent; color:var(--ai-orange);
  filter:drop-shadow(0 0 14px rgba(255,90,0,.55)); animation:ai-fire-shift 1.3s ease-in-out infinite alternate; }
.ai-chooser-ai ul { color:var(--ai-soft); }
.ai-chooser-fx { position:relative; margin:0; font-size:.88rem; color:var(--ai-soft); }
.ai-chooser-ai button { background:linear-gradient(90deg, #ff2e00, #ff7a00 55%, #ffc400);
  color:#1a0600; font-family:var(--ai-mono); letter-spacing:.06em; box-shadow:0 0 22px rgba(255,90,0,.6); }
.ai-chooser-rule { display:flex; align-items:center; gap:.6rem; padding:.7rem .9rem; border-radius:10px;
  font-weight:700; }
.ai-chooser-classic .ai-chooser-rule { background:var(--cl-panel); border:1px solid var(--cl-line) !important; }
.ai-chooser-ai .ai-chooser-rule { background:var(--ai-panel); border:1px solid var(--ai-line) !important; }
.ai-chooser-foot { padding:1rem 2rem; text-align:center; font-size:.95rem; color:#b7c5d3;
  border-top:1px solid #22303d !important; }
@media (max-width: 720px) {
  .ai-chooser-lanes { grid-template-columns:1fr; }
}

/* ---- keyframes ----------------------------------------------------------- */
@keyframes ai-fire-shift { from { background-position:0 0; } to { background-position:0 100%; } }
@keyframes ai-glitch-a {
  0%, 84%, 100% { clip-path:inset(0 0 100% 0); transform:none; }
  86% { clip-path:inset(12% 0 58% 0); transform:translate(-5px, -1px); }
  89% { clip-path:inset(62% 0 10% 0); transform:translate(4px, 1px); }
  92% { clip-path:inset(34% 0 38% 0); transform:translate(-3px, 0); } }
@keyframes ai-glitch-b {
  0%, 85%, 100% { clip-path:inset(0 0 100% 0); transform:none; }
  87% { clip-path:inset(48% 0 22% 0); transform:translate(5px, 1px); }
  90% { clip-path:inset(8% 0 70% 0); transform:translate(-4px, -1px); }
  93% { clip-path:inset(70% 0 4% 0); transform:translate(2px, 0); } }
/* a flame licks: it stretches, squashes and sways from its base */
@keyframes ai-lick-a {
  0%, 100% { transform:scale(1, 1) skewX(0); }
  25% { transform:scale(.9, 1.14) skewX(-7deg); }
  50% { transform:scale(1.06, .88) skewX(3deg); }
  75% { transform:scale(.94, 1.08) skewX(6deg); } }
@keyframes ai-lick-b {
  0%, 100% { transform:scale(1, 1) skewX(3deg); }
  33% { transform:scale(.94, 1.1) skewX(-5deg); }
  66% { transform:scale(1.04, .92) skewX(6deg); } }
@keyframes ai-lick-c {
  0%, 100% { transform:scale(1, .95) skewX(-4deg); }
  30% { transform:scale(.92, 1.16) skewX(5deg); }
  60% { transform:scale(1.08, .9) skewX(-2deg); } }
/* an ember drifts up, wobbling, and burns out */
@keyframes ai-ember {
  0% { transform:translate(0, 0) scale(1); opacity:0; } 10% { opacity:1; }
  35% { transform:translate(12px, -90px); }
  65% { transform:translate(-10px, -190px) scale(.8); opacity:.8; }
  100% { transform:translate(6px, -300px) scale(.4); opacity:0; } }
@keyframes ai-roll { from { transform:translateY(0); } to { transform:translateY(calc(100vh + 320px)); } }
@keyframes ai-blink { 50% { opacity:0; } }
@keyframes ai-heat { from { transform:translateY(0) scale(1); } to { transform:translateY(-2px) scale(1.15); } }
@keyframes ai-crt {
  0%, 15%, 40%, 55%, 100% { opacity:1; transform:none; }
  8%   { opacity:.35; transform:translateX(-9px) skewX(5deg); }
  47%  { opacity:.5; transform:translateX(7px); } }
@keyframes ai-warn { 0%, 100% { opacity:0; } 15%, 80% { opacity:1; } }
/* a wrong flag again: Classic shakes its head; AI-modus jolts, tears and burns */
@keyframes ctf-refail {
  0%, 100% { transform:none; }
  15% { transform:translateX(-8px); } 30% { transform:translateX(7px); }
  45% { transform:translateX(-5px); } 60% { transform:translateX(4px); }
  75% { transform:translateX(-2px); } }
@keyframes ai-refail {
  0% { transform:none; }
  10% { transform:translateX(-12px) skewX(-8deg); opacity:.5;
        box-shadow:0 0 28px rgba(255,46,0,.9), inset 0 0 30px rgba(255,122,0,.45); }
  20% { transform:translateX(10px) skewX(5deg); opacity:1; }
  32% { transform:translateX(-8px); opacity:.65; }
  44% { transform:translateX(6px); opacity:1;
        box-shadow:0 0 18px rgba(255,46,0,.6), inset 0 0 18px rgba(255,122,0,.3); }
  58% { transform:translateX(-4px); } 72% { transform:translateX(2px); }
  100% { transform:none; box-shadow:none; } }
@keyframes ai-boot-out { to { opacity:0; transform:scaleY(.02); filter:brightness(3); } }

/* ---- a solve (ai-mode.js celebrate): a card over the page for ~3 s, never
        taking a click. Classic is calm; AI-modus burns. ---------------------- */
.ctf-win { position:fixed; inset:0; z-index:10002; pointer-events:none; overflow:hidden;
  display:flex; align-items:center; justify-content:center; transition:opacity .4s ease; }
.ctf-win.ctf-win-out { opacity:0; }
.ctf-win i { position:absolute; top:0; display:block; }
.ctf-win-card { position:relative; z-index:1; text-align:center; max-width:calc(100vw - 32px);
  padding:1.6rem 2.4rem 1.4rem; animation:ctf-win-in .45s cubic-bezier(.2,1.4,.4,1) both; }
.ctf-win-title, .ctf-win-sub, .ctf-win-note, .ctf-win-kicker { overflow-wrap:anywhere; }

.ctf-win-classic .ctf-win-card { background:var(--cl-panel); border:1px solid var(--cl-accent);
  border-radius:16px; color:var(--cl-ink); font-family:"Lato", system-ui, sans-serif;
  box-shadow:0 18px 60px rgba(0,0,0,.55), 0 0 0 6px rgba(90,176,255,.12); }
.ctf-win-check { width:64px; height:64px; display:block; margin:0 auto .6rem; fill:none;
  stroke:var(--cl-accent); stroke-width:3.5; stroke-linecap:round; stroke-linejoin:round; }
.ctf-win-check circle { stroke-dasharray:145; stroke-dashoffset:145; animation:ctf-win-draw .6s ease-out .15s forwards; }
.ctf-win-check path { stroke-dasharray:40; stroke-dashoffset:40; animation:ctf-win-draw .35s ease-out .65s forwards; }
.ctf-win-classic .ctf-win-title { font-size:clamp(1.6rem, 5vw, 2.2rem); font-weight:700; letter-spacing:.01em; }
.ctf-win-classic .ctf-win-sub { margin-top:.2rem; color:var(--cl-muted); font-size:1.1rem; }
.ctf-win-confetti { border-radius:2px; }

.ctf-win-ai::before { content:""; position:absolute; inset:0;
  background:radial-gradient(ellipse at 50% 110%, rgba(255,46,0,.35), transparent 60%);
  animation:ctf-win-heat .9s ease-out both; }
.ctf-win-ai .ctf-win-card { background:rgba(6,4,3,.92); border:1px solid var(--ai-orange);
  color:var(--ai-fg); font-family:var(--ai-mono);
  box-shadow:0 0 40px rgba(255,46,0,.55), inset 0 0 30px rgba(255,122,0,.18); }
.ctf-win-ai .ctf-win-kicker { color:var(--ai-neon); font-size:.9rem; letter-spacing:.12em; text-transform:uppercase; }
.ctf-win-ai .ctf-win-title { font-size:clamp(2.4rem, 9vw, 4.4rem); font-weight:900; line-height:1.05;
  letter-spacing:.04em; background:var(--ai-fire); background-size:100% 220%;
  -webkit-background-clip:text; background-clip:text; color:transparent;
  filter:drop-shadow(0 0 14px rgba(255,90,0,.7));
  animation:ai-fire-shift 1.4s linear infinite alternate, ctf-win-glitch 2.4s steps(1) infinite; }
.ctf-win-ai .ctf-win-sub { margin-top:.3rem; color:var(--ai-amber); font-size:1.15rem; font-weight:700; }
.ctf-win-ai .ctf-win-note { margin-top:.2rem; color:var(--ai-muted); font-size:.85rem; }
.ctf-win-ember { border-radius:50%; top:auto !important; bottom:-12px; }

@keyframes ctf-win-in { from { opacity:0; transform:scale(.85) translateY(12px); } to { opacity:1; transform:none; } }
@keyframes ctf-win-draw { to { stroke-dashoffset:0; } }
@keyframes ctf-win-heat { 0% { opacity:0; } 15% { opacity:1; } 100% { opacity:.6; } }
@keyframes ctf-win-glitch {
  0%, 100% { transform:none; }
  31% { transform:translate(-3px, 1px) skewX(-6deg); }
  33% { transform:none; }
  71% { transform:translate(4px, -1px) skewX(4deg); }
  73% { transform:none; } }

/* respect reduced motion: keep the palette, drop every animation (ai-mode.js
   also skips the boot sequence, the flicker and the rain) */
@media (prefers-reduced-motion: reduce) {
  html[data-ai-mode="on"] *, html[data-ai-mode="on"] *::before, html[data-ai-mode="on"] *::after,
  #ai-chooser *, #ai-boot, .challenge-button, .ctf-win, .ctf-win *,
  .notification-row .alert { animation:none !important; transition:none !important; }
  .ctf-win-check circle, .ctf-win-check path { stroke-dashoffset:0; }
  .challenge-button:hover { transform:none !important; }
  #ai-rain, #ai-rollbar { display:none !important; }
}

/* Print: organisers take the final scoreboard off the Scoreboard page (docs/ai-mode.md).
   The AI-modus skin paints burning text and light-on-dark tables, and the Classic lane
   runs on Bootstrap's dark palette (pinned by ai-mode.head.js): both vanish or turn
   illegible when a browser prints without background graphics, so for print force plain
   black-on-white text in either lane, drop the gradient text-fill, and hide the effect
   layers. */
@media print {
  html[data-ai-mode="on"] .jumbotron h1,
  html[data-ai-mode="on"] .navbar-brand,
  html[data-ai-mode="on"] .category-header h3,
  html[data-ai-mode="on"], html[data-ai-mode="on"] body,
  html[data-ai-mode="on"] table, html[data-ai-mode="on"] th, html[data-ai-mode="on"] td,
  html[data-ai-mode="on"] .text-muted, html[data-ai-mode="on"] .footer {
    color:#000 !important; background:#fff !important;
    -webkit-text-fill-color:#000 !important; text-shadow:none !important;
    filter:none !important; animation:none !important; }
  /* Classic: ink-on-paper Bootstrap palette, so tables and headings follow. */
  html:not([data-ai-mode="on"])[data-bs-theme="dark"] {
    --bs-body-color:#000; --bs-body-color-rgb:0,0,0; --bs-body-bg:#fff; --bs-body-bg-rgb:255,255,255;
    --bs-emphasis-color:#000; --bs-emphasis-color-rgb:0,0,0; --bs-heading-color:#000;
    --bs-secondary-color:#444; --bs-border-color:#999; }
  html:not([data-ai-mode="on"]) body, html:not([data-ai-mode="on"]) .navbar,
  html:not([data-ai-mode="on"]) .navbar-brand, html:not([data-ai-mode="on"]) .navbar .nav-link,
  html:not([data-ai-mode="on"]) .jumbotron,
  html:not([data-ai-mode="on"]) table, html:not([data-ai-mode="on"]) th, html:not([data-ai-mode="on"]) td,
  html:not([data-ai-mode="on"]) .text-muted, html:not([data-ai-mode="on"]) .footer {
    color:#000 !important; background:#fff !important; box-shadow:none !important; }
  #ai-rain, #ai-rollbar, #ai-boot, #ai-chooser, #ai-fx-toggle, .theme-switch { display:none !important; }
}
