/*
 * Judging — the unified rewrite of Judges Interface + Prime Time.
 * Loaded only by templates/judging/judging.twig; the legacy pages (now
 * theme-adopted, styling-only) keep judges-interface.css. All markup here
 * is rendered by judging.js.
 * Tables, forms, cards and badges ride the global portal skin — only the
 * judging-specific layout and the corner-color system live here.
 *
 * Pink rgb(207,35,202) and teal rgb(0,218,216) are the corner colors — they
 * are functional data colors (which side is which), not chrome. No portal
 * token exists for them, so they are deliberate literals (same as
 * mission-control's corner colors).
 */

/* The corner family is the kit's now (v3 §2.8) — the local names stay as
   aliases so every consumer below rides along. The hand-picked inks were
   deleted after the contrast check the plan asked for: the derived inks
   clear 4.5:1 on both canvases (dark 6.60/13.00, light 7.14/5.69) and the
   old light blue #068a89 actually FAILED it at 3.82:1. The inks are
   theme-aware, so the dark override went with them. */
.jdg-page {
    --jdg-pink: var(--portal-c-corner-pink);
    --jdg-blue: var(--portal-c-corner-blue);
    --jdg-pink-soft: var(--portal-c-corner-pink-soft);
    --jdg-blue-soft: var(--portal-c-corner-blue-soft);
    --jdg-pink-border: var(--portal-c-corner-pink-border);
    --jdg-blue-border: var(--portal-c-corner-blue-border);
    --jdg-pink-text: var(--portal-c-corner-pink-ink);
    --jdg-blue-text: var(--portal-c-corner-blue-ink);
}

/* ── Shared bits ─────────────────────────────────────────────────── */

.jdg-select-label,
.jdg-slider-label,
.jdg-meta-label,
.jdg-section-title,
.jdg-segment-title {
    display: block;
    font-size: var(--portal-text-2xs);
    font-weight: var(--portal-weight-strong);
    letter-spacing: var(--portal-label-tracking);
    text-transform: uppercase;
    color: var(--portal-c-text-muted);
}

.jdg-select-label {
    margin-bottom: 0.375rem;
}

/* The selects arrive via AJAX (the Fight one only after a tournament is
 * chosen), so a scoring-tab label without its control would float alone.
 * judging.js stamps .has-select on the column once its <select> exists —
 * a JS-driven class instead of :has(), which silently never matched on
 * older Safari/Firefox. */
.jdg-select-col .jdg-select-label {
    display: none;
}

.jdg-select-col.has-select .jdg-select-label {
    display: block;
}

/* Tier-2 placeholder the shape of the select it stands in for */
.jdg-select-skeleton {
    height: 2.375rem;
}

/* ── Focus mode ──────────────────────────────────────────────────── */

/* While a fight is open in the scoring panel the stat row folds away: a
 * judge mid-fight should reach the sliders without scrolling a screen of
 * metrics. judging.js adds/removes .jdg-scoring, and re-syncs it on tab
 * change so the stats come back with every other tab. */
.jdg-page.jdg-scoring .jdg-stat-row {
    display: none;
}

/* ── Fight information strip ─────────────────────────────────────── */

/* Kit card-header shape: back button, fight name, recording link, then the
 * live timer pinned right. */
.jdg-fight-strip-header {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
}

.jdg-back-btn {
    flex-shrink: 0;
}

.jdg-back-label {
    margin-left: 0.375rem;
}

.jdg-recording-link {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: var(--portal-text-sm);
    color: var(--portal-c-accent);
    text-decoration: none;
}

.jdg-recording-link:hover {
    text-decoration: underline;
}

/* The stopwatch is the header's live data slot — mono, tabular so the
 * digits don't jitter every second */
.jdg-timer-chip {
    display: inline-flex;
    align-items: baseline;
    gap: 0.5rem;
}

.jdg-timer-label {
    font-size: var(--portal-text-2xs);
    font-weight: var(--portal-weight-strong);
    letter-spacing: var(--portal-label-tracking);
    text-transform: uppercase;
    color: var(--portal-c-text-muted);
}

/* Shared video modal (both /judging's own and the public scores page's copy)
 * — the modal-content already has its own border/radius/shadow, so the
 * fvp-slot inside it goes flush. */
#jdg-video-modal .fvp-slot,
#jdgp-video-modal .fvp-slot {
    border: none;
    border-radius: 0;
}

/* Video | meta+notes, side by side once there's room for both to be useful;
 * a single column below that (video keeps its 16:9 slot, meta follows). */
.jdg-fight-strip-body {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

@media (min-width: 992px) {
    .jdg-fight-strip-body {
        grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
        align-items: start;
    }
}

.jdg-meta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem 2.5rem;
}

.jdg-meta-value {
    display: block;
    font-family: var(--bs-font-monospace);
    font-size: var(--portal-text-base);
    margin-top: 0.125rem;
}

.jdg-meta-value a {
    color: var(--portal-c-accent);
    text-decoration: none;
}

.jdg-meta-value a:hover {
    text-decoration: underline;
}

.jdg-meta-icon {
    font-size: var(--portal-text-xs);
    margin-left: 0.25rem;
}

/* ── Corner cards ────────────────────────────────────────────────── */

/* No corner stripe on the card edge. It used to be `border-top: 3px solid`
 * + a per-corner border-top-color, but `.portal-page-themed .card` (0,2,0)
 * sets the border-color SHORTHAND and beat the per-corner rule (0,1,0) from
 * the 2026-08-09 restyle onward — leaving a 3px grey edge that read as an
 * artifact. Restoring it would mean out-specifying the card skin to paint
 * exactly the kind of flat opaque stripe that restyle deliberately retired.
 * Corner identity is carried three other ways already: the header chip, the
 * running total, and the slider thumbs. */

.jdg-corner-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Right-hand data slot of the corner header — this side's running total, so
 * each column answers "where is this bot at?" on its own */
.jdg-corner-live {
    display: inline-flex;
    align-items: baseline;
    gap: 0.375rem;
    margin-left: auto;
}

.jdg-corner-live-label {
    font-size: var(--portal-text-2xs);
    font-weight: var(--portal-weight-strong);
    letter-spacing: var(--portal-label-tracking);
    text-transform: uppercase;
    color: var(--portal-c-text-muted);
}

/* 1.125rem at line-height 1 is an 18px box — exactly the card-title's
 * (0.9375rem x --portal-leading-tight). Anything taller becomes the header's
 * tallest child and pushes the two corner headers out of line with the
 * Scorecard's, which has no right-hand readout to match. */
.jdg-corner-live-num {
    font-family: var(--bs-font-monospace);
    font-size: var(--portal-text-lg);
    font-weight: var(--portal-weight-strong);
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

/* Baseline alignment lets the label's own line box grow the flex container
 * past both children — center keeps the readout inside the 18px box. */
.jdg-corner-live-label {
    line-height: 1;
}

/* Plain kit card-title, corner-tinted. It was a pill chip until 2026-08-10:
 * against two neighbouring headers carrying plain titles, the bubble read as
 * a badge rather than the card's name. The tint is the corner cue and is
 * functional data colour, not decoration. */
.jdg-corner-pink .jdg-corner-title { color: var(--jdg-pink-text); }
.jdg-corner-blue .jdg-corner-title { color: var(--jdg-blue-text); }

.jdg-bot-identity {
    text-align: center;
    margin-bottom: 1rem;
}

.jdg-bot-photo {
    max-width: 180px;
    max-height: 110px;
    object-fit: contain;
    margin-bottom: 0.5rem;
}

.jdg-bot-name {
    font-size: 1.375rem;
    font-weight: var(--portal-weight-strong);
    margin-bottom: 0;
    overflow-wrap: anywhere;
}

/* Condition heading row: the title and the Multibot switch that governs
 * which slider set is live sit on one line, above the sliders themselves. */
.jdg-condition-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
    padding-bottom: 0.375rem;
    border-bottom: 1px solid var(--portal-c-border-subtle);
}

/* ── Sliders ─────────────────────────────────────────────────────── */

.jdg-slider-group {
    margin-bottom: 1.125rem;
}

.jdg-slider-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.75rem;
    margin-bottom: 0.25rem;
}

/* Points + words, split: the number is the score (mono chip), the sentence
 * is the rubric wording it came from */
.jdg-slider-readout {
    display: inline-flex;
    align-items: baseline;
    gap: 0.5rem;
    min-width: 0;
}

.jdg-slider-pts {
    font-family: var(--bs-font-monospace);
    font-size: var(--portal-text-xs);
    font-weight: var(--portal-weight-strong);
    line-height: 1;
    padding: 0.2rem 0.45rem;
    border-radius: var(--bs-border-radius-sm);
    background: var(--portal-c-border-subtle);
    color: var(--portal-c-text);
}

/* The bottom two rubric steps are heavy damage — tint the chip with the
 * badge tokens so a wrecked bot reads across three sliders at a glance.
 * Severity is data, not ornament (same call as .jdg-waiting-late). */
.jdg-slider-pts.jdg-sev-3 {
    background: var(--portal-c-badge-warning-bg);
    color: var(--portal-c-badge-warning-color);
}

.jdg-slider-pts.jdg-sev-4 {
    background: var(--portal-c-badge-danger-bg);
    color: var(--portal-c-badge-danger-color);
}

.jdg-slider-desc {
    font-size: var(--portal-text-sm);
    text-align: right;
    color: var(--portal-c-text);
}

/* The range control is the kit's (v3 §2.8) — track, thumb, focus ring and
   coarse sizing all come from portal-components.css. What stays is what is
   judging's own: the tall hit area (a judge slides this mid-fight on an
   iPad) and the corner-coloured thumb per side. */
.jdg-page .form-range {
    height: 2.75rem;
}

.jdg-page .form-range::-webkit-slider-thumb {
    background-color: var(--jdg-range-thumb, var(--portal-c-accent));
}

.jdg-page .form-range::-moz-range-thumb {
    background-color: var(--jdg-range-thumb, var(--portal-c-accent));
}

.jdg-page .form-range:disabled::-webkit-slider-thumb {
    background-color: var(--portal-c-text-muted);
}

.jdg-page .form-range:disabled::-moz-range-thumb {
    background-color: var(--portal-c-text-muted);
}

.jdg-corner-pink { --jdg-range-thumb: var(--jdg-pink); }
.jdg-corner-blue { --jdg-range-thumb: var(--jdg-blue); }

/* ── Multibot ────────────────────────────────────────────────────── */

/* Rides in .jdg-condition-head, so it carries no margin of its own */
.jdg-multibot-check {
    margin: 0;
    padding-left: 2.25rem;
    font-size: var(--portal-text-sm);
    flex-shrink: 0;
}

.jdg-multibot-check .form-check-input {
    margin-left: -2.25rem;
}

.jdg-corner-pink .form-check-input:checked {
    background-color: var(--jdg-pink);
    border-color: var(--jdg-pink);
}

.jdg-corner-blue .form-check-input:checked {
    background-color: var(--jdg-blue);
    border-color: var(--jdg-blue);
}

.jdg-multibot-segment {
    border: 1px solid var(--portal-c-border-subtle);
    border-radius: var(--bs-border-radius);
    padding: 0.75rem 0.75rem 0.25rem;
    margin-bottom: 0.75rem;
}

.jdg-segment-title {
    margin-bottom: 0.625rem;
}

/* ── Center column (the scorecard) ───────────────────────────────── */

/* Each column sizes to its own content. Bootstrap's default stretch made
 * every card as tall as the tallest, so flipping ONE corner to Multibot
 * inflated the other corner by ~400px of empty card. */
.jdg-corners-row {
    align-items: flex-start;
}

.jdg-center-sticky {
    position: sticky;
    top: 1rem;
}

/* One block per rubric term. Condition is derived from the corner sliders
 * and read-only here; Attack is the only control the judge owns. Both wear
 * the same readout shape so the arithmetic (condition + attack = total)
 * reads straight down the column. */
.jdg-metric {
    padding-bottom: 1rem;
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--portal-c-border-subtle);
}

.jdg-metric-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}

.jdg-metric-note {
    font-size: var(--portal-text-xs);
    color: var(--portal-c-text-muted);
}

.jdg-attack-readouts {
    display: flex;
    justify-content: center;
    align-items: baseline;
    gap: 1.25rem;
    margin-bottom: 0.5rem;
}

.jdg-attack-num {
    font-family: var(--bs-font-monospace);
    font-size: 2.25rem;
    font-weight: var(--portal-weight-strong);
    line-height: 1;
    min-width: 2ch;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.jdg-attack-num-pink { color: var(--jdg-pink-text); }
.jdg-attack-num-blue { color: var(--jdg-blue-text); }

.jdg-attack-vs {
    font-size: var(--portal-text-sm);
    color: var(--portal-c-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--portal-label-tracking);
}

.jdg-attack-hint {
    display: flex;
    justify-content: space-between;
    font-size: var(--portal-text-xs);
    margin-top: 0.375rem;
}

.jdg-attack-hint span:first-child { color: var(--jdg-pink-text); }
.jdg-attack-hint span:last-child { color: var(--jdg-blue-text); }

/* The call the sliders just made, named. Condition (6) + attack (5) is an
 * odd 11, so there is always a leader — no tie state exists. Before this
 * block the confirm dialog was the first place a judge saw which bot they
 * had won the fight for. */
.jdg-verdict {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.25rem 0.625rem;
    padding: 0.625rem 0.875rem;
    margin-bottom: 1rem;
    border: 1px solid;
    border-radius: var(--bs-border-radius);
}

.jdg-verdict-pink {
    background: var(--jdg-pink-soft);
    border-color: var(--jdg-pink-border);
}

.jdg-verdict-blue {
    background: var(--jdg-blue-soft);
    border-color: var(--jdg-blue-border);
}

.jdg-verdict-label {
    font-size: var(--portal-text-2xs);
    font-weight: var(--portal-weight-strong);
    letter-spacing: var(--portal-label-tracking);
    text-transform: uppercase;
    color: var(--portal-c-text-muted);
    width: 100%;
}

.jdg-verdict-name {
    font-size: var(--portal-text-lg);
    font-weight: var(--portal-weight-strong);
    overflow-wrap: anywhere;
    min-width: 0;
}

.jdg-verdict-pink .jdg-verdict-name { color: var(--jdg-pink-text); }
.jdg-verdict-blue .jdg-verdict-name { color: var(--jdg-blue-text); }

.jdg-verdict-score {
    display: inline-flex;
    align-items: baseline;
    gap: 0.25rem;
    margin-left: auto;
}

.jdg-verdict-dash {
    color: var(--portal-c-text-muted);
}

/* ── Tables (Live Scores / Broadcast) ────────────────────────────── */
/* Base table voice (headers, borders, hover, density) comes from the
 * global .portal-page-themed .table skin — only judging extras live here. */

.jdg-scores-totals {
    display: flex;
    gap: 1.25rem;
    font-size: var(--portal-text-sm);
    color: var(--portal-c-text-muted);
}

.jdg-scores-totals strong {
    font-family: var(--bs-font-monospace);
    color: var(--portal-c-text);
}

/* Tables sit flush at the card bottom — no hairline above the edge */
.jdg-table tbody tr:last-child td {
    border-bottom: none;
}

.jdg-table a {
    color: var(--portal-c-accent);
    text-decoration: none;
}

.jdg-table a:hover {
    text-decoration: underline;
}

/* Awaiting Decision rows are click targets (whole row = "judge this"),
 * not just their Judge button — signal it */
.jdg-table .jdg-fight-row {
    cursor: pointer;
}

/* Rows this judge already scored are inert: visibly done, not clickable */
.jdg-table .jdg-row-scored {
    opacity: 0.55;
    cursor: default;
}

/* Empty until checkAvailability() confirms footage exists — no icon for
 * "not checked yet" or "not uploaded yet" avoids reading either as an error. */
.jdg-video-avail {
    margin-left: 0.4rem;
    font-size: var(--portal-text-xs);
}

.jdg-video-avail-ready {
    color: var(--portal-c-badge-success-color);
}

/* Matchup cell: bot thumbnail + corner-colored name per side. min-width:0
 * on both the row and each side is what lets .portal-truncate actually
 * ellipsis inside a flex container. */
.jdg-matchup {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}

.jdg-matchup-side {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    min-width: 0;
}

.jdg-row-bot {
    flex: 0 0 auto;
    width: 34px;
    height: 24px;
    object-fit: contain;
    border-radius: var(--bs-border-radius);
}

/* Corner-colored matchup names — same text tokens as the corner chips,
 * so they hold contrast in both themes */
.jdg-table .jdg-name-pink {
    color: var(--jdg-pink-text);
    font-weight: var(--portal-weight-label);
}

.jdg-table .jdg-name-blue {
    color: var(--jdg-blue-text);
    font-weight: var(--portal-weight-label);
}

.jdg-table .jdg-vs-sep {
    color: var(--portal-c-text-muted);
    flex: 0 0 auto;
}

/* Waiting ≥5 minutes — amber nudge, badge token so it tracks the theme */
.jdg-table .jdg-waiting-late {
    color: var(--portal-c-badge-warning-color);
    font-weight: var(--portal-weight-label);
}

/* Winner cell — soft corner-color tint with an accent edge */
.jdg-table .jdg-winner-cell-pink {
    --bs-table-bg: var(--jdg-pink-soft);
    box-shadow: inset 3px 0 0 var(--jdg-pink);
    font-weight: var(--portal-weight-label);
}

.jdg-table .jdg-winner-cell-blue {
    --bs-table-bg: var(--jdg-blue-soft);
    box-shadow: inset 3px 0 0 var(--jdg-blue);
    font-weight: var(--portal-weight-label);
}

/* Broadcast winner chip — corner-colored, so not a status-badge state */
/* The chip geometry is the kit's .portal-chip (v3, --mono voice); what is
   judging's own is only the corner colouring below. */

.jdg-winner-pink {
    color: var(--jdg-pink-text);
    background: var(--jdg-pink-soft);
    border-color: var(--jdg-pink-border);
}

.jdg-winner-blue {
    color: var(--jdg-blue-text);
    background: var(--jdg-blue-soft);
    border-color: var(--jdg-blue-border);
}

/* Sort indicators — same contract as V1 (.sortable / .sort-asc / .sort-desc) */
.jdg-table th.sortable {
    cursor: pointer;
    padding-right: 1.375rem;
    position: relative;
}

.jdg-table th.sortable:after {
    content: '↕';
    position: absolute;
    right: 6px;
    color: var(--portal-c-text-muted);
}

.jdg-table th.sortable.sort-asc:after {
    content: '↑';
    color: var(--portal-c-accent);
}

.jdg-table th.sortable.sort-desc:after {
    content: '↓';
    color: var(--portal-c-accent);
}

/* ── Judging-specific additions (beyond the salvaged V2 skin) ─────── */

/* Fight timer in the info strip — data, so mono; color steps mirror the
 * legacy timer (info → success after 3:30 → warning after 6:30) */
.jdg-timer {
    font-family: var(--bs-font-monospace);
    font-size: var(--portal-text-base);
}

.jdg-timer.jdg-timer-mid { color: var(--bs-success); }
.jdg-timer.jdg-timer-late { color: var(--bs-warning); }

/* Live totals in the verdict strip — display-only mirror of the server
 * calculation, so the confirm dialog never surprises the judge */
.jdg-preview-total {
    font-family: var(--bs-font-monospace);
    font-size: var(--portal-text-2xl);
    font-weight: var(--portal-weight-strong);
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

/* Post-submit undo bar — sits where the scoring panel was */
.jdg-undo-bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 0.75rem 1rem;
    margin-bottom: 1rem;
    border: 1px solid var(--portal-c-border);
    border-left: 3px solid var(--portal-c-accent);
    border-radius: var(--bs-border-radius);
    background: var(--portal-c-surface);
}

.jdg-undo-bar .fa-circle-check {
    color: var(--portal-c-accent);
}

.jdg-undo-secs {
    font-family: var(--bs-font-monospace);
    font-size: var(--portal-text-sm);
}

/* ── Header ──────────────────────────────────────────────────────── */

/* "Updated HH:MM:SS" ticker beside the mode badge — data, so mono */
.jdg-last-updated {
    font-family: var(--bs-font-monospace);
    font-size: var(--portal-text-xs);
    font-variant-numeric: tabular-nums;
}

/* ── Tab row ──────────────────────────────────────────────────────
   This row PROTOTYPED the kit's rail — the nowrap swipe track with the
   hidden scrollbar started here and became .portal-tabs-rail (v3 §2.8).
   jdg-tab-actions stays as a marker class beside the kit's
   (judging.spec.js reads it). */
}

/* ── Help modal ──────────────────────────────────────────────────── */

.jdg-help-section {
    margin-bottom: 1.25rem;
}

.jdg-help-section:last-child {
    margin-bottom: 0;
}

.jdg-help-section h6 {
    font-size: var(--portal-text-2xs);
    font-weight: var(--portal-weight-strong);
    letter-spacing: var(--portal-label-tracking);
    text-transform: uppercase;
    color: var(--portal-c-text-muted);
    margin-bottom: 0.5rem;
}

.jdg-help-table td,
.jdg-help-table th {
    font-size: var(--portal-text-sm);
}

/* ── Score dock (tablet/phone running summary) ───────────────────── */

/* Sticks below the topbar while the judge scrolls the corner cards — the ≥lg
 * layout gets the same job done by the sticky center card. The shape is
 * .portal-dock (portal-kit.css): pinned, opaque, and deliberately not a .card.
 *
 * This page hand-rolled it first and pinned at `top: 0.5rem`, which is half a
 * centimetre from the top of the VIEWPORT — and .portal-topbar is fixed there,
 * 40px of it, so a dock the same height slid under the chrome the moment the
 * judge scrolled and the running score was gone exactly when it was wanted.
 * The component's default clears the topbar.
 *
 * Nothing page-specific is left, including the old 1rem gap: a private
 * single-class override here would sit LATER in the cascade than portal-kit
 * at equal specificity and would silently defeat the dock's own phone rule,
 * which is the breakpoint this bar (d-lg-none) actually lives at. */

.jdg-dock-group {
    display: flex;
    align-items: baseline;
    gap: 0.375rem;
}

.jdg-dock-label {
    font-size: var(--portal-text-2xs);
    font-weight: var(--portal-weight-strong);
    letter-spacing: var(--portal-label-tracking);
    text-transform: uppercase;
    color: var(--portal-c-text-muted);
}

.jdg-dock-num {
    font-family: var(--bs-font-monospace);
    font-size: var(--portal-text-lg);
    font-weight: var(--portal-weight-strong);
    font-variant-numeric: tabular-nums;
}

/* The dock's job is the running answer, so the leader's name leads it. Bot
 * names are long and the dock is one line — this is the group that gives. */
.jdg-dock-leader-group {
    min-width: 0;
}

.jdg-dock-leader {
    font-weight: var(--portal-weight-strong);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.jdg-dock-leader.jdg-name-pink { color: var(--jdg-pink-text); }
.jdg-dock-leader.jdg-name-blue { color: var(--jdg-blue-text); }

.jdg-dock-sep {
    color: var(--portal-c-text-muted);
}

/* The sticky center card shares the dock's opacity requirement */
.jdg-center-sticky .jdg-center {
    background-color: var(--portal-c-surface-opaque, var(--portal-c-surface));
}

/* ── Insights (agreement fill bars — Mission Control's hand-rolled
      progress-bar idiom; no charting library in the portal) ────────── */

.jdg-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 8rem;
}

.jdg-bar-track {
    flex: 1;
    height: 0.5rem;
    border-radius: 999px;
    background: var(--portal-c-border-subtle);
    overflow: hidden;
}

.jdg-bar-fill {
    height: 100%;
    border-radius: 999px;
    background: var(--portal-c-accent);
    transition: width var(--portal-dur-2, 0.2s) var(--portal-ease-out, ease-out);
}

.jdg-bar-value {
    font-family: var(--bs-font-monospace);
    font-size: var(--portal-text-sm);
    min-width: 2.5rem;
    text-align: right;
}

/* ── Responsive tiers ────────────────────────────────────────────── */

/* Tablet portrait (768-991): corner cards 2-up, the attack/submit card
 * full-width below them (its order-1 already puts it last). */
@media (min-width: 768px) and (max-width: 991.98px) {
    .jdg-corners-row > .col-lg-4:not(.order-1) {
        flex: 0 0 50%;
        max-width: 50%;
    }

    .jdg-corners-row > .order-1 {
        flex: 0 0 100%;
        max-width: 100%;
    }
}

/* Phone: pill icons off (six text labels fit a swipe track at 375px),
 * tighter fight strip, smaller bot photos. */
@media (max-width: 767.98px) {
    .jdg-page .portal-tabs .nav-link i {
        display: none;
    }

    .jdg-fight-strip .card-body {
        padding: 0.875rem;
    }

    /* The header wraps at this width — a right-shoved timer on its own line
     * reads as a stray element, so it rejoins the left edge. */
    .jdg-fight-strip-header .jdg-timer-chip {
        margin-left: 0;
    }

    .jdg-meta-row {
        gap: 0.75rem 1.5rem;
    }

    .jdg-bot-photo {
        max-width: 120px;
        max-height: 80px;
    }

    /* Row thumbnails shrink rather than vanish — the table scrolls
     * horizontally, so the bots stay recognizable on a phone */
    .jdg-row-bot {
        width: 26px;
        height: 20px;
    }

    .jdg-attack-num {
        font-size: var(--portal-text-3xl);
    }
}

@media (prefers-reduced-motion: reduce) {
    .jdg-bar-fill {
        transition: none;
    }
}
