/* board-3d.css — styles for the 2.5D Three.js renderer overlay.
 *
 * The 3D canvas lives in #board-3d-host, a viewport-fixed element whose
 * rect tracks #game-board (game-render-3d.js writes the inline left/top/
 * width/height). In 2.5D mode (body.board-3d), the 2D board chrome inside
 * #game-board is hidden but layout-preserving (visibility:hidden) so the
 * canvas sits over the same area. Result modal + claim overlay (also
 * children of #game-board) stay visible — they're z-index'd above the
 * canvas in their own CSS rules.
 *
 * The 2D action bar (#game-actionbar) lives outside #game-board and stays
 * fully interactive — that's how the player still uses the existing
 * tsumo/riichi/etc. buttons in 2.5D mode. Own-hand discard interaction is
 * deferred to a follow-up iteration; in iter 1, switch back to 2D for
 * full interactivity. (See `Board mode` tab description.)
 */

/* Host is invisible by default. body.board-3d (set by the 3D module on
   mount) flips it to a viewport-fixed pane between the header and the
   action bar. No JS measurement — CSS-only positioning so the layout
   doesn't depend on the size of any visibility:hidden element. */
#board-3d-host {
    display: none;
    pointer-events: none;        /* clicks fall through to 2D DOM beneath */
    background: transparent;     /* canvas paints its own colour */
}

#board-3d-host[hidden] { display: none !important; }

/* Anti-flash (refresh into a 3D table): the dispatcher sets body.board-3d-pending
   synchronously when 3D is selected, BEFORE Three.js downloads. While pending and
   in-game, hide the flat 2D grid and show #board-3d-loading instead, so the 2D
   board doesn't flash for a couple seconds before the 3D scene mounts. The class
   clears on the first 3D frame (board-3d-ready) or on mount failure/timeout, after
   which the 2D grid either stays hidden (3D took over) or reappears (2D fallback). */
#board-3d-loading { display: none; }
body.board-3d-pending.in-game #game-board > .board-grid { visibility: hidden; }
body.board-3d-pending.in-game #board-3d-loading {
    display: flex;
    position: fixed;
    top: 60px; left: 0; right: 0; bottom: 0;
    z-index: 501;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.9rem;
    color: var(--muted);
    font-size: 0.9rem;
    pointer-events: none;
}
.board-3d-spinner {
    width: 34px; height: 34px;
    border: 3px solid color-mix(in srgb, var(--muted) 35%, transparent);
    border-top-color: var(--accent-gold, #d9b25a);
    border-radius: 50%;
    animation: board-3d-spin 0.85s linear infinite;
}
@keyframes board-3d-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .board-3d-spinner { animation: none; } }

/* Show the 3D canvas only once the game is actually playing —
   game-render.js's ensureMounted() adds body.in-game when the first
   game notification arrives. Before then (Forming / ConfirmingReadiness
   / etc.), the player should see the 2D waiting page (compass seats,
   rules panel) UNobstructed by the 3D canvas. */
body.board-3d.in-game #board-3d-host {
    display: block;
    position: fixed;
    top: 60px;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 500;
}


#board-3d-canvas {
    width: 100%;
    height: 100%;
    display: block;
    /* Host has pointer-events:none so empty corners of the host pass
       clicks through to underneath. Canvas re-enables pointer-events so
       clicks on it (own-hand tile discards via raycast) are received. */
    pointer-events: auto;
}

/* Once the game is playing AND the 3D scene has confirmed first paint,
   hide the central 2D table chrome. Three gates compounded:
     - body.board-3d         — user opted into 2.5D
     - body.in-game          — first game notification arrived
     - body.board-3d-ready   — 3D scene has rendered at least one frame
   Until all three are set, 2D stays visible — the player always sees
   the game state, even if Three.js is slow / fails / produces a blank
   scene. */
body.board-3d.in-game.board-3d-ready #game-board > .board-grid {
    visibility: hidden;
}

/* GitLab #8 — strip the same opaque green background during the PENDING
   window too (server emits board-3d-pending at byte 0; board-3d is added only
   on 3D mount). Once game-render.js's ensureMounted() un-hides #game-board (on
   the first snapshot), its z-900 dark-green gradient would otherwise paint a
   green block over the loading spinner AND the mounting 3D scene until mount
   completes — intermittently visible over the hand on slower mounts. Keep it
   transparent throughout pending → ready. (pointer-events stays default here;
   nothing under the spinner is interactive yet.) */
body.board-3d-pending.in-game #game-board {
    background: transparent !important;
}

/* CRITICAL: .game-board is position:fixed, inset:0, z-index:900 with a
   dark green radial-gradient background that covers the ENTIRE viewport.
   It paints OVER our #board-3d-host (z-index:500), so the canvas is
   completely invisible in 2.5D mode without this rule. Strip the
   gradient so the canvas below shows through. */
body.board-3d.in-game #game-board {
    background: transparent !important;
    /* Pass clicks through to the canvas below by default. Specific
       interactive children (action bar buttons, claim panel, result
       modal, game-id badge, ceremony overlay) re-enable pointer-events
       on themselves below. Without this, clicks on the empty centre of
       the table would land on .game-board itself and never reach the
       canvas for tile-discard raycast. */
    pointer-events: none !important;
}

/* Interactive HTML overlays that DO need to receive clicks. These are
   direct children of #game-board with their own z-stacking above the
   canvas — re-enable pointer-events so they remain clickable. */
body.board-3d.in-game #game-board > .game-result,
body.board-3d.in-game #game-board > .claim-overlay,
body.board-3d.in-game #game-board > .game-id-badge,
body.board-3d.in-game #game-board > .game-exit,
body.board-3d.in-game #game-board > .hint-toggle,
body.board-3d.in-game #game-board > .hint-drawer {
    pointer-events: auto;
}

/* The 2D ceremony card (.game-ceremony) renders the mesh-swap shuffle,
   wall-stacks-rise, and dice-tumble cards on top of the table. In 3D
   mode we replace those with real 3D animations (game-render-3d.js's
   apply* ceremonies), so the 2D card would just be visual noise floating
   over the scene. Hide it entirely. */
body.board-3d.in-game #game-board > .game-ceremony {
    display: none !important;
}

/* Result modal and claim overlay must visually layer above the canvas.
   They live inside #game-board with z-index 950+/1000 — already above the
   canvas's stacking context. The visibility:hidden rule above doesn't
   affect direct children OTHER than .board-grid. */

/* The page header (lotus brand + user dropdown) sits BENEATH the
   .game-board overlay during gameplay — in 2D mode it's hidden by
   .game-board's opaque dark-green radial-gradient background. In 3D
   mode we strip .game-board's background (above) so the canvas shows
   through, which also stops covering the header. Explicitly hide the
   header during in-game so 3D matches 2D's immersive look. */
body.board-3d.in-game > header {
    display: none;
}
/* With the 60px header gone, the canvas host can extend to the top of
   the viewport so the 3D scene fills the whole pane. */
body.board-3d.in-game #board-3d-host {
    top: 0;
}

/* The wall-break marker (.wall-pair.wall-consumed.wall-break) is a gold
   dashed ring that 2D draws on top of vacated wall stacks. Its rule in
   lotustable.css sets `visibility: visible`, which OVERRIDES the
   inherited `visibility: hidden` we set on .board-grid above — so the
   gold marker leaks through in 3D mode. Force it hidden here. */
body.board-3d.in-game.board-3d-ready #game-board .wall-pair.wall-consumed.wall-break {
    visibility: hidden;
}

/* ---- 3D camera controls (orbit) ----------------------------------------
   Hidden by default; shown only once the 2.5D board is live (board-3d-ready).
   A small recenter button + a one-line "drag to look" hint, bottom-centre. */
.cam-controls { display: none; }
body.board-3d.board-3d-ready .cam-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    position: fixed;               /* viewport-anchored, like the decor drawer */
    left: 50%;
    bottom: 0.6rem;
    transform: translateX(-50%);
    z-index: 906;                  /* above the in-game board overlay (z 900) */
    pointer-events: none;          /* hint text is non-interactive */
}
.cam-controls .cam-hint {
    font-size: 0.72rem;
    color: rgba(245, 240, 232, 0.66);
    background: rgba(20, 28, 22, 0.42);
    padding: 0.15rem 0.5rem;
    border-radius: 0.6rem;
    user-select: none;
    white-space: nowrap;
}
.cam-controls .cam-btn {
    pointer-events: auto;          /* but the button is clickable */
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    border: 1px solid rgba(200, 164, 90, 0.5);
    background: rgba(20, 28, 22, 0.6);
    color: #e8dfce;
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, transform 0.15s;
}
.cam-controls .cam-btn:hover {
    background: rgba(40, 52, 40, 0.85);
    transform: rotate(-40deg);
}

/* ---- scene tuning panel (advanced live look controls) ------------------
   Shown only in 2.5D board mode; collapsed to a 🎚 chip until toggled. */
.scene-tune { display: none; }
body.board-3d .scene-tune {
    display: block;
    position: fixed;               /* viewport-anchored, like the decor drawer */
    top: 3.2rem;                   /* clear of the header / connection pill */
    right: 0.6rem;
    z-index: 907;                  /* above the in-game board overlay (z 900) */
}
.scene-tune-toggle {
    width: 2rem;
    height: 2rem;
    border-radius: 0.5rem;
    border: 1px solid rgba(200, 164, 90, 0.5);
    background: rgba(20, 28, 22, 0.6);
    color: #e8dfce;
    font-size: 1.05rem;
    line-height: 1;
    cursor: pointer;
    margin-left: auto;
    display: block;
}
.scene-tune-toggle:hover { background: rgba(40, 52, 40, 0.85); }
.scene-tune-body {
    display: none;
    margin-top: 0.4rem;
    width: 14rem;
    padding: 0.6rem 0.7rem 0.7rem;
    border-radius: 0.6rem;
    border: 1px solid rgba(200, 164, 90, 0.35);
    background: rgba(16, 22, 18, 0.86);
    color: #e8dfce;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(4px);
}
.scene-tune[data-open="true"] .scene-tune-body { display: block; }
.scene-tune-body h4 {
    margin: 0 0 0.5rem;
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: #c8a45a;
}
.scene-tune-body label {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 0.2rem 0.4rem;
    margin-bottom: 0.5rem;
    font-size: 0.72rem;
}
.scene-tune-body label em {
    font-style: normal;
    color: rgba(232, 223, 206, 0.6);
    font-variant-numeric: tabular-nums;
}
.scene-tune-body input[type="range"] {
    grid-column: 1 / -1;
    width: 100%;
    accent-color: #c8a45a;
}
.scene-tune-body input[type="color"] {
    grid-column: 2;
    width: 2.2rem;
    height: 1.3rem;
    padding: 0;
    border: 1px solid rgba(200, 164, 90, 0.4);
    border-radius: 0.3rem;
    background: none;
    cursor: pointer;
}
