/* =====================================================================
   ALERTS  --  aparte browser source, transparant, over je beeld
   Ontwerpmaat 2560 x 1072 (de gameplay-zone).
   Zelfde ribbon-taal als de balken en de scenes.
   ===================================================================== */

html,body{width:100vw;height:100vh;background:transparent;overflow:hidden}
#stage{position:absolute;top:0;left:0;transform-origin:0 0}

#alertHost{position:absolute;left:0;right:0;top:52px;display:grid;justify-items:center}

.alert{
  grid-area:1/1;display:flex;flex-direction:column;align-items:center;gap:14px;
  opacity:0;transform:translateY(-34px);will-change:transform,opacity;
}
.alert .rib{--rib-h:96px;--rib-cut:30px}
.alert .rib__cap{height:32px;padding:0 18px;font-size:16px;letter-spacing:.24em;
  margin-left:30px;border-radius:7px}
.alert .rib__bar{margin-top:-12px}
.alert .rib__val{font-size:44px;padding-left:26px}
.alert .rib__in{padding-right:54px}
.alert .rib__acc svg{width:40px;height:40px;margin-right:8px}

/* ---- beloning bij een sub -------------------------------------------
   Boven de melding. De wig komt binnen met een korte zwaai en staat daarna
   stil: de melding zelf duurt maar vijf seconden, dus doorlopende beweging
   voegt niets toe en kost wel bitrate.

   Een eigen foto (goals.subs.image) krijgt dezelfde maat en een donkere
   ondergrond, zodat een uitgeknipte productfoto op wit niet als een gat in
   je overlay staat. */
.alert__reward{display:flex;flex-direction:column;align-items:center;gap:9px}
/* Dezelfde halfdoorzichtige plaat als het pilletje en het bericht eronder.
   Zonder plaat zweeft een tekening over drukke gameplay: de donkere kop
   valt weg tegen wat er toevallig achter ligt. Vlak en niet verlopend, dus
   er valt niets te banden. */
.alert__wig{width:150px;height:150px;display:grid;place-items:center;
  background:#0a0b0de6;border:1px solid var(--ink-700);border-radius:16px;
  padding:10px}
.alert__wig svg{width:100%;height:100%;display:block}
img.alert__wig{object-fit:contain}
.alert.in .alert__wig{animation:wigIn 620ms var(--ease) 80ms both}
@keyframes wigIn{
  0%  {opacity:0;transform:translateY(-16px) rotate(-9deg) scale(.86)}
  60% {opacity:1;transform:translateY(0)     rotate(4deg)  scale(1.03)}
  100%{opacity:1;transform:none}
}

/* De afspraak eronder, klein: de melding gaat over wie er gesubd heeft, dit
   is het onderschrift. */
.alert__promise{
  font-size:15px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--acc,var(--paper));
  background:#0a0b0de6;border:1px solid var(--ink-700);
  border-radius:var(--r-pill);padding:6px 16px;
}

/* bedrag of tier, in een eigen pilletje onder de ribbon */
.alert__meta{
  font-family:var(--f-mono);font-size:17px;color:var(--acc,var(--jade));
  background:#0a0b0de6;border:1px solid var(--ink-700);
  border-radius:var(--r-pill);padding:7px 18px;
}
.alert__meta:empty{display:none}

/* Bericht bij een sub of tip. Afgekapt zodat een roman je beeld niet vult. */
.alert__msg{
  max-width:900px;font-size:19px;color:var(--paper-dim);text-align:center;
  background:#0a0b0dd9;border-radius:14px;padding:10px 22px;
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
}
.alert__msg:empty{display:none}

.alert.in {animation:alertIn  420ms var(--ease) forwards}
.alert.out{animation:alertOut 300ms var(--ease) forwards}
@keyframes alertIn {from{opacity:0;transform:translateY(-34px)}
                    to  {opacity:1;transform:translateY(0)}}
@keyframes alertOut{from{opacity:1;transform:translateY(0)}
                    to  {opacity:0;transform:translateY(-26px)}}

/* het kopblok licht kort op bij binnenkomst */
.alert.in .rib__acc{animation:accHit 520ms var(--ease) 120ms}
@keyframes accHit{0%{filter:brightness(2.1)}100%{filter:none}}

/* =====================================================================
   RAIDMELDING  --  over het hele vlak, bij een nieuwe beste poging of een
   kill. Dit is wat in de raidkaart niet kan: die bron is 248px hoog.

   De was erachter is vlak en half doorzichtig, dus je gameplay blijft er
   vaag door zichtbaar en er valt niets te banden. Kort aanhouden voor een
   nieuwe beste poging: acht seconden. Een kill blijft negentien seconden
   staan -- daar loopt eerst het vuurwerk (tot een kleine veertien seconden),
   en dan nog ruim vier seconden rust om de cijfers te lezen. Zie de kop bij
   .fw hieronder voor de opbouw van dat vuurwerk.
   ===================================================================== */
#raidHost{position:absolute;inset:0;pointer-events:none}

.alert--raid{
  position:absolute;inset:0;display:grid;place-items:center;
  background:rgba(10,11,13,.72);opacity:0;transform:none;
}
.alert--raid::before,.alert--raid::after{
  content:'';position:absolute;left:0;right:0;height:2px;
  background:var(--acc);opacity:.5;
}
.alert--raid::before{top:0}
.alert--raid::after {bottom:0}

.alert--raid.in {animation:raidIn  460ms var(--ease) forwards}
.alert--raid.out{animation:raidOut 340ms var(--ease) forwards}
@keyframes raidIn {from{opacity:0}to{opacity:1}}
@keyframes raidOut{from{opacity:1}to{opacity:0}}

/* ---- bossart achter de melding --------------------------------------
   Dezelfde afbeelding als het hoekje op de raidkaart in de onderbalk
   (`boss.portraitUrl` uit Raider.IO's live-tracking), maar hier over het
   hele vlak. Twee dingen staan dat in de weg, en samen bepalen ze de vorm.

   Ten eerste: die portretten zijn **128x64**. Op een melding van 2560 breed
   is dat twintig keer opgeblazen. Scherp bedoeld wordt dat een blokkenbrij,
   dus het is hier kleur en geen plaatje -- een waas in de kleuren van de
   boss achter je tekst.

   Ten tweede: het portret is een buste op een **zwart vlak**, en de melding
   ligt over je gameplay met een was van 72% erover. Normaal samengesteld
   valt zo'n zwart vlak samen met die was en zie je niets; het eerste dat
   hier stond was op een druk beeld niet van de was te onderscheiden.
   `mix-blend-mode:screen` lost allebei op: zwart telt niet mee, dus alleen
   de boss licht op en de rest blijft de was. Vandaar ook geen masker dat het
   midden vrijhoudt -- daar zit juist het enige wat niet zwart is.

   .raid__art  -- vol vlak, zwaar geblurd, midden op de tekst. De bossnaam
                  staat er op 132px overheen, dus de waas blijft op de helft
                  hangen en dooft naar de randen uit.
   .raid__bust -- hetzelfde portret, niet geblurd, tegen de rechterflank.
                  Daar staat geen tekst (.raid__mid houdt 120px marge), en
                  onderaan het midden zou hij door de statistiekenrij lopen.
                  Dezelfde plek als de characters op de pauzeschermen.

   Beide lagen horen in de DOM vóór .raid__mid, zodat de tekst erover valt.
   Ze staan er alleen als er een afbeelding is: js/alerts.js hangt ze niet op
   bij een lege bossImg, en dan is de melding wat hij hiervoor was.

   .raid__bust is de terugval voor als er geen render is (zie hieronder): dan
   is dit precies wat er al stond, portret en al. Is er wel een render, dan
   komt .raid__bust niet eens in de DOM -- js/alerts.js hangt dan .raid__render
   op in plaats daarvan, en .raid__art blijft gewoon staan voor de was. */
.raid__art,.raid__bust{
  position:absolute;z-index:0;pointer-events:none;
  background-repeat:no-repeat;mix-blend-mode:screen;
}
.raid__art{
  inset:0;background-size:cover;background-position:center 44%;
  opacity:.5;filter:blur(30px) saturate(1.5);
  /* Opschalen, anders trekt de blur een doorzichtige rand langs het vlak. */
  transform:scale(1.15);
  -webkit-mask-image:radial-gradient(72% 92% at 50% 46%,
                     #000 0%,#000 52%,transparent 100%);
          mask-image:radial-gradient(72% 92% at 50% 46%,
                     #000 0%,#000 52%,transparent 100%);
}
.raid__bust{
  right:-40px;bottom:0;width:1020px;height:660px;
  background-size:contain;background-position:right bottom;opacity:.62;
  -webkit-mask-image:linear-gradient(to left,#000 0%,#000 34%,transparent 96%);
          mask-image:linear-gradient(to left,#000 0%,#000 34%,transparent 96%);
}

/* ---- volle renders (js/bossart.js) ----------------------------------
   600x600 renders van het volle model, op een egale rgb(24,24,24) grond.
   Ze vervangen .raid__bust: één render tegen de rechterflank, twee tegen
   allebei (tweebossgevechten). .raid__art blijft de was erachter en
   gebruikt dan de eerste render als er geen Raider.IO-portret is.

   `mix-blend-mode:screen` + `contrast()` stond hier eerder, met het idee dat
   screen "zwart niet laat meetellen". Dat klopt binnen de pagina zelf, maar
   niet voor wat er in OBS terechtkomt: een browser source is voor OBS een
   textuur met een EIGEN alphakanaal, en een JPEG heeft er geen -- overal
   ondoorzichtig. mix-blend-mode verandert alleen de kleur per pixel, niet de
   alpha van het vak zelf, en dat vak bleef dus overal even ondoorzichtig als
   de `opacity` hieronder zei: zwarte grond en boss door elkaar, allebei
   even dekkend. Buiten dat vak lag een net iets ándere ondoorzichtigheid
   (de was van de melding zelf) -- en dat verschil in alpha, niet in kleur,
   was de harde rand die je op stream zag: een rechthoek, precies op de rand
   van het element.

   De oplossing zit daarom niet in CSS maar in js/alerts.js: keyArt() tekent
   de render op een canvas en vult van de rand naar binnen alles weg dat op
   de rgb(24,24,24)-grond lijkt, met een ECHT alphakanaal (canvas -> blob ->
   object-URL). Wat hier binnenkomt heeft dus al gaten waar de grond zat;
   deze laag hoeft alleen nog de vorm en de plek te regelen. Faalt het
   wegkeren (geen CORS, decodeerfout), dan komt de rauwe render terug met
   .raid__render--masked erbij: een ovaal masker in plaats van niets, want
   een zichtbare rechthoek is nog altijd erger dan een zachte ovale rand om
   een grond die niet weggekeerd kon worden.

   940x940, vierkant: de renders zijn zelf vierkant en het model staat erin
   gecentreerd, dus zo landt het midden van het figuur op een vaste afstand
   van de rand in plaats van ergens in een rechthoek met een andere
   verhouding. Onderaan verankerd (-30px, staat op de grond in het
   origineel), -170px van de zijkant zodat dat midden op ~300px van de rand
   van het doek uitkomt: dit is een kill, de boss mag groot in beeld komen.

   Het masker dooft naar het midden uit, gespiegeld voor de linkerflank, en
   staat verder van de rand dan bij de oude 563px-brede versie: bij een
   lange bossnaam ("Nek'zali the Soulcoiler" op 132px) moet er ruimte
   overblijven voor de tekst voordat het figuur weer vol ondoorzichtig
   wordt, anders knalt de naam tegen een volle boss aan in plaats van
   erover te lezen. */
.raid__render{
  position:absolute;z-index:0;bottom:-30px;width:940px;height:940px;
  pointer-events:none;background-repeat:no-repeat;background-size:contain;
  background-position:bottom;opacity:1;
  animation:raidRenderIn 700ms var(--ease) 220ms both;
}
.raid__render--left{
  left:-170px;--slide:-60px;
  -webkit-mask-image:linear-gradient(to right,#000 0px,#000 300px,transparent 680px);
          mask-image:linear-gradient(to right,#000 0px,#000 300px,transparent 680px);
}
.raid__render--right{
  right:-170px;--slide:60px;
  -webkit-mask-image:linear-gradient(to left,#000 0px,#000 300px,transparent 680px);
          mask-image:linear-gradient(to left,#000 0px,#000 300px,transparent 680px);
}
/* Alleen als keyArt() zelf niet lukte: de grond staat er dan nog steeds op,
   dus liever een zachte ovale rand eromheen dan de harde rechthoek die de
   rest van deze sectie net oplost. Zelfde class-specificiteit als hierboven,
   dus wint gewoon doordat deze regel er later in het bestand staat -- geen
   twee maskers tegelijk optellen voor iets dat de uitzondering is. */
.raid__render--masked{
  -webkit-mask-image:radial-gradient(ellipse 62% 58% at 50% 60%,#000 0%,#000 55%,transparent 100%);
          mask-image:radial-gradient(ellipse 62% 58% at 50% 60%,#000 0%,#000 55%,transparent 100%);
}
/* Schuift van buiten het doek naar zijn plek, iets na de was (die opkomt via
   de opacity-animatie op .alert--raid zelf, vanaf 0ms; dit start 220ms later
   zodat de figuur duidelijk ná de achtergrond komt aanzetten). */
@keyframes raidRenderIn{
  from{opacity:0;transform:translateX(var(--slide))}
  to  {opacity:1;transform:none}
}

/* De was komt op, de inhoud komt eronder vandaan. Twee bewegingen die bij
   elkaar horen, niet vijf losse. */
.raid__mid{position:relative;z-index:1;text-align:center;padding:0 120px;
  animation:raidRise 520ms var(--ease) both}
@keyframes raidRise{from{opacity:0;transform:translateY(26px)}
                    to  {opacity:1;transform:none}}

.raid__eyebrow{
  font-family:var(--f-mono);font-size:30px;color:var(--acc);
  letter-spacing:.42em;text-transform:uppercase;padding-left:.42em;
}
.raid__boss{
  margin-top:22px;font-size:132px;font-weight:600;line-height:1.02;
  letter-spacing:-.035em;color:var(--paper);
}
/* Alleen bij een kill (js/alerts.js zet 'm er dan pas bij): wie 'm neerlegde.
   Zelfde haakjes als de raidkaart (‹gildenaam›, zie js/banner.js), en
   dezelfde kleur als de rest van het kill-accent. Komt 180ms na de bossnaam
   op -- vandaar de eigen (kortere) raidRise in plaats van meeliften op
   .raid__mid, dat al bij 0ms begint. */
.raid__guild{
  margin-top:10px;font-size:56px;font-weight:600;color:var(--acc);
  animation:raidRise 420ms var(--ease) 180ms both;
}
.raid__where{
  margin-top:18px;font-size:24px;font-weight:600;color:var(--ink-300);
  letter-spacing:.16em;text-transform:uppercase;
}
/* De bronvermelding staat in de hoek, buiten het midden: de melding gaat
   over de boss, niet over waar het cijfer vandaan komt. Hij komt mee op met
   de was, want hij zit in hetzelfde element -- geen eigen beweging. */
.raid__src{
  position:absolute;right:38px;bottom:26px;z-index:1;
  font-size:16px;font-weight:600;letter-spacing:.16em;
  color:var(--ink-400);
}

.raid__stats{display:flex;justify-content:center;gap:76px;margin-top:56px}
.raid__v{
  font-family:var(--f-mono);font-variant-numeric:tabular-nums;
  font-size:62px;font-weight:500;line-height:1;color:var(--acc);
}
/* Deze labels staan over je gameplay, niet over een egale scene. ink-400
   valt daar weg tegen een druk beeld, dus een stap lichter. */
.raid__l{
  margin-top:12px;font-size:15px;font-weight:600;color:var(--ink-200);
  letter-spacing:.18em;text-transform:uppercase;
}

/* ---- vuurwerk: kill-melding én SE-meldingen --------------------------
   Dezelfde .fw-vorm voor de grote show bij een kill (hier ~19s, voorbij rond
   14,5s) en de kleine bursts bij follow/sub/cheer/tip/raid (hier binnen 4s,
   ruim binnen hun 5200ms) -- alleen bij een kill hangt .fw als kind in de
   melding zelf, bij een SE-melding los in #stage. De opbouw, de tabel met
   bursts en de planning (wanneer een burst zijn DOM krijgt en weer
   kwijtraakt) staan in js/alerts.js -- hier staat alleen de vorm. Een
   nieuwe beste poging krijgt zelf nog steeds niets: als een wipe al
   vuurwerk kreeg, zegt het bij een kill niets meer.

   Ronde stipjes en geen verlopen: een gevulde cirkel is een plat vlak, en
   honderden van die dingen die een paar seconden bewegen is nog altijd minder
   werk voor de encoder dan één was die van kleur verschiet. Kleuren komen
   uitsluitend uit tokens: --jade, --paper, --gold (css/tokens.css) bij een
   kill, en var(--acc) plus --paper/--gold bij een SE-melding -- --acc is
   zelf ook gewoon zo'n token, alleen per meldingssoort al ingevuld. */
.fw{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.fw__b{position:absolute;width:0;height:0}

/* Het opstijgende stipje. Zonder dit komt de ring uit niets tevoorschijn en
   leest hij als een sterretje in plaats van als vuurwerk. */
.fw__t{
  position:absolute;width:5px;height:34px;margin:-17px 0 0 -2px;border-radius:3px;
  background:var(--c);
  animation:fwRise 380ms cubic-bezier(.3,.6,.4,1) var(--d) both;
}
@keyframes fwRise{
  0%  {transform:translateY(var(--rise));opacity:0}
  22% {opacity:.95}
  100%{transform:translateY(0);opacity:0}
}

/* Buitenste element: radiaal naar buiten, ease-out, dus snel weg en dan
   uitdempen. */
.fw__s{
  position:absolute;
  animation:fwFly var(--life) cubic-bezier(.12,.72,.26,1) var(--sd) both;
}
@keyframes fwFly{
  0%  {transform:translate(0,0);opacity:0}
  7%  {opacity:1}
  62% {opacity:1}
  100%{transform:translate(var(--tx),var(--ty));opacity:0}
}

/* Binnenste element: valt, ease-in, dus versnellend. Samen met de buitenste
   geeft dat de parabool. */
.fw__s b{
  display:block;width:var(--sz);height:var(--sz);
  margin:calc(var(--sz) / -2) 0 0 calc(var(--sz) / -2);
  border-radius:50%;background:var(--c);
  animation:fwFall var(--life) cubic-bezier(.45,0,.85,.55) var(--sd) both;
}
@keyframes fwFall{from{transform:translateY(0)}to{transform:translateY(var(--drop))}}

/* ---- crackle/glitter: vonken die knipperen in plaats van vloeiend uitdoven
   Zelfde tweelaagse opbouw als hierboven (buiten vliegt, binnen valt), maar
   de binnenste laag krijgt een tweede animatie erbij: een harde, getrapte
   opacity naast de val. `steps()` in plaats van een vloeiende easing is
   precies het verschil tussen "dooft uit" en "knippert" -- en twee
   animaties op dezelfde 'b' kunnen naast elkaar, want fwFall raakt alleen
   transform en fwFlicker alleen opacity.

   Specificiteit moet hoger dan .fw__s b (anders verliest de tweede animatie
   het gewoon van de gewone val), vandaar de klasse erbij in de selector in
   plaats van los. */
.fw__s b.fw__s--crk{
  animation:
    fwFall    var(--life) cubic-bezier(.45,0,.85,.55) var(--sd) both,
    fwFlicker 90ms         steps(2,jump-none)          var(--sd) infinite;
}
@keyframes fwFlicker{0%,100%{opacity:1}50%{opacity:.3}}

/* ---- dubbele ring: een tweede, kleinere ring in een tweede kleur op
   dezelfde burst. Geen eigen klasse nodig -- js/alerts.js zet gewoon een
   tweede --c rechtstreeks op die vonken, en die wint van de --c die op
   .fw__b staat omdat inline style zwaarder weegt dan een geërfde waarde. */

@media (prefers-reduced-motion:reduce){
  .alert,.alert.in,.alert.out{animation:none;opacity:1;transform:none}
  .alert.in .rib__acc{animation:none}
  .alert--raid,.alert--raid.in,.alert--raid.out,.raid__mid,
  .raid__guild{animation:none;opacity:1}
  /* Geen schuif, alleen meteen zichtbaar -- net als de rest hierboven. */
  .raid__render{animation:none;opacity:1}
  /* Vuurwerk is puur beweging. Stilstaand zijn het honderden stippen over je
     gameplay, dus dan liever niets: js/alerts.js plant in dat geval sowieso
     niets in, en dit vangt de rest af. */
  .fw{display:none}
}
