﻿@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');

*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

:root {

    --bg:      #0c0e1c;
    --bg-2:    #14172a;
    --bg-3:    #1b1e35;


    --line:      #292e48;
    --line-soft: #1d2138;


    --ink:   #e7e9ee;
    --ink-2: #b6bac6;
    --ink-3: #7a8094;
    --ink-4: #4a5063;
    --mute-accent: #57799d;


    --accent:      #2b5fc4;
    --accent-glow: #4a82e0;
    --accent-2:    #5a8cc9;
    --accent-3:    #6b77e0;


    --ok:   #6bd49b;
    --warn: #ffb454;
    --bad:  #ff6b6b;
    --info: #7aaeff;


    --r-sm: 0.375rem;
    --r-md: 0.625rem;
    --r-lg: 0.875rem;


    --pad: 1.125rem;
    --gap: 0.875rem;


    --sh-card: 0 0.063rem 0 rgba(255,255,255,0.04) inset, 0 0.125rem 0.5rem rgba(0,0,0,0.35), 0 0.75rem 2rem rgba(0,0,0,0.45);
    --sh-pop:  0 0.063rem 0 rgba(255,255,255,0.05) inset, 0 0.5rem 1.5rem rgba(0,0,0,0.5),  0 1.75rem 4rem rgba(0,0,0,0.55);
    --sh-glow: 0 0 0 0.063rem rgba(43,95,196,0.15), 0 0 2rem rgba(43,95,196,0.12);

}

*:not(html):not(body)::-webkit-scrollbar {
    width: 0.375rem;
    height: 0.375rem;
}
*:not(html):not(body)::-webkit-scrollbar-track {
    background: var(--bg);
    border-radius: 0.25rem;
}
*:not(html):not(body)::-webkit-scrollbar-thumb {
    background: var(--line);
    border-radius: 0.25rem;
}
*:not(html):not(body)::-webkit-scrollbar-thumb:hover {
    background: var(--ink-4);
}
*:not(html):not(body) {
    scrollbar-width: thin;
    scrollbar-color: var(--line) var(--bg);
}

.skip-nav {
    position: absolute;
    top: -9999px;
    left: 0;
}
.skip-nav:focus {
    top: 0;
    z-index: 9999;
    padding: 0.5em 1em;
    background: var(--bg);
    color: var(--ink);
    border: 1px solid var(--accent);
    border-radius: var(--r-sm);
}

/* REMOVED 2026-09-06 (Session 218). .profile-sections was the Profile page's own
   two-column card grid, and global.css's .gp-card-columns-2 comment named it as one of
   the local copies that utility exists to absorb. The page did not adopt it — it moved
   to the RAILS layout instead (.gp-rails-2 / .gp-rail in global.css), which is a
   different mechanism: this grid shared rows across its columns, rails share none.
.profile-sections {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.125rem;
    align-items: start;
} */

/* MOVED 2026-09-06 (Session 218) to pages/profile.css and RENAMED .profile-btn-group.
   Profile was its only user, but it was serving THREE different controls there — the
   theme picker, the 12h/24h picker and every dashboard Show/Hide pair — so a name taken
   from one of the three was wrong for the other two.
.theme-selector {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
} */

/* .theme-btn — removed; replaced with .btn (P2) */
/* .theme-btn {
    display: inline-flex;
    align-items: center;
    padding: 0.375rem 0.875rem;
    font-size: 0.75rem;
    font-family: inherit;
    font-weight: 500;
    background: var(--bg-2);
    border: 1px solid var(--line);
    color: var(--ink-2);
    border-radius: var(--r-sm);
    cursor: pointer;
    transition: all 0.15s;
} */

/* .theme-btn:hover { border-color: var(--ink-4); color: var(--ink); background: var(--bg-3); } */

/* .theme-btn-active — removed; replaced with .btn-active (P2) */
/* .theme-btn-active {
    border-color: var(--accent);
    color: var(--ink);
    background: rgba(43,95,196,0.12);
    box-shadow: 0 0 0 3px rgba(43,95,196,0.08), inset 0 1px 0 rgba(255,255,255,0.05);
} */

html, body {
    height: 100%;
}

body {
    background-color: var(--bg);
    color: var(--ink);
    font-family: Inter, system-ui, sans-serif;
    font-size: 1rem;
    /* line-height: 1.6; */
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    -webkit-font-smoothing: antialiased;
}

body::before {
    content: '';
    position: fixed;
    inset: 0;
    background:
        radial-gradient(0.063rem 0.063rem at 20% 30%, rgba(184,150,227,0.18), transparent 50%),
        radial-gradient(0.063rem 0.063rem at 70% 80%, rgba(125,155,214,0.15), transparent 50%),
        radial-gradient(0.063rem 0.063rem at 40% 70%, rgba(255,255,255,0.10), transparent 50%),
        radial-gradient(0.063rem 0.063rem at 85% 20%, rgba(255,255,255,0.12), transparent 50%),
        radial-gradient(0.063rem 0.063rem at 15% 85%, rgba(125,155,214,0.12), transparent 50%);
    pointer-events: none;
    z-index: 0;
}

a {
    color: var(--accent-2);
    text-decoration: none;
}

a:hover {
    color: var(--accent-glow);
}

input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
    -webkit-box-shadow: 0 0 0 1000px var(--bg-2) inset !important;
    -webkit-text-fill-color: var(--ink) !important;
    transition: background-color 5000s ease-in-out 0s;
    caret-color: var(--ink);
}

header {
    background: linear-gradient(180deg, var(--bg-3) 0%, var(--bg-2) 100%);
    border-bottom: 1px solid var(--line-soft);
    position: sticky;
    top: 0;
    z-index: 100;
}

nav {
    max-width: 73.75rem;
    margin: 0 auto;
    padding: 0 2rem;
    height: 3.5rem;
    display: flex;
    align-items: center;
    gap: 1.5rem;
}

.nav-brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 700;
    font-size: 0.938rem;
    letter-spacing: 0.013rem;
    color: var(--ink);
    margin-right: auto;
    text-decoration: none;
    transition: color 0.15s;
}

.nav-brand:hover { color: var(--accent-glow); }

.nav-link-notif {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}

.nav-notif-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.25rem;
    height: 1.25rem;
    padding: 0 0.25rem;
    font-size: 0.688rem;
    font-weight: 600;
    border-radius: 0.188rem;
    border: 1px solid #ff6b6b;
    background: rgba(220,50,50,0.18);
    color: #ffaaaa;
    line-height: 1.25rem;
    text-align: center;
    flex-shrink: 0;
    pointer-events: none;
}

/* REQUIRED, not defensive. The `hidden` attribute hides an element via `display: none` in the
   BROWSER'S stylesheet, and the rule above sets `display: inline-flex` in an AUTHOR stylesheet —
   author beats user-agent, so `hidden` alone does nothing here and a zero badge would still render.
   Without this line, `<span class="nav-notif-badge" hidden>0</span>` shows a red 0.
   This is why the older JS-populated badges hide themselves with inline `style="display:none"`. */
.nav-notif-badge[hidden] {
    display: none;
}

.nav-link {
    font-size: 0.813rem;
    color: var(--ink-3);
    text-decoration: none;
    transition: color 0.15s;
}

.nav-link:hover { color: var(--ink); }

.nav-menu {
    position: relative;
}

.nav-account {
    margin-left: auto;
}

/* inline-flex + gap so a .nav-notif-badge sits clear of the label instead of touching it — the same
   treatment .nav-link-notif gives the Dashboard link, and the same 0.375rem (UI/Badges.md).
   Added 2026-08-06: the Admin button's badge is emitted with no whitespace before it, so nothing
   separated the two, and the Guild Master button relied on a collapsed newline. A gap makes the
   spacing the button's own rather than a property of how the markup happens to be formatted. */
.nav-menu-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    background: none;
    border: none;
    color: var(--ink-3);
    cursor: pointer;
    font-size: 0.813rem;
    font-family: inherit;
    padding: 0;
    line-height: inherit;
    transition: color 0.15s;
}

.nav-menu-btn:hover { color: var(--ink); }

.nav-dropdown {
    display: none;
    position: absolute;
    top: calc(100% + 0.625rem);
    left: 0;
    background: var(--bg-3);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    min-width: 11.25rem;
    z-index: 100;
    box-shadow: var(--sh-card);
}

.nav-dropdown-right {
    left: auto;
    right: 0;
}

.nav-dropdown.open { display: block; }

.nav-dropdown-item {
    display: block;
    padding: 0.563rem 1rem;
    font-size: 0.813rem;
    color: var(--ink-3);
    text-decoration: none;
    transition: color 0.15s, background-color 0.15s;
    white-space: nowrap;
}

.nav-dropdown-item:hover {
    color: var(--ink);
    background-color: rgba(43,95,196,0.06);
}

.account-menu { position: relative; }
.guild-menu { position: relative; }
.admin-menu { position: relative; }
.raidleader-menu { position: relative; }
.account-dropdown, .guild-dropdown, .admin-dropdown, .raidleader-dropdown {
    display: none; position: absolute; top: calc(100% + 0.625rem); left: 0;
    background: var(--bg-3); border: 1px solid var(--line);
    border-radius: var(--r-sm); min-width: 160px; z-index: 100; box-shadow: var(--sh-card);
}
.account-dropdown { left: auto; right: 0; }
.account-dropdown.open, .guild-dropdown.open, .admin-dropdown.open, .raidleader-dropdown.open { display: block; }
.account-dropdown-item, .guild-dropdown-item, .admin-dropdown-item, .raidleader-dropdown-item {
    display: block; padding: 0.563rem 1rem; font-size: 0.813rem; color: var(--ink-3);
    text-decoration: none; transition: color 0.15s, background-color 0.15s; white-space: nowrap;
}
.account-dropdown-item:hover, .guild-dropdown-item:hover,
.admin-dropdown-item:hover, .raidleader-dropdown-item:hover {
    color: var(--ink); background-color: rgba(43,95,196,0.06);
}

/* Phone nav-collapse base — desktop-transparent wrapper + hidden hamburger.
   The wrapper generates no box on desktop (display:contents) so the nav renders
   identically; phone overrides live in css/phone/global.css. */
.nav-collapse { display: contents; }
.nav-toggle { display: none; }

main {
    flex: 1;
    position: relative;
    z-index: 1;
    max-width: 73.75rem;
    width: 100%;
    margin: 0 auto;
    padding: 1.75rem 2rem 3.75rem;
}

h1 {
    font-size: 1.375rem;
    font-weight: 700;
    letter-spacing: -0.013rem;
    margin-bottom: 0.25rem;
    color: var(--ink);
}

/*  flex-wrap added 2026-08-27 so the external-links row can be a third flex child that takes its own
    line (see .char-ext-links). The icon and text still share line one — nothing else in here wraps.
.char-page-head {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}
*/
.char-page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}

/*  #loot-history-view rules (the Loot Distribution History tab's sticky sidebar and its active row)
    moved to css/pages/loot-distribution.css on 2026-09-30 (Session 236), with the rest of that page.
    Removed rather than commented out: the block carried its own comment, and CSS comments do not
    nest (the same reason as the Teams move further down). */

.char-page-layout .roster-sidebar,
.char-page-layout .raider-view-main {
    align-self: flex-start;
}
.char-page-layout .roster-sidebar-body {
    padding-bottom: 0.75rem;
}

#char-main-content .gp-tab {
    min-height: 2.25rem;
}
#char-main-content .gp-tabs {
    position: relative;
    z-index: 1;
}

.char-admin-panel {
    margin-bottom: 1rem;
    display: inline-block;
}

/*  Gear warnings, to the LEFT of the Admin card (Session 212). inline-block like .char-admin-panel,
    so the two sit side by side with no wrapper and either can be absent — the Admin card is
    IsAdmin-gated and this one is not, so all four combinations occur.

    vertical-align: top because the two cards are rarely the same height: this one grows with the
    number of warnings (up to 14 observed) while the Admin card is a fixed two rows. Without it the
    shorter card baseline-aligns and appears to float. */
.char-gear-warnings {
    margin-bottom: 1rem;
    margin-right: 0.75rem;
    display: inline-block;
    vertical-align: top;
}

/*  The global `ol li, ul li { margin-bottom: .4rem }` would space these apart like prose; a warning
    list is a dense readout, so the gap is reset here rather than the list being built from <div>s.
    Same reasoning as the flat-<button> note in Teams/Documents. */
.char-gear-warning-list {
    margin: 0;
    padding-left: 1.1rem;
}

.char-gear-warning-list li {
    margin-bottom: 0;
    font-size: 0.813rem;
    color: var(--ink-2);
}

/*  External resource links under the character's name — icons only, the site name in the anchor's
    title.

    flex-basis: 100% makes it take its OWN LINE inside .char-page-head (which is flex-wrap: wrap), so
    the row starts at the header's left edge — UNDER THE CLASS ICON — rather than indented to the
    name (instructed 2026-08-27). The alternative, placing it after .char-page-head, would have had
    that element's 1.5rem margin-bottom between the two.

    margin-top is 0 because the parent's `gap: 0.75rem` already spaces the wrapped line. */
.char-ext-links {
    display: flex;
    flex-basis: 100%;
    align-items: center;
    gap: 0.375rem;
}

.char-ext-link {
    display: inline-flex;
    line-height: 0;
    opacity: 0.75;
    transition: opacity 0.1s;
}

.char-ext-link:hover {
    opacity: 1;
}

/*  Fixed box with object-fit because the imported logos are square but not one size (64px to 460px
    on disk) — same reason .gp-links-icon sets one.

    1.5rem, half again the 1rem the card menus use (instructed 2026-08-27). DELIBERATELY LARGER THAN
    .gp-links-icon rather than shared with it: there the icon sits beside a text label and is a hint,
    here it IS the control and carries the whole target, so the two are not the same component at
    different sizes. */
.char-ext-link img {
    width: 1.5rem;
    height: 1.5rem;
    object-fit: contain;
}
.char-admin-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.char-admin-row + .char-admin-row {
    margin-top: 0.375rem;
}
.char-admin-label {
    font-size: 0.719rem;
    color: var(--ink-3);
    min-width: 6rem;
}
.char-admin-value {
    font-size: 0.813rem;
    font-family: 'JetBrains Mono', monospace;
    color: var(--ink-2);
}

button.gp-panel-row {
    width: 100%;
    min-height: 2.25rem;
    background: none;
    border-top: none;
    border-right: none;
    text-align: left;
    font-size: 0.781rem;
    font-family: inherit;
    color: var(--ink-2);
}

h2 {
    font-size: 1.1rem;
    font-weight: 600;
    margin-bottom: 0.75rem;
    color: var(--ink);
}

p {
    color: var(--ink-3);
    margin-bottom: 1rem;
}

ol, ul {
    color: var(--ink-3);
    padding-left: 1.5rem;
    margin-bottom: 1rem;
}

ol li, ul li {
    margin-bottom: 0.4rem;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    table-layout: auto;
    font-size: 0.813rem;
    margin-bottom: 1.5rem;
}
.gp-card-table .data-table { margin-bottom: -1px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
/* Exception to the -1px above, for a table inside a scrolling split panel. That margin exists to
   merge the table's bottom border with a card FOOTER's top border; inside .gp-split-left-body no
   footer follows, and the negative margin is subtracted from the body's layout height but NOT from
   its scrollHeight. The body then reports content exactly 1px taller than its box and draws a
   scrollbar on a panel whose content fits (measured: table 534, body 533). Specificity 0,3,0 so it
   beats the rule above regardless of file order. */
.gp-card-table .gp-split-left-body > .data-table { margin-bottom: 0; }
.gp-card-table .detail-row .data-table { border-top: none; border-bottom: none; }
.gp-card-table .detail-row .detail-panel { gap: 0; }
.gp-card-table .data-table td:last-child, .gp-card-table .data-table th:last-child { padding-right: 1.125rem; }
.gp-card-table .data-table .detail-row > td { padding-right: 0; }
.data-table thead th {
    /* text-align: left; */
    text-align: center;
    padding: 0.75rem 1rem;
    font-size: 0.688rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.038rem;
    color: var(--ink-3);
    border-bottom: 1px solid var(--line-soft);
    background: rgba(255,255,255,0.015);
    white-space: nowrap;
}
/* .data-table thead th:last-child { text-align: right; } */
.th-group { border-bottom: 1px solid var(--line); }
.group-start { border-left: 1px solid var(--line); }
.group-end { border-right: 1px solid var(--line); }
/* .data-table td {
    padding: 0.75rem 1rem;
    color: var(--ink-2);
    vertical-align: middle;
} */
.data-table td {
    padding: 0.75rem 0.5rem;
    color: var(--ink-2);
    vertical-align: middle;
}
/* .data-table td:last-child { text-align: right; white-space: nowrap; padding-right: 1rem; } */
/* .data-table tr:not(.detail-row) td:last-child { text-align: right; white-space: nowrap; padding-right: 1rem; } */
.data-table td.col-controls, .data-table th.col-controls { text-align: right; white-space: nowrap; width: 1px; padding-right: 1rem; vertical-align: top; }
/* Control spacing lives on the INNER WRAPPER, never on the td itself.

   Why not the td: a td is a table-cell participating in the table's width algorithm, and
   display:flex removes it from that. width:1px then becomes the flex basis — with flex-wrap the
   buttons stack vertically, and with nowrap the column still mis-sizes. That was tried and reverted
   in Session 174; do not retry it as a CSS-only change on the cell.

   Why a wrapper is the real fix, not just a workaround: a flex container DISCARDS whitespace-only
   text nodes between its items. The gap is therefore exactly what is declared, whether the markup
   came from Razor or was generated by script. It replaces the previous arrangement, where spacing
   was the incidental whitespace between controls in the markup — undeclared, dependent on
   font-size, and absent entirely from any script that did not remember to emit it.

   The wrapper class is .action-cell, defined below. Every td.col-controls holding more than nothing
   wraps its controls in one. */
/* .data-table td.col-expand + td { padding-left: 1rem; } */
/* .data-table td:first-child:not(.col-expand) { padding-left: 1rem; } */
.data-table tr:not(.detail-row) td:first-child:not(.col-expand) { padding-left: 1rem; }
/* .data-table td.col-expand { padding-left: 0; padding-right: 0; } */
/* .data-table td.col-expand, .data-table th.col-expand { padding-left: 0; padding-right: 0; min-width: 18px; } */
.data-table td.col-expand, .data-table th.col-expand { position: relative; padding-left: 0; padding-right: 0; min-width: 1.125em; }
.data-table tbody tr {
    border-top: 1px solid var(--line);
    transition: background 0.12s;
    background: var(--bg-2);
}
.data-table tbody tr:first-child { border-top: none; }
.data-table tbody tr:last-child { border-bottom: none; }
.data-table tbody tr:hover {
    background-image: linear-gradient(rgba(43,95,196,0.06), rgba(43,95,196,0.06));
}

/* Table column type rules — apply matching class to both th and td */
.col-fill { width: 100%; }
/* .col-flag MOVED to the centred group below on 2026-09-06 (Session 218) — it was here.
.col-date,
.col-time,
.col-duration,
.col-status,
.col-flag,
.col-expand,
.col-shrink,
.col-actions { width: 1px; white-space: nowrap; } */
.col-date,
.col-time,
.col-duration,
.col-status,
.col-expand,
.col-shrink,
.col-actions { width: 1px; white-space: nowrap; }
/* .data-table td.col-date { text-align: right; } */
.data-table td.col-date,
.data-table td.col-time,
.data-table td.col-duration { text-align: right; }
.col-num,
.col-pct,
.col-currency { width: 1px; white-space: nowrap; text-align: right; }
/*  .col-flag JOINED THIS GROUP 2026-09-06 (Session 218), instructed.

    IT LANDS BESIDE .col-check RATHER THAN GETTING A RULE OF ITS OWN, and the two belong together:
    .col-check is a boolean rendered as a SYMBOL and .col-flag is the same fact rendered as TEXT
    (Yes/No, On/Off). They were centred and left-aligned respectively, which is one treatment for one
    kind of value split by how it happens to be spelled.

    !! IT IS A GLOBAL CLASS AND THIS MOVES 11 CELLS ACROSS 4 VIEWS: Accounts/_AccountPageSettings,
    Admin/_WorkerStatusTable, CustomPages/_CustomPagesTable and Surveys/Manage. Three of those were
    not opened for this change. */
.col-icon,
.col-check,
.col-flag { width: 1px; white-space: nowrap; text-align: center; }
.col-desc { max-width: 40ch; overflow-wrap: break-word; }
.col-code { white-space: nowrap; font-family: monospace; }
/*  ALIGNMENT UTILITIES — added 2026-09-17 (Session 224), instructed.

    WHY THEY EXIST NOW. Every alignment-bearing column class above is bound to a value TYPE (dates right,
    numbers right, booleans centre), so there was no way to say "this TEXT column is centred / right".
    UI/Tables.md recorded the gap, declined a utility, and named a third page wanting one as the signal to
    revisit. By then four tables carried page-local copies (the Accounts Discord table, the Team Members
    rank column, the Manage Team GoW columns) and the two rank history tables were the next two.

    A SECOND KIND OF COLUMN CLASS, deliberately: a type class says what the value IS, one of these says only
    where it sits. Stack one ON a type class (`col-status col-align-center`); never use one instead of it.

    (0,2,1) — beats .data-table td (0,1,1), and ties .data-table td.col-date, which it follows, so it wins
    there too. The th variant is needed for right-alignment: .data-table thead th centres every header.

    The existing page-local rules were NOT migrated onto these — working code, left as it is. */
.data-table th.col-align-center,
.data-table td.col-align-center { text-align: center; }
.data-table th.col-align-right,
.data-table td.col-align-right { text-align: right; }
/*  .col-align-left added 2026-09-29 (Session 233), instructed: the dashboard Raid Roster card's date column,
    where a right-aligned .col-date left dates of different lengths ragged on the left. */
.data-table th.col-align-left,
.data-table td.col-align-left { text-align: left; }
/*  .col-tight added 2026-10-03 (Session 244), instructed: a COMPACT COLUMN — horizontal padding cut to
    0.375rem on the header and every cell. `.data-table thead th` pads 1rem each side, which on a short
    header in a narrow column (Manage Roster's "Rot.") is most of the column. Same kind of class as the
    col-align-* utilities above: it says nothing about what the value is, so it STACKS on a type class
    or a page column class, never replaces one. Vertical padding is untouched, so the row height and the
    header row height stay those of the table. Specificity (0,2,1) beats .data-table thead th (0,1,2)
    and .data-table td (0,1,1). UI/Tables.md "Compact column". */
.data-table th.col-tight,
.data-table td.col-tight { padding-left: 0.375rem; padding-right: 0.375rem; }

/*  RANK HISTORY TABLES — Trials History (Views/Trials/History.cshtml) and the Character page's Ranks tab
    (Views/Character/_RankHistory.cshtml). One class on both, because they are one table shape on two pages.

    From and To are .col-status, which shrink-wraps (width: 1px), so a short rank such as "Trial" gave the
    column barely the width of the word and a centred value sat cramped. A minimum keeps the two rank
    columns a steady width (instructed, 4rem). */
.data-table.rank-history-table th.col-status,
.data-table.rank-history-table td.col-status { min-width: 4rem; }
/*  Event is these tables' fill column (.col-fill, width: 100%) and must NOT wrap (both instructed
    2026-09-17). .col-fill carries no white-space rule and .col-shrink cannot be stacked on it — its
    width: 1px would fight the 100% — so the no-wrap is stated here, for these two tables only. */
.data-table.rank-history-table td.col-fill { white-space: nowrap; }
.col-name { max-width: 30ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Sortable column */
.sortable-col { cursor: pointer; user-select: none; white-space: nowrap; }
.sortable-col:hover { color: var(--accent); }
.sort-indicator { font-size: 0.625rem; margin-left: 0.25rem; }
.data-table thead th.sortable-col:has(a) { padding: 0; }
/* .data-table thead th.sortable-col a { display: block; padding: 0.75rem 1rem; } */
/* .data-table thead th.sortable-col a { display: block; padding: 0.75rem 1rem; position: relative; } */
/* .data-table thead th.sortable-col a .sort-indicator { position: absolute; right: 0.5rem; top: 50%; transform: translateY(-50%); margin: 0; } */
.data-table thead th.sortable-col a { display: block; padding: 0.75rem 1rem; text-align: center; }

/* Compact density modifier */
.data-table--compact td { padding: 0.375rem 0.5rem; }

/*  RULED TABLE — a separator between every column. Added 2026-08-24 (Session 208).

    A MODIFIER ON .data-table RATHER THAN A PAGE RULE, and that is the whole reason it is here
    instead of beside the member tables that asked for it. This file's own opening rule is that no
    table may define its own border rules outside .data-table, and Directive 18 says that when the
    standard has no form for a case you extend the standard rather than inventing a page-local third
    way. So it is shared, named and documented (UI/Tables.md), and any table that wants ruling gets
    the same treatment.

    `+ td` / `+ th` SKIPS THE FIRST COLUMN BY CONSTRUCTION — a leading border would draw a line down
    the outside edge of the card, which is the card's job and not the table's. Nothing has to know
    which column is first.

    --line-soft, NOT --line: the separators divide, they do not frame. .group-start / .group-end use
    the stronger --line to bracket a COLUMN GROUP, and border-collapse resolves the shared edge in
    favour of the wider, darker one — so a group's boundary still reads as stronger than the
    separators inside it. That layering is deliberate; do not level the two. */
.data-table--ruled thead th + th,
.data-table--ruled tbody td + td { border-left: 1px solid var(--line-soft); }

/* Section separator row — week/group label spanning all columns */
.data-table tr.data-table-section td {
    background: var(--bg-3);
    padding-top: 0.375rem;
    padding-bottom: 0.375rem;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--ink-3);
    letter-spacing: 0.02em;
}

.status-ok      { color: var(--ok); }
.status-missing { color: var(--ink-3); }
.status-error   { color: var(--bad); }
.status-zero    { color: var(--ink-4); }

.status-warning { color: var(--warn); }

/* Override .data-table td default ink colour when these utility classes are explicitly applied to a cell. */
.data-table td.status-ok      { color: var(--ok); }
.data-table td.status-missing { color: var(--ink-3); }
.data-table td.status-error   { color: var(--bad); }
.data-table td.status-warning { color: var(--warn); }
.data-table td.status-zero    { color: var(--ink-4); }
.data-table td.text-muted { color: var(--ink-3); }

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.375em 0.75em;
    font-size: 0.875rem;
    font-family: inherit;
    font-weight: 500;
    line-height: 1.3;
    box-sizing: border-box;
    text-decoration: none;
    color: var(--ink);
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: 0.25rem;
    cursor: pointer;
    transition: all 0.15s;
    box-shadow: 0 1px 0 rgba(255,255,255,0.03) inset, 0 1px 2px rgba(0,0,0,0.3);
}
.btn:hover {
    background: var(--bg-3);
    border-color: var(--ink-4);
    color: var(--ink);
}
.btn:active { transform: translateY(1px); }
/*  A CHECKBOX-BACKED TOGGLE IS A <label>, AND A LABEL'S TEXT IS SELECTABLE (2026-10-03, instructed). A
    real <button> is not, so double-clicking a column toggle highlighted its label while a button beside
    it did not. One rule on the element+class rather than one per page: it reaches every checkbox-backed
    .btn — the column toggles on Manage Roster, Manage Team, Team Members, Raider View and the loot
    Compare view, and the filter/picker toggles built the same way. A link styled .btn is untouched.
    UI/Buttons.md. */
label.btn {
    -webkit-user-select: none;
    user-select: none;
}

.btn-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05rem;
    padding: 0.125rem 0.375rem;
    border-radius: 0.25rem;
    background: var(--bg-3);
    color: var(--ink-3);

    border: 1px solid var(--line);
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    transition: color 0.15s, border-color 0.15s;
}
.btn-badge:hover { color: var(--ink-2); border-color: var(--ink-4); }
.btn-badge[data-mode="realm"] { color: var(--accent-glow); border-color: var(--accent); }

.btn-sm {
    font-size: 0.8rem;
    padding: 0.313em 0.625em;
}
.btn-sq { padding: 0.313em; }

.btn-xs {
    font-size: 0.75rem;
    padding: 0.25em 0.5em;
}

.btn-primary {
    background: linear-gradient(180deg, #1f4ea8 0%, #143580 100%);
    border-color: #6a98ea;
    color: white;
    box-shadow: 0 1px 0 rgba(255,255,255,0.45) inset, 0 4px 12px rgba(43,95,196,0.4), 0 0 0 1px rgba(74,130,224,0.4);
}

.btn-primary:hover {
    background: linear-gradient(180deg,
        color-mix(in oklab, #fff 24%, transparent),
        color-mix(in oklab, #1f4ea8 32%, transparent));
    border-color: color-mix(in oklab, #6a98ea 45%, transparent);
    backdrop-filter: blur(8px) saturate(1.3);
    box-shadow:
        inset 0 1px 0 #ffffff77,
        inset 0 -10px 16px -8px color-mix(in oklab, #1f4ea8 70%, transparent),
        0 8px 26px -8px color-mix(in oklab, #1f4ea8 85%, transparent);
    color: white;
}

.btn-accent {
    --acc: var(--accent);
    --acc-bright: color-mix(in oklab, var(--accent) 65%, #fff);
    background: color-mix(in oklab, var(--acc) 6%, transparent);
    border-color: var(--acc-bright);
    color: var(--acc-bright);
    box-shadow:
        0 0 0 1px color-mix(in oklab, var(--acc) 10%, transparent),
        0 0 14px 1px color-mix(in oklab, var(--acc) 50%, transparent),
        inset 0 0 12px -6px color-mix(in oklab, var(--acc-bright) 70%, transparent);
    text-shadow: 0 0 10px color-mix(in oklab, var(--acc-bright) 70%, transparent);
}
.btn-accent:hover {
    background: color-mix(in oklab, var(--acc) 26%, transparent);
    border-color: var(--acc-bright);
    color: #fff;
    box-shadow:
        0 0 0 1px color-mix(in oklab, var(--acc) 20%, transparent),
        0 0 26px 3px color-mix(in oklab, var(--acc) 85%, transparent),
        inset 0 0 16px -4px color-mix(in oklab, var(--acc-bright) 80%, transparent);
}

.btn-ghost {
    background: transparent;
    border-color: var(--line-soft);
    color: var(--ink-2);
    box-shadow: none;
}
.btn-ghost:hover { border-color: var(--line); color: var(--ink); background: transparent; }

.btn-save {
    background: rgba(43,95,196,0.2);
    border-color: rgba(43,95,196,0.5);
    color: #cfe0ff;
    box-shadow: none;
}

.btn-save:hover { background: rgba(43,95,196,0.3); border-color: rgba(43,95,196,0.8); color: #cfe0ff; }

/* .btn-ok, .btn-warn, .btn-danger, .btn-col {
    background: color-mix(in oklab, var(--col) 8%, var(--bg));
    border-color: color-mix(in oklab, var(--col) 40%, transparent);
    color: color-mix(in oklab, var(--col) 72%, #fff);
    box-shadow: none;
} */
/* .btn-ok, .btn-warn, .btn-danger, .btn-col {
    background: color-mix(in oklab, var(--col) 12%, var(--bg));
    border-color: color-mix(in oklab, var(--col) 90%, transparent);
    color: color-mix(in oklab, var(--col) 78%, #fff);
    box-shadow: inset 0 0 10px -1px color-mix(in oklab, var(--col) 85%, transparent);
}
.btn-ok:hover, .btn-warn:hover, .btn-danger:hover, .btn-col:hover { background: color-mix(in oklab, var(--col) 8%, var(--bg)); border-color: color-mix(in oklab, var(--col) 40%, transparent); color: color-mix(in oklab, var(--col) 72%, #fff); filter: brightness(1.12); }
.btn-ok:hover, .btn-warn:hover, .btn-danger:hover, .btn-col:hover {
    background: color-mix(in oklab, var(--col) 18%, var(--bg));
    border-color: var(--col);
    color: color-mix(in oklab, var(--col) 90%, #fff);
    box-shadow: inset 0 0 10px -1px color-mix(in oklab, var(--col) 100%, transparent), 0 0 12px -4px color-mix(in oklab, var(--col) 55%, transparent);
} */
/* scol — semantic color buttons */
.btn-ok, .btn-warn, .btn-danger {
    background: color-mix(in oklab, var(--col) 12%, var(--bg));
    border-color: color-mix(in oklab, var(--col) 55%, transparent);
    color: color-mix(in oklab, var(--col) 78%, #fff);
    box-shadow: inset 0 0 10px -1px color-mix(in oklab, var(--col) 45%, transparent);
}
.btn-ok:hover, .btn-warn:hover, .btn-danger:hover {
    background: color-mix(in oklab, var(--col) 18%, var(--bg));
    border-color: color-mix(in oklab, var(--col) 75%, transparent);
    color: color-mix(in oklab, var(--col) 90%, #fff);
    box-shadow: inset 0 0 10px -1px color-mix(in oklab, var(--col) 75%, transparent), 0 0 12px -4px color-mix(in oklab, var(--col) 55%, transparent);
}
.btn-ok { --col: oklch(0.66 0.15 150); }
.btn-warn { --col: oklch(0.80 0.15 92); }
.btn-danger { --col: oklch(0.62 0.20 25); }
/* scol-off */
.btn-scol-off { opacity: 0.55; box-shadow: inset 0 0 6px -2px color-mix(in oklab, var(--col) 20%, transparent); border-color: color-mix(in oklab, var(--col) 20%, transparent); }
.btn-scol-off:hover { opacity: 0.78; filter: none; border-color: color-mix(in oklab, var(--col) 40%, transparent); box-shadow: inset 0 0 10px -1px color-mix(in oklab, var(--col) 25%, transparent), 0 0 12px -4px color-mix(in oklab, var(--col) 55%, transparent); }
/* col — dynamic color buttons */
.btn-col {
    background: color-mix(in oklab, var(--col) 12%, var(--bg));
    border-color: color-mix(in oklab, var(--col) 90%, transparent);
    color: color-mix(in oklab, var(--col) 78%, #fff);
    box-shadow: inset 0 0 10px -1px color-mix(in oklab, var(--col) 85%, transparent);
}
.btn-col:hover {
    background: color-mix(in oklab, var(--col) 18%, var(--bg));
    border-color: var(--col);
    color: color-mix(in oklab, var(--col) 90%, #fff);
    box-shadow: inset 0 0 10px -1px color-mix(in oklab, var(--col) 100%, transparent), 0 0 12px -4px color-mix(in oklab, var(--col) 55%, transparent);
}
/* col-off */
/* .btn-col-off { opacity: 0.4; }
.btn-col-off:hover { opacity: 0.7; filter: none; } */
.btn-col-off { opacity: 0.55; box-shadow: inset 0 0 6px -2px color-mix(in oklab, var(--col) 20%, transparent); border-color: color-mix(in oklab, var(--col) 20%, transparent); }
.btn-col-off:hover { opacity: 0.78; filter: none; border-color: color-mix(in oklab, var(--col) 40%, transparent); box-shadow: inset 0 0 10px -1px color-mix(in oklab, var(--col) 25%, transparent), 0 0 12px -4px color-mix(in oklab, var(--col) 55%, transparent); }

.btn-active {
    --acc: var(--accent);
    --acc-bright: color-mix(in oklab, var(--accent) 65%, #fff);
    background:
        radial-gradient(120% 140% at 50% -30%, color-mix(in oklab, var(--acc) 30%, transparent), transparent 60%),
        var(--bg);
    border-color: color-mix(in oklab, var(--acc-bright) 30%, transparent);
    box-shadow:
        inset 0 0 0 1px color-mix(in oklab, var(--acc-bright) 55%, transparent),
        inset 0 1px 0 color-mix(in oklab, #fff 35%, transparent),
        0 3px 14px -8px color-mix(in oklab, var(--acc) 55%, transparent);
    color: var(--ink);
}
.btn-active:hover {
    box-shadow:
        inset 0 0 0 1px color-mix(in oklab, var(--acc-bright) 85%, transparent),
        inset 0 0 14px -4px color-mix(in oklab, var(--acc-bright) 60%, transparent),
        inset 0 1px 0 color-mix(in oklab, #fff 50%, transparent),
        0 6px 22px -8px color-mix(in oklab, var(--acc) 80%, transparent);
}

.btn-icon {
    width: 1.375rem;
    height: 1.375rem;
    padding: 0;
    background: linear-gradient(180deg, var(--bg-3) 0%, var(--bg) 100%);
    border-color: rgba(255,255,255,0.12);
    box-shadow: 0 0.063rem 0 rgba(255,255,255,0.04) inset, 0 0.125rem 0.25rem rgba(0,0,0,0.5);
}
.btn-icon:hover {
    --acc: var(--accent);
    --acc-bright: color-mix(in oklab, var(--accent) 65%, #fff);
    background: linear-gradient(180deg, var(--bg) 0%, var(--bg-3) 100%);
    border-color: color-mix(in oklab, var(--acc-bright) 30%, transparent);
    box-shadow:
        inset 0 0 0 1px color-mix(in oklab, var(--acc-bright) 85%, transparent),
        inset 0 0 8px -2px color-mix(in oklab, var(--acc-bright) 60%, transparent),
        inset 0 1px 0 color-mix(in oklab, #fff 50%, transparent),
        0 4px 14px -6px color-mix(in oklab, var(--acc) 80%, transparent);
}
.btn-icon-muted { color: var(--ink-3); }
.btn-icon-muted:hover { --acc: oklch(0.66 0.15 150); --acc-bright: color-mix(in oklab, oklch(0.66 0.15 150) 65%, #fff); color: oklch(0.66 0.15 150); }
.btn-icon-ok { color: oklch(0.66 0.15 150); }
.btn-icon-ok:hover { --acc: oklch(0.66 0.15 150); --acc-bright: color-mix(in oklab, oklch(0.66 0.15 150) 65%, #fff); color: oklch(0.66 0.15 150); }
.btn-icon-bad { color: var(--bad); }
.btn-icon-bad:hover { --acc: var(--bad); --acc-bright: color-mix(in oklab, var(--bad) 65%, #fff); color: var(--bad); }
.btn-icon-danger { color: var(--ink-3); }
.btn-icon-danger:hover { --acc: var(--bad); --acc-bright: color-mix(in oklab, var(--bad) 65%, #fff); color: var(--bad); }

.btn-group {
    display: inline-flex;
}
.btn-group .btn {
    border-radius: 0;
    position: relative;
}
.btn-group .btn:first-child { border-radius: var(--r-sm) 0 0 var(--r-sm); }
.btn-group .btn:last-child { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
.btn-group .btn + .btn { margin-left: -0.063rem; }
.btn-group .btn:hover,
.btn-group .btn.btn-active { z-index: 1; }
/* .btn-group .btn-icon { ... } — use .btn-group-icon instead; .btn-icon is not a valid .btn-group child */
/* .btn-group .btn-icon.btn-active { ... } — use .btn-group-icon .btn.btn-active instead */
.btn-group-icon .btn {
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.btn-group-icon.btn-group-sm .btn {
    width: 1.5rem;
    height: 1.5rem;
}
.btn-group-icon .btn.btn-active {
    --acc: var(--accent);
    --acc-bright: color-mix(in oklab, var(--accent) 65%, #fff);
    background:
        radial-gradient(120% 140% at 50% -30%, color-mix(in oklab, var(--acc) 30%, transparent), transparent 60%),
        var(--bg);
    border-color: color-mix(in oklab, var(--acc-bright) 30%, transparent);
    box-shadow:
        inset 0 0 0 1px color-mix(in oklab, var(--acc-bright) 85%, transparent),
        inset 0 0 12px -2px color-mix(in oklab, var(--acc-bright) 60%, transparent),
        inset 0 1px 0 color-mix(in oklab, #fff 50%, transparent);
}

.btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}

/* Pill toggle — JS segmented control (.toggle-pill) + CSS checkbox variant (.toggle-pill-check) */
.toggle-pill,
.toggle-pill-check {
    --pill-acc: var(--accent);
    --pill-acc-glow: color-mix(in oklab, var(--pill-acc) 65%, #fff);
    position: relative;
    display: inline-flex;
    align-self: flex-start;
    padding: 4px;
    border-radius: 999px;
    background: var(--bg);
    border: 1px solid var(--line);
    box-shadow: inset 0 1px 3px #00000060;
    user-select: none;
}
.toggle-pill-check { cursor: pointer; }
.toggle-pill-check input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    margin: 0;
    pointer-events: none;
}
.toggle-pill .seg,
.toggle-pill-check .seg {
    position: relative;
    z-index: 1;
    padding: 0.5em 1.125em;
    font: inherit;
    font-size: 0.813rem;
    font-weight: 650;
    line-height: 1;
    white-space: nowrap;
    color: var(--ink-3);
    cursor: pointer;
    border-radius: 999px;
    transition: color 0.25s ease, text-shadow 0.25s ease;
}
.toggle-pill-check .seg { flex: 1; }
/* JS pill active state */
.toggle-pill .seg[data-active] {
    color: var(--ink);
    text-shadow: 0 1px 6px color-mix(in oklab, var(--pill-acc) 50%, transparent);
}
/* Checkbox active states — checked = 1st seg (On), unchecked = 2nd seg (Off) */
/* .toggle-pill-check input:checked ~ .seg:nth-child(2),
.toggle-pill-check input:not(:checked) ~ .seg:nth-child(3) {
    color: var(--ink);
    text-shadow: 0 1px 6px color-mix(in oklab, var(--pill-acc) 50%, transparent);
} */
/* Checkbox checked (On) — bright */
.toggle-pill-check input:checked ~ .seg:nth-child(2) {
    color: var(--ink);
    text-shadow: 0 1px 6px color-mix(in oklab, var(--pill-acc) 50%, transparent);
}
/* Checkbox unchecked (Off) — dimmed */
.toggle-pill-check input:not(:checked) ~ .seg:nth-child(3) {
    color: var(--ink-2);
}
/* Shared knob visual */
.toggle-pill .knob,
.toggle-pill-check .knob {
    position: absolute;
    z-index: 0;
    top: 4px;
    left: 4px;
    height: calc(100% - 8px);
    border-radius: 999px;
    pointer-events: none;
    background: linear-gradient(180deg,
        color-mix(in oklab, #fff 16%, transparent),
        color-mix(in oklab, var(--pill-acc) 22%, transparent));
    border: 1px solid color-mix(in oklab, var(--pill-acc-glow) 45%, transparent);
    backdrop-filter: blur(8px) saturate(1.3);
    box-shadow:
        inset 0 1px 0 #ffffff55,
        inset 0 -8px 14px -8px color-mix(in oklab, var(--pill-acc) 60%, transparent),
        0 4px 18px -8px color-mix(in oklab, var(--pill-acc) 60%, transparent);
}
/* JS pill knob — width set by gp-toggle.js */
.toggle-pill .knob {
    width: 0;
    transition:
        transform 0.34s cubic-bezier(0.34, 1.3, 0.5, 1),
        width 0.34s cubic-bezier(0.34, 1.3, 0.5, 1),
        box-shadow 0.25s ease,
        background 0.25s ease,
        border-color 0.25s ease;
}
/* Checkbox knob — CSS-driven; grey when unchecked, accent when checked */
.toggle-pill-check .knob {
    width: calc(50% - 4px);
    transform: translateX(calc(100%));
    transition:
        transform 0.34s cubic-bezier(0.34, 1.3, 0.5, 1),
        box-shadow 0.25s ease,
        background 0.25s ease,
        border-color 0.25s ease;
    background: linear-gradient(180deg,
        color-mix(in oklab, #fff 10%, transparent),
        color-mix(in oklab, var(--ink-4) 28%, transparent));
    border-color: color-mix(in oklab, var(--line) 80%, transparent);
    box-shadow:
        inset 0 1px 0 #ffffff22,
        inset 0 -8px 14px -8px color-mix(in oklab, var(--ink-4) 25%, transparent),
        0 4px 18px -8px color-mix(in oklab, var(--ink-4) 15%, transparent);
}
.toggle-pill-check input:checked ~ .knob {
    transform: translateX(0);
    background: linear-gradient(180deg,
        color-mix(in oklab, #fff 16%, transparent),
        color-mix(in oklab, var(--pill-acc) 22%, transparent));
    border-color: color-mix(in oklab, var(--pill-acc-glow) 45%, transparent);
    box-shadow:
        inset 0 1px 0 #ffffff55,
        inset 0 -8px 14px -8px color-mix(in oklab, var(--pill-acc) 60%, transparent),
        0 4px 18px -8px color-mix(in oklab, var(--pill-acc) 60%, transparent);
}
/* A NEUTRAL SEGMENT (2026-10-03): a .seg carrying data-neutral is a real choice meaning "none". While
   it is the active one, the knob takes the MUTED look of the unchecked checkbox knob above, so "None"
   reads as not-chosen rather than as a third coloured answer. First caller: the rotation preference
   pill (Weekly | None | Daily). UI/TogglePill.md "Neutral segment".
   (Replaced, the same day, a .toggle-pill-tristate rule that muted a knob parked between two segments.) */
.toggle-pill:has(.seg[data-neutral][data-active]) .knob {
    background: linear-gradient(180deg,
        color-mix(in oklab, #fff 10%, transparent),
        color-mix(in oklab, var(--ink-4) 28%, transparent));
    border-color: color-mix(in oklab, var(--line) 80%, transparent);
    box-shadow:
        inset 0 1px 0 #ffffff22,
        inset 0 -8px 14px -8px color-mix(in oklab, var(--ink-4) 25%, transparent),
        0 4px 18px -8px color-mix(in oklab, var(--ink-4) 15%, transparent);
}
@media (prefers-reduced-motion: reduce) {
    .toggle-pill .knob,
    .toggle-pill-check .knob { transition: width 0.01s linear, transform 0.01s linear; }
}
/* Color variants — override --pill-acc only; --pill-acc-glow derives automatically */
.toggle-pill-red,
.toggle-pill-check.toggle-pill-red { --pill-acc: var(--bad); }
.toggle-pill-green,
.toggle-pill-check.toggle-pill-green { --pill-acc: var(--ok); }
.toggle-pill-dull,
.toggle-pill-check.toggle-pill-dull { --pill-acc: var(--ink-3); }
/* Disabled state. Keyed off the native attribute via :has(), NOT a companion class —
   UI/ClassNaming.md forbids mirroring an attribute with a class because the two drift the
   moment one writer sets the attribute and forgets the class. Values match the num-stepper's
   documented disabled treatment (UI/Controls.md) so the two read as the same state.
   pointer-events on the label is what stops a click reaching the input; a disabled checkbox
   ignores clicks itself, but the LABEL wrapper would otherwise still show a pointer cursor. */
.toggle-pill-check:has(input:disabled) {
    opacity: 0.45;
    cursor: not-allowed;
    --pill-acc: var(--ink-3);
}
.toggle-pill-check:has(input:disabled) .seg { pointer-events: none; }
/* Flip modifier — swaps positive/negative: Off (unchecked) is the accent/active state, On (checked) is dimmed */
.toggle-pill-check.toggle-pill-flip input:checked ~ .seg:nth-child(2) {
    color: var(--ink-2);
    text-shadow: none;
}
.toggle-pill-check.toggle-pill-flip input:not(:checked) ~ .seg:nth-child(3) {
    color: var(--ink);
    text-shadow: 0 1px 6px color-mix(in oklab, var(--pill-acc) 50%, transparent);
}
.toggle-pill-check.toggle-pill-flip .knob {
    background: linear-gradient(180deg,
        color-mix(in oklab, #fff 16%, transparent),
        color-mix(in oklab, var(--pill-acc) 22%, transparent));
    border-color: color-mix(in oklab, var(--pill-acc-glow) 45%, transparent);
    box-shadow:
        inset 0 1px 0 #ffffff55,
        inset 0 -8px 14px -8px color-mix(in oklab, var(--pill-acc) 60%, transparent),
        0 4px 18px -8px color-mix(in oklab, var(--pill-acc) 60%, transparent);
}
.toggle-pill-check.toggle-pill-flip input:checked ~ .knob {
    background: linear-gradient(180deg,
        color-mix(in oklab, #fff 10%, transparent),
        color-mix(in oklab, var(--ink-4) 28%, transparent));
    border-color: color-mix(in oklab, var(--line) 80%, transparent);
    box-shadow:
        inset 0 1px 0 #ffffff22,
        inset 0 -8px 14px -8px color-mix(in oklab, var(--ink-4) 25%, transparent),
        0 4px 18px -8px color-mix(in oklab, var(--ink-4) 15%, transparent);
}
/* Small size modifier */
.toggle-pill-sm .seg,
.toggle-pill-check.toggle-pill-sm .seg {
    font-size: 0.688rem;
    padding: 0.375em 0.875em;
}

.error-panel {
    background: rgba(255,107,107,0.05);
    border: 1px solid rgba(255,107,107,0.25);
    border-left: 0.188rem solid var(--bad);
    border-radius: var(--r-sm);
    padding: 0.625rem 0.875rem;
    margin-bottom: 1.125rem;
    box-shadow: inset 3px 0 8px rgba(255,107,107,0.08);
}

.error-panel-message {
    color: var(--bad);
    font-size: 0.813rem;
    font-family: 'JetBrains Mono', monospace;
    margin-bottom: 0.375rem;
    word-break: break-word;
}

/* The margin above exists to separate the message from an .error-panel-suggestion beneath it. Most
   panels have no suggestion, and there it is 0.375rem of dead space against the panel's own padding.
   Added 2026-08-06. :last-child so a panel that DOES carry a suggestion is untouched. */
.error-panel-message:last-child {
    margin-bottom: 0;
}

.error-panel-suggestion {
    color: var(--ink-3);
    font-size: 0.781rem;
    margin-bottom: 0;
}

.info-notice {
    background: rgba(90,140,201,0.05);
    border: 1px solid rgba(90,140,201,0.3);
    border-left: 0.188rem solid var(--accent-2);
    border-radius: var(--r-sm);
    padding: 0.625rem 0.875rem;
    font-size: 0.813rem;
    color: var(--ink-2);
    margin-bottom: 1.125rem;
    box-shadow: inset 3px 0 8px rgba(90,140,201,0.08);
}

/* MOVED 2026-09-06 (Session 218) to pages/accounts.css under Conventions §5.4's incremental split.
   All six are used by Views\Accounts\Index.cshtml and by nothing else — verified against every view
   before moving. .search-options-row additionally gained a flex row there, when a second checkbox
   joined the first.
   .gc-search-group and .guild-search-clear DELIBERATELY STAYED HERE: three views use them
   (Accounts, GuildCharacters and ModerateTeam\_GuildCharacterList), so they are shared and are not
   this page's to move.
.accounts-toolbar {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    margin-bottom: 0.5rem;
    flex-wrap: wrap;
}

.search-options-row {
    margin-bottom: 1.125rem;
}

.search-option-label {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.781rem;
    color: var(--ink-2);
    cursor: pointer;
    user-select: none;
}

.search-input {
    min-width: 17.5rem;
}

.page-size-row {
    display: flex;
    align-items: center;
    gap: 0.375rem;
}

.page-size-label {
    font-size: 0.75rem;
    color: var(--ink-3);
} */

.sort-header {
    color: var(--ink-3);
    font-size: 0.688rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.038rem;
    text-decoration: none;
    transition: color 0.15s;
}
.sort-header:hover { color: var(--ink); }

.account-name-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.muted-subtitle {
    font-size: 0.688rem;
    color: var(--ink-3);
    margin-top: 0.188rem;
    font-family: 'JetBrains Mono', monospace;
}

.banned-badge {
    display: inline-flex;
    align-items: center;
    font-size: 0.688rem;
    font-weight: 600;
    padding: 0.188rem 0.563rem;
    border-radius: 0.188rem;
    border: 1px solid rgba(255,107,107,0.25);
    background: rgba(255,107,107,0.05);
    color: var(--bad);
}

.battletag-badge {
    display: inline-block;
    padding: 0.125rem 0.438rem;
    font-size: 0.688rem;
    border-radius: 0.188rem;
    background: var(--bg-3);
    color: var(--ink-3);
    border: 1px solid var(--line-soft);
    font-family: 'JetBrains Mono', monospace;
    white-space: nowrap;
}
/*  ---------------------------------------------------------------------------
    Badge icons — Battle.net and Discord. Added 2026-09-06 (Session 218).

    CSS MASKS, not <img> and not inline SVG. A mask takes its colour from
    background-color, which is the only one of the three that lets the glyph follow the
    badge's own ink — and the Discord badge's ink changes with its confirmed state below.
    Established pattern here: .modteam-lock-icon and the role icons both do this.

    currentColor rather than a named variable, so each icon inherits whatever its badge
    resolved to and no rule has to be kept in step with another.

    !! THE TWO SOURCE FILES ARE DIFFERENT SHAPES — battlenet.svg is a 32x32 square,
    discord.svg is 640x512 (5:4). They are sized SEPARATELY on purpose; giving both the
    same box would squash one. Do not "tidy" them into a shared rule.
    --------------------------------------------------------------------------- */
.badge-icon {
    display: inline-block;
    vertical-align: -0.09em;
    margin-right: 0.25rem;
    background-color: currentColor;
    mask-repeat: no-repeat;
    mask-position: center;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
    -webkit-mask-size: 100% 100%;
}

/* Square source, square box. */
.badge-icon-battlenet {
    width: 0.75rem;
    height: 0.75rem;
    mask-image: url('/img/battlenet.svg');
    -webkit-mask-image: url('/img/battlenet.svg');
}

/* 5:4 source, so the box is 5:4 — same height as the Battle.net glyph, wider. */
.badge-icon-discord {
    width: 0.938rem;
    height: 0.75rem;
    mask-image: url('/img/discord.svg');
    -webkit-mask-image: url('/img/discord.svg');
}

/*  ---------------------------------------------------------------------------
    Discord tag badge — the .battletag-badge family, colour-coded by confirmation.

    It reuses .battletag-badge rather than redeclaring one, so the two read as a set and a
    change to the family reaches both. Only the ink and the border move.

    SEMANTIC COLOURS, never a fixed hex (Conventions §5.6). --ok for a proved mapping,
    --ink-3 for a claim — and the ink scale rather than an opacity, because each theme
    defines its own direction for "dimmer".
    --------------------------------------------------------------------------- */
.discord-badge {
    margin-left: 0.25rem;
}

/*  The Account page's badge row sits UNDER the .gp-page-subtitle rather than beside it, so it needs
    its own top gap — the Character page's badges are inline in .ccw-realm and need none.
    It is a row rather than a bare wrapper so the badges and the "(X more)" link align on their
    baseline when the row wraps. */
.discord-badge-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem;
    margin-top: 0.375rem;
}

/* The badges carry their own left margin for the inline case; inside the flex row the gap owns the
   spacing, so the first one must not add to it. */
.discord-badge-row .discord-badge {
    margin-left: 0;
}

/* Confirmed: the mapping was proved through Discord authentication. */
.discord-badge-confirmed {
    color: var(--ok);
    border-color: color-mix(in srgb, var(--ok) 45%, var(--line-soft));
}

/* Unconfirmed: somebody asserted it. Deliberately quieter than the confirmed state. */
.discord-badge-unconfirmed {
    color: var(--ink-3);
}

/*  A copyable badge. The cursor is the only permanent affordance — the badge must still read as a
    value rather than as a button, so there is no border or background change at rest.

    user-select: none BECAUSE THE CLICK IS THE COPY. Without it a double-click highlights the tag,
    which is both noise and a worse version of what one click already does. Same treatment
    .sortable-col and .search-option-label already use for the same reason: an element whose click
    means something other than "select this text".
    -webkit- prefix for Safari, which still needs it. */
.discord-badge.js-gp-copy {
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
}

/*  Copy confirmed, for ~1.2s. gp-copy.js adds and removes the class; this decides what it looks like.

    THE BADGE ALREADY CARRIES A STATE COLOUR (confirmed/unconfirmed), so this must not be a THIRD
    colour competing with those — it brightens the border the badge already has and leaves the ink
    alone. --ok would collide with .discord-badge-confirmed and say nothing on a row already green. */
.gp-copy-copied {
    border-color: var(--accent);
    box-shadow: 0 0 0 0.125rem color-mix(in srgb, var(--accent) 25%, transparent);
}

/*  The "(X more)" link. GM/Admin only — the resolver never sets a count for anyone else.
    It is a plain link and carries no .battletag-badge: it is not a tag, and dressing it as
    one would read as a fourth tag named "(2 more)". */
.discord-badge-more {
    margin-left: 0.25rem;
    font-size: 0.688rem;
    color: var(--ink-3);
    white-space: nowrap;
}

.discord-badge-more:hover {
    color: var(--accent);
}

.char-realm { display: block; font-size: 0.75rem; color: var(--ink-3); }
.gc-team-tag { display: inline; }
.gc-team-tag + .gc-team-tag::before { content: ", "; }
.gc-sort-col { cursor: pointer; user-select: none; white-space: nowrap; }
.gc-sort-col:hover { color: var(--accent); }
.gc-sort-indicator { font-size: 0.625rem; margin-left: 0.25rem; color: var(--accent); }
.gc-search-group { display: inline-flex; align-items: stretch; }
.gc-search-group input[type="text"] { border-radius: var(--r-sm) 0 0 var(--r-sm); border-right: none; }
.gc-search-group .guild-search-clear { border: 1px solid var(--line); border-radius: 0 var(--r-sm) var(--r-sm) 0; padding: 0 0.5rem; background: var(--bg-2); display: flex; align-items: center; }
.gc-search-group .modteam-input ~ .guild-search-clear { border-color: var(--line); }
.gc-search-group .guild-search-clear:hover { background: var(--bg-3); color: var(--ink); }
.gc-search-group:focus-within input[type="text"] { border-color: var(--accent); }
.gc-search-group:focus-within .guild-search-clear { border-color: var(--accent); }

.copy-btn {
    background: none;
    border: none;
    color: var(--ink-3);
    font-size: 0.8rem;
    cursor: pointer;
    padding: 0;
    line-height: 1;
    transition: color 0.15s;
}

.copy-btn:hover {
    color: var(--ink);
}

.role-cell {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    align-items: center;
}

.role-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.313rem;
    padding: 0.188rem 0.563rem;
    font-size: 0.688rem;
    font-weight: 500;
    border-radius: 0.188rem;
    background: var(--bg-3);
    border: 1px solid var(--line);
    color: var(--ink-2);
}

.role-remove-btn {
    background: none;
    border: none;
    color: var(--ink-3);
    font-size: 0.85rem;
    cursor: pointer;
    padding: 0;
    line-height: 1;
    transition: color 0.15s;
}

.role-remove-btn:hover {
    color: var(--bad);
}

.assign-role-form {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

/* .role-select {
    padding: 0.2rem 0.4rem;
    font-size: 0.8rem;
    font-family: inherit;
    background-color: var(--bg-3);
    border: 1px solid var(--line);
    border-radius: 0.188rem;
    color: var(--ink);
} */

.text-muted { color: var(--ink-3); }
/*.label-required::after { content: " *"; color: var(--warn); }*/
.gp-label-required::after { content: " *"; color: var(--bad); }
.gp-save-indicator { width: 0.5rem; height: 0.5rem; border-radius: 50%; flex-shrink: 0; align-self: center; display: none; transition: background 0.2s; }
.gp-save-indicator.is-saved { display: block; background: var(--ok); }
.gp-save-indicator.is-dirty { display: block; background: var(--bad); }

.char-link {
    color: var(--accent-2);
    font-size: 0.813rem;
    cursor: default;
}

/* The standard wrapper for a row's action controls, and the only thing that spaces them.
   Always the single child of td.col-controls (see that rule for why the gap cannot go on the cell).
   Being a flex container is what makes the gap deterministic: whitespace-only text nodes between
   flex items are discarded, so markup whitespace no longer contributes anything. */
.action-cell {
    display: flex;
    gap: 0.375rem;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: flex-end;
}

.row-banned td {
    opacity: 0.7;
}

.row-banned {
    border-left: 0.188rem solid var(--bad) !important;
    background: rgba(255,107,107,0.04);
}

.pagination-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 1rem;
}

.pagination-info {
    font-size: 0.75rem;
    color: var(--ink-3);
}

.pagination-links {
    display: flex;
    gap: 0.375rem;
}

/* Moved to pages/my-characters.css 2026-09-26 (Session 231) — used by My Characters alone.
.chars-toolbar {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    margin-bottom: 1.125rem;
}
*/

.char-cards-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0.875rem;
}

.char-card-wide {
    position: relative;
    overflow: hidden;
    padding: 1rem 1.125rem 0.875rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    min-width: 0;
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    box-shadow: var(--sh-card);
    transition: transform 0.15s, box-shadow 0.15s;
    font-family: Inter, system-ui, sans-serif;
    color: var(--ink);
}
.char-card-wide:hover {
    transform: translateY(-0.063rem);
    box-shadow:
        0 0.063rem 0 rgba(255,255,255,0.04) inset,
        0 0.25rem 1rem rgba(0,0,0,0.4),
        0 1rem 2.5rem rgba(0,0,0,0.5),
        0 0 0 0.063rem var(--accent),
        0 0 1.5rem color-mix(in oklch, var(--accent) 35%, transparent);
}

.char-top {
    position: absolute;
    left: 0; right: 0; top: 0;
    height: 0.188rem;
    background: var(--accent);
    box-shadow: 0 0 12px var(--accent);
}

.ccw-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
}
.ccw-name-block { display: flex; flex-direction: column; gap: 0.188rem; min-width: 0; }
.ccw-name-line { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.ccw-name-line .role-icon { margin-right: -0.313rem; }

.ccw-class-icon {
    width: 1.375rem;
    height: 1.375rem;
    border-radius: 0.188rem;
    border: 1px solid rgba(255,255,255,0.12);
    box-shadow: 0 0.063rem 0 rgba(255,255,255,0.04) inset, 0 0.125rem 0.25rem rgba(0,0,0,0.5);
    flex-shrink: 0;
    display: block;
}

.ccw-lvl-sub {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.688rem;
    font-weight: 400;
    color: var(--ink-4);
    letter-spacing: 0.019rem;
    flex-shrink: 0;
}

.ccw-realm {
    display: flex;
    align-items: center;
    gap: 0.375rem;
}

.ccw-lvl-inline {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--ink-3);
    letter-spacing: 0.019rem;
    flex-shrink: 0;
}
a.ccw-name { text-decoration: none; }
.ccw-name {
    font-weight: 700;
    font-size: 1.063rem;
    letter-spacing: 0.006rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.ccw-realm {
    font-size: 0.719rem;
    color: var(--ink-3);
    margin-top: 0.125rem;
    letter-spacing: 0.006rem;
}

/* One setting per row on the account page's Account settings tab: label left, switch hard
   right. Both rows share the structure so the two pills align on the same edge. */
.acc-settings-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.375rem 0;
}
.acc-settings-label {
    font-size: 0.813rem;
    color: var(--ink-2);
    min-width: 0;
}
/* Mandatory, not cosmetic: .toggle-pill-check is inline-flex, and a flex item has its display
   blockified, so inside a flex row it computes to flex and stretches to the full width. Its
   segments are flex: 1 with a 0 basis, so nothing inside holds it at content width either.
   See UI/TogglePill.md, "Placing a pill inside a flex container". */
/* .acc-settings-row .toggle-pill-check { flex: 0 0 auto; } */
/* The JS pill too since 2026-10-03 (the three-state rotation preference pill). */
.acc-settings-row .toggle-pill-check,
.acc-settings-row .toggle-pill { flex: 0 0 auto; }

/* The Discord card's empty / unavailable line on the Account settings tab. That card is a
   gp-card-table, which zeroes the card's own padding so its table can reach both edges, so every
   non-table block inside carries its own (UI/Tables.md). 1.125rem matches .gp-card-padded.
   NOT .gp-card-body-padded, which the partial above uses and which has NO CSS RULE ANYWHERE in
   wwwroot/css — it applies nothing. Found 2026-09-06; reported, not fixed, because correcting it
   means deciding what its nine consuming views were meant to look like. */
.acc-discord-note {
    padding: 1.125rem;
}
.acc-discord-note p {
    margin: 0;
}

/*  The "add a tag on somebody else's behalf" row on the Account settings Discord card.

    IT CARRIES ITS OWN PADDING for the same reason .acc-discord-note above does: the card is
    gp-card-table, which zeroes the card's padding so the table can reach both edges, and every
    non-table block inside has to restore its own (UI/Tables.md).

    THE TOP BORDER IS THE TABLE'S BOTTOM EDGE DOING DOUBLE DUTY when rows exist, and the only
    divider when they do not — the empty state renders a note above this with no border of its own.

    IN site.css AND NOT pages/accounts.css, which would look like the tidier home: AccountPage.cshtml
    declares NO Styles section at all and never loads a page stylesheet, so a rule placed there would
    simply not apply. All 22 .acc- rules are here for the same reason. Splitting this page's CSS is a
    separate job and needs the section adding first. */
.acc-discord-add {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 1.125rem;
    border-top: 1px solid var(--line);
}
/*  Matches the input beside it — the global input rule is 0.813rem, and a label left at the body
    size would sit a step larger than the field it names. */
.acc-discord-add-label {
    font-size: 0.813rem;
    color: var(--ink);
    cursor: pointer;
}

/*  Centre the "Added by" column on the Account settings Discord card.

    PAGE-LOCAL BECAUSE NO DOCUMENTED CLASS FITS. Every alignment-bearing column class in this file is
    bound to a value TYPE, not to alignment: right is dates (.col-date/.col-time/.col-duration),
    numbers (.col-num/.col-pct/.col-currency) or actions (.col-controls), and centre is icons and
    booleans (.col-icon/.col-check/.col-flag). The text classes — .col-name, .col-desc, .col-code,
    .col-status — are all left and have no centred variant. There is no class meaning "a name, centred".

    THE ALTERNATIVE WAS AN ALIGNMENT UTILITY (.col-align-center) AND IT WAS DECLINED, for now: it would
    introduce a SECOND KIND of column class into a system where every class names what the value IS,
    leaving a reader two conventions to hold. If a third page ever wants this, that is the moment to
    revisit it — UI/Tables.md records the gap.

    IT DOES NOT TOUCH .col-name ITSELF, which four other views rely on for its left alignment.

    Scoped to the table rather than the cells so the th and the td stay in step; (0,2,1) beats both
    .col-name (0,1,0) and .data-table td (0,1,1). */
.acc-discord-table th.col-name,
.acc-discord-table td.col-name {
    text-align: center;
}

/* Icon-only badge row on a Moderate Team member card, between the realm line and the
   rank/role controls. Icons only, not .gp-badge text chips. The row collapses to nothing
   when empty, so a member with no markers costs no vertical space. */
.ccw-badges {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin-top: 0.313rem;
}
.ccw-badges:empty { display: none; }
/* 1.375rem square with the same rounding, border and inset shadow as .ccw-class-icon and
   .role-icon, so the three read as one family of card icons rather than three sizes. */
.ccw-badge-icon {
    width: 1.375rem;
    height: 1.375rem;
    border-radius: 0.188rem;
    border: 1px solid rgba(255,255,255,0.12);
    box-shadow: 0 0.063rem 0 rgba(255,255,255,0.04) inset, 0 0.125rem 0.25rem rgba(0,0,0,0.5);
    flex-shrink: 0;
    display: block;
    object-fit: contain;
}
/* "No account linked" marker. Built like .role-icon — the same 1.375rem frame with a smaller
   glyph inside — so it sits in the family rather than beside it. The glyph is a CSS MASK, not
   an <img>: broken-link.svg carries no fill, so as an image it would render black and vanish
   on a dark theme. Masking lets it take a theme colour, which is how .role-icon-svg and
   .signups-note-icon already work. */
.ccw-badge-noaccount {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.375rem;
    height: 1.375rem;
    border-radius: 0.188rem;
    background: linear-gradient(180deg, var(--bg-3) 0%, var(--bg) 100%);
    border: 1px solid rgba(255,255,255,0.12);
    box-shadow: 0 0.063rem 0 rgba(255,255,255,0.04) inset, 0 0.125rem 0.25rem rgba(0,0,0,0.5);
    flex-shrink: 0;
    cursor: default;
}
.ccw-badge-noaccount::before {
    content: '';
    display: block;
    width: 0.875rem;
    height: 0.875rem;
    background-color: var(--ink-3);
    -webkit-mask: url('/img/broken-link.svg') no-repeat center / contain;
    mask: url('/img/broken-link.svg') no-repeat center / contain;
}

/*  "Not a GoW guild member" — the character has no record in the daily GoW roster snapshot.
    Added 2026-08-24 (Session 208).

    DELIBERATELY IDENTICAL CHROME TO .ccw-badge-noaccount above, differing only in its mask. The two
    sit in the same badge row and mean different things, so they must read as two members of one
    family rather than as two unrelated marks — copying the existing badge is what makes that true
    (Directive 18). The icon takes a theme colour through the mask for the same reason that one does:
    a flat-black SVG disappears on a dark theme. */
/*  GEAR WARNINGS badge (Session 212). Same box as .ccw-badge-notguild / -noaccount beside it — one
    badge family, one size — with warning.svg and var(--warn) inside.

    var(--warn) AND NOT var(--bad), following the roster empty-roster icon's reasoning above: a
    missing enchant is a caution, not a failure, and the badges beside it are neutral --ink-3. The
    colour is what makes this one read as "look at me" among them.

    cursor: help rather than default — unlike its neighbours this badge has something to reveal. */
.ccw-badge-gearwarn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.375rem;
    height: 1.375rem;
    border-radius: 0.188rem;
    background: linear-gradient(180deg, var(--bg-3) 0%, var(--bg) 100%);
    border: 1px solid rgba(255,255,255,0.12);
    box-shadow: 0 0.063rem 0 rgba(255,255,255,0.04) inset, 0 0.125rem 0.25rem rgba(0,0,0,0.5);
    flex-shrink: 0;
    cursor: help;
}

.ccw-badge-gearwarn::before {
    content: '';
    display: block;
    width: 0.875rem;
    height: 0.875rem;
    background-color: var(--warn);
    -webkit-mask: url('/img/warning.svg') no-repeat center / contain;
    mask: url('/img/warning.svg') no-repeat center / contain;
}

/*  THE SITE'S SCRIPTED HOVER TOOLTIP. FIXED and on document.body, positioned by gp-tooltip.js —
    NOT the absolutely positioned .signups-note-tooltip treatment, because a clipping ancestor
    (.char-card-wide is `overflow: hidden`, table cells are worse) cuts an absolute bubble off at
    its edge. Standard: UI/Tooltips.md.

    RENAMED 2026-09-07 (Session 220) from .gp-warn-tip / .gp-warn-tip-* , with the script. The
    component was written for the gear-warning badge and named after it; it now carries prose for
    any caller, so "warn" described one caller rather than the thing. DECLARATIONS UNCHANGED — this
    was a rename, not a restyle.

    THE LOOK IS DELIBERATELY .signups-note-tooltip's — same surface, border, radius, shadow and type
    size — so the two read as one component with two mechanisms rather than two components. Only the
    escape from the clipping ancestor differs, and the content. */
.gp-tip {
    display: none;
    position: fixed;
    z-index: 200;
    max-width: 18rem;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 0.375rem 0.5rem;
    font-size: 0.75rem;
    color: var(--ink-2);
    box-shadow: var(--sh-pop);
    /*  Never between the cursor and the badge: moving onto the bubble would fire mouseout on the
        badge and flicker it. */
    pointer-events: none;
}

.gp-tip.is-open { display: block; }

/*  The WARNINGS form's heading — var(--warn) because it counts warnings. The prose form has no
    heading, which is why it does not arrive in amber. */
.gp-tip-head {
    color: var(--warn);
    font-weight: 600;
    margin-bottom: 0.25rem;
}

/*  The LIST form's heading (.js-gp-list, added 2026-09-29, Session 235). The warnings heading's
    weight and spacing, but NOT its amber: this one names a list rather than counting problems, and a
    heading in var(--warn) reads as one. Kept beside its siblings here rather than in global.css so the
    component is not split across two files; the whole .gp-tip block moves together when it moves. */
.gp-tip-title {
    color: var(--ink);
    font-weight: 600;
    margin-bottom: 0.25rem;
}

/*  The list form's OBJECT item (2026-09-29): text on the left, a note on the right (a date on the
    Guild Teams progress tooltip). Still .gp-tip-item, so still nowrap — each side stays on one line and
    the gap keeps them apart. */
.gp-tip-row {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
}
.gp-tip-note {
    color: var(--ink-3);
}
/*  A dimmed line, e.g. a boss not yet killed. The ink scale rather than opacity (Conventions 5.6):
    each theme defines its own direction for "dimmer". The note dims with it. */
.gp-tip-item.is-muted,
.gp-tip-item.is-muted .gp-tip-note {
    color: var(--ink-4);
}

/*  One line per warning. nowrap keeps a short phrase on one line; it is why prose needs
    .gp-tip-text below rather than this. */
.gp-tip-item {
    white-space: nowrap;
    line-height: 1.5;
}

/*  The PROSE body, for the .js-gp-tip form (added 2026-09-07, Session 220).

    IT EXISTS BECAUSE .gp-tip-item ABOVE IS `white-space: nowrap`. That keeps one gear warning on one
    line, which is right for a short phrase and wrong for a sentence: nowrap plus the panel's 18rem
    max-width gives one clipped line instead of a wrapped paragraph.

    No colour and no weight of its own — it inherits the panel's, unlike .gp-tip-head. */
/* .gp-tip-text {
    line-height: 1.5;
} */
/*  pre-line (2026-10-03): a "\n" in data-tip becomes a line break, so one tooltip can carry separate
    lines (the rotation preference's Weekly / Daily). Spaces still collapse and text still wraps. No
    data-tip before that date contained a newline, so the existing callers render as before. */
.gp-tip-text {
    line-height: 1.5;
    white-space: pre-line;
}

/*  The bold term at the start of a data-tip-terms line (2026-10-03), e.g. "Weekly:". Weight only; it
    keeps the panel's colour. */
.gp-tip-term {
    font-weight: 600;
}

/*  The prose form's optional WARNING LINE (data-tip-warning, 2026-10-03), between the heading and the
    body. Warning colour, the warning icon in front — the site's existing pair, drawn exactly as
    .ccw-badge-gearwarn::before draws it (warning.svg as a mask, filled with var(--warn), so it takes the
    theme colour). Flex with the icon not shrinking, so a wrapped line stays beside the icon. First
    caller: the rotation preference pill on My Signups. */
.gp-tip-warning {
    display: flex;
    align-items: flex-start;
    gap: 0.375rem;
    color: var(--warn);
    line-height: 1.5;
    margin-bottom: 0.25rem;
}
.gp-tip-warning::before {
    content: '';
    flex-shrink: 0;
    width: 0.875rem;
    height: 0.875rem;
    margin-top: 0.188rem;
    background-color: var(--warn);
    -webkit-mask: url('/img/warning.svg') no-repeat center / contain;
    mask: url('/img/warning.svg') no-repeat center / contain;
}

.ccw-badge-notguild {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.375rem;
    height: 1.375rem;
    border-radius: 0.188rem;
    background: linear-gradient(180deg, var(--bg-3) 0%, var(--bg) 100%);
    border: 1px solid rgba(255,255,255,0.12);
    box-shadow: 0 0.063rem 0 rgba(255,255,255,0.04) inset, 0 0.125rem 0.25rem rgba(0,0,0,0.5);
    flex-shrink: 0;
    cursor: default;
}
.ccw-badge-notguild::before {
    content: '';
    display: block;
    width: 0.875rem;
    height: 0.875rem;
    background-color: var(--ink-3);
    -webkit-mask: url('/img/member.svg') no-repeat center / contain;
    mask: url('/img/member.svg') no-repeat center / contain;
}

.ccw-more-icon {
    background: none;
    border: none;
    color: var(--ink-3);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    padding: 0.25rem 0.5rem;
    letter-spacing: 0.063rem;
    border-radius: 0.188rem;
    align-self: flex-start;
    margin-top: 0.125rem;
    transition: color 0.12s, background 0.12s;
}
.ccw-more-icon:hover { color: var(--ink); background: rgba(255,255,255,0.04); }

.ccw-meta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.625rem 1.125rem;
    padding: 0.5rem 0;
    border-top: 1px solid var(--line-soft);
    border-bottom: 1px solid var(--line-soft);
    min-height: 2.063rem;
    align-items: center;
}
.ccw-meta-row.ccw-meta-empty::before {
    content: '— No team —';
    font-size: 0.719rem;
    color: var(--ink-4);
    font-style: italic;
}
.ccw-meta-item { display: inline-flex; align-items: center; gap: 0.375rem; font-size: 0.75rem; color: var(--ink-2); }
.ccw-meta-text { letter-spacing: 0.006rem; }
/*  SUPERSEDED 2026-08-24 (Session 208) — the team logo was removed from both My Characters card
    lists, which were its ONLY two usages (grepped across Views/, wwwroot/css and wwwroot/js before
    removing). The rule is kept commented rather than deleted so the treatment is recoverable if the
    badge is ever wanted back; nothing references it now.

.ccw-team-logo {
    width: 1.125rem; height: 1.125rem;
    border-radius: 0.188rem;
    background: linear-gradient(135deg, #2b3a5a, #1a2440);
    border: 1px solid var(--line-soft);
    color: var(--ink-2);
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: 0.031rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    flex-shrink: 0;
}
*/

.ccw-controls-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: nowrap;
}
.ccw-controls-row:last-child { margin-top: auto; }

.ccw-controls-row form {
    display: inline-flex;
    align-items: center;
    margin: 0;
    padding: 0;
}

/*.ccw-controls-row .btn,
.ccw-controls-row a.btn,
.ccw-controls-row button,
.ccw-controls-row select {
    font-size: 0.688rem;
    font-family: inherit;
    padding: 0.313rem 0.563rem;
    border-radius: 0.25rem;
    height: auto;
    line-height: 1;
    flex-shrink: 0;
}

.ccw-controls-row select {
    padding-right: 1.375rem;
    background-size: 0.5rem;
    background-position: right 0.375rem center;
    flex: 1 1 auto;
    min-width: 0;
}*/
/*  SUPERSEDED 2026-08-24 (Session 208) — the selector gained the member TABLE's selects so both
    layouts size their rank and role controls identically. Same declarations, one more selector.

.ccw-controls-row select {
    font-size: 0.688rem;
    font-family: inherit;
    padding: 0.313rem 0.563rem;
    padding-right: 1.375rem;
    border-radius: 0.25rem;
    height: auto;
    line-height: 1;
    flex-shrink: 0;
    flex: 1 1 auto;
    background-size: 0.5rem;
    background-position: right 0.375rem center;
    min-width: 0;
}
*/

/*  The rank and role selects, in BOTH layouts of the member list.

    The table's copies were full-size form controls beside the card's compact ones — the same control
    at two sizes, which is the divergence Directive 18 treats as a defect rather than a matter of
    taste. They are one declaration now, not two that can drift.

    GROUPED RATHER THAN COPIED. Restating the six sizing values under a second selector is how the
    two would slowly stop matching; adding a selector to the rule that already owns them cannot.

    The three FLEX declarations are inert where they do not apply, which is why they can stay in the
    shared rule: the table's rank cell IS a flex row (.modteam-cell-rank, lock beside select) and
    they do useful work there, while the role select is a direct child of its <td> and simply ignores
    them. Nothing had to be split out. */
.ccw-controls-row select,
.modteam-member-table td select {
    font-size: 0.688rem;
    font-family: inherit;
    padding: 0.313rem 0.563rem;
    padding-right: 1.375rem;
    border-radius: 0.25rem;
    height: auto;
    line-height: 1;
    flex-shrink: 0;
    flex: 1 1 auto;
    background-size: 0.5rem;
    background-position: right 0.375rem center;
    min-width: 0;
}

.ccw-rank-static { flex: 1 1 8.75rem; min-width: 7.5rem; display: inline-flex; align-items: center; }
.ccw-rank-empty { font-size: 0.75rem; color: var(--ink-3); font-style: italic; }

.char-card {
    position: relative;
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 0.75rem;
    width: 10rem;
    cursor: default;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.char-card-level { font-size: 0.688rem; color: var(--ink-3); }
.char-card-name { font-size: 0.875rem; font-weight: 700; }
.char-card-divider { border: none; border-top: 1px solid currentColor; margin: 2px 0; opacity: 0.3; }
.char-card-realm { font-size: 0.719rem; color: var(--ink-3); }

/* Moved to pages/my-characters.css 2026-09-26 (Session 231) — only My Characters' import view renders
   it (Views/Profile/_ImportableCharacters.cshtml also names it, but no action returns that partial).
.char-card-importable { opacity: 0.55; cursor: pointer; transition: opacity 0.15s, transform 0.15s, box-shadow 0.15s; }
.char-card-importable:hover { opacity: 0.85; }
.char-card-importable.selected {
    opacity: 1;
    transform: translateY(-0.063rem);
    box-shadow:
        0 0.063rem 0 rgba(255,255,255,0.04) inset,
        0 0.25rem 1rem rgba(0,0,0,0.4),
        0 0 0 0.063rem var(--accent),
        0 0 1.125rem color-mix(in oklch, var(--accent) 30%, transparent);
}
*/

.import-action-bar {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    margin-top: 0.875rem;
    margin-bottom: 0.875rem;
}

.section-title-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.625rem;
}

.section-title-row h2 { margin-bottom: 0; }

/* .icon-btn — removed; replaced with .btn.btn-icon (P3a) */
/* .icon-btn {
    padding: 0.25rem 0.375rem;
    display: inline-flex;
    align-items: center;
    color: var(--ink-3);
    background: none;
    border: 1px solid var(--line-soft);
    border-radius: 0.25rem;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
} */

/* .icon-btn:hover { color: var(--ink-2); border-color: var(--line); } */

/* RENAMED 2026-09-06 (Session 218) to .gp-label-cell and moved to global.css. It was
   used by Guild Setup and Profile, so a profile- prefix was wrong under
   UI/ClassNaming.md's rule about a component-scoped class reaching a second page.
.profile-label {
    color: var(--ink-3);
    font-size: 0.75rem;
    width: 8.75rem;
    min-width: 20%;
    vertical-align: middle;
} */
.data-table td span + .btn {
    margin-left: 0.5rem;
}

/*  ...WHICH IS WRONG INSIDE AN .action-cell, BECAUSE THAT WRAPPER OWNS CONTROL SPACING ITSELF.

    UI/Tables.md: "Every td.col-controls wraps its controls in a single .action-cell div. That
    wrapper is the only thing that spaces controls." It is a flex row with `gap: 0.375rem`, so the
    rule above lands ON TOP of that gap — and only on a button that happens to follow a bare
    <span>. Where two <button>s sit side by side it does not fire at all, so two rows of the same
    table come out unevenly spaced with nothing in either markup to explain why. That is what the
    empty-roster and empty-article markers hit: they are <span>s standing in a control's slot.

    DELIBERATELY NARROW — IT NAMES THE TWO MARKERS RATHER THAN EVERY SPAN IN AN .action-cell.
    `.data-table td .action-cell span + .btn` would be the general fix and is arguably the correct
    one, but it also reaches Views/Teams/Index.cshtml, whose delete and detach confirm rows put a
    <span class="team-action-warning"> before their buttons inside an .action-cell. Those rows are
    working code on another page: they are double-spaced by the same accident, and tightening them
    by 0.5rem is a change nobody asked for. Raised rather than swept.

    The rule above is untouched — it predates .action-cell and still serves the label-then-button
    cells it was written for.

    Specificity (0,4,1) against its (0,2,2), so neither depends on source order. */
.data-table td .action-cell .roster-empty-icon + .btn,
.data-table td .action-cell .tactics-empty-icon + .btn {
    margin-left: 0;
}

.gp-create-panel {
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    box-shadow: var(--sh-card);
    padding: 1.125rem;
    margin-bottom: 1.125rem;
}

.gp-create-panel h2 {
    font-size: 0.813rem;
    font-weight: 600;
    color: var(--ink);
    margin-bottom: 0.875rem;
    padding-bottom: 0.625rem;
    border-bottom: 1px solid var(--line-soft);
}

.gp-create-form {
    display: flex;
    gap: 0.625rem;
    align-items: center;
    flex-wrap: wrap;
}

.roles-create-name { width: 12.5rem; }
.roles-create-description { flex: 1; min-width: 17.5rem; }

.roles-create-error {
    font-size: 0.75rem;
    color: var(--bad);
    margin-top: 0.5rem;
}

.role-permissions-detail td,
.role-ranks-detail .role-detail-cell,
.rank-roles-detail .role-detail-cell,
.rank-time-limit-detail td {
    background: var(--bg);
    padding: 1.125rem 1.25rem 1.375rem;
    box-shadow: inset 0 1px 0 rgba(220,230,255,0.08),
                inset 0 0.5rem 1rem -0.625rem rgba(0,0,0,0.5),
                inset 0 -0.5rem 1rem -0.625rem rgba(0,0,0,0.5);
}

.permissions-modules-grid { display: grid; gap: 0.75rem; }
.permissions-modules-grid-6 { grid-template-columns: repeat(6, 1fr); }
.permissions-modules-grid-5 { grid-template-columns: repeat(5, 1fr); }

.permission-module {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    min-width: 7.5rem;
}

.permission-module-name {
    font-size: 0.656rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.038rem;
    color: var(--ink-3);
    margin-bottom: 0.125rem;
}

.permission-action-label {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.781rem;
    color: var(--ink-2);
    cursor: pointer;
    user-select: none;
}

.role-cell-edit-input { width: 100%; }

.role-cell-actions { white-space: nowrap; }

.role-delete-warning {
    font-size: 0.75rem;
    color: var(--ink-3);
    margin-right: 0.5rem;
}

.permission-per-team-label {
    font-size: 0.813rem;
    font-weight: 600;
    color: var(--ink);
    margin-bottom: 0.625rem;
    margin-top: 0.25rem;
}

/* RENAMED 2026-09-06 (Session 218) to .gp-input-narrow and moved to global.css — three
   pages used it (Guild Setup, the Teams table, Profile) and only one was Profile.
.profile-name-input { width: 12rem; } */

#force-logout-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.65);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 9999;
}

#force-logout-dialog {
    background: var(--bg-3);
    border: 1px solid var(--line);
    border-radius: 0.375rem;
    padding: 2rem 2.5rem;
    max-width: 23.75rem;
    width: 100%;
    text-align: center;
}

#force-logout-dialog h3 {
    margin: 0 0 0.75rem;
    font-size: 1.1rem;
}

#force-logout-dialog p {
    color: var(--ink-3);
    margin: 0 0 0.4rem;
    font-size: 0.9rem;
}

#force-logout-dialog .btn {
    margin-top: 1.25rem;
    display: inline-block;
}

.feedback-table td { text-align: left; }
.feedback-chevron-col { width: 1.5rem; }
.feedback-chevron-cell { text-align: center; color: var(--ink-4); font-size: 0.688rem; cursor: pointer; }
.feedback-date-cell { white-space: nowrap; width: 10rem; }
.feedback-submitter-cell { white-space: nowrap; width: 12rem; }
.feedback-action-cell { width: 6rem; }
.feedback-location-label { color: var(--ink-3); font-size: 0.75rem; margin: 0 0 0.5rem; word-break: break-all; }
.feedback-preview-cell { color: var(--ink-2); }
.feedback-main-row { cursor: pointer; }
.feedback-main-row:hover td { background: var(--bg-2); }
.feedback-unread .feedback-preview-cell { font-weight: 600; color: var(--ink); }

.feedback-sub-cell {
    font-size: 0.813rem;
    line-height: 1.6;
    color: var(--ink-2);
}
.feedback-new-tag {
    display: inline-flex;
    align-items: center;
    font-size: 0.625rem;
    font-weight: 600;
    padding: 0.063rem 0.375rem;
    border-radius: 0.25rem;
    background: color-mix(in srgb, var(--ok) 20%, transparent);
    color: var(--ok);
    letter-spacing: 0.031rem;
    margin-right: 0.375rem;
    vertical-align: middle;
}
.feedback-msg-segment { margin: 0; text-align: left; }
.feedback-separator { border: none; border-top: 1px solid var(--line); margin: 0.75rem 0; }

.btn-attention {
    background: linear-gradient(180deg, #a01818 0%, #7c0e0e 100%);
    border-color: #e05050;
    color: white;
    box-shadow: 0 1px 0 rgba(255,255,255,0.45) inset, 0 4px 12px rgba(160,24,24,0.4), 0 0 0 1px rgba(200,60,60,0.4);
    position: relative;
    overflow: hidden;
    isolation: isolate;
}
.btn-attention::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(110deg, transparent 30%, #ffffff70 47%, #ffffffcc 50%, #ffffff70 53%, transparent 70%);
    transform: translateX(-130%) skewX(-18deg);
    animation: btn-attention-sweep 5s cubic-bezier(.6, 0, .2, 1) infinite;
    mix-blend-mode: screen;
    pointer-events: none;
}
.btn-attention:hover::after {
    animation-play-state: paused;
    opacity: 0;
}
@keyframes btn-attention-sweep {
    0%,  18% { transform: translateX(-130%) skewX(-18deg); }
    55%,100% { transform: translateX( 130%) skewX(-18deg); }
}
@media (prefers-reduced-motion: reduce) {
    .btn-attention::after { animation: none; }
}

.btn-attention:hover {
    background: linear-gradient(180deg,
        color-mix(in oklab, #fff 24%, transparent),
        color-mix(in oklab, #a01818 32%, transparent));
    border-color: color-mix(in oklab, #e05050 45%, transparent);
    backdrop-filter: blur(8px) saturate(1.3);
    box-shadow:
        inset 0 1px 0 #ffffff77,
        inset 0 -10px 16px -8px color-mix(in oklab, #a01818 70%, transparent),
        0 8px 26px -8px color-mix(in oklab, #a01818 85%, transparent);
    color: white;
}

.feedback-widget {
    position: fixed;
    bottom: 1.5rem;
    right: 1.5rem;
    z-index: 900;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.5rem;
}

.feedback-panel {
    width: 22rem;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    box-shadow: var(--sh-pop);
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
}

.feedback-panel-title {
    font-size: 0.813rem;
    font-weight: 600;
    color: var(--ink);
}

.feedback-textarea {
    width: 100%;
    resize: none;
    background: var(--bg-3);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    color: var(--ink);
    font-family: inherit;
    font-size: 0.813rem;
    padding: 0.438rem;
    line-height: 1.4;
}
.feedback-textarea:focus { outline: none; border-color: var(--accent); }

.feedback-panel-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.feedback-char-count {
    font-size: 0.75rem;
    color: var(--ink-3);
}
.feedback-char-count.feedback-char-warn { color: var(--warn); }
.feedback-char-count.feedback-char-low { color: var(--bad); }

.feedback-status {
    font-size: 0.75rem;
    min-height: 1rem;
}

/*  Teams page styles moved to css/pages/teams.css (incremental site.css split), 2026-08-18.

    THE MOVED RULES ARE NOT LEFT COMMENTED OUT HERE, unlike the Seasons block further down, and
    the reason is mechanical rather than a change of habit: this block carried two comments of
    its own (the 2026-08-07 superseded notes), and CSS comments DO NOT NEST — the first inner
    comment terminator would have ended the wrapper and released the rest of the block as live
    CSS. The rules are preserved verbatim in pages/teams.css, which is what a move means.

    WHAT DID NOT MOVE, and it is not an oversight: .team-ranks-group, .team-ranks-group-title,
    .ranks-empty and the .rank-* rules below belong to GuildSetup and GuildRoles, and
    .team-selection-grid (further down) is used by nine SelectTeam-style views. Every one is
    named for a team and hosted by another page.  */

.team-ranks-group {
    margin-bottom: 1.75rem;
}

.team-ranks-group-title {
    font-size: 0.813rem;
    color: var(--ink-2);
    margin-bottom: 0.5rem;
}

.ranks-empty {
    color: var(--ink-3);
    font-size: 0.813rem;
}

.rank-val.rank-val-technical,
td:nth-child(2) .rank-val {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.75rem;
    color: var(--ink-2);
}

.rank-input { width: 100%; }
.rank-input-sm { width: 5rem; }

.rank-actions { white-space: nowrap; }

.rank-create-form .rank-input { width: 11.25rem; }

/* Old single-row header (logo + team-name h1 + sync button). Replaced to follow the PageHeading
   standard: section-name h1 + team-name subtitle, with a member-count line under the whole group.
.modteam-header {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    margin-bottom: 1.125rem;
}
.modteam-title {
    margin: 0;
    flex: 1;
    font-size: 1.375rem;
    font-weight: 700;
    color: var(--ink);
}
*/
.modteam-header {
    display: flex;
    flex-direction: column;
    margin-bottom: 1.125rem;
}

.modteam-head-main {
    display: flex;
    align-items: center;
    gap: 0.875rem;
}

/*  The "All Teams" back link, on the two pages that have one (Team Members, Team Info). It sits
    above .modteam-head-main as a direct child of the flex COLUMN, where the default `stretch` would
    make it span the full header width — the text still renders at the left, so it looks correct
    while quietly swallowing clicks aimed at the empty space beside it.

    Scoped to the direct child so it cannot reach a back link anywhere else. Manage Team has none. */
.modteam-header > .approve-back-link {
    align-self: flex-start;
}

.modteam-head-text {
    flex: 1;
    min-width: 0;
}

.modteam-head-text h1 {
    margin: 0;
}

/* Zero the paragraphs' bottom margin so the text block is tight to its content — otherwise the trailing
   margin below the count line inflates the measured height and the logo appears to hang below the text. */
.modteam-head-text p {
    margin-bottom: 0;
}

/* Keep the sync button vertically centred instead of stretching to the full header height. */
.modteam-sync-form {
    align-self: center;
}

/* Header action group — Snapshot + Sync. The sync form used to be a direct flex child of
   .modteam-head-main; adding a second control beside it needed a wrapper so the two sit together
   on the right instead of competing for the same slot. .modteam-head-text keeps flex:1, so this
   stays hard right. */
.modteam-head-actions {
    display: flex;
    align-items: center;
    align-self: center;
    flex: 0 0 auto;
    gap: 0.5rem;
}

/* Snapshot control. BOTH states are rendered in Index.cshtml and these rules pick one, keyed off
   data-sync-pending on the wrapper, which moderate-team.js flips in updateSyncBtn().

   They are two different ELEMENTS rather than one element with an attribute toggled because
   UI/Buttons.md requires the native disabled attribute (.btn:disabled) and forbids a class-based
   fake, and an <a> cannot carry `disabled` — so the enabled state is an anchor, which is what gives
   target="_blank" with no JavaScript, and the blocked state is a real disabled <button>.

   Keeping both in the DOM and hiding one is what keeps that markup in exactly ONE place. The
   alternative is rebuilding the control in moderate-team.js when the sync state changes, i.e. a
   second copy of it in a second language — the defect Session 178 removed from this page. */
.modteam-snapshot-wrap {
    display: inline-flex;
    align-items: center;
}

.modteam-snapshot-wrap[data-sync-pending="false"] .modteam-snapshot-blocked {
    display: none;
}

.modteam-snapshot-wrap[data-sync-pending="true"] .modteam-snapshot-link {
    display: none;
}

/* Square logo box sized to the heading text height. CSS cannot reliably derive a square's WIDTH from
   a stretch-driven height in a flex row (the width resolves from the empty content to 0 before the
   height is known, so aspect-ratio has nothing to work from). The exact size is set in JS —
   wwwroot/js/gp-header-logo.js, a GLOBAL file since 2026-08-27; it was sizeLogo() in
   pages/moderate-team.js until Team Members and Team Info adopted this header and rendered logos
   nothing ever sized. The width/height below is a fallback so the logo still shows at a sensible
   size if JS doesn't run — but it is SMALLER than the real text block, so a page seeing this size is
   a page where the script did not reach the header.

   CONFIRMED EMPIRICALLY 2026-08-04. Two attempts, both failed exactly as this comment predicts:
     1. aspect-ratio:1 while width/height were still present -> the box squared to the FIXED size,
        smaller than the text block.
     2. aspect-ratio:1 with width and height removed AND .modteam-head-main set to
        align-items:stretch -> the box collapsed to ZERO width, leaving only its border.
   Flex resolves the main axis (width, in a row) BEFORE the cross axis is stretched, so at width
   resolution time the height is still indefinite and there is nothing for aspect-ratio to transfer
   from. flex:0 0 auto then falls back to the content size, and the content is an absolutely
   positioned <img> contributing nothing — hence zero.
   DO NOT RETRY THIS. Keep sizeLogo(). A superseded comment above this one used to describe the
   stretch + aspect-ratio approach as if it worked; it has been deleted, because it is what prompted
   the retry. */
.modteam-logo-wrap {
    position: relative;
    flex: 0 0 auto;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
    overflow: hidden;
}

/* Old fixed-size logos (2.5rem, then 3.75rem). Replaced with a wrapper-driven box (.modteam-logo-wrap)
   so the logo dynamically tracks the 3-line heading height instead of a hardcoded size.
.modteam-logo {
    width: 2.5rem;
    height: 2.5rem;
    object-fit: contain;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
}
*/
/* Absolutely positioned so the image contributes NO height — otherwise the <img>'s intrinsic size
   inflates the wrapper (and the row) instead of the wrapper tracking the text-block height. */
.modteam-logo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.modteam-toolbar {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 1.125rem;
    align-items: center;
}

/* Refresh-Characters warning: some members could not be found on Battle.net. A caution, not a
   failure — the refresh succeeded for everyone else — so it is the documented info-notice + amber
   modifier from UI/Notices.md, overriding the three colour properties only. Text colour is left as
   ink-2 per that standard. Lives here with the other .modteam-* rules rather than in a page
   stylesheet; the .modteam-* block has not been split out of site.css yet. */
.modteam-refresh-warning {
    background: color-mix(in oklch, var(--warn) 5%, transparent);
    border-color: color-mix(in oklch, var(--warn) 30%, transparent);
    border-left-color: var(--warn);
    /* Anchors the dismiss button to the top-right corner. The notice is moved out of
       #modteam-content and persists until dismissed, so it needs a way out. */
    position: relative;
}

.modteam-refresh-warning-list {
    margin: 0.375rem 0;
    padding-left: 1.25rem;
}

.modteam-notice-dismiss {
    position: absolute;
    top: 0.375rem;
    right: 0.5rem;
    background: none;
    border: 0;
    padding: 0;
    line-height: 1;
    font-size: 1rem;
    color: var(--ink-3);
    cursor: pointer;
}

.modteam-notice-dismiss:hover {
    color: var(--ink-2);
}

.modteam-sort-bar {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    margin-bottom: 0.75rem;
}
.modteam-sort-label {
    font-size: 0.688rem;
    color: var(--ink-3);
    margin-right: 0.125rem;
}
/* .modteam-sort-btn.btn-active — dead: selector targeted wrong class (js-modteam-sort-btn); .btn-active handles active state
.modteam-sort-btn.btn-active {
    background: var(--bg-3);
    border-color: var(--accent);
    color: var(--ink);
} */
/*  SUPERSEDED 2026-08-24 (Session 208) — split into a shared block and two layout blocks so the
    table's group title can drop the bottom border. See the note under the split.

.modteam-role-group-heading {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.656rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.038rem;
    color: var(--ink-3);
    padding: 0.25rem 0;
    border-bottom: 1px solid var(--line-soft);
    margin-bottom: 0.125rem;
}
*/

/*  GROUP TITLE — the shared treatment, and then one block per layout.

    THE TWO LAYOUTS MUST NOT SHARE ONE CLASS, and the border is why. In the card grid the heading
    has nothing beneath it but a gap, so it draws its own bottom border to separate itself from the
    cards that follow. In the table the very next element is a <tr>, and .data-table already gives
    every body row a border-top — so the same rule lands a second line directly under the first and
    the title reads as sitting in a box.

    Everything that is genuinely common stays declared ONCE, in the grouped selector below. Only the
    two properties that differ get their own block, so this is a split rather than a copy. */
.modteam-role-group-heading,
.modteam-table-group-heading {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.656rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.038rem;
    color: var(--ink-3);
    padding: 0.25rem 0;
}

/*  The card grid's heading. grid-column spans the whole row of the cards grid; the border and the
    margin separate it from the cards beneath. */
.modteam-role-group-heading {
    grid-column: 1 / -1;
    border-bottom: 1px solid var(--line-soft);
    margin-bottom: 0.125rem;
}

/*  The table's heading. NO border-bottom — the row below brings its own border-top — and no
    grid-column, which is meaningless inside a table cell. */
.modteam-table-group-heading {
    border-bottom: 0;
    margin-bottom: 0;
}

/* SUPERSEDED 2026-08-06 — .gp-badge now sets text-transform, letter-spacing and font-weight on
   ITSELF, so there is nothing left for this container reset to fix. Deleting the copy rather than
   keeping the two in step: the badge is the thing that has to survive being placed in a styled
   heading, so the fix belongs on the badge, not on every host that might contain one.
   The heading is already a flex row with a gap, so no margin is needed to separate the badges.

   Original reason, kept because it is why the badge sets those three properties at all: the heading
   is uppercase, letter-spaced and 600 weight; the old .role-rank-badge set none of those, so without
   a reset the badges inherited all three and looked nothing like the same badge on GuildSetup and
   GuildRoles. Inherited uppercase would also have dragged them under the Badges.md rule that an
   uppercase badge needs line-height: 1.
.modteam-role-group-heading .role-linked-ranks {
    text-transform: none;
    letter-spacing: normal;
    font-weight: 400;
}
*/

/* Per-group member count shown next to a sort group heading, e.g. "Tank (3)". Lighter than the
   heading label so it reads as a secondary value. */
.modteam-group-count {
    font-weight: 400;
    opacity: 0.75;
}

/* ---- Member list: the two layouts (Session 208) ------------------------------------------------
   The Manage Team and Team Members pages render every member TWICE — as a card and as a table row
   — and one layout is shown. Which one is a per-viewer choice in localStorage, so only JavaScript
   can know it.

   THE SWITCH IS AN ATTRIBUTE ON <html>, NOT A CLASS ON A CONTAINER, and that is the whole
   anti-flash mechanism. member-layout-boot.js sets it from the <head>, before any page markup is
   parsed, so the correct layout is hidden from the very first paint. A class on a container could
   only be applied once that container exists, which is exactly too late.

   Cards are the default and the unqualified state — the absence of the attribute is a complete
   answer, so there is no third state to reason about. */
.modteam-layout-table {
    display: none;
}

html[data-member-layout="table"] .modteam-layout-cards {
    display: none;
}

html[data-member-layout="table"] .modteam-layout-table {
    display: block;
}

/* The layout switch sits hard right in the grouping bar. The MARGIN IS ON THE WRAPPER, never on the
   pill, so the pill keeps exactly the appearance it has everywhere else on the site.

   The wrapper is also why UI/TogglePill.md's flex-parent caveat does not bite here: .modteam-sort-bar
   is display:flex, and a .toggle-pill placed directly in it would blockify and span the bar. Inside
   this span the pill is in ordinary block flow and its inline-flex shrink-wraps as designed. */
.modteam-layout-switch {
    margin-left: auto;
    display: inline-block;
}

/* ---- Member table: column toggles -------------------------------------------------------------
   The checkbox-backed .btn form from UI/Buttons.md — the label carries .btn and the real checkbox
   stays the state. Only the LAYOUT is declared here; nothing restates what .btn-active looks like. */
.modteam-col-toggles {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
}

.modteam-col-toggle input[type="checkbox"] {
    display: none;
}

/* .role-detail-label is a block with a top margin, which is right in a subrow card and wrong in a
   flex row. Layout only — the type treatment is the shared class's and is not restated. */
.modteam-col-toggle-label {
    margin-top: 0;
    margin-right: 0.25rem;
}

/* ---- Member table: the group heading row ------------------------------------------------------
   THE HEADING CLASS IS ON A DIV INSIDE THE CELL, NEVER ON THE <td>. It carries display:flex, and a
   flex td stops being a table-cell and collapses its own colspan — the same trap UI/Tables.md
   records for .detail-panel.

   That div is .modteam-table-group-heading, NOT the card grid's .modteam-role-group-heading. The two
   share their type treatment through a grouped selector further up and differ in exactly one thing
   that matters: the card's heading draws a bottom border to separate itself from the cards below,
   and in a table the next element is a <tr> that already brings its own border-top — so the shared
   rule would put two lines under every group title. */
/*  SUPERSEDED 2026-08-24 (Session 208), same day. `transparent` was the wrong tool for both jobs and
    did neither — see the rule below.

.data-table tbody tr.modteam-group-row td {
    padding: 0.625rem 1rem 0.25rem;
    background: transparent;
}

.data-table tbody tr.modteam-group-row:hover td {
    background: transparent;
}
*/

/*  A GROUP HEADING IS NOT A MEMBER, so it is tinted one step DARKER than the rows it introduces and
    takes no hover at all.

    var(--bg) is that step: rows are var(--bg-2), and var(--bg) is the darker neighbour this document
    already pairs them with — it is what .detail-panel uses to sit behind a row for the same reason.

    !! THE OPAQUE BACKGROUND IS ALSO WHAT KILLS THE HOVER, and `transparent` could never have done
    it. .data-table tbody tr:hover applies a background-IMAGE gradient to the <tr>, and a transparent
    <td> lets it show straight through — the heading row highlighted exactly like a member row. A
    <td> background paints ABOVE its <tr>'s, whatever the specificity (this file's Row Attention
    Highlight note is the same fact from the other direction), so one opaque cell answers both the
    tint and the hover and no :hover rule is needed at all.

    Setting it on the <tr> instead would lose to nothing and fix nothing: the hover gradient is on
    that same element and would simply layer over it. */
.data-table tbody tr.modteam-group-row td {
    padding: 0.625rem 1rem 0.25rem;
    background: var(--bg);
}

/*  SUPERSEDED 2026-08-24 (Session 208) — the table's heading is .modteam-table-group-heading now
    and zeroes its own margin, so there is nothing left for a context override to fix.

.modteam-group-row .modteam-role-group-heading {
    margin-bottom: 0;
}
*/

/* The class group heading's icon, in both layouts. The role heading's icon is a masked div sized by
   .role-icon; a class icon is a plain <img>, so it needs its own box here.

   UNREACHABLE SINCE 2026-08-27 (Session 212): the class group heading no longer renders an icon, so
   no .ccw-class-icon exists inside either heading. Commented rather than deleted because it is the
   other half of a one-line restore — gp-char-sort.js's class spec has `imgOf` commented out on the
   same date, and uncommenting that alone would bring the icon back UNSIZED at its natural
   resolution. Restore both or neither.

   .ccw-class-icon ITSELF IS STILL LIVE and must not be touched: it is the class icon on the member
   card and the member table row, which this change did not affect.
.modteam-role-group-heading .ccw-class-icon,
.modteam-table-group-heading .ccw-class-icon {
    width: 1rem;
    height: 1rem;
}
*/

/* ---- Member table: the name cell --------------------------------------------------------------
   Level and realm sit under the name, which is the one thing this cell does that no other name cell
   on the site does.

   The anchor carries NO shared component class and none should be invented — a bare <a> already has
   the portal's link colour and hover (UI/Tables.md). These rules are LAYOUT ONLY: the colour is set
   per row from the server-resolved class colour, and nothing here restates weight or hover. */
/*  SUPERSEDED 2026-08-24 — the name shares a flex line with the role icon now, so the anchor is a
    flex item rather than a block, and it has to carry its own truncation. See below.

.modteam-cell-name {
    display: block;
}
*/

/*  The role icon and the name on one line, as they are on the card. The icon moved here from a
    column of its own: it identifies who the row is about rather than being a field in its own
    right. */
.modteam-cell-name-line {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    min-width: 0;
}

/*  THE TRUNCATION HAD TO MOVE ONTO THE NAME ITSELF. .col-name sets overflow, text-overflow and
    white-space on the CELL, which truncates text in the cell's own flow — it does not reach text
    inside a nested flex item, so the name would have overflowed the 30ch cap instead of ellipsing.
    min-width: 0 is what allows a flex item to shrink below its content width at all; without it the
    item refuses to shrink and there is nothing to ellipse. */
.modteam-cell-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.modteam-cell-sub {
    display: block;
    font-size: 0.688rem;
    color: var(--ink-3);
}

/* The rank cell holds a select and a lock button side by side on an own-character row. */
.modteam-cell-rank {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

/*  The controls sit in the vertical middle of their cell.

    .data-table td.col-controls sets vertical-align: TOP globally (site.css ~513), which is right for
    a table whose rows are one line high — the buttons then line up with the text. This table's rows
    are TWO lines, because the name cell carries level and realm beneath the name, so top-aligned
    controls hang off the first line and read as belonging to it.

    !! SCOPED TO THIS TABLE ON PURPOSE. Changing the global rule would move the controls in every
    table in the project, which is a migration and not a fix — and the top alignment is correct for
    all of them. .action-cell's own align-items: center only centres the buttons WITHIN the wrapper;
    it cannot move the wrapper inside the cell.

    Three class selectors beat the two-class global rule outright rather than winning on source
    order, which a tie would leave to whichever rule happens to sit later in the file. */
.data-table.modteam-member-table td.col-controls {
    vertical-align: middle;
}

/*  TEAM MEMBERS ONLY — the Rank cell is centred.

    .data-table thead th is already text-align: center globally, so this makes the column agree with
    its own header rather than introducing a new alignment: the heading sat centred over a
    left-aligned value.

    WHY IT IS NOT ON .col-status. That class is the column TYPE and is shared by every status column
    in the project; alignment here is a local presentation choice for one table, not a change to what
    a status column is. UI/Tables.md's own gp-kv-table section establishes this shape — context
    overrides keyed off a class, never a redefinition of the shared rule.

    WHY THE PAGE MODIFIER EXISTS AT ALL. .modteam-member-table is shared with the Manage Team table,
    whose Rank column sits between other left-aligned columns and stays as it is. There was no
    selector that could reach one table and not the other, so the Team Members table carries a second
    class.

    Keyed on data-col rather than on .col-status alone, so a status column added to this table later
    is not silently centred by a rule that was written for Rank. */
.data-table.teamcomp-member-table td.col-status[data-col="rank"] {
    text-align: center;
}

/*  A TIGHTER HEADER, because this table's is TWO ROWS.

    .data-table thead th is padding: 0.75rem 1rem, which is right for a single header row. Stacked
    twice it is 3rem of vertical padding above the first member, and the group label and the column
    labels under it read as two separate bands rather than one heading.

    Only the VERTICAL padding is reduced; the horizontal 1rem is left alone, since that is what keeps
    a header aligned with the cell beneath it.

    !! SCOPED TO THIS TABLE ON PURPOSE. .data-table thead th is the header of every table in the
    project and all the others have ONE row, where the current padding is correct — changing it
    globally would restyle dozens of surfaces to fix a problem only this table has. That is a
    migration, not a fix, and it is the same call made for the controls column's vertical-align
    above. If a compact header is ever wanted site-wide it should be a documented modifier rather
    than a redefinition of the base rule. */
.data-table.modteam-member-table thead th {
    padding-top: 0.375rem;
    padding-bottom: 0.375rem;
}

/*  The group label row is tighter still. It labels the row beneath it rather than a column, so the
    two want to read as one block — the space belongs BELOW the pair, not between them. */
.data-table.modteam-member-table thead th.th-group {
    padding-top: 0.25rem;
    padding-bottom: 0.125rem;
}

/*  The raid kill counts are centred under their group heading.

    .col-num right-aligns, which is right for a column of figures read against each other down the
    page. These three are read ACROSS the row instead — LFR, Normal, Heroic for one player — and sit
    under a centred .th-group label, so centring is what lines each figure up with its own header.

    SCOPED TO THIS TABLE, and keyed on data-col rather than on .col-num: the alignment belongs to
    these three columns, not to every numeric column in the project. Same shape as the Team Members
    rank rule above and as UI/Tables.md's gp-kv-table context overrides. */
/*  Superseded 2026-08-26 — mpluskeys joined the list. The M+ count is a single figure per row
    like Tier, and is centred for the same reason.
.data-table.modteam-member-table td[data-col="raidkills"],
.data-table.modteam-member-table td[data-col="tier"] {
    text-align: center;
}
*/
/*  Superseded 2026-08-27 — ilvl and ilvle joined the list, which makes the alignment uniform across
    every GoW-sourced column: iLvl, Equip, Tier, Raid kills, M+ and the vault grid.

    NOTE THIS EXTENDS THE RULE PAST THE RATIONALE WRITTEN ABOVE. Item level IS a column of figures
    read against each other down the page, which is the case that comment gives for right-aligning —
    it is the one column here somebody sorts to compare members. Centred by instruction, and the
    uniformity of the GoW block is what the change buys.
.data-table.modteam-member-table td[data-col="raidkills"],
.data-table.modteam-member-table td[data-col="tier"],
.data-table.modteam-member-table td[data-col="mpluskeys"] {
    text-align: center;
}
*/
.data-table.modteam-member-table td[data-col="raidkills"],
.data-table.modteam-member-table td[data-col="tier"],
.data-table.modteam-member-table td[data-col="mpluskeys"],
.data-table.modteam-member-table td[data-col="ilvl"],
.data-table.modteam-member-table td[data-col="ilvle"] {
    text-align: center;
}

/* ---- The character external-links menu (Session 212) -------------------------------------------

   RENAMED FROM .modteam-links-* ON 2026-08-27, the same day it was written, when the My Characters
   page took the same menu and the script moved to the global gp-links-menu.js. A gp- prefix is this
   project's mark for a global, page-independent component (UI/ClassNaming.md), and a menu on three
   pages named after one of them is the fault that rename exists to prevent.

.modteam-links-menu { … }  .modteam-links-item { … }  .modteam-links-icon { … }
   The bodies are unchanged — only the three selectors moved. The full previous block is the one
   directly below, kept per the editing rule.
*/

/*  SUPERSEDED 2026-08-27 — renamed .modteam-links-* to .gp-links-*, bodies unchanged.
(* ---- Member card: the external-links menu (Session 212) ----------------------------------------

   The card's "…" button opens this. It is the SAME MECHANISM as the roster status picker
   (.roster-status-dropdown, further down this file): one panel on document.body, position: fixed,
   placed from the trigger's rect, shown by .is-open. The panel geometry below is copied from it
   rather than re-invented — Directive 18, since there is no UI doc for menus and that is the live
   form this project uses for a per-row click-open menu.

   WHAT DIFFERS IS ONLY THE ITEM, and only because the content differs: a status option is a
   <button> holding a word, a link row is an <a> holding a logo and a label, so it needs the flex
   row and the icon rule below. The panel itself is unchanged.

   POSITION AND Z-INDEX ARE NOT NEGOTIABLE HERE. `fixed` is what lets the panel escape the card's
   overflow and stacking context — a menu absolutely positioned inside .ccw would be clipped by the
   grid. The z-index matches the status picker's 201 so the two behave alike against the sticky
   page header (z-index 100). *)
.modteam-links-menu {
    position: fixed;
    z-index: 201;
    display: none;
    flex-direction: column;
    overflow: hidden;
    min-width: 9.5rem;
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    (*  --r-sm (0.375rem), NOT --r-md. The panel geometry was copied from .roster-status-dropdown,
        which uses --r-md — the CARD radius (0.625rem, what .gp-card carries). A menu reads as a
        control rather than as a surface, so it sits nearer .btn's 0.25rem. --r-sm is the token
        between the two and is preferred to a bare 0.25rem so the value stays on the scale.
        This is a DELIBERATE divergence from the copied picker, not drift. *)
    border-radius: var(--r-sm);
    box-shadow: var(--sh-card);
}

.modteam-links-menu.is-open { display: flex; }

.modteam-links-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.313rem 0.75rem;
    font-size: 0.813rem;
    color: var(--ink-2);
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.1s;
}

.modteam-links-item:hover {
    background: var(--bg-3);
    color: var(--ink);
    text-decoration: none;
}

(*  The imported logos range from 64px to 460px square and are not resized on disk, so the box is
    fixed here and object-fit keeps a non-square source from stretching. *)
.modteam-links-icon {
    width: 1rem;
    height: 1rem;
    object-fit: contain;
    flex: 0 0 auto;
}

*/

/* ---- The character external-links menu, live version (Session 212) ----------------------------------------

   The card's "…" button opens this. It is the SAME MECHANISM as the roster status picker
   (.roster-status-dropdown, further down this file): one panel on document.body, position: fixed,
   placed from the trigger's rect, shown by .is-open. The panel geometry below is copied from it
   rather than re-invented — Directive 18, since there is no UI doc for menus and that is the live
   form this project uses for a per-row click-open menu.

   WHAT DIFFERS IS ONLY THE ITEM, and only because the content differs: a status option is a
   <button> holding a word, a link row is an <a> holding a logo and a label, so it needs the flex
   row and the icon rule below. The panel itself is unchanged.

   POSITION AND Z-INDEX ARE NOT NEGOTIABLE HERE. `fixed` is what lets the panel escape the card's
   overflow and stacking context — a menu absolutely positioned inside .ccw would be clipped by the
   grid. The z-index matches the status picker's 201 so the two behave alike against the sticky
   page header (z-index 100). */
.gp-links-menu {
    position: fixed;
    z-index: 201;
    display: none;
    flex-direction: column;
    overflow: hidden;
    min-width: 9.5rem;
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    /*  --r-sm (0.375rem), NOT --r-md. The panel geometry was copied from .roster-status-dropdown,
        which uses --r-md — the CARD radius (0.625rem, what .gp-card carries). A menu reads as a
        control rather than as a surface, so it sits nearer .btn's 0.25rem. --r-sm is the token
        between the two and is preferred to a bare 0.25rem so the value stays on the scale.
        This is a DELIBERATE divergence from the copied picker, not drift. */
    border-radius: var(--r-sm);
    box-shadow: var(--sh-card);
}

.gp-links-menu.is-open { display: flex; }

.gp-links-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.313rem 0.75rem;
    font-size: 0.813rem;
    color: var(--ink-2);
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.1s;
}

.gp-links-item:hover {
    background: var(--bg-3);
    color: var(--ink);
    text-decoration: none;
}

/*  The imported logos range from 64px to 460px square and are not resized on disk, so the box is
    fixed here and object-fit keeps a non-square source from stretching. */
.gp-links-icon {
    width: 1rem;
    height: 1rem;
    object-fit: contain;
    flex: 0 0 auto;
}

/* ---- Member table: the great vault cell (Session 208) ------------------------------------------
   Three raid boxes over three dungeon boxes, matching GoW's own panel. Raids on top by instruction.

   The grid is fixed at three columns rather than auto-flowing, so the two rows always align even
   when a box is empty — an auto grid would reflow the dungeon row under a short raid row and the
   pairing would stop reading as slots. */
.modteam-vault-grid {
    display: grid;
    grid-template-columns: repeat(3, auto);
    gap: 0.125rem;
    justify-content: center;
}

/*  ONE BOX. The colour arrives as --vault-col, resolved SERVER-SIDE from Rarity and written by the
    view as an inline custom property — the class never names a colour, and a view never writes a
    literal.

    THE FALLBACK IN var() IS THE UNRESOLVED-TRACK STATE, not a default nobody meant. When no raid
    slot in the guild anchored that track this week the view emits no --vault-col at all, and the box
    renders in muted ink with its numbers still shown. A wrong colour would be worse than none. */
.modteam-vault-box {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.75rem;
    padding: 0.063rem 0.188rem;
    border-radius: 0.188rem;
    font-size: 0.625rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--vault-col, var(--ink-3));
    border: 1px solid color-mix(in oklab, var(--vault-col, var(--ink-3)) 55%, transparent);
    background: color-mix(in oklab, var(--vault-col, var(--ink-3)) 12%, transparent);
}

/* An unearned slot. Muted throughout and carrying the cross, never a colour — it earned nothing, so
   there is no track to show. */
.modteam-vault-box-empty {
    color: var(--ink-3);
    border-color: var(--line-soft);
    background: transparent;
    opacity: 0.55;
}

/* The cell shrink-wraps around the grid rather than stretching it. */
.modteam-vault-cell {
    padding-left: 0.375rem;
    padding-right: 0.375rem;
}

/* Rank lock toggle icon (own-character cards). Colour comes from .btn-icon-bad
   (locked, red) / .btn-icon-ok (unlocked, green) via currentColor. Default glyph
   is the closed lock (locked); the unlocked state swaps to the open-lock glyph. */
.modteam-lock-icon {
    display: inline-block;
    width: 0.75rem;
    height: 0.75rem;
    background-color: currentColor;
    mask: url('/img/lock.svg') no-repeat center / contain;
    -webkit-mask: url('/img/lock.svg') no-repeat center / contain;
}

/* Unlocked (green) state swaps the closed lock for the open-lock glyph. */
.js-modteam-rank-lock.btn-icon-ok .modteam-lock-icon {
    mask-image: url('/img/lock-open.svg');
    -webkit-mask-image: url('/img/lock-open.svg');
}

.modteam-char-cards {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 0.75rem;
}

.modteam-card {
    position: relative;
    overflow: hidden;
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 0.875rem 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    box-shadow: var(--sh-card);
    transition: transform 0.15s, box-shadow 0.15s;
}
.modteam-card:hover {
    transform: translateY(-0.063rem);
    box-shadow:
        0 0.063rem 0 rgba(255,255,255,0.04) inset,
        0 0.25rem 1rem rgba(0,0,0,0.4),
        0 1rem 2.5rem rgba(0,0,0,0.5),
        0 0 0 0.063rem var(--accent),
        0 0 1.5rem color-mix(in oklch, var(--accent) 35%, transparent);
}

.modteam-card-level {
    font-size: 0.75rem;
    color: var(--ink-3);
}

.modteam-card-name {
    font-weight: 700;
    font-size: 1.063rem;
    letter-spacing: 0.006rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

.modteam-card-realm {
    font-size: 0.8rem;
    color: var(--ink-3);
}

.modteam-card-rank-badge {
    font-size: 0.75rem;
    background-color: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: 0.188rem;
    padding: 0.1rem 0.35rem;
    display: inline-block;
    width: fit-content;
}

.modteam-team-badge {
    font-size: 0.7rem;
    background-color: rgba(255,255,255,0.08);
    border: 1px solid var(--line);
    border-radius: 0.188rem;
    padding: 0.1rem 0.3rem;
    display: inline-block;
}

.sync-other-teams {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem;
}

.sync-other-teams-label {
    font-size: 0.656rem;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.038rem;
    font-weight: 600;
    flex-shrink: 0;
}

.gp-char-cards-6 {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 0.75rem;
}

.gp-char-card-compact {
    position: relative;
    overflow: hidden;
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 0.875rem 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    box-shadow: var(--sh-card);
    transition: transform 0.15s, box-shadow 0.15s;
}
.gp-char-card-compact:hover {
    transform: translateY(-0.063rem);
    box-shadow:
        0 0.063rem 0 rgba(255,255,255,0.04) inset,
        0 0.25rem 1rem rgba(0,0,0,0.4),
        0 1rem 2.5rem rgba(0,0,0,0.5),
        0 0 0 0.063rem var(--accent),
        0 0 1.5rem color-mix(in oklch, var(--accent) 35%, transparent);
}
.gp-char-card-compact .ccw-name-line {
    justify-content: space-between;
}
.gp-char-card-compact .ccw-name {
    font-size: 0.8rem;
}
.roster-group-label {
    font-size: 0.75rem;
    color: var(--ink-3);
    margin: 0.75rem 0 0.375rem;
}

/* .modteam-remove-btn — dead: class not assigned in HTML; Remove button uses btn btn-xs btn-danger directly
.modteam-remove-btn {
    margin-top: 0.25rem;
    width: 100%;
} */

.modteam-empty {
    color: var(--ink-3);
    font-size: 0.875rem;
    margin-top: 0.5rem;
}

.sync-conflict-view {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.sync-section {
    border: 1px solid var(--line);
    border-radius: 0.375rem;
    padding: 1rem;
}

.sync-section-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

.sync-section-title {
    font-weight: 600;
    font-size: 0.9rem;
    flex: 1;
}

.sync-bulk-actions {
    display: flex;
    gap: 0.4rem;
}

.sync-global-actions {
    display: flex;
    gap: 0.5rem;
    justify-content: flex-end;
}

.sync-card-actions {
    display: flex;
    gap: 0.3rem;
    margin-top: 0.35rem;
}

.sync-card-removed {
    opacity: 0.7;
}

.sync-card-new {
    border-color: var(--accent);
}

.modteam-guild-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: flex-end;
    margin-bottom: 1rem;
}

.guild-search-clear {
    background: none;
    border: none;
    color: var(--ink-3);
    cursor: pointer;
    font-size: 1.1rem;
    padding: 0 0.2rem;
    line-height: 1;
}

.guild-search-clear:hover {
    color: var(--ink);
}

.modteam-filter-group {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.modteam-filter-label {
    font-size: 0.75rem;
    color: var(--ink-3);
    white-space: nowrap;
}

.modteam-input {
    padding: 0.3rem 0.5rem;
    font-size: 0.875rem;
    font-family: inherit;
    color: var(--ink);
    background-color: var(--bg);
    border: 1px solid var(--line);
    border-radius: 0.25rem;
}

select.modteam-input { padding-right: 1.75rem; }

.modteam-input-sm {
    width: 5rem;
}

.modteam-input:focus {
    outline: none;
    border-color: var(--accent);
}

.modteam-guild-table td {
    font-size: 0.875rem;
}

.sync-no-conflicts-notice {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: var(--bg-2);
    border-left: 0.188rem solid var(--ok);
    padding: 0.6rem 1rem;
    border-radius: 0.25rem;
    margin-bottom: 1rem;
    font-size: 0.875rem;
}

.sync-no-conflicts-dismiss {
    background: none;
    border: none;
    color: var(--ink-3);
    cursor: pointer;
    font-size: 1.1rem;
    padding: 0 0.2rem;
    line-height: 1;
}

.sync-no-conflicts-dismiss:hover {
    color: var(--ink);
}

.modteam-bnet-panel {
    max-width: 31.25rem;
}

.modteam-bnet-header {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1rem;
    font-weight: 600;
}

.modteam-bnet-row {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    flex-wrap: wrap;
}

.modteam-bnet-error {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--bad);
    font-size: 0.875rem;
    margin-bottom: 0.75rem;
}

.char-card-teams {
    display: flex;
    flex-wrap: wrap;
    gap: 0.2rem;
    margin-top: 0.25rem;
}

.char-team-badge {
    font-size: 0.7rem;
    background-color: rgba(255,255,255,0.08);
    border: 1px solid var(--line);
    border-radius: 0.188rem;
    padding: 0.1rem 0.3rem;
}

.role-detail-cell { padding: 1.125rem 1.25rem 1.375rem; }

.role-detail-label {
    font-size: 0.688rem;
    font-weight: 600;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.031rem;
    display: block;
    margin-top: 0.625rem;
    margin-bottom: 0;
    text-align: left;
}

.role-ranks-section {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* SUPERSEDED 2026-08-06 — renamed and consolidated into .gp-badge / .gp-badge-row /
   .gp-badge-close (search "BADGE — the portal's one small bordered chip" in this file).
   These were component-scoped names for something reused on three unrelated pages, which
   UI/ClassNaming.md says should carry the gp- prefix. Values are unchanged except that the badge
   now sets its own font-weight, text-transform and letter-spacing.
.role-linked-ranks {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.role-rank-badge {
    font-size: 0.688rem;
    background: var(--bg-3);
    border: 1px solid var(--line);
    border-radius: 0.188rem;
    padding: 0.188rem 0.563rem;
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    color: var(--ink-2);
}

.role-rank-unlink-btn {
    background: none;
    border: none;
    color: var(--ink-3);
    cursor: pointer;
    font-size: 0.85rem;
    padding: 0;
    line-height: 1;
}

.role-rank-unlink-btn:hover {
    color: var(--ink);
}
*/

.role-link-rank-form {
    display: flex;
    gap: 0.4rem;
    align-items: center;
}

.rank-link-role-form {
    display: flex;
    gap: 0.4rem;
    align-items: center;
}

.role-rank-select {
    min-width: 12.5rem;
    max-width: 20rem;
}

.team-selection-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 1.125rem;
    margin-top: 1.5rem;
}

.team-selection-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.625rem;
    padding: 1.5rem 1.75rem;
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    box-shadow: var(--sh-card);
    text-decoration: none;
    color: var(--ink);
    min-width: 11.25rem;
    transition: transform 0.15s, box-shadow 0.15s;
}

.team-selection-card:hover {
    transform: translateY(-0.125rem);
    box-shadow:
        0 0.063rem 0 rgba(255,255,255,0.04) inset,
        0 0.25rem 1rem rgba(0,0,0,0.4),
        0 1rem 2.5rem rgba(0,0,0,0.5),
        0 0 0 0.063rem var(--accent),
        0 0 1.5rem color-mix(in oklch, var(--accent) 35%, transparent);
}

.team-selection-logo {
    width: 4.5rem;
    height: 4.5rem;
    object-fit: contain;
    border-radius: var(--r-sm);
    border: 1px solid var(--line-soft);
}

.team-selection-logo-placeholder {
    width: 4.5rem;
    height: 4.5rem;
    background: var(--bg-3);
    border: 1px solid var(--line-soft);
    border-radius: var(--r-sm);
}

.team-selection-name {
    font-weight: 600;
    font-size: 1rem;
    color: var(--ink);
}

.team-selection-count {
    font-size: 0.75rem;
    color: var(--ink-3);
}

/* ---- Picker card extras (Session 208) ----------------------------------------------------------
   Two pages now put a per-team FACT on their picker card. Both live inside .team-selection-card,
   which is a centred column, so both align to it rather than introducing a second axis.

   THESE ARE PAGE-SPECIFIC AND DELIBERATELY NOT ADDED TO .team-selection-card ITSELF, which is shared
   by ten views. The card stays what it is; a page's own fact is styled by that page's class, the
   same split the view models make. */

/*  Approve BiSlist — how many bislists are waiting.
    Zero is RENDERED rather than hidden, so the muted state is the common one and the highlighted
    one is the exception. The colour is the only thing that changes; the line is always there. */
.approve-picker-pending {
    font-size: 0.75rem;
    color: var(--ink-3);
}

.approve-picker-pending-waiting {
    color: var(--accent-glow);
    font-weight: 600;
}

/*  Recruitment — the team's full summary, every class and every open spec.
    IT IS THE CONTENT OF THIS PAGE, not a footnote: the picker is read as an overview of what the
    whole guild needs. So the list is left-aligned and allowed its full height rather than being
    clamped — a truncated summary would defeat the reason it is on the picker at all. */
.recruit-picker-summary {
    width: 100%;
    margin-top: 0.25rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--line-soft);
    font-size: 0.75rem;
    text-align: left;
}

.recruit-picker-summary-empty {
    color: var(--ink-3);
    font-style: italic;
}

/*  Never a <ul>/<li> with the global list margins — the picker card is a flex column and a
    default list margin gaps the rows apart, the same trap UI/Layout.md records for split-panel
    rows. */
.recruit-picker-summary-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.recruit-picker-summary-group {
    margin: 0 0 0.188rem 0;
    line-height: 1.35;
}

.recruit-picker-summary-class {
    font-weight: 600;
}

.recruit-picker-summary-specs {
    color: var(--ink-2);
    margin-left: 0.313rem;
}

.bnet-result-card {
    margin-top: 1rem;
    padding: 0.75rem 1rem;
    background-color: var(--bg-2);
    border-radius: 0.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.bnet-result-name {
    font-weight: 600;
    font-size: 1rem;
}

.bnet-result-fields {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.875rem;
}

.bnet-result-sep {
    color: var(--ink-3);
}

.bnet-result-avg {
    color: var(--ink-3);
}

.bnet-already-on-team {
    font-size: 0.8rem;
    color: var(--ink-3);
    border: 1px solid var(--line);
    border-radius: 0.25rem;
    padding: 0.2rem 0.5rem;
}

/* Superseded 2026-08-07 — promoted to global.css as .gp-notice-dismissible /
   .gp-notice-dismiss. The component was never ranks-specific and had three unrelated consumers
   (Team Ranks, Team Documents, the blog post editor), so the name had stopped being true — the
   same reason .role-rank-badge became .gp-badge. The global version also adds a
   [hidden] { display: none } rule these lacked. All call sites updated in the same pass.

.ranks-error-notice {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: rgba(255,107,107,0.05);
    border: 1px solid rgba(255,107,107,0.25);
    border-left: 0.188rem solid var(--bad);
    border-radius: var(--r-sm);
    padding: 0.625rem 0.875rem;
    margin-bottom: 0.875rem;
    font-size: 0.813rem;
    color: var(--bad);
    box-shadow: inset 3px 0 8px rgba(255,107,107,0.08);
}

.ranks-error-dismiss {
    background: none;
    border: none;
    color: var(--ink-3);
    cursor: pointer;
    font-size: 1.1rem;
    padding: 0 0.2rem;
    line-height: 1;
}

.ranks-error-dismiss:hover {
    color: var(--ink);
}
*/

.rank-roles-panel-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.5rem;
}

.rank-roles-panel-header .role-detail-label {
    margin-top: 0;
}

.error-page {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 4rem 2rem;
    text-align: center;
}

.error-page-code {
    font-size: 6rem;
    font-weight: 700;
    line-height: 1;
    color: var(--accent);
    opacity: 0.6;
    margin-bottom: 1rem;
}

.error-page-title {
    font-size: 1.8rem;
    margin-bottom: 0.75rem;
}

.error-page-message {
    color: var(--ink-3);
    margin-bottom: 2rem;
}

.raids-toolbar {
    margin-bottom: 1.125rem;
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

.raid-import-btn.import-locked {
    opacity: 0.35;
    cursor: not-allowed;
    border-style: dashed;
}

.import-inline-progress {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
    color: var(--ink-3);
}

.import-progress-spinner {
    width: 0.875rem;
    height: 0.875rem;
    border: 2px solid var(--line);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    flex-shrink: 0;
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

.browse-raids-panel {
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    box-shadow: var(--sh-card);
    padding: 1.125rem 1.25rem;
    margin-bottom: 1.125rem;
}

.browse-raids-heading {
    font-size: 0.781rem;
    color: var(--ink-3);
    margin-bottom: 0.875rem;
}

.browse-expansion {
    margin-bottom: 1.25rem;
}

.browse-expansion-name {
    font-size: 0.844rem;
    font-weight: 600;
    color: var(--ink);
    margin-bottom: 0.375rem;
    display: flex;
    align-items: center;
    gap: 0.625rem;
}

.browse-raids-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.browse-raid-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.625rem 0.25rem;
    border-top: 1px solid var(--line);
}

.browse-raid-name {
    flex: 1;
    font-size: 0.813rem;
    color: var(--ink-2);
}

.browse-imported-badge {
    font-size: 0.75rem;
    color: var(--ink-3);
    font-style: italic;
}

.browse-no-raids {
    font-size: 0.85rem;
    padding: 0.25rem 0;
}

.raid-action-warning {
    color: var(--warn);
    font-size: 0.75rem;
    margin-right: 0.5rem;
}

.edit-raid-header {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.edit-raid-title {
    flex: 1;
}

.edit-raid-header h1 {
    margin: 0;
}

.edit-raid-shortname {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
    margin-top: 0.35rem;
}

.encounter-section {
    margin-bottom: 0.5rem;
    border: 1px solid var(--line);
    border-radius: 0.25rem;
    overflow: hidden;
}

.encounter-header {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.75rem;
    background: var(--bg-2);
    cursor: pointer;
    user-select: none;
}

.encounter-header:hover {
    background: rgba(255,255,255,0.04);
}

/*  The .team-schedule-* rules moved to css/pages/teams.css with the rest of the Teams page,
    2026-08-18. All three are used only by Views/Teams/Index.cshtml and _TeamsTable.cshtml.
    Not left commented out here for the same reason as the main block above — the superseded
    .team-schedule-table note is itself a comment, and CSS comments do not nest.  */

.shortname-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.3rem 0.75rem;
    font-size: 0.85rem;
    background: var(--bg-2);
    border-top: 1px solid var(--line);
}

.shortname-row-label {
    font-size: 0.8rem;
}

.shortname-input {
    flex: 1;
    max-width: 24rem;
}

.shortname-error {
    font-size: 0.8rem;
    color: var(--ink-3);
}

.encounter-toggle-icon {
    font-size: 0.75rem;
    color: var(--ink-3);
    width: 0.75rem;
}

.encounter-name {
    font-weight: 600;
    flex: 1;
}

.encounter-item-count {
    font-size: 0.8rem;
    color: var(--ink-3);
}

.encounter-items {
    padding: 0.5rem 0;
}

.encounter-no-items {
    padding: 0.25rem 0.75rem;
    font-size: 0.85rem;
}

.raid-item-row {
    border-bottom: 1px solid var(--line);
    padding: 0.4rem 0.75rem;
}

.raid-item-row:last-child {
    border-bottom: none;
}

.item-view-summary {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.item-right-group {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-left: auto;
    flex-shrink: 0;
}

.item-wowhead-link {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    text-decoration: none;
    cursor: default;
}

.item-wowhead-link:hover {
    text-decoration: none;
}

.item-icon {
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 0.188rem;
    border: 2px solid transparent;
    flex-shrink: 0;
    box-sizing: border-box;
}

.item-name {
    flex: 1;
    font-size: 0.9rem;
}

.item-slot {
    font-size: 0.8rem;
    min-width: 5.625rem;
    text-align: right;
}

.item-slot-overridden {
    color: #c8923a;
}

.item-role-badge {
    background: rgba(255,255,255,0.08);
    border: 1px solid var(--line);
    padding: 0.1rem 0;
    border-radius: 0.188rem;
    font-size: 0.72rem;
    width: 2.875rem;
    text-align: center;
    flex-shrink: 0;
}

.item-bislist-badge {
    background: rgba(80,200,120,0.12);
    color: #50c878;
    border: 1px solid rgba(80,200,120,0.35);
    padding: 0.1rem 0;
    border-radius: 0.188rem;
    font-size: 0.72rem;
    width: 2.875rem;
    text-align: center;
    flex-shrink: 0;
}

.item-class-badge {
    padding: 0.1rem 0;
    border-radius: 0.188rem;
    font-size: 0.72rem;
    width: 2.875rem;
    text-align: center;
    flex-shrink: 0;
    border: 1px solid transparent;
}

.item-class-badge-all {
    background: rgba(80, 200, 120, 0.12);
    color: #50c878;
    border-color: rgba(80, 200, 120, 0.35);
}

.item-class-badge-none {
    background: rgba(224, 92, 92, 0.12);
    color: #e05c5c;
    border-color: rgba(224, 92, 92, 0.35);
}

.item-class-badge-some {
    background: rgba(212, 168, 75, 0.12);
    color: #d4a84b;
    border-color: rgba(212, 168, 75, 0.35);
}

.item-badge-inactive {
    background: rgba(255,255,255,0.03);
    color: var(--ink-3);
    border-color: rgba(255,255,255,0.08);
    opacity: 0.45;
}

.item-edit-area {
    padding: 0.5rem 0;
}

.item-edit-fields {
    display: flex;
    gap: 1.5rem;
    margin-bottom: 0.75rem;
    flex-wrap: wrap;
}

.item-edit-field {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.item-edit-label {
    font-size: 0.85rem;
    color: var(--ink-3);
    white-space: nowrap;
}

.item-edit-original-slot {
    font-size: 0.85rem;
}

/* .item-edit-select {
    background: var(--bg-2);
    border: 1px solid var(--line);
    color: var(--ink);
    padding: 0.2rem 0.4rem;
    border-radius: 0.188rem;
    font-size: 0.85rem;
}

.item-edit-select option {
    background: var(--bg-2);
    color: var(--ink);
} */

.item-edit-checkboxes {
    display: flex;
    gap: 1rem;
    margin-bottom: 0.75rem;
    flex-wrap: wrap;
}

.item-edit-check-label {
    font-size: 0.85rem;
    display: flex;
    align-items: center;
    gap: 0.3rem;
    cursor: pointer;
}

.item-edit-classes {
    margin-bottom: 0.75rem;
}

.item-edit-classes-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
}

.item-class-select-btns {
    display: flex;
    gap: 0.3rem;
}

.item-class-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
    margin-top: 0.4rem;
}

.item-class-label {
    font-size: 0.85rem;
    display: flex;
    align-items: center;
    gap: 0.3rem;
    cursor: pointer;
}

.item-edit-actions {
    display: flex;
    gap: 0.5rem;
}

/* Seasons page styles moved to css/pages/seasons.css (incremental site.css split).
.seasons-create-name { width: 17.5rem; }

.season-active-badge {
    display: inline-flex;
    align-items: center;
    font-size: 0.688rem;
    font-weight: 600;
    padding: 0.188rem 0.563rem;
    border-radius: 0.188rem;
    color: #a4e6c2;
    border: 1px solid rgba(107,212,155,0.70);
    background: rgba(58,142,96,0.1);
}

.season-cell-raids {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    align-items: center;
}

.season-raid-badge {
    font-size: 0.688rem;
    background: var(--bg-2);
    border: 1px solid var(--line);
    color: var(--ink-3);
    border-radius: 0.188rem;
    padding: 0.188rem 0.563rem;
    display: inline-block;
    white-space: nowrap;
}

.season-edit-input { width: 15rem; }

.season-action-warning {
    font-size: 0.75rem;
    color: var(--warn);
    margin-right: 0.5rem;
}
*/

footer {
    background: linear-gradient(180deg, var(--bg-3) 0%, var(--bg-2) 100%);
    border-top: 1px solid var(--line-soft);
    text-align: center;
    padding: 1rem 2rem;
    font-size: 0.75rem;
    color: var(--ink-3);
    position: relative;
    z-index: 1;
}

.bislist-header {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    margin-bottom: 1.125rem;
}

.bislist-class-icon {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
}

.bislist-title {
    margin: 0;
    font-size: 1.375rem;
    font-weight: 700;
    letter-spacing: -0.013rem;
}

.bislist-realm { font-size: 0.75rem; color: var(--ink-3); }

.bislist-draft-tabs {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    align-items: flex-end;
    margin-bottom: 1.125rem;
}

/* .bislist-draft-tab { padding: 0.375rem 0.875rem; font-size: 0.781rem; color: var(--ink-2); } */
.bislist-draft-tab {
    color: var(--ink-2);
}
.bislist-draft-tab:hover:not(:disabled) { color: var(--ink); }

.bislist-draft-tab-disabled { opacity: 0.4; cursor: default; }

.bislist-team-group { display: flex; flex-direction: column; gap: 0.188rem; }
.bislist-team-group-label { font-size: 0.688rem; color: var(--ink-3); padding: 0 0.125rem; transition: color 0.15s; }

.bislist-team-group:has(.btn-active) .bislist-team-group-label { color: var(--ink-2); }
/* .bislist-team-split { display: flex; } — .btn-group */

/* .bislist-team-draft-btn { position: relative; font-size: 0.75rem; color: var(--ink-2); border-radius: var(--r-sm) 0 0 var(--r-sm); } */
/* .bislist-team-draft-btn { font-size: 0.75rem; color: var(--ink-2); } */
.bislist-team-draft-btn { color: var(--ink-2); }
/* .bislist-team-draft-btn:hover:not(:disabled) { color: var(--ink); z-index: 1; } */
.bislist-team-draft-btn:hover:not(:disabled) { color: var(--ink); }
/* .bislist-team-draft-btn.btn-active { z-index: 1; } — .btn-group */
.bislist-team-draft-btn:disabled { opacity: 0.4; cursor: default; }

/* .bislist-team-compare-btn { position: relative; margin-left: -0.063rem; font-size: 0.75rem; color: var(--ink-2); border-radius: 0; } */
/* .bislist-team-compare-btn { font-size: 0.75rem; color: var(--ink-2); } */
.bislist-team-compare-btn { color: var(--ink-2); }
/* .bislist-team-compare-btn:hover:not(:disabled) { color: var(--ink); z-index: 1; } */
.bislist-team-compare-btn:hover:not(:disabled) { color: var(--ink); }
/* .bislist-team-compare-btn.btn-active { z-index: 1; } — .btn-group */
.bislist-team-compare-btn:disabled { opacity: 0.4; cursor: default; }

/* .bislist-team-bis-btn { position: relative; margin-left: -0.063rem; font-size: 0.75rem; color: var(--ink-2); border-radius: 0 var(--r-sm) var(--r-sm) 0; } */
/* .bislist-team-bis-btn { font-size: 0.75rem; color: var(--ink-2); } */
.bislist-team-bis-btn { color: var(--ink-2); }
/* .bislist-team-bis-btn:hover:not(:disabled) { color: var(--ink); z-index: 1; } */
.bislist-team-bis-btn:hover:not(:disabled) { color: var(--ink); }
/* .bislist-team-bis-btn.btn-active { z-index: 1; } — .btn-group */
.bislist-team-bis-btn:disabled { opacity: 0.4; cursor: default; }

.bislist-notice-box { margin-bottom: 0.875rem; }

.bislist-notice {
    padding: 0.625rem 0.875rem;
    border-radius: var(--r-sm);
    font-size: 0.813rem;
    border: 1px solid;
    border-left-width: 0.188rem;
    margin-bottom: 0.375rem;
}

.bislist-notice-info {
    color: var(--accent-2);
    border-color: rgba(90,140,201,0.3);
    border-left-color: var(--accent-2);
    background: rgba(90,140,201,0.05);
    box-shadow: inset 3px 0 8px rgba(90,140,201,0.08);
}

.bislist-notice-warning {
    color: var(--warn);
    border-color: rgba(255,180,84,0.3);
    border-left-color: var(--warn);
    background: rgba(255,180,84,0.05);
    box-shadow: inset 3px 0 8px rgba(255,180,84,0.08);
}
.bislist-slot-warning { display: flex; flex-wrap: wrap; align-items: center; gap: 0.375rem; padding: 0.5rem 0.75rem; margin-bottom: 0.75rem; border-left: 2px solid var(--warn); background: rgba(255,180,84,0.06); border-radius: 0 0.25rem 0.25rem 0; font-size: 0.813rem; }
.bislist-slot-warning-label { color: var(--warn); font-weight: 500; margin-right: 0.25rem; }
.bislist-slot-warning-item { color: var(--ink-3); }

.bislist-draft-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.875rem;
}
/* .bislist-copy-toggle-chevron transition: transform removed — chevron now uses textContent toggle: ⮞/⮟ */
.bislist-copy-toggle-chevron { display: inline-block; font-size: 0.75rem; }
.bislist-copy-panel { display: flex; align-items: center; flex-wrap: wrap; gap: 0.75rem; padding: 0.625rem 0.875rem; margin-bottom: 0.875rem; background: var(--bg-2); border: 1px solid var(--line); border-radius: 0.25rem; font-size: 0.813rem; }
.bislist-copy-option { display: flex; align-items: center; gap: 0.375rem; cursor: pointer; color: var(--ink-3); }

.bislist-delete-submission-btn {
    margin-left: auto;
    /* color: var(--bad); — .btn-danger */
    /* border-color: rgba(255,107,107,0.25); — .btn-danger */
}
/* .bislist-delete-submission-btn:hover { border-color: var(--bad); background: var(--bg-2); } — .btn-danger:hover */

.bislist-locked-badge {
    font-size: 0.688rem;
    font-weight: 500;
    background: rgba(212,160,60,0.10);
    border: 1px solid rgba(255,180,84,0.70);
    color: #ffd27a;
    border-radius: 0.25rem;
    padding: 0.313rem 0.688rem;
}

.gp-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 0;
    margin-left: 0.938rem;
    padding-bottom: 0;
}

.gp-tab {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.875rem;
    font-size: 0.813rem;
    font-family: inherit;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-bottom: none;
    border-radius: 0.5rem 0.5rem 0 0;
    cursor: pointer;
    margin-bottom: -0.063rem;
    color: var(--ink-3);
    transition: color 0.15s, border-color 0.15s, box-shadow 0.15s;
}

.gp-tab { opacity: 0.45; }
.gp-tab:hover { color: var(--ink-2); opacity: 0.75; }
.gp-tab-active { color: var(--ink); border-color: var(--line); box-shadow: inset 0 -2px 0 var(--accent); opacity: 1; }

.bislist-spec-icon {
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 0.125rem;
}

.bislist-spec-star {
    width: 0.875rem;
    height: 0.875rem;
    pointer-events: none;
    user-select: none;
}

.bislist-spec-star-hidden {
    display: none;
}
.approve-spec-tab-warning { width: 0.75rem; height: 0.75rem; flex-shrink: 0; filter: invert(1) sepia(1) saturate(8) hue-rotate(5deg); opacity: 0.9; }

.bislist-main-spec-control {
    margin-bottom: 1rem;
    padding: 0.6rem 0.8rem;
    background: rgba(255,255,255,0.03);
    border: 1px solid var(--line);
    border-radius: 0.25rem;
}

.bislist-toggle-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    cursor: pointer;
}

.bislist-toggle-switch-wrap {
    position: relative;
    flex-shrink: 0;
}

.bislist-toggle-input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.bislist-toggle-track {
    display: block;
    width: 2.25rem;
    height: 1.25rem;
    background: rgba(255,255,255,0.12);
    border-radius: 0.625rem;
    border: 1px solid var(--line);
    position: relative;
    transition: background 0.2s, border-color 0.2s;
    cursor: pointer;
}

.bislist-toggle-input:checked + .bislist-toggle-track {
    background: var(--accent);
    border-color: var(--accent);
}

.bislist-toggle-thumb {
    position: absolute;
    top: 0.125rem;
    left: 0.125rem;
    width: 0.875rem;
    height: 0.875rem;
    background: #fff;
    border-radius: 50%;
    transition: transform 0.2s;
}

.bislist-toggle-input:checked + .bislist-toggle-track .bislist-toggle-thumb {
    transform: translateX(1rem);
}

.bislist-toggle-label-text {
    font-size: 0.82rem;
    color: var(--ink-3);
    user-select: none;
}

.bislist-item-list {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.bislist-item-list .bislist-item-card { flex: 0 0 calc(33.33% - 0.34rem); min-width: 0; }
.bislist-item-list .bislist-group-header { flex: 0 0 100%; }

.bislist-item-card {
    border: 1px solid var(--line);
    border-radius: 0.25rem;
    overflow: visible;
    position: relative;
    box-shadow: var(--sh-card);
}

.bislist-card-top {
    padding: 0.6rem 0.8rem 0.5rem;
    background: linear-gradient(to bottom, rgba(255,255,255,0.045) 0%, rgba(255,255,255,0.01) 100%);
    border-radius: 0.25rem 0.25rem 0 0;
}

.bislist-card-divider {
    height: 0.063rem;
    background: var(--line);
}

.bislist-card-body {
    padding: 0.55rem 0.8rem 0.6rem;
    background: linear-gradient(to bottom, rgba(0,0,0,0.08) 0%, rgba(255,255,255,0.02) 100%);
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.4rem;
}

.bislist-item-header {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    position: relative;
}

.bislist-item-icon-link {
    flex-shrink: 0;
}

.bislist-item-icon {
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 0.188rem;
    border: 2px solid var(--line);
    display: block;
}

.bislist-item-title {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.bislist-item-name-row { display: flex; align-items: center; gap: 0.25rem; min-width: 0; }
.bislist-item-name {
    font-size: 0.9rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-decoration: none;
    flex: 1;
    min-width: 0;
}

.bislist-item-subtitle {
    font-size: 0.72rem;
    color: rgba(136,136,136,0.6);
}
.bislist-item-subtitle-raid { display: block; }

.bislist-item-note-btn {
    flex-shrink: 0;

    padding: 0.125rem 0.25rem;
    background: transparent;
    border-color: transparent;
    box-shadow: none;
}
.bislist-item-note-btn:hover { background: transparent; border-color: transparent; }

.bislist-roll-row {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

/* .bislist-roll-select {
    background: var(--bg-2);
    border: 1px solid var(--line);
    color: var(--ink);
    border-radius: 0.188rem;
    padding: 0.2rem 0.5rem;
    font-size: 0.82rem;
    font-family: inherit;
} */

.bislist-obtained-row {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

/* .bislist-obtained-btn { font-size: 0.688rem; font-weight: 500; padding: 0.15rem 0.55rem; background: rgba(255,255,255,0.04); border: 1px solid var(--line); border-radius: 0.25rem; cursor: pointer; color: var(--ink-3); font-family: inherit; transition: background 0.1s, color 0.1s; width: 100%; } */
.bislist-obtained-btn {
    font-size: 0.688rem;
    padding: 0.15rem 0.55rem;
    background: rgba(255,255,255,0.04);
    color: var(--ink-3);
    box-shadow: none;
    transition: background 0.1s, border-color 0.1s, color 0.1s;
    width: 100%;
}

/* .bislist-obtained-btn:hover { color: var(--ink); } */
.bislist-obtained-btn:hover {
    background: rgba(255,255,255,0.08);
    border-color: var(--ink-3);
    color: var(--ink-2);
}

/* .bislist-obtained-active.bislist-obtained-normal { background: rgba(30,255,0,0.1); border-color: rgba(30,255,0,0.4); color: #1eff00; } */
/* .bislist-obtained-active.bislist-obtained-heroic { background: rgba(0,112,221,0.15); border-color: rgba(0,112,221,0.5); color: #0070dd; } */
/* .bislist-obtained-active.bislist-obtained-mythic { background: rgba(163,53,238,0.15); border-color: rgba(163,53,238,0.5); color: #a335ee; } */
.bislist-obtained-active {
    background: color-mix(in oklab, var(--col) 8%, var(--bg));
    border-color: color-mix(in oklab, var(--col) 40%, transparent);
    color: color-mix(in oklab, var(--col) 72%, #fff);
}
.bislist-obtained-active:hover {
    background: color-mix(in oklab, var(--col) 8%, var(--bg));
    border-color: color-mix(in oklab, var(--col) 40%, transparent);
    color: color-mix(in oklab, var(--col) 72%, #fff);
    filter: brightness(1.12);
}

.bislist-item-note-area {
    display: none;
    position: absolute;
    top: calc(100% + 0.25rem);
    right: 0;
    width: 13.75rem;
    z-index: 10;
    background: var(--bg-3);
    border: 1px solid var(--line);
    border-radius: 0.25rem;
    padding: 0.375rem;
    box-shadow: var(--sh-pop);
}

.bislist-note-visible {
    display: block;
}

.bislist-item-note-text {
    font-size: 0.82rem;
    color: var(--ink);
    margin: 0;
}

.bislist-item-note-input {
    width: 100%;
    background: var(--bg-2);
    border: 1px solid var(--line);
    color: var(--ink);
    border-radius: 0.188rem;
    padding: 0.3rem 0.5rem;
    font-size: 0.82rem;
    font-family: inherit;
    resize: vertical;
    min-height: 3rem;
    box-sizing: border-box;
}

.char-card-actions {
    margin-top: 0.6rem;
    display: flex;
    justify-content: center;
}

.bislist-sort-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
}

.bislist-sort-label {
    font-size: 0.78rem;
}

/* .bislist-sort-active { border-color: var(--accent); color: var(--accent); } — replaced by .btn-active */

.bislist-group-header {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.063rem;
    padding: 0.5rem 0 0.25rem;
    margin-top: 0.5rem;
    border-bottom: 1px solid var(--line);
    margin-bottom: 0.4rem;
}

.bislist-group-header:first-child {
    margin-top: 0;
}

.bislist-filter-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-bottom: 0.5rem;
}

/* .bislist-roll-btn { font-size: 0.688rem; font-weight: 500; padding: 0.15rem 0.55rem; background: rgba(255,255,255,0.04); border: 1px solid var(--line); border-radius: 0.25rem; cursor: pointer; color: var(--ink-3); font-family: inherit; transition: background 0.12s, border-color 0.12s, color 0.12s; width: 100%; } */
.bislist-roll-btn {
    font-size: 0.688rem;
    padding: 0.15rem 0.55rem;
    background: rgba(255,255,255,0.04);
    color: var(--ink-3);
    box-shadow: none;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
    width: 100%;
}

/* .bislist-roll-btn:hover { border-color: var(--ink-3); color: var(--ink); } */
.bislist-roll-btn:hover {
    background: rgba(255,255,255,0.08);
    border-color: var(--ink-3);
    color: var(--ink-2);
}

/* .bislist-roll-active-all      { background: rgba(43,95,196,0.12);   border-color: rgba(74,130,224,0.50);  color: var(--accent-glow); } — dead: Roll enum has no All type */
/* .bislist-roll-active-bis      { background: rgba(196,68,68,0.1);    border-color: rgba(255,107,107,0.70); color: #ffb1b1; } */
/* .bislist-roll-active-major    { background: rgba(212,160,60,0.12);  border-color: rgba(255,180,84,0.70);  color: #ffd27a; } */
/* .bislist-roll-active-minor    { background: rgba(58,142,96,0.1);    border-color: rgba(107,212,155,0.70); color: #a4e6c2; } */
/* .bislist-roll-active-offspec  { background: transparent;            border-color: rgba(122,128,148,0.65); color: #b6bac6; } — dead: Roll enum has no Offspec type */
/* .bislist-roll-active-transmog { background: rgba(186,85,211,0.10);  border-color: rgba(220,120,255,0.70); color: #e8a0df; } — dead: Roll enum has no Transmog type */
.bislist-roll-active-bis, .bislist-roll-active-major, .bislist-roll-active-minor {
    background: color-mix(in oklab, var(--col) 8%, var(--bg));
    border-color: color-mix(in oklab, var(--col) 40%, transparent);
    color: color-mix(in oklab, var(--col) 72%, #fff);
}
.bislist-roll-active-bis:hover, .bislist-roll-active-major:hover, .bislist-roll-active-minor:hover {
    background: color-mix(in oklab, var(--col) 8%, var(--bg));
    border-color: color-mix(in oklab, var(--col) 40%, transparent);
    color: color-mix(in oklab, var(--col) 72%, #fff);
    filter: brightness(1.12);
}
/* 2026-08-10 — a .loot-roll-col-* alias was added here and REMOVED the same day. It existed so the
   Compare view's column toggles could be .btn-col buttons in the roll colours; those toggles were
   then made plain .btn-active to match the rest of their group, so the alias had no consumer left.
   A selector with no usage cannot be checked against reality (Directive 18), so it is gone rather
   than kept "in case". The count CELLS still use .bislist-roll-active-* below. */
.bislist-roll-active-bis   { --col: oklch(0.62 0.20 25); }
.bislist-roll-active-major { --col: oklch(0.80 0.15 92); }
.bislist-roll-active-minor { --col: oklch(0.66 0.15 150); }

.bislist-roll-locked {
    font-size: 0.688rem;
    font-weight: 500;
    padding: 0.125rem 0.5rem;
    border-radius: 0.25rem;
    border-width: 1px;
    border-style: solid;
    letter-spacing: 0.025rem;
    flex-shrink: 0;
    align-self: flex-start;
}

.bislist-btn-group {
    margin-bottom: 0;
}

.bislist-btn-group-label {
    display: block;
    font-size: 0.7rem;
    margin-bottom: 0.2rem;
}

.bislist-note-icon {
    display: inline-block;
    width: 0.813rem;
    height: 0.813rem;
    -webkit-mask: url('/img/note.svg') no-repeat center / contain;
    mask: url('/img/note.svg') no-repeat center / contain;
    background-color: rgba(255,255,255,0.2);
    vertical-align: middle;
    pointer-events: none;
    flex-shrink: 0;
}

.bislist-item-note-btn:hover .bislist-note-icon { background-color: rgba(255,255,255,0.4); }

.bislist-note-btn-has-note .bislist-note-icon { background-color: white; }

.bislist-note-btn-has-note:hover .bislist-note-icon { background-color: rgba(255,255,255,0.75); }

.approve-note-changed .bislist-note-icon { background-color: #ffb454; }
.approve-note-changed:hover .bislist-note-icon { background-color: rgba(255,180,84,0.75); }

.approve-back-link {
    display: inline-block;
    margin-bottom: 1rem;
    color: var(--ink-3);
    font-size: 0.85rem;
    text-decoration: none;
}

.approve-back-link:hover {
    color: var(--ink);
}

/* Shared two-column split layout — fixed left panel + flexible right panel */
.gp-split-layout {
    display: flex;
    gap: 1.125rem;
    align-items: flex-start;
}

.gp-split-left {
    width: 13rem;
    flex-shrink: 0;
    position: sticky;
    top: 1rem;
    /* max-height: calc(100vh - 7.75rem); — old: only accounted for nav + sticky-top + footer, missed main padding and page-head */
    max-height: calc(100vh - 12rem); /* CSS fallback for pages without JS; gp-split.js overrides this at runtime with a precise measured value */
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.gp-split-left-header {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.625rem 0.875rem 0.375rem;
    border-bottom: 1px solid var(--line);
    flex-shrink: 0;
}

.gp-split-left-title {
    font-size: 0.656rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.044rem;
    color: var(--ink-3);
}

.gp-split-left-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

.gp-split-right {
    flex: 1;
    min-width: 0;
}

/* Left panel row — selection highlight */
.gp-split-left-row {
    cursor: pointer;
    transition: background 0.15s;
}

.gp-split-left-row:hover {
    background: linear-gradient(to right, rgba(255, 255, 255, 0.04), transparent);
}

/* is-active: colour-coded by class colour when --char-color is set on the row; falls back to the
   PALE BLUE selection colour for non-character lists.

   CORRECTED 2026-08-06 — the fallback was pure white, which made this the only selected-row
   treatment in the portal that did not match the others. The selection colour is #dce6ff for the
   left accent and the wash, #aac8ff for the top and bottom edges. The same pair is used by the Loot
   Distribution boss column (.loot-boss-active), the Roster/Manage roster list
   (.gp-panel-row.btn-active — .roster-list-item until the 2026-08-18 rename) and .gp-list-active.
   Those three agreed; this one was the outlier.

   THE TWO VALUES ARE NOT INTERCHANGEABLE. #dce6ff is the accent and the wash, #aac8ff is the
   slightly deeper edge — collapsing them to one value loses the edge definition.

   --char-color still overrides all four when set, so character lists are unaffected. */
.gp-split-left-row.is-active {
    background: linear-gradient(to right, color-mix(in oklch, var(--char-color, #dce6ff) 10%, transparent), transparent);
    box-shadow:
        inset 0 1px 0 color-mix(in oklch, var(--char-color, #aac8ff) 22%, transparent),
        inset 0 -1px 0 color-mix(in oklch, var(--char-color, #aac8ff) 22%, transparent),
        inset 2px 0 0 var(--char-color, #dce6ff);
}

/* WCL page — spacing between stacked team sections */
.gp-wcl-section + .gp-wcl-section {
    margin-top: 1.5rem;
}

.gp-row-subtitle {
    font-size: 0.75rem;
    color: var(--ink-3);
    margin-top: 0.125rem;
}

.approve-bislist-layout {
    display: flex;
    gap: 1.125rem;
    align-items: flex-start;
}

.approve-bislist-left {
    width: 13.75rem;
    flex-shrink: 0;
    overflow-y: auto;
    max-height: calc(100vh - 10rem);

}
.approve-bislist-left.gp-card-table {
    padding-top: 0.938rem;
    padding-bottom: 0.938rem;
}

.approve-bislist-right {
    flex: 1;
    min-width: 0;
}

.approve-character-row {
    padding: 0.625rem 0.875rem;
    cursor: pointer;
    border-left: 0.188rem solid transparent;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--line);
    transition: background 0.12s;
    user-select: none;
    position: relative;
    font-size: 0.813rem;
}

.approve-character-row:first-child { border-top: 1px solid var(--line); }
.approve-character-row:last-child { border-bottom: 1px solid var(--line); }

.approve-character-row:hover { background: rgba(255,255,255,0.02); }

.approve-character-row-active {
    background: linear-gradient(to right, rgba(255,255,255,0.06), rgba(255,255,255,0));
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.06),
                inset -0.063rem 0 0 rgba(255,255,255,0.06),
                inset 0 -0.063rem 0 rgba(255,255,255,0.06);
}

.approve-character-row-active::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to right, var(--char-color, #888), transparent);
    opacity: 0.08;
    pointer-events: none;
}

.approve-character-name {
    font-size: 0.813rem;
    font-weight: 600;
    color: var(--ink-2);
}

.approve-character-row-active .approve-character-name { color: var(--ink); }

.approve-bis-warning-icon { width: 0.875rem; height: 0.875rem; opacity: 0.8; filter: invert(1) sepia(1) saturate(5) hue-rotate(5deg); flex-shrink: 0; }

.approve-empty-notice {
    padding: 1rem;
    font-size: 0.85rem;
}

.approve-action-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1.125rem;
    flex-wrap: wrap;
}

.approve-decline-note { flex: 1; min-width: 11.25rem; max-width: 21.25rem; }

.approve-previous-decline {
    background: rgba(255,180,84,0.05);
    border: 1px solid rgba(255,180,84,0.3);
    border-left: 0.188rem solid var(--warn);
    border-radius: var(--r-sm);
    padding: 0.625rem 0.875rem;
    margin-bottom: 0.875rem;
    font-size: 0.813rem;
    box-shadow: inset 3px 0 8px rgba(255,180,84,0.08);
}
.approve-previous-decline-label { color: var(--ink-3); margin-right: 0.375rem; }

.approve-character-heading {
    margin: 0 0 0.875rem 0;
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: -0.013rem;
}

.approve-item-row {
    display: flex;
    gap: 0.875rem;
    margin-bottom: 0.375rem;
    padding-left: 0.875rem;
}

.approve-item-col { flex: 1; min-width: 0; }

.approve-item-status-removed .approve-item-col-draft { opacity: 0.3; }
.approve-item-status-new .approve-item-col-submission { opacity: 0.3; }

.approve-item-card-actions { position: absolute; top: 50%; right: 0.5rem; transform: translateY(-50%); z-index: 1; display: flex; align-items: center; gap: 0.25rem; }
.approve-roll-badge { position: static; }

.approve-item-card {
    background: var(--bg-2);
    border: 1px solid var(--line-soft);
    border-left: 0.188rem solid var(--line-soft);
    border-radius: 0 var(--r-sm) var(--r-sm) 0;
    padding: 0.5rem 0.625rem;
    position: relative;
    overflow: visible;
    display: flex;
    flex-direction: column;
    box-shadow: var(--sh-card);
    gap: 0.375rem;
}

.approve-item-status-new .approve-item-col-draft .approve-item-card {
    border-left-color: #4ade80;
}
.approve-item-status-new .approve-item-col-draft .approve-item-card::before {
    content: ''; position: absolute; top: 0; bottom: 0; left: -0.875rem; width: 0.875rem;
    background: linear-gradient(to left, rgba(74,222,128,0.28), transparent);
    pointer-events: none;
}

.approve-item-status-removed .approve-item-col-submission .approve-item-card {
    border-left-color: #ff6b6b;
    opacity: 0.78;
}
.approve-item-status-removed .approve-item-col-submission .approve-item-card::before {
    content: ''; position: absolute; top: 0; bottom: 0; left: -0.875rem; width: 0.875rem;
    background: linear-gradient(to left, rgba(255,107,107,0.28), transparent);
    pointer-events: none;
}

.approve-item-status-modified .approve-item-card {
    border-left-color: #ffb454;
}
.approve-item-status-modified .approve-item-card::before {
    content: ''; position: absolute; top: 0; bottom: 0; left: -0.875rem; width: 0.875rem;
    background: linear-gradient(to left, rgba(255,180,84,0.28), transparent);
    pointer-events: none;
}

.approve-item-status-unchanged .approve-item-card {
    border-left-color: #5a8cc9;
}
.approve-item-status-unchanged .approve-item-card::before {
    content: ''; position: absolute; top: 0; bottom: 0; left: -0.875rem; width: 0.875rem;
    background: linear-gradient(to left, rgba(90,140,201,0.28), transparent);
    pointer-events: none;
}

.approve-spec-panel { margin-top: 0.375rem; }

.approve-spec-content-card {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    margin-top: 0;
}

.compare-column-headers {
    display: flex;
    gap: 0.875rem;
    margin: 0.5rem 0 0.375rem 0.875rem;
}

.compare-column-header-left,
.compare-column-header-right {
    flex: 1;
    font-size: 0.688rem;
    text-transform: uppercase;
    letter-spacing: 0.038rem;
    color: var(--ink-3);
}

.compare-spec-panel {
    margin-top: 0.25rem;
}

/*  Loot Distribution page styles moved to css/pages/loot-distribution.css (incremental site.css
    split), 2026-09-30 (Session 236): every .loot-* rule, the .row-icgroup / .row-icbtn icon buttons
    (only the loot player column uses them) and the .loot-compare-count override.

    REMOVED RATHER THAN COMMENTED OUT, as with the Teams move: the block carried many comments of its
    own and CSS comments do not nest. The rules are preserved verbatim in the page file, their own
    commented-out predecessors included.

    TWO CLASSES WENT TO global.css INSTEAD, RENAMED, because other pages use them:
      .loot-diff-badge(-normal|-heroic|-mythic) -> .gp-difficulty-badge(...)  Character Loot tab, Guild Teams
      .loot-history-icon                        -> .gp-lootbox-icon           Admin Styles Example

    WHAT DID NOT MOVE: .bislist-roll-active-* above belong to the bislist; the loot count cells only
    read their --col. */

.page-head {
    margin-bottom: 1.375rem;
}

.page-sub {
    font-size: 0.813rem;
    color: var(--ink-3);
    margin-top: 0.25rem;
}
.gp-page-subtitle {
    font-size: 0.813rem;
    font-weight: 700;
    font-family: system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
    color: var(--mute-accent);
    margin-top: 0.25rem;
    text-transform: uppercase;
}

/*  [Session 227] THE DASHBOARD CLOCK IS GONE and these rules have no elements left to style.
    Removed by instruction: no ticking clock on the dashboard, and no time toggle anywhere on the
    site. Nothing on the portal shows the current time now; every time displayed is a stored moment
    converted on the server to the viewer's chosen zone.

    .clock-label and .clock-datetime were ALREADY DEAD before this session — the markup they were
    written for had been replaced by the flat .clock-time / .clock-date pair, and neither class
    appeared in any view.

    SUPERSEDED:
    .dashboard-clock { display: flex; align-items: center; gap: 0.375rem; margin-top: 0.375rem; }
    .clock-label { display: inline-flex; align-items: center; justify-content: flex-end; font-size: 0.625rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05rem; padding: 0.125rem 0.375rem; border-radius: 0.25rem; background: var(--bg-3); color: var(--ink-3); border: 1px solid var(--line-soft); white-space: nowrap; }
    .clock-datetime { display: flex; align-items: baseline; gap: 0.25rem; }
    .clock-time { font-size: 0.75rem; font-weight: 600; color: var(--ink-3); font-variant-numeric: tabular-nums; }
    .clock-date { font-size: 0.75rem; color: var(--ink-3); }
    .clock-date::before { content: "*"; margin-right: 0.188rem; color: var(--ink-3); }
*/

.welcome-hero {
    position: relative;
    padding: 4.5rem 0 3.75rem;
    min-height: 30rem;
    overflow: hidden;
}

.welcome-glow {
    position: absolute;
    width: 30rem;
    height: 30rem;
    left: 8%;
    top: -7.5rem;
    background: radial-gradient(closest-side, rgba(43,95,196,0.3), transparent 70%);
    filter: blur(2.5rem);
    pointer-events: none;
    z-index: 0;
}

.welcome-glow-2 {
    left: 55%;
    top: 30%;
    background: radial-gradient(closest-side, rgba(90,140,201,0.18), transparent 70%);
}

.welcome-content {
    position: relative;
    z-index: 1;
    max-width: 37.5rem;
}

.welcome-kicker {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.719rem;
    color: var(--accent-2);
    letter-spacing: 0.031rem;
    text-transform: uppercase;
    margin-bottom: 0.75rem;
}

.welcome-title {
    font-size: 2.75rem;
    font-weight: 700;
    letter-spacing: -0.063rem;
    margin: 0 0 0.875rem;
    background: linear-gradient(180deg, #fff 0%, #b6bac6 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    line-height: 1.1;
}

.welcome-lede {
    font-size: 0.938rem;
    color: var(--ink-2);
    margin: 0 0 1.75rem;
    line-height: 1.6;
    max-width: 30rem;
}

.welcome-cta {
    display: flex;
    gap: 0.625rem;
    flex-wrap: wrap;
}

.welcome-survey-card {
    max-width: 37.5rem;
    margin-top: 1.75rem;
}

.survey-card-kicker {
    font-size: 0.719rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.031rem;
    color: var(--accent-2);
    margin-bottom: 0.375rem;
}

.survey-card-title {
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--ink);
    margin: 0 0 0.5rem;
}

.survey-card-desc {
    font-size: 0.875rem;
    color: var(--ink-2);
    line-height: 1.5;
    margin: 0 0 0.75rem;
}

.survey-card-deadline {
    font-size: 0.813rem;
    color: var(--ink-3);
}

.survey-card-meta-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
}

.survey-card-meta-row .survey-card-deadline {
    margin: 0;
}

.survey-card-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 1rem;
}

.survey-carousel-controls { margin-top: 0.5rem; }

/* .survey-fill-selector {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    max-width: 25rem;
    margin-bottom: 1.5rem;
} */

.survey-selection-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 1.125rem;
    margin-top: 1.5rem;
}

.survey-selection-card {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 1.5rem 1.75rem;
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    box-shadow: var(--sh-card);
    text-decoration: none;
    color: var(--ink);
    min-width: 14rem;
    max-width: 22rem;
    transition: transform 0.15s, box-shadow 0.15s;
}

.survey-selection-card:hover {
    transform: translateY(-0.125rem);
    box-shadow:
        0 0.063rem 0 rgba(255,255,255,0.04) inset,
        0 0.25rem 1rem rgba(0,0,0,0.4),
        0 1rem 2.5rem rgba(0,0,0,0.5),
        0 0 0 0.063rem var(--accent),
        0 0 1.5rem color-mix(in oklch, var(--accent) 35%, transparent);
}

.survey-selection-name {
    font-weight: 600;
    font-size: 1rem;
    color: var(--ink);
}

.survey-selection-desc {
    font-size: 0.875rem;
    color: var(--ink-2);
}

.survey-selection-deadline {
    font-size: 0.75rem;
    color: var(--ink-3);
    margin-top: 0.25rem;
}

.survey-detail-flex {
    display: flex;
    gap: 1.25rem;
    align-items: flex-start;
    flex-wrap: wrap;
}

.survey-detail-edit {
    flex: 1 1 20rem;
}

.survey-field-group {
    display: flex;
    flex-direction: column;
    gap: 0.188rem;
}

.survey-field-group .role-detail-label {
    margin-top: 0;
}

.survey-form-actions {
    width: 100%;
    display: flex;
    justify-content: flex-end;
    margin-top: 0.625rem;
}

.gp-create-form textarea {
    width: 100%;
    box-sizing: border-box;
    margin-top: 0.25rem;
    resize: vertical;
}

.js-survey-edit-form input,
.js-survey-edit-form select,
.js-survey-edit-form textarea {
    width: 100%;
    box-sizing: border-box;
    margin-top: 0.25rem;
}

.js-survey-edit-form textarea {
    resize: vertical;
}

.js-survey-edit-error {
    margin-top: 0.5rem;
}

.js-survey-edit-form .role-detail-label:first-child {
    margin-top: 0;
}

.survey-detail-teams {
    flex: 1 1 16rem;
}

.survey-team-tag {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    background: var(--bg-3);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 0.25em 0.5em;
    font-size: 0.813rem;
    margin: 0.25rem 0.25rem 0 0;
}

.survey-team-tag-remove {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    color: var(--ink-3);
    font-size: 1rem;
    line-height: 1;
}

.survey-team-tag-remove:hover {
    color: var(--bad);
}

.survey-team-add-row {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.75rem;
    align-items: center;
}

.gp-muted-note {
    font-size: 0.813rem;
    color: var(--ink-3);
    margin: 0;
}

/* Survey fill page */

/* The superseded .survey-status-banner block that stood here (the banner and its two status variants,
   replaced by .info-notice plus the two modifiers below) was DELETED 2026-09-29 (Session 235). It was
   commented out as a whole, but held comments of its own: the first inner close ended the outer
   comment early, the rest parsed as broken CSS, and its trailing close became part of the next
   selector — so the .survey-status-open rule below was silently dropped and an open survey's notice
   rendered as a plain .info-notice. Never wrap a block containing comments in another comment. */

.survey-status-open {
    background: color-mix(in oklch, var(--ok) 5%, transparent);
    border-color: color-mix(in oklch, var(--ok) 30%, transparent);
    border-left-color: var(--ok);
}

.survey-status-submitted {
    background: color-mix(in oklch, var(--warn) 5%, transparent);
    border-color: color-mix(in oklch, var(--warn) 30%, transparent);
    border-left-color: var(--warn);
}
.survey-criteria-notice {
    background: color-mix(in oklch, var(--bad) 5%, transparent);
    border: 1px solid color-mix(in oklch, var(--bad) 30%, transparent);
    border-left: 0.188rem solid var(--bad);
    border-radius: var(--r-sm);
    padding: 0.625rem 0.875rem;
    font-size: 0.813rem;
    color: var(--ink-2);
    margin-bottom: 1.125rem;
}
.survey-criteria-list {
    margin: 0;
    padding-left: 1.25rem;
}

.survey-player-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 1rem;
    margin-bottom: 1.25rem;
}
.survey-player-col-third { grid-column: span 2; }
.survey-player-col-half { grid-column: span 3; }
.survey-aspiration-options {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.survey-aspiration-options .survey-team-toggle {
    justify-content: flex-start;
}
.survey-teams-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1rem;
    margin-bottom: 1.25rem;
}
@media (max-width: 48em) {
    .survey-teams-grid {
        grid-template-columns: 1fr;
    }
}
.survey-teams-grid .gp-card {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    background: var(--bg-2);
}
.survey-team-card-name {
    display: block;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--ink);
    text-align: left;
    margin-bottom: 0.25rem;
}
.survey-team-card-body {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
}
@media (max-width: 48em) {
    .survey-team-card-body {
        grid-template-columns: 1fr;
    }
}
.survey-team-info-col,
.survey-team-questions-col {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.survey-team-card-schedule {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}
.survey-team-schedule-slot {
    display: flex;
    justify-content: space-between;
    font-size: 0.719rem;
    color: var(--ink-3);
}
.survey-team-desc {
    font-size: 0.813rem;
    color: var(--ink-2);
}
.survey-team-desc-toggle {
    background: none;
    border: none;
    padding: 0;
    margin-left: 0.25rem;
    color: var(--accent);
    font-size: 0.813rem;
    cursor: pointer;
    text-decoration: underline;
}
.survey-team-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.313em 0.688em;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    cursor: pointer;
    font-size: 0.813rem;
    color: var(--ink-3);
    transition: background 0.15s, color 0.15s, border-color 0.15s;
    user-select: none;
}
.survey-team-toggle input[type="checkbox"],
.survey-team-toggle input[type="radio"] { display: none; }
.survey-team-toggle:has(input:checked) {
    --acc: var(--accent);
    --acc-bright: color-mix(in oklab, var(--accent) 65%, #fff);
    background: color-mix(in oklab, var(--acc) 6%, transparent);
    border-color: var(--acc-bright);
    color: var(--acc-bright);
    box-shadow:
        0 0 0 1px color-mix(in oklab, var(--acc) 10%, transparent),
        0 0 14px 1px color-mix(in oklab, var(--acc) 50%, transparent),
        inset 0 0 12px -6px color-mix(in oklab, var(--acc-bright) 70%, transparent);
    text-shadow: 0 0 10px color-mix(in oklab, var(--acc-bright) 70%, transparent);
}

.survey-section-card {
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 1.25rem;
    margin-bottom: 1.25rem;
}

.survey-section-heading {
    font-size: 1rem;
    font-weight: 600;
    margin: 0 0 1rem 0;
    color: var(--ink-1);
}

.survey-field-row {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    margin-bottom: 0.875rem;
}
.survey-field-label-row {
    display: flex;
    align-items: center;
}
.survey-field-label-row .gp-save-indicator { margin-left: auto; }

.survey-text-input {
    max-width: 28rem;
}

.survey-save-status {
    font-size: 0.75rem;
}

.survey-save-status--ok {
    color: var(--ok);
}

.survey-save-status--error {
    color: var(--bad);
}

.survey-team-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--line);
    flex-wrap: wrap;
}

.survey-team-row:last-child {
    border-bottom: none;
}

.survey-team-row-name {
    min-width: 10rem;
    font-weight: 500;
}

.survey-team-row-checks {
    display: flex;
    gap: 0.875rem;
}

.survey-team-check-label {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.875rem;
    cursor: pointer;
}

.survey-team-row-priority {
    flex: 1;
}

.survey-character-card {
    display: grid;
    grid-template-columns: repeat(24, 1fr);
    align-items: start;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}
.survey-character-info {
    grid-column: span 8;
}
.survey-add-character-card {
    grid-column: span 8;
}
#survey-import-panel {
    grid-column: span 16;
}
.survey-character-card .survey-spec-slot {
    grid-column: span 4;
}

.survey-character-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.survey-character-name {
    font-weight: 600;
    font-size: 1rem;
}

.survey-character-realm {
    font-size: 0.813rem;
    color: var(--ink-3);
}

.survey-character-remove {
    margin-left: auto;
    /* background: none; — .btn-icon */
    /* border: none; — .btn-icon */
    /* cursor: pointer; — .btn */
    /* color: var(--ink-3); — .btn-icon-danger */
    /* font-size: 1.125rem; — .btn-icon fixed size */
    /* line-height: 1; — .btn-icon */
    /* padding: 0; — .btn-icon */
}

/* .survey-character-remove:hover { color: var(--bad); } — .btn-icon-danger:hover */

/*.survey-character-favor-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}*/
.survey-character-favor-row {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.survey-character-favor-row .role-detail-label,
.survey-spec-selectors .role-detail-label { margin: 0; }

#survey-form-content .role-detail-label { color: #7aaeff; }

/*.survey-spec-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}*/

.survey-spec-slot {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.survey-spec-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}
.survey-spec-identity {
    display: flex;
    align-items: center;
    gap: 0.375rem;
}

/*.survey-spec-btn { ... } — removed; replaced by toggle-pill-check */
/*.survey-spec-btn--ghost { ... } — removed */
/*.survey-spec-btn--ghost:hover { ... } — removed */
/*.survey-spec-btn--added { ... } — removed */

.survey-spec-icon {
    width: 1.5rem;
    height: 1.5rem;
    object-fit: cover;
    border-radius: var(--r-sm);
}
.survey-spec-name {
    font-size: 0.625rem;
    color: var(--ink-3);
    text-align: center;
    line-height: 1.2;
}

.survey-spec-detail {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.survey-spec-selectors {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.survey-add-character-ghost {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 3.5rem;
    border: 2px dashed var(--line);
    border-radius: var(--r-sm);
    background: none;
    color: var(--ink-3);
    cursor: pointer;
    font-size: 0.875rem;
}

.survey-add-character-ghost:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.survey-import-list {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}
.survey-import-item {
    display: block;
    cursor: pointer;
    user-select: none;
}
.survey-import-item input[type="checkbox"] { display: none; }
.survey-import-item:has(input:checked) .gp-char-card-compact {
    border-color: color-mix(in oklab, var(--accent) 65%, #fff);
    box-shadow:
        0 0.063rem 0 rgba(255,255,255,0.04) inset,
        0 0.25rem 1rem rgba(0,0,0,0.4),
        0 1rem 2.5rem rgba(0,0,0,0.5),
        0 0 0 0.063rem var(--accent),
        0 0 1.5rem color-mix(in oklch, var(--accent) 35%, transparent);
}
.survey-import-realm {
    font-size: 0.719rem;
    color: var(--ink-3);
}

.survey-import-actions {
    display: flex;
    gap: 0.5rem;
}

.survey-message-row {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    margin-bottom: 0.875rem;
    flex: 1;
}

.survey-message-textarea {
    width: 100%;
    box-sizing: border-box;
    resize: vertical;
    flex: 1;
}

.survey-submit-row {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.75rem;
    margin-top: 1.125rem;
}

.survey-page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

/* Survey fill — locked state when submitted */
#survey-form-content[data-submitted] input:not([type="hidden"]),
#survey-form-content[data-submitted] select,
#survey-form-content[data-submitted] textarea,
#survey-form-content[data-submitted] button,
#survey-form-content[data-submitted] .toggle-pill-check,
#survey-form-content[data-submitted] .survey-team-toggle {
    opacity: 0.45;
    pointer-events: none;
}

/* Survey Results (.sr-*, #sr-*) moved to css/pages/survey-results.css
   (loaded per-page via @section Styles in Views/Surveys/Results.cshtml).
   The .gp-section-card.btn-accent rules below stay here — they are gp- globals,
   not results-specific. */

/* .gp-section-card's own background/border (declared after .btn-accent above, same
   specificity) would otherwise silently win and hide the accent tint/border-color;
   this compound selector out-specifies it so the full .btn-accent look renders. */
.gp-section-card.btn-accent {
    background: color-mix(in oklab, var(--acc) 6%, transparent);
    border-color: var(--acc-bright);
}
.gp-section-card.btn-accent:hover {
    background: color-mix(in oklab, var(--acc) 26%, transparent);
    border-color: var(--acc-bright);
}

/* (Survey Results .sr-* / #sr-* rules moved to css/pages/survey-results.css — see note above.) */

.switch-account-wrap {
    max-width: 30rem;
    margin: 3.75rem auto 0;
    position: relative;
}

.switch-account-wrap::before {
    content: '';
    position: absolute;
    width: 23.75rem;
    height: 23.75rem;
    left: 10%;
    top: -5rem;
    background: radial-gradient(closest-side, rgba(90,140,201,0.22), transparent 70%);
    filter: blur(2.5rem);
    pointer-events: none;
    z-index: 0;
}

.switch-account-card {
    box-shadow: var(--sh-pop);
    padding: 1.75rem !important;
    position: relative;
    z-index: 1;
}

.switch-account-lede {
    font-size: 0.844rem;
    color: var(--ink-2);
    margin-bottom: 1.125rem;
    line-height: 1.5;
}

.switch-account-steps {
    list-style: none;
    padding: 0;
    margin: 0 0 1.375rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.switch-account-steps li {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    font-size: 0.844rem;
    color: var(--ink-2);
}

.switch-step-n {
    width: 1.375rem;
    height: 1.375rem;
    border-radius: 50%;
    background: rgba(43,95,196,0.12);
    border: 1px solid rgba(43,95,196,0.3);
    color: var(--accent-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.688rem;
    font-weight: 600;
    flex-shrink: 0;
}

.switch-account-cta {
    display: flex;
    gap: 0.625rem;
    flex-wrap: wrap;
}

/*  url ADDED 2026-09-06. It was missing from all four lists below, so an input[type="url"]
    fell through every one of them and rendered as the browser's NATIVE control — a white box
    with dark text on a dark page. Nothing errors; the input simply looks like it belongs to a
    different site. Caught on the Dev Options relay address field, the first type="url" in the
    codebase, so adding it changes no existing surface. */
input[type="text"],
input[type="number"],
input[type="password"],
input[type="email"],
input[type="search"],
input[type="url"],
input[type="date"],
input[type="time"],
input[type="datetime-local"] {
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 0.313rem 0.75rem;
    font-size: 0.813rem;
    font-family: inherit;
    line-height: 1.3;
    color: var(--ink);
    outline: none;
    transition: border-color 0.15s, box-shadow 0.15s;
    box-sizing: border-box;
}
textarea {
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 0.438rem 0.75rem;
    font-size: 0.813rem;
    font-family: inherit;
    color: var(--ink);
    outline: none;
    transition: border-color 0.15s, box-shadow 0.15s;
    box-sizing: border-box;
}

input[type="text"]:focus,
input[type="number"]:focus,
input[type="password"]:focus,
input[type="email"]:focus,
input[type="search"]:focus,
input[type="url"]:focus,
input[type="date"]:focus,
input[type="time"]:focus,
input[type="datetime-local"]:focus,
textarea:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px rgba(43,95,196,0.15);
}

input[type="text"]::placeholder,
input[type="number"]::placeholder,
input[type="password"]::placeholder,
input[type="email"]::placeholder,
input[type="search"]::placeholder,
input[type="url"]::placeholder,
textarea::placeholder {
    color: var(--ink-3);
}

input[type="text"]:disabled,
input[type="number"]:disabled,
input[type="password"]:disabled,
input[type="url"]:disabled,
input[type="date"]:disabled,
input[type="time"]:disabled,
input[type="datetime-local"]:disabled,
select:disabled,
textarea:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

input[type="date"]::-webkit-calendar-picker-indicator {
    filter: invert(1);
    opacity: 0.45;
    cursor: pointer;
    border-radius: 0.125rem;
}
input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 0.85; }
input[type="time"]::-webkit-calendar-picker-indicator { filter: invert(1); opacity: 0.45; cursor: pointer; border-radius: 0.125rem; }
input[type="time"]::-webkit-calendar-picker-indicator:hover { opacity: 0.85; }
input[type="datetime-local"]::-webkit-calendar-picker-indicator { filter: invert(1); opacity: 0.45; cursor: pointer; border-radius: 0.125rem; }
input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover { opacity: 0.85; }

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
    background: var(--bg-3);
    border-left: 1px solid var(--line);
    color: var(--ink-3);
    opacity: 1;
    cursor: pointer;
}

.num-stepper {
    display: inline-flex;
    align-items: stretch;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    overflow: hidden;
}
.num-stepper:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px rgba(43, 95, 196, 0.15);
}
.num-stepper-btn {
    background: none;
    border: none;
    color: var(--ink-3);
    cursor: pointer;
    min-width: 1.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    line-height: 1;
    transition: color 0.12s, background 0.12s;
}
.num-stepper-btn:hover { color: var(--ink); background: var(--bg-3); }
.num-stepper-dec { border-right: 1px solid var(--line); }
.num-stepper-inc { border-left: 1px solid var(--line); }
.num-stepper .num-stepper-input {
    background: none;
    border: none;
    border-radius: 0;
    color: var(--ink);
    text-align: center;
    padding: 0.313rem 0;
    width: 2.75rem;
    font-size: 0.813rem;
    font-family: inherit;
    line-height: 1.3;
    outline: none;
    box-shadow: none;
    min-width: 0;
    -moz-appearance: textfield;
}
.num-stepper .num-stepper-input:focus { border-color: transparent; box-shadow: none; }
.num-stepper .num-stepper-input::-webkit-inner-spin-button,
.num-stepper .num-stepper-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.num-stepper:has(.num-stepper-input:disabled) { opacity: 0.45; cursor: not-allowed; }
.num-stepper:has(.num-stepper-input:disabled) .num-stepper-btn { cursor: not-allowed; pointer-events: none; }

select {
    appearance: none;
    background: var(--bg-2) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%237a8094'/%3E%3C/svg%3E") no-repeat right 0.625rem center;
    background-size: 0.625rem;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 0.313rem 1.75rem 0.313rem 0.75rem;
    font-size: 0.813rem;
    font-family: inherit;
    line-height: 1.3;
    color: var(--ink);
    outline: none;
    cursor: pointer;
    transition: border-color 0.15s;
    box-sizing: border-box;
}

select:focus { border-color: var(--accent); }
select:disabled { opacity: 0.45; cursor: not-allowed; }

.gp-select {
    padding: 0.313rem 1.375rem 0.313rem 0.5rem;
    border-radius: 0.25rem;
}

.gp-select-compact {
    padding: 0.2rem 1.375rem 0.2rem 0.4rem;
    border-radius: 0.188rem;
}

.gp-select-card-head {
    padding-top: 0.25em;
    padding-right: 1.375rem;
    padding-bottom: 0.25em;
    padding-left: 0.375em;
    border-radius: 0.25rem;
    font-size: 0.7rem;
    color: var(--ink-3);
}

input[type="checkbox"] {
    appearance: none;
    width: 0.813rem;
    height: 0.813rem;
    border: 1px solid var(--line);
    background: var(--bg-2);
    border-radius: 0.125rem;
    cursor: pointer;
    position: relative;
    flex-shrink: 0;
    transition: background 0.12s, border-color 0.12s;
}

input[type="checkbox"]:checked {
    background: #2b5fc4;
    border-color: #2b5fc4;
}

input[type="checkbox"]:disabled { opacity: 0.45; cursor: not-allowed; }

input.bislist-toggle-input,
input.bislist-main-spec-checkbox {
    appearance: none;
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    margin: 0;
    border: none;
    background: none;
    box-shadow: none;
    pointer-events: none;
}

.gp-card {
    background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 100%);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    box-shadow: var(--sh-card);
}

.gp-card-padded { padding: 1.125rem; display: flex; flex-direction: column; }
.gp-card-actions { display: flex; gap: 0.5rem; margin-top: 0.75rem; }

.gp-card-table { padding: 0; overflow: hidden; display: flex; flex-direction: column; }

/* gp-card-table-auto — card + inner data-table both size to content width.
   Use on small static tables where stretching to container width leaves visual slack
   (alternative to the all-shrink-wrap + filler-column pattern in UI/Tables.md). */
.gp-card-table-auto { width: max-content; max-width: 100%; }
.gp-card-table-auto .data-table { width: auto; }

.gp-card-mb-wide { margin-bottom: 1.5rem; }
.gp-card-mb-med { margin-bottom: 1.25rem; }
.gp-card-mb-narrow { margin-bottom: 1rem; }

.gp-card-divider { height: 1px; background: var(--line); margin: 0.5rem 0; }
.gp-card-padded .gp-card-divider { margin-left: calc(-1 * var(--pad)); margin-right: calc(-1 * var(--pad)); }
[data-trials-team-id] { display: flex; flex-direction: column; flex: 1; }
.dash-signups-content,
.dash-raider-signups-content { display: flex; flex-direction: column; flex: 1; }

.gp-card-header {
    font-size: 0.813rem;
    font-weight: 600;
    color: var(--ink);
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding-bottom: 0.625rem;
    margin-bottom: 0.875rem;
    border-bottom: 1px solid var(--line-soft);
}

.gp-section-card {
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    overflow: hidden;
}

.gp-section-card-header {
    background: var(--bg-3);
    border-bottom: 1px solid var(--line-soft);
    padding: 0.313rem 0.625rem;
    font-size: 0.656rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.038rem;
    color: var(--ink-3);
    text-align: left;
}
.gp-section-card-body {
    padding: 0.625rem;
}
.gp-section-card-body:has(> table) { padding: 0; overflow: hidden; }

/* Full-width card inside a .gp-section-card grid — spans every column whatever the grid's column
   count. Generic, not worker-specific. Any grid rule that sizes .gp-section-card must exclude this
   modifier (see .worker-status-detail-grid), or it wins on specificity and the card stays narrow. */
.gp-section-card-fullrow { grid-column: 1 / -1; }

.gp-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    cursor: default;
}

.role-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.375rem;
    height: 1.375rem;
    border-radius: 0.188rem;
    background: linear-gradient(180deg, var(--bg-3) 0%, var(--bg) 100%);
    border: 1px solid rgba(255,255,255,0.12);
    box-shadow: 0 0.063rem 0 rgba(255,255,255,0.04) inset, 0 0.125rem 0.25rem rgba(0,0,0,0.5);
    flex-shrink: 0;
}
.role-icon[data-role="tank"] { --role-color: #2e68b0; }
.role-icon[data-role="healer"] { --role-color: #1f9c3a; }
.role-icon[data-role="damage"],
.role-icon[data-role="ranged"],
.role-icon[data-role="melee"] { --role-color: #9e2630; }
.role-icon-svg {
    display: block;
    width: 0.875rem;
    height: 0.875rem;
    background-color: var(--role-color, var(--ink-3));
    mask-image: var(--role-icon-url);
    mask-size: 100% 100%;
    -webkit-mask-image: var(--role-icon-url);
    -webkit-mask-size: 100% 100%;
}

.expanded-panel {
    background: var(--bg);
    padding: 1.125rem 1.25rem 1.375rem;
    box-shadow: inset 0 1px 0 rgba(220,230,255,0.08),
                inset 0 0.5rem 1rem -0.625rem rgba(0,0,0,0.5),
                inset 0 -0.5rem 1rem -0.625rem rgba(0,0,0,0.5);
}
.detail-row > td { padding: 0; }
.detail-row .data-table { font-size: 0.75rem; }
.detail-row .data-table tbody tr { background: transparent; }
.detail-row .data-table tbody tr:hover { background-image: none; }
.detail-row .data-table tr td:first-child:not(.col-expand) { padding-left: 1.5rem; }
.detail-panel {
    background: var(--bg);
    padding: 1.125rem 1.25rem 1.375rem;
    color: var(--ink-2);
    font-size: 0.813rem;
    box-shadow: inset 0 1px 0 rgba(220,230,255,0.08),
                inset 0 0.5rem 1rem -0.625rem rgba(0,0,0,0.5),
                inset 0 -0.5rem 1rem -0.625rem rgba(0,0,0,0.5);
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: 0.75rem;
}

/* D2 continuous spine indicator */
tr[data-expandable] .col-expand { position: relative; }
tr[data-expandable] { background: var(--bg-2); cursor: pointer; }

.expand-spine {
    position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
    background: color-mix(in oklab, var(--accent) 35%, var(--bg));
    z-index: 2;
    transition: width 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}
/* .expand-notch {
    position: absolute; left: 2px; top: 50%; transform: translateY(-50%);
    width: 18px; height: 23px; border-radius: 0 8px 8px 0;
    background: var(--bg-3); border: 1px solid var(--line); border-left: 0;
    color: var(--ink-3); z-index: 3;
    transition: left 0.18s ease, border-color 0.16s ease, color 0.16s ease, box-shadow 0.18s ease;
} */
.expand-notch {
    position: absolute; left: 2px; top: 50%; transform: translateY(-50%);
    width: 1.125em; height: 1.4375em; border-radius: 0 8px 8px 0;
    background: var(--bg-3); border: 1px solid var(--line); border-left: 0;
    color: var(--ink-3); z-index: 3;
    transition: left 0.18s ease, border-color 0.16s ease, color 0.16s ease, box-shadow 0.18s ease;
}
/* .expand-notch-glyph {
    position: absolute; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    font-size: 15px; font-weight: 600; line-height: 1;
} */
/* .expand-notch-glyph {
    position: absolute; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    font-size: 0.9375em; font-weight: 600; line-height: 1;
} */
.expand-notch-glyph {
    position: absolute; top: 50%; left: 50%;
    transform: translate(calc(-50% - 1px), -50%);
    font-size: 0.9375em; font-weight: 600; line-height: 1;
}

tr[data-expandable]:hover .expand-spine {
    width: 3px;
    background: linear-gradient(180deg, var(--accent), color-mix(in oklab, var(--accent) 35%, var(--bg)));
    box-shadow: 0 0 14px -2px rgba(43,95,196,0.40);
}
tr[data-expandable]:hover .expand-notch {
    left: 3px;
    border-color: rgba(43,95,196,0.45);
    color: var(--accent-glow);
    box-shadow: 2px 0 12px -4px rgba(43,95,196,0.40);
}
tr[data-expandable][data-expanded] .expand-spine {
    width: 3px; background: var(--accent);
    box-shadow: 0 0 14px -2px rgba(43,95,196,0.40);
}
tr[data-expandable][data-expanded] .expand-notch {
    left: 3px;
    border-color: rgba(43,95,196,0.45); color: var(--accent-glow);
}

.expand-spine-detail { position: relative; }
.expand-spine-detail::before {
    content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
    background: linear-gradient(180deg, var(--accent), color-mix(in oklab, var(--accent) 35%, var(--bg)));
    box-shadow: 0 0 14px -2px rgba(43,95,196,0.40); z-index: 2;
}
.detail-panel.expand-spine-detail { padding-left: 1.375rem; }

.gp-trail {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.781rem;
    margin-bottom: 0.5rem;
}

.gp-trail-link {
    color: var(--ink-3);
    text-decoration: none;
    cursor: pointer;
    transition: color 0.15s;
}

.gp-trail-link:hover { color: var(--ink); }

.gp-trail-sep {
    color: var(--ink-3);
    font-size: 0.625rem;
    user-select: none;
}

.gp-trail-current { color: var(--ink); }

.gp-notice {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    padding: 0.625rem 0.875rem;
    border-radius: var(--r-sm);
    border: 1px solid;
    border-left-width: 0.188rem;
    font-size: 0.813rem;
    margin-bottom: 0.875rem;
}

.gp-notice-bad {
    color: var(--bad);
    border-color: rgba(255,107,107,0.25);
    border-left-color: var(--bad);
    background: rgba(255,107,107,0.05);
    box-shadow: inset 3px 0 8px rgba(255,107,107,0.08);
}

.gp-notice-ok {
    color: var(--ok);
    border-color: rgba(107,212,155,0.3);
    border-left-color: var(--ok);
    background: rgba(107,212,155,0.05);
    box-shadow: inset 3px 0 8px rgba(107,212,155,0.08);
}

.gp-notice-warn {
    color: var(--warn);
    border-color: rgba(255,180,84,0.3);
    border-left-color: var(--warn);
    background: rgba(255,180,84,0.05);
    box-shadow: inset 3px 0 8px rgba(255,180,84,0.08);
}

.gp-notice-info {
    color: var(--accent-2);
    border-color: rgba(90,140,201,0.3);
    border-left-color: var(--accent-2);
    background: rgba(90,140,201,0.05);
    box-shadow: inset 3px 0 8px rgba(90,140,201,0.08);
}

/* SUPERSEDED 2026-08-06 — consolidated into .gp-badge below, together with .role-rank-badge.
   The two were one component written twice: same job, differing only in size and radius. See
   UI/Badges.md.
.gp-tag {
    display: inline-flex;
    align-items: center;
    font-size: 0.75rem;
    padding: 0.188rem 0.563rem;
    border-radius: 0.25rem;
    border: 1px solid;
    font-weight: 500;
}

.gp-tag-neutral  { color: var(--ink-3);  border-color: var(--line);              background: var(--bg-2); }
.gp-tag-ok       { color: #a4e6c2;       border-color: rgba(107,212,155,0.70);   background: rgba(58,142,96,0.1); }
.gp-tag-warn     { color: #ffd27a;       border-color: rgba(255,180,84,0.70);    background: rgba(212,160,60,0.10); }
.gp-tag-bad      { color: var(--bad);    border-color: rgba(255,107,107,0.25);   background: rgba(255,107,107,0.05); }
.gp-tag-info     { color: #9fb4ff;       border-color: rgba(159,180,255,0.50);   background: rgba(43,95,196,0.14); }
*/

/* =====================================================================
   BADGE — the portal's one small bordered chip. See UI/Badges.md.
   ---------------------------------------------------------------------
   Consolidated 2026-08-06 from .gp-tag and .role-rank-badge, which were
   two answers to one question: identical padding, differing only in font
   size and radius. The surviving values are the project's de-facto
   standard measured across ten badge classes — 0.688rem text, 0.188rem
   radius — so this matches the badges around it rather than either
   original exactly.

   Base = neutral. Add a semantic modifier ONLY when the colour means
   something; there is no -neutral modifier because this IS it.

   IT SETS font-weight, text-transform AND letter-spacing DELIBERATELY,
   even though they look like defaults. Without them the badge inherits
   whatever it is placed inside, and dropped into a styled heading it
   would render uppercase, letter-spaced and bold — which is exactly what
   happened on the Manage Team rank headings and needed a container
   reset. Self-contained is what makes it safe to reuse anywhere.
   ===================================================================== */
.gp-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.688rem;
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
    padding: 0.188rem 0.563rem;
    border-radius: 0.188rem;
    border: 1px solid var(--line);
    background: var(--bg-3);
    color: var(--ink-2);
}

/* Semantic colours. Each overrides all three of colour, border and background so a modifier never
   half-applies over the neutral base. */
.gp-badge-ok     { color: #a4e6c2;      border-color: rgba(107,212,155,0.70);   background: rgba(58,142,96,0.1); }
.gp-badge-warn   { color: #ffd27a;      border-color: rgba(255,180,84,0.70);    background: rgba(212,160,60,0.10); }
.gp-badge-bad    { color: var(--bad);   border-color: rgba(255,107,107,0.25);   background: rgba(255,107,107,0.05); }
.gp-badge-info   { color: #9fb4ff;      border-color: rgba(159,180,255,0.50);   background: rgba(43,95,196,0.14); }


/* PROMOTION / HIGHLIGHT — "this one is special", not "this one is good".
   Added 2026-08-06 for the blog Featured badge. THE ONLY MODIFIER BUILT ON THEME TOKENS rather than
   fixed hex, deliberately: the other four name fixed semantic colours that must read the same in
   every palette, while accent IS the palette and follows all seven. Use it when the meaning is
   "singled out"; use -ok when the meaning is "succeeded". */
.gp-badge-accent { color: var(--accent-glow); border-color: var(--accent);      background: transparent; }

/* Wrapping row of badges. Never let badges run inline in prose — they need the gap. */
.gp-badge-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

/* Optional close control INSIDE a badge — removes the link the badge names.
   Read UI/Badges.md before adding one: it is a delete button wearing a small ×, and it belongs only
   on a breakable link, for a viewer permitted to break it, where undoing is cheap.
   line-height: 1 stops the glyph stretching the badge; the badge's own gap does the spacing. */
.gp-badge-close {
    background: none;
    border: none;
    padding: 0;
    color: var(--ink-3);
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1;
}

.gp-badge-close:hover {
    color: var(--ink);
}

.gp-list-active {
    border-left: 2px solid #dce6ff;
    background: linear-gradient(to right, rgba(220,230,255,0.1), rgba(220,230,255,0));
    box-shadow: inset 0 1px 0 rgba(170,200,255,0.22),
                inset -0.063rem 0 0 rgba(170,200,255,0.22),
                inset 0 -0.063rem 0 rgba(170,200,255,0.22);
}

.bis-item-tier {
    display: inline-flex;
    align-items: center;
    font-size: 0.656rem;
    font-weight: 600;
    padding: 0.125rem 0.5rem;
    border-radius: 0.188rem;
    border-width: 1px;
    border-style: solid;
    letter-spacing: 0.025rem;
    flex-shrink: 0;
}

.bis-item-tier-bis      { color: #ffb1b1; border-color: rgba(255,107,107,0.70);  background: rgba(196,68,68,0.1); }
.bis-item-tier-major    { color: #ffd27a; border-color: rgba(255,180,84,0.70);   background: rgba(212,160,60,0.12); }
.bis-item-tier-minor    { color: #a4e6c2; border-color: rgba(107,212,155,0.70);  background: rgba(58,142,96,0.1); }
.bis-item-tier-offspec  { color: #b6bac6; border-color: rgba(122,128,148,0.65);  background: transparent; }
.bis-item-tier-transmog { color: #e8a0df; border-color: rgba(220,120,255,0.70);  background: rgba(186,85,211,0.10); }

.diff-pill {
    font-family: inherit;
    font-size: 0.719rem;
    background: transparent;
    color: var(--ink-3);
    border: 1px solid var(--line-soft);
    border-radius: 0.25rem;
    padding: 0.25rem 0.625rem;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    transition: all 0.15s;
}
.diff-pill:hover { color: var(--ink); }

.diff-pill-normal.on  { color: #1EFF00; background: rgba(30,255,0,0.10);    border-color: rgba(30,255,0,0.45);    box-shadow: 0 0 10px rgba(30,255,0,0.20); }
.diff-pill-heroic.on  { color: #0070DD; background: rgba(0,112,221,0.12);   border-color: rgba(0,112,221,0.45);   box-shadow: 0 0 10px rgba(0,112,221,0.25); }
.diff-pill-mythic.on  { color: #d6a8ff; background: rgba(163,53,238,0.18);  border-color: rgba(163,53,238,0.50);  box-shadow: 0 0 10px rgba(163,53,238,0.25); }
.diff-pill-unknown.on { color: #9D9D9D; background: rgba(157,157,157,0.10); border-color: rgba(157,157,157,0.40); }

.bis-item {
    border-radius: 0 var(--r-sm) var(--r-sm) 0;
    border-left: 0.188rem solid var(--line-soft);
    position: relative;
    overflow: visible;
}

.bis-item-added     { border-left-color: #4ade80; }
.bis-item-changed   { border-left-color: #ffb454; }
.bis-item-removed   { border-left-color: #ff6b6b; opacity: 0.78; }
.bis-item-unchanged { border-left-color: #5a8cc9; }

.bis-item-added::before,
.bis-item-changed::before,
.bis-item-removed::before,
.bis-item-unchanged::before {
    content: '';
    position: absolute;
    top: 0; bottom: 0;
    left: -0.875rem;
    width: 0.875rem;
    pointer-events: none;
}
.bis-item-added::before     { background: linear-gradient(to left, rgba(74,222,128,0.28),  transparent); }
.bis-item-changed::before   { background: linear-gradient(to left, rgba(255,180,84,0.28),  transparent); }
.bis-item-removed::before   { background: linear-gradient(to left, rgba(255,107,107,0.28), transparent); }
.bis-item-unchanged::before { background: linear-gradient(to left, rgba(90,140,201,0.28),  transparent); }

.key-colour-ok  { color: #FFFFFF; }
.key-colour-bad { color: #ff6b6b; }

.dashboard-changelog-card { font-size: 0.813rem; display: flex; flex-direction: column; }
/* .gp-card-footer-padded { display: flex; justify-content: flex-end; margin-top: auto; margin-left: -1.125rem; margin-right: -1.125rem; padding: 0.5625rem 1.125rem 0; border-top: 1px solid var(--line); } */
/* .gp-card-footer-padded { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: auto; margin-left: -1.125rem; margin-right: -1.125rem; padding: 0.5625rem 1.125rem 0; border-top: 1px solid var(--line); } */
.gp-card-footer-padded { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.75rem; margin-left: -1.125rem; margin-right: -1.125rem; padding: 0.5625rem 1.125rem 0; border-top: 1px solid var(--line); }
/* .gp-card-footer { display: flex; justify-content: flex-end; margin-top: auto; padding: 0.5625rem 1.125rem 1.125rem; border-top: 1px solid var(--line); } */
.gp-card-footer { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: auto; padding: 0.5625rem 1.125rem 1.125rem; border-top: 1px solid var(--line); }
.changelog-summary-list { list-style: none; padding: 0; margin: 0; }
.changelog-summary-date-heading { font-size: 0.688rem; font-weight: 600; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.05rem; padding: 0.5rem 0 0.125rem; border-top: 1px solid var(--line-soft); margin-top: 0.25rem; }
.changelog-summary-date-heading:first-child { border-top: none; margin-top: 0; padding-top: 0; }

.changelog-summary-item { display: flex; align-items: baseline; gap: 0.375rem; padding: 0.188rem 0; }

.changelog-entry-date { color: var(--ink-3); opacity: 0.65; }
.changelog-list { display: flex; flex-direction: column; gap: 0.75rem; }

.changelog-category-badge {
    display: inline-block;
    font-size: 0.625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.038rem;
    padding: 0.063rem 0.375rem;
    border-radius: 0.188rem;
    border: 1px solid;
    flex-shrink: 0;
    vertical-align: middle;
}
.changelog-category-0 { color: #6ecc8e; border-color: rgba(110,204,142,0.4); background: rgba(110,204,142,0.08); }
.changelog-category-1 { color: #7ab4e8; border-color: rgba(122,180,232,0.4); background: rgba(122,180,232,0.08); }
.changelog-category-2 { color: #e8a07a; border-color: rgba(232,160,122,0.4); background: rgba(232,160,122,0.08); }
.changelog-category-3 { color: var(--ink-3); border-color: var(--line); background: transparent; }
.changelog-category-4 { color: #e8d07a; border-color: rgba(232,208,122,0.4); background: rgba(232,208,122,0.08); }
.changelog-day-header { margin-bottom: 0.4rem; }
.changelog-category-heading { font-size: 0.75rem; font-weight: 600; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.031rem; margin: 0.375rem 0 0.125rem; }
.changelog-pagination {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 1.25rem;
}
.changelog-pagination-label { font-size: 0.813rem; color: var(--ink-3); }
.changelog-pagination-disabled { opacity: 0.35; pointer-events: none; cursor: default; }

.changelog-entry + .changelog-entry { margin-top: 0.2rem; }
.changelog-entry summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: 0.35rem; user-select: none; }
.changelog-entry summary::-webkit-details-marker { display: none; }

.changelog-entry-title { font-weight: 400; font-size: 0.875rem; margin: 0; color: var(--ink-3); }
.changelog-entry-chevron { color: var(--ink-3); opacity: 0.5; flex-shrink: 0; transition: transform 0.15s; font-size: 0.75rem; }
details[open].changelog-entry .changelog-entry-chevron { transform: rotate(90deg); }

.changelog-entry-body { margin-top: 0.2rem; padding-left: 1rem; font-size: 0.8rem; color: var(--ink-3); opacity: 0.75; }

/* SUPERSEDED 2026-10-01 (Session 239): the Notifications card is a compact data table now, and its
   empty state is .dash-card-empty (pages/dashboard.css). Nothing else used these.
.dash-notif-empty { margin: 0; }

.dash-notif-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.dash-notif-item {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.375rem 0.5rem;
    border-radius: 0.25rem;
    font-size: 0.813rem;
    background: var(--bg-2);
}
*/

.dash-notif-badge {
    display: inline-flex;
    align-items: center;
    font-size: 0.625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05rem;
    padding: 0.125rem 0.375rem;
    border-radius: 0.25rem;
    flex-shrink: 0;
    white-space: nowrap;
}

.dash-notif-badge-player {
    background: var(--bg-3);
    color: var(--ink-3);
}

.dash-notif-badge-rl {
    background: color-mix(in srgb, var(--accent-2) 15%, transparent);
    color: var(--accent-2);
}

/* MOVED to wwwroot/css/pages/messages.css 2026-08-19 (Session 202). The three modifiers are used by
   Views\Messages\Index.cshtml alone, so they belong to that page; the .dash-notif-badge base above
   stays here because the dashboard's Notifications card uses it too. RosterChange joins the system
   rule's selector there rather than getting a fourth colour. */
/*.dash-msg-badge-system {
    background: color-mix(in srgb, var(--accent-2) 15%, transparent);
    color: var(--accent-2);
}
.dash-msg-badge-feedback {
    background: color-mix(in srgb, var(--warn) 15%, transparent);
    color: var(--warn);
}
.dash-msg-badge-personal {
    background: var(--bg-3);
    color: var(--ink-3);
}*/

/* SUPERSEDED 2026-10-01 (Session 239) with the list above. The declined colour moved to
   pages/dashboard.css as .dash-notif-declined .dash-notif-text.
.dash-notif-message { flex: 1; font-size: 0.813rem; }
.dash-notif-declined .dash-notif-message { color: var(--bad); }
.dash-notif-link { margin-left: auto; }
*/

.dash-pending-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.dash-pending-item {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    font-size: 0.813rem;
}

.dash-pending-count {
    font-weight: 700;
    font-size: 1rem;
    color: var(--accent);
    min-width: 1.5rem;
    text-align: right;
}

.dash-pending-team { flex: 1; }

.raider-view-layout { display: flex; align-items: flex-start; gap: 1rem; }

.raider-view-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1rem; }
.raider-view-announcement { font-size: 0.875rem; color: var(--ink-2); }
/* .raider-view-announcement-body { white-space: pre-wrap; } — added 2026-08-06 for the plain-text stopgap and
   removed the same day. The renderer emits explicit <br /> and the container now carries .gp-richtext,
   whose rules live in rich-text.css. No consumer remains. */
/* RaiderView's table (.raider-static-table, .raider-player-th / -cell, .raider-status-cell, .raider-table-scroll,
   .raider-col-th) MOVED to css/pages/roster-raider-view.css 2026-09-29 (Session 234), with the arrow scrolling
   replaced by native overflow. */
/* Roster status colour coding (.raider-status-*, .col-status.raider-status-*) moved to css/shared/roster.css */

/* .raider-table-nav MOVED to css/pages/group-roster.css 2026-09-29 and renamed .grp-roster-table-nav — the
   roster page group's file, linked by Manage and RaiderView only (Conventions.md 5.4). */

.roster-last-updated {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.75rem;
    color: var(--ink-3);
}

/* .gp-card-table-head { padding: 0.75rem 1rem 0.5rem; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; } */
/* .gp-card-table-head > div > h2 { margin-bottom: 0.125rem; } */
/* .gp-card-table-head > div > .roster-last-updated { margin-bottom: 0; } */
.gp-card-header-padded { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-left: -1.125rem; margin-right: -1.125rem; padding-left: 1.125rem; padding-right: 1.125rem; padding-bottom: 0.5rem; margin-bottom: 0.75rem; border-bottom: 1px solid var(--line); }
.gp-card-header-padded h2 { margin-bottom: 0; }
.gp-card-header-padded > div > h2 { margin-bottom: 0.125rem; }
.gp-card-header-padded > div > .roster-last-updated { margin-bottom: 0; }
.gp-card-header-compact { padding: 1.125rem 1.125rem 0.5rem; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.gp-card-header-controls { display: flex; align-items: center; gap: 0.5rem; }
.gp-card-header-compact > div > h2 { margin-bottom: 0.125rem; }
.gp-card-header-compact > div > .roster-last-updated { margin-bottom: 0; }
/*.dash-roster-empty { color: var(--ink-3); font-size: 0.813rem; padding: 0.75rem 1rem; margin: 0; }*/
/* .dash-card-empty MOVED to css/pages/dashboard.css 2026-08-23 (Session 206), with a new border-top for the missing header divider. */
tr[data-expandable] td.col-status,
tr[data-expandable] td.col-date { font-weight: 600; }
/*.dash-roster-footer { padding: 0.375rem 1rem 0.75rem; display: flex; justify-content: flex-end; }*/
/*.dash-roster-table { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }*/
/*table.data-table.dash-roster-table { margin-bottom: 0.75rem; }*/
/*.data-table tr.dash-roster-date-row { border-bottom: 1px solid var(--line); }*/
/*.data-table tr.dash-roster-date-row { cursor: pointer; }*/
/*.data-table tr.dash-roster-date-row td { padding: 0; font-size: 0.75rem; line-height: 1.3; } [old — padding:0 blocked compact row padding on col-expand cell]*/
/*.data-table tr.dash-roster-date-row td:not(.col-expand) { padding: 0; font-size: 0.75rem; line-height: 1.3; }*/
/*.data-table tr.dash-roster-col-row td { padding: 0.188rem 1rem; font-size: 0.75rem; line-height: 1.3; color: var(--ink-3); }*/
/*.dash-roster-date-cell { display: flex; align-items: center; padding: 0.188rem 0.25rem 0.188rem 1rem; width: 100%; }*/
/*.dash-roster-date-ann { width: 1px; white-space: nowrap; vertical-align: middle; }*/
/*.data-table tr.dash-roster-date-row td.dash-roster-date-ann { padding: 0.188rem 0.25rem; text-align: center; }*/
/*.dash-roster-ann-wrap { display: inline-flex; }*/
/*.dash-roster-ann-icon { display: block; width: 0.75rem; height: 0.75rem; background-color: var(--bad); -webkit-mask-image: url('/img/announcement.svg'); mask-image: url('/img/announcement.svg'); -webkit-mask-size: contain; mask-size: contain; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; }*/
/*.dash-roster-date-cell a { color: var(--ink); text-decoration: none; }*/
/*.dash-roster-date-cell a:hover { color: var(--accent-glow); }*/
/*.dash-roster-date-cell .js-dash-roster-time { color: var(--ink-3); margin-left: auto; }*/
/*.data-table tr.dash-roster-col-row { background: var(--bg); border-top: none; }*/

/*.data-table tr.dash-roster-col-row .dash-roster-col-label { padding-left: 1.5rem; }*/
/*.data-table tr.dash-roster-col-row .dash-roster-col-char { font-weight: 600; white-space: nowrap; }*/
/*.data-table tr.dash-roster-col-row .dash-roster-col-role { width: 1px; white-space: nowrap; font-size: 0; line-height: 0; }*/
/*.data-table tr.dash-roster-col-row td.dash-roster-col-role { padding: 0.188rem 0.25rem; text-align: center; }*/
/*.data-table tr.dash-roster-col-row .role-icon { width: 1.2rem; height: 1.2rem; }*/
/*.data-table tr.dash-roster-col-row .role-icon-svg { width: 0.9rem; height: 0.9rem; }*/
/*.data-table tr.dash-roster-col-row td.raider-status-1 { color: var(--ok); text-align: right; padding-right: 0.25rem; }*/
/*.data-table tr.dash-roster-col-row td.raider-status-1 { text-align: right; padding-right: 0.25rem; }*/
/*.data-table tr.dash-roster-col-row td.raider-status-2 { color: #f87171; text-align: right; padding-right: 0.25rem; }*/
/*.data-table tr.dash-roster-col-row td.raider-status-2 { text-align: right; padding-right: 0.25rem; }*/
/*.data-table tr.dash-roster-col-row td.raider-status-3 { color: #f59e0b; text-align: right; padding-right: 0.25rem; }*/
/*.data-table tr.dash-roster-col-row td.raider-status-3 { text-align: right; padding-right: 0.25rem; }*/
/*.data-table tr.dash-roster-col-row td.raider-status-0 { color: var(--ink-3); text-align: right; padding-right: 0.25rem; }*/
/*.data-table tr.dash-roster-col-row td.raider-status-0 { text-align: right; padding-right: 0.25rem; }*/

.dash-team-carousel { display: flex; flex-direction: column; gap: 0.5rem; }
.dash-team-subtitle { font-size: 0.75rem; color: var(--ink-3); margin: 0 0 0.375rem; }
/* Carousel styles (.carousel-*) MOVED to css/shared/carousel.css 2026-08-23 (Session 206) — used by Views/Home/Index.cshtml as well as the dashboard, so shared/ rather than a page file. */

.trials-carousel-controls { margin-bottom: 0.375rem; }
.trials-slide { display: none; }
.trials-slide.active { display: flex; flex-direction: column; }
.trials-team-name { font-size: 0.8rem; margin: 0 0 0.375rem; }
.trials-table thead th { padding: 0.188rem 0.5rem; font-size: 0.688rem; line-height: 1.3; }
.trials-table td { padding: 0.125rem 0.5rem; font-size: 0.75rem; line-height: 1.3; }
.gp-card-trials { overflow: hidden; }
.gp-card-trials > h2 { margin-bottom: 0.125rem; }
.gp-card-trials .trials-table { margin-left: -1.125rem; margin-right: -1.125rem; width: calc(100% + 2.25rem); margin-bottom: 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.gp-card-trials .trials-table thead th:first-child,
.gp-card-trials .trials-table td:first-child { padding-left: 1.125rem; }
.gp-card-trials .trials-table thead th:last-child,
.gp-card-trials .trials-table td:last-child { padding-right: 1.125rem; }
.trials-card-subhead { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.5rem; }
.trials-card-subhead .roster-last-updated { margin: 0; }
/* .trials-card-subhead .btn { font-size: 0.688rem; padding: 0.313rem 0.563rem; color: var(--ink-3); border-color: var(--line-soft); box-shadow: none; } */
/* .trials-card-subhead .btn:hover { color: var(--ink-2); border-color: var(--line); } */
.dash-trials-update-status { font-size: 0.75rem; }
.dash-no-access-notice { margin-bottom: 0; }

/* .gp-card-signups MOVED to css/global.css 2026-08-23 (Session 206) — gp- prefixed, plus a scoped footer margin-top:auto. */
.signups-subhead-controls { display: flex; align-items: center; gap: 0.375rem; }

.signups-btn { font-size: 0.688rem; padding: 0.313rem 0.563rem; color: var(--ink-3); border-color: var(--line-soft); box-shadow: none; }
.signups-btn:hover { color: var(--ink-2); border-color: var(--line); }
/* .raider-signup-status-area { margin-top: 0.5rem; } */
/* .raider-signup-status-area { margin-top: 0.5rem; padding-bottom: 0.5rem; } */
/* SPACING REMOVED 2026-08-23 (Session 206). The margin and padding existed to hold the status LIST
   off the header and the footer inside a padded card. The area now holds a TABLE in a
   gp-card-table, where the table is meant to reach the card's edges and the blocks either side
   already carry their own padding — gp-card-header-compact below itself, .raider-signups-footer
   above itself. Keeping either value would have inset the table from exactly the edges the card
   type exists to let it reach (UI/Cards.md). The element stays: it is the AJAX paint target. */
/* .raider-signups-footer { display: flex; align-items: center; margin: auto -1.125rem 0; padding: 0.5rem 1.125rem 0; border-top: 1px solid var(--line); } */
/* THE NEGATIVE SIDE MARGINS WENT WITH gp-card-padded — 2026-08-23 (Session 206). The card became
   gp-card-table so its table can reach both edges (UI/Cards.md: content wins), which zeroes the
   card's padding — so a footer bleeding -1.125rem sideways to cancel that padding would now hang
   OUTSIDE the card. It carries its own padding instead, including the bottom padding the card no
   longer supplies, exactly as .gp-card-footer does for every other table card. */
/* .raider-signups-footer { display: flex; align-items: center; margin: auto 0 0; padding: 0.5rem 1.125rem 1.125rem; border-top: 1px solid var(--line); } */
/* REPLACED BY .gp-card-footer 2026-08-23 (Session 206). Once the card became a gp-card-table this
   rule was re-deriving, line for line, what the documented footer for that card type already
   provides: the top border, the edge-to-edge padding including a table card's missing bottom
   padding, and margin-top:auto to sit on the card's bottom edge (UI/Cards.md). A private class
   restating a standard is the Directive 18 defect, so the markup uses .gp-card-footer and this
   rule is gone. .raider-signups-footer-spacer stays — it is what keeps the settings LEFT inside a
   justify-content: flex-end footer, by absorbing the free space that property would distribute. */
/* Non-table blocks in a table card carry their own padding (UI/Cards.md). .signups-empty is the
   loading placeholder and the two empty states; scoped so the Team Signups card, which is still
   gp-card-padded and inherits its inset, is untouched. */
.gp-card-table .signups-empty { padding: 0.75rem 1.125rem; }
/* The settings cogwheel (.raider-signups-settings-btn / -icon and its hover, active and edit-mode rules) was REMOVED 2026-08-23 (Session 206) with the fold it opened. /img/settings.svg went with it — it had no other consumer. */
/* .icon-btn:disabled { opacity: 0.4; cursor: not-allowed; } */
.raider-signups-footer-spacer { flex: 1; }
/* .raider-signups-source-toggle { display: none; border: 1px solid var(--line); border-radius: 0.25rem; overflow: hidden; } */
/* .raider-signups-source-toggle { display: none; } and its .settings-open reveal REMOVED 2026-08-23 (Session 206): the settings are no longer folded, so the toggle is visible by default. IT IS STILL HIDDEN FOR A RESTRICTED ACCOUNT by applySignupSettings' inline style — that is SU11 and a separate rule from the fold. */
.raider-signups-source-toggle { display: inline-flex; }
/* .raider-signups-toggle-btn { background: none; border: none; padding: 0.2rem 0.5rem; font-size: 0.75rem; color: var(--ink-3); cursor: pointer; } */
.raider-signups-toggle-btn { padding: 0.2rem 0.5rem; font-size: 0.75rem; color: var(--ink-3); }
/* .raider-signups-toggle-btn.active { background-color: var(--accent); color: var(--ink); } */
/* .raider-signups-toggle-btn.btn-active { background-color: var(--accent); color: var(--ink); } [old — flat blue; replaced by standard .btn-active gradient/glow] */
/* .raider-signups-toggle-btn:not(.active):hover { background-color: var(--bg-3); } */
.raider-signups-toggle-btn:not(.btn-active):hover { background-color: var(--bg-3); }
/* .raider-signups-auto-wrap { display: inline-flex; align-items: center; gap: 0.375rem; margin-left: 0.5rem; } */
/* margin-left dropped 2026-08-23: .gp-card-footer sets gap: 0.5rem, so the margin doubled the
   separation from the GoW/Local toggle beside it. */
.raider-signups-auto-wrap { display: inline-flex; align-items: center; gap: 0.375rem; }
/* the .settings-open reveal for .raider-signups-auto-wrap went with the fold, 2026-08-23 */
.raider-signups-auto-label { font-size: 0.75rem; color: var(--ink-3); }
/* The rotation preference pill beside Auto (2026-10-03). The wrapper is the tooltip trigger; the pill
   inside a flex footer would otherwise span it (UI/TogglePill.md "Placing a pill inside a flex
   container"), hence flex: 0 0 auto on both. The focus ring has an offset (UI/Tooltips.md). */
.raider-signups-rotation-wrap { display: inline-flex; align-items: center; flex: 0 0 auto; border-radius: 999px; }
.raider-signups-rotation-wrap .toggle-pill { flex: 0 0 auto; }
.raider-signups-rotation-wrap:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.raider-signups-auto-btn { position: relative; width: 2rem; height: 1rem; padding: 0; border: 1px solid var(--line); border-radius: 0.5rem; background: var(--bg-3); cursor: pointer; box-sizing: border-box; }
.raider-signups-auto-btn::after { content: ''; position: absolute; width: 0.625rem; height: 0.625rem; border-radius: 50%; background: var(--ink-3); top: 50%; left: 0.125rem; transform: translateY(-50%); transition: left 0.15s, background 0.15s; }
.raider-signups-auto-btn.active { background: var(--accent); border-color: var(--accent); }
.raider-signups-auto-btn.active::after { left: calc(2rem - 0.625rem - 0.125rem - 2px); background: var(--ink); }
.raider-signups-auto-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.raider-signups-edit-controls { display: flex; align-items: center; }
/* .settings-open and .edit-mode rules for the edit/save controls REMOVED 2026-08-23 (Session 206): nothing batches now, so there is no edit mode and no fold to hide them for. */
/* The My Signups card's LIST rules were REMOVED 2026-08-23 (Session 206) when the card became a TABLE: .raider-signup-row, .raider-signup-player and the whole .raider-signup-edit-* family (row/main/status/note) plus .raider-signup-note-counter, which belonged to the deleted batch edit form. Each was checked for other consumers first. The table's cells come from .data-table; the inline note editor's rules live in pages/dashboard.css. .raider-signup-status-text and .raider-signup-note SURVIVE — both still render on a GoW-owned row, which is read-only. */
.raider-signup-status-text { font-size: 0.75rem; color: var(--ink-3); }
/* .raider-signup-note MOVED to css/pages/dashboard.css 2026-08-23 (Session 206), where it gained a border and margin. */

.dash-signups-update-status { font-size: 0.75rem; color: var(--ink-3); line-height: 1; }

.signups-empty { font-size: 0.813rem; margin: 0; }
.signups-columns { display: flex; gap: 0.5rem; }
.signups-col { flex: 1; min-width: 0; }
.signups-col-title { font-size: 0.688rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.038rem; margin-bottom: 0.25rem; }
/* .signups-col-declined { color: #ff6b6b; } */
/* .signups-col-tentative { color: #ffd27a; } */
/* .signups-col-pending { color: #7aaeff; } */
/* Promoted to global status theme vars (Session 164): declined #ff6b6b -> --bad, tentative #ffd27a -> --warn (unified amber), pending #7aaeff -> --info. Mirrors roster D2 mapping. */
.signups-col-declined { color: var(--bad); }
.signups-col-tentative { color: var(--warn); }
.signups-col-pending { color: var(--info); }
.signups-col-empty { font-size: 0.75rem; }

.signups-player { display: flex; align-items: center; gap: 0.25rem; font-size: 0.75rem; line-height: 1.5; white-space: nowrap; }
/* .signups-player-dim { color: #ff6b6b; cursor: default; } */
/* Promoted (Session 164): declined-red #ff6b6b -> --bad (same status red as .signups-col-declined). */
.signups-player-dim { color: var(--bad); cursor: default; }
.signups-gow-badge { height: 0.875rem; width: auto; flex-shrink: 0; }
.signups-player[draggable="true"] { cursor: grab; }
.signups-player.is-dragging { opacity: 0.4; cursor: grabbing; }
.signups-column.is-drag-over { background: color-mix(in srgb, var(--accent) 10%, transparent); border-radius: var(--r-sm); }
.signups-more { font-size: 0.75rem; color: var(--ink-3); margin-top: 0.125rem; }

.signups-note-wrap { display: inline-flex; align-items: flex-end; position: relative; margin-left: 0.25rem; vertical-align: text-bottom; padding-bottom: 0.125rem; }

.signups-note-icon { display: inline-block; width: 0.75rem; height: 0.75rem; background-color: var(--ink-3); -webkit-mask: url('/img/note.svg') no-repeat center / contain; mask: url('/img/note.svg') no-repeat center / contain; cursor: default; }
.signups-note-wrap:hover .signups-note-icon { background-color: var(--ink-2); }
.signups-note-tooltip { display: none; position: absolute; bottom: calc(100% + 0.25rem); right: 0; min-width: 8rem; max-width: 14rem; background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 0.375rem 0.5rem; font-size: 0.75rem; color: var(--ink-2); white-space: normal; word-break: break-word; z-index: 200; box-shadow: var(--sh-pop); pointer-events: none; }
.signups-note-wrap:hover .signups-note-tooltip { display: block; }
.signups-column { flex: 1; min-width: 0; }

.signups-column-head { font-size: 0.688rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.038rem; color: var(--ink-2); margin-bottom: 0.375rem; }

.signups-column-head--accepted { color: var(--ok); }
/* .signups-column-head--tentative { color: #ffd27a; } */
/* .signups-column-head--declined { color: #ff6b6b; } */
/* .signups-column-head--pending { color: #7aaeff; } */
/* Promoted to global status theme vars (Session 164): tentative -> --warn, declined -> --bad, pending -> --info. Accepted already used --ok. */
.signups-column-head--tentative { color: var(--warn); }
.signups-column-head--declined { color: var(--bad); }
.signups-column-head--pending { color: var(--info); }

.dash-grid {
    display: grid;

    grid-template-columns: repeat(6, 1fr);
    gap: 1rem;
    align-items: start;
    font-size: 0.875rem;
}
.dash-grid .span-2 { grid-column: span 2; }
.dash-grid .span-3 { grid-column: span 3; }
.dash-grid .span-4 { grid-column: span 4; }
.dash-grid .span-6 { grid-column: span 6; }
.dash-section-label {
    grid-column: 1 / -1;
    font-size: 0.688rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.075rem;
    color: var(--ink-3);
    padding-top: 0.75rem;
    border-top: 1px solid var(--line);
}
.dash-section-label:first-child {
    border-top: none;
    padding-top: 0;
}

.nav-logo-img {
    height: 1.5rem;
    width: auto;
    flex-shrink: 0;
}

.gp-table-wide-label {
    table-layout: fixed;
}
/* Follows the .profile-label -> .gp-label-cell rename of 2026-09-06 (Session 218). This
   rule is Guild Setup's, which is the evidence that the old name was wrong.
.gp-table-wide-label .profile-label {
    width: 20rem;
    vertical-align: top;
    padding-top: 1rem;
} */
.gp-table-wide-label .gp-label-cell {
    width: 20rem;
    vertical-align: top;
    padding-top: 1rem;
}
.gp-table-wide-label td:last-child {
    text-align: left;
    white-space: normal;
    vertical-align: middle;
}

.gp-field-desc {
    font-size: 0.719rem;
    margin-top: 0.25rem;
    max-width: 22rem;
}

.meta-field-value { margin-right: 0.5rem; }

.meta-field-error {
    font-size: 0.75rem;
    color: var(--bad);
    margin-left: 0.5rem;
}

.meta-field-status {
    font-size: 0.75rem;
    color: var(--ink-3);
    margin-left: 0.75rem;
}

.meta-desc-textarea {
    width: 100%;
    min-height: 4rem;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: 0.25rem;
    color: var(--ink);
    font-size: 0.813rem;
    padding: 0.375rem 0.5rem;
    resize: vertical;
}

.meta-desc-counter {
    font-size: 0.688rem;
    color: var(--ink-3);
    display: block;
    text-align: right;
    margin-top: 0.125rem;
}

.gp-section-title {
    font-size: 1rem;
    font-weight: 600;
    color: var(--ink);
    margin: 1.5rem 0 0.75rem;
}

.site-logo-upload-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
    align-items: start;
    margin-bottom: 1.5rem;
}

.site-logo-card {
    padding: 1.125rem;
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
}

.site-logo-card-label {
    font-weight: 600;
    font-size: 0.875rem;
    color: var(--ink);
}

.site-logo-card-desc {
    font-size: 0.75rem;
    margin: 0;
}

.site-logo-dropzone {
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px dashed var(--line);
    border-radius: 0.25rem;
    padding: 1.25rem 1.5rem;
    background: var(--bg-2);
    cursor: default;
    transition: border-color 0.15s, background 0.15s;
}

.site-logo-dropzone.dragover {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 8%, transparent);
}

.site-logo-dropzone-text {
    font-size: 0.813rem;
    color: var(--accent);
    pointer-events: none;
}

.site-logo-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px dashed var(--line);
    border-radius: 0.5rem;
    width: 7.5rem;
    height: 5rem;
    background: var(--bg);
    flex-shrink: 0;
}

.site-logo-placeholder-text {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.813rem;
    color: var(--ink-3);
    pointer-events: none;
    letter-spacing: 0.05rem;
}

.site-logo-preview-wrap {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.site-logo-preview {
    max-height: 3.5rem;
    max-width: 8rem;
    width: auto;
    border-radius: 0.25rem;
    border: 1px solid var(--line);
}

.site-logo-error {
    font-size: 0.75rem;
    color: var(--bad);
    min-height: 1rem;
    margin: 0;
}

.site-logo-browser-toggle {
    align-self: flex-start;
}

.site-logo-browser-panel {
    display: none;
    border-top: 1px solid var(--line-soft);
    padding-top: 0.625rem;
}

.site-logo-browser-panel.site-logo-browser-visible {
    display: block;
}

.site-logo-browser-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.site-logo-browser-empty {
    font-size: 0.75rem;
    color: var(--ink-3);
}

.site-logo-thumb {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    padding: 0.375rem;
    border: 1px solid var(--line-soft);
    border-radius: 0.25rem;
    cursor: pointer;
    transition: border-color 0.12s;
    width: 5rem;
}

.site-logo-thumb:hover { border-color: var(--accent); }

.site-logo-thumb.incompatible {
    opacity: 0.4;
    cursor: default;
}
.site-logo-thumb.incompatible:hover { border-color: var(--line-soft); }

.site-logo-thumb img {
    width: 3rem;
    height: 3rem;
    object-fit: contain;
}

.site-logo-thumb-name {
    font-size: 0.563rem;
    color: var(--ink-3);
    word-break: break-all;
    text-align: center;
    max-width: 4.25rem;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.site-logo-thumb-delete {
    position: absolute;
    top: 0.125rem;
    right: 0.125rem;
    width: 1rem;
    height: 1rem;
    padding: 0;
    font-size: 0.625rem;
    line-height: 1;
    background: var(--bg-3);
    border: 1px solid var(--line-soft);
    border-radius: 0.125rem;
    cursor: pointer;
    color: var(--ink-3);
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.12s;
}

.site-logo-thumb:hover .site-logo-thumb-delete { opacity: 1; }

.trials-team-group { margin-bottom: 2rem; }
.trials-team-heading { font-size: 1.125rem; margin-bottom: 0.5rem; }
.trials-empty { padding: 0.5rem 0; }
.trials-actions { white-space: nowrap; }

/* The subrow's cards sat flush against each other. SCOPED TO THIS PAGE ON PURPOSE: .detail-panel's
   own gap is shared by every expandable row in the portal, and changing it there would move
   GuildRoles, TeamRanks and Feedback to suit one page. 1.125rem matches the panel's own padding.

   THE SELECTOR IS CHAINED TO MATCH `.gp-card-table .detail-row .detail-panel { gap: 0 }` (site.css,
   near the top), which is (0,3,0) and ZEROES the panel's own 0.75rem inside any table card — this
   subrow is inside one. A plain `.trials-character-detail .detail-panel` rule is (0,2,0) and LOSES
   to it, which is why the first attempt changed nothing at all: not a stale stylesheet, an
   outranked one. survey-results.css hit the same rule and solved it the same way. */
/* .trials-character-detail .detail-panel { gap: 1.125rem; } */
.gp-card-table .detail-row.trials-character-detail .detail-panel { gap: 1.125rem; }

/* The attendance card's two value columns (Season, Trial). LAYOUT ONLY — the numbers' size, the
   label styling and the table's borders all come from .gp-kv-table.
   Chained through .gp-kv-table to outrank its own `td:last-child { text-align: left }`, which is
   (0,2,1) and would otherwise win over a plainer selector and leave the Trial column adrift from
   its header. */
/* .gp-kv-table.trials-attendance-kv td:not(:first-child) {
    text-align: right;
    padding-left: 0.875rem;
} */
/* The Extensions card beside it right-aligns its value column the same way (2026-09-17) — one grouped
   rule, not a copy, so the two cards in the same subrow cannot drift apart. */
.gp-kv-table.trials-attendance-kv td:not(:first-child),
.gp-kv-table.trials-extensions-kv td:not(:first-child) {
    text-align: right;
    padding-left: 0.875rem;
}
/*.trials-row-expired { background: rgba(255,107,107,0.06); }*/
/*.trials-row-expired { background: rgba(255,107,107,0.09); box-shadow: inset 0 0 0 1px rgba(255,107,107,0.28); }*/
/*.trials-row-expired td { background: rgba(255,107,107,0.08); box-shadow: inset 0 0 10px rgba(255,107,107,0.22); }*/
/*.data-row-attention { background: rgba(255,107,107,0.06); }*/
.data-row-attention td { background: rgba(255,107,107,0.06); }
.data-cell-attention { background: rgba(255,107,107,0.06); }
.data-cell-warn { background: rgba(255,180,84,0.06); }
.trials-expires-expired { color: #ff6b6b; font-weight: 600; }
.rank-time-limit-label { display: inline-flex; align-items: center; gap: 0.25rem; font-size: 0.875rem; cursor: pointer; }

/* Attendance-card styles (.att-*) MOVED to css/pages/dashboard.css 2026-08-23 (Session 206). The Attendance PAGE has its own unrelated .att-* classes in pages/attendance.css. */

/* ROSTER PAGES: MOVED OUT OF site.css 2026-09-29 (Sessions 234 and 235). Now in:
     pages/roster-manage.css       the Manage page: its table, the page toolbar, the layout settings panel,
                                   .roster-layout and #rosterSidebar, the raid list's empty-roster marker, edit
                                   controls and delete button, the status / role pickers, the announcement editor
     pages/roster-raider-view.css  RaiderView: its table, .roster-list-date / .roster-list-time
     pages/group-roster.css        both: the table nav bar, width toggle, body.layout-full-width, and
                                   .grp-roster-page-head / .grp-roster-sidebar-toggle (were .roster-page-head /
                                   .roster-sidebar-toggle)
   WHAT STAYS BELOW is used by a page OUTSIDE the roster group, and is left for review rather than moved
   (ToDo): .roster-boss-group-title (Attendance), .roster-sidebar* (Character, Loot Distribution, Account
   page), .roster-list-info (Character), .roster-publish-icon / .roster-trash-icon (Tactics),
   .roster-announcement-display-compact (dashboard only). */

/* SUPERSEDED 2026-09-29 (Session 235): no markup or script uses any of these. The subhead, date picker
   and slot select went with the GoW flow and date-based roster creation (Session 193); .roster-gow-group,
   .roster-published-badge and .roster-list-actions had no consumer; .roster-nav-col-left / -right were the
   column-arrow cells, gone in Session 234. The announcement editor's h2/h3/ul/ol/li rules were overridden
   in full by .gp-richtext (rich-text.css) and quill.snow.css, so they styled nothing.
.roster-toolbar-subhead { display: flex; align-items: center; gap: 0.5rem; }
.roster-gow-group { display: inline-flex; align-items: stretch; transition: box-shadow 0.2s; border-radius: var(--r-sm); }
.roster-datepicker { }
.roster-schedule-select { min-width: 9rem; }
.roster-list-actions { display: flex; align-items: center; gap: 0.25rem; flex-shrink: 0; }
.roster-published-badge { font-size: 0.656rem; color: var(--ok); font-weight: 600; white-space: nowrap; }
.roster-nav-col-left {
    position: sticky;
    left: 0;
    z-index: 10;
    width: 2.25rem;
    min-width: 2.25rem;
    max-width: 2.25rem;
    padding: 0;
    text-align: center;
    vertical-align: middle;
    background: var(--bg-2);
    box-shadow: 2px 0 4px rgba(0,0,0,0.15);
}
.roster-nav-col-left .roster-nav-btn {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    width: 100%;
    height: 100%;
}
.roster-nav-col-left .roster-nav-btn:hover:not(:disabled) {
    background: transparent;
    box-shadow: inset 1px 0 0 var(--line), inset -1px 0 0 var(--line);
}
.data-table tbody tr:hover .roster-nav-col-left {
    background-color: var(--bg-2);
    background-image: linear-gradient(rgba(43,95,196,0.06), rgba(43,95,196,0.06));
}
.roster-nav-col-right {
    position: sticky;
    right: 0;
    z-index: 10;
    width: 2.25rem;
    min-width: 2.25rem;
    max-width: 2.25rem;
    padding: 0;
    text-align: center;
    vertical-align: middle;
    background: var(--bg-2);
    box-shadow: -2px 0 4px rgba(0,0,0,0.15);
}
.roster-nav-col-right .roster-nav-btn {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    width: 100%;
    height: 100%;
}
.roster-nav-col-right .roster-nav-btn:hover:not(:disabled) {
    background: transparent;
    box-shadow: inset 1px 0 0 var(--line);
}
.data-table tbody tr:hover .roster-nav-col-right {
    background-color: var(--bg-2);
    background-image: linear-gradient(rgba(43,95,196,0.06), rgba(43,95,196,0.06));
}
.roster-announcement-editor h2 { font-size: 1.063rem; font-weight: 600; margin: 0.375rem 0 0.188rem; }
.roster-announcement-editor h3 { font-size: 0.938rem; font-weight: 600; margin: 0.25rem 0 0.125rem; }
.roster-announcement-editor ul, .roster-announcement-editor ol { padding-left: 1.5rem; margin: 0.25rem 0; }
.roster-announcement-editor li { margin: 0.125rem 0; }
*/

.roster-boss-group-title { font-size: 0.656rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.038rem; color: var(--ink-3); margin-bottom: 0.375rem; }
.roster-boss-group-title + .roster-boss-group-title,
.roster-boss-buttons + .roster-boss-group-title { margin-top: 0.625rem; }
.roster-sidebar {
    position: sticky;
    left: 0;
    flex-shrink: 0;
    width: 13rem;
    z-index: 10;
    overflow: hidden;
    transition: width 0.2s ease;
    align-self: stretch;
}
.roster-sidebar.is-collapsed { width: 2.25rem; }
.roster-sidebar-header {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 0.375rem;
    padding: 0.625rem 0.875rem 0.375rem;
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}
.roster-sidebar-title {
    font-size: 0.656rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.044rem;
    color: var(--ink-3);
    overflow: hidden;
    transition: opacity 0.15s;
}
.roster-sidebar.is-collapsed .roster-sidebar-title { opacity: 0; max-width: 0; overflow: hidden; }
.roster-sidebar.is-collapsed .roster-sidebar-header { justify-content: center; padding-left: 0; padding-right: 0; gap: 0; }
.roster-sidebar-body { overflow: hidden; }
.roster-sidebar.is-collapsed .roster-sidebar-body { display: none; }
/* .gp-panel-row — THE PORTAL'S SHARED SIDEBAR ROW.
 *
 * RENAMED 2026-08-18, from .roster-list-item / .roster-list-item-sub. Rosters were the first
 * consumer and then stopped being the only one: the Accounts account page, the Character page
 * and the Loot Distribution member list all use it and none of them is about rosters.
 * UI/ClassNaming.md's rule is that the moment a component-scoped class is used by a second
 * unrelated page its NAME is wrong — this had four. Same correction .role-rank-badge took to
 * become .gp-badge and .gp-announcement took to become .gp-richtext.
 *
 * The rename was the documented candidate in UI/Layout.md, which had proposed .gp-panel-row and
 * left it undone. FOLDING .loot-boss-row AND .blog-publication-link INTO IT IS THE OTHER HALF
 * AND IS NOT DONE — they remain separate near-duplicates.
 *
 * NOTE .roster-list-info AND .roster-list-actions ARE NOT RENAMED. .roster-list-info has the
 * same problem (Roster and Character both use it) and is left deliberately rather than swept;
 * .roster-list-actions has no view consumer at all. */
.gp-panel-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.438rem 0.875rem 0.438rem 1.625rem;
    border-bottom: 1px solid var(--line-soft);
    border-left: 2px solid transparent;
    cursor: pointer;
    color: inherit;
    text-decoration: none;
    transition: background 0.12s;
}
.gp-panel-row:last-child { border-bottom: none; }
.gp-panel-row:hover { background: rgba(255,255,255,0.02); color: var(--ink); }
.gp-panel-row.btn-active {
    color: var(--ink);
    border-left-color: #dce6ff;
    background: linear-gradient(to right, rgba(220,230,255,0.1), rgba(220,230,255,0));
    box-shadow: inset 0 1px 0 rgba(170,200,255,0.22),
                inset -0.063rem 0 0 rgba(170,200,255,0.22),
                inset 0 -0.063rem 0 rgba(170,200,255,0.22);
}
.roster-list-info { display: flex; flex-direction: column; gap: 0.063rem; min-width: 0; flex: 1; }
.gp-panel-row-sub { font-size: 0.75rem; color: var(--ink-4); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.roster-publish-icon { display: inline-block; width: 0.875rem; height: 0.875rem; background-color: currentColor; mask-image: url('/img/publish.svg'); mask-size: contain; mask-repeat: no-repeat; mask-position: center; -webkit-mask-image: url('/img/publish.svg'); -webkit-mask-size: contain; -webkit-mask-repeat: no-repeat; -webkit-mask-position: center; }
.roster-publish-btn[data-published="1"] .roster-publish-icon { background-color: var(--ok); }
.roster-trash-icon { display: inline-block; width: 0.875rem; height: 0.875rem; background-color: currentColor; mask-image: url('/img/trash.svg'); mask-size: contain; mask-repeat: no-repeat; mask-position: center; -webkit-mask-image: url('/img/trash.svg'); -webkit-mask-size: contain; -webkit-mask-repeat: no-repeat; -webkit-mask-position: center; }

/* white-space: pre-wrap was added on 2026-08-06 for the plain-text stopgap and removed the same day when
   DeltaRenderer landed: the renderer emits explicit <br /> and no literal newlines, so the rule no longer
   has anything to preserve. The h2/h3/ul/ol/li rules below are live again — the renderer produces exactly
   those tags. Content-level rules for the ql- classes live in rich-text.css, not here. */
.roster-announcement-display-compact { padding: 0.625rem 0.875rem; border-bottom: 1px solid var(--line); font-size: 0.75rem; color: var(--ink-3); line-height: 1.6; max-height: 5rem; overflow-y: auto; box-shadow: inset 0 0.5rem 1.5rem -0.375rem rgba(0,0,0,0.9), inset 0 -0.5rem 1.5rem -0.375rem rgba(0,0,0,0.9); }
.roster-announcement-display-compact h2 { font-size: 1.063rem; font-weight: 600; margin: 0.375rem 0 0.188rem; }
.roster-announcement-display-compact h3 { font-size: 0.938rem; font-weight: 600; margin: 0.25rem 0 0.125rem; }
.roster-announcement-display-compact ul, .roster-announcement-display-compact ol { padding-left: 1.5rem; margin: 0.25rem 0; }
.roster-announcement-display-compact li { margin: 0.125rem 0; }

/* .worker-status-chevron transition: transform removed — chevron now uses textContent toggle: ⮞/⮟ */
.worker-status-chevron { display: inline-block; font-size: 0.75rem; color: var(--ink-4); line-height: 1; }
.chevron-cell { width: 1%; white-space: nowrap; }
.worker-status-detail-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 0.75rem; margin-bottom: 0.75rem; }
/* .worker-status-detail-grid > .gp-section-card { grid-column: span 4; } */
/* Excludes the full-row modifier. Without the :not(), this rule (0,2,0) beats
   .gp-section-card-fullrow (0,1,0) on specificity no matter which file loads later, and a
   full-width card would silently render as a narrow one. */
.worker-status-detail-grid > .gp-section-card:not(.gp-section-card-fullrow) { grid-column: span 4; }

/* Tick log card body — capped height with its own scroll so 20 rows never grow the expanded row
   unbounded. Scrollbars are globally standardised, so no scrollbar rules here. */
.worker-ticklog-body { max-height: 18rem; overflow-y: auto; }

/* Per-tick issue list on the tick log page — one line per swallowed item, no bullets, muted. */
.worker-ticklog-issues { margin: 0; padding-left: 1rem; list-style: none; }
.worker-ticklog-issues li { color: var(--warn); font-size: 0.813rem; }
.worker-ticklog-issues li + li { margin-top: 0.15rem; }
/* .worker-kv-table { border-collapse: collapse; font-size: 0.813rem; width: 100%; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); margin-bottom: 0.5rem; } */
/* .worker-kv-table td { padding: 0.125rem 0; vertical-align: middle; } */
/* .worker-kv-table td:first-child { padding-left: 0.625rem; padding-right: 0.75rem; } */
/* .worker-kv-table td:last-child { padding-right: 0.625rem; text-align: left; white-space: normal; } */
/* .gp-kv-table { border-collapse: collapse; font-size: 0.813rem; width: 100%; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); margin-bottom: 0.5rem; } */
.gp-kv-table { border-collapse: collapse; font-size: 0.813rem; width: auto; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); margin-bottom: 0.5rem; }
.gp-kv-table td { padding: 0.125rem 0; vertical-align: middle; }
.gp-kv-table td:first-child { padding-left: 0.625rem; padding-right: 0.75rem; }
.gp-kv-table td:last-child { padding-right: 0.625rem; text-align: left; white-space: normal; }

/* Shared utility — visually suppressed / inactive state */
.is-dimmed { opacity: 0.45; }

/* Team Events */
.te-add-icon { display: inline-block; width: 0.875rem; height: 0.875rem; background-color: currentColor; mask: url('/img/add.svg') no-repeat center / contain; -webkit-mask: url('/img/add.svg') no-repeat center / contain; }
.te-delete-icon { display: inline-block; width: 0.875rem; height: 0.875rem; background-color: currentColor; mask: url('/img/trash.svg') no-repeat center / contain; -webkit-mask: url('/img/trash.svg') no-repeat center / contain; }
.te-complete-icon { display: inline-block; width: 0.875rem; height: 0.875rem; background-color: currentColor; mask: url('/img/tick.svg') no-repeat center / contain; -webkit-mask: url('/img/tick.svg') no-repeat center / contain; }
.te-unlinked-body { padding: 0.75rem 1rem; }
/*.te-link-row { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.5rem; }*/
/*.te-link-row select { flex: 1; min-width: 0; }*/

/* Dashboard — Messages card */
.dash-msg-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 0; width: 100%; }
.dash-msg-tick-icon { display: inline-block; width: 0.75rem; height: 0.75rem; background-color: currentColor; mask: url('/img/tick.svg') no-repeat center / contain; -webkit-mask: url('/img/tick.svg') no-repeat center / contain; }
.dash-msg-trash-icon { display: inline-block; width: 0.75rem; height: 0.75rem; background-color: currentColor; mask: url('/img/trash.svg') no-repeat center / contain; -webkit-mask: url('/img/trash.svg') no-repeat center / contain; }

/* The membership change notifications write one field per line, and a message body is plain text —
   without this the newlines collapse and the whole body renders as one run-on line.

   SCOPED TO THE BODY, NOT PUT ON .detail-panel. That class is shared by every expandable row in the
   portal (GuildRoles, TeamRanks, Feedback, Trials, Loot Distribution) and is display:grid, so
   pre-line there would start rendering the source indentation between its child elements as visible
   blank lines, on pages that have nothing to do with messages.

   KEPT IN site.css rather than moved to pages/messages.css with the badge modifiers: both the
   dashboard Messages card and /Messages render this element, and the dashboard has no page CSS file
   to share it with. Added 2026-08-19 (Session 202). */
.dash-msg-body { white-space: pre-line; }

/* Messages — mail state icons */
.msg-mail-icon { display: inline-block; width: 0.875rem; height: 0.875rem; background-color: currentColor; }
.msg-mail-icon-closed { mask: url('/img/mail-closed.svg') no-repeat center / contain; -webkit-mask: url('/img/mail-closed.svg') no-repeat center / contain; }
.msg-mail-icon-open { mask: url('/img/mail-open.svg') no-repeat center / contain; -webkit-mask: url('/img/mail-open.svg') no-repeat center / contain; color: var(--ink-3); }

/* Air Datepicker — highlighted date dot indicator */
.air-datepicker-cell.gp-dp-highlight { position: relative; }
.air-datepicker-cell.gp-dp-highlight::after { content: ''; position: absolute; bottom: 3px; left: 50%; transform: translateX(-50%); width: 4px; height: 4px; border-radius: 50%; background: var(--accent); pointer-events: none; }
/* .worker-kv-table .worker-kv-label { color: #7aaeff; font-size: 0.688rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.038rem; white-space: nowrap; width: 1%; } */
/* .data-table .worker-kv-table { border-top: none; border-bottom: none; } */
/* .data-table .worker-kv-table tbody tr { border-top: none; background: transparent; transition: none; } */
/* .data-table .worker-kv-table tbody tr:hover { background-image: none; } */
.gp-kv-table .gp-kv-label { color: #7aaeff; font-size: 0.688rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.038rem; white-space: nowrap; width: 1%; }
.data-table .gp-kv-table { border-top: none; border-bottom: none; }
.data-table .gp-kv-table tbody tr { border-top: none; background: transparent; transition: none; }
.data-table .gp-kv-table tbody tr:hover { background-image: none; }

.note-status-icon { display: inline-block; width: 0.875rem; height: 0.875rem; background-color: currentColor; mask: url('/img/label-important.svg') no-repeat center / contain; -webkit-mask: url('/img/label-important.svg') no-repeat center / contain; }

.acc-note-filters { display: flex; gap: 0.5rem; margin-bottom: 0.75rem; }
.acc-note-add-header { position: relative; cursor: pointer; user-select: none; margin-bottom: 0; padding-left: calc(2px + 1.125em + 0.5rem); transition: background-color 0.1s; }
.acc-note-add-header:hover { background-color: var(--bg-3); }
.acc-note-add-header[data-expanded] { margin-bottom: 0.75rem; }
.acc-note-add-header:hover .expand-spine { width: 3px; background: linear-gradient(180deg, var(--accent), color-mix(in oklab, var(--accent) 35%, var(--bg))); box-shadow: 0 0 14px -2px rgba(43,95,196,0.40); }
.acc-note-add-header:hover .expand-notch { left: 3px; border-color: rgba(43,95,196,0.45); color: var(--accent-glow); box-shadow: 2px 0 12px -4px rgba(43,95,196,0.40); }
.acc-note-add-header[data-expanded] .expand-spine { width: 3px; background: var(--accent); box-shadow: 0 0 14px -2px rgba(43,95,196,0.40); }
.acc-note-add-header[data-expanded] .expand-notch { left: 3px; border-color: rgba(43,95,196,0.45); color: var(--accent-glow); }
.acc-note-form, .note-edit-form { display: flex; flex-direction: column; }
.acc-note-form { flex: 1; }
.acc-note-form .role-detail-label:first-of-type, .note-edit-form .role-detail-label:first-of-type { margin-top: 0; }
.acc-note-form textarea, .note-edit-form textarea { width: 100%; resize: vertical; margin-bottom: 0.75rem; }
.acc-note-form select, .note-edit-form select { margin-bottom: 0.75rem; }
.acc-note-form-actions { display: flex; align-items: center; justify-content: flex-end; gap: 0.625rem; margin-top: auto; padding-top: 0.625rem; }
.acc-note-form-error { font-size: 0.813rem; color: var(--bad); display: none; }
.note-edit-cell { padding: 0.75rem 1.125rem; }
