/* Lobby styles for Moonfall game */

/* Lobby toast — used for ephemeral confirmations like "Invite link copied" */
.lobby-toast {
    position: fixed;
    bottom: 4.5vmin;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1500;
    padding: 1.16vmin 2.32vmin;
    background: rgba(20, 20, 36, 0.95);
    color: #fff;
    border: 1px solid rgba(88, 101, 242, 0.55);
    border-radius: 999px;
    font-size: 1.62vmin;
    box-shadow: 0 0.7vmin 1.5vmin rgba(0, 0, 0, 0.5);
    pointer-events: none;
    opacity: 1;
    /* Spring-settled rise-in; the exit transition below eases it away. Every
       frame carries the full translate pair so centering never breaks. */
    animation: lobby-toast-in 0.38s cubic-bezier(0.22, 1.18, 0.32, 1);
    transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.55, 0, 0.8, 0.36);
}

@keyframes lobby-toast-in {
    from {
        opacity: 0;
        transform: translate(-50%, 1.4vmin) scale(0.96);
    }

    to {
        opacity: 1;
        transform: translate(-50%, 0) scale(1);
    }
}

.lobby-toast-exit {
    opacity: 0;
    transform: translate(-50%, 1vmin);
}

@media (prefers-reduced-motion: reduce) {
    .lobby-toast {
        animation: none;
    }
}


#lobby-view {
    display: none; /* Hidden by default until auth state is confirmed */
    /* Fill #app *above the reserved legal-footer strip* and become the scroll
       frame. main.js toggles display to `block` once auth settles; block is
       fine for a scroll container and keeps the JS show/hide state machine
       untouched. --legal-footer-h is measured live by legal-footer-fit.js so
       the panels never sit under Terms/Privacy at any language or width; the
       fallback covers the pre-JS frame. The inner .lobby-scroll does the flex
       centring so we never fight that inline display. */
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: var(--legal-footer-h, 40px);
    z-index: 10;
    text-align: center;
    overflow-y: auto;
    overflow-x: hidden;
    /* Momentum scroll on touch; the bar is invisible until needed anyway. */
    -webkit-overflow-scrolling: touch;
}

/* Centres the logo + panel column when it fits the space above the footer, and
   lets it scroll from the top (never clipped) when a long translation — German,
   French, or the CJK line metrics — makes the column taller than that space.
   `safe center` is the key: on overflow it falls back to top-alignment so the
   logo stays reachable instead of being pushed above y=0. */
.lobby-scroll {
    display: flex;
    flex-direction: column;
    /* stretch so the panels keep their full 58vmin width; the column itself is
       centred by max-width + margin:auto, and the logo centres via text-align. */
    align-items: stretch;
    justify-content: safe center;
    min-height: 100%;
    box-sizing: border-box;
    width: calc(100% - clamp(32px, 6vw, 96px));
    max-width: 1180px;
    margin: 0 auto;
    /* Fixed account/language/audio chrome may share the logo's horizontal span
       at valid data-dependent widths. Reserve its first row at every size. */
    padding-top: clamp(64px, 8vh, 96px);
    padding-bottom: clamp(16px, 2.5vh, 32px);
    /* One `gap` owns the vertical rhythm (logo ↔ panel column). Kept tight so
       the whole column fits above the footer on short viewports without
       scrolling — with a little slack for Firefox's slightly taller text
       metrics — while still breathing on tall screens via the clamp ceiling. */
    gap: clamp(12px, 2vh, 24px);
}

.lobby-command-center {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto;
    align-items: stretch;
    gap: clamp(12px, 1.5vw, 20px);
    width: 100%;
}

.lobby-panels-container {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: stretch;
    gap: clamp(12px, 1.5vw, 20px);
}
.lobby-scroll .logo-container {
    margin-bottom: 0;
}
.lobby-scroll #game-logo {
    width: clamp(132px, 18vmin, 220px);
    max-width: 220px;
}

/* The wordmark is a presentation-only desktop toy. Animate the image rather
   than its layout box so the command center never shifts when it bounces. */
.lobby-logo-toy {
    display: inline-grid;
    place-items: center;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    color: inherit;
    line-height: 0;
    cursor: pointer !important;
}

.lobby-logo-toy:hover:not([disabled]) {
    background: transparent;
    color: inherit;
    box-shadow: none;
}

.lobby-logo-toy:disabled {
    background: transparent;
    border: 0;
    opacity: 1;
    cursor: default !important;
}

.lobby-logo-toy:focus-visible {
    outline: 2px solid rgba(167, 139, 250, 0.9);
    outline-offset: 5px;
}

@keyframes lobbyLogoBounce {
    0%, 100% { transform: none; }
    16% { transform: translateY(3px) rotate(-1.8deg) scale(0.94); }
    43% { transform: translateY(-9px) rotate(2.3deg) scale(1.09); }
    68% { transform: translateY(2px) rotate(-1deg) scale(0.98); }
    84% { transform: translateY(-2px) rotate(0.4deg) scale(1.02); }
}

@keyframes lobbyLogoGlow {
    0%, 100% { filter: none; }
    50% { filter: drop-shadow(0 0 20px rgba(167, 139, 250, 0.7)); }
}

@media (min-width: 761px) and (hover: hover) and (pointer: fine) {
    .lobby-logo-toy.is-playing #game-logo {
        animation: lobbyLogoBounce 0.68s cubic-bezier(0.2, 0.82, 0.22, 1);
        transform-origin: 50% 70%;
        will-change: transform;
    }
}

@media (prefers-reduced-motion: reduce) {
    .lobby-logo-toy.is-playing #game-logo {
        animation: lobbyLogoGlow 0.26s linear !important;
        transform: none !important;
        will-change: filter;
    }
}
.lobby-panels-container > .panel {
    margin-bottom: 0;
    display: flex;
    flex-direction: column;
}

/* Short viewports (small/un-maximized landscape windows): compact the hero and
   spacing so the full menu — including the last panel's buttons — fits above
   the legal footer even in the wordiest locales (German/French wrap; CJK line
   metrics run tall). Normal-height screens keep the roomier spacing above. */
@media (max-height: 700px) {
    #game-logo {
        max-width: min(24vmin, 210px);
    }
    .lobby-scroll {
        padding-top: 56px;
        padding-bottom: 10px;
        gap: 10px;
    }
    .lobby-panels-container {
        gap: 10px;
    }
    .panel {
        padding: 1.3vmin 2.3vmin;
    }
    /* A subtitle's max-content is what a fit-content card measures against, so an
   uncapped one-line subtitle silently dictated the width of every command card.
   Let it wrap — the BUTTON is what the card exists to hold. The capped block is
   narrower than its panel, so it must centre itself: LONGHAND auto margins at
   0,3,0 specificity, because three later `.panel-subtitle` margin shorthands
   (the base rule and two width bands) all reset horizontal margins to 0 and
   pinned the grey text to the panel's left edge. */
.lobby-panels-container > .panel > .panel-subtitle,
#deck-manager .panel-subtitle {
    max-width: 24ch;
    margin-left: auto;
    margin-right: auto;
}

.panel-subtitle {
        margin-bottom: 0.8vmin;
    }
}

/* Ensure lobby is hidden when game is active */
body.game-active #lobby-view {
    display: none !important;
}

.foundry-surface-host {
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: #08050d;
}

.foundry-surface-host[hidden] {
    display: none;
}

.foundry-surface-root {
    width: 100%;
    height: 100%;
    background: #08050d;
}

body.foundry-surface-active {
    overflow: hidden;
}

/* Hide lobby chrome behind the opaque Foundry surface.
   The audio volume control stays as the deliberate exception so players can
   adjust music and sound effects while inside the Foundry. */
/* The phone-only Quests control. Desktop shows the inline rail instead and
   must never paint this; only the phone gate in mobile.css reveals it. */
.lobby-quests-btn {
    display: none;
}

body.foundry-surface-active .user-controls,
body.foundry-surface-active .language-selector {
    display: none !important;
}

body.foundry-surface-active #audio-volume-control {
    z-index: 2100 !important;
}

.panel {
    position: relative;
    box-sizing: border-box;
    min-width: 0;
    padding: clamp(16px, 1.7vw, 24px);
    margin: 0;
    overflow: hidden;
    text-align: left;
    background:
      radial-gradient(circle at 12% 0%, rgba(157, 108, 203, 0.17), transparent 42%),
      linear-gradient(145deg, rgba(22, 16, 31, 0.94), rgba(8, 7, 14, 0.9));
    border: 1px solid rgba(232, 211, 239, 0.24);
    border-radius: clamp(12px, 1.2vw, 18px);
    box-shadow: 0 16px 38px rgba(0, 0, 0, 0.32), inset 0 1px rgba(255, 255, 255, 0.04);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
}

.panel::before {
    content: '';
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: linear-gradient(180deg, #e4c263, rgba(147, 91, 185, 0.55));
}

.panel h2 {
    margin: 0 0 6px;
    color: #f4e9f6;
    font-size: clamp(18px, 1.7vw, 26px);
    letter-spacing: 0.035em;
}

#pvp-game {
    width: 100%;
    margin: 0 auto;
}

#pvp-game .button-row {
    display: block;
    align-items: stretch;
    container-type: inline-size;
    gap: clamp(8px, 0.8vmin, 12px);
    margin-top: auto;
    margin-bottom: 8px;
}

/* PvP is a compact control surface inside a bounded panel, so its typography
   and padding must also be bounded by the component rather than a 4K viewport.
   This keeps localized labels horizontal and leaves the flex row room to fit. */
#pvp-game button,
#pvp-game #room-code-input,
#pvp-game .pvp-discord-link {
    font-size: clamp(13px, 1.25vmin, 18px);
    line-height: 1.2;
}

#pvp-game button,
#pvp-game .pvp-discord-link {
    padding: clamp(8px, 0.85vmin, 12px) clamp(12px, 1.25vmin, 18px);
    /* Global controls use `transition: all`; responsive typography and padding
       must snap together or Discord briefly outruns its sibling buttons while
       a viewport rotates/resizes. Keep only visual interaction properties
       animated so the row is geometrically stable on the first rendered frame. */
    transition-property: background-color, color, border-color, box-shadow, opacity, transform;
}

.pvp-room-actions,
.room-invite-actions {
    display: flex;
    flex: 0 1 auto;
    min-width: 0;
    align-items: stretch;
    justify-content: center;
}

.pvp-room-actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(8px, 0.8vmin, 12px);
}

.pvp-room-actions > button,
.room-invite-actions > button {
    min-width: 0;
    max-width: 100%;
    overflow-wrap: anywhere;
    word-break: normal;
    hyphens: auto;
}

/* The row already owns spacing through gap. Global button/link margins extend
   outside the flex well at large scales and were visibly squeezing labels. */
#pvp-game > .button-row > .pvp-room-actions > button {
    margin: 0;
}

#join-room-bar {
    margin-top: 0.93vmin;
}

.room-state-head {
    width: 100%;
    min-width: 0;
    margin-top: auto;
    align-items: stretch;
    gap: clamp(6px, 0.6vmin, 10px);
}

.room-code-label {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    align-items: center;
    justify-content: center;
    /* A flex container drops the whitespace between its children, so the label
       and the code ran together as "Room Code:3d944260". (Before the words were
       wrapped for the phone the same collapse split the colon off the label
       instead — "Room Code :3d944…".) The phone hides the words out of flow,
       where a gap costs nothing. */
    gap: 0.35em;
    margin: 0;
    padding: clamp(8px, 0.85vmin, 12px);
    border-radius: 0.58vmin;
    background-color: rgba(116, 89, 128, 0.7);
    overflow-wrap: anywhere;
}

.room-state-head > .go-back-btn {
    flex: 0 1 auto;
    margin: 0;
}

.pvp-discord-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.7vmin;
    background-color: #5865F2;
    color: #fff;
    border: 1px solid #5865F2;
    padding: clamp(8px, 1.16vmin, 18px) clamp(12px, 1.74vmin, 28px);
    margin: clamp(4px, 0.58vmin, 10px);
    border-radius: clamp(4px, 0.46vmin, 8px);
    cursor: pointer;
    transition: all 0.3s ease;
    -webkit-backdrop-filter: blur(0.35vmin);
    backdrop-filter: blur(0.35vmin);
    font-size: clamp(13px, 1.85vmin, 28px);
    line-height: 1;
    text-decoration: none;
}

.pvp-discord-link:hover,
.pvp-discord-link:focus-visible {
    background-color: #4752C4;
    border-color: #ffffff;
    box-shadow: 0 0 1.16vmin rgba(88, 101, 242, 0.7);
}

.pvp-discord-link:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

.pvp-discord-link-icon {
    width: 1em;
    height: 1em;
    flex-shrink: 0;
    overflow: visible;
}

.user-controls .pvp-discord-link {
    width: 30px;
    height: 30px;
    min-width: 30px;
    min-height: 30px;
    padding: 0;
    margin: 0;
    gap: 0;
    border-radius: 999px;
    box-sizing: border-box;
}

.user-controls .pvp-discord-link > span {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}

#room-info {
    margin-top: clamp(8px, 1vmin, 14px);
    padding: clamp(8px, 0.85vmin, 12px);
    background-color: rgba(116, 89, 128, 0.7);
    border-radius: 0.58vmin;
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    justify-content: center;
    align-items: center;
    gap: clamp(4px, 0.45vmin, 8px);
}

#room-info button,
#room-info .pvp-discord-link {
    margin: 0;
}

.room-invite-actions {
    gap: clamp(6px, 0.6vmin, 10px);
}

.room-invite-row {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-width: 0;
    container-type: inline-size;
    gap: clamp(6px, 0.6vmin, 10px);
}

.room-invite-row > .pvp-discord-link {
    flex: 0 0 auto;
    align-self: stretch;
}

/* The localized actions adapt inside their own left-hand group. At phone-size
   panel widths they stack there, while Discord remains the fixed right-hand
   sibling instead of wrapping below or being clipped by the lobby frame. */
@container (max-width: 280px) {
    .pvp-room-actions,
    .room-invite-actions {
        flex-direction: column;
        align-items: stretch;
    }

    /* Both Discord instances stay compact beside their stacked group — the
       initial Create/Join cluster and the created-room invite cluster. The
       doubled class outranks the landscape media block's later align-self:
       stretch on the same selector. */
    .room-invite-row > .pvp-discord-link.pvp-discord-link,
    #pvp-game > .button-row > .pvp-discord-link.pvp-discord-link {
        align-self: center;
    }
}

/* Inside room-info, the Discord button is icon-only — the glyph + Discord
   blurple is unambiguous, and the compact fixed sibling leaves maximum width
   for the localized Copy Room Code / Copy Invite Link action group. */
#room-info .pvp-discord-link > span {
    display: none;
}

#room-info .pvp-discord-link {
    gap: 0;
    padding-left: clamp(8px, 0.85vmin, 12px);
    padding-right: clamp(8px, 0.85vmin, 12px);
    min-inline-size: 24px;
    min-block-size: 24px;
    box-sizing: border-box;
}

/* Touch ergonomics: with the compact desktop chrome the lobby CTAs measure
   ~30-33px tall — under the 44px touch bar. On coarse pointers give every
   tappable lobby control a 44px minimum hit target. min-height alone does it:
   buttons auto-centre their label and the flex rows stretch with them, so
   type size, padding, and alignment stay exactly as on desktop. */
@media (pointer: coarse) {
    #tutorial-btn,
    #solo-adventure-btn,
    #create-room-btn,
    #join-room-btn,
    #copy-code-btn,
    #copy-link-btn,
    #open-foundry-btn,
    #open-collection-btn,
    #go-back-btn,
    .pvp-discord-link,
    #room-code-input {
        /* #room-code-input is sized by main.css's generic input rule (~33px);
           the lobby owns its touch bump alongside the CTAs it sits between. */
        min-height: 44px;
    }

    /* The icon-only Discord button in #room-info is compacted to 24px minimums
       above — on touch it needs the full target on BOTH axes. */
    #room-info .pvp-discord-link {
        min-inline-size: 44px;
        min-block-size: 44px;
    }
}

#game-status {
    margin-top: 2.88vmin;
}

.status-row {
    display: flex;
    justify-content: space-between;
    margin-bottom: 0.93vmin;
    font-size: clamp(11px, 1.62vmin, 24px);
}

.ready-status {
    color: #4CAF50;
    font-weight: bold;
}

.pending-status {
    color: #FFC107;
}

#single-player-panel {
    width: 100%;
    margin: 0 auto;
}

#single-player-panel .button-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    justify-content: center;
    gap: clamp(8px, 1.16vmin, 12px);
    margin-top: auto;
}

#tutorial-btn,
#solo-adventure-btn,
#create-room-btn,
#join-room-btn,
#copy-code-btn,
#copy-link-btn,
#open-foundry-btn,
#open-collection-btn,
#go-back-btn,
.pvp-discord-link,
#room-code-input {
    min-height: 44px;
}

.tutorial-resume-manga-note {
    max-width: 48ch;
    margin: 1.16vmin auto 0;
    color: #f2d680;
    font-size: clamp(11px, 1.4vmin, 20px);
    line-height: 1.35;
    text-align: center;
    text-transform: none;
}

/* These values used to live in a stray tutorial.css global that loaded later
   and won the cascade — its `margin` shorthand also zeroed the horizontal
   auto-margins that centre the 24ch-capped subtitle on short viewports,
   pinning the grey text left. The winning look now lives here, in the file
   that owns the surface. */
.panel-subtitle {
    margin: 0.5vmin 0 1.5vmin;
    font-size: 1.4vmin;
    color: rgba(238, 219, 241, 0.6);
    font-weight: normal;
    text-transform: none;
    /* even two-line wrap on narrow panels — no stranded orphan word ("AI",
       "decks"). No-op when it fits on one line, so wide widths are unchanged. */
    text-wrap: balance;
}

/* Deck Manager Panel */
#deck-manager {
    width: 100%;
    margin: 0 auto;
    grid-column: auto;
    display: flex;
    flex-direction: column;
    align-items: stretch;
}

#deck-manager h2 {
    margin-bottom: 0.58vmin;
}

#deck-manager .panel-subtitle {
    margin-bottom: clamp(12px, 1.3vw, 18px);
}

#deck-manager .button-row {
    display: grid;
    grid-template-columns: 1fr;
    align-items: stretch;
    margin-top: auto;
    gap: 10px;
}

/* Inherit default button styles for manage decks */

.go-back-btn {
    position: static;
    padding: clamp(8px, 1.16vmin, 18px) clamp(14px, 2.3vmin, 36px);
    margin: 0 auto 0.58vmin 0;
    background-color: rgba(0, 0, 0, 0.5);
    border: 1px solid rgba(238, 219, 241, 0.3);
    color: #eedbf1;
    font-family: 'Mulish', sans-serif;
    font-size: clamp(11px, 1.62vmin, 24px);
    border-radius: clamp(4px, 0.46vmin, 8px);
    cursor: pointer;
    transition: all 0.3s ease;
    z-index: 100;
    display: none;
    /* Hidden by default */
}

.go-back-btn:hover {
    background-color: rgba(238, 219, 241, 0.1);
    border-color: rgba(238, 219, 241, 0.8);
}

/* Add a class to show the button via JS */
.show-back-button .go-back-btn {
    display: block;
}

#lobby-quests {
  position: static;
  width: auto;
  min-width: 0;
  display: none;
  padding: clamp(14px, 1.6vmin, 20px);
  border-radius: clamp(10px, 1vmin, 14px);
  background: linear-gradient(135deg, rgba(20, 15, 30, 0.92), rgba(45, 26, 64, 0.88));
  border: 1px solid rgba(238, 219, 241, 0.28);
  box-shadow: 0 1.2vmin 3vmin rgba(0, 0, 0, 0.45);
  -webkit-backdrop-filter: blur(0.7vmin);
  backdrop-filter: blur(0.7vmin);
  text-align: left;
  color: #f3e9f8;
  z-index: auto;
}

#lobby-quests.is-visible {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

body.game-active #lobby-quests,
body.foundry-surface-active #lobby-quests {
  display: none;
}

.lobby-quests-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: clamp(8px, 1.1vmin, 12px);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: clamp(11px, 1.2vmin, 14px);
  color: rgba(233, 217, 243, 0.85);
}

.lobby-quests-count {
  padding: 2px 10px;
  border-radius: 999px;
  background: rgba(125, 85, 165, 0.35);
  border: 1px solid rgba(186, 152, 222, 0.35);
  font-size: clamp(11px, 1.1vmin, 13px);
  color: #f0d5ff;
}

.lobby-quests-list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  min-height: 0;
  overflow: visible;
  gap: clamp(6px, 0.9vmin, 10px);
}

.lobby-quest-item {
  display: flex;
  flex-wrap: wrap; /* the progress bar sits on its own row below */
  align-items: flex-start;
  justify-content: space-between;
  gap: clamp(8px, 1vmin, 12px);
  padding: clamp(8px, 0.9vmin, 12px);
  border-radius: clamp(8px, 0.7vmin, 10px);
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(238, 219, 241, 0.2);
  min-width: 0;
}

.lobby-quest-text {
  flex: 1;
  font-size: clamp(13px, 1.4vmin, 16px);
  line-height: 1.4;
  color: rgba(243, 233, 248, 0.95);
  min-width: 0;
  overflow-wrap: anywhere;
}

.lobby-quest-progress {
  padding: 2px 8px;
  border-radius: clamp(8px, 0.6vmin, 10px);
  font-size: clamp(11px, 1.1vmin, 13px);
  font-weight: 600;
  color: #ffd98a;
  background: rgba(255, 217, 138, 0.12);
  border: 1px solid rgba(255, 217, 138, 0.35);
  white-space: nowrap;
}

.lobby-quests-empty {
  font-size: clamp(12px, 1.2vmin, 14px);
  color: rgba(233, 217, 243, 0.6);
}

.lobby-quests-debug {
  display: flex;
  flex-direction: column;
  gap: clamp(5px, 0.7vmin, 8px);
  margin-top: clamp(8px, 1.1vmin, 12px);
}

.lobby-quests-debug-row {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(6px, 0.9vmin, 10px);
}

.lobby-quests-debug-btn {
  margin: 0;
  padding: 6px 10px;
  font-size: clamp(11px, 1.1vmin, 13px);
  background: rgba(255, 217, 138, 0.12);
  border: 1px solid rgba(255, 217, 138, 0.35);
  color: #ffe5ad;
  box-shadow: none;
}

.lobby-quests-debug-btn:hover:not([disabled]) {
  background: rgba(255, 217, 138, 0.2);
  box-shadow: 0 0 12px rgba(255, 217, 138, 0.35);
}

.lobby-quests-debug-btn[disabled] {
  opacity: 0.5;
  cursor: default;
}

/* The artificial "force complete" shortcut is visually distinct (dashed/muted)
   so it never reads as a real, rule-following action. */
.lobby-quests-debug-btn--artificial {
  background: rgba(255, 255, 255, 0.06);
  border-style: dashed;
  color: rgba(255, 229, 173, 0.75);
}

.lobby-quests-debug-status {
  margin: 0;
  min-height: 1.2em;
  font-size: clamp(10px, 1vmin, 12px);
  line-height: 1.3;
  color: rgba(255, 255, 255, 0.72);
}

.lobby-quests-debug-status[data-tone="error"] {
  color: #ff9d9d;
}

@media (max-width: 1100px), (max-aspect-ratio: 10/7) {
  .lobby-command-center {
    grid-template-columns: 1fr;
  }

  #lobby-quests {
    width: 100%;
  }

  .lobby-quests-list {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 900px) {
  .lobby-scroll {
    padding-top: 86px;
  }
}

@media (max-width: 600px) {
  .lobby-scroll {
    padding-top: 130px;
  }
}

@media (max-width: 720px) {
  .lobby-panels-container {
    grid-template-columns: 1fr;
  }

  #deck-manager {
    grid-column: auto;
    display: block;
  }

  #deck-manager .button-row {
    margin-top: 12px;
  }

  .lobby-quests-list {
    grid-template-columns: 1fr;
  }
}

/* Quest progress bar: animated fill + one-shot tick pulse when progress
   advances (the quest list previously showed only a bare wins/target). */
.lobby-quest-bar {
    flex-basis: 100%;
    width: 100%;
    height: 5px;
    margin-top: 4px;
    border-radius: 3px;
    background: rgba(238, 219, 241, 0.12);
    overflow: hidden;
}

.lobby-quest-bar-fill {
    height: 100%;
    border-radius: 3px;
    background: linear-gradient(90deg, rgba(160, 110, 220, 0.85), rgba(238, 190, 91, 0.9));
    transition: width 400ms cubic-bezier(0.2, 0.9, 0.3, 1);
}

.lobby-quest-item--tick {
    animation: lobby-quest-tick 600ms ease-out;
}

.lobby-quest-item--tick .lobby-quest-bar-fill {
    position: relative;
    overflow: hidden;
}

.lobby-quest-item--tick .lobby-quest-bar-fill::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(105deg, transparent 30%, rgba(255, 244, 214, 0.85) 50%, transparent 70%);
    animation: lobby-quest-shine 700ms ease-out 150ms both;
}

@keyframes lobby-quest-tick {
    0% { filter: brightness(1); }
    30% { filter: brightness(1.45); }
    100% { filter: brightness(1); }
}

@keyframes lobby-quest-shine {
    from { transform: translateX(-120%); }
    to { transform: translateX(120%); }
}

@media (prefers-reduced-motion: reduce) {
    .lobby-quest-item--tick,
    .lobby-quest-item--tick .lobby-quest-bar-fill::after {
        animation: none;
    }
}

/* "Searching for opponent" — a soft breathing pulse so the wait reads as an
   active search rather than a frozen panel. Cleared at the match-found handoff. */
#waiting-host.waiting-host--searching p {
    animation: waiting-host-breathe 1.6s ease-in-out infinite;
}

#waiting-host {
    align-items: center;
    justify-content: center;
    gap: clamp(6px, 0.6vmin, 10px);
}

#waiting-host > p {
    margin: 0;
}

@keyframes waiting-host-breathe {
    0%, 100% {
        opacity: 0.55;
    }
    50% {
        opacity: 1;
        text-shadow: 0 0 10px rgba(185, 154, 220, 0.6);
    }
}

@media (prefers-reduced-motion: reduce) {
    #waiting-host.waiting-host--searching p {
        animation: none;
        opacity: 1;
    }
}

/* Desktop lobby intentionally mirrors origin/main. */
@media (orientation: landscape) and (min-height: 561px),
       (orientation: portrait) and (min-width: 769px) {
    .lobby-scroll {
        width: 90%;
        max-width: 58vmin;
        padding-top: 52px;
        padding-bottom: clamp(4px, 0.8vmin, 12px);
        gap: clamp(5px, 0.95vmin, 15px);
    }

    .lobby-command-center {
        display: block;
        width: 100%;
    }

    .lobby-panels-container {
        display: flex;
        flex-direction: column;
        gap: clamp(5px, 0.95vmin, 15px);
        /* Cards are sized by their CONTENTS, not by the column they sit in.
           Stretching them to the full 58vmin scroll column left 69-70% empty
           space around the Single Player and Moon Foundry buttons — measured at
           1920x1080: a 626px card holding a 177px button. Centre and let each
           card be as wide as it needs. */
        align-items: center;
        width: 100%;
    }

    .lobby-panels-container > .panel {
        width: fit-content;
        max-width: 100%;
        min-width: min(100%, 15rem);
    }

    .lobby-scroll #game-logo {
        width: 100%;
        max-width: 42vmin;
    }

    .lobby-panels-container > .panel {
        display: block;
        margin-bottom: 0;
    }

    .panel {
        position: static;
        overflow: visible;
        padding: 1.85vmin 2.3vmin;
        text-align: center;
        background: rgba(0, 0, 0, 0.7);
        border: 1px solid rgba(238, 219, 241, 0.5);
        border-radius: 0.46vmin;
        box-shadow: none;
        -webkit-backdrop-filter: blur(0.58vmin);
        backdrop-filter: blur(0.58vmin);
    }

    .panel::before {
        display: none;
    }

    .panel h2 {
        margin: 0 0 1.74vmin;
        color: #eedbf1;
        font-size: clamp(18px, 3.5vmin, 56px);
        letter-spacing: normal;
    }

    #pvp-game > .panel-subtitle {
        display: none;
    }

    .panel-subtitle {
        margin-bottom: 1.74vmin;
        font-size: clamp(11px, 1.62vmin, 24px);
        text-wrap: wrap;
    }

    #pvp-game .button-row {
        display: flex;
        justify-content: center;
        align-items: center;
        flex-wrap: nowrap;
        gap: 1.16vmin;
        margin-top: 0;
        margin-bottom: 1.16vmin;
    }

    #pvp-game .pvp-room-actions {
        display: flex;
        flex: 0 1 auto;
        gap: 1.16vmin;
    }

    #pvp-game button,
    #pvp-game #room-code-input,
    #pvp-game .pvp-discord-link {
        font-size: clamp(13px, 1.85vmin, 28px);
        line-height: normal;
    }

    #pvp-game button,
    #pvp-game .pvp-discord-link {
        padding: clamp(8px, 1.16vmin, 18px) clamp(12px, 1.74vmin, 28px);
    }

    #pvp-game > .button-row > .pvp-room-actions > button {
        margin: clamp(4px, 0.58vmin, 10px);
    }

    #pvp-game > .button-row > .pvp-discord-link {
        flex: 0 0 auto;
        align-self: stretch;
    }

    #tutorial-btn,
    #solo-adventure-btn,
    #create-room-btn,
    #join-room-btn,
    #copy-code-btn,
    #copy-link-btn,
    #open-foundry-btn,
    #open-collection-btn,
    #go-back-btn,
    .pvp-discord-link,
    #room-code-input {
        min-height: 0;
    }

    #room-info {
        margin-top: 1.74vmin;
        padding: 1.16vmin;
        gap: 0.58vmin;
    }

    .room-invite-actions,
    .room-invite-row {
        gap: 0.58vmin;
    }

    #room-info .pvp-discord-link {
        padding-left: 1.16vmin;
        padding-right: 1.16vmin;
    }

    #single-player-panel .button-row {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        gap: 1.16vmin;
        margin-top: 1.16vmin;
    }

    #deck-manager {
        display: block;
    }

    #deck-manager .panel-subtitle {
        margin-bottom: 1.74vmin;
    }

    #deck-manager .button-row {
        display: block;
        margin-top: 0;
    }

    #lobby-quests {
        position: fixed;
        left: 2.3vmin;
        bottom: calc(var(--legal-footer-h, 40px) + 1vmin);
        width: clamp(280px, 28vw, 420px);
        min-width: 0;
        z-index: 15;
    }

    #lobby-quests.is-visible {
        display: block;
    }

    .lobby-quests-list {
        display: flex;
        flex-direction: column;
        gap: clamp(6px, 0.9vmin, 10px);
    }
}

/* Keep the origin/main desktop composition while its left quest rail has
   room. At tablet/narrow-desktop widths that rail would intersect the centred
   panel column, so return Quests to document flow below the panels. This rule
   intentionally follows the desktop-parity block so the collision fallback
   remains authoritative at 1024x768 and similarly square aspect ratios. */
@media (max-width: 1100px), (max-aspect-ratio: 10/7) {
    #lobby-quests {
        position: static;
        left: auto;
        bottom: auto;
        width: min(90vw, 420px);
        margin: clamp(5px, 0.95vmin, 15px) auto 0;
        z-index: auto;
    }
}

/* Common 768px-tall laptops also need this compact stacked composition:
   Gecko's Japanese line metrics otherwise push the final Foundry action under
   the legal footer. Squarer tablets are overridden by the tablet canvas below. */
@media (orientation: landscape) and (min-height: 561px) and (max-height: 800px) {
    .lobby-scroll #game-logo {
        max-width: 32vmin;
    }

    .lobby-scroll {
        padding-bottom: 4px;
        gap: clamp(4px, 0.9vmin, 10px);
    }

    .lobby-panels-container {
        gap: clamp(4px, 0.9vmin, 10px);
    }

    .panel {
        padding: 1.3vmin 2.3vmin;
    }
}

/* Landscape tablets use the modern command canvas: three equal play cards and
   an in-flow quest ribbon. This deliberately excludes wide/short laptops and
   every phone breakpoint, preserving their established compositions. */
@media (orientation: landscape) and (min-width: 960px) and (min-height: 561px) and (max-width: 1560px) and (max-aspect-ratio: 17/10) {
    /* DENSE, NOT STRETCHED — the phone's lobby at tablet scale.

       Measured at 1366x1024 before this band changed: the column came to 572px
       inside a 997px box, so 43% of an iPad's lobby was air, and the three play
       cards were 401x287 with their buttons pinned to the bottom edge by
       `margin-top: auto` — a hollow band between the subtitle and the controls.
       Growing the cards to fill the canvas was tried and measured WORSE: 568px
       cards with the same buttons stranded at the bottom of a bigger void, and
       the quest ribbon driven into the referral rail.

       The phone gets this right by sizing each card to its CONTENT and stacking
       the results tightly, which is what makes that screen read as an app
       rather than a page. This band now does the same at a tablet's scale. */
    .lobby-scroll {
        width: calc(100% - clamp(32px, 5vw, 64px));
        max-width: 1240px;
        padding-top: clamp(52px, 6vh, 72px);
        padding-bottom: clamp(12px, 2vh, 24px);
        gap: clamp(14px, 1.8vh, 20px);
    }

    .lobby-command-center {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto auto;
        gap: clamp(14px, 1.4vw, 20px);
        width: 100%;
    }

    /* Created-room copy grows vertically in long locales. Reclaim decorative
       spacing in that state so the logo, real quests, Feedback, and every
       52px room action remain inside the tablet canvas without shrinking. */
    #lobby-view.show-back-button .lobby-scroll {
        padding-bottom: 0;
    }

    #lobby-view.show-back-button .lobby-command-center {
        gap: 10px;
    }

    .lobby-panels-container {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        align-items: stretch;
        gap: clamp(12px, 1.4vw, 20px);
    }

    .lobby-scroll #game-logo {
        width: clamp(224px, 27vmin, 276px);
        max-width: 276px;
    }

    .lobby-panels-container > .panel {
        position: relative;
        display: flex;
        flex-direction: column;
        min-width: 0;
        /* A FLOOR, not a filled box. The floor is not what made the card
           hollow — `margin-top: auto` was, by flinging the controls to the far
           edge of it. With the controls following their subtitle, spare height
           falls harmlessly to the bottom of the card, so the tablet keeps the
           substantial 244px command card `lobby.spec.js` requires ("command
           cards use the available tablet height") without the void.
           24vmin rather than 28vmin: at 1024x768 the old value resolved to the
           288px cap, which is 45px more than the content needs. */
        min-height: clamp(244px, 24vmin, 288px);
        margin: 0;
        padding: clamp(20px, 2vw, 28px);
        overflow: hidden;
        text-align: left;
        background:
          radial-gradient(circle at 12% 0%, rgba(157, 108, 203, 0.17), transparent 42%),
          linear-gradient(145deg, rgba(22, 16, 31, 0.94), rgba(8, 7, 14, 0.9));
        border: 1px solid rgba(232, 211, 239, 0.24);
        border-radius: clamp(12px, 1.2vw, 18px);
        box-shadow: 0 16px 38px rgba(0, 0, 0, 0.32), inset 0 1px rgba(255, 255, 255, 0.04);
        -webkit-backdrop-filter: blur(12px);
        backdrop-filter: blur(12px);
    }

    .lobby-panels-container > .panel::before {
        display: block;
    }

    .lobby-panels-container > .panel h2 {
        margin: 0 0 8px;
        color: #f4e9f6;
        font-size: clamp(22px, 2vw, 28px);
        letter-spacing: 0.035em;
    }

    #pvp-game > .panel-subtitle {
        display: block;
    }

    .lobby-panels-container .panel-subtitle,
    #deck-manager .panel-subtitle {
        margin: 0 0 clamp(12px, 1.2vw, 16px);
        font-size: clamp(15px, 1.3vw, 18px);
        line-height: 1.4;
    }

    /* This band composes the whole card left — title, subtitle, actions. Undo
       the short-viewport auto-centring (which outranks the shorthand above) so
       a 24ch-capped subtitle stays left with the rest of the composition. */
    .lobby-panels-container > .panel > .panel-subtitle,
    #deck-manager .panel-subtitle {
        margin-left: 0;
        margin-right: 0;
    }

    /* TWO ACROSS, like the phone. A single column of full-width buttons in a
       400px card is a desktop shape; the phone puts its pair side by side, and
       that is what keeps each card short enough to sit tight against the next.
       `margin-top: auto` goes with the forced height that needed it — the
       controls now follow their subtitle instead of being pushed to an edge
       that no longer exists. */
    #single-player-panel .button-row,
    #deck-manager .button-row {
        display: grid;
        /* PAIRED WHERE IT FITS, stacked where it does not. An unconditional
           two-column grid halves each button, and at 1024x768 that left German
           `lobby.openFoundry` needing 122px in a 121px content box — one pixel
           of clipping, in one locale, on the narrowest tablet. `auto-fit` with
           a 150px floor keeps the pair on the wide tablets that can pay for it
           and falls back to a single column on the ones that cannot, instead of
           trusting that every translation fits the same box. */
        grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
        gap: clamp(10px, 1vw, 12px);
        margin-top: 0;
    }

    #pvp-game .button-row {
        display: flex;
        align-items: stretch;
        gap: clamp(10px, 1vw, 12px);
        margin-top: 0;
        margin-bottom: clamp(10px, 1vw, 12px);
    }

    #pvp-game .pvp-room-actions {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        /* The tablet grid is physically one row even when the inherited
           narrow-container flex fallback matches. Keep the computed contract
           aligned with that rendered row for localized labels and QA. */
        flex-direction: row;
        flex: 1 1 auto;
        gap: clamp(10px, 1vw, 12px);
    }

    #room-info .room-invite-row {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 52px;
        align-items: stretch;
        gap: clamp(10px, 1vw, 12px);
    }

    #room-info .room-invite-actions {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        flex-direction: row;
        align-items: stretch;
        min-width: 0;
        gap: clamp(10px, 1vw, 12px);
    }

    #room-info .room-invite-actions > button {
        min-width: 0;
        white-space: normal;
    }

    #room-info .pvp-discord-link {
        align-self: stretch;
        min-inline-size: 52px;
        min-block-size: 52px;
        min-height: 52px;
        padding: 8px;
    }

    #pvp-game > .button-row > .pvp-room-actions > button,
    #pvp-game > .button-row > .pvp-discord-link {
        margin: 0;
    }

    /* The tablet grid renders the actions as a physical row even when the
       narrow-container stack query matches, so Discord returns to the shared
       equal-height row (doubled class outranks the container-query center). */
    #pvp-game > .button-row > .pvp-discord-link.pvp-discord-link,
    #room-info .room-invite-row > .pvp-discord-link.pvp-discord-link {
        align-self: stretch;
    }

    #pvp-game button,
    #pvp-game #room-code-input,
    #pvp-game .pvp-discord-link {
        font-size: clamp(16px, 1.3vw, 18px);
        line-height: 1.2;
    }

    #single-player-panel button,
    #deck-manager button {
        font-size: clamp(16px, 1.3vw, 18px);
        line-height: 1.2;
    }

    #pvp-game button,
    #pvp-game .pvp-discord-link {
        padding: 8px clamp(8px, 1vw, 14px);
    }

    #tutorial-btn,
    #solo-adventure-btn,
    #create-room-btn,
    #join-room-btn,
    #copy-code-btn,
    #copy-link-btn,
    #open-foundry-btn,
    #open-collection-btn,
    #go-back-btn,
    .pvp-discord-link,
    #room-code-input {
        min-height: 52px;
    }

    #tutorial-btn,
    #solo-adventure-btn,
    #create-room-btn,
    #join-room-btn,
    #copy-code-btn,
    #copy-link-btn,
    #open-foundry-btn,
    #open-collection-btn,
    #go-back-btn,
    .pvp-discord-link {
        transition-property: background-color, color, border-color, box-shadow, opacity, transform;
    }

    #lobby-quests {
        position: static;
        left: auto;
        bottom: auto;
        width: 100%;
        margin: 0;
        padding: clamp(14px, 1.4vw, 18px);
        z-index: auto;
    }

    #lobby-quests.is-visible {
        display: flex;
    }

    .lobby-quests-list {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: clamp(10px, 0.9vw, 12px);
    }

    .lobby-quests-list:has(.lobby-quest-item:first-child:nth-last-child(1)) {
        grid-template-columns: minmax(0, 1fr);
    }

    .lobby-quests-list:has(.lobby-quest-item:first-child:nth-last-child(2)) {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .lobby-quest-item {
        min-height: 72px;
        padding: clamp(10px, 0.9vw, 14px);
    }

    .lobby-quest-text {
        font-size: clamp(14px, 1.2vw, 16px);
        line-height: 1.35;
    }

    .lobby-quests-header,
    .lobby-quests-empty {
        font-size: clamp(14px, 1.15vw, 15px);
    }

    .lobby-quests-count,
    .lobby-quest-progress {
        font-size: clamp(12px, 1vw, 14px);
    }
}

/* Keep the same substantial type and 52px actions at the shallow edge of the
   tablet band, while reclaiming decorative height so the complete command
   canvas remains visible without a browser-like scroll lane. */
@media (orientation: landscape) and (min-width: 960px) and (min-height: 561px) and (max-height: 700px) and (max-width: 1560px) and (max-aspect-ratio: 17/10) {
    .lobby-scroll {
        padding-top: 56px;
        padding-bottom: 0;
        gap: 8px;
    }

    .lobby-command-center {
        gap: 8px;
    }

    .lobby-scroll #game-logo {
        width: 160px;
        max-width: 160px;
    }

    .lobby-panels-container {
        gap: 10px;
    }

    .lobby-panels-container > .panel {
        min-height: 200px;
        padding: 14px;
    }

    .lobby-panels-container .panel-subtitle,
    #deck-manager .panel-subtitle {
        margin-bottom: 8px;
    }

    #single-player-panel .button-row,
    #deck-manager .button-row,
    #pvp-game .button-row {
        gap: 8px;
    }

    #pvp-game .button-row {
        margin-bottom: 8px;
    }

    #lobby-quests {
        padding: 10px;
    }

    .lobby-quests-header {
        margin-bottom: 6px;
    }

    .lobby-quests-list {
        gap: 8px;
    }

    .lobby-quest-item {
        min-height: 64px;
        padding: 8px;
    }
}
