/* ============================================
   EasyFPL — Sidebar nav + flyout sub-nav + palette
   Scoped entirely to .v2-theme (set on <html> by every page using this
   design) — does not affect any other page sharing common.css.
   ============================================ */

:root {
    --v2-sidebar-w: 232px;
    --v2-sidebar-w-collapsed: 76px;
    --v2-page-title-size: clamp(56px, 7.5vw, 104px);
    --v2-page-title-spacing: -6px;
    --v2-page-gutter: 32px;
    --v2-page-title-top: 40px;
}

/* V2 uses one typeface throughout. This also catches older page-specific and
   dynamically rendered rules that still name Space Grotesk, Georgia, etc. */
html.v2-theme body,
html.v2-theme body * {
    font-family: var(--font-body) !important;
}

/* Keep every tool-page heading on the same grid as the dashboard greeting. */
.v2-theme .v2-main-content > main.main-content,
.v2-theme .v2-main-content > main.content {
    max-width: 1440px !important;
    padding-top: var(--v2-page-title-top) !important;
    padding-right: var(--v2-page-gutter) !important;
    padding-left: var(--v2-page-gutter) !important;
}

/* The 24px under the heading was being supplied by the subtitle that used to
   sit in here. With that gone the first card started at the title's baseline,
   where every other page leaves a gap — .page-header's own margin-bottom. */
.v2-theme .news-page-header {
    max-width: 1440px !important;
    padding: var(--v2-page-title-top) var(--v2-page-gutter) 0 !important;
    margin-bottom: 24px;
}

.v2-theme .v2-page-hint {
    display: flex;
    align-items: center;
    min-height: 36px;
    margin: 0 0 14px;
    padding: 8px 14px;
    border: 1px solid rgba(96, 165, 250, 0.15);
    border-radius: var(--radius-md);
    background: rgba(96, 165, 250, 0.06);
    color: var(--text-secondary);
    font-size: 12px;
    line-height: 1.4;
}

.v2-theme .v2-page-heading {
    font-family: var(--font-display) !important;
    font-size: var(--v2-page-title-size) !important;
    line-height: 0.95 !important;
    font-weight: 600 !important;
    letter-spacing: var(--v2-page-title-spacing) !important;
    color: var(--color-primary-muted) !important;
    opacity: 1;
}

@media (max-width: 768px) {
    :root {
        --v2-page-title-size: clamp(46px, 13vw, 64px);
        --v2-page-gutter: 20px;
        --v2-page-title-top: 28px;
    }
}

/* The page shell owns navigation animation. Disabling the browser snapshot
   transition prevents a second full-page fade from washing over it. */
@view-transition {
    navigation: none;
}

::view-transition-group(root) {
    animation: none;
}

::view-transition-old(root) {
    animation: none;
    mix-blend-mode: normal;
}

::view-transition-new(root) {
    animation: none;
    mix-blend-mode: normal;
}

html.v2-theme-transition::view-transition-old(root) {
    animation: v2-theme-old 620ms cubic-bezier(0.22, 1, 0.36, 1) both;
    mix-blend-mode: normal;
}

html.v2-theme-transition::view-transition-new(root) {
    animation: v2-theme-new 620ms cubic-bezier(0.22, 1, 0.36, 1) both;
    mix-blend-mode: normal;
}

@keyframes v2-theme-old {
    from { opacity: 1; }
    to { opacity: 0; }
}

@keyframes v2-theme-new {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* Reserve the final layout before sidebar-nav.js starts the reveal. This is
   what prevents already-visible content from blinking out and back in. */
.v2-theme body:not(.v2-sequence-ready) .v2-page-heading,
.v2-theme body:not(.v2-sequence-ready) .v2-main-content > .tabs-container,
.v2-theme body:not(.v2-sequence-ready) .v2-main-content > .ticker-bar,
.v2-theme body:not(.v2-sequence-ready) .v2-main-content > .news-strip,
.v2-theme body:not(.v2-sequence-ready) .v2-main-content > .price-ticker-bar,
.v2-theme body:not(.v2-sequence-ready) main.main-content > *:not(.header-row):not(.loading-overlay),
.v2-theme body:not(.v2-sequence-ready) main.content > *:not(.v2-page-heading),
.v2-theme body:not(.v2-sequence-ready) .hero-banner .hero-inner > *,
.v2-theme body:not(.v2-sequence-ready) #newsDisplay {
    opacity: 0;
}

/* Shared staged page entrance. Elements are marked by sidebar-nav.js only
   after the sidebar and the page shell both exist, preventing partial paints. */
.v2-enter-sidebar,
.v2-enter-topbar,
.v2-enter-heading,
.v2-enter-block {
    opacity: 0;
    will-change: opacity;
}

.v2-enter-topbar {
    transform: translateY(-6px);
    will-change: opacity, transform;
}

.v2-sequence-ready .v2-enter-sidebar {
    animation: v2-sidebar-enter 720ms cubic-bezier(0.22, 1, 0.36, 1) 20ms both;
}

.v2-sequence-ready .v2-enter-topbar {
    animation: v2-topbar-enter 760ms cubic-bezier(0.22, 1, 0.36, 1) 180ms both;
}

.v2-sequence-ready .v2-enter-heading {
    animation: v2-content-enter 800ms cubic-bezier(0.22, 1, 0.36, 1) 320ms both;
}

.v2-sequence-ready .v2-enter-block {
    animation: v2-content-enter 860ms cubic-bezier(0.22, 1, 0.36, 1)
        calc(480ms + (var(--v2-enter-order, 0) * 90ms)) both;
}

/* Content arriving from an API joins the sequence at once rather than waiting
   through the shell's initial delay again. */
.v2-sequence-ready .v2-enter-block.v2-enter-late {
    animation-delay: calc(40ms + (var(--v2-enter-order, 0) * 80ms));
}

@keyframes v2-sidebar-enter {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes v2-topbar-enter {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes v2-content-enter {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

/* Older page styles contain their own entrance animations. The shared shell
   replaces them on V2 pages so panels never animate twice. */
.v2-theme .my-team-dashboard-top,
.v2-theme .squad-alerts-panel,
.v2-theme .transfer-rec,
.v2-theme .verdict-section,
.v2-theme .lo-section,
.v2-theme .ts-section,
.v2-theme .na-section,
.v2-theme .so-section,
.v2-theme .ta-section {
    animation: none !important;
}

/* Players and Teams already reserve their final layout with skeleton content.
   Their legacy full-viewport loaders covered that layout during navigation and
   caused the pale/blank flash visible in recordings. */
.v2-theme .v2-main-content > .loading-overlay {
    background: transparent !important;
    backdrop-filter: none !important;
    pointer-events: none !important;
}

@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(root),
    ::view-transition-old(root),
    ::view-transition-new(root) { animation: none; }

    html.v2-theme-transition::view-transition-old(root),
    html.v2-theme-transition::view-transition-new(root) {
        animation: none !important;
    }

    .v2-enter-sidebar,
    .v2-enter-topbar,
    .v2-enter-heading,
    .v2-enter-block {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
}

/* ===== NEW COLOR PALETTE (values only — same variable names as common.css,
   so every existing component picks these up automatically) ===== */
.v2-theme {
    --surface-bg: #EAEAE8;
    --surface-0: #FFFFFF;
    --surface-1: #FFFFFF;
    --surface-2: #F1F1EF;
    --surface-3: #E6E6E3;
    --surface-4: #D3D3D3;

    --color-primary: #10B981;
    --color-primary-hover: #059669;
    --color-primary-muted: rgba(16, 185, 129, 0.10);
    --color-primary-glow: rgba(16, 185, 129, 0.25);
    --color-primary-text: #065F46;

    --text-primary: #100F0F;
    --text-secondary: #636363;
    /* Was #A4A4A4 — 2.49:1 on white, barely half the 4.5:1 WCAG AA needs for
       body text, on the theme that ships by default. Darkened until it clears
       AA on the surfaces it actually sits on (white 5.49, surface-2 4.85,
       page background 4.56). It now sits closer to --text-secondary than a
       'muted' token ideally would; legibility is the better trade.
       Known residual: on --surface-3 (#E6E6E3) this reads 4.39:1, just under
       the 4.5 bar. Going darker would make it indistinguishable from
       --text-secondary (#636363), so the small badges that pair the two are
       left at 4.39 rather than collapsing the hierarchy for 0.11. */
    --text-muted: #696969;

    --border-subtle: #EDEDEB;
    --border-default: transparent;
    --border-emphasis: #E4E4E1;
    --shadow-sm: 0 1px 2px rgba(17, 15, 15, 0.05), 0 1px 3px rgba(17, 15, 15, 0.06);

    /* New secondary accent (maroon) — not in the base palette, used for
       featured/highlight moments (banners, star badges). */
    --color-accent-2: #7A2233;
    --color-accent-2-hover: #631B29;
    --color-accent-2-muted: rgba(122, 34, 51, 0.10);
    --color-accent-2-text: #7A2233;
}

.v2-theme[data-theme="dark"] {
    --surface-bg: #15191F;
    --surface-0: #15191F;
    --surface-1: #1B2027;
    --surface-2: #232A33;
    --surface-3: #2E3742;
    --surface-4: #3A4552;

    --color-primary: #00E57D;
    --color-primary-hover: #2AED97;
    --color-primary-muted: rgba(0, 229, 125, 0.14);
    --color-primary-glow: rgba(0, 229, 125, 0.28);
    --color-primary-text: #00E57D;
    --color-success: #00E57D;
    --color-warning: #FFB000;
    --color-error: #FF4D5A;
    --color-info: #939CAA;

    --text-primary: #F4F5F7;
    --text-secondary: #C5CBD4;
    /* Cleared AA on the base surfaces but fell to 4.35:1 on surface-3 and
       3.52:1 on surface-4, which small badges do use. Lifted to pass on both. */
    --text-muted: #A8B1BF;

    --border-subtle: #20262E;
    --border-default: transparent;
    --border-emphasis: #303944;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);

    --color-accent-2: #C1495F;
    --color-accent-2-hover: #D4738A;
    --color-accent-2-muted: rgba(193, 73, 95, 0.18);
    --color-accent-2-text: #D4738A;
}

/* ===== SIDEBAR SHELL ===== */
.v2-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    height: 100vh;
    width: var(--v2-sidebar-w);
    background: var(--surface-0);
    border-right: 1px solid var(--border-default);
    display: flex;
    flex-direction: column;
    padding: 20px 14px;
    gap: 20px;
    z-index: 50;
    overflow-y: visible;
}

.v2-sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    flex-shrink: 0;
}

.v2-sidebar-logo {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 8px;
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 600;
    color: var(--text-primary);
    text-decoration: none;
    flex-shrink: 0;
}

.v2-sidebar-logo .icon {
    width: 20px;
    height: 20px;
    color: var(--color-primary);
    flex-shrink: 0;
}

.v2-sidebar-logo b {
    color: var(--color-primary);
    font-weight: 600;
}

.v2-sidebar-collapse {
    width: 30px;
    height: 30px;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
    transition: background 180ms ease, color 180ms ease;
}

.v2-sidebar-collapse:hover {
    background: var(--surface-2);
    color: var(--text-primary);
}

.v2-sidebar-collapse .icon {
    width: 17px;
    height: 17px;
}

.v2-sidebar-collapse .v2-expand-icon {
    display: none;
}

/* Width transitions are enabled only for a deliberate toggle click. Keeping
   them off during startup prevents the saved state from widening on load. */
.v2-sidebar-resizing .v2-sidebar {
    transition: width 480ms cubic-bezier(0.22, 1, 0.36, 1),
        padding 480ms cubic-bezier(0.22, 1, 0.36, 1);
}

.v2-sidebar-resizing .v2-main-content {
    transition: margin-left 480ms cubic-bezier(0.22, 1, 0.36, 1);
}

.v2-sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    overflow: visible;
}

.v2-sidebar-group-label {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: 0 10px;
    margin-bottom: 6px;
}

.v2-nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    border-radius: var(--radius-md);
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 13.5px;
    font-weight: 600;
    white-space: nowrap;
    border: none;
    background: none;
    width: 100%;
    text-align: left;
    cursor: pointer;
    font-family: var(--font-body);
    position: relative;
}

.v2-nav-item .icon {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    color: var(--color-primary);
}

.v2-nav-item:hover {
    background: var(--surface-2);
    color: var(--text-primary);
}

.v2-nav-item.active {
    background: var(--color-primary-muted);
    color: var(--color-primary-text);
}

.v2-nav-item.active .icon {
    color: var(--color-primary);
}

.v2-nav-item.active::before {
    content: '';
    position: absolute;
    left: -9px;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 62%;
    border-radius: 0 4px 4px 0;
    background: var(--color-primary);
}

/* ===== FLYOUT SUB-NAV ===== */
.v2-nav-group {
    position: relative;
}

.v2-flyout-toggle {
    margin-left: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    padding: 2px;
    cursor: pointer;
    color: var(--text-muted);
    border-radius: var(--radius-sm);
    flex-shrink: 0;
}

.v2-flyout-toggle .icon {
    width: 14px;
    height: 14px;
    transition: transform 0.15s ease;
}

.v2-nav-group.open .v2-flyout-toggle .icon {
    transform: rotate(90deg);
}

.v2-flyout-toggle:hover {
    background: var(--surface-3);
}

.v2-flyout-panel {
    position: absolute;
    left: calc(100% + 10px);
    top: 0;
    min-width: 480px;
    background: var(--surface-1);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
    padding: 14px;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 4px 20px;
    opacity: 0;
    pointer-events: none;
    transform: translateX(-6px);
    transition: opacity 0.15s ease, transform 0.15s ease;
    z-index: 60;
}

.v2-nav-group.open .v2-flyout-panel {
    opacity: 1;
    pointer-events: auto;
    transform: translateX(0);
}

.v2-flyout-group-title {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: 4px 8px;
}

.v2-flyout-item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px;
    border-radius: var(--radius-md);
    text-decoration: none;
    color: var(--text-primary);
}

.v2-flyout-item:hover {
    background: var(--surface-2);
}

.v2-flyout-icon {
    width: 16px;
    height: 16px;
    color: var(--color-primary);
    flex-shrink: 0;
    margin-top: 1px;
}

.v2-flyout-name {
    display: block;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

.v2-flyout-desc {
    display: block;
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 1px;
}

/* ===== SIDEBAR BOTTOM (team ID + theme toggle) ===== */
.v2-sidebar-bottom {
    margin-top: auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding-top: 14px;
    border-top: 1px solid var(--border-default);
    flex-shrink: 0;
}

.v2-sidebar-team-id #navTidInput {
    padding: 0 2px;
}

.v2-tid-form {
    display: flex;
    gap: 6px;
}

.v2-tid-form input {
    flex: 1;
    min-width: 0;
    padding: 7px 10px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-default);
    background: var(--surface-2);
    color: var(--text-primary);
    font-size: 12px;
}

.v2-sidebar-team-id #navTidBadge {
    padding: 0 2px;
}

.v2-sidebar-team-id .nav-tid-badge {
    width: 100%;
    justify-content: space-between;
}

.v2-theme-switch {
    width: 100%;
    height: 38px;
    padding: 4px;
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: 3px;
    border: 1px solid var(--border-emphasis);
    border-radius: var(--radius-full);
    background: var(--surface-2);
    color: var(--text-muted);
    cursor: pointer;
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.04);
    position: relative;
    overflow: hidden;
}

.v2-theme-switch::before {
    content: '';
    position: absolute;
    top: 4px;
    left: 4px;
    width: calc((100% - 11px) / 2);
    height: 28px;
    border-radius: var(--radius-full);
    background: var(--surface-0);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
    transform: translateX(calc(100% + 3px));
    transition: transform 420ms cubic-bezier(0.22, 1, 0.36, 1),
        background-color 260ms ease, box-shadow 260ms ease;
}

[data-theme="dark"] .v2-theme-switch::before {
    transform: translateX(0);
    background: #343D49;
    box-shadow: 0 1px 5px rgba(0, 0, 0, 0.35);
}

.v2-theme-option {
    height: 28px;
    border-radius: var(--radius-full);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: color 260ms ease, background 260ms ease, box-shadow 260ms ease;
    position: relative;
    z-index: 1;
}

.v2-theme-option .icon {
    width: 15px;
    height: 15px;
}

html:not([data-theme="dark"]) .v2-theme-light,
[data-theme="dark"] .v2-theme-dark {
    color: var(--text-primary);
}

[data-theme="dark"] .v2-theme-switch {
    background: #202730;
    border-color: #343E4A;
}

[data-theme="dark"] .v2-theme-dark {
    color: var(--color-primary);
}

/* ===== MAIN CONTENT OFFSET ===== */
html.v2-theme body {
    background: var(--surface-0);
}

.v2-main-content {
    margin-left: var(--v2-sidebar-w);
    min-height: 100vh;
    background: linear-gradient(160deg, #DDEFE4 0%, #F1FAF5 48%, #FFFFFF 100%);
    background-clip: padding-box;
}
[data-theme="dark"] .v2-main-content {
    background: linear-gradient(160deg, #15191F 0%, #17201D 52%, #18241F 100%);
}

/* The shell used to be a rounded card with a 32px curve down its left edge,
   and the first marquee or tab strip inside it had to be given the same curve
   so it did not paint a square corner over one. It made the top-left of every
   dashboard page a notch — one rounded corner on a page that is otherwise all
   square edges, and the only place the gradient behind showed through. Square
   now, and there is nothing for a child to match. */

/* User-controlled desktop icon rail. */
.v2-sidebar-collapsed .v2-sidebar {
    width: var(--v2-sidebar-w-collapsed);
    padding: 20px 10px;
    align-items: center;
}

.v2-sidebar-collapsed .v2-sidebar-header {
    width: 100%;
    justify-content: center;
    gap: 2px;
}

.v2-sidebar-collapsed .v2-sidebar-logo {
    padding: 0;
}

.v2-sidebar-collapsed .v2-sidebar-logo span,
.v2-sidebar-collapsed .v2-nav-item > span,
.v2-sidebar-collapsed .v2-sidebar-group-label,
.v2-sidebar-collapsed .v2-sidebar-team-id {
    display: none;
}

.v2-sidebar-collapsed .v2-sidebar-bottom {
    width: 52px;
}

.v2-sidebar-collapsed .v2-theme-switch {
    height: 34px;
    padding: 3px;
    gap: 2px;
}

.v2-sidebar-collapsed .v2-theme-option {
    height: 26px;
}

.v2-sidebar-collapsed .v2-theme-switch::before {
    top: 3px;
    left: 3px;
    width: calc((100% - 8px) / 2);
    height: 26px;
    transform: translateX(calc(100% + 2px));
}

[data-theme="dark"].v2-sidebar-collapsed .v2-theme-switch::before {
    transform: translateX(0);
}

.v2-sidebar-collapsed .v2-theme-option .icon {
    width: 13px;
    height: 13px;
}

.v2-sidebar-collapsed .v2-nav-item {
    justify-content: center;
    padding: 10px;
    width: 44px;
}

.v2-sidebar-collapsed .v2-flyout-toggle {
    display: none;
}

.v2-sidebar-collapsed .v2-sidebar-collapse .v2-collapse-icon {
    display: none;
}

.v2-sidebar-collapsed .v2-sidebar-collapse .v2-expand-icon {
    display: block;
}

.v2-sidebar-collapsed .v2-main-content {
    margin-left: var(--v2-sidebar-w-collapsed);
}

/* ===== LIGHT CARD-AESTHETIC BOOST (scoped, doesn't touch other pages) ===== */
.v2-main-content .hss-card,
.v2-main-content .hero-squad-panel,
.v2-main-content .hero-deadline-banner,
.v2-main-content .rec-card,
.v2-main-content .route-card,
.v2-main-content .chart-card,
.v2-main-content .stats-container,
.v2-main-content .teams-grid > * {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
    border-radius: var(--radius-xl);
}

[data-theme="dark"] .v2-main-content .hss-card,
[data-theme="dark"] .v2-main-content .hero-squad-panel,
[data-theme="dark"] .v2-main-content .hero-deadline-banner,
[data-theme="dark"] .v2-main-content .rec-card,
[data-theme="dark"] .v2-main-content .route-card,
[data-theme="dark"] .v2-main-content .chart-card,
[data-theme="dark"] .v2-main-content .stats-container {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

/* ===== RESPONSIVE: icon-only rail on narrow screens ===== */
@media (max-width: 900px) {
    .v2-sidebar-collapse {
        display: none;
    }

    .v2-sidebar {
        width: var(--v2-sidebar-w-collapsed);
        padding: 20px 10px;
        align-items: center;
    }

    .v2-sidebar-logo span,
    .v2-nav-item span,
    .v2-sidebar-group-label {
        display: none;
    }

    .v2-nav-item {
        justify-content: center;
        padding: 10px;
        width: 44px;
    }

    .v2-flyout-toggle {
        display: none;
    }

    .v2-nav-group:hover .v2-flyout-panel {
        opacity: 1;
        pointer-events: auto;
        transform: translateX(0);
    }

    .v2-main-content {
        margin-left: var(--v2-sidebar-w-collapsed);
    }

    /* Team ID widget stays usable in collapsed mode — stacked, full-width
       within the narrow rail, instead of being hidden with no alternative. */
    .v2-tid-form {
        flex-direction: column;
    }

    .v2-tid-form input {
        width: 56px;
        font-size: 10px;
        padding: 5px 6px;
        text-align: center;
    }

    .v2-tid-form .btn {
        padding: 5px 6px;
        font-size: 11px;
    }

    .v2-sidebar-team-id .nav-tid-badge {
        flex-direction: column;
        align-items: center;
        gap: 2px;
        padding: 6px 4px;
        font-size: 9px;
    }
}

/* ===== STICKY-OFFSET FIX =====
   Several shared/page components are position:sticky with a hardcoded
   top offset sized to clear the old 56px .top-nav bar (e.g. tabs-container
   at top:56px, filter-bar at top:91px = 56 + tabs-container's own height).
   The sidebar layout has no top bar, so every one of these offsets is
   subtracted by exactly 56px here — preserving how they stack relative
   to each other, just removing the space that used to be reserved for
   the nav that no longer exists in this layout. */
.v2-main-content .tabs-container {
    top: 0;
}

.v2-main-content .tabs-container.tabs-hidden ~ .filter-bar {
    top: 0;
}

.v2-main-content .filter-bar {
    top: 35px; /* was 91px (56px nav + 35px tabs-container height) */
}

.v2-main-content .tw-budget-bar-top {
    top: 0;
}

.v2-main-content .tw-scout-col {
    top: 64px; /* was 120px (56px nav + 64px budget bar) */
}

/* ===== Touch targets =====
   Measured at a 500px viewport: seven classes of control rendered under the
   44px minimum, the worst being icon buttons at 18x18 and 22x15. Rather than
   inflate them visually, an ::after overlay extends the hit area beyond the
   painted box — the control looks identical and the thumb gets a real target.
   Pointer-coarse only, so mouse layouts are untouched. */
@media (pointer: coarse), (max-width: 767px) {
    .nav-tid-change,
    .v2-theme-switch,
    .footer-mail,
    .footer-links a { position: relative; }

    .nav-tid-change::after,
    .v2-theme-switch::after,
    .footer-mail::after,
    .footer-links a::after {
        content: ''; position: absolute; left: 50%; top: 50%;
        transform: translate(-50%, -50%);
        width: 100%; height: 44px; min-width: 44px;
    }

    .v2-nav-item { min-height: 44px; }
}

/* ============================================================
   CLEAN SURFACE PASS

   The dashboard had accumulated three habits that read as noise rather
   than information: a green wash behind every page, page titles at 104px
   in 10%-opacity green (a decorative ghost, not a heading), and cards that
   each announced themselves with a different coloured edge.

   The fix is to spend contrast where it carries meaning. The page ground
   goes flat and neutral so a white card is legible as a card; headings go
   solid and small so they read as labels; the accent green is reserved for
   state that matters — the active nav item, a sorted column, a positive
   number. Nothing here changes what any colour *means*: FDR scales,
   position colours and verdict pills are untouched.

   Everything is scoped to .v2-main-content or .v2-theme, so the one page
   that is not a dashboard — the logged-out landing on index.html — keeps
   its own look via the explicit exception below.
   ============================================================ */

:root {
    /* The ground a card sits on. Neutral, not tinted: a green wash under a
       white card leaves too little separation to see the card's edge. */
    --v2-ground: #F5F6F8;
    --v2-card-border: rgba(17, 24, 39, 0.07);
    --v2-card-radius: 16px;
    /* Two shadows doing separate jobs: a 1px contact shadow that defines the
       edge, and a wide, very soft ambient one that lifts the card off the
       ground without a visible grey halo. */
    /* Softened, and now the site's only shadow.

       Panels were carrying one of two: this one, and --shadow-sm, which is a
       harder, closer pair. So some sections sat on a wide soft lift, some on a
       tight dark one, and some — where a rule had been written without either
       — on nothing at all. Three depths on one page reads as a mistake even
       when you cannot name it.

       The value is the one --shadow-sm already carried: a tight double pair,
       close to the edge. --v2-card-shadow is defined as it rather than the
       other way round, so both names resolve to the same pixels and the
       fifteen rules that ask for --shadow-sm need no edit. */
    --v2-card-shadow: 0 1px 2px rgba(17, 15, 15, 0.05),
                      0 1px 3px rgba(17, 15, 15, 0.06);
    --shadow-sm: var(--v2-card-shadow);
}

[data-theme="dark"] {
    --v2-ground: #12161B;
    --v2-card-border: rgba(255, 255, 255, 0.07);
    --v2-card-shadow: 0 1px 2px rgba(0, 0, 0, 0.4),
                      0 1px 3px rgba(0, 0, 0, 0.3);
    --shadow-sm: var(--v2-card-shadow);
}

/* ----- Page ground ----- */

.v2-main-content {
    background: var(--v2-ground);
}

[data-theme="dark"] .v2-main-content {
    background: var(--v2-ground);
}

/* The logged-out landing is not a dashboard page and is out of scope for
   this pass. It is the only place a .hero-banner appears without
   .hero-logged-in, so that absence identifies it without a new flag for
   index.html's state toggle to keep in sync. */
.v2-main-content:has(.hero-banner:not(.hero-logged-in)) {
    background: linear-gradient(160deg, #DDEFE4 0%, #F1FAF5 48%, #FFFFFF 100%);
}

[data-theme="dark"] .v2-main-content:has(.hero-banner:not(.hero-logged-in)) {
    background: linear-gradient(160deg, #15191F 0%, #17201D 52%, #18241F 100%);
}

/* ----- Headings -----
   The old title was clamp(56px, 7.5vw, 104px) in --color-primary-muted,
   which is green at 10% alpha — a watermark you read past rather than
   with. At 32px solid it is a heading again, and the ~70px of vertical
   space it gives back is the single largest source of the reference
   layouts' calm. */
:root {
    --v2-page-title-size: clamp(26px, 2.4vw, 32px);
    /* In em rather than px, so the tracking stays proportional when the
       title drops to 24px on a phone instead of biting twice as hard. */
    --v2-page-title-spacing: -0.022em;
    --v2-page-title-top: 32px;
}

@media (max-width: 768px) {
    :root {
        --v2-page-title-size: 24px;
        --v2-page-title-top: 24px;
    }
}

/* One weight for every page title.

   Every page already computed 650, so they were not disagreeing in the
   stylesheet — but 650 is not a weight Inter ships. The browser picks the
   nearest cut it has and synthesises the rest, and how much it synthesises
   depends on which cuts a given page has actually finished loading, which
   is why two identical rules could still look like two different weights.
   600 is a real cut, so it renders as itself everywhere. */
.v2-theme .v2-page-heading {
    line-height: 1.25 !important;
    font-weight: 600 !important;
    color: var(--text-primary) !important;
}

/* Lucide icons in a heading were sized against the old 104px title. */
.v2-theme .v2-page-heading .icon,
.v2-theme .v2-page-heading [data-lucide] {
    width: 22px;
    height: 22px;
    vertical-align: -3px;
    color: var(--color-primary);
}

/* Section headings inside a page: one step down from the page title, and
   the same size wherever they appear. Several pages had these at 22-28px,
   close enough to the page title to compete with it. */
.v2-main-content main h2,
.v2-main-content .section-title,
.v2-main-content .card-title {
    font-size: 17px;
    font-weight: 650;
    letter-spacing: -0.2px;
    line-height: 1.35;
    color: var(--text-primary);
}

/* ----- Cards -----
   One surface treatment, applied to the containers that were already
   carrying a card-like look with slightly different values each. */
.v2-main-content .hss-card,
.v2-main-content .hero-squad-panel,
.v2-main-content .hero-deadline-banner,
.v2-main-content .rec-card,
.v2-main-content .rec-card-v2,
.v2-main-content .route-card,
.v2-main-content .chart-card,
.v2-main-content .stats-container,
.v2-main-content .soft-card,
.v2-main-content .pp-card,
.v2-main-content .price-card,
.v2-main-content .rising-card,
.v2-main-content .swing-card,
.v2-main-content .tm-summary-card,
.v2-main-content .fx-split-card,
.v2-main-content .teams-grid > * {
    background: var(--surface-1);
    border: 1px solid var(--v2-card-border);
    border-radius: var(--v2-card-radius);
    box-shadow: var(--v2-card-shadow);
}

/* ----- Tables -----
   The bones were already right — 14px padding, small caps headers. What
   made them look busy was a filled grey header band and a 2px rule under
   it. A flat header on the card surface, one hairline, and a tinted hover
   row is enough structure to track a row across twenty columns. */
.v2-main-content .data-table thead th,
.v2-main-content table:not(.matrix-table) thead th {
    background: var(--surface-1);
    border-bottom: 1px solid var(--border-emphasis);
    color: var(--text-muted);
    font-size: 10.5px;
    letter-spacing: 0.6px;
    padding: 13px 16px;
}

.v2-main-content .data-table thead th:hover,
.v2-main-content table:not(.matrix-table) thead th:hover {
    background: var(--surface-2);
    color: var(--text-primary);
}

.v2-main-content .data-table td,
.v2-main-content table:not(.matrix-table) td {
    border-bottom: 1px solid var(--border-subtle);
}

/* The hover tint is the accent at 5% rather than a grey step: it reads as
   "this row is live" instead of "this row is disabled". */
.v2-main-content .data-table tbody tr:hover,
.v2-main-content table:not(.matrix-table) tbody tr:hover {
    background: color-mix(in srgb, var(--color-primary) 5%, transparent);
}

.v2-main-content .data-table tbody tr:hover td.col-player {
    background: color-mix(in srgb, var(--color-primary) 5%, var(--surface-1));
}

/* The frozen identity column sat on --surface-2, a visibly different grey
   from the rows it belongs to. */
.v2-main-content .data-table th.col-player {
    background: var(--surface-1);
}

/* The last row's hairline doubles up with the card edge below it. */
.v2-main-content .data-table tbody tr:last-child td,
.v2-main-content table:not(.matrix-table) tbody tr:last-child td {
    border-bottom: none;
}

/* ============================================================
   DASHBOARD FOOTER

   The four-column footer is a landing-page component: it exists to
   introduce the site to someone who has just arrived. Inside the dashboard
   it earns none of that height. The Tools column is a second copy of the
   sidebar the manager is already looking at, and the brand block introduces
   a product they are demonstrably already using. Three things survive
   because they still do work anywhere: where the data comes from, the two
   link groups that are *not* in the sidebar, and the legal + freshness line.

   It also stops being a dark slab. On a light dashboard #111827 was the
   heaviest element on the page and it sat under content it had nothing to
   do with; a hairline and the page ground put it in the same design as
   everything above it.

   Scoped away from the logged-out landing on index.html by the same
   hero-banner test used for the page ground above, so that page keeps the
   full footer it was designed with. Every rule carries the same prefix
   rather than being undone afterwards, so there is one description of the
   dashboard footer rather than two that have to agree.
   ============================================================ */

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .site-footer {
    background: transparent;
    /* No rule across the top. The footer already separates itself by sitting
       on the page ground below the last panel, and a full-width hairline under
       a row of cards reads as the start of something rather than the end. */
    border-top: none;
    color: var(--text-muted);
    margin-top: 36px;
    /* loadFooter() appends to <body>, outside .v2-main-content, so the
       footer does not inherit the main column's offset and would otherwise
       run underneath the fixed sidebar. */
    margin-left: var(--v2-sidebar-w);
}

.v2-sidebar-collapsed .site-footer {
    margin-left: var(--v2-sidebar-w-collapsed);
}

/* One row instead of a grid: badge on the left, link groups trailing right. */
.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-top {
    max-width: 1440px;
    padding: 16px var(--v2-page-gutter);
    display: flex;
    align-items: center;
    gap: 12px 28px;
    flex-wrap: wrap;
}

/* The Learn/Company groups run inline — title, then its links as a row. */
.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-col {
    display: flex;
    align-items: center;
    gap: 8px 14px;
    flex-wrap: wrap;
    margin: 0;
}

/* After .footer-col, not before: the two carry equal specificity, so the
   one that hides has to be the one the cascade reaches last. */
.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-col--tools,
.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-brand-name,
.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-tagline {
    display: none;
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-col--learn {
    margin-left: auto;
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-col-title {
    margin: 0;
    font-size: 10px;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    opacity: 0.75;
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-links {
    display: flex;
    /* common.css stacks these into a column for the tall landing footer. */
    flex-direction: row;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin: 0;
    list-style: none;
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-links li {
    margin: 0;
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-links a,
.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-mail {
    font-size: 12px;
    color: var(--text-secondary);
    margin: 0;
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-links a:hover,
.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-mail:hover {
    color: var(--color-primary);
}

/* The API badge keeps its pill, at the size of the row it now sits in. */
.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-api-badge {
    margin: 0;
    padding: 5px 12px;
    font-size: 11.5px;
    color: var(--color-primary-text);
    background: color-mix(in srgb, var(--color-primary) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-primary) 20%, transparent);
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-bottom {
    max-width: 1440px;
    padding: 12px var(--v2-page-gutter) 16px;
    border-top: 1px solid var(--border-subtle);
    font-size: 11.5px;
    color: var(--text-muted);
}

@media (max-width: 900px) {
    .v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .site-footer {
        margin-left: var(--v2-sidebar-w-collapsed);
    }

    .v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-col--learn {
        margin-left: 0;
    }
}

/* ----- Footer: telling the categories from the links -----
   Inline, the group labels scanned as more links: "FAQ COMPANY Contact Us"
   read as one run. Three things separate them now — the labels are smaller,
   tracked wider and lower in contrast; the gap inside a group is tighter
   than the gap between groups; and a rule sits between the two groups so
   the boundary is drawn rather than implied.

   The email stops being a link with an icon stuck to it and becomes the
   pill it always was in intent — which also balances the row, since the
   API badge is the same shape at the other end of it. */

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-col-title {
    font-size: 9.5px;
    font-weight: 700;
    /* common.css tracks everything matching [class*="title"] to -0.5px with
       !important. That rule is aimed at headings; a small-caps category label
       is the one place on the page that needs tracking to open up rather than
       tighten, and negative tracking is exactly what made these read as links.
       The original 1.5px in common.css was being overridden the same way. */
    letter-spacing: 0.12em !important;
    opacity: 0.55;
}

/* Tighter within a group than between groups: 12px against the row's 26px. */
.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-col {
    gap: 8px 12px;
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-links {
    gap: 12px;
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-col--company {
    border-left: 1px solid var(--border-emphasis);
    padding-left: 26px;
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-mail {
    margin: 0 0 0 6px;
    padding: 5px 12px;
    border: 1px solid var(--border-emphasis);
    border-radius: var(--radius-full);
    background: var(--surface-1);
    color: var(--text-secondary);
    transition: border-color 160ms ease, color 160ms ease;
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-mail:hover {
    border-color: color-mix(in srgb, var(--color-primary) 40%, transparent);
    color: var(--color-primary);
}

.v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-mail .icon {
    width: 13px;
    height: 13px;
    opacity: 0.7;
}

/* The divider only makes sense while the groups sit side by side. */
@media (max-width: 900px) {
    .v2-theme body:not(:has(.hero-banner:not(.hero-logged-in))) .footer-col--company {
        border-left: none;
        padding-left: 0;
    }
}

/* ----- Section icons -----
   One small outline mark in front of each panel heading. The set is drawn in
   v2Icon() in common.js; this is only how it sits and how big it is.

   stroke-width is set here rather than left to each source, because these
   arrive two ways — inline from v2Icon() on panels that re-render, and from
   lucide on the static ones — and lucide's own default is 2. Normalising it
   in CSS is what keeps a heading rendered by JS and one written in HTML from
   drifting a quarter-pixel apart. */
.v2-main-content :is(.md-title, .mk-title, .eo-title, .v2-pitch-title, .v2-feed-title) {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.v2-sec-icon,
.v2-main-content :is(.md-title, .mk-title, .eo-title, .v2-pitch-title, .v2-feed-title) > svg {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    stroke-width: 1.8;
    /* The accent carries "this is a section", the same job the emoji does in
       the reference. It is the one place green appears without meaning good. */
    color: var(--color-primary);
}

/* ----- Top bars: grow into place instead of appearing under the cursor -----
   #tickerBar, #newsStrip and #priceTickerBar each start .hidden and drop that
   class independently, whenever their own data lands. Every one of them is
   display:none until that moment, so each arrival shoved the whole page down
   by its own height — three separate jolts of 30-32px, arriving over about a
   second, which is most of what reads as the dashboard loading "glitchy".

   Reserving the space up front would trade the jolt for up to ~94px of empty
   strip on a load where a bar never populates. Animating the height costs
   nothing in that case — a bar that never arrives stays at zero — and turns
   the ones that do arrive into a movement the eye can follow rather than a
   snap it can only notice after the fact. */
.v2-main-content > :is(.ticker-bar, .news-strip, .price-ticker-bar) {
    transition: height 300ms cubic-bezier(0.22, 1, 0.36, 1),
                opacity 300ms ease;
    will-change: height;
}

.v2-main-content > :is(.ticker-bar, .news-strip, .price-ticker-bar).hidden {
    /* .hidden is display:none !important in common.css — there is no way to
       animate out of that, so these three opt out of it and collapse instead. */
    display: flex !important;
    height: 0 !important;
    min-height: 0 !important;
    padding-top: 0;
    padding-bottom: 0;
    border-bottom-width: 0;
    opacity: 0;
    overflow: hidden;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .v2-main-content > :is(.ticker-bar, .news-strip, .price-ticker-bar) {
        transition: none;
    }
}

/* ============================================================
   PLAYER IDENTITY — face, badge, position edge

   One set of marks, used by the dashboard pitch, the squad pitch, the draft
   planner, the lineup wizard and both transfer views. Drawn by v2IdentityHTML()
   in common.js.
   ============================================================ */

/* Two sizes are driven from here rather than being restated at every call
   site: a row wants the mark small and beside the name, a pitch card wants the
   face to be the card. Contexts override the two variables, nothing else. */
.v2-pid {
    --v2-pid-face: 30px;
    --v2-pid-crest: 18px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
}

.v2-pid-avatar {
    position: relative;
    width: var(--v2-pid-face); height: var(--v2-pid-face);
    border-radius: 50%;
    background: rgba(15, 23, 42, 0.06);
    overflow: hidden;
    flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
}

[data-theme="dark"] .v2-pid-avatar { background: rgba(255, 255, 255, 0.07); }

.v2-pid-initials {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted);
}

/* The club photos are cut-outs on transparency framed head-and-shoulders, so
   the circle crops high rather than centring on the chest. */
.v2-pid-face {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: 50% 12%;
}

/* Only ever seen when no photo arrives — see .has-photo, set on load. */
.v2-pid-avatar.has-photo .v2-pid-initials { display: none; }

.v2-pid-crest {
    position: relative;
    width: var(--v2-pid-crest); height: var(--v2-pid-crest);
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
}

.v2-pid-crest img {
    position: relative; z-index: 1;
    width: 100%; height: 100%;
    object-fit: contain;
}

.v2-pid-crest-fallback {
    position: absolute; z-index: 0;
    font-size: 7.5px; font-weight: 700;
    color: var(--text-muted);
}

/* ===== The pitch form =====
   Face and club badge side by side, both larger than a row's. The portrait
   form below hangs the crest off the face's corner and puts the score on the
   other one, which reads well but leaves the number small and half over a
   photo — on a pitch the two figures you scan are the projection and the score,
   and they had become the least legible things on the card. Here the pair is
   the identity and nothing else, and the number gets a line of its own beneath
   at a size worth reading. */
.v2-pid-pitch {
    --v2-pid-face: 38px;
    --v2-pid-crest: 24px;
    gap: 6px;
    align-self: center;
}
.v2-pid-pitch .v2-pid-avatar {
    background: rgba(15, 23, 42, 0.07);
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.9), 0 1px 4px rgba(0, 0, 0, 0.16);
}
.v2-pid-pitch .v2-pid-initials { font-size: 13px; }

/* ===== The portrait form =====
   On a pitch card the face is the subject, not a bullet beside the name — so
   the mark grows and the crest stops taking half the row: it becomes a small
   disc overlapping the portrait's lower-right, the way a club badge sits on a
   shirt. The card gets its whole width back for the face and the name, and
   "who, and for whom" is still one glance.

   Applied by context, since the markup is the same v2IdentityHTML() everywhere.
   The initials underneath are unchanged and still carry the no-photo case. */
.v2-pid-portrait {
    --v2-pid-face: 46px;
    --v2-pid-crest: 21px;
    position: relative;
    display: block;
    /* Width plus a square ratio rather than width and height, so --v2-pid-face
       may be a percentage: the dashboard's cards are a percentage of the pitch
       and the face has to track them, or a tablet gets a 44px head on a 64px
       card. */
    width: var(--v2-pid-face);
    aspect-ratio: 1;
    margin: 0 auto;
}
.v2-pid-portrait .v2-pid-avatar {
    width: 100%; height: 100%;
    background: rgba(15, 23, 42, 0.07);
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.9), 0 2px 5px rgba(0, 0, 0, 0.18);
}
.v2-pid-portrait .v2-pid-initials { font-size: 14px; }
.v2-pid-portrait .v2-pid-crest {
    position: absolute;
    right: calc(var(--v2-pid-crest) * -0.19);
    bottom: calc(var(--v2-pid-crest) * -0.09);
    z-index: 2;
    border-radius: 50%;
    background: #fff;
    padding: 2px;
    box-sizing: content-box;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.28);
}
.v2-pid-portrait .v2-pid-crest-fallback { font-size: calc(var(--v2-pid-crest) * 0.42); }

/* The other corner. A pitch card has one number worth scanning — what this
   player is projected to score, or what he actually scored — and below the
   name it was competing with the fixture for a line neither of them fitted on.
   As a pill on the portrait's lower-left it mirrors the crest, reads at a
   glance across a whole XI, and gives the row back. Cards opt in by putting
   their points element inside .v2-pid-portrait. */
.v2-pid-portrait .v2-pid-num {
    position: absolute;
    left: -5px;
    bottom: -2px;
    z-index: 2;
    display: inline-flex; align-items: baseline; gap: 1px;
    padding: 1px 5px;
    border-radius: 999px;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.28);
    font-family: var(--font-mono, monospace);
    font-size: 10px;
    font-weight: 800; line-height: 1.4;
    color: #0F172A;
    white-space: nowrap;
}
.v2-pid-portrait .v2-pid-num .u {
    font-family: var(--font-body, inherit);
    font-size: 0.62em; font-weight: 700;
    text-transform: uppercase; letter-spacing: .02em;
    opacity: .62;
}

/* ----- Position as an edge, not a label -----
   GK/DEF/MID/FWD as text costs a column on every row and repeats what a
   colour can say in three pixels. The colours are the site's existing
   --position-* tokens, so the edge, the pitch and the charts agree. */
.v2-pos-edge {
    position: relative;
}

/* Wide enough to hold the position's initial, so the edge names the position
   as well as colouring it. A 3px stripe asked you to have learnt the palette;
   a letter does not, and it costs far less room than the GK/DEF/MID/FWD pill
   this replaced. The letter is set through content on the pseudo-element, so
   no row markup has to carry it. */
.v2-pos-edge::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md) 0 0 var(--radius-md);
    background: var(--v2-pos-color, var(--position-mid));
    color: #FFFFFF;
    font-size: 10px;
    font-weight: 800;
    line-height: 1;
    letter-spacing: 0;
}

.v2-pos-edge.pos-gk  { --v2-pos-color: var(--position-gk); }
.v2-pos-edge.pos-def { --v2-pos-color: var(--position-def); }
.v2-pos-edge.pos-mid { --v2-pos-color: var(--position-mid); }
.v2-pos-edge.pos-fwd { --v2-pos-color: var(--position-fwd); }

.v2-pos-edge.pos-gk::before  { content: 'G'; }
.v2-pos-edge.pos-def::before { content: 'D'; }
.v2-pos-edge.pos-mid::before { content: 'M'; }
.v2-pos-edge.pos-fwd::before { content: 'F'; }

/* A pseudo-element's text is not dependable for a screen reader, so the row's
   own tooltip and its player detail still carry the position in words. */

/* ----- Fixture difficulty, one ramp everywhere -----
   The same five steps the squad table uses: dark green, light green, grey,
   orange, dark red. It moves in lightness as well as hue, so it survives
   being printed in black and white, and the two ends — the ones that change
   a decision — are the two darkest chips in any row. */
/* The literals moved to --fdr-* in styles/common.css, which is now the only
   place the ramp is written down. */
.v2-fdr-1 { background: var(--fdr-1) !important; color: var(--fdr-1-ink) !important; }
.v2-fdr-2 { background: var(--fdr-2) !important; color: var(--fdr-2-ink) !important; }
.v2-fdr-3 { background: var(--fdr-3) !important; color: var(--fdr-3-ink) !important; }
.v2-fdr-4 { background: var(--fdr-4) !important; color: var(--fdr-4-ink) !important; }
.v2-fdr-5 { background: var(--fdr-5) !important; color: var(--fdr-5-ink) !important; }

[data-theme="dark"] .v2-fdr-2 { background: #4ADE80 !important; color: #08240F !important; }
[data-theme="dark"] .v2-fdr-3 { background: #3A424D !important; color: #D5DAE2 !important; }

/* ----- A section is a box -----
   Applied by v2WrapSections() in common.js, which wraps each .section-header
   and everything under it up to the next one. Same surface, border and radius
   as the panels the rest of the site draws, so a group of cards reads as one
   thing rather than as cards that happen to be near each other. */
.v2-section {
    padding: 16px;
    margin-bottom: 20px;
    background: var(--surface-1);
    border: 1px solid var(--v2-card-border, var(--border-emphasis));
    border-radius: var(--v2-card-radius, 16px);
    box-shadow: var(--v2-card-shadow, none);
}

/* Inside a box, a rule under the heading and a border around the box are two
   lines doing one job. */
.v2-section > .section-header {
    border-bottom: none;
    padding-bottom: 0;
    margin-bottom: 6px;
}
.v2-section > .section-header h2 svg,
.v2-section > .section-header h2 i {
    color: var(--color-primary);
    flex-shrink: 0;
}
.v2-section > .section-desc { margin-bottom: 14px; }
.v2-section > :last-child { margin-bottom: 0; }

/* Cards sit on the section, so they take the next surface up rather than the
   same one — otherwise a card on a panel of the same colour is invisible. */
.v2-section .stat-card,
.v2-section .strength-card,
.v2-section .rival-card,
.v2-section .insight-card { background: var(--surface-2); }


/* ===== The player hero =====

   A player's name over his club's colour, with the portrait standing on the
   bottom edge and the crest beside the club name. It was written for the squad
   analysis modal and lived in my-team.css, which meant it was reachable from
   one page — so every other player card on the site went its own way and none
   of them looked like this one.

   Moved here unchanged so the players page can use the same thing for its
   modal and its cards. --club is the shirt colour and --club-ink something
   legible on top of it; both come from clubColours() in common.js.
   ===================================================================== */
.pdm-hero {
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: end;
    gap: 0 22px;
    min-height: 176px;
    padding: 0 26px;
    background: var(--club, #37003C);
    color: var(--club-ink, #fff);
    overflow: hidden;
    flex-shrink: 0;
}
.pdm-hero-shape {
    position: absolute; inset: 0; pointer-events: none;
    background:
        linear-gradient(108deg, rgba(255, 255, 255, .10) 0 32%, transparent 32.4% 44%,
                        rgba(255, 255, 255, .07) 44.4% 61%, transparent 61.4%),
        radial-gradient(120% 150% at 88% 0%, rgba(255, 255, 255, .16), transparent 62%),
        linear-gradient(180deg, transparent 55%, rgba(0, 0, 0, .22));
}
.pdm-hero-photo {
    position: relative; z-index: 1;
    align-self: end; height: 176px; width: 178px;
    display: flex; align-items: flex-end; justify-content: center;
}
/* The portrait fails for a player the photo endpoint has never had — the
   <img> removes itself — and a 178px hole where a face was is worse than no
   face at all, so the column collapses with it. */
.pdm-hero-photo:empty { width: 0; }
/* A fixed box, and the photo fitted inside it.
 *
 * It was `height: 176px; width: auto`, which sizes the element from the
 * image's own proportions — and the images are not one shape. The current
 * library is 250x250; the fallback that catches everyone it has not reshot is
 * 110x140, a much taller crop. So a player served from the fallback rendered
 * 176px tall and only 138px wide, standing visibly taller and narrower than
 * the square-cropped player beside him. Gibbs-White is not that tall.
 *
 * With the box fixed and object-fit doing the fitting, both crops occupy the
 * same space and neither is stretched: the shorter one is letterboxed rather
 * than blown up. */
.pdm-hero-face {
    height: 176px; width: 100%; max-width: 178px;
    object-fit: contain; object-position: bottom center;
    filter: drop-shadow(0 6px 14px rgba(0, 0, 0, .3));
}
.pdm-hero-text {
    position: relative; z-index: 1;
    display: flex; flex-direction: column; gap: 1px;
    padding: 26px 0 24px; min-width: 0;
}
.pdm-hero-first {
    font-family: var(--font-display, inherit);
    font-size: 25px; font-weight: 300; line-height: 1.1;
    letter-spacing: -.01em; opacity: .92;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pdm-hero-last {
    font-family: var(--font-display, inherit);
    font-size: 40px; font-weight: 800; line-height: 1.02;
    letter-spacing: -.02em;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pdm-hero-meta {
    display: flex; align-items: center; gap: 8px; margin-top: 9px;
    font-size: 13.5px; font-weight: 600; opacity: .95;
}
.pdm-hero-meta em { font-style: normal; opacity: .55; }
.pdm-hero-crest { width: 22px; height: 22px; object-fit: contain; }

.pdm-hero-side {
    position: relative; z-index: 1;
    display: flex; flex-direction: column; align-items: flex-end; gap: 4px;
    padding: 26px 0 24px; text-align: right;
}
.pdm-hero-chip {
    padding: 3px 11px; border-radius: 999px; margin-bottom: 4px;
    font-size: 10.5px; font-weight: 800; letter-spacing: .06em;
    background: rgba(255, 255, 255, .95); color: #111;
}
.pdm-hero-chip.v-sell { background: #DC2626; color: #fff; }
.pdm-hero-chip.v-monitor { background: #F59E0B; color: #1F1F1F; }
.pdm-hero-chip.v-star, .pdm-hero-chip.v-hold { background: rgba(255, 255, 255, .95); color: #111; }
.pdm-hero-price {
    font-family: var(--font-mono, monospace);
    font-size: 24px; font-weight: 800; line-height: 1.1;
}
.pdm-hero-own { font-size: 11.5px; opacity: .8; }

/* ----- The compact form -----
   The same hero at card size. A recommendation card, a rising-form card and a
   route card are all "one player, at a glance", which is what the hero says —
   so they say it the same way rather than each inventing a header. The portrait
   is smaller and the name comes down with it; nothing else changes. */
.pdm-hero.is-compact {
    min-height: 92px;
    padding: 0 14px;
    gap: 0 12px;
    border-radius: var(--v2-card-radius, 16px) var(--v2-card-radius, 16px) 0 0;
}
.pdm-hero.is-compact .pdm-hero-photo { height: 92px; width: 84px; }
.pdm-hero.is-compact .pdm-hero-face { height: 92px; max-width: 84px; }
.pdm-hero.is-compact .pdm-hero-text { padding: 12px 0 11px; }
.pdm-hero.is-compact .pdm-hero-first { font-size: 13px; }
.pdm-hero.is-compact .pdm-hero-last { font-size: 20px; }
.pdm-hero.is-compact .pdm-hero-meta { font-size: 11px; }
.pdm-hero.is-compact .pdm-hero-crest { width: 16px; height: 16px; }
.pdm-hero.is-compact .pdm-hero-side { padding: 12px 0 11px; }
.pdm-hero.is-compact .pdm-hero-price { font-size: 18px; }
.pdm-hero.is-compact .pdm-hero-own { font-size: 10px; }
/* The rank goes to the left corner, because the star is in the right one.
   Both were top-right and the number sat on top of the star, which is the one
   control on the card you are meant to be able to click. .pdm-hero-side is
   relative, so the chip is taken out of it and positioned against the hero. */
.pdm-hero.is-compact .pdm-hero-chip,
.pdm-hero.is-mini .pdm-hero-chip {
    position: absolute; top: 8px; left: 12px; z-index: 2;
    margin-bottom: 0;
    font-size: 9px; padding: 2px 7px;
}
.pdm-hero.is-compact .pdm-hero-side,
.pdm-hero.is-mini .pdm-hero-side { position: static; }

/* Smaller still, for the route cards — there the chart under the header is
   the subject and the header only has to say who. */
.pdm-hero.is-mini { min-height: 72px; padding: 0 12px; }
.pdm-hero.is-mini .pdm-hero-photo { height: 72px; width: 62px; }
.pdm-hero.is-mini .pdm-hero-face { height: 72px; max-width: 62px; }
.pdm-hero.is-mini .pdm-hero-text { padding: 9px 0 8px; }
.pdm-hero.is-mini .pdm-hero-first { display: none; }
.pdm-hero.is-mini .pdm-hero-last { font-size: 16px; }
.pdm-hero.is-mini .pdm-hero-meta { font-size: 10px; }
.pdm-hero.is-mini .pdm-hero-side { padding: 9px 0 8px; }
.pdm-hero.is-mini .pdm-hero-price { font-size: 15px; }

@media (max-width: 520px) {
    .pdm-hero.is-compact { min-height: 80px; }
    .pdm-hero.is-compact .pdm-hero-photo { height: 80px; width: 66px; }
    .pdm-hero.is-compact .pdm-hero-face { height: 80px; max-width: 66px; }
    .pdm-hero.is-compact .pdm-hero-last { font-size: 17px; }
}

/* ----- "How to use this page", in the heading -----
   One page had help and its button was in a KPI strip halfway down; the other
   four had none. It belongs beside the title, which is the one element every
   page has in the same place and the first thing on screen — so the ? is
   always where you last saw it. */
.v2-page-help {
    display: inline-flex; align-items: center; justify-content: center;
    width: 24px; height: 24px;
    margin-left: 10px;
    padding: 0;
    vertical-align: middle;
    /* Deliberately not --border-default. Some pages redefine that token to
       `transparent`, which gave this a transparent ring and a white fill on a
       white page — a control you could only find by knowing it was there. A
       button whose whole job is to be findable cannot inherit its visibility
       from a token that is allowed to be invisible, so it carries the brand
       green and says what it is. */
    border: 1px solid color-mix(in srgb, var(--color-primary) 40%, transparent);
    border-radius: 50%;
    background: color-mix(in srgb, var(--color-primary) 12%, #fff);
    color: var(--color-primary);
    cursor: pointer;
    transition: color 140ms ease, border-color 140ms ease, background 140ms ease;
}
.v2-page-help { font-family: var(--font-display); font-size: 14px; font-weight: 800; line-height: 1; }
.v2-page-help:hover {
    color: #fff;
    border-color: var(--color-primary);
    background: var(--color-primary);
}

/* ----- One section title -----
   Panels across the site each grew their own heading with the same intent and
   slightly different numbers — .pa-panel-title on the players page, a private
   .v2-info-title on the dashboard, .sq-panel-title in My Team. They are the
   same object and they now share one definition, so a change to it is a
   change everywhere rather than in three places and a miss. */
.v2-section-title {
    display: flex; align-items: center; gap: 8px;
    font-family: var(--font-display);
    font-size: 17px; font-weight: 650; letter-spacing: -0.2px;
    color: var(--text-primary);
}
.v2-section-title svg,
.v2-section-title .v2-sec-icon {
    width: 17px; height: 17px;
    color: var(--color-primary);
    flex-shrink: 0;
}


/* Every section, on the same lift.

   .v2-section and the panels that draw themselves with `var(--v2-card-shadow,
   none)` were fine; the ones that had never been given a box-shadow at all sat
   flat beside them. One shadow, everywhere a section is drawn.

   A second pass, from a sweep across every page and every tab, adds the
   last of them: the pitch on the squad page was the loudest — an 805x837
   white card with a hairline border sitting flat beside panels that were
   lifted — with the lineup wizard's three blocks, the scout's featured
   card and the players table behind it. */
.v2-section,
.pa-panel,
.chart-category.pa-panel,
.charts-filter-panel,
.v2-info-panel,
.sq-panel,
.input-section,
.momentum-matrix-section,
.scout-report-panel,
.news-card,
.news-card-hero,
.sd-card,
.v2-desk-card,
.v2-qa-card,
.pitch-field,
.lw-intel,
.lw-sum-block,
.lw-final-section,
.sd-featured,
.table-section {
    box-shadow: var(--v2-card-shadow);
}

/* ===== The account menu, at the foot of the sidebar =====

   It was a compact strip — avatar and name on the left, a bell and a gear
   squeezed onto the right — and three of its five things were 28px icons
   with no words. A stack instead: who you are, then notifications,
   settings, the theme, and the upgrade. One row each, all the same shape,
   each one saying what it is. Go premium is the only coloured row, and the
   only one that can be absent: it is not shown to someone already paying.
   ===================================================================== */
.v2-account {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px;
    margin-bottom: 8px;
    border: 1px solid var(--v2-card-border, var(--border-emphasis));
    border-radius: 12px;
    background: var(--surface-1);
}
.v2-account[hidden] { display: none; }

/* One row. Everything in the menu is one of these, including the bell that
   notifications.js draws and the Go premium link. */
.v2-acct-row,
.v2-account .nt-bell {
    display: flex; align-items: center; gap: 9px;
    width: 100%;
    min-height: 34px;
    padding: 7px 8px;
    border: none; border-radius: 8px;
    background: none;
    color: var(--text-secondary);
    font-family: inherit; font-size: 12px; font-weight: 600;
    text-align: left; text-decoration: none;
    cursor: pointer;
    transition: background 130ms ease, color 130ms ease;
}
.v2-acct-row:hover,
.v2-account .nt-bell:hover {
    background: var(--surface-2);
    color: var(--text-primary);
}
.v2-acct-row[hidden] { display: none; }

.v2-acct-ico,
.v2-account .nt-bell-icon {
    display: grid; place-items: center;
    width: 18px; height: 18px; flex-shrink: 0;
    color: var(--text-muted);
}
.v2-acct-row:hover .v2-acct-ico,
.v2-account .nt-bell:hover .nt-bell-icon { color: var(--color-primary); }
.v2-acct-ico svg,
.v2-account .nt-bell-icon svg { width: 16px; height: 16px; }

.v2-acct-label,
.v2-account .nt-bell-label {
    flex: 1; min-width: 0;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* --- who you are --- */
.v2-acct-you { padding: 8px; gap: 9px; }
.v2-acct-you:hover { background: var(--surface-2); }

.v2-account-avatar {
    display: grid; place-items: center;
    width: 32px; height: 32px; flex-shrink: 0;
    border-radius: 50%;
    background: color-mix(in srgb, var(--color-primary) 16%, transparent);
    color: var(--color-primary);
    font-size: 11px; font-weight: 800;
    overflow: hidden;
}
.v2-account-avatar img { width: 100%; height: 100%; object-fit: cover; }
.v2-account-avatar.lg { width: 56px; height: 56px; font-size: 17px; }

.v2-account-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; line-height: 1.2; }
.v2-account-name {
    font-size: 12.5px; font-weight: 700; color: var(--text-primary);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* The team ID as a label rather than a line of grey text. It is the one
   thing in this menu you might read out or type somewhere else, and a
   tinted chip is how the rest of the site marks a value you can act on. */
.v2-account-sub {
    align-self: flex-start;
    max-width: 100%;
    padding: 1.5px 7px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--color-primary) 14%, transparent);
    color: var(--color-primary-text, var(--color-primary));
    font-size: 10px; font-weight: 700; letter-spacing: .02em;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.v2-account-sub:empty { display: none; }

/* Shown only to someone who is paying — for everyone else the absence of
   this and the presence of Go premium say the same thing between them. */
.v2-account-plan {
    flex-shrink: 0;
    padding: 2px 6px;
    border-radius: 5px;
    background: color-mix(in srgb, var(--color-primary) 18%, transparent);
    color: var(--color-primary-text, var(--color-primary));
    font-size: 9px; font-weight: 800; letter-spacing: .06em;
}
.v2-account-plan[hidden] { display: none; }

/* --- notifications --- */
/* The panel is positioned against this row, so the row is its context. */
.v2-account .nt-centre { position: relative; width: 100%; }
.v2-account .nt-bell { width: 100%; height: auto; border-radius: 8px; }
.v2-account .nt-bell.has-new .nt-bell-icon { color: var(--color-primary); }

.v2-account .nt-count {
    flex-shrink: 0;
    min-width: 17px; padding: 1px 5px;
    border-radius: 999px;
    background: var(--color-primary);
    color: #fff;
    font-size: 9.5px; font-weight: 800; line-height: 1.5;
    text-align: center;
}

/* --- the theme ---

   A row that previews rather than a switch that reports. At rest it names
   the mode you are in; point at it and it becomes the mode you would get,
   the word and the mark turning together; move away and it turns back. The
   preview is the label, so there is nothing else to read.

   All four states are in the markup — two words, two marks — and these
   rules pick between them from .is-dark and :hover. Nothing is written
   from JS but which mode is currently on, so the hover state cannot drift
   out of step with it.

   Show the sun-and-"Light mode" pair when you are in light and not
   pointing, or in dark and pointing. The moon pair is the complement. */
.v2-acct-theme .v2-acct-ico { display: grid; place-items: center; overflow: visible; }
.v2-acct-theme .v2-acct-ico svg {
    grid-area: 1 / 1;
    opacity: 0;
    transform: rotate(-100deg) scale(.4);
    transition: opacity 220ms ease, transform 420ms cubic-bezier(.34, 1.4, .64, 1);
}
.v2-acct-theme:not(.is-dark) .v2-theme-sun,
.v2-acct-theme.is-dark:hover .v2-theme-sun,
.v2-acct-theme.is-dark:not(:hover) .v2-theme-moon,
.v2-acct-theme:not(.is-dark):hover .v2-theme-moon {
    opacity: 1;
    transform: none;
}
/* :hover wins over the resting pair, so the resting one must be told to
   leave when the pointer arrives. */
.v2-acct-theme:not(.is-dark):hover .v2-theme-sun,
.v2-acct-theme.is-dark:hover .v2-theme-moon {
    opacity: 0;
    transform: rotate(100deg) scale(.4);
}

/* The words ride the same swap, sliding rather than turning — a word that
   rotates is a word you cannot read on the way past. */
.v2-theme-words { display: grid; align-items: center; overflow: hidden; }
.v2-theme-word {
    grid-area: 1 / 1;
    opacity: 0;
    transform: translateY(9px);
    transition: opacity 200ms ease, transform 300ms cubic-bezier(.22, 1, .36, 1);
    white-space: nowrap;
}
.v2-acct-theme:not(.is-dark) .w-light,
.v2-acct-theme.is-dark:hover .w-light,
.v2-acct-theme.is-dark:not(:hover) .w-dark,
.v2-acct-theme:not(.is-dark):hover .w-dark {
    opacity: 1;
    transform: none;
}
.v2-acct-theme:not(.is-dark):hover .w-light,
.v2-acct-theme.is-dark:hover .w-dark {
    opacity: 0;
    transform: translateY(-9px);
}

@media (prefers-reduced-motion: reduce) {
    .v2-acct-theme .v2-acct-ico svg,
    .v2-theme-word { transition-duration: 1ms; }
}

/* --- go premium ---
   The one coloured row, because it is the one thing in the menu asking for
   something rather than offering it. */
.v2-premium {
    margin-top: 4px;
    justify-content: center;
    background: linear-gradient(135deg, var(--color-primary), color-mix(in srgb, var(--color-primary) 62%, #0b7));
    color: #fff;
    font-weight: 700;
    transition: filter 140ms ease, transform 140ms ease;
}
.v2-premium:hover { background: linear-gradient(135deg, var(--color-primary), color-mix(in srgb, var(--color-primary) 62%, #0b7)); color: #fff; filter: brightness(1.07); transform: translateY(-1px); }
.v2-premium .v2-acct-ico, .v2-premium:hover .v2-acct-ico { color: #fff; }
.v2-premium .v2-acct-label { flex: 0 0 auto; }
.v2-premium[hidden] { display: none; }

/* The stacked menu replaces the standalone theme pill, which stays only for
   the state before a team is loaded — the menu is hidden then, and the site
   still has to be switchable. */
.v2-sidebar-team-id[hidden] { display: none; }
.v2-account:not([hidden]) ~ #v2ThemeFallback { display: none; }

/* The two buttons in "Connected squad". */
.v2-set-group[hidden] { display: none; }

/* The field, and the word that tells you it stuck. It fades in where
   there is already room for it rather than appearing and shoving the
   hint below down a line. */
.v2-set-field { position: relative; display: flex; align-items: center; }
.v2-set-field .v2-set-input { flex: 1; min-width: 0; padding-right: 62px; }
.v2-set-saved {
    position: absolute;
    right: 10px;
    font-size: 11px; font-weight: 700;
    color: var(--color-primary-text, var(--color-primary));
    opacity: 0;
    transform: translateY(2px);
    pointer-events: none;
    transition: opacity 200ms ease, transform 200ms ease;
}
.v2-set-saved.is-on { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
    .v2-set-saved { transition-duration: 1ms; }
}
.v2-set-actions { display: inline-flex; gap: 6px; flex-shrink: 0; }
.v2-set-ghost.danger { color: var(--color-negative, #B3261E); }
.v2-set-ghost.danger:hover { border-color: var(--color-negative, #B3261E); }

/* Collapsed, the menu keeps the marks and drops the words.

   These were written against .v2-sidebar.is-collapsed, which is not a
   class this site has: the rail is .v2-sidebar-collapsed, and it is on
   <html>, not on the sidebar. So none of it ever applied — the rows kept
   their labels, their ID chip and a 30px switch inside a 52px rail, and
   every one of them overflowed it.

   The rail leaves 52px. A row is a 40px square in the middle of that, with
   nothing in it but its icon. */
.v2-sidebar-collapsed .v2-account {
    padding: 4px;
    gap: 4px;
}
.v2-sidebar-collapsed .v2-account-text,
.v2-sidebar-collapsed .v2-account-plan,
.v2-sidebar-collapsed .v2-acct-label,
.v2-sidebar-collapsed .nt-bell-label,
.v2-sidebar-collapsed .v2-theme-words { display: none; }

.v2-sidebar-collapsed .v2-acct-row,
.v2-sidebar-collapsed .v2-account .nt-bell {
    width: 40px;
    min-height: 40px;
    margin: 0 auto;
    padding: 0;
    justify-content: center;
    gap: 0;
}
/* The avatar is the identity, so it stays — as the whole of that row. */
.v2-sidebar-collapsed .v2-acct-you { padding: 0; }
.v2-sidebar-collapsed .v2-account-avatar { width: 30px; height: 30px; }

/* With the label gone there is nothing for the count to sit beside, so it
   becomes a dot on the bell instead of a chip next to nothing. */
.v2-sidebar-collapsed .v2-account .nt-count {
    position: absolute;
    top: 4px; right: 4px;
    min-width: 8px; width: 8px; height: 8px;
    padding: 0;
    font-size: 0;
    line-height: 0;
}
.v2-sidebar-collapsed .v2-account .nt-bell { position: relative; }

.v2-sidebar-collapsed .v2-premium { margin-top: 2px; }

/* The notification panel hangs off the rail rather than off a 230px
   column, so it needs to know how far to clear. */
.v2-sidebar-collapsed .v2-sidebar .nt-drop { left: calc(100% + 8px); }

/* ===== Settings ===== */
/* The edge and the lift Visual Analysis has. It had neither, so on a light
   page the sheet ran into the blurred page behind it with nothing marking
   where one stopped and the other began. The login sheet is the same
   object, so it takes the same. */
.v2-settings .modal-container,
.v2-login .modal-container,
.tw-guard .modal-container {
    width: min(560px, calc(100vw - 32px));
    max-height: 86vh;
    display: flex; flex-direction: column;
    background: var(--surface-1);
    border: 1px solid var(--border-emphasis);
    border-radius: var(--v2-card-radius, 16px);
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35);
    overflow: hidden;
}
.v2-set-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 18px;
    border-bottom: 1px solid var(--border-subtle);
}
.v2-set-body { overflow-y: auto; padding: 4px 18px 20px; }

.v2-set-group { padding: 16px 0; border-bottom: 1px solid var(--border-subtle); }
.v2-set-group:last-child { border-bottom: none; }
.v2-set-group.is-target { scroll-margin-top: 12px; }
.v2-set-label {
    font-size: 9.5px; font-weight: 800; letter-spacing: .07em;
    text-transform: uppercase; color: var(--text-muted);
    margin-bottom: 10px;
}
.v2-set-row { display: flex; align-items: flex-start; gap: 14px; }
.v2-set-row.between { align-items: center; justify-content: space-between; }
.v2-set-stack { display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 0; }
.v2-set-inline { display: flex; align-items: center; gap: 8px; }
.v2-set-value { font-size: 12.5px; color: var(--text-secondary); }

.v2-set-input {
    width: 100%;
    padding: 8px 11px;
    border: 1px solid var(--border-emphasis);
    border-radius: var(--radius-md);
    background: var(--surface-1);
    color: var(--text-primary);
    font-family: inherit; font-size: 13px;
}
.v2-set-input:focus {
    outline: none; border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-primary-muted);
}

.v2-set-file input { display: none; }
.v2-set-file span,
.v2-set-ghost {
    display: inline-block;
    padding: 6px 13px;
    border: 1px solid var(--border-emphasis);
    border-radius: 999px;
    background: var(--surface-1);
    color: var(--text-secondary);
    font-family: inherit; font-size: 11.5px; font-weight: 600;
    cursor: pointer;
}
.v2-set-file span:hover,
.v2-set-ghost:hover { border-color: var(--color-primary); color: var(--color-primary); }

.v2-set-hint { margin: 0; font-size: 11px; line-height: 1.5; color: var(--text-muted); }

.v2-set-check {
    display: flex; align-items: flex-start; gap: 9px;
    padding: 6px 0;
    font-size: 12.5px; color: var(--text-secondary); cursor: pointer;
}
.v2-set-check input { margin-top: 2px; cursor: pointer; }

/* ----- The two plans ----- */
.v2-plan { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 520px) { .v2-plan { grid-template-columns: 1fr; } }

.v2-plan-card {
    position: relative;
    padding: 14px;
    border: 1px solid var(--border-emphasis);
    border-radius: 12px;
    background: var(--surface-1);
}
.v2-plan-card.premium {
    border-color: color-mix(in srgb, var(--color-primary) 45%, transparent);
    background: color-mix(in srgb, var(--color-primary) 5%, var(--surface-1));
}
.v2-plan-card.current { box-shadow: inset 0 0 0 1px var(--color-primary); }
.v2-plan-name { font-size: 12px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted); }
.v2-plan-price {
    font-family: var(--font-display); font-size: 26px; font-weight: 700;
    color: var(--text-primary); margin: 2px 0 10px;
}
.v2-plan-price span { font-family: var(--font-body, inherit); font-size: 12px; font-weight: 500; color: var(--text-muted); }
.v2-plan-list { margin: 0 0 12px; padding: 0 0 0 16px; }
.v2-plan-list li { font-size: 11.5px; line-height: 1.7; color: var(--text-secondary); }
.v2-plan-tag {
    display: inline-block; padding: 3px 10px; border-radius: 999px;
    background: var(--color-primary); color: #fff;
    font-size: 10px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
}
.v2-plan-cta {
    width: 100%; padding: 9px 12px;
    border: none; border-radius: 999px;
    background: var(--color-primary); color: #fff;
    font-family: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
}
.v2-plan-cta:hover:not(:disabled) { filter: brightness(1.07); }
.v2-plan-cta:disabled { background: var(--surface-3); color: var(--text-muted); cursor: default; }

/* ----- What the display preferences actually do ----- */
.v2-compact .data-table td,
.v2-compact .data-table th { padding-top: 5px; padding-bottom: 5px; }
.v2-compact .sq-row { padding-top: 6px; padding-bottom: 6px; }
.v2-dim-bench .sq-row.is-bench,
.v2-dim-bench .pcard.on-bench { opacity: .62; }


/* =====================================================================
   ONE INSET FOR EVERY TITLE

   A section title landed in a different place on almost every panel: 19px in
   and 25px down on the dashboard's two, 17/21 on the players and squad
   panels, 17/17 on the teams page, 18/15 on the market strip. None of them
   was wrong on its own and together they read as carelessness, because the
   eye tracks the left edge of a run of headings and these did not line up.

   One pair of numbers, declared once. Panels that pad their own content take
   it as padding; panels whose content must run edge to edge — a pitch, a
   table, the deadline card — put it on the heading instead, which is the only
   way to inset the title without insetting what is under it.
   ===================================================================== */
:root {
    /* A tick, as a mask, so a "this one is selected" mark can be drawn in
       whatever colour the control already is rather than shipped twice in
       two colours. */
    --v2-check-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20.3 5.7a1 1 0 0 1 0 1.4l-9.9 9.9a1 1 0 0 1-1.4 0l-5.3-5.3a1 1 0 1 1 1.4-1.4l4.6 4.6 9.2-9.2a1 1 0 0 1 1.4 0Z'/%3E%3C/svg%3E");

    --v2-title-x: 18px;
    --v2-title-y: 20px;
    /* And one gap under it. The inset was made consistent; the space
       between a heading and the thing it heads was not, so panels that
       started their titles on the same line still began their content on
       different ones — 12px under the dashboard's deadline title, 6px on
       the teams page, 10px under the snapshot header. This is the second
       half of the same idea: same distance in from the corner, same
       distance down to the content. */
    /* The same number as the inset above it, deliberately. Two different
       values would have been defensible, but then the space above a heading
       and the space below it differ on every panel — which is the thing
       being fixed here, one level up. One number, above and below. */
    --v2-title-gap: var(--v2-title-y);
}

/* Panels that pad their content. */
.pa-panel,
.v2-section,
.sq-panel,
.chart-category.pa-panel,
.charts-filter-panel {
    padding: var(--v2-title-y) var(--v2-title-x) var(--v2-title-x);
}

/* Panels that cannot: the heading carries the inset alone. */
.v2-info-panel > .v2-section-title,
.all-players-head,
.v2-set-head {
    padding: var(--v2-title-y) var(--v2-title-x) 0;
    margin-bottom: var(--v2-title-gap);
}

/* The gap below the heading, wherever the heading sits. */
.pa-panel > .v2-section-title,
.v2-section > .v2-section-title,
.sq-panel > .v2-section-title,
.v2-section > .section-header,
.pa-panel > .section-header,
.sq-panel > .section-header,
.charts-filter-panel > .v2-section-title {
    margin-bottom: var(--v2-title-gap);
}

/* The dashboard strips, which had their own smaller numbers. */
.v2-market > .mk-head,
.v2-matchday > .md-head,
.v2-news > .v2-feed-head {
    padding-top: var(--v2-title-y);
    padding-left: var(--v2-title-x);
    padding-right: var(--v2-title-x);
}


/* The Rivals and Teams pages write their section headings as <h2> inside a
   .section-header rather than as a .v2-section-title. Same object, so the same
   type: 17px at 650, with the icon sized and coloured to match. Left as an h2
   for the document outline. */
.v2-section > .section-header h2 {
    display: flex; align-items: center; gap: 8px;
    font-family: var(--font-display);
    font-size: 17px; font-weight: 650; letter-spacing: -0.2px;
    color: var(--text-primary);
    line-height: 1.5;
}
.v2-section > .section-header h2 svg,
.v2-section > .section-header h2 i {
    width: 17px; height: 17px;
    color: var(--color-primary);
    flex-shrink: 0;
}


/* ----- News source badges, everywhere news is shown -----
   These were declared inside fpl-news.html, so the dashboard — which renders
   the same .news-card-category markup from the same feed data — had the
   element and none of the colours, and every source there came out grey. A
   badge that means "BBC" on one page has to mean it on the other, so the
   colours live where both can reach them.

   The hues are the publishers' own, at a 12% wash so a row of them reads as
   labels rather than as a row of buttons. */
.news-card-category {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 3px 8px; border-radius: 4px;
    font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .3px;
    background: var(--surface-2); color: var(--text-muted);
}
.news-card-category svg { width: 11px; height: 11px; }
.news-card-category.cat-bbc      { background: rgba(187, 29, 29, 0.12);  color: #BB1D1D; }
.news-card-category.cat-pl       { background: rgba(56, 0, 106, 0.12);   color: #38006A; }
.news-card-category.cat-sky      { background: rgba(0, 98, 178, 0.12);   color: #0062B2; }
.news-card-category.cat-guardian { background: rgba(5, 81, 126, 0.12);   color: #05517E; }
.news-card-category.cat-injury   { background: rgba(239, 68, 68, 0.15);  color: #EF4444; }
.news-card-category.cat-price    { background: rgba(59, 130, 246, 0.12); color: #3B82F6; }
.news-card-category.cat-transfer { background: rgba(16, 185, 129, 0.12); color: #10B981; }
.news-card-category.cat-external { background: rgba(139, 92, 246, 0.10); color: #8B5CF6; }

[data-theme="dark"] .news-card-category.cat-pl { background: rgba(151, 71, 255, 0.16); color: #B794F6; }
[data-theme="dark"] .news-card-category.cat-guardian { background: rgba(90, 165, 214, 0.16); color: #7EC2E8; }


/* ===== The help drawer, on every page that opens one =====

   .detail-overlay and .detail-panel were defined in my-team.css, and only My
   Team loads that. So on Players, Teams and Rivals the drawer opened into the
   DOM with no styles at all — present, technically visible, and impossible to
   see. Clicking the ? did exactly what it was told and nothing appeared.

   Self-contained here, under its own class, so it cannot be lost that way
   again. The My Team drawer keeps its own richer markup and picks these up
   too. */
.detail-overlay {
    position: fixed; inset: 0; z-index: 220;
    background: rgba(15, 23, 42, 0.34);
    opacity: 0; visibility: hidden;
    transition: opacity 200ms ease, visibility 200ms ease;
}
.detail-overlay.show { opacity: 1; visibility: visible; }

.detail-overlay .detail-panel {
    position: absolute; top: 0; right: 0;
    width: 100%; max-width: 520px; height: 100%;
    display: flex; flex-direction: column;
    background: var(--surface-1);
    border-left: 1px solid var(--border-emphasis);
    box-shadow: -8px 0 32px rgba(0, 0, 0, 0.22);
    transform: translateX(100%);
    transition: transform 240ms ease;
}
.detail-overlay.show .detail-panel { transform: translateX(0); }

.detail-overlay .detail-header {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-shrink: 0;
    padding: var(--v2-title-y, 20px) var(--v2-title-x, 18px);
    border-bottom: 1px solid var(--border-subtle);
}
.detail-overlay .detail-header .player-name {
    font-family: var(--font-display);
    font-size: 17px; font-weight: 650; color: var(--text-primary);
}
.detail-overlay .detail-close {
    width: 30px; height: 30px; flex-shrink: 0;
    display: grid; place-items: center;
    border: none; border-radius: 50%;
    background: var(--surface-2); color: var(--text-secondary);
    font-size: 20px; line-height: 1; cursor: pointer;
}
.detail-overlay .detail-close:hover { background: var(--surface-3); color: var(--text-primary); }

.detail-overlay .detail-body {
    overflow-y: auto;
    padding: 4px var(--v2-title-x, 18px) 24px;
}

.help-intro { font-size: 12.5px; line-height: 1.6; color: var(--text-secondary); margin: 14px 0 4px; }
.help-section-title {
    margin-top: 18px; margin-bottom: 2px;
    font-size: 9.5px; font-weight: 800; letter-spacing: .07em;
    text-transform: uppercase; color: var(--text-muted);
}
.help-step {
    display: flex; gap: 12px;
    padding: 11px 0;
    border-bottom: 1px solid var(--border-subtle);
}
.help-step:last-child { border-bottom: none; }
.help-step-title { font-size: 12.5px; font-weight: 700; color: var(--text-primary); margin-bottom: 2px; }
.help-step-text { font-size: 12px; line-height: 1.6; color: var(--text-secondary); }

@media (max-width: 560px) {
    .detail-overlay .detail-panel { max-width: none; }
}


/* ===== The v2 modal shell =====
   Moved from player-profile.css, which only two pages load — so the settings
   modal, which opens from the sidebar on all thirteen, was getting none of it.
   The page behind a modal blurs rather than the overlay frosting over it,
   which is why there is no wash on the overlay itself. ===== */
.v2-modal.modal-overlay {
    position: fixed; inset: 0; z-index: 220;
    display: flex; align-items: center; justify-content: center;
    padding: 24px;
    /* No wash and no backdrop-filter here — the page itself is blurred
       instead (body.v2-blurred below), so the blur covers the content
       rather than being a sheet of frosting between you and the modal. */
    background: transparent;
    opacity: 0;
    visibility: hidden;
    /* pointer-events:none is not optional here. Laying the overlay out so it
       can animate leaves a full-viewport element at z-index 220 over the page;
       without this it wins every hit test, and nothing underneath can be
       clicked or dragged at all. */
    pointer-events: none;
    transition: opacity 200ms ease, visibility 0s linear 240ms;
}

.v2-modal.modal-overlay.open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 200ms ease, visibility 0s;
}

/* The page behind the modal. The sidebar is navigation and stays legible;
   everything else settles out of focus rather than snapping.

   Both selectors are needed. <main class="main-content"> is the article on
   most pages, but the shell around it — the page heading, the tab strip, the
   tickers — is .v2-main-content's own children, and blurring only the inner
   one left the top third of the dashboard sharp behind a modal. The modal is
   appended to <body>, outside both, so it never blurs itself. */
body.v2-blurred .v2-main-content,
body.v2-blurred .main-content {
    filter: blur(7px);
    transition: filter 240ms ease;
    pointer-events: none;
}
/* Nested, they would blur twice. */
body.v2-blurred .v2-main-content .main-content { filter: none; }


/* =====================================================================
   THE NOTIFICATION CENTRE

   All of this lived in index.html's inline <style>. The bell markup is in
   sidebar-nav.html and so appears on all thirteen pages, and the feed is
   now rendered on all thirteen — but the rules that make a bell a bell and
   a panel a panel were on one of them. Everywhere else the bell collapsed
   to a bare icon on a line and the panel rendered as an unstyled list of
   links, which is what it looks like when a component's stylesheet is
   somewhere else.

   It moves here, where every page already loads it. index.html loses
   nothing: it loads this file too, and earlier in the head than its own
   <style>, so its remaining overrides still win.
   ===================================================================== */

/* The alerts offer, now inside the notification panel's header rather
   than as a third block on the dashboard grid. It is a switch on the
   thing it switches: this panel is the list of what would be sent.

   Compact by default — a label and a control — because the header is
   a header. What the alerts actually cover opens on click, and the
   permission prompt is still only ever raised from a button, since a
   browser refusal is one-shot per origin. */
.pn-offer {
    position: relative;
    display: inline-flex; align-items: center; gap: 8px;
    padding: 0; border: none; background: transparent;
}
.pn-offer.muted { opacity: .75; }
.pn-text {
    font-size: 11px; line-height: 1.4; font-weight: 500; color: var(--text-muted);
    max-width: 190px;
}
.pn-btn {
    padding: 6px 14px; border-radius: 999px; cursor: pointer; white-space: nowrap;
    border: 1px solid var(--color-primary); background: var(--color-primary); color: #fff;
    font-family: var(--font-body); font-size: 11.5px; font-weight: 700;
}
.pn-btn:hover { filter: brightness(1.08); }
.pn-btn.ghost { background: transparent; color: var(--text-secondary); border-color: var(--border-default); }

/* What will be sent, listed before it is agreed to. The permission
   cannot be asked for twice, so vagueness here is expensive. */
/* In the header the summary is the whole control: the long sentence
   collapses to a short label, and the detail is a click away. */
.pn-sum {
    display: inline-flex; align-items: center; gap: 7px;
    cursor: pointer; list-style: none;
}
.pn-sum::-webkit-details-marker { display: none; }
.pn-sum .pn-text { display: none; }
.pn-more {
    padding: 3px 10px; border-radius: 999px; white-space: nowrap;
    border: 1px solid var(--border-default); color: var(--text-secondary);
    background: var(--surface-2);
    font-size: 10.5px; font-weight: 700;
}
.pn-more::after { content: ' ▾'; }
.pn-offer:hover .pn-more { border-color: var(--color-primary); color: var(--text-primary); }
.pn-offer.on .pn-more { border-color: var(--color-success); color: var(--color-success); }
.pn-offer[open] .pn-more::after { content: ' ▴'; }

/* Opened, the detail appears beneath the header, in the panel's own
   flow.

   It was an absolutely-positioned popover, and it was invisible: the
   panel it hangs inside is `overflow-y: auto` so it can scroll a long
   activity list, and an overflow container clips absolutely-positioned
   children as readily as any other. Clicking "Alerts off" therefore
   opened a details element whose contents were cropped out of
   existence, and the button that actually asks for the permission
   could never be reached.

   In flow it pushes the activity list down instead, which the panel
   already knows how to scroll. */
.pn-offer[open] { display: block; width: 100%; }
.pn-offer[open] .pn-body {
    margin-top: 10px; padding: 12px;
    border: 1px solid var(--border-default); border-radius: 10px;
    background: var(--surface-2);
}
.pn-offer[open] .pn-body .pn-text { display: block; max-width: none; margin-bottom: 8px; }
.pn-offer[open] .pn-btn { margin-top: 10px; width: 100%; }

.pn-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 7px; }
.pn-item { display: flex; flex-direction: column; gap: 1px; padding-left: 14px; position: relative; }
.pn-item::before { content: '•'; position: absolute; left: 0; color: var(--color-success); }
.pn-item.off::before { content: '○'; color: var(--text-muted); }
.pn-item-l { font-size: 12px; font-weight: 700; color: var(--text-primary); }
.pn-item-d { font-size: 11px; line-height: 1.45; color: var(--text-muted); }

/* ===== Activity feed (scripts/notifications.js) =====
   Beside the gameweek badge, because the two things that answer "where
   are we now" belong together. */
.nt-centre { position: relative; margin-left: auto; }
.nt-bell {
    position: relative; width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid transparent; background: transparent;
    color: var(--text-secondary); line-height: 1; padding: 0;
    transition: color .15s ease, background .15s ease;
}
.nt-bell:hover { background: var(--surface-2); color: var(--text-primary); }
.nt-bell-icon { display: inline-flex; }
.nt-bell-icon svg { width: 20px; height: 20px; }
/* The state is the dot and nothing else. The bell used to also take a
   green ring when there was something new, which said "good" about a
   channel that carries injuries and price falls just as often. */
.nt-dot {
    position: absolute; top: 5px; right: 5px; width: 9px; height: 9px;
    border-radius: 50%; background: var(--color-error);
    /* Ringed in the surface behind it so the dot stays a separate
       shape where it overlaps the bell's outline. */
    box-shadow: 0 0 0 2px var(--surface-1);
}

.nt-drop {
    position: absolute; top: 42px; right: 0; z-index: 60; width: min(380px, calc(100vw - 32px));
    border-radius: 12px; border: 1px solid var(--border-default);
    background: var(--surface-1); box-shadow: 0 12px 32px rgba(0,0,0,.28);
    max-height: 70vh; overflow-y: auto; text-align: left;
}
.nt-drop[hidden] { display: none; }
.nt-head {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 8px 10px;
    padding: 12px 14px; border-bottom: 1px solid var(--border-subtle);
    font-size: 12.5px; font-weight: 700; color: var(--text-primary);
}
/* Closed it is a chip beside the title; opened it takes the row under
   it, which is what flex-wrap on the header is for. */
.nt-head-alerts { display: inline-flex; }
.nt-head-alerts:has(.pn-offer[open]) { flex: 1 0 100%; }
.nt-empty { margin: 0; padding: 14px; font-size: 12px; line-height: 1.55; color: var(--text-muted); }
.nt-group { display: flex; flex-direction: column; }
.nt-group-l {
    padding: 9px 14px 5px; font-size: 9.5px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted);
}
.nt-row {
    display: grid; grid-template-columns: 1fr auto; gap: 1px 10px;
    padding: 9px 14px; text-decoration: none;
    border-left: 2px solid transparent; border-top: 1px solid var(--border-subtle);
}
.nt-row:hover { background: var(--surface-2); }
.nt-row.good { border-left-color: var(--color-success); }
.nt-row.bad { border-left-color: var(--color-error); }
.nt-row.info { border-left-color: var(--border-default); }
.nt-row-title { font-size: 12.5px; font-weight: 700; color: var(--text-primary); }
.nt-row-body { grid-column: 1; font-size: 11.5px; line-height: 1.45; color: var(--text-muted); }
.nt-row-when { grid-row: 1; grid-column: 2; font-size: 10px; color: var(--text-muted); white-space: nowrap; }


/* ----- The notification panel, opened from the sidebar -----
   It was written for a bell in the dashboard header: 380px wide, anchored to
   the right edge of its host. In the sidebar that host is ~230px wide and at
   the left of the screen, so `right: 0` hung the panel off the left edge and
   most of it was outside the viewport — which is why it could not be read.

   Beside the sidebar instead, and rising from the bell rather than dropping
   from it, because the bell is near the bottom of the column. */
.v2-sidebar .nt-drop {
    top: auto;
    bottom: -6px;
    right: auto;
    left: calc(100% + 10px);
    width: min(360px, calc(100vw - var(--v2-sidebar-w, 232px) - 24px));
    max-height: min(70vh, 520px);
}

/* The rows themselves, which had nothing but the inline rules on the
   dashboard — so on any page that opens this they were unstyled text. */
.nt-panel { font-size: 12.5px; }
.nt-row { color: inherit; }
.nt-row-title { font-size: 12px; font-weight: 700; color: var(--text-primary); }
.nt-row-body { font-size: 11.5px; line-height: 1.5; color: var(--text-secondary); }
.nt-row-when { font-size: 10px; color: var(--text-muted); white-space: nowrap; }


/* =====================================================================
   THE LANDING SHELL

   Two shells, one question: is there a Team ID saved. With one, the
   sidebar — a list of things you can do to a squad. Without one, every
   item in that list leads to a page that opens by asking for the ID you
   have not got, and a first-time visitor was being shown the whole rail
   anyway. This is what they get instead: what the site is, what it
   costs, and the way in.

   sidebar-nav.js puts .v2-shell-landing or .v2-shell-app on <html>, so
   the two states can be told apart from anywhere without asking storage
   again.
   ===================================================================== */
.v2-landing-nav {
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 60;
    height: 64px;
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 0 24px;
    background: color-mix(in srgb, var(--surface-0) 88%, transparent);
    backdrop-filter: saturate(1.4) blur(10px);
    -webkit-backdrop-filter: saturate(1.4) blur(10px);
    border-bottom: 1px solid var(--border-emphasis);
}

.v2-landing-logo {
    flex-shrink: 0;
    font-family: var(--font-display);
    font-size: 19px; font-weight: 700; letter-spacing: -0.4px;
    color: var(--text-primary);
    text-decoration: none;
}
.v2-landing-logo b { color: var(--color-primary); font-weight: 700; }

.v2-landing-links {
    display: flex; align-items: center; gap: 4px;
    margin-left: 12px;
}
.v2-landing-links a {
    padding: 8px 12px;
    border-radius: 8px;
    font-size: 13px; font-weight: 600;
    color: var(--text-secondary);
    text-decoration: none;
    white-space: nowrap;
    transition: background 130ms ease, color 130ms ease;
}
.v2-landing-links a:hover { background: var(--surface-2); color: var(--text-primary); }
.v2-landing-links a.active { color: var(--color-primary-text); background: var(--color-primary-muted); }

.v2-landing-actions {
    margin-left: auto;
    display: flex; align-items: center; gap: 10px;
    flex-shrink: 0;
}
/* The pill is a two-option switch elsewhere in a 232px column; up here it
   only needs to be a control the size of the button beside it. */
.v2-landing-theme { flex-shrink: 0; width: auto; }

.v2-landing-login {
    padding: 9px 18px;
    white-space: nowrap;
    border: none; border-radius: 999px;
    background: var(--color-primary);
    color: #fff;
    font-family: inherit; font-size: 13px; font-weight: 700;
    cursor: pointer;
    transition: filter 140ms ease, transform 140ms ease;
}
.v2-landing-login:hover { filter: brightness(1.07); transform: translateY(-1px); }

/* The rail is gone, so the page gets the whole width and clears the bar. */
.v2-shell-landing .v2-main-content {
    margin-left: 0;
    padding-top: 64px;
}
/* Sticky things inside it were offset for a shell with nothing above them. */
.v2-shell-landing .v2-main-content .tabs-container,
.v2-shell-landing .v2-main-content .tw-budget-bar-top { top: 64px; }
.v2-shell-landing .v2-main-content .filter-bar { top: 99px; }

.v2-landing-burger {
    display: none;
    width: 40px; height: 40px;
    align-items: center; justify-content: center;
    border: 1px solid var(--border-emphasis);
    border-radius: 10px;
    background: var(--surface-1);
    color: var(--text-primary);
    cursor: pointer; padding: 0;
}
.v2-landing-burger svg { width: 19px; height: 19px; }

/* Below the breakpoint the links drop out of the bar and open under it. */
@media (max-width: 900px) {
    .v2-landing-nav { gap: 10px; padding: 0 14px; }
    .v2-landing-burger { display: inline-flex; order: 3; }
    .v2-landing-actions { order: 2; margin-left: auto; }
    .v2-landing-links {
        order: 4;
        position: fixed;
        top: 64px; left: 0; right: 0;
        margin-left: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 2px;
        padding: 10px 14px 14px;
        background: var(--surface-0);
        border-bottom: 1px solid var(--border-emphasis);
        box-shadow: var(--v2-card-shadow);
        display: none;
    }
    body.v2-landing-open .v2-landing-links { display: flex; }
    .v2-landing-links a { padding: 12px; min-height: 44px; display: flex; align-items: center; }
    .v2-landing-login { padding: 9px 14px; }
}

@media (max-width: 560px) {
    .v2-landing-theme { display: none; }
}

/* ----- Logging in ----- */
.v2-login-form { display: flex; gap: 8px; align-items: stretch; }
.v2-login-form .v2-set-input { flex: 1; min-width: 0; }
.v2-login-form .btn { flex-shrink: 0; white-space: nowrap; }
.v2-set-input.is-bad { border-color: var(--color-negative, #B3261E); }
.v2-login .v2-set-hint code {
    font-family: var(--font-mono);
    font-size: 11px;
    background: var(--surface-2);
    padding: 1px 5px;
    border-radius: 4px;
}


/* The league's captain, on the same hero a player's own card wears. */
.cap-hero { min-height: 152px; border-radius: var(--v2-card-radius, 16px); }
.cap-hero .pdm-hero-photo { height: 152px; width: 148px; }
.cap-hero-pct {
    background: rgba(255, 255, 255, .18);
    color: var(--club-ink, #fff);
    font-size: 15px; font-weight: 800;
    font-variant-numeric: tabular-nums;
}
.cap-hero .pdm-hero-price {
    font-size: 10.5px; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase;
    opacity: .82;
}
.cap-hero-verdict {
    margin-top: 10px;
    padding: 9px 12px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--color-warning, #D97706) 11%, transparent);
    color: var(--text-secondary);
    font-size: 12.5px;
}
.cap-hero-verdict.is-match {
    background: color-mix(in srgb, var(--color-primary) 11%, transparent);
    color: var(--color-primary-text, var(--color-primary));
}

/* The Rivals pitch shows ownership rather than points, and marks the two
   things that matter there: whether the template player is already yours. */
.rv-card { position: relative; }
.rv-own-flag {
    position: absolute; top: -7px; left: 50%;
    transform: translateX(-50%);
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 8px; font-weight: 800; letter-spacing: .06em;
    white-space: nowrap;
    z-index: 2;
}
.rv-card.you-have { border-color: var(--color-primary); }
.rv-card.you-have .rv-own-flag { background: var(--color-primary); color: #fff; }
.rv-card.you-missing { border-color: color-mix(in srgb, var(--verdict-sell, #EF4444) 55%, transparent); }
.rv-card.you-missing .rv-own-flag { background: var(--verdict-sell, #EF4444); color: #fff; }
.rv-card.you-missing .v2-pid-portrait { opacity: .72; }

/* =====================================================================
   THE SHARED PITCH

   One pitch, three pages. It was written for the GW Draft, reused by the
   Lineup Wizard, and lived in my-team.css — which the Rivals page does
   not load, so the Most Popular XI had to draw a pitch of its own out of
   different markup. It moves here, where every page already loads it,
   and the Rivals pitch becomes the same object as the other two.

   Nothing in it changed in the move.
   ===================================================================== */

.planner-swap-btn svg, .dp-act svg { width: 12px; height: 12px; }
.dp-pitch-card {
    position: relative;
    border-radius: var(--radius-xl);
    border: 1px solid var(--border-default);
    background: repeating-linear-gradient(0deg, #57ab5a 0, #57ab5a 12.5%, #4e9e51 12.5%, #4e9e51 25%);
    box-shadow: var(--shadow-md);
    padding: 14px 12px 12px;
    overflow: hidden;
}
.dp-pitch-card::before {
    content: ''; position: absolute;
    left: 6%; right: 6%; top: 50%;
    border-top: 2px solid rgba(255, 255, 255, 0.22);
    pointer-events: none;
}
.dp-pitch-card::after {
    content: ''; position: absolute;
    left: 50%; top: 50%;
    width: 128px; height: 128px;
    transform: translate(-50%, -50%);
    border: 2px solid rgba(255, 255, 255, 0.22);
    border-radius: 50%;
    pointer-events: none;
}
.dp-pitch, .dp-bench { position: relative; z-index: 1; }
.dp-pitch { display: flex; flex-direction: column; gap: 10px; }
.dp-row { display: flex; justify-content: center; gap: 8px; flex-wrap: nowrap; }
.dp-bench {
    margin-top: 10px;
    padding: 12px 14px 14px;
    background: var(--surface-1);
    border: 1px solid var(--v2-card-border, var(--border-emphasis));
    border-radius: var(--v2-card-radius, 16px);
    box-shadow: var(--v2-card-shadow, none);
}
.dp-bench-label {
    display: flex; align-items: center; gap: 7px;
    font-size: 9px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 9px;
}
.dp-bench-label::after {
    content: ''; flex: 1; height: 1px;
    background: var(--border-subtle, var(--border-emphasis));
}
.dp-bench-row { display: flex; justify-content: center; gap: 8px; flex-wrap: nowrap; }
.dp-card {
    position: relative;
    /* The card is fluid, not fixed. --dp-card-w is the width it wants; the
       flex line below lets it give width back when the row would otherwise
       wrap, because a back five folding onto two lines destroys the one
       thing a pitch exists to show. Nothing is dropped on the way down —
       the card just gets narrower, and the phone breakpoints lower the
       starting width rather than fighting this. */
    --dp-card-w: 116px;
    flex: 0 1 var(--dp-card-w);
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 7px 7px 6px;
    border-radius: var(--radius-lg);
    background: var(--surface-1);
    border: 1px solid transparent;
    border-top: 3px solid var(--text-muted);
    cursor: pointer;
    transition: transform 140ms ease, box-shadow 140ms ease, border-color 140ms ease;
}
.dp-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.dp-card .v2-pid-portrait { --v2-pid-face: 46%; --v2-pid-crest: 19px; margin-bottom: 2px; }
.dp-transfer svg { width: 11px; height: 11px; }
.dp-card.pos-gk { border-top-color: #f59e0b; }
.dp-card.pos-def { border-top-color: #10b981; }
.dp-card.pos-mid { border-top-color: #3b82f6; }
.dp-card.pos-fwd { border-top-color: #ef4444; }
.dp-card.is-out { opacity: .55; }
.dp-card.swap-selected { border-color: var(--color-primary); box-shadow: 0 0 0 2px var(--color-primary); }
.dp-card.swap-target { border-color: var(--verdict-hold); box-shadow: 0 0 0 2px var(--verdict-hold); }
.dp-card.swap-ineligible { opacity: .35; cursor: not-allowed; }
.dp-name { font-size: 12px; font-weight: 700; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dp-meta { font-size: 9px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dp-xp { font-size: 15px; font-weight: 700; font-family: var(--font-mono); color: var(--text-primary); cursor: help; line-height: 1.1; }
.dp-xp-u { font-size: 9px; color: var(--text-muted); margin-left: 1px; }
.dp-badges { position: absolute; top: -6px; left: 5px; display: flex; gap: 2px; z-index: 2; }
.dp-badge { font-size: 8px; font-weight: 800; padding: 1px 4px; border-radius: 3px; cursor: help; line-height: 1.5; }
.dp-badge.cap { background: var(--color-captain, #facc15); color: #111827; }
.dp-badge.vice { background: var(--text-muted); color: #fff; }
.dp-badge.in { background: var(--verdict-hold); color: #fff; }
.dp-badge.out { background: var(--verdict-sell); color: #fff; }
.dp-badge.doubt { background: var(--verdict-monitor); color: #111827; }
.dp-badge.bench { background: var(--surface-3); color: var(--text-secondary); }
.dp-transfer {
    position: absolute;
    top: -6px; right: 4px;
    width: 19px; height: 19px;
    border-radius: 50%;
    border: 1px solid var(--border-default);
    background: var(--surface-1);
    color: var(--text-secondary);
    font-size: 10px;
    line-height: 1;
    cursor: pointer;
    opacity: 0;
    transition: opacity 140ms ease;
    z-index: 2;
}
.dp-card:hover .dp-transfer { opacity: 1; }
.dp-transfer:hover { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.dp-card { --dp-card-w: 96px; }
.dp-pitch-card, .dp-bench { max-width: 760px; margin-left: auto; margin-right: auto; }
.dp-pitch, .dp-bench-row { max-width: 720px; margin-left: auto; margin-right: auto; }
.dp-table-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 9px; }
.dp-view-toggle { display: inline-flex; border: 1px solid var(--border-default); border-radius: var(--radius-md); overflow: hidden; }
.dp-view-btn {
    padding: 6px 12px;
    border: none;
    background: var(--surface-1);
    color: var(--text-secondary);
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
}
.dp-view-btn + .dp-view-btn { border-left: 1px solid var(--border-default); }
.dp-view-btn.active { background: var(--color-primary); color: #fff; }
.dp-table-hint { font-size: 10px; color: var(--text-muted); }
.planner-pos-header .dp-group-name {
    font-size: 10px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
    color: var(--color-primary);
}
.planner-pos-header .dp-group-stat {
    font-size: 9px; font-weight: 700; text-transform: none; letter-spacing: 0;
    color: var(--text-muted); text-align: center; cursor: help;
}
.planner-pos-header .dp-group-stat.recent { color: var(--text-secondary); }
.dp-gw-head {
    border: none; background: none; cursor: pointer;
    font: inherit; color: inherit; padding: 2px 4px;
}
.dp-dgw-tag { font-size: 8px; font-weight: 800; color: var(--color-info); }
.dp-xp-cell {
    padding: 4px 6px; border-radius: 5px; text-align: center;
    font-size: 12px; font-weight: 700; font-family: var(--font-mono); cursor: help;
}
.dp-xp-cell.xp-great { background: color-mix(in srgb, var(--verdict-hold) 22%, transparent); color: var(--verdict-hold); }
.dp-xp-cell.xp-good { background: color-mix(in srgb, var(--verdict-hold) 12%, transparent); color: var(--text-primary); }
.dp-xp-cell.xp-ok { background: var(--surface-2); color: var(--text-secondary); }
.dp-xp-cell.xp-poor { background: var(--surface-2); color: var(--text-muted); }
.dp-xp-cell.xp-blank { background: var(--surface-3); color: var(--text-muted); }
.dp-act-row { display: flex; gap: 3px; }
.dp-act {
    width: 28px; height: 28px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-default);
    background: var(--surface-1);
    color: var(--text-secondary);
    font-size: 12px; font-weight: 700;
    cursor: pointer;
    transition: background 140ms ease, color 140ms ease, border-color 140ms ease;
}
.dp-act:hover { border-color: var(--color-primary); color: var(--text-primary); }
.dp-act.is-cap { background: var(--color-captain, #facc15); border-color: var(--color-captain, #facc15); color: #111827; }
.dp-act.is-vice { background: var(--text-muted); border-color: var(--text-muted); color: #fff; }
.planner-layout-wrapper.sidebar-collapsed .dp-sidebar { display: none; }
.dp-side-toggle {
    position: absolute;
    top: 8px; right: 0;
    transform: translateX(50%);
    z-index: 3;
    width: 22px; height: 34px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-default);
    background: var(--surface-1);
    color: var(--text-secondary);
    font-size: 10px;
    cursor: pointer;
}
.planner-layout-wrapper.sidebar-collapsed .dp-side-toggle { right: 0; transform: none; }
.dp-side-toggle:hover { border-color: var(--color-primary); color: var(--color-primary); }
.dp-sidebar {
    border: 1px solid var(--border-default);
    border-radius: var(--radius-xl);
    background: var(--surface-1);
    overflow: hidden;
    min-width: 0;
}
.dp-side-tabs { display: flex; border-bottom: 1px solid var(--border-default); }
.dp-side-tab {
    flex: 1;
    padding: 9px 6px;
    border: none;
    background: transparent;
    color: var(--text-muted);
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    border-bottom: 2px solid transparent;
}
.dp-side-tab.active { color: var(--color-primary); border-bottom-color: var(--color-primary); }
.dp-side-body { padding: 10px; }
.dp-side-empty { font-size: 11px; color: var(--text-muted); line-height: 1.55; }
.dp-copilot-note { font-size: 10px; color: var(--text-muted); line-height: 1.5; margin-bottom: 8px; }
.dp-move {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 7px 8px;
    margin-bottom: 6px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    background: var(--surface-2);
}
.dp-move-body { flex: 1; min-width: 0; }
.dp-move-players { display: flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; }
.dp-move-out { color: var(--text-muted); text-decoration: line-through; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dp-move-arrow { color: var(--text-muted); flex-shrink: 0; }
.dp-move-in { color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dp-move-gain { font-weight: 700; cursor: help; }
.dp-move-gain.good { color: var(--verdict-hold); }
.dp-move-gain.bad { color: var(--text-muted); }
.dp-move-apply {
    flex: 0 0 auto;
    padding: 4px 9px;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-primary);
    background: var(--color-primary);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    cursor: pointer;
}
.dp-move-apply:hover { filter: brightness(1.08); }
.dp-move-suggest { align-items: flex-start; }
.dp-move-why { font-size: 10px; color: var(--text-secondary); line-height: 1.5; margin-top: 4px; }
.dp-suggest-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.dp-suggest-actions .draft-action-btn { font-size: 10px; padding: 5px 10px; }
.dp-notes-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.dp-notes textarea {
    width: 100%; min-height: 220px;
    padding: 8px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-2);
    color: var(--text-primary);
    font-size: 12px;
    font-family: inherit;
    resize: vertical;
}
/* Both of these lost their @media wrapper at some point and had been
   applying at every width since. Unconditionally showing a "collapsed"
   sidebar left a 2px-wide, 1502px-tall element in the grid row beside a
   728px pitch, stretching the row to its height — which is the 774px of
   white space under the bench. And the toggle that reopens the rail was
   hidden everywhere, so there was no way back to it.

   Below the breakpoint where the wrapper stops being two columns, a
   collapsed rail should simply stack under the pitch, and a control for
   collapsing a column that no longer exists has nothing to do. */
@media (max-width: 1100px) {
    .dp-side-toggle { display: none; }
    .planner-layout-wrapper.sidebar-collapsed .dp-sidebar { display: block; }
}
.dp-card.lw-picked { border-color: var(--color-primary); box-shadow: 0 0 0 2px var(--color-primary); }
.dp-xp-run {
    font-size: 10px;
    font-weight: 600;
    font-family: var(--font-mono);
    color: var(--text-muted);
    cursor: help;
    line-height: 1.1;
    margin-top: 1px;
}
.dp-xp-run-u { font-size: 8px; margin-left: 2px; opacity: 0.85; }
    .dp-xp-run { font-size: 9px; }
    .dp-xp-run-u { font-size: 7px; }
