/* Shared Page Styles - 2025 Modern Design Trends */

.page-container {
    width: 100%;
    max-width: 100%;
}

/* Page Header - Minimal & Clean */
.page-header {
    margin-bottom: var(--space-3xl);
    padding-bottom: var(--space-xl);
    border-bottom: 1px solid var(--ascend-border);
}

.page-title {
    font-size: 2.25rem;
    font-weight: 700;
    margin: 0 0 var(--space-sm) 0;
    color: var(--ascend-text-primary);
    font-family: var(--ascend-font-primary);
    letter-spacing: -0.02em;
}

.page-subtitle {
    font-size: 1.125rem;
    color: var(--ascend-text-secondary);
    margin: 0;
    font-weight: 400;
}

/* Empty State - Centered, Spacious, Modern */
.empty-state-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 400px;
    padding: var(--space-3xl);
    text-align: center;
}

.empty-state-icon {
    width: 120px;
    height: 120px;
    border-radius: var(--radius-2xl);
    background: linear-gradient(135deg, rgba(49, 221, 227, 0.1), rgba(184, 133, 54, 0.08));
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: var(--space-2xl);
    border: 1px solid rgba(49, 221, 227, 0.15);
}

.empty-state-icon i {
    font-size: 3.5rem;
    background: linear-gradient(135deg, var(--ascend-accent), var(--ascend-secondary));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.empty-state-title {
    font-size: 1.75rem;
    font-weight: 600;
    color: var(--ascend-text-primary);
    margin: 0 0 var(--space-md) 0;
    font-family: var(--ascend-font-primary);
}

.empty-state-description {
    font-size: 1rem;
    color: var(--ascend-text-secondary);
    max-width: 480px;
    line-height: 1.6;
    margin: 0 0 var(--space-2xl) 0;
}

.empty-state-actions {
    display: flex;
    gap: var(--space-md);
    flex-wrap: wrap;
    justify-content: center;
}

/* Modern Buttons - 2025 Trends: Subtle shadows, smooth interactions */
.btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-md) var(--space-2xl);
    font-size: 0.9375rem;
    font-weight: 600;
    border-radius: var(--radius-lg);
    border: none;
    cursor: pointer;
    transition: all var(--transition-smooth);
    text-decoration: none;
    font-family: var(--ascend-font-secondary);
}

/* Match the shared Button component's primary (dark text on a cyan gradient) so a
   button that resolves to this GLOBAL rule (this file loads AFTER the scoped CSS
   bundle in App.razor) stays readable. The old white-on-cyan/gold rendered the
   public Subscribe buttons as unreadable ghost text (#1109). */
.btn-primary {
    background: linear-gradient(135deg, #31DDE3 0%, #42e8ed 100%);
    color: #042047;
    box-shadow: 0 2px 8px rgba(49, 221, 227, 0.25);
}

.btn-primary:hover {
    box-shadow: 0 6px 20px rgba(49, 221, 227, 0.35);
    transform: translateY(-2px);
}

.btn-primary:active {
    transform: translateY(0);
    box-shadow: 0 2px 8px rgba(49, 221, 227, 0.25);
}

.btn-outline {
    background: transparent;
    color: var(--ascend-text-primary);
    border: 2px solid var(--ascend-border);
}

.btn-outline:hover {
    border-color: var(--ascend-accent);
    background: rgba(49, 221, 227, 0.05);
    color: var(--ascend-accent);
}

.btn-sm {
    padding: var(--space-sm) var(--space-lg);
    font-size: 0.875rem;
}

/* Profile Specific Styles */
.profile-content {
    width: 100%;
}

/* #7177: `profile-card` is only ever passed as CssClass to the shared <Card>, whose
   scoped `.ascend-card[b-*]` rule out-specifies this one (0-2-0 beats 0-1-0), so the
   background and border here have never painted. They are kept coherent rather than
   left as a light-theme fossil: --ascend-bg-card is now the dark card surface, and the
   near-white --ascend-border that used to sit beside it would draw a bright ring. */
.profile-card {
    background: var(--ascend-bg-card);
    border: 1px solid rgba(49, 221, 227, 0.3);
    border-radius: var(--radius-xl);
    padding: var(--space-3xl);
    box-shadow: var(--shadow-md);
}

.profile-avatar-section {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-lg);
    padding-bottom: var(--space-3xl);
    border-bottom: 1px solid var(--ascend-border);
    margin-bottom: var(--space-3xl);
}

.profile-avatar-large {
    width: 120px;
    height: 120px;
    border-radius: var(--radius-full);
    background: linear-gradient(135deg, var(--ascend-accent), var(--ascend-secondary));
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-size: 3.5rem;
    box-shadow: 0 8px 24px rgba(49, 221, 227, 0.3);
    border: 4px solid white;
}

.profile-avatar-large img {
    width: 100%;
    height: 100%;
    border-radius: var(--radius-full);
    object-fit: cover;
}

.profile-info-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-xl);
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

/* #7258: this read `color: var(--ascend-text-primary)` - #0f172a, which is
   also --ascend-bg-dark. The label was being painted in the page background
   colour and was therefore invisible on every page that did not restate it
   locally (the Lichess study import and the Social Calendar filters, both
   sitting directly above inputs from the same light block). Same rot, same
   file, same fix: a token that belongs to the dark theme. */
.form-label {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--ascend-text-light);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* .form-input / .form-textarea live in wwwroot/app.css (#7258).
   They used to be defined HERE, and defined LIGHT - background
   var(--ascend-bg-card) (#ffffff) over color var(--ascend-text-primary)
   (#0f172a) - which is why eight pages rendered solid white boxes on the dark
   theme and roughly 28 scoped .razor.css files carried a private dark
   restatement to compensate. This file loads AFTER app.css, so leaving a copy
   here would silently outrank the real definition at equal specificity. There
   is one definition now; do not reintroduce one here. */

/* Responsive Design */
@media (max-width: 768px) {
    .page-title {
        font-size: 1.75rem;
    }

    .page-subtitle {
        font-size: 1rem;
    }

    .empty-state-container {
        min-height: 300px;
        padding: var(--space-2xl) var(--space-lg);
    }

    .empty-state-icon {
        width: 100px;
        height: 100px;
    }

    .empty-state-icon i {
        font-size: 3rem;
    }

    .empty-state-title {
        font-size: 1.5rem;
    }

    .profile-card {
        padding: var(--space-2xl) var(--space-xl);
    }

    .profile-avatar-large {
        width: 100px;
        height: 100px;
        font-size: 3rem;
    }
}

@media (max-width: 480px) {
    .page-header {
        margin-bottom: var(--space-2xl);
    }

    .page-title {
        font-size: 1.5rem;
    }

    .empty-state-actions {
        flex-direction: column;
        width: 100%;
    }

    /* #7748 - this was `.btn { width: 100%; justify-content: center }`, a
       GLOBAL rule in a globally-loaded sheet. It is invisible at the call
       site and it defeats flex-wrap outright, because a 100% width becomes
       the flex basis and every button then fills a line of its own. It cost
       the #7731 header fix a measurement cycle and forced an explicit
       `width: auto` override there; .waitlist-submit on Home carried the same
       override for the same reason.

       INVERTED TO OPT-IN rather than re-scoped, because the sweep is small
       and knowable: `.btn` as a standalone class token exists at exactly 13
       call sites in 3 files (Home.razor 7, MarketingHeader.razor 5,
       Profile.razor 1) - counted over every .razor/.html in the app, and
       confirmed in a browser at 430px across 33 routes. Everything else on
       the site renders through the shared Button component, which emits
       `.ascend-btn` and has its own FullWidth parameter and never saw this
       rule at all. So the six Home hero/CTA anchors that DO want a full-bleed
       button on a phone now say so with .btn-block, and nothing else has to
       fight a rule it cannot see.

       justify-content moves with the width: on an auto-width inline-flex
       button it centers nothing, so it only ever meant anything here. */
    .btn-block {
        width: 100%;
        justify-content: center;
    }

    .profile-card {
        padding: var(--space-xl);
    }

    .assistant-paths {
        flex-direction: column;
    }

    .assistant-empty {
        padding: 2rem 1rem;
        border-radius: 16px;
    }

    .assistant-empty h3 {
        font-size: 1.05rem;
    }
}

/* Assistant Empty State — AI-voiced guidance for empty pages */
.assistant-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 3rem 2rem;
    gap: 0.75rem;
}

.assistant-empty-icon {
    width: 56px;
    height: 56px;
    border-radius: 16px;
    background: linear-gradient(135deg, rgba(184, 133, 54, 0.2), rgba(49, 221, 227, 0.15));
    border: 1px solid rgba(184, 133, 54, 0.35);
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 0.5rem;
}

.assistant-empty-icon svg {
    color: #B88536;
}

.assistant-empty h3 {
    font-family: var(--ascend-font-primary);
    font-size: 1.25rem;
    font-weight: 700;
    color: #ffffff;
    margin: 0;
}

.assistant-intro {
    font-family: var(--ascend-font-secondary);
    font-size: 0.9rem;
    color: rgba(255, 255, 255, 0.55);
    margin: 0;
    max-width: 520px;
    line-height: 1.6;
}

.assistant-list {
    list-style: none;
    padding: 0;
    margin: 0.5rem 0 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    text-align: left;
    max-width: 520px;
}

.assistant-list li {
    font-family: var(--ascend-font-secondary);
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.5);
    line-height: 1.5;
    padding-left: 1.25rem;
    position: relative;
}

.assistant-list li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.55em;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: rgba(49, 221, 227, 0.5);
}

.assistant-list li strong {
    color: rgba(255, 255, 255, 0.75);
    font-weight: 600;
}

.assistant-note {
    font-family: var(--ascend-font-secondary);
    font-size: 0.82rem;
    color: rgba(49, 221, 227, 0.6);
    margin: 0.25rem 0 0;
    font-style: italic;
    max-width: 520px;
}

.assistant-paths {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    text-align: left;
    max-width: 520px;
    margin-top: 0.25rem;
}

.assistant-path {
    font-family: var(--ascend-font-secondary);
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.5);
    line-height: 1.6;
}

.assistant-path-label {
    color: #31DDE3;
    font-weight: 600;
}

/* #8837 - the layout is the shared .action-row action-row--center (app.css),
   put on the element beside this class: stacked at one width on a phone
   ("Create Repertoire" 171px sat over "Study Library" 145px at 390 when this
   was a hand-rolled wrapping row), a centered row above 480px. Only the
   spacing above it lives here. */
.assistant-actions {
    margin-top: 0.75rem;
}

.assistant-action-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.6rem 1.25rem;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 50px;
    color: rgba(255, 255, 255, 0.7);
    font-family: var(--ascend-font-secondary);
    font-size: 0.82rem;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: all 0.2s ease;
}

.assistant-action-btn:hover {
    background: rgba(49, 221, 227, 0.1);
    border-color: rgba(49, 221, 227, 0.3);
    color: #31DDE3;
    transform: translateY(-1px);
}

.assistant-action-btn.primary {
    background: linear-gradient(135deg, #31DDE3 0%, #42e8ed 100%);
    border: none;
    color: #ffffff;
    box-shadow: 0 4px 16px rgba(49, 221, 227, 0.3);
}

.assistant-action-btn.primary:hover {
    background: linear-gradient(135deg, #42e8ed 0%, #31DDE3 100%);
    box-shadow: 0 6px 20px rgba(49, 221, 227, 0.4);
    color: #ffffff;
}

.assistant-action-btn svg {
    width: 14px;
    height: 14px;
}

.empty-state-link {
    color: #31DDE3;
    text-decoration: none;
}

.empty-state-link:hover {
    text-decoration: underline;
}

/* QuickGrid overrides — scoped ::deep can't reach QuickGrid internals.
   QuickGrid renders: <table><thead><tr><th><button class="col-title">
   <div class="col-title-text">Title</div></button></th></tr></thead>
   The <button> has user-agent color: buttontext — must override it explicitly. */
.studies-table {
    width: 100% !important;
    border-collapse: collapse !important;
    table-layout: fixed !important;
}

.studies-table th {
    font-family: var(--ascend-font-primary) !important;
    font-size: 0.75rem !important;
    font-weight: 600 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.08em !important;
    color: #31DDE3 !important;
    background: transparent !important;
    padding: 0.75rem 1rem !important;
    border-bottom: 1px solid rgba(49, 221, 227, 0.3) !important;
    text-align: left !important;
    vertical-align: middle !important;
}

/* Override <button> and <div> inside th — user-agent sets color: buttontext on buttons */
.studies-table th button,
.studies-table th .col-title,
.studies-table th .col-title-text,
.studies-table .col-title,
.studies-table .col-title-text {
    color: #31DDE3 !important;
    font-family: var(--ascend-font-primary) !important;
    font-size: 0.75rem !important;
    font-weight: 600 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.08em !important;
}

/* QuickGrid's default theme sets `.col-title-text { white-space: nowrap;
   text-overflow: ellipsis; overflow: hidden }` which clips short headers
   like TYPE, STATUS, CHAPTERS in narrow columns once the sort-arrow icon
   eats the remaining width. Letting the header wrap to two lines is
   cheaper than padding every column out, and a two-line header reads
   fine in the available row height (Joe-flagged 2026-04-29). */
.studies-table th .col-title-text,
.studies-table .col-title-text,
.quickgrid[theme=default] .col-title-text {
    white-space: normal !important;
    text-overflow: clip !important;
    overflow: visible !important;
    line-height: 1.15 !important;
}

/* Sort affordance — QuickGrid renders the column-title button on every
   sortable column, but by default it's indistinguishable from a static
   header. Hover state + cursor make sortability discoverable. The
   selected/sorted column already gets the QuickGrid arrow indicator. */
.studies-table th button {
    cursor: pointer !important;
    background: transparent !important;
    border: none !important;
    padding: 0 !important;
    transition: color 0.15s ease;
}

.studies-table th button:hover,
.studies-table th button:hover .col-title-text {
    color: #31DDE3 !important;
}

/* Override QuickGrid theme default bold */
.quickgrid[theme=default] .col-title {
    font-weight: 600 !important;
}

.quickgrid[theme=default] > thead > tr > th {
    font-weight: 600 !important;
    color: #31DDE3 !important;
    background: transparent !important;
}

/* #6614 - sortable QuickGrid columns render their header as a
   <button class="col-title"><span class="col-title-text">...</span></button>.
   The <button> carries the user-agent `color: buttontext` (near-black) and does
   NOT inherit the th color, so every sortable header read as black on the dark
   theme (Joe smoke, /admin/triage 'Count' column). Color the button + its text
   with the brand cyan token GLOBALLY so ANY sortable grid inherits the fix, not
   just the pages (studies-table, played-grid) that patched it locally. */
.quickgrid[theme=default] .col-title,
.quickgrid[theme=default] .col-title-text {
    color: var(--ascend-accent) !important;
}

.quickgrid[theme=default] .col-title {
    cursor: pointer;
    background: transparent;
    border: none;
    transition: color 0.15s ease;
}

.quickgrid[theme=default] .col-title:hover,
.quickgrid[theme=default] .col-title:hover .col-title-text {
    color: var(--ascend-accent-light) !important;
}

/* Keep the active-sort header (QuickGrid toggles col-sort-asc/desc on the th)
   in brand cyan too, so the sortable affordance stays legible once clicked. */
.quickgrid[theme=default] th.col-sort-asc .col-title,
.quickgrid[theme=default] th.col-sort-asc .col-title-text,
.quickgrid[theme=default] th.col-sort-desc .col-title,
.quickgrid[theme=default] th.col-sort-desc .col-title-text {
    color: var(--ascend-accent) !important;
}

/* ==================================================================
   #6859 - QuickGrid dark-theme baseline (GLOBAL owner for QuickGrid's
   built-in chrome). QuickGrid ships Blazor's light-theme defaults:
   black SVG sort arrows, a light-gray Paginator (#ccc border, black
   arrow glyphs, #eee hover blobs), a white ColumnOptions popup - all
   of which read as black/unstyled on the ASCENDCHESS dark theme.
   This stylesheet loads AFTER the scoped bundle (App.razor), so
   equal-specificity rules here win by order; !important is used only
   where QuickGrid's scope attribute out-specifies a plain selector.

   The arrow glyphs are BLACK inline-SVG background-images with no
   fill - unrecolorable - so we re-draw the same stock shapes as CSS
   MASKS and let background-color (the accent token) become the glyph
   color (pattern proven on the SME Workbench paginator, 2026-07-17
   canary). Sizing/layout/flip-transforms stay with QuickGrid's own
   rules - we only re-skin. */

/* Sort indicator - the black default arrow, now brand cyan. QuickGrid
   flips the ascending arrow with its own scaleY(-1), which flips the
   mask with it, so one glyph serves both directions. */
.quickgrid[theme=default] th.col-sort-asc .sort-indicator,
.quickgrid[theme=default] th.col-sort-desc .sort-indicator {
    background-image: none !important;
    background-color: var(--ascend-accent) !important;
    -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M 2 3.25 L 12 20.75 L 22 3.25 L 12 10 z"/></svg>') center / 1rem no-repeat;
    mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M 2 3.25 L 12 20.75 L 22 3.25 L 12 10 z"/></svg>') center / 1rem no-repeat;
}

/* Column-title hover blob - replace the stock gray with a brand tint. */
.quickgrid[theme=default] button.col-title:hover,
.quickgrid[theme=default] .col-options-button:hover {
    background-color: rgba(49, 221, 227, 0.08) !important;
}

.quickgrid[theme=default] button.col-title:active,
.quickgrid[theme=default] .col-options-button:active {
    background-color: rgba(49, 221, 227, 0.16) !important;
}

/* ColumnOptions - the hamburger button draws its glyph with
   stroke="currentColor", so the color token alone re-skins it; the
   popup panel ships white-on-silver and needs the dark card look.
   (No current page uses <ColumnOptions>, but the chrome is themed
   here so the first page that does is not black-on-white.) */
.quickgrid[theme=default] .col-options-button {
    color: var(--ascend-accent);
}

.quickgrid[theme=default] .col-options {
    background: var(--ascend-primary-dark) !important;
    border-color: rgba(49, 221, 227, 0.3) !important;
    color: rgba(255, 255, 255, 0.85);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
    border-radius: 0.5rem;
}

/* Body-cell dark baseline for grids with no page-level styling (the
   admin/SME roster grids). :where() zeroes the selector's specificity
   so ANY page-scoped ::deep rule still wins - this only catches cells
   nothing else styles. Padding is deliberately NOT touched (QuickGrid's
   own theme rule out-specifies :where and pages own their density). */
:where(.quickgrid[theme=default]) > tbody > tr > td {
    font-family: var(--ascend-font-secondary);
    color: rgba(255, 255, 255, 0.8);
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

:where(.quickgrid[theme=default]) > tbody > tr:hover > td {
    background-color: rgba(49, 221, 227, 0.04);
}

/* #7782 - QUICKGRID'S PAGINATION FILLER ROWS, HIDDEN ONCE FOR EVERY GRID.
   A QuickGrid given a `Pagination` state does not stop at the data: after the
   real rows it pads the page out to ItemsPerPage with bare <tr> elements full
   of empty <td>s. That is QuickGrid's own RenderNonVirtualizedRows, verbatim -
   "ensure we render the exact number of expected rows per page, even if there
   aren't enough data items. This avoids the layout jumping on the last page."

   On a light default theme those rows are invisible. On ours they are not: the
   body-cell baseline right above draws a bottom border on every <td>, so a
   3-item page of a 25-per-page grid reads as three rows of content trailed by
   22 ruled empty lines. Reported from /sme/workbench (Issue #7782, "this is
   endemic with all QuickGrid tables"), and it is the same in every paginated
   grid on the site.

   We take the other side of QuickGrid's trade: a page that ends where the data
   ends is worth more than a pager that never moves.

   WHY THIS SELECTOR CANNOT REACH A DATA ROW. The filler rows are the only rows
   QuickGrid renders WITHOUT `aria-rowindex` - RenderRow puts it on every data
   row, and RenderPlaceholderRow puts it on every virtualization placeholder -
   so `:not([aria-rowindex])` is exactly the filler set and nothing else.
   `display: none` also drops them out of the accessibility tree, which the
   markup never wanted announced. The leading `table` element is a deliberate
   specificity bump: it keeps a page-scoped `::deep ... tbody tr` rule from
   tying with this one on specificity and winning on source order.

   IT REPLACES A PER-GRID HACK, which is the whole point. The same symptom was
   fixed for ONE grid on 2026-04-29 with `.studies-table tbody tr:not(:has(td *))
   { display: none !important; }` - the study library only. That is exactly the
   "have to target them specifically" the owner filed #7782 about: 37 other grids
   never got it. It was also unsound. It hides a row because no cell of it
   contains an ELEMENT, so a perfectly real row whose cells hold only text - the
   Type and Waiting columns on the SME workbench queue are plain text - is a row
   it would have silently swallowed. The study library's rows survived only
   because every one of them happens to carry a cover image and a title link.
   Row identity is the framework's `aria-rowindex`, not a guess at how full a
   cell looks, so that rule is gone and this one covers the library too.

   GLOBAL BY DESIGN, exactly like the #6859 chrome above. It keys on
   `.quickgrid`, the class QuickGrid always writes on its own <table>, so all
   38 grid usages - and every grid added after this - are covered with nothing
   to opt into and nothing to forget.

   Ratchet: AscendChess.Components.Tests/Architecture/QuickGridBlankRowRatchetTests.cs
   pins both halves - that the rule is still here, and that QuickGrid still
   builds filler rows the way this selector assumes. */
table.quickgrid > tbody > tr:not([aria-rowindex]) {
    display: none;
}

/* Paginator - QuickGrid's <Paginator> chrome, themed once for every
   grid (SME Rulings, SME Workbench, Coach Bridge student view, and
   any future usage). Root selector needs !important: the bundle's
   `.paginator[b-...]` out-specifies a plain `.paginator`. */
.paginator {
    border-top: 1px solid rgba(49, 221, 227, 0.2) !important;
    margin-top: 0.5rem !important;
    padding: 0.6rem 0.25rem 0 !important;
    color: rgba(255, 255, 255, 0.8) !important;
    font-family: var(--ascend-font-secondary);
    /* #8484 - the narrow layout below keys off the Paginator's OWN width (its
       card), not the viewport: the coach student panel can be narrow inside a
       wide window. flex-wrap lets the count drop to its own line there; on a
       wide card everything still fits one row and nothing wraps. */
    container: ascend-paginator / inline-size;
    flex-wrap: wrap;
    row-gap: 0.5rem;
}

/* Current-page indicator ("Page N of M" strongs) in brand cyan. */
.paginator .pagination-text strong {
    color: var(--ascend-accent);
    font-weight: 600;
}

.paginator nav button {
    border: 0;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

/* Arrow buttons: stock black SVGs re-drawn as masks, accent-colored.
   QuickGrid's own scaleX(-1) flip still produces next/last variants. */
.paginator nav button.go-first,
.paginator nav button.go-last {
    background-color: var(--ascend-accent);
    background-image: none;
    -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g transform="rotate(90) scale(0.8)" transform-origin="12 12"><path d="m 2,1.5 l 10,17.5 l 10,-17.5 l -10,7.75 l -10,-7.75 z"/><rect height="2" width="20" y="20.5" x="2"/></g></svg>') center / 1rem no-repeat;
    mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g transform="rotate(90) scale(0.8)" transform-origin="12 12"><path d="m 2,1.5 l 10,17.5 l 10,-17.5 l -10,7.75 l -10,-7.75 z"/><rect height="2" width="20" y="20.5" x="2"/></g></svg>') center / 1rem no-repeat;
}

.paginator nav button.go-previous,
.paginator nav button.go-next {
    background-color: var(--ascend-accent);
    background-image: none;
    -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g transform="rotate(90)" transform-origin="12 12"><path d="M 2 3.25 L 12 20.75 L 22 3.25 L 12 11 z"/></g></svg>') center / 1rem no-repeat;
    mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g transform="rotate(90)" transform-origin="12 12"><path d="M 2 3.25 L 12 20.75 L 22 3.25 L 12 11 z"/></g></svg>') center / 1rem no-repeat;
}

/* With the glyph painted through a mask, hover/active recolor the
   glyph itself (a background box cannot show through a mask). These
   out-specify the bundle's gray #eee/#aaa hover rules by order. */
.paginator nav button:not([disabled]):hover {
    background-color: var(--ascend-accent-light);
}

.paginator nav button:not([disabled]):active {
    background-color: var(--ascend-text-light);
}

.paginator nav button[disabled] {
    cursor: default;
}

/* #8311 - THE STOCK PAGINATOR'S BUTTONS HAD NO TOUCH FLOOR EITHER, ON FOUR
   SURFACES AT ONCE, AND THE LIVE RATCHET WAS NEVER GOING TO SAY SO.

   QuickGrid sizes these from its own bundled stylesheet (a 1rem mask inside a
   small square), so they are well under 44px on a coarse pointer - and they
   are the only way through a 25-row queue. The reason they survived is the
   #8311 reason, one step further out than the pagers the bug was filed
   against: not "they render only past page 1", but "the live #7736 gate does
   not walk /sme/workbench, /sme/rulings or /coach-bridge/student/{playerId}
   at all" - the first two are role-gated behind SME/admin and the third is
   parameterized. So nothing measured them, ever.

   Themed once, here, for every usage (SME Workbench queue, SME Rulings
   history, the coach's student game list; the fourth, the rule-release
   preview, was retired by #8636), for the
   same reason the rules above are global: the Paginator's markup cannot carry
   a page's CSS scope, so a per-page floor could not reach it.

   Both axes: the glyph is a mask with no text beside it, so a height-only
   floor leaves exactly the 39x44 shape the /games chevrons wore. The buttons
   sit in their own nav with the page text outside it, so growing the box
   cannot overlap anything it should not. !important for the reason the root
   selector needs it - QuickGrid's bundled `.paginator[b-...] nav button` rule
   out-specifies a plain descendant selector. */
@media (hover: none) and (pointer: coarse) {
    .paginator nav button {
        min-width: var(--touch-target) !important;
        min-height: var(--touch-target) !important;
    }
}

/* #8484 - THE FLOOR ABOVE MADE THE ONE-ROW PAGINATOR WIDER THAN ITS CARD.
   QuickGrid lays the Paginator out as one row: the item count, then a nav of
   first/previous, "Page N of M", next/last. With four 44x44 buttons that row
   measured 302px at a 344px viewport, against a 260px card content box, so the
   go-last button sat 16px past the card's clipped edge on /sme/workbench,
   /sme/rulings and the coach student panel (it fit exactly at 390).

   Keep the floor; change the layout. In a narrow card the count takes a line,
   "Page N of M" takes the next (order: -1 lifts it above the buttons it sits
   between in the markup), and the four buttons share a compact row: 4 x 44
   plus three 0.5rem gaps is about 200px. 480px is the house mobile tier
   (app.css), used here as a container width. Specificity: QuickGrid's
   `nav[b-...]` and `.pagination-text[b-...]` tie with these selectors, and
   this sheet loads after the scoped bundle, so order wins without
   !important. */
@container ascend-paginator (max-width: 480px) {
    .paginator .summary {
        flex: 1 0 100%;
    }

    .paginator nav {
        flex: 1 0 100%;
        flex-wrap: wrap;
        margin-left: 0;
        row-gap: 0.5rem;
    }

    .paginator .pagination-text {
        order: -1;
        flex: 1 0 100%;
        margin: 0;
    }
}

/* ================================================================ */

.studies-table td {
    font-family: var(--ascend-font-secondary) !important;
    font-size: 0.9rem !important;
    color: rgba(255, 255, 255, 0.8) !important;
    padding: 1.1rem 0.75rem !important;
    border-bottom: 1px solid rgba(255, 255, 255, 0.05) !important;
    background: transparent !important;
    vertical-align: middle !important;
}

.studies-table th {
    /* match td horizontal padding so cells line up. Prior 1rem horizontal
       was too generous and contributed to the 2026-04-29 cramped/clipped
       layout (action column hidden under overflow). */
    padding-left: 0.75rem !important;
    padding-right: 0.75rem !important;
}

.studies-table tr:hover td {
    background: rgba(49, 221, 227, 0.05) !important;
}

/* Column widths use rem so they scale with the user's text-size preference
   (accessibility) and stay coherent with the rest of the design tokens. The
   only ch-fixed minima are the thumbnail and the action-button strip, which
   can't usefully shrink past their content. Title col is left auto so
   table-layout:fixed gives it the elastic remainder. */
.studies-table .col-cover {
    /* The thumbnail is 3.25rem wide and the cell pads 1rem left + 0.5rem right
       (total 4.75rem of content), so the column needs at least that much room
       or the right edge clips. 5rem leaves a hair of breathing room. */
    width: 5rem !important;
    padding: 0.75rem 0.5rem 0.75rem 1rem !important;
}

/* #7803 — EVERY COLUMN IS SELECTED BY ITS CLASS, NEVER BY ITS INDEX.

   These rules used to read th/td:nth-child(2..6). That is the selector shape
   #7260/#7276 already outlawed on the /games grid, and it is what broke this
   one: an nth-of-type rule in the ≤640px block below was written to hide the
   Delete trash when the cell held two buttons, and when the hidden-vs-paused
   flag added a THIRD button the same index silently retargeted the new Hide
   control and display:none'd it. The customer reported "the hide btn is
   missing on Library Studies' rows in mobile" (#7803) and it was: 0x0 at 344
   and 390 on a coarse pointer, while DELETE — the destructive one — survived.

   A positional selector cannot survive a conditional control; identity can.
   The classes come from TemplateColumn Class= in StudyLibrary.razor and are
   pinned by StudiesColumnIdentityTests, so they cannot silently disappear the
   way an index could. */

/* Title column — auto = remaining space under table-layout:fixed */
.studies-table .col-study,
.studies-table th.col-study {
    width: auto !important;
}

/* Type column — short labels (Course / Book / Strategy / Games) */
.studies-table .col-type,
.studies-table th.col-type {
    width: 5.5rem !important;
}

/* Status column — pill is short, but "Not started" is the longest label */
.studies-table .col-status,
.studies-table th.col-status {
    width: 7rem !important;
}

/* Chapters column — small integer */
.studies-table .col-chapters,
.studies-table th.col-chapters {
    width: 5.5rem !important;
}

/* Last Accessed column — date like "Apr 29, 2026" */
.studies-table .col-accessed,
.studies-table th.col-accessed {
    width: 7.5rem !important;
}

/* Actions column — sized for what the cell can actually hold: THREE 2rem
   icon-buttons + two 0.375rem gaps = 6.75rem of content, plus 0.5rem padding
   each side = 7.75rem. In rem so it scales with the user's text-size
   preference (a 1.5x browser zoom keeps the cell proportional to the buttons
   inside).

   #7803 — this read 6.5rem, and its comment said "two 2rem icon-buttons",
   because it was written when the cell held two. The hidden-vs-paused split
   made it three and nothing here moved, so at 6.5rem the three buttons no
   longer fit: flex shrank them from their declared 2rem to about 27px. That
   was the same under-sizing as the phone bug, resolved quietly instead of
   destructively, and it is why the desktop icons were 27x32 rather than
   32x32. Sizing the cell for three is what makes .btn-icon-sm render at the
   size it declares. StudiesActionCellContractTests pins the arithmetic. */
.studies-table .col-actions,
.studies-table th.col-actions {
    width: 7.75rem !important;
    min-width: 7.75rem !important;
    padding: 0.5rem !important;
    text-align: right !important;
}

/* Responsive hides, keyed on the column CLASS (see the #7803 note above).
   The breakpoints fire on viewport width, but the actual table width is
   viewport - sidebar (280px or 240px below 1024px) - card padding (~112px).
   At viewport 1100px, table has only ~700px to spread 7 columns — so we
   shed Last Accessed (lowest-signal) earlier than the cover-thumb / status /
   actions trio. At 900px Type also drops. At 480px Chapters drops too.

   Hiding a whole COLUMN is safe in a way hiding one button inside a cell is
   not: the data stays on the study's own page, and no interactive control
   disappears out from under the reader. */
@media (max-width: 1100px) {
    .studies-table .col-accessed,
    .studies-table th.col-accessed {
        display: none !important;
    }
}

@media (max-width: 900px) {
    .studies-table .col-type,
    .studies-table th.col-type {
        display: none !important;
    }
}

/* ≤640px (small phones, narrow tablets) — drop Status since the Play / Pause
   icon in the action column already signals state. Shrink chapters cell to
   its content (the integer is short). Joe-flagged 2026-04-30: mobile view was
   cramped because Status (7rem) + Actions (6.5rem) + Cover (4rem) ate ~17rem
   of fixed width on a 20rem viewport, leaving Title with no elastic room. */
@media (max-width: 640px) {
    .studies-table .col-status,
    .studies-table th.col-status {
        display: none !important;
    }

    .studies-table .col-chapters,
    .studies-table th.col-chapters {
        width: 3rem !important;
    }

    /* #7803 — THE ACTIONS CELL MUST BE WIDE ENOUGH FOR THE TARGETS INSIDE IT.

       What was here before: a 3rem (48px) cell plus
       `.action-btns .btn-icon-sm:nth-of-type(2) { display: none }`, written
       when the cell held exactly two buttons and meant to drop the Delete
       trash. The comment said so. Then the hidden-vs-paused split added a
       third button (Pause · Hide · Delete) and the index moved: the rule
       hid HIDE and kept DELETE — the benign, reversible control vanished and
       the destructive one stayed. Measured on prod and reproduced on dev at
       344 and 390 on a coarse pointer: Hide 0x0, Delete 44x44.

       Worse, 48px could not hold what was left either. #7736 put a 44px
       floor on .btn-icon-sm for a coarse pointer, and min-width blocks flex
       shrinking, so the two surviving buttons overflowed a 32px-wide flex
       box; elementFromPoint at the Pause button's own center returned
       something else, i.e. it was not reliably tappable either.

       So the cell is sized to what it actually has to hold. 7rem = 112px,
       less 0.5rem padding each side = 96px of content, which fits two 44px
       targets plus the 0.375rem gap (94px). Three controls wrap onto a
       second line rather than being crushed — the row grows in height, which
       is visible and recoverable, instead of a control disappearing, which
       is neither. .action-btns carries flex-wrap: wrap for exactly that
       (StudyLibrary.razor.css).

       Nothing is hidden by index here, or at all: whatever the row renders
       is what the reader can reach. */
    .studies-table .col-actions,
    .studies-table th.col-actions {
        width: 7rem !important;
        min-width: 7rem !important;
    }
}

@media (max-width: 480px) {
    .studies-table .col-chapters,
    .studies-table th.col-chapters {
        display: none !important;
    }

    .studies-table .col-cover {
        width: 3rem !important;
        padding: 0.5rem 0.25rem 0.5rem 0.5rem !important;
    }

    .studies-table td {
        font-size: 0.8rem !important;
        padding: 0.5rem 0.375rem !important;
    }

    .studies-table th {
        padding: 0.375rem !important;
    }
}

/* #7736 — QUICKGRID'S SORT HEADER IS A BUTTON, AND IT WAS 16 PIXELS TALL.

   QuickGrid renders `<th><button class="col-title">…</button></th>` (see the
   note further up this file). That button is a real, keyboard-reachable
   interactive control — it sorts the column — and on /studies it measured
   206x16 at 390px. Sixteen pixels is under WCAG 2.2 AA 2.5.8's 24px floor on
   ANY pointer, not just a finger, so the first rule here is unconditional.

   This lives in SharedPages.css because that is QuickGrid's single global
   owner for chrome it renders itself (#6859) — a page-scoped rule could not
   reach it anyway, since the markup is the component's and carries no page
   scope attribute. One rule, all 30+ grids. */
.quickgrid .col-title {
    min-height: 1.5rem;
}

@media (hover: none) and (pointer: coarse) {
    .quickgrid .col-title {
        min-height: var(--touch-target);
    }
}

/* #7845 - .assistant-action-btn, measured 202x39 by the #7736 gate on /studies
   (prod, e2e@ account). It is the action inside an empty state ("Create Your
   First Study" on /studies, the /games and /opening-hub empty states), so
   it only renders for an account with nothing in that list - the demo account
   has content, which is why the sweep never saw it. BookCatalog closed the same
   control on /library alone (#7736 follow-on); the class is global, so the
   floor belongs here with it. Empty states center their actions with a
   0.75rem gap, so the box grows rather than borrowing a neighbor's space. */
@media (hover: none) and (pointer: coarse) {
    .assistant-action-btn {
        min-height: var(--touch-target);
    }
}
