/**
 * War 2050 - Game UI Layout
 * Full-screen canvas with floating HUD overlays
 */

/* =================================================================
   FULL-SCREEN GAME CANVAS
   ================================================================= */

.game-fullscreen {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100vw;
    height: 100vh;
    z-index: var(--z-canvas);

    /* A HORIZON, NOT A FIELD.
       At the default phone zoom this surface is 90% of the screen and it was a
       single flat #0a0f1a, so the base read as a plate cut out and laid on
       nothing: measured, the ground was relative luminance 0.208 against a
       backdrop of 0.005, a 4.71:1 step with no values in between. That is the
       signature of a cut-out rather than a place.

       The linear ramp puts a mid-tone band across the middle of the screen,
       which the eye reads as distance; the radial darkens the corners so the
       brightest thing on screen ends up being the buildings' lit windows
       rather than empty ground.

       The canvas above this is deliberately transparent. `gameCanvas.js`
       claimed that was to show a background image which nothing has ever
       served to this page — so this is the surface that comment was reserving,
       finally occupied. */
    /* The three stops are custom properties so dayNight.js can move them with
       the sun. Defaults are the daytime values, so a page that never loads the
       script still gets the graded backdrop rather than a flat field.

       The vignette does NOT move. It is a framing device rather than weather —
       tying it to the time of day would make the corners crawl for no reason. */
    background:
        radial-gradient(118% 78% at 50% 42%,
            rgba(0, 0, 0, 0) 0%,
            rgba(0, 0, 0, 0) 44%,
            rgba(0, 0, 0, 0.40) 78%,
            rgba(0, 0, 0, 0.66) 100%),
        linear-gradient(180deg,
            var(--sky-top, #070b14) 0%,
            var(--sky-band, #17212f) 50%,
            var(--sky-bottom, #090e18) 100%);
    /* NO TRANSITION HERE. A gradient cannot be interpolated on the GPU, so
       transitioning one repaints the entire viewport every frame for as long as
       it runs — on a phone that is a stall, and it fired every time the sky
       moved. If the sky ever needs to ease rather than step, cross-fade a
       second layer's opacity instead; opacity IS compositable. */
    overflow: hidden;
}

.game-fullscreen canvas {
    display: block;
    width: 100% !important;
    height: 100% !important;
}

/* Loading state for canvas */
.game-fullscreen .canvas-loading {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    color: var(--color-text-muted);
    z-index: 10; /* stacking within .game-fullscreen only, not the region ladder - exempt per §2, same reasoning as .popup-close */
}

.game-fullscreen .canvas-loading.hidden {
    display: none;
}

/* =================================================================
   FLOATING GAME HUD
   ================================================================= */

.game-hud {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    pointer-events: none;
    z-index: var(--z-hud);
}

.game-hud.hidden {
    display: none;
}

/* All HUD children receive pointer events */
.game-hud > * {
    pointer-events: auto;
}

/* =================================================================
   TOP LEFT HUD CONTAINER
   Wraps profile and resources for consistent width alignment
   ================================================================= */

.top-left-hud {
    position: fixed;
    top: calc(var(--space-4) + var(--safe-top));
    left: calc(var(--space-4) + var(--safe-left));
    display: inline-flex;
    flex-direction: column;
    gap: 3px;
    z-index: var(--z-hud);
    /* Regions A and B are independently anchored to opposite corners with
       no shared parent, so nothing stops them meeting in the middle on a
       narrow screen. Measured at 360px: A ended at x=188 and B began at
       x=190 - a 2px gap, i.e. one more character of callsign away from a
       collision. Splitting the width guarantees a gap instead of leaving
       it to the content. */
    max-width: calc(52% - var(--space-3));
    min-width: 0;
}

/* =================================================================
   TOP RIGHT HUD CONTAINER
   Overseer box + Life bar stacked vertically
   ================================================================= */

.top-right-hud {
    position: fixed;
    top: calc(var(--space-4) + var(--safe-top));
    right: calc(var(--space-4) + var(--safe-right));
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-2);
    z-index: var(--z-hud);
    /* See .top-left-hud - the other half of the same guarantee. */
    max-width: calc(48% - var(--space-3));
    min-width: 0;
}

/* Both corner blocks are content-sized; without this the Overseer box and
   the life bar can push past the max-width above instead of honouring it. */
.top-left-hud > *,
.top-right-hud > * {
    max-width: 100%;
}

/* =================================================================
   RESOURCES BAR (Below user profile, inside top-left-hud)
   ================================================================= */

.resource-bar-floating {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 3px;
    width: 100%;
    /* Safety valve, not a layout mode. Three chips of 12px Orbitron need
       ~200px and region A gives 219px at 412 and 206px at 390, so this never
       fires at either of the target widths. Below ~370px it does, and one
       wrapped row of chips is a better failure than three chips spilling out
       of region A into the Overseer's box. */
    flex-wrap: wrap;
}

.resource-bar-floating .resource-item {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 4px 8px;
    background: rgba(26, 39, 68, 0.95);
    border: 1px solid rgba(212, 175, 55, 0.2);
    border-radius: var(--radius-sm);
    backdrop-filter: blur(4px);
    flex: 1;
}

.resource-bar-floating .resource-icon {
    width: 14px;
    height: 14px;
}

.resource-bar-floating .resource-icon.gold { color: var(--color-accent-gold); }
.resource-bar-floating .resource-icon.energy { color: var(--color-accent-cyan); }
.resource-bar-floating .resource-icon.materials { color: var(--color-accent-green); }
.resource-bar-floating .resource-icon.bonds { color: var(--color-accent-bond); }
.resource-icon.bonds { color: var(--color-accent-bond); }

.resource-bar-floating .resource-value {
    font-family: var(--font-display);
    /* 11px -> the 12px floor. Orbitron is a wide face, so the three chips buy
       the width back from padding and gap rather than from the digits
       (docs/TYPE-LEGIBILITY.md rule 6) - see the breakpoint blocks below. */
    font-size: var(--text-xs);
    font-weight: var(--font-bold);
    color: var(--color-text-primary);
    letter-spacing: 0.02em;
    line-height: 1.25;
}

/* =================================================================
   ACTION BUTTONS (Bottom Center)
   ================================================================= */

.action-buttons-floating {
    position: fixed;
    bottom: var(--region-c-offset);
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: rgba(10, 15, 26, 0.9);
    border: 1px solid rgba(212, 175, 55, 0.2);
    border-radius: var(--radius-lg);
    backdrop-filter: blur(8px);
    z-index: var(--z-hud);
    /* Guard against any other stylesheet's generic .action-bar-left/-right
       rule (e.g. the unrelated dead .action-bar component in components.css)
       ever reintroducing a wrap here. Region C is a single row at every
       breakpoint above the phone threshold - see docs/HUD-LAYOUT.md §3 and
       the arithmetic in the 640px block below, which is why phone is now
       the documented exception. */
    flex-wrap: nowrap;
    /* Region C must never be wider than the screen it sits on. Without
       this the bar simply overflows: measured at 635px wide on a 390px
       viewport, putting Build/Units/Research/Map entirely off-screen to
       the left (elementFromPoint over #btn-build returned null - the
       button could not be tapped at all). --region-c-height backs the
       token in variables.css that every panel above derives its offset
       from; declaring it here keeps the two from drifting. */
    max-width: calc(100vw - var(--safe-left) - var(--safe-right));
    min-height: var(--region-c-height);
}

.action-buttons-floating .action-bar-left,
.action-buttons-floating .action-bar-right {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: nowrap;
}

.action-buttons-floating .action-bar-left {
    padding-right: var(--space-4);
    border-right: 1px solid rgba(212, 175, 55, 0.2);
}

/* The icon cluster is declared 44x44 in components.css but was rendering
   at ~40px wide because flex let it shrink inside the over-wide bar.
   Pinning the basis keeps the WCAG 2.5.5 minimum real rather than
   nominal (§7 asks for the padded hit area to be confirmed, not assumed). */
.action-buttons-floating .btn-icon {
    flex: 0 0 var(--touch-target);
    min-width: var(--touch-target);
    min-height: var(--touch-target);
}

/* The skip button's own padding made it 46px tall, 2px more than every
   other control in the row, which is exactly the amount by which the bar
   overran --region-c-height and put the tutorial strip back on top of it.
   Pinning it to the same 44px as its neighbours makes the token and the
   rendered height agree - the layout probe asserts they do. */
.action-buttons-floating .tutorial-skip-btn {
    height: var(--touch-target);
    min-height: var(--touch-target);
    padding-top: 0;
    padding-bottom: 0;
}

/* =================================================================
   USER PROFILE (Inside top-left-hud container)
   ================================================================= */

.user-profile-floating {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    background: rgba(26, 39, 68, 0.95);
    border: 1px solid rgba(212, 175, 55, 0.3);
    border-radius: var(--radius-md);
    backdrop-filter: blur(4px);
    cursor: pointer;
    transition: all var(--transition-fast);
}

.user-profile-floating:hover {
    background: rgba(212, 175, 55, 0.1);
    border-color: var(--color-accent-gold);
}

.user-profile-floating .user-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--color-primary-600);
    border: 1px solid var(--color-accent-gold);
    object-fit: cover;
}

.user-profile-floating .user-info {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.user-profile-floating .user-name {
    font-size: var(--text-xs);
    font-weight: var(--font-semibold);
    color: var(--color-text-primary);
    line-height: 1.25;
    letter-spacing: 0.02em;
}

.user-profile-floating .user-rank {
    /* Was 10px, and 8px on a phone - an uppercase, letter-spaced label at 8px
       is the exact combination docs/TYPE-LEGIBILITY.md rule 5 calls the worst
       possible one. The tracking comes down instead of the size. */
    font-size: var(--text-xs);
    color: var(--color-accent-gold);
    text-transform: uppercase;
    line-height: 1.25;
    letter-spacing: 0.02em;
}

/* =================================================================
   HIDDEN STATE
   ================================================================= */

.hidden {
    display: none !important;
}

/* =================================================================
   RESPONSIVE ADJUSTMENTS
   Single breakpoint set per docs/HUD-LAYOUT.md §3: 1024 (Tablet) and
   640 (Phone). The old 768/480 thresholds are retired - see the
   contract for why they no longer earn their own breakpoint.
   ================================================================= */

@media (max-width: 1024px) {
    .top-left-hud {
        top: calc(var(--space-2) + var(--safe-top));
        left: calc(var(--space-2) + var(--safe-left));
    }

    .top-right-hud {
        top: calc(var(--space-2) + var(--safe-top));
        right: calc(var(--space-2) + var(--safe-right));
    }

    .user-profile-floating {
        padding: 5px 8px;
        gap: 6px;
    }

    .user-profile-floating .user-avatar {
        width: 24px;
        height: 24px;
    }

    /* No font-size steps here any more. Region A used to shrink its type at
       every breakpoint (12/11/10 for the callsign, 10/9/8 for the rank,
       11/10/9 for the resource values) and by the phone breakpoint all three
       were unreadable. Type holds at the 12px floor across all three
       breakpoints; what shrinks instead is padding, gap and icon size. */
    .resource-bar-floating .resource-item {
        padding: 3px 5px;
        gap: 3px;
    }

    .resource-bar-floating .resource-icon {
        width: 12px;
        height: 12px;
    }

    .action-buttons-floating {
        padding: var(--space-2);
        gap: var(--space-2);
    }

    .action-buttons-floating .btn {
        padding: var(--space-2);
        font-size: var(--text-xs);
    }
}

/* Tablet, narrow end (641-820px): §3 says the four primaries keep their
   labels across the whole tablet range. Measured, they cannot - region C
   holds ten controls, and at 641px the labelled version renders ~662px
   wide, i.e. it overflows the viewport it is centred in. Rather than add
   a sixth breakpoint (§3 exists to remove those), the icon-only collapse
   that already fires at 640 is extended just far enough up to cover the
   range where the labels do not fit. Above 820px the labels are back. */
@media (min-width: 641px) and (max-width: 820px) {
    .action-buttons-floating #btn-build,
    .action-buttons-floating #btn-units,
    .action-buttons-floating #btn-research,
    .action-buttons-floating #btn-map,
    .action-buttons-floating #btn-menu {
        font-size: 0;
        gap: 0;
        padding: 0;
        min-width: var(--touch-target);
        min-height: var(--touch-target);
    }
}

/* Phone (<=640px): action bar labels collapse to icon-only for the four
   primary buttons instead of wrapping to a second row (the old flex-wrap
   behaviour ate into centre stage - see §3 "Tablet -> Phone"). The four
   IDs are stable hooks already in index.html; hiding the text node via
   font-size:0 leaves the SVG icon (sized with HTML width/height
   attributes, not em units) untouched. Menu keeps its label per the
   contract; the zoom/menu cluster was already icon-only. */
@media (max-width: 640px) {
    .user-profile-floating {
        padding: 4px 6px;
    }

    .user-profile-floating .user-avatar {
        width: 22px;
        height: 22px;
    }

    /* THE PHONE WIDTH SPLIT MOVES FROM 52/48 TO 56/44.
       Region A's three resource chips are its widest content, and at 12px
       Orbitron they measure ~200px however tightly they are packed - against
       a 52% cap that gives 202px at 412 and only 191px at 390. Measured
       before this change: 218px of chips inside a 191px cap at 390, i.e. the
       chips spilled 27px out of region A and into the 8px gap that the
       52/48 split exists to guarantee.
       The split is what yields, for two reasons. Region B is not using its
       48%: the Overseer's header wraps at 12px anyway, so the box was 186px
       wide holding 164px of content. And narrowing region B pulls its bottom
       edge UP (the portrait is width-driven at min(100%, 180px)), which buys
       back most of the height the wrapped header costs. The 24px guaranteed
       gap between the two corner blocks is unchanged - both caps still
       subtract --space-3, and 56 + 44 is still 100. */
    .top-left-hud {
        max-width: calc(56% - var(--space-3));
    }

    .top-right-hud {
        max-width: calc(44% - var(--space-3));
    }

    /* The rest of the chips' width comes out of padding and tracking, per
       docs/TYPE-LEGIBILITY.md rule 6 - never out of the digits. */
    .resource-bar-floating {
        gap: 2px;
    }

    .resource-bar-floating .resource-item {
        padding: 3px 2px;
        gap: 1px;
    }

    .resource-bar-floating .resource-value {
        letter-spacing: 0;
    }

    .resource-bar-floating .resource-icon {
        width: 10px;
        height: 10px;
    }

    /* -------------------------------------------------------------
       REGION C ON A PHONE — two rows, deliberately

       docs/HUD-LAYOUT.md §3 makes "single row at every breakpoint" an
       invariant and §5 expects icon-only primaries to deliver it. That
       arithmetic no longer closes. Region C now holds ten controls
       (Build, Units, Research, Map, Orders, Transmissions, Zoom+,
       Zoom-, Centre, Menu) plus the tutorial Skip button while
       orientation runs. Ten controls at the §7 minimum of 44px is
       440px of buttons before a single gap or pad - more than a 360px
       or 390px viewport has. hudPanels.css already flagged this when
       Orders and Transmissions were added ("sub-640 widths need a
       structural answer, not another gap reduction"); this is that
       answer.

       Measured before: 635px of bar on a 390px viewport, centred, so
       Build/Units/Research/Map hung off the left edge entirely and
       elementFromPoint over #btn-build returned null. Nothing about
       stacking order or z-index could have fixed that - the buttons
       were not on the screen.

       The three options were: drop controls (Zoom+/Zoom- are arguably
       redundant since gameCanvas.js implements pinch-to-zoom, but
       removing working controls to win a layout argument is the wrong
       trade), go below 44px (fails §7), or use two rows. Two rows it
       is - and unlike the flex-wrap behaviour §3 rejected, the wrap
       point here cannot drift with content: each row is exactly one of
       the two wrappers that already exist in index.html, pinned to
       100%. The bar also goes edge-to-edge, which buys back the 32px
       the centred pill was spending on margins.

       Cost: 110px of a 640px-tall screen. With region A's 132px that
       leaves 398px of clear centre stage - 62% of viewport height,
       inside §6's 50% floor.
       ------------------------------------------------------------- */
    .action-buttons-floating {
        left: 0;
        right: 0;
        bottom: 0;
        transform: none;
        flex-wrap: wrap;
        gap: 6px;
        padding: var(--space-2) calc(var(--space-2) + var(--safe-right))
                 calc(var(--space-2) + var(--safe-bottom)) calc(var(--space-2) + var(--safe-left));
        border-radius: 0;
        border-left: none;
        border-right: none;
        border-bottom: none;
        max-width: 100%;
    }

    .action-buttons-floating .action-bar-left,
    .action-buttons-floating .action-bar-right {
        /* One full-width row each. */
        flex: 1 0 100%;
        gap: 4px;
        justify-content: center;
        min-height: var(--touch-target);
    }

    /* The divider was a right border on a side-by-side pair; stacked, the
       6px row gap does the same job without spending height on a rule. */
    .action-buttons-floating .action-bar-left {
        padding-right: 0;
        border-right: none;
    }

    /* Share each row's width evenly. flex-basis 0 beats the 44px width
       .btn-icon declares, so the icons grow to fill instead of leaving a
       ragged row, while min-width holds the WCAG floor if they ever have
       to shrink. */
    .action-buttons-floating .action-bar-left > .btn,
    .action-buttons-floating .action-bar-right > .btn {
        flex: 1 1 0;
        min-width: var(--touch-target);
        min-height: var(--touch-target);
        padding-left: 0;
        padding-right: 0;
    }

    .action-buttons-floating .btn-icon {
        flex: 1 1 0;
    }

    /* BUILD / UNITS / RESEARCH / MAP GET THEIR LABELS BACK ON PHONE.
       They were collapsed to font-size:0 because ten controls plus the
       tutorial Skip button could not fit one row - and that was true. It
       stopped being true the moment region C became two rows: the four
       primaries now have a row of their own and nothing else in it. At 412px
       that is (412 - 16 padding - 3 gaps of 4) / 4 = 96px per button against
       a widest content of ~66px ("Research" at 12px plus its 16px icon); at
       390px it is 90px against the same 66px. There is no width argument left
       for hiding them, and an unlabelled icon row is exactly the "text you
       cannot read" the owner is complaining about.

       Menu stays icon-only. It is the eighth control in the *right* row
       (queues, transmissions, achievements, zoom in, zoom out, centre, Menu,
       and Skip while orientation runs) and that row genuinely has no room.
       The hamburger glyph carries it and title/aria are unaffected - the
       label is hidden, not shrunk, which is a different thing from the 12px
       floor. Flagged in the lane report: the contrast audit cannot tell the
       two apart and reports this button as "0px". */
    .action-buttons-floating #btn-build,
    .action-buttons-floating #btn-units,
    .action-buttons-floating #btn-research,
    .action-buttons-floating #btn-map {
        gap: 4px;
        padding: 0 4px;
        min-width: var(--touch-target);
        min-height: var(--touch-target);
    }

    .action-buttons-floating #btn-menu {
        font-size: 0;
        gap: 0;
        padding: 0;
        min-width: var(--touch-target);
        min-height: var(--touch-target);
    }
}

/* =================================================================
   REDUCED MOTION
   docs/HUD-LAYOUT.md §7 calls this file out by name as missing a
   prefers-reduced-motion block despite shipping a transition.
   ================================================================= */

@media (prefers-reduced-motion: reduce) {
    .user-profile-floating {
        transition: none;
    }
}

/* --- Placement mode is a mode, and says so ------------------------------
   Entering it used to leave the screen pixel-identical to the idle base view.
   The strip sits above the action bar — reachable, out of the way of the
   ground being chosen, and fixed to the screen rather than to the world, so
   panning and zooming do not move the way out. */
.placement-banner {
    position: fixed;
    left: 50%;
    bottom: calc(var(--region-c-reserve, 120px) + var(--space-3));
    transform: translateX(-50%);
    z-index: var(--z-panel);

    display: flex;
    align-items: center;
    gap: var(--space-3);
    max-width: calc(100vw - var(--space-4) * 2);
    padding: var(--space-2) var(--space-3);

    background: var(--color-primary-900);
    border: 1px solid var(--color-accent-gold);
    border-radius: var(--radius-sm);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
}

.pb-mode {
    font-family: var(--font-display);
    font-size: var(--text-xs);
    font-weight: var(--font-bold);
    letter-spacing: 0.14em;
    color: var(--color-accent-gold);
}

.pb-name {
    font-size: var(--text-sm);
    color: var(--color-text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pb-cancel {
    min-height: var(--touch-target);
    padding: 0 var(--space-3);
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text-secondary);
    font-size: var(--text-xs);
    cursor: pointer;
}

.pb-cancel:hover {
    border-color: var(--color-accent-red);
    color: var(--color-text-primary);
}

/* --- The build badge ----------------------------------------------------
   A small line above the action bar saying which build this device is
   actually running, and a tap to expand it into the facts that tell a
   promotion problem apart from a caching problem apart from a real defect.

   Sits ABOVE the action row rather than in it: it is a label, not a control,
   and it must never take a tap meant for Build or Map. */
#build-badge {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: calc(var(--region-c-reserve, 120px) + 2px);
    z-index: var(--z-hud, 400);

    max-width: calc(100vw - var(--space-3) * 2);
    padding: 2px var(--space-2);

    font-family: var(--font-mono, ui-monospace, monospace);
    /* Under the 12px floor on purpose, and this is the documented exception:
       the floor exists for text a player READS while playing. This is a
       diagnostic stamp they look at deliberately, once, when something is
       wrong — and the expanded panel below is at full size. Keeping it small
       is what lets it sit over the world without becoming furniture. */
    font-size: 10px;
    line-height: 1.4;
    letter-spacing: 0.04em;

    color: var(--color-text-muted);
    background: rgba(10, 15, 26, 0.72);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    /* It is a label. Taps land on it, drags go to the map underneath. */
    touch-action: manipulation;
}

#build-badge.is-open {
    /* Opened, it is a document rather than a stamp: full width, readable
       size, and scrollable, because the user agent string alone is longer
       than a phone is wide. */
    left: var(--space-3);
    right: var(--space-3);
    transform: none;
    max-width: none;
    max-height: 52vh;
    overflow-y: auto;
    padding: var(--space-3);
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
    background: var(--color-primary-900);
    border-color: var(--color-accent-gold);
}

.bb-list { margin: 0; }

.bb-row {
    display: grid;
    grid-template-columns: 8.5em 1fr;
    gap: var(--space-2);
    padding: 3px 0;
    border-bottom: 1px solid var(--color-border);
}

.bb-row:last-child { border-bottom: none; }

.bb-row dt {
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.bb-row dd {
    margin: 0;
    color: var(--color-text-primary);
    /* The agent string has no spaces to break at. */
    word-break: break-word;
}
