/* events.css — special-event themes on the public pages (v105).

   An event recolours the site by swapping its colour TOKENS — every page is
   drawn from the same few variables — so nothing is redrawn and nothing new
   can break the layout. js/events.js sets <html data-event="…"> from what the
   server says is showing, and adds the moving decorations (bats, snow,
   lanterns…) on a canvas that never takes a click.

   Every pairing below was checked against WCAG AA (4.5:1) in both the dark
   and the light (Parchment) look: link text and gold on the ground, muted
   text on panels, dark text on every stop of the button ramp, white on the
   light-mode button. The dark block names :not([data-theme="parchment"]) so
   it can never override the light one. */

/* ── Halloween ─────────────────────────────────────────────────────────── */
html[data-event="halloween"]:not([data-theme="parchment"]){
  --void:#0b0711; --panel:#150d1f; --sunk:#08050d; --field:#100a18; --edge:#2c1a3d; --edge-soft:#1e1229;
  --scarlet:#ff7a18; --scarlet-ink:#ff9a3d; --ember:#ff9a3d; --crimson:#4e1680; --gold:#ffb627; --ice:#b98cff; --rose:#8dff6a;
  --on-accent:#14060b;
  --ramp:linear-gradient(96deg,#ffd166 0%,#ffa53a 45%,#ff8a1f 100%);
  --ramp-deco:linear-gradient(96deg,#ffb627 0%,#ff7a18 38%,#b98cff 74%,#4e1680 100%);
  --ramp-text:linear-gradient(96deg,#ffd166,#ff9a3d 42%,#c9a2ff 92%);
}
html[data-event="halloween"][data-theme="parchment"]{
  --void:#f8f3ec; --panel:#ffffff; --sunk:#efe6da; --field:#fbf7f1; --edge:#e0d2c0; --edge-soft:#ece2d4;
  --scarlet:#b24400; --scarlet-ink:#a63f00; --ember:#a63f00; --crimson:#5a1c8f; --gold:#8a5400; --ice:#6b2fb3; --rose:#3d7a1f;
  --on-accent:#ffffff; --ramp:var(--scarlet);
  --ramp-deco:linear-gradient(96deg,#c27a0a 0%,#b24400 40%,#6b2fb3 80%,#5a1c8f 100%);
  --ramp-text:linear-gradient(96deg,#9a5a00,#b24400 40%,#6b2fb3 90%);
}
/* ── Christmas & winter ────────────────────────────────────────────────── */
html[data-event="winter"]:not([data-theme="parchment"]){
  --void:#070b14; --panel:#0e1526; --sunk:#050810; --field:#0a101d; --edge:#1d2a40; --edge-soft:#141e30;
  --scarlet:#e3263f; --scarlet-ink:#ff5f6f; --ember:#ff5f6f; --crimson:#8a0f24; --gold:#ffd479; --ice:#9fd8ff; --rose:#c9f0ff;
  --muted:#a6b0c4; --text:#f2f6fb; --on-accent:#14060b;
  --ramp:linear-gradient(96deg,#ffd479 0%,#ff9a6b 45%,#f0485c 100%);
  --ramp-deco:linear-gradient(96deg,#ffd479 0%,#f0485c 40%,#9fd8ff 80%,#1d4f7a 100%);
  --ramp-text:linear-gradient(96deg,#ffe3a1,#ffffff 45%,#9fd8ff 90%);
}
html[data-event="winter"][data-theme="parchment"]{
  --void:#f3f7fb; --panel:#ffffff; --sunk:#e6edf5; --field:#f7fafd; --edge:#d3dce8; --edge-soft:#e3eaf2;
  --scarlet:#b3122b; --scarlet-ink:#b3122b; --ember:#b3122b; --crimson:#7d0c22; --gold:#7d5a00; --ice:#1c6aa3; --rose:#3a7fb0;
  --muted:#4f5b6e; --text:#141a24; --on-accent:#ffffff; --ramp:var(--scarlet);
  --ramp-text:linear-gradient(96deg,#9a7000,#b3122b 50%,#1c6aa3 90%);
}
/* ── New Year ──────────────────────────────────────────────────────────── */
html[data-event="newyear"]:not([data-theme="parchment"]){
  --void:#05060f; --panel:#0c0e1f; --sunk:#04050b; --field:#080a17; --edge:#1d2140; --edge-soft:#13162d;
  --scarlet:#ffc23a; --scarlet-ink:#ffd46b; --ember:#ffd46b; --crimson:#3a2a7a; --gold:#ffe08a; --ice:#9cc0ff; --rose:#d9c2ff;
  --muted:#a8a9c4; --text:#f5f3ff; --on-accent:#14060b;
  --ramp:linear-gradient(96deg,#fff1b8 0%,#ffd46b 45%,#f2b632 100%);
  --ramp-deco:linear-gradient(96deg,#fff1b8 0%,#ffc23a 40%,#9cc0ff 80%,#3a2a7a 100%);
  --ramp-text:linear-gradient(96deg,#fff6d0,#ffd46b 45%,#c0d6ff 92%);
}
html[data-event="newyear"][data-theme="parchment"]{
  --void:#f7f5ef; --panel:#ffffff; --sunk:#ece8dc; --field:#faf8f3; --edge:#ddd6c4; --edge-soft:#e9e3d4;
  --scarlet:#8a6400; --scarlet-ink:#7a5a00; --ember:#7a5a00; --crimson:#3a2a7a; --gold:#7a5a00; --ice:#2a56a8; --rose:#5a46a8;
  --muted:#55546a; --text:#16151f; --on-accent:#ffffff; --ramp:var(--scarlet);
  --ramp-text:linear-gradient(96deg,#8a6400,#a37800 45%,#2a56a8 92%);
}
/* ── Valentine's & spring ──────────────────────────────────────────────── */
html[data-event="valentine"]:not([data-theme="parchment"]){
  --void:#0e0710; --panel:#1a0d1b; --sunk:#0a050b; --field:#140a15; --edge:#36193a; --edge-soft:#241128;
  --scarlet:#ff4d8d; --scarlet-ink:#ff7aa8; --ember:#ff7aa8; --crimson:#9c1a52; --gold:#ffc2d6; --ice:#ffb3c7; --rose:#ffd1e0;
  --muted:#b8a2b8; --text:#fbf1f6; --on-accent:#14060b;
  --ramp:linear-gradient(96deg,#ffd1e0 0%,#ff9cc0 45%,#ff5e98 100%);
  --ramp-deco:linear-gradient(96deg,#ffd1e0 0%,#ff5e98 45%,#9c1a52 100%);
  --ramp-text:linear-gradient(96deg,#ffe0ea,#ff9cc0 45%,#ff5e98 92%);
}
html[data-event="valentine"][data-theme="parchment"]{
  --void:#fbf4f6; --panel:#ffffff; --sunk:#f2e4ea; --field:#fdf8fa; --edge:#ead2dc; --edge-soft:#f2e2e9;
  --scarlet:#b0124f; --scarlet-ink:#b0124f; --ember:#b0124f; --crimson:#7a0e3c; --gold:#9c2a5a; --ice:#a8225f; --rose:#c4577e;
  --muted:#5e5060; --text:#1f1219; --on-accent:#ffffff; --ramp:var(--scarlet);
  --ramp-text:linear-gradient(96deg,#c4577e,#b0124f 60%,#7a0e3c);
}
/* ── Easter ────────────────────────────────────────────────────────────── */
html[data-event="easter"]:not([data-theme="parchment"]){
  --void:#080d0f; --panel:#0f1a1c; --sunk:#060a0b; --field:#0b1416; --edge:#1f3336; --edge-soft:#152426;
  --scarlet:#8fd16a; --scarlet-ink:#a6e07f; --ember:#a6e07f; --crimson:#3b5f8a; --gold:#ffe066; --ice:#c4b5ff; --rose:#ffb3d1;
  --muted:#a4b4b0; --text:#f2f8f4; --on-accent:#14060b;
  --ramp:linear-gradient(96deg,#ffe066 0%,#cdea8c 45%,#8fd16a 100%);
  --ramp-deco:linear-gradient(96deg,#ffe066 0%,#8fd16a 35%,#c4b5ff 70%,#ffb3d1 100%);
  --ramp-text:linear-gradient(96deg,#fff0a0,#cdea8c 40%,#d9ceff 92%);
}
html[data-event="easter"][data-theme="parchment"]{
  --void:#f6f8f1; --panel:#ffffff; --sunk:#e9eedf; --field:#fafbf6; --edge:#d6decb; --edge-soft:#e5ebdb;
  --scarlet:#3e7a1c; --scarlet-ink:#3e7a1c; --ember:#3e7a1c; --crimson:#2a4f78; --gold:#7a6400; --ice:#5b44b8; --rose:#b0457a;
  --muted:#4f5a50; --text:#152015; --on-accent:#ffffff; --ramp:var(--scarlet);
  --ramp-text:linear-gradient(96deg,#7a6400,#3e7a1c 50%,#5b44b8 92%);
}
/* ── Chinese New Year ──────────────────────────────────────────────────── */
html[data-event="cny"]:not([data-theme="parchment"]){
  --void:#0f0606; --panel:#1c0b0b; --sunk:#0a0404; --field:#160909; --edge:#3d1714; --edge-soft:#2a100e;
  --scarlet:#e8202a; --scarlet-ink:#ff5a5f; --ember:#ff5a5f; --crimson:#8a0f14; --gold:#ffcc33; --ice:#ffd98a; --rose:#ffb38a;
  --muted:#c0a8a0; --text:#fbf3ec; --on-accent:#14060b;
  --ramp:linear-gradient(96deg,#ffe08a 0%,#ffc233 45%,#ff7b3d 100%);
  --ramp-deco:linear-gradient(96deg,#ffe08a 0%,#ffcc33 30%,#e8202a 70%,#8a0f14 100%);
  --ramp-text:linear-gradient(96deg,#ffe8a8,#ffcc33 45%,#ff5a5f 92%);
}
html[data-event="cny"][data-theme="parchment"]{
  --void:#fbf5ec; --panel:#ffffff; --sunk:#f2e6d6; --field:#fdf9f3; --edge:#ead6c0; --edge-soft:#f2e4d2;
  --scarlet:#b0141c; --scarlet-ink:#b0141c; --ember:#b0141c; --crimson:#7a0c12; --gold:#8a5f00; --ice:#9a5a00; --rose:#b04a2a;
  --muted:#5e5048; --text:#1f1210; --on-accent:#ffffff; --ramp:var(--scarlet);
  --ramp-text:linear-gradient(96deg,#8a5f00,#b0141c 60%,#7a0c12);
}
/* A custom event's two colours come in as --ev-a and --ev-b (js/events.js
   lifts --ev-ink until it clears 4.5:1 on the ground). */
html[data-event="custom"]:not([data-theme="parchment"]){
  --scarlet:var(--ev-a); --scarlet-ink:var(--ev-ink); --ember:var(--ev-ink); --gold:var(--ev-b);
  --ramp:linear-gradient(96deg,var(--ev-b) 0%,var(--ev-a) 100%); --on-accent:var(--ev-on);
  --ramp-text:linear-gradient(96deg,var(--ev-b),var(--ev-ink) 70%);
}
html[data-event="custom"][data-theme="parchment"]{
  --scarlet:var(--ev-a-l); --scarlet-ink:var(--ev-a-l); --ember:var(--ev-a-l); --gold:var(--ev-b-l);
  --ramp:var(--ev-a-l); --on-accent:#ffffff;
}

/* ── the banner line ───────────────────────────────────────────────────── */
.fx-ev-banner{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 18px;padding:10px 16px;border-radius:12px;
  background:color-mix(in srgb,var(--scarlet) 12%,var(--panel));border:1px solid color-mix(in srgb,var(--scarlet) 45%,var(--edge));
  color:var(--text);font-family:'Manrope',system-ui,sans-serif;font-size:15px;line-height:1.45;font-weight:500;max-width:100%}
.fx-ev-banner .fx-ev-mark{flex:none;font-size:18px;line-height:1}
.fx-ev-banner a{color:var(--scarlet-ink);font-weight:700;text-decoration:underline;text-underline-offset:3px}
.fx-ev-banner span{overflow-wrap:anywhere;min-width:0}
/* The words take the room that is left, so on a phone the pumpkin, the line
   and the pause button share one row instead of stacking into three. */
.fx-ev-banner>span:not(.fx-ev-mark){flex:1 1 0;min-width:9rem}
.fx-ev-banner .fx-ev-pause{flex:none}
.hero .fx-ev-banner{align-self:flex-start;margin-bottom:16px}
.fx-ev-banner[hidden]{display:none}

/* ── the effects button (pauses everything that moves) ─────────────────── */
.fx-ev-pause[hidden]{display:none}
.fx-ev-pause{white-space:nowrap}
/* On a phone the header has no room for the word: the symbol alone, still
   named for screen readers, still a full-size target. */
@media (max-width:600px){
  .fx-ev-pause .fx-ev-w{display:none}
  .fx-ev-pause{min-width:40px;justify-content:center}
}
.fx-ev-pause.floating{position:fixed;left:max(16px,env(safe-area-inset-left,0px));bottom:calc(18px + env(safe-area-inset-bottom,0px));z-index:56;
  display:inline-flex;align-items:center;justify-content:center;gap:7px;min-height:44px;min-width:44px;padding:8px 14px;border-radius:100px;cursor:pointer;
  background:var(--panel);color:var(--muted);border:1px solid var(--edge);
  font-family:'JetBrains Mono',ui-monospace,monospace;font-size:11px;letter-spacing:.12em;text-transform:uppercase}
.fx-ev-pause.floating:hover{color:var(--text);border-color:var(--gold)}
.fx-ev-pause.inbanner{margin-left:auto;display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:36px;min-width:44px;padding:6px 12px;border-radius:100px;cursor:pointer;background:transparent;
  color:var(--text);border:1px solid color-mix(in srgb,var(--scarlet) 45%,var(--edge));
  font-family:'JetBrains Mono',ui-monospace,monospace;font-size:11px;letter-spacing:.12em;text-transform:uppercase}
.fx-ev-pause.inbanner:hover{border-color:var(--gold)}
@media (pointer:coarse){.fx-ev-pause.inbanner{min-height:44px}}
.fx-ev-pause:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

/* ── the moving layer, and full-strength Halloween's fog and cobwebs ────
   v106: all of it sits BEHIND the page — in front of the glowing
   background, behind every word, button and picture, and behind the menu.
   The page's content is lifted onto layer 5 for it; the hero's glow,
   vignette and stars are on 0–2, the fog on 3, the bats and cobwebs on 4. */
html[data-event]:not([data-fx-panel]) section>.wrap,html[data-event]:not([data-fx-panel]) main,html[data-event]:not([data-fx-panel]) footer{position:relative;z-index:5}
.fx-ev-canvas{position:fixed;inset:0;width:100%;height:100%;pointer-events:none;z-index:4}
/* v109: in the panels (the Developer Portal and Fluxion Business) the content
   is not lifted — their dialogs, menus and docked chat keep the layering they
   were built with. The decorations go underneath everything instead: drawn
   over the page's ground and nothing else, so every card, word and button is
   in front of them. */
html[data-fx-panel] .fx-ev-canvas{z-index:-1}
/* …and quieter: a work tool's words come first, so a bat crossing behind a
   line of text never darkens it much. */
html[data-fx-panel] .fx-ev-canvas{opacity:.55}
html[data-fx-panel][data-theme="parchment"] .fx-ev-canvas{opacity:.4}
/* The fog drifts inside a box the size of the screen, so it never pokes past
   the edges (on a phone that made the whole page scroll sideways). */
.fx-ev-fog{position:fixed;left:0;right:0;bottom:0;height:42vh;pointer-events:none;z-index:3;opacity:.42;overflow:hidden}
.fx-ev-fog::before{content:'';position:absolute;left:-10%;right:-10%;top:0;bottom:-15%;
  background:
    radial-gradient(40% 60% at 20% 100%, color-mix(in srgb,var(--ice) 22%,transparent), transparent 78%),
    radial-gradient(45% 55% at 70% 100%, color-mix(in srgb,var(--text) 14%,transparent), transparent 80%),
    radial-gradient(35% 50% at 45% 100%, color-mix(in srgb,var(--crimson) 30%,transparent), transparent 70%);
  /* soft by its gradients alone: a blur filter over this much of the screen
     costs a phone's graphics chip on every frame */
  will-change:transform;animation:fxfog 22s ease-in-out infinite alternate}
@keyframes fxfog{0%{transform:translate3d(-3%,0,0) scale(1)}100%{transform:translate3d(3%,-2%,0) scale(1.06)}}
/* Cobwebs: in the top corners of the PAGE (they scroll away with it), not
   the screen. The right-hand one is the left-hand box mirrored. */
.fx-ev-web{position:absolute;top:0;width:220px;height:220px;pointer-events:none;z-index:4;overflow:hidden}
.fx-ev-web.tl{left:0}
.fx-ev-web.tr{right:0;transform:scaleX(-1)}
.fx-ev-silk{position:absolute;inset:0;background-image:var(--silk-d);background-repeat:no-repeat;background-size:contain;
  opacity:.68;transform-origin:0 0;animation:fxsway 9s ease-in-out infinite}
html[data-theme="parchment"] .fx-ev-silk{background-image:var(--silk-l);opacity:.6}
.fx-ev-web.tr .fx-ev-silk{animation-duration:11s;animation-delay:-4s}
/* a draft now and then: most of the time still, then a slow give and settle */
@keyframes fxsway{0%,58%,100%{transform:rotate(0)}68%{transform:rotate(.9deg) scale(1.006)}80%{transform:rotate(-.5deg)}90%{transform:rotate(.2deg)}}
/* The spider lets itself down on a thread, waits, and climbs back. */
.fx-ev-spider{position:absolute;right:80px;top:26px;width:26px;height:170px;pointer-events:none;z-index:4;transform-origin:50% 0;
  animation:fxdangle 7s ease-in-out infinite alternate}
.fx-ev-spider i{position:absolute;left:50%;top:0;width:1px;height:100%;margin-left:-.5px;transform-origin:50% 0;
  background:linear-gradient(rgba(236,230,244,.15),rgba(236,230,244,.6));animation:fxthread 19s ease-in-out infinite}
html[data-theme="parchment"] .fx-ev-spider i{background:linear-gradient(rgba(58,42,68,.12),rgba(58,42,68,.55))}
.fx-ev-spider b{position:absolute;left:0;top:100%;width:26px;height:26px;margin-top:-6px;background-image:var(--spider-d);
  background-size:contain;background-repeat:no-repeat;animation:fxclimb 19s ease-in-out infinite}
html[data-theme="parchment"] .fx-ev-spider b{background-image:var(--spider-l)}
/* the spider rides the end of the thread: 65% of the thread's length up */
@keyframes fxthread{0%,12%{transform:scaleY(.35)}42%,64%{transform:scaleY(1)}94%,100%{transform:scaleY(.35)}}
@keyframes fxclimb{0%,12%{transform:translateY(calc(var(--drop,170px) * -.65))}42%,64%{transform:translateY(0)}94%,100%{transform:translateY(calc(var(--drop,170px) * -.65))}}
@keyframes fxdangle{0%{transform:rotate(-2.5deg)}100%{transform:rotate(2.5deg)}}
@media (max-width:700px){
  .fx-ev-web{width:140px;height:140px}
  .fx-ev-spider{right:46px;top:16px;height:120px;--drop:120px;animation:none}
  .fx-ev-fog{height:30vh;opacity:.32}
}
/* Flickering light — the logo's glow, the status lights and the buttons'
   halo gutter like candles. Slow, uneven and small: never a flash. */
html[data-fx="full"][data-event="halloween"] .heroart img{animation:fxcandle 5.3s steps(1,end) infinite}
html[data-fx="full"][data-event="halloween"] .dot{animation:fxdot 3.7s steps(1,end) infinite}
@keyframes fxcandle{
  0%,100%{filter:drop-shadow(0 18px 50px color-mix(in srgb,var(--scarlet) 55%,transparent))}
  17%{filter:drop-shadow(0 18px 42px color-mix(in srgb,var(--scarlet) 38%,transparent))}
  23%{filter:drop-shadow(0 18px 54px color-mix(in srgb,var(--scarlet) 60%,transparent))}
  61%{filter:drop-shadow(0 18px 40px color-mix(in srgb,var(--ice) 40%,transparent))}
  67%{filter:drop-shadow(0 18px 52px color-mix(in srgb,var(--scarlet) 58%,transparent))}}
@keyframes fxdot{0%,100%{opacity:1}31%{opacity:.55}36%{opacity:1}72%{opacity:.7}76%{opacity:1}}

/* Paused by the visitor, or asked for less motion: nothing moves. The colours
   and the cobwebs (which do not move) stay. */
html[data-fx-paused] .fx-ev-canvas,html[data-fx-paused] .fx-ev-fog{display:none}
html[data-fx-paused] .heroart img,html[data-fx-paused] .dot{animation:none!important}
html[data-fx-paused] .fx-ev-silk,html[data-fx-paused] .fx-ev-spider,html[data-fx-paused] .fx-ev-spider *{animation-play-state:paused}
@media (prefers-reduced-motion:reduce){
  .fx-ev-canvas,.fx-ev-fog{display:none}
  html[data-event] .heroart img,html[data-event] .dot{animation:none!important}
  .fx-ev-silk,.fx-ev-spider,.fx-ev-spider *{animation:none!important}
}
@media print{.fx-ev-canvas,.fx-ev-fog,.fx-ev-web,.fx-ev-spider,.fx-ev-pause,.fx-ev-banner,.fx-ss-pill{display:none!important}}

/* ── v109: the panels' banner line and seasonal-theme choice ──────────────
   A slim strip under the header, holding the event's line and the choice:
   Full (colours and decorations), Colours only, or Off. While an event is on
   and the strip is not there to hold it, a small control in the header does. */
.fx-panel-bar{margin:12px auto 0;width:calc(100% - 32px);max-width:var(--fx-bar-max,1218px);
  padding:8px 12px;font-size:13.5px;gap:8px 12px}
.fx-panel-bar .fx-ev-line{flex:1 1 14rem;min-width:0}
.fx-ss{display:inline-flex;align-items:center;gap:8px;margin-left:auto;
  font-family:'JetBrains Mono',ui-monospace,monospace;font-size:11px;letter-spacing:.06em;color:var(--muted);font-weight:400}
.fx-ss select,.fx-ss-pill select{font:inherit;letter-spacing:inherit;color:var(--text);background:var(--panel);
  border:1px solid var(--edge);border-radius:6px;padding:4px 6px;min-height:30px;cursor:pointer}
.fx-ss select:focus-visible,.fx-ss-pill select:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.fx-ss-pill .fx-ss-w{display:none}
.fx-ss-pill select{background:transparent;border:0;padding:0 2px;min-height:0;color:inherit}
.fx-ss-pill select option,.fx-ss select option{background:var(--panel);color:var(--text)}
@media (max-width:600px){.fx-ss .fx-ss-w{display:none}.fx-panel-bar{width:calc(100% - 24px);font-size:13px}}
@media (pointer:coarse){.fx-ss select{min-height:40px}}

/* The welcome screen before it has drawn: a plain cover in the site's ground,
   set by boot.js the moment the page starts, so the homepage never flashes up
   first. It lifts by itself after four seconds, whatever happens. */
html.fx-welcoming body::after{content:'';position:fixed;inset:0;z-index:9999;background:#0a0812;
  animation:fxcover 0s linear 4s forwards}
@keyframes fxcover{to{visibility:hidden;opacity:0}}
