html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

a, .btn-link {
    color: #006bb7;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* Entry Renderer Tag Colors — per-theme CSS custom properties */

/* Dark Fantasy (default) */
.theme-dark-fantasy {
    --tag-default: #b0bec5;
    --tag-dice: #DAA520;
    --tag-dc: #ef5350;
    --tag-spell: #ce93d8;
    --tag-item: #4fc3f7;
    --tag-condition: #ef5350;
    --tag-skill: #81c784;
    --tag-creature: #ffb74d;
    --tag-action: #90a4ae;
    --tag-readaloud: #ce93d8;
    --tag-quote: #90a4ae;
}

/* Parchment (light theme) */
.theme-parchment {
    --tag-default: #5d4037;
    --tag-dice: #8B4513;
    --tag-dc: #c62828;
    --tag-spell: #7b1fa2;
    --tag-item: #0277bd;
    --tag-condition: #c62828;
    --tag-skill: #2e7d32;
    --tag-creature: #e65100;
    --tag-action: #546e7a;
    --tag-readaloud: #7b1fa2;
    --tag-quote: #546e7a;
}

/* Crimson Night */
.theme-crimson-night {
    --tag-default: #e0b0b0;
    --tag-dice: #ff6b6b;
    --tag-dc: #ff4444;
    --tag-spell: #e090c0;
    --tag-item: #80d0e0;
    --tag-condition: #ff4444;
    --tag-skill: #90c890;
    --tag-creature: #ffb070;
    --tag-action: #b0a0a0;
    --tag-readaloud: #e090c0;
    --tag-quote: #b0a0a0;
}

/* Forest Grove */
.theme-forest-grove {
    --tag-default: #a0c0a0;
    --tag-dice: #8bc34a;
    --tag-dc: #ff7043;
    --tag-spell: #b39ddb;
    --tag-item: #4dd0e1;
    --tag-condition: #ff7043;
    --tag-skill: #66bb6a;
    --tag-creature: #ffa726;
    --tag-action: #8aa88a;
    --tag-readaloud: #b39ddb;
    --tag-quote: #8aa88a;
}

/* Ocean Depths */
.theme-ocean-depths {
    --tag-default: #90c0d0;
    --tag-dice: #4dd0e1;
    --tag-dc: #ef5350;
    --tag-spell: #b39ddb;
    --tag-item: #80deea;
    --tag-condition: #ef5350;
    --tag-skill: #80cbc4;
    --tag-creature: #ffb74d;
    --tag-action: #80aab0;
    --tag-readaloud: #b39ddb;
    --tag-quote: #80aab0;
}

/* Entry Renderer Styles */
.entry-tag { color: var(--tag-default, #b0bec5); }
.entry-tag-bold { font-weight: bold; }
.entry-tag-italic { font-style: italic; }
.entry-tag-dice { color: var(--tag-dice, #DAA520); font-weight: 600; }
.entry-tag-dc { color: var(--tag-dc, #ef5350); font-weight: 600; }
.entry-tag-spell { color: var(--tag-spell, #ce93d8); }
.entry-tag-item { color: var(--tag-item, #4fc3f7); }
.entry-tag-condition { color: var(--tag-condition, #ef5350); }
.entry-tag-skill { color: var(--tag-skill, #81c784); }
.entry-tag-creature { color: var(--tag-creature, #ffb74d); }
.entry-tag-action { color: var(--tag-action, #90a4ae); }

.entry-inset {
    border-left: 3px solid var(--mud-palette-primary);
    background: rgba(255,255,255,0.03);
    border-radius: 4px;
}

.entry-readaloud {
    border-left: 3px solid var(--tag-readaloud, #ce93d8);
    background: rgba(206,147,216,0.05);
    border-radius: 4px;
    font-style: italic;
}

.entry-quote {
    border-left: 3px solid var(--tag-quote, #90a4ae);
    font-style: italic;
}

.entry-quote-by {
    font-style: normal;
    color: var(--tag-quote, #90a4ae);
    font-size: 0.9em;
}

.entry-list { padding-left: 1.5rem; }
.entry-list li { margin-bottom: 0.25rem; }

.entry-table { overflow-x: auto; }
.entry-table table { width: 100%; border-collapse: collapse; }
.entry-table th, .entry-table td { padding: 4px 8px; border-bottom: 1px solid rgba(255,255,255,0.1); }
.entry-table th { font-weight: 600; color: var(--mud-palette-primary); }
.entry-table-caption { font-size: 1.1em; }

/* Responsive Layout Improvements */

/* Tables: horizontal scroll on small screens */
.mud-table, .mud-simple-table {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* Character sheet stat boxes: constrain on small screens */
@media (max-width: 599px) {
    /* Compact header stats on mobile */
    .stat-box-row {
        gap: 0.5rem !important;
    }

    .stat-box-row > div {
        min-width: 50px;
    }

    /* Reduce padding on mobile */
    .mud-paper.pa-4 {
        padding: 12px !important;
    }

    /* Portrait: smaller on mobile */
    .mud-avatar.mud-avatar-large {
        width: 60px !important;
        height: 60px !important;
    }

    /* Compact tab text */
    .mud-tab {
        min-width: auto !important;
        padding: 6px 10px !important;
        font-size: 0.8rem !important;
    }

    /* Reduce font size in tables */
    .mud-simple-table td, .mud-simple-table th {
        font-size: 0.85rem;
        padding: 4px 6px;
    }
}

/* Medium screens: slightly more breathing room */
@media (min-width: 600px) and (max-width: 959px) {
    .mud-tab {
        min-width: auto !important;
        padding: 6px 14px !important;
    }
}

/* Character list cards: responsive portrait images */
.character-card-portrait {
    max-width: 100%;
    height: auto;
    object-fit: cover;
}

/* Click-to-roll interactive elements */
.clickable-roll {
    cursor: pointer;
    transition: background-color 0.15s ease;
    border-radius: 4px;
}
.clickable-roll:hover {
    background-color: rgba(var(--mud-palette-primary-rgb), 0.08);
}

/* Print-friendly character sheet */
@media print {
    /* Hide all UI chrome */
    .mud-drawer, .mud-appbar, .mud-fab,
    .mud-tabs-header, .mud-snackbar-provider,
    .no-print, .mud-dialog-provider,
    button, .mud-button, .mud-icon-button {
        display: none !important;
    }

    /* Reset layout */
    .mud-main-content {
        margin-left: 0 !important;
        padding: 8px !important;
    }

    .mud-layout {
        display: block !important;
    }

    /* Paper styling */
    .mud-paper {
        box-shadow: none !important;
        border: 1px solid #999;
        break-inside: avoid;
    }

    /* Force light colors for print */
    body, .mud-main-content, .mud-paper {
        background: white !important;
        color: black !important;
    }

    .mud-text-primary, .mud-typography {
        color: black !important;
    }

    .mud-text-secondary {
        color: #555 !important;
    }

    /* Character sheet specifics */
    .mud-tabs {
        border: none !important;
    }

    .mud-tab-panel {
        display: block !important;
        visibility: visible !important;
        padding: 0 !important;
    }

    /* Show all tab panels for print */
    .print-all-tabs .mud-tabs .mud-tab-panel {
        display: block !important;
    }

    /* Table styling */
    .mud-table, .mud-simple-table {
        border-collapse: collapse;
    }

    .mud-table td, .mud-table th,
    .mud-simple-table td, .mud-simple-table th {
        border: 1px solid #ccc !important;
        padding: 2px 6px !important;
        font-size: 10pt !important;
    }

    /* Chips */
    .mud-chip {
        border: 1px solid #999 !important;
        background: transparent !important;
        color: black !important;
        font-size: 9pt !important;
    }

    /* Compact spacing */
    .mud-grid-item {
        padding: 4px !important;
    }

    /* Page breaks */
    .print-page-break {
        page-break-before: always;
    }

    /* Font sizes */
    .mud-typography-h4 { font-size: 16pt !important; }
    .mud-typography-h5 { font-size: 14pt !important; }
    .mud-typography-h6 { font-size: 12pt !important; }
    .mud-typography-body1 { font-size: 10pt !important; }
    .mud-typography-body2 { font-size: 9pt !important; }
    .mud-typography-caption { font-size: 8pt !important; }

    /* Page setup */
    @page {
        margin: 0.5in;
        size: letter;
    }
}

/* ============================================================
   DDB-style character sheet (Phase 1: top banner + stats row)
   ============================================================ */

.dnd-banner {
    background: #1a1a1a;
    color: #f5f5f5;
    padding: 12px 24px;
    border-radius: 4px;
    margin-bottom: 16px;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    align-items: center;
    gap: 16px;
}

.dnd-banner-left {
    display: flex;
    align-items: center;
    gap: 16px;
    min-width: 0;
}

.dnd-banner-center {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 16px;
    row-gap: 6px;
    justify-items: stretch;
    align-items: center;
    min-width: 0;
}

.dnd-banner-center > * {
    width: 100%;
}

.dnd-portrait-frame {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    background: #333;
    border: 2px solid #555;
}

.dnd-portrait-frame img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.dnd-name {
    font-size: 1.75rem;
    font-weight: 700;
    line-height: 1.1;
    margin: 0;
    color: #f5f5f5;
    letter-spacing: 0.01em;
}

.dnd-subtitle {
    font-size: 0.85rem;
    color: #b0b0b0;
    margin-top: 2px;
}

.dnd-xp-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.75rem;
    color: #888;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    margin-top: 4px;
}

.dnd-banner-right {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    flex-wrap: wrap;
}

/* The banner is always dark (#1a1a1a) regardless of theme. Force all
   inline buttons / icon buttons / menus to contrast against it so themes
   like Parchment don't render dark-on-dark and disappear. */
.dnd-banner .mud-button-root,
.dnd-banner .mud-icon-button,
.dnd-banner .mud-menu .mud-button-root {
    color: #f5f5f5 !important;
}
.dnd-banner .mud-button-outlined,
.dnd-banner .mud-icon-button-outlined {
    border-color: rgba(245, 245, 245, 0.45) !important;
}
.dnd-banner .mud-button-outlined:hover,
.dnd-banner .mud-icon-button-outlined:hover {
    border-color: #f5f5f5 !important;
    background: rgba(255, 255, 255, 0.08) !important;
}
.dnd-banner .mud-button-root .mud-icon-root,
.dnd-banner .mud-icon-button .mud-icon-root {
    color: inherit !important;
}
/* Filled / primary-color buttons keep their theme background but need
   readable text — pick light or dark text based on perceived brightness
   via a contrast variable. Filled buttons in the banner are e.g. Level Up
   (Warning) and Save (Primary); Mud already chooses readable text for
   those, so leave them alone — only override when no Color is set
   (Color.Default falls to white text via the rule above). */

.dnd-stat-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: stretch;
    margin-bottom: 16px;
    padding: 0 4px;
}

/* Ability score box (label / big number / mod pill hanging below) */
.dnd-ability-box {
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
    border-radius: 4px;
    padding: 6px 14px 18px;
    text-align: center;
    background: var(--mud-palette-surface, #fff);
    position: relative;
    min-width: 88px;
    font-variant-numeric: tabular-nums;
    transition: background-color 0.15s ease;
}
.dnd-ability-box.clickable-roll:hover {
    background: rgba(var(--mud-palette-primary-rgb), 0.08);
}
.dnd-ability-box .dnd-ability-edit {
    max-width: 76px;
    margin: 2px auto 0;
}
.dnd-ability-box .dnd-ability-edit .mud-input-control {
    margin: 0;
}
.dnd-ability-box .dnd-ability-edit input {
    text-align: center;
    font-weight: 700;
    font-size: 1.2rem;
    padding: 4px 0;
}
.dnd-ability-box .label {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary, #555);
}
.dnd-ability-box .score {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.1;
    margin-top: 2px;
}
.dnd-mod-pill {
    position: absolute;
    bottom: -13px;
    left: 50%;
    transform: translateX(-50%);
    background: var(--mud-palette-surface, #fff);
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
    border-radius: 14px;
    padding: 1px 14px;
    font-size: 0.95rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Generic small stat card (Proficiency, Speed) */
.dnd-stat-card {
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
    border-radius: 4px;
    padding: 6px 12px;
    text-align: center;
    background: var(--mud-palette-surface, #fff);
    min-width: 100px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    transition: background-color 0.15s ease;
}
.dnd-stat-card.clickable-roll:hover {
    background: rgba(var(--mud-palette-primary-rgb), 0.08);
}
.dnd-stat-card .label {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary, #555);
}
.dnd-stat-card .value {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}
.dnd-stat-card .value-suffix {
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--mud-palette-text-secondary, #777);
}
.dnd-stat-card .sublabel {
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary, #777);
    margin-top: 2px;
}

/* Heroic Inspiration — compact diamond with a tooltip-bound label */
.dnd-inspiration {
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
    border-radius: 4px;
    padding: 6px 10px;
    text-align: center;
    background: var(--mud-palette-surface, #fff);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    min-width: 0;
}
.dnd-inspiration .icon {
    width: 16px;
    height: 16px;
    background: transparent;
    border: 1.5px solid var(--mud-palette-text-secondary, #888);
    transform: rotate(45deg);
    border-radius: 2px;
    margin-bottom: 2px;
}
.dnd-inspiration.active .icon {
    background: var(--mud-palette-warning, #d4a017);
    border-color: var(--mud-palette-warning, #d4a017);
}
.dnd-inspiration .sublabel {
    font-size: 0.55rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary, #777);
    line-height: 1.1;
}

/* HP card — the big right-side one */
.dnd-hp-card {
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
    border-radius: 4px;
    padding: 6px 14px;
    background: var(--mud-palette-surface, #fff);
    display: flex;
    align-items: center;
    gap: 16px;
    min-width: 320px;
}
.dnd-hp-actions {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.dnd-hp-action-btn {
    border: 1px solid var(--mud-palette-error, #c92a2a);
    background: transparent;
    color: var(--mud-palette-error, #c92a2a);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 2px 10px;
    border-radius: 12px;
    cursor: pointer;
    transition: background-color 0.15s ease;
}
.dnd-hp-action-btn.heal { color: var(--mud-palette-success, #4caf50); border-color: var(--mud-palette-success, #4caf50); }
.dnd-hp-action-btn:hover { background: rgba(var(--mud-palette-primary-rgb), 0.08); }

.dnd-hp-values {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-left: auto;
}
.dnd-hp-cell { display: flex; flex-direction: column; align-items: center; }
.dnd-hp-cell .label {
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary, #777);
}
.dnd-hp-cell .value {
    font-size: 1.7rem;
    font-weight: 700;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
}
.dnd-hp-slash {
    font-size: 1.7rem;
    color: var(--mud-palette-text-secondary, #888);
    align-self: center;
    padding: 0 2px;
}
.dnd-hp-card .sublabel {
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary, #777);
    margin-left: 8px;
    align-self: center;
}

/* ============================================================
   Phase 2: Three-column body
   ============================================================ */

/* Skills column — vertical scrollable list, DDB-style. */
.dnd-skills-card {
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
    border-radius: 4px;
    background: var(--mud-palette-surface, #fff);
    /* One grid for the whole card, with the header and every row as `display: contents`.
       Per-row grids could not do this job: a fractional name column pushed the bonus to the far
       edge, and a content-sized one measured each row separately so the bonuses stopped lining up.
       Here the name track is `auto` — as wide as the longest name and no wider — the bonus sits
       immediately after it, and the last track absorbs whatever is left so nothing is clipped. */
    display: grid;
    /* The name track can shrink: as bare `auto` a long name — "Alchemist's Supplies" in the tools
       card — grew the track past the card's own width and the rows bled out through the corners.
       minmax(0, …) lets it give way, and the name cell truncates rather than pushing. */
    /* 38/40 rather than 32/36: the uppercase PROF and MOD headers filled their tracks exactly
       and read as one word. */
    /* Both the name and the bonus are sized by their contents, and the last track eats the slack.
       max-content on the name is deliberate: as minmax(0, auto) it was the track that gave way when
       space got tight, so names truncated to "Religio" and "Surviva" while a fixed 56px bonus
       column kept its width regardless. A name matters more than a gap. */
    grid-template-columns: 46px 34px minmax(0, max-content) max-content minmax(0, 1fr);
    column-gap: 6px;
    align-items: center;
    /* Restored: this clips the rows to the rounded border. Dropping it is what let them escape. */
    overflow: hidden;
}
.dnd-skills-header,
.dnd-skill-row {
    display: contents;
}
/* Padding and rules live on the cells, since the row itself no longer has a box. */
.dnd-skills-header > * {
    padding: 8px 0 4px;
    /* A label must not decide a column's width — "BONUS" is twice the width of the "+1" it labels. */
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary, #777);
    border-bottom: 1px solid var(--mud-palette-divider);
}
.dnd-skill-row > * {
    padding: 6px 0;
    border-bottom: 1px solid var(--mud-palette-divider);
    cursor: pointer;
    transition: background-color 0.15s ease;
}
.dnd-skills-header > *:first-child,
.dnd-skill-row > *:first-child { padding-left: 12px; }
.dnd-skills-header > *:last-child,
.dnd-skill-row > *:last-child { padding-right: 12px; }
.dnd-skill-row:last-of-type > * { border-bottom: none; }
.dnd-skill-row:hover > * { background: rgba(var(--mud-palette-primary-rgb), 0.06); }
/* Tools card reuses the same look but is 3-column (no ability mod). */
.dnd-tools-card {
    grid-template-columns: 46px minmax(0, max-content) max-content minmax(0, 1fr);
}
.dnd-tools-card .dnd-skills-empty {
    grid-column: 1 / -1;
    padding: 12px;
    font-size: 0.8rem;
    color: var(--mud-palette-text-secondary, #777);
    text-align: center;
    font-style: italic;
}
.dnd-skill-prof-cell {
    display: flex;
    justify-content: center;
}
.dnd-skill-prof {
    width: 14px; height: 14px; border-radius: 50%;
    border: 1.5px solid var(--mud-palette-text-secondary, #888);
    display: inline-block; margin: 0 auto;
}
.dnd-skill-prof.proficient {
    background: var(--mud-palette-text-primary, #1a1a1a);
    border-color: var(--mud-palette-text-primary, #1a1a1a);
}
.dnd-skill-prof.expertise {
    background: radial-gradient(circle, var(--mud-palette-warning, #d4a017) 40%, var(--mud-palette-text-primary, #1a1a1a) 42%);
    border-color: var(--mud-palette-warning, #d4a017);
}
.dnd-skill-ability {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--mud-palette-text-secondary, #888);
    text-transform: uppercase;
}
.dnd-skill-name {
    font-size: 0.95rem;
    /* Prefers its full length and gives way before the bonus does: the bonus is the number you
       came for, so it is the one thing in the row that must never be cut off. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dnd-skill-bonus {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: right;
    font-size: 1rem;
}
.dnd-card-footer {
    grid-column: 1 / -1;
    text-align: center;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary, #777);
    padding: 8px;
    border-top: 1px solid var(--mud-palette-divider);
    background: var(--mud-palette-surface, #fff);
}

/* Defenses card row at the top of the right column. */
.dnd-defenses-row {
    display: flex;
    gap: 12px;
    align-items: stretch;
    margin-bottom: 16px;
    flex-wrap: wrap;
}
.dnd-defenses-row .dnd-stat-card { min-width: 110px; }
.dnd-defenses-card {
    flex: 1 1 240px;
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
    border-radius: 4px;
    background: var(--mud-palette-surface, #fff);
    padding: 10px 14px;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px 16px;
}
.dnd-defenses-card h4 {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary, #555);
    margin: 0 0 4px;
}
.dnd-defenses-card .empty-msg {
    font-size: 0.8rem;
    color: var(--mud-palette-text-secondary, #888);
}

/* ============================================================
   Phase 3: Cartouche card styling
   ============================================================ */

/* Wraps a sidebar/middle-column section so it gets a section-title
   "footer" sitting on the bottom border, plus corner ornaments. */
.dnd-card {
    position: relative;
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
    border-radius: 4px;
    background: var(--mud-palette-surface, #fff);
    padding: 14px 16px 28px;          /* extra bottom space for the title */
    margin-bottom: 18px;
}
.dnd-card.no-footer { padding-bottom: 14px; }

/* Centered uppercase section title overlapping the bottom border */
.dnd-card-title {
    position: absolute;
    left: 50%;
    bottom: -10px;
    transform: translateX(-50%);
    background: var(--mud-palette-surface, #fff);
    padding: 0 12px;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary, #555);
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}
.dnd-card-title .gear {
    cursor: pointer;
    opacity: 0.6;
    transition: opacity 0.15s ease;
}
.dnd-card-title .gear:hover { opacity: 1; }

/* Subtle corner ornaments — small inward tick marks on each corner */
.dnd-card::before,
.dnd-card::after {
    content: '';
    position: absolute;
    width: 8px;
    height: 8px;
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
    pointer-events: none;
}
.dnd-card::before {
    top: -1.5px;
    left: -1.5px;
    border-right: none;
    border-bottom: none;
    border-top-left-radius: 4px;
}
.dnd-card::after {
    top: -1.5px;
    right: -1.5px;
    border-left: none;
    border-bottom: none;
    border-top-right-radius: 4px;
}

/* Bottom corners get matching ornaments via a wrapper hack — use
   a child element since we've used both pseudos for the top. */
.dnd-card-corners-bottom {
    position: absolute;
    inset: auto 0 -1.5px 0;
    height: 8px;
    pointer-events: none;
}
.dnd-card-corners-bottom::before,
.dnd-card-corners-bottom::after {
    content: '';
    position: absolute;
    bottom: 0;
    width: 8px;
    height: 8px;
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
}
.dnd-card-corners-bottom::before {
    left: -1.5px;
    border-right: none;
    border-top: none;
    border-bottom-left-radius: 4px;
}
.dnd-card-corners-bottom::after {
    right: -1.5px;
    border-left: none;
    border-top: none;
    border-bottom-right-radius: 4px;
}

/* Global cartouche skin: red border on every card on the sheet, drop the
   default elevation shadow. Less invasive than rewriting every section. */
.character-sheet-skin .mud-paper.mud-elevation-4,
.character-sheet-skin .mud-paper.mud-elevation-2 {
    border: 1.5px solid var(--mud-palette-error, #c92a2a);
    box-shadow: none !important;
    background: var(--mud-palette-surface, #fff);
}
.character-sheet-skin .mud-paper.mud-elevation-6 {
    border: 2px solid var(--mud-palette-warning, #d4a017);
    box-shadow: none !important;
}
/* Sidebar/section h6 titles — uppercase + tracked + smaller, more like
   DDB's section labels than full headings. */
.character-sheet-skin .mud-paper > .mud-typography-h6:first-child {
    font-size: 0.85rem !important;
    font-weight: 700 !important;
    letter-spacing: 0.08em !important;
    text-transform: uppercase !important;
    color: var(--mud-palette-text-secondary, #555) !important;
    margin-bottom: 10px !important;
}
/* Lift Skills card spacing to match the rest. */
.dnd-skills-card { margin-bottom: 18px; }
/* --- Actions panel -------------------------------------------------------
   One scroll container over the whole panel body, so the Attack action's
   weapon table and the bonus actions below it scroll together rather than
   as two independent boxes.

   The minimum is five rows: short lists still reserve the space, so the
   panel does not resize under the cursor as filter chips change what it
   holds. --dnd-action-row is the assumed row height — catalog rows carry a
   name and a description, so they are taller than a dense table row. */
.dnd-actions-scroll {
    --dnd-action-row: 2.6rem;
    --dnd-action-rows: 5;

    /* height is the starting size; min-height is the floor a drag cannot go below. Both must be set
       and max-height must NOT be — a fixed max pins the box and the resize grip does nothing. */
    height: calc(var(--dnd-action-row) * var(--dnd-action-rows));
    min-height: calc(var(--dnd-action-row) * var(--dnd-action-rows));

    /* Native drag-to-grow, no JavaScript. Requires a non-visible overflow to work at all. */
    resize: vertical;
    overflow: auto;

    /* Room for the grip in the bottom-right corner so it never sits on top of a row. */
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--mud-palette-divider);
}

/* Keep the weapon-table header in view while its rows scroll under it. */
.dnd-actions-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--mud-palette-surface);
}

/* ---- Monster browser -------------------------------------------------------------------------
   A two-pane bestiary: the list scrolls on the left, the selected creature stays put on the right.
   Each pane owns its own scrollbar so reading a long stat block never scrolls the list away. */

.dnd-bestiary {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    align-items: start;
}

/* Full viewport minus the page header and the filter card above. */
.dnd-bestiary-detail {
    max-height: calc(100vh - 260px);
    overflow-y: auto;
}

/* A DEFINITE height, not a max-height: the table container inside resolves its own height against
   this one, and percentages cannot resolve against a max. Scrolling belongs to that inner
   container rather than to this element — MudBlazor gives .mud-table-container overflow-y:auto, so
   it is the nearest scrolling ancestor of the header cells whatever this element does, and a
   sticky header can only stick to the thing that actually scrolls. */
.dnd-bestiary-list {
    height: calc(100vh - 260px);
    overflow: hidden;
}

.dnd-bestiary-list .mud-table,
.dnd-bestiary-list .mud-table-container {
    height: 100%;
    max-height: 100%;
}

/* MudSimpleTable's FixedHeader does the sticking; this only supplies the background and the rule
   beneath it. A transparent sticky header lets the rows show through as they pass under it. */
.dnd-bestiary-table thead th {
    background-color: var(--mud-palette-surface) !important;
    box-shadow: inset 0 -1px 0 var(--mud-palette-divider);
    z-index: 2;
}

.dnd-sortable {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}

.dnd-sortable:hover {
    color: var(--mud-palette-primary);
}

.dnd-bestiary-selected > td {
    background-color: rgba(var(--mud-palette-primary-rgb), 0.12);
}

@media (max-width: 960px) {
    .dnd-bestiary {
        grid-template-columns: 1fr;
    }

    .dnd-bestiary-list {
        height: 70vh;
    }

    .dnd-bestiary-detail {
        max-height: none;
    }
}

/* Stat block header: identity and defences on the left, token on the right.
   The token is sized to span from the creature's name down to its Speed line, so the header reads
   as one block rather than a portrait sitting above a list. */
.dnd-statblock-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 8px;
}

.dnd-statblock-head-text {
    min-width: 0;   /* lets a long creature name wrap instead of shoving the token off the edge */
    flex: 1 1 auto;
}

.dnd-monster-token {
    width: 140px;
    height: 140px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    background-color: var(--mud-palette-background-grey);
    transition: transform 150ms ease-out;
    cursor: zoom-in;
}

/* Enlarge on hover by scaling rather than by changing the box, so nothing around it reflows.
   Anchored to the top right corner: the token grows inward across the stat block it belongs to,
   instead of off the edge of the pane. */
.dnd-monster-token:hover {
    transform: scale(2.75);
    transform-origin: top right;
    position: relative;
    z-index: 20;
}

/* Monster browser source picker: three groups side by side, each scrolling if it is long.
   Adventures is by far the biggest group, so it gets its own scrollbar rather than pushing the
   list off the page. */
.dnd-source-groups {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 16px;
}

.dnd-source-books {
    display: flex;
    flex-direction: column;
    max-height: 220px;
    overflow-y: auto;
    padding-left: 12px;
}

.dnd-source-books .mud-checkbox {
    margin: 0;
}

/* Only a tag we can actually explain gets the help cursor and the dotted underline. Offering that
   affordance on a term with nothing behind it is what made these look clickable when they are not. */
.entry-tag-explained {
    cursor: help;
    border-bottom: 1px dotted currentColor;
}

/* ---- Compendium browsers ---------------------------------------------------------------------
   Three columns: facet sidebar, list, detail. Same scrolling discipline as the bestiary — each
   column owns its own scrollbar so reading one never scrolls another away. */

.dnd-browser {
    display: grid;
    grid-template-columns: 220px 1fr 1.2fr;
    gap: 16px;
    align-items: start;
}

.dnd-browser-facets,
.dnd-browser-list,
.dnd-browser-detail {
    max-height: calc(100vh - 210px);
    overflow-y: auto;
}

/* The list scrolls inside its table container so a sticky header has something to stick to. */
.dnd-browser-list {
    height: calc(100vh - 210px);
    overflow: hidden;
}

.dnd-browser-list .mud-table,
.dnd-browser-list .mud-table-container {
    height: 100%;
    max-height: 100%;
}

.dnd-browser-list thead th {
    background-color: var(--mud-palette-surface) !important;
    box-shadow: inset 0 -1px 0 var(--mud-palette-divider);
    z-index: 2;
}

@media (max-width: 960px) {
    .dnd-browser { grid-template-columns: 1fr; }
    .dnd-browser-facets, .dnd-browser-list, .dnd-browser-detail { max-height: none; height: auto; overflow: visible; }
}

/* Facet sidebar */
.dnd-facet-group {
    border-bottom: 1px solid var(--mud-palette-divider);
    padding: 2px 0;
}

.dnd-facet-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    width: 100%;
    padding: 6px 4px;
    background: none;
    border: none;
    cursor: pointer;
    font: inherit;
    font-weight: 600;
    color: var(--mud-palette-text-primary);
}

.dnd-facet-active-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--mud-palette-primary);
    margin-right: auto;
}

.dnd-facet-values {
    padding: 0 0 6px 4px;
}

.dnd-facet-value {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    padding: 2px 4px;
    background: none;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font: inherit;
    font-size: 0.85rem;
    color: var(--mud-palette-text-primary);
    text-align: left;
}

.dnd-facet-value:hover {
    background: rgba(var(--mud-palette-primary-rgb), 0.08);
}

/* The tri-state mark keeps a fixed slot so labels don't shift as states change. */
.dnd-facet-mark {
    width: 14px;
    flex-shrink: 0;
    font-weight: 700;
}

.dnd-facet-require { color: var(--mud-palette-primary); }
.dnd-facet-exclude { color: var(--mud-palette-error); text-decoration: line-through; }

.dnd-facet-label {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dnd-facet-count {
    color: var(--mud-palette-text-secondary);
    font-size: 0.75rem;
}

.dnd-facet-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
}

/* Detail pane meta line under an entry's name */
.dnd-browser-meta {
    color: var(--mud-palette-text-secondary);
    font-style: italic;
}

/* The bestiary with its facet sidebar: a third column joins the pair. */
.dnd-bestiary-faceted {
    grid-template-columns: 220px 1fr 1.2fr;
}

@media (max-width: 960px) {
    .dnd-bestiary-faceted { grid-template-columns: 1fr; }
}

/* ---- Ruleset workbench -----------------------------------------------------------------------
   Two columns: facet sidebar and the name table. Same scrolling discipline as the browsers. */

.dnd-workbench {
    display: grid;
    grid-template-columns: 240px 1fr;
    gap: 16px;
    align-items: start;
}

.dnd-workbench-facets {
    max-height: calc(100vh - 280px);
    overflow-y: auto;
}

.dnd-workbench-list {
    height: calc(100vh - 280px);
    overflow: hidden;
}

.dnd-workbench-list .mud-table,
.dnd-workbench-list .mud-table-container {
    height: 100%;
    max-height: 100%;
}

.dnd-workbench-list thead th {
    background-color: var(--mud-palette-surface) !important;
    box-shadow: inset 0 -1px 0 var(--mud-palette-divider);
    z-index: 2;
}

@media (max-width: 960px) {
    .dnd-workbench { grid-template-columns: 1fr; }
    .dnd-workbench-facets, .dnd-workbench-list { max-height: none; height: auto; overflow: visible; }
}

.rw-sources {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 0.72rem;
    color: var(--mud-palette-text-secondary);
}

/* The per-row All / DM / None segmented control. Plain buttons, because a MudBlazor component
   per cell across two thousand rows is felt in every render. */
.rw-seg {
    display: inline-flex;
    border: 1px solid var(--mud-palette-divider);
    border-radius: 4px;
    overflow: hidden;
}

.rw-seg button {
    padding: 2px 8px;
    font-size: 0.72rem;
    line-height: 1.4;
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--mud-palette-text-secondary);
}

.rw-seg button + button {
    border-left: 1px solid var(--mud-palette-divider);
}

.rw-seg button.rw-on-all {
    background: var(--mud-palette-success);
    color: var(--mud-palette-success-text);
}

.rw-seg button.rw-on-dm {
    background: var(--mud-palette-warning);
    color: var(--mud-palette-warning-text);
}

.rw-seg button.rw-on-none {
    background: var(--mud-palette-error);
    color: var(--mud-palette-error-text);
}

/* ---- Source book columns ---------------------------------------------------------------------
   Column flow, not grid flow: the alphabetized book list reads down each column before moving
   right, matching how a reader scans an ordered list. Breakpoints mirror the old xs/sm/md grid. */

.dnd-source-columns {
    /* Sized by column width, not count: the browser fits as many ~300px columns as the page
       offers, so a wide monitor gets five and a phone gets one without media queries. */
    column-width: 300px;
    column-gap: 8px;
}

.dnd-source-columns-item {
    break-inside: avoid;
    border-bottom: 2px solid var(--mud-palette-divider);
}

/* Entity-override tooltips carry a summary plus a sentence of description; the default tooltip
   width would fold that into a tall sliver. */
.dnd-entity-tip {
    max-width: 420px;
    text-align: center;
}

/* The detail popup's prose column; without a cap a spell's full text runs the dialog too tall. */
.dnd-entity-detail-body {
    max-height: 55vh;
    overflow-y: auto;
}

/* The per-printing expander under a workbench row. */
.rw-printings {
    /* One grid across all printings — display:contents makes each printing's five cells direct
       grid items, so source, status, chip, view, and button line up as columns. */
    display: grid;
    grid-template-columns: repeat(4, max-content);
    column-gap: 16px;
    row-gap: 4px;
    align-items: center;
    padding: 4px 0 8px;
}

.rw-printing {
    display: contents;
}

.rw-printing-off {
    font-size: 0.72rem;
    color: var(--mud-palette-error);
    font-style: italic;
}

/* A disabled-source printing reads as crossed out; the presented one reads as the headline. */
.rw-src-off span {
    text-decoration: line-through;
}

.rw-src-wins span {
    font-weight: 700;
}

/* Side-by-side printing comparison. The button rides to the right of the printing list,
   vertically centered on it. */
.rw-printings-wrap {
    display: flex;
    align-items: center;
    gap: 32px;
}

.rw-printings-actions {
    flex-shrink: 0;
}

.dnd-compare {
    display: grid;
    gap: 16px;
    max-height: 65vh;
    overflow-y: auto;
    align-items: start;
}

.dnd-compare-col {
    min-width: 0;
}

.dnd-compare-col + .dnd-compare-col {
    border-left: 1px solid var(--mud-palette-divider);
    padding-left: 16px;
}

.rw-sortable {
    cursor: pointer;
    user-select: none;
}

/* An unavailable name reads as faded, not disabled — the fade covers the text cells (name,
   meta, sources) while the expander and the availability control keep full strength, since a
   child cannot undo a parent's opacity. */
tr.rw-row-none td:not(:first-child):not(:last-child) {
    opacity: 0.45;
}

/* The keep-or-reset dialog's row list. */
.rw-toggle-list {
    max-height: 50vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.rw-toggle-row {
    display: flex;
    align-items: center;
    gap: 12px;
}

.rw-toggle-label {
    flex: 1;
    font-size: 0.85rem;
}

/* Item charges: a fixed-width counter. This cell used to render one circle per charge, so its
   width tracked the item — 66 circles for the worst offender in the dataset. */
.dnd-charge-counter {
    display: flex;
    align-items: center;
    gap: 2px;
    white-space: nowrap;
}
.dnd-charge-counter .mud-icon-button {
    /* MudBlazor's small icon button is a 30px circle whatever the icon inside it, which read as a
       gap either side of every control in a 72px column. */
    padding: 0;
    min-width: 0;
    width: 18px;
    height: 18px;
}
/* Three controls and a count in one table cell: at the default 20px the icons alone were wider
   than the column needs to be. */
.dnd-charge-counter .mud-icon-button .mud-icon-root {
    font-size: 14px;
}
.dnd-charge-count {
    font-size: 0.75rem;
    white-space: nowrap;
}
.dnd-charge-count {
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
    min-width: 34px;
    text-align: center;
}

/* Currency and quantity fields size to their contents, not to their container. A purse of four
   digits is a large purse and a stack of three is a large stack; the inputs were running to 150px
   because a MudBlazor field fills whatever it is given. The width has to land on the input control
   itself — putting it on the component's Style attribute did not survive. */
.dnd-currency-fields .mud-input-control {
    width: 74px;
    min-width: 0;
}

/* Compact tables: the attacks and equipment lists set how narrow the sheet can be, and MudBlazor
   spends 16px of padding on each side of every cell — 224px across seven columns before a single
   character is drawn. Fixed layout also makes the header widths mean what they say; under `auto`
   they are a suggestion the browser overrules as soon as a cell's content is wider. */
.dnd-compact-table table {
    table-layout: fixed;
    width: 100%;
}
.dnd-compact-table th,
.dnd-compact-table td {
    padding: 4px 6px !important;
}
/* Inputs fill their cell rather than carrying a width of their own. */
.dnd-compact-table .mud-input-control,
.dnd-compact-table .mud-input {
    width: 100% !important;
    min-width: 0;
}
/* An item name longer than its column is cut with an ellipsis rather than wrapped: a wrapped name
   makes its row two lines tall, and a list of equipment is easier to read down when every row is
   the same height. The full name is on the cell's title. */
/* A name too long for its column is cut with an ellipsis rather than wrapped: a wrapped name makes
   its row two lines tall, and a list reads down better when the rows are the same height.
   The ellipsis has to sit on the element that holds the text — put on the cell it never drew,
   because text-overflow only applies to a block's own inline content and the name lives in a span
   among icons and chips. That is why the names were simply disappearing. */
.dnd-ellipsis {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}
.dnd-compact-table td:first-child {
    overflow: hidden;
    white-space: nowrap;
}

/* Small notes beside an item's name — the fold count, "weightless". These were chips, which spend
   their padding and a gap either side to say one word. */
.dnd-item-note {
    font-size: 0.7rem;
    color: var(--mud-palette-text-secondary, #777);
    margin-left: 4px;
    white-space: nowrap;
}
.dnd-item-note-warning { color: var(--mud-palette-warning, #d4a017); }

/* Quantity, weight and the two checkbox columns are narrow and their contents are short — centred
   they read as columns; left or right aligned they drift away from their own headers. */
.dnd-equipment-list th:nth-child(2),
.dnd-equipment-list th:nth-child(3),
.dnd-equipment-list th:nth-child(4),
.dnd-equipment-list th:nth-child(5),
.dnd-equipment-list td:nth-child(2),
.dnd-equipment-list td:nth-child(3),
.dnd-equipment-list td:nth-child(4),
.dnd-equipment-list td:nth-child(5) {
    text-align: center;
}
/* The inputs and checkboxes inside those cells centre with them. */
.dnd-equipment-list td:nth-child(2) .mud-input-control,
.dnd-equipment-list td:nth-child(2) input {
    text-align: center;
}
.dnd-equipment-list td:nth-child(4),
.dnd-equipment-list td:nth-child(5) {
    padding-left: 0 !important;
    padding-right: 0 !important;
}
.dnd-equipment-list td:nth-child(4) .mud-checkbox,
.dnd-equipment-list td:nth-child(5) .mud-checkbox {
    margin: 0 auto;
    display: flex;
    justify-content: center;
}

/* Actions table: To Hit is a short signed number under a short header, so it centres like the
   equipment table's narrow columns. Weapon and damage stay left, where a reader scans them. */
.dnd-attacks-table th:nth-child(2),
.dnd-attacks-table td:nth-child(2) {
    text-align: center;
}

/* ============================================================
   Sheet columns — three tracks with draggable dividers
   ============================================================ */
.dnd-sheet-columns {
    display: grid;
    /* The first two tracks are what a person can drag; the third takes what is left, because it
       holds the attacks table and every tab and is the one worth widening. */
    grid-template-columns:
        var(--sheet-c1, 2fr)
        4px
        var(--sheet-c2, 3fr)
        4px
        minmax(0, var(--sheet-c3, 7fr));
    gap: 0 8px;
    align-items: start;
}
.dnd-sheet-col {
    min-width: 0;   /* without this a wide table stops the track from ever shrinking */
}
.dnd-col-handle {
    position: relative;
    align-self: stretch;
    cursor: col-resize;
    /* The line is 1px; the grab area is the whole 4px track plus a few pixels either side, since a
       single pixel is not something anyone can hit with a mouse. */
    width: 4px;
    justify-self: center;
}
.dnd-col-handle::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    width: 1px;
    background: var(--mud-palette-divider);
    transition: background-color 0.15s ease, width 0.15s ease;
}
.dnd-col-handle::after {
    /* Invisible, and the reason a 1px line is usable. */
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: -4px;
    right: -4px;
}
.dnd-col-handle:hover::before,
.dnd-col-handle.dragging::before {
    background: var(--mud-palette-primary);
    width: 2px;
}

/* Stacked below the layout's breakpoint, where there are no columns to resize. */
@media (max-width: 959px) {
    .dnd-sheet-columns {
        grid-template-columns: minmax(0, 1fr);
    }
    .dnd-col-handle {
        display: none;
    }
}

/* A draggable right edge on the item name column. The handle lives in the header cell, the way a
   spreadsheet's does; the width it writes is remembered with the rest of the sheet layout. */
.dnd-resizable-col {
    position: relative;
}
.dnd-th-handle {
    position: absolute;
    top: 0;
    bottom: 0;
    right: -5px;
    /* Wider than the bar it draws, so there is grab room either side of it. */
    width: 10px;
    cursor: col-resize;
}
.dnd-th-handle::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    margin-left: -1.5px;
    /* Visible enough to read as something you can take hold of, rather than a table rule. */
    width: 3px;
    border-radius: 2px;
    background: var(--mud-palette-text-secondary, #777);
    transition: background-color 0.15s ease;
}
.dnd-th-handle:hover::before,
.dnd-th-handle.dragging::before {
    background: var(--mud-palette-primary);
}
/* Zero until the name column is narrowed, at which point it takes what the name gave up — without
   it, a fixed table hands the slack back to every column in proportion and they all grow. */
.dnd-equip-spacer {
    padding: 0 !important;
}

/* Saving throws read down the columns — STR/DEX/CON on the left, INT/WIS/CHA on the right —
   which is how every printed sheet orders them. Column flow into three rows does that from the
   natural DOM order. A container query, not a breakpoint, folds it to one column when the
   sidebar itself is squeezed: what matters is this box's width, not the window's. */
.dnd-saves { container-type: inline-size; }
.dnd-saves-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: repeat(3, auto);
    grid-auto-flow: column;
    column-gap: 8px;
}
@container (max-width: 150px) {
    .dnd-saves-grid {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: none;
        grid-auto-flow: row;
    }
}

/* The Advanced effects (JSON) editor: drag the corner to give a big blob room to breathe. */
.dnd-resizable-json textarea {
    resize: vertical;
    min-height: 90px;
}

/* Manual screenshots (Docs/ManualFigure.razor) */
.manual-figure { margin: 12px 0 20px; }
.manual-figure img { display: block; max-width: 100%; height: auto; border: 1px solid var(--mud-palette-lines-default); border-radius: 6px; box-shadow: 0 2px 8px rgba(0,0,0,.18); }
.manual-figure figcaption { margin-top: 6px; font-size: 0.85rem; opacity: .75; font-style: italic; }
