﻿/*
 * FMBackroom "night match" theme for the Blazor-hosted player search page.
 *
 * The palette below is the same one Resources/Styles/Colors.xaml defines for the XAML pages, which
 * is itself designs/backroom/theme.css - keep the three in step, or the browser page will drift away
 * from the rest of the app. Everything under "Radzen remap" restates colour only; the Radzen
 * material-dark theme stays responsible for layout.
 *
 * The hex field is carried here as it is on every XAML page, but the search app itself sits on one
 * opaque surface with a single border and a status bar, so the field runs behind the head and the
 * page margins only and not behind the grid - see designs/player_search_v4.html.
 */

/* The WebView cannot see the fonts MAUI registers for the XAML pages, so the same four files are
   served from wwwroot/fonts and declared here. Without this the page falls back to Segoe UI while
   every other screen is in Inter, and the two halves of the app stop looking like one product. */
@font-face {
    font-family: 'Inter';
    src: url('../fonts/Inter-Regular.ttf') format('truetype');
    font-weight: 400;
    font-display: block;
}

@font-face {
    font-family: 'Inter';
    src: url('../fonts/Inter-Medium.ttf') format('truetype');
    font-weight: 500;
    font-display: block;
}

@font-face {
    font-family: 'Inter';
    src: url('../fonts/Inter-SemiBold.ttf') format('truetype');
    font-weight: 600;
    font-display: block;
}

@font-face {
    font-family: 'Backroom Mono';
    src: url('../fonts/CascadiaMono.ttf') format('truetype');
    font-weight: 400;
    font-display: block;
}

/* The same icon font the XAML pages draw their glyphs from (Resources/Fonts/TablerIcons.ttf), so the
   one icon these pages carry - the plugin gear in the head - is the same shape as everywhere else. */
@font-face {
    font-family: 'TablerIcons';
    src: url('../fonts/TablerIcons.ttf') format('truetype');
    font-weight: 400;
    font-display: block;
}

:root {
    /* ---- FMBackroom palette (mirrors Resources/Styles/Colors.xaml) --------------------------- */
    --bg: #0B111E;
    --surface: #141C2E;
    --surface-2: #1A2336;
    --surface-3: #212C43;
    --line: #37455F;
    --line-soft: #2B3651;
    --line-top: #414C68;                 /* the lit top edge of a hairline */
    --text: #E9EEF7;
    --text-2: #9AA8BF;
    --text-3: #65748F;
    --blue: #2E63E8;
    --blue-lt: #5D8CFF;
    --red: #E23A31;
    --red-lt: #FF5A50;
    --gold: #F0B429;
    --green: #3ECF8E;
    --amber: #E8973D;
    --blue-tint: rgba(93, 140, 255, .14);
    --blue-edge: rgba(93, 140, 255, .30);
    --blue-wash: rgba(93, 140, 255, .06);  /* hover, one step below selection */
    --label: #8095C9;                      /* every mono micro-cap */
    --edge: rgba(255, 255, 255, .07);      /* the white top edge on anything raised */

    --display: 'Inter', 'Segoe UI', system-ui, sans-serif;
    --body: 'Inter', 'Segoe UI', system-ui, sans-serif;
    --mono: 'Backroom Mono', 'Consolas', ui-monospace, monospace;

    --r-lg: 16px;
    --r-md: 12px;
    --r-sm: 9px;
    --shadow: 0 24px 60px -30px rgba(0, 0, 0, .95);

    /* ---- Radzen remap --------------------------------------------------------------------- */
    --rz-body-background-color: var(--bg);
    --rz-base-background-color: var(--bg);
    --rz-text-color: var(--text);
    --rz-text-title-color: var(--text);
    --rz-text-secondary-color: var(--text-2);
    --rz-text-disabled-color: var(--text-3);

    --rz-primary: var(--blue);
    --rz-primary-dark: #1F4DC4;
    --rz-primary-light: var(--blue-lt);
    --rz-on-primary: #FFFFFF;

    --rz-panel-background-color: var(--surface);
    --rz-panel-border: 1px solid var(--line-soft);

    --rz-input-background-color: var(--surface-2);
    --rz-input-color: var(--text);
    --rz-input-border: 1px solid var(--line);
    --rz-input-focus-border: 1px solid var(--blue-lt);
    --rz-input-placeholder-color: var(--text-3);

    --rz-grid-background-color: var(--surface);
    --rz-grid-color: var(--text);
    --rz-grid-border: 1px solid var(--line-soft);
    --rz-grid-cell-border: 1px solid var(--line-soft);
    --rz-grid-header-background-color: var(--surface-2);
    --rz-grid-header-color: var(--label);
    --rz-grid-header-border: 1px solid var(--line-soft);
    --rz-grid-stripe-background-color: var(--surface);
    --rz-grid-row-hover-background-color: var(--blue-wash);
    --rz-grid-selected-row-background-color: var(--blue-tint);
    --rz-grid-selected-row-color: var(--text);
    --rz-grid-footer-background-color: var(--surface-2);
}

/* The background is on html alone, NOT on body: it propagates to the canvas from there, which is
   painted below the hex field's negative z-index. A background on body is a normal element
   background instead, and would cover the field completely. */
html {
    background-color: var(--bg);
}

html, body {
    height: 100%;
    margin: 0;
    color: var(--text);
    font-family: var(--body);
    font-size: 14px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    /* The WebView is a fixed pane inside a MAUI page; the grid owns its own scrolling. */
    overflow: hidden;
}

#app {
    height: 100%;
}

/* ---- the hex field -------------------------------------------------------------------------
   The tiling and the three corner glows behind the page, from designs/backroom/theme.css and the
   same thing Controls/HexFieldView draws for the XAML pages. Fixed rather than in the document
   because the field belongs to the window: nothing here scrolls but the grid, and the field must
   not move with it. The markup is in index.html.

   Behind the page at z-index -1 rather than in front of it at 0 as the design sheets have it. The
   sheets lift their page wrapper to z-index 1 to compensate, but that wrapper would be .fm-page,
   and a stacking context around the whole app traps the column picker's backdrop beneath the
   Radzen popups that are appended to body. */
.br-field { position: fixed; inset: 0; z-index: -1; pointer-events: none; }
.br-field svg { width: 100%; height: 100%; }
.br-glow { position: fixed; z-index: -1; pointer-events: none; border-radius: 50%; filter: blur(150px); }
.br-glow.a { width: 720px; height: 720px; top: -330px; left: -210px; background: rgba(46, 99, 232, .30); }
.br-glow.b { width: 640px; height: 640px; bottom: -280px; right: -260px; background: rgba(226, 58, 49, .16); }
.br-glow.c { width: 420px; height: 420px; top: 38%; right: -200px; background: rgba(46, 99, 232, .13); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: #2A3854; border-radius: 6px; border: 2px solid var(--bg); }
::-webkit-scrollbar-track { background: transparent; }
:focus-visible { outline: 2px solid var(--blue-lt); outline-offset: 2px; border-radius: 4px; }

/* ---- page layout -------------------------------------------------------------------------
   A page head, then one search app: filters, the grid, and a status line, inside a single
   bordered surface. A flex column rather than a fixed grid template precisely because the column
   picker comes and goes: with named rows, hiding it would shift every later child up a row and
   hand the 1fr row to the wrong element.

   The table MUST get a bounded height or RadzenDataGrid's virtualisation has nothing to measure
   against and falls back to rendering every row. */
.fm-page {
    display: flex;
    flex-direction: column;
    gap: 12px;
    height: 100%;
    padding: 20px 20px 16px;
    box-sizing: border-box;
}

/* min-width: 0, NOT the flex default of auto: a flex item's automatic minimum size is its content,
   which here is the data grid's ~2300px-wide table. That stretches the whole column to match, so
   the filter bar stops wrapping and everything past the window edge is silently clipped. */
.fm-page > * {
    min-width: 0;
    flex: 0 0 auto;
}

.fm-head {
    padding-bottom: 16px;
    border-bottom: 1px solid var(--line-soft);
    border-image: linear-gradient(90deg, var(--red) 0, rgba(226, 58, 49, .55) 90px, var(--line-soft) 300px) 1;
}

/* The title on the left; the save pill and the plugin gear hard against the right edge, so they
   land where the XAML pages' PageHeadView puts them. */
.fm-head-row {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* The app-level chrome at the end of the head row: the pill (when a save is open) and the gear
   (always). The wrapper carries the margin rather than the pill so the gear stays in the corner
   when the pill is hidden. */
.fm-head-chrome {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    margin-left: auto;
}

/* Which save the figures on this page came from. Green because it states that a save is loaded
   rather than warning about anything, so it can never be read as the amber and red that mean a
   value fell. A button: it opens the save's details and Change save. Mirrors Controls/SavePillView.cs. */
.fm-save-pill {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 4px 10px;
    border: 1px solid rgba(62, 207, 142, .34);
    border-radius: 999px;
    background: rgba(62, 207, 142, .13);
    color: var(--green);
    font-family: inherit;
    font-size: 11.5px;
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
}

.fm-save-pill:hover {
    filter: brightness(1.15);
}

.fm-save-dot {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--green);
}

/* The plugin setup gear. Mirrors Controls/PluginSetupButtonView.cs - a 16px-radius Surface2 chip
   with the Tabler "tool" glyph at 15px in the muted text colour - so the gear in this head is the
   same object as the gear in every XAML head. */
.fm-gear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 7px 8px;
    border: 1px solid var(--line);
    border-radius: 16px;
    background: var(--surface-2);
    color: var(--text-2);
    font-family: 'TablerIcons';
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
}

.fm-gear:hover {
    border-color: var(--blue-edge);
    color: var(--text);
}

.fm-head h1 {
    font-family: var(--display);
    font-size: 27px;
    font-weight: 600;
    letter-spacing: -.038em;
    margin: 0;
    line-height: 1.1;
}

/* The line under the title saying what the page is for, led by one cell of the mark in brand red.
   Red here can never be mistaken for a warning, because nothing on it can be acted on. */
.fm-page-sub {
    display: flex;
    align-items: center;
    gap: 9px;
    margin: 7px 0 0;
    color: var(--text-2);
    font-size: 13px;
}

.fm-page-sub::before {
    content: "";
    flex: 0 0 auto;
    width: 7px;
    height: 8px;
    background: var(--red);
    clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
}

.fm-app {
    display: flex;
    flex-direction: column;
    min-height: 0;
    flex: 1 1 auto;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    overflow: hidden;
    background: var(--surface);
    box-shadow: inset 0 1px 0 var(--edge), var(--shadow);
}

.fm-filter-panel {
    background-color: var(--surface);
    border-bottom: 1px solid var(--line-soft);
    padding: 14px 16px;
}

/* One filter: its own label above its own control, so the row wraps as whole fields. */
.fm-field {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.fm-flabel {
    font-family: var(--mono);
    font-size: 9.5px;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--label);
    white-space: nowrap;
}

.fm-filter-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 10px 14px;
}

/* .fbox - a frame around a pair of numbers, so a range reads as one control. */
.fm-fbox {
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 3px 9px;
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12.5px;
    color: var(--text-2);
}

.fm-fbox .rz-textbox,
.fm-fbox .rz-numeric,
.fm-fbox input {
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;
    font-family: var(--mono);
    font-size: 12.5px;
}

/* Radzen draws its own spinner buttons; inside a shared frame they read as clutter. */
.fm-fbox .rz-spinner-up,
.fm-fbox .rz-spinner-down {
    display: none;
}

.fm-check {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 12.5px;
    color: var(--text-2);
    white-space: nowrap;
}

/* Divider above a new block of filters, so the panel reads as sections rather than one long wrap. */
.fm-filter-section {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--line-soft);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

/* With every filter in the popup, the button row is all the panel holds - the gap it keeps from the
   filters above it would read as uneven padding. */
.fm-filter-panel > .fm-apply-row:first-child {
    margin-top: 0;
}

.fm-section-title {
    font-family: var(--mono);
    font-size: 9.5px;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--text-3);
}

.fm-filter-note {
    color: var(--text-3);
    font-size: 12.5px;
}

/* Apply gets its own line. Nothing above it takes effect until it is pressed, and a button sharing
   a row with the filters reads as one more filter. */
.fm-apply-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 14px;
    flex-wrap: wrap;
}

/* Apply and Reset pushed to the far end of the row, away from the popup buttons on the left: the
   left side shapes the view, the right side runs it. */
.fm-apply-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-left: auto;
}

/* ---- column picker -------------------------------------------------------------------------
   The grouped visibility sheet, as a modal. There are ~250 columns in four sections, which no
   in-page panel can show without either squeezing the grid off the screen or hiding most of the
   choices behind a short scroller. */
.fm-modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1200;
    background: rgba(11, 17, 30, .72);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}

.fm-modal {
    display: flex;
    flex-direction: column;
    width: min(1180px, 100%);
    max-height: 88vh;
    background: var(--surface);
    border: 1px solid var(--line);
    border-top-color: var(--line-top);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    overflow: hidden;
}

.fm-modal-head {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 14px 18px;
    background: var(--surface-2);
    border-bottom: 1px solid var(--line-soft);
}

.fm-modal-title {
    margin: 0 0 2px;
    font-family: var(--display);
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
}

.fm-modal-head-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}

.fm-modal-close {
    background: none;
    border: none;
    color: var(--text-2);
    font-size: 22px;
    line-height: 1;
    padding: 2px 6px;
    cursor: pointer;
    border-radius: var(--r-sm);
}

.fm-modal-close:hover {
    background: var(--blue-wash);
    color: var(--text);
}

/* The one scrolling region: the header and footer stay put, so "Reset to defaults" and "Done" are
   reachable from anywhere in a list this long. */
.fm-modal-body {
    padding: 4px 18px 14px;
    overflow-y: auto;
}

.fm-modal-foot {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 10px 18px;
    background: var(--surface-2);
    border-top: 1px solid var(--line-soft);
}

/* ---- search filters --------------------------------------------------------------------------
   The same modal shell as the column picker, narrower: this one holds two wrapping rows of fields
   rather than 250 checkboxes, and at the picker's width the fields spread into one long line that
   is harder to read than the panel they came out of. */
.fm-modal-filters {
    width: min(880px, 100%);
}

/* ---- the Detailed stats bubble chart ----------------------------------------------------------
   Wide, because a scatter wants width; the canvas takes what the viewport leaves after the pickers. */
.fm-modal-chart {
    width: min(1180px, 100%);
}

.fm-chart-pickers {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px 16px;
    margin: 12px 0 10px;
}

.fm-chart-frame {
    position: relative;
    border: 1px solid var(--line-soft);
    border-radius: var(--r-md);
    background: var(--surface-2);
}

.fm-chart-canvas {
    width: 100%;
    height: min(560px, 58vh);
    min-height: 320px;
}

.fm-chart-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    text-align: center;
    color: var(--text-2);
    background: rgba(20, 28, 46, .72);
    border-radius: var(--r-md);
}

.fm-chart-selection {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 34px;
    margin-top: 8px;
}

.fm-chart-caption {
    margin-top: 8px;
}

@media (max-width: 700px) {
    .fm-chart-pickers .rz-dropdown {
        width: 100% !important;
    }

    .fm-chart-pickers .fm-field {
        flex: 1 1 100%;
    }
}

/* ---- saved column setups ---------------------------------------------------------------------
   Save as / Load / delete-confirm, each a modal over the column picker rather than a panel inside
   it: the picker's body is a 250-row scroller, and anything added to it would be scrolled away from
   the moment the user went looking for the columns they wanted to keep.

   Three stacking levels, because all three can be on screen at once: the picker at 1200, the save
   and load sheets above it, and the delete confirmation above those - a question about a row has to
   sit over the list the row is in. */
.fm-modal-backdrop--sub {
    z-index: 1300;
    background: rgba(11, 17, 30, .55);
}

.fm-modal-backdrop--alert {
    z-index: 1400;
    background: rgba(11, 17, 30, .55);
}

/* One field or one short list, so these are sized to their content rather than to the picker's
   1180px - a name box that wide reads as a search bar. */
.fm-modal--sub {
    width: min(480px, 100%);
}

.fm-modal--alert {
    width: min(420px, 100%);
}

.fm-modal-body--sub {
    padding: 16px 18px;
}

.fm-field--wide {
    width: 100%;
}

/* A native input rather than a Radzen one - the "already saved" warning has to answer as the name is
   typed - so it borrows the same Radzen variables the boxes beside it use, and looks like them. */
.fm-setup-input {
    width: 100%;
    box-sizing: border-box;
    padding: 8px 10px;
    font-family: var(--body);
    font-size: 13px;
    color: var(--rz-input-color);
    background: var(--rz-input-background-color);
    border: var(--rz-input-border);
    border-radius: var(--r-sm);
    outline: none;
}

.fm-setup-input::placeholder {
    color: var(--rz-input-placeholder-color);
}

.fm-setup-input:focus {
    border: var(--rz-input-focus-border);
}

/* The filter pickers' search box sits in the modal head beside the buttons, so it is sized to itself
   rather than to the row - the setup sheets' full-width box would push Clear all off the end. */
.fm-picker-search {
    width: 220px;
    padding: 5px 9px;
    font-size: 12.5px;
}

.fm-modal-note {
    margin: 12px 0 0;
    color: var(--text-2);
    font-size: 12.5px;
    line-height: 1.5;
}

/* Amber rather than red: replacing a setup and a failed write are both worth reading before the
   next click, but neither has broken anything yet. */
.fm-modal-note--warn {
    color: var(--amber);
}

/* Capped and scrolled, because the list grows with use and a modal that reflows the page every time
   a setup is added stops being a place the eye knows. */
.fm-setup-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 46vh;
    overflow-y: auto;
}

.fm-setup-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 10px 9px 12px;
    background: var(--surface-2);
    border: 1px solid var(--line-soft);
    border-radius: var(--r-sm);
    cursor: pointer;
}

.fm-setup-row:hover {
    background: var(--blue-wash);
    border-color: var(--line);
}

/* Selection is a border and a tint, not just a tint: the rows are one click from replacing every
   column choice, and "which one is armed" has to be readable at a glance. */
.fm-setup-row--selected,
.fm-setup-row--selected:hover {
    background: var(--blue-tint);
    border-color: var(--blue-edge);
}

.fm-setup-row-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    margin-right: auto;
}

.fm-setup-row-name {
    font-size: 13px;
    font-weight: 500;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fm-setup-row-meta {
    font-family: var(--mono);
    font-size: 10.5px;
    color: var(--text-3);
}

.fm-setup-delete {
    flex: none;
    background: none;
    border: none;
    color: var(--text-3);
    font-size: 18px;
    line-height: 1;
    padding: 2px 7px;
    border-radius: var(--r-sm);
    cursor: pointer;
}

.fm-setup-delete:hover {
    background: rgba(226, 58, 49, .16);
    color: var(--red-lt);
}

/* ---- manage shortlists -----------------------------------------------------------------------
   The popup shares the saved-setup list's rows wholesale; what is here is only what it adds - a
   width of its own, the "current" tag, and a neutral hover for the rename pencil, which promises
   an edit rather than the delete cross's removal. */
.fm-modal-shortlists {
    width: min(680px, 100%);
}

.fm-shortlist-current {
    margin-left: 8px;
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--green);
}

.fm-setup-action {
    flex: none;
    display: inline-flex;
    align-items: center;
    background: none;
    border: none;
    color: var(--text-3);
    line-height: 1;
    padding: 4px 7px;
    border-radius: var(--r-sm);
    cursor: pointer;
}

.fm-setup-action:hover {
    background: var(--blue-wash);
    color: var(--text);
}

/* Attributes / Positions / Scores. The heading is sticky because the Scores section alone runs to
   nine positions - without it a screen of role checkboxes says nothing about what it belongs to. */
.fm-cols-section + .fm-cols-section {
    margin-top: 18px;
}

.fm-cols-section-head {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 10px 0 8px;
    background: var(--surface);
    border-bottom: 1px solid var(--line-soft);
    margin-bottom: 10px;
}

.fm-cols-section-title {
    font-family: var(--display);
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: .02em;
    color: var(--text);
}

.fm-cols-section-head a {
    color: var(--blue-lt);
    font-size: 11px;
    text-decoration: none;
}

/* A grid rather than wrapped flex: the subgroups run from four checkboxes (Set pieces) to seventeen
   (Winger), and ragged flex columns make a list that long hard to read down. */
.fm-columns-groups {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 14px 18px;
    align-items: start;
}

.fm-columns-group {
    min-width: 0;
}

.fm-columns-group-header {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 6px;
}

.fm-columns-group-header a {
    color: var(--blue-lt);
    font-size: 11px;
    text-decoration: none;
}

/* Pushed away from the section's own all/none pair so the two kinds of toggle do not read as one row
   of six links. */
.fm-cols-phase-toggle {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    margin-left: 8px;
    font-size: 11px;
    color: var(--text-3);
}

.fm-cols-phase-toggle a {
    color: var(--blue-lt);
    font-size: 11px;
    text-decoration: none;
}

.fm-columns-phase + .fm-columns-phase {
    margin-top: 8px;
}

/* Indented under the position heading, and lighter than it: the eye should find "Central Defender"
   first and "Out of possession" only inside it. */
.fm-columns-phase-header {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin: 0 0 3px 2px;
}

.fm-columns-phase-title {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: uppercase;
    color: var(--text-3);
}

.fm-columns-phase-header a {
    color: var(--blue-lt);
    font-size: 10.5px;
    text-decoration: none;
}

/* Sibling selector, not a descendant one: only the options that actually sit under a phase heading
   are indented, so the attribute groups (one phase, no heading) keep their flush list. */
.fm-columns-phase-header ~ .fm-columns-option {
    padding-left: 8px;
}

/* Top-aligned, not centred: a role name like "Splitting Outlet Attacking Midfielder (in possession)"
   wraps to two lines, and a checkbox floating beside the middle of a two-line label reads as though it
   belonged to neither. */
.fm-columns-option {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    font-size: 12.5px;
    line-height: 1.35;
    color: var(--text-2);
    padding: 2px 0;
    cursor: pointer;
}

.fm-columns-option input {
    accent-color: var(--blue);
    margin-top: 2px;
    flex: 0 0 auto;
}

/* ---- position rows -----------------------------------------------------------------------------
   Role fit and Match engine each fan out into a row per position. The heading takes the whole width
   of the picker's grid so the nine rows can lay out in a grid of their own, and an opened row grows
   in place - align-items: start on both grids keeps its neighbours from stretching to match. */
.fm-columns-group--positions {
    grid-column: 1 / -1;
}

/* ---- identity ----------------------------------------------------------------------------------
   One flat list of twenty-odd facts with no heading beside it. In a single 230px strip it ran the
   full height of the modal with three-quarters of the width empty, so the heading takes the whole
   row and its list flows down-then-across in up to three columns. CSS multi-column rather than a
   grid: `columns: 3 230px` is "at most three, none narrower than 230px", so the list folds to two
   and then one column as the modal narrows - the same collapse the attribute headings get from
   their auto-fill grid - and a checklist reads better down a column than across a row. */
.fm-columns-group--flowed {
    grid-column: 1 / -1;
}

.fm-columns-group--flowed .fm-columns-overall {
    display: block;
    columns: 3 230px;
    column-gap: 18px;
    margin-bottom: 0;
}

/* A label and its checkbox stay together across a column break. */
.fm-columns-group--flowed .fm-columns-option {
    break-inside: avoid;
}

.fm-columns-overall {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 0 18px;
    margin-bottom: 8px;
}

/* The overall sub-heading spans the row so the checkboxes flow under it. */
.fm-columns-overall > .fm-columns-phase-header {
    grid-column: 1 / -1;
}

.fm-columns-positions {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 8px 18px;
    align-items: start;
}

.fm-columns-position {
    border: 1px solid var(--line-soft);
    border-radius: 6px;
    padding: 4px 8px;
    min-width: 0;
}

.fm-columns-position--open {
    background: var(--surface-2);
}

.fm-columns-position-head {
    display: flex;
    align-items: center;
    gap: 8px;
}

.fm-columns-position-head a {
    color: var(--blue-lt);
    font-size: 11px;
    text-decoration: none;
}

/* The head is a disclosure button, not a checkbox: it opens the panel and nothing else. Heavier than
   the figures under it, so the eye finds "Central Defender" first and "Fit score" only inside it. */
.fm-columns-position-toggle {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    padding: 2px 0;
    background: none;
    border: none;
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--text);
    text-align: left;
    cursor: pointer;
}

.fm-columns-position-toggle:hover .fm-columns-position-name {
    color: var(--blue-lt);
}

.fm-columns-position-chevron {
    display: inline-flex;
    flex: 0 0 auto;
    color: var(--text-3);
    transition: transform .12s ease;
}

.fm-columns-position--open .fm-columns-position-chevron {
    transform: rotate(90deg);
}

/* "3/17" with a tick: what the panel is contributing to the grid, readable while it is shut. Green
   once anything inside is on, and the same badge greyed when nothing is - a different glyph for
   "nothing" would make the eye re-learn the row. */
.fm-columns-position-count {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    flex: 0 0 auto;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    color: var(--text-3);
}

.fm-columns-position-count svg {
    opacity: .45;
}

.fm-columns-position-count--on {
    color: var(--green);
}

.fm-columns-position-count--on svg {
    opacity: 1;
}

.fm-columns-position-body {
    padding: 4px 0 4px 20px;
    border-top: 1px solid var(--line-soft);
    margin-top: 4px;
}

.fm-columns-position-body .fm-columns-phase {
    margin-top: 6px;
}

/* ---- the grid and the status bar ---------------------------------------------------------- */
.fm-grid {
    flex: 1 1 auto;
    min-height: 0;
}

.fm-statusbar {
    display: flex;
    gap: 14px;
    align-items: center;
    padding: 9px 16px;
    background: var(--surface-2);
    border-top: 1px solid var(--line-soft);
    font-size: 12px;
    color: var(--text-3);
}

.fm-statusbar .fm-right {
    margin-left: auto;
    font-family: var(--mono);
    font-size: 11.5px;
}

/* Attribute cells, RAG-coloured on the same thresholds as Controls/ThemeColors.AttributeColor:
   15+ is a strength, 8- a hole, and the ordinary middle is left as plain text rather than
   coloured - three colours on every cell is no signal at all. */
.fm-attr-good,
.fm-attr-high,
.fm-attr-mid,
.fm-attr-low {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
}

.fm-attr-good { color: var(--green); }
.fm-attr-high { color: var(--text); }
.fm-attr-mid  { color: var(--amber); }
.fm-attr-low  { color: var(--red); }

/* Computed score cells are NULL until the scoring pass has run, and an em dash is the honest
   answer there - a 0 would read as "scored, and terrible". */
.fm-score-none { color: var(--text-3); }

/* ---- the name cell -------------------------------------------------------------------------
   The name, and a button that copies it. The button is pushed to the right-hand edge so the column
   of copy targets is straight, rather than ragged along the ends of the names. */
.fm-name-cell {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    min-width: 0;
}

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

/* Faint until the row is hovered, rather than hidden until then. 5,000 icons at full strength would
   be a column of clutter over the one thing on the grid that is actually being read - but a button
   that is `visibility: hidden` is not hit-testable, so the first click after the pointer enters a
   row lands on the row underneath and opens the player instead of copying his name. Low opacity
   keeps it out of the way AND keeps it clickable. */
.fm-copy {
    margin-left: auto;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--text-3);
    cursor: pointer;
    opacity: .25;
    transition: opacity .12s, color .12s, background-color .12s;
}

.rz-data-row:hover .fm-copy,
.fm-copy:focus-visible {
    opacity: 1;
}

.fm-copy:hover {
    opacity: 1;
    background: var(--surface-3);
    color: var(--text);
}

/* Stays up for a moment after a copy, so the click has an answer. Full strength regardless of
   hover - the pointer may already have moved on by the time it is drawn. */
.fm-copy-done,
.rz-data-row:hover .fm-copy-done {
    opacity: 1;
    color: var(--green);
}

/* The row's actions sit together at the right. Only the first takes the auto margin that pushes the
   pair away from the name; a second one would otherwise be shoved to the far edge on its own. */
.fm-copy + .fm-copy {
    margin-left: 2px;
}

/* Already on the shortlist: held at half strength so the row reads as "done" at a glance without
   competing with the name, and it stays that way rather than timing out like the copy tick. */
.fm-on-list,
.rz-data-row:hover .fm-on-list {
    opacity: .65;
    color: var(--green);
}

/* Clicking a shortlisted player takes him back off, so the hover state says so rather than
   promising another add. Declared after the rule above, which it ties with on specificity. */
.fm-on-list:hover {
    opacity: 1;
    color: var(--red);
}

.fm-add-failed,
.rz-data-row:hover .fm-add-failed {
    opacity: 1;
    color: var(--red);
}

/* ---- Radzen touch-ups --------------------------------------------------------------------- */

/* The material-dark theme carries its own face and its own weights, and both of them shout. One
   family and one weight for everything except a heading, which is what the design does. */
.rz-button,
.rz-inputtext,
.rz-textbox,
.rz-dropdown,
.rz-dropdown-label,
.rz-dropdown-item,
.rz-numeric,
.rz-spinner-input,
.rz-grid-table,
.rz-datatable-thead th,
.rz-data-grid-data td,
.rz-panel,
.rz-dialog {
    font-family: var(--body);
    letter-spacing: 0;
}

.rz-button {
    font-weight: 500;
    text-transform: none;
    border-radius: var(--r-sm);
    box-shadow: none;
}

.rz-button.rz-primary {
    background: var(--blue);
    color: #fff;
}

.rz-button.rz-light {
    background: var(--surface-3);
    color: var(--text);
    border: 1px solid var(--line);
}

.rz-textbox, .rz-dropdown, .rz-numeric, .rz-spinner {
    border-radius: var(--r-sm);
}


/* Radzen draws the header sort/filter affordances at body font size; the FM tables are denser. */
.rz-datatable-thead th,
.rz-data-grid-data td {
    padding: 4px 8px;
}

.rz-datatable-thead th {
    font-family: var(--mono);
    font-size: 9.5px;
    letter-spacing: .09em;
    text-transform: uppercase;
    font-weight: 500;
}

.rz-grid-table {
    font-size: 12.5px;
}

/* The header text, wrapped so it can carry a title attribute explaining the column - see the
   HeaderTemplate in PlayerSearch.razor. It has to keep behaving like the bare text Radzen would have
   drawn: inline so it does not push the sort caret onto its own line, and ellipsed rather than wrapped
   because the widths in PlayerColumns are measured for one line. The help cursor is the only visible
   difference, and it is the affordance - nothing else on the grid says a tooltip is there. */
.fm-col-header {
    display: inline;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: help;
}

/* The per-column filter row. It is not in the design and it is the loudest thing on the grid, so it
   is pushed back to the weight of a caption rather than removed - it is real functionality. */
.rz-column-filter,
.rz-cell-filter {
    opacity: .55;
    transition: opacity .12s;
}

.rz-datatable-thead:hover .rz-column-filter,
.rz-datatable-thead:hover .rz-cell-filter {
    opacity: 1;
}

.rz-data-grid, .rz-datatable {
    border: 0 !important;
    border-radius: 0 !important;
}

/* The frozen name column carries a second line, so it is the one cell that is not a number. */
.rz-frozen-cell {
    background: var(--surface) !important;
}

/* ---- the detailed statistics page -----------------------------------------------------------
   Components/DetailedStats.razor. Everything here is either a control the player search does not
   have - a chip, a two-state segment, a heading that sorts the database rather than the page - or a
   mark for something only this grid has to say: that a figure was never collected. */

/* A chip is a filter that is on or off, drawn as a word rather than as a checkbox: four position
   groups and a handful of seasons are read at a glance across the top of a page, and a column of
   ticks is not. The input is kept in the DOM for the keyboard and the screen reader, and hidden. */
.fm-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--text-3);
    font-family: var(--body);
    font-size: 12px;
    cursor: pointer;
    user-select: none;
}

.fm-chip:hover {
    border-color: var(--blue-edge);
    color: var(--text-2);
}

.fm-chip.on {
    border-color: var(--blue-edge);
    background: var(--blue-wash);
    color: var(--text);
}

.fm-chip input {
    display: none;
}

/* The chart selection's chip: on, and cleared by its own cross rather than toggled by a click. */
.fm-chip-clear {
    background: none;
    border: none;
    padding: 0 0 0 2px;
    color: var(--text-2);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
}

.fm-chip-clear:hover {
    color: var(--red-lt);
}

/* Two states of one question, so a segment rather than two buttons: which of these is the grid in,
   not which of these do I want to press. */
.fm-seg {
    display: inline-flex;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    overflow: hidden;
    background: var(--surface-2);
}

.fm-seg button {
    padding: 4px 12px;
    border: 0;
    background: none;
    color: var(--text-3);
    font-family: var(--body);
    font-size: 12px;
    cursor: pointer;
}

.fm-seg button.on {
    background: var(--blue-wash);
    color: var(--text);
}

/* ---- the position-scoped player search ------------------------------------------------------
   Pages/PlayerSearch.razor. The scope row - nine position keys as a segment, the position's name,
   the role dropdown - sits above the filter buttons, because it is the question the whole grid
   answers rather than one more filter on it. */
.fm-scope-row {
    gap: 12px;
    flex-wrap: wrap;
}

.fm-pos-seg button {
    font-family: var(--mono);
    font-weight: 600;
    min-width: 38px;
}

.fm-scope-name {
    font-family: var(--display);
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    min-width: 150px;
}

.fm-field--inline {
    flex-direction: row;
    align-items: center;
    gap: 8px;
}

/* The five standout-skill bands: a word in a cell, coloured by band. Elite and Strong read as
   strengths, Poor as a hole; the ordinary middle is left as plain text, the way attribute cells are. */
.fm-band {
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: .02em;
}

.fm-band-elite { color: var(--green); }
.fm-band-strong { color: var(--green); font-weight: 500; }
.fm-band-average { color: var(--text-2); font-weight: 400; }
.fm-band-below { color: var(--amber); font-weight: 500; }
.fm-band-poor { color: var(--red); }

/* The signed "vs CA" chip: effective CA less actual CA. Sign and colour, no ring. */
.fm-delta {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
}

.fm-delta-plus { color: var(--green); }
.fm-delta-minus { color: var(--red); }
.fm-delta-level { color: var(--text-3); }

.fm-effca {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--text);
}

/* "uncal." - the position has no calibrated population. Marked, never a fallback to the out-of-100
   figure, and never a dash that reads as "not scored". */
.fm-uncalibrated {
    font-size: 11px;
    font-style: italic;
}

/* ---- "About this column" in the column picker -------------------------------------------------
   Every option can open its explanation in place. The toggle is a small ⓘ beside the label so the
   checklist stays a checklist; the note flows under the row and pushes the next one down. */
.fm-columns-item {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 4px;
    break-inside: avoid;
}

.fm-columns-item .fm-columns-option {
    flex: 1 1 auto;
}

.fm-about-toggle {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin-top: 3px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 50%;
    background: var(--surface-2);
    color: var(--text-3);
    font-family: var(--display);
    font-size: 10px;
    font-style: italic;
    line-height: 1;
    cursor: pointer;
}

.fm-about-toggle:hover,
.fm-about-toggle[aria-expanded="true"] {
    border-color: var(--blue-edge);
    color: var(--text);
}

.fm-about {
    flex: 1 1 100%;
    margin: 0 0 6px 22px;
    font-size: 11.5px;
    line-height: 1.4;
    color: var(--text-3);
}

/* A heading that re-runs the query. It is a pointer, not the help cursor the search grid's headings
   carry, because clicking this one does something. */
.fm-sortable {
    cursor: pointer;
}

.fm-sortable:hover {
    color: var(--blue-lt);
}

.fm-sorted {
    color: var(--text);
    font-family: var(--body);
}

.fm-right-header {
    display: inline-block;
    width: 100%;
    text-align: right;
}

/* The last of the base columns, so the eye knows where the player stops and the statistics start
   without a second header row. */
.fm-edge {
    border-right: 1px solid var(--line) !important;
}

.fm-scope,
.fm-mono {
    font-family: var(--mono);
    font-size: 11.5px;
}

/* "FM never gathered this", which is not the same as zero. Amber and outlined rather than coloured
   text: it is a property of the row, and it has to be legible next to a scope key that is already
   monospaced and quiet. */
.fm-nodetail {
    display: inline-block;
    margin-left: 6px;
    padding: 0 4px;
    border: 1px solid rgba(232, 151, 61, .32);
    border-radius: 4px;
    font-family: var(--mono);
    font-size: 9px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--amber);
}

/* A figure FM counted in only some of the line's matches - a partial-detail line's dribbles,
   interceptions, distance. Dimmed like a blank, because it is closer to one than to a measurement,
   and italic so it cannot be mistaken for a blank's neighbour; the badge on the scope cell and the
   cell's own tooltip carry the explanation. */
.fm-stat-partial {
    color: var(--text-3);
    font-style: italic;
}

/* The season floor beside the averaging chip: a label and a small numeric, spaced as the chips are
   and only drawn while the chip is on. */
.fm-min-seasons {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-right: 4px;
}

/* Minutes is the divisor every per-90 on the row is computed from, so it reads as the column the
   others are measured against rather than as one more number. */
.fm-stat-strong {
    color: var(--text);
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
}

#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    padding: 8px 12px;
    background: var(--red);
    color: #FFFFFF;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    float: right;
}

/* ---- similar players ------------------------------------------------------------------------ */

.fm-sim-target {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px 18px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--surface-3);
}

.fm-sim-target-who {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
}

.fm-sim-name {
    font-size: 16px;
    font-weight: 600;
    color: var(--text);
    text-decoration: none;
}

.fm-sim-name:hover { text-decoration: underline; }

.fm-sim-sig {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.fm-sim-chip {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11.5px;
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    background: var(--surface-3);
    color: var(--text);
}

.fm-sim-chip--up { color: var(--green); border: 1px solid color-mix(in srgb, var(--green) 40%, transparent); }

.fm-sim-chip--down { color: var(--red-lt); border: 1px solid color-mix(in srgb, var(--red) 40%, transparent); }

.fm-sim-radios {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
}

.fm-sim-slider {
    display: flex;
    align-items: center;
    gap: 8px;
}

.fm-sim-wait {
    padding: 18px 16px;
}

.fm-sim-grid {
    min-height: 420px;
}

.fm-sim-why {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
    color: var(--text-2, var(--text));
    font-size: 12px;
}
