/* ==========================================================================
   CORE STYLESHEET
   This block was originally shipped MINIFIED on a single 16,360-character line,
   with every later addition appended below it as readable, commented CSS. It has
   been expanded here (one selector per line, declarations inline) so the whole
   file reads consistently. No declaration was changed: the expansion was done by
   parsing the rules and asserting the parsed rule set is identical afterwards,
   apart from the deliberately-removed orphans noted below.

   Removed in the same pass - styling for markup that no longer exists:
     .tab-pane .modal-body .modal-header-left .modal-header-actions .modal-subheader
     .date-nav .nav-arrow-btn .fav-item .stealth-link .logoPh .score-row .col-time
     .col-title .col-panel .settings-grid-2col .leagues-grid .icon-action-btn
     .imp-high/.imp-med/.imp-low .text-success .text-danger  #hdr  #dev-tools-host
   (#dev-tools-host was the Time Travel host, deleted deliberately in D1.)

   KEPT despite being unreferenced: .screen-box .sel-wrap .col-sel - the dormant
   TV-assignment feature's styling. See #day-print-btn in index.html.
   ========================================================================== */
*{box-sizing:border-box}

body{
    accent-color:var(--primary);
    background-color:#1f232b;
    color:#e7eefc;
    display:flex;
    flex-direction:column;
    font-family:'Segoe UI',Tahoma,Geneva,Verdana,sans-serif;
    font-size:17px;
    height:100dvh;
    height:100vh;
    margin:0;
    overflow:hidden;
    padding:0;
    transition:background .3s;
}

html.light body{
    background-color:#f5f7fa;
    color:#222;
}

#logo{
    align-items:center;
    display:flex;
    font-size:1.6em;
    font-weight:bold;
    white-space:nowrap;
}

#logo #version-text{
    background:rgb(255 255 255 / 10%);
    border-radius:4px;
    color:#888;
    font-size:.5em;
    font-weight:normal;
    margin-left:8px;
    padding:2px 6px;
}

#controls{
    display:flex;
    gap:15px;
}
#settings-btn:hover{background:rgb(255 255 255 / 10%)}
html.light #settings-btn{color:#222}
html.light #settings-btn:hover{background:rgb(0 0 0 / 5%)}

#calendar-host{
    background:#333;
    display:grid;
    flex:1;
    gap:1px;
    grid-template-columns:repeat(7,1fr);

    /* FOUR rows (ENH00041). Must match CAL_VIEW_SPANS.month / 7 in
       render.guide.js - the cells are emitted by JS and laid out here, so a
       disagreement either squeezes a row off the bottom or leaves a blank one.
       tests/test_js_syntax.py asserts the two agree. */
    grid-template-rows:repeat(4,1fr);
    overflow:hidden;
}
html.light #calendar-host{background:#ccc}

.cal-cell{
    background:#1f232b;
    cursor:pointer;
    display:flex;
    flex-direction:column;
    min-height:0;
    padding:5px;
    position:relative;
    transition:background .2s;
}
html.light .cal-cell{background:#fff}
.cal-cell:hover{background:#2a2e38}
html.light .cal-cell:hover{background:#f0f0f0}

/* TODAY. The one cell a reader looks for first, so it gets the strongest
   treatment on the grid now that the month boundary no longer competes for it:
   a thicker full-accent ring rather than a thin dark one, plus a soft outer
   glow so the cell reads as raised instead of merely bordered. */
.cal-cell.is-today{
    background:#252b36;
    box-shadow:inset 0 0 0 3px var(--primary,#5e95ff),
               0 0 0 1px rgb(94 149 255 / 35%),
               0 0 12px rgb(94 149 255 / 28%);
    z-index:1;
}
html.light .cal-cell.is-today{background:#e6f0ff}

.cal-date-num{
    align-items:baseline;
    color:#888;
    display:flex;
    font-size:1.1em;
    font-weight:bold;
    gap:5px;
    margin-bottom:5px;
}

/* (shown/total) beside the date. Lighter and smaller than the number itself -
   it is context for the day, not a competing headline. */
.cal-count{
    color:#6f7889;
    font-size:.62em;
    font-weight:600;
    letter-spacing:0;
}
html.light .cal-count{color:#8a93a3}
.cal-cell.is-today .cal-count{color:#b9c9e8}
html.light .cal-cell.is-today .cal-count{color:#4a6a95}

/* Today's DATE NUMBER: white and heavy against the #888 every other day uses.
   Weight and colour together, because the number is small enough that either
   alone reads as "slightly different" rather than "this is the one". */
.cal-cell.is-today .cal-date-num{
    color:#fff;
    font-weight:900;
    letter-spacing:.02em;
    text-shadow:0 1px 3px rgb(0 0 0 / 55%);
}

/* Light theme inverts it: white on a pale blue cell would be nearly invisible,
   so near-black carries the same "heaviest thing here" role instead. */
html.light .cal-cell.is-today .cal-date-num{
    color:#0b1220;
    text-shadow:none;
}
html.light .cal-content{color:#555}
.cal-mobile-header{display:none}
.cal-mobile-body{display:none}

@media (width <=768px){
    #calendar-host{
    -webkit-overflow-scrolling:touch;
    background:#1f232b;
    display:flex;
    flex-direction:column;
    min-height:0;
    overflow-y:auto;
}

    .cal-cell{
    align-items:center;
    border-bottom:1px solid #333;
    flex-direction:row;
    flex:0 0 auto;
    height:auto;
    justify-content:space-between;
    min-height:0;
    padding:16px 18px;
}
    .cal-date-num{display:none}
    .cal-content{display:none}

    .cal-mobile-header{
    align-items:center;
    display:flex;
    justify-content:space-between;
    width:100%;
}

    .cal-mobile-date{
    font-size:1.1em;
    font-weight:bold;
}

    .cal-mobile-count{
    color:#888;
    font-size:.9em;
}

    .cal-cell.mobile-expanded{
    background:#2a2e38;
    border-bottom:1px solid var(--primary);
    flex-direction:column;
}

    .cal-mobile-body{
    border-top:1px solid #444;
    display:none;
    margin-top:15px;
    padding-top:15px;
    width:100%;
}
    .cal-cell.mobile-expanded .cal-mobile-body{display:block}

    .mob-bd-row{
    border-bottom:1px solid #333;
    display:flex;
    font-size:.9em;
    justify-content:space-between;
    padding:8px 0;
}

    .mob-open-btn{
    margin-top:15px;
    padding:12px;
    width:100%;
}
}

.modal{
    align-items:center;
    display:flex;
    height:100%;
    justify-content:center;
    left:0;
    position:fixed;
    top:0;
    width:100%;
    z-index:1000;
}

.modal-content{
    background-color:#1f232b!important;
    border-radius:8px;
    border:1px solid #444;
    box-shadow:0 10px 25px rgb(0 0 0 / 50%);
    display:flex;
    flex-direction:column;
    height:calc(94vh - var(--tk-h,64px));
    margin:3vh auto;
    max-height:calc(94vh - var(--tk-h,64px));
    max-width:95vw;
    position:relative;
    width:1250px;
    z-index:1002;
}

.day-modal-content{
    background-color:#1f232b!important;
    border-radius:8px;
    border:1px solid #444;
    box-shadow:0 10px 25px rgb(0 0 0 / 50%);
    display:flex;
    flex-direction:column;
    height:calc(94vh - var(--tk-h,64px));
    margin:3vh auto;
    max-height:calc(94vh - var(--tk-h,64px));
    max-width:95vw;
    position:relative;
    width:1250px;
    z-index:1002;
}

html.light .modal-content{
    background:#fff!important;
    border:1px solid #ccc;
    box-shadow:0 10px 25px rgb(0 0 0 / 20%);
    color:#222;
}

html.light .day-modal-content{
    background:#fff!important;
    border:1px solid #ccc;
    box-shadow:0 10px 25px rgb(0 0 0 / 20%);
    color:#222;
}

.modal-header{
    align-items:center;
    border-bottom:1px solid #444;
    display:flex;
    flex-shrink:0;
    justify-content:space-between;
    padding:10px 20px;
}
html.light .modal-header{border-bottom:1px solid #eee}

#day-modal-title{
    display:inline-block;
    flex-shrink:0;
    overflow:hidden;
    text-align:center;
    text-overflow:ellipsis;
    white-space:nowrap;
    width:320px;
}

.modal-header h3{
    font-size:1.4em;
    margin:0;
    white-space:nowrap;
}

/* THE close affordance, shared by level-1 modal headers (.close-btn) and
   level-2 popover cards (.tip-close, positioned separately further down). One
   definition so the control a user learns on the Day modal looks and behaves
   identically on a game or team card. It is also the ONLY way to close either
   level - click-off was removed (see the note on window.onclick in js/main.js). */
.close-btn,.tip-close{
    background:0 0;
    border:none;
    color:inherit;
    cursor:pointer;
    user-select:none;
    font-size:1.35em;
    line-height:1;
    opacity:.55;
    transition:opacity .15s,color .15s;
    flex-shrink:0;
    padding:0 2px;
}

.close-btn:hover,.tip-close:hover,
.close-btn:focus-visible,.tip-close:focus-visible{
    opacity:1;
    color:#fff;
}
html.light .close-btn:hover,html.light .tip-close:hover{color:#1b2431}

.tab-btn{
    background:0 0;
    border-bottom:2px solid transparent;
    border:none;
    color:#888;
    cursor:pointer;
    flex:1;
    font-weight:500;
    padding:12px;
}

.tab-btn.active{
    background:rgb(94 149 255 / 5%);
    border-bottom:2px solid var(--primary);
    color:var(--primary);
}

.tab-info{
    color:#888;
    font-size:.85em;
    font-style:italic;
    margin-bottom:15px;
}

/* min-width:0 and gap are the whole no-overflow story. A flex item defaults to
   min-width:auto, which means it refuses to shrink below its content - so a long
   league name did not truncate, it pushed the tri-switch out past the modal edge
   instead. Constraining the row (and the label, below) makes the NAME the thing
   that gives, which is the only part that can afford to. */
.league-row{
    align-items:center;
    background:#252b36;
    border-radius:6px;
    border:1px solid #333;
    display:flex;
    gap:8px;
    justify-content:space-between;
    min-width:0;
    padding:8px 12px;
}

/* First child of a row is always the label. Truncate rather than overflow, and
   keep the full text reachable via its title attribute. */
.league-row>span:first-child{
    min-width:0;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

/* The switch never shrinks and never wraps - it is the fixed anchor the label
   truncates against. */
.league-row .tri-switch{flex:0 0 auto}

html.light .league-row{
    background:#f9f9f9;
    border:1px solid #ddd;
}

.tri-switch{
    background:#111;
    border-radius:4px;
    display:flex;
    gap:2px;
    padding:2px;
}
html.light .tri-switch{background:#ddd}

.tri-opt{
    border-radius:3px;
    color:#666;
    cursor:pointer;
    font-size:.75em;
    font-weight:bold;
    padding:4px 8px;
}

.tri-opt.active{
    background:var(--primary);
    color:#fff;
}

/* --- SOCX group (see the "SOCX decomposition" spec in README.md) -------------
   The group row is always present, even at zero, and always shows its count -
   that is the "hidden but discoverable" half of the design. The + expands the
   list; it changes no visibility state, so nobody opts into eighty
   competitions by clicking a disclosure control. */

/* The leagues list is no longer one flat grid - it is a stack of per-sport
   sections, each with its own heading and its own 3-up grid inside. */

.lg-sport-head{
    align-items:baseline;
    border-bottom:1px solid #333;
    color:#9db4d6;
    display:flex;
    font-size:.82em;
    font-weight:800;
    gap:8px;
    letter-spacing:.06em;
    margin:14px 2px 6px;
    padding-bottom:4px;
    text-transform:uppercase;
}
.lg-sport-head:first-child{margin-top:2px}

.lg-sport-head i{
    color:#7d8799;
    font-size:.9em;
    font-style:normal;
    font-weight:600;
}

.lg-sport-note{
    color:#7d8799;
    font-size:.82em;
    font-style:italic;
    font-weight:500;
    letter-spacing:0;
    margin-left:auto;
    text-transform:none;
}
html.light .lg-sport-note{color:#697382}

html.light .lg-sport-head{
    border-bottom-color:#ddd;
    color:#4a6a95;
}
html.light .lg-sport-head i{color:#697382}
.lg-sport-grid{margin-bottom:2px}

/* SOCX gets its OWN full-width row, not a cell in the 3-up grid: it carries a
   long label, a parenthetical, a count and an expander, none of which fit a
   third of the width, and its flyout needs the whole modal to be readable. */
.socx-group-row{
    margin-top:18px;
    width:100%;
}

.socx-group-label{
    align-items:center;
    display:flex;
    flex-wrap:wrap;
    gap:6px;
    min-width:0;
}

.socx-paren{
    color:#888;
    font-size:.82em;
}
html.light .socx-paren{color:#666}

.socx-count{
    background:#111;
    border-radius:10px;
    color:#aaa;
    font-size:.75em;
    font-weight:bold;
    padding:1px 8px;
}

html.light .socx-count{
    background:#e4e4e4;
    color:#555;
}

/* The competitions render as an ordinary section now (see _renderSocxGroup):
   same grid, same row styling as Hockey or Golf, shown or hidden by the
   group's own switch. The previous fixed-height scrolling flyout was right
   while the modal still fit on one screen; once it did not, an inner scroll
   region inside an already-scrolling modal was two scrollbars fighting. */
.socx-empty{
    color:#9aa3b2;
    font-size:.85em;
    line-height:1.5;
    padding:8px 4px;
}

/* TWO columns for the discovered competitions - their names are long and
   foreign, and three across pushed the switch off the modal. */
.socx-grid{grid-template-columns:repeat(2,minmax(0,1fr))}

@media (width <=820px){.socx-grid{grid-template-columns:1fr}}

/* Group row actions: the bulk switch (only while the list shows) and the
   list button. */
.socx-actions{
    align-items:center;
    display:flex;
    flex:0 0 auto;
    gap:10px;
}

.socx-bulk{
    align-items:center;
    display:flex;
    gap:6px;
}

.socx-bulk i{
    color:#7d8799;
    font-size:.78em;
    font-style:italic;
    white-space:nowrap;
}
html.light .socx-bulk i{color:#697382}

.socx-listbtn{
    background:#111;
    border-radius:5px;
    border:1px solid #444;
    color:var(--primary,#5e95ff);
    cursor:pointer;
    font-size:.8em;
    font-weight:700;
    padding:5px 12px;
    white-space:nowrap;
}

.socx-listbtn:hover{
    background:var(--primary,#5e95ff);
    border-color:var(--primary,#5e95ff);
    color:#fff;
}

html.light .socx-listbtn{
    background:#eee;
    border-color:#ccc;
}

/* Content appearing below must never shift what is already on screen. Paired
   with the scrollTop restore in renderLeaguesCol - the JS handles the rebuild,
   this handles ordinary reflow. */
.leagues-host{
    display:flex;
    flex-direction:column;
    gap:4px;overflow-anchor:auto}
html.light .socx-empty{color:#666}

.socx-sub-name{
    align-items:center;
    display:flex;
    gap:6px;
    min-width:0;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

/* Gender badge. Identical size, weight and position for both - the only
   difference is hue and glyph, which is the point: one is not an annotation on
   the other. Shape differs as well as colour, so it survives greyscale and
   colourblindness. Both get a light-theme variant; adjusting only one for
   contrast would stop them being equivalent. */
.lg-gender{
    flex:0 0 auto;
    font-size:1.05em;
    font-weight:bold;
    line-height:1;
}
.lg-gender-f{color:#ff6fb5}
.lg-gender-m{color:#8ec7ff}
html.light .lg-gender-f{color:#c2185b}
html.light .lg-gender-m{color:#1565c0}

.btn-primary{
    background-color:var(--primary);
    border-radius:4px;
    border:none;
    color:#fff;
    cursor:pointer;
    font-weight:500;
    padding:8px 16px;
}
.btn-primary:hover{background-color:var(--primary-dark)}

.btn-primary:disabled{
    cursor:not-allowed;
    opacity:.5;
}

.league-group{
    border-radius:6px;
    border:1px solid #444;
    margin-bottom:15px;
    overflow:hidden;
}

.league-group summary{
    background:#252b36;
    cursor:pointer;
    font-weight:bold;
    padding:10px 15px;
    user-select:none;
}
html.light .league-group summary{background:#e9ecef}

.schedule-grid-container{
    background:#1f232b;
    border-bottom:1px solid #333;
    margin:0;
    padding:2px 0;
}

html.light .schedule-grid-container{
    background:#fff;
    border-bottom:1px solid #eee;
}

.grid-game-row{
    align-items:center;
    display:grid;
    gap:10px;
    padding:4px 10px;
    width:100%;
}

.col-league{
    align-items:center;
    color:#888;
    display:flex;
    flex-direction:column;
    font-size:.85em;
    gap:3px;
    justify-content:center;
    text-align:center;
    text-transform:uppercase;
}

.col-starttime{
    color:#9db4d6;
    font-size:.8em;
    font-weight:700;
    line-height:1.1;
    text-transform:none;
    white-space:nowrap;
}
html.light .col-starttime{color:#4a6a95}

.col-date-val{
    color:#7fa8d8;
    font-size:.9em;
    text-transform:none;
}

/* CENTRE COLUMN WIDTH. 210px until v0.18.2.198, when football's row cue gained
   its clock line: "3rd & 14 at WSU 38" had about 94px to live in once the two
   score numbers and their padding were taken out of 210, so it clipped, and a
   second line above it had nowhere to go. 260 gives the chip ~144px and the
   clock a full line of its own.

   300 SINCE BUG00036: 260 still clipped a long down and distance ("1st & 10 at
   DET 35"), and Drew asked for either a wider status or a third line, in that
   order of preference. The teams either side are names that already ellipsis,
   so they give the room up gracefully; the status had nowhere else to get it.

   THE TWO SELECTORS MUST STAY EQUAL - the day row and the scoreboard popover.
   The popover reuses the row's skeleton, so a mismatch shows up as the score
   numbers moving when you hover. Moving one and not the other is exactly the
   mistake this paragraph is here to prevent, and it was made anyway on the
   first pass of BUG00036; tests/test_js_syntax.py asserts it now rather than
   trusting the comment. */
.teamsgrid{
    align-items:center;
    display:grid;
    gap:5px;
    grid-template-columns:1fr 300px 1fr;
    width:100%;
}

.scoreboard{
    align-items:center;
    display:grid;
    gap:5px;
    grid-template-columns:1fr 300px 1fr;
    width:100%;
}

.side-away{
    align-items:center;
    display:flex;
    flex-direction:row;
    gap:10px;
    justify-content:flex-end;
    min-width:0;
    overflow:hidden;
    text-align:right;
    width:100%;
}
.side-away .team-stacked{align-items:flex-end}

.side-home{
    align-items:center;
    display:flex;
    flex-direction:row;
    gap:10px;
    justify-content:flex-start;
    min-width:0;
    overflow:hidden;
    text-align:left;
    width:100%;
}
.side-home .team-stacked{align-items:flex-start}

.status-col{
    align-items:center;
    display:flex;
    flex-direction:column;
    font-family:monospace;
    justify-content:center;
    line-height:1.1;
    min-width:140px;
    text-align:center;
}

.at{
    color:#666;
    font-size:.8em;
    text-align:center;
}

.team-stacked{
    display:flex;
    flex-direction:column;
    max-width:var(--team-width);
    overflow:hidden;
}

.t-loc{
    color:#ccc;
    font-size:.85em;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

.t-nick{
    color:#fff;
    font-size:.9em;
    font-weight:600;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}
html.light .t-loc{color:#555}
html.light .t-nick{color:#000}

.logo{
    flex-shrink:0;
    height:36px;
    object-fit:contain;
    width:36px;
}

.sb-logo-tip{
    height:32px;
    max-height:100px;
    max-width:100px;
    object-fit:contain;
    width:32px;
}

.col-nets{
    color:#aaa;
    font-size:.85em;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

.col-sel{
    display:flex;
    justify-content:flex-end;
}
.grid-cols-6{grid-template-columns:72px 1fr 6px 200px 0}
.grid-cols-5{grid-template-columns:52px 1fr 6px 200px 0}

@media (width <=900px){
    .grid-game-row{
    gap:5px 10px;
    grid-template-columns:1fr 60px;
    grid-template-rows:auto auto;
}
    .col-league{display:none}

    .col-league.col-date{
    color:#7fa8d8;
    display:block;
    font-size:.75em;
    grid-column:1;
    grid-row:2;
    text-align:left;
}

    .col-teams{
    grid-column:1;
    grid-row:1;
}

    .col-nets{
    font-size:.8em;
    grid-column:2;
    grid-row:1;
    text-align:right;
}

    .col-sel{
    font-size:.75em;
    grid-column:2;
    grid-row:2;
    justify-content:flex-end;
}
    .col-imp{display:none}
}

.sel-wrap{
    background:#111;
    border-radius:4px;
    display:flex;
    gap:2px;
    overflow:hidden;
}

.screen-box{
    align-items:center;
    appearance:none;
    background:#222;
    border-radius:4px;
    border:1px solid #ccc;
    color:#fff;
    cursor:pointer;
    display:flex;
    font-size:.65em;
    font-weight:bold;
    height:28px;
    justify-content:center;
    margin:0;
    width:28px;
}
.screen-box::after{content:attr(data-sc)}

.screen-box:checked{
    background:var(--primary);
    border-color:var(--primary);
    color:#fff;
}

.row-loathe{
    background:rgb(231 76 60 / 10%)!important;
    border-left:4px solid #e74c3c!important;
}

.col-imp{
    color:#888;
    font-weight:bold;
    text-align:center;padding:0!important}

.tooltip{
    background:#181b21;
    border-radius:4px;
    border:1px solid #444;
    box-shadow:0 5px 15px rgb(0 0 0 / 50%);
    display:none;
    font-size:.9em;
    max-height:80vh;
    max-width:500px;
    overflow-y:auto;
    padding:10px;
    pointer-events:none;
    position:fixed;
    z-index:99999!important;
}

html.light .tooltip{
    background:#fff;
    border-color:#ccc;
    color:#222;
}

.fav-list{
    align-content:flex-start;
    display:flex;
    flex-wrap:wrap;
    gap:0;
    width:100%;
}

.fav-delete{
    color:#888;
    font-weight:bold;
    margin-left:8px;
    opacity:.3;
    transition:opacity .2s;
}

.factor-row{
    border-bottom:1px solid #333;
    display:flex;
    justify-content:space-between;
    padding:10px 0;
}

.factor-input{
    background:#111;
    border:1px solid #444;
    color:#fff;
    padding:4px;
    text-align:center;
    width:60px;
}

.theme-icons{
    background:#111;
    border-radius:4px;
    display:flex;
    margin-left:10px;
    padding:2px;
}

.theme-icon-btn{
    background:0 0;
    border-radius:3px;
    border:none;
    color:#666;
    cursor:pointer;
    padding:4px 6px;
}

.theme-icon-btn.active{
    background:#333;
    color:#fff;
}

/* THE DAY FILTER BAR. Two rows and no more: a row of sport buttons, and the
   league panel for whichever sport is open beneath it. See the block comment
   above _dayFilterBar in js/render.guide.js for why it is not a list of
   collapsible sections - that shape shortened each section without reducing how
   many there were, so the bar still grew with coverage. The 40vh cap stays as a
   backstop and should now never be reached. */
.filter-bar{
    display:flex;
    flex-direction:column;
    gap:7px;
    max-height:40vh;
    overflow:hidden auto;
    padding:10px;
    scrollbar-width:thin;
}

/* ONE ROW. It wraps rather than scrolls sideways if a day ever carries more
   sports than fit - a hidden control is worse than a second line, and at ten
   groups this does not wrap at any width worth designing for. */
.dfs-row{
    align-items:center;
    display:flex;
    flex-wrap:wrap;
    gap:7px 8px;
}

.filter-group{
    background:#111;
    border-radius:4px;
    display:flex;
    flex:0 0 auto;
}

.filter-group button{
    background:0 0;
    border:none;
    color:#ccc;
    cursor:pointer;
    font-size:.85em;
    padding:5px 10px;
}
.filter-group button:hover{color:#fff}

/* The sport button REPORTS on/off and SETS nothing - clicking it opens the
   panel. Three states, because all-on and some-on are different facts and
   while the panel is shut this button is the only thing reporting either. */
.dfs-pill{
    align-items:center;
    background:#252b36;
    border-radius:12px;
    border:1px solid #444;
    color:#8b98ab;
    cursor:pointer;
    display:inline-flex;
    font-size:.85em;
    gap:7px;
    padding:5px 11px;
    white-space:nowrap;
}

.dfs-pill:hover{
    border-color:#6b7688;
    color:#dfe7f3;
}

.dfs-pill.active{
    background:var(--primary-dim);
    border-color:var(--primary);
    color:var(--primary);
}

/* Part-lit: the sport's colour at the border, but not filled - "some of this is
   showing" reads as neither on nor off, which is what it is. */
.dfs-pill.partial{
    border-color:var(--primary);
    border-style:dashed;
    color:#c9d9f0;
}

/* The open one is anchored to the panel below it: same background, and the
   bottom corners squared off so the two read as one object. */
.dfs-pill.is-open{
    background:#20262f;
    border-bottom-left-radius:3px;
    border-bottom-right-radius:3px;
    border-color:#6b7688;
    color:#fff;
}

.dfs-pill.is-open.active,
.dfs-pill.is-open.partial{border-color:var(--primary)}

.dfs-name{
    font-weight:700;
    letter-spacing:.02em;
}

.dfs-count{
    font-size:.9em;
    font-weight:800;
    opacity:.8;
}

/* THE PANEL that floats down. Its own surface rather than loose pills on the
   bar, so it is obvious the leagues in it belong to the button above. */
.dfl-panel{
    background:#20262f;
    border-radius:8px;
    border:1px solid #39414f;
    padding:8px 10px 10px;
}

@keyframes dfl-drop{
    from{
        opacity:0;
        transform:translateY(-7px);
    }

    to{
        opacity:1;
        transform:none;
    }
}

/* Only on the render that OPENED it - see DAY_FILTER_JUST_OPENED. Replaying
   this on every league toggle would read as a flicker, not as motion. */
.dfl-panel.is-new{animation:dfl-drop .16s ease-out}

@media (prefers-reduced-motion:reduce){
    .dfl-panel.is-new{animation:none}
}

/* All/None first, then the caption - the same order as the sports row above,
   so the pair reads as one control at two scales. It lives here rather than in
   the scrolling list so it stays put: inside the list it scrolled away with the
   pills, and on soccer's 59 competitions the control for "show me all of these"
   was off-screen for almost all of what it applies to. */
.dfl-head{
    align-items:center;
    display:flex;
    gap:10px;
    padding:0 2px 7px;
}

.dfl-caption{
    align-items:baseline;
    display:flex;
    gap:8px;
    min-width:0;
    overflow:hidden;
}

.dfl-name{
    color:#dfe7f3;
    font-size:.92em;
    font-weight:800;
    letter-spacing:.02em;
}

.dfl-meta{
    color:#8b98ab;
    font-size:.82em;
    white-space:nowrap;
}
.dfl-meta b{color:#c9d9f0}

/* Soccer was 59 competitions on the day this was measured. The panel scrolls at
   that size rather than growing - capping ONE panel is the whole reason only one
   sport is ever open.

   11vh, halved from the 22vh it shipped at for an afternoon: at 22 the box was
   about a quarter of the window and still read as the bar dominating the modal,
   which is the complaint this whole control exists to answer. The px floor is
   for short windows, where 11vh alone would leave under two rows of pills and
   the box would stop being a list at all. */
.dfl-pills{
    align-items:center;
    display:flex;
    flex-wrap:wrap;
    gap:8px 10px;
    max-height:max(11vh,92px);
    overflow:hidden auto;
    scrollbar-width:thin;
}

html.light .dfs-pill{
    background:#eef0f4;
    border-color:#ccc;
    color:#5a6675;
}

html.light .dfs-pill.is-open{
    background:#e3e7ee;
    border-color:#9aa5b4;
    color:#111;
}

html.light .dfl-panel{
    background:#e3e7ee;
    border-color:#c3cad4;
}

html.light .dfl-name{color:#1e2733}

html.light .dfl-meta{color:#5a6675}
html.light .dfl-meta b{color:#1e2733}

.filter-pill.active{
    background:var(--primary-dim);
    border-color:var(--primary);
    color:var(--primary);
    font-weight:bold;
}

.calendar-popup{
    background:#1f232b;
    border-radius:8px;
    border:1px solid #555;
    box-shadow:0 10px 30px rgb(0 0 0 / 80%);
    display:none;
    left:50%;
    padding:15px;
    position:absolute;
    top:50%;
    transform:translate(-50%,-50%);
    width:min(320px,92vw);
    z-index:3000;
}

html.light .calendar-popup{
    background:#fff;
    border:1px solid #ccc;
}

.clickable-date-title{
    border-radius:4px;
    cursor:pointer;
    padding:2px 8px;
    transition:background .2s;
}
.clickable-date-title:hover{background:rgb(255 255 255 / 10%)}

.cal-header{
    align-items:center;
    display:flex;
    font-weight:bold;
    justify-content:space-between;
    margin-bottom:10px;
}

.cal-grid{
    display:grid;
    gap:5px;
    grid-template-columns:repeat(7,1fr);
    text-align:center;
}

.cal-day-label{
    color:#888;
    font-size:.8em;
    margin-bottom:5px;
}

.cal-day{
    border-radius:4px;
    color:#555;
    font-size:.9em;
    padding:8px 0;
}

.cal-day.valid{
    color:#fff;
    cursor:pointer;
}
html.light .cal-day.valid{color:#333}
.cal-day.valid:hover{background:#333}

.cal-day.selected{
    background:var(--primary);
    color:#fff!important;
}
.cal-day.today{border:1px solid var(--primary)}

/* HIDDEN ON SCREEN, always. #print-area is a staging area for the printable
   sheet; only the @media print block below reveals it.
   Without this it was a plain <div> that rendered whatever printSelectedGames()
   injected - and since .pt-logo's sizing also lives in the print block, the team
   logos came out at their natural size. The result was a giant unstyled schedule
   dumped down the page after every print, sitting behind the modal and still
   there after closing it. The dormant printDaySchedule() had the same latent
   flaw; it just could never fire, so nothing ever revealed it. */
#print-area{display:none}

@media print{
    body>*:not(#print-area){display:none!important}

    .print-header{
    border-bottom:2px solid #000;
    margin-bottom:20px;
    padding-bottom:10px;
    text-align:center;
}

    .print-table{
    border-collapse:collapse;
    font-size:12pt;
    width:100%;
}

    .print-table th{
    border-bottom:2px solid #000;
    padding:5px;
    text-align:left;
}

    .print-table td{
    border-bottom:1px solid #ccc;
    padding:8px 5px;
    vertical-align:middle;
}

    .pt-time{
    font-weight:bold;
    width:80px;
}

    .pt-net{
    font-size:.9em;
    line-height:1.45;
    width:118px;
}

    .pt-screen{
    font-size:1.2em;
    font-weight:bold;
    text-align:center;
    width:80px;
}

    /* --- BRACKET SHEET ------------------------------------------------------
       The on-screen bracket is dark, scrolls sideways, and caps its own height.
       None of that survives contact with paper, so the print rules undo all
       three: ink-on-white, nothing clipped, nothing scrollable, and no box
       allowed to break across a page. Landscape is set by printBracket() at
       print time (js/main.js) - @page cannot be scoped to a class, so it is
       injected and removed rather than living here. */
    .print-bracket .tv-ladder{
    display:flex;
    gap:8px;
    overflow:visible;
    max-height:none;
    align-items:stretch;
    page-break-inside:avoid;
    break-inside:avoid;
    zoom:1;
}

    /* The on-screen zoom control is a screen affordance; paper has no use for
       it, and a printed bracket must never inherit a 50% zoom the reader
       happened to leave selected. */
    .tv-zoom{display:none}

    .print-bracket .tv-rung{
    min-width:0;
    flex:1 1 0;
}
    .print-bracket .tv-rung-body{gap:4px}

    .print-bracket .tv-rung-name{
    color:#000;
    font-size:9pt;
    border-bottom:1.5px solid #000;
    margin-bottom:5px;
    padding-bottom:2px;
}

    .print-bracket .tv-tie{
    background:#fff;
    border:1px solid #333;
    border-radius:4px;
    padding:3px 4px;
    page-break-inside:avoid;
    break-inside:avoid;
}

    /* A ghost has to stay visibly a placeholder in greyscale, where colour and
       opacity are unreliable - so it is the DASHED BORDER that carries the
       meaning on paper, exactly as the favourites sheet marks by weight rather
       than colour. */
    .print-bracket .tv-ghost{
    opacity:1;
    border-style:dashed;
    border-color:#999;
}
    .print-bracket .tv-ghost .tv-name{color:#999}

    .print-bracket .tv-side{
    color:#000;
    font-size:9pt;
}

    .print-bracket .tv-score{
    color:#000;
    font-weight:bold;
}
    .print-bracket .tv-won .tv-name{font-weight:bold}
    .print-bracket .tv-won .tv-score{color:#000}

    .print-bracket .tv-meta{
    color:#444;
    border-top:1px solid #ddd;
    font-size:7pt;
}

    .print-bracket .tv-tv{
    color:#000;
    font-weight:bold;
}

    .print-bracket .tv-logo{
    width:12px;
    height:12px;
}
    .print-bracket .tv-groups{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}

    .print-bracket .tv-gtable td{
    color:#000;
    border-bottom:1px solid #ccc;
    font-size:9pt;
}
    .print-bracket .tv-gpos,.print-bracket .tv-grec{color:#444}

    /* --- print-list sheet ---------------------------------------------------
       Favourites are marked with WEIGHT, not colour - see .pt-fav below. The
       sheet is now fully greyscale-safe, so print-color-adjust is no longer
       load-bearing; it is kept only so team and league logos print as their
       actual artwork rather than being lightened away with the rest of the
       "backgrounds" browsers strip to save ink. */
    #print-area{
    background:#fff;
    color:#000;
    display:block!important;
    -webkit-print-color-adjust:exact;
    print-color-adjust:exact;
}

    .pt-date{
    width:90px;
    white-space:nowrap;
}

    /* WRAPS, unlike the date beside it. The League column used to hold a key
       ("MLB", or later "aff.championship") which always fit in one nowrap line;
       it now holds a real name, and "AFC Champions League Two Qualifying" at
       12pt with nowrap would drag the whole table off the right edge of the
       page. Two lines in this cell costs nothing - the matchup column beside it
       is already two lines by design. */
    .pt-lg{width:120px}

    .pt-logo{
    width:18px;
    height:18px;
    object-fit:contain;
    vertical-align:middle;
    margin-right:4px;
}
    .pt-team{white-space:nowrap}

    /* Matchup stacks: visitor line, then "@ home" line. Each line is a flex row
       opening with a fixed 14px slot so the logos align vertically down the
       column regardless of whether the row is starred. */
    .pt-side{
    align-items:center;
    display:flex;
    line-height:1.45;
    white-space:nowrap;
}
    .pt-side+.pt-side{margin-top:2px}

    .pt-lead{
    flex:0 0 14px;
    text-align:left;
    width:14px;
}
    .pt-at{color:#666}

    /* FAVOURITES ARE MARKED BY WEIGHT, NOT COLOUR.
       This was a pale yellow row fill, which is correct reasoning for a colour
       printer and backwards for a mono one: greyscale renders that yellow as a
       mid-grey wash UNDER the text, so the row a reader is meant to find first
       came out lower-contrast and more subdued than the ordinary rows around
       it - the highlight actively hid its own row.
       Weight has no such failure mode. It survives greyscale, photocopying, a
       fax, and a browser that ignores print-color-adjust entirely, because it
       is carried by the glyphs themselves rather than by anything behind them.
       The star stays as a second, non-typographic cue and goes black for the
       same reason the fill went away. */
    .pt-star{
    color:inherit;
    font-size:1.05em;
}
    .pt-fav td{font-weight:800}
    .pt-fav .pt-team{letter-spacing:.01em}

    /* Repeat the header on every page of a long list, and never split a game
       across a page break. */
    .print-table thead{display:table-header-group}

    .print-table tr{
    page-break-inside:avoid;
    break-inside:avoid;
}

    @page{margin:14mm}
}

::-webkit-scrollbar{
    height:8px;
    width:8px;
}
::-webkit-scrollbar-track{background:#111}

::-webkit-scrollbar-thumb{
    background:#444;
    border-radius:4px;
}
::-webkit-scrollbar-thumb:hover{background:#666}
html.light ::-webkit-scrollbar-track{background:#eee}
html.light ::-webkit-scrollbar-thumb{background:#bbb}

.tippy-box[data-theme~='translucent']{
    backdrop-filter:blur(8px);
    background-color:rgb(24 27 33 / 95%);
    border-radius:8px;
    border:1px solid #444;
    box-shadow:0 8px 24px rgb(0 0 0 / 50%);
    color:#e7eefc;
    font-family:inherit;
}
.status-text{color:#5e95ff !important}

/* ============================================================
   COMPATIBILITY PATCH (2026-07)
   The HTML/JS drifted to new class names during AI editing
   sessions while this stylesheet kept the old ones. Everything
   above is the untouched original; the rules below map the new
   names onto the original design. This is also what fixes the
   "settings modal stuck open with all tabs stacked" bug: the
   original CSS had no display rules for .modal-overlay or
   .tab-content.
   ============================================================ */

/* Modal overlays: hidden by default; JS sets display:flex to open */

/* NO backdrop-filter here. Dimming and blur are the job of the ONE shared scrim
   (#popover-backdrop), which is positioned directly beneath whatever layer is
   topmost. Every overlay carrying its own blur is how the app ended up with four
   independent blur sources stacking on each other. */
.modal-overlay{
    display:none;
    position:fixed;
    top:0;
    left:0;
    width:100%;
    height:100%;
    box-sizing:border-box;
    padding-bottom:var(--tk-h,64px);
    z-index:1000;
    justify-content:center;
    align-items:center;
}

/* Settings tab panes (old name: .tab-pane) */
.tab-content{
    display:none;
    padding:20px;
}
.tab-content.active{display:block}

.tab-controls{
    display:flex;
    flex:1;
    margin-right:15px;
}
.tab-controls .tab-btn{flex:1}

/* Header (old ids: #hdr / #logo / #controls) */
.app-header{
    flex:0 0 auto;
    background:#181b21;
    border-bottom:1px solid #333;
    padding:10px 20px;
    display:flex;
    justify-content:space-between;
    align-items:center;
    z-index:50;
}

html.light .app-header{
    background:#fff;
    border-bottom:1px solid #ccc;
}

.header-left h1{
    margin:0;
    font-size:1.6em;
    font-weight:bold;
    white-space:nowrap;
    display:flex;
    align-items:center;
}

.header-left #version-text{
    font-size:.5em;
    font-weight:normal;
    color:#888;
    margin-left:8px;
    background:rgb(255 255 255 / 10%);
    padding:2px 6px;
    border-radius:4px;
}

.header-right{
    display:flex;
    gap:15px;
    align-items:center;
}

/* Buttons (old names: .nav-arrow-btn / .today-btn / .icon-action-btn) */
.nav-btn{
    background:0 0;
    border:1px solid #444;
    color:#ccc;
    cursor:pointer;
    border-radius:4px;
    width:30px;
    height:30px;
    display:flex;
    align-items:center;
    justify-content:center;
}
.nav-btn:hover{background:#333}

.nav-btn:disabled{
    opacity:.3;
    cursor:default;
    background:0 0;
}

.btn-secondary{
    background:var(--primary-dim);
    color:var(--primary);
    border:1px solid var(--primary);
    border-radius:4px;
    padding:5px 10px;
    cursor:pointer;
    font-size:.8em;
    font-weight:bold;
}

.btn-secondary:disabled{
    opacity:0;
    pointer-events:none;
}

.icon-btn{
    background:0 0;
    border:1px solid #444;
    color:#ccc;
    width:32px;
    height:32px;
    border-radius:4px;
    display:flex;
    align-items:center;
    justify-content:center;
    cursor:pointer;
}

.icon-btn:hover{
    background:#333;
    color:#fff;
}

.icon-btn:disabled{
    opacity:.3;
    cursor:default;
    background:0 0;
}

#settings-btn{
    align-items:center;
    background:0 0;
    color:#e7eefc;
    cursor:pointer;
    display:flex;
    justify-content:center;
    transition:background .2s;
    border:none;
    width:auto;
    height:auto;
    font-size:1.5em;
    border-radius:50%;
    padding:5px;
}

/* Day modal internals */
.modal-header h2{
    margin:0;
    font-size:1.3em;
    white-space:nowrap;
    cursor:pointer;
    padding:2px 8px;
    border-radius:4px;
}
.modal-header h2:hover{background:rgb(255 255 255 / 10%)}

.modal-nav-left,.modal-nav-right{
    display:flex;
    gap:8px;
    align-items:center;
}

#day-modal-body{
    padding:10px 15px;
    overflow-y:auto;
    flex:1;
}

.view-tabs{
    display:flex;
    border-bottom:1px solid #444;
    background:#181b21;
    flex-shrink:0;
}

html.light .view-tabs{
    background:#f0f0f0;
    border-bottom:1px solid #ccc;
}

.view-tab-btn{
    flex:1;
    padding:12px;
    background:0 0;
    border:none;
    color:#888;
    cursor:pointer;
    font-weight:500;
    border-bottom:2px solid transparent;
}

.view-tab-btn.active{
    color:var(--primary);
    border-bottom:2px solid var(--primary);
    background:rgb(94 149 255 / 5%);
}

.static-summary{
    background:#252b36;
    padding:10px 15px;
    font-weight:bold;
    user-select:none;
}
html.light .static-summary{background:#e9ecef}

.rank-sup{
    font-size:.8em;
    color:var(--primary);
    font-weight:bold;
}

.team-logo{
    width:36px;
    height:36px;
    object-fit:contain;
    flex-shrink:0;
}

/* Settings odds and ends */

/* Match the day-view modal's footprint (was 860x660, too small on desktop). */

.settings-grid{
    display:grid;
    grid-template-columns:repeat(3,1fr);
    gap:10px;
}

@media (width <=768px){.settings-grid{grid-template-columns:1fr}}

.fav-picker-row{
    display:flex;
    gap:8px;
    flex-wrap:wrap;
    margin-bottom:15px;
}

.fav-picker-row select{
    background:#111;
    border:1px solid #444;
    color:#fff;
    padding:6px;
    border-radius:4px;
    flex:1;
    min-width:140px;
}

html.light .fav-picker-row select{
    background:#fff;
    color:#222;
    border-color:#ccc;
}

/* Masks the admin code without the input being type="password".
   Chrome offers "Update password?" for any password field it sees a value typed
   into, so the only reliable way to stop that prompt is to not be one - see the
   comment on #admin-code-input in index.html. text-security gives the same dots.
   Supported in Chrome/Edge/Safari and Firefox 119+; on anything older the code
   is briefly visible while typing, which is an acceptable trade for a LAN admin
   code that is never stored in the browser anyway. */

/* Flashed briefly when the server rejects the admin code (POST /admin/auth 401). */
.admin-code-bad{
    border-color:#e74c3c!important;
    box-shadow:0 0 0 2px rgb(231 76 60 / 35%);
}

/* Locked admin tab: every control is genuinely `disabled` (see
   setAdminControlsEnabled). Only the CONTROLS are dimmed - the data is not.
   This used to fade the entire matrix, footer and controls block at .55, which
   greyed out the counts, timestamps and run logs as well: the panel is
   READ-OPEN by design and those numbers are the whole reason to look at it, so
   dimming them made a working display look broken. Locking removes the ability
   to act, not the ability to read. */
.admin-locked .adm-matrix button:disabled,
.admin-locked .adm-controls button:disabled,
.admin-locked .adm-matrix input:disabled,
.admin-locked .adm-controls input:disabled,
.admin-locked .adm-matrix select:disabled,
.admin-locked .adm-controls select:disabled{opacity:.45}
.admin-locked .adm-boot{opacity:.6}
.admin-locked .admin-unlock-row{opacity:1}

/* ==========================================================================
   UNIFIED ADMIN MATRIX
   Rows = data sources (live / guide / standings / structure / logos / db),
   columns = Records | Last Run | Cadence | Action. This replaced four separate
   blocks (status table, stats line, cadence list, database panel) that each
   reported overlapping numbers from different sources.

   It is a grid rather than a <table> so a cell can hold a slider, a button, or
   a multi-line run log without fighting table layout, and so the whole thing
   can re-flow to two columns on a phone (media query at the bottom).
   ========================================================================== */

/* Six columns since v1.9.2: a live ELAPSED counter sits to the right of every
   action button. It ticks while a job runs and freezes on the final figure when
   it finishes, so "is this still going, and how long has it been?" is answerable
   at a glance instead of by reading two timestamps and subtracting. */
.adm-matrix{
    display:grid;
    grid-template-columns:minmax(140px,1.1fr) minmax(96px,.7fr) minmax(200px,1.5fr) minmax(180px,1.35fr) auto minmax(84px,auto);
    align-items:center;
    border:1px solid #333;
    border-radius:8px;
    overflow:hidden;
    font-size:.86em;
    background:rgb(0 0 0 / 12%);
}

html.light .adm-matrix{
    border-color:#ddd;
    background:#fbfcfd;
}

.adm-matrix>div{
    padding:8px 10px;
    border-bottom:1px solid #2a2f38;
    min-width:0;
}
html.light .adm-matrix>div{border-bottom-color:#e6e8ec}

/* Last row of six data rows = the final five cells. */

/* Six cells per row since the ELAPSED column was added. */
.adm-matrix>div:nth-last-child(-n+6){border-bottom:0}

/* Backfill reuses the matrix grid so its cells line up with the table above,
   but it is a UTILITY rather than a scheduled source - it sits below the costs
   and the cadence controls, separated by a rule so it doesn't read as a seventh
   data row. */

/* BACKFILL LAYOUT (2026-08-05).
   It used to share the matrix's six columns, which squeezed a unit picker, two
   date inputs, a league multi-select and an estimate into the ~180px Cadence
   column - everything wrapped onto its own line and the reset button landed
   under the dropdowns. It has more controls than any matrix row, so it gets its
   own two-row grid: identity/records/last-run/action across the top, and the
   full width beneath for the controls. */
.adm-backfill{
    margin-top:16px;
    padding-top:14px;
    border-top:1px solid #2a2f38;
    grid-template-columns:minmax(140px,1.1fr) minmax(96px,.7fr) minmax(200px,1.5fr) auto minmax(84px,auto);
}

/* The controls cell spans every column on a second row. */
.adm-backfill .adm-cad-backfill{
    grid-column:1 / -1;
    border-bottom:0;
    display:flex;
    flex-wrap:wrap;
    align-items:flex-start;
    gap:10px 18px;
    padding-top:2px;
}
.adm-backfill>div{border-bottom:0}

/* Each control group keeps its label and inputs together when the row wraps. */

.adm-h{
    font-size:.82em;
    letter-spacing:.6px;
    text-transform:uppercase;
    font-weight:800;
    color:#8fb2dd;
    background:rgb(0 0 0 / 28%);
}

html.light .adm-h{
    color:#5a6a80;
    background:#eef1f5;
}
.adm-h-act{text-align:right}

/* Source name + one line of plain English about what that job actually does. */
.adm-src b{
    display:block;
    color:#e7eefc;
    font-weight:800;
}

.adm-src span{
    display:block;
    font-size:.85em;
    color:#7d8799;
    line-height:1.25;
    margin-top:1px;
}
html.light .adm-src b{color:#1b2431}
html.light .adm-src span{color:#697382}

/* Records: one big number, one qualifier - so "games" can never be mistaken
   for "teams" the way it was when four renderers each printed a bare count. */
.adm-rec{font-variant-numeric:tabular-nums}

.adm-rec b{
    display:block;
    font-size:1.35em;
    font-weight:800;
    color:var(--primary);
    line-height:1.1;
}

.adm-rec span{
    display:block;
    font-size:.8em;
    color:#8fb2dd;
    margin-top:1px;
    line-height:1.2;
}
html.light .adm-rec span{color:#4a6a95}

/* Proof-of-run label: START is always bold; RUNTIME/END are italic while the
   job is in flight and bold once the numbers are final. */
.adm-log{
    color:#8fb2dd;
    font-size:.94em;
    display:flex;
    align-items:center;
    gap:6px;
    flex-wrap:wrap;
    font-variant-numeric:tabular-nums;
}

.adm-log b{
    color:#e7eefc;
    font-weight:800;
}
.adm-log .rl-sep{color:#4d5a6e}

.adm-log .rl-idle{
    font-style:italic;
    opacity:.75;
}

.adm-log .rl-done{
    font-weight:800;
    font-style:normal;
    color:#e7eefc;
}

.adm-log .rl-live{
    font-style:italic;
    font-weight:400;
    color:#ffd24a;
}

.adm-log .rl-badge{
    font-size:.72em;
    font-weight:800;
    letter-spacing:1px;
    color:#1f232b;
    background:#4ade80;
    border-radius:10px;
    padding:1px 8px;
}

.adm-log-na{
    font-style:italic;
    opacity:.7;
}
html.light .adm-log{color:#4a6a95}
html.light .adm-log b,html.light .adm-log .rl-done{color:#223}

/* Cadence: slider + readout, or a static note for the jobs that have no timer. */
.adm-cad{font-size:.94em}

.adm-elapsed{
    color:#9aa3b2;
    font-variant-numeric:tabular-nums;
    font-weight:700;
    text-align:right;
    white-space:nowrap;
}

/* Previous run's time, stacked above the live counter while a job is running.
   A number ticking upward says nothing on its own; the same number beside
   "last 17.2s" says immediately whether this run is normal. */
.el-prev{
    color:#7d8799;
    display:block;
    font-size:.78em;
    font-weight:600;
}
.el-now{display:block}
html.light .el-prev{color:#8a93a3}
html.light .adm-elapsed{color:#5a6373}

/* Running: accent + a slow pulse, so a long job reads as alive rather than hung. */
.adm-elapsed.el-run{
    color:var(--primary,#5e95ff);
    animation:elpulse 1.6s ease-in-out infinite;
}

@keyframes elpulse{0%,100%{opacity:1}50%{opacity:.55}}
.adm-h-el{text-align:right}

/* Total for the whole ordered sequence, beside the Update All button. */
.adm-seq{
    color:#9aa3b2;
    font-variant-numeric:tabular-nums;
    font-weight:700;
    margin-right:10px;
}

.adm-seq.el-run{
    color:var(--primary,#5e95ff);
    animation:elpulse 1.6s ease-in-out infinite;
}

.adm-cad-top{
    display:flex;
    justify-content:center;
    margin-bottom:2px;
}

.adm-cad input[type="range"]{
    width:100%;
    margin:0;
    display:block;
}

.adm-cad-note{
    color:#7d8799;
    font-style:italic;
    text-align:center;
}
html.light .adm-cad-note{color:#697382}

.cadence-val{
    font-variant-numeric:tabular-nums;
    font-weight:800;
    color:var(--primary);
    background:var(--primary-dim);
    border:1px solid var(--primary);
    border-radius:12px;
    padding:1px 10px;
    font-size:.9em;
    min-width:70px;
    text-align:center;
}

.cadence-scale{
    display:flex;
    justify-content:space-between;
    font-size:.7em;
    color:#7d8799;
    margin-top:1px;
}

.cadence-scale span:nth-child(2){
    color:#9a7fd0;
    font-weight:700;
}
html.light .cadence-scale{color:#667}

/* Backfill: a date range + optional league picker in place of a slider,
   plus a live request-count estimate so a large pull isn't a surprise. */
.adm-cad-backfill{
    display:flex;
    flex-direction:column;
    gap:4px;
}

/* The .bf-dates date inputs went in v0.17.13.104 (the range is derived, so a
   second way to state it could only disagree) and #bf-leagues in v0.17.18.109
   (a backfill is every league or nothing, by the day). */
.bf-estimate{
    flex:1 1 100%;
    margin-top:2px;
    font-size:.78em;
    color:#7d8799;
    text-align:center;
    font-style:italic;
}

.bf-estimate.bf-estimate-warn{
    color:#ffb54a;
    font-weight:700;
    font-style:normal;
}
html.light .bf-estimate{color:#697382}

/* Walk-backwards controls: amount + unit, and the frontier they count back
   from. Wraps rather than squeezing - the Cadence column is narrow. */
.bf-walk{
    margin:0;
    flex:0 0 auto;
    display:flex;
    align-items:center;
    flex-wrap:wrap;
    gap:4px;
    font-size:.82em;
    color:#8fb2dd;
    margin-bottom:5px;
}

.bf-walk select{
    background:rgb(0 0 0 / 25%);
    color:#e7eefc;
    border:1px solid #3a4150;
    border-radius:5px;
    padding:2px 4px;
    font-size:.95em;
}

.bf-walk b{
    color:#e7eefc;
    font-variant-numeric:tabular-nums;
}

.bf-walk button{
    padding:1px 7px;
    font-size:.95em;
    line-height:1.5;
}
html.light .bf-walk{color:#4a6a95}

html.light .bf-walk select{
    background:#fff;
    color:#1b2431;
    border-color:#ccd2db;
}
html.light .bf-walk b{color:#1b2431}

/* Coverage: what has been looked at, versus what exists. */

html.light .adm-coverage{
    border-color:#ddd;
    background:#fbfcfd;
}

.adm-cov-head{
    display:flex;
    align-items:center;
    flex-wrap:wrap;
    gap:8px;
    font-size:.84em;
    color:#9aa4b5;
}
.adm-cov-head b{color:#e7eefc}

.adm-cov-head span{
    flex:1;
    min-width:0;
}

.adm-cov-head b,.adm-cov-head span b{
    color:#e7eefc;
    font-variant-numeric:tabular-nums;
}
html.light .adm-cov-head{color:#5a6373}
html.light .adm-cov-head b,html.light .adm-cov-head span b{color:#1b2431}

/* Gaps: shown only when there are some, so it reads as an alert rather than a
   permanent zero nobody looks at. */
.adm-cov-gaps{
    display:flex;
    align-items:center;
    flex-wrap:wrap;
    gap:10px;
    margin-top:8px;
    padding:6px 9px;
    border-radius:6px;
    font-size:.82em;
    background:rgb(255 181 74 / 12%);
    border:1px solid rgb(255 181 74 / 45%);
    color:#ffb54a;
}

.adm-cov-gaps span{
    flex:1;
    min-width:0;
}
.adm-cov-gaps b{color:#ffd489}

/* Only accepted days remain: a settled decision, not an outstanding problem. */
.adm-cov-gaps.cov-gaps-ok{
    background:rgb(120 140 170 / 10%);
    border-color:rgb(120 140 170 / 35%);
    color:#9aa4b5;
}
.adm-cov-gaps.cov-gaps-ok b{color:#c7d0de}

html.light .adm-cov-gaps{
    background:rgb(200 120 0 / 8%);
    border-color:rgb(200 120 0 / 40%);
    color:#8a5a00;
}
html.light .adm-cov-gaps b{color:#6a4400}

.adm-cov-detail{
    margin-top:9px;
    max-height:320px;
    overflow:auto;
}

.cov-table{
    width:100%;
    border-collapse:collapse;
    font-size:.78em;
    font-variant-numeric:tabular-nums;
}

.cov-table th,.cov-table td{
    padding:3px 7px;
    text-align:right;
    white-space:nowrap;
    border-bottom:1px solid #242a33;
}
.cov-table th:first-child,.cov-table td:first-child{text-align:left}

.cov-table th{
    color:#8fb2dd;
    font-weight:600;
    position:sticky;
    top:0;
    background:#161a21;
}
.cov-table td{color:#c7d0de}

html.light .cov-table th{
    background:#fbfcfd;
    color:#4a6a95;
}
html.light .cov-table td{color:#3a4250}
html.light .cov-table th,html.light .cov-table td{border-bottom-color:#e6e8ec}

/* Attempted, never a single game: a dead slug rather than a quiet sport. */
.cov-table tr.cov-dead td{color:#ffb54a}

/* History mode: jumping the calendar to a backfilled date. */
.view-date-input{
    background:rgb(0 0 0 / 25%);
    color:#e7eefc;
    border:1px solid #3a4150;
    border-radius:5px;
    padding:3px 5px;
    font-size:.8em;
    margin-right:4px;
}

html.light .view-date-input{
    background:#fff;
    color:#1b2431;
    border-color:#ccd2db;
}

.history-banner{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:12px;
    flex-wrap:wrap;
    padding:7px 14px;
    background:#3a2f14;
    color:#ffd489;
    border-bottom:1px solid #5a4a20;
    font-size:.86em;
}

html.light .history-banner{
    background:#fff6e0;
    color:#7a5a10;
    border-bottom-color:#e8d4a0;
}

.adm-act{text-align:right}

/* The snapshot row is the only Action cell with TWO controls (take one, then
   fetch it). Wraps rather than overflowing, because the Download link only
   appears once a snapshot exists and the column is not sized for both. */
.adm-act-snapshot{
    display:flex;
    flex-wrap:wrap;
    gap:6px;
    justify-content:flex-end;
    align-items:center;
}

.adm-act-snapshot a{
    font-size:.82em;
    padding:5px 13px;
    white-space:nowrap;
    text-decoration:none;
    line-height:normal;
}

@media (width <=768px){
    .adm-act-snapshot{justify-content:flex-start}
}

.cadence-run{
    font-size:.82em;
    padding:5px 13px;
    white-space:nowrap;
}

/* Cross-cutting detail that belongs to no single row (last run cost, retained
   date span, busiest leagues). One line each, under the grid. */

/* The status bar. Moved above the matrix (2026-08-05), so it is styled as a
   panel rather than as a trailing caption - at the top of the tab it is the
   first thing read, and loose text there looks like an orphaned line. */
.adm-footer{
    font-size:.82em;
    color:#8fb2dd;
    line-height:1.7;
    font-variant-numeric:tabular-nums;
    border:1px solid #2a2f38;
    border-radius:8px;
    background:#161a21;
    padding:8px 11px;
    margin-bottom:10px;
}

.adm-footer b{
    color:#e7eefc;
    font-weight:800;
}

html.light .adm-footer{
    color:#4a6a95;
    border-color:#ddd;
    background:#fbfcfd;
}
html.light .adm-footer b{color:#223}

/* Statistics sit directly under the status bar, so they share its rhythm. */
.adm-coverage{
    border:1px solid #2a2f38;
    border-radius:8px;
    background:#161a21;
    padding:9px 11px;
    margin-top:0;
    margin-bottom:10px;
}

.adm-controls{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:14px;
    flex-wrap:wrap;
    margin-top:12px;
}

.adm-boot{
    display:flex;
    align-items:center;
    gap:8px;
    font-size:.85em;
    color:#9db4d6;
    cursor:pointer;
    user-select:none;
}
.adm-boot input{margin:0}
html.light .adm-boot{color:#4a6a95}

.adm-controls-btns{
    display:flex;
    gap:10px;
    flex-wrap:wrap;
}

/* Phone: five columns can't survive ~380px, so stack. Each source becomes a
   banner heading with its four cells listed beneath it - same information, same
   order, just read top-to-bottom. Column headers are dropped since each cell
   already carries its own qualifier text. */
@media (width <=760px){
    .adm-matrix{grid-template-columns:1fr}
    .adm-h{display:none}

    .adm-src{
    background:rgb(0 0 0 / 28%);
    border-bottom:0;
    border-top:1px solid #2a2f38;
}

    html.light .adm-src{
    background:#eef1f5;
    border-top-color:#e6e8ec;
}

    .adm-src span{
    display:inline;
    margin-left:6px;
}

    /* First source row sits flush against the grid's own border. It's child 6,
       not 1 - the five .adm-h headers are still in the DOM, just display:none. */
    .adm-matrix>.adm-src:nth-child(6){border-top:0}
    .adm-act{text-align:left}
}

/* Enh 8: staged-removal bar. Only visible while removals are pending; nothing
   is persisted until Apply is confirmed, so Cancel is a true undo. */
.fav-stage-bar{
    display:flex;
    align-items:center;
    gap:10px;
    flex-wrap:wrap;
    width:100%;
    padding:9px 14px;
    margin-bottom:8px;
    border-radius:6px;
    background:rgb(231 76 60 / 12%);
    border:1px solid rgb(231 76 60 / 45%);
}

.fav-stage-count{
    flex:1;
    min-width:140px;
    font-size:.9em;
    font-weight:700;
    color:#ff9a90;
}
html.light .fav-stage-count{color:#a3352c}

.fav-stage-bar button{
    font-size:.85em;
    padding:5px 12px;
}

/* Enh 10: search box above the favorites picker grid. */
.fp-search-row{
    display:flex;
    gap:8px;
    align-items:center;
    padding:0 0 10px;
}

.fp-search{
    flex:1;
    min-width:0;
    background:#111;
    border:1px solid #444;
    color:#fff;
    padding:8px 12px;
    border-radius:6px;
    font-size:.95em;
}

html.light .fp-search{
    background:#fff;
    border-color:#ccc;
    color:#222;
}
.fp-search::placeholder{color:#7d8799}

.fp-search-clear{
    background:0 0;
    border:1px solid #444;
    color:#ccc;
    border-radius:6px;
    padding:7px 11px;
    cursor:pointer;
    font-size:.85em;
    white-space:nowrap;
}

.fp-search-clear:hover{
    background:#333;
    color:#fff;
}

.fp-no-match{
    color:#8fb2dd;
    font-style:italic;
    padding:12px 4px;
    text-align:center;
}

/* Enh 11: field-league (golf/racing) summary inside the league hover popover,
   shown where a standings table would be for team sports. */
.lst-wrap.lst-field{width:min(560px,94vw)}

/* A hovered bracket sizes to the ladder, not to the standings column budget
   leagueStandingsTip computes for a table it is not rendering. */
.lst-wrap.lst-bracket{width:min(900px,94vw)}
.lst-bracket .tv-ladder{max-height:66vh}
.lst-fe-wrap{margin-top:8px}

.lst-fe-title{
    font-size:.82em;
    font-weight:800;
    text-transform:uppercase;
    letter-spacing:1px;
    color:var(--primary);
    margin:10px 0 5px;
}

.lst-fe{
    display:grid;
    grid-template-columns:44px minmax(0,1fr) minmax(0,1.1fr) 54px;
    gap:8px;
    align-items:center;
    padding:3px 6px;
    border-radius:4px;
    font-size:.92em;
}
.lst-fe:nth-child(odd){background:rgb(255 255 255 / 4%)}

.lst-fe-when{
    color:#8590a4;
    font-variant-numeric:tabular-nums;
    font-size:.9em;
}

.lst-fe-evt{
    color:#c9d9f0;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}

.lst-fe-who{
    color:#e7eefc;
    font-weight:700;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}

.lst-fe-score{
    color:#ffd24a;
    text-align:right;
    font-variant-numeric:tabular-nums;
    font-weight:700;
}

/* Wins-tally rows carry only name + count, so they get their own 2-col track
   (an adjacency selector here would also catch the 4-col event rows). */
.lst-fe.lst-fe-tally{grid-template-columns:minmax(0,1fr) 54px}

.modal-footer-controls{
    padding:15px 20px;
    border-top:1px solid #444;
    background:#181b21;
    display:flex;
    justify-content:flex-end;
    align-items:center;
    gap:10px;
    flex-shrink:0;
}

html.light .modal-footer-controls{
    background:#f0f0f0;
    border-top:1px solid #ccc;
}
.bucket-row input{border-radius:4px}

/* Save confirmation box */
.save-confirm-box{
    background:#1f232b;
    border:1px solid var(--primary);
    border-radius:8px;
    padding:30px 50px;
    text-align:center;
    box-shadow:0 10px 25px rgb(0 0 0 / 50%);
}
html.light .save-confirm-box{background:#fff}

/* Mobile day-cell breakdown list */
.mob-bd-list{width:100%}

/* Print matchup column */
.pt-match{font-weight:500}


/* ============================================================
   SCOREBOARD TOOLTIP (v0.7.6 - 2x scale)
   Styled after a physical arena scoreboard: away | clock | home
   across the top, a details strip below. Logos and fonts are
   doubled from the original for readability.
   ============================================================ */
.sb-tip{
    width: min(720px, 94vw);
    max-width: 94vw;
    max-height: 88vh;
    overflow: hidden auto;
    box-sizing: border-box;
    background: #12386b;
    background: linear-gradient(180deg, #1a4a8a 0%, #12386b 100%);
    border: 3px solid #0c2547;
    border-radius: 12px;
    padding: 22px 28px 20px;
    color: #fff;
    font-family: 'Arial Narrow', Arial, sans-serif;
}

.sb-league{
    text-align: center;
    font-size: 1.3em;
    letter-spacing: 3px;
    color: var(--sb-fg-dim, #9dc2f0);
    text-transform: uppercase;
    margin-bottom: 12px;
    position: relative;
}

/* Broadcast-style "LIVE" badge - a real TV score bug always carries one.
   Pulses gently so it reads as "actively updating" without being distracting. */
.sb-live-badge{
    display:inline-block;
    vertical-align:middle;
    margin-left:10px;
    font-size:.5em;
    font-weight:800;
    letter-spacing:1.5px;
    text-transform:uppercase;
    color:#fff;
    background:#e74c3c;
    border-radius:10px;
    padding:3px 10px;
    animation:sb-live-pulse 2s ease-in-out infinite;
}

@keyframes sb-live-pulse{0%,100%{opacity:1}50%{opacity:.55}}

.sb-main{
    display: grid;
    grid-template-columns: minmax(0,1fr) auto minmax(0,1fr);
    align-items: center;
    gap: 14px;
}

.sb-side{
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
    overflow: hidden;
}
.sb-guest{ align-items: flex-end; }
.sb-home{ align-items: flex-start; }

/* Identity row: team name beside its logo, horizontal like the list rows. */
.sb-id{
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    max-width: 100%;
}

.sb-name{
    display: flex;
    flex-direction: column;
    min-width: 0;
    max-width: 100%;
}

.sb-guest .sb-name{
    align-items: flex-end;
    text-align: right;
}

.sb-home  .sb-name{
    align-items: flex-start;
    text-align: left;
}

.sb-side .sb-logo-tip{
    width: clamp(42px, 8.5vmin, 58px);
    height: clamp(42px, 8.5vmin, 58px);
    object-fit: contain;
    filter: drop-shadow(0 2px 4px rgb(0 0 0 / 50%));
    flex-shrink: 0;
}

.sb-abbr-row{
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    max-width: 100%;
}
.sb-guest .sb-abbr-row{ justify-content: flex-end; }
.sb-home  .sb-abbr-row{ justify-content: flex-start; }

.sb-abbr{
    font-weight: 800;
    font-size: clamp(1.15em, 4vmin, 1.9em);
    font-style: italic;
    letter-spacing: 1px;
    color: var(--sb-fg, #fff);
    line-height: 1.05;
    white-space: normal;
    overflow-wrap: break-word;
    min-width: 0;
    max-width: 100%;
}

/* Location line (small) shown above the nickname, e.g. "Kansas City". */
.sb-loc{
    font-size: clamp(.75em, 2vmin, .95em);
    font-weight: 600;
    color: var(--sb-fg-dim, #9dc2f0);
    line-height: 1.1;
    max-width: 100%;
    overflow-wrap: break-word;
}
.sb-guest .sb-loc{ text-align: right; }
.sb-home  .sb-loc{ text-align: left; }

.sb-rank{
    font-size: .55em;
    color: #ffd24a;
    vertical-align: super;
    margin-right: 3px;
    font-style: normal;
}

.sb-score-num{
    font-family: DS-Digital, "Courier New", monospace;
    font-size: clamp(2em, 8vmin, 4em);
    font-weight: 900;
    color: #ffb019;
    line-height: 1;
    text-shadow: 0 0 10px rgb(255 176 25 / 50%);

    /* .sb-side is a flex column right/left-aligned (toward the center chip) for
       the identity row above - without this override the score inherits that
       same alignment and sits bunched next to it. Stretching to the FULL side
       width and centering the text spreads the score across its own half
       instead, rather than crowding the middle. */
    align-self: stretch;
    text-align: center;
}

.sb-winner .sb-score-num{
    color: #ffd24a;
    text-shadow: 0 0 16px rgb(255 210 74 / 70%);
}
.sb-winner .sb-abbr{ color: #ffd24a; }

/* ============================================================
   EXPERIMENTAL (2026-07) - big background team logo watermark.
   Gated in JS by SB_BIG_LOGO_BG (see sbSide in builders.js): set
   that to `false` to stop adding the .sb-side-bglogo class/markup
   entirely, at which point this whole block simply never matches
   anything - no other change needed to fully revert.
   To ADJUST instead of revert:
     - .sb-side-bglogo -> square-ness (aspect-ratio), corner roundedness,
       outer padding, vertical centering of content (justify-content)
     - .sb-side-bg    -> logo inset % (10% each side = 80% of the box) and fade
     - .sb-side-overlay -> overlay darkness (background alpha)
   ============================================================ */
.sb-side-bglogo{
    position: relative;
    overflow: hidden;
    border-radius: 16px;
    padding: 8px;

    /* Forces a PERFECT SQUARE tied to the box's own (dynamic) width, rather than
       whatever height the content happens to need - which is also what makes it
       slightly taller than before, since the width already exceeded the old
       content-driven height. justify-content re-centers the now-shorter content
       inside the taller box (.sb-side-bglogo IS .sb-side, already a flex column). */
    aspect-ratio: 1 / 1;
    justify-content: center;
}

.sb-side-bg{
    /* <img> is a REPLACED element: with inset(10%) + width/height:auto, the spec
       has it size to its OWN INTRINSIC pixel dimensions (inset gets ignored for
       sizing, only used for position) - so it rendered at full natural size and
       got clipped by overflow:hidden, ignoring object-fit entirely since there
       was no smaller box left for it to "contain" itself within. Explicit
       width/height:80% forces the actual box size; object-fit then properly
       shrinks the image to fit inside THAT on whichever axis it needs to (i.e.
       "80% of height/width, whichever is smaller") without distorting it. */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 80%;
    height: 80%;
    object-fit: contain;
    object-position: center;
    opacity: .3;
    z-index: 0;
    pointer-events: none;
}

.sb-side-overlay{
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: rgb(8 16 28 / 40%);
}

.sb-side-bglogo .sb-id,.sb-side-bglogo .sb-score-num{
    position: relative;
    z-index: 2;
}

.sb-center{
    font-family:monospace;
    line-height:1.1;
    text-align:center;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-width: clamp(110px, 28vw, 180px);
    padding: 8px 16px;
    background: var(--sb-chip, #08192f);
    border-radius: 8px;
    border: 2px solid rgb(255 255 255 / 14%);
}

.sb-center-top{
    font-family: DS-Digital, "Courier New", monospace;
    font-size: clamp(1.5em, 6vmin, 2.8em);
    font-weight: 900;
    line-height: 1;
    color: #ffb019;
    text-shadow: 0 0 10px rgb(255 176 25 / 50%);
    white-space: nowrap;
}

.sb-center-bot{
    font-size: 1.3em;
    color: #cdd9ec;
    margin-top: 6px;
    text-transform: uppercase;
    letter-spacing: 2px;
    white-space: nowrap;
}

.sb-center.sb-sched .sb-center-top{
    font-size: 2.3em;
    color: #7fb0f0;
    text-shadow: none;
}

.sb-center.sb-final .sb-center-top{
    color: #ff6b6b;
    text-shadow: 0 0 10px rgb(255 107 107 / 40%);
}

.sb-center.sb-live  .sb-center-top{
    color: #4ade80;
    text-shadow: 0 0 10px rgb(74 222 128 / 50%);
}

/* "Awaiting Update" - ESPN still calls it scheduled hours after kickoff. Sized
   like sb-sched (it shows a start time) but in the muted amber used everywhere
   else for this state, deliberately NOT the live green: these games are usually
   already over. */
.sb-center.sb-stale .sb-center-top{
    font-size: 2.3em;
    color: #b0873a;
    text-shadow: none;
}

.sb-details{
    margin-top: 16px;
    padding-top: 12px;
    border-top: 2px solid var(--sb-line, #2a5a9a);
    text-align: center;
}

.sb-matchup{
    font-size: 1.5em;
    color: var(--sb-fg, #e8f0fc);
    font-weight: 600;
}

/* ESPN's own label for an oddball match ("Club Friendly", etc) - a small pill
   under the matchup line, same weight class as the network chips below it. */
.sb-note{
    display:inline-block;
    margin-top:6px;
    font-size:.85em;
    font-weight:700;
    letter-spacing:.4px;
    text-transform:uppercase;
    color:var(--sb-fg,#e8f0fc);
    background:rgb(255 255 255 / 14%);
    border:1px solid var(--sb-line,#2a5a9a);
    border-radius:10px;
    padding:2px 11px;
}

.sb-nets{
    font-size: 1.35em;
    color: var(--sb-fg-dim, #9dc2f0);
    margin-top: 6px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px;
}
.sb-nets-icon{ flex: 0 0 auto; }

/* One chip per broadcast source. Linked chips (telecastUrl matched the network)
   are interactive; unmatched ones stay as plain, non-clickable chips rather
   than pretending to be links that go nowhere. */
.sb-net-chip{
    font-size: .72em;
    font-weight: 700;
    line-height: 1;
    padding: 5px 10px;
    border-radius: 999px;
    border: 1px solid var(--sb-fg-dim, #9dc2f0);
    color: var(--sb-fg, #fff);
    background: rgb(255 255 255 / 8%);
    white-space: nowrap;
    text-decoration: none;
}

.sb-net-chip.is-link{
    cursor: pointer;
    transition: background .15s, transform .1s;
}

.sb-net-chip.is-link:hover{
    background: rgb(255 255 255 / 22%);
    transform: translateY(-1px);
}

.sb-net-chip.is-none{
    opacity: .7;
    font-style: italic;
    border-style: dashed;
}

.sb-imp-lbl{
    display: block;
    color: var(--sb-fg-dim, #9dc2f0);
    font-weight: 800;
    text-transform: uppercase;
    font-size: .8em;
    letter-spacing: 1px;
    margin-top: 8px;
}

.sb-imp{
    font-size: 1.25em;
    color: #ffd24a;
    margin-top: 2px;
    letter-spacing: 1px;
}

/* Hover the factor list to see the actual arithmetic (native title tooltip). */
.sb-imp.has-calc{ cursor: help; }

.sb-imp-hint{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.05em;
    height: 1.05em;
    margin-left: 7px;
    border-radius: 50%;
    font-size: .62em;
    font-weight: 800;
    letter-spacing: 0;
    vertical-align: middle;
    color: var(--sb-fg-dim, #9dc2f0);
    border: 1px solid currentcolor;
    opacity: .7;
}
.sb-imp.has-calc:hover .sb-imp-hint{ opacity: 1; }

/* Keep tippy's own box from adding a competing background */
.tippy-box[data-theme~='sb']{ background: transparent; }

/* ============================================================
   IN-POPOVER "View on ESPN" LINKS (v1.0.3)
   The hover/tap popovers (scoreboard, team, standings) each carry a
   tappable link. Since a mobile TAP now opens the popover instead of
   navigating, this link is how touch users reach ESPN. Sized as a real
   tap target (>=40px tall).
   ============================================================ */
.sb-link,.tt-link,.lst-link{
    display: block;
    margin-top: 12px;
    padding: 10px 14px;
    min-height: 40px;
    line-height: 20px;
    text-align: center;
    text-decoration: none;
    font-weight: 700;
    font-size: 1em;
    border-radius: 8px;
}

.sb-link{
    background: rgb(255 255 255 / 16%);
    color: var(--sb-fg,#fff);
    border: 1px solid rgb(255 255 255 / 28%);
}
.sb-link:hover{ background: rgb(255 255 255 / 26%); }

.tt-link{
    background: rgb(255 255 255 / 14%);
    color: #fff;
    border: 1px solid rgb(255 255 255 / 30%);
}
.tt-link:hover{ background: rgb(255 255 255 / 24%); }

.lst-link{
    margin: 12px auto 2px;
    max-width: 320px;
    background: var(--primary,#5e95ff);
    color: #fff;
}
.lst-link:hover{ background: var(--primary-dark,#4a7cc7); }

/* Popovers must fit a phone screen: cap width to the viewport and let content
   scroll VERTICALLY. The standings popover carries an inline pixel width + a
   multi-column grid for desktop, so on a phone we override both to a single
   full-width column that scrolls down instead of off the side. */
@media (width <= 480px) {
    .tippy-box{ max-width: 96vw !important; }

    .lst-wrap{
    width: auto !important;
    max-width: 96vw !important;
}

    .lst-scroll{
    grid-template-columns: 1fr !important;
    max-height: 70vh;
}
    .sb-tip,.tt-tip{ max-height: 82vh; }
}

/* Scoreboard extras (v0.7.9): team record under abbr, venue + weather lines */
.sb-record{
    font-size:1.1em;
    color:var(--sb-fg-dim,#9dc2f0);
    font-weight:600;
    font-style:italic;
    margin-top:-2px;
}
.sb-winner .sb-record{color:#ffd24a}

.sb-venue{
    font-size:1.2em;
    color:var(--sb-fg-dim,#c9d9f0);
    margin-top:6px;
}

.sb-weather{
    font-size:1.2em;
    color:var(--sb-fg-dim,#9dc2f0);
    margin-top:4px;
}

.sb-odds{
    font-size:1.2em;
    color:var(--sb-fg-dim,#9dc2f0);
    margin-top:4px;
}

/* Standing position under each scoreboard side (v0.7.10) - smaller but readable */
.sb-standing{
    font-size:0.95em;
    color:var(--sb-fg-dim,#7fa8d8);
    margin-top:2px;
    font-style:italic;
    white-space:normal;
    line-height:1.15;
}
.sb-winner .sb-standing{color:#e0c877}

/* ============================================================
   LOGO BACKDROP (v0.7.10)
   Driven by CSS custom properties set from settings (JS applies
   them live). Default: none. When enabled, every team logo gets
   a shape behind it so light-on-transparent logos stay visible.
   ============================================================ */

html.light{
    --primary-dark:#5e1fb0;
    --primary-dim:rgb(119 40 215 / 10%);
    --primary:#7728d7;
    --logo-bg-soft:rgb(0 0 0 / 22%);
}

/* Every logo surface must carry the backdrop, or the puck setting looks broken
   on whichever one was forgotten. Keep this list in sync when adding a new logo
   class. Deliberately EXCLUDED:
     - .sb-side-bg      the big faded watermark behind the game-modal team text
     - .sb-league-logo  the league mark at the TOP of the game modal - it sits on
                        the themed header, where a puck reads as a stray plate */
.logo,
.team-logo,
.sb-logo-tip,
.logo-preview,
.league-logo-img,
.cal-league-logo,
.lb-logo,
.tk-tlg,
.tk-group-lg,
.filter-pill-logo,
.tt-logo,
.fav-card-logo,
.tt-l5g-logo,
.fp-cell img,
.fp-league img,
.fp-team img{
    background:var(--logo-bg);
    padding:var(--logo-pad);
    border-radius:var(--logo-round);
    box-sizing:content-box;
}

/* ============================================================
   TEAM POPOVER (v0.7.11) - distinct from the game scoreboard.
   Header (logo, name, record) + the team's standings group with
   this team highlighted.
   ============================================================ */

/* Two widths, deliberately different (see .tt-tip-wide below):
   - BASE is the docked/side card sitting beside a game scoreboard. Widened from
     340px so the standings table's seven columns and news headlines breathe,
     while staying narrower than the standalone card so it doesn't crowd the
     game card between the two of them.
   - WIDE is the standalone card, where the team IS the subject and has the
     anchor spot to itself.
   Both keep a vw cap so narrow screens still fit; preventOverflow handles the
   rest. These two numbers are the only ones to change to re-tune the sizes. */
.tt-tip{
    width:min(500px,92vw);
    max-width:540px;
    max-height:88vh;
    overflow:hidden auto;
    background:linear-gradient(180deg,#1a4a8a 0%,#12386b 100%);
    border:2px solid #0c2547;
    border-radius:10px;
    padding:14px 16px;
    color:#fff;
    font-family:'Arial Narrow',Arial,sans-serif;
}

/* Enh 4: a team card opened standalone (not docked beside a game) gets more
   room - see _setTeamCardWidth in render.js, toggled on the standalone-sticky
   branch of _positionTeamCard only. A docked child stays at the base width. */
.tt-tip.tt-tip-wide{
    width:min(780px,92vw);
    max-width:820px;
}

/* DOCKED card - flanking a sticky game scoreboard, so it shares the viewport with
   that card AND its opposite number. Sized against that budget rather than a flat
   500px: ~660px is reserved for the scoreboard plus the two 12px gaps and the
   viewport padding, and what's left is split between the two flanking cards.
   Caps at the normal 500px on a wide screen (2559px viewport -> 500px), and
   shrinks instead of colliding on a narrower one. The 280px floor keeps it
   legible rather than letting it collapse to a sliver on a small desktop; below
   about 1220px the pair will start to reach the screen edges, which is visible
   and recoverable, unlike silently sliding over the scoreboard.
   Paired with mainAxis:false in _positionTeamCard - the width is what has to fit,
   because the POSITION is now fixed at 12px from the game card. */
.tt-tip.tt-tip-docked{
    width:max(280px,min(500px,calc((100vw - 660px) / 2)));
    max-width:500px;
}

/* No border-bottom here. Every section below the header is introduced by a
   .tt-section-title, which draws its OWN border-top - so a rule here produced a
   second line ~10px above the first section title ("LAST 5"), i.e. two
   horizontal rules stacked at the top of every card. The separator is owned by
   the section titles alone; the header keeps only its spacing. */

.tt-logo{
    width:58px;
    height:58px;
    object-fit:contain;
    flex-shrink:0;
    filter:drop-shadow(0 2px 4px rgb(0 0 0 / 50%));
}

.tt-headtext{
    display:flex;
    flex-direction:column;
    gap:2px;
}

/* Full name on ONE line: city/area (lighter weight) then nickname (bold),
   e.g. "Seattle Mariners" - matching the scoreboard's full-name convention. */
.tt-fullname{
    font-size:1.25em;
    line-height:1.15;
}

.tt-city-part{
    font-weight:400;
    color:#c9d9f0;
}

.tt-nick-part{
    font-weight:800;
    font-style:italic;
}

.tt-abbr-row{
    display:flex;
    align-items:center;
    gap:6px;
    margin-top:1px;
}

.tt-abbr{
    font-size:1em;
    color:#9dc2f0;
    letter-spacing:1px;
}

.tt-record{
    font-size:1.2em;
    color:#ffd24a;
    font-weight:700;
    margin-top:2px;
}

.tt-rank{
    font-size:.6em;
    color:#ffd24a;
    vertical-align:super;
    font-style:normal;
}

/* The separator for the Standings section lives on the CONTAINER, not on its
   inner .tt-section-title (which is overridden to no-border below). The title
   scrolls with the group table inside this box, so a rule drawn on it would
   scroll away and leave Standings looking un-separated from Last 5. On the box
   it stays put, giving Standings the same single rule every other section has. */
.tt-standings{
    margin-top:10px;
    padding-top:8px;
    border-top:1px solid #2a5a9a;
    max-height:46vh;
    overflow:hidden auto;
}

/* Standings rows. ESPN-style stat columns: W-L-PCT-GB-STRK (W/L sports) or
   W-D-L-PTS (points-based soccer). */
.tt-row{
    display:grid;
    align-items:center;
    gap:6px;
    padding:3px 8px;
    border-radius:4px;
    font-size:1em;
}
.tt-row-wl{grid-template-columns:22px minmax(0,1fr) 26px 26px 44px 40px 42px}
.tt-row-pts{grid-template-columns:22px minmax(0,1fr) 26px 26px 26px 44px}

.tt-row .tt-pos{
    color:#7fa8d8;
    text-align:right;
    font-variant-numeric:tabular-nums;
}

.tt-row .tt-team{
    font-weight:600;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}

.tt-row .tt-st{
    color:#c9d9f0;
    text-align:right;
    font-variant-numeric:tabular-nums;
    font-size:.92em;
}

.tt-row .tt-st-key{
    font-weight:800;
    color:#fff;
}

.tt-row.tt-shead{
    padding-top:0;
    padding-bottom:4px;
    border-bottom:1px solid #2a5a9a;
    margin-bottom:2px;
}

.tt-row.tt-shead .tt-team,.tt-row.tt-shead .tt-st{
    color:#8fb2dd;
    font-size:.7em;
    text-transform:uppercase;
    letter-spacing:.5px;
    font-weight:700;
}

.tt-row.tt-me{
    background:rgb(255 210 74 / 18%);
    outline:1px solid rgb(255 210 74 / 50%);
}

.tt-row.tt-me .tt-team,.tt-row.tt-me .tt-pos,.tt-row.tt-me .tt-st{
    color:#ffd24a;
    font-weight:800;
}

/* Team card additions (v1.0.4): Last-5 / Disabled List sections. Section
   titles unify the standings/last-5/DL headers. */
.tt-section-title{
    font-size:.85em;
    color:#9dc2f0;
    text-transform:uppercase;
    letter-spacing:1.5px;
    margin:10px 0 6px;
    text-align:center;
    border-top:1px solid #2a5a9a;
    padding-top:8px;
}

/* Container owns the rule (above), so the inner title contributes neither a
   border nor extra leading - otherwise the box's padding-top and the title's
   own margin-top would stack into an oversized gap under the rule. */
.tt-standings .tt-section-title{
    border-top:none;
    padding-top:0;
    margin-top:0;
}

/* Standings sub-line: the team's position (e.g. "2nd American League West"),
   folded directly under the "Standings" title instead of restated separately. */
.tt-section-sub{
    font-size:.78em;
    color:#c9d9f0;
    text-transform:none;
    letter-spacing:.3px;
    font-weight:600;
    margin-top:3px;
}

/* Last 5: an ESPN-style schedule mini-list (vs/@ opponent, result, score),
   most-recent first. */

/* Columns: vs/@ | logo | opponent | SCORE | W/L. Score sits in its own fixed,
   right-aligned column BEFORE the result so both stay in a straight line down
   the list (was ...| W/L | score, which left the W/L riding on ragged text). */

/* vs | logo | opponent | date | score | result. The date column is its own slot
   so every row lines up whether it is played (date + score + W/L) or upcoming
   (date only) - Last 5 and Next 5 now share one column layout. */
.tt-l5g{
    display:grid;
    grid-template-columns:24px 24px minmax(0,1fr) 40px 46px 22px;
    align-items:center;
    gap:8px;
    padding:4px 8px;
    border-radius:4px;
}

.tt-l5g-date{
    color:#9dc2f0;
    font-size:.82em;
    text-align:right;
    font-variant-numeric:tabular-nums;
}

.tt-l5g-clickable{
    cursor:pointer;
    transition:background .15s;
}
.tt-l5g-clickable:hover{background:rgb(255 255 255 / 8%)}
.tt-l5g:nth-child(odd){background:rgb(255 255 255 / 4%)}

.tt-l5g-vs{
    color:#8fb2dd;
    font-size:.85em;
    text-align:center;
}

.tt-l5g-logo{
    width:22px;
    height:22px;
    object-fit:contain;
}

.tt-l5g-opp{
    font-weight:600;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}

.tt-l5g-res{
    font-weight:800;
    text-align:center;
}
.tt-l5g-w{color:#3ad07a}
.tt-l5g-l{color:#ff5f61}
.tt-l5g-t{color:#9db4d6}
.tt-l5g-o{color:#9db4d6}

/* In-progress marker in the Next/Last lists (a dot, never a fabricated W/L). */
.tt-l5g-live{color:#4ade80}

/* Shown instead of rows when a side has nothing to list - says WHY rather than
   silently collapsing, since "no games" and "outside the loaded range" differ. */
.tt-sched-empty{
    color:#8fb2dd;
    font-size:.85em;
    font-style:italic;
    padding:5px 8px;
}

.tt-l5g-score{
    color:#c9d9f0;
    font-variant-numeric:tabular-nums;
    font-size:.92em;
    text-align:right;
}

/* Disabled list: one player per row, wraps/scrolls with the card. */
.tt-dl-item{
    display:flex;
    align-items:baseline;
    gap:8px;
    padding:4px 6px;
    font-size:.95em;
    border-bottom:1px solid rgb(42 90 154 / 40%);
}
.tt-dl-item:last-child{border-bottom:none}

.tt-dl-pos{
    min-width:34px;
    font-weight:800;
    color:#9dc2f0;
    font-size:.85em;
    text-transform:uppercase;
}

.tt-dl-name{
    font-weight:600;
    color:#fff;
}

.tt-dl-status{
    color:#ff9b9b;
    font-size:.85em;
    white-space:nowrap;
}

.tt-dl-detail{
    color:#c9d9f0;
    font-size:.82em;
    font-style:italic;
    margin-left:auto;
}

/* Team news: fetched live per popover (js/builders.js ensureTeamNews) -
   thumbnail + headline + date, whole row is the article link. */
.tt-news-item{
    display:flex;
    align-items:center;
    gap:8px;
    padding:5px 6px;
    border-bottom:1px solid rgb(42 90 154 / 40%);
    text-decoration:none;
    color:inherit;
}
.tt-news-item:last-child{border-bottom:none}
.tt-news-item:hover{background:rgb(255 255 255 / 6%)}
html.light .tt-news-item:hover{background:rgb(0 0 0 / 5%)}

/* Fixed-height news list. THIS is what stops the team card jumping: the block
   occupies identical space whether news is loading, absent, or fully loaded, so
   a late /team-news response can't resize the card. --tt-news-rows is the only
   number to change if you want more or fewer rows visible; it matches
   runner.TEAM_NEWS_LIMIT (4) so a full response fits without scrolling. */

/* SIZES TO ITS CONTENT, capped. Not a fixed height any more.
   The earlier version reserved up to 7 rows on a tall screen, which was simply
   wrong: runner.TEAM_NEWS_LIMIT caps the response at 4 articles, so rows 5-7
   could never be filled and every card carried three rows of dead space.
   --tt-news-max-rows must therefore track TEAM_NEWS_LIMIT; the 40vh guard is
   for short screens, where even 4 rows is too much and scrolling is right.

   On the anti-jump guarantee this softens: the skeleton renders exactly
   TEAM_NEWS_LIMIT rows, so the common case (a full response) still swaps in at
   an identical height. A team with FEWER than 4 articles now settles shorter
   when the fetch lands - but the prefetch (hover-intent + scoreboard open,
   v1.4.6.3) means the data is usually already cached at first render, and a
   docked card is top-anchored so any settle extends downward rather than
   lurching out from under the cursor. Reserving space that can never be used
   is the worse trade. */
.tt-news-list{
    --tt-news-row-h:55px;
    --tt-news-max-rows:4;

    max-height:min(calc(var(--tt-news-max-rows) * var(--tt-news-row-h)), 40vh);
    overflow-y:auto;
    overscroll-behavior:contain;
}

.tt-news-none{
    color:#8fb2dd;
    font-size:.85em;
    font-style:italic;
    padding:8px;
}

/* Skeleton placeholders shown while the fetch is in flight - same box model as
   a real .tt-news-item so the swap is invisible. */
.tt-news-skel{opacity:.45}

.tt-skel-box,.tt-skel-line{
    background:linear-gradient(90deg,
    rgb(255 255 255 / 7%) 25%,rgb(255 255 255 / 14%) 37%,rgb(255 255 255 / 7%) 63%);
    background-size:400% 100%;
    animation:tt-skel 1.4s ease-in-out infinite;
    border-radius:4px;
}

.tt-skel-line{
    height:10px;
    width:150px;
    margin-bottom:6px;
}

.tt-skel-line-short{
    width:80px;
    margin-bottom:0;
}

html.light .tt-skel-box,html.light .tt-skel-line{
    background:linear-gradient(90deg,
    rgb(0 0 0 / 6%) 25%,rgb(0 0 0 / 12%) 37%,rgb(0 0 0 / 6%) 63%);
    background-size:400% 100%;
}

@keyframes tt-skel{0%{background-position:100% 50%}100%{background-position:0 50%}}

/* Reserved row while the Last/Next 5 backfill is in flight - see teamLastNextHtml. */
.tt-sched-slot{height:26px}

@media (prefers-reduced-motion: reduce){
    .tt-skel-box,.tt-skel-line{animation:none}
}

.tt-news-img{
    width:44px;
    height:44px;
    object-fit:cover;
    border-radius:4px;
    flex-shrink:0;
}
.tt-news-text{min-width:0}

.tt-news-head{
    font-size:.9em;
    color:#e7eefc;
    font-weight:600;
    line-height:1.25;
    display:-webkit-box;
    -webkit-line-clamp:2;
    -webkit-box-orient:vertical;
    overflow:hidden;
}
html.light .tt-news-head{color:#1b2431}

.tt-news-date{
    font-size:.78em;
    color:#9dc2f0;
    margin-top:2px;
}

/* Favorite heart in scoreboard + team popover (v0.7.12) */
.fav-heart{
    cursor:pointer;
    display:inline-flex;
    align-items:center;
    justify-content:center;
    padding:2px;
    border-radius:50%;
    transition:transform .1s,background .15s;
}

.fav-heart:hover{
    transform:scale(1.2);
    background:rgb(255 255 255 / 12%);
}
.sb-fav{margin-top:8px}

.tt-fav{
    margin-left:auto;
    align-self:flex-start;
}

.tt-header{
    display:flex;
    align-items:center;
    gap:14px;
    padding-bottom:4px;position:relative}

/* Favorites view modal (v0.7.12) */
#favorites-modal-body{
    padding:10px 15px;
    overflow-y:auto;
    flex:1;
}

.fav-empty{
    text-align:center;
    color:#888;
    padding:40px 20px;
    font-size:1.1em;
}

/* ============================================================
   CALENDAR DAY-OF-WEEK HEADER + MONTH RIBBONS (v0.7.12)
   ============================================================ */
.cal-dow-header{
    display:grid;
    grid-template-columns:repeat(7,1fr);
    gap:1px;
    background:#1f232b;
    border-bottom:2px solid var(--primary,#5e95ff);
    flex:0 0 auto;
    z-index:5;
}

.cal-dow-header > div{
    text-align:center;
    padding:6px 0;
    font-size:.72em;
    font-weight:700;
    letter-spacing:2px;
    text-transform:uppercase;
    color:var(--primary,#5e95ff);
}
html.light .cal-dow-header{background:#f0f0f0}

/* Month markers: the STARTING month names itself top-left, the ENDING month
   bottom-right on its last day. The two are now styled IDENTICALLY - same
   translucent fill, same accent text, same weight - and differ only in which
   corner they sit in, which is the part that actually carries meaning.
   The month-start ribbon used to be a solid accent block with white text and a
   drop shadow, i.e. the highest-contrast element anywhere on the grid. It made
   the month boundary read as a major division of the calendar when it is
   really just a label, and the effect got worse the more the eye had to cross
   it. Matching it to the quieter outgoing-month treatment leaves the boundary
   legible without letting it dominate. */
.cal-cell.month-start{
    box-shadow:inset 3px 0 0 rgb(94 149 255 / 50%);
}

.cal-month-ribbon{
    position:absolute;
    top:0;
    left:0;
    background:rgb(94 149 255 / 22%);
    color:var(--primary,#5e95ff);
    font-size:.62em;
    font-weight:800;
    letter-spacing:1.5px;
    text-transform:uppercase;
    padding:2px 8px 3px;
    border-bottom-right-radius:8px;
    z-index:2;
    pointer-events:none;
}

/* Nudge the date number so it doesn't collide with the ribbon */
.cal-cell.month-start .cal-date-num{margin-top:16px}

/* End-of-month marker: the ending month's name, bottom-right, reading
   "all days up to here are this month". */
.cal-month-end-ribbon{
    position:absolute;
    bottom:0;
    right:0;
    background:rgb(94 149 255 / 22%);
    color:var(--primary,#5e95ff);
    font-size:.62em;
    font-weight:800;
    letter-spacing:1.5px;
    text-transform:uppercase;
    padding:2px 8px 3px;
    border-top-left-radius:8px;
    z-index:2;
    pointer-events:none;
}
.cal-cell.month-end{box-shadow:inset -3px 0 0 rgb(94 149 255 / 50%)}

/* When TODAY is also the first or last day of a month, both rules target the
   same property at equal specificity and the month one wins purely by coming
   later in the file - which silently strips today's ring on exactly two days a
   month. These compounds restate both shadows together so the ring always
   survives; the month bar rides alongside it. */
.cal-cell.is-today.month-start{
    box-shadow:inset 3px 0 0 rgb(94 149 255 / 50%),
               inset 0 0 0 3px var(--primary,#5e95ff),
               0 0 12px rgb(94 149 255 / 28%);
}

.cal-cell.is-today.month-end{
    box-shadow:inset -3px 0 0 rgb(94 149 255 / 50%),
               inset 0 0 0 3px var(--primary,#5e95ff),
               0 0 12px rgb(94 149 255 / 28%);
}

/* Hide the DOW header on mobile (calendar becomes a vertical list there) */
@media (width <=768px){
    .cal-dow-header{display:none}
    .cal-cell.month-start .cal-date-num{margin-top:0}

    .cal-month-ribbon{
    position:static;
    display:inline-block;
    border-radius:4px;
    margin-bottom:4px;
}
}

/* ============================================================
   COLLAPSIBLE GAME-STATE SECTIONS (v0.7.13)
   Time View is now grouped by state (live/delayed/scheduled/final)
   instead of a single completed/scheduled split. Each state gets a
   colored accent on its summary bar so you can tell them apart at
   a glance, and "Completed" starts collapsed by default.
   ============================================================ */
.state-section{margin-bottom:12px}

.state-section summary{
    display:flex;
    align-items:center;
    gap:8px;
}

.state-section summary::before{
    content:"";
    display:inline-block;
    width:8px;
    height:8px;
    border-radius:50%;
    flex-shrink:0;
}

.state-live summary::before{
    background:#4ade80;
    box-shadow:0 0 6px rgb(74 222 128 / 70%);
}

.state-delayed summary::before{
    background:#ffb019;
    box-shadow:0 0 6px rgb(255 176 25 / 60%);
}
.state-scheduled summary::before{background:#5e95ff}
.state-final summary::before{background:#888}
.state-final summary{color:#999}
.state-live summary{color:#4ade80}
.state-delayed summary{color:#ffb019}

/* Awaiting Update (BUG00003). A DULLER amber than .state-delayed, and no glow:
   the section is about our source being behind, not about anything happening. */
.state-stale summary::before{background:#b0873a}
.state-stale summary{color:#b0873a}

/* ============================================================
   TEAM POPOVER "no standings yet" hint (v0.7.13)
   ============================================================ */
.tt-nostandings{
    margin-top:10px;
    padding:8px 4px;
    text-align:center;
    font-size:.85em;
    color:#9dc2f0;
    font-style:italic;
    border-top:1px solid #2a5a9a;
}

/* ============================================================
   FAVORITES: make them pop out more everywhere they appear
   (v0.7.13) - brighter tint, stronger left accent, subtle glow,
   and a distinct "Favorites" section header instead of the plain
   static-summary bar other sections use.
   ============================================================ */
.row-love{
    background:rgb(46 204 113 / 16%)!important;
    border-left:5px solid #2ecc71!important;
    box-shadow:inset 0 0 20px rgb(46 204 113 / 8%);
    position:relative;
}

.row-love::after{
    content:"\2605";
    position:absolute;
    right:6px;
    top:50%;
    transform:translateY(-50%);
    color:#2ecc71;
    font-size:.8em;
    opacity:.55;
    pointer-events:none;
}

#day-favorites-section > .static-summary{
    background:linear-gradient(90deg, rgb(46 204 113 / 25%) 0%, rgb(46 204 113 / 8%) 100%)!important;
    color:#2ecc71!important;
    font-weight:800!important;
    letter-spacing:.5px;
    border-left:5px solid #2ecc71;
}

/* ============================================================
   PHONE SUPPORT (v0.7.14)
   Targets real phone viewports (Pixel-class: ~412-430px CSS width
   portrait). Two things drive this file, and they share one fix:
   fluid, viewport-relative sizing instead of hardcoded px. That
   also happens to be the right fix for a 4K TV under aggressive
   Windows display scaling - the browser reports a small logical
   viewport there too, so the same fluid rules keep things sane in
   both directions without any separate "detect real resolution"
   logic (which would fight the browser rather than help it).
   ============================================================ */
@media (width <= 480px) {
    /* Scoreboard popover: scale every dimension down together via clamp() so
       it's readable but never overflows a phone screen. */
    .sb-tip{ padding: 12px 14px 10px; }

    .sb-league{
    font-size: 1em;
    margin-bottom: 8px;
}

    .sb-side{
    min-width: 0;
    gap: 4px;
}

    .sb-side .sb-logo-tip{
    width: clamp(32px, 9vw, 46px);
    height: clamp(32px, 9vw, 46px);
}
    .sb-abbr{ font-size: clamp(1.1em, 5vw, 1.6em); }
    .sb-score-num{ font-size: clamp(1.6em, 8vw, 2.4em); }

    .sb-center{
    min-width: clamp(72px, 22vw, 92px);
    padding: 6px 8px;
}
    .sb-center-top{ font-size: clamp(1.1em, 5.5vw, 1.6em); }
    .sb-center-bot{ font-size: clamp(.7em, 3vw, .9em); }
    .sb-record,.sb-standing{ font-size: clamp(.7em, 3vw, .9em); }
    .sb-matchup{ font-size: clamp(.9em, 4vw, 1.1em); }
    .sb-nets,.sb-imp{ font-size: clamp(.8em, 3.5vw, .95em); }

    /* Team popover: same fluid approach. */
    .tt-tip{ padding: 10px 12px; }

    .tt-logo{
    width: clamp(40px, 12vw, 58px);
    height: clamp(40px, 12vw, 58px);
}
    .tt-fullname{ font-size: clamp(1em, 5vw, 1.3em); }
    .tt-record{ font-size: clamp(1em, 4.5vw, 1.2em); }

    .tt-row{
    font-size: clamp(.85em, 4vw, 1em);
    padding: 3px 5px;
}

    /* Settings tabs: 6 tabs no longer squish to unreadable widths - they
       scroll horizontally instead, like a native app's segmented control. */
    .tab-controls{
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
    .tab-controls::-webkit-scrollbar{ display: none; }

    .tab-controls .tab-btn{
    flex: 0 0 auto;
    white-space: nowrap;
    padding: 10px 14px;
    font-size: .9em;
}

    /* Day-modal view tabs (Time/League/Live): shrink text/padding to fit three
       tabs across a phone width without wrapping or scrolling. */
    .view-tab-btn{
    padding: 8px 4px;
    font-size: .82em;
}

    /* Day modal title needs to actually shrink instead of holding a fixed
       320px, or it pushes the nav arrows off a narrow header. */

    /* Bigger, easier-to-tap touch targets for the small icon buttons. */
    .nav-btn,.icon-btn{
    width: 40px;
    height: 40px;
}

    .fav-heart svg{
    width: 24px;
    height: 24px;
}
    .fav-heart{ padding: 6px; }

    /* Modals: use the full screen rather than floating with margins. Use
       100dvh (dynamic viewport height) so the phone's address bar collapsing
       doesn't push content off-screen the way 100vh can. Reserve the ticker's
       height (--tk-h) so the modal - and its scroll-bottom / footer - sits ABOVE
       the bottom-line ticker instead of hiding behind it. */
    .modal-overlay{
    align-items: flex-start;
    height: 100dvh;
}

    .modal-content,.day-modal-content,.settings-content{
    width: 100vw;
    max-width: 100vw;
    height: calc(100dvh - var(--tk-h, 0px));
    max-height: calc(100dvh - var(--tk-h, 0px));
    margin: 0;
    border-radius: 0;
}

    /* Settings modal: header + tab bar + footer stay put; only the active tab
       scrolls. Without this the whole panel scrolls and the tab bar disappears
       behind the sticky header, so the other tabs become unreachable. */
    .settings-content{
    display: flex;
    flex-direction: column;
}
    .settings-content .modal-header{ flex: 0 0 auto; }

    .settings-tabs-row{
    flex: 0 0 auto;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    min-height: 44px;
}
    .settings-content .modal-footer-controls{ flex: 0 0 auto; }

    /* Keep the modal header (date title, nav arrows, and the X close button)
       PINNED to the top of the screen so it's always reachable. Previously the
       header scrolled away with the body and you couldn't see or tap the X. */
    .day-modal-content .modal-header,
.modal-content .modal-header,
#favorites-modal .modal-header{
    position: sticky;
    top: 0;
    z-index: 20;
    background: #1f232b;
    flex-shrink: 0;
}

    html.light .day-modal-content .modal-header,
html.light .modal-content .modal-header{ background: #fff; }

    /* --- The close button reachability fix ---
       The header packs up to 8 controls (prev-week, prev-day, title, today,
       next-day, next-week, print, close) into one flex row. On a ~380px phone
       that overflows no matter how the header is positioned vertically, and
       the close button - being last - was the one shoved off-screen. Fix: pull
       it OUT of the flex flow entirely and pin it to the header's top-right
       corner with position:absolute, so it can never be pushed off no matter
       how many nav buttons are present. Let everything else wrap underneath. */
    .modal-header{
    position: relative;
    flex-wrap: wrap;
    padding-right: 52px;
    row-gap: 8px;
}

    .modal-header .close-btn{
    position: absolute;
    top: 6px;
    right: 8px;
    z-index: 21;
    background: rgb(255 255 255 / 8%);
    border-radius: 50%;
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
}

    /* Title takes its own full-width row so it's never squeezed by the arrows. */
    #day-modal-title{
    font-size: .95em;
    order: -1;
    width: 100%;
    max-width: 100%;
    margin-bottom: 4px;
}

    .modal-nav-left,.modal-nav-right{
    flex-wrap: wrap;
    gap: 6px;
}
    .modal-nav-right #day-print-btn{ display: none; }  /* printing isn't a phone workflow */
    .modal-nav-right .btn-secondary{
    font-size: .8em;
    padding: 4px 8px;
}

    /* Make the close button a bigger, unmissable tap target on mobile. */
    .close-btn{
    font-size: 2em;
    padding: 4px 12px;
    line-height: 1;
}

    /* Ensure the scrollable region is the body, not the whole modal, so the
       sticky header has something to stick relative to. */
    #day-modal-body,#favorites-modal-body{
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    min-height: 0;
}

    .settings-content .tab-content.active{
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto; -webkit-overflow-scrolling: touch; }

    /* Grid row text sizes down slightly so team names don't truncate as hard. */
    .t-nick{ font-size: .85em; }
    .t-loc{ font-size: .78em; }

    /* --- Team row layout on narrow phones ---
       The desktop team grid is "1fr 260px 1fr" (away | score | home) which is
       far too wide for a ~320px usable column, so names clipped from the edges
       ("roit / ers" instead of "Detroit / Tigers"). Here we shrink the center
       column, drop the fixed team-width cap, and shrink the logos so the full
       team name has room. Names may wrap to a second line rather than clip. */
    .teamsgrid,.scoreboard{
    grid-template-columns: 1fr auto 1fr;
    gap: 6px;
}
    .status-col,.sb-center{ min-width: 0; }
    .team-stacked{ max-width: none; }
    .t-nick,.t-loc{ white-space: normal; }   /* allow wrap instead of clip */
    .side-away,.side-home{ gap: 6px; }

    /* On desktop the away side is right-aligned (mirror layout). On a phone that
       means a long name clips from the LEFT ("roit" instead of "Detroit"), which
       reads terribly. Left-align both sides on phones so any wrap/clip happens on
       the right where it's far less confusing. */
    .side-away{
    flex-direction: row-reverse;
    justify-content: flex-end;
    text-align: left;
}

    .side-away .team-stacked{
    align-items: flex-start;
    text-align: left;
}

    .col-teams .logo,.col-teams .team-logo{
    width: 28px;
    height: 28px;
}
    .status-text{ font-size: .8em; }
    }

/* Slightly larger phones / small tablets in portrait: less aggressive than
   the 480px tier above, but still fluid rather than fixed. */
@media (width >= 481px) and (width <= 768px) {
    .sb-tip{ width: min(480px, 90vw); }

    .tab-controls{
    overflow-x: auto;
    scrollbar-width: none;
}

    .tab-controls .tab-btn{
    flex: 0 0 auto;
    white-space: nowrap;
}
}

/* ============================================================
   ADMIN PROGRESS BAR + LOCK (v0.8.2)
   Driven by /admin-status.progress; shown only while a fetch job
   (guide/structure/standings) is running.
   ============================================================ */
.admin-progress{margin:14px 0 4px;}

/* The batch bar (ENH00022) sits above the per-job one and reads as the
   quieter of the two: it is context for the bar below, not a second thing
   competing for attention. Slimmer track, dimmer fill, same geometry. */
.admin-batch{margin-bottom:8px}

.admin-batch-track{
    height:8px;
    border-radius:4px
}

.admin-batch .admin-progress-fill{
    background:linear-gradient(90deg,#3a4a63,#5b7699)
}

.admin-batch .admin-progress-label{
    color:#7f93b3;
    margin-bottom:4px
}

.admin-progress-label{
    font-size:.85em;
    color:#9db4d6;
    margin-bottom:6px;
    font-family:monospace;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}

.admin-progress-track{
    width:100%;
    height:14px;
    background:#11151c;
    border:1px solid #333;
    border-radius:7px;
    overflow:hidden;
}

html.light .admin-progress-track{
    background:#e6e9ee;
    border-color:#ccc;
}

.admin-progress-fill{
    height:100%;
    width:0;
    background:linear-gradient(90deg,var(--primary-dark),var(--primary));
    border-radius:7px;
    transition:width .4s ease;
}

.admin-lock-row{
    margin-top:18px;
    padding-top:12px;
    border-top:1px solid #333;
    display:flex;
    justify-content:flex-end;
}
html.light .admin-lock-row{border-top:1px solid #ddd}

#btn-admin-lock{
    background:rgb(231 76 60 / 12%);
    color:#e74c3c;
    border:1px solid #e74c3c;
}
#btn-admin-lock:hover{background:rgb(231 76 60 / 22%)}

.admin-ghost-input{
    -webkit-text-security:disc;
    text-security:disc;
    margin-left:5px;
    background:#111;
    border:1px solid #444;
    color:#fff;
    padding:4px 8px;
    border-radius:4px;
    width:110px;
    font-size:.85em;
}

html.light .admin-ghost-input{
    background:#fff;
    border:1px solid #ccc;
    color:#222;
}

/* ============================================================
   LEAGUE LOGOS (v0.8.2)
   League label in each game row + calendar day cells. Logos come
   from images/_leagues/<ABBR>.png; if a logo is missing the inline
   onerror swaps in the .league-text / .cal-league-abbr fallback.
   ============================================================ */
.league-label{
    display:inline-flex;
    align-items:center;
    justify-content:center;
    cursor:pointer;
}

.league-logo-img{
    height:36px;
    width:36px;
    object-fit:contain;
    vertical-align:middle;
}
html.light .league-logo-img{filter:none}

/* Calendar day-cell chips: one consistent logo size everywhere (a mild viewport
   clamp, not per-day scaling). Chips wrap to new lines when needed. When a day
   has 5+ leagues we render a compact text list instead (one league per line) so
   they stay differentiable. */
.cal-content{
    color:#ccc;
    flex:1;
    font-size:.9em;
    line-height:1.3;
    display:flex;
    flex-wrap:wrap;
    gap:6px 10px;
    align-items:flex-start;
    align-content:flex-start;
    overflow:hidden;
}

/* min-width:0 + overflow:hidden is what stops the caption escaping the chip.
   The label used to be the raw league key, which for a discovered competition
   is an ESPN slug - "uefa.europa_conf_qual" inside a 66px chip simply drew over
   its neighbours, because nothing clipped it. The short label makes that
   unlikely; these rules make it impossible, whatever the text turns out to be. */
.cal-league-chip{
    display:flex;
    flex-direction:column;
    align-items:center;
    gap:2px;
    cursor:pointer;
    flex:0 0 auto;
    max-width:calc(var(--cal-icon,36px) + 30px);
    min-width:0;
    overflow:hidden;
}

.cal-league-logo{
    height:var(--cal-icon,36px);
    width:var(--cal-icon,36px);
    object-fit:contain;
}

.cal-league-caption{
    display:flex;
    align-items:baseline;
    gap:3px;
    line-height:1;
    max-width:100%;
    min-width:0;
}

/* The abbreviation is the only part that may shrink - the game count must stay
   readable, since it is the number the cell exists to convey. */
.cal-league-abbr{
    color:#cdd9ec;
    font-size:.78em;
    font-weight:700;
    letter-spacing:.2px;
    min-width:0;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}
html.light .cal-league-abbr{color:#333}

.cal-league-count{flex:0 0 auto;
    font-size:.82em;
    font-weight:800;
    color:var(--primary);
}

/* Gold secondary count: how many of that league's games involve a favorite team.
   Only rendered when non-zero, so a day with no favorites looks unchanged. */
.cal-fav-count{
    font-size:.82em;
    font-weight:800;
    color:#ffd24a;
    margin-left:4px;
}

.cal-fav-count::before{
    content:"\2605";
    font-size:.85em;
    margin-right:1px;
}
html.light .cal-fav-count{color:#b8860b}

/* crowded-day text fallback: small pills that flow left-to-right and wrap to
   the next line when the row fills, like text justifying in a book, rather
   than one league per line stacked vertically (which was the same list at 10x
   the height for no benefit - nothing about a vertical stack made the entries
   any more readable than a wrapped row does). */
.cal-content:has(.cal-text-row){
    flex-flow:row wrap;
    gap:3px 6px;
}

.cal-text-row{
    display:flex;
    align-items:baseline;
    gap:4px;
    cursor:pointer;
    font-size:.82em;
    line-height:1.3;
    white-space:nowrap;
    flex:0 0 auto;
    background:rgb(255 255 255 / 6%);
    border-radius:4px;
    padding:1px 6px;
}
html.light .cal-text-row{background:rgb(0 0 0 / 5%)}

.cal-text-abbr{
    font-weight:700;
    color:#cdd9ec;
}
html.light .cal-text-abbr{color:#333}

.cal-text-count{
    font-weight:800;
    color:var(--primary);
}

/* Day-modal filter pills as league icons (title/alt carries the name) */

/* Bigger, and labelled. A logo alone was ambiguous once dozens of soccer
   competitions started sharing the same generic fallback icon - the row read as
   identical grey circles. Short name disambiguates; the title carries the full
   one. */
.filter-pill{
    background:#252b36;
    border-radius:12px;
    border:1px solid #444;
    color:#888;
    cursor:pointer;
    font-size:.85em;
    white-space:nowrap;
    display:inline-flex;
    align-items:center;
    gap:6px;
    padding:4px 10px 4px 7px;
}

.filter-pill-logo{
    height:30px;
    width:30px;
    object-fit:contain;
}

.filter-pill-name{
    font-size:.95em;
    font-weight:700;
    letter-spacing:.02em;
    max-width:96px;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

.filter-pill-count{
    font-size:.95em;
    font-weight:800;
}

/* League standings hover popover: sized to content, groups laid out in a
   responsive grid so 2 divisions sit 2-wide, 6 divisions ~3-wide x 2-tall,
   etc. Scrolls only when it would exceed the viewport. */
.lst-wrap{
    max-width:min(1180px,94vw);
    font-family:'Segoe UI',Tahoma,sans-serif;
}

.lst-title{
    font-size:1.2em;
    font-weight:800;
    letter-spacing:.5px;
    text-transform:uppercase;
    color:#e7eefc;
    padding:2px 2px 9px;
    border-bottom:1px solid #3a4a5a;
    text-align:center;
}

/* The MODAL supplies its own <h2> header (openLeagueModal in js/main.js), and it
   renders the very same builder into its body - so the panel carried two titles,
   stacked. Suppressed here rather than parameterising the builder: the builder
   stays single-purpose, and the two views cannot drift apart, which is the whole
   reason the modal reuses it. */
#league-modal-body .lst-title{display:none}

/* THE MODAL SIZES ITSELF. leagueStandingsTip computes a pixel width because a
   hover popover has to shrink to fit its content - but the same inline width
   followed it into the full-screen modal, which pinned a 2-group league to
   600px inside a panel nearly a thousand wide: standings crammed into the left
   half, clipped, with empty space beside them. The modal overrides it and hands
   its columns the room it actually has. !important because it is beating an
   inline style, which is the one thing a stylesheet cannot outrank. */
#league-modal-body .lst-wrap{
    width:auto!important;
    max-width:100%;
}

/* overflow-x:auto, NOT hidden. `hidden` silently threw away whatever did not fit
   the per-column budget: the standings modal showed records and points cut off
   mid-cell with no scrollbar to indicate there was more. A budget that is
   occasionally wrong is survivable; one that is wrong AND invisible is not.
   Content the reader cannot reach is worse than a scrollbar. */
.lst-scroll{
    display:grid;
    gap:6px 22px;
    max-height:78vh;
    overflow:auto;
    margin-top:9px;
}

.lst-col{
    min-width:0;
    break-inside:avoid;
}

.lst-group{
    font-size:.9em;
    font-weight:800;
    text-transform:uppercase;
    letter-spacing:.4px;
    color:var(--primary);
    margin:6px 0 3px;
}

/* table-layout:auto (was `fixed`) so the TEAM column sizes to its CONTENT rather
   than getting only the leftovers after the fixed-width stat columns. With
   `fixed` + the nowrap below + ellipsis on .lst-team, long names such as
   "Washington Commanders" were truncated even when the popover had width to
   spare. Every team's full name must now be readable, on one line. */
.lst-table{
    width:100%;
    border-collapse:collapse;
    font-size:1em;
    table-layout:auto;
}

.lst-table td{
    padding:2px 6px;
    border-bottom:1px solid rgb(255 255 255 / 6%);
    white-space:nowrap;
}

.lst-pos{
    color:#8590a4;
    text-align:right;
    width:1.6em;
}

/* Badge + abbreviation, not the full name - see leagueStandingsTip for why. The
   badge is what makes the abbreviation readable at a glance; without it "TB"
   beside "TEX" beside "TOR" is three pieces of punctuation. */
.lst-team{
    color:#e7eefc;
    display:flex;
    align-items:center;
    gap:6px;
}

.lst-logo{
    width:18px;
    height:18px;
    object-fit:contain;
    flex:0 0 18px;
}

.lst-abbr{
    font-weight:600;
    letter-spacing:.02em;
}

.lst-rec{
    color:#9db4d6;
    text-align:right;
    font-variant-numeric:tabular-nums;
    width:3.6em;
}

.lst-gb{
    color:#8590a4;
    text-align:right;
    font-variant-numeric:tabular-nums;
    width:2.6em;
}

.lst-empty{
    color:#8590a4;
    padding:10px 4px;
    font-style:italic;
    text-align:center;
}

/* Upstream failure banner in the admin panel. Red because it is the one thing
   on that panel that means "nothing you are looking at is current". */
.adm-upstream{
    background:rgb(231 76 60 / 14%);
    border:1px solid #e74c3c;
    border-radius:8px;
    padding:9px 12px;
    margin:0 0 12px;
    color:#ffd7d2;
    font-size:.94em;
    line-height:1.45;
}

html.light .adm-upstream{
    background:rgb(231 76 60 / 9%);
    color:#7a1c12;
}

.adm-upstream-hint{
    display:block;
    margin-top:3px;
    opacity:.85;
    font-size:.92em;
}

/* ===========================================================================
   LEAGUE HOME (#league-modal-body) - see leagueHomeHtml in js/builders.js.

   STANDINGS LEAD, THEN TIME RUNS LEFT TO RIGHT. The three schedule lists share
   ONE band so their unequal lengths meet at a single ragged edge instead of
   leaving a hole in three different rows, and the two reliably tall blocks -
   standings and news - are paired with each other.
   =========================================================================== */

/* THE PANEL SIZES TO ITS CONTENT. .day-modal-content sets a FIXED
   height:calc(94vh - ticker), which is right for the day view (a long list that
   always fills it) and wrong here: a league whose sections end two-thirds down
   left the last third as empty box. max-height still caps it, so a 31-conference
   standings table behaves exactly as before. */

/* Wider than the other modals. A bracket is four or five rungs across before
   the ties even have names in them, and the league home puts a news column
   beside it - 1250px was making both cramped for no reason, since the panel now
   sizes to content vertically anyway. */
#league-modal .day-modal-content{
    height:auto;
    min-height:0;
    width:1460px;
}

/* THE RAIL BESIDE THE PANEL (ENH00043).

   Drew: "a second narrow modal, to the left (kind of like how games are done
   with away and home teams)". So the league home is two things side by side:
   a narrow column of games, and the panel it belongs to.

   320px, which is the scoreboard's centre column plus the rail's own padding -
   a game row is date, two abbreviations, a score and two logos, and that is
   what it takes to hold them without wrapping.

   DOM ORDER IS THE NARROW ORDER (standings, news, games) and the areas below
   lift the rail to the left on a wide screen. Every breakpoint names its areas
   explicitly, so the placement never falls back to source order. */
.lh-wrap{
    font-family:'Segoe UI',Tahoma,sans-serif;
    display:grid;
    grid-template-columns:var(--lh-rail-w,320px) minmax(0,1fr);
    grid-template-areas:"rail main";
    gap:10px;
    align-items:start;
}

/* STICKY, and that is the point of the exercise. NCAA Football's standings
   panel is sixteen conferences tall; without this the games scroll away on the
   one view whose job is to say what is on. align-self:start keeps it its own
   height rather than the panel's. */
.lh-rail{
    grid-area:rail;
    align-self:start;
    position:sticky;
    top:0;
    display:flex;
    flex-direction:column;
    gap:10px;
    min-width:0;
}

/* Each list gets its own cap in the rail rather than sharing the band's, which
   was sized for a third of a modal rather than a column of one. */
.lh-rail .lh-list{max-height:min(32vh,320px)}

.lh-wrap.lh-field{
    grid-template-columns:minmax(0,1fr);
    grid-template-areas:"main";
}


/* align-items:start, NOT the default stretch. Stretching made every card in a
   row as tall as the tallest, which put the empty space INSIDE the short card -
   exactly the "swathe of whitespace" under a 9-game Today next to 15 results.
   At natural height the space moves outside the cards, to the bottom edge of
   the band, where it reads as the end of the content rather than a hole in it. */
.lh-grid{
    grid-area:main;
    display:grid;
    grid-template-columns:2fr minmax(0,1fr);
    gap:10px;
    align-items:start;
    grid-template-areas:"standings news";
}
.lh-standings{grid-area:standings}
.lh-news{grid-area:news}

/* Under 1100px the rail stops being a column beside the panel and becomes a
   band under it - 320px off the width is most of a standings table at that
   size, and the games are no use if the table they sit beside is unreadable. */
@media (width <=1100px){
    .lh-wrap{
    grid-template-columns:minmax(0,1fr);
    grid-template-areas:"main" "rail";
}

    .lh-rail{
    position:static;
    flex-flow:row wrap;
}

    .lh-rail>.lh-sec{flex:1 1 280px}
}

/* One column under 760px, for the panel as well as the rail. DOM order IS this
   order, so nothing is reordered: standings, news, then the games. */
@media (width <=760px){
    .lh-grid{
    grid-template-columns:1fr;
    grid-template-areas:"standings" "news";
}

    .lh-rail{flex-direction:column}
}

/* Cards, quietly. A hairline and a barely-there fill are enough to say "this is
   one section" - five heavily-boxed panels on one screen would compete with the
   logos and scores, which are the things worth looking at. */
.lh-sec{
    background:rgb(255 255 255 / 3%);
    border:1px solid #333b47;
    border-radius:10px;
    padding:8px 10px 9px;
    min-width:0;
}

html.light .lh-sec{
    background:rgb(0 0 0 / 2%);
    border-color:#dde2ea;
}

.lh-sec-title{
    display:flex;
    align-items:baseline;
    gap:9px;
    margin:0 0 5px;
    font-size:.82em;
    font-weight:800;
    letter-spacing:.08em;
    text-transform:uppercase;
    color:var(--primary,#5e95ff);
}

/* The window the section is ACTUALLY showing ("Yesterday", "Jul 28 – Aug 2").
   The fill rule widens the range when a day is thin; saying so is the
   difference between a helpful section and a quietly misleading one. */
.lh-sec-when{
    font-size:.92em;
    font-weight:600;
    letter-spacing:.02em;
    text-transform:none;
    color:#8590a4;
}

.lh-empty{
    color:#8590a4;
    font-style:italic;
    padding:8px 2px;
    font-size:.92em;
}

/* A cap so one long list cannot set the height of the whole panel - a 20-game
   Saturday would otherwise push news and standings off the screen. Only the
   list scrolls; its heading stays put, which is why the rows have their own
   wrapper (see _lhSection). */
.lh-list{
    max-height:min(46vh,430px);
    overflow:hidden auto;
}

/* A game row: date | away (right-aligned, into the middle) | score/time | home
   (left-aligned, out of the middle) | live dot. The two 1fr team columns mirror
   each other about the score, so scores line up down the section however long
   the names are. */
.lh-row{
    display:grid;
    grid-template-columns:2.6em minmax(0,1fr) auto minmax(0,1fr) 1.1em;
    align-items:center;
    gap:8px;
    padding:2px 4px;
    border-radius:6px;
    border-bottom:1px solid rgb(255 255 255 / 5%);
    cursor:pointer;
}
html.light .lh-row{border-bottom-color:rgb(0 0 0 / 6%)}
.lh-row:last-child{border-bottom:none}
.lh-row:hover{background:rgb(255 255 255 / 6%)}
html.light .lh-row:hover{background:rgb(0 0 0 / 5%)}

.lh-row-day{
    color:#8590a4;
    font-size:.85em;
    font-variant-numeric:tabular-nums;
}

.lh-row-team{
    display:flex;
    align-items:center;
    gap:6px;
    min-width:0;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
    border-radius:4px;
    padding:1px 3px;
}

/* The team is a target of its own inside a row that is also a target - say so,
   or the two are indistinguishable until something unexpected opens. */
.lh-row-team[data-lst-team]:hover{
    background:rgb(94 149 255 / 18%);
    color:#fff;
}

html.light .lh-row-team[data-lst-team]:hover{
    background:rgb(0 123 255 / 14%);
    color:#000;
}

.lh-away{
    justify-content:flex-end;
    text-align:right;
}
.lh-home{justify-content:flex-start}
.lh-row-fav{font-weight:800}

.lh-row-logo{
    width:20px;
    height:20px;
    object-fit:contain;
    flex:0 0 20px;
}

.lh-row-score{
    font-weight:800;
    font-variant-numeric:tabular-nums;
    color:#e7eefc;
    padding:0 2px;
    white-space:nowrap;
}

.lh-row-score i{
    color:#8590a4;
    font-style:normal;
    padding:0 3px;
}
html.light .lh-row-score{color:#222}

.lh-row-time{
    color:#9db4d6;
    font-size:.9em;
    font-variant-numeric:tabular-nums;
    white-space:nowrap;
}

/* sb-live-pulse, the keyframe the scoreboard's own live badge uses - one live
   idiom across the app rather than a second one that drifts out of step. */
.lh-row-live{
    color:#e74c3c;
    font-size:.8em;
    animation:sb-live-pulse 2s ease-in-out infinite;
}
.lh-row-final .lh-row-day{opacity:.75}

/* ---- TOURNAMENT VIEW: bracket, groups, round list -------------------------
   The ladder is columns of ties, widest round on the left, reading toward the
   final - which is how a bracket is read on paper and on every scoreboard. It
   scrolls sideways rather than shrinking: a Round of 32 is five rungs wide and
   squeezing that into a panel would make every name unreadable. */
.tv-wrap{
    display:grid;
    gap:12px;
}

/* ZOOM, via the `zoom` property rather than transform: scale(). scale() paints
   smaller but keeps the original layout box, so the scrollable area stays the
   size it was and half the bracket is still unreachable - which is the opposite
   of the problem being solved. `zoom` reflows, so the ladder genuinely gets
   smaller and the scroll shrinks with it.
   Deliberately NOT an image render: at any zoom the boxes stay real elements,
   so the ties are still clickable and the text still selectable and printable. */
.tv-wrap[data-zoom="80"] .tv-ladder{zoom:.8}
.tv-wrap[data-zoom="65"] .tv-ladder{zoom:.65}
.tv-wrap[data-zoom="50"] .tv-ladder{zoom:.5}

.tv-zoom{
    display:flex;
    gap:2px;
    align-items:center;
    margin-left:auto;
}

.tv-zoom button{
    background:rgb(255 255 255 / 6%);
    border:1px solid #3a4553;
    color:#9db4d6;
    border-radius:5px;
    font:inherit;
    font-size:.8em;
    padding:1px 7px;
    cursor:pointer;
    line-height:1.6;
}

.tv-zoom button:hover{
    background:rgb(255 255 255 / 14%);
    color:#e7eefc;
}

.tv-zoom button.on{
    background:var(--primary,#5e95ff);
    border-color:var(--primary,#5e95ff);
    color:#fff;
}

html.light .tv-zoom button{
    background:rgb(0 0 0 / 4%);
    color:#556;
    border-color:#ccd;
}

/* EVERY RUNG IS THE SAME HEIGHT, and its boxes are distributed evenly inside
   it. That one rule produces the whole bracket geometry for free:
   `space-around` centres item i of n at (i + 0.5)/n of the column, so with 8
   ties in the first rung and 4 in the next, the quarter-final at 2/16 sits
   exactly between the two round-of-16 boxes at 1/16 and 3/16 - and the final,
   alone in its column, lands dead centre.

   No measuring, no JS, and it stays true when a rung is half ghosts. */

/* SCROLLS BOTH WAYS. A Round of 32 is sixteen boxes tall - roughly a thousand
   pixels - so a ladder that only scrolled sideways simply had its bottom half
   cut off by the panel. Capped at the viewport and scrollable in both axes;
   the rungs keep their natural height, so the geometry above still holds and it
   is the CONTAINER that moves, not the bracket that squashes. */
.tv-ladder{
    display:flex;
    gap:14px;
    align-items:stretch;
    overflow:auto;
    padding-bottom:4px;
    max-height:min(72vh,900px);
}

/* Wider than the first pass, deliberately. Each box now carries when, where and
   TV as well as the teams, and a bracket that has to be squinted at is not worth
   drawing. The ladder scrolls sideways rather than compressing. */
.tv-rung{
    display:flex;
    flex-direction:column;
    min-width:196px;
    flex:0 0 auto;
}

.tv-rung-body{
    flex:1;
    display:flex;
    flex-direction:column;
    justify-content:space-around;
    gap:6px;
    min-height:0;
}

.tv-rung-name{
    font-size:.78em;
    font-weight:800;
    letter-spacing:.06em;
    text-transform:uppercase;
    color:var(--primary,#5e95ff);
    display:flex;
    align-items:baseline;
    gap:6px;
}

.tv-count{
    color:#8590a4;
    font-weight:600;
    letter-spacing:0;
}

/* Teams joining a round part-way through - UEFA qualifying seeds them in, the
   NFL and the CFP call the same thing a bye. Derived by subtraction, so it
   keeps working when a format changes size. */
.tv-entrants{
    color:#9db4d6;
    font-weight:600;
    letter-spacing:0;
    text-transform:none;
    font-size:.92em;
    opacity:.8;
}

/* A ladder that stops without saying why reads as missing data. This says the
   count does not halve cleanly, so the rest depends on a draw we have not seen. */
.tv-rung-note{max-width:210px}

.tv-unknown-note{
    color:#8590a4;
    font-size:.82em;
    line-height:1.45;
    font-style:italic;
    border:1px dashed #3a4553;
    border-radius:7px;
    padding:7px 9px;
}

.tv-tie{
    background:rgb(255 255 255 / 4%);
    border:1px solid #333b47;
    border-radius:7px;
    padding:3px 5px;
    display:grid;
    gap:1px;
    cursor:pointer;
    position:relative;
}

html.light .tv-tie{
    background:rgb(0 0 0 / 2%);
    border-color:#dde2ea;
}
.tv-tie:hover{background:rgb(255 255 255 / 9%)}
html.light .tv-tie:hover{background:rgb(0 0 0 / 5%)}

.tv-side{
    display:grid;
    grid-template-columns:16px minmax(0,1fr) 1.6em;
    align-items:center;
    gap:5px;
    font-size:.9em;
    color:#c8d3e6;
}
html.light .tv-side{color:#333}

.tv-logo{
    width:16px;
    height:16px;
    object-fit:contain;
}

.tv-name{
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}

.tv-score{
    text-align:right;
    font-variant-numeric:tabular-nums;
    color:#9db4d6;
}

/* The team that went through, in a tie that is actually decided. Never shown
   for a tie still being played - a leader is not a winner. */
.tv-won .tv-name{
    font-weight:800;
    color:#e7eefc;
}

.tv-won .tv-score{
    color:#2ecc71;
    font-weight:800;
}
html.light .tv-won .tv-name{color:#000}

/* A slot we know the SIZE of but not the occupants. SAME BOX, dashed border and
   dimmed - it is the same component with nothing in it, not a different thing,
   so the ladder reads as one object with parts still to be filled. */
.tv-ghost{
    border-style:dashed;
    opacity:.45;
    cursor:default;
    background:none;
}
.tv-ghost:hover{background:none}

.tv-unknown .tv-name{
    color:#7d879b;
    font-style:normal;
}

/* When / where / TV. The line is always present so every box in a rung is the
   same height and the rungs line up across the ladder. */
.tv-meta{
    display:flex;
    flex-wrap:wrap;
    gap:4px 8px;
    align-items:baseline;
    margin-top:3px;
    padding-top:3px;
    border-top:1px solid rgb(255 255 255 / 7%);
    font-size:.74em;
    color:#8590a4;
    min-height:1.25em;
}
html.light .tv-meta{border-top-color:rgb(0 0 0 / 8%)}

.tv-when{
    font-variant-numeric:tabular-nums;
    white-space:nowrap;
}

.tv-where{
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
    max-width:11em;
    opacity:.85;
}

.tv-tv{
    color:var(--primary,#5e95ff);
    font-weight:700;
    white-space:nowrap;
}

.tv-tbd{
    opacity:.5;
    font-style:italic;
}

/* In the meta line, not floated over the box - absolutely positioned it sat on
   top of the score column and read as "AG0". */
.tv-agg{
    text-transform:uppercase;
    letter-spacing:.05em;
    font-weight:700;
    opacity:.75;
}

.tv-groups{
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
    gap:10px;
}
.tv-group{min-width:0}

.tv-gtable{
    width:100%;
    border-collapse:collapse;
    font-size:.9em;
}

.tv-gtable td{
    padding:2px 5px;
    border-bottom:1px solid rgb(255 255 255 / 6%);
    white-space:nowrap;
}
html.light .tv-gtable td{border-bottom-color:rgb(0 0 0 / 7%)}

.tv-gpos{
    color:#8590a4;
    text-align:right;
    width:1.4em;
}
.tv-gteam{color:#e7eefc}
html.light .tv-gteam{color:#222}

.tv-grec{
    color:#9db4d6;
    text-align:right;
    font-variant-numeric:tabular-nums;
}
.tv-rounds{gap:10px}
.tv-round-block{min-width:0}

/* FIELD LEAGUES (golf, racing). The leaderboard is the headline - it is what
   you look at when you are watching - so it leads and spans the full width,
   with the season summary beside the two event lists underneath. */
.lh-grid-field{grid-template-areas:"today today today" "standings results next" "news news news"}

@media (width <=1100px){
    .lh-grid-field{grid-template-areas:"today today" "standings news" "results next"}
}

@media (width <=760px){
    .lh-grid-field{grid-template-areas:"today" "standings" "results" "next" "news"}
}

.lh-sec-board{
    min-width:0;
    overflow-x:auto;
}

/* buildLeaderboardTip is a POPOVER body by origin - it sizes itself for a
   floating card. Inside a panel it should fill the width it is given. */
.lh-board .lb-tip{
    max-width:100%;
    padding:0;
}
.lh-board .tip-close{display:none}

/* An event row: date span, name, and who won or is leading. No score column -
   a tournament does not have one. */
.lh-ev{grid-template-columns:6.5em minmax(0,1fr) minmax(0,12em) 1.1em}

.lh-ev-when{
    color:#8590a4;
    font-size:.85em;
    white-space:nowrap;
}

.lh-ev-name{
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
    font-weight:600;
}

.lh-ev-who{
    color:#9db4d6;
    font-size:.9em;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
    text-align:right;
}

.lh-ev-who i{
    color:#8590a4;
    font-style:normal;
    font-size:.9em;
    margin-right:4px;
}

.lh-ev-none{
    opacity:.6;
    font-style:italic;
}

/* The standings section holds the shared builder, which brings its own wrap. */
.lh-standings .lst-wrap{margin:0}

/* The ESPN button is furniture, not content - it was taking 12px above and a
   full button's height below in a section that already ends with a table. */
.lh-standings .lst-link{
    margin:8px auto 0;
    padding:6px 12px;
    font-size:.9em;
}

.lh-standings .lst-scroll{
    margin-top:4px;
    gap:4px 18px;
}

/* News: image, headline, date. Fixed row height so the skeleton and the real
   thing occupy identical space (same reasoning as .tt-news-list). */
.lh-news-list{
    display:grid;
    gap:2px;
}

.lh-news-item{
    display:flex;
    align-items:center;
    gap:9px;
    padding:3px 4px;
    min-height:40px;
    border-bottom:1px solid rgb(255 255 255 / 5%);
    text-decoration:none;
    color:inherit;
    border-radius:6px;
}
html.light .lh-news-item{border-bottom-color:rgb(0 0 0 / 6%)}
.lh-news-item:last-child{border-bottom:none}
.lh-news-item:hover{background:rgb(255 255 255 / 6%)}
html.light .lh-news-item:hover{background:rgb(0 0 0 / 5%)}

.lh-news-img{
    width:52px;
    height:34px;
    object-fit:cover;
    border-radius:4px;
    flex:0 0 52px;
}
.lh-news-body{min-width:0}

.lh-news-head{
    font-size:.92em;
    line-height:1.3;
    color:#e7eefc;
    display:-webkit-box;
    -webkit-line-clamp:2;
    -webkit-box-orient:vertical;
    overflow:hidden;
}
html.light .lh-news-head{color:#222}

.lh-news-date{
    font-size:.8em;
    color:#8590a4;
    margin-top:2px;
}

/* Logo beside the league name in the modal's own header. */
#league-modal-title{
    display:flex;
    align-items:center;
    gap:10px;
}

.lh-head-logo{
    width:28px;
    height:28px;
    object-fit:contain;
    flex:0 0 28px;
}

/* Managed favorites (settings): responsive grid of stacked cards
   (logo + abbr + full name + league), styled like a scoreboard side. */
#favorites-container{
    display:grid;
    grid-template-columns:repeat(auto-fill,minmax(118px,1fr));
    gap:10px;
    align-content:start;
}

.fav-card{
    position:relative;
    display:flex;
    flex-direction:column;
    align-items:center;
    text-align:center;
    gap:3px;
    background:#252b36;
    border:1px solid #3a3f49;
    border-top:4px solid #5a6472;
    border-radius:8px;
    padding:12px 8px 10px;
    user-select:none;
    min-width:0;
}

html.light .fav-card{
    background:#f5f7fa;
    border-color:#ddd;
    border-top-color:#bbb;
}
.fav-card.love{border-top-color:#2ecc71}
.fav-card.loathe{border-top-color:#e74c3c}

.fav-card-logo{
    width:46px;
    height:46px;
    object-fit:contain;
    margin-bottom:2px;
}

/* Player (golf/racing) favorite card: heart badge instead of a team logo. */
.fav-card-heart{
    display:flex;
    align-items:center;
    justify-content:center;
    font-size:2em;
    color:#ffc400;
    line-height:1;
}
.fav-card-player{border-top-color:#ffc400}

.fav-card-abbr{
    font-weight:800;
    font-size:1.05em;
    letter-spacing:.5px;
}

.fav-card-name{
    font-size:.78em;
    color:#9db4d6;
    line-height:1.15;
    width:100%;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}
html.light .fav-card-name{color:#556}

.fav-card-league{
    font-size:.66em;
    font-weight:800;
    color:#8aa0c0;
    background:rgb(255 255 255 / 7%);
    border:1px solid #3a3f49;
    border-radius:8px;
    padding:1px 8px;
    text-transform:uppercase;
    letter-spacing:.4px;
    margin-top:2px;
}

html.light .fav-card-league{
    color:#556;
    background:rgb(0 0 0 / 5%);
    border-color:#ccc;
}

.fav-card .fav-delete{
    position:absolute;
    top:3px;
    right:6px;
    font-weight:bold;
    opacity:0;
    transition:opacity .2s;
}

.deletion-active .fav-card{
    cursor:pointer;
    border-color:#e74c3c;
}

.deletion-active .fav-card .fav-delete{
    opacity:1;
    color:#e74c3c;
}

.deletion-active .fav-card:hover{
    background:rgb(231 76 60 / 12%);
    transform:translateY(-1px);
}

/* Telecast links in the network column */
.net-link{
    color:#7fb2ff;
    text-decoration:none;
    border-bottom:1px dotted rgb(127 178 255 / 50%);
}

.net-link:hover{
    color:#9dc4ff;
    border-bottom-style:solid;
}
html.light .net-link{color:#0069d9}

/* --- Graphical favorites picker --- */
.fav-graphic-picker{margin:0 0 18px}

.fp-modebar{
    display:flex;
    gap:8px;
    margin-bottom:12px;
}

.fp-mode{
    background:#252b36;
    border:1px solid #3a3f49;
    color:#9db4d6;
    border-radius:6px;
    padding:7px 16px;
    cursor:pointer;
    font-weight:700;
    font-size:.95em;
}

.fp-mode.active.love{
    background:rgb(46 204 113 / 18%);
    border-color:#2ecc71;
    color:#2ecc71;
}

.fp-mode.active.loathe{
    background:rgb(231 76 60 / 18%);
    border-color:#e74c3c;
    color:#e74c3c;
}

.fp-hint{
    color:#9db4d6;
    font-size:.92em;
    margin-bottom:12px;
    display:flex;
    align-items:center;
    flex-wrap:wrap;
    gap:4px;
}

.fp-back{
    background:#252b36;
    border:1px solid #3a3f49;
    color:#cdd9ec;
    border-radius:5px;
    padding:3px 10px;
    cursor:pointer;
}

.fp-back:hover{
    border-color:var(--primary);
    color:#fff;
}

.fp-scroll{
    max-height:52vh;
    overflow:hidden auto;
    padding:2px 6px 2px 2px;
}

.fp-group{
    font-size:.82em;
    font-weight:800;
    text-transform:uppercase;
    letter-spacing:.4px;
    color:var(--primary);
    margin:12px 0 6px;
    position:sticky;
    top:0;
    background:#1f232b;
    padding:3px 0;
    z-index:1;
}
html.light .fp-group{background:#fff}
.fp-scroll .fp-group:first-child{margin-top:0}

.fp-grid{
    display:grid;
    grid-template-columns:repeat(auto-fill,minmax(86px,1fr));
    gap:9px;
}

.fp-cell{
    position:relative;
    display:flex;
    flex-direction:column;
    align-items:center;
    gap:6px;
    background:#252b36;
    border:1px solid #3a3f49;
    border-radius:9px;
    padding:11px 6px;
    cursor:pointer;
    color:#cdd9ec;
    transition:transform .1s,border-color .1s,background .1s;
}

.fp-cell:hover{
    transform:translateY(-2px);
    border-color:var(--primary);
}

.fp-cell img{
    width:42px;
    height:42px;
    object-fit:contain;
}

.fp-cell span{
    font-size:.82em;
    font-weight:700;
    text-align:center;
    line-height:1;
}

.fp-team.faved.love{
    border-color:#2ecc71;
    background:rgb(46 204 113 / 14%);
}

.fp-team.faved.loathe{
    border-color:#e74c3c;
    background:rgb(231 76 60 / 14%);
}

.fp-badge{
    position:absolute;
    top:4px;
    right:5px;
    font-size:.9em;
    line-height:1;
}
.fp-badge.love{color:#2ecc71}
.fp-badge.loathe{color:#e74c3c}

html.light .fp-cell,html.light .fp-mode,html.light .fp-back{
    background:#f5f7fa;
    border-color:#ddd;
    color:#333;
}

/* Favorite markers inside standings */
.lst-fav{
    color:#ff5e7a;
    font-size:.92em;
}
.lst-fav.loathe{color:#e74c3c}

.lst-team-fav{
    font-weight:800;
    color:#fff;
}
html.light .lst-team-fav{color:#000}
.lst-row-fav .lst-pos{color:#ff9db0}

.tt-fav .tt-team{
    font-weight:800;
    color:#fff;
}

/* Enh 3: standings rows open that team's own popover - hint it's clickable. */
.lst-row-clickable{cursor:pointer}
.lst-row-clickable:hover{background:rgb(255 255 255 / 6%)}
html.light .lst-row-clickable:hover{background:rgb(0 0 0 / 5%)}

/* Status column is now a link to the game on ESPN */
a.status-col{color:inherit}
a.status-col:hover .status-text,a.status-col:hover .sched-time{filter:brightness(1.25)}

/* Favorites lock toggle (replaces the delete checkbox) + setup bar */
.fav-lock{
    display:inline-flex;
    align-items:center;
    gap:7px;
    margin-top:12px;
    background:#252b36;
    border:1px solid #3a3f49;
    color:#9db4d6;
    border-radius:7px;
    padding:7px 14px;
    cursor:pointer;
    font-weight:700;
    font-size:.9em;
}

.fav-lock:hover{
    border-color:var(--primary);
    color:#cdd9ec;
}

.fav-lock.unlocked{
    background:rgb(231 76 60 / 16%);
    border-color:#e74c3c;
    color:#e74c3c;
}

html.light .fav-lock{
    background:#f5f7fa;
    border-color:#ddd;
    color:#333;
}

.fav-setup-title{
    font-weight:800;
    color:var(--primary);
    font-size:1.05em;
}

/* Favorites: distinct panels for "Your Teams" (list/delete) vs "Add Teams" (picker). */
.fav-section{
    background:rgb(0 0 0 / 16%);
    border:1px solid #333;
    border-radius:8px;
    margin:0 12px 16px;
    overflow:hidden;
}

html.light .fav-section{
    background:#f7f8fa;
    border-color:#ddd;
}

.fav-section-head{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:12px;
    padding:11px 16px;
    background:rgb(255 255 255 / 3%);
    border-bottom:1px solid #333;
}

html.light .fav-section-head{
    background:#eef0f4;
    border-bottom:1px solid #ddd;
}
.fav-section .fav-list{padding:0}

.fav-section-add .fav-graphic-picker{
    margin:0;
    padding:12px 16px 8px;
}
.fav-section .fav-empty{padding:22px 16px}

/* Settings modal title (header now has a title; tabs moved to their own row). */
.settings-title{
    margin:0;
    font-size:1.4em;
    font-weight:700;
    white-space:nowrap;
}

.settings-tabs-row{
    display:flex;
    background:#181b21;
    border-bottom:1px solid #444;
    flex-shrink:0;
}

html.light .settings-tabs-row{
    background:#f0f0f0;
    border-bottom:1px solid #ccc;
}

/* Active settings tab is the scroll region so its header/tabs/footer stay put. */
.settings-content .tab-content.active{
    flex:1 1 auto;
    min-height:0;
    overflow-y:auto;
}

/* Admin unlock prompt (shown until the code is entered). */
.admin-unlock-row{
    display:flex;
    align-items:center;
    gap:10px;
    flex-wrap:wrap;
    background:rgb(231 76 60 / 8%);
    border:1px solid rgb(231 76 60 / 35%);
    border-radius:6px;
    padding:10px 14px;
    margin-bottom:14px;
}
.admin-lock-icon{font-size:1.1em}

.admin-lock-msg{
    color:#e7b3ad;
    font-size:.9em;
    flex:1;
    min-width:160px;
}
html.light .admin-lock-msg{color:#a3352c}
#fav-view-cards{padding:10px 16px 0}
#fav-view-picker{padding:12px 16px 16px}
.fav-lock svg{flex-shrink:0}

/* --- Bottom-line ticker --- */
#ticker{
    flex:0 0 auto;
    height:var(--tk-h,64px);
    background:#12161d;
    border-top:2px solid var(--primary,#5e95ff);
    overflow:hidden;
    position:relative;
    z-index:3000;
    white-space:nowrap;
    box-shadow:0 -4px 16px rgb(0 0 0 / 45%);
}
#ticker.empty{display:none}

html.light #ticker{
    background:#eef1f5;
    border-top:2px solid var(--primary,#007bff);
}

/* The marquee is driven by JS (requestAnimationFrame -> inline transform), NOT a
   CSS animation - see _tkStartMarquee in render.js. A CSS animation's progress is
   a fraction of its duration, so changing the duration mid-flight (which the
   hover crawl rate does) makes the track jump to a different offset; with a
   duplicated track that reads as two ticker copies flickering. Driving it
   ourselves keeps position as explicit state, so speed changes never jump. */
#ticker-track{
    display:inline-block;
    white-space:nowrap;
    height:var(--tk-h);
    will-change:transform;
}

.tk-item{
    display:inline-flex;
    align-items:center;
    gap:calc(var(--tk-h)*.16);
    height:var(--tk-h);
    padding:0 calc(var(--tk-h)*.34);
    color:#cdd9ec;
    text-decoration:none;
    font-size:calc(var(--tk-h)*.34);
    vertical-align:top;
}

.tk-item:hover{
    color:#fff;
    background:rgb(255 255 255 / 5%);
}
html.light .tk-item{color:#333}

/* Per-team logos in the ticker (league logo shows once on the group marker). */
.tk-tlg{
    height:calc(var(--tk-h)*.5);
    width:calc(var(--tk-h)*.5);
    object-fit:contain;
    flex-shrink:0;
}
.tk-abbrs{white-space:nowrap}

.tk-teams{
    font-variant-numeric:tabular-nums;
    font-weight:600;
    display:inline-flex;
    align-items:center;
    gap:calc(var(--tk-h)*.12);
}
.tk-teams b{color:#fff}
html.light .tk-teams b{color:#000}

/* Field events in the ticker: event name bold, leader/winner dimmer. */
.tk-ev-name{
    font-weight:800;
    color:#fff;
}
html.light .tk-ev-name{color:#111}
.tk-ev-lead{color:#9dc2f0}
html.light .tk-ev-lead{color:#33465e}
.tk-ev-lead b{color:#5eea9b}

.tk-status{
    color:#8590a4;
    font-size:.82em;
}

.tk-live .tk-status{
    color:#ff5252;
    font-weight:800;
}

.tk-fav .tk-teams{
    color:#2ecc71;
    font-weight:800;
}
.tk-fav .tk-teams b{color:#2ecc71}

.tk-src{
    color:#7fb2ff;
    font-size:.78em;
    border:1px solid rgb(127 178 255 / 35%);
    border-radius:4px;
    padding:1px 6px;
}

html.light .tk-src{
    color:#0069d9;
    border-color:rgb(0 105 217 / 35%);
}

/* The bullet between two games in the same league.

   IT TAKES UP NO WIDTH OF ITS OWN. A box of .20 with -.10 of margin each side
   nets to zero, so the two games it separates ABUT - their backgrounds meet -
   and the bullet is centred exactly on that seam, half of it over each. It
   used to be a real .04-wide gap in the run, which is why a favourite's green
   stopped short of the dot with a strip of bar showing between them.

   Positioned and raised so the game backgrounds, which now cover both halves
   of it, paint UNDER the glyph rather than over it. And transparent to the
   mouse: it sits on top of two hoverable games, and the preview card has no
   business closing because the cursor crossed a dot.

   The font-size is here because it was never anywhere - the glyph inherited
   the page's 16px and was the one thing in the bar that did not grow with the
   size slider. .16 is what 16px was at the default height, so the dot is the
   size it has always been and now scales with everything else. */
.tk-sep{
    display:inline-block;
    position:relative;
    z-index:1;
    width:calc(var(--tk-h)*.20);
    margin:0 calc(var(--tk-h)*-.10);
    padding:0;
    text-align:center;
    font-size:calc(var(--tk-h)*.16);
    color:#39414f;
    height:var(--tk-h);
    line-height:var(--tk-h);
    vertical-align:top;
    pointer-events:none;
}

/* THE PINNED LEAGUE (ENH00036). Held at the left edge while its games scroll
   past underneath, and swapped when the next league's marker slides under it.

   OPAQUE, AND OVER THE TRACK rather than beside it: a column of its own would
   narrow the scrolling area every time a league name changed width, and the
   bar would breathe. The games it covers on their way out have already crossed
   the whole bar, so nothing is lost by hiding the last inch of their exit.

   The fade off its right edge is what stops a GAME looking sliced by a hard
   line - it slides under rather than hitting a wall. A league MARKER does not
   slide under: it shoves the pin off to the left instead (BUG00037), and the
   geometry below is what makes that handoff invisible.

   SAME BOX AS .tk-group, TO THE PIXEL - same padding, and a 2px left border to
   stand in for the marker's divider. At the moment of the swap the pin and the
   marker it copies are both at x=0, so the copy lands exactly on top of the
   original and nothing moves. The border is transparent because a divider at
   the far left of the bar is a line to nowhere; it is here for its width. The
   background is painted under it (background-clip is border-box by default),
   so the real marker's blue divider underneath stays covered.

   #ticker already carries position:relative and overflow:hidden, so this needs
   nothing added to it. */
#ticker-pin{
    align-items:center;
    background:#12161d;
    border-left:2px solid transparent;
    bottom:0;
    display:none;

    /* .tk-group's gap, to the character. The pin's content is a marker's
       innerHTML verbatim, so any spacing it does NOT inherit is a way for the
       frozen label to drift from the identical one scrolling a foot to its
       right - which is exactly what shipped: no gap here at all, so the
       pinned logo sat hard against its text. */
    gap:calc(var(--tk-h)*.14);
    left:0;
    padding:0 calc(var(--tk-h)*.30);
    position:absolute;
    top:0;
    will-change:transform;
    z-index:3;
}

#ticker-pin.on{display:flex}

#ticker-pin::after{
    background:linear-gradient(to right,#12161d,rgb(18 22 29 / 0%));
    bottom:0;
    content:"";
    pointer-events:none;
    position:absolute;
    right:calc(var(--tk-h)*-.22);
    top:0;
    width:calc(var(--tk-h)*.22);
}

html.light #ticker-pin{background:#eef1f5}

html.light #ticker-pin::after{
    background:linear-gradient(to right,#eef1f5,rgb(238 241 245 / 0%));
}

/* THE PIN DELIBERATELY RESTYLES NOTHING INSIDE ITSELF. The marker's innards
   are reused verbatim, so .tk-group-lg and .tk-group-name below style both
   copies and the two cannot drift. ENH00036 shipped a 46% logo and a .26 font
   here against the marker's 50% and .3, which is small enough that neither
   looked wrong on its own and the pair looked wrong side by side.

   What the pin does drop is the divider: .tk-group's border-left separates
   segments in the run, and here it would be a line to nowhere. That comes free
   from reusing the innerHTML rather than the element. */

/* League segment marker: a divider + logo + league name that heads each
   per-league group in the ticker so groupings are visually distinct.

   THE DIVIDER IS THE BAR'S OWN BORDER, STOOD ON END. It was a hardcoded
   rgb(94 149 255 / 55%) - the only primary-coloured thing in the ticker that
   did not follow --primary - so on any theme but the default it was a blue
   line under a purple one. Same token as #ticker's border-top now, light
   fallback included, so the two cannot drift again.

   NO MARGIN. The .14 margin that used to sit here held the divider a gap away
   from the run it divides: the last game's background stopped short and the
   line floated in the space after it. The divider is the boundary, so it
   belongs ON the boundary - the padding to its right is what keeps the logo
   off it. */
.tk-group{
    display:inline-flex;
    align-items:center;
    gap:calc(var(--tk-h)*.14);
    height:var(--tk-h);
    padding:0 calc(var(--tk-h)*.30);
    vertical-align:top;
    border-left:2px solid var(--primary,#5e95ff);
}
html.light .tk-group{border-left-color:var(--primary,#007bff)}

.tk-group-lg{
    height:calc(var(--tk-h)*.5);
    width:calc(var(--tk-h)*.5);
    object-fit:contain;
    flex-shrink:0;
}

.tk-group-name{
    /* 150% of the .3 it replaced - Drew's figure, ENH00037, and applied to the
       league TEXT only: the games (.tk-item, .34), the scores (.tk-teams) and
       every logo in the bar keep the size they had. The league label is now
       the largest text in the ticker, which is the point: it is the one thing
       on the bar that says what you are looking at. */
    font-size:calc(var(--tk-h)*.45);
    font-weight:800;
    letter-spacing:.06em;
    text-transform:uppercase;
    color:var(--primary,#5e95ff);
}
html.light .tk-group-name{color:var(--primary,#007bff)}

/* An "airing" interstitial (a favorite/live game shown between league segments)
   gets a faint wash so you can tell it's the recurring highlight, not part of a
   league's own run. */
.tk-air{background:rgb(94 149 255 / 6%)}
.tk-air.tk-live{background:rgb(255 82 82 / 9%)}
.tk-air.tk-fav{background:rgb(46 204 113 / 9%)}

/* ============================================================
   LIVE SITUATION WIDGETS (v1.0.7)
   Graphical game state: baseball diamond + count/outs, football
   possession + down/distance, plus a last-play line. Rendered in
   the scoreboard popover (full), the day-row status cue (compact),
   and the ticker (tiny). Popover styles read the sb theme vars.
   ============================================================ */

/* Popover widget */
.sit{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:18px;
    margin:14px 0 2px;
    padding:12px 0;
    border-top:1px solid var(--sb-line,#2a5a9a);
}
.sit-diamond{flex-shrink:0}

.sit-dia-outline{
    fill:none;
    stroke:var(--sb-fg-dim,#9dc2f0);
    stroke-width:2;
    opacity:.5;
}

.sit-base{
    fill:transparent;
    stroke:var(--sb-fg-dim,#9dc2f0);
    stroke-width:2;
}

.sit-base.on{
    fill:#ffd24a;
    stroke:#ffd24a;
}

.sit-bmeta{
    display:flex;
    flex-direction:column;
    gap:5px;
    align-items:flex-start;
    font-family:'Arial Narrow',Arial,sans-serif;
}

.sit-inning{
    font-size:1.25em;
    font-weight:800;
    color:var(--sb-fg,#fff);
}

.sit-count{
    font-size:1.3em;
    font-weight:700;
    color:var(--sb-fg,#fff);
    letter-spacing:1px;
}

.sit-outs{
    display:flex;
    align-items:center;
    gap:6px;
}

.sit-out{
    width:12px;
    height:12px;
    border-radius:50%;
    border:2px solid var(--sb-fg-dim,#9dc2f0);
    box-sizing:border-box;
}

.sit-out.on{
    background:#e74c3c;
    border-color:#e74c3c;
}

/* Football */
.sit-football{
    flex-direction:column;
    gap:6px;
    padding-left:16px;
    padding-right:16px;
}

.sit-poss{
    font-size:1.35em;
    font-weight:800;
    color:var(--sb-fg,#fff);
}
.sit-ball{font-size:.95em}

.sit-dd{
    font-size:1.2em;
    font-weight:700;
    color:var(--sb-fg,#fff);
}

.sit-pips{
    display:flex;
    gap:8px;
}

.sit-pip{
    width:22px;
    height:6px;
    border-radius:3px;
    background:var(--sb-fg-dim,#9dc2f0);
    opacity:.35;
}

.sit-pip.on{
    background:#ffd24a;
    opacity:1;
}

.sit-football.redzone{
    background:rgb(231 76 60 / 15%);
    border-radius:8px;
}

/* Hockey/basketball period pips - same .sit-pips/.sit-pip language as
   football's down markers above, parsed from status text (see
   _periodPipsWidget in builders.js; no backend field for this exists yet). */
.sit-hockey,.sit-basketball{
    flex-direction:column;
    gap:6px;
    padding-left:16px;
    padding-right:16px;
}

/* The running clock, above the period label. Largest thing in the widget
   because it is the number that changes and the one being watched - the period
   is context for it, not the headline. Tabular figures so the digits do not
   shuffle sideways as the seconds tick. */
.sit-clock{
    color:var(--sb-fg,#fff);
    font-size:1.5em;
    font-variant-numeric:tabular-nums;
    font-weight:800;
    letter-spacing:.5px;
    line-height:1.05;
}

.sit-period-lbl{
    font-size:1.3em;
    font-weight:800;
    color:var(--sb-fg,#fff);
    letter-spacing:1px;
}

.sit-ot{
    font-size:1.3em;
    font-weight:800;
    color:#ffd24a;
}
.sb-center-sit .sit-period-lbl,.sb-center-sit .sit-ot{font-size:1em}

/* In the scoreboard the clock keeps the emphasis; the period drops back. */
.sb-center-sit .sit-clock{font-size:1.45em}
.sb-center-sit .sit-period-lbl{opacity:.85}

.sit-rz{
    font-size:.85em;
    font-weight:800;
    color:#ff6b6b;
    letter-spacing:2px;
}

/* Last-plays list (all sports; up to 5, newest first) */
.sb-lastplay{
    margin-top:10px;
    padding-top:9px;
    border-top:1px dashed var(--sb-line,#2a5a9a);
    font-size:1.05em;
    text-align:center;
    line-height:1.3;
}

.sb-lastplay-lbl{
    display:block;
    color:var(--sb-fg-dim,#9dc2f0);
    font-weight:800;
    text-transform:uppercase;
    font-size:.8em;
    letter-spacing:1px;
    margin-bottom:5px;
}

.sb-play{
    padding:2px 0;
    color:var(--sb-fg-dim,#c9d9f0);
    font-size:.92em;
}
.sb-play + .sb-play{border-top:1px solid rgb(255 255 255 / 6%)}

.sb-play-latest{
    color:var(--sb-fg,#fff);
    font-weight:700;
}

/* Compact row cue (day-view status column). Baseball: LEFT half is the base
   diamond alone, given real size to actually read; RIGHT half stacks the inning
   label (top) over the outs dots (bottom). Previously the inning text ran full-
   width above a diamond+outs row squeezed underneath - the diamond only ever
   got a sliver of the available height. */
.sit-cue{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:9px;
    margin-top:3px;
}

.sit-cue .sit-diamond{
    width:40px;
    height:40px;
    flex-shrink:0;
}

.sit-cue .sit-dia-outline{
    stroke:#7fa8d8;
    opacity:.8;
    stroke-width:2.5;
}

.sit-cue .sit-base{
    stroke:#7fa8d8;
    stroke-width:2.5;
}

.sit-cue-meta{
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    justify-content:center;
    gap:4px;
}

.sit-cue-inning{
    font-size:.85em;
    font-weight:700;
    color:#c9d9f0;
    line-height:1.1;
    white-space:nowrap;
}
html.light .sit-cue-inning{color:#33414f}

.sit-cue-outs{
    display:inline-flex;
    align-items:center;
    gap:5px;
}

.sit-cue-out{
    width:12px;
    height:12px;
    border-radius:50%;
    border:2.5px solid #9db4d6;
    box-sizing:border-box;
}

.sit-cue-out.on{
    background:#e74c3c;
    border-color:#e74c3c;
}
html.light .sit-cue-out{border-color:#4a6a95}

.sit-cue-fb{
    font-size:.8em;
    font-weight:800;
    color:#c78b00;
    background:rgb(255 210 74 / 14%);
    border:1px solid rgb(255 210 74 / 50%);
    border-radius:4px;
    padding:2px 7px;
    white-space:nowrap;
}

/* The ball, against whichever edge of the chip the team holding it sits on
   (ENH00025). The row draws both teams either side of this cell, so the SIDE is
   the whole message and no abbreviation is spent on it.

   Sized below the chip text and nudged off the baseline so it reads as a mark
   rather than a character. The padding shifts to the opposite edge so the chip
   does not grow when a ball appears - a chip that changes width every time
   possession changes would make the column jitter all afternoon. */
.sit-cue-ball{
    font-size:.82em;
    line-height:1;
    vertical-align:-1px;
}

.sit-cue-fb.poss-away .sit-cue-ball{margin-right:4px}

.sit-cue-fb.poss-home .sit-cue-ball{margin-left:4px}

.sit-cue-fb.poss-away{padding-left:4px}

.sit-cue-fb.poss-home{padding-right:4px}

.sit-cue-fb.redzone{
    color:#e74c3c;
    background:rgb(231 76 60 / 15%);
    border-color:rgb(231 76 60 / 50%);
}

/* SHOTS ON GOAL, AS A PAIR IN THE ROW'S OWN GEOMETRY (ENH00026). The away
   number on the left and the home number on the right, because that is already
   where the two teams are drawn - the same reason the football sits on a side
   rather than spelling out an abbreviation. The label goes between them so
   neither number needs one.

   Tabular figures and a minimum width per number so the pair does not shuffle
   sideways as the shots climb through 9 to 10. */
.sit-sog,.sit-pf{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:6px;
    font-variant-numeric:tabular-nums;
    line-height:1;
}

.sit-pair-n{
    font-weight:800;
    color:#c9d9f0;
    min-width:1.6em;
    text-align:center;
}
html.light .sit-pair-n{color:#33414f}

.sit-pair-lbl{
    font-size:.72em;
    font-weight:700;
    letter-spacing:.6px;
    opacity:.62;
}

/* TIMEOUTS AS AMBER DOTS (ENH00027), each team's on its own side of the cell -
   the row already draws the teams either side, so the position says whose they
   are and no label is spent on it.

   The two sides are pushed apart rather than centred as one run, so five dots
   against two reads as an imbalance at a glance instead of as one long row that
   has to be counted. Amber because it is the colour of a warning and that is
   what a team low on timeouts is; it is deliberately not the chip amber, which
   means "down and distance" elsewhere in this same column. */
.sit-tos{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:14px;
    width:100%;
    line-height:1;
}

.sit-to-side{
    display:inline-flex;
    gap:3px;
    align-items:center;
    min-height:6px;
}

.sit-to-dot{
    width:6px;
    height:6px;
    border-radius:50%;
    background:#f0a830;
    box-shadow:0 0 0 1px rgb(240 168 48 / 35%);
}

html.light .sit-to-dot{
    background:#c07d08;
    box-shadow:0 0 0 1px rgb(192 125 8 / 30%);
}

/* No DATA, as against none left - the dash matches what the number pair does
   for a missing side, so the two absences look the same wherever they appear. */
.sit-to-na{
    font-size:.72em;
    font-weight:700;
    opacity:.5;
}

/* ---- PER-GAME DETAIL (ENH00034) ---------------------------------------- */

/* Scoring Plays | All Plays. A segmented pair rather than a dropdown: there are
   two of them and the one you are not on is worth naming. */
.sb-plays{margin-top:10px}

.sb-plays-tabs{
    display:flex;
    gap:0;
    margin-bottom:6px;
}

.sb-plays-tab{
    background:rgb(255 255 255 / 6%);
    border:1px solid var(--sb-line,#2a5a9a);
    color:inherit;
    cursor:pointer;
    flex:1 1 0;
    font-size:.74rem;
    font-weight:700;
    opacity:.72;
    padding:4px 6px;
}

.sb-plays-tab:first-child{border-radius:6px 0 0 6px}

.sb-plays-tab:last-child{
    border-left:0;
    border-radius:0 6px 6px 0;
}

.sb-plays-tab.active{
    background:rgb(255 255 255 / 18%);
    opacity:1;
}

.sb-plays-n{
    font-size:.68rem;
    font-weight:800;
    opacity:.7;
}

/* Capped and scrolled: a finished NFL game is ~200 plays, and a card that grows
   to 200 rows is a card you cannot see the rest of. */
.sb-plays-body{
    display:flex;
    flex-direction:column;
    gap:3px;
    max-height:220px;
    overflow-y:auto;
    padding-right:2px;
}

.sb-pl{
    border-left:2px solid transparent;
    display:flex;
    font-size:.74rem;
    gap:6px;
    line-height:1.3;
    padding:2px 4px;
}

/* A scoring play inside the ALL list is worth finding at a glance - it is the
   same mark the Scoring tab is made of. */
.sb-pl.is-scoring{
    background:rgb(232 179 57 / 10%);
    border-left-color:#e8b339;
}

.sb-pl-when{
    flex:0 0 auto;
    font-variant-numeric:tabular-nums;
    font-weight:700;
    min-width:4.2em;
    opacity:.65;
}

.sb-pl-text{
    flex:1 1 auto;
    min-width:0;
}

.sb-pl-score{
    flex:0 0 auto;
    font-variant-numeric:tabular-nums;
    font-weight:800;
    opacity:.8;
}

.sb-pl-none{
    font-size:.74rem;
    opacity:.5;
    padding:6px 2px;
}

/* Win probability. A sparkline, not a chart: the card is ~340px wide, and the
   SHAPE - who has led, and how violently it moved - is the message. The number
   beside it is the current state.

   Drawn from the HOME side's series for its whole length, so a rising line
   always means the same thing. */
.sb-wp{margin-top:10px}

.sb-wp-lbl{
    font-size:.7rem;
    font-weight:800;
    letter-spacing:.6px;
    opacity:.65;
    text-transform:uppercase;
}

/* The plot is positioned so the NOW label can sit against the same x the
   marker is drawn at. */
.sb-wp-plot{
    padding-bottom:12px;
    position:relative;
}

.sb-wp-svg{
    display:block;
    height:46px;
    width:100%;
}

/* One per period boundary, so "three of four quarters played" reads off the
   chart rather than being inferred from where the line stops. */
.sb-wp-tick{
    stroke:currentcolor;
    stroke-width:1;
    opacity:.14;
}

/* Where the game actually is. Only drawn while it is still moving - on a
   finished game it would be labelling the end of something that has stopped. */
.sb-wp-now{
    stroke:#fff;
    stroke-dasharray:2 2;
    stroke-width:1;
    opacity:.5;
}

.sb-wp-dot{
    fill:#e8b339;
    stroke:#1b1b1b;
    stroke-width:1;
}

.sb-wp-nowlbl{
    bottom:0;
    font-size:.6rem;
    font-weight:800;
    letter-spacing:.5px;
    opacity:.7;
    position:absolute;
    transform:translateX(-50%);
}

.sb-wp-mid{
    stroke:currentcolor;
    stroke-dasharray:3 3;
    stroke-width:1;
    opacity:.25;
}

.sb-wp-line{
    fill:none;
    stroke:#e8b339;
    stroke-linejoin:round;
    stroke-width:2;
    vector-effect:non-scaling-stroke;
}

.sb-wp-ends{
    display:flex;
    font-size:.72rem;
    font-weight:700;
    justify-content:space-between;
    opacity:.85;
}

/* --- the team card's game panel ---------------------------------------- */

/* TWO COLUMNS (ENH00035). Leaders and team stats are both narrow lists, and
   stacked they pushed everything else - Last 5, standings, news - a long way
   down the card. align-items:start so a short list does not stretch to match a
   long one; min-width:0 so a long player name ellipses inside its column
   instead of widening it. */
.tt-gamedetail{
    align-items:start;
    border-bottom:1px solid var(--sb-line,#2a5a9a);
    column-gap:10px;
    display:grid;
    grid-template-columns:1fr 1fr;
    padding-bottom:6px;
}

.tt-gd-col{min-width:0}

/* Narrower columns want a tighter row: the headshot and the category line are
   what give, not the name or the number. */
.tt-gamedetail .tt-gl-face{
    height:22px;
    width:22px;
}

.tt-gamedetail .tt-gl-name{font-size:.76rem}

.tt-gamedetail .tt-gl-cat{font-size:.64rem}

.tt-gamedetail .tt-gl-val{font-size:.72rem}

.tt-gamedetail .tt-ts-lbl{font-size:.68rem}

.tt-gamedetail .tt-ts-mine{font-size:.74rem}

.tt-gamedetail .tt-ts-theirs{
    font-size:.7rem;
    min-width:2.4em;
}

.tt-gl{
    display:flex;
    flex-direction:column;
    gap:4px;
}

.tt-gl-row{
    align-items:center;
    display:flex;
    gap:7px;
}

.tt-gl-face{
    background:rgb(255 255 255 / 8%);
    border-radius:50%;
    flex:0 0 auto;
    height:28px;
    object-fit:cover;
    width:28px;
}

.tt-gl-who{
    display:flex;
    flex:1 1 auto;
    flex-direction:column;
    min-width:0;
}

.tt-gl-name{
    font-size:.8rem;
    font-weight:700;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

.tt-gl-pos{
    font-size:.7rem;
    font-weight:600;
    opacity:.6;
}

.tt-gl-cat{
    font-size:.68rem;
    opacity:.6;
}

.tt-gl-val{
    flex:0 0 auto;
    font-size:.76rem;
    font-weight:800;
    text-align:right;
}

/* Label, this team's number, the opponent's, and a bar for this team's share.
   The grid is fixed so the numbers line up down the column - a per-row flex
   would let a long label shove them out of alignment. */
.tt-ts{
    display:flex;
    flex-direction:column;
    gap:3px;
}

.tt-ts-row{
    align-items:center;
    column-gap:6px;
    display:grid;
    grid-template-columns:1fr auto auto;
    grid-template-rows:auto auto;
}

.tt-ts-lbl{
    font-size:.72rem;
    opacity:.7;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

.tt-ts-mine{
    font-size:.78rem;
    font-variant-numeric:tabular-nums;
    font-weight:800;
}

.tt-ts-theirs{
    font-size:.74rem;
    font-variant-numeric:tabular-nums;
    min-width:3em;
    opacity:.5;
    text-align:right;
}

/* Spans the row under the three cells. Only drawn when both sides are numeric,
   so there is never a bar under "19:02" pretending to be a ratio. */
.tt-ts-bar{
    background:rgb(255 255 255 / 10%);
    border-radius:2px;
    display:block;
    grid-column:1 / -1;
    height:3px;
    overflow:hidden;
}

.tt-ts-bar > span{
    background:var(--theme-color,#7728d7);
    display:block;
    height:100%;
}

/* ---- CALENDAR VIEW SWITCH + DAY COLUMNS (ENH00031) ---------------------- */

/* Segmented control in the header. One row, one lit segment: the view the
   calendar is actually in, which is the thing a control like this exists to
   say. */
.cal-view-switch{
    display:inline-flex;
    align-items:stretch;
    border:1px solid var(--sb-line,#2a5a9a);
    border-radius:6px;
    overflow:hidden;
}

.cal-view-btn{
    background:transparent;
    border:0;
    border-right:1px solid var(--sb-line,#2a5a9a);
    color:#9dc2f0;
    cursor:pointer;
    font-size:.78rem;
    font-weight:700;
    padding:4px 10px;
    white-space:nowrap;
}

.cal-view-btn:last-child{border-right:0}

.cal-view-btn:hover{background:rgb(157 194 240 / 12%)}

.cal-view-btn.active{
    background:var(--theme-color,#7728d7);
    color:#fff;
}

html.light .cal-view-btn{color:#33414f}

/* The columns.
   #calendar-host.calendar-cols, NOT .calendar-cols: the host carries an ID rule
   pinning a 7x4 month grid (grid-template-columns:repeat(7,1fr);
   grid-template-rows:repeat(4,1fr)), and an ID beats a class - so the first cut
   of these rules lost every time and five columns were laid into seven. The DOM
   was right, which is why the tests passed; only the computed layout was wrong.

   EVERY DAY GETS AN EQUAL SHARE OF THE FULL WIDTH, from a custom property set at
   render time rather than a class per count: three days is a third each, five a
   fifth, and a span nobody has written a rule for still divides evenly. */
#calendar-host.calendar-cols{
    background:transparent;
    display:grid;
    gap:6px;
    grid-template-columns:repeat(var(--cal-cols,7),minmax(0,1fr));
    grid-template-rows:1fr;
    overflow:hidden;
    padding:6px;
}

/* min-height:0 is load-bearing: a grid item defaults to min-content, so without
   it the column refuses to shrink and its body scrollbar never appears - the
   whole run of leagues pushes the column past the bottom of the page instead. */
.cal-col{
    background:#1f232b;
    border:1px solid var(--sb-line,#2a5a9a);
    border-radius:8px;
    cursor:pointer;
    display:flex;
    flex-direction:column;
    min-height:0;
    min-width:0;
    overflow:hidden;
}

html.light .cal-col{background:#fff}

.cal-col:hover{border-color:var(--theme-color,#7728d7)}

/* Today is marked from the real clock, not from whatever date is being viewed. */
.cal-col.is-today{
    border-color:var(--theme-color,#7728d7);
    box-shadow:inset 0 0 0 1px var(--theme-color,#7728d7);
}

.cal-col-head{
    align-items:baseline;
    border-bottom:1px solid var(--sb-line,#2a5a9a);
    display:flex;
    flex:0 0 auto;
    gap:6px;
    padding:6px 8px;
}

.cal-col-dow{
    font-size:.8rem;
    font-weight:800;
    letter-spacing:.4px;
    text-transform:uppercase;
}

.cal-col-dom{
    font-size:.72rem;
    opacity:.7;
}

.cal-col-n{
    font-size:.72rem;
    font-weight:700;
    margin-left:auto;
    opacity:.75;
}

/* The body takes the rest of the column's height and scrolls only if the day
   genuinely has more leagues than fit. */
.cal-col-body{
    display:flex;
    flex:1 1 auto;
    flex-direction:column;
    gap:3px;
    min-height:0;
    overflow-y:auto;
    padding:6px;
}

.cal-col-empty{
    font-size:.74rem;
    opacity:.4;
    padding:8px 2px;
    text-align:center;
}

/* One league in one day. The whole chip is the hit target - it is what opens
   that league's games, and a logo alone is a small thing to ask someone to hit. */
.cal-col-lg{
    align-items:center;
    border:1px solid transparent;
    border-radius:6px;
    display:flex;
    gap:8px;
    min-width:0;
    padding:4px 6px;
}

.cal-col-lg:hover{
    background:rgb(157 194 240 / 12%);
    border-color:var(--sb-line,#2a5a9a);
}

/* THE SAME SIZE THE MONTH GRID USES, from the same variable - so the icon-size
   setting moves both and the two views cannot drift apart. 18px was a column's
   guess at "compact"; Drew: "make the icons for the leagues much bigger as well.
   How they are on the monthly view at least." */
.cal-col-lg-logo{
    flex:0 0 auto;
    height:var(--cal-icon,36px);
    object-fit:contain;
    width:var(--cal-icon,36px);
}

.cal-col-lg-name{
    flex:1 1 auto;
    font-size:.88rem;
    font-weight:700;
    min-width:0;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

.cal-col-lg-n{
    flex:0 0 auto;
    font-size:.86rem;
    font-variant-numeric:tabular-nums;
    font-weight:800;
    opacity:.8;
}

/* The gold favourite badge, same language as the month cell's. */
.cal-col-lg-fav{
    background:#e8b339;
    border-radius:8px;
    color:#1b1b1b;
    flex:0 0 auto;
    font-size:.72rem;
    font-weight:800;
    padding:0 5px;
}

/* One column has the whole width, so it spends it. */
#calendar-host.calendar-cols[style*="--cal-cols:1"] .cal-col-lg-name{font-size:.95rem}

/* Phones cannot carry five or seven columns at any readable size, so the grid
   becomes one column and the days stack - the same leagues, scrolled rather
   than squeezed. */
@media (width <= 768px){
    #calendar-host.calendar-cols{
        grid-template-columns:1fr;
        grid-template-rows:none;
        overflow-y:auto;
    }

    .cal-col{min-height:120px}
}

/* THE BOOK LINE under a scheduled game's start time (ENH00028). Deliberately
   quieter than the time above it: the time is why the row is in the list, and
   the line is extra - it should read as a footnote, not compete. Its own colour
   rather than inheriting, because the parent carries an inline blue that is
   meant for the time alone.

   Ellipsis rather than wrap: a long line ("KC -4.5 . O/U 47.5") must not push a
   scheduled row taller than the rows around it. */
.sched-odds{
    font-size:.78em;
    font-weight:600;
    color:#8fa4bf;
    line-height:1.2;
    margin-top:2px;
    max-width:100%;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

html.light .sched-odds{color:#5c7089}

/* The day row's basketball stack: clock and period, fouls, then the dots. */
.sit-cue-nba{
    flex-direction:column;
    gap:3px;
    min-width:0;
    max-width:100%;
}

.sit-cue-nba .sit-pf{font-size:.85em}

.sit-basketball .sit-pf{
    font-size:1.05em;
    gap:10px;
}

.sit-basketball .sit-pair-n{min-width:2em}

/* The power play. TEAL RATHER THAN THE FOOTBALL CHIP'S AMBER: the two never
   appear on the same row, but they appear in the same column minutes apart on
   a mixed evening, and the colour is what says which sport is being looked at
   before any of the text is read. */
.sit-pp{
    font-size:.78em;
    font-weight:800;
    color:#2bb3a3;
    background:rgb(43 179 163 / 14%);
    border:1px solid rgb(43 179 163 / 50%);
    border-radius:4px;
    padding:1px 6px;
    white-space:nowrap;
}
html.light .sit-pp{color:#17796d}

/* Against whichever edge the team with the advantage sits on, so "who has it"
   costs no width - ENH00025's trick, reused. */
.sit-pp.poss-away{align-self:flex-start}

.sit-pp.poss-home{align-self:flex-end}

/* The day row's hockey stack: clock and period, shots, then the power play if
   there is one. Same column rules the football wrapper uses. */
.sit-cue-nhl{
    flex-direction:column;
    gap:3px;
    min-width:0;
    max-width:100%;
}

.sit-cue-nhl .sit-sog{font-size:.85em}

/* The popover has the room the row does not, so the pair reads at the widget's
   own size there instead of the row's. */
.sit-hockey .sit-sog{
    font-size:1.05em;
    gap:10px;
}

.sit-hockey .sit-pair-n{min-width:2em}

/* Football stacks: clock + quarter on top, the down & distance chip below.
   .sit-cue is a ROW (baseball's diamond sits beside its meta), so the wrapper
   has to override the direction rather than inherit it. Column instead of
   side-by-side because the chip is already the widest thing in the cell -
   "3rd & 14 at WSU 38" - and putting a clock next to it would push one of the
   two out of the column at any width worth having. */
.sit-cue-fbwrap{
    flex-direction:column;
    gap:3px;
    min-width:0;
    max-width:100%;
}

.sit-cue-fbclock{
    font-size:.85em;
    font-weight:700;
    color:#c9d9f0;
    line-height:1.1;
    white-space:nowrap;
    font-variant-numeric:tabular-nums;
}
html.light .sit-cue-fbclock{color:#33414f}

/* The chip is the one thing here allowed to shrink: at a narrow width the yard
   line ("at WSU 38") is the least important part of it, so ellipsis there
   beats pushing the score numbers off the row.

   BUT THE BALL IS NOT PART OF WHAT SHRINKS (BUG00036). The ellipsis used to sit
   on the chip itself, which made the ball just more text to cut: on home
   possession, where it trails the down and distance, "2nd & 8 at SEA 38..."
   dropped it entirely and the row stopped saying who had the ball at all - on
   exactly the long-yardage situations where that matters most.

   A flex row instead: the ball holds its size at either end and only the text
   between them gives way. */
.sit-cue-fbwrap .sit-cue-fb{
    align-items:baseline;
    display:flex;
    max-width:100%;
    overflow:hidden;
}

.sit-cue-fb .sit-cue-ball{flex:0 0 auto}

.sit-cue-dd{
    flex:0 1 auto;
    min-width:0;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

/* Ticker token: sized to match the ticker text (scales with --tk-h). The
   situation lives in a slot; an empty slot collapses so it adds no gap. Bumped
   from .58/.12 - at the old scale the diamond and out-dots were nearly
   indistinguishable at typical ticker heights. */
.tk-sit-slot{
    display:inline-flex;
    align-items:center;
}
.tk-sit-slot:empty{display:none}

.tk-sit{
    display:inline-flex;
    align-items:center;
    gap:calc(var(--tk-h)*.07);
    margin-left:calc(var(--tk-h)*.1);
    vertical-align:middle;
}

.tk-sit .sit-diamond{
    width:calc(var(--tk-h)*.75);
    height:calc(var(--tk-h)*.75);
}

.tk-sit .sit-dia-outline{
    stroke:#b9c6d8;
    opacity:.95;
    stroke-width:2.5;
}

.tk-sit .sit-base{
    stroke:#b9c6d8;
    stroke-width:2.5;
}

/* Outs as dots (filled = out) so it reads as OUTS, not a baserunner. */
.tk-sit-outs{
    display:inline-flex;
    align-items:center;
    gap:calc(var(--tk-h)*.06);
}

.tk-out{
    width:calc(var(--tk-h)*.16);
    height:calc(var(--tk-h)*.16);
    border-radius:50%;
    border:2.5px solid #a3b0c4;
    box-sizing:border-box;
}

.tk-out.on{
    background:#ff5252;
    border-color:#ff5252;
}

.tk-sit-fb{
    font-size:calc(var(--tk-h)*.32);
    font-weight:800;
    color:#ffd24a;
    border:1px solid rgb(255 210 74 / 45%);
    border-radius:5px;
    padding:0 6px;
}

.tk-sit-fb.redzone{
    color:#ff6b6b;
    border-color:rgb(231 76 60 / 50%);
}

/* Scoreboard league logo (replaces the league text) */

/* League mark at the top of the game modal. Sized to roughly two-thirds of the
   (now much larger, square) team logo boxes below it, and fluid so it keeps that
   relationship across viewport sizes - a flat 52px read as unchanged next to
   them. max-width is generous so wide wordmarks (NCAAF, LALIGA) aren't squashed.
   No puck backdrop here on purpose - see the exclusion note on the puck rule. */
.sb-league-logo{
    height:clamp(58px,8.5vmin,88px);
    width:auto;
    max-width:220px;
    object-fit:contain;
    vertical-align:middle;
    filter:drop-shadow(0 1px 3px rgb(0 0 0 / 40%));
}

/* Situation widget when it lives in the scoreboard CENTER chip: meta (inning /
   count / outs) on the LEFT, base diamond filling the RIGHT at a much bigger
   size - the diamond is the part that actually needs room to read, so it gets
   the majority of the available width instead of being squeezed as small as
   the text. Fixed light-on-dark colors (the chip is always dark) so it stays
   legible whatever the theme accent. */
.sb-center-sit{
    padding:10px 14px;
    min-width:clamp(160px,30vw,230px);
    max-width:250px;
}

.sb-center-sit .sit{
    border-top:none;
    margin:0;
    padding:0;
    gap:12px;
}

.sb-center-sit .sit-baseball{
    flex-direction:row;
    align-items:center;
    justify-content:space-between;
}

.sb-center-sit .sit-bmeta{
    align-items:flex-start;
    gap:5px;
}

.sb-center-sit .sit-diamond{
    width:72px;
    height:72px;
    flex-shrink:0;
}

.sb-center-sit .sit-inning{
    font-size:1.2em;
    color:#fff;
}

.sb-center-sit .sit-count{
    font-size:1.5em;
    font-weight:800;
    color:#fff;
}

.sb-center-sit .sit-out{
    width:15px;
    height:15px;
    border-color:#9dc2f0;
}

.sb-center-sit .sit-dia-outline,.sb-center-sit .sit-base{
    stroke:#9dc2f0;
    opacity:.85;
    stroke-width:2.5;
}
.sb-center-sit .sit-poss,.sb-center-sit .sit-dd{color:#fff}
.sb-center-sit .sit-football{gap:4px}
.sb-center-sit .sit-dd{font-size:1em}

/* Reset-to-default (danger) button */
.btn-danger{
    background:#a3342b;
    color:#fff;
    border:1px solid #7d2820;
    padding:8px 16px;
    border-radius:4px;
    cursor:pointer;
    font-weight:600;
}
.btn-danger:hover{background:#c0392b}

/* ============================================================
   FIELD EVENTS (golf tournaments / motor races)
   A type:"event" row has no two-team matchup; the center cell shows the event
   name + per-day round label on the left and the current leader on the right.
   The whole center cell (.eventgrid) is the leaderboard-popover trigger.
   ============================================================ */
.event-row .col-teams{
    display:flex;
    align-items:center;
}

.eventgrid{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:12px;
    width:100%;
    min-width:0;
}
.eventgrid:hover{filter:brightness(1.12)}

.event-info{
    display:flex;
    flex-direction:column;
    gap:2px;
    min-width:0;
}

.event-name{
    font-weight:800;
    color:#e8eefb;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}
html.light .event-name{color:#1a2433}

.event-round{
    font-size:.8em;
    color:#9dc2f0;
    text-transform:uppercase;
    letter-spacing:.5px;
}
html.light .event-round{color:#4a6da0}

.event-leader{
    display:flex;
    align-items:baseline;
    gap:8px;
    flex-shrink:0;
    max-width:52%;
    min-width:0;
}

.event-leader-name{
    color:#cdd9ec;
    font-weight:600;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}
html.light .event-leader-name{color:#33465e}

.event-leader-score{
    font-weight:800;
    color:#5eea9b;
    font-variant-numeric:tabular-nums;
}
html.light .event-leader-score{color:#0a8f4d}
.event-tee{flex-shrink:0}

/* A subtle left accent so field events read as a distinct kind at a glance. */
.event-row{background:linear-gradient(90deg,rgb(94 149 255 / 6%),transparent 60%)}
html.light .event-row{background:linear-gradient(90deg,rgb(0 123 255 / 5%),transparent 60%)}

.sb-tip,.tt-tip{position:relative}

/* Per-popover close (X). Clicking it (or the shared backdrop behind a sticky
   cluster, see .popover-backdrop) closes the whole sticky cluster. */

/* Appearance is defined once alongside .close-btn near the top of this file so
   both levels match; only POSITION differs - a card has no header bar to sit in,
   so its X floats in the corner. */
.sb-tip>.tip-close,.tt-tip>.tip-close{
    position:absolute;
    top:4px;
    right:8px;
    z-index:4;
}

/* Shared backdrop behind a STICKY (click-promoted) game/team/leaderboard popover
   cluster - blurs+dims everything beneath (Day modal, calendar); clicking it
   closes the whole cluster. Sits ABOVE modal-content (1002) but BELOW the
   popovers themselves (tippy zIndex 9000+ in initTippy). Deliberately stops
   ABOVE the ticker (--tk-h) rather than covering the whole viewport, so the
   bottom line stays visible/hoverable/clickable while a cluster is sticky. */

/* THE SCRIM - the app's only dim+blur layer. Its z-index is assigned at runtime
   by _syncScrim (js/render.tips.js) so it always sits directly BENEATH the topmost
   visible layer: under a pinned card when one is up, under the level-1 panel
   otherwise, and hidden entirely when nothing is open. */
.popover-backdrop{
    display:none;
    position:fixed;
    inset:0 0 var(--tk-h,64px) 0;
    z-index:999;
    background-color:rgb(0 0 0 / 30%);
    backdrop-filter:blur(5px);
    -webkit-backdrop-filter:blur(5px);
}
.popover-backdrop.active{display:block}

/* Day-row live score: numbers flank the status/situation cell (away # · status · home #)
   so the base diamond / down chip has room to read. Horizontal padding on the
   group pushes the away/home numbers IN from the column's outer edges - without
   it they land right next to the team logos just across the grid boundary. */
@media (width >=769px){ .status-col{min-width:300px} }

.sc-inline{
    display:flex;
    flex-direction:row;
    align-items:center;
    justify-content:center;
    gap:14px;
    width:100%;
    padding:0 14px;
    box-sizing:border-box;
}

.sc-num{
    font-size:1.5em;
    font-weight:800;
    font-family:monospace;
    color:#fff!important;
    line-height:1;
    font-variant-numeric:tabular-nums;
    flex:0 0 auto;
}

.sc-mid{
    display:flex;
    flex-direction:column;
    align-items:center;
    justify-content:center;
    min-width:0;
    flex:1 1 auto;
}
html.light .sc-num{color:#111!important}

/* Give the team names a touch less room so the wider center never crowds them. */
:root{
    --logo-bg:transparent;
    --logo-pad:0px;
    --logo-round:50%;

    /* The "soft" preset, resolved per THEME rather than baked into JS.
       It was a flat rgba(255,255,255,.22) - white at 22% - which is a light
       grey puck on the dark theme and very nearly nothing on the light one,
       where white-on-white leaves logos with no backdrop at all.
       The light value is the exact inversion: same 22%, opposite end of the
       scale, so both themes get a puck of identical contrast against their own
       background instead of one theme getting the effect and the other not.
       Declared here rather than assigned in applyLogoBackdrop() because JS
       writes --logo-bg as an INLINE style, which beats any stylesheet rule -
       a `html.light` override could never win. Pointing the inline value at
       this variable lets the cascade resolve it at use time, so switching
       theme (including a system theme flipping underneath us) updates the
       puck with no JS re-run at all. */
    --logo-bg-soft:rgb(255 255 255 / 22%);
    --primary-dark:#5e1fb0;
    --primary-dim:rgb(119 40 215 / 15%);
    --primary:#7728d7;
    --team-width:220px;
}

/* Leaderboard popover (reuses the .sb-tip shell look). Width is driven by content
   (1 or 2 columns) up to 94vw; fitTipHeight caps the height to the available
   viewport space and lets it scroll when the field is very long. */
.lb-tip{
    width:auto;
    max-width:94vw;
    max-height:88vh;
    overflow-y:auto;
    box-sizing:border-box;
    background:linear-gradient(180deg,#1a4a8a 0%,#12386b 100%);
    border:3px solid #0c2547;
    border-radius:12px;
    padding:14px 16px 12px;
    color:#fff;
    font-family:'Arial Narrow',Arial,sans-serif;
}

.lb-head{
    display:flex;
    align-items:center;
    gap:12px;
    padding-bottom:8px;
    margin-bottom:8px;
    border-bottom:1px solid #2a5a9a;
}

.lb-logo{
    width:40px;
    height:40px;
    object-fit:contain;
    flex-shrink:0;
    filter:drop-shadow(0 2px 4px rgb(0 0 0 / 50%));
}

.lb-headtext{
    display:flex;
    flex-direction:column;
    gap:1px;
    min-width:0;
    flex:1;
}

.lb-title{
    font-weight:800;
    font-size:1.2em;
    font-style:italic;
    line-height:1.05;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}

.lb-league{
    color:#9dc2f0;
    font-size:.85em;
    letter-spacing:1px;
    text-transform:uppercase;
    flex-shrink:0;
}

.lb-close{
    flex-shrink:0;
    cursor:pointer;
    font-size:1.6em;
    line-height:.8;
    color:#9dc2f0;
    user-select:none;
    padding:0 2px;
}
.lb-close:hover{color:#fff}

.lb-sub{
    color:#9dc2f0;
    font-size:.82em;
}

/* N side-by-side columns of players (count set by JS for the viewport width).
   Columns are wide enough that full player names fit without truncation. */
.lb-body{
    display:flex;
    gap:16px;
    align-items:flex-start;
}

.lb-col{
    width:360px;
    flex:0 0 360px;
}

.lb-list{
    display:flex;
    flex-direction:column;
    gap:2px;
}

/* Column grids, chosen by which data exists (dt = detail+total, t = total only,
   n = neither): leading heart, pos, name, then optional Thru/Rd and/or Total. */
.lb-cols{
    display:grid;
    align-items:center;
    gap:6px;
    padding:3px 5px;
    border-radius:5px;
}
.lb-c-dt{grid-template-columns:18px 22px minmax(0,1fr) 34px 36px 42px}
.lb-c-t{grid-template-columns:18px 22px minmax(0,1fr) 44px}
.lb-c-n{grid-template-columns:18px 22px minmax(0,1fr)}

.lb-colhead{
    color:#8fb2dd;
    font-size:.72em;
    text-transform:uppercase;
    letter-spacing:.5px;
    border-bottom:1px solid #24487e;
    margin-bottom:2px;
    padding-bottom:3px;
}
.lb-colhead .lb-score,.lb-colhead .lb-today{color:#8fb2dd}
.lb-row:nth-child(odd){background:rgb(255 255 255 / 5%)}

.lb-fav{
    cursor:pointer;
    text-align:center;
    color:#5b7699;
    font-size:1.05em;
    line-height:1;
    user-select:none;
    transition:color .1s,transform .1s;
}

.lb-fav:hover{
    color:#9dc2f0;
    transform:scale(1.2);
}

.lb-pos{
    color:#9dc2f0;
    text-align:right;
    font-variant-numeric:tabular-nums;
}

.lb-name{
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}

.lb-thru{
    color:#cdd9ec;
    font-size:.85em;
    text-align:right;
    white-space:nowrap;
}

.lb-today{
    color:#cdd9ec;
    text-align:right;
    font-variant-numeric:tabular-nums;
}

.lb-score{
    font-weight:800;
    color:#5eea9b;
    font-variant-numeric:tabular-nums;
    text-align:right;
}

.lb-empty{
    color:#9dc2f0;
    font-style:italic;
    padding:6px 2px;
}

/* A favorited player: filled heart, gold accent, bold - stands out at a glance. */
.lb-row-fav{background:rgb(255 196 0 / 14%)!important}
.lb-row-fav .lb-fav{color:#ffc400}

.lb-row-fav .lb-name{
    color:#ffe08a;
    font-weight:800;
}
.lb-row-fav .lb-pos{color:#ffd873}

/* Divider before favorites that ranked below the visible cut. */

/* Footer: expand/collapse toggle + ESPN link (new tab). */
.lb-foot{
    display:flex;
    align-items:center;
    gap:12px;
    margin-top:10px;
    padding-top:8px;
    border-top:1px solid #2a5a9a;
}

.lb-more{
    flex:1;
    padding:9px;
    background:rgb(255 255 255 / 8%);
    border:1px solid #2a5a9a;
    color:#cdd9ec;
    border-radius:6px;
    font-weight:700;
    font-size:.92em;
    cursor:pointer;
}

.lb-more:hover{
    background:rgb(255 255 255 / 14%);
    color:#fff;
}

.lb-espn{
    color:#9dc2f0;
    font-weight:700;
    font-size:.9em;
    text-decoration:none;
    white-space:nowrap;
}

.lb-espn:hover{
    color:#fff;
    text-decoration:underline;
}

/* Phones: single full-width column, tighter grids. */
@media (width <=768px){
    .lb-body{
    flex-direction:column;
    gap:10px;
}

    .lb-col{
    width:100%;
    flex:1 1 auto;
}
    .lb-tip{width:min(94vw,420px)}
}

@media (width <=480px){
    .eventgrid{gap:8px}
    .event-name{font-size:.95em}
    .event-leader{max-width:46%}

    .lb-tip{
    width:95vw;
    padding:12px 13px 10px;
}

    .lb-c-dt{
    grid-template-columns:18px 24px 1fr 46px 38px 42px;
    gap:6px;
}

    .lb-c-t{
    grid-template-columns:18px 24px 1fr 42px;
    gap:6px;
}

    .lb-c-n{
    grid-template-columns:18px 24px 1fr;
    gap:6px;
}
}

/* ============================================================
   SETTINGS MODAL: static height (2026-07)
   The panel used to resize as you switched tabs (each tab's
   content drove the height). Now all tab panels are grid-stacked
   into one cell, so the tab body is always as tall as the TALLEST
   tab (Display/Highlights) and the modal height never changes.
   openTab() toggles the .active CLASS only (no inline display).
   ============================================================ */
.settings-content{
    width:1250px;
    max-width:95vw;
    height:auto;
    max-height:calc(94vh - var(--tk-h,64px));
}

.settings-tab-body{
    flex:1 1 auto;
    min-height:0;
    display:grid;
    grid-template-columns:1fr;
    grid-template-rows:minmax(0,1fr);
    overflow:hidden;
}

/* All panels occupy the same grid cell; inactive ones are hidden but still
   reserve their footprint, so the cell (and modal) sizes to the tallest. */
.settings-tab-body>.tab-content{
    grid-area:1/1;
    display:block;
    min-height:0;
    overflow-y:auto;
    visibility:hidden;
    pointer-events:none;
}

.settings-tab-body>.tab-content.active{
    visibility:visible;
    pointer-events:auto;
    z-index:1;
}

@media (width <=768px){
    /* On phones the modal fills the screen, so the "static height" concern is
       moot. Drop the grid-stack (a tall tab could be clipped) and show only the
       active tab, scrolling within the fixed frame - the original behavior. */
    .settings-content{
    height:calc(100dvh - var(--tk-h,0px));
    max-height:calc(100dvh - var(--tk-h,0px));
}

    .settings-tab-body{
    display:flex;
    flex-direction:column;
    overflow:hidden;
}

    .settings-tab-body>.tab-content{
    display:none;
    visibility:visible;
    flex:1 1 auto;
    min-height:0;
    overflow-y:auto;
    -webkit-overflow-scrolling:touch;
}
    .settings-tab-body>.tab-content.active{display:block}
}

/* Section header with inline bulk-action buttons (Leagues tab). */
.settings-section-head{
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:12px;
    flex-wrap:wrap;
    margin-bottom:10px;
}
.settings-section-head h3{margin:0}

.league-bulk-actions{
    display:flex;
    gap:6px;
    flex-wrap:wrap;
}

.btn-chip{
    background:#252b36;
    border:1px solid #444;
    color:#cdd9ec;
    border-radius:14px;
    padding:4px 12px;
    font-size:.8em;
    font-weight:600;
    cursor:pointer;
    white-space:nowrap;
    transition:all .15s;
}

.btn-chip:hover{
    background:#333;
    color:#fff;
    border-color:#666;
}

.btn-chip-primary{
    background:var(--primary-dim);
    border-color:var(--primary);
    color:var(--primary);
}

.btn-chip-primary:hover{
    background:var(--primary);
    color:#fff;
}

html.light .btn-chip{
    background:#eef0f4;
    border-color:#ccc;
    color:#334;
}
html.light .btn-chip:hover{background:#e2e6ee}

/* Sport-category on/off chips above the League Visibility list. "On" (every
   league in that sport currently Open) uses the primary-filled treatment so
   it reads distinctly from the plain bulk-action chips above it. */
.sport-cat-chips{
    display:flex;
    flex-direction:column;
    gap:8px;
    margin:2px 0 14px;
}

.fan-row{
    align-items:center;
    display:flex;
    flex-wrap:wrap;
    gap:6px;
}

.fan-caption{
    color:#7d8799;
    flex:0 0 auto;
    font-size:.76em;
    font-style:italic;
    letter-spacing:.04em;
    margin-right:2px;
    min-width:96px;
    text-transform:uppercase;
}
html.light .fan-caption{color:#697382}

/* Icon + label + count. The icon does the recognising at a glance; the label
   removes any ambiguity about which sport a shape is meant to be; the count
   tells you how much you are about to switch before you switch it. */
.fan-chip{
    align-items:center;
    background:#252b36;
    border:1px solid #444;
    border-radius:16px;
    color:#9db4d6;
    cursor:pointer;
    display:inline-flex;
    font-size:.8em;
    font-weight:700;
    gap:6px;
    padding:5px 12px 5px 9px;
    transition:all .15s;
    white-space:nowrap;
}

.fan-chip:hover{
    background:#333;
    border-color:#666;
    color:#fff;
}

.fan-chip.active{
    background:var(--primary-dim);
    border-color:var(--primary);
    color:var(--primary);
}

.fan-chip.active:hover{
    background:var(--primary);
    color:#fff;
}

.fan-chip em{
    background:rgb(0 0 0 / 30%);
    border-radius:9px;
    font-size:.85em;
    font-style:normal;
    font-weight:600;
    opacity:.8;
    padding:0 6px;
}

.fan-ico{
    flex:0 0 auto;
    height:18px;
    width:18px;
}

html.light .fan-chip{
    background:#eef0f4;
    border-color:#ccc;
    color:#556;
}
html.light .fan-chip:hover{background:#e2e6ee}
html.light .fan-chip em{background:rgb(0 0 0 / 8%)}

/* ADD vs ONLY. Deliberately loud when ONLY is armed - the next click hides
   everything else, and that should never be a surprise. */
.fan-only-row{
    align-items:center;
    display:flex;
    gap:8px;
}

.fan-only-row i{
    color:#7d8799;
    font-size:.76em;
}
html.light .fan-only-row i{color:#697382}

.fan-only{
    background:#252b36;
    border:1px solid #444;
    border-radius:5px;
    color:#9db4d6;
    cursor:pointer;
    font-size:.72em;
    font-weight:800;
    letter-spacing:.08em;
    padding:4px 12px;
}

.fan-only.active{
    background:#b8860b;
    border-color:#d4a017;
    color:#fff;
}

html.light .fan-only{
    background:#eef0f4;
    border-color:#ccc;
    color:#556;
}

html.light .fan-only.active{
    background:#b8860b;
    border-color:#966d09;
    color:#fff;
}

/* Favorites picker: individual-player tracking for field leagues (PGA/NASCAR/...). */
.fp-player-add{
    display:flex;
    gap:8px;
    padding:4px 0 12px;
}

.fp-player-input{
    flex:1;
    min-width:0;
    background:#111;
    border:1px solid #444;
    color:#fff;
    padding:9px 12px;
    border-radius:6px;
    font-size:.95em;
}

html.light .fp-player-input{
    background:#fff;
    border-color:#ccc;
    color:#222;
}
.fp-player-addbtn{white-space:nowrap}

.fp-player-list{
    display:flex;
    flex-direction:column;
    gap:6px;
}

.fp-player-row{
    display:flex;
    align-items:center;
    gap:10px;
    background:#252b36;
    border:1px solid #3a4150;
    border-left:4px solid #2ecc71;
    border-radius:6px;
    padding:8px 12px;
}

html.light .fp-player-row{
    background:#eef0f4;
    border-color:#ccd;
}

.fp-player-row .fp-player-heart{
    color:#ffcf3f;
    font-size:1.05em;
}

.fp-player-row .fp-player-nm{
    flex:1;
    min-width:0;
    font-weight:600;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

.fp-player-row .fp-player-del{
    cursor:pointer;
    color:#e74c3c;
    font-weight:bold;
    font-size:1.15em;
    opacity:.75;
    padding:0 4px;
}
.fp-player-row .fp-player-del:hover{opacity:1}

.fp-player-empty{
    color:#888;
    font-style:italic;
    padding:6px 0;
}

/* A search-result row (a seen-but-not-yet-favorited athlete) - neutral border
   and an outline heart, distinct from the green/gold "already tracked" rows
   above, so it's clear tapping ADDS rather than removes. */
.fp-player-row-add{
    cursor:pointer;
    border-left-color:#444;
    transition:background .15s,border-color .15s;
}
.fp-player-row-add .fp-player-heart{color:#7d8799}

.fp-player-row-add:hover{
    background:#2f3542;
    border-left-color:var(--primary);
}
.fp-player-row-add:hover .fp-player-heart{color:var(--primary)}
html.light .fp-player-row-add:hover{background:#e2e6ee}

/* ==========================================================================
   PRINT LIST  (TV assignment, revived)
   ========================================================================== */

/* Per-row toggle, in the .col-sel cell the dormant feature already reserved. */
.pl-add{
    cursor:pointer;
    display:inline-flex;
    align-items:center;
    justify-content:center;
    padding:2px;
    border-radius:4px;
    color:#7c8ba1;
    opacity:.65;
    transition:opacity .15s,color .15s,background .15s;
}

.pl-add:hover{
    opacity:1;
    color:#cfe0ff;
    background:rgb(255 255 255 / 10%);
}

/* Added: solid accent, and the little + drops away - it invited the ADD, and
   showing it on an already-added game would misread as "add again". */
.pl-add.in-list{
    opacity:1;
    color:var(--accent,#7728d7);
}
.pl-add.in-list .pl-plus{display:none}
html.light .pl-add{color:#8a94a6}

html.light .pl-add:hover{
    color:#1b2431;
    background:rgb(0 0 0 / 6%);
}

/* Count badge on every print button, so the header shows how many are queued
   without opening anything. */
.print-list-btn{position:relative}

.print-list-btn::after{
    content:attr(data-count);
    position:absolute;
    top:-2px;
    right:-4px;
    min-width:15px;
    height:15px;
    padding:0 3px;
    border-radius:8px;
    background:var(--accent,#7728d7);
    color:#fff;
    font-size:10px;
    line-height:15px;
    font-weight:700;
    text-align:center;
    pointer-events:none;
}
.print-list-btn[data-count="0"]::after{display:none}

/* --- review rows inside the modal --- */
.pl-empty{
    padding:40px 20px;
    text-align:center;
    color:#8fb2dd;
    font-style:italic;
    line-height:1.6;
}

.pl-row{
    display:grid;
    grid-template-columns:28px 58px minmax(0,1fr) 140px 24px;
    align-items:center;
    gap:10px;
    padding:8px 10px;
    border-bottom:1px solid #2a2f38;
}
.pl-row:last-child{border-bottom:0}
.pl-row:hover{background:rgb(255 255 255 / 4%)}

/* Favourites stand out in the review list AND on the sheet - see .pt-fav. */
.pl-row.pl-fav{
    background:rgb(255 210 74 / 10%);
    box-shadow:inset 3px 0 0 #ffd24a;
}

.pl-lg-logo{
    width:24px;
    height:24px;
    object-fit:contain;
}

.pl-when{
    text-align:right;
    font-variant-numeric:tabular-nums;
    line-height:1.2;
}

.pl-date{
    font-size:.78em;
    color:#9dc2f0;
}
.pl-time{font-weight:700}

.pl-match{
    display:flex;
    align-items:center;
    gap:8px;
    min-width:0;
    flex-wrap:wrap;
}

.pl-team{
    display:inline-flex;
    align-items:center;
    gap:6px;
    min-width:0;
}

.pl-team-logo{
    width:22px;
    height:22px;
    object-fit:contain;
    flex-shrink:0;
}

.pl-at{
    color:#8fb2dd;
    font-size:.85em;
}

.pl-nets{
    font-size:.85em;
    color:#9dc2f0;
    text-align:right;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}

.pl-remove{
    cursor:pointer;
    color:#8fb2dd;
    font-size:1.3em;
    line-height:1;
    text-align:center;
    opacity:.6;
    transition:opacity .15s,color .15s;
}

.pl-remove:hover{
    opacity:1;
    color:#ff5f61;
}

@media (width <=768px){
    .pl-row{grid-template-columns:24px 52px minmax(0,1fr) 24px}

    .pl-nets{
    grid-column:2 / 4;
    text-align:left;
}
}

/* Clickable standings row on a TEAM card - matches the league popover's rows. */
.tt-row-click{cursor:pointer}
.tt-row-click:hover{background:rgb(255 255 255 / 10%)}
html.light .tt-row-click:hover{background:rgb(0 0 0 / 6%)}

/* Clickable league emblem on the game scoreboard (not SOCX - see gameTip). */
.sb-league-click{
    cursor:pointer;
    border-radius:8px;
    transition:background .15s;
}
.sb-league-click:hover{background:rgb(255 255 255 / 14%)}

/* CURRENT GAME block on a standalone team card. The row itself is the real
   day-modal row (see _currentGameHtml), so it needs no styling of its own -
   only a tint marking it as the live/contextual item, and a pointer cursor
   since the whole row is a click target here. */

/* No whole-row pointer: like the day row, this has SEPARATE targets - the score
   cell opens the game, each team side opens that team, the league emblem opens
   the league. A row-wide cursor:pointer promised one big button and delivered
   three small ones. */
.tt-current .grid-game-row{
    border-radius:6px;
    transition:background .15s;
}
.tt-current .grid-game-row:hover{background:rgb(255 255 255 / 6%)}
html.light .tt-current .grid-game-row:hover{background:rgb(0 0 0 / 6%)}

/* (shown/total) in the header and the day-modal title. Same counter as the
   calendar cells - see countLabel in js/utils.js. */
.page-count{
    color:#6f7889;
    font-size:.42em;
    font-weight:600;
    margin-left:8px;
    vertical-align:middle;
}
html.light .page-count{color:#8a93a3}

.title-count{
    color:#8a93a3;
    font-size:.7em;
    font-weight:600;
}
html.light .title-count{color:#6f7889}

/* ============================================================
   SECTION COUNTS  (v1.10.2)
   A count on every collapsible header, and a summary strip above the Time View
   sections. The per-section numbers were always there but spread down a long
   page with Completed collapsed by default, so "how much of today is over?"
   meant scrolling and adding up.
   ============================================================ */
.sec-count{
    background:rgb(0 0 0 / 35%);
    border-radius:10px;
    color:#cdd9ec;
    font-size:.78em;
    font-weight:700;
    margin-left:8px;
    padding:1px 8px;
}

html.light .sec-count{
    background:rgb(0 0 0 / 8%);
    color:#334;
}

/* Secondary note (favourites pulled into their own section) - deliberately
   quieter than the count it qualifies. */
.sec-sub{
    color:#8a93a3;
    font-size:.72em;
    font-style:italic;
    font-weight:500;
    margin-left:8px;
}
html.light .sec-sub{color:#697382}

.day-summary-strip{
    display:flex;
    flex-wrap:wrap;
    gap:8px;
    margin:0 0 10px;
    padding:0 2px;
}

.dss-item{
    background:#252b36;
    border:1px solid #333;
    border-radius:12px;
    color:#9aa3b2;
    font-size:.78em;
    padding:3px 11px;
    white-space:nowrap;
}

.dss-item b{
    color:#e7eefc;
    font-weight:800;
    margin-right:3px;
}

html.light .dss-item{
    background:#f2f4f8;
    border-color:#ddd;
    color:#556;
}
html.light .dss-item b{color:#1b2431}

/* State colours match the section headings they summarise, so the strip reads
   as an index of the page rather than as unrelated decoration. */
.dss-live{border-color:#2e7d32}
.dss-live b{color:#66bb6a}
.dss-delayed{border-color:#8d6e00}
.dss-delayed b{color:#e0a800}
.dss-stale{border-color:#6b5324}
.dss-stale b{color:#b0873a}
.dss-fav{border-color:#2e7d32}
.dss-fav b{color:#7fd18a}


/* --- The job queue (ENH00001 Build C) ------------------------------------ */

/* A viewer for what the server is doing. Sits below the backfill controls. */
.adm-queue{
    margin-top:14px;
    border-top:1px solid #2a2f3a;
    padding-top:10px
}

.adm-queue-head{
    display:flex;
    align-items:baseline;
    gap:10px;
    margin-bottom:6px
}

.adm-queue-title{font-weight:600}

.adm-queue-sub{
    font-size:.85em;
    color:#8b93a3
}

.adm-queue-sub.adm-queue-warn{color:#e0a33e}

.adm-queue-row{
    display:flex;
    align-items:center;
    gap:8px;
    padding:3px 0;
    font-size:.9em;
    border-bottom:1px solid #22262f
}

.adm-queue-row:last-child{border-bottom:none}
.adm-queue-running{color:#c9d1e0}

.adm-queue-pos{
    width:1.6em;
    color:#6b7280;
    text-align:right
}

.adm-queue-name{
    flex:1 1 auto;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap
}

.adm-queue-meta{
    color:#8b93a3;
    font-variant-numeric:tabular-nums;
    white-space:nowrap
}

/* BUG00021. How a run came to be queued, beside its name. Dimmer and smaller
   than the job description on purpose: it is the answer to a question you only
   sometimes have, and it must not compete with the name you are scanning for. */

.adm-queue-origin{
    color:#6b7280;
    font-size:.85em;
    margin-left:6px
}

.adm-queue-btn{
    padding:1px 7px;
    font-size:.85em;
    line-height:1.5
}

.adm-queue-badge{
    font-size:.75em;
    letter-spacing:.04em;
    padding:1px 6px;
    border-radius:3px;
    background:#2a2f3a;
    color:#9aa4b5
}

.adm-q-done{
    background:#1e3a2a;
    color:#7fc79b
}

.adm-q-failed{
    background:#3a1e1e;
    color:#d98a8a
}

.adm-q-cancelled{
    background:#3a331e;
    color:#d9c48a
}

.adm-queue-empty{
    color:#6b7280;
    font-size:.88em;
    padding:3px 0
}

.adm-queue-recent{margin-top:6px}

.adm-queue-recent summary{
    cursor:pointer;
    color:#8b93a3;
    font-size:.85em
}

/* --- the Schedule section (ENH00001 Build D) ---------------------------
   Shares .adm-queue-row with the queue above on purpose: they are two views
   of the same thing and reading as one family is the point. Only the parts
   the queue has no equivalent for are defined here. */

.adm-sched-row{gap:6px}

.adm-sched-off .adm-queue-name{
    color:#6b7280;
    text-decoration:line-through
}

.adm-sched-on{
    display:flex;
    align-items:center;
    cursor:pointer
}

.adm-sched-on input{
    margin:0;
    cursor:pointer
}

.adm-sched-due{
    min-width:5.5em;
    text-align:right
}

.adm-sched-interval{
    display:inline-flex;
    align-items:center;
    gap:4px
}

.adm-sched-interval input[type="number"]{
    width:4.2em;
    padding:1px 4px;
    font-size:.9em
}

.adm-sched-interval select{
    padding:1px 4px;
    font-size:.9em
}

/* The optional time-of-day beside the interval (BUG00020). Sized to its own
   content so the schedule rows stay on one line - a time input left to its
   default width pushes the Set button off the end of a narrow panel. */
.adm-sched-at-lbl{
    color:#8b98ab;
    font-size:.82em;
    padding:0 2px;
}

.adm-sched-interval input[type="time"]{
    background:#1b1f27;
    border:1px solid #3a4150;
    border-radius:4px;
    color:#dfe7f3;
    font-size:.85em;
    padding:3px 4px;
    width:6.5em;
}

html.light .adm-sched-interval input[type="time"]{
    background:#fff;
    border-color:#c3cad4;
    color:#1e2733;
}

html.light .adm-sched-at-lbl{color:#5a6675}

.adm-sched-unknown{
    font-size:.78em;
    padding:0 5px;
    border-radius:3px;
    background:#3a331e;
    color:#d9c48a
}

.adm-sched-add{
    display:flex;
    flex-wrap:wrap;
    align-items:flex-end;
    gap:10px;
    padding:6px 0 2px
}

.adm-sched-add label{
    display:flex;
    flex-direction:column;
    gap:3px;
    font-size:.82em;
    color:#8b93a3
}

.adm-sched-note{
    flex:1 1 100%;
    font-size:.85em;
    color:#8b93a3
}

/* Parameter inputs, rendered from the selected kind's own declaration. */
.adm-sched-params{
    display:inline-flex;
    align-items:flex-end;
    gap:10px
}

.adm-cad-link{
    color:#8ab4f8;
    text-decoration:none
}

.adm-cad-link:hover{text-decoration:underline}

html.light .adm-sched-off .adm-queue-name{color:#98a1af}


html.light .adm-sched-add label,
html.light .adm-sched-note{color:#697382}
html.light .adm-cad-link{color:#1a63c7}

/* Application log (ENH00015). Monospace and dense on purpose: this is read
   by scanning for a shape, not by reading sentences, and the whole reason it
   exists is that the Portainer viewer is hard to scan. */
.adm-log-controls{
    display:flex;
    flex-wrap:wrap;
    align-items:flex-end;
    gap:8px;
    margin:8px 0
}

.adm-log-controls label{
    display:flex;
    flex-direction:column;
    gap:3px;
    font-size:.85em;
    color:#8b93a3
}

.adm-log-msg{
    font-size:.8em;
    color:#8b93a3;
    margin-left:auto
}

.adm-log-rows{
    max-height:340px;
    overflow:auto;
    background:#151821;
    border:1px solid #2a2f3a;
    border-radius:4px;
    padding:6px
}

.adm-log-row{
    font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
    font-size:.78em;
    line-height:1.5;
    white-space:pre-wrap;
    overflow-wrap:anywhere;
    padding:2px 4px;
    border-bottom:1px solid #1e222c;
    color:#c3cad6
}

.adm-log-row:last-child{border-bottom:none}
.adm-log-row.lvl-warning{color:#e8c07d}
.adm-log-row.lvl-error{color:#e88b8b}

.adm-log-row.lvl-critical{
    color:#ff6b6b;
    font-weight:600
}
