/* ══════════════════════════════════════════════════════════════════════
   SKETCH.SOCIAL — SEASONAL THEMES
   ──────────────────────────────────────────────────────────────────────
   Four holidays, each active only on its own date (see seasonal.js).
   Nothing here applies unless <html> carries a data-season attribute, so
   the site is untouched for 361 days of the year.

   Every theme overrides the SAME small set of tokens the page already
   uses — --bg, --card, --nav-bg, --text, --border, --accent — so no
   layout, spacing or type changes are involved and nothing can break
   structurally when a theme switches on.
   ══════════════════════════════════════════════════════════════════════ */

html[data-season="halloween"]{
  --bg:#1b1220; --card:#241a2c; --nav-bg:#241a2c;
  --text:#f4ecf7; --text2:#bda8c9; --text3:#9a86a6;
  --border:#3a2a45; --accent:#e8761f;
  --season-2:#b06adf;
  --season-band:linear-gradient(90deg,#e8761f,#b06adf);
  --season-band-ink:#1b1220;
}
html[data-season="christmas"]{
  --bg:#dcecf7; --card:#ffffff; --nav-bg:#eaf4fb;   /* cold winter sky */
  --text:#0f2417; --text2:#4a6152; --text3:#6b8375;
  --border:#cfdbd2; --accent:#186b3a;
  --season-2:#c8323c;
  --season-band:linear-gradient(90deg,#186b3a,#c8323c);
  --season-band-ink:#ffffff;
}
html[data-season="patricks"]{
  --bg:#edf3eb; --card:#ffffff; --nav-bg:#e4efe4;
  --text:#0d2b18; --text2:#456052; --text3:#6a8574;
  --border:#cddccf; --accent:#128a3e;
  --season-2:#d8a531;
  --season-band:linear-gradient(90deg,#128a3e,#d8a531);
  --season-band-ink:#ffffff;
}
/* ── New Year's ────────────────────────────────────────────────────────
   A night sky, so the fireworks have something to burst against — the
   only theme besides Halloween that goes dark, and for the same reason:
   the decoration needs it. */
html[data-season="newyears"]{
  /* Gold, black and silver. Black is the ground rather than a near-black
     blue, and silver does the work the second colour did — it keeps the
     scheme to three tones without needing a hue anywhere. */
  --bg:#0a0a0c; --card:#17171b; --nav-bg:#141417;
  --text:#f2f2f4; --text2:#b9bcc4; --text3:#8b8e97;
  --border:#2f3038; --accent:#e5c15a;          /* gold   */
  --season-2:#c8ccd4;                          /* silver */
  --season-band:linear-gradient(90deg,#e5c15a,#c8ccd4);
  --season-band-ink:#0a0a0c;
  --deco:
    radial-gradient(circle at 18% 12%, rgba(229,193,90,.13), transparent 40%),
    radial-gradient(circle at 82% 22%, rgba(200,204,212,.10), transparent 42%);
}

html[data-season="valentines"]{
  --bg:#fbeef2; --card:#ffffff; --nav-bg:#fbe2ea;
  --text:#2a0f1b; --text2:#6d4655;
  --text3:#8a6675;
  --border:#f0d5de; --accent:#d1385f;
  --season-2:#f08cb0;
  --season-band:linear-gradient(90deg,#d1385f,#f08cb0);
  --season-band-ink:#ffffff;
}

/* ── Sprite canvases ──────────────────────────────────────────────────
   Both sit BEHIND the page content. The click handler works off
   coordinates rather than hit-testing, so sprites stay clickable from
   back there and never block a button. */
#ssFallBg, #ssFall{
  position:fixed; inset:0; pointer-events:none; display:none;
}
/* z-index:-1, not 0. At 0 they painted on TOP of the page content,
   because the feed's containers create no stacking context of their own
   to sit above them. Negative pulls them behind the content while still
   leaving them above the page background. */
html[data-season] #ssFallBg{ display:block; z-index:0; opacity:.5; }
html[data-season] #ssFall  { display:block; z-index:0; }

/* Give the page's own containers a layer so nothing can slip in front. */
html[data-season] body > nav,
html[data-season] .page,
html[data-season] .feed-container,
html[data-season] .sketch-card,
html[data-season] .sidebar-panel{ position:relative; z-index:1; }

/* ── Image-backed drifting sprites ────────────────────────────────────
   Real <img> elements rather than canvas draws, because a canvas only
   ever renders a GIF's first frame. Positioned with transform only, so
   moving them never triggers layout. */
#ssSprites{ position:fixed; inset:0; pointer-events:none; z-index:0; display:none; }
/* Every season that uses an image sprite has to be listed here — the
   layer is display:none by default, so a season missing from this list
   renders nothing at all no matter what the JS does. */
html[data-season="patricks"] #ssSprites,
html[data-season="christmas"] #ssSprites,
html[data-season="halloween"] #ssSprites,
html[data-season="newyears"] #ssSprites{ display:block; }
#ssSprites .ss-sprite{
  position:absolute; top:0; left:0;
  width:28px; height:auto;          /* a size before the first frame runs */
  user-select:none; -webkit-user-drag:none;
  /* No will-change here. With 44 sprites on screen it asked Firefox for
     44 separate compositor layers, which costs more than it saves —
     transform-only movement is already cheap to composite. */
}

/* ── Seasonal greeting card ───────────────────────────────────────────
   Sits at the top of the sidebar (or above the feed on phones). Given
   real presence rather than a quiet strip: the season's gradient fills
   the card, the heading is PunkKid on that colour, and a soft shine
   sweeps across it every few seconds so it catches the eye once without
   demanding attention afterwards. */
#ssGreet{
  display:none; position:relative; overflow:hidden;
  background:var(--season-band, var(--accent));
  border:2px solid var(--text);
  border-radius:var(--r,12px);
  padding:15px 16px 15px 18px;
  margin-bottom:14px;
  box-shadow:4px 4px 0 var(--text);
}
html[data-season] #ssGreet{ display:block; }

/* Sweep of light across the card. Transform-only, so it composites
   without repainting anything underneath. */
#ssGreet::after{
  content:''; position:absolute; top:-60%; bottom:-60%; left:-40%; width:34%;
  background:linear-gradient(100deg, transparent, rgba(255,255,255,.42), transparent);
  transform:skewX(-18deg) translateX(0);
  animation:ssShine 5.5s ease-in-out infinite;
  pointer-events:none;
}
@keyframes ssShine{
  0%, 62% { transform:skewX(-18deg) translateX(0); }
  92%,100%{ transform:skewX(-18deg) translateX(760%); }
}

#ssGreet .ss-greet-mark{
  position:absolute; right:-14px; top:-14px;
  width:74px; height:74px; border-radius:50%;
  background:rgba(255,255,255,.16);
  pointer-events:none;
}
#ssGreet .ss-greet-text{ position:relative; z-index:1; }
#ssGreet b{
  display:block;
  font-family:var(--font-display); font-weight:400;
  font-size:23px; line-height:1.14; letter-spacing:.5px;
  color:#fff;
  text-shadow:0 2px 0 rgba(0,0,0,.22);
}
#ssGreet span{
  display:block; margin-top:5px;
  font-family:var(--font-body); font-size:12.5px; font-weight:600;
  line-height:1.5; color:rgba(255,255,255,.92);
}

/* Valentine's and St Patrick's gradients are light enough that white text
   needs a touch more weight behind it. */
html[data-season="patricks"] #ssGreet b,
html[data-season="valentines"] #ssGreet b{ text-shadow:0 2px 0 rgba(0,0,0,.3); }

@media (max-width:640px){
  #ssGreet{ padding:13px 14px; margin:0 0 12px; box-shadow:3px 3px 0 var(--text); }
  #ssGreet b{ font-size:20px; }
  #ssGreet .ss-greet-mark{ width:58px; height:58px; }
}
@media (prefers-reduced-motion: reduce){
  #ssGreet::after{ animation:none; opacity:0; }
}

/* ── Christmas lights ─────────────────────────────────────────────────
   `top` is set from JS to the nav's measured bottom edge — hardcoding it
   fails, because the band above the nav changes where the nav sits. */
/* Absolute inside the nav, hanging off its bottom edge. The nav is
   sticky, so the string stays with it and no fixed-positioning quirks
   apply — see the note in seasonal.js. */
#ssLights{ display:none; position:absolute; left:0; right:0; top:100%;
           height:90px; z-index:1; pointer-events:none; }
html[data-season="christmas"] body > nav,
html[data-season="christmas"] nav{ overflow:visible; }
html[data-season="christmas"] #ssLights{ display:block; }
/* height must match BOX in seasonal.js buildLights(). */
#ssLights .ss-wire{ width:100%; height:44px; display:block; overflow:visible; }

/* Bulbs are real images laid over the SVG cord. Each is centred on its
   point of the curve, so `left` is the position along the wire and `top`
   is the height of the wire there. */
#ssLights .ss-bulb{
  position:absolute;
  /* Both dimensions fixed. With height:auto the rendered height followed
     each file's own aspect ratio, so the broken variants — a different
     shape to the intact ones — came out noticeably larger. object-fit
     keeps whatever shape the artwork is inside a constant box. */
  width:38px; height:54px;
  object-fit:contain; object-position:center top;

  /* The artwork is upright (cap at the bottom); on a string the bulbs hang
     the other way up, so it's flipped.

     The origin must be the CENTRE. Rotating 180deg about the top edge
     swings the whole body up and over that point, which is what put every
     bulb above the wire; about the centre the box stays where it was
     placed and only its contents invert. */
  /* -4px lifts the cap onto the wire. object-position pins the artwork to
     the top of its 38px box, but the cap still sits a few pixels inside
     the PNG's own transparent margin, which left a visible gap. */
  transform:translate(-50%, -19px) rotate(180deg);
  transform-origin:50% 50%;

  pointer-events:auto; cursor:pointer;
  filter:drop-shadow(0 0 7px currentColor);
  transition:filter .15s, opacity .15s;
}
/* Glow colour per bulb, via currentColor so one shadow rule covers all. */
#ssLights .ss-bulb[data-col="red"]   { color:rgba(226,59,59,.75); }
#ssLights .ss-bulb[data-col="green"] { color:rgba(58,166,85,.75); }
#ssLights .ss-bulb[data-col="blue"]  { color:rgba(63,127,214,.75); }
#ssLights .ss-bulb[data-col="yellow"]{ color:rgba(242,182,50,.8); }
#ssLights .ss-bulb[data-col="purple"]{ color:rgba(208,90,196,.75); }
#ssLights .ss-bulb[data-col="orange"]{ color:rgba(239,143,42,.78); }

#ssLights .ss-bulb:not(.dead){ animation:ssTwinkle 2.6s ease-in-out infinite; }
#ssLights .ss-bulb:nth-child(3n)  { animation-delay:-.9s; }
#ssLights .ss-bulb:nth-child(3n+1){ animation-delay:-1.7s; }

/* A live bulb sways when the cursor nears it, just before it goes. */
/* Pivot at the cap for the sway — that's the bottom of the artwork, which
   after the flip sits against the wire. */
#ssLights .ss-bulb:not(.dead):hover{
  animation:ssSway .4s ease-in-out;
  transform-origin:50% 100%;
}

/* Once broken: no glow, no twinkle, and it hangs a touch lower. */
#ssLights .ss-bulb.dead{
  filter:none; opacity:.9;
  animation:none !important;
  /* Slightly smaller than an intact bulb — the glass is gone, so a broken
     one reading a touch smaller is both truer and stops the artwork's
     different proportions making it look oversized. */
  width:28px; height:40px;
  /* 180 + 6: still flipped, just knocked slightly askew. */
  transform:translate(-50%, -9px) rotate(186deg);
}
@keyframes ssSway{
  0%,100%{ transform:translate(-50%,-19px) rotate(175deg); }
  50%    { transform:translate(-50%,-19px) rotate(185deg); }
}

@keyframes ssTwinkle{
  0%,100%{ filter:drop-shadow(0 0 8px currentColor) brightness(1.04); }
  50%    { filter:drop-shadow(0 0 3px currentColor) brightness(.94); }
}

/* ── St Patrick's rainbow ─────────────────────────────────────────────
   ONE element painted with a repeating-radial-gradient, not six nested
   circles with huge borders. At 130vmax those six bordered ellipses were
   ~1900px across each, and Firefox rasterises rounded borders far more
   slowly than Chrome — that stack alone was the source of the lag.

   A single gradient is one paint, and because the bands are colour stops
   rather than boxes it costs the same whatever size the window is. */
/* An SVG arc, not a 130vmax gradient.

   The gradient version had to rasterise roughly 1900x1900px — about 14MB
   of texture — every time it was painted. Firefox felt that far more than
   Chrome, which is why the lag showed up there first.

   This is a 200x200 viewBox stretched to fill instead: the browser
   rasterises a tiny bitmap and the GPU scales it, so the cost is
   effectively fixed no matter how large the window is. The arcs are
   stroked circles, so the bands stay crisp at any size. */
#ssRainbow{
  display:none; position:fixed; right:-46vmax; bottom:-46vmax;
  width:112vmax; height:112vmax;
  pointer-events:none; z-index:0; opacity:.24;
  background-repeat:no-repeat; background-position:center; background-size:100% 100%;
  background-image:url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'>\
<g fill='none' stroke-width='9'>\
<circle cx='100' cy='100' r='92' stroke='%23e2453c'/>\
<circle cx='100' cy='100' r='83' stroke='%23ef8f2a'/>\
<circle cx='100' cy='100' r='74' stroke='%23f4d03f'/>\
<circle cx='100' cy='100' r='65' stroke='%233fae5a'/>\
<circle cx='100' cy='100' r='56' stroke='%233f7fd6'/>\
<circle cx='100' cy='100' r='47' stroke='%238a5bc4'/>\
</g></svg>");
  /* contain:paint means nothing here can influence layout elsewhere, so
     the browser never re-examines it while scrolling. No will-change:
     on Firefox that pinned the huge tile in memory and made things worse
     rather than better. */
  contain:paint;
}
html[data-season="patricks"] #ssRainbow{ display:block; }

/* ── Settled snow ─────────────────────────────────────────────────────
   Switched off for now. The rules are removed rather than left inert so
   nothing half-renders; seasonal.js no longer sets data-snow either.
   ────────────────────────────────────────────────────────────────────── */

/* ── Cobwebs: a real SVG. The gradient version relied on hairline colour
   stops that browsers round away, so it drew nothing at all. ────────── */
html[data-season="halloween"] .sketch-card,
html[data-season="halloween"] .sidebar-panel{ position:relative; }
html[data-season="halloween"] [data-web]::after{
  content:''; position:absolute; top:0; left:0; width:70px; height:70px; z-index:4;
  pointer-events:none; opacity:.5;
  background-image:var(--ss-web, url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 70 70'><g fill='none' stroke='%23ffffff' stroke-width='1.1' stroke-linecap='round'><path d='M0 0 L70 26 M0 0 L52 52 M0 0 L26 70 M0 0 L66 8 M0 0 L8 66'/><path d='M14 2 Q10 10 2 14'/><path d='M27 5 Q19 19 5 27'/><path d='M41 9 Q29 29 9 41'/><path d='M55 13 Q38 38 13 55'/><path d='M68 17 Q47 47 17 68'/></g></svg>"));
  background-repeat:no-repeat; background-position:top left; background-size:contain;
}
html[data-season="halloween"] [data-web="right"]::after{
  left:auto; right:0; transform:scaleX(-1);
}


@media (prefers-reduced-motion: reduce){
  #ssFall, #ssFallBg{ display:none !important; }
  }
/* ══════════════════════════════════════════════════════════════════════
   SEASONAL BRANDING
   ──────────────────────────────────────────────────────────────────────
   The wordmark, search field and notification bell pick up the season's
   colours. Each theme uses only its two accents (--accent and --season-2)
   plus the existing ink, so the palette stays as small as it is the rest
   of the year and nothing turns into a colour salad.

   The bell and search are image assets, so they're tinted with a filter
   rather than recoloured — hue-rotate keeps the artwork's own shading
   and highlights intact instead of flattening it to a solid fill.
   ══════════════════════════════════════════════════════════════════════ */

/* ── Wordmark ──────────────────────────────────────────────────────────
   Two-tone: "Sketch" and "Social" take different halves of each theme's
   pair. seasonal.js wraps the two text nodes in <i> first, since the
   markup is `Sketch<em>.</em>Social` and CSS can't target a bare text
   node. Only `color` is set — the outline is a text-shadow, and touching
   that would flatten the letterforms. */
html[data-season] .nav-logo-text .ss-lg-a,
html[data-season] .nav-logo-text .ss-lg-b{ font-style:normal; }

/* Halloween — orange / purple */
html[data-season="halloween"] .nav-logo-text .ss-lg-a{ color:#f0932b !important; }
html[data-season="halloween"] .nav-logo-text .ss-lg-b{ color:#b06adf !important; }
html[data-season="halloween"] .nav-logo-text em{ color:#f0932b !important; }

/* Christmas — red / green */
html[data-season="christmas"] .nav-logo-text .ss-lg-a{ color:#c8323c !important; }
html[data-season="christmas"] .nav-logo-text .ss-lg-b{ color:#1c7a41 !important; }
html[data-season="christmas"] .nav-logo-text em{ color:#c8323c !important; }

/* St Patrick's — green / orange */
html[data-season="patricks"] .nav-logo-text .ss-lg-a{ color:#17a04a !important; }
html[data-season="patricks"] .nav-logo-text .ss-lg-b{ color:#e07b21 !important; }
html[data-season="patricks"] .nav-logo-text em{ color:#d8a531 !important; }

/* Valentine's — red / pink */
html[data-season="valentines"] .nav-logo-text .ss-lg-a{ color:#c81f45 !important; }
html[data-season="valentines"] .nav-logo-text .ss-lg-b{ color:#f08cb0 !important; }
html[data-season="valentines"] .nav-logo-text em{ color:#c81f45 !important; }

/* ── Artwork tinting ──────────────────────────────────────────────────
   One rule per season, pointing at an SVG colour matrix injected by
   seasonal.js. Declarative: nothing to wire up per element, and no
   silent failure mode if a script runs in the wrong order. */
html[data-season="halloween"]  .sidebar-title-img,
html[data-season="halloween"]  #notifBtn img,
html[data-season="halloween"]  #modBtn img,
html[data-season="halloween"]  .draw-btn img,
html[data-season="halloween"]  #postSketchBtn img,
html[data-season="halloween"]  #saveCanvasBtn img,
html[data-season="halloween"]  .m-fab-draw img{ filter:url(#ssTintOrange); }

html[data-season="christmas"]  .sidebar-title-img,
html[data-season="christmas"]  #modBtn img,
html[data-season="christmas"]  .draw-btn img,
html[data-season="christmas"]  #postSketchBtn img{ filter:url(#ssTintRed); }
/* The other half of the pair, so Christmas isn't one flat wall of red. */
html[data-season="christmas"]  #notifBtn img,
html[data-season="christmas"]  #saveCanvasBtn img,
html[data-season="christmas"]  .m-fab-draw img{ filter:url(#ssTintGreen); }

html[data-season="patricks"]   .sidebar-title-img,
html[data-season="patricks"]   #notifBtn img,
html[data-season="patricks"]   #modBtn img,
html[data-season="patricks"]   .draw-btn img,
html[data-season="patricks"]   #postSketchBtn img,
html[data-season="patricks"]   #saveCanvasBtn img,
html[data-season="patricks"]   .m-fab-draw img{ filter:url(#ssTintOrange); }

html[data-season="valentines"] .sidebar-title-img,
html[data-season="valentines"] #notifBtn img,
html[data-season="valentines"] #modBtn img,
html[data-season="valentines"] .draw-btn img,
html[data-season="valentines"] #postSketchBtn img,
html[data-season="valentines"] #saveCanvasBtn img,
html[data-season="valentines"] .m-fab-draw img{ filter:url(#ssTintPink); }

/* ── Search ───────────────────────────────────────────────────────── */
html[data-season] #searchBarShell{
  border-color:var(--accent) !important;
  background:var(--card) !important;
}
html[data-season] #searchBtn{ color:var(--text) !important; }
html[data-season] #searchBtn::placeholder{ color:var(--text3) !important; }
html[data-season] #searchWrap svg{ stroke:var(--accent) !important; }
html[data-season] .sp-expand{
  background:var(--card) !important;
  color:var(--accent) !important;
  border-top-color:var(--border) !important;
}

html[data-season] #notifBadge{ background:var(--accent) !important; }

/* Draw / Post / Download artwork — tinted, not recoloured, so the
   spraypaint texture in the PNGs survives. */
html[data-season="halloween"]  #saveCanvasBtn img,
html[data-season="christmas"]  #saveCanvasBtn img,
html[data-season="valentines"] #saveCanvasBtn img,
html[data-season="valentines"] .m-fab-draw img{ filter:grayscale(1) sepia(1) hue-rotate(298deg) saturate(3.4) brightness(.97); }

/* ── Buttons and active states ────────────────────────────────────── */
html[data-season] .nav-tab.active{
  background:var(--accent) !important; color:#fff !important;
}
html[data-season] .postBtn,
html[data-season] .draw-btn,
html[data-season] .create-btn:hover{ border-color:var(--accent); }
html[data-season] .sidebar-toggle-btn{
  border-color:var(--accent) !important; color:var(--accent) !important;
}
html[data-season] .m-strip-chip .cnt{ background:var(--accent) !important; }
html[data-season] .m-strip-item .ring{ border-color:var(--accent) !important; }

/* ── Vote colours ─────────────────────────────────────────────────────
   Themed too. The arrow shapes carry the up/down meaning on their own, so
   the colour is free to move — but each pair is still chosen to keep a
   warm/positive and cool-or-dark/negative relationship, so the two never
   read as interchangeable at a glance.

   Everything (hover, active fill, the counts) reads from --up and --down,
   so these two lines per theme cover the whole component. */
html[data-season="halloween"]{
  --up:#f0932b;      /* pumpkin  */
  --down:#7a4bb0;    /* deep violet — cool against the orange */
}
html[data-season="christmas"]{
  --up:#1c7a41;      /* fir      */
  --down:#c8323c;    /* holly red — already the natural pair */
}
html[data-season="patricks"]{
  --up:#17a04a;      /* shamrock */
  --down:#9a6b16;    /* dark gold, reads clearly against the green */
}
html[data-season="valentines"]{
  --up:#e2547d;      /* rose     */
  --down:#8e2447;    /* deep wine — same family, clearly darker */
}

/* The thumb glyphs are images on some cards, so tint those to match. */
html[data-season] .vote-btn.active.upvote   img{ filter:brightness(0) invert(1); }
html[data-season] .vote-btn.active.downvote img{ filter:brightness(0) invert(1); }


/* ══════════════════════════════════════════════════════════════════════
   LITE MODE — every page that isn't the feed
   ──────────────────────────────────────────────────────────────────────
   Palette, branding and wordmark only. The decorations are explicitly
   hidden here rather than merely not built, so that if a future page ever
   loads the full script by accident it still can't sprout pumpkins.
   ══════════════════════════════════════════════════════════════════════ */
html[data-season-mode="lite"] #ssLights,
html[data-season-mode="lite"] #ssSprites,
html[data-season-mode="lite"] #ssFall,
html[data-season-mode="lite"] #ssFallBg,
html[data-season-mode="lite"] #ssGreet{ display:none !important; }

/* The rainbow is a single static gradient, so it's cheap enough to keep
   as a backdrop on the quieter pages too. */
html[data-season-mode="lite"] #ssRainbow{ opacity:.16; }

/* Page furniture that only exists outside the feed. */
html[data-season] .back-btn,
html[data-season] .create-btn{ border-color:var(--accent) !important; }
html[data-season] .hero-title,
html[data-season] .subs-header,
html[data-season] .page-title{ color:var(--text); }
html[data-season] .take-on-btn{
  background:var(--season-band, var(--accent)) !important;
}
html[data-season] .challenge-card,
html[data-season] .about-card,
html[data-season] .tag-chip:hover{ border-color:var(--accent); }
/* Removed the old unscoped `html[data-season] a{ color:var(--accent); }`
   rule — it matched EVERY anchor tag sitewide, including standalone
   branded buttons like the Join Discord badge that are semantically <a>
   but styled to look nothing like an inline link. The properly scoped
   version (content links inside cards/panels only) already exists
   further down. */

/* ══════════════════════════════════════════════════════════════════════
   PAGE-SPECIFIC THEMING — challenges, profile, thread
   ──────────────────────────────────────────────────────────────────────
   The token overrides already recolour the page ground and text on every
   page. These reach the parts that hardcode their own colours, so the
   three busiest pages feel themed rather than just re-tinted.

   Everything here is scoped to html[data-season], so it costs nothing on
   an ordinary day.
   ══════════════════════════════════════════════════════════════════════ */

/* ── Shared surfaces ──────────────────────────────────────────────── */
html[data-season] .challenge-card,
html[data-season] .medal-card,
html[data-season] .award-card,
html[data-season] .report-card,
html[data-season] .mod-popup,
html[data-season] .dropdown-menu,
html[data-season] .empty-thread,
html[data-season] .modal{
  background:var(--card);
  border-color:var(--border);
  color:var(--text);
}

/* Tabs and pills pick up the season accent when active. */
/* Recolour only. These tabs are underlined, not filled — giving them a
   background changed their shape, which is why Ongoing/Previous stopped
   looking like the rest of the site. */
html[data-season] .tab-btn.active,
html[data-season] .medal-tab-btn.active,
html[data-season] .sub-tab-bar .active{
  color:var(--accent) !important;
  border-bottom-color:var(--accent) !important;
}
html[data-season] .tab-bar,
html[data-season] .sub-tab-bar,
html[data-season] .medal-tab-btn{ border-color:var(--border); }

/* ── Challenges ───────────────────────────────────────────────────── */
html[data-season] .challenges-hero{
  background:var(--season-band, var(--accent)) !important;
  border:2px solid var(--text);
  border-radius:var(--r,12px);
  color:#fff;
  box-shadow:4px 4px 0 var(--text);
}
html[data-season] .challenges-hero h1,
html[data-season] .challenges-hero p{ color:#fff; }
html[data-season] .challenge-card:hover{
  border-color:var(--accent);
  box-shadow:4px 4px 0 var(--accent);
}
html[data-season] .challenge-timer{
  background:color-mix(in srgb, var(--accent) 16%, transparent);
  color:var(--accent);
  border-radius:var(--radius-pill, 999px);
}
html[data-season] .challenge-winner{ border-color:var(--accent); }
html[data-season] .medal-showcase{ background:color-mix(in srgb, var(--accent) 9%, transparent); }

/* ── Profile ──────────────────────────────────────────────────────── */
/* A wash of the season over the banner, so the page reads themed even on
   a profile whose own cover art is a completely different palette. */
html[data-season] .banner-overlay{
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 26%, transparent) 0%,
    transparent 46%,
    color-mix(in srgb, var(--text) 42%, transparent) 100%);
}
html[data-season] .profile-tab.active,
html[data-season] .following{
  background:var(--accent) !important;
  border-color:var(--accent) !important;
  color:#fff !important;
}
html[data-season] .award-title,
html[data-season] .medal-title{ color:var(--accent); }
/* The real class names on the profile are .p-stat / .stat-lbl / .stat-tab
   — .stat-value and .stat-label don't exist there. */
/* Handled in the readability block at the end — setting these from the
   page tokens put dark text on the dark stats bar. */
html[data-season] .stat-tab.active{
  background:var(--accent) !important;
  border-color:var(--accent) !important;
  color:#fff !important;
}
html[data-season] .profile-stats-bar{ border-color:var(--border); }

/* ── Thread ───────────────────────────────────────────────────────── */
/* The chain down the side of a thread is the page's strongest structural
   line, so tinting it does more than recolouring any single control. */
html[data-season] .chain-connector{
  background:linear-gradient(180deg, var(--accent), var(--season-2, var(--accent)));
}
html[data-season] .post-image-wrap{ border-color:var(--border); }
html[data-season] .locked-badge{
  background:var(--accent) !important; color:#fff !important;
}
html[data-season] .bookmark-btn.active,
html[data-season] .copy-btn:hover{ color:var(--accent); border-color:var(--accent); }
html[data-season] .hidden-overlay{
  background:color-mix(in srgb, var(--text) 88%, transparent);
}
html[data-season] .hidden-overlay-view-btn{
  background:var(--accent); border-color:var(--accent); color:#fff;
}

/* ── Shared: the sketchy shadow follows the accent on hover ───────── */
html[data-season] .back-btn:hover,
html[data-season] .create-btn:hover,
html[data-season] .draw-btn:hover{ box-shadow:3px 3px 0 var(--accent); }

/* ══════════════════════════════════════════════════════════════════════
   EXTRA FLAIR — thread, profile, challenges
   ──────────────────────────────────────────────────────────────────────
   These pages hardcode a blue (rgba(107,107,255,…)) for their remix
   controls, so they stayed stubbornly blue under every theme. Overriding
   those explicitly is what makes the pages feel seasonal rather than
   merely re-tinted around the edges.
   ══════════════════════════════════════════════════════════════════════ */

/* ── Thread: remix controls ───────────────────────────────────────── */
html[data-season] .remix-cta{
  background:linear-gradient(135deg,
    color-mix(in srgb, var(--accent) 12%, var(--card)),
    var(--card));
  border:2px solid var(--accent);
  box-shadow:3px 3px 0 color-mix(in srgb, var(--accent) 45%, transparent);
}
html[data-season] .remix-cta-btn{
  background:var(--season-band, var(--accent)) !important;
  color:#fff !important;
  border:2px solid var(--text) !important;
  box-shadow:3px 3px 0 var(--text);
  transition:transform .1s, box-shadow .1s;
}
html[data-season] .remix-cta-btn:hover{
  transform:translate(-1px,-1px);
  box-shadow:4px 4px 0 var(--text);
}
html[data-season] .remix-cta-btn:active{
  transform:translate(1px,1px);
  box-shadow:1px 1px 0 var(--text);
}
html[data-season] .remix-btn{
  background:color-mix(in srgb, var(--accent) 12%, transparent) !important;
  border-color:color-mix(in srgb, var(--accent) 45%, transparent) !important;
  color:var(--accent) !important;
}
html[data-season] .remix-btn:hover{
  background:color-mix(in srgb, var(--accent) 22%, transparent) !important;
}
html[data-season] .remix-label{ color:var(--accent) !important; }
html[data-season] .remix-presence-dot{ background:var(--accent) !important; }

/* The post a thread branches from gets a coloured spine, so the shape of
   the conversation reads at a glance. */
html[data-season] .post-card{ position:relative; }
html[data-season] .post-card::before{
  content:''; position:absolute; left:0; top:0; bottom:0; width:3px;
  background:linear-gradient(180deg, var(--accent), var(--season-2, var(--accent)));
  border-radius:var(--r,12px) 0 0 var(--r,12px);
  opacity:.85; pointer-events:none;
}

/* ── Profile ──────────────────────────────────────────────────────── */
html[data-season] .profile-name{ color:var(--text); }
html[data-season] .follow-btn{
  background:var(--season-band, var(--accent)) !important;
  border-color:var(--text) !important;
  color:#fff !important;
}
html[data-season] .medal-slot{
  border-color:color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow:0 0 0 2px color-mix(in srgb, var(--accent) 18%, transparent);
}
/* A soft seasonal glow behind the avatar, so the identity area picks up
   the theme without covering anyone's own picture. */
/* The class is .profile-avatar — .profile-pic-wrap doesn't exist here.
   A ring rather than a glow, since the avatar has no wrapper to sit a
   backdrop behind. */
html[data-season] .profile-avatar{
  box-shadow:0 0 0 3px var(--accent),
             0 0 0 6px color-mix(in srgb, var(--accent) 30%, transparent);
}

/* ── Challenges ───────────────────────────────────────────────────── */
html[data-season] .challenge-meta,
html[data-season] .creator{ color:var(--text2); }
html[data-season] .creator strong,
html[data-season] .creator b{ color:var(--accent); }
html[data-season] .empty-state{
  border:2px dashed color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius:var(--r,12px);
  color:var(--text2);
}
/* Corner flash on each challenge card — a small nod rather than a wash. */
html[data-season] .challenge-card{ position:relative; overflow:hidden; }
html[data-season] .challenge-card::after{
  content:''; position:absolute; top:-26px; right:-26px;
  width:64px; height:64px; transform:rotate(45deg);
  background:var(--season-band, var(--accent));
  opacity:.9; pointer-events:none;
}


/* ══════════════════════════════════════════════════════════════════════
   PAGE GROUND
   ──────────────────────────────────────────────────────────────────────
   The standalone pages set `body{background:var(--color-line)}` — a fixed
   token that no theme touches — rather than var(--bg). That is why the
   feed changed colour and every other page stayed grey. Setting it here
   is the single change that makes the themes visible site-wide.
   ══════════════════════════════════════════════════════════════════════ */
html[data-season] body{
  background:var(--bg) !important;
  color:var(--text);
}
html[data-season] nav{
  background:var(--nav-bg) !important;
  border-bottom-color:var(--border) !important;
}
/* Cards and panels that hardcode white. */
html[data-season] .challenge-card,
html[data-season] .post-card,
html[data-season] .sidebar-panel,
html[data-season] .sketch-card,
html[data-season] .tab-bar,
html[data-season] .sub-tab-bar{ background:var(--card) !important; }

/* ══════════════════════════════════════════════════════════════════════
   READABILITY + NAV BUTTONS
   ══════════════════════════════════════════════════════════════════════ */

/* ── Halloween: text on a dark ground ─────────────────────────────────
   The page tokens flip --text to a pale ink, but several components set
   their own dark colour, so on Halloween they became black-on-black.
   These pin them to something readable. */
html[data-season="halloween"] .challenge-title,
html[data-season="halloween"] .challenges-hero h1,
html[data-season="halloween"] .hero-title,
html[data-season="halloween"] .profile-name,
html[data-season="halloween"] .feed-title,
html[data-season="halloween"] .sidebar-title,
html[data-season="halloween"] .post-title{ color:#f4ecf7 !important; }

html[data-season="halloween"] .challenge-card,
html[data-season="halloween"] .post-card,
html[data-season="halloween"] .sidebar-panel,
html[data-season="halloween"] .sketch-card{ color:#f4ecf7; }
html[data-season="halloween"] .challenge-meta,
html[data-season="halloween"] .creator,
html[data-season="halloween"] .stat-lbl{ color:#bda8c9 !important; }
html[data-season="halloween"] .creator strong,
html[data-season="halloween"] .creator b{ color:#f0932b !important; }

/* Inactive tabs were near-black on the dark ground — unreadable until
   selected. Purple keeps them clearly secondary but legible. */
html[data-season="halloween"] .tab-btn,
html[data-season="halloween"] .medal-tab-btn,
html[data-season="halloween"] .stat-tab{ color:#b06adf !important; }
html[data-season="halloween"] .tab-btn:hover,
html[data-season="halloween"] .medal-tab-btn:hover{ color:#d8b3f0 !important; }
html[data-season="halloween"] .tab-btn.active,
html[data-season="halloween"] .medal-tab-btn.active,
html[data-season="halloween"] .stat-tab.active{
  color:#f0932b !important;
  border-bottom-color:#f0932b !important;
}

/* ── Nav buttons take the season ──────────────────────────────────────
   Create Challenge and Back to Feed are the two controls always visible
   in the nav, so leaving them neutral made the bar look untouched even
   once everything around it was themed. */
html[data-season] .create-btn{
  background:var(--season-band, var(--accent)) !important;
  border:2px solid var(--text) !important;
  color:#fff !important;
  box-shadow:3px 3px 0 var(--text) !important;
  transition:transform .1s, box-shadow .1s;
}
html[data-season] .create-btn:hover{
  transform:translate(-1px,-1px);
  box-shadow:4px 4px 0 var(--text) !important;
}
html[data-season] .create-btn:active{
  transform:translate(1px,1px);
  box-shadow:1px 1px 0 var(--text) !important;
}

/* Back to Feed stays the quieter of the two — outlined rather than
   filled, so the primary action still leads. */
html[data-season] .back-btn{
  background:var(--card) !important;
  border:2px solid var(--accent) !important;
  color:var(--accent) !important;
  box-shadow:3px 3px 0 var(--accent) !important;
  transition:transform .1s, box-shadow .1s;
}
html[data-season] .back-btn:hover{
  background:color-mix(in srgb, var(--accent) 12%, var(--card)) !important;
  transform:translate(-1px,-1px);
}
html[data-season] .back-btn:active{
  transform:translate(1px,1px);
  box-shadow:1px 1px 0 var(--accent) !important;
}

/* Halloween's card surface is dark, so the outlined button needs its own
   fill to stay legible. */
html[data-season="halloween"] .back-btn{
  background:#2e2138 !important;
  color:#f0932b !important;
  border-color:#f0932b !important;
  box-shadow:3px 3px 0 #f0932b !important;
}


/* ══════════════════════════════════════════════════════════════════════
   SEASONAL MASCOT
   ──────────────────────────────────────────────────────────────────────
   santa · bag · leprechaun · heart, one per season. Parks in the
   bottom-right corner, sliding in from off-screen and back out again on
   a timer.

   #ssMascot is a WRAPPER (not the image itself) so Halloween's candy
   counter can ride along as part of the same assembly and slide in/out
   with the bag, instead of being a separate fixture pinned elsewhere.
   Every other season just has one child — the image — and looks
   identical to before.

   Positioned with transform rather than `right`, so the slide is a
   compositor-only animation and never triggers layout — the same reason
   the drifting sprites move this way.
   ══════════════════════════════════════════════════════════════════════ */
#ssMascot{
  position:fixed;
  right:16px;
  bottom:16px;
  z-index:70;
  display:flex; flex-direction:column; align-items:center; gap:6px;
  /* Interactive, so hovering can shoo it away. It sits above the compose
     button rather than over it, so nothing underneath is blocked. */
  pointer-events:auto;
  cursor:pointer;
  user-select:none; -webkit-user-drag:none;
  /* Parked off-screen until its turn. */
  transform:translateX(calc(100% + 26px));
  transition:transform .85s cubic-bezier(.22,1,.36,1);
}
#ssMascot.in{ transform:translateX(0); }
#ssMascot .ssMascotImg{ width:190px; height:auto; display:block; }

/* Clear of the compose button, which lives in the same corner. */
html[data-season] #ssMascot{ bottom:112px; }

/* Per-season sizing, on the IMAGE now rather than the wrapper — the
   wrapper shrinks to fit its content instead. The artwork isn't drawn at
   a common scale, so one width made some characters loom and others get
   lost; these bring them to roughly equal presence on screen. Halloween
   is sized up from where it sat as a bare mascot before, now that it's
   carrying the counter and isn't competing with a permanent bottom-left
   fixture any more. */
html[data-season="halloween"]  #ssMascot .ssMascotImg{ width:180px; }
html[data-season="christmas"]  #ssMascot .ssMascotImg{ width:172px; }
html[data-season="patricks"]   #ssMascot .ssMascotImg{ width:220px; }
html[data-season="valentines"] #ssMascot .ssMascotImg{ width:205px; }

/* ── Candy counter, riding along on the bag ───────────────────────────
   Sketchy chip treatment — black border, hard shadow, PunkKid — sized to
   match the bigger mascot rather than the small standalone pill it used
   to be. Part of the same slide-in assembly, so it only shows when the
   bag itself is visiting, and hovering either dismisses both together. */
#ssCandyBag{
  display:flex; align-items:center;
  padding:9px 20px;
  background:var(--card); border:2px solid var(--text);
  border-radius:999px;
  box-shadow:3px 3px 0 var(--text);
}
#ssCandyBag span{
  font-family:var(--font-display); font-weight:400;
  font-size:28px; line-height:1; letter-spacing:.3px;
  color:var(--text);
  min-width:1ch;
}
/* A little bounce every time a piece drops in, so the count doesn't just
   silently tick over. */
#ssCandyBag.bump{ animation:ssCandyBump .38s ease; }
@keyframes ssCandyBump{
  0%   { transform:scale(1); }
  35%  { transform:scale(1.15) rotate(-3deg); }
  65%  { transform:scale(.97) rotate(2deg); }
  100% { transform:scale(1); }
}
@media (prefers-reduced-motion: reduce){
  #ssCandyBag.bump{ animation:none; }
}

/* On a phone, vmax follows the HEIGHT, so a 112vmax arc anchored to the
   bottom-right fell almost entirely off-screen. Sizing from vw instead —
   and anchoring lower and more centrally — keeps a real band of colour
   visible, at a higher opacity to survive the smaller area. */
@media (max-width:640px){
  /* Off entirely on phones. A 190vw arc still only showed a sliver, and
     scaling it further meant a huge texture for almost no colour. It
     appears in the drawer instead, where it has a defined space to sit
     in — see the drawer rules below. */
  #ssRainbow{ display:none !important; }

  #ssMascot .ssMascotImg{ width:132px; }
  #ssMascot{ right:10px; }
  html[data-season="halloween"]  #ssMascot .ssMascotImg{ width:126px; }
  html[data-season="christmas"]  #ssMascot .ssMascotImg{ width:120px; }
  html[data-season="patricks"]   #ssMascot .ssMascotImg{ width:152px; }
  html[data-season="valentines"] #ssMascot .ssMascotImg{ width:142px; }
  html[data-season] #ssMascot{ bottom:104px; }

  #ssCandyBag{ padding:7px 15px; }
  #ssCandyBag span{ font-size:20px; }
}

/* Never on the quieter pages, and never when motion is unwelcome. */
html[data-season-mode="lite"] #ssMascot{ display:none !important; }
@media (prefers-reduced-motion: reduce){
  #ssMascot{ display:none !important; }
}


/* ══════════════════════════════════════════════════════════════════════
   PROFILE BANNER LEGIBILITY
   ──────────────────────────────────────────────────────────────────────
   The name and stats sit over whatever cover image a user has uploaded,
   so no colour can be guaranteed to read against it. A glow solves what
   a colour change cannot: a dark halo behind light text stays legible on
   a pale cover, and the seasonal tint on top of it keeps it themed.
   ══════════════════════════════════════════════════════════════════════ */
html[data-season] .profile-name{
  color:#ffffff !important;
  text-shadow:
    0 0 3px rgba(0,0,0,.85),          /* tight halo — carries the contrast */
    0 1px 6px rgba(0,0,0,.7),
    0 0 18px color-mix(in srgb, var(--accent) 85%, transparent),
    0 0 34px color-mix(in srgb, var(--accent) 55%, transparent);
}

/* The stats bar is a dark surface, so these want light text, not the
   page's ink. The accent glow ties them to the season without hurting
   contrast the way a coloured fill would. */
html[data-season] .p-stat{
  color:#ffffff !important;
  text-shadow:
    0 1px 3px rgba(0,0,0,.75),
    0 0 12px color-mix(in srgb, var(--accent) 70%, transparent);
}
html[data-season] .p-stat b,
html[data-season] .p-stat strong{ color:#ffffff !important; }

html[data-season] .stat-lbl{
  color:rgba(255,255,255,.82) !important;
  text-shadow:0 1px 3px rgba(0,0,0,.7);
}

/* Anything else riding on the cover gets the same treatment. */
html[data-season] .banner-content .profile-handle,
html[data-season] .banner-content .profile-bio{
  color:rgba(255,255,255,.92) !important;
  text-shadow:0 1px 4px rgba(0,0,0,.8);
}

/* Halloween's ground is dark to begin with, so the halo can be softer and
   the accent does more of the work. */
html[data-season="halloween"] .profile-name{
  text-shadow:
    0 0 3px rgba(0,0,0,.7),
    0 0 16px rgba(240,147,43,.9),
    0 0 32px rgba(176,106,223,.6);
}

/* ══════════════════════════════════════════════════════════════════════
   REMAINING SURFACES — follow button, search, popups, mobile drawer
   ══════════════════════════════════════════════════════════════════════ */

/* ── Follow / following ───────────────────────────────────────────── */
html[data-season] .follow-btn,
html[data-season] .follow-button,
html[data-season] button.follow{
  background:var(--season-band, var(--accent)) !important;
  border:2px solid var(--text) !important;
  color:#fff !important;
  box-shadow:3px 3px 0 var(--text) !important;
}
/* Already-following is the quieter state, so it stays outlined. */
html[data-season] .follow-btn.following,
html[data-season] .follow-btn.is-following,
html[data-season] .following{
  background:var(--card) !important;
  color:var(--accent) !important;
  border-color:var(--accent) !important;
  box-shadow:3px 3px 0 color-mix(in srgb, var(--accent) 50%, transparent) !important;
}

/* ── Search field and its panel ───────────────────────────────────── */
html[data-season] #searchWrap,
html[data-season] #searchBarShell,
html[data-season] #searchPanel,
html[data-season] #fullSearchOverlayInner{
  background:var(--card) !important;
  border-color:var(--accent) !important;
  color:var(--text) !important;
}
html[data-season] #searchBtn,
html[data-season] #fsInput{ color:var(--text) !important; }
html[data-season] #searchBtn::placeholder,
html[data-season] #fsInput::placeholder{ color:var(--text3) !important; }
html[data-season] #searchPanelBody .sp-item:hover,
html[data-season] .fs-result:hover{
  background:color-mix(in srgb, var(--accent) 12%, transparent) !important;
}
html[data-season] .sp-expand{
  background:color-mix(in srgb, var(--accent) 10%, var(--card)) !important;
  color:var(--accent) !important;
  border-top-color:var(--border) !important;
}
html[data-season] #fullSearchOverlayHead{
  background:var(--card) !important;
  border-bottom-color:var(--accent) !important;
  color:var(--text) !important;
}
html[data-season] .fs-chip{
  background:var(--card) !important;
  border-color:var(--accent) !important;
  color:var(--text) !important;
}

/* ── Notification and report popups ───────────────────────────────── */
html[data-season] #notifPanel,
html[data-season] #modPanel,
html[data-season] .mod-popup,
html[data-season] .notif-panel{
  background:var(--card) !important;
  border-color:var(--accent) !important;
  color:var(--text) !important;
}
html[data-season] #notifPanel .notif-panel-head,
html[data-season] #modPanel .mod-panel-head{
  background:var(--season-band, var(--accent)) !important;
  border-bottom-color:var(--border) !important;
}
/* Only the TITLE goes white. A blanket rule on the header's children also
   hit "Clear all" and "Mark all read", which carry their own white fill —
   white text on a white button. */
html[data-season] .notif-panel-title,
html[data-season] .mod-panel-title{ color:#fff !important; }
html[data-season] .notif-item,
html[data-season] .mod-item{ border-bottom-color:var(--border) !important; }
html[data-season] .notif-item:hover,
html[data-season] .mod-item:hover{
  background:color-mix(in srgb, var(--accent) 10%, transparent) !important;
}
html[data-season] .notif-item.unread{
  background:color-mix(in srgb, var(--accent) 16%, transparent) !important;
}

/* ── Mobile drawer ────────────────────────────────────────────────── */
html[data-season] .m-drawer{
  background:var(--card) !important;
  border-left-color:var(--accent) !important;
  color:var(--text) !important;
}
html[data-season] .m-drawer-head{
  background:var(--season-band, var(--accent)) !important;
  color:#fff !important;
}
html[data-season] .m-drawer-head .m-drawer-name,
html[data-season] .m-drawer-head .m-drawer-handle,
html[data-season] .m-drawer-head .m-drawer-stat{ color:#fff !important; }
html[data-season] .m-drawer-nav a,
html[data-season] .m-drawer-nav button{ color:var(--text) !important; }
html[data-season] .m-drawer-nav a:active,
html[data-season] .m-drawer-nav a:hover{
  background:color-mix(in srgb, var(--accent) 12%, transparent) !important;
}
html[data-season] .m-drawer-av{
  border-color:#fff !important;
  box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 45%, transparent);
}
html[data-season] .m-drawer-legal{ border-top-color:var(--border) !important; }
html[data-season] .m-drawer-legal-row a,
html[data-season] .m-drawer-legal-copy{ color:var(--text2) !important; }
html[data-season] .m-drawer-scrim{
  background:color-mix(in srgb, var(--text) 55%, transparent) !important;
}

/* ══════════════════════════════════════════════════════════════════════
   MOBILE DRAWER — readability + the rainbow's new home
   ══════════════════════════════════════════════════════════════════════ */

/* The drawer header was the season gradient at full strength, which put
   dark text on heavily saturated colour. Two fixes together: the gradient
   is muted, and the text is explicitly white with a shadow so it holds up
   regardless of which part of the gradient sits behind it. */
html[data-season] .m-drawer-head{
  background:
    linear-gradient(180deg, rgba(0,0,0,.22), rgba(0,0,0,.34)),
    var(--season-band, var(--accent)) !important;
  background-blend-mode:multiply;
  color:#fff !important;
}
html[data-season] .m-drawer-head .m-drawer-name,
html[data-season] .m-drawer-head .m-drawer-handle,
html[data-season] .m-drawer-head .m-drawer-stat,
html[data-season] .m-drawer-head .m-drawer-stat b,
html[data-season] .m-drawer-head .m-drawer-stat span{
  color:#fff !important;
  text-shadow:0 1px 3px rgba(0,0,0,.55);
}

/* St Patrick's and Valentine's are the lightest gradients, so they need
   the most help before white text is comfortable on them. */
html[data-season="patricks"] .m-drawer-head,
html[data-season="valentines"] .m-drawer-head{
  background:
    linear-gradient(180deg, rgba(0,0,0,.3), rgba(0,0,0,.42)),
    var(--season-band, var(--accent)) !important;
}

/* ── The rainbow, in the drawer ────────────────────────────────────────
   A band across the top of the drawer on St Patrick's. It reads clearly
   here because it has a bounded space rather than being a huge arc mostly
   off the side of a phone screen. */
html[data-season="patricks"] .m-drawer-head{ position:relative; overflow:hidden; }
html[data-season="patricks"] .m-drawer-head::after{
  content:''; position:absolute; left:-20%; right:-20%; bottom:-118%;
  height:200%; border-radius:50%;
  pointer-events:none; opacity:.55;
  background:url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'>\
<g fill='none' stroke-width='9'>\
<circle cx='100' cy='100' r='92' stroke='%23e2453c'/>\
<circle cx='100' cy='100' r='83' stroke='%23ef8f2a'/>\
<circle cx='100' cy='100' r='74' stroke='%23f4d03f'/>\
<circle cx='100' cy='100' r='65' stroke='%233fae5a'/>\
<circle cx='100' cy='100' r='56' stroke='%233f7fd6'/>\
<circle cx='100' cy='100' r='47' stroke='%238a5bc4'/>\
</g></svg>") no-repeat center top;
  background-size:100% 100%;
}
/* Keep the account details above the arc. */
html[data-season="patricks"] .m-drawer-head > *{ position:relative; z-index:1; }

/* ══════════════════════════════════════════════════════════════════════
   MOBILE DRAWER — rainbow backdrop + readable header
   ══════════════════════════════════════════════════════════════════════ */

/* St Patrick's: the arc moves in here, where a tall narrow panel suits it
   far better than a phone viewport did. */
/* NO position here. The drawer is position:fixed and slides in with a
   transform; setting position:relative overrode that, so it stopped being
   an overlay and tapping the avatar showed only the scrim. A fixed element
   is already a containing block, so ::before positions against it fine. */
html[data-season="patricks"] .m-drawer{
  overflow:hidden;
}
html[data-season="patricks"] .m-drawer::before{
  content:'';
  position:absolute; left:-45%; bottom:-50%;
  width:190%; height:100%;
  pointer-events:none; z-index:0; opacity:.28;
  background-repeat:no-repeat; background-position:center; background-size:100% 100%;
  background-image:url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'>\
<g fill='none' stroke-width='9'>\
<circle cx='100' cy='100' r='92' stroke='%23e2453c'/>\
<circle cx='100' cy='100' r='83' stroke='%23ef8f2a'/>\
<circle cx='100' cy='100' r='74' stroke='%23f4d03f'/>\
<circle cx='100' cy='100' r='65' stroke='%233fae5a'/>\
<circle cx='100' cy='100' r='56' stroke='%233f7fd6'/>\
<circle cx='100' cy='100' r='47' stroke='%238a5bc4'/>\
</g></svg>");
}
/* Everything in the drawer sits above the arc. */
html[data-season="patricks"] .m-drawer > *{ position:relative; z-index:1; }

/* ── Header legibility ────────────────────────────────────────────────
   A full-strength gradient behind dark text was unreadable. Muted to
   about half strength over the card colour, and the text pinned light
   with a shadow, so it holds up whichever season is running. */
html[data-season] .m-drawer-head{
  background:
    linear-gradient(color-mix(in srgb, var(--card) 42%, transparent),
                    color-mix(in srgb, var(--card) 42%, transparent)),
    var(--season-band, var(--accent)) !important;
  color:#fff !important;
}
html[data-season] .m-drawer-head span,
html[data-season] .m-drawer-head b,
html[data-season] .m-drawer-head div:not([class*="btn"]),
html[data-season] .m-drawer-head a:not([class*="btn"]){
  color:#fff !important;
  text-shadow:0 1px 3px rgba(0,0,0,.55);
}

/* ══════════════════════════════════════════════════════════════════════
   LAYERING — glows stay under every popup
   ──────────────────────────────────────────────────────────────────────
   The banner glows are wide (up to 34px), so they bleed past the banner
   and can end up sitting over anything opened from the nav. Two fixes:
   the glows are tightened, and every popup is given an explicit layer
   well above the banner so it can never be overlapped.
   ══════════════════════════════════════════════════════════════════════ */
html[data-season] #notifPanel,
html[data-season] #notifWrap,
html[data-season] #modPanel,
html[data-season] #modWrap,
html[data-season] #navDropdown,
html[data-season] #searchPanel,
html[data-season] #fullSearchOverlay,
html[data-season] .dropdown-menu,
html[data-season] .mod-popup,
html[data-season] .modal,
html[data-season] .award-card,
html[data-season] .medal-card{ z-index:12000 !important; }

/* The nav itself has to outrank the banner too, or a popup anchored to it
   inherits the wrong stacking context. */
html[data-season] body > nav,
html[data-season] nav{ z-index:11000 !important; }

/* The drawing page's undo/redo pill is DESIGNED to overlap the fixed nav
   band — style.css gives the nav z-index:50 and the pill 60, with a
   comment saying exactly that. The site-wide nav override above pushes
   the nav to 11000, so the pill needs to clear that to stay visible, but
   only just: an earlier attempt used 11500 for both this and the animate
   toggle, which lifted them above genuinely-higher UI like modals and
   made the pill appear to float over scrolling content.

   11001 keeps the original relationship (pill exactly one layer above
   the nav) without outranking anything else. */
html[data-season] #midicons,
html[data-season] #animToggleBtn{ z-index:11001 !important; }

/* Its background is a hardcoded #fff in style.css, so it stayed white on
   every theme regardless of z-index. Position is re-asserted because two
   mobile media queries in index.html set it to `static`, and without
   restating it here the desktop rule could lose to those on a short
   viewport. */
html[data-season] #midicons{
  position:fixed !important;
  background:var(--card) !important;
  box-shadow:0 6px 10px -2px rgba(0,0,0,.4) !important;
}

/* Banner furniture explicitly BELOW all of that. */
html[data-season] .banner-content{ z-index:2 !important; }
html[data-season] .banner-overlay{ z-index:1 !important; }
html[data-season] .profile-avatar{ position:relative; z-index:2; }

/* Tighter glows — enough to lift text off a busy cover, not enough to
   spill into neighbouring UI. */
html[data-season] .profile-name{
  text-shadow:
    0 0 3px rgba(0,0,0,.85),
    0 1px 5px rgba(0,0,0,.7),
    0 0 12px color-mix(in srgb, var(--accent) 80%, transparent) !important;
}
html[data-season] .p-stat{
  text-shadow:
    0 1px 3px rgba(0,0,0,.75),
    0 0 8px color-mix(in srgb, var(--accent) 60%, transparent) !important;
}

/* Halloween: purple rather than the white halo, which read as a glare
   against the dark ground. */
html[data-season="halloween"] .profile-name{
  color:#f4ecf7 !important;
  text-shadow:
    0 0 3px rgba(0,0,0,.9),
    0 0 10px rgba(176,106,223,.95),
    0 0 20px rgba(140,74,190,.65) !important;
}
html[data-season="halloween"] .p-stat{
  color:#f0e4f7 !important;
  text-shadow:
    0 1px 3px rgba(0,0,0,.85),
    0 0 9px rgba(176,106,223,.8) !important;
}
html[data-season="halloween"] .profile-avatar{
  box-shadow:0 0 0 3px #b06adf,
             0 0 0 6px rgba(176,106,223,.28) !important;
}

/* ══════════════════════════════════════════════════════════════════════
   HALLOWEEN — no dark text on dark surfaces
   ──────────────────────────────────────────────────────────────────────
   Halloween is the only theme with a dark ground, so it's the only one
   where a component that hardcodes its own near-black text goes
   unreadable. Patching them one at a time hasn't kept up — this covers
   the surfaces wholesale instead.

   The approach: inside any panel, card or popup, inherit a light ink by
   default. Elements that bring their OWN background (filled buttons,
   badges, chips) are excluded, because those already set a text colour
   that works against their own fill.
   ══════════════════════════════════════════════════════════════════════ */
html[data-season="halloween"] #notifPanel,
html[data-season="halloween"] #modPanel,
html[data-season="halloween"] #navDropdown,
html[data-season="halloween"] #searchPanel,
html[data-season="halloween"] #fullSearchOverlayInner,
html[data-season="halloween"] .m-drawer,
html[data-season="halloween"] .dropdown-menu,
html[data-season="halloween"] .mod-popup,
html[data-season="halloween"] .modal,
html[data-season="halloween"] .sidebar-panel,
html[data-season="halloween"] .sketch-card,
html[data-season="halloween"] .challenge-card,
html[data-season="halloween"] .post-card,
html[data-season="halloween"] .award-card,
html[data-season="halloween"] .medal-card,
html[data-season="halloween"] .empty-state{
  color:#f4ecf7 !important;
}

/* Descendants inherit that light ink — but only where they don't paint a
   background of their own. */
html[data-season="halloween"] #notifPanel *:not([class*="btn"]):not([class*="badge"]):not([class*="chip"]):not([class*="dot"]),
html[data-season="halloween"] #modPanel *:not([class*="btn"]):not([class*="badge"]):not([class*="chip"]):not([class*="dot"]),
html[data-season="halloween"] #navDropdown *:not([class*="btn"]):not([class*="badge"]),
html[data-season="halloween"] #searchPanel *:not([class*="btn"]):not([class*="chip"]),
html[data-season="halloween"] #fullSearchOverlayInner *:not([class*="btn"]):not([class*="chip"]),
html[data-season="halloween"] .m-drawer-nav *,
html[data-season="halloween"] .dropdown-menu *,
html[data-season="halloween"] .mod-popup *:not([class*="btn"]):not([class*="badge"]){
  color:#f4ecf7 !important;
}

/* Secondary text stays secondary — a muted lilac rather than the same
   full-strength ink, so hierarchy survives. */
html[data-season="halloween"] .notif-time,
html[data-season="halloween"] .mod-meta,
html[data-season="halloween"] .mod-reason,
html[data-season="halloween"] .notif-empty,
html[data-season="halloween"] .mod-empty,
html[data-season="halloween"] .sp-meta,
html[data-season="halloween"] .fs-meta,
html[data-season="halloween"] .m-drawer-legal-copy,
html[data-season="halloween"] .m-drawer-legal-row a{
  color:#bda8c9 !important;
}

/* Inputs need the same treatment — a dark caret on a dark field is just
   as unreadable as dark body text. */
html[data-season="halloween"] input,
html[data-season="halloween"] textarea,
html[data-season="halloween"] select{
  color:#f4ecf7 !important;
  background:#2e2138 !important;
  border-color:#4a3a58 !important;
}
html[data-season="halloween"] input::placeholder,
html[data-season="halloween"] textarea::placeholder{ color:#9a86a6 !important; }

/* Text sitting on the season's accent fill goes white — but NOT with a
   universal child selector. `.panel-head *` also caught the Clear all and
   Mark all read buttons, which carry their own white fill, so their label
   vanished. Only the titles and plain text are named. */
html[data-season="halloween"] .notif-panel-head,
html[data-season="halloween"] .notif-panel-title,
html[data-season="halloween"] .mod-panel-head,
html[data-season="halloween"] .mod-panel-title,
html[data-season="halloween"] .m-drawer-head,
html[data-season="halloween"] .m-drawer-head span,
html[data-season="halloween"] .m-drawer-head b,
html[data-season="halloween"] .m-drawer-head div:not([class*="btn"]){
  color:#ffffff !important;
}

/* ══════════════════════════════════════════════════════════════════════
   HALLOWEEN — search
   ──────────────────────────────────────────────────────────────────────
   The result rows hardcode #1c2230 (a near-black) rather than reading a
   token, so they stayed dark on the dark panel. The field itself also
   gets a lifted surface: on a dark theme a slightly raised fill reads as
   an input far better than a field the same colour as the bar it sits in.
   ══════════════════════════════════════════════════════════════════════ */
html[data-season="halloween"] #searchBarShell,
html[data-season="halloween"] #fsInputWrap{
  background:#2e2138 !important;
  border-color:#5a4468 !important;
}
html[data-season="halloween"] #searchBtn,
html[data-season="halloween"] #fsInput{
  color:#f4ecf7 !important;
  background:transparent !important;
}
html[data-season="halloween"] #searchBtn::placeholder,
html[data-season="halloween"] #fsInput::placeholder{ color:#a794b3 !important; }

/* The magnifier is an SVG stroked with currentColor. */
html[data-season="halloween"] #searchWrap svg,
html[data-season="halloween"] #fsInputWrap svg{ stroke:#f0932b !important; }

/* Result rows. */
html[data-season="halloween"] .sp-name,
html[data-season="halloween"] .fs-name,
html[data-season="halloween"] .sp-item,
html[data-season="halloween"] .fs-result{ color:#f4ecf7 !important; }
html[data-season="halloween"] .sp-sub,
html[data-season="halloween"] .fs-sub,
html[data-season="halloween"] .sp-empty,
html[data-season="halloween"] .fs-empty{ color:#bda8c9 !important; }
html[data-season="halloween"] .sp-group-title,
html[data-season="halloween"] .fs-section-title{ color:#f0932b !important; }
html[data-season="halloween"] .sp-item:hover,
html[data-season="halloween"] .fs-result:hover{
  background:rgba(240,147,43,.14) !important;
}
html[data-season="halloween"] .fs-chip{
  background:#2e2138 !important;
  border-color:#5a4468 !important;
  color:#f4ecf7 !important;
}
html[data-season="halloween"] .fs-chip.active{
  background:#f0932b !important; border-color:#f0932b !important; color:#1b1220 !important;
}
html[data-season="halloween"] #fsTabs button{ color:#bda8c9 !important; }
html[data-season="halloween"] #fsTabs button.active{
  color:#f0932b !important; border-bottom-color:#f0932b !important;
}
html[data-season="halloween"] .sp-expand{
  background:#2e2138 !important;
  color:#f0932b !important;
  border-top-color:#4a3a58 !important;
}

/* ══════════════════════════════════════════════════════════════════════
   HALLOWEEN — notification & report rows
   ──────────────────────────────────────────────────────────────────────
   Every one of these sets a hardcoded literal rather than a token:
   .notif-text #333, .mod-detail #555, the panel titles #1c2230. A rule
   targeting descendants generically can't beat a colour set directly on
   the element at equal specificity, which is why the headers went light
   earlier but the message text stayed black.

   Each is named explicitly here so there's nothing left to lose the tie.
   ══════════════════════════════════════════════════════════════════════ */
html[data-season="halloween"] .notif-text,
html[data-season="halloween"] .notif-body,
html[data-season="halloween"] .mod-item-body,
html[data-season="halloween"] .mod-detail{
  color:#f4ecf7 !important;
}
html[data-season="halloween"] .notif-text b,
html[data-season="halloween"] .notif-text strong,
html[data-season="halloween"] .mod-detail b,
html[data-season="halloween"] .mod-detail strong{
  color:#ffffff !important;
}

/* Timestamps and secondary lines: readable, but still clearly secondary. */
html[data-season="halloween"] .notif-time,
html[data-season="halloween"] .notif-empty,
html[data-season="halloween"] .mod-meta,
html[data-season="halloween"] .mod-empty{
  color:#bda8c9 !important;
}

/* The report reason keeps its warning red, just lifted enough to carry on
   a dark ground — #c0392b is too deep to read there. */
html[data-season="halloween"] .mod-reason{ color:#ff6b5e !important; }

/* Panel titles and their action buttons. */
html[data-season="halloween"] .notif-panel-title,
html[data-season="halloween"] .mod-panel-title{ color:#ffffff !important; }
html[data-season="halloween"] .notif-clear-btn,
html[data-season="halloween"] .mod-mark-all-btn{
  color:#ffffff !important;
  border-color:rgba(255,255,255,.45) !important;
}

/* Unread rows: a warm tint instead of the default pale highlight, which
   was invisible against the dark panel. */
html[data-season="halloween"] .notif-item.unread,
html[data-season="halloween"] .mod-item.unread{
  background:rgba(240,147,43,.16) !important;
}
html[data-season="halloween"] .mod-unread-dot{ background:#f0932b !important; }
html[data-season="halloween"] .notif-item,
html[data-season="halloween"] .mod-item{ border-bottom-color:#3a2a45 !important; }
html[data-season="halloween"] .notif-item:hover,
html[data-season="halloween"] .mod-item:hover{
  background:rgba(240,147,43,.1) !important;
}

/* .trending is a gold #8a5d00 with no background of its own, so it needs
   lifting on a dark ground. The badges are excluded on purpose: they
   carry their own light fill, where dark text is correct. */
html[data-season="halloween"] .trending{ color:#f2b632 !important; }

/* ══════════════════════════════════════════════════════════════════════
   CONTRAST PASS
   ──────────────────────────────────────────────────────────────────────
   From an audit of every hardcoded text colour against each theme's real
   surfaces, measured with the WCAG contrast formula rather than judged
   by eye. Only genuine failures are listed — gold and cream text sitting
   on its own dark modal (the medal award, the crown card) measures badly
   in isolation but is correct in place, so it's deliberately untouched.
   ══════════════════════════════════════════════════════════════════════ */

/* ── All themes: greys that are too light on a white card ────────────
   #aaa on white is 2.06:1 and #bbb is 1.70:1 — both well under the 4.5
   needed for body text. These are timestamps and empty states, so they
   should stay secondary, just not invisible. */
html[data-season="christmas"] .notif-time,
html[data-season="christmas"] .mod-meta,
html[data-season="christmas"] .notif-empty,
html[data-season="christmas"] .mod-empty,
html[data-season="patricks"] .notif-time,
html[data-season="patricks"] .mod-meta,
html[data-season="patricks"] .notif-empty,
html[data-season="patricks"] .mod-empty,
html[data-season="valentines"] .notif-time,
html[data-season="valentines"] .mod-meta,
html[data-season="valentines"] .notif-empty,
html[data-season="valentines"] .mod-empty{
  color:#6b7280 !important;          /* 5.0:1 on white — passes AA */
}
html[data-season] .empty-msg{ color:var(--text2) !important; }

/* ── Halloween: the two remaining dark-on-dark spots ───────────────── */
html[data-season="halloween"] #fullSearchOverlayHead,
html[data-season="halloween"] #fullSearchOverlayHead *{ color:#f4ecf7 !important; }
html[data-season="halloween"] .wc-rule{ color:#e8c98a !important; }

/* Halloween's own secondary greys, kept consistent with the lilac used
   everywhere else rather than drifting to a different muted tone. */
html[data-season="halloween"] .empty-msg,
html[data-season="halloween"] .sub-meta,
html[data-season="halloween"] .challenge-sub,
html[data-season="halloween"] .muted,
html[data-season="halloween"] .subtle,
html[data-season="halloween"] small{ color:#bda8c9 !important; }

/* Links inside cards need to read as links on every ground. */
html[data-season] .sketch-card a,
html[data-season] .post-card a,
html[data-season] .challenge-card a,
html[data-season] .sidebar-panel a{ color:var(--accent) !important; }
html[data-season="halloween"] .sketch-card a,
html[data-season="halloween"] .post-card a,
html[data-season="halloween"] .challenge-card a,
html[data-season="halloween"] .sidebar-panel a{ color:#f0932b !important; }

/* #a89a80 is a warm grey left over from the old cream palette — 2.3:1 on
   a white card, so these search empty-states and section labels were
   barely visible under the three light themes. */
html[data-season] .sp-empty,
html[data-season] .fs-empty,
html[data-season] .ta-empty,
html[data-season] .empty-msg,
html[data-season] .sp-section-title,
html[data-season] .fs-section-title{ color:var(--text2) !important; }

html[data-season="halloween"] .sp-empty,
html[data-season="halloween"] .fs-empty,
html[data-season="halloween"] .ta-empty{ color:#bda8c9 !important; }
html[data-season="halloween"] .sp-section-title,
html[data-season="halloween"] .fs-section-title{ color:#f0932b !important; }

/* The last holdouts, all sharing the same warm grey. Named individually
   because CSS can't select on a colour value — these are every selector
   in the codebase that sets #a89a80. */
html[data-season] .ta-section-label,
html[data-season] .ta-empty,
html[data-season] .tab-btn,
html[data-season] #fsTabs button:not(.active){ color:var(--text2) !important; }

html[data-season="halloween"] .ta-section-label,
html[data-season="halloween"] .ta-empty,
html[data-season="halloween"] .tab-btn,
html[data-season="halloween"] #fsTabs button:not(.active){ color:#bda8c9 !important; }

/* .restrict-item's green is fine on a dark ground but thin on white. */
html[data-season="christmas"] .restrict-item,
html[data-season="patricks"] .restrict-item,
html[data-season="valentines"] .restrict-item{ color:#177a38 !important; }
html[data-season="halloween"] .restrict-item{ color:#4fd97a !important; }


/* ── Header action buttons ────────────────────────────────────────────
   "Clear all" and "Mark all read" sit on the header's coloured band but
   keep a white fill of their own, so their text must stay dark. Earlier
   rules set them white along with the rest of the header, which made them
   invisible against their own background. */
html[data-season] .notif-clear-btn,
html[data-season] .mod-mark-all-btn{
  background:#ffffff !important;
  color:#1c2230 !important;
  border-color:#1c2230 !important;
}
html[data-season] .notif-clear-btn:hover,
html[data-season] .mod-mark-all-btn:hover{
  background:var(--card) !important;
  color:var(--accent) !important;
  border-color:var(--accent) !important;
}

/* Halloween keeps a dark button instead, so it doesn't punch a white hole
   in an otherwise dark panel — light text on a dark fill this time. */
html[data-season="halloween"] .notif-clear-btn,
html[data-season="halloween"] .mod-mark-all-btn{
  background:#2e2138 !important;
  color:#f4ecf7 !important;
  border-color:#f0932b !important;
}
html[data-season="halloween"] .notif-clear-btn:hover,
html[data-season="halloween"] .mod-mark-all-btn:hover{
  background:#3a2a45 !important;
  color:#f0932b !important;
}


/* ── New Year's: night-sky surfaces ───────────────────────────────────
   Same treatment as Halloween — a dark ground means anything that
   hardcodes near-black text goes unreadable, so the surfaces are covered
   wholesale rather than one component at a time. */
html[data-season="newyears"] #notifPanel,
html[data-season="newyears"] #modPanel,
html[data-season="newyears"] #navDropdown,
html[data-season="newyears"] #searchPanel,
html[data-season="newyears"] #fullSearchOverlayInner,
html[data-season="newyears"] .m-drawer,
html[data-season="newyears"] .dropdown-menu,
html[data-season="newyears"] .mod-popup,
html[data-season="newyears"] .modal,
html[data-season="newyears"] .sidebar-panel,
html[data-season="newyears"] .sketch-card,
html[data-season="newyears"] .challenge-card,
html[data-season="newyears"] .post-card{ color:#f2f2f4 !important; }

html[data-season="newyears"] .notif-text,
html[data-season="newyears"] .notif-body,
html[data-season="newyears"] .mod-item-body,
html[data-season="newyears"] .mod-detail,
html[data-season="newyears"] .sp-name,
html[data-season="newyears"] .fs-name,
html[data-season="newyears"] .challenge-title,
html[data-season="newyears"] .profile-name,
html[data-season="newyears"] .hero-title{ color:#f2f2f4 !important; }

html[data-season="newyears"] .notif-time,
html[data-season="newyears"] .mod-meta,
html[data-season="newyears"] .notif-empty,
html[data-season="newyears"] .mod-empty,
html[data-season="newyears"] .sp-sub,
html[data-season="newyears"] .fs-sub,
html[data-season="newyears"] .sp-empty,
html[data-season="newyears"] .fs-empty,
html[data-season="newyears"] .challenge-meta,
html[data-season="newyears"] .creator,
html[data-season="newyears"] .stat-lbl,
html[data-season="newyears"] .tab-btn,
html[data-season="newyears"] .ta-empty,
html[data-season="newyears"] .empty-msg{ color:#b9bcc4 !important; }

html[data-season="newyears"] .sp-section-title,
html[data-season="newyears"] .fs-section-title,
html[data-season="newyears"] .creator strong,
html[data-season="newyears"] .tab-btn.active,
html[data-season="newyears"] .stat-tab.active{ color:#e5c15a !important; }
html[data-season="newyears"] .tab-btn.active,
html[data-season="newyears"] .stat-tab.active{ border-bottom-color:#e5c15a !important; }

html[data-season="newyears"] input,
html[data-season="newyears"] textarea,
html[data-season="newyears"] select,
html[data-season="newyears"] #searchBarShell,
html[data-season="newyears"] #fsInputWrap{
  background:#202026 !important;
  color:#f2f2f4 !important;
  border-color:#3a3b44 !important;
}
html[data-season="newyears"] input::placeholder,
html[data-season="newyears"] #searchBtn::placeholder,
html[data-season="newyears"] #fsInput::placeholder{ color:#8b8e97 !important; }
html[data-season="newyears"] #searchBtn,
html[data-season="newyears"] #fsInput{ color:#f2f2f4 !important; }
html[data-season="newyears"] #searchWrap svg{ stroke:#e5c15a !important; }

html[data-season="newyears"] .notif-clear-btn,
html[data-season="newyears"] .mod-mark-all-btn{
  background:#202026 !important; color:#f2f2f4 !important; border-color:#e5c15a !important;
}
html[data-season="newyears"] .back-btn{
  background:#202026 !important; color:#e5c15a !important;
  border-color:#e5c15a !important; box-shadow:3px 3px 0 #e5c15a !important;
}
html[data-season="newyears"] .notif-item.unread{ background:rgba(229,193,90,.16) !important; }
html[data-season="newyears"] .sp-item:hover,
html[data-season="newyears"] .fs-result:hover{ background:rgba(229,193,90,.12) !important; }

/* Wordmark: gold and blue. */
html[data-season="newyears"] .nav-logo-text .ss-lg-a{ color:#e5c15a !important; }
html[data-season="newyears"] .nav-logo-text .ss-lg-b{ color:#c8ccd4 !important; }
html[data-season="newyears"] .nav-logo-text em{ color:#e5c15a !important; }

/* Artwork tint. */
html[data-season="newyears"] .sidebar-title-img,
html[data-season="newyears"] #notifBtn img,
html[data-season="newyears"] #modBtn img,
html[data-season="newyears"] .draw-btn img,
html[data-season="newyears"] #postSketchBtn img,
html[data-season="newyears"] #saveCanvasBtn img,
html[data-season="newyears"] .m-fab-draw img{ filter:url(#ssTintGold); }

/* Votes. */
/* Gold up, silver down — the arrows carry the meaning. */
html[data-season="newyears"]{ --up:#e5c15a; --down:#9aa0ab; }

/* Profile legibility on the night sky. */
html[data-season="newyears"] .profile-name{
  color:#ffffff !important;
  text-shadow:0 0 3px rgba(0,0,0,.85), 0 0 12px rgba(229,193,90,.9) !important;
}
html[data-season="newyears"] .profile-avatar{
  box-shadow:0 0 0 3px #e5c15a, 0 0 0 6px rgba(229,193,90,.3) !important;
}


/* ── New Year's: distant fireworks ────────────────────────────────────
   Static bursts painted into the background, in the same three tones as
   the rest of the theme — gold, silver and white. Radial gradients, so
   this is one paint and nothing animates. */
html[data-season="newyears"] body::before{
  content:''; position:fixed; inset:0; z-index:0; pointer-events:none;
  opacity:.6;
  background:
    radial-gradient(circle 3px at 18% 22%, rgba(229,193,90,.95), transparent 100%),
    radial-gradient(circle 92px at 18% 22%, rgba(229,193,90,.15), transparent 70%),
    radial-gradient(circle 2px at 74% 16%, rgba(200,204,212,.9), transparent 100%),
    radial-gradient(circle 72px at 74% 16%, rgba(200,204,212,.12), transparent 70%),
    radial-gradient(circle 2px at 46% 9%,  rgba(255,255,255,.85), transparent 100%),
    radial-gradient(circle 62px at 46% 9%, rgba(255,255,255,.09), transparent 70%),
    radial-gradient(circle 2px at 88% 40%, rgba(229,193,90,.8), transparent 100%),
    radial-gradient(circle 56px at 88% 40%, rgba(229,193,90,.1), transparent 70%),
    radial-gradient(circle 1px at 12% 62%, rgba(255,255,255,.5), transparent 100%),
    radial-gradient(circle 1px at 33% 38%, rgba(200,204,212,.42), transparent 100%),
    radial-gradient(circle 1px at 58% 71%, rgba(255,255,255,.45), transparent 100%),
    radial-gradient(circle 1px at 81% 58%, rgba(200,204,212,.35), transparent 100%),
    radial-gradient(circle 1px at 92% 12%, rgba(255,255,255,.48), transparent 100%),
    radial-gradient(circle 1px at 27% 84%, rgba(200,204,212,.38), transparent 100%);
}

/* Same dark gold that needed lifting on Halloween — unreadable on any
   dark ground. */
html[data-season="newyears"] .wc-rule{ color:#e5c15a !important; }

/* ══════════════════════════════════════════════════════════════════════
   DRAWING PAGE (index.html) — lite theming
   ──────────────────────────────────────────────────────────────────────
   This page has no #sketchGrid, so it always runs in lite mode: no
   lights/pumpkins/sprites/mascot, just the palette + wordmark + button
   tints every lite page gets for free. The one thing lite mode doesn't
   reach on its own is this page's OWN panels — toolbox, palette column,
   the mobile dock, layers panel, save row — which hardcode var(--c-white)
   rather than a theme token, so they'd stay stark white islands on a dark
   Halloween or New Year's page otherwise.
   ══════════════════════════════════════════════════════════════════════ */
html[data-season] .toolbox,
html[data-season] .paletteColumn,
html[data-season] #mDock,
html[data-season] .layersPanel,
html[data-season] #saveRowGlobal{
  background:var(--card) !important;
  border-color:var(--border) !important;
}
/* .stageHeader is deliberately NOT in that list. It's a transparent grid
   container spanning the full stage width — giving it a background
   painted a long empty box across the page, which is exactly the stray
   white bar that kept appearing. Only its child .paletteSelector has a
   real surface, and that's themed separately below. */
html[data-season] .stageHeader{ background:transparent !important; }
html[data-season] .leftColumn,
html[data-season] .rightColumn,
html[data-season] .stage{ background:var(--bg) !important; }

/* Halloween / New Year's are dark grounds — the drawing surface itself
   (the actual canvas) stays white on purpose, since that's the paper the
   art is drawn on and changing it would recolour every sketch. Only the
   chrome around it themes.

   .toolbox and .layersPanel are deliberately left OUT of this — they now
   get a light, accent-tinted background (see further down) rather than
   the plain dark --card every other panel uses, so forcing light text
   onto them here would put pale text on a pale surface. Their own text
   colour is handled where that background is set. */
html[data-season="halloween"] .paletteColumn,
html[data-season="halloween"] #mDock,
html[data-season="halloween"] #saveRowGlobal{ color:#f4ecf7 !important; }
html[data-season="newyears"] .paletteColumn,
html[data-season="newyears"] #mDock,
html[data-season="newyears"] #saveRowGlobal{ color:#f2f2f4 !important; }

/* More white surfaces unique to this page — the zoom pill, the animate
   timeline strip, the lock/animate-settings toggle, and the draft-recovery
   banner all hardcode var(--c-white) too. Left out of the block above
   because none of them share its selector list; each needs picking out on
   its own. These are the "long white boxes" that stayed lit up regardless
   of season once the panels around them went dark. */
/* .zoomPill and #animLockToggle also have html.dark-mode rules elsewhere
   in this page (from an earlier dark-mode pass) that carry !important and
   sit later in the document than this stylesheet's <link>, so on equal
   specificity they'd normally win when dark mode and a season are both
   on. Repeating the attribute selector is a legitimate way to raise this
   rule's specificity above a single class, so it wins regardless of
   document order or whether dark mode is also active. */
html[data-season][data-season] .zoomPill,
html[data-season][data-season] #animLockToggle{
  background:var(--card) !important;
  border-color:var(--border) !important;
  color:var(--text) !important;
}
html[data-season="halloween"][data-season] .zoomPill,
html[data-season="halloween"][data-season] #animLockToggle{ color:#f4ecf7 !important; }
html[data-season="newyears"][data-season] .zoomPill,
html[data-season="newyears"][data-season] #animLockToggle{ color:#f2f2f4 !important; }

html[data-season] .zoomPill,
html[data-season] #lockToggle,
html[data-season] #animLockToggle,
html[data-season] #animPanel,
html[data-season] #draftRecoveryBanner{
  background:var(--card) !important;
  border-color:var(--border) !important;
  color:var(--text) !important;
}
html[data-season="halloween"] .zoomPill,
html[data-season="halloween"] #lockToggle,
html[data-season="halloween"] #animLockToggle,
html[data-season="halloween"] #animPanel,
html[data-season="halloween"] #draftRecoveryBanner{ color:#f4ecf7 !important; }
html[data-season="newyears"] .zoomPill,
html[data-season="newyears"] #lockToggle,
html[data-season="newyears"] #animLockToggle,
html[data-season="newyears"] #animPanel,
html[data-season="newyears"] #draftRecoveryBanner{ color:#f2f2f4 !important; }

/* ── Toolbox & layers ─────────────────────────────────────────────────
   Uses the theme's own --card surface, same as every other panel on the
   page. An earlier version mixed the accent colour into white at 22% to
   guarantee icon contrast, but that produced a tint belonging to no part
   of the palette — it read as arbitrary rather than themed.

   The tool icons are dark line art, so on the two dark themes the panel
   needs to stay light for them to be visible at all. Those two get an
   explicit light surface; the three light themes just use --card. */
html[data-season] .toolbox,
html[data-season] .layersPanel{
  background:var(--card) !important;
  border-color:var(--border) !important;
}
html[data-season="halloween"] .toolbox,
html[data-season="halloween"] .layersPanel,
html[data-season="newyears"] .toolbox,
html[data-season="newyears"] .layersPanel{
  /* Light panel on a dark page — the icons inside are dark line art and
     would otherwise disappear entirely. */
  background:#f2f2f4 !important;
  border-color:var(--accent) !important;
  color:#1c2230 !important;
}
html[data-season] .tool.active{
  background:color-mix(in srgb, var(--accent) 30%, #fff) !important;
  border-color:var(--accent) !important;
}

/* ── The other two reported white boxes ───────────────────────────────
   .paletteSelector (the "1 2 3 4" saved-palette pill) and #captionInput
   both hardcode background:#fff in style.css — a separate stylesheet
   from index.html's own <style> block, which is why the earlier pass
   through this page missed them; that pass only grepped index.html. */
html[data-season] .paletteSelector{
  background:var(--card) !important;
}
html[data-season] .palNum{
  color:var(--text) !important;
}
html[data-season="halloween"] .paletteSelector{ color:#f4ecf7 !important; }
html[data-season="newyears"]  .paletteSelector{ color:#f2f2f4 !important; }

html[data-season] #captionInput{
  background:var(--card) !important;
  border-color:var(--border) !important;
  color:var(--text) !important;
}
html[data-season] #captionInput::placeholder{ color:var(--text3) !important; }

/* The custom colour-swatch editor popup — also #fff in style.css.
   .layerThumbWrap, found in the same sweep, is deliberately left alone:
   it previews a layer's actual drawn content, so tinting it would make
   an empty/transparent area render as theme-coloured instead of the
   correct white — the same reason .paper itself stays untouched. */
html[data-season] .swatchEditor{
  background:var(--card) !important;
  border-color:var(--border) !important;
  color:var(--text) !important;
}
html[data-season="halloween"] .swatchEditor{ color:#f4ecf7 !important; }
html[data-season="newyears"]  .swatchEditor{ color:#f2f2f4 !important; }

/* ══════════════════════════════════════════════════════════════════════
   ACCOUNT DROPDOWN — profile picture popup on profile/settings/every page
   ──────────────────────────────────────────────────────────────────────
   .dropdown-menu and .dropdown-item both READ theme tokens (--card,
   --text2) rather than hardcoding a colour, and profile.html/settings.html
   each define their own local copy of these two rules pointing at the
   same tokens — which should, in theory, resolve correctly through
   html[data-season]'s higher specificity over :root. In practice it was
   reported white-on-white on Halloween/New Year's regardless, so rather
   than keep relying on that chain of custom-property inheritance across
   three different files, these set the colours directly and explicitly,
   the same way the notification and search panels were fixed earlier.
   ══════════════════════════════════════════════════════════════════════ */
html[data-season="halloween"] .dropdown-menu{
  background:#241a2c !important;
  border-color:#4a3a58 !important;
  box-shadow:0 4px 16px rgba(0,0,0,.4) !important;
}
html[data-season="halloween"] .dropdown-item{
  color:#f4ecf7 !important;
  background:transparent !important;
}
html[data-season="halloween"] .dropdown-item:hover{
  background:#3a2a45 !important;
  color:#ffffff !important;
}
html[data-season="halloween"] .dropdown-item.danger{ color:#ff6b5e !important; }
html[data-season="halloween"] .dropdown-item.danger:hover{ background:rgba(255,107,94,.16) !important; }

html[data-season="newyears"] .dropdown-menu{
  background:#17171b !important;
  border-color:#3a3b44 !important;
  box-shadow:0 4px 16px rgba(0,0,0,.5) !important;
}
html[data-season="newyears"] .dropdown-item{
  color:#f2f2f4 !important;
  background:transparent !important;
}
html[data-season="newyears"] .dropdown-item:hover{
  background:#23262f !important;
  color:#ffffff !important;
}
html[data-season="newyears"] .dropdown-item.danger{ color:#ff6b5e !important; }
html[data-season="newyears"] .dropdown-item.danger:hover{ background:rgba(255,107,94,.16) !important; }
