/* ==================================================================
   Bracket — masthead, roster, board, cards, champion, celebration.
   ================================================================== */

/* ---------------- masthead ---------------- */
#masthead {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--cs-1);
    width: 100%;
    max-width: 1280px;
}
/* The studio link and the ? share one row above the mark. .cs-site-link
   itself is in base.css — the walkthrough carries one too, and that page
   has no reason to load the board's geometry. */
.masthead-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--cs-4);
    width: 100%;
    margin-bottom: var(--cs-2);
}

/* The ? is a .cs-button, so it is the same metal as every other control
   and gets the same hover sweep and press. Only the shape changes: a
   round chip reads as a marker rather than as another command in the
   console's row. */
.cs-help-btn {
    flex: none;
    width: 30px;
    min-height: 30px;
    padding: 0;
    border-radius: 50%;
    display: inline-grid;
    place-items: center;
    font-size: 14px;
    font-weight: 700;
    line-height: 1;
    color: var(--cs-text-secondary);
}
.cs-help-btn:hover {
    border-color: var(--cs-cosmic);
    color: var(--cs-ice);
    box-shadow: 0 4px 8px rgba(0,0,0,.35),
                inset 0 1px 0 rgba(255,255,255,.10),
                0 0 16px rgba(142,220,255,.20);
}

/* The mark is a wide lockup (roughly 3.75:1), so height is the binding
   constraint on a desktop window and width takes over on a phone. The
   source is trimmed to its own artwork — an untrimmed export carries
   enough transparent margin that max-height would be measuring mostly
   empty space and the letters would come out half size. */
#masthead img {
    max-width: min(520px, 86vw);
    max-height: 112px;
    width: auto; height: auto;
    object-fit: contain;
    /* Seat the chrome on the void: a faint cool bloom, no colour cast. */
    filter: drop-shadow(0 3px 14px rgba(0,0,0,.8))
            drop-shadow(0 0 22px rgba(221,246,255,.12));
    -webkit-user-drag: none;
}
#masthead .subtitle {
    font-size: 13px;
    /* Tracked out far enough that it reads as a rule under the mark
       rather than as a second, competing word. */
    letter-spacing: .58em;
    text-indent: .58em;     /* re-centres against the trailing space */
    margin-top: -2px;
}

/* ---------------- console (toolbar) ---------------- */
#console { width: 100%; max-width: 1280px; }
#console .cs-panel-inner {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--cs-4);
}

.console-group {
    display: flex;
    flex-direction: column;
    gap: var(--cs-1);
    min-width: 0;
}
.console-group .row {
    display: flex;
    align-items: center;
    gap: var(--cs-2);
    flex-wrap: wrap;
}
.console-sep {
    align-self: stretch;
    width: 1px;
    background: linear-gradient(180deg, transparent, var(--cs-chrome-shadow) 22%,
                var(--cs-chrome-shadow) 78%, transparent);
    flex: none;
}
#console .spacer { flex: 1 1 auto; min-width: 0; }

#player-input { width: 190px; }
#custom-bracket-size { width: 84px; }

#save-status {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--cs-cosmic);
    white-space: nowrap;
    opacity: 0;
    transition: opacity var(--cs-slow);
}
#save-status.visible { opacity: .85; }

.hint {
    font-size: 11px;
    color: var(--cs-text-muted);
    line-height: 1.5;
    max-width: 100%;
}
.hint b { color: var(--cs-text-secondary); font-weight: 650; }

/* ---------------- trash ---------------- */
#trash {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--cs-2);
    min-width: 140px;
    min-height: 30px;
    padding: 0 var(--cs-3);
    border-radius: var(--cs-radius-md);
    background: var(--cs-void);
    border: 1px dashed var(--cs-chrome-shadow);
    box-shadow: inset 0 1px 3px rgba(0,0,0,.9);
    font-size: 10px;
    font-weight: 650;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--cs-text-muted);
    transition: border-color var(--cs-fast), color var(--cs-fast),
                box-shadow var(--cs-fast);
}
#trash.drag-over {
    border-color: var(--tm-danger);
    border-style: solid;
    color: #f4c3c7;
    box-shadow: inset 0 1px 3px rgba(0,0,0,.9), 0 0 16px rgba(226,125,134,.28);
}

/* ---------------- roster ---------------- */
#roster { width: 100%; max-width: 1280px; }

#player-pool {
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: var(--cs-2);
    min-height: 64px;
    padding: var(--cs-2);
    border-radius: var(--cs-radius-md);
    background: rgba(5,6,7,.42);
    border: 1px dashed var(--cs-chrome-shadow);
    box-shadow: inset 0 1px 4px rgba(0,0,0,.7);
    transition: border-color var(--cs-fast), box-shadow var(--cs-fast);
}
#player-pool.drag-over {
    border-color: var(--cs-cosmic);
    border-style: solid;
    box-shadow: inset 0 1px 4px rgba(0,0,0,.7), 0 0 18px rgba(142,220,255,.18);
}
/* Speaks only when the bench is actually empty. */
#player-pool:empty::after {
    content: "Bench empty — add a player above";
    align-self: center;
    margin: auto;
    font-size: 11px;
    color: var(--cs-text-disabled);
    letter-spacing: .04em;
}

/* ---------------- board ---------------- */
#board {
    position: relative;
    width: 100%;
    max-width: 1280px;
    flex: 1;
}
#board .cs-panel-inner { padding: var(--cs-4) var(--cs-3); }

/* The hero star sits under the bracket as a watermark, the same way the
   visualiser seats it under the scope. Low enough that a card over it
   still reads; present enough that the empty board is not a void. */
#board-watermark {
    position: absolute;
    left: 50%; top: 50%;
    width: min(560px, 70%);
    transform: translate(-50%, -50%);
    opacity: .07;
    pointer-events: none;
    z-index: 0;
    -webkit-user-drag: none;
}

#bracket-area {
    position: relative;
    z-index: 1;
    display: flex;
    justify-content: safe center;
    align-items: stretch;
    gap: var(--tm-round-gap);
    min-height: 300px;
    padding-bottom: var(--cs-2);
    overflow-x: auto;
}
#bracket-area:empty::after {
    content: "No board yet — choose a size and generate one";
    margin: auto;
    font-size: 12px;
    color: var(--cs-text-disabled);
    letter-spacing: .04em;
}

.round-column {
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    gap: var(--cs-3);
    flex: none;
    padding: var(--cs-1);
    border-radius: var(--cs-radius-md);
    transition: background var(--cs-normal);
}
.round-column:hover { background: rgba(142,220,255,.025); }

.round-column > h3 {
    margin: 0 0 var(--cs-1);
    font-size: 10px;
    text-align: center;
    /* Chrome type, since the kit ships no plate for these words. */
    letter-spacing: .18em;
}

/* ---------------- matchup ---------------- */
.matchup-box {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--cs-1);
    padding: var(--cs-2);
    border-radius: var(--cs-radius-md);
    background: linear-gradient(180deg, rgba(28,34,41,.58), rgba(14,17,21,.72));
    box-shadow: 0 6px 16px rgba(0,0,0,.34),
                var(--cs-chrome-seat),
                inset 0 1px 0 rgba(255,255,255,.05);
    transition: box-shadow var(--cs-normal);
}
/* Chrome ring, quieter than the panels' so a column of them does not
   turn into a wall of metal. */
.matchup-box::before {
    content: "";
    position: absolute; inset: 0;
    border-radius: inherit;
    padding: 1px;
    background: var(--cs-chrome-edge);
    opacity: .5;
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude;
    pointer-events: none;
    transition: opacity var(--cs-normal);
}
.matchup-box:hover::before { opacity: 1; }

/* A short chrome tick off the right edge, reading as bracket linework.
   Deliberately a stub and not a connector: rounds can be added, deleted
   and resized by hand, so no drawn line could keep telling the truth
   about which slot feeds which. */
.matchup-box::after {
    content: "";
    position: absolute;
    right: calc(var(--tm-round-gap) / -2 - 1px);
    top: 50%;
    width: calc(var(--tm-round-gap) / 2);
    height: 1px;
    background: linear-gradient(90deg, var(--cs-dark-chrome), transparent);
    pointer-events: none;
}
.round-column:last-child .matchup-box::after { display: none; }

/* ---------------- drop zone ---------------- */
.drop-zone {
    position: relative;
    width: var(--tm-slot-w);
    height: var(--tm-slot-h);
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--cs-radius-sm);
    /* A recessed well, like the meter troughs in the visualiser. */
    background: var(--cs-void);
    border: 1px solid transparent;
    box-shadow: inset 0 2px 5px rgba(0,0,0,.9), inset 0 1px 0 rgba(255,255,255,.02);
    transition: border-color var(--cs-fast), box-shadow var(--cs-fast);
}
.drop-zone.drag-over {
    border-color: var(--cs-cosmic);
    box-shadow: inset 0 2px 5px rgba(0,0,0,.9), 0 0 16px rgba(142,220,255,.30);
}
/* Rejected drop: the slot is already taken. */
.drop-zone.reject {
    border-color: var(--tm-danger);
    box-shadow: inset 0 2px 5px rgba(0,0,0,.9), 0 0 16px rgba(226,125,134,.36);
}

.drop-zone .player-card {
    position: absolute;
    inset: 0;
    width: 100%; height: 100%;
    margin: 0;
    z-index: 2;
}

/* ---------------- champion ---------------- */
.champion-zone {
    border-color: rgba(230,216,154,.42);
    box-shadow: inset 0 2px 5px rgba(0,0,0,.9), 0 0 20px var(--tm-champion-glow);
}
.champion-zone.drag-over {
    border-color: var(--tm-champion);
    box-shadow: inset 0 2px 5px rgba(0,0,0,.9), 0 0 28px rgba(230,216,154,.5);
}
/* The champion heading is struck in gold rather than chrome — the same
   ramp shape as --cs-chrome, warmed. It is the only warm light here. */
.champion-column > h3 {
    /* background-image, not the `background` shorthand: the shorthand
       resets background-clip, which would drop the text clipping this
       inherits from .cs-chrome-type and paint the gold across the whole
       box instead of into the letters. */
    background-image: linear-gradient(180deg,
        #fffdf4 0%, #f2e7bd 18%, #b7a878 44%,
        #fffbe9 62%, #8d825c 82%, #efe6c4 100%);
    filter: drop-shadow(0 1px 0 rgba(0,0,0,.85))
            drop-shadow(0 0 14px rgba(230,216,154,.22));
}

/* ---------------- player card ---------------- */
.player-card {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: var(--tm-slot-w);
    min-height: var(--tm-slot-h);
    padding: 0 var(--cs-3);
    border-radius: var(--cs-radius-sm);
    background: var(--tm-card);
    border: 1px solid var(--tm-card-edge);
    box-shadow: 0 4px 10px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,255,255,.07);
    font-size: 12px;
    font-weight: 650;
    letter-spacing: .02em;
    color: var(--cs-text);
    text-align: center;
    cursor: grab;
    overflow: hidden;
    /* Long names shrink rather than breaking the slot's width. */
    white-space: nowrap;
    text-overflow: ellipsis;
    transition: border-color var(--cs-fast), background var(--cs-fast),
                box-shadow var(--cs-fast), transform var(--cs-fast);
}
.player-card:hover {
    background: var(--tm-card-hi);
    border-color: var(--cs-titanium);
    box-shadow: 0 6px 14px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.10),
                0 0 14px rgba(142,220,255,.12);
}
.player-card:active { cursor: grabbing; transform: translateY(1px); }
/* The same one-pass metallic sweep the buttons use. */
.player-card::before {
    content: "";
    position: absolute; inset: 0;
    background: linear-gradient(105deg, transparent 32%,
                rgba(255,255,255,.12) 48%, rgba(221,246,255,.18) 52%, transparent 68%);
    transform: translateX(-130%);
    transition: transform 620ms ease;
    pointer-events: none;
}
.player-card:hover::before { transform: translateX(130%); }

.player-card .label {
    position: relative;
    z-index: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}

/* Card being dragged. */
.player-card.dragging { opacity: .45; }

/* ---------------- pinned winner ----------------
   A held result rather than a live card: dimmed, un-draggable, and
   marked with the chrome star from the kit. The badge is the brand's
   own five-point star, not a letter in a circle. */
.pinned-winner {
    background: linear-gradient(180deg, rgba(30,40,50,.85), rgba(12,17,22,.9));
    border-color: rgba(142,220,255,.5);
    box-shadow: inset 0 0 14px var(--tm-pinned-glow),
                0 0 12px rgba(142,220,255,.22);
    color: var(--cs-ice);
    opacity: .82;
    cursor: default !important;
    /* Inert so the live card sitting in the same slot stays grabbable. */
    pointer-events: none;
    z-index: 1 !important;
    /* A live card clips its highlight sweep; a held result has no sweep
       to clip, and its star badge sits outside the card's box on
       purpose. Clipping here turned the star into a corner triangle. */
    overflow: visible;
}
.pinned-winner::before { content: none; }
.pinned-winner .label { font-weight: 600; }

/* Right-clicking a held result has to reach something, and the ghost
   itself is pointer-events: none so it never steals a drag. */
.pinned-winner-overlay {
    position: absolute;
    inset: 0;
    z-index: 3;
    cursor: context-menu;
    pointer-events: auto;
}

/* ---------------- celebration ---------------- */
#winner-screen {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1000;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: var(--cs-4);
    padding: var(--cs-6);
    background:
        radial-gradient(ellipse 60% 50% at 50% 45%, rgba(30,48,78,.55), transparent 70%),
        rgba(5,6,7,.94);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}
#winner-screen.open { display: flex; }

/* #winner-star is a sprite; sprites.css owns its box, its filter and
   its two animations. */
#winner-screen .eyebrow {
    font-size: 11px;
    letter-spacing: .42em;
    text-indent: .42em;
    color: var(--cs-text-secondary);
    text-transform: uppercase;
    font-weight: 650;
    animation: tm-rise 600ms 120ms ease-out both;
}
#winner-name-display {
    font-size: clamp(34px, 8vw, 76px);
    line-height: 1.05;
    text-align: center;
    max-width: 90vw;
    overflow-wrap: anywhere;
    animation: tm-pop 800ms 140ms cubic-bezier(.2,.9,.25,1.15) both;
}
#winner-screen .cs-button { animation: tm-rise 600ms 320ms ease-out both; }

@keyframes tm-pop {
    0%   { transform: scale(.6); opacity: 0; }
    62%  { transform: scale(1.06); }
    100% { transform: scale(1); opacity: 1; }
}
@keyframes tm-rise {
    from { transform: translateY(10px); opacity: 0; }
    to   { transform: translateY(0); opacity: 1; }
}

/* ---------------- narrow windows ---------------- */
@media (max-width: 760px) {
    :root { --tm-slot-w: 140px; --tm-round-gap: 34px; }
    #app { padding: var(--cs-4) var(--cs-2) var(--cs-8); }
    #console .cs-panel-inner { gap: var(--cs-3); }
    .console-sep { display: none; }
    #player-input { width: 100%; min-width: 140px; }
}

/* ==================================================================
   Select then place
   ==================================================================

   Cosmic light is reserved for state, and "in hand" is the strongest
   transient state the board has — so the carried card is the brightest
   thing on screen while it is being carried, and nothing else is.
   ================================================================== */

.player-card.is-carried {
    z-index: 6;
    border-color: var(--cs-cosmic);
    box-shadow: 0 10px 22px rgba(0,0,0,.7),
                0 0 0 1px var(--cs-cosmic),
                0 0 26px rgba(142,220,255,.45);
    /* Lifted, not enlarged: growing the card would push its neighbours
       around inside a slot that is a fixed size. */
    transform: translateY(-3px);
    cursor: grabbing;
}

/* Where it can go, said before it is clicked. Dragging can only refuse
   after the fact; this is the same answer given in advance. */
body.is-carrying .drop-zone.can-take,
body.is-carrying #player-pool.can-take {
    border-color: rgba(142,220,255,.55);
    background: rgba(142,220,255,.06);
    box-shadow: inset 0 0 0 1px rgba(142,220,255,.18);
}
body.is-carrying #trash.can-take {
    border-color: rgba(226,125,134,.6);
    color: #f4c3c7;
}
/* Enough to read as unavailable, not so much that the board becomes
   unreadable while you are deciding where to put someone. */
body.is-carrying .drop-zone.cannot-take {
    opacity: .52;
}
body.is-carrying .drop-zone.can-take:hover,
body.is-carrying .drop-zone.can-take:focus-visible {
    border-color: var(--cs-cosmic);
    background: rgba(142,220,255,.13);
    outline: none;
}

/* A slot the keyboard has landed on has to be visible on its own, not
   only under a pointer. */
.drop-zone:focus-visible,
#player-pool:focus-visible,
#trash:focus-visible,
.player-card:focus-visible {
    outline: 2px solid var(--cs-cosmic);
    outline-offset: 2px;
}

/* The line that says what is in hand. */
.board-activity {
    margin: 0 0 var(--cs-2);
    padding: 7px var(--cs-3);
    border: 1px solid rgba(142,220,255,.28);
    border-radius: var(--cs-radius-md);
    background: rgba(142,220,255,.07);
    color: var(--cs-ice);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .04em;
}
.board-activity[hidden] { display: none; }

/* ==================================================================
   Renaming in place
   ================================================================== */

/* A round heading edits in the heading's own slot, at the heading's own
   size, so the column does not jump while it is being renamed. */
.round-rename {
    width: 100%;
    margin: 0 0 var(--cs-1);
    padding: 0;
    border: 0;
    border-bottom: 1px solid var(--cs-cosmic);
    background: transparent;
    color: var(--cs-text);
    font-family: var(--cs-font-ui);
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .18em;
    text-align: center;
    text-transform: uppercase;
    outline: none;
    user-select: text;
}

.player-card.is-editing {
    cursor: text;
    border-color: var(--cs-cosmic);
    box-shadow: 0 0 0 1px var(--cs-cosmic), 0 0 18px rgba(142,220,255,.3);
}
.player-card.is-editing::before { content: none; }   /* no sheen over a field */

.card-rename {
    width: 100%;
    min-width: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--cs-text);
    font-family: inherit;
    font-size: inherit;
    font-weight: inherit;
    letter-spacing: inherit;
    outline: none;
    user-select: text;
}

/* ==================================================================
   The bench: a height of its own, and a filter
   ==================================================================

   Without a ceiling the bench simply grows — forty players is a
   thousand pixels of column that pushes the board off the page. It
   scrolls instead, which is also what makes filtering worth anything.
   ================================================================== */

#bench-filter {
    flex: none;
    width: 100%;
    margin-bottom: var(--cs-2);
    font-size: 12px;
}

#player-pool {
    max-height: min(46vh, 420px);
    overflow-y: auto;
    overscroll-behavior: contain;
}

.player-card.is-filtered-out { display: none; }

/* :empty cannot speak for a bench that is full but entirely filtered
   out, so that case gets its own message. */
#player-pool.no-matches::after {
    content: "No one on the bench matches that";
    align-self: center;
    margin: auto;
    padding: var(--cs-4) 0;
    color: var(--cs-text-disabled);
    font-size: 11px;
    letter-spacing: .04em;
}

#bench-count {
    flex: none;
    font-size: 11px;
    color: var(--cs-text-muted);
    font-variant-numeric: tabular-nums;
}

/* ==================================================================
   The readout
   ================================================================== */

#board-summary {
    flex: none;
    max-width: 100%;
    font-size: 11px;
    color: var(--cs-text-muted);
    font-variant-numeric: tabular-nums;
    text-align: right;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The rule between the heading and the readout has to be allowed to
   collapse, or the readout is pushed out of the panel on a phone. */
.cs-module-head .cs-rule { min-width: var(--cs-4); }

@media (max-width: 620px) {
    #board-summary { font-size: 10px; }
    /* Stacked, the readout gets the width it needs instead of competing
       with the heading for one line. */
    #board .cs-module-head { flex-wrap: wrap; }
    #board-summary { text-align: left; width: 100%; }
    #player-pool { max-height: min(40vh, 320px); }
}
