
html {
    overflow-x: clip; /* clip instead of hidden — prevents horizontal scroll without creating a scroll container, so position:fixed children remain viewport-anchored */
}

body {
    font-family: var(--font-body), serif;
    color: var(--text-color);
    margin: 0;
    padding: 0;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-header), serif;
    color: var(--text-color);
    transition: color 0.3s ease;
}

a {
    color: var(--color-copper);
}

a:hover {
    color: var(--color-copper-light);
}
/* Form Elements */
.form-control, .form-select {
    display: block;
    width: 100%;
}

.form-control, .form-select, input[type="text"], input[type="number"],
input[type="email"], input[type="password"], input[type="search"],
input[type="url"], input[type="tel"], input[type="date"], input[type="time"],
input[type="datetime-local"], input[type="month"], input[type="week"],
textarea, select {
    box-sizing: border-box;
    padding: 0.375rem 0.75rem;
    font-size: 1rem;
    font-weight: 400;
    line-height: 1.5;
    border-radius: 0.375rem;
    background-color: var(--bg-input);
    border: 1px solid var(--input-border);
    /* --text-color, not --text-primary: --text-primary is a fixed dark ink that
       never moves, and it was only ever legible because --bg-input was pale in
       both modes. Now that the surface follows the mode the text has to as well. */
    color: var(--text-color);
    font-family: var(--font-body), serif;
    transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

/* The list a <select> drops down is drawn by the browser, not by the page. Chrome
   and Firefox honour a background on <option>; Safari does not, which is what
   `color-scheme` on the theme wrapper in tokens.css covers. Both are needed —
   neither alone paints every browser's popup. */
option, optgroup {
    background-color: var(--bg-input);
    color: var(--text-color);
}

.form-control:focus, .form-select:focus, input:focus, textarea:focus, select:focus {
    background-color: var(--bg-input);
    border-color: var(--color-gold);
    box-shadow: 0 0 0 0.2rem var(--focus-shadow);
    outline: none;
}

/* --text-muted, not --text-secondary: the latter is a fixed dark ink and would
   vanish into a dark input. Widened past .form-control at the same time — a bare
   <input placeholder="…"> had no rule at all and took the browser's grey. */
.form-control::placeholder,
input::placeholder,
textarea::placeholder {
    color: var(--text-muted);
    opacity: 0.85;
}

/* Chrome paints an autofilled field with its own near-white wash and ignores
   background-color outright. An inset shadow the size of the box is the only
   thing it does honour, so the surface is drawn with one. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
select:-webkit-autofill {
    -webkit-box-shadow: 0 0 0 1000px var(--bg-input) inset;
    -webkit-text-fill-color: var(--text-color);
    caret-color: var(--text-color);
}

/* Bootstrap overrides for focus states */
.btn:focus, .btn:active:focus, .form-control:focus {
    box-shadow: 0 0 0 0.1rem var(--bg-main), 0 0 0 0.25rem var(--color-gold);
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--valid-outline);
}

.invalid {
    outline: 1px solid var(--color-danger);
}

.validation-message {
    color: var(--color-danger);
}

main {
    flex: 1;
}

/* ========================================
   Ember Anvil Loading Animation
   ======================================== */
.forge-loader {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    width: 100%;
    min-height: 100vh;
    padding: 1rem;
    box-sizing: border-box;
}

.forge-loader-ring {
    position: relative;
    width: 10rem;
    height: 10rem;
    filter: drop-shadow(0 0 12px rgba(var(--color-gold-rgb), 0.35));
    animation: forge-breathe 3s ease-in-out infinite;
}

@media (min-width: 641px) {
    .forge-loader-ring {
        width: 12rem;
        height: 12rem;
    }
}

.forge-loader-svg {
    width: 100%;
    height: 100%;
    overflow: visible;
}

.forge-anvil {
    transform-origin: center;
    animation: forge-anvil-pulse 1.2s ease-in-out infinite;
}

.forge-track {
    fill: none;
    stroke: var(--text-secondary);
    stroke-width: 8;
    opacity: 0.6;
}

.forge-progress {
    fill: none;
    stroke: url(#forge-progress-gradient);
    stroke-width: 8;
    stroke-linecap: round;
    transform: rotate(-90deg);
    transform-origin: 50% 50%;
    /* ponytail: circumference as % of viewBox normalized diagonal (sqrt(w²+h²)/sqrt(2) = 160 for square).
       2πr / 160 = 2π * 90 / 160 ≈ 3.5343. Using the full diagonal (226.27) was wrong by 1/√2, capping fill at ~70.7%. */
    stroke-dasharray: calc(3.5343 * var(--blazor-load-percentage, 0%)), 1000%;
    transition: stroke-dasharray 0.15s ease-out;
    filter: url(#forge-glow);
}

#forge-progress-gradient .forge-gradient-start { animation: forge-gradient-start 5s ease-in-out infinite; }
#forge-progress-gradient .forge-gradient-mid { animation: forge-gradient-mid 5s ease-in-out infinite; }
#forge-progress-gradient .forge-gradient-end { animation: forge-gradient-end 5s ease-in-out infinite; }

@keyframes forge-gradient-start {
    0%, 25% { stop-color: var(--mm-accent-red); }
    35% { stop-color: var(--mm-accent-red); }
    50% { stop-color: var(--dh-bg-dark); }
    65% { stop-color: var(--dh-bg-dark); }
    100% { stop-color: var(--mm-accent-red); }
}

@keyframes forge-gradient-mid {
    0%, 25% { stop-color: var(--mm-accent-red); }
    35% { stop-color: var(--mm-accent-red); }
    50% { stop-color: var(--dh-bg-dark); }
    65% { stop-color: var(--dh-bg-dark); }
    100% { stop-color: var(--mm-accent-red); }
}

@keyframes forge-gradient-end {
    0%, 25% { stop-color: var(--mm-accent-red); }
    35% { stop-color: var(--dh-bg-dark); }
    50% { stop-color: var(--dh-bg-dark); }
    65% { stop-color: var(--mm-accent-red); }
    100% { stop-color: var(--mm-accent-red); }
}

.forge-hammer {
    stroke: var(--mm-accent-maroon);
    stroke-width: 1;
    transform-origin: 80px 78px;
    animation: forge-strike 1.2s ease-in-out infinite;
}

.forge-sparks {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 0;
    height: 0;
    pointer-events: none;
}

.forge-sparks span {
    position: absolute;
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--dh-accent-gold-light);
    opacity: 0;
    top: 0;
    left: 0;
    animation: forge-spark 1.2s ease-out infinite;
}

.forge-sparks span:nth-child(1) { animation-delay: 0.3s; --spark-angle: -35deg; --spark-distance: 28px; --spark-color: var(--dh-accent-gold-light); }
.forge-sparks span:nth-child(2) { animation-delay: 0.35s; --spark-angle: -15deg; --spark-distance: 36px; --spark-color: var(--color-gold); }
.forge-sparks span:nth-child(3) { animation-delay: 0.4s; --spark-angle: 5deg; --spark-distance: 32px; --spark-color: var(--dh-accent-teal); }
.forge-sparks span:nth-child(4) { animation-delay: 0.45s; --spark-angle: 25deg; --spark-distance: 24px; --spark-color: var(--dh-accent-teal-light); }
.forge-sparks span:nth-child(5) { animation-delay: 0.5s; --spark-angle: 45deg; --spark-distance: 30px; --spark-color: var(--dh-accent-gold-light); }
.forge-sparks span:nth-child(6) { animation-delay: 0.55s; --spark-angle: 70deg; --spark-distance: 22px; --spark-color: var(--color-gold); }
.forge-sparks span:nth-child(7) { animation-delay: 0.6s; --spark-angle: -60deg; --spark-distance: 26px; --spark-color: var(--dh-accent-teal); }
.forge-sparks span:nth-child(8) { animation-delay: 0.65s; --spark-angle: -80deg; --spark-distance: 34px; --spark-color: var(--dh-accent-teal-light); }

.forge-loader-text {
    text-align: center;
    font-family: var(--font-header), serif;
    font-weight: 700;
    font-size: 1rem;
    color: var(--text-header);
    letter-spacing: 0.5px;
}

.forge-loader-text:after {
    content: var(--blazor-load-percentage-text, "Loading");
}

@keyframes forge-breathe {
    0%, 100% { filter: drop-shadow(0 0 10px rgba(var(--color-gold-rgb), 0.3)); }
    50% { filter: drop-shadow(0 0 18px rgba(var(--dh-accent-teal-rgb), 0.45)); }
}

@keyframes forge-anvil-pulse {
    0%, 100% { transform: scale(1); }
    55% { transform: scale(1.02); }
    70% { transform: scale(0.99); }
}

@keyframes forge-strike {
    0% { transform: rotate(-10deg); }
    40% { transform: rotate(10deg); }
    55% { transform: rotate(-45deg); }
    60% { transform: rotate(-47deg); }
    80% { transform: rotate(10deg); }
    100% { transform: rotate(-10deg); }
}

@keyframes forge-spark {
    0%, 40% {
        opacity: 0;
        transform: translate(0, 0) scale(0.5);
    }
    45% {
        opacity: 1;
        transform: translate(0, 0) scale(1);
    }
    90% {
        opacity: 0;
        transform: translate(
            calc(var(--spark-distance) * cos(var(--spark-angle))),
            calc(var(--spark-distance) * sin(var(--spark-angle)) * -1)
        ) scale(0.4);
    }
    100% {
        opacity: 0;
        transform: translate(
            calc(var(--spark-distance) * cos(var(--spark-angle))),
            calc(var(--spark-distance) * sin(var(--spark-angle)) * -1)
        ) scale(0.2);
    }
}

@media (prefers-reduced-motion: reduce) {
    .forge-loader-ring,
    .forge-anvil,
    .forge-hammer,
    .forge-sparks span,
    #forge-progress-gradient .forge-gradient-start,
    #forge-progress-gradient .forge-gradient-mid,
    #forge-progress-gradient .forge-gradient-end {
        animation: none;
    }

    .forge-sparks {
        display: none;
    }
}

/* Blazor Error UI */
#blazor-error-ui {
    color-scheme: light only;
    background: var(--bg-card);
    border-top: 2px solid var(--color-danger);
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(var(--shadow-rgb), 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
    color: var(--text-primary);
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
    color: var(--color-danger);
}

#blazor-error-ui .reload {
    color: var(--color-copper);
}

@media (min-width: 641px) {
    article {
        padding-left: 2rem !important;
        padding-right: 1.5rem !important;
    }
}

/* .privacy-toggle and its descendants moved to
   Common/Components/Editing/PublicVisibilityToggle.razor.css (ladder rung 2):
   the three renderers collapsed into that component once it stopped needing an
   EditContext. */

/* Icon button utilities */
.btn-icon {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
}

.btn-icon-only {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.5rem;
    aspect-ratio: 1;
}

/* Subtle nav link button used across detail/compare/conversion pages */
.btn-nav-link {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    background: none;
    border: none;
    padding: 0.3rem 0.6rem;
    color: var(--text-muted);
    font-size: 0.875rem;
    font-family: var(--font-body), serif;
    cursor: pointer;
    border-radius: 4px;
    transition: background-color 0.15s, color 0.15s;
    text-decoration: none;
}

.btn-nav-link:hover {
    background-color: var(--editor-highlight-bg);
    color: var(--text-color);
}

.btn-nav-link:disabled,
.btn-nav-link[disabled] {
    opacity: 0.4;
    cursor: default;
}

.btn-nav-link:disabled:hover,
.btn-nav-link[disabled]:hover {
    background: none;
    color: var(--text-muted);
}

/* ========================================
   Theme-Aware Button Styles (merged with Bootstrap replacements)
   ======================================== */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.5rem 1rem;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 1rem;
    font-family: var(--font-header), serif;
    font-weight: 600;
    line-height: 1.5;
    text-align: center;
    text-decoration: none;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    transition: all 0.2s ease;
    vertical-align: middle;
    user-select: none;
    white-space: nowrap;
}

.btn-sm {
    padding: 0.375rem 0.75rem;
    font-size: 0.875rem;
    border-radius: 0.25rem;
}

.btn:disabled,
.btn[disabled] {
    opacity: 0.65;
    cursor: not-allowed;
    pointer-events: none;
}

.btn:focus-visible {
    outline: 2px solid var(--focus-color);
    outline-offset: 2px;
}

.btn-primary {
    background: linear-gradient(180deg, var(--color-gold-light) 0%, var(--color-gold) 50%, var(--color-gold-dark) 100%);
    color: var(--on-primary-text);
    border: 1px solid var(--color-gold-dark);
}

.btn-primary:hover,
.btn-primary:focus {
    background: linear-gradient(180deg, var(--color-gold) 0%, var(--color-gold-dark) 100%);
    box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.2);
    color: var(--on-primary-text);
}

.btn-primary:active {
    background: var(--color-gold-dark);
}

.btn-secondary {
    background: linear-gradient(180deg, var(--color-secondary-light) 0%, var(--color-secondary) 50%, var(--color-secondary-dark) 100%);
    color: var(--on-secondary-text);
    border: 1px solid var(--color-secondary-dark);
}

.btn-secondary:hover,
.btn-secondary:focus {
    background: linear-gradient(180deg, var(--color-secondary) 0%, var(--color-secondary-dark) 100%);
    box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.2);
    color: var(--on-secondary-text);
}

.btn-secondary:active {
    background: var(--color-secondary-dark);
}

.btn-danger {
    background: linear-gradient(180deg, var(--color-danger-light) 0%, var(--color-danger) 100%);
    color: var(--on-danger-text);
    border: 1px solid var(--color-danger-dark);
}

.btn-danger:hover,
.btn-danger:focus {
    background: linear-gradient(180deg, var(--color-danger) 0%, var(--color-danger-dark) 100%);
    box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.2);
    color: var(--on-danger-text);
}

.btn-danger:active {
    background: var(--color-danger-dark);
}

.btn-info {
    background: linear-gradient(180deg, var(--color-copper-light) 0%, var(--color-copper) 100%);
    color: var(--on-info-text);
    border: 1px solid var(--color-copper-dark);
}

.btn-info:hover,
.btn-info:focus {
    background: linear-gradient(180deg, var(--color-copper) 0%, var(--color-copper-dark) 100%);
    box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.2);
    color: var(--on-info-text);
}

.btn-info:active {
    background: var(--color-copper-dark);
}

.btn-warning {
    background: linear-gradient(180deg, var(--color-warning-light) 0%, var(--color-warning) 100%);
    color: var(--on-warning-text);
    border: 1px solid var(--color-warning-dark);
}

.btn-warning:hover,
.btn-warning:focus {
    background: linear-gradient(180deg, var(--color-warning) 0%, var(--color-warning-dark) 100%);
    box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.2);
    color: var(--on-warning-text);
}

.btn-warning:active {
    background: var(--color-warning-dark);
}

.btn-success {
    background: linear-gradient(180deg, var(--color-success-light) 0%, var(--color-success) 100%);
    color: var(--on-success-text);
    border: 1px solid var(--color-success-dark);
}

.btn-success:hover,
.btn-success:focus {
    background: linear-gradient(180deg, var(--color-success) 0%, var(--color-success-dark) 100%);
    box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.2);
    color: var(--on-success-text);
}

.btn-success:active {
    background: var(--color-success-dark);
}

.btn-accent {
    background: linear-gradient(180deg, var(--color-copper-light) 0%, var(--color-copper) 100%);
    color: var(--on-info-text);
    border: 1px solid var(--color-copper-dark);
}

.btn-accent:hover,
.btn-accent:focus {
    background: linear-gradient(180deg, var(--color-copper) 0%, var(--color-copper-dark) 100%);
    box-shadow: 0 2px 4px rgba(var(--shadow-rgb), 0.2);
    color: var(--on-info-text);
}

.btn-accent:active {
    background: var(--color-copper-dark);
}

.btn-accent:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Text utilities */
.text-muted {
    color: var(--text-muted) !important;
}

/* ── Bootstrap-replacement utilities ── */
/* `.form-group` left this file on 2026-08-16: it is `FormField`'s own class
   now, and FormField is the only component that renders it, so the rule is a
   rung-1 selector in FormField.razor.css. */

.visually-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

.mt-2 {
    margin-top: 0.5rem;
}

/* ========================================
   Toggle Switch (universal checkbox style)
   ======================================== */

/* The off state is declared here, beside the `:checked` rule it pairs with.
   It was missing until 2026-08-16: the track had a colour when checked and
   nothing when not, and the only reason an unchecked toggle read as off was
   FoeEditorShell's `::deep .form-group input` skin painting it by accident —
   on the four editor pages only. When that skin was deleted (it was one of
   three copies of an input re-skin), every unchecked toggle on those pages
   started rendering filled, i.e. looking switched on. */
input[type="checkbox"] {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    display: inline-block;
    width: 2.25rem;
    height: 1.25rem;
    border-radius: 5px;
    cursor: pointer;
    flex-shrink: 0;
    vertical-align: middle;
    transition: background 0.18s ease, box-shadow 0.18s ease;
    background: var(--card-bg);
    border: 1px solid var(--card-border);
}

input[type="checkbox"]::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 0.2rem;
    transform: translateY(-50%);
    width: 0.85rem;
    height: 0.85rem;
    border-radius: 50%;
    background: gray;
    transition: left 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
                background 0.18s ease;
}

input[type="checkbox"]:checked {
    background: var(--color-gold);
}

input[type="checkbox"]:checked::before {
    background: var(--color-secondary);
}

input[type="checkbox"]:checked::before {
    left: calc(2.25rem - 0.85rem - 0.2rem);
}

input[type="checkbox"]:focus-visible {
    outline: 2px solid var(--color-gold);
    outline-offset: 2px;
}

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

input[type="checkbox"]:disabled::before {
    box-shadow: none;
}

/* ── Touch Targets ── */
.touch-target-min {
    min-height: 44px;
    min-width: 44px;
}

/* ── Foe-list card chrome (shared layer) ──
   Pages that hand-roll card-grid markup (Home featured-preview, FeaturedFeed,
   EnvironmentList) live here. Pages on <FoeListLayout> keep their own scoped
   copy; this block is the source of truth for the shared primitives. ponytail:
   the per-page scoped copies in EncounterList.razor.css / FoeListLayout.razor.css
   duplicate this so scoped-CSS stripping can happen later without re-deriving
   from the old foe-list.css. */

/* Shared content-width container for major pages (list, edit, import, compare, print, detail, etc.) */
.page-width {
    max-width: 1400px;
    margin: 0 auto;
    width: 100%;
    box-sizing: border-box;
}

@media (min-width: 1600px) {
    .page-width {
        max-width: 1800px;
    }
}

/* .foe-list / .list-header moved to Common/Components/UI/ListPage.razor.css
   (ladder rung 2): the six list routes render <ListPage> instead of
   hand-rolling the shell. */

/* .search-filter-container / .filter-row moved to the components that render
   them (SearchFilterContainer, FilterRow in Common/Components/UI, rung 2). */

/* .card-grid / .card-item / .card-content moved to the components that render
   them (CardGrid/EntityCard/CardContent). .card-header-row, .card-type,
   .card-tags, .card-stats and .stat moved to CardContent.razor.css /
   CardStatsShell.razor.css with the markup (ladder rung 1/2). The remaining
   descendant chrome (.card-tag, .card-teaser-description,
   .card-footer-creator, .card-actions) moved to the CardTag /
   CardTeaserDescription / CardFooterCreator / CardActions components
   (ladder rung 2) once their callers rendered the atoms instead of copying
   the markup. */

/* List-mode overrides moved to Common/Components/UI/CardGrid.razor.css: the
   grid owns `.card-grid--list`, and everything it reaches into is slotted in
   by callers, so the rules became ::deep there (rung 3). */

/* Page states: .empty-state and its h3/p children moved to
   Common/Components/UI/EmptyState.razor.css (ladder rung 2) — Home and
   Supporters render <EmptyState> now instead of hand-rolling the container. */

@media (max-width: 768px) {
    /* .filter-row mobile variant moved to FilterRow.razor.css */
}

@media (max-width: 480px) {
    /* .foe-list padding moved to ListPage.razor.css, .card-grid to CardGrid.razor.css */

    /* .card-content narrow-screen rules moved to CardContent.razor.css — that
       component owns the element, including the .card-header-row/.card-type
       min-width and overflow-wrap overrides. */
}

/* ========================================
   Cross-cutting patterns relocated from app.css (phase 07)
   ======================================== */

/* Relevance badges — hand-rolled raw markup (DaggerheartSearchResultItem,
   DnDSearchResultItem, CardContent, EnvironmentDisplay, EncounterList,
   MonsterDisplay, AdversaryDisplay, Home, FeatureSuggestionPanel) that reuses
   the Badge atom's class names without going through <Badge>, so Badge.razor.css's
   scoped copy can't reach them — this global copy is what actually styles them.
   .badge-role / .badge-property ARE live: FeatureSuggestionBadges.cs (used by
   FeatureSuggestionPanel.razor's raw <span>) returns "badge badge-role" /
   "badge badge-property" for tactical-role and Flying/Swimming/Burrowing tags,
   and tokens.css still carries --badge-role-*/--badge-property-* across all
   4 themes — keep them. */
.badge-role {
    background: var(--badge-role-bg);
    color: var(--badge-role-text);
}

.badge-type {
    background: var(--badge-type-bg);
    color: var(--badge-type-text);
}

.badge-property {
    background: var(--badge-property-bg);
    color: var(--badge-property-text);
}

.badge-featured {
    background-color: var(--color-gold);
    color: var(--on-primary-text);
}

.badge-scheduled {
    background-color: var(--color-copper);
    color: var(--on-primary-text);
}

/* .feature-editor moved to Common/Components/Editing/FeatureEditor.razor.css
   (ladder rung 2): the five renderers now render <FeatureEditor>. The
   editor-page variant stays in FoeEditorShell.razor.css. */

/* Adversary/Monster builder: stat suggestion buttons */
.btn-suggestion {
    font-size: 0.75rem;
    padding: 0.1rem 0.5rem;
    border: 1px solid var(--accent-color);
    background: transparent;
    color: var(--accent-color);
    border-radius: 4px;
    cursor: pointer;
}

.btn-suggestion:hover {
    background: var(--accent-color);
    color: var(--on-primary-text);
}

/* .tag-grid moved to Common/Components/UI/TagGrid.razor.css (ladder rung 2):
   the four renderers now render <TagGrid> instead of hand-rolling the div. */

/* .linked-foes-edit-list / .linked-foe-edit-item moved to
   Common/Components/Editing/LinkedFoeEditList.razor.css, .linked-foe-chip to
   LinkedFoeChip.razor.css (ladder rung 2). */

/* Role Suggestion (role-chip-name survives; role-chip/--active/-primary/
   -secondary/-confidence/-label/-power-modifier had zero consumers — dropped) */
.role-chip-name {
    font-weight: 500;
}

/* Spell Group family owned by SpellGroup (Common/Components/UI/SpellGroup.razor):
   .spell-group/.spell-group-header scoped there, .form-group--compact reached as a
   ::deep fragment hook. The .btn-danger rules were dead — the header remove button
   is btn-nav-link. */


/* ── Encounter difficulty palette (shared, defined once) ──
   The structural readout chrome (.difficulty-row/-label/-value) is owned by
   DifficultyBadge/DifficultyReadout (Common/Components/UI). These color rules
   stay global because the label class is composed at runtime
   (`difficulty-@Level.ToLowerInvariant()`) and a scoped rule cannot target a
   runtime-composed name. */

/* One rule per label in GameSystems.DifficultyLabels (D&D: Low/Moderate/Hard/
   Overwhelming; Daggerheart: Trivial/Easy/Standard/Hard/Overwhelming) plus the
   "None" empty-encounter case. The class is composed as
   `difficulty-@Label.ToLowerInvariant()`, so adding a label without a rule here
   renders an uncoloured badge. `medium`/`high`/`deadly` were removed in the
   2026-08-02 sweep — no label has produced them since the 2024-rules rename. */
.difficulty-trivial { background: var(--difficulty-easy-bg); color: var(--difficulty-easy-text); }
.difficulty-easy { background: var(--difficulty-easy-bg); color: var(--difficulty-easy-text); }
.difficulty-low { background: var(--difficulty-easy-bg); color: var(--difficulty-easy-text); }
.difficulty-moderate { background: var(--difficulty-moderate-bg); color: var(--difficulty-moderate-text); }
.difficulty-standard { background: var(--difficulty-moderate-bg); color: var(--difficulty-moderate-text); }
.difficulty-hard { background: var(--difficulty-hard-bg); color: var(--difficulty-hard-text); }
.difficulty-overwhelming { background: var(--difficulty-deadly-bg); color: var(--difficulty-deadly-text); }
.difficulty-none { background: var(--card-bg); color: var(--text-muted); }

/* ── Encounter card description ──
   .encounter-desc left on 2026-08-17: all seven renderers sat inside a
   <CardStatsShell>, whose `::deep .stat` already set the same size and colour
   at (0,2,0) against this rule's (0,1,0), so only its italic was reaching
   anything. They render <CardDescriptionStat> now, which owns that italic. */

/* ── Filter chrome: clear-filters moved to ClearFiltersButton.razor.css (rung 2)
   when the five drawers that hand-wrote the button started rendering it.
   filter-tag/filter-label moved to FilterTag.razor.css /
   ActiveFilterChips.razor.css the same way. ── */

/* ── List search row (shared: ListSearchControls, FoeListLayout, ContentBundleList,
   CollectionList — the last three hand-write the row) ── */
/* .search-row moved to Common/Components/UI/SearchRow.razor.css (rung 2). */


/* (also rendered by EncounterScenarioPanel) */
/* .suggestion-loading moved to Common/Components/UI/SuggestionLoading.razor.css (rung 2). */

/* GlobalUtilities: white-space: nowrap button utility (ListSearchControls + ContentBundleList), same shape as touch-target-min. */
.filter-toggle {
    white-space: nowrap;
}

/* .builder-actions moved to EncounterBuilder.razor.css (rung 2 / Task 15):
   ContentBundleEdit adopted FoeEditorShell + FormActions, so EncounterBuilder is
   the sole author and the rule became scoped. The old mobile column variant was
   ContentBundleEdit-only and died with it — EncounterBuilder already hides this
   bar on mobile (its own 768px block) in favour of .builder-mobile-actions. */

/* ── Filter group (shared: Monster/Adversary/Encounter filter controls,
   ContentBundleList, EnvironmentList — each renders its own copy) ── */
/* .filter-group moved to Common/Components/UI/FilterGroup.razor.css (rung 2):
   the seven filter components render <FilterGroup> now. MultiSelectDropdown
   composes the class onto its own root and carries its own copy. */

