@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');

html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

a, .btn-link {
    color: #0366d6;
}

.progress-centered {
    position: fixed;
    top: 50%;
    left: 50%;
}
.progress-center {
    margin: auto;
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.content {
    padding-top: 1.1rem;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid red;
}

.validation-message {
    color: red;
}

#.blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

 #   .blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.redballbutton {
    display: inline-block;
    border: none;
    width: 32px;
    height: 32px;
    background-image: url('images/buttons/red32.png');
    background-color: transparent;
    /*transform: scale(0.75);*/
    transform-origin: left;
    padding: 10px;
}

.greenballbutton {
    display: inline-block;
    border: none;
    width: 32px;
    height: 31px;
    background-image: url('images/buttons/green32.png');
    background-color: transparent;
    /*transform: scale(0.75);*/
    transform-origin: left;
    padding: 10px;
}

.acebutton {
    display: inline-block;
    border: none;
    width: 32px;
    height: 32px;
    background-image: url('images/buttons/ace32.png');
    background-color: transparent;
    /*transform: scale(0.75);*/
    transform-origin: left;
    padding: 10px;
}

.lightbluetableheader {
    padding-left: 5px;
    padding-right: 5px;
    text-align: center;
    background-color: #2988BC;
    color: white;
    font-size:11px;
}

.darkbluetableheader {
    padding-left: 5px;
    padding-right: 5px;
    text-align: center;
    background-color: #2F496E;
    color: white;
    font-size: 11px;
}

.lightballtablecell {
    text-align:center;
    padding: 10px;
    background-color: #2988BC;
}

/*  SECTIONS  */
.section {
    clear: both;
    padding: 0px;
    margin: 0px;
}

/* #846 - .section zeroes every margin, so these row bands butt straight up against each other.
   That only shows when the row above ends in something tall: the "Service Game Win Rate"
   heading sat directly under a pie chart with nothing between them.

   Applied to the ROW, not the heading - spacing the heading alone would drop column 1 and
   leave the other two columns of the same band sitting high. Two classes in the selector so
   it out-specifies .section's margin shorthand without !important. */
.section.section-gap-top {
    margin-top: 1cm;
}

/*  COLUMN SETUP  */
.col {
    display: block;
    float: left;
    margin: 0% 0% 0% 0%;
    padding-left: 2px;
    padding-right: 2px;
}

.colwidespace {
    display: block;
    float: left;
    margin: 0% 0% 0% 0%;
    padding-left: 20px;
    padding-right: 20px;
}

.servecolblue {
    color: white;
    display: block;
    float: left;
    margin: 0% 0% 0% 0%;
    background-color: #0056B8;
    height: 20%;
    width: 20%;
}

.colwhite {
    color: black;
    display: block;
    float: left;
    margin: 0% 0% 0% 0%;
    /*    padding-left: 2px;
    padding-right: 2px;*/
    background-color: white;
    height: 100%;
}

.colwhitedisabled {
    color: grey;
    display: block;
    float: left;
    margin: 0% 0% 0% 0%;
    /*    padding-left: 2px;
    padding-right: 2px;*/
    background-color: white;
    height: 100%;
}

.colblue {
    color:white;
    display: block;
    float: left;
    margin: 0% 0% 0% 0%;
/*    padding-left: 2px;
    padding-right: 2px;*/
    background-color: #0056B8;
    height:100%;
}

.colbluedisabled {
    color: grey;
    display: block;
    float: left;
    margin: 0% 0% 0% 0%;
    /*    padding-left: 2px;
    padding-right: 2px;*/
    background-color: #0056B8;
    height: 100%;
}

.col:first-child {
    margin-left: 0;
}

/*  GROUPING  */
.group:before,
.group:after {
    content: "";
    display: table;
}

.group:after {
    clear: both;
}

.group {
    zoom: 1; /* For IE 6/7 */
}

/*  GRID OF TWO  */
.span_2_of_2 {
    width: 100%;
}

.span_1_of_2 {
    width: 49.2%;
}

.span_1_of_5 {
    width: 20%;
}

/*  GO FULL WIDTH AT LESS THAN 480 PIXELS */
/*
                                    @@media only screen and (max-width: 480px) {
                                        .col {
                                            margin: 1% 0 1% 0%;
                                        }
                                    }*/

/*  GRID OF THREE  */
.span_3_of_3 {
    width: 100%;
}

.span_2_of_3 {
    width: 66.13%;
}

.span_1_of_3 {
    width: 33%;
}

.span_1_of_4 {
    width: 25%;
}

.span_1_of_4 {
    width: 20%;
}

.tagger{
    width:500px;
}


.headertext {
    font-size:12px;
}

.disabledheadertext {
    font-size: 12px;
    color:darkgray;
}

/*@@media screen and (min-width: 601px) {
    .headertext {
        font-size: 12px;
        font-weight: Bold;
    }
}

@@media screen and (max-width: 600px) {
    .headertext {
        font-size: 10px;
        font-weight: Bold;
    }
}*/

@media only screen and (max-width: 480px) {
    .span_2_of_2, .span_1_of_2 {
        width: 100%;
    }

    .span_1_of_4, .span_2_of_4, .span_3_of_4, .span_4_of_4, .span_1_of_5 {
        width: 100%;
    }

    .span_3_of_3, .span_2_of_3, .span_1_of_3 {
        width: 100%;
    }
}

@media only screen and (max-width: 600px) {
    .span_1_of_2_wide, .span_1_of_5 {
        width: 100%;
    }
    .blank_avatar {
        display:none !important;
    }
    .blank_avatar_small {
        display: block !important;
    }
    .summary_chart {
        width: 500px !important;
        height: 240px !important;
    }
    .largeavatar {
        /* make a square container */
        width: 60px !important;
        height: 60px !important;
        /* fill the container, preserving aspect ratio, and cropping to fit */
        background-size: cover;
        /* center the image vertically and horizontally */
        background-position: top center;
        /* round the edges to a circle with border radius 1/2 container size */
        border-radius: 50%;
    }

    .tinyavatar {
        /* make a square container */
        width: 30px;
        height: 30px;
        /* fill the container, preserving aspect ratio, and cropping to fit */
        background-size: cover;
        /* center the image vertically and horizontally */
        background-position: top center;
        /* round the edges to a circle with border radius 1/2 container size */
        border-radius: 50%;
    }
}

.span_1_of_2_wide {
    width: 49.2%;
}

/*  GRID OF FOUR  */
.span_4_of_4 {
    width: 100%;
}

.span_3_of_4 {
    width: 74.6%;
}

.span_2_of_4 {
    width: 49.2%;
}

.span_1_of_4 {
    width: 23.8%;
}

/*  GO FULL WIDTH BELOW 480 PIXELS */
/*@@media only screen and (max-width: 480px) {
    .col {
        margin: 1% 0 1% 0%;
    }

    .span_1_of_4, .span_2_of_4, .span_3_of_4, .span_4_of_4 {
        width: 100%;
    }
    .tagger
        {
        width:100%;
    }
}*/

@media only screen and (min-width: 852px) and (orientation: portrait)
{
    .tagger {
        width: 100%;
    }
}
/*  GRID OF SIX  */
.span_6_of_6 {
    width: 100%;
}

.span_5_of_6 {
    width: 83.33%;
}

.span_4_of_6 {
    width: 66.66%;
}

.span_3_of_6 {
    width: 50%;
}

.span_2_of_6 {
    width: 33.33%;
}

.span_1_of_6 {
    width: 16.66%;
}

/*  GO FULL WIDTH BELOW 480 PIXELS */
@media only screen and (max-width: 480px) {
    .col {
        margin: 1% 0 1% 0%;
    }

    .span_1_of_6, .span_2_of_6, .span_3_of_6, .span_4_of_6, .span_5_of_6, .span_6_of_6 {
        width: 100%;
    }

    .largeavatar {
        /* make a square container */
        width: 20px;
        height: 20px;
        /* fill the container, preserving aspect ratio, and cropping to fit */
        background-size: cover;
        /* center the image vertically and horizontally */
        background-position: top center;
        /* round the edges to a circle with border radius 1/2 container size */
        border-radius: 50%;
    }

    .tinyavatar {
        /* make a square container */
        width: 8px;
        height: 8px;
        /* fill the container, preserving aspect ratio, and cropping to fit */
        background-size: cover;
        /* center the image vertically and horizontally */
        background-position: top center;
        /* round the edges to a circle with border radius 1/2 container size */
        border-radius: 50%;
    }

    .largepiechart {
        width: 50px;
        height: 50px;
    }

    .h1
    {
        font-size:1em;
    }
}

.summary_chart {
    width: 300px;
    height: 120px;
}
.blank_avatar {
    display: block;
}

.blank_avatar_small {
    display: none;
}

.largeavatar {
    /* make a square container */
    width: 100px;
    height: 100px;
    /* fill the container, preserving aspect ratio, and cropping to fit */
    background-size: cover;
    /* center the image vertically and horizontally */
    background-position: top center;
    /* round the edges to a circle with border radius 1/2 container size */
    border-radius: 50%;

}

.tinyavatar {
    /* make a square container */
    width: 40px;
    height: 40px;
    /* fill the container, preserving aspect ratio, and cropping to fit */
    background-size: cover;
    /* center the image vertically and horizontally */
    background-position: top center;
    /* round the edges to a circle with border radius 1/2 container size */
    border-radius: 50%;
}

.largepiechart {
    width: 250px;
    height: 250px;
}

.blankavatar {
    fill: darkgray;
    opacity: 0.5;
}

.e-list-item-header {
    font-family: HelveticaNeue-Bold, 'Segoe UI' !important;
    font-size: 14px !important;
    color: #000000 !important;
}

/* #1066 - the player's name in the team player list (PlayerList.razor), in the brand typeface and ink
   (www.135ti.com, as measured for #822). It used .e-list-item-header above, whose HelveticaNeue-Bold is a
   Mac-only font name: Windows fell back to Segoe UI while the lines under the name were Arial. */
.player-list-name {
    font-family: Raleway, Arial, sans-serif;
    font-weight: 700;
    font-size: 15px;
    color: #263746;
}

/* #1080 - the message text in a dialog. It used .e-list-item-header too, and that rule's !important beat the
   #888 dialog style, so with the preview on the title was Raleway and the message under it Segoe UI. Outside
   the preview this keeps the old values, so a dialog looks exactly as it did; body.ui-next .dialog-message in
   the #888 block below gives it the dialog's own typeface. No !important on either: nothing else names it. */
.dialog-message {
    font-family: HelveticaNeue-Bold, 'Segoe UI';
    font-size: 14px;
    color: #000000;
}

.clickable-grid .dxbl-grid-data-row {
    cursor: pointer;
}

.clickable-grid .dxbl-grid-data-row:hover td {
    background-color: rgba(0, 86, 184, 0.06) !important;
}

.ballbutton {
    background-color: #0056B8;
    border: none;
}

.ballbuttondisabled {
    background-color: #0056B8;
    border: none;
    opacity: 0.5;
}

@media only screen and (max-width: 480px) {
    .ballbutton {
        width: 30px;
        background-color: #0056B8;
        border: none;
    }

    .ballbuttondisabled {
        width: 30px;
        background-color: #0056B8;
        border: none;
        opacity: 0.5;
    }

    .contentdiv {
        max-width: none !important;
        z-index: 50;
        margin-top: 90px;
    }
}

/* #828 - required-field marker. The portal had no way of showing which fields are mandatory;
   this is the pattern. aria-hidden on the asterisk itself keeps it out of the accessible name,
   which the validation message already covers properly. */
/* Specificity and !important are deliberate. site.css is linked BEFORE the Syncfusion and
   DevExpress theme stylesheets in _Host.cshtml, so a theme rule of equal specificity that colours
   content inside a form caption wins on order alone - which is why a plain .required-marker
   rendered in the caption's inherited colour rather than red. Scoped to this one marker. */
span.required-marker {
    color: #b3261e !important;
    font-weight: 600;
    margin-left: 0.15rem;
}


/* #829 - lifted out of PlayerProfile.razor's private style block: the Add Player dialog on
   TeamDashboard now uses the same layout, and duplicating them would let the two drift. */
/* #824/#829 - replaces the MudBlazor FAB, so the dialog is DevExpress throughout. */
.load-photo-button {
    cursor: pointer;
}
/* #824/#829 - picture and button on one row instead of stacked. Wraps on a narrow screen so the
   button drops under the circle rather than overflowing. */
.photo-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
}

/* #837 - the scrolling body of a dialog's BodyTemplate.

   The max-height and overflow-y are the mechanism, and they are not decoration. An earlier pass
   removed them on the theory that DevExpress's Scrollable="true" replaces them: Scrollable does
   add .dxbl-popup-scrollable, and the theme really does give .dxbl-modal-body overflow-y:auto
   under it. In this app that does not produce a usable scrollbar - measured, on both a dialog
   that had Scrollable all along (New Player, Save at y=978 with the window too short) and on
   Edit Player after its own container was taken away. Reading the stylesheet was not enough.

   So this is back to the shape that was actually observed working, and every long form dialog
   now shares it rather than one dialog carrying a private copy.

   The height is keyed to the popup's own MaxHeight="90vh" rather than being a flat 80vh. The
   header sits above this and costs about 3.5rem, so a flat 80vh overflows the popup's cap once
   the window is short: at a 349px viewport 80vh is 279px and the header takes it to 335px
   against a 314px cap, and the popup clips exactly where it is supposed to scroll. Subtracting
   4rem keeps the body inside the cap at every height. */
.dialog-body {
    padding: 1rem;
    max-height: calc(90vh - 4rem);
    overflow-y: auto;
}

/* #838 - the sign-up QR code. Capped rather than sized: the image is generated at 20 pixels per
   module so it stays sharp when saved and printed, which is larger than it needs to be on screen. */
.qr-code-image {
    width: 100%;
    max-width: 260px;
    height: auto;
    image-rendering: pixelated;
}

/* The encoded URL, shown as selectable text so it can be pasted into an email rather than only
   scanned. Subscribe URLs carry a GUID and sometimes a product id, so they have to wrap. */
.qr-code-url {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8rem;
    overflow-wrap: anywhere;
    word-break: break-all;
    user-select: all;
    margin: 0;
}

/* #862 - the per-package sign-up code button on Edit Team. A link-styled button so it sits with the
   Remove link beside it, but holding an icon rather than the word "QR". The line-height reset stops
   Bootstrap's button padding pushing the row taller than the other grid cells. */
.qr-icon-button {
    line-height: 1;
    vertical-align: middle;
}

/* #861 - a hint that only means anything to a finger, so it is hidden unless the pointer is one.
   Hidden by default rather than shown by default: a desktop is the case that must not change, and
   the two queries together are what separate a phone or tablet from a laptop with a touchscreen. */
.touch-only {
    display: none;
}

@media (hover: none) and (pointer: coarse) {
    .touch-only {
        display: block;
    }
}

/* #831 - separates the Save/Cancel bar from the form above it. Referenced by both Add Player
   dialogs as well as Edit Player, so it cannot live in one page's own <style> block. */
.action-section {
    padding-top: 1rem;
}

/* #831 - the player photo preview and its empty-state placeholder. Both dialogs that show a photo
   row live on different pages (Edit Player on PlayerProfile, Add Player on TeamDashboard), so these
   have to be global rather than sitting in either page's own <style> block. */
.player-photo-preview {
    width: 75px;
    height: 75px;
    border-radius: 50%;
    object-fit: cover;
}

.no-photo-placeholder {
    width: 75px;
    height: 75px;
    border-radius: 50%;
    background-color: lightgray;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* #824/#829 - referenced by the action bar and defined nowhere, so the validation summary and the
   buttons had no relationship to each other. flow-root contains the buttons' float, which is
   what previously let the dialog's bottom padding collapse. */
.form-actions {
    display: flow-root;
    padding-top: 0.5rem;
    border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.form-section {
    margin-bottom: 1.5rem;
}
.section-header {
    font-weight: 600;
    margin-bottom: 0.5rem;
}
/* #836 - space above every section heading except the first, so a heading reads as belonging to
   the fields below it rather than the ones above. PADDING, not margin: .form-section has no
   padding or border, so a heading's margin-top collapses into the previous section's 1.5rem
   margin-bottom and the larger wins. Measured on the Test slot - margin-top: 20px left the gap at
   exactly 24px; this padding took it to 37px above the heading against 9px below it.

   Edit Team is one DxFormLayout with @if (isGTAdmin) inline, so its headings cannot be wrapped in
   .form-section and are full-width layout items instead (#830). Those items render as siblings in
   one row, so .section-header-item - our class, not DevExpress's dxbl-fl-* internals - picks out
   every heading after the first the same way. */
.form-section + .form-section > .section-header,
.section-header-item:not(:first-child) .section-header {
    padding-top: 0.75rem;
}
.action-buttons
{
    float:right;
}
/* #824/#829 - phone. Bootstrap 4's sm breakpoint, so this agrees with the ColSpanSm the
   form layout uses rather than inventing another number. Stack the buttons full width
   and let the grid keep its own horizontal scroll. */
@media (max-width: 575.98px) {
    .action-buttons {
        float: none;
        display: flex;
        flex-direction: column;
        gap: 0.5rem;
    }

    .action-buttons .dxbl-btn {
        width: 100%;
    }

    .dialog-body {
        padding: 0.75rem;
    }
}

/* #824/#829 - the credit columns total ~890px of explicit width. Rather than let them truncate on
   a narrow screen, the grid scrolls inside its own box so the dialog itself never scrolls
   sideways. Used by both the Edit Player and Add Player dialogs. */
.service-credits-wrapper {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* #830 - hex text box plus a swatch that opens the browser colour picker. The swatch is sized to
   match the text box height so the pair reads as one control. */
.colour-field {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.colour-field .colour-field-text {
    flex: 1 1 auto;
    min-width: 0;
}

.colour-field-swatch {
    flex: 0 0 auto;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0.15rem;
    border: 1px solid rgba(0, 0, 0, 0.2);
    border-radius: 3px;
    background: transparent;
    cursor: pointer;
}

.colour-field-swatch:disabled {
    cursor: default;
    opacity: 0.5;
}

/* ==========================================================================
   #864 - the reworked Point Analysis layout, behind the #863 trial toggle.
   Every rule is prefixed .pa- and lives inside .pa-shell, so none of it can
   reach the existing tab, which renders the other branch of the markup.
   ========================================================================== */

/* Rail beside results rather than filters-then-results on separate screens.
   minmax(0,1fr) on the main column matters: without the 0 minimum a wide grid
   refuses to shrink and pushes the rail off screen. */
.pa-shell {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 1rem;
    align-items: start;
    padding-top: 0.5rem;
}

/* The measured failure of the old tab was 481-1000px, where three float columns
   stayed side by side and truncated their values mid-digit. One breakpoint, and
   below it the rail sits above the results instead of beside them. */
@media (max-width: 1000px) {
    .pa-shell {
        grid-template-columns: minmax(0, 1fr);
    }

    .pa-rail {
        position: static;
        max-height: 20rem;
    }
}

.pa-rail {
    position: sticky;
    top: 0.5rem;
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    border: 1px solid #dee2e6;
    border-radius: 4px;
    background: #fff;
}

.pa-rail-head {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: 0.5rem;
    background: #fff;
    border-bottom: 1px solid #dee2e6;
}

.pa-rail-body {
    padding: 0.25rem 0.5rem 0.75rem;
}

.pa-group + .pa-group {
    margin-top: 0.5rem;
}

.pa-group-head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0.5rem 0 0.25rem;
    font-size: 0.8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #495057;
}

.pa-group-toggle {
    cursor: pointer;
    user-select: none;
}

.pa-caret {
    width: 0.75rem;
    color: #868e96;
}

/* The badge is what makes collapsing safe - a shut group still says that
   something inside it is filtering. */
.pa-badge {
    margin-left: auto;
    min-width: 1.25rem;
    padding: 0 0.35rem;
    border-radius: 999px;
    background: #0056b8;
    color: #fff;
    font-size: 0.7rem;
    line-height: 1.25rem;
    text-align: center;
}

.pa-block {
    margin-bottom: 0.5rem;
}

.pa-block-head {
    font-size: 0.75rem;
    font-weight: 600;
    color: #6c757d;
    margin-bottom: 0.15rem;
}

/* 0.8rem, not the 10px the old grid forced. Small enough for a dense rail and
   still readable. */
.pa-stat {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
    padding: 0.15rem 0.25rem;
    font-size: 0.8rem;
    border-radius: 3px;
    cursor: pointer;
}

.pa-stat:hover {
    background: #f1f3f5;
}

.pa-stat-text {
    flex: 1 1 auto;
    min-width: 0;
}

/* The count must never be the thing that gets clipped - it is the reason the
   row is there. The label wraps instead. */
.pa-stat-num {
    flex: 0 0 auto;
    color: #6c757d;
    font-variant-numeric: tabular-nums;
}

/* "No points did this" is an answer, so the row stays and is muted rather than
   removed - a list that changes length while you filter is hard to follow. */
.pa-stat-empty {
    opacity: 0.45;
}

/* #1094 - Server, Combined Length and Point Winner pinned in the sticky rail head,
   so the winner split stays in view while the filters below are set. One row per
   block: a short heading, then equal-width options showing the %. The count is in
   the tooltip: on the 3-option row each button is ~66px, and "100.00% (1234)"
   wrapped every button to four lines, eating the narrow layout's 20rem rail. */
.pa-pinned {
    margin-top: 0.5rem;
}

.pa-pin-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.pa-pin-row + .pa-pin-row {
    margin-top: 0.3rem;
}

.pa-pin-head {
    flex: 0 0 4.75rem;
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1.1;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #495057;
}

.pa-pin-options {
    flex: 1 1 auto;
    min-width: 0;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: 0.25rem;
}

.pa-pin-option {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    margin: 0;
    padding: 0.15rem 0.2rem;
    border: 1px solid #ced4da;
    border-radius: 4px;
    font-size: 0.75rem;
    line-height: 1.15;
    text-align: center;
    cursor: pointer;
    user-select: none;
}

.pa-pin-option:hover {
    background: #f1f3f5;
}

/* The box itself is hidden; the whole option is the click target and its
   colour is the state. Still a real checkbox, so the keyboard reaches it. */
.pa-pin-option input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.pa-pin-option:focus-within {
    outline: 2px solid #0056b8;
    outline-offset: 1px;
}

.pa-pin-on,
.pa-pin-on:hover {
    background: #0056b8;
    border-color: #0056b8;
    color: #fff;
}

.pa-pin-text {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
}

.pa-pin-num {
    font-size: 0.68rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    opacity: 0.85;
}

.pa-video {
    color: #0056b8;
    font-size: 0.6rem;
}

.pa-main {
    min-width: 0;
}

/* Sticky, because the old tab put Show Points at the top only and it scrolled
   away long before the last filter. */
.pa-actionbar {
    position: sticky;
    top: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    padding: 0.5rem 0;
    background: #fff;
    border-bottom: 1px solid #dee2e6;
}

.pa-actionbar-spacer {
    flex: 1 1 auto;
}

.pa-count {
    font-size: 1.1rem;
}

.pa-count-of {
    color: #6c757d;
    font-size: 0.85rem;
}

.pa-working {
    color: #6c757d;
    font-size: 0.85rem;
}

.pa-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    padding: 0.5rem 0;
}

.pa-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.15rem 0.25rem 0.15rem 0.5rem;
    border: 1px solid #b8daff;
    border-radius: 999px;
    background: #e7f1ff;
    font-size: 0.78rem;
}

.pa-chip-key {
    color: #6c757d;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.pa-chip-x {
    border: 0;
    background: transparent;
    color: #495057;
    font-size: 1rem;
    line-height: 1;
    padding: 0 0.25rem;
    cursor: pointer;
}

.pa-chip-x:hover {
    color: #b00020;
}

.pa-empty {
    padding: 2rem 1rem;
    color: #6c757d;
    text-align: center;
}

/* Video and list side by side, and stacked once there is no room for both.
   The old tab's 75/25 split above 1600px left the point detail too narrow. */
/* #884 - the two columns are custom properties so the separator can move them.
   Unset they fall back to the even split this had before, so nothing changes
   until somebody drags. */
.pa-results {
    display: grid;
    grid-template-columns: minmax(0, var(--pa-video-col, 1fr)) auto minmax(0, var(--pa-list-col, 1fr));
    gap: 1rem;
    padding-top: 0.5rem;
}

/* #884 - the separator. role="separator" and tabindex on the element, so it is
   not a mouse-only control. */
.pa-splitter {
    width: 10px;
    align-self: stretch;
    justify-self: center;
    border: none;
    padding: 0;
    background: transparent;
    cursor: col-resize;
    touch-action: none;
    position: relative;
    border-radius: 999px;
}

/* The grabbable line. Drawn on a child pseudo-element rather than the element
   itself so the hit area stays a comfortable 10px while the line reads as 2px. */
.pa-splitter::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 4px;
    width: 2px;
    border-radius: 999px;
    background: #DBE5EF;
}

.pa-splitter:hover::before,
.pa-dragging .pa-splitter::before {
    background: #0056B8;
    left: 3px;
    width: 4px;
}

.pa-splitter:focus-visible {
    outline: 2px solid #0056B8;
    outline-offset: 1px;
}

/* While dragging, stop the pointer selecting text in either pane and stop the
   iframe-ish player swallowing the move events. */
.pa-results.pa-dragging {
    user-select: none;
}

.pa-results.pa-dragging .pa-video,
.pa-results.pa-dragging .pa-list {
    pointer-events: none;
}

/* Collapsed is a state, not a zero-width column: a zero column still renders the
   grid inside it and still takes focus.

   ⚠ THREE tracks, not two, and this is the bug that shipped in the first cut.
   The visible children are the video, the separator and - once collapsed - the
   restore rail: three items either way, because .pa-list and .pa-list-restore
   swap places and display:none takes an item out of the grid entirely. Declaring
   two tracks here left the third child to wrap into an implicit second row
   directly beneath .pa-video, which is where .pa-video-controls sits, so the
   restore button landed on top of the player's own buttons. */
.pa-results.pa-collapsed {
    grid-template-columns: minmax(0, var(--pa-video-col, 1fr)) auto auto;
}

.pa-results.pa-collapsed .pa-list {
    display: none;
}

/* The collapsed panel's edge, in the column the table vacated - which is where
   somebody looks for it. A rail rather than a pill: it cannot collide with
   anything because it is its own grid track. */
.pa-list-restore {
    display: none;
    align-items: center;
    justify-content: center;
    align-self: stretch;
    width: 28px;
    padding: 0;
    background: #fff;
    border: 1px solid #DBE5EF;
    border-radius: 10px;
    color: #0056B8;
    cursor: pointer;
}

.pa-list-restore:hover {
    border-color: #0056B8;
    background: #EAF2FA;
}

.pa-list-restore:focus-visible {
    outline: 2px solid #0056B8;
    outline-offset: 1px;
}

.pa-results.pa-collapsed .pa-list-restore {
    display: inline-flex;
}

@media (max-width: 1200px) {
    /* Stacked. The separator has no meaning between two rows, and this is the
       behaviour #884 must not break - it is why this is a CSS grid and not a
       DxSplitter, which sizes its panes with inline styles and has no
       responsive parameter to hand the layout back. */
    .pa-results,
    .pa-results.pa-collapsed {
        grid-template-columns: minmax(0, 1fr);
    }

    .pa-splitter,
    .pa-results.pa-collapsed .pa-list-restore {
        display: none;
    }

    /* A drag from a wider window must not leave the stacked layout collapsed. */
    .pa-results.pa-collapsed .pa-list {
        display: block;
    }
}

.pa-video-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    padding-top: 0.5rem;
}

.pa-list {
    min-width: 0;
}

/* 0.8rem rather than the 10px the old results grid forced on every cell. */
.pa-grid .e-grid .e-rowcell,
.pa-grid .e-grid .e-headercelldiv {
    font-size: 0.8rem;
}

/* ==========================================================================
   #822 - the reworked Player Profile layout, shown only to users who have the
   #863 preview preference on (renamed to NewLayout by #881).

   Every rule is prefixed .pp- and lives inside .pp-shell, so none of it can
   reach the existing header - which renders the other branch of the markup -
   or any of the SIXTEEN other pages that share the span_1_of_* float grid
   (Breakdown, TeamDashboard, PointTagger, MatchVideoTagger, Reports,
   ShotFilter and ten more). Same convention as the .pa- block above, and for
   the same reason.

   Values are measured off www.135ti.com, not invented: Raleway 700/800, blue
   #0056B8, lime #C4D600, ink #263746, slate #4F5C67, muted #93A1AD, cards at
   1px #DBE5EF on a 20px radius, and the site's own blue-tinted shadow on the
   one raised surface. The letterspaced uppercase label is the site's device.

   Breakpoints are Bootstrap 4's (sm 576 / md 768 / lg 992) so they line up
   with DevExpress ColSpanSm / ColSpanMd rather than inventing more ad-hoc
   max-width patches. The width that is actually broken in the old layout is
   481-1024px, where three 33% floats stay side by side.
   ========================================================================== */

/* The layout container the page has never had. Without this the header spreads
   five elements across 3400px with voids between them.

   TWO WIDTHS, deliberately. This one is the WORKING width: the Point Analysis
   tab is a 300px filter rail, a point grid and a video, and at 1280 the video
   column came out at 916px - so a 16:9 player 515px tall, smaller than it was
   before this container existed. The reading width below is what the header and
   the Profile tab keep. */
.pp-shell {
    max-width: 1760px;
    margin: 0 auto;
    padding: 1.5rem 1.5rem 2rem 1.5rem;
    font-family: Raleway, Arial, sans-serif;
    color: #263746;
}

/* ---- identity bar ---- */

/* ---- one width ----

   The header and the Profile card sit at the shell width, so they line up with
   the tab strip above them. An earlier pass capped these two narrower than the
   strip and it read as a mistake, which it was.

   The Profile grid's column count is what has to be controlled instead - see
   .pp-grid below. Leaving it on auto-fit at this width produced FOUR to FIVE
   columns, not three. */

.pp-shell .pp-identity {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    background: #fff;
    border: 1px solid #DBE5EF;
    border-radius: 20px;
    box-shadow: rgba(0, 86, 184, 0.16) 0 15px 35px 0;
    padding: 1.5rem 1.625rem;
    margin-bottom: 1.125rem;
}

.pp-shell .pp-avatar {
    width: 88px;
    height: 88px;
    flex-shrink: 0;
    border-radius: 50%;
    background: #0056B8;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.pp-shell .pp-avatar-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.pp-shell .pp-avatar-initials {
    font-size: 1.875rem;
    font-weight: 800;
    line-height: 1;
}

.pp-shell .pp-identity-main {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    flex-grow: 1;
    min-width: 0;
}

/* The old header put an h1 at Bootstrap's 2.5rem into a 234px inner column,
   where it wrapped to two or three lines. Grouped with the metadata it has the
   width to sit on one. */
.pp-shell .pp-name {
    font-size: 1.875rem;
    font-weight: 800;
    line-height: 1.1;
    margin: 0;
    color: #263746;
}

/* This line rendered at 11px in the old header and was simply lost. */
.pp-shell .pp-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.625rem;
    font-size: 0.9375rem;
    color: #4F5C67;
}

.pp-shell .pp-meta-dot {
    color: #93A1AD;
}

/* ---- team / coach / consultant, as chips rather than a third of the page each ---- */

.pp-shell .pp-people {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.6875rem;
}

.pp-shell .pp-chip {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.5rem 0.875rem 0.5rem 0.5625rem;
    border: 1px solid #DBE5EF;
    border-radius: 10px;
    text-decoration: none;
    color: inherit;
}

.pp-shell a.pp-chip:hover {
    border-color: #0056B8;
    text-decoration: none;
}

.pp-shell .pp-chip-badge {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 50%;
    background: #EEF3F7;
    color: #4F5C67;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.71875rem;
    font-weight: 700;
    overflow: hidden;
}

/* A club crest is not a face - square it off so it does not read as a person. */
.pp-shell .pp-chip-badge-team {
    border-radius: 8px;
    background: #EAF2FA;
    color: #0056B8;
}

.pp-shell .pp-chip-img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.pp-shell .pp-chip-img-round {
    object-fit: cover;
}

.pp-shell .pp-chip-text {
    display: flex;
    flex-direction: column;
    gap: 0.1875rem;
    min-width: 0;
}

.pp-shell .pp-chip-label {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: #93A1AD;
    line-height: 1;
}

.pp-shell .pp-chip-value {
    font-size: 0.84375rem;
    font-weight: 600;
    color: #263746;
    line-height: 1.3;
}

.pp-shell .pp-btn {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    height: 38px;
    padding: 0 0.9375rem;
    background: #fff;
    border: 1px solid #DBE5EF;
    border-radius: 10px;
    font-family: inherit;
    font-size: 0.84375rem;
    font-weight: 600;
    color: #263746;
    cursor: pointer;
}

.pp-shell .pp-btn:hover {
    border-color: #0056B8;
    color: #0056B8;
}

/* ---- the panel the tabs and their content sit in ---- */

/* The Profile tab's card. Full shell width, so its edges line up with the tab
   strip directly above it. */
.pp-shell .pp-panel {
    background: #fff;
    border: 1px solid #DBE5EF;
    border-radius: 20px;
    overflow: hidden;
}

/* ---- the summary grid on the Profile tab ---- */

/* Explicit column counts, NOT repeat(auto-fit, minmax(...)).

   #822 asked for auto-fit so the ladder needed no media queries, and that works
   while the container is a fixed 1280. It stops working once the shell is fluid
   up to 1760, and the arithmetic says so: for auto-fit to give three columns at
   a 1366 laptop AND still only three at 1760, the minmax minimum has to be more
   than 397.5px and no more than 406px. A nine-pixel window is not a design, it
   is a coincidence waiting to break - and at the 280px it was set to, a
   full-width panel produced four to five columns and shrank every chart.

   Three is the right count for six cells: two clean rows. Four leaves a ragged
   second row of two.

   minmax(0, 1fr) rather than a pixel minimum, so a column can never be wider
   than the space it has - the trap that makes an auto-fit grid overflow a phone
   sideways.

   Desktop-first to match the rest of this block, so the narrower overrides come
   after and win on source order. Bootstrap 4's breakpoints (md 768, xl 1200). */
.pp-shell .pp-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1.625rem 1.5rem;
    padding: 1.5rem;
}

@media (max-width: 1199.98px) {
    .pp-shell .pp-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.pp-shell .pp-cell {
    display: flex;
    flex-direction: column;
    gap: 0.9375rem;
    min-width: 0;
}

.pp-shell .pp-label {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: #93A1AD;
}

/* The 135 Benchmark is the headline number on the page and had no panel at all -
   a bare span at font-size: xx-large inside a .benchmarkdiv with no CSS. */
.pp-shell .pp-label-accent {
    color: #C4D600;
}

.pp-shell .pp-stat-panel {
    border: 1px solid #DBE5EF;
    border-radius: 20px;
    padding: 1.375rem 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.pp-shell .pp-stat {
    font-size: 3.5rem;
    font-weight: 800;
    line-height: 1;
    color: #263746;
    font-variant-numeric: tabular-nums;
}

.pp-shell .pp-stat-sub {
    font-size: 0.8125rem;
    color: #4F5C67;
}

.pp-shell .pp-stat-bar {
    height: 4px;
    border-radius: 999px;
    background: #C4D600;
    margin-top: 0.25rem;
}

/* ---- the video player is bounded by the viewport, not by the column ----

   For a 16:9 video the constraint that actually bites is HEIGHT, not width. The
   unconstrained layout this replaced was producing a player 1744px tall on a
   3440px monitor - taller than the screen - which pushed the point list off the
   bottom. Capping the width at 70vh worth of 16:9 makes the screen the limit:
   about 1792px wide on a 1440-tall display, about 1344px on a 1080 laptop, and
   the point list stays visible on both.

   Width only. The player sets its own height from its aspect ratio, so there is
   nothing here for Bitmovin to fight, and max-width never forces a size - a
   narrower column still wins.

   Targeted on the id rather than .pa-video, because #864 uses that class for two
   different things: this wrapper and the small "has video" dot in the match list.

   ⚠ This applies to the new layout only. The old layout has the same unbounded
   player and would benefit from the same cap, but changing it is outside #822 -
   the toggle has to put the existing page back exactly as it was. */
.pp-shell #bmplayer {
    max-width: calc(70vh * 16 / 9);
}

/* The pies size to their cell instead of rendering at a fixed 190px inside it.
   No max-width: a 260px cap made the CHART the limiting factor once the cells
   grew to ~538px, which is the same complaint in a different place.

   ⚠ The pie's HEIGHT is still Height="220px" in Profile.razor, so a wider cell
   buys a wider legend rather than a bigger pie. Raising it is a markup change
   and wants looking at on screen first. */
.pp-shell .pp-chart {
    width: 100%;
}

/* The win-rate tables used a .win-rate-table class that has no CSS anywhere, so
   they rendered as bare browser-default tables. */
.pp-shell .pp-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.84375rem;
}

.pp-shell .pp-table th {
    text-align: left;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: #93A1AD;
    padding: 0 0 0.5625rem 0;
    border-bottom: 1px solid #DBE5EF;
}

.pp-shell .pp-table td {
    padding: 0.625rem 0;
    border-bottom: 1px solid #EEF3F7;
    color: #263746;
}

.pp-shell .pp-table th.pp-num,
.pp-shell .pp-table td.pp-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.pp-shell .pp-table td.pp-num {
    font-weight: 700;
}

/* ---- md and below: the identity bar stops being one row ---- */

@media (max-width: 767.98px) {
    .pp-shell {
        padding: 1rem 0.875rem 1.5rem 0.875rem;
    }

    .pp-shell .pp-identity {
        flex-direction: column;
        align-items: flex-start;
        gap: 1rem;
        padding: 1rem;
        border-radius: 16px;
    }

    .pp-shell .pp-name {
        font-size: 1.4375rem;
    }

    .pp-shell .pp-meta {
        font-size: 0.8125rem;
        gap: 0.5rem;
    }

    /* Chips scroll sideways rather than stacking into a tall column: three of
       them stacked pushed the tabs below the fold on a phone. */
    .pp-shell .pp-people {
        flex-wrap: nowrap;
        overflow-x: auto;
        width: 100%;
        padding-bottom: 0.25rem;
    }

    .pp-shell .pp-grid {
        grid-template-columns: minmax(0, 1fr);
        padding: 1.125rem 1rem;
        gap: 1.25rem;
    }

    .pp-shell .pp-stat {
        font-size: 3rem;
    }

    /* 44px is the floor for a touch target. */
    .pp-shell .pp-btn {
        height: 44px;
    }
}

/* ==========================================================================
   #885 - the reworked site menu, shown only when the #863 preview preference
   is on (renamed NewLayout by #881).

   Every rule is prefixed .tb- and lives inside .tb-shell, so none of it can
   reach the existing DxMenu, which renders the other branch of MainLayout.
   Same convention as the .pa- (#864) and .pp- (#822) blocks above.

   Values are the marketing site's, measured off www.135ti.com: Raleway 600 at
   16px for nav, blue #0056B8, and LIME #C4D600 as the active state - which is
   what the site's own nav does, so this is the brand's real navigation rather
   than an approximation of it.
   ========================================================================== */

.tb-shell {
    font-family: Raleway, Arial, sans-serif;
}

.tb-shell .tb-bar {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    height: 60px;
    padding: 0 1rem 0 1.25rem;
    background: #0056B8;
}

/* The bar is 90px today ONLY because MarketingLogo.png is 117x82. At 60px it
   reduces to 68x48 and gets tight. A horizontal lockup is the right asset and
   is wanted for email and PDF headers anyway - see the work item. */
.tb-shell .tb-logo {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

.tb-shell .tb-logo img {
    height: 48px;
    width: 68px;
}

.tb-shell .tb-groups {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    flex-grow: 1;
    margin: 0;
    padding: 0;
    list-style: none;
}

.tb-shell .tb-group {
    position: relative;
}

/* One rule for the links and the submenu buttons, so a group heading and a
   plain destination cannot drift apart. */
.tb-shell .tb-top {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    height: 60px;
    padding: 0 1rem;
    background: transparent;
    border: none;
    font-family: inherit;
    font-size: 1rem;
    font-weight: 600;
    color: rgba(255, 255, 255, .88);
    white-space: nowrap;
    cursor: pointer;
    text-decoration: none;
    box-shadow: inset 0 -3px 0 transparent;
}

.tb-shell .tb-top:hover {
    color: #fff;
    text-decoration: none;
}

/* The active-page indicator. The old menu had NOTHING - nothing in it told you
   where you were. Lime, because that is what the marketing site's nav uses. */
.tb-shell .tb-on {
    color: #C4D600;
    box-shadow: inset 0 -3px 0 #C4D600;
}

.tb-shell .tb-top:focus-visible,
.tb-shell .tb-icon-btn:focus-visible,
.tb-shell .tb-avatar:focus-visible {
    outline: 2px solid #C4D600;
    outline-offset: -2px;
}

/* 18px, stroke 1.85 - the same set and weight already shipped in
   PlayerIdentityBar (#822). Retires the oi oi-* glyphs in this path: SIX of the
   eleven items shared oi oi-list-rich, so the icons carried no information. */
.tb-shell .tb-icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}

.tb-shell .tb-caret {
    width: 13px;
    height: 13px;
    flex-shrink: 0;
    opacity: .75;
}

/* ---- submenus ---- */

.tb-shell .tb-menu {
    display: none;
    position: absolute;
    top: 60px;
    left: 0;
    z-index: 1200;
    min-width: 200px;
    margin: 0;
    padding: 0.375rem;
    list-style: none;
    background: #fff;
    border: 1px solid #DBE5EF;
    border-radius: 10px;
    box-shadow: rgba(0, 86, 184, 0.16) 0 15px 35px 0;
}

/* Hover AND focus-within, so the submenus are reachable by keyboard rather than
   being a mouse-only affordance. */
.tb-shell .tb-group:hover .tb-menu,
.tb-shell .tb-group:focus-within .tb-menu {
    display: block;
}

/* Clicking a menu item leaves focus on it - Blazor navigates without a reload and
   the bar is part of the layout, so :focus-within above would hold the menu open
   until you clicked somewhere else. site-menu.js sets this on click and clears it
   as soon as the pointer leaves the group.

   Same specificity as the two rules above, so it has to come AFTER them to win. */
.tb-shell .tb-group.tb-dismissed .tb-menu {
    display: none;
}

.tb-shell .tb-menu-right {
    left: auto;
    right: 0;
}

.tb-shell .tb-menu a {
    display: block;
    padding: 0.5rem 0.75rem;
    border-radius: 7px;
    font-size: 0.9375rem;
    font-weight: 500;
    color: #263746;
    text-decoration: none;
    white-space: nowrap;
}

.tb-shell .tb-menu a:hover {
    background: #EAF2FA;
    color: #0056B8;
    text-decoration: none;
}

.tb-shell .tb-menu-head {
    padding: 0.375rem 0.75rem 0.5rem 0.75rem;
    margin-bottom: 0.25rem;
    border-bottom: 1px solid #EEF3F7;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: #93A1AD;
}

/* Development-only tools, set apart from the admin pages that ship. */
.tb-shell .tb-sep {
    margin-top: 0.25rem;
    padding-top: 0.375rem;
    border-top: 1px solid #EEF3F7;
}

/* ---- right-hand side ---- */

.tb-shell .tb-right {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}

.tb-shell .tb-icon-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border: none;
    background: transparent;
    border-radius: 999px;
    color: rgba(255, 255, 255, .88);
    cursor: pointer;
}

.tb-shell .tb-icon-btn:hover {
    background: rgba(255, 255, 255, .14);
    color: #fff;
}

/* A distinct avatar for the new bar.

   CORRECTION: an earlier note here claimed .avatar-circle had no CSS anywhere and
   that the existing avatar was not round. Both were wrong. MainLayout.razor
   carries a <style> block defining .avatar-circle at 34px with border-radius:50%,
   plus .avatar-img, .avatar-initials, .menu_item and .fixed - it was missed by
   searching the .css files only. The existing avatar IS a circle.

   This one exists because the bar is a different component with its own scope,
   not because the old one was broken. It is 38px against 34px and takes its
   colours from the measured site palette. */
.tb-shell .tb-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    padding: 0;
    overflow: hidden;
    border: none;
    border-radius: 50%;
    background: #C4D600;
    font-family: inherit;
    font-size: 0.84375rem;
    font-weight: 700;
    color: #263746;
    cursor: pointer;
}

.tb-shell .tb-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ⚠ The 90px that has to come OFF the content.

   MainLayout.razor carries a <style> block - not a stylesheet, which is why no
   search of the css files finds it - setting

       .contentdiv { padding: 20px; margin-top: 90px; }

   That margin exists to clear the existing header, which really is fixed: the
   same block defines .fixed with top/left/width and a z-index. It is 90px because
   MarketingLogo.png is 117x82.

   This bar is 60px AND in normal flow, so the margin is not just unnecessary, it
   is additive: 60 + 90 = 150px of nothing between the bar and the page.

   Two classes beats the one in that style block, so this wins on specificity
   rather than on source order - which matters, because a block inside the markup
   comes after every stylesheet link in the document. The padding stays: that is
   the page's own gutter, not header clearance. */
.contentdiv.tb-flow {
    margin-top: 0;
}

/* ---- md and below ---- */

@media (max-width: 767.98px) {
    /* The same block drops the content margin to 50px below 768px. Still additive. */
    .contentdiv.tb-flow {
        margin-top: 0;
    }

    .tb-shell .tb-bar {
        gap: 0.5rem;
        padding: 0 0.5rem;
        flex-wrap: wrap;
        height: auto;
        min-height: 56px;
    }

    .tb-shell .tb-logo img {
        height: 40px;
        width: 57px;
    }

    /* The groups take the full width on their own row and scroll sideways,
       rather than collapsing into a hamburger. Four groups fit; eleven items
       never would, which is what the grouping bought. */
    .tb-shell .tb-groups {
        order: 3;
        width: 100%;
        overflow-x: auto;
        gap: 0;
    }

    .tb-shell .tb-top {
        height: 48px;
        padding: 0 0.75rem;
        font-size: 0.9375rem;
    }

    /* A submenu pinned to a scrolling row would be clipped by its own overflow,
       so on a phone the group opens as a full-width sheet under the bar. */
    .tb-shell .tb-menu {
        position: fixed;
        top: auto;
        left: 0.5rem;
        right: 0.5rem;
        min-width: 0;
    }

    .tb-shell .tb-right {
        margin-left: auto;
    }
}


/* ==========================================================================
   #888 - one shared dialog style, for DevExpress AND Syncfusion dialogs.

   EVERY rule below is under body.ui-next, which _Host.cshtml emits only when
   the #881 preview preference is on. With the toggle off the class is absent,
   so not one of these selectors matches and no dialog changes in any way. That
   is the whole scoping mechanism - there is nothing to prefix and nothing to
   nest, because the gate is on the document.

   A body class rather than an ancestor in the component tree, because DxPopup
   and SfDialog render PORTALED - measured: the popup's parent chain is
   .dxbl-modal > .dxbl-popup-cell > DXBL-POPUP-ROOT, a sibling of the whole
   component tree - and MainLayout's own MFA popup is outside any page
   container regardless.

   ⚠ THE TWO LIBRARIES ARE STYLED BY DIFFERENT MECHANISMS. That is deliberate,
   and it was measured in the browser rather than inferred from the theme CSS.

   DevExpress is styled by OVERRIDING ITS TOKENS, not by selector. Its theme
   styles the popup through
       .dxbl-modal > .dxbl-modal-root > .dxbl-popup > .dxbl-modal-content
   which is FOUR classes, and the header through six. A plain
   "body.ui-next .dxbl-modal-content" is two classes and one element, so it
   LOSES - and it loses SILENTLY AND PARTIALLY, which is what made the first
   attempt so hard to see: border and max-width landed, because the theme rule
   does not set those, while border-radius, box-shadow and font-family did
   not. The dialog looked untouched while three of its properties were ours.

   Those theme rules read var(--dxbl-popup-*), and the tokens are declared on
   ".dxbl-modal" - ONE class. So "body.ui-next .dxbl-modal" outranks the
   declaration, and the theme then computes OUR values in its own rules. It
   also survives a DevExpress upgrade, which a hand-copy of their descendant
   chain would not.

   Syncfusion exposes no equivalent token layer, so it keeps direct rules.

   ⚠ A DxPopup HAS NO .dxbl-modal-body ELEMENT. Measured structure:
       div.dxbl-modal-content
         dxbl-popup-header.dxbl-modal-header   (a custom element)
         div.<the page's own container>        <- the body IS the page markup
         div.dxbl-modal-footer
   The first pass styled .dxbl-modal-body, which matched nothing at all. The
   body is spaced by --dxbl-popup-body-padding-* instead.

   site.css is linked BEFORE both theme stylesheets, so a rule of equal
   specificity would lose on source order regardless.

   Values are the marketing site's, as measured for #822: Raleway, ink #263746,
   slate #4F5C67, 1px #DBE5EF, 20px radius, and the blue-tinted shadow.
   ========================================================================== */

/* ---- DevExpress: the token layer ----------------------------------------
   Verified on screen against the Video Details dialog: radius, shadow,
   Raleway, header and footer padding, and both surface colours all resolve
   from here. */
body.ui-next .dxbl-modal {
    --dxbl-popup-border-radius: 20px;
    --dxbl-popup-border-color: #DBE5EF;
    --dxbl-popup-border-width: 1px;
    --dxbl-popup-shadow: rgba(0, 86, 184, .16) 0 15px 35px 0;
    --dxbl-popup-font-family: Raleway, Arial, sans-serif;
    --dxbl-popup-color: #263746;
    --dxbl-popup-bg: #fff;
    /* Header white, not the theme grey, so the title reads as a heading
       rather than a title bar. */
    --dxbl-popup-header-bg: #fff;
    --dxbl-popup-header-color: #263746;
    --dxbl-popup-header-font-size: 1.125rem;
    --dxbl-popup-header-font-weight: 800;
    --dxbl-popup-header-padding-x: 1.375rem;
    --dxbl-popup-header-padding-y: 1.125rem;
    --dxbl-popup-header-btn-color: #93A1AD;
    --dxbl-popup-header-btn-hover-color: #0056B8;
    --dxbl-popup-body-padding-x: 1.375rem;
    --dxbl-popup-body-padding-y: 1.375rem;
    --dxbl-popup-footer-bg: #F4F7FA;
    --dxbl-popup-footer-padding-x: 1.375rem;
    --dxbl-popup-footer-padding-y: 1rem;
    /* ⚠ Backdrop colour AND opacity, both as tokens, never as a direct rule.
       An rgba() background is multiplied BY this opacity - a direct
       rgba(...,.45) rule alongside opacity .45 measured about 20% on screen,
       far too pale to read as a modal. */
    --dxbl-popup-back-bg: #091426;
    --dxbl-popup-back-opacity: .45;
}

/* ⚠ The one rule here that fixes a live bug rather than restyling anything,
   and the one DevExpress rule that is NOT a token - there is no token for a
   cap that has to know the viewport.

   DevExpress puts a fixed margin:28px on its popup, so any width above
   100vw - 56px is clipped on the right - 96vw overflowed by 8px at a 500px
   viewport, measured. #840 is the same bug from the other direction: the
   Verify Email dialog is a fixed 450px and overflows a phone at both edges.

   This one WINS on its own because the theme chain does not set max-width;
   confirmed on screen as min(100%, 2082px). It cannot make a dialog larger -
   min() only ever takes the smaller. */
body.ui-next .dxbl-modal-content {
    max-width: min(100%, calc(100vw - 56px));
}

/* #906 - round the footer's bottom corners to match the popup. The theme rounds the HEADER's top
   corners from the radius token but gives the FOOTER only a background, and the popup does not
   clip (overflow: visible). Invisible while the footer was the dialog's own colour; once
   --dxbl-popup-footer-bg above tinted it, its square corners painted over the rounded bottom of
   every footer dialog. The footer's ::before layer inherits this radius, so one rule covers both.
   Same calc the theme uses for the header, so the phone radius flows through it. Like the cap
   above, it wins alone: the theme's footer rule sets no radius to outrank. */
body.ui-next .dxbl-modal-content > .dxbl-modal-footer {
    border-bottom-left-radius: calc(var(--dxbl-popup-border-radius) - var(--dxbl-popup-border-width));
    border-bottom-right-radius: calc(var(--dxbl-popup-border-radius) - var(--dxbl-popup-border-width));
}

/* ---- Syncfusion: direct rules, no token layer to aim at ------------------
   ⚠ NOT yet confirmed on screen - no SfDialog was open during the #888
   browser pass. The DevExpress half above was measured; this half is written
   to the same values but still needs a look before it can be called done. */

body.ui-next .e-dialog {
    border: 1px solid #DBE5EF;
    border-radius: 20px;
    box-shadow: rgba(0, 86, 184, .16) 0 15px 35px 0;
    font-family: Raleway, Arial, sans-serif;
    color: #263746;
    overflow: hidden;
    max-width: min(100%, calc(100vw - 56px));
}

body.ui-next .e-dlg-header-content {
    padding: 1.125rem 1.375rem;
    background: #fff;
    border-bottom: 1px solid #DBE5EF;
}

body.ui-next .e-dlg-header {
    font-family: Raleway, Arial, sans-serif;
    font-size: 1.125rem;
    font-weight: 800;
    line-height: 1.2;
    color: #263746;
}

body.ui-next .e-dlg-closeicon-btn {
    color: #93A1AD;
}

body.ui-next .e-dlg-closeicon-btn:hover {
    color: #0056B8;
}

body.ui-next .e-dlg-content {
    padding: 1.375rem;
    font-family: Raleway, Arial, sans-serif;
    font-size: 0.9375rem;
    color: #263746;
}

/* #1080 - a dialog's message, in both libraries: the same typeface, size and ink as the Syncfusion body
   above, and as the DevExpress body tokens. It has to be stated rather than inherited, because the plain
   .dialog-message rule above sets the old values on the span itself. */
body.ui-next .dialog-message {
    font-family: Raleway, Arial, sans-serif;
    font-size: 0.9375rem;
    line-height: 1.5;
    color: #263746;
}

body.ui-next .e-footer-content {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.625rem;
    padding: 1rem 1.375rem;
    background: #F4F7FA;
    border-top: 1px solid #DBE5EF;
}

body.ui-next .e-dlg-container .e-dlg-overlay {
    background: rgba(9, 20, 38, .45);
}

/* ---- the scrolling body, shared ------------------------------------------
   ⚠ .dialog-body is #837 and it is the MECHANISM by which a long dialog
   scrolls here - not decoration. DxPopup Scrollable="true" does add
   .dxbl-popup-scrollable and the theme really does give .dxbl-modal-body an
   overflow-y under it, but in this app that does not produce a usable
   scrollbar. Measured, twice, after an earlier pass removed the max-height on
   the theory that Scrollable replaced it.

   It is the page's own class, so it faces no theme rule and needs no token.

   ⚠ #836 - the padding READS the body tokens rather than being dropped in
   favour of them. Nothing else applies them here: in a DxPopup with a
   BodyTemplate, .dialog-body is a direct child of .dxbl-modal-content, and
   every element up to the popup measured padding: 0px. Dropping it put every
   field in all seven .dialog-body dialogs flush against the dialog's edges.
   Reading the tokens keeps the body in step with the header and footer, and
   picks up the phone value from the media block below without restating it. */
body.ui-next .dialog-body {
    padding: var(--dxbl-popup-body-padding-y) var(--dxbl-popup-body-padding-x);
    max-height: calc(90vh - 8rem);
    overflow-y: auto;
}

/* ---- narrow screens ---- */

@media (max-width: 575.98px) {
    /* On a phone the 28px-a-side margin is most of the screen, so the dialog
       goes nearly full width and loses the big radius, which reads as a sheet
       rather than a shrunken desktop dialog. */
    body.ui-next .dxbl-modal {
        --dxbl-popup-border-radius: 14px;
        --dxbl-popup-header-padding-x: 1rem;
        --dxbl-popup-body-padding-x: 1rem;
        --dxbl-popup-footer-padding-x: 1rem;
    }

    body.ui-next .dxbl-modal-content {
        max-width: calc(100vw - 16px);
    }

    body.ui-next .e-dialog {
        max-width: calc(100vw - 16px);
        border-radius: 14px;
    }

    body.ui-next .e-dlg-header-content,
    body.ui-next .e-dlg-content,
    body.ui-next .e-footer-content {
        padding-left: 1rem;
        padding-right: 1rem;
    }

    /* Less chrome above and below it, so more of a long form is visible. */
    body.ui-next .dialog-body {
        max-height: calc(90vh - 6.5rem);
    }
}

/* ---- #1029 PR 3b - the rally clip court popup (Pages/Admin/RallyClipCourtPlacer.razor) ----
   Lives here, not in a <style> block on the page: a class that must reach a popup belongs in the cache-busted
   shared sheet. All class names start cp- so nothing here can reach another dialog. */
.cp-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 1rem;
    align-items: start;
}

@media (max-width: 800px) {
    .cp-layout {
        grid-template-columns: minmax(0, 1fr);
    }
}

.cp-caption {
    font-size: .9rem;
    margin-bottom: .5rem;
}

/* The video and the SVG overlay fill the same box (object-fit: fill), and the box has the video's own aspect
   ratio, so a click maps to a video pixel as (clientX - left) * W / width. --cp-ar caps the width so a tall (phone,
   portrait) video is not taller than the dialog. */
.cp-stage {
    position: relative;
    width: min(100%, calc((90vh - 14rem) * var(--cp-ar, 1.7778)));
    background: #000;
    margin: 0 auto;
    overflow: hidden;
}

.cp-video,
.cp-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: fill;
    display: block;
}

.cp-overlay {
    cursor: crosshair;
    touch-action: none;
    outline: none;
    user-select: none;
}

.cp-overlay:focus-visible {
    box-shadow: inset 0 0 0 2px #1e88e5;
}

.cp-spinner-wrap,
.cp-error {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    gap: .75rem;
    align-items: center;
    justify-content: center;
    color: #fff;
    background: rgba(0, 0, 0, .55);
    text-align: center;
    padding: 1rem;
}

.cp-spinner {
    width: 2.25rem;
    height: 2.25rem;
    border: 4px solid rgba(255, 255, 255, .3);
    border-top-color: #fff;
    border-radius: 50%;
    animation: cp-spin 1s linear infinite;
}

@keyframes cp-spin {
    to {
        transform: rotate(360deg);
    }
}

.cp-error-hint {
    font-size: .85rem;
    opacity: .85;
}

.cp-help {
    font-size: .8rem;
    color: #555;
    margin-top: .5rem;
}

.cp-schematic-box {
    display: flex;
    gap: .75rem;
    align-items: flex-start;
    margin-bottom: .5rem;
}

.cp-schematic {
    flex: 0 0 auto;
    width: 76px;
    height: 152px;
}

.cp-schematic-court {
    fill: #e8f5e9;
    stroke: #2e7d32;
    stroke-width: 1;
}

.cp-schematic-line {
    stroke: #2e7d32;
    stroke-width: .8;
}

.cp-schematic-net {
    stroke: #444;
    stroke-width: 1.2;
    stroke-dasharray: 2 1.5;
}

.cp-schematic-label {
    font-size: 6px;
    fill: #666;
    font-family: sans-serif;
}

.cp-dot-unset {
    fill: #bdbdbd;
}

.cp-dot-placed {
    fill: #1e88e5;
}

.cp-dot-hidden {
    fill: #fff;
    stroke: #888;
    stroke-width: .8;
}

.cp-dot-active {
    fill: #ff9100;
    stroke: #bf360c;
    stroke-width: 1;
}

.cp-expected {
    font-size: .85rem;
}

.cp-expected-title {
    font-weight: 600;
}

.cp-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-bottom: .5rem;
}

.cp-notice {
    background: #fff8e1;
    border: 1px solid #ffe082;
    border-radius: 4px;
    padding: .4rem .6rem;
    font-size: .82rem;
    margin-bottom: .5rem;
}

.cp-rows {
    border: 1px solid #ddd;
    border-radius: 4px;
    max-height: 22rem;
    overflow-y: auto;
}

.cp-row {
    display: flex;
    gap: .5rem;
    padding: .3rem .5rem;
    border-bottom: 1px solid #eee;
    cursor: pointer;
}

.cp-row:last-child {
    border-bottom: 0;
}

.cp-row-active {
    background: #fff3e0;
}

.cp-row-num {
    flex: 0 0 1.4rem;
    font-weight: 700;
    color: #555;
}

.cp-meaning {
    font-size: .75rem;
    color: #666;
}

.cp-state {
    font-size: .72rem;
    border-radius: 3px;
    padding: 0 .35rem;
    margin-left: .25rem;
}

.cp-state-unset {
    background: #eeeeee;
    color: #555;
}

.cp-state-placed {
    background: #e3f2fd;
    color: #0d47a1;
}

.cp-state-hidden {
    background: #fafafa;
    border: 1px solid #bbb;
    color: #666;
}

.cp-prefill {
    margin-top: .5rem;
}

.cp-recent {
    border: 1px solid #ddd;
    border-radius: 4px;
    max-height: 18rem;
    overflow-y: auto;
}

.cp-recent-item {
    display: flex;
    gap: .5rem;
    align-items: center;
    padding: .4rem;
    border-bottom: 1px solid #eee;
    font-size: .8rem;
}

.cp-recent-disabled {
    opacity: .5;
}

.cp-recent-thumb {
    flex: 0 0 96px;
    width: 96px;
    height: 54px;
    object-fit: cover;
    background: #eee;
}

.cp-recent-nothumb {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .7rem;
    color: #888;
}

.cp-recent-text {
    flex: 1 1 auto;
    min-width: 0;
}

.cp-recent-why {
    color: #b71c1c;
}

.cp-confirm {
    margin-top: .75rem;
}

.cp-problems {
    color: #b71c1c;
    font-size: .82rem;
    padding-left: 1.1rem;
    margin-bottom: .4rem;
}

.cp-confirm-note {
    font-size: .78rem;
    color: #666;
}
