/* Blazor SignalR reconnect overlay — framed Quindi mark, text-free, no buttons.
   Providing an element with id="components-reconnect-modal" makes blazor.web.js
   skip its built-in shadow-DOM dialog and instead just toggle state classes on
   our element (verified against Microsoft.AspNetCore.App 10.0). State classes:
     .components-reconnect-show          circuit lost, attempting to rejoin
     .components-reconnect-retrying      a retry is scheduled
     .components-reconnect-paused        rejoin paused (e.g. tab backgrounded)
     .components-reconnect-failed        retries exhausted — terminal
     .components-reconnect-rejected      server state gone — terminal
     .components-reconnect-resume-failed resume failed — terminal
     .components-reconnect-hide          reconnected — hide
   While rejoining: the framed mark breathes inside the green port of Blazor's
   own ripple animation (the framework default, recoloured from #0087ff to the
   brand green). In the terminal states the animation freezes and the tile dims;
   there is no reload button — the long retry schedule (see App.razor) keeps
   trying for ~2h, and on the terminal "rejected"/"resume-failed"/"failed"
   states App.razor auto-reloads the page (the framework would reload itself on
   its built-in dialog, but a custom modal only toggles a class — see App.razor). */

#components-reconnect-modal {
    /* Hidden until the framework adds a state class. No class == idle. */
    display: none;
    position: fixed;
    inset: 0;
    /* Above Excalidraw's chrome (max 9999) and the default Blazor overlay
       (10000) — a lost connection must block all interaction. */
    z-index: 100000;
    place-items: center;
    background: rgba(10, 10, 10, 0.55);
}

/* Any live state shows the overlay; -hide collapses it again. */
#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-retrying,
#components-reconnect-modal.components-reconnect-paused,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-resume-failed,
#components-reconnect-modal.components-reconnect-rejected {
    display: grid;
    animation: glass-fade 0.18s ease;
}

#components-reconnect-modal.components-reconnect-hide {
    display: none;
}

/* Centering stage for the ripple + framed mark. */
.reconnect-graphic {
    position: relative;
    display: grid;
    place-items: center;
    width: 260px;
    height: 260px;
}

/* --- Blazor's standard rejoining ripple, recoloured green --------------- */
/* Two concentric rings expand from the centre and fade — the framework's own
   animation (1.5s cubic-bezier(0, 0.2, 0.8, 1), 2nd ring delayed -0.5s),
   enlarged to 240px so the green rings clearly radiate out past the 132px tile
   (the inner travel stays hidden behind the opaque tile, so the rings read as
   emanating from the mark). */
.reconnect-ripple {
    grid-area: 1 / 1;
    position: relative;
    width: 240px;
    height: 240px;
    display: none;
}
#components-reconnect-modal.components-reconnect-show .reconnect-ripple,
#components-reconnect-modal.components-reconnect-retrying .reconnect-ripple,
#components-reconnect-modal.components-reconnect-paused .reconnect-ripple {
    display: block;
}
.reconnect-ripple div {
    position: absolute;
    border: 2px solid var(--accent);
    opacity: 1;
    border-radius: 50%;
    animation: reconnect-ripple 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}
.reconnect-ripple div:nth-child(2) {
    animation-delay: -0.5s;
}

/* --- framed brand mark (always visible) --------------------------------- */
.reconnect-tile {
    grid-area: 1 / 1;
    position: relative;
    z-index: 1;
    display: grid;
    place-items: center;
    width: 132px;
    height: 132px;
    /* Framed tile — app-icon feel, matches the app's glass surfaces. Solid so
       the ripple reads as radiating from behind it. */
    background: var(--quindi-surface);
    border: 1px solid var(--quindi-border);
    border-radius: var(--radius-xl);
    box-shadow: var(--glass-shadow);
    overflow: hidden;
}

.reconnect-logo {
    width: 84px;
    height: auto;
    display: block;
    filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.45));
}

/* While rejoining: the mark breathes. */
#components-reconnect-modal.components-reconnect-show .reconnect-logo,
#components-reconnect-modal.components-reconnect-retrying .reconnect-logo,
#components-reconnect-modal.components-reconnect-paused .reconnect-logo {
    animation: reconnect-breathe 2s ease-in-out infinite;
}

/* Paused: not actively retrying — freeze ripple + breathing and dim. */
#components-reconnect-modal.components-reconnect-paused .reconnect-ripple div,
#components-reconnect-modal.components-reconnect-paused .reconnect-logo {
    animation-play-state: paused;
}
#components-reconnect-modal.components-reconnect-paused .reconnect-graphic {
    opacity: 0.6;
}

/* Terminal: the connection is gone — hold the mark steady and slightly dimmed
   (ripple is already hidden in these states). */
#components-reconnect-modal.components-reconnect-failed .reconnect-tile,
#components-reconnect-modal.components-reconnect-resume-failed .reconnect-tile,
#components-reconnect-modal.components-reconnect-rejected .reconnect-tile {
    opacity: 0.7;
}

@keyframes reconnect-ripple {
    0%   { top: 120px; left: 120px; width: 0;     height: 0;     opacity: 0; }
    4.9% { top: 120px; left: 120px; width: 0;     height: 0;     opacity: 0; }
    5%   { top: 120px; left: 120px; width: 0;     height: 0;     opacity: 1; }
    /* Hold full opacity until the ring clears the tile (~126px ≈ tile edge),
       so it emerges bright and only fades on the way out. */
    55%  { opacity: 1; }
    100% { top: 0;     left: 0;    width: 240px; height: 240px; opacity: 0; }
}
@keyframes reconnect-breathe {
    0%, 100% { transform: scale(0.94); }
    50%      { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .reconnect-logo,
    .reconnect-ripple div,
    #components-reconnect-modal { animation: none !important; }
}
