:root,
[data-theme="oxblood"] {
    /* Oxblood — aged guild ledger (default) */
    --ink-deep:      #181210;
    --ink-leather:   #261a14;
    --ink-parchment: #30221a;
    --ink-rule:      #4a3428;
    --ink-faint:     #5c4232;

    --gilt:          #d4a747;
    --gilt-dim:      #8a6e2d;
    --gilt-shadow:   #5a4416;

    --ruby:          #8b1a1a;
    --ruby-bright:   #c44b4b;

    --ivory:         #ece0c8;
    --ivory-dim:     #c9b896;
    --dust:          #b0a085;
    --shadow:        #050201;

    --glow-primary: rgba(90, 18, 18, 0.45);
    --glow-corner:  rgba(60, 30, 12, 0.35);
}

[data-theme="steel"] {
    /* Steel Hall — cool slate, polished steel accent */
    --ink-deep:      #1a1f28;
    --ink-leather:   #252b36;
    --ink-parchment: #2d3441;
    --ink-rule:      #3d4656;
    --ink-faint:     #4d5872;

    --gilt:          #9bb1c7;
    --gilt-dim:      #5d6e85;
    --gilt-shadow:   #3a4658;

    --ruby:          #8b1a1a;
    --ruby-bright:   #d05858;

    --ivory:         #e6ebf2;
    --ivory-dim:     #b8c2d0;
    --dust:          #8a96a8;
    --shadow:        #0a0e14;

    --glow-primary: rgba(60, 90, 130, 0.35);
    --glow-corner:  rgba(40, 60, 90, 0.30);
}

[data-theme="verdant"] {
    /* Verdant Hall — deep forest, oxidised bronze accent */
    --ink-deep:      #161e1a;
    --ink-leather:   #1f2924;
    --ink-parchment: #28342c;
    --ink-rule:      #3a4c40;
    --ink-faint:     #4a5e4f;

    --gilt:          #c89464;
    --gilt-dim:      #7e5d3d;
    --gilt-shadow:   #4a3a25;

    --ruby:          #8b1a1a;
    --ruby-bright:   #d05858;

    --ivory:         #e8e4d2;
    --ivory-dim:     #c4c2a8;
    --dust:          #9aa28a;
    --shadow:        #06090a;

    --glow-primary: rgba(40, 80, 50, 0.32);
    --glow-corner:  rgba(80, 50, 30, 0.28);
}

[data-theme="mage"] {
    /* Mage Tower — deep indigo, pewter accent */
    --ink-deep:      #1a1726;
    --ink-leather:   #2a2438;
    --ink-parchment: #332c46;
    --ink-rule:      #463e5e;
    --ink-faint:     #564d72;

    --gilt:          #bfb4d4;
    --gilt-dim:      #7c7397;
    --gilt-shadow:   #4a4264;

    --ruby:          #8b1a1a;
    --ruby-bright:   #d05858;

    --ivory:         #ece6f2;
    --ivory-dim:     #c4bcd4;
    --dust:          #9890ab;
    --shadow:        #08060f;

    --glow-primary: rgba(80, 60, 130, 0.40);
    --glow-corner:  rgba(60, 50, 100, 0.30);
}

:root {
    /* Type — same across all themes */
    --font-display: 'Cinzel', 'Trajan Pro', 'Times New Roman', serif;
    --font-body:    'Hanken Grotesk', system-ui, -apple-system, sans-serif;
    --font-mono:    'JetBrains Mono', 'Menlo', monospace;
}

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

html { -webkit-font-smoothing: antialiased; font-size: 100%; }

/* Themed scrollbars. Firefox + modern browsers honour scrollbar-color /
   scrollbar-width on `*` so any overflow surface (page, modal card,
   .scroll-table wrappers, expanded breakdowns, etc.) inherits the
   theme without each one opting in. WebKit's pseudo-element rules
   below provide the same look for Chrome / Edge / Safari. Both layers
   read theme variables, so swapping themes recolours the scrollbar
   in lockstep with the rest of the chrome. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--ink-faint) var(--ink-leather);
}
::-webkit-scrollbar {
    width: 0.5rem;
    height: 0.5rem;
}
::-webkit-scrollbar-track {
    background: var(--ink-leather);
}
::-webkit-scrollbar-thumb {
    background: var(--ink-faint);
    border-radius: 0.25rem;
    border: 0.125rem solid var(--ink-leather); /* inset effect */
}
::-webkit-scrollbar-thumb:hover {
    background: var(--ink-rule);
}
::-webkit-scrollbar-corner {
    background: var(--ink-leather);
}

/* UI scale — driven by the per-user `scale` preference rendered onto
   `<html data-scale>`. All sizes in this stylesheet are rem-based, so
   bumping the root font-size here scales everything (text, spacing,
   borders, container caps) uniformly. */
html[data-scale="75"]  { font-size: 75%; }
html[data-scale="100"] { font-size: 100%; }
html[data-scale="125"] { font-size: 125%; }

body {
    font-family: var(--font-body);
    font-size: 1.0625rem;
    line-height: 1.6;
    color: var(--ivory);
    background: var(--ink-deep);
    min-height: 100vh;
    background-image:
        radial-gradient(ellipse 80% 55% at 50% -10%, var(--glow-primary) 0%, transparent 60%),
        radial-gradient(ellipse 50% 50% at 0% 110%, var(--glow-corner) 0%, transparent 60%),
        radial-gradient(ellipse 50% 50% at 100% 110%, var(--glow-corner) 0%, transparent 60%);
    background-attachment: fixed;
    transition: background-color 0.35s ease;
}

/* ─── Layout ─────────────────────────────────────────── */

.layout {
    max-width: 93.75rem;
    margin: 0 auto;
    min-height: 100vh;
    background: var(--ink-leather);
    border-left: 0.0625rem solid var(--ink-rule);
    border-right: 0.0625rem solid var(--ink-rule);
    box-shadow:
        0 0 5rem rgba(0, 0, 0, 0.65),
        inset 0 0.0625rem 0 rgba(212, 167, 71, 0.06);
    display: flex;
    flex-direction: column;
}

/* ─── Header ─────────────────────────────────────────── */

header {
    padding: 2.25rem 3rem 1.75rem;
    background: var(--ink-parchment);
    border-bottom: 0.0625rem solid var(--ink-rule);
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 2rem;
    position: relative;
    animation: fadeInUp 0.7s ease-out backwards;
}

/* The gilt rule that sits centred beneath the header */
header::after {
    content: '';
    position: absolute;
    left: 50%;
    bottom: -0.0625rem;
    width: 38%;
    max-width: 22.5rem;
    height: 0.0625rem;
    transform: translateX(-50%);
    background: linear-gradient(90deg,
        transparent 0%,
        var(--gilt-dim) 30%,
        var(--gilt) 50%,
        var(--gilt-dim) 70%,
        transparent 100%);
    opacity: 0.7;
}

.brand {
    display: flex;
    align-items: center;
    gap: 1.1rem;
}

.sigil {
    width: 1.6em;
    height: 1.6em;
    color: var(--gilt);
    flex-shrink: 0;
    filter: drop-shadow(0 0.0625rem 0 var(--shadow));
}

.sigil path { fill: none; stroke: currentColor; stroke-width: 1.4; }
.sigil .core { fill: currentColor; stroke: none; }

header h1 {
    font-family: var(--font-display);
    font-size: 1.65rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ivory);
    text-shadow: 0 0.0625rem 0 var(--shadow);
    line-height: 1;
}

header h1 .sep {
    color: var(--gilt);
    margin: 0 0.35em;
    font-weight: 400;
    opacity: 0.85;
}

.header-actions {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    animation: fadeInUp 0.7s 0.15s ease-out backwards;
}

.user-info {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.1;
    gap: 0.35rem;
}

.user-info .label {
    font-family: var(--font-body);
    font-size: 0.65rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--dust);
}

.user-info .name {
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 500;
    color: var(--ivory-dim);
}

.logout-form button,
.login-link {
    display: inline-block;
    background: transparent;
    border: 0.0625rem solid var(--ink-faint);
    color: var(--dust);
    padding: 0.55rem 1.05rem;
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    text-decoration: none;
    cursor: pointer;
    transition: color 0.25s ease, border-color 0.25s ease, background 0.25s ease;
}

.logout-form button:hover,
.login-link:hover {
    color: var(--ivory);
    border-color: var(--gilt-dim);
    background: rgba(212, 167, 71, 0.04);
}

.theme-switcher {
    display: flex;
    gap: 0.5rem;
}

.theme-switcher select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background: transparent;
    border: 0.0625rem solid var(--ink-faint);
    color: var(--dust);
    padding: 0.55rem 2.1rem 0.55rem 1rem;
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    cursor: pointer;
    border-radius: 0;
    line-height: 1;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23b0a085' stroke-width='1.4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.85rem center;
    background-size: 0.5625rem 0.375rem;
    transition: color 0.25s ease, border-color 0.25s ease, background-color 0.25s ease;
}

.theme-switcher select:hover,
.theme-switcher select:focus {
    color: var(--ivory);
    border-color: var(--gilt-dim);
    outline: none;
}

.theme-switcher select option {
    background: var(--ink-parchment);
    color: var(--ivory);
    font-family: var(--font-body);
}


/* ─── Nav ────────────────────────────────────────────── */

nav {
    background: transparent;
    padding: 0 3rem;
    border-bottom: 0.0625rem solid var(--ink-rule);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
}

nav ul {
    list-style: none;
    display: flex;
    gap: 0.25rem;
}

nav li {
    animation: fadeInUp 0.5s ease-out backwards;
}

nav li:nth-child(1) { animation-delay: 0.20s; }
nav li:nth-child(2) { animation-delay: 0.26s; }
nav li:nth-child(3) { animation-delay: 0.32s; }
nav li:nth-child(4) { animation-delay: 0.38s; }
nav li:nth-child(5) { animation-delay: 0.44s; }
nav li:nth-child(6) { animation-delay: 0.50s; }

nav a {
    display: block;
    padding: 1.15rem 1.4rem;
    color: var(--dust);
    text-decoration: none;
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    border-bottom: 0.125rem solid transparent;
    transition: color 0.2s ease, border-color 0.25s ease, letter-spacing 0.3s ease;
    position: relative;
}

nav a:hover {
    color: var(--ivory);
    border-bottom-color: var(--gilt-dim);
    letter-spacing: 0.16em;
}

nav a.active {
    color: var(--gilt);
    border-bottom-color: var(--gilt);
}

nav a.active::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, transparent 0%, rgba(212, 167, 71, 0.06) 100%);
    pointer-events: none;
}

/* ─── Nav dropdown sub-menu ──────────────────────────── */

.nav-item--parent {
    position: relative;
}

/* Pure category parent — same chrome as `nav a`, but not a link.
   Used for tabs that exist only to group their children (e.g. the
   Officers tab, which has no page of its own). */
.nav-category {
    display: block;
    padding: 1.15rem 1.4rem;
    color: var(--dust);
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    border-bottom: 0.125rem solid transparent;
    transition: color 0.2s ease, border-color 0.25s ease, letter-spacing 0.3s ease;
    cursor: default;
    user-select: none;
}

.nav-item--parent:hover .nav-category,
.nav-item--parent:focus-within .nav-category {
    color: var(--ivory);
    border-bottom-color: var(--gilt-dim);
    letter-spacing: 0.16em;
}

.nav-category.active {
    color: var(--gilt);
    border-bottom-color: var(--gilt);
}

.nav-chevron {
    width: 0.6rem;
    height: 0.4rem;
    margin-left: 0.4rem;
    vertical-align: middle;
    color: currentColor;
    opacity: 0.7;
    transition: transform 0.2s ease, opacity 0.2s ease;
}

.nav-item--parent:hover .nav-chevron,
.nav-item--parent:focus-within .nav-chevron {
    transform: rotate(180deg);
    opacity: 1;
}

.nav-submenu {
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 12rem;
    list-style: none;
    margin: 0;
    padding: 0.35rem 0;
    background: var(--ink-leather);
    border: 0.0625rem solid var(--ink-rule);
    border-top: none;
    box-shadow: 0 0.5rem 1.25rem rgba(0, 0, 0, 0.45);
    display: flex;
    flex-direction: column;
    gap: 0;

    /* Hidden until the parent <li> is hovered or focused. Using
       opacity + visibility (rather than display:none) so the menu
       can fade and so keyboard focus works without a layout jump. */
    opacity: 0;
    visibility: hidden;
    transform: translateY(-0.25rem);
    transition: opacity 0.15s ease, transform 0.18s ease, visibility 0s linear 0.18s;
    z-index: 50;
}

.nav-item--parent:hover .nav-submenu,
.nav-item--parent:focus-within .nav-submenu {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity 0.15s ease, transform 0.18s ease, visibility 0s linear 0s;
}

.nav-submenu li {
    animation: none; /* override the stagger fade-in from `nav li` */
}

.nav-submenu a {
    display: block;
    padding: 0.65rem 1.4rem;
    border-bottom: none;
    letter-spacing: 0.12em;
    font-size: 0.72rem;
}

.nav-submenu a:hover {
    color: var(--ivory);
    background: var(--ink-parchment);
    border-bottom: none;
    letter-spacing: 0.13em;
}

.nav-submenu a.active {
    color: var(--gilt);
    border-bottom: none;
}

.nav-submenu a.active::after {
    content: none;
}

/* ─── Main / Page sections ───────────────────────────── */

main {
    flex: 1;
    padding: 3.5rem 3rem 4.5rem;
    animation: fadeInUp 0.7s 0.5s ease-out backwards;
}

/* Login page: center the card in the remaining viewport height. */
main:has(.login-page) {
    display: flex;
    align-items: center;
    justify-content: center;
}

.login-page {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.page-section {
    max-width: 72ch;
}

.page-section h2 {
    font-family: var(--font-body);
    font-size: 2.4rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    text-transform: none;
    color: var(--ivory);
    line-height: 1.1;
    text-shadow: 0 0.0625rem 0 var(--shadow);
}

/* The gilt flourish under each page heading */
.page-section h2 + .ornament {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    margin: 1.25rem 0 1.75rem;
    color: var(--gilt-dim);
    width: 8rem;
}

.page-section .ornament .line {
    flex: 1;
    height: 0.0625rem;
    background: linear-gradient(90deg, currentColor 0%, transparent 100%);
}

.page-section .ornament .lozenge {
    width: 0.375rem;
    height: 0.375rem;
    background: var(--gilt);
    transform: rotate(45deg);
    box-shadow: 0 0 0.5rem rgba(212, 167, 71, 0.4);
}

.page-section .lede {
    font-family: var(--font-body);
    font-size: 1.125rem;
    font-weight: 400;
    color: var(--ivory-dim);
    line-height: 1.65;
    max-width: 60ch;
}

/* ─── Admin (sidebar + content) ──────────────────────── */

.admin-layout {
    display: grid;
    grid-template-columns: 13.75rem 1fr;
    align-items: start;
    gap: 0;
}

.admin-nav {
    padding-right: 1.5rem;
    border-right: 0.0625rem solid var(--ink-rule);
}

.admin-nav-title {
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--gilt-dim);
    padding: 0 0 0.85rem 0.85rem;
    margin-bottom: 0.5rem;
    border-bottom: 0.0625rem solid var(--ink-rule);
}

.admin-nav ul {
    list-style: none;
    display: flex;
    flex-direction: column;
}

.admin-nav a {
    display: block;
    padding: 0.6rem 0.85rem;
    color: var(--dust);
    text-decoration: none;
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 500;
    border-left: 0.125rem solid transparent;
    transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.admin-nav a:hover {
    color: var(--ivory);
    background: rgba(212, 167, 71, 0.03);
}

.admin-nav a.active {
    color: var(--gilt);
    border-left-color: var(--gilt);
    background: rgba(212, 167, 71, 0.04);
}

.admin-content {
    padding-left: 2.5rem;
}

.page-section.page-section--wide {
    max-width: none;
}

/* ─── Data table ─────────────────────────────────────── */

.data-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 1.5rem;
    font-size: 0.95rem;
}

.data-table thead th {
    text-align: left;
    padding: 0.75rem 1rem;
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--gilt-dim);
    border-bottom: 0.0625rem solid var(--ink-rule);
    background: rgba(0, 0, 0, 0.15);
}

.data-table tbody td {
    padding: 0.85rem 1rem;
    border-bottom: 0.0625rem solid var(--ink-rule);
    color: var(--ivory);
    vertical-align: middle;
}

.data-table tbody tr:hover td {
    background: rgba(212, 167, 71, 0.025);
}

.data-table tbody tr.row-deactivated td {
    color: var(--dust);
    opacity: 0.75;
}

/* Vertical column separators — inner borders only (no left edge on
   col 1, no right edge on last col). Applied to both header and body.
   Half-opacity so they read lighter than the horizontal row borders. */
.data-table thead th:not(:last-child),
.data-table tbody td:not(:last-child) {
    border-right: 0.0625rem solid color-mix(in srgb, var(--ink-rule) 50%, transparent);
}

/* DataTables sort icons — larger and white. The :before/:after
   pseudo-elements carry ▲/▼ glyphs; DT sets opacity separately
   so the active/inactive distinction is preserved. */
table.dataTable thead span.dt-column-order::before,
table.dataTable thead span.dt-column-order::after {
    font-size: 1.5em;
    color: #fff;
}

.world-buff-icon {
    display: block;
    width: 1.2rem;
    height: 1.2rem;
    border-radius: 0.25rem;
    margin: 0 auto;
}

table.dataTable.world-buff-table thead th:not(:first-child),
table.dataTable.world-buff-table tbody td:not(:first-child) {
    text-align: center;
    padding-right: 1.2rem;
}

/* Toggleable buff column. The icon button is intentionally minimal
   so it inherits the TH layout; clicking it dims the column and
   recomputes the row Total. */
.world-buff-table .wb-toggle {
    appearance: none;
    border: none;
    background: transparent;
    padding: 0;
    margin: 0 auto;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: filter 0.15s ease-out;
}

.world-buff-table .wb-toggle:hover .world-buff-icon {
    filter: brightness(1.2);
    box-shadow: 0 0 0 0.0625rem var(--gilt-dim);
}

.world-buff-table .wb-toggle:focus-visible {
    outline: 0.0625rem solid var(--gilt-dim);
    outline-offset: 0.125rem;
    border-radius: 0.25rem;
}

.world-buff-table .wb-col.wb-col-disabled .world-buff-icon {
    filter: grayscale(1);
    opacity: 0.4;
}

/* Higher-specificity override so the disabled column wins over
   DataTables' row-striping / hover backgrounds (otherwise the
   darken effect only shows up on the header). */
table.dataTable.world-buff-table tbody td.wb-cell.wb-col-disabled {
    background: rgba(0, 0, 0, 0.35);
    color: var(--dust);
    opacity: 0.6;
    text-decoration: line-through;
    text-decoration-color: var(--ruby);
    text-decoration-thickness: 0.0625rem;
}

/* World Buff Report filter bar */
.wb-report-filters[hidden] { display: none; }
.wb-report-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin-top: 1rem;
    margin-bottom: 1rem;
}

.wb-report-filters fieldset {
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.25rem;
    background: rgba(0, 0, 0, 0.2);
    padding: 0.6rem 1rem 0.75rem;
    display: flex;
    flex-direction: column;
}

/* Center the Total% and Attended cells in the world buff tables */
.wb-total,
th:has(+ th > .wb-total),
.wb-attended {
    text-align: center;
}

.data-table thead th.wb-total,
.data-table thead th.wb-attended,
.data-table tbody td.wb-total,
.data-table tbody td.wb-attended {
    text-align: center;
}

/* Themed radio buttons for the WB report filters */
.wb-report-filters input[type="radio"] {
    appearance: none;
    -webkit-appearance: none;
    width: 0.9rem;
    height: 0.9rem;
    border: 0.1125rem solid var(--ink-faint);
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.3);
    cursor: pointer;
    flex-shrink: 0;
    position: relative;
    transition: border-color 0.12s;
    vertical-align: middle;
}

.wb-report-filters input[type="radio"]:hover {
    border-color: var(--gilt-dim);
}

.wb-report-filters input[type="radio"]:checked {
    border-color: var(--gilt);
}

.wb-report-filters input[type="radio"]:checked::after {
    content: '';
    position: absolute;
    inset: 0.15rem;
    border-radius: 50%;
    background: var(--gilt);
}

/* World buff "Only show relevant buffs" checkbox control row */
.wb-table-controls {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 0.5rem;
}

.wb-table-controls input[type="checkbox"] {
    width: 1.125rem;
    height: 1.125rem;
    cursor: pointer;
}

/* Class-irrelevant buff cells: hide the value in relevant-only mode,
   leaving the cell blank. */
table.wb-relevant-only td.wb-class-skip .wb-actual { display: none; }

/* Heat tint: cells below 50% uptime get progressively more red. */
.data-table .muted.wb-cell { color: color-mix(in srgb, rgb(220, 60, 60) calc(var(--wb-heat, 0) * 100%), var(--dust)); }

/* ─── World Buff breakdown popup ────────────────────── */
.wb-popup {
    position: fixed;
    z-index: 1000;
    background: var(--ink-parchment);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.375rem;
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.65);
    min-width: 22rem;
    max-width: 30rem;
    max-height: 22rem;
    display: flex;
    flex-direction: column;
    font-size: 0.875rem;
}
.wb-popup[hidden] { display: none; }

.wb-popup__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.55rem 0.9rem;
    border-bottom: 0.0625rem solid var(--ink-rule);
    flex-shrink: 0;
}
.wb-popup__title {
    font-weight: 600;
    color: var(--gilt);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wb-popup__close {
    background: none;
    border: none;
    color: var(--dust);
    cursor: pointer;
    font-size: 1.25rem;
    line-height: 1;
    padding: 0;
    flex-shrink: 0;
}
.wb-popup__close:hover { color: var(--ivory); }

.wb-popup__body {
    overflow-y: auto;
    padding: 0.15rem 0;
}

.wb-popup__table {
    width: 100%;
    border-collapse: collapse;
}
.wb-popup__table td {
    padding: 0.35rem 0.9rem;
    vertical-align: middle;
}
.wb-popup__table td.wb-popup__types { color: var(--muted); font-size: 0.85rem; white-space: nowrap; }
.wb-popup__table td.wb-popup__att   { text-align: center; white-space: nowrap; font-size: 0.85rem; }
.wb-popup__table td:nth-child(4)    { text-align: center; min-width: 4rem; }
.wb-popup__table td:nth-child(5)    { text-align: right; white-space: nowrap; }
.wb-popup__table tr:hover td { background: rgba(255, 255, 255, 0.04); }

.wb-popup__pct          { font-weight: 600; color: color-mix(in srgb, rgb(220, 60, 60) calc(var(--wb-heat, 0) * 100%), var(--ivory)); }
.wb-popup__raid-link    { font-size: 0.8rem; }

/* Clickable cells */
table.world-buff-table tbody td.wb-clickable { cursor: pointer; }
table.world-buff-table tbody td.wb-clickable:hover { background: rgba(255, 255, 255, 0.06) !important; }

/* ─── Scrollable table wrapper ───────────────────────── */
/* Wrap a .data-table in <div class="scroll-table"> to give it a
   capped height with vertical scrolling. Pair with
   .data-table--sticky-head to keep the header row visible while
   scrolling — sticky needs an opaque bg on the th cells so rows
   underneath don't bleed through. */
.scroll-table {
    max-height: 25rem;
    overflow-y: auto;
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.25rem;
    margin-top: 1.5rem;
}

.scroll-table > .data-table {
    margin-top: 0;
}

.data-table--sticky-head thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    /* Override the translucent rgba(0,0,0,0.15) on the row so rows
       scrolling beneath are masked out. ink-leather matches the
       layout's underlying surface for a clean overlap. */
    background: var(--ink-leather);
    box-shadow: inset 0 -0.0625rem 0 var(--ink-rule);
    border-bottom: 0;
}

.data-table .muted {
    color: var(--dust);
    font-variant-numeric: tabular-nums;
}

/* ─── Missing World Buffs report ─────────────────────────── */
.missing-wb-raid {
    margin-bottom: 1.25rem;
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.375rem;
    overflow: hidden;
}

.missing-wb-raid__summary {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.55rem 0.9rem;
    background: rgba(0, 0, 0, 0.2);
    cursor: pointer;
    user-select: none;
    list-style: none;
}

.missing-wb-raid__summary::-webkit-details-marker { display: none; }
.missing-wb-raid__summary::before {
    content: '▶';
    font-size: 0.65rem;
    color: var(--gilt-dim);
    transition: transform 0.15s ease-out;
    flex-shrink: 0;
}
.missing-wb-raid[open] > .missing-wb-raid__summary::before {
    transform: rotate(90deg);
}

.missing-wb-raid__summary:hover { background: rgba(255, 255, 255, 0.04); }

.missing-wb-raid__date {
    font-weight: 600;
    color: var(--ivory);
}

.missing-wb-raid__types {
    font-size: 0.8rem;
    color: var(--gilt-dim);
    background: rgba(0, 0, 0, 0.3);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.25rem;
    padding: 0.1rem 0.45rem;
}

.missing-wb-raid__count {
    margin-left: auto;
    font-size: 0.8rem;
    color: var(--dust);
}

.missing-wb-raid__summary .missing-wb-raid__view-link {
    font-size: 0.8rem;
    white-space: nowrap;
    flex-shrink: 0;
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.25rem;
    padding: 0.15rem 0.5rem;
}

.missing-wb-raid__summary .missing-wb-raid__view-link:hover {
    border-color: var(--gilt-dim);
}

.missing-wb-table-wrap {
    overflow-x: auto;
    border-top: 0.0625rem solid var(--ink-rule);
}

.missing-wb-table {
    margin-top: 0;
}

.missing-wb-table thead th:not(:first-child),
.missing-wb-table tbody td:not(:first-child) {
    text-align: center;
    width: 2.5rem;
    padding-left: 0.4rem;
    padding-right: 0.4rem;
}

.missing-wb-cell {
    vertical-align: middle;
}

.missing-wb-x {
    font-size: 1rem;
    font-weight: 700;
    color: var(--ruby);
    line-height: 1;
}

.missing-wb-low {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--gilt);
}

.missing-wb-partial {
    font-size: 0.78rem;
    margin-left: 0.3rem;
}

.data-table .actions-col {
    text-align: right;
    width: 1%;
    white-space: nowrap;
}

.class-cell {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.mc-source-cell {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

/* ─── Raider links + detail page ─────────────────────── */
.raider-link {
    color: var(--ivory);
    text-decoration: none;
    border-bottom: 0.0625rem dotted var(--ink-faint);
}

.raider-link:hover {
    color: var(--gilt);
    border-bottom-color: var(--gilt-dim);
}

.gear-progression__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}
.gear-progression__header .subhead { margin: 0; }
.gear-progression__controls {
    display: inline-flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}
.gear-progression__role-label {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.85rem;
    color: var(--ivory-dim);
}
.gear-progression__role-select {
    font-size: 0.85rem;
    padding: 0.15rem 0.45rem;
    background: rgba(0, 0, 0, 0.3);
    color: var(--ivory);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.25rem;
}
.gear-progression__toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    cursor: pointer;
    user-select: none;
    font-size: 0.85rem;
    color: var(--ivory-dim);
}
/* Hide the native checkbox visually but keep it accessible — the
   .gear-progression__toggle-box sibling renders the styled state. */
.gear-progression__toggle input[type="checkbox"] {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    border: 0;
}
.gear-progression__toggle-box {
    display: inline-block;
    width: 1.18rem;
    height: 1.18rem;
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.22rem;
    background: rgba(0, 0, 0, 0.3);
    position: relative;
    flex-shrink: 0;
    transition: background 120ms ease, border-color 120ms ease;
}
.gear-progression__toggle input[type="checkbox"]:checked + .gear-progression__toggle-box {
    background: var(--gilt-dim, #9b7a3a);
    border-color: var(--gilt);
}
.gear-progression__toggle input[type="checkbox"]:checked + .gear-progression__toggle-box::after {
    content: "";
    position: absolute;
    left: 0.33rem;
    top: 0.07rem;
    width: 0.36rem;
    height: 0.7rem;
    border: solid var(--ink-paper, #f4ebd1);
    border-width: 0 0.15rem 0.15rem 0;
    transform: rotate(45deg);
}
.gear-progression__toggle input[type="checkbox"]:focus-visible + .gear-progression__toggle-box {
    outline: 0.125rem solid var(--gilt);
    outline-offset: 0.125rem;
}
.gear-progression__toggle:hover .gear-progression__toggle-box {
    border-color: var(--gilt-dim);
}
.gear-progression__toggle-hint {
    font-size: 0.75rem;
    cursor: help;
}
.gear-progression {
    display: grid;
    grid-template-columns: minmax(8rem, auto) 1fr;
    gap: 1.5rem;
    align-items: start;
    margin-bottom: 2rem;
}
.gear-progression__stat { margin: 0; }
.gear-progression__chart {
    position: relative;
    min-height: 16rem;
}
.gear-progression__chart canvas {
    max-width: 100%;
}
.gear-tooltip {
    position: absolute;
    pointer-events: none;
    background: var(--ink-leather);
    color: var(--ink-paper, #e6dec9);
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    padding: 0.5rem 0.75rem;
    font-size: 0.8rem;
    line-height: 1.4;
    box-shadow: 0 0.5rem 1.25rem rgba(0, 0, 0, 0.55);
    opacity: 0;
    transition: opacity 120ms ease-out;
    /* Size to natural content. With `width: auto` and a positioned
       absolute element where only `left` is set, the browser
       constrains width by the distance to the containing block's right
       edge — which makes the tooltip get pinched as the hover point
       moves near the right side of the chart. `max-content` overrides
       that. The JS handler clamps the left position to keep the
       tooltip visible. */
    width: max-content;
    max-width: 22rem;
    z-index: 60;
}
.gear-tooltip__title {
    font-weight: 600;
    color: var(--gilt);
    margin-bottom: 0.3rem;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.gear-tooltip__header { margin-bottom: 0.3rem; }
.gear-tooltip__muted { color: var(--dust); font-size: 0.78rem; }
.gear-tooltip__section-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--gilt-dim);
    margin-top: 0.4rem;
    margin-bottom: 0.15rem;
}
.gear-tooltip__list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.gear-tooltip__item {
    display: block;
    margin: 0.1rem 0;
    white-space: nowrap;
}
.gear-tooltip__item--add .gear-tooltip__sign { color: #6dd56d; font-weight: 600; }
.gear-tooltip__item--rem .gear-tooltip__sign { color: #e07a5f; font-weight: 600; }
.gear-tooltip__ilvl { color: var(--dust); font-size: 0.75rem; }
/* Wowhead injects an <ins>/<small> wrapper inside the anchor when it
   iconizes the link. Keep them aligned with the surrounding text. */
.gear-tooltip__item a { text-decoration: none; }
/* The whole tooltip already declines pointer events, but Wowhead binds
   hover listeners directly on its enriched links which would otherwise
   re-enable them and intercept the mouse — popping their own tooltip
   on top of ours and breaking the chart's hover state. Killing pointer
   events on the anchor blocks both Wowhead hover and click; the
   tradeoff is no click-through to Wowhead.com, which matches the
   user's preference. */
.gear-tooltip__item a,
.gear-tooltip__item a * {
    pointer-events: none !important;
}
@media (max-width: 40rem) {
    .gear-progression { grid-template-columns: 1fr; }
}
.raider-class {
    margin: 0.5rem 0 1.5rem 0;
    font-size: 1.05rem;
    color: var(--ivory-dim);
    display: flex;
    align-items: center;
    gap: 1.5rem;
    flex-wrap: wrap;
}
.discord-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.15rem 0.7rem 0.15rem 0.55rem;
    border: 0.0625rem solid rgba(88, 101, 242, 0.5);
    border-radius: 999rem;
    /* Neutral dark fill so the blurple logo reads cleanly against it. */
    background: rgba(0, 0, 0, 0.35);
    font-size: 0.85rem;
    line-height: 1.3;
    color: var(--ivory);
}
.discord-pill__icon {
    width: 1rem;
    height: 1rem;
    display: inline-block;
}
.discord-pill__name {
    white-space: nowrap;
}

.stat-list {
    display: grid;
    /* `1fr` upper bound (not a fixed max) so auto-fit packs as many
       tracks of the 15.625rem minimum as fit on the viewport, then
       distributes leftover width back across them. A fixed maximum
       made the browser prefer fewer, wider tracks (3 fat tiles per
       row instead of 5–6 narrower ones on a wide screen). */
    grid-template-columns: repeat(auto-fit, minmax(15.625rem, 1fr));
    gap: 1rem;
    margin: 1rem 0 0 0;
    padding: 0;
}

.stat-list > div {
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    padding: 0.85rem 1rem;
    background: rgba(0, 0, 0, 0.15);
    max-width: 25rem;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
}

/* Modifier: stack values directly under their labels rather than
   pushing them to the bottom of the tile. Used on the View Raider
   page where rows mix short tiles (Raids Attended, iLvl, Guild,
   Has Cloak, Discord) with tall ones (Best Parse / Avg Parse) —
   without this, the short tiles' values float to the bottom and
   read as detached from their label. Other pages with uniformly
   tall tiles (Overview, Statistics) keep the default. */
.stat-list--stacked > div {
    justify-content: flex-start;
}

.stat-corner-icon { position: relative; }
.stat-corner-icon__btn {
    position: absolute;
    bottom: 0.5rem;
    right: 0.5rem;
    background: none;
    border: none;
    padding: 0.15rem;
    cursor: pointer;
    line-height: 0;
    border-radius: 0.2rem;
}
.stat-corner-icon__img {
    display: block;
    width: 1.1rem;
    height: 1.1rem;
    filter: brightness(0) invert(1);
    opacity: 0.35;
    pointer-events: none;
    transition: opacity 0.15s ease;
}
.stat-corner-icon__btn:hover .stat-corner-icon__img,
.stat-corner-icon__btn:focus-visible .stat-corner-icon__img { opacity: 0.85; }
/* Second icon button sits to the left of the primary one. */
.stat-corner-icon__btn--secondary { right: 2.1rem; }
/* Top-anchored variant — use when tile content would be obscured by the default bottom position. */
.stat-corner-icon__btn--top { bottom: auto; top: 0.5rem; }

.stat-list > div > dd {
    display: flex;
    flex-direction: column;
}

/* A grid cell holding two stacked tiles (e.g. "MC Clears" sitting
   above "MC Fastest Clear" on the Overview page). The wrapper itself
   is invisible — its children carry the tile chrome.
   Uses subgrid so the inner tiles inherit the parent grid's row
   tracks: row 1 across every column matches in height (Total Raids
   ↔ each "<zone> Clears"), and row 2 likewise across the fastest-
   clear tiles. Default `align-items: stretch` does the rest. */
.stat-list > div.stat-list__stack {
    border: none;
    border-radius: 0;
    padding: 0;
    background: none;
    display: grid;
    grid-row: span 2;
    grid-template-rows: subgrid;
    /* Single full-width column — without this the implicit column is
       auto-sized to its content (~128px), leaving the inner tiles
       narrower than the stack's actual grid track. */
    grid-template-columns: 1fr;
    gap: 1rem;
}

.stat-list__stack > div {
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    padding: 0.85rem 1rem;
    background: rgba(0, 0, 0, 0.15);
}

.stat-list dt {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--dust);
}

.stat-list dd {
    margin: 0.4rem 0 0 0;
    font-family: 'Cinzel', serif;
    font-size: 1.7rem;
    color: var(--ivory);
    /* Wrap inside the tile rather than overflowing — Discord
       nicknames can be long, run-on, and lacking spaces. */
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Sub-line beneath a stat-list value — used for "(N partial clears)"
   and "in the last 30 days" qualifiers. Smaller, dimmer, on its own
   row so it reads as context rather than another data point. */
.stat-list__sub {
    display: block;
    font-family: var(--font-body, inherit);
    font-size: 0.78rem;
    color: var(--dust);
    margin-top: 0.15rem;
}

/* When a sub-line sits as a direct child of a corner-icon tile, keep
   its right edge clear of the absolutely-positioned button (Rankings
   boss tiles render the sub at the bottom of the card, where it would
   otherwise overlap the open icon). */
.stat-corner-icon > .stat-list__sub {
    margin-right: 1rem;
}


/* Linked-character expansion in the Petri / pot leaderboards. The main
   row carries a circular ▸ chevron that rotates 90° when its sub-rows
   open; each linked character is its own <tr> below sharing the parent
   table's column grid, so the per-character count column-aligns with
   the main Uses column. Sub-rows are hidden by default. */
/* Rank cell holds the optional toggle + rank number side by side.
   Whitespace is set with margin on the toggle, not flex on the td,
   so the cell still behaves as a normal table cell. */
.use-row__rank-num { vertical-align: middle; }
.use-row__expand-col {
    width: 2rem;
    text-align: center;
    padding-left: 0.25rem;
    padding-right: 0.25rem;
}
.use-row__toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.4rem;
    height: 1.4rem;
    vertical-align: middle;
    background: rgba(0, 0, 0, 0.2);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 50%;
    padding: 0;
    cursor: pointer;
    color: var(--ivory-dim);
    font-size: 0.8rem;
    line-height: 1;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.use-row__toggle:hover,
.use-row__toggle:focus-visible {
    background: var(--ink-leather);
    border-color: var(--gilt-dim);
    color: var(--ivory);
}
.use-row__chevron {
    display: inline-block;
    transition: transform 0.15s ease;
    transform-origin: center;
}
.use-row.is-expanded .use-row__chevron { transform: rotate(90deg); }
.use-row__sub > td {
    padding-top: 0.4rem;
    padding-bottom: 0.4rem;
    background: rgba(0, 0, 0, 0.12);
    border-bottom-color: var(--ink-leather);
    font-size: 0.92rem;
}
.use-row__sub-name {
    /* Indent so it visually nests under the parent group row. */
    padding-left: 2.5rem !important;
    color: var(--ivory-dim);
}
.use-row__sub-count {
    color: var(--ivory-dim);
    font-variant-numeric: tabular-nums;
}

/* Two-column split inside a single stat-list tile (e.g. "Petris Used"
   showing Total and Most side-by-side). Replaces the dd's default
   single-column layout with a flex row + vertical divider. */
.stat-split {
    flex-direction: row !important;
    gap: 0;
    margin-top: 0.4rem !important;
}
.stat-split__col {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 0 0.5rem;
}
.stat-split__col + .stat-split__col {
    border-left: 0.0625rem solid var(--ink-faint);
}
.stat-split__label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--dust);
    margin-bottom: 0.25rem;
}
.stat-split__value {
    font-family: 'Cinzel', serif;
    font-size: 1.7rem;
    color: var(--ivory);
    line-height: 1;
}

.raider-link-line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin: 0.5rem 0;
    color: var(--ivory-dim);
}

.raider-alt-list {
    list-style: none;
    padding: 0;
    margin: 0.5rem 0 1rem 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.raider-alt-list > li {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.raider-link-form {
    display: inline;
    margin: 0;
}

.raider-link-add {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.75rem;
    margin: 1rem 0 0 0;
    padding: 0.85rem 1rem;
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    background: rgba(0, 0, 0, 0.15);
}

.raider-link-add label {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    flex-grow: 1;
    min-width: 13.75rem;
}

.raider-link-add label > span {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--dust);
}

.raider-link-add input[type="text"] {
    padding: 0.45rem 0.65rem;
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    background: rgba(0, 0, 0, 0.25);
    color: var(--ivory);
    font: inherit;
}

.raider-link-add input[type="text"]:focus {
    outline: none;
    border-color: var(--gilt-dim);
}

.raider-nickname-form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.75rem;
    margin: 1rem 0 0 0;
    padding: 0.85rem 1rem;
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    background: rgba(0, 0, 0, 0.15);
}

.raider-nickname-form label {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    flex-grow: 1;
    min-width: 13.75rem;
}

.raider-nickname-form label > span {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--dust);
}

.raider-nickname-form input[type="text"] {
    padding: 0.45rem 0.65rem;
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    background: rgba(0, 0, 0, 0.25);
    color: var(--ivory);
    font: inherit;
}

.raider-nickname-form input[type="text"]:focus {
    outline: none;
    border-color: var(--gilt-dim);
}

/* ─── Raiders list grouping ──────────────────────────── */
.raiders-table .expand-col {
    width: 1%;
    white-space: nowrap;
    padding-right: 0;
}

.expand-toggle {
    appearance: none;
    -webkit-appearance: none;
    width: 1.375rem;
    height: 1.375rem;
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    background: rgba(0, 0, 0, 0.25);
    color: var(--ivory-dim);
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.95rem;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.expand-toggle:hover {
    border-color: var(--gilt-dim);
    color: var(--ivory);
}

.expand-toggle[aria-expanded="true"] {
    border-color: var(--gilt-dim);
    color: var(--gilt);
}

.raiders-table tr.group-row td {
    font-weight: 500;
}

.raiders-table tr.member-row td {
    padding-left: 2.5rem;
    background: rgba(0, 0, 0, 0.15);
    border-top: 0.0625rem dashed var(--ink-faint);
}

.class-cluster {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
}

/* ─── Sync progress modal ─────────────────────────── */
.sync-progress-card {
    min-width: 26.25rem;
}

.progress-block {
    margin: 0.85rem 0;
}

.progress-label {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ivory-dim);
    margin: 0 0 0.4rem 0;
}

.progress-bar {
    height: 0.625rem;
    background: var(--ink-faint);
    border-radius: 62.4375rem;
    overflow: hidden;
    border: 0.0625rem solid var(--ink-faint);
}

.progress-bar-fill {
    height: 100%;
    background: var(--gilt);
    transition: width 0.25s ease;
    width: 0;
}

/* ─── Tabs (Raid detail) ─────────────────────────────── */
/* Underline-style tab bar — gilt accent on the active tab,
   ivory hover on the inactive ones. Panels hide via the native
   [hidden] attribute that tabs.js toggles. */
.tabs {
    margin-top: 2rem;
}

.tabs__nav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    border-bottom: 0.0625rem solid var(--ink-rule);
    margin-bottom: 1.25rem;
}

.tabs__tab {
    appearance: none;
    background: transparent;
    border: 0;
    border-bottom: 0.125rem solid transparent;
    color: var(--dust);
    padding: 0.7rem 1.1rem;
    font-family: var(--font-display);
    font-size: 0.95rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
    margin-bottom: -0.0625rem; /* overlap the .tabs__nav border so the active underline replaces it */
}

.tabs__tab:hover {
    color: var(--ivory);
}

.tabs__tab[aria-selected="true"] {
    color: var(--gilt);
    border-bottom-color: var(--gilt);
}

.tabs__tab:focus-visible {
    outline: 0.0625rem solid var(--gilt);
    outline-offset: 0.125rem;
    border-radius: 0.125rem;
}

.tabs__panel[hidden] {
    display: none;
}

/* Nested sub-tabs: same visual idiom as the top-level tab strip but
   slightly smaller so it reads as a child of its parent tab panel
   rather than a peer. Sits flush under the main tab bar — the parent
   .tabs__nav already provides the gap below itself. */
.sub-tabs {
    margin-top: 0;
}

.sub-tabs__nav {
    margin-bottom: 1rem;
    gap: 0.15rem;
    border-bottom-color: var(--ink-faint);
}

.sub-tabs__nav .tabs__tab {
    font-size: 0.82rem;
    padding: 0.4rem 0.85rem;
    letter-spacing: 0.06em;
}

/* Stack the panel's contents (stat card, lede, table) with a
   consistent 15px gap. `:not([hidden])` keeps the existing hidden-
   panel rule winning since flex would otherwise override it at the
   same specificity. */
.sub-tabs > .tabs__panel:not([hidden]) {
    display: flex;
    flex-direction: column;
    gap: 0.9375rem;
}

/* ─── Sub-raid tab strip (Raid detail, split-night raids) ── */
.sub-raid-tabs {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.4rem;
    margin: 0 0 1.5rem 0;
}

.sub-raid-tabs__tab {
    display: inline-block;
    padding: 0.45rem 1rem;
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.1875rem;
    background: transparent;
    color: var(--dust);
    font-family: var(--font-display);
    font-size: 0.85rem;
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    text-decoration: none;
    transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}

.sub-raid-tabs__tab:hover {
    color: var(--ivory);
    border-color: var(--gilt-dim);
}

.sub-raid-tabs__tab.is-active {
    color: var(--gilt);
    border-color: var(--gilt);
    background: rgba(0, 0, 0, 0.15);
}

.sub-raid-tabs__tab:focus-visible {
    outline: 0.0625rem solid var(--gilt);
    outline-offset: 0.125rem;
}

/* ─── Manage Raids "Parses" column ── */
.parses-tick  { color: #a6d36b; font-size: 1.2rem; font-weight: 600; }
.parses-cross { color: var(--dust); font-size: 1.2rem; font-weight: 600; cursor: help; }

/* ─── Raid composition pieces (Raids list Composition column) ── */
.comp-tank   { color: #6da4d6; font-weight: 500; margin-right: 0.5rem; display: inline-flex; align-items: center; gap: 0.25rem; }
.comp-healer { color: #6dd683; font-weight: 500; margin-right: 0.5rem; display: inline-flex; align-items: center; gap: 0.25rem; }
.comp-dps    { color: #d6766d; font-weight: 500; display: inline-flex; align-items: center; gap: 0.25rem; }
.composition-stat { flex-direction: row !important; align-items: center; gap: 1rem; margin-top: 0.4rem; }

/* ─── iLvl tier colors (matches WoW item-quality palette) ── */
.ilvl-grey   { color: #9d9d9d; font-weight: 500; }
.ilvl-white  { color: #ffffff; font-weight: 500; }
.ilvl-green  { color: #1eff00; font-weight: 500; }
.ilvl-blue   { color: #3aa1ff; font-weight: 500; } /* lifted from #0070dd for contrast on dark themes */
.ilvl-purple { color: #c466ff; font-weight: 500; } /* lifted from #a335ee */
.ilvl-orange { color: #ff8000; font-weight: 500; }

/* ─── Parse percentile colors (matches WCL's own palette) ── */
.parse-grey   { color: #9d9d9d; font-weight: 500; }
.parse-green  { color: #1eff00; font-weight: 500; }
.parse-blue   { color: #3aa1ff; font-weight: 500; }
.parse-purple { color: #c466ff; font-weight: 500; }
.parse-orange { color: #ff8000; font-weight: 500; }
.parse-pink   { color: #e268a8; font-weight: 600; }

/* ─── Improvement / positive delta ──────────────────── */
.text-improvement { color: #4ade80; }

/* ─── Dead-character marker ──────────────────────────── */
.dead-marker {
    display: inline-block;
    width: 1.15em;
    height: 1.15em;
    margin-left: 0.35rem;
    vertical-align: -0.2em;
    cursor: help;
}

h2 .dead-marker {
    width: 0.85em;
    height: 0.85em;
    margin-left: 0.5rem;
    vertical-align: 0.05em;
}

.class-cell.is-dead {
    color: var(--dust);
    text-decoration: line-through;
    text-decoration-color: var(--ruby);
    text-decoration-thickness: 0.0625rem;
}

/* ─── Collapsible section (details/summary) ──────────── */
/* Generic show/hide section used for the Fire Blossom and GFPP
   blocks on the MC tab. Pair the .collapsible wrapper with
   .collapsible__summary on the <summary>; that summary picks up
   .subhead typography while we add a rotating chevron. */
.collapsible {
    margin: 2.5rem 0 1rem;
}

.collapsible[open] {
    margin-bottom: 1rem;
}

.collapsible__summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    /* Override .subhead's vertical margin so the wrapper provides
       the spacing (otherwise we'd get double-margin between sections). */
    margin: 0;
    user-select: none;
}

.collapsible__summary::-webkit-details-marker {
    display: none;
}

.collapsible__summary::before {
    content: '';
    width: 0.5rem;
    height: 0.5rem;
    border-right: 0.125rem solid var(--gilt-dim);
    border-bottom: 0.125rem solid var(--gilt-dim);
    transform: rotate(-45deg);
    transition: transform 0.15s ease, border-color 0.15s ease;
}

.collapsible[open] > .collapsible__summary::before {
    transform: rotate(45deg);
}

.collapsible__summary:hover {
    color: var(--ivory);
}

.collapsible__summary:hover::before {
    border-color: var(--gilt);
}

.collapsible__summary:focus-visible {
    outline: 0.0625rem solid var(--gilt);
    outline-offset: 0.1875rem;
    border-radius: 0.125rem;
}

/* Scroll wrapper around the collapsible's table. Defaults to a
   400px clamp with sticky thead; the .is-expanded class (toggled
   by the button in the summary) drops the clamp so the table
   flows at natural height. JS handles the in-flight max-height
   animation since CSS can't transition to/from `none` directly. */
.collapsible__scroll {
    max-height: 25rem;
    overflow-y: auto;
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.25rem;
    margin-top: 1.5rem;
    transition: max-height 0.35s ease;
}

.collapsible__scroll > .data-table,
.collapsible__scroll .dt-container > .data-table {
    margin-top: 0;
}

.collapsible__scroll thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--ink-leather);
    box-shadow: inset 0 -0.0625rem 0 var(--ink-rule);
    border-bottom: 0;
}

.collapsible__scroll.is-expanded {
    max-height: none;
    overflow-y: visible;
}

/* Expand/collapse toggle button sitting on the right of each
   .collapsible__summary. Click is intercepted in JS so it doesn't
   also flip the surrounding <details> open state. */
.collapsible__expand-toggle {
    margin-left: auto;
    appearance: none;
    background: transparent;
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.1875rem;
    color: var(--dust);
    cursor: pointer;
    padding: 0.3rem 0.45rem;
    line-height: 0;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.collapsible__expand-toggle:hover {
    color: var(--gilt);
    border-color: var(--gilt-dim);
}

.collapsible__expand-toggle:focus-visible {
    outline: 0.0625rem solid var(--gilt);
    outline-offset: 0.125rem;
}

.collapsible__expand-toggle__icon {
    display: inline-block;
}

.collapsible__expand-toggle[aria-expanded="false"] .collapsible__expand-toggle__icon--collapse,
.collapsible__expand-toggle[aria-expanded="true"]  .collapsible__expand-toggle__icon--expand {
    display: none;
}

/* When the surrounding <details> is collapsed there's no table to
   resize — hide the toggle so the summary doesn't carry a button
   that would do nothing visible if clicked. Scoped to <details> so
   div.collapsible wrappers (standalone expand bars) always show it. */
details.collapsible:not([open]) .collapsible__expand-toggle {
    display: none;
}

/* Expand bar for standalone tables not wrapped in a <details>.
   Sits above the .collapsible__scroll wrapper and right-aligns
   the expand toggle button. */
.expand-bar {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 0.5rem;
}

/* ─── Total Raid Time breakdown (stat-list cell) ─────── */
/* Sub-list rendered under the main duration value inside the
   Deaths-row stat tile. Keeps the headline number prominent
   in the existing display font and stacks per-type rows in
   the body font below. */
.raid-time-breakdown {
    list-style: none;
    margin: 0.55rem 0 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 0.6rem;
    row-gap: 0.15rem;
    font-family: var(--font-body);
    font-size: 0.78rem;
    line-height: 1.2;
    color: var(--ivory-dim);
}

.raid-time-breakdown li {
    display: contents;
}

.raid-time-breakdown__code {
    color: var(--gilt-dim);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 500;
}

.raid-time-breakdown__value {
    font-variant-numeric: tabular-nums;
}

/* ─── GFPP stats card (Raid view) ────────────────────── */
/* Sits below the .stat-list at the top of a raid view, only
   when the raid included Molten Core. Average is the headline,
   worst/best stats sit beneath a gilt rule. */
.gfpp-card {
    margin-top: 1rem;
    padding: 1.1rem 1.4rem 1.25rem;
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    background: rgba(0, 0, 0, 0.15);
}

.gfpp-card__title {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--dust);
}

.gfpp-card__subtitle {
    margin-top: 0.15rem;
    font-size: 0.78rem;
    font-style: italic;
    color: var(--ink-faint);
}

.gfpp-card__value {
    margin-top: 0.35rem;
    font-family: var(--font-display);
    font-size: 2.6rem;
    line-height: 1;
    text-shadow: 0 0.0625rem 0 var(--shadow);
}

.gfpp-card__bounds {
    display: flex;
    gap: 2.5rem;
    margin-top: 1rem;
    padding-top: 0.85rem;
    border-top: 0.0625rem solid var(--ink-rule);
    flex-wrap: wrap;
}

.gfpp-card__bound {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.gfpp-card__bound-label {
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--dust);
}

.gfpp-card__bound-value {
    font-family: var(--font-display);
    font-size: 1.15rem;
    line-height: 1.1;
}

.gfpp-card__bound-name {
    font-size: 0.85rem;
    color: var(--ivory-dim);
    text-decoration: none;
    border-bottom: 0.0625rem dotted var(--ink-rule);
    width: max-content;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.gfpp-card__bound-name:hover {
    color: var(--gilt);
    border-bottom-color: var(--gilt-dim);
}

/* ─── Partial-presence tooltip ───────────────────────── */
/* Trigger sits in the Presence cell on the raid detail page.
   Dotted underline tells the user there's hidden detail; on
   hover/focus a parchment-styled card floats above listing the
   bosses they were missing, grouped by zone. */
.presence-partial {
    position: relative;
    display: inline-block;
    text-decoration: underline dotted;
    text-decoration-thickness: 0.0625rem;
    text-underline-offset: 0.1875rem;
    cursor: help;
    outline: none;
}

.presence-partial:focus-visible {
    outline: 0.0625rem solid var(--gilt);
    outline-offset: 0.125rem;
    border-radius: 0.125rem;
}

.presence-tooltip {
    position: absolute;
    bottom: calc(100% + 0.625rem);
    left: 50%;
    transform: translateX(-50%) translateY(0.25rem);
    z-index: 50;

    /* width: max-content lets the box grow to fit its content (so a long
       boss list on a single line is preferred), capped at max-width.
       Without this, the abs-positioned box shrink-fits to the trigger's
       narrow containing block and wraps mid-name. */
    width: max-content;
    min-width: 14rem;
    max-width: calc(22rem + 9.375rem);
    padding: 0.85rem 1rem 0.95rem;

    background: linear-gradient(180deg, var(--ink-parchment) 0%, var(--ink-leather) 100%);
    border: 0.0625rem solid var(--gilt-dim);
    border-radius: 0.125rem;
    box-shadow:
        0 0 0 0.0625rem var(--shadow),
        0 0.75rem 1.75rem -0.5rem rgba(0, 0, 0, 0.7),
        0 0 1.5rem -0.375rem var(--glow-primary);

    color: var(--ivory);
    text-align: left;
    text-decoration: none;
    line-height: 1.4;
    white-space: normal;

    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition:
        opacity 0.18s ease-out,
        transform 0.18s ease-out,
        visibility 0s linear 0.18s;
}

/* Gilt arrow under the card pointing at the trigger. Two stacked
   pseudos: the outer (::before) draws the gilt border edge, the
   inner (::after) sits one pixel up inside it for the fill, so the
   arrow seam matches the card's 1px gilt outline. */
.presence-tooltip::before,
.presence-tooltip::after {
    content: '';
    position: absolute;
    left: 50%;
    width: 0;
    height: 0;
    border-left: 0.4375rem solid transparent;
    border-right: 0.4375rem solid transparent;
}

.presence-tooltip::before {
    top: 100%;
    transform: translateX(-50%);
    border-top: 0.4375rem solid var(--gilt-dim);
}

.presence-tooltip::after {
    top: 100%;
    transform: translateX(-50%) translateY(-0.0625rem);
    border-top: 0.4375rem solid var(--ink-leather);
}

.presence-partial:hover .presence-tooltip,
.presence-partial:focus-visible .presence-tooltip,
.presence-partial:focus-within .presence-tooltip,
.dead-marker-wrap:hover .presence-tooltip,
.dead-marker-wrap:focus-visible .presence-tooltip,
.dead-marker-wrap:focus-within .presence-tooltip {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
    transition:
        opacity 0.18s ease-out,
        transform 0.18s ease-out,
        visibility 0s;
}

/* Dead-marker tooltip wrapper — shares the .presence-tooltip popup
   styling but doesn't carry the dotted-underline that .presence-partial
   uses for text-trigger targets (the icon doesn't need it). The wrapper
   inherits the marker's left margin so it sits the same distance from
   preceding text whether or not the tooltip is wrapped around it. */
.dead-marker-wrap {
    position: relative;
    display: inline-block;
    margin-left: 0.35rem;
    cursor: help;
    line-height: 1;
}

.dead-marker-wrap .dead-marker {
    margin-left: 0;
}

h2 .dead-marker-wrap {
    margin-left: 0.5rem;
}

.presence-tooltip__title {
    display: block;
    font-family: var(--font-display);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--gilt);
    text-shadow: 0 0.0625rem 0 var(--shadow);
    padding-bottom: 0.45rem;
    margin-bottom: 0.55rem;
    border-bottom: 0.0625rem solid var(--ink-rule);
}

.presence-tooltip__list {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 0.85rem;
    row-gap: 0.4rem;
    font-size: 0.85rem;
}

.presence-tooltip__list dt {
    font-family: var(--font-display);
    font-size: 0.72rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--gilt-dim);
    white-space: nowrap;
    padding-top: 0.08em;
}

.presence-tooltip__list dd {
    color: var(--ivory);
    margin: 0;
}

.death-tooltip__list {
    list-style: none;
    margin: 0;
    padding: 0;
    color: var(--ivory);
    font-size: 0.78rem;
    line-height: 1.5;
    text-align: left;
    max-height: 14rem;
    overflow-y: auto;
}

.death-tooltip__list li {
    display: flex;
    flex-direction: column;
    gap: 0.05rem;
    padding-block: 0.15rem;
}

.death-tooltip__name {
    font-weight: 500;
}

.death-tooltip__cause {
    font-size: 0.72rem;
    color: var(--gilt-dim);
    white-space: normal;
}

.death-tooltip__fight {
    color: var(--gilt);
}

.death-tooltip__note {
    margin-top: 0.25rem;
    padding-top: 0.25rem;
    border-top: 0.0625rem solid var(--gilt-dim);
    color: var(--gilt-dim);
    font-style: italic;
    white-space: normal;
}

.death-cause {
    list-style: none;
    margin: 0.5rem 0 0;
    padding: 0;
    font-size: 0.85rem;
    line-height: 1.5;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.death-cause li {
    color: var(--ivory);
}

.death-cause__note {
    font-style: italic;
    color: var(--gilt-dim);
    border-left: 0.125rem solid var(--gilt-dim);
    padding-left: 0.6rem;
    margin-top: 0.25rem;
}

.death-cause-form {
    margin-top: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-width: 36rem;
}

.death-cause-form label {
    font-size: 0.85rem;
    color: var(--gilt);
}

.death-cause-form textarea {
    width: 100%;
    font-family: inherit;
    font-size: 0.9rem;
    padding: 0.5rem 0.65rem;
    background: var(--ink-leather);
    border: 0.0625rem solid var(--gilt-dim);
    color: var(--ivory);
    border-radius: 0.1875rem;
    resize: vertical;
}

.class-cell.is-dead .class-icon {
    filter: grayscale(0.85) brightness(0.6);
}

.stat-list > div.stat-dead {
    border-color: var(--ruby);
}

.stat-list > div.stat-dead dd {
    font-size: 1.05rem;
    color: var(--ivory-dim);
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.death-status-line {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.raider-lifecycle-form {
    margin: 0.75rem 0 1rem 0;
}

/* Inline two action buttons (Mark as Dead + Link Characters) side-by-side. */
.action-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin: 0.75rem 0 1rem 0;
}

.action-row > form,
.action-row .raider-lifecycle-form {
    margin: 0;
}

.raider-link-add-wrap {
    margin: 0 0 1rem 0;
}

.raider-link-add-wrap > .raider-link-add {
    margin-top: 0;
}

/* ─── Filter panel (Attendance page) ─────────────────── */
.filter-panel {
    margin-top: 1.5rem;
    margin-bottom: 1.5rem;
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.375rem;
    background: rgba(0, 0, 0, 0.15);
}

.filter-panel-summary {
    /* Strip the default disclosure marker so we can supply our own chevron. */
    list-style: none;
    cursor: pointer;
    padding: 0.7rem 1.25rem;
    font-family: 'Cinzel', serif;
    font-size: 0.95rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ivory-dim);
    user-select: none;
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.filter-panel-summary::-webkit-details-marker {
    display: none;
}

.filter-panel-summary::before {
    content: '';
    width: 0.5rem;
    height: 0.5rem;
    border-right: 0.125rem solid var(--gilt-dim);
    border-bottom: 0.125rem solid var(--gilt-dim);
    transform: rotate(-45deg);
    transition: transform 0.15s ease;
}

.filter-panel[open] > .filter-panel-summary::before {
    transform: rotate(45deg);
}

.filter-panel-summary:hover {
    color: var(--ivory);
}

.filter-panel[open] > .filter-panel-summary {
    border-bottom: 0.0625rem solid var(--ink-faint);
}

.filter-bar {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    padding: 1rem 1.25rem;
}

.filter-search {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    max-width: 20rem;
}

.filter-search > span {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--dust);
}

.filter-search > input {
    padding: 0.45rem 0.65rem;
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    background: rgba(0, 0, 0, 0.25);
    color: var(--ivory);
    font: inherit;
}

.filter-search > input:focus {
    outline: none;
    border-color: var(--gilt-dim);
}

.filter-group {
    border: none;
    padding: 0;
    margin: 0;
}

.filter-group > legend {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--dust);
    margin-bottom: 0.5rem;
    padding: 0;
}

.filter-options {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
}

/* Dropdown variant inside a .filter-group (e.g. the Raiders Guild
   filter). Pulls the same theme tokens as inputs in the modal/login
   forms so it doesn't look like a stock browser select. */
.filter-select {
    appearance: none;
    background: var(--ink-deep);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.1875rem;
    color: var(--ivory);
    padding: 0.4rem 0.7rem;
    font-family: var(--font-body);
    font-size: 0.95rem;
    min-width: 11rem;
    cursor: pointer;
}

.filter-select:focus {
    outline: 0.0625rem solid var(--gilt);
    outline-offset: 0.0625rem;
}

/* Clear-flag form on the Manage Syncs admin page — dropdown + submit
   laid out on one row, with the small-cap label tucked above the
   select like a stat-list dt so the screen reader and the eye both
   read "label → control → action" in the same direction. */
.clear-flag-form {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1rem;
}

.clear-flag-form__field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    min-width: 14rem;
}

.clear-flag-form__field > span {
    font-family: var(--font-body);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--dust);
}

.clear-flag-form__select {
    /* The flag column names are wider than the .filter-select default
       (e.g. "attendance_synced_at"), so widen the minimum and switch
       to monospace so they line up consistently in the dropdown. */
    min-width: 14rem;
    font-family: var(--font-mono);
    font-size: 0.85rem;
    letter-spacing: 0.02em;
}

/* Dropdown inlined into a sentence (e.g. the Low Health Players
   threshold picker). Sized to the option text, picks up the body
   font + page-section colors so it reads as part of the prose. */
.inline-select {
    appearance: none;
    background: var(--ink-deep);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.1875rem;
    color: var(--gilt);
    padding: 0.05rem 0.4rem;
    font-family: inherit;
    font-size: inherit;
    cursor: pointer;
    margin: 0 0.2rem;
}

.inline-select:focus {
    outline: 0.0625rem solid var(--gilt);
    outline-offset: 0.0625rem;
}

.filter-option {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    cursor: pointer;
    color: var(--ivory-dim);
}

.filter-option:hover {
    color: var(--ivory);
}

.filter-actions {
    display: flex;
    gap: 0.75rem;
    align-items: center;
}

.class-icon {
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 0.1875rem;
    flex-shrink: 0;
    /* Blizzard's classicon art ships with a transparent border ring;
       a faint outline tightens the contrast on dark backgrounds. */
    box-shadow: 0 0 0 0.0625rem rgba(0, 0, 0, 0.4);
}

/* Wraps a class-icon when the cell may carry a dead marker, so the
   skull can be positioned absolutely on top of the icon (centered).
   Inline-block + line-height: 0 so the wrap sits flush against
   adjacent flex items in .class-cell without adding vertical space. */
.class-icon-wrap {
    position: relative;
    display: inline-block;
    line-height: 0;
    flex-shrink: 0;
}

.class-icon-wrap .dead-marker-wrap,
.class-icon-wrap > .dead-marker {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    margin: 0;
}

.class-icon-wrap .dead-marker {
    width: 1.05rem;
    height: 1.05rem;
    vertical-align: baseline;
}

/* Per-class mini-grid that sits at the bottom of each Raider
   Statistics tile (Overview page). Two visual rows: a row of class
   icons on top, a row of counts below. Implemented as one flex
   column per class — uniform icon and count heights mean per-cell
   stacking is enough to keep both rows aligned across cells. */
.class-breakdown {
    display: grid;
    grid-template-columns: repeat(8, minmax(0, 1fr));
    gap: 0.35rem 0.25rem;
    padding-top: 0.5rem;
    border-top: 0.0625rem dotted var(--ink-faint);
}

/* ─── Roster stat tile — class breakdown slide-out panel ── */
.stat-tile { position: relative; }

.stat-breakdown-toggle {
    display: block;
    width: 100%;
    background: none;
    border: none;
    border-top: 0.0625rem solid var(--ink-faint);
    padding: 0.3rem 0;
    cursor: pointer;
    color: var(--dust);
    text-align: center;
    line-height: 1;
    transition: color 0.15s;
    margin-top: auto;
}
.stat-breakdown-toggle:hover,
.stat-breakdown-toggle:focus-visible { color: var(--ivory-dim); outline: none; }
.stat-breakdown-toggle svg {
    display: block;
    margin: 0 auto;
    transition: transform 0.25s ease;
}
.stat-breakdown-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

.stat-breakdown-panel {
    position: absolute;
    top: 100%;
    left: -0.0625rem;
    right: -0.0625rem;
    z-index: 20;
    background: var(--ink-parchment);
    border: 0.0625rem solid var(--ink-faint);
    border-top: none;
    border-radius: 0 0 0.25rem 0.25rem;
    overflow: hidden;
    max-height: 0;
    transition: max-height 0.25s ease;
}
.stat-breakdown-panel.is-open { max-height: 6rem; }
.stat-breakdown-panel > .class-breakdown {
    padding: 0.6rem 1rem 0.75rem;
    border-top: none;
}

/* The first breakdown in a dd claims any spare vertical space above
   it — the breakdown ends up flush with the bottom of the tile while
   the headline number + optional sub-line sit at the top. Subsequent
   breakdowns (e.g. the second grid in the Total Deaths tile) stack
   directly under the first with their own dotted divider. */
.stat-list > div > dd > .class-breakdown:first-of-type {
    margin-top: auto;
}

/* Caption row shown above the icons inside a labelled breakdown
   (Total Deaths uses "In Raid" / "Other"). Spans the full width of
   the per-class grid by claiming all 8 columns. */
.class-breakdown__label {
    grid-column: 1 / -1;
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--dust);
    margin-bottom: -0.1rem;
}

.class-breakdown__cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    min-width: 0;
}

.class-breakdown__icon {
    width: 1rem;
    height: 1rem;
    border-radius: 0.1875rem;
    box-shadow: 0 0 0 0.0625rem rgba(0, 0, 0, 0.4);
}

.class-breakdown__count {
    font-family: var(--font-body);
    font-size: 0.78rem;
    line-height: 1;
    color: var(--ivory-dim);
    font-variant-numeric: tabular-nums;
}

/* ─── Attendance podium — top-3 leaderboard inside a stat tile ── */
.att-podium {
    display: flex;
    gap: 0.4rem;
    margin-top: 0.6rem;
    width: 100%;
}
.att-podium__place {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 0.2rem 0.4rem;
    border-radius: 0.25rem;
    background: rgba(255, 255, 255, 0.03);
    border: 0.0625rem solid var(--ink-faint);
    text-align: center;
    min-width: 0;
}
.att-podium__rank {
    font-family: var(--font-head);
    font-size: 0.9rem;
    font-weight: 700;
    line-height: 1;
}
.att-podium__place--1 .att-podium__rank { color: var(--gilt); }
.att-podium__place--2 .att-podium__rank { color: #b0b0c0; }
.att-podium__place--3 .att-podium__rank { color: #9b6f42; }
.att-podium__count {
    font-family: var(--font-head);
    font-size: 1.4rem;
    font-weight: 700;
    line-height: 1;
    color: var(--ivory);
}
.att-podium__name {
    font-size: 0.78rem;
    line-height: 1.2;
    color: var(--ivory-dim);
    word-break: break-word;
    overflow-wrap: anywhere;
}
a.att-podium__name:not([class*="wc-"]) { color: var(--ivory-dim); }
a.att-podium__name:not([class*="wc-"]):hover { color: var(--ivory); }

/* ─── Lazy-load skeleton spinner ── */
@keyframes stat-spin { to { transform: rotate(360deg); } }
.stat-loading {
    display: inline-block;
    width: 0.85rem;
    height: 0.85rem;
    border: 0.125rem solid var(--ink-faint);
    border-top-color: var(--gilt);
    border-radius: 50%;
    animation: stat-spin 0.75s linear infinite;
    vertical-align: middle;
    opacity: 0.7;
}

.zone-loading-placeholder {
    display: flex;
    justify-content: center;
    padding: 3rem 0;
}

.row-tag {
    display: inline-block;
    margin-left: 0.5rem;
    padding: 0.1rem 0.6rem;
    font-size: 0.65rem;
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--gilt-dim);
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 62.4375rem;
    vertical-align: middle;
}

.status-pill {
    display: inline-block;
    padding: 0.2rem 0.75rem;
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    border: 0.0625rem solid;
    border-radius: 62.4375rem;
    line-height: 1.4;
}

/* Raid view: title row + pills row. The Edit Raid button sits inline
   with the title for managers; the loading-state pills moved onto a
   sibling row beneath so the heading stays clean. */
.raid-title {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.75rem;
}

.raid-title__edit {
    font-size: 0.75rem;
    padding: 0.25rem 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    align-self: center;
}

.raid-status-pills {
    margin: 0.4rem 0 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

/* ── Data-Loading pill with hover tooltip ────────────────────────────
   A single "Data Loading" pill replaces the old per-feature pills.
   Hovering reveals a floating tooltip listing which syncs are pending.
*/
.sync-loading-pill {
    position: relative;
    cursor: help;
}
.sync-loading-tooltip {
    position: absolute;
    bottom: calc(100% + 0.4rem);
    left: 50%;
    transform: translateX(-50%);
    z-index: 50;
    min-width: 11rem;
    padding: 0.45rem 0.7rem;
    background: var(--ink-leather);
    color: var(--ink-paper, #e6dec9);
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.5);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 120ms ease-out, visibility 120ms ease-out;
    white-space: nowrap;
}
.sync-loading-pill:hover .sync-loading-tooltip,
.sync-loading-pill:focus-visible .sync-loading-tooltip,
.sync-loading-pill:focus-within .sync-loading-tooltip {
    opacity: 1;
    visibility: visible;
}
.sync-loading-tooltip::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 0.35rem solid transparent;
    border-top-color: var(--ink-faint);
}
.sync-loading-tooltip__list {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    font-size: 0.75rem;
    line-height: 1.4;
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
}
.sync-loading-tooltip__item {
    display: block;
}
.sync-loading-tooltip__item::before {
    content: "• ";
    color: var(--gilt-dim);
}

.status-pill--on {
    color: var(--gilt);
    border-color: var(--gilt-dim);
    background: rgba(212, 167, 71, 0.06);
}

.status-pill--off {
    color: var(--dust);
    border-color: var(--ink-faint);
    background: transparent;
}

/* Verdant green — for "all good" / "complete" states (e.g. fully synced). */
.status-pill--ok {
    color: #a6d36b;
    border-color: #6b8a30;
    background: rgba(155, 209, 78, 0.08);
}

/* Ember orange — for "needs attention" / "incomplete" states. */
.status-pill--warn {
    color: #f0a04a;
    border-color: #a36a25;
    background: rgba(240, 160, 74, 0.08);
}

/* ─── Inline action buttons ──────────────────────────── */

.action-buttons {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 1.25rem;
}

.btn-link {
    background: none;
    border: none;
    padding: 0.25rem 0;
    color: var(--ivory-dim);
    font-family: var(--font-body);
    font-size: 0.85rem;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    transition: color 0.2s ease;
}

.btn-link:hover {
    color: var(--gilt);
}

/* Bordered variant — applied to row-action buttons in tables and the
   inline Edit Date button. Plain .btn-link links (back-link, URL link
   inside log table) stay borderless. */
.action-buttons form {
    margin: 0;
    display: inline-flex;
}

.action-buttons .btn-link,
.action-row .btn-link,
.raid-date-row [data-edit-date] {
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.1875rem;
    padding: 0.3rem 0.75rem;
}

.action-buttons .btn-link:hover,
.action-row .btn-link:hover,
.raid-date-row [data-edit-date]:hover {
    border-color: var(--gilt-dim);
}

/* Destructive variant — used on Delete-style row actions. */
.action-buttons .btn-link--danger,
.action-row .btn-link--danger {
    color: var(--ruby-bright);
    border-color: var(--ruby);
}

.action-buttons .btn-link--danger:hover,
.action-row .btn-link--danger:hover {
    color: var(--ivory);
    background: var(--ruby);
    border-color: var(--ruby);
}

.btn-ghost,
.btn-danger,
.btn-primary,
.btn-success {
    padding: 0.6rem 1.25rem;
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    border-radius: 0.125rem;
    cursor: pointer;
    text-decoration: none;
    transition: all 0.2s ease;
}

.btn-ghost {
    background: transparent;
    color: var(--dust);
    border: 0.0625rem solid var(--ink-faint);
}

.btn-ghost:hover {
    color: var(--ivory);
    border-color: var(--gilt-dim);
}

/* Segmented toggle: two-button group acting as a tab strip. Outer ends
   are rounded; the inner edges sit flat against each other so they
   read as a single control. Active button is filled with gilt, the
   other is dimmed. */
.segmented-toggle {
    display: inline-flex;
    margin: 1rem 0 0;
    background: transparent;
}
.raid-chart {
    position: relative;
    height: 20rem;
    margin: 0.5rem 0 1rem;
}
.raid-chart canvas { max-width: 100%; }
/* Sub-headers inside the Charts sub-panel sit close to the segmented
   toggle above; the default .subhead top margin makes them float. */
[data-tanking-view-panel="charts"] .subhead { margin-top: 1rem; }
.segmented-toggle__btn {
    background: rgba(0, 0, 0, 0.25);
    color: var(--dust);
    border: 0.0625rem solid var(--ink-rule);
    padding: 0.4rem 1.1rem;
    font-size: 0.78rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.segmented-toggle__btn:first-child {
    border-radius: 999rem 0 0 999rem;
    /* Collapse the touching border so the seam reads as one stroke. */
    border-right-width: 0;
    padding-left: 1.3rem;
}
.segmented-toggle__btn:last-child {
    border-radius: 0 999rem 999rem 0;
    padding-right: 1.3rem;
}
.segmented-toggle__btn:hover {
    color: var(--ivory);
    border-color: var(--gilt-dim);
}
.segmented-toggle__btn:first-child:hover {
    /* Restore the right border when hovering the left button so the
       hover state is symmetric, then drop it again only when neither
       button is hovered. */
    border-right-width: 0.0625rem;
    margin-right: -0.0625rem;
}
.segmented-toggle__btn[aria-selected="true"] {
    background: var(--gilt-dim, #9b7a3a);
    color: var(--ink-paper, #f4ebd1);
    border-color: var(--gilt);
}
.segmented-toggle__btn[aria-selected="true"]:first-child {
    border-right-width: 0.0625rem;
    margin-right: -0.0625rem;
}
.segmented-toggle__btn:focus-visible {
    outline: 0.125rem solid var(--gilt);
    outline-offset: 0.125rem;
    z-index: 1;
}

/* Generic disabled / in-flight state for the shared button classes
   — prevents a double-submit visually mirroring the JS-set
   `disabled` attribute on [data-disable-on-submit] forms. */
.btn-ghost:disabled,
.btn-danger:disabled,
.btn-primary:disabled,
.btn-success:disabled,
.btn-ghost.is-busy,
.btn-danger.is-busy,
.btn-primary.is-busy,
.btn-success.is-busy {
    opacity: 0.55;
    cursor: progress;
    pointer-events: none;
}

.btn-danger {
    background: var(--ruby);
    color: var(--ivory);
    border: 0.0625rem solid var(--ruby);
}

.btn-danger:hover {
    background: var(--ruby-bright);
    border-color: var(--ruby-bright);
}

.btn-success {
    background: #3a7d4f;
    color: var(--ivory);
    border: 0.0625rem solid #3a7d4f;
}

.btn-success:hover {
    background: #4f9a66;
    border-color: #4f9a66;
}

.btn-primary {
    background: transparent;
    color: var(--gilt);
    border: 0.0625rem solid var(--gilt-dim);
    font-weight: 600;
    letter-spacing: 0.16em;
}

.btn-primary:hover {
    background: var(--gilt);
    color: var(--ink-deep);
    border-color: var(--gilt);
}

/* ─── API budget indicator ───────────────────────────── */

.api-budget {
    max-width: 9.375rem;
    margin-top: 1.5rem;
    margin-bottom: -0.25rem;
    padding: 0.6rem 0.75rem;
    background: rgba(0, 0, 0, 0.18);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.25rem;
    font-size: 0.85rem;
}

.api-budget-label {
    color: var(--ivory-dim);
    font-weight: 500;
    line-height: 1.25;
    margin-bottom: 0.45rem;
}

.api-budget-bar-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.35rem;
}

.api-budget-bar {
    flex: 1;
    height: 0.625rem;
    background: rgba(255, 255, 255, 0.05);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 62.4375rem;
    overflow: hidden;
}

.api-budget-bar-fill {
    height: 100%;
    transition: width 0.3s ease, background 0.3s ease;
}

.api-budget-percent {
    color: var(--ivory-dim);
    font-weight: 600;
    font-size: 0.75rem;
    flex-shrink: 0;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.api-budget-meta {
    color: var(--dust);
    font-size: 0.75rem;
    line-height: 1.4;
    font-variant-numeric: tabular-nums;
}

/* ─── Toolbar above tables ───────────────────────────── */

.table-toolbar {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 0.75rem;
    margin-top: 1.5rem;
    margin-bottom: -0.5rem;
}

/* "Syncing…" placeholder shown in place of the Sync buttons while a
   worker is already running. Matches the dimmer voice of .muted so
   it doesn't compete with the still-active "Add Raid" button. Acts
   as a button — clicking opens the progress modal for the running job. */
.sync-indicator {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--dust);
    font-size: 0.85rem;
    letter-spacing: 0.04em;
    background: transparent;
    border: none;
    padding: 0;
    margin: 0;
    font-family: inherit;
    cursor: pointer;
    transition: color 0.15s ease;
}

.sync-indicator:hover,
.sync-indicator:focus-visible {
    color: var(--ivory);
    outline: none;
}

.sync-indicator:focus-visible {
    text-decoration: underline;
    text-underline-offset: 0.25rem;
}

.sync-spinner {
    width: 0.85rem;
    height: 0.85rem;
    border: 0.125rem solid var(--ink-faint);
    border-top-color: var(--gilt);
    border-radius: 50%;
    animation: sync-spinner-rot 0.9s linear infinite;
}

@keyframes sync-spinner-rot {
    to { transform: rotate(360deg); }
}

/* ─── Inline alert ───────────────────────────────────── */

.alert {
    margin-top: 1rem;
    padding: 0.75rem 1rem;
    border-left: 0.125rem solid;
    font-family: var(--font-body);
    font-size: 0.95rem;
    line-height: 1.5;
}

.alert-error {
    background: rgba(139, 26, 26, 0.18);
    border-color: var(--ruby);
    color: var(--ruby-bright);
}

.alert-success {
    background: rgba(58, 125, 79, 0.15);
    border-color: #3a7d4f;
    color: #7fc28f;
}

/* Ember orange — same family as .status-pill--warn but as a banner. */
.alert-warn {
    background: rgba(163, 106, 37, 0.18);
    border-color: #a36a25;
    color: #f0a04a;
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
}

/* Neutral notice — for queued-job confirmations and similar
   non-error, non-success messages. Uses the existing dust palette
   so it reads as informational rather than alarming. */
.alert-info {
    background: rgba(212, 167, 71, 0.06);
    border-color: var(--ink-faint);
    color: var(--ivory-dim);
}

.alert__icon {
    font-size: 1.1rem;
    line-height: 1.4;
    flex-shrink: 0;
    /* The unicode warning sign sits a touch low in most fonts; nudge up
       so it aligns optically with the first line of text. */
    transform: translateY(-0.0625rem);
}

/* Inline ⚠ marker for "this number may be off" cases — surfaces the
   reason via the title attribute on hover/focus rather than stealing
   space with a banner. Used next to the per-zone Total Raid Time
   breakdown when no log included that zone's trash. */
.warning-tip {
    display: inline-block;
    margin-left: 0.3rem;
    color: #f0a04a;
    cursor: help;
    font-size: 0.9em;
}

.warning-tip:focus-visible {
    outline: 0.0625rem solid var(--gilt);
    outline-offset: 0.125rem;
    border-radius: 0.125rem;
}

/* ─── Error page ─────────────────────────────────────── */

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

.error-page h1 {
    font-family: var(--font-display);
    font-size: 1.75rem;
    color: var(--ivory);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    margin-bottom: 1rem;
    text-shadow: 0 0.0625rem 0 var(--shadow);
}

.error-page p {
    color: var(--ivory-dim);
    font-size: 1.05rem;
    max-width: 36ch;
}

/* ─── Edit Raid form ─────────────────────────────────── */

.raid-date-row {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 1.5625rem;
    margin: 1.5rem 0;
}

.raid-date-row .lede {
    margin: 0;
}

.raid-date-edit {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.raid-date-edit[hidden] {
    display: none;
}

.raid-date-edit input[type="date"] {
    padding: 0.55rem 0.75rem;
    background: var(--ink-deep);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.125rem;
    color: var(--ivory);
    font-family: var(--font-body);
    font-size: 0.95rem;
    color-scheme: dark;
    transition: border-color 0.2s ease;
}

.raid-date-edit input[type="date"]:focus {
    outline: none;
    border-color: var(--gilt);
}

.raid-date-edit input[type="date"]::-webkit-calendar-picker-indicator {
    filter: invert(1) opacity(0.65);
    cursor: pointer;
}

.subhead {
    font-family: var(--font-body);
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--gilt-dim);
    margin: 2.5rem 0 1rem;
}

.raid-log-form {
    margin-top: 1rem;
}

.raid-types {
    border: none;
    padding: 0;
    margin: 0 0 1.5rem;
}

.raid-types legend {
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--dust);
    margin-bottom: 0.75rem;
    padding: 0;
}

.raid-types-options {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(6.875rem, 1fr));
    gap: 0.5rem 1rem;
}

.raid-type-option {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    cursor: pointer;
    color: var(--ivory-dim);
    font-family: var(--font-body);
    font-size: 0.95rem;
}

.raid-type-option:hover {
    color: var(--ivory);
}

.log-url-fields {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.log-url-fields input[type="url"] {
    width: 100%;
    padding: 0.6rem 0.85rem;
    background: var(--ink-deep);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.125rem;
    color: var(--ivory);
    font-family: var(--font-body);
    font-size: 0.95rem;
    color-scheme: dark;
    transition: border-color 0.2s ease;
}

.log-url-fields input[type="url"]:focus {
    outline: none;
    border-color: var(--gilt);
}

.form-actions {
    display: flex;
    gap: 0.75rem;
    justify-content: flex-end;
    margin-top: 1.5rem;
}

/* ─── Drag-to-reorder rows ───────────────────────────── */

.data-table .drag-col {
    width: 1%;
    padding-left: 0.75rem;
    padding-right: 0;
}

.drag-handle {
    display: inline-block;
    color: var(--dust);
    cursor: grab;
    line-height: 1;
    font-size: 1.05rem;
    letter-spacing: -0.3em;
    padding: 0 0.4rem;
    transition: color 0.15s ease;
    user-select: none;
}

.drag-handle:hover {
    color: var(--gilt);
}

.drag-handle:active {
    cursor: grabbing;
}

/* Sortable.js classes */
.sortable-ghost {
    opacity: 0.4;
    background: rgba(212, 167, 71, 0.05);
}

.sortable-chosen td {
    background: rgba(212, 167, 71, 0.04);
}

/* ─── Styled checkbox (reusable) ─────────────────────── */

.checkbox-toggle {
    appearance: none;
    -webkit-appearance: none;
    width: 1.125rem;
    height: 1.125rem;
    border: 0.0625rem solid var(--ink-faint);
    background-color: transparent;
    background-repeat: no-repeat;
    background-position: center;
    background-size: 0.8125rem 0.8125rem;
    cursor: pointer;
    margin: 0;
    vertical-align: middle;
    transition: border-color 0.2s ease, background-color 0.2s ease;
}

.checkbox-toggle:hover:not(:disabled) {
    border-color: var(--gilt-dim);
}

.checkbox-toggle:checked {
    border-color: var(--gilt);
    background-color: var(--gilt);
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M2.5 6.5l2.5 2.5L9.5 3.5' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.checkbox-toggle:disabled {
    cursor: not-allowed;
    opacity: 0.55;
}

/* ─── Permissions grid ───────────────────────────────── */

.permissions-grid th:not(:first-child),
.permissions-grid td:not(:first-child) {
    text-align: center;
    width: 1%;
    padding-left: 1.5rem;
    padding-right: 1.5rem;
}

.permissions-grid .permission-cell {
    line-height: 1;
}

/* ─── Modal (native <dialog>) ────────────────────────── */

.modal {
    border: 0;
    outline: none;
    padding: 0;
    margin: auto;
    background: transparent;
    color: var(--ivory);
    max-width: 30rem;
    width: calc(100% - 2rem);
}
.modal--wide { max-width: 80rem; }

.modal::backdrop {
    background: rgba(0, 0, 0, 0.65);
    backdrop-filter: blur(0.125rem);
}

.modal-card {
    background: var(--ink-parchment);
    border: 0.0625rem solid var(--ink-rule);
    padding: 2rem 2.25rem;
    box-shadow: 0 1.875rem 5rem rgba(0, 0, 0, 0.7);
    /* Cap height so wide modals (Petri / pot leaderboards rendered in
       full, fastest-clear lists, etc.) scroll within the dialog
       instead of pushing the close button off-screen. The themed
       scrollbar styling at the top of this file applies. */
    max-height: 90vh;
    overflow-y: auto;
}
/* Top accent reserved for high-attention modals (e.g. confirmations).
   Informational modals keep the standard ink-rule border on every edge
   so a colored top stripe doesn't read as a stray "white line" on
   themes where --gilt sits in the pale-blue / off-white range. */
.modal--danger .modal-card { border-top: 0.125rem solid var(--ruby); }

.modal-card label {
    display: block;
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--dust);
    margin-bottom: 0.55rem;
}

.modal-card label + input + label {
    margin-top: 1.4rem;
}

.modal-card input[type="text"],
.modal-card input[type="password"],
.modal-card input[type="date"] {
    width: 100%;
    padding: 0.6rem 0;
    background: transparent;
    border: none;
    border-bottom: 0.0625rem solid var(--ink-rule);
    color: var(--ivory);
    font-family: var(--font-body);
    font-size: 1.05rem;
    line-height: 1.4;
    color-scheme: dark;
    transition: border-color 0.2s ease;
}

.modal-card input[type="text"]:focus,
.modal-card input[type="password"]:focus,
.modal-card input[type="date"]:focus {
    outline: none;
    border-bottom-color: var(--gilt);
}

.modal-card input[type="date"]::-webkit-calendar-picker-indicator {
    filter: invert(1) opacity(0.65);
    cursor: pointer;
    padding-right: 0;
}

.modal-card select {
    width: 100%;
    padding: 0.6rem 1.5rem 0.6rem 0;
    background: transparent;
    border: none;
    border-bottom: 0.0625rem solid var(--ink-rule);
    color: var(--ivory);
    font-family: var(--font-body);
    font-size: 1.05rem;
    line-height: 1.4;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    border-radius: 0;
    cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23ece0c8' stroke-width='1.4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0 center;
    background-size: 0.625rem 0.4375rem;
    transition: border-color 0.2s ease;
}

.modal-card select:focus {
    outline: none;
    border-bottom-color: var(--gilt);
}

.modal-card select option {
    background: var(--ink-parchment);
    color: var(--ivory);
}

.modal-card input:-webkit-autofill,
.modal-card input:-webkit-autofill:hover,
.modal-card input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--ivory);
    -webkit-box-shadow: 0 0 0 62.5rem var(--ink-parchment) inset;
    caret-color: var(--ivory);
    transition: background-color 5000s ease-in-out 0s;
}

.modal-card form .modal-actions {
    margin-top: 2rem;
}

.modal-card h3 {
    font-family: var(--font-body);
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--ivory);
    margin-bottom: 1rem;
    padding-bottom: 0.85rem;
    border-bottom: 0.0625rem solid var(--ink-rule);
}

.modal-card p {
    font-family: var(--font-body);
    font-size: 1rem;
    color: var(--ivory-dim);
    line-height: 1.55;
    margin-bottom: 1.75rem;
}

.modal-card strong {
    color: var(--ivory);
    font-weight: 600;
}

/* Chart modal header: h3 on the left, filter dropdown on the right,
   sharing the same border-bottom as a normal modal-card h3 would. */
.chart-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding-bottom: 1rem;
    margin-bottom: 1.25rem;
    border-bottom: 0.0625rem solid var(--ink-rule);
}
.chart-modal-header h3 {
    margin: 0;
    padding: 0;
    border: none;
}
.modal-card .chart-filter {
    flex-shrink: 0;
    width: max-content;
    background: transparent;
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.2rem;
    color: var(--ivory-dim);
    font-family: var(--font-body);
    font-size: 0.75rem;
    padding: 0.3rem 0.5rem;
    cursor: pointer;
}
.modal-card .chart-filter option { background: var(--ink-parchment); color: var(--ivory); }
.modal-card .chart-filter:focus  { outline: none; border-color: var(--gilt); }

/* Chart canvas wrapper — constrains height so the chart doesn't fill
   the viewport on a wide modal. Chart.js reads these dimensions on
   first render; the canvas itself stays responsive via its own
   maintainAspectRatio: true setting. */
.chart-wrap {
    position: relative;
    margin: 1.5rem 0 0.5rem;
    width: 100%;
    height: calc(22rem + 100px);
}

.modal-actions {
    display: flex;
    gap: 0.75rem;
    justify-content: flex-end;
}

/* ─── Login ──────────────────────────────────────────── */

.login-wrap {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    background: var(--ink-deep);
    background-image: radial-gradient(ellipse 60% 50% at center, var(--glow-primary) 0%, transparent 70%);
    background-attachment: fixed;
}

.login-card {
    position: relative;
    background: var(--ink-parchment);
    border: 0.0625rem solid var(--ink-rule);
    padding: 3rem 3.25rem 2.75rem;
    width: 100%;
    max-width: 23.75rem;
    box-shadow:
        0 0.0625rem 0 rgba(212, 167, 71, 0.05) inset,
        0 1.875rem 5rem rgba(0, 0, 0, 0.7);
    animation: fadeInUp 0.7s ease-out;
}

/* Gilt corner brackets — like a framed plate */
.login-card::before,
.login-card::after {
    content: '';
    position: absolute;
    width: 0.875rem;
    height: 0.875rem;
    border: 0.0625rem solid var(--gilt-dim);
}

.login-card::before {
    top: 0.5625rem;
    left: 0.5625rem;
    border-right: none;
    border-bottom: none;
}

.login-card::after {
    bottom: 0.5625rem;
    right: 0.5625rem;
    border-left: none;
    border-top: none;
}

.login-card h1 {
    font-family: var(--font-body);
    font-size: 0.9rem;
    font-weight: 600;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--gilt);
    text-align: center;
    padding-bottom: 1.4rem;
    margin-bottom: 2rem;
    border-bottom: 0.0625rem solid var(--ink-rule);
    text-shadow: 0 0.0625rem 0 var(--shadow);
}

.login-card label {
    display: block;
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--dust);
    margin-bottom: 0.55rem;
}

.login-card label + input { margin-bottom: 0; }

.login-card form > label + input + label { margin-top: 1.4rem; }

.login-card input[type="text"],
.login-card input[type="password"] {
    width: 100%;
    padding: 0.6rem 0;
    background: transparent;
    border: none;
    border-bottom: 0.0625rem solid var(--ink-rule);
    color: var(--ivory);
    font-family: var(--font-body);
    font-size: 1.15rem;
    line-height: 1.4;
    transition: border-color 0.2s ease;
}

.login-card input[type="text"]:focus,
.login-card input[type="password"]:focus {
    outline: none;
    border-bottom-color: var(--gilt);
}

.login-card input:-webkit-autofill,
.login-card input:-webkit-autofill:hover,
.login-card input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--ivory);
    -webkit-box-shadow: 0 0 0 62.5rem var(--ink-parchment) inset;
    caret-color: var(--ivory);
    transition: background-color 5000s ease-in-out 0s;
}

.login-card button {
    width: 100%;
    margin-top: 2.25rem;
    padding: 0.9rem;
    background: transparent;
    color: var(--gilt);
    border: 0.0625rem solid var(--gilt-dim);
    border-radius: 0;
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background 0.25s ease, color 0.25s ease, letter-spacing 0.4s ease;
}

.login-card button:hover {
    background: var(--gilt);
    color: var(--ink-deep);
    border-color: var(--gilt);
    letter-spacing: 0.2em;
}

.login-error {
    background: rgba(139, 26, 26, 0.18);
    border-left: 0.125rem solid var(--ruby);
    color: var(--ruby-bright);
    padding: 0.75rem 1rem;
    font-family: var(--font-body);
    font-size: 0.95rem;
    margin-bottom: 1.5rem;
}

/* ─── Animations ─────────────────────────────────────── */

@keyframes fadeInUp {
    from { opacity: 0; transform: translateY(0.5rem); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ─── Boss Kills: fixed narrow width ─────────────── */
/* Override the default .data-table { width: 100% } so the
   table sits at a sensible compact width regardless of panel
   size. Forced to the left edge of its container — DataTables
   wrappers can otherwise centre tables that don't span the
   full width. */
.boss-kills-table,
table.dataTable.boss-kills-table,
.dt-container:has(> .boss-kills-table) {
    width: 35rem;
    max-width: 100%;
    margin-left: 0;
    margin-right: auto;
}

.boss-kills-table th:first-child,
.boss-kills-table td:first-child,
table.dataTable.boss-kills-table th:first-child,
table.dataTable.boss-kills-table td:first-child {
    text-align: left;
}

/* Crown the row holding the guild's fastest kill of an encounter — true
   gold across every theme (--gilt is theme-tinted and reads as light
   blue on Steel, which doesn't match the 👑 marker). */
.boss-kills-table tbody tr.boss-kills-table__fastest,
.boss-kills-table tbody tr.boss-kills-table__fastest td,
.boss-kills-table tbody tr.boss-kills-table__fastest td.muted {
    color: #d4a747;
}

/* ─── Raiders: fixed-width columns + child rows ───── */
/* Same DataTables row.child() pattern as the Attendance table —
   pin column widths so parent rows + expanded member sub-rows
   stay aligned. */
#raiders-table {
    table-layout: fixed;
    width: 100%;
}

#raiders-table th:nth-child(1),
#raiders-table td:nth-child(1) { width: 2.5rem; }   /* expand-col */
#raiders-table th:nth-child(2),
#raiders-table td:nth-child(2) { width: auto; }     /* Raider     */
#raiders-table th:nth-child(3),
#raiders-table td:nth-child(3) { width: 30%; }      /* Class      */
#raiders-table th:nth-child(4),
#raiders-table td:nth-child(4) { width: 5rem; }     /* iLvl       */
#raiders-table th:nth-child(5),
#raiders-table td:nth-child(5) { width: 12rem; }    /* Guild      */

/* ─── Attendance: fixed-width columns + child rows ── */
/* The Attendance table uses DataTables row.child() to expand linked
   player groups inline. row.child() inserts <tr>s after layout has
   already been computed, which under table-layout: auto causes the
   right-hand columns to drift between parent and child rows. We pin
   column widths with table-layout: fixed + explicit widths here so
   every row — parent or child — uses the same column geometry. */
#attendance-table {
    table-layout: fixed;
    width: 100%;
}

#attendance-table th:nth-child(1),
#attendance-table td:nth-child(1) { width: 2.5rem; }   /* expand-col      */
#attendance-table th:nth-child(2),
#attendance-table td:nth-child(2) { width: auto; }     /* Raider name     */
#attendance-table th:nth-child(3),
#attendance-table td:nth-child(3) { width: 9rem; }     /* Class           */
#attendance-table th:nth-child(4),
#attendance-table td:nth-child(4) { width: 11rem; }    /* 1st Raid Date   */
#attendance-table th:nth-child(5),
#attendance-table td:nth-child(5) { width: 6rem; }     /* Attended        */
#attendance-table th:nth-child(6),
#attendance-table td:nth-child(6) { width: 9rem; }     /* Since 1st Attend*/
#attendance-table th:nth-child(7),
#attendance-table td:nth-child(7) { width: 7rem; }     /* Overall         */

/* Right-align numeric columns. DataTables auto-applies
   .dt-type-numeric to parent rows in these columns, but child rows
   added via row.child() bypass that pipeline. Aligning by column
   index keeps parent + child consistent. */
#attendance-table th:nth-child(5),
#attendance-table th:nth-child(6),
#attendance-table th:nth-child(7),
#attendance-table td:nth-child(5),
#attendance-table td:nth-child(6),
#attendance-table td:nth-child(7) {
    text-align: right;
}

/* Member rows rendered by DataTables' row.child() when the expand
   toggle is clicked. Cells inherit the column widths from the
   table-layout: fixed rule above; this just adds the visual shading
   + dashed dividers to match the Raiders page member-row look. */
tr.member-row-child > td {
    background: rgba(0, 0, 0, 0.15);
    border-top: 0.0625rem dashed var(--ink-faint);
    border-bottom: 0.0625rem dashed var(--ink-faint);
    font-size: 0.9rem;
}

/* ─── Dev-mode banner ─────────────────────────────── */
/* Sits at the very top of the page when DEV_MODE=true in .env. Hard
   ruby-red so it's obvious the user isn't on production. Sticky-top
   so it stays visible as the user scrolls. The body's
   `has-dev-banner` class is here only to reserve the spot if a future
   layout needs to offset content underneath. */
.dev-banner {
    position: sticky;
    top: 0;
    z-index: 1000;
    /* Height reserved for the .layout min-height calc below. Keep in sync
       if the padding/font-size/border below changes. */
    --dev-banner-height: 2.1rem;
    box-sizing: border-box;
    height: var(--dev-banner-height);
    padding: 0.5rem 1rem;
    text-align: center;
    font-family: var(--font-display);
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #fff;
    background: #8b1a1a;
    border-bottom: 0.0625rem solid #5a0f0f;
    box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.4);
}

/* When the dev banner is present it consumes vertical space above
   .layout — shrink .layout's min-height by the banner's height so the
   page doesn't overflow the viewport when content would otherwise fit. */
.has-dev-banner .layout {
    min-height: calc(100vh - 2.1rem);
}

/* ── Parse breakdown tooltip ─────────────────────────────────────────
   Hover/focus the parse cell on the Attendees tab to surface a per-
   boss parse breakdown. CSS-only; no JS.
*/
.parse-cell {
    position: relative;
    cursor: help;
    display: inline-block;
}
.parse-cell:focus { outline: none; }
.parse-cell .parse-tooltip {
    position: absolute;
    bottom: calc(100% + 0.375rem);
    left: 50%;
    transform: translateX(-50%);
    z-index: 50;
    min-width: 11rem;
    padding: 0.5rem 0.75rem;
    background: var(--ink-leather);
    color: var(--ink-paper, #e6dec9);
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.5);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 120ms ease-out, visibility 120ms ease-out;
    text-align: left;
    white-space: nowrap;
}
.parse-cell:hover .parse-tooltip,
.parse-cell:focus-visible .parse-tooltip,
.parse-cell:focus-within .parse-tooltip {
    opacity: 1;
    visibility: visible;
}
.parse-cell .parse-tooltip::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 0.375rem solid transparent;
    border-top-color: var(--ink-faint);
}
.parse-tooltip__list {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 0.875rem;
}
.parse-tooltip__list li {
    display: flex;
    justify-content: space-between;
    gap: 1.25rem;
    padding: 0.125rem 0;
}
.parse-tooltip__boss {
    color: var(--ink-paper, #e6dec9);
}
.parse-tooltip__pct {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

/* ── WoW class colors ─────────────────────────────────────────────────
   Standard Blizzard class palette. Apply .wc-<lowercase-class> to a
   text element (or its wrapping link) to color the name. Used in stat
   boxes and other compact contexts where the name needs to read at a
   glance. Icons stay separate (.class-icon).
*/
.wc-druid   { color: #ff7d0a; }
.wc-hunter  { color: #abd473; }
.wc-mage    { color: #69ccf0; }
.wc-paladin { color: #f58cba; }
.wc-priest  { color: #ffffff; }
.wc-rogue   { color: #fff569; }
.wc-shaman  { color: #0070de; }
.wc-warlock { color: #9482c9; }
.wc-warrior { color: #c79c6e; }
/* On a hovered raider-link, keep the class color rather than letting
   the global link hover override it. */
a.raider-link.wc-druid:hover,   a.raider-link.wc-druid:focus   { color: #ffa050; }
a.raider-link.wc-hunter:hover,  a.raider-link.wc-hunter:focus  { color: #c4ed98; }
a.raider-link.wc-mage:hover,    a.raider-link.wc-mage:focus    { color: #9ee0f5; }
a.raider-link.wc-paladin:hover, a.raider-link.wc-paladin:focus { color: #f9b6d3; }
a.raider-link.wc-priest:hover,  a.raider-link.wc-priest:focus  { color: #d8d8d8; }
a.raider-link.wc-rogue:hover,   a.raider-link.wc-rogue:focus   { color: #fff89d; }
a.raider-link.wc-shaman:hover,  a.raider-link.wc-shaman:focus  { color: #4d9bff; }
a.raider-link.wc-warlock:hover, a.raider-link.wc-warlock:focus { color: #b6a8db; }
a.raider-link.wc-warrior:hover, a.raider-link.wc-warrior:focus { color: #dcb98c; }

/* ── Boss section heading (Statistics / Rankings boss cards) ─────────
   Larger and lighter than the .subhead section label so the two
   levels of hierarchy are visually distinct. */
.boss-card {
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.35rem;
    background: rgba(0, 0, 0, 0.12);
    padding: 1rem 1rem 0.75rem;
    margin-top: 1.25rem;
    margin-bottom: 0;
}
.boss-card:first-child { margin-top: 0.5rem; }
.boss-card .stat-list { margin-top: 0.5rem; }
.boss-card .stat-list + .stat-list { margin-top: 1rem; }
.boss-card .subhead { margin-top: 1rem; margin-bottom: 1rem; }

.boss-name {
    font-size: 1.1rem;
    font-weight: 400;
    color: var(--gilt);
    letter-spacing: 0.03em;
    margin: 0 0 1rem;
}

/* ── Tight stat-list variant ────────────────────────────────────────
   Default .stat-list uses minmax(15.625rem, 1fr) so a single box
   stretches to fill the row. That leaves 2-tile rows (e.g. the
   per-boss rankings) far apart with empty space between them. The
   --tight modifier caps the track at the same 25rem the box itself
   maxes out at, so two boxes pack tightly side-by-side and any
   leftover horizontal space lands at the end of the row.
*/
.stat-list--tight {
    grid-template-columns: repeat(auto-fit, minmax(15.625rem, 25rem));
}

/* Compact class-cell for use inside stat boxes — the table contexts
   keep the larger 20px icon + 0.5rem gap. */
.stat-list .class-cell { gap: 0.25rem; }
.stat-list .class-cell .class-icon {
    width: 0.75rem;
    height: 0.75rem;
}

/* Tighter spacing variant for subheads that sit directly above a
   stat-list, where the default margin-bottom feels excessive. */
.subhead--tight { margin-bottom: 0; }
/* Recent Records on the View Raider Overview tab: the .subhead--tight
   above the scroll-list collapses against it otherwise. */
.subhead--tight + .notable-events-list { margin-top: 0.6rem; }

/* ── Per-boss class parse table (Rankings page) ──────────────────────
   Class icons sit in thead (outside boxes). Role icons are the first
   column. Each tbody td is its own bordered card. border-collapse:
   separate lets individual cells carry border-radius. */
.class-parse-table {
    border-collapse: separate;
    border-spacing: 0.4rem 0.4rem;
    width: 100%;
    table-layout: fixed;
    margin-top: 0.4rem;
    margin-bottom: 0.25rem;
}
.class-parse-table thead th {
    text-align: center;
    font-weight: normal;
    padding: 0 0 0.1rem;
}
.class-parse-table tbody td {
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    background: rgba(0, 0, 0, 0.15);
    padding: 0.4rem 0.5rem;
    vertical-align: middle;
}
.class-parse-table__cell {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 0.5rem;
}
.class-parse-table tbody td.class-parse-table__none {
    border: none;
    background: none;
}
.class-parse-table__role-icon {
    display: block;
    width: 24px;
    height: 24px;
    flex-shrink: 0;
}
.class-parse-table__name {
    min-width: 0;
    text-align: center;
    font-size: 0.7rem;
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.class-parse-table__name > a {
    display: inline;
}
.class-parse-table__pct {
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
}
.class-parse-table__empty {
    display: block;
    text-align: center;
    color: var(--color-muted);
}

/* Parse tooltip header — sits above the per-boss list and labels
   whether the rows are DPS or Healing parses. */
.parse-tooltip__header {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--gilt-dim);
    padding-bottom: 0.25rem;
    margin-bottom: 0.25rem;
    border-bottom: 0.0625rem solid var(--ink-faint);
}

/* Three-dots player-actions button shown to the left of the
   raider name in the attendees table (officers only). Reads as
   a subtle affordance — small, muted, only colours up on hover. */
.player-actions-btn {
    background: transparent;
    border: 0;
    padding: 0 0.35rem;
    margin-right: 0.2rem;
    color: var(--dust);
    cursor: pointer;
    font-size: 1.1rem;
    line-height: 1;
    border-radius: 0.15rem;
    transition: color 0.15s ease, background 0.15s ease;
    vertical-align: middle;
}
.player-actions-btn:hover,
.player-actions-btn:focus-visible {
    color: var(--gilt);
    background: rgba(255, 255, 255, 0.06);
    outline: none;
}

/* ─── Custom right-click context menu (attendees) ──────
   Tiny floating menu shown next to the cursor on right-click
   over a player row. Hidden by default; positioned absolutely
   by JS using page-coordinate `top` / `left`. */
.context-menu {
    position: absolute;
    z-index: 200;
    list-style: none;
    margin: 0;
    padding: 0.25rem 0;
    min-width: 10rem;
    background: var(--ink-leather);
    border: 0.0625rem solid var(--ink-rule);
    box-shadow: 0 0.5rem 1.25rem rgba(0, 0, 0, 0.5);
}
.context-menu[hidden] { display: none; }
.context-menu li {
    padding: 0.5rem 1rem;
    font-family: var(--font-body);
    font-size: 0.85rem;
    color: var(--ivory);
    cursor: pointer;
    user-select: none;
}
.context-menu li:hover {
    background: var(--ink-parchment);
    color: var(--gilt);
}

/* Player hover tooltip on the View RaidHelper Event page. The
   tooltip sits as the last child of a `.signup-box__name`
   marked with `--has-tooltip`. Hover/focus-within on the name
   reveals it; pointer-events: none on the tooltip itself so it
   doesn't steal the underlying link's click target. */
.signup-box__name--has-tooltip {
    position: relative;
}
.player-tooltip {
    position: absolute;
    bottom: calc(100% + 0.4rem);
    left: 0;
    z-index: 60;
    min-width: 16rem;
    padding: 0.6rem 0.8rem;
    background: var(--ink-leather);
    border: 0.0625rem solid var(--ink-faint);
    border-radius: 0.25rem;
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.55);
    color: var(--ivory);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 120ms ease-out, visibility 120ms ease-out;
    white-space: nowrap;
}
.signup-box__name--has-tooltip:hover .player-tooltip,
.signup-box__name--has-tooltip:focus-within .player-tooltip {
    opacity: 1;
    visibility: visible;
}
.player-tooltip__title {
    display: block;
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--gilt);
    padding-bottom: 0.35rem;
    margin-bottom: 0.35rem;
    border-bottom: 0.0625rem solid var(--ink-faint);
}
.player-tooltip__row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    font-size: 0.8rem;
    margin-bottom: 0.45rem;
}
.player-tooltip__row > span:first-child { color: var(--dust); }
.player-tooltip__header {
    display: block;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--gilt-dim);
    padding-top: 0.3rem;
    margin-bottom: 0.3rem;
    border-top: 0.0625rem dashed var(--ink-faint);
}
.player-tooltip__stats {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    font-size: 0.8rem;
    margin-bottom: 0.3rem;
}
.player-tooltip__stat {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
}
.player-tooltip__stat > span:first-child { color: var(--dust); }
.player-tooltip__stat > span:last-child {
    font-variant-numeric: tabular-nums;
}

/* RaidHelper events list — Status pill. Green for future events,
   muted grey for past ones. Same chrome as the foreign-guild pill
   so the page reads consistently. */
.status-pill {
    display: inline-block;
    font-size: 0.65rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    border-radius: 999px;
    padding: 0.1rem 0.55rem;
    line-height: 1.5;
    white-space: nowrap;
    border: 0.0625rem solid var(--ink-rule);
}
.status-pill--upcoming {
    color: #6dd56d;
    border-color: rgba(109, 213, 109, 0.55);
    background: rgba(109, 213, 109, 0.1);
}
.status-pill--past {
    color: var(--dust);
    background: rgba(255, 255, 255, 0.04);
}
/* Type-tag pills on the RaidHelper events list. Distinct hues so the
   eye picks out raid size at a glance. Attune sits on amber to mark
   it apart from attendance-counting raids. */
.status-pill--forty {
    color: #f5c46d;
    border-color: rgba(245, 196, 109, 0.45);
    background: rgba(245, 196, 109, 0.1);
}
.status-pill--twenty {
    color: #87b6ff;
    border-color: rgba(135, 182, 255, 0.45);
    background: rgba(135, 182, 255, 0.1);
}
.status-pill--attune {
    color: #b48cff;
    border-color: rgba(180, 140, 255, 0.55);
    background: rgba(180, 140, 255, 0.1);
}
/* Tag pills can stack — give them a small inline gap so two on the
   same row (40-man + 20-man) don't bunch together. */
td .status-pill + .status-pill { margin-left: 0.25rem; }

/* ─── RaidHelper sign-up totals strip ──────────────────
   Compact summary row shown above the class boxes on the
   View Event page — tanks/healers + per-guild headcount.
*/
.signup-totals-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: 1rem;
}

.signup-totals {
    flex: 1 1 0;
    min-width: 18rem;
    list-style: none;
    margin: 0;
    padding: 0.65rem 1rem;
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    background: var(--ink-leather);
    border: 0.0625rem solid var(--ink-rule);
}

.signup-totals--compact {
    flex: 0 0 auto;
    min-width: 0;
}

.signup-totals li {
    display: flex;
    align-items: baseline;
    gap: 0.45rem;
}

.signup-totals__label {
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--dust);
}

.signup-totals__value {
    font-family: var(--font-body);
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--ivory);
    font-variant-numeric: tabular-nums;
}

/* ─── RaidHelper sign-up roster boxes ──────────────────
   3-column grid of class-bucket boxes shown on the
   View Event page. Tank gets its own box (members with
   role_name === 'Tanks'); everyone else falls into the
   box matching their class.
*/
.signup-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
    margin-top: 0.5rem;
}

@media (max-width: 60rem) {
    .signup-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 36rem) {
    .signup-grid { grid-template-columns: 1fr; }
}

/* Composition tab — boxes per RaidHelper group, slot numbers
   shown inline. Same chrome as the sign-up boxes; the comp-grid
   wrapper just gives it the same 3-up responsive layout. */
.comp-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
    margin-top: 0.5rem;
}
@media (max-width: 60rem) {
    .comp-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 36rem) {
    .comp-grid { grid-template-columns: 1fr; }
}

/* Wide variants for the Attendance tab so all buckets fit on a
   single row at standard viewport widths. */
.comp-grid--four { grid-template-columns: repeat(4, 1fr); }
.comp-grid--five { grid-template-columns: repeat(5, 1fr); }
@media (max-width: 75rem) {
    .comp-grid--five { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 60rem) {
    .comp-grid--four,
    .comp-grid--five { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 36rem) {
    .comp-grid--four,
    .comp-grid--five { grid-template-columns: 1fr; }
}

.comp-box__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.comp-box__list li {
    font-size: 0.92rem;
    line-height: 1.3;
    display: flex;
    align-items: baseline;
    justify-content: flex-start;
    gap: 0.4rem;
}
/* Pin the spec to the right edge of the row — `margin-left: auto`
   pushes it to the far end while leaving the confirmed tick + name
   flush-left as before. */
.comp-box__list .signup-box__spec {
    margin-left: auto;
}

.comp-box__confirmed {
    display: inline-flex;
    align-items: center;
    color: #6dd56d;
    margin-left: 0.2rem;
}
.comp-box__confirmed svg {
    width: 0.85rem;
    height: 0.85rem;
}

/* Bench / Tentative / Absence — same box chrome as the class
   roster, but each box spans the full width and lists names inline
   (comma-separated) rather than as a vertical list. Stacked
   vertically. Empty buckets are skipped at render time. */
.signup-status-stack {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin-top: 1rem;
}

.signup-box--full {
    width: 100%;
}

.signup-box__inline {
    margin: 0;
    line-height: 1.6;
    font-size: 0.92rem;
}

.signup-box {
    background: var(--ink-leather);
    border: 0.0625rem solid var(--ink-rule);
    padding: 0.85rem 1rem 1rem;
}

.signup-box__header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding-bottom: 0.55rem;
    margin-bottom: 0.55rem;
    border-bottom: 0.0625rem solid var(--ink-rule);
}

.signup-box__icon {
    width: 1.25rem;
    height: 1.25rem;
    object-fit: cover;
    border-radius: 0.125rem;
    flex: 0 0 auto;
}

.signup-box__title {
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ivory);
    flex: 1 1 auto;
}

.signup-box__count {
    font-family: var(--font-body);
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--dust);
    flex: 0 0 auto;
}

.signup-box__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.signup-box__list li {
    font-size: 0.92rem;
    line-height: 1.3;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
}

/* Warning icon shown next to a sign-up name when the Discord user
   isn't linked to any raider — flags that an officer needs to add a
   manual mapping. Uses --ruby-bright (or a dark amber fallback) to
   stand out against the class colour without overwhelming the row. */
.signup-box__unlinked {
    display: inline-flex;
    align-items: center;
    color: #d4a747;
    margin-left: 0.15rem;
    cursor: help;
    flex: 0 0 auto;
}

.signup-box__unlinked svg {
    width: 0.85rem;
    height: 0.75rem;
}

/* When the unlinked indicator is rendered as a button (officers can
   click to open the link picker), strip the default browser button
   chrome and make the icon read as a clickable cue. */
.signup-box__unlinked--btn {
    background: transparent;
    border: 0;
    padding: 0;
    cursor: pointer;
    transition: color 0.15s ease, transform 0.15s ease;
}

.signup-box__unlinked--btn:hover,
.signup-box__unlinked--btn:focus-visible {
    color: var(--ruby-bright, #ff6b6b);
    transform: scale(1.1);
    outline: none;
}

/* Names linked to a raider profile inherit the surrounding class
   color (.wc-warrior, .wc-mage, …) rather than the global link
   colour. Underline only on hover so the box stays clean at rest. */
.signup-box__link {
    color: inherit;
    text-decoration: none;
    border-bottom: 0.0625rem dotted currentColor;
    transition: opacity 0.15s ease;
}

.signup-box__link:hover,
.signup-box__link:focus {
    opacity: 0.85;
    border-bottom-style: solid;
}

.signup-box__spec {
    font-size: 0.75rem;
    color: var(--dust);
    font-style: italic;
    white-space: nowrap;
}

/* Foreign-guild tag pill — shown after a sign-up's name when the
   Discord nickname carries a `<GuildName>` prefix that isn't
   Rubicon's own tag. The chrome reads as a small badge so the eye
   reads the in-game name first, the guild second. */
.signup-box__name {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
    flex-wrap: wrap;
}

#missing-cloaks-modal .player-tooltip {
    display: none;
}

.ony-missing-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    padding: 0.1rem;
    cursor: pointer;
    color: var(--dust);
    opacity: 0.7;
    transition: opacity 120ms;
    vertical-align: middle;
}

.ony-missing-btn:hover,
.ony-missing-btn:focus-visible {
    opacity: 1;
    color: var(--ivory);
}

.ony-missing-btn svg {
    width: 0.85rem;
    height: 0.85rem;
    display: block;
}

.ony-no-cloak {
    display: inline-block;
    font-size: 0.6rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #f87171;
    border: 0.0625rem solid #f87171;
    border-radius: 0.25rem;
    padding: 0.05em 0.35em;
    line-height: 1.4;
    white-space: nowrap;
    align-self: center;
    flex-shrink: 0;
    margin-right: 0.25rem;
}

.signup-box__guild {
    display: inline-block;
    font-size: 0.65rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--dust);
    background: rgba(255, 255, 255, 0.04);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 999px;
    padding: 0.05rem 0.5rem;
    line-height: 1.4;
    white-space: nowrap;
}

.signup-box__empty {
    font-style: italic;
    text-align: center;
    padding: 0.25rem 0;
}

/* ─── Manual attendance form ─────────────────────────── */

.manual-import-divider {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin: 1.5rem 0;
    max-width: 48rem;
    color: var(--dust);
    font-size: 0.85rem;
}

.manual-import-divider::before,
.manual-import-divider::after {
    content: '';
    flex: 1;
    height: 0.0625rem;
    background: var(--ink-rule);
}

.manual-json-textarea,
textarea#json-import-input,
textarea#manual-export-json {
    background: var(--ink-deep);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.1875rem;
    color: var(--ivory);
    padding: 0.5rem 0.6rem;
    font-family: monospace;
    font-size: 0.82rem;
    resize: vertical;
}

.manual-att-check {
    width: 1.5rem;
    height: 1.5rem;
    cursor: pointer;
    accent-color: var(--gilt);
}

.raider-col-inner {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.btn-icon {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--dust);
    padding: 0.15rem 0.25rem;
    line-height: 1;
    border-radius: 0.1875rem;
    display: inline-flex;
    align-items: center;
}

.btn-icon:hover {
    color: var(--ivory);
}

.manual-override-new {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.manual-override-input {
    background: var(--ink-deep);
    border: 0.0625rem solid var(--ink-rule);
    border-radius: 0.1875rem;
    color: var(--ivory);
    padding: 0.35rem 0.6rem;
    font-family: var(--font-body);
    font-size: 0.9rem;
    width: 10rem;
}

.manual-override-input:focus {
    outline: 0.0625rem solid var(--gilt);
    outline-offset: 0.0625rem;
}

.manual-override-cancel {
    font-size: 0.8rem;
    opacity: 0.7;
}

.manual-override-cancel:hover {
    opacity: 1;
}

/* ── Notable Events list (Overview page) ──────────────────────────────────── */
.notable-events-list {
    list-style: none;
    margin: 0 0 1.5rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.notable-events-list--scroll {
    max-height: 18rem;
    overflow-y: auto;
    padding-right: 0.25rem;
}
.notable-event--group {
    cursor: pointer;
    user-select: none;
}
.notable-event.notable-event--group {
    border-left-color: var(--gilt);
}
.notable-event--group:hover {
    background: rgba(255, 255, 255, 0.03);
}
.notable-event__open {
    flex-shrink: 0;
    width: 0.9rem;
    height: 0.9rem;
    filter: brightness(0) invert(1);
    opacity: 0.4;
    pointer-events: none;
    transition: opacity 0.15s ease;
    align-self: center;
}
.notable-event--group:hover .notable-event__open {
    opacity: 0.85;
}
.notable-group-modal__title {
    font-family: var(--font-body);
    font-size: 0.9rem;
    color: var(--ivory-dim);
    margin: 0 0 1rem;
}
.notable-event {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    font-size: 0.9rem;
    padding: 0.35rem 0.5rem;
    border-left: 0.2rem solid var(--ink-rule);
}
.notable-events-date-header {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--dust);
    padding: 0.6rem 0.5rem 0.2rem;
    margin-top: 0.2rem;
}
.notable-events-date-header:first-child {
    padding-top: 0.1rem;
    margin-top: 0;
}
.notable-event__icon {
    flex-shrink: 0;
}
.notable-event__desc {
    flex: 1;
    line-height: 1.4;
}
.notable-event__link {
    flex-shrink: 0;
    font-size: 0.85rem;
    text-decoration: none;
    opacity: 0.6;
}
.notable-event__link:hover {
    opacity: 1;
}
