/* Painterly cursor vars (--cur-*) come from /viewer/cursors.css — the
   shared sheet every page (home, index, play) links before this one. */
html, body {
    color-scheme: dark;   /* dark UA widgets: autofill dropdown, scrollbars */
    margin: 0;
    padding: 0;
    cursor: var(--cur-walk, default);
    background: #05080c;
    color: #c8d2dc;
    font: 12px/1.4 ui-monospace, Menlo, Consolas, monospace;
    overflow: hidden;
}

#stage {
    position: fixed;
    inset: 0;
}

/* No-UI screenshot mode — toggled by "!" (dungeon.js). Hides every DOM
   overlay, leaving just the canvas. Class-based so toggling off restores
   each element's original visibility with no inline-style residue. */
html.no-ui #ui,
html.no-ui #hud,
html.no-ui #fxbar,
html.no-ui #minimap,
html.no-ui #minimap_window,
/* Life/mana/xp bars are drawn by a separate PIXI overlay canvas
   (hud_bars.js), not by #ui — hide it explicitly or it survives "!". */
html.no-ui #hud_bars_gl { visibility: hidden !important; }

/* Loading overlay — covers everything (canvas + HUD + drops) during
   boot and during in-place zone swaps. Hides the brief "see the centre
   of the new map then teleport to spawn" flash; gives the renderer +
   GPU a few frames to upload textures + link batch shaders before the
   first painted frame the player sees. Pure CSS fade; toggle via the
   .visible class from JS. Painterly dark (radial vignette over a deep
   blue-black) to match the painted-bg register, not pure black. */
#loading-overlay {
    position: fixed;
    inset: 0;
    z-index: 100;
    /* Splash fallback (jpg optional): shows until #loading-video starts, or
       always if the mp4 is absent. The vignette lives in ::after so it also
       covers the video; the overlay stays opaque via #04060a regardless. */
    background:
        url("loading_bg.jpg") center / cover no-repeat,
        #04060a;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    pointer-events: none;
    /* Snappy fade-in (cover the swap quickly), gentler fade-out (reveal
       the new zone smoothly). Driven by .visible → fade-in duration
       wins; removing .visible → fade-out duration wins. */
    transition: opacity 180ms ease-out;
}
#loading-overlay.visible {
    opacity: 1;
    pointer-events: auto;
    transition: opacity 180ms ease-in;
}
/* Painterly splash under the vignette: still image with a slow Ken Burns
   zoom. transform-only, so the compositor keeps it moving while boot blocks
   the main thread (same reason the bar is scaleX). Starts >1 so cover-fit
   edges never peek in. */
#loading-art {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    animation: loading-zoom 45s ease-out forwards;
}
@keyframes loading-zoom {
    from { transform: scale(1.02); }
    to   { transform: scale(1.16); }
}
/* Vignette above bg/video, below the text + bar. */
#loading-overlay::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        radial-gradient(ellipse at center,
            rgba(8, 10, 16, 0.30) 0%,
            rgba(6,  8, 12, 0.62) 62%,
            rgba(2,  3,  5, 0.94) 100%);
}
.loading-inner {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 18px;
}
.loading-spinner {
    width: 38px;
    height: 38px;
    border: 2px solid rgba(200, 210, 220, 0.12);
    border-top-color: rgba(220, 200, 150, 0.85);
    border-radius: 50%;
    animation: loading-spin 0.9s linear infinite;
}
@keyframes loading-spin {
    to { transform: rotate(360deg); }
}
.loading-text {
    color: rgba(200, 210, 220, 0.7);
    font: 13px/1.2 Oswald, ui-sans-serif, system-ui, sans-serif;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
}
/* Boot-only stepped progress: named step (in .loading-text) + bar + "n / N". */
.loading-progress {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
}
.loading-bar {
    width: 174px;
    height: 5px;
    border-radius: 3px;
    background: rgba(200, 210, 220, 0.14);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
    overflow: hidden;
}
.loading-bar-fill {
    height: 100%;
    width: 100%;
    border-radius: 3px;
    background: linear-gradient(90deg,
        rgba(200, 175, 120, 0.85),
        rgba(240, 218, 165, 0.95));
    /* Driven via scaleX, NOT width: boot blocks the main thread for long
       stretches (texture decode/upload) and width/JS-timer animations
       freeze right then. Transform animations run on the compositor and
       keep gliding regardless. */
    transform-origin: left center;
    transform: scaleX(0.02);
}
/* Pre-JS creep: step 1 (scripts + WS join) runs before any of our JS can
   update the bar. setLoadingStep takes over with inline glides. */
.loading-bar-fill.creep {
    animation: loading-creep 10s ease-out forwards;
}
@keyframes loading-creep {
    from { transform: scaleX(0.02); }
    to   { transform: scaleX(0.28); }
}
/* Milestone glide (setLoadingStep): from/to come in via CSS vars; each real
   milestone restarts it from the current on-screen scale. */
@keyframes loading-glide {
    from { transform: scaleX(var(--bar-from, 0)); }
    to   { transform: scaleX(var(--bar-to, 1)); }
}
.loading-step-num {
    color: rgba(200, 210, 220, 0.45);
    font: 11px/1 Oswald, ui-sans-serif, system-ui, sans-serif;
    letter-spacing: 0.14em;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
}

/* Drop labels — DOM overlay sibling of #stage. PIXI debug markers stay
   in debugLayer (anchor for future ground-item sprite); the div carries
   the clickable name + quality color, D2-style. */
#drop-overlay {
    position: fixed;
    inset: 0;
    /* z-index 0: above #stage (also 0, but earlier in DOM) so labels float
       over the bake, yet below #ui (z-index 1) so inventory/menus cover them. */
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
}
/* Boxless drop name — same painterly register as .connexion-label: no
   border/background, tracked-out Oswald, layered shadow for legibility over
   any bake. The quality color is the only chrome; it floats above the item.

   Two visibility modes, driven by JS classes (see _updateDropLabelVisibility):
     - hidden by default (opacity 0, pointer-events none → never blocks the
       canvas under invisible loot);
     - `.shown`  → revealed (Alt-held shows all, or hovering one icon);
     - `.hover`  → that label + its icon highlight together. */
.drop-label {
    position: absolute;
    left: 0;
    top: 0;
    transform: translate(-50%, -100%);
    font: 400 16px/1.1 "Oswald", "Trajan Pro", Georgia, serif;
    letter-spacing: 0.08em;
    white-space: nowrap;
    padding-bottom: 14px;   /* reaches down toward the icon → bridges the hover gap */
    pointer-events: none;
    user-select: none;
    cursor: var(--cur-point, pointer);
    text-shadow:
        -1px -1px 0 rgba(0, 0, 0, 0.95),
         1px -1px 0 rgba(0, 0, 0, 0.95),
        -1px  1px 0 rgba(0, 0, 0, 0.95),
         1px  1px 0 rgba(0, 0, 0, 0.95),
         0  1px 3px rgba(0, 0, 0, 0.90),
         0  0  10px rgba(0, 0, 0, 0.55);
    opacity: 0;
    transition: opacity 120ms ease-out, filter 120ms ease-out;
}
.drop-label.shown {
    opacity: 0.82;
    pointer-events: auto;
}
.drop-label.hover {
    opacity: 1;
    filter: brightness(1.18);
}
.drop-label.colornormal    { color: #ffffff; border-color: #ffffff; }
.drop-label.colormagic     { color: hsla(240, 80%, 72%, 1); border-color: hsla(240, 80%, 72%, 1); }
.drop-label.colorenchanted { color: hsla(270, 80%, 70%, 1); border-color: hsla(270, 80%, 70%, 1); }
.drop-label.colorrare      { color: hsla(60, 80%, 70%, 1);  border-color: hsla(60, 80%, 70%, 1); }
.drop-label.colorunique    { color: hsla(35, 80%, 70%, 1);  border-color: hsla(35, 80%, 70%, 1); }
.drop-label.colorset       { color: hsla(120, 80%, 65%, 1); border-color: hsla(120, 80%, 65%, 1); }
.drop-label.colorruneword  { color: hsla(30, 60%, 55%, 1);  border-color: hsla(30, 60%, 55%, 1); }
.drop-label.colorcrafted   { color: hsla(120, 80%, 65%, 1); border-color: hsla(120, 80%, 65%, 1); }
.drop-label.colorcorrupted { color: hsla(0, 80%, 70%, 1);   border-color: hsla(0, 80%, 70%, 1); }
.drop-label.colorgold      { color: hsla(45, 100%, 80%, 1); border-color: hsla(45, 100%, 80%, 1); }

#stage canvas {
    display: block;
    image-rendering: pixelated;
}

#hud {
    position: fixed;
    top: 10px;
    left: 10px;
    z-index: 10;
    background: rgba(8, 12, 18, 0.7);
    border: 1px solid #1a2230;
    padding: 8px 10px;
    border-radius: 4px;
    max-width: 460px;
}

#hud label { cursor: var(--cur-point, pointer); }
#hud input[type=checkbox] { vertical-align: middle; margin-right: 4px; }

#hud .row {
    margin: 2px 0;
}

#hud b {
    color: #e0e8f2;
}

#hud #status {
    color: #7a8a9a;
}

/* Character HUD — bottom-left corner. Restrained palette (no gradients,
   no shadows); the rendered scene is the visual centre, the HUD is just
   data readout. D.6 cut A; will get D2-style flair once the inventory
   grid lands and the aesthetic budget makes sense to spend. */
#char-hud {
    position: fixed;
    left: 12px;
    bottom: 12px;
    z-index: 10;
    width: 280px;
    padding: 10px 12px;
    background: rgba(8, 12, 18, 0.78);
    border: 1px solid #2a364a;
    border-radius: 5px;
    color: #d0d8e2;
    font: 13px/1.3 system-ui, -apple-system, sans-serif;
    pointer-events: none;     /* never steals clicks from the canvas */
}
#char-hud[hidden] { display: none; }
.char-hud-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin: 2px 0 4px;
}
.char-hud-top    { font-size: 14px; }
.char-hud-bottom { font-size: 11px; color: #8090a0; margin-top: 4px; }
#char-hud-name   { color: #e0e8f2; font-weight: 600; }
.char-hud-level  { color: #c89a4a; }
.char-hud-gold   { color: #c8a040; }
.char-hud-bar {
    position: relative;
    height: 12px;
    background: #0b0f15;
    border: 1px solid #1a2230;
    border-radius: 2px;
    overflow: hidden;
    margin: 3px 0;
}
.char-hud-bar-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: 0%;
    transition: width 120ms linear;
}
.char-hud-life .char-hud-bar-fill { background: #a02020; }
.char-hud-mana .char-hud-bar-fill { background: #2858a0; }
.char-hud-bar-label {
    position: relative;
    display: block;
    text-align: center;
    line-height: 12px;
    font-size: 10px;
    color: #e8eef6;
    text-shadow: 0 0 2px #000, 0 0 2px #000;
}

/* Clickable connexion button — DOM div over the PIXI canvas, shown when
   the server's checkConnexions fires `new_connexion` (hero in the
   approach rayon). Click triggers click_connexion → zone swap.
   Lifted from ~/rpg/frontend/css/game.css .connexion. */
.connexion-button {
    position: absolute;
    transform: translate(-50%, -50%);
    padding: 8px 16px;
    pointer-events: all;
    user-select: none;
    z-index: 20;
    max-width: 220px;
    box-sizing: border-box;
    background: rgba(74, 158, 255, 0.25);
    border: 2px solid rgba(74, 158, 255, 0.6);
    border-radius: 8px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    color: #fff;
    text-align: center;
    white-space: nowrap;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
    box-shadow:
        0 4px 12px rgba(0, 0, 0, 0.3),
        inset 0 1px 0 rgba(255, 255, 255, 0.15);
    backdrop-filter: blur(4px);
    transition: transform .15s ease, background .15s ease, border-color .15s ease;
    cursor: var(--cur-point, pointer);
}
.connexion-button:hover {
    background: rgba(74, 158, 255, 0.40);
    border-color: rgba(74, 158, 255, 0.85);
    transform: translate(-50%, -50%) scale(1.05);
}
.connexion-button:active {
    transform: translate(-50%, -50%) scale(0.97);
}

/* Clickable waypoint button — gold variant of .connexion-button. Shown
   when the server's checkConnexions rayon fires `new_waypoint` (hero in
   the approach radius of the zone's waypoint pad). Left-click opens the
   waypoints modal via `click_waypoint`. */
.waypoint-button {
    position: absolute;
    transform: translate(-50%, -50%);
    padding: 8px 16px;
    pointer-events: all;
    user-select: none;
    z-index: 20;
    max-width: 220px;
    box-sizing: border-box;
    background: rgba(246, 193, 119, 0.25);
    border: 2px solid rgba(246, 193, 119, 0.6);
    border-radius: 8px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    color: #fff;
    text-align: center;
    white-space: nowrap;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
    box-shadow:
        0 4px 12px rgba(0, 0, 0, 0.3),
        inset 0 1px 0 rgba(255, 255, 255, 0.15);
    backdrop-filter: blur(4px);
    transition: transform .15s ease, background .15s ease, border-color .15s ease;
    cursor: var(--cur-point, pointer);
}
.waypoint-button:hover {
    background: rgba(246, 193, 119, 0.40);
    border-color: rgba(255, 224, 160, 0.95);
    transform: translate(-50%, -50%) scale(1.05);
}
.waypoint-button:active {
    transform: translate(-50%, -50%) scale(0.97);
}

/* Scrollable list of destination maps inside the #waypoints modal. The modal
   itself caps at 85vh with overflow:hidden; the tabs + Close stay fixed while
   the map list scrolls when an act has more waypoints than fit. */
.waypoint_list {
    overflow-y: auto;
    max-height: 60vh;
    min-height: 0;
}

/* Footer "Close" row inside the #waypoints modal. Reuses .waypoint styling
   from game.css so it visually belongs to the list; centered + dimmer to
   read as an action, not a destination. Adds top margin to detach it from
   the zone list above. */
.waypoint.waypoint_close {
    margin-top: 12px;
    text-align: center;
    color: rgba(220, 220, 230, 0.7);
    letter-spacing: 0.5px;
    text-transform: uppercase;
}

/* Connexion overlay — body-level container for the clickable mouth buttons.
   Mirrors #drop-overlay (sibling of #stage; z-index above the canvas; the
   container itself ignores pointer-events so the canvas keeps every
   background click except where a button reenables them locally). */
#connexion-overlay {
    position: fixed;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    overflow: hidden;
}

/* Hover label for connexion slots (the painterly-coherent replacement for
   the legacy .connexion-button div). No box, no border, no background —
   just tracked-out Oswald above the gate with a warm drop shadow that
   stays legible over wheat, dirt, and night register alike. */
#connexion-label-overlay {
    position: fixed;
    inset: 0;
    z-index: 3;
    pointer-events: none;
    overflow: hidden;
}
.connexion-label {
    position: absolute;
    transform: translate(-50%, -100%);
    white-space: nowrap;
    font: 400 16px "Oswald", "Trajan Pro", Georgia, serif;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: #fbf2d8;
    /* Layered shadow recipe:
         - tight 1-px outline in 8 directions → crisp edge over any bg
         - mid black drop  → grounding
         - wide warm glow  → painterly bloom, lifts off the bake
    */
    text-shadow:
        -1px -1px 0 rgba(0, 0, 0, 0.95),
         1px -1px 0 rgba(0, 0, 0, 0.95),
        -1px  1px 0 rgba(0, 0, 0, 0.95),
         1px  1px 0 rgba(0, 0, 0, 0.95),
         0  1px 3px rgba(0, 0, 0, 0.90),
         0  0  10px rgba(0, 0, 0, 0.55),
         0  0  22px rgba(255, 180, 100, 0.30);
    opacity: 0;
    transition: opacity 140ms ease-out;
}
.connexion-label.visible { opacity: 1; }

/* Town-portal hover label — same typography as the connexion label but a
   cool ice-blue ink + blue bloom instead of warm gold (gold reads wrong
   against the blue swirl). */
.portal-label {
    position: absolute;
    transform: translate(-50%, -100%);
    white-space: nowrap;
    font: 400 16px "Oswald", "Trajan Pro", Georgia, serif;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: #dceeff;
    text-shadow:
        -1px -1px 0 rgba(0, 0, 0, 0.95),
         1px -1px 0 rgba(0, 0, 0, 0.95),
        -1px  1px 0 rgba(0, 0, 0, 0.95),
         1px  1px 0 rgba(0, 0, 0, 0.95),
         0  1px 3px rgba(0, 0, 0, 0.90),
         0  0  10px rgba(0, 0, 0, 0.55),
         0  0  22px rgba(120, 190, 255, 0.45);
    opacity: 0;
    transition: opacity 140ms ease-out;
}
.portal-label.visible { opacity: 1; }

/* Crafting formula tooltip + in-hand item must float ABOVE the
   inventory panel. game.css's #inventory_conteneur is z-index:35, so
   #formula's default 30 and .item.hand's stacking inherit-from-#ui
   leave them under the modal. Bump above. */
#formula { z-index: 40 !important; }
.item.hand { z-index: 40; position: fixed; pointer-events: none; }

/* Cursor-follow position: --handx/--handy (top-left anchored) and --handb
   (bottom anchor for #formula) are set on <html> by dungeon.js inside a rAF,
   already divided by uiz. Keeping it out of the Vue template means moving the
   mouse touches one composited transform instead of re-rendering the HUD.
   .item.hand (0,2,0) beats game.css's .hand (0,1,0) centering transform, so
   re-apply the -50%/-50% here. */
.item.hand {
    left: 0; top: 0;
    transform: translate(-50%, -50%)
               translate3d(var(--handx, 0px), var(--handy, 0px), 0);
    will-change: transform;
}
#formula {
    left: var(--handx, 0px);
    bottom: var(--handb, 0px);
}

/* Autofill: Chrome's UA background can only be beaten by an inset shadow.
   Generic fallback for pages that don't link painterly-hud.css (index.html). */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
    -webkit-text-fill-color: #ece3cf;
    caret-color: #ece3cf;
    box-shadow: inset 0 0 0 1000px rgba(12, 9, 6, 0.94);
    transition: background-color 9999s ease-in-out 0s;
}
