/* Live match layout, board rendering, units, projectiles, and command controls. */

.game-page {
    height: 100svh;
    width: 100%;
    padding: 0 clamp(4px, 1.2vw, 12px) clamp(4px, 1.2vw, 12px);
    overflow: hidden;
}

.game-shell {
    height: 100%;
    min-height: 0;
    width: min(1180px, 100%);
    margin: 0 auto;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: clamp(6px, 1.4vw, 12px);
}

.game-toolbar,
.command-bar,
.arena {
    border: 1px solid var(--line);
    border-radius: 8px;
    background: rgba(18, 22, 29, 0.94);
    box-shadow: 0 12px 36px rgba(0, 0, 0, 0.22);
}

.game-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 4px 10px;
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    border-top: 0;
}

.game-heading {
    flex: 1 1 auto;
    min-width: 0;
}

/* Status doubles as the page title now, so it must ellipsis on mobile rather
   than wrap - wrapping would push the resource strip and break toolbar height. */
.toolbar-status {
    display: block;
    font-size: clamp(0.82rem, 1.8vw, 0.96rem);
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Holds one strip normally, or P2 stacked over P1 in replays. */
.resource-stack {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.resource-strip {
    min-width: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(3, minmax(58px, auto));
    gap: 6px;
}

/* Replay strips carry a 4th cell for the lumber upgrade count. */
.resource-strip.with-lumber {
    grid-template-columns: repeat(4, minmax(52px, auto));
}

/* Opponent strip is tinted to read as "the other player" at a glance. */
.resource-strip.opponent div {
    border-color: rgba(214, 109, 109, 0.32);
    background: rgba(214, 109, 109, 0.1);
}

.resource-strip div {
    min-width: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 5px;
    padding: 4px 7px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.06);
}

.resource-strip dt {
    color: var(--muted);
    font-size: 0.68rem;
    line-height: 1;
}

.resource-strip dd {
    margin: 0;
    font-family: Consolas, "Liberation Mono", monospace;
    font-size: 0.9rem;
    font-weight: 800;
    line-height: 1;
}

.game-toolbar .restart-actions button,
.game-toolbar .game-actions button {
    min-height: 36px;
    padding: 0 12px;
    font-size: 0.9rem;
}

.restart-actions {
    flex: 0 0 auto;
}

.game-actions {
    display: flex;
    gap: 8px;
}

.arena {
    min-height: 0;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: 2px;
    align-items: center;
    padding: clamp(8px, 2vw, 16px);
    background: rgba(11, 14, 19, 0.78);
}

.finish-line {
    min-width: 0;
    display: grid;
    align-items: center;
    gap: 10px;
}

.finish-line.opponent {
    grid-template-columns: minmax(0, 1fr) auto;
}

.finish-line.player {
    grid-template-columns: auto minmax(0, 1fr);
}

/* Stacks the health number with the faction glyph snug beneath it, sharing the
   slim auto column the number used to occupy on its own. */
.finish-line-health {
    min-width: 42px;
    display: grid;
    justify-items: center;
    gap: 2px;
}

.finish-line strong {
    font-family: Consolas, "Liberation Mono", monospace;
    font-size: 1rem;
    text-align: center;
}

.finish-line-faction {
    font-size: 0.85rem;
    line-height: 1;
}

.health-track {
    height: 16px;
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 8px;
    background: rgba(0, 0, 0, 0.32);
}

.health-fill {
    width: var(--health-percent);
    height: 100%;
    background: linear-gradient(90deg, #3da77a, #7dd1ad);
    transition: width var(--transition-fast);
}

.finish-line.opponent .health-fill {
    margin-left: auto;
    background: linear-gradient(90deg, #8fc4ff, #4c91d6);
}

/*
 * The board sizes itself from container-query units against this wrapper:
 *   width:  min(100cqw, 100cqh * cols/rows)
 *   height: min(100cqh, 100cqw * rows/cols)
 * so it fills the arena's middle row at the right aspect for ANY row count.
 *
 * For that to work this wrapper MUST have a definite size in both axes.
 * Gotcha: `.arena` uses `align-items: center` (so the slim finish-line bars
 * don't stretch). That cascades to every grid item as `align-self: center`,
 * which would collapse this wrapper to its content height. Combined with
 * `container-type: size` (which deliberately ignores descendants for sizing)
 * `100cqh` resolves to 0 and the board becomes an invisible speck.
 *
 * The explicit stretch + 100% sizes below opt this wrapper out of that
 * centering so the container has a real box for the board's cq math.
 */
.board-area {
    container-type: size;
    align-self: stretch;
    justify-self: stretch;
    width: 100%;
    height: 100%;
    min-width: 0;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.game-board {
    width: min(100cqw, calc(100cqh * var(--board-columns) / var(--board-rows)));
    height: min(100cqh, calc(100cqw * var(--board-rows) / var(--board-columns)));
    display: grid;
    grid-template-columns: repeat(var(--board-columns), minmax(0, 1fr));
    grid-template-rows: repeat(var(--board-rows), minmax(0, 1fr));
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: #0c1015;
    position: relative;
    overflow: hidden;
}

.board-tile {
    min-height: 0;
    height: auto;
    padding: 0;
    border-radius: 0;
    border-right: 1px solid rgba(255, 255, 255, 0.08);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(255, 255, 255, 0.04);
    color: var(--text);
    font-size: clamp(0.7rem, 2vw, 1rem);
    position: relative;
    display: grid;
    place-items: center;
    overflow: hidden;
}

.board-tile:hover:not(:disabled),
.board-tile:focus-visible:not(:disabled) {
    filter: brightness(1.16);
    transform: none;
}

.board-tile.enemy-field {
    background: rgb(var(--player-two-rgb) / 0.16);
}

.board-tile.no-mans-land {
    background: rgb(var(--neutral-zone-rgb) / 0.14);
    cursor: not-allowed;
}

.board-tile.unbuildable {
    cursor: not-allowed;
}

.board-tile.buildable {
    cursor: pointer;
}

.board-tile.player-field {
    background: rgb(var(--player-one-strong-rgb) / 0.18);
}

.board-tile.occupied.wall,
.board-tile.occupied.wide-wall {
    background: rgb(var(--player-one-rgb) / 0.42);
    font-weight: 900;
}

.board-tile.occupied.archer {
    background: rgb(var(--player-one-rgb) / 0.44);
    font-weight: 900;
}

.board-tile.occupied.stone-mine,
.board-tile.occupied.farm,
.board-tile.occupied.outpost,
.board-tile.occupied.bahamut,
.board-tile.occupied.ram,
.board-tile.occupied.paladin {
    background: rgb(var(--player-one-rgb) / 0.46);
    font-weight: 900;
}

.board-tile.occupied.player-2.wall,
.board-tile.occupied.player-2.wide-wall {
    background: rgb(var(--player-two-rgb) / 0.46);
}

.board-tile.occupied.player-2.archer {
    background: rgb(var(--player-two-light-rgb) / 0.48);
}

.board-tile.occupied.player-2.stone-mine,
.board-tile.occupied.player-2.farm,
.board-tile.occupied.player-2.outpost,
.board-tile.occupied.player-2.bahamut,
.board-tile.occupied.player-2.ram,
.board-tile.occupied.player-2.paladin {
    background: rgb(var(--player-two-rgb) / 0.48);
}

.board-tile.preview-valid {
    z-index: 5;
    box-shadow: inset 0 0 0 3px rgb(var(--player-one-rgb) / 0.95), 0 0 22px rgb(var(--player-one-strong-rgb) / 0.36);
}

.board-tile.preview-invalid {
    z-index: 5;
    box-shadow: inset 0 0 0 3px rgb(var(--danger-rgb) / 0.95), 0 0 22px rgb(var(--danger-strong-rgb) / 0.36);
}

/* Informational tile shading for build previews whose projectile behavior depends
   on spacing - Longbowman's unarmed flight window, Catapult's landing tile, etc.
   Pink so it reads as "informational" rather than valid/invalid. */
.board-tile.info-zone {
    z-index: 3;
    background: rgb(255 105 180 / 0.32);
    box-shadow: inset 0 0 0 2px rgb(255 105 180 / 0.75);
}

/* Projectiles render in their own layer above the units so projectileLerp.js can
   glide each token between tiles with a CSS transform, independent of the fixed
   simulation tick rate. The layer mirrors .unit-layer's grid so a token can be
   grid-placed onto its current logical tile, then nudged sub-tile by transform. */
.projectile-layer {
    position: absolute;
    inset: 0;
    z-index: 6;
    display: grid;
    grid-template-columns: inherit;
    grid-template-rows: inherit;
    pointer-events: none;
}

.projectile-token {
    position: relative;
    min-width: 0;
    min-height: 0;
    display: grid;
    place-items: center;
    /* will-change keeps the per-frame transform on the compositor. The transform
       itself is set inline by projectileLerp.js; it rests at zero on the tile. */
    will-change: transform;
}

/* Wide projectiles (Width >= 2) span multiple columns as one continuous shell.
   Visual only - the simulation already owns collision width on ProjectileState.Width. */
.projectile-token.wide {
    margin: 2px;
    border-radius: 6px;
    background: rgb(var(--player-one-strong-rgb) / 0.36);
    box-shadow: inset 0 0 14px rgb(var(--player-one-strong-rgb) / 0.55);
}

.projectile-token.wide.player-2 {
    background: rgb(var(--player-two-light-rgb) / 0.38);
    box-shadow: inset 0 0 14px rgb(var(--player-two-light-rgb) / 0.55);
}

.unit-layer {
    position: absolute;
    inset: 0;
    z-index: 3;
    display: grid;
    grid-template-columns: inherit;
    grid-template-rows: inherit;
    pointer-events: none;
}

.placement-preview-layer {
    position: absolute;
    inset: 0;
    z-index: 5;
    display: grid;
    grid-template-columns: inherit;
    grid-template-rows: inherit;
    pointer-events: none;
}

.unit-token {
    position: relative;
    min-width: 0;
    min-height: 0;
    display: grid;
    place-items: center;
    margin: 2px;
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgb(var(--player-one-rgb) / 0.52);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
    color: var(--text);
    font-weight: 900;
    animation: unit-token-fade-in 120ms ease-out both;
}

.placement-preview-token {
    position: relative;
    min-width: 0;
    min-height: 0;
    display: grid;
    place-items: center;
    margin: 2px;
    overflow: hidden;
    border: 2px dashed rgb(var(--player-one-rgb) / 0.86);
    background: rgb(var(--player-one-rgb) / 0.24);
    box-shadow: 0 0 18px rgb(var(--player-one-strong-rgb) / 0.26);
    opacity: 0.84;
}

.placement-preview-token.invalid {
    border-color: rgb(var(--danger-rgb) / 0.88);
    background: rgb(var(--danger-rgb) / 0.18);
    box-shadow: 0 0 18px rgb(var(--danger-strong-rgb) / 0.24);
}

.unit-token.archer {
    background: rgb(var(--player-one-rgb) / 0.56);
}

.unit-token.stone-mine,
.unit-token.farm,
.unit-token.outpost,
.unit-token.bahamut,
.unit-token.ram,
.unit-token.paladin {
    background:
        linear-gradient(135deg, rgba(255, 255, 255, 0.1), transparent 42%),
        rgb(var(--player-one-rgb) / 0.58);
}

.unit-token.player-2 {
    background: rgb(var(--player-two-rgb) / 0.58);
}

.unit-token.player-2.archer {
    background: rgb(var(--player-two-light-rgb) / 0.6);
}

.unit-token.player-2.stone-mine,
.unit-token.player-2.farm,
.unit-token.player-2.outpost,
.unit-token.player-2.bahamut,
.unit-token.player-2.ram,
.unit-token.player-2.paladin {
    background:
        linear-gradient(135deg, rgba(255, 255, 255, 0.09), transparent 42%),
        rgb(var(--player-two-rgb) / 0.6);
}

/* Craters are ownerless terrain - grey so they don't read as either player's color.
   Rule comes after the player-1/player-2 blocks so it wins regardless of the
   `player-0` ownership class the renderer also emits. */
.unit-token.crater,
.unit-token.player-0.crater,
.unit-token.player-1.crater,
.unit-token.player-2.crater {
    background: rgb(140 140 140 / 0.55);
    border-color: rgba(200, 200, 200, 0.2);
}

.unit-sprite {
    position: relative;
    z-index: 1;
    width: 100%;
    height: 100%;
    display: block;
    object-fit: contain;
    padding: 4%;
    filter: drop-shadow(0 3px 3px rgba(0, 0, 0, 0.44));
}

.unit-token.wall .unit-sprite,
.unit-token.crater .unit-sprite,
.placement-preview-token.wall .unit-sprite,
.placement-preview-token.crater .unit-sprite {
    padding: 2%;
}

.unit-token.wide-wall .unit-sprite,
.placement-preview-token.wide-wall .unit-sprite {
    padding: 2% 1%;
}

.unit-token.stone-mine .unit-sprite,
.unit-token.farm .unit-sprite,
.unit-token.outpost .unit-sprite,
.unit-token.bahamut .unit-sprite,
.unit-token.ram .unit-sprite,
.placement-preview-token.stone-mine .unit-sprite,
.placement-preview-token.farm .unit-sprite,
.placement-preview-token.outpost .unit-sprite,
.placement-preview-token.bahamut .unit-sprite,
.placement-preview-token.ram .unit-sprite {
    padding: 3%;
}

@keyframes unit-token-fade-in {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

.unit-health {
    position: absolute;
    bottom: -2px;
    right: -1px;
    z-index: 2;
    color: rgba(255, 255, 255, 0.86);
    font-family: Consolas, "Liberation Mono", monospace;
    font-size: clamp(0.46rem, 1.35vw, 0.64rem);
    font-weight: 800;
    line-height: 1;
    padding: 1px 2px;
    border-radius: 4px 0 0 0;
    background: rgba(0, 0, 0, 0.42);
}

.unit-meter {
    position: absolute;
    inset: auto 3px 3px;
    z-index: 2;
    height: 4px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.34);
}

.unit-meter::after {
    content: "";
    display: block;
    width: var(--meter-percent);
    height: 100%;
    border-radius: inherit;
    background: var(--warn);
}

/* Construction keeps the charge-bar fill but has a brick texture. */
.unit-meter.unit-meter-building::after {
    /* Mortar lines read as blocks being laid. */
    background:
        repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.3) 0 1px, transparent 1px 4px),
        var(--warn);
}

.projectile-glyph {
    color: #f6d27a;
    font-size: clamp(0.74rem, 1.9vw, 1rem);
    font-weight: 900;
    line-height: 1;
}

.projectile-token.player-2 .projectile-glyph {
    color: #8fc4ff;
}

/* Fixed height + overflow:hidden keeps the board from reflowing when the bar
   swaps between choosing/confirming modes; children must size to fit, not push. */
.command-bar {
    height: 112px;
    min-width: 0;
    display: grid;
    grid-template-rows: 1fr;
    align-items: stretch;
    gap: 8px;
    padding: 10px 10px 11px;
    overflow: hidden;
}

.tool-panel,
.tool-strip,
.placement-actions {
    min-width: 0;
    display: grid;
    gap: 8px;
    height: 100%;
}

/* auto + minmax(0,1fr) lets the header take its natural height and gives the
   strip the rest; without minmax(0,...) the buttons would overflow the bar. */
.tool-panel {
    grid-template-rows: auto minmax(0, 1fr);
}

.tool-panel .tool-strip {
    height: auto;
}

.tool-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-height: 40px;
}

.tool-panel-header.with-economy-action {
    display: grid;
    grid-template-columns: minmax(116px, auto) minmax(0, 1fr) minmax(92px, auto);
    align-items: center;
    gap: clamp(14px, 4vw, 42px);
}

.tool-mode-label {
    margin: 0;
    color: var(--muted);
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.tool-panel-header.with-economy-action .tool-mode-label {
    justify-self: center;
}

.tool-mode-switch {
    min-width: 92px;
    min-height: 40px;
    padding: 0 12px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    font-size: 1rem;
    font-weight: 900;
}

.tool-mode-switch-copy {
    font-size: 0.82rem;
    line-height: 1;
}

.lumber-upgrade-button {
    width: 116px;
    min-height: 40px;
    padding: 4px 9px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.lumber-upgrade-button img {
    width: 30px;
    height: 30px;
    flex: 0 0 30px;
    object-fit: contain;
}

.lumber-upgrade-copy {
    min-width: 0;
    display: grid;
    line-height: 1;
    text-align: left;
}

.lumber-upgrade-copy small {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lumber-upgrade-copy small {
    color: var(--muted);
    font-family: Consolas, "Liberation Mono", monospace;
    font-size: 0.72rem;
    font-weight: 800;
}

/* --tool-count is set inline from Razor (VisibleTools.Length) so the strip
   reshapes when paging between buildings (3) and non-building units (4). */
.tool-strip {
    grid-template-columns: repeat(var(--tool-count), minmax(0, 1fr));
}

.placement-actions {
    grid-template-columns: minmax(0, 1fr) minmax(42px, 0.18fr) minmax(0, 1fr);
    align-items: stretch;
}

.placement-action {
    height: 100%;
    min-height: 0;
    font-size: clamp(1.05rem, 3vw, 1.45rem);
    font-weight: 900;
}

.placement-action.cancel {
    grid-column: 3;
}

.tool-button {
    min-width: 0;
    min-height: 0;
    height: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 0 12px;
    white-space: nowrap;
}

.tool-empty {
    grid-column: 1 / -1;
    margin: 0;
    display: grid;
    place-items: center;
    min-height: 0;
    height: 100%;
    color: var(--muted);
    font-weight: 800;
    text-align: center;
}

.tool-button:disabled {
    border-color: var(--control-border-soft);
    background: var(--control-bg-soft);
}

.tool-button-glyph {
    --control-glyph-bg: rgba(0, 0, 0, 0.2);
    width: 30px;
    height: 30px;
    flex: 0 0 30px;
}

.tool-button-glyph img {
    width: 96%;
    height: 96%;
}

.tool-button .tool-copy {
    min-width: 0;
    width: auto;
    height: auto;
    display: grid;
    place-items: start;
    gap: 1px;
    border-radius: 0;
    background: transparent;
    color: inherit;
    font-weight: 700;
    line-height: 1.05;
}

.tool-copy strong {
    max-width: 100%;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.86rem;
    line-height: 1.05;
}

.tool-copy small {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--muted);
    font-family: Consolas, "Liberation Mono", monospace;
    font-size: 0.66rem;
    font-weight: 700;
    line-height: 1;
}

.game-status {
    margin: 0;
    color: var(--muted);
    line-height: 1.3;
    font-size: 0.85em;
    overflow-wrap: break-word;
    min-width: 0;
}

@media (min-width: 761px) {
    .tool-panel,
    .tool-strip,
    .placement-actions {
        align-self: stretch;
    }
}

@media (max-width: 760px) {
    .game-toolbar {
        gap: 8px;
        padding: 4px 8px;
        flex-wrap: wrap;
    }

    .resource-stack {
        order: 3;
        flex-basis: 100%;
    }

    .resource-strip {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .resource-strip.with-lumber {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }

    .command-bar {
        height: 120px;
        padding: 8px 2px 9px;
    }

    .replay-shell {
        grid-template-rows: auto minmax(0, 1fr) clamp(24px, 7svh, 56px);
    }

    .tool-panel,
    .tool-strip,
    .placement-actions {
        align-self: stretch;
    }

    .tool-button {
        flex-direction: column;
        gap: 2px;
        padding: 0 4px;
        font-size: 0.82rem;
    }

    .tool-button-glyph {
        width: 30px;
        height: 30px;
        flex: 0 0 30px;
    }

    .tool-button .tool-copy {
        width: auto;
        height: auto;
        flex: 1 1 auto;
        place-items: center;
        text-align: center;
    }

    .tool-copy strong {
        font-size: 0.68rem;
        text-overflow: clip;
    }

    .tool-copy small {
        font-size: 0.56rem;
    }

    .tool-panel-header.with-economy-action {
        grid-template-columns: 104px minmax(0, 1fr) 76px;
        gap: 8px;
    }

    .tool-mode-switch {
        min-width: 76px;
        min-height: 38px;
        padding: 0 8px;
        gap: 5px;
    }

    .tool-mode-switch-copy {
        font-size: 0.72rem;
    }

    .lumber-upgrade-button {
        width: 104px;
        min-height: 38px;
        padding: 4px 7px;
        gap: 6px;
    }

    .lumber-upgrade-button img {
        width: 26px;
        height: 26px;
        flex-basis: 26px;
    }

    .lumber-upgrade-copy small {
        font-size: 0.62rem;
    }

    .placement-actions {
        grid-template-columns: minmax(0, 1fr) minmax(34px, 0.22fr) minmax(0, 1fr);
    }

    .placement-action {
        height: 100%;
        min-height: 0;
    }
}

.replay-page {
    gap: 12px;
}

.replay-loader {
    margin: auto;
    display: grid;
    gap: 16px;
    justify-items: center;
    border-style: dashed;
    transition: border-color var(--transition-fast), background var(--transition-fast);
}

.replay-loader p {
    margin: 0;
    color: var(--muted);
    font-weight: 800;
    text-align: center;
}

.replay-loader.drag-over {
    border-color: var(--accent);
    background: rgba(255, 255, 255, 0.08);
}

.replay-controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    flex-wrap: wrap;
}

.replay-controls p {
    margin: 0;
}

.replay-speed {
    display: flex;
    gap: 6px;
}

.replay-speed .selected {
    outline: 2px solid var(--accent);
}
