/* ── Filter panel ───────────────────────────────────── */
.quest-layout {
    display: flex;
    gap: 24px;
    align-items: flex-start;
    padding: 20px;
}

.quest-filters {
    width: 240px;
    flex-shrink: 0;
    background: #1a1a1a;
    border: 1px solid #333;
    border-radius: 4px;
    padding: 14px;
    font-size: 0.85rem;
    position: sticky;
    top: 20px;
    max-height: calc(100vh - 40px);
    overflow-y: auto;
}

.quest-filters h3 {
    margin: 0 0 12px;
    font-size: 0.9rem;
    color: #ccc;
    border-bottom: 1px solid #333;
    padding-bottom: 6px;
}

.filter-section {
    margin-bottom: 16px;
}

.filter-section label {
    display: block;
    color: #aaa;
    margin-bottom: 4px;
    font-size: 0.8rem;
}

.filter-section select,
.search-input {
    width: 100%;
    background: #111;
    color: #d6d8d8;
    border: 1px solid #444;
    border-radius: 3px;
    padding: 4px 6px;
    font-size: 0.82rem;
    box-sizing: border-box;
}

.arc-details summary {
    cursor: pointer;
    color: #aaa;
    font-size: 0.8rem;
    padding: 2px 0;
    list-style: none;
    display: flex;
    align-items: center;
    gap: 4px;
    margin-bottom: 4px;
}

.arc-details summary::before {
    content: '▶';
    font-size: 0.6em;
}

.arc-details[open] summary::before {
    content: '▼';
}

/* ── Level slider ───────────────────────────────────── */
.level-range-dual {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.dual-slider-wrap {
    position: relative;
    height: 20px;
}

.dual-slider-track,
.dual-slider-range {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    height: 4px;
    border-radius: 2px;
    pointer-events: none;
}

.dual-slider-track {
    left: 0;
    right: 0;
    background: #444;
}

.dual-slider-range {
    background: #c8a84b;
}

.dual-slider-wrap input[type=range] {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    pointer-events: none;
}

.dual-slider-wrap input[type=range]::-webkit-slider-runnable-track {
    background: transparent;
    height: 4px;
}

.dual-slider-wrap input[type=range]::-moz-range-track {
    background: transparent;
    height: 4px;
}

.dual-slider-wrap input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
    pointer-events: all;
    cursor: pointer;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #c8a84b;
    border: 2px solid #1a1c1c;
    margin-top: -6px;
}

.dual-slider-wrap input[type=range]::-moz-range-thumb {
    pointer-events: all;
    cursor: pointer;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #c8a84b;
    border: 2px solid #1a1c1c;
    box-sizing: border-box;
}

.dual-slider-labels {
    position: relative;
    height: 18px;
    margin-top: 2px;
    font-size: 0.8rem;
    color: #d6d8d8;
}

.slider-val {
    position: absolute;
    transform: translateX(-50%);
}

/* ── Adventure pack list ────────────────────────────── */
.pack-toggle-all {
    display: flex;
    gap: 8px;
    margin-bottom: 6px;
}

.pack-toggle-all button {
    background: none;
    border: 1px solid #444;
    color: #aaa;
    font-size: 0.75rem;
    padding: 2px 6px;
    border-radius: 3px;
    cursor: pointer;
}

.pack-toggle-all button:hover {
    background: #222;
    color: #ddd;
}

.pack-list {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.pack-list label {
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    color: #aaa;
    margin: 0;
}

.pack-list label:hover {
    color: #ddd;
}

.filter-apply {
    width: 100%;
    background: #2a2a2a;
    border: 1px solid #555;
    color: #d6d8d8;
    padding: 6px;
    border-radius: 3px;
    cursor: pointer;
    font-size: 0.85rem;
    margin-top: 4px;
}

.filter-apply:hover {
    background: #333;
}

/* ── Quest table ────────────────────────────────────── */
.quest-main {
    flex: 1;
    min-width: 0;
}

.quest-main h2 {
    margin: 0 0 12px;
    font-size: 1.1rem;
}

.quest-count {
    font-size: 0.8rem;
    color: #666;
    margin-bottom: 10px;
}

.quest-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.82rem;
}

.quest-table th {
    background: #1a1a1a;
    color: #aaa;
    padding: 6px 8px;
    text-align: left;
    border-bottom: 1px solid #333;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
}

/* The sort affordance and arrows live in item.css, which _Layout loads on every page — the item
   browse and search tables sort too and never load this sheet. */

.quest-table td {
    padding: 5px 8px;
    border-bottom: 1px solid #222;
    color: #bbb;
    white-space: nowrap;
}

.quest-table tr:hover td {
    background: #1a1a1a;
}

.quest-table td a {
    color: #c8a84b;
    text-decoration: none;
}

.quest-table td a:hover {
    text-decoration: underline;
}

.quest-table td.xp {
    color: #888;
    font-size: 0.78rem;
}

.quest-table td.favor {
    color: #8ab4d0;
}

.pack-details summary {
    cursor: pointer;
    color: #aaa;
    font-size: 0.8rem;
    padding: 2px 0;
    list-style: none;
    display: flex;
    align-items: center;
    gap: 4px;
    margin-bottom: 4px;
}

.pack-details summary::before {
    content: '▶';
    font-size: 0.6em;
}

.pack-details[open] summary::before {
    content: '▼';
}

.quest-table tr.quest-heroic td {
    background: rgba(200, 168, 75, 0.10);
}

.quest-table tr.quest-epic td {
    background: rgba(80, 140, 210, 0.13);
}

.quest-table tr.quest-legendary td {
    background: rgba(160, 100, 220, 0.15);
}

/* --- Pack detail -------------------------------------
   Two tables on one page, so each needs a name. The count sits in the heading rather than on a line
   of its own: "how many quests" is part of what the heading answers. */
.pack-section {
    margin: 22px 0 8px;
    font-size: 0.95rem;
    color: #ddd;
    font-weight: 600;
}

.pack-section:first-of-type {
    margin-top: 4px;
}

.pack-section-count {
    margin-left: 6px;
    font-size: 0.78rem;
    font-weight: 400;
    color: #777;
}

/* A cell holding both difficulty bands: heroic on top, epic or legendary below.
   The row background can no longer carry the tier now that one row is both, so the colour moves onto
   the values themselves — the same three hues the quest list washes its rows in, promoted from a 10%
   tint to a text colour so they still read at this size. */
.quest-table td.tiered span {
    display: block;
    line-height: 1.45;
}

.tier-heroic { color: #c8a84b; }
.tier-epic { color: #6ea3dc; }
.tier-legendary { color: #ac7ee0; }

.quest-table td.tiered.xp span {
    font-size: 0.78rem;
}

/* The colours are only legible as a set once something names them. */
.tier-key {
    display: flex;
    gap: 14px;
    margin: 8px 0 0;
    font-size: 0.75rem;
}

/* .raid-badge lives in item.css: the pack index draws one and never loads this sheet. */

.tier-legend {
    margin-top: 16px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.legend-item {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.85em;
    color: #999;
    padding: 3px 6px;
    border-radius: 3px;
}

.legend-swatch {
    width: 16px;
    height: 12px;
    border-radius: 2px;
    flex-shrink: 0;
}

.legend-item.quest-heroic .legend-swatch {
    background: rgba(200, 168, 75, 0.25);
}

.legend-item.quest-epic .legend-swatch {
    background: rgba(80, 140, 210, 0.35);
}

.legend-item.quest-legendary .legend-swatch {
    background: rgba(160, 100, 220, 0.4);
}

/* ── Quest Detail Page ───────────────────────────────── */
.quest-detail-page {
    padding: 20px;
}

/* ── Entry plate ─────────────────────────────────────
   The one place this page spends any boldness. Everything below it stays quiet.

   Two type roles, which is most of the difference between this page and the developer draft it
   replaces: a serif for the things that name something, the existing sans for everything that
   measures something. */
.quest-detail-page {
    --ink: #111;
    --ink-raise: #17171a;
    --rule: #2f2f34;
    --gold: #c8a84b;
    --gold-lit: #e0c97a;
    --muted: #8a8a90;
    --display: Georgia, "Iowan Old Style", "Times New Roman", serif;
}

/* Bleeds past the 20px on the page wrapper and the 20px on the body, so the band lines up with the
   site header above it rather than floating in a gutter. */
.quest-hero {
    display: flex;
    align-items: center;
    gap: 30px;
    margin: -20px -40px 0;
    padding: 26px 40px;
    background: var(--ink-raise);
    border-bottom: 1px solid var(--rule);
}

/* Shown whole, never cropped.
   These are not photographs that can be trimmed to taste: each is a composition the artist framed
   inside an ornate border, with the figures deliberately breaking out of it above and below. The
   band sits at the same height in every one, but the subject may be at the left, the centre or the
   right, and any fixed crop that suits one of them beheads the figure in another. Constraining the
   height and letting the width follow keeps all 638 correct — and because the art carries its own
   black surround, it sits on this page without needing a frame drawn around it. */
.quest-hero-art {
    flex-shrink: 0;
    height: clamp(170px, 23vw, 320px);
    width: auto;
    display: block;
}

.quest-hero-plate {
    min-width: 0;
}

/* Without art the band would be a slab of nothing, so the rule does the work the picture would. */
.quest-hero:not(.has-art) {
    border-top: 2px solid var(--gold);
}

.quest-eyebrow {
    font-size: 0.7rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--gold);
    margin-bottom: 8px;
}

.quest-title {
    font-family: var(--display);
    font-size: clamp(1.7rem, 3.4vw, 2.6rem);
    font-weight: normal;
    line-height: 1.1;
    letter-spacing: 0.01em;
    color: #f2ecd8;
    margin: 0;
    text-shadow: 0 2px 14px rgba(0, 0, 0, 0.8);
}

/* The glance: what you decide on before opening anything. The table below stays authoritative. */
.quest-placard {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 22px;
    margin-top: 12px;
    font-size: 0.85rem;
    color: #cfd1d1;
}

.placard-fact {
    display: flex;
    align-items: baseline;
    gap: 7px;
    font-variant-numeric: tabular-nums;
}

.placard-label {
    font-size: 0.66rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--muted);
}

@media (max-width: 700px) {
    /* Side by side there is not enough width for both, and shrinking the art to fit would undo the
       point of showing it whole. */
    .quest-hero {
        display: block;
        margin-left: -20px;
        margin-right: -20px;
        padding: 0 20px 20px;
    }

    .quest-hero-art {
        height: auto;
        width: 100%;
        margin: 0 -20px 18px;
        max-width: none;
        width: calc(100% + 40px);
    }

    /* A 150px label beside its value leaves under 200px for the value on a phone, which is how the
       aliases and the XP table ended up running off the side of the page. Stacked, each gets the
       full width. */
    .quest-detail-page .quest-table,
    .quest-detail-page .quest-table tbody,
    .quest-detail-page .quest-table tr,
    .quest-detail-page .quest-table td {
        display: block;
        width: auto;
        max-width: none;
    }

    .quest-detail-page .quest-table .fn {
        width: auto;
        padding: 14px 0 3px;
    }

    .quest-detail-page .quest-table .fv { padding: 0 0 12px; }

    /* Its own minimum was wider than the screen. */
    .quest-detail-page .quest-xp-table { min-width: 0; width: 100%; }
    .quest-detail-page .quest-xp-table th,
    .quest-detail-page .quest-xp-table td { padding-right: 0; }

    /* Two columns with a 300px floor each put a 600px page on a 390px screen. Stacked, the floor
       stops applying and nothing forces the page wider than the phone. */
    .quest-detail-page .quest-content { flex-direction: column; }
    .quest-detail-page .quest-left-column,
    .quest-detail-page .quest-right-column { min-width: 0; width: 100%; }
}

.quest-header {
    display: flex;
    align-items: center;
    gap: 20px;
    margin-bottom: 20px;
    padding-bottom: 16px;
    border-bottom: 1px solid #3a3a3a;
}

.quest-image-container {
    flex-shrink: 0;
}

.quest-adventure-image {
    max-width: 150px;
    max-height: 100px;
    object-fit: cover;
    border-radius: 4px;
    border: 1px solid #444;
}

.quest-name {
    margin: 0;
    font-size: 24px;
    color: #e0c97a;
}

.quest-content {
    display: flex;
    gap: 20px;
}

.quest-left-column, .quest-right-column {
    flex: 1;
    min-width: 300px;
}

.quest-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.quest-table .fn {
    font-weight: bold;
    padding: 8px 8px 8px 0;
    vertical-align: top;
    width: 130px;
    color: #aaa;
}

.quest-table .fv {
    padding: 8px;
    vertical-align: top;
    color: #d6d8d8;
}

.quest-section {
    margin-top: 24px;
    margin-bottom: 16px;
    font-weight: bold;
    font-size: 16px;
    border-bottom: 2px solid #c8a84b;
    padding-bottom: 8px;
    color: #e0c97a;
}

.quest-content.single-column .quest-left-column {
    flex: 1 1 100%;
}

/* ── Contents ────────────────────────────────────────── */
.quest-body {
    display: flex;
    gap: 24px;
    align-items: flex-start;
}

.quest-sections {
    order: 1;
    flex: 1;
    /* Without this a wide loot table forces the flex item past its share and shoves the contents
       list off the edge instead of scrolling inside its own wrapper. */
    min-width: 0;
}

/* Ordered rather than placed second in the source: it should be reachable early by keyboard, but
   the content deserves the left-hand, wider half of the page. */
.quest-toc {
    order: 2;
    width: 210px;
    flex-shrink: 0;
    position: sticky;
    top: 16px;
    /* Long chest lists scroll within the list rather than growing past the viewport, which would
       defeat the point of it staying put. */
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    padding: 12px 14px;
    background: #1a1a1a;
    border: 1px solid #333;
    border-radius: 4px;
    font-size: 0.85rem;
}

.quest-toc ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Chest names run long and there are rarely more than a handful of entries, so the nesting is shown
   by indent rather than by bullets that would compete with the item lists further down. */
.quest-toc ul ul {
    padding-left: 18px;
    margin: 2px 0 4px;
}

.quest-toc li { padding: 2px 0; }

.quest-toc-heading {
    font-size: 0.66rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 10px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--rule);
}

.quest-toc > ul > li > a {
    font-family: var(--display);
    font-size: 1rem;
    color: var(--gold-lit);
}

.quest-toc > ul > li + li { margin-top: 8px; }

.quest-toc ul ul a {
    color: #aaa;
    font-weight: normal;
}

.quest-toc ul ul a:hover { color: #d6d8d8; }

/* Each section is jumped to by name, so it wears one. */
.quest-panel + .quest-panel { margin-top: 32px; }

/* A section heading names a thing, so it takes the display face. The rule is hairline and full
   width rather than a heavy 2px bar — the words should carry the division, not the ink. */
.quest-panel-heading {
    margin-bottom: 18px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--rule);
    color: var(--gold-lit);
    font-family: var(--display);
    font-size: 1.35rem;
    font-weight: normal;
    letter-spacing: 0.01em;
}

.quest-detail-page .quest-section {
    margin-top: 30px;
    margin-bottom: 14px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--rule);
    font-family: var(--display);
    font-size: 1.05rem;
    font-weight: normal;
    color: var(--gold-lit);
}

/* Without the debug panel beside it this table has the whole content width to itself, and a
   label/value pair stretched across 1100px is two columns with a desert between them. */
.quest-detail-page .quest-table { max-width: 720px; }

/* The label column reads as an index down the left rather than competing with its own values. */
.quest-detail-page .quest-table .fn {
    font-family: inherit;
    font-size: 0.72rem;
    font-weight: normal;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--muted);
    width: 150px;
    padding: 10px 12px 10px 0;
}

/* The index's table sets nowrap so its columns stay on one line. Inherited here it drove long
   values — an alias, a destination name — straight out of the column and under the panel beside it
   instead of wrapping. */
.quest-detail-page .quest-table .fv {
    padding: 9px 0;
    border-bottom: 1px solid #1c1c20;
    white-space: normal;
}

/* Post-heroic tiers read as an alarm in the shared red. The site already says "epic" in blue on the
   index rows and in the loot tables, so it says it in blue here too. */
.quest-detail-page .cr-tier { line-height: 1.6; }
.quest-detail-page .cr-epic { color: #8ab4d0; font-weight: 600; }
.quest-detail-page .cr-normal { color: #d6d8d8; }

/* A table inside a table cell: its header has to sit quieter than the row label to its left, or the
   two compete over which one is the heading. */
.quest-detail-page .quest-xp-table th {
    font-size: 0.68rem;
    font-weight: normal;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
    border-bottom: 1px solid var(--rule);
}

.quest-detail-page .quest-xp-table td { font-variant-numeric: tabular-nums; }
.quest-detail-page .quest-xp-table .xp-tier { color: var(--muted); }

.quest-detail-page .quest-table tr:last-child .fv,
.quest-detail-page .quest-table tr:last-child .fn {
    border-bottom: none;
}

/* A jump lands the heading hard against the top of the viewport otherwise. */
.quest-panel,
.quest-section,
.map-frame { scroll-margin-top: 16px; }

/* Side by side needs width for both. Narrow, the list goes back to sitting above the content, where
   sticking it to the viewport would only eat the screen it is meant to help navigate. */
@media (max-width: 900px) {
    .quest-body { display: block; }

    .quest-toc {
        width: auto;
        position: static;
        max-height: none;
        margin-bottom: 24px;
    }
}

.quest-empty {
    color: #777;
    font-style: italic;
}

.map-list {
    display: flex;
    flex-direction: column;
    gap: 20px;
    /* Entries size to their map rather than stretching, so the hover outline
       wraps the image instead of the whole column. */
    align-items: center;
}

.map-entry {
    display: block;
    max-width: 100%;
    border: 1px solid #333;
    border-radius: 4px;
    overflow: hidden;
    background: #0a0a0a;
    line-height: 0;
}

.map-entry:hover {
    border-color: #c8a84b;
}

/* Never upscale past the map's own resolution — these are small bitmaps and stretching them
   to the column width just blurs them. Narrow viewports still shrink them to fit. */
.map-entry img {
    display: block;
    max-width: 100%;
    height: auto;
}

/* ── Map stage (shared by the quest page and the full-size map page) ── */
.map-stage-wrap {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
}

/* The frame the map and its markers sit in. Overflow is visible so a boss name beside a pin at the
   edge can run past the art rather than being cut in half — the labels are page elements, not part
   of the image, and clipping them to the picture serves nothing. */
.map-frame {
    position: relative;
    overflow: visible;
    max-width: 100%;
    border: 1px solid #333;
    border-radius: 4px;
    background: #0a0a0a;
    line-height: 0;
}

/* Shrink-wraps the image so the overlay's percentage positions resolve against exactly the drawn
   pixels. Wide maps — Saltmarsh is 2229px — scale down to fit rather than being clipped. */
.map-canvas {
    position: relative;
    display: inline-block;
    max-width: 100%;
}

.map-full {
    display: block;
    max-width: 100%;
    height: auto;
    user-select: none;
}

/* Upscaled dungeon art is pixel art: smoothing turns it to mush, nearest-neighbour keeps the
   walls and doors crisp. */
.map-upscaled .map-full {
    max-width: none;
    image-rendering: pixelated;
}

.map-overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

/* Centred on its point and left at the icon's own size — Mapster draws them the same way, and
   these range from 10x10 to 16x24, so a common box would distort every non-square one. */
.map-marker {
    position: absolute;
    display: block;
    line-height: 0;
    pointer-events: auto;
    cursor: help;
    transform: translate(calc(-50% + var(--nudge-x, 0px)), calc(-50% + var(--nudge-y, 0px)))
               scale(var(--marker-scale, 1));
    transform-origin: 50% 50%;
}

.map-marker img {
    display: block;
    image-rendering: pixelated;
}

/* Markers cluster tightly — traps beside the panel that disarms them, shrines in pairs — so the
   one under the cursor lifts clear of its neighbours instead of staying half-buried. */
.map-marker.hot {
    z-index: 5;
    transform: translate(calc(-50% + var(--nudge-x, 0px)), calc(-50% + var(--nudge-y, 0px)))
               scale(calc(var(--marker-scale, 1) * 1.5));
}

@media (prefers-reduced-motion: reduce) {
    .map-marker.hot { transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); }
}

/* A marker's name, on every named marker while the legend's Captions toggle is on. Sits beside the
   pin and is allowed to overlap the art rather than push anything around. */
.map-captions-off .map-marker-name { display: none; }

.map-marker-name {
    position: absolute;
    left: 100%;
    top: 50%;
    transform: translateY(-50%);
    margin-left: 4px;
    padding: 0 3px;
    border-radius: 2px;
    background: rgba(10, 10, 10, 0.72);
    color: #fff;
    font-size: 9px;
    line-height: 1.5;
    white-space: nowrap;
    pointer-events: none;
}

/* Instant, unlike the browser's own title delay. */
.map-tip {
    position: absolute;
    z-index: 8;
    padding: 3px 7px;
    border: 1px solid #555;
    border-radius: 3px;
    background: rgba(12, 12, 12, 0.96);
    color: #eee;
    font-size: 0.8rem;
    line-height: 1.4;
    white-space: nowrap;
    pointer-events: none;
}

/* ── Zoom and pan (the full-size map page only) ────────────────────
   The frame stops shrink-wrapping its map and becomes a fixed viewport the map moves inside, the
   way a map tool works. The canvas keeps its natural size and a transform does the scaling, so the
   markers — positioned as percentages of the image — follow for nothing, and the separation nudges
   computed in screen pixels scale along with them.

   overflow: hidden is what makes it a window rather than a page that grows. The quest page's frames
   are untouched: they stay shrink-wrapped and scroll with the document. */
/* Everything between the page and a zooming frame shrink-wraps its map: .map-list centres its
   children, .map-stage-wrap starts them, and .map-frame-outer is an inline-block. That is right for
   the quest page, where a frame should be exactly as wide as the picture in it — and wrong here,
   where the frame is a window onto a map bigger than itself and wants all the room there is.
   So the chain is told to stretch, one level at a time, only for a zooming stage. */
.map-list > .map-zoom-stage { align-self: stretch; width: 100%; }
.map-zoom-stage { align-items: stretch; }
.map-zoom-stage .map-stage-row { width: 100%; }
.map-zoom-stage .map-frame-outer {
    display: block;
    flex: 1;
    min-width: 0;
    max-width: none;
}

/* height is set in script from the room actually below the frame — see sizeFrame in map-stage.js.
   This is the floor it starts from and what it falls back to without script. */
.map-frame.map-zoom {
    display: block;
    width: 100%;
    height: min(78vh, 900px);
    min-height: 360px;
    overflow: hidden;
    cursor: grab;
    touch-action: none;
}
.map-frame.map-zoom.grabbing { cursor: grabbing; }
.map-frame.map-zoom:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* The transform does the fitting, so nothing may constrain the canvas to the frame's width first —
   left at max-width: 100% the map would be shrunk twice and the fit maths would start from a lie. */
.map-frame.map-zoom .map-canvas {
    max-width: none;
    transform-origin: 0 0;
    /* Deliberately no will-change: transform. It promotes the canvas to its own layer, which the
       browser rasterises once and then scales as a bitmap — so the map softens as you zoom and the
       marker labels turn to mush, which is the opposite of the point. Without it the layer is
       re-rasterised at the scale actually on screen and everything stays sharp. */
}
.map-frame.map-zoom .map-full { max-width: none; }

/* At or above 1:1 the map is being magnified, and these are pixel art: nearest-neighbour keeps the
   walls and doors as drawn where smoothing turns them to mush. Below 1:1 it is being shrunk, where
   pixelating instead aliases them into noise, so that case keeps the browser's own filtering. */
.map-frame.map-zoom.zoomed-in .map-full { image-rendering: pixelated; }

/* Markers hold their size on screen while the map grows under them.
   
   Their positions are percentages of the image, so those follow the canvas transform exactly and
   want no help. Their size does not: left alone, a chest icon at 8x is 8x the icon, which buries
   the room it is standing in. Undoing the canvas scale on the marker keeps the pin the size it was
   drawn — the same thing a map tool does with its pins.
   
   Applied by redefining --marker-scale rather than the transform itself, so the hover and
   reduced-motion rules, which each restate the transform, pick it up without repeating this. */
.map-frame.map-zoom .map-marker { --marker-scale: calc(1 / var(--map-zoom, 1)); }

.map-zoom-controls {
    position: absolute;
    right: 10px;
    top: 10px;
    z-index: 3;
    display: flex;
    gap: 4px;
}

.map-zoom-controls button {
    min-width: 30px;
    height: 28px;
    padding: 0 8px;
    background: rgba(12, 10, 11, 0.82);
    border: 1px solid #3a3a3a;
    border-radius: 3px;
    color: var(--text);
    font-family: inherit;
    font-size: 0.85rem;
    line-height: 1;
    cursor: pointer;
}
.map-zoom-controls button:hover { background: rgba(30, 26, 28, 0.95); border-color: #5a5a5a; color: #fff; }
.map-zoom-controls button:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

.map-frame-outer {
    position: relative;
    display: inline-block;
    max-width: 100%;
}

/* The map art itself still stops at the frame; only the overlay is allowed past it. */
.map-canvas { overflow: visible; }

/* Filters on the left, maps to their right. */
.map-layout {
    display: flex;
    align-items: flex-start;
    gap: 20px;
}

.map-layout .map-list { flex: 1; min-width: 0; }

.map-filters-panel {
    flex-shrink: 0;
    width: 190px;
    /* The maps run long, and a legend you have scrolled past is no legend at all. */
    position: sticky;
    top: 12px;
    max-height: calc(100vh - 24px);
    overflow-y: auto;
    padding: 8px 10px;
    border: 1px solid #333;
    border-radius: 4px;
    background: #161616;
}

.map-filters-panel > summary {
    cursor: pointer;
    color: #c8a84b;
    font-size: 0.85rem;
    list-style: none;
    display: flex;
    align-items: center;
    gap: 6px;
}

.map-filters-panel > summary::before {
    content: '▾';
    font-size: 0.7em;
}

.map-filters-panel:not([open]) > summary::before { content: '▸'; }

.map-filters {
    display: flex;
    flex-direction: column;
    gap: 3px;
    margin-top: 8px;
    font-size: 0.82rem;
    color: #bbb;
}

/* Narrow screens put the legend above the maps rather than beside them. */
@media (max-width: 900px) {
    .map-layout { flex-direction: column; }
    .map-filters-panel {
        width: 100%;
        position: static;
        max-height: none;
    }
    .map-filters {
        flex-direction: row;
        flex-wrap: wrap;
        gap: 4px 14px;
    }
}

.map-filter {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    cursor: pointer;
    user-select: none;
}

.map-filter:hover { color: #fff; }
.map-filter input { cursor: pointer; margin: 0; }
.map-filter-icon { image-rendering: pixelated; }

/* All On / All Off and the Captions toggle, ruled off under the type list. */
.map-filters-actions {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid #333;
    font-size: 0.82rem;
    color: #bbb;
}

.map-filters-buttons {
    display: flex;
    gap: 4px;
}

/* The zoom controls' buttons, so the map's two sets of controls read as one family. */
.map-filters-buttons button {
    flex: 1;
    height: 24px;
    padding: 0 8px;
    background: rgba(12, 10, 11, 0.82);
    border: 1px solid #3a3a3a;
    border-radius: 3px;
    color: var(--text);
    font-family: inherit;
    font-size: 0.8rem;
    line-height: 1;
    cursor: pointer;
}
.map-filters-buttons button:hover { background: rgba(30, 26, 28, 0.95); border-color: #5a5a5a; color: #fff; }
.map-filters-buttons button:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

/* Narrow screens lay the legend out in rows; the actions follow suit rather than stretching. */
@media (max-width: 900px) {
    .map-filters-actions {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        gap: 6px 14px;
    }
    .map-filters-buttons button { flex: 0 0 auto; }
}

.map-detail-link {
    font-size: 0.82rem;
    color: #c8a84b;
    text-decoration: none;
}

.map-detail-link:hover { text-decoration: underline; }

.map-observed-note {
    margin-top: 8px;
    font-size: 0.8rem;
    color: #777;
    font-style: italic;
}

.cr-tier {
    display: block;
    line-height: 1.5;
}

.quest-objective-list {
    margin: 0 0 4px;
    padding-left: 20px;
    line-height: 1.7;
}

/* Wide enough to overflow a narrow column, so it scrolls inside its own box. */
.quest-optional-wrap {
    overflow-x: auto;
}

.quest-optional-table {
    border-collapse: collapse;
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
}

.quest-optional-table th,
.quest-optional-table td {
    padding: 4px 10px;
    border-bottom: 1px solid #2a2a2a;
    text-align: right;
    white-space: nowrap;
}

.quest-optional-table thead th {
    color: #c8a84b;
    font-weight: 600;
    text-align: center;
}

/* Objective and % span both header rows, and centring them across the pair floats them out of line
   with the difficulty headings they sit beside. Dropped to the bottom, the whole header row reads
   as one line. */
.quest-optional-table thead th[rowspan] { vertical-align: bottom; }

.quest-optional-table .obj-name {
    text-align: left;
    white-space: normal;
    min-width: 220px;
}

.quest-optional-table .obj-pct {
    text-align: right;
}

.quest-bonus-wrap {
    overflow-x: auto;
}

.quest-bonus-table {
    border-collapse: collapse;
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
}

.quest-bonus-table th,
.quest-bonus-table td {
    padding: 4px 10px;
    border-bottom: 1px solid #2a2a2a;
    text-align: right;
    white-space: nowrap;
}

.quest-bonus-table thead th {
    color: #c8a84b;
    font-weight: 600;
    text-align: center;
}

/* The counter spans its three tiers, so a rule under each of them would cut the group in half. Only
   the last row of a group carries one, which is what draws the five ladders apart. */
.quest-bonus-table tbody th.bonus-counter {
    border-bottom: 1px solid #3a3a3a;
    color: #c8a84b;
    font-weight: 600;
    text-align: left;
    vertical-align: top;
    padding-top: 6px;
}

.quest-bonus-table .bonus-name {
    text-align: left;
    min-width: 180px;
}

.quest-bonus-table .bonus-count,
.quest-bonus-table .bonus-pct {
    text-align: right;
}

/* A tier nobody has earned here yet. Dimmed rather than dropped: the ladder has three rungs whether
   or not this quest has seen them, and hiding the empty ones would read as if it had fewer. */
.quest-bonus-table .bonus-unseen .bonus-name,
.quest-bonus-table .bonus-unseen .bonus-count,
.quest-bonus-table .bonus-unseen .bonus-pct {
    color: #666;
}

.quest-bonus-note,
.pack-note {
    margin-top: 10px;
    font-size: 0.78rem;
    color: #777;
    font-style: italic;
}

.difficulty-note {
    display: inline-block;
    margin-top: 4px;
    padding: 1px 7px;
    border: 1px solid #6a5a2a;
    border-radius: 3px;
    background: #201d12;
    color: #c8a84b;
    font-size: 0.8rem;
    line-height: 1.5;
}

.quest-xp-table {
    border-collapse: collapse;
    font-size: 0.9rem;
    min-width: 240px;
}

.quest-xp-table th {
    text-align: right;
    padding: 2px 14px 4px 0;
    font-weight: bold;
    color: #aaa;
    border-bottom: 1px solid #3a3a3a;
}

.quest-xp-table th:first-child {
    text-align: left;
}

.quest-xp-table td {
    padding: 3px 14px 3px 0;
    color: #d6d8d8;
}

.quest-xp-table td.xp-tier {
    color: #aaa;
}

.quest-xp-table td.xp-value {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.quest-details-panel {
    background: #1a1a1a;
    padding: 16px;
    border-radius: 4px;
    border: 1px solid #333;
}

.quest-details-panel.debug-panel {
    border: 1px dashed #6a5a2a;
    background: #17150f;
}

.debug-tag {
    font-size: 11px;
    font-weight: bold;
    letter-spacing: 0.08em;
    color: #17150f;
    background: #c8a84b;
    border-radius: 3px;
    padding: 2px 6px;
    margin-left: 8px;
    vertical-align: middle;
}

.quest-details-panel h3 {
    margin-top: 0;
    font-size: 16px;
    color: #c8a84b;
    border-bottom: 1px solid #333;
    padding-bottom: 8px;
}

.quest-details-panel ul {
    margin: 0;
    padding-left: 20px;
}

.quest-details-panel li {
    margin-bottom: 6px;
    font-size: 0.9rem;
    color: #d6d8d8;
}

.cr-normal { }
.cr-hard { color: var(--gold-lit); font-weight: 600; }
.cr-elite { color: var(--legendary); font-weight: 600; }
.cr-epic { color: var(--epic); font-weight: 600; }
.cr-legendary { color: var(--legendary); font-weight: 600; }

.quest-objectives-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.quest-objective {
    background: #222;
    padding: 14px;
    border-radius: 4px;
    border-left: 3px solid #888;
    position: relative;
}

.quest-objective.optional {
    border-left-color: #e67e22;
    background: rgba(230, 126, 34, 0.1);
}

.quest-objective::before {
    content: attr(data-chapter);
    position: absolute;
    top: 50%;
    left: -40px;
    transform: translateY(-50%);
    font-size: 11px;
    font-weight: bold;
    color: #aaa;
    background: #333;
    padding: 3px 8px;
    border-radius: 3px;
}

.quest-objective.optional::before {
    background: rgba(230, 126, 34, 0.2);
}

.objective-text {
    color: #d6d8d8;
    line-height: 1.5;
    margin-left: 35px;
}

.quest-rewards-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.quest-reward {
    padding: 10px 12px;
    background: #222;
    border-radius: 4px;
    font-size: 0.9rem;
    border-left: 3px solid #c8a84b;
}

.reward-type {
    font-weight: bold;
    color: #e67e22;
}

.quest-journal-area {
    padding: 12px;
    background: #222;
    border-radius: 4px;
    font-style: italic;
    color: #aaa;
}

/* ── Responsive Design ───────────────────────────────── */
@media (max-width: 768px) {
    .quest-header {
        flex-direction: column;
        align-items: flex-start;
    }

    .quest-image-container {
        max-width: 100%;
    }

    .quest-content {
        flex-direction: column;
    }

    .quest-objective::before {
        position: static;
        display: block;
        margin-bottom: 8px;
    }
}

/* ── Progression Chain Display ───────────────────────── */
.quest-prerequisite-chain {
    margin-top: 20px;
    padding: 16px;
    background: #1a1a1a;
    border-radius: 4px;
    border: 1px solid #333;
}

.quest-prerequisite-chain h3 {
    margin-top: 0;
    font-size: 14px;
    color: #c8a84b;
    border-bottom: 1px solid #333;
    padding-bottom: 8px;
}

.prerequisite-step {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px dashed #444;
}

.prerequisite-step:last-child {
    border-bottom: none;
}

.prerequisite-arrow {
    font-size: 12px;
    color: #aaa;
}

.prerequisite-quest {
    flex: 1;
}

.prerequisite-quest a {
    color: #c8a84b;
    text-decoration: none;
}

.prerequisite-quest a:hover {
    text-decoration: underline;
}

/* ── Quest Arcs Display ───────────────────────────────── */
.quest-arcs-section {
    margin-top: 16px;
}

.quest-arcs-section h3 {
    margin: 0 0 8px;
    font-size: 0.9rem;
    color: #c8a84b;
    border-bottom: 1px solid #444;
    padding-bottom: 4px;
}

.quest-arc-details {
    margin-bottom: 8px;
}

.quest-arc-summary {
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 8px;
    background: #222;
    border-radius: 3px;
    font-size: 0.85rem;
    color: #aaa;
}

.quest-arc-summary:hover {
    background: #2a2a2a;
    color: #ddd;
}

.quest-arc-summary::before {
    content: '▶';
    font-size: 0.6em;
}

.quest-arc-details[open] .quest-arc-summary::before {
    content: '▼';
}

.quest-arc-name {
    flex: 1;
    color: #c8a84b;
    font-weight: 500;
}

.quest-arc-count {
    font-size: 0.75rem;
    color: #888;
}

.quest-arc-quests {
    margin-left: 12px;
    padding: 6px 0;
}

.quest-arc-quests a {
    display: block;
    color: #bbb;
    font-size: 0.8rem;
    padding: 3px 8px;
    text-decoration: none;
}

.quest-arc-quests a:hover {
    color: #c8a84b;
    text-decoration: underline;
}

/* ── Quest Arc Memberships Display ────────────────────── */
.quest-arc-memberships {
    margin-top: 16px;
}

.quest-arc-membership {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: #1a1a1a;
    border-radius: 4px;
    margin-bottom: 6px;
    font-size: 0.9rem;
    border: 1px solid #333;
}

.quest-arc-membership.master-arc {
    border-left: 3px solid #c8a84b;
    background: rgba(200, 168, 75, 0.05);
}

.quest-arc-membership.member-arc {
    border-left: 3px solid #888;
    background: rgba(200, 168, 75, 0.03);
}

.arc-role {
    font-weight: bold;
    font-size: 0.75rem;
    padding: 2px 6px;
    border-radius: 3px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.arc-role.master {
    background: #c8a84b;
    color: #000;
}

.arc-role.member {
    background: #444;
    color: #aaa;
}

.quest-arc-membership a {
    color: #c8a84b;
    text-decoration: none;
    font-weight: 500;
}

.quest-arc-membership a:hover {
    text-decoration: underline;
}

.quest-arc-id {
    font-size: 0.75rem;
    color: #666;
}

/* ── Quest Arcs Page (Arcs.cshtml) ───────────────────── */
.quest-arcs-page {
    padding: 20px;
}

.quest-arcs-page .quest-header {
    margin-bottom: 24px;
    padding-bottom: 16px;
    border-bottom: 1px solid #3a3a3a;
}

.quest-arcs-page .quest-count {
    font-size: 0.85rem;
    color: #666;
    margin-top: 4px;
}

.quest-arcs-list {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.quest-arc-item {
    background: #1a1a1a;
    border-radius: 4px;
    border: 1px solid #333;
    overflow: hidden;
}

.quest-arc-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    background: #222;
    cursor: pointer;
    user-select: none;
    border-bottom: 1px solid #333;
}

.arc-title-section {
    display: flex;
    align-items: center;
    gap: 10px;
}

.master-badge {
    color: #c8a84b;
    font-size: 1.1em;
}

.arc-name {
    margin: 0;
    font-size: 1.05rem;
    color: #e0c97a;
    font-weight: 500;
}

.quest-count-badge {
    font-size: 0.8rem;
    color: #666;
    background: #333;
    padding: 2px 8px;
    border-radius: 10px;
}

.expand-indicator {
    font-size: 0.9em;
    color: #aaa;
    transition: transform 0.2s;
}

.quest-arc-item[data-expanded="true"] .expand-indicator {
    transform: rotate(180deg);
}

.arc-metadata {
    display: flex;
    gap: 16px;
    padding: 8px 16px;
    background: #1f1f1f;
    font-size: 0.85rem;
    color: #888;
    border-bottom: 1px solid #333;
}

.min-level {
    display: flex;
    align-items: center;
    gap: 4px;
}

.min-level::before {
    content: 'Lvl ';
    font-weight: bold;
    color: #c8a84b;
}

.quest-members {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.3s ease-out, padding 0.2s;
    background: #161616;
}

.quest-members.show {
    max-height: 2000px;
    padding: 12px 16px;
}

.quest-member-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 0;
    font-size: 0.9rem;
}

.master-quest .master-indicator,
.quest-member-item.master-quest {
    color: #c8a84b;
}

.master-indicator {
    font-size: 1.2em;
    font-weight: bold;
}

.quest-member-item a {
    color: #c8a84b;
    text-decoration: none;
    flex: 1;
}

.quest-member-item a:hover {
    text-decoration: underline;
}

.quest-id {
    font-size: 0.75rem;
    color: #666;
}

/* Story arc banner on a quest page: which arc the quest belongs to, and its siblings.
   Sits directly under the title, before the placard, so the context reads before the numbers. */
.quest-arc-banner {
    margin: 0 0 14px;
    padding: 10px 14px;
    background: #1f1f1f;
    border: 1px solid #333;
    border-left: 3px solid #c8a84b;
    border-radius: 3px;
}

.quest-arc-banner-title {
    font-size: 0.9rem;
    color: #bbb;
}

.quest-arc-banner-title strong {
    color: #c8a84b;
}

.quest-arc-banner-members {
    margin-top: 6px;
    font-size: 0.85rem;
    line-height: 1.6;
}

.quest-arc-banner-members a {
    color: #c8a84b;
    text-decoration: none;
}

.quest-arc-banner-members a:hover {
    text-decoration: underline;
}

/* The quest you are already on is named but not linked. */
.quest-arc-current {
    color: #e8e8e8;
    font-weight: 600;
}

.quest-arc-sep {
    color: #555;
}

.arc-relationships {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 16px;
    background: #1f1f1f;
    border-top: 1px solid #333;
}

.relationship-line {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.85rem;
}

.rel-label {
    color: #888;
    font-size: 0.78rem;
}

.arc-relationships a {
    color: #c8a84b;
    text-decoration: none;
}

.arc-relationships a:hover {
    text-decoration: underline;
}

/* ── Quest Arcs Toggle Filters ───────────────────────── */
.toggle-filters {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    color: #aaa;
    cursor: pointer;
    user-select: none;
}

.toggle-filters input[type="checkbox"] {
    width: 14px;
    height: 14px;
    accent-color: #c8a84b;
}

/* ── Chest loot ─────────────────────────────────────── */
/* The skull count sits in the Reaper header, so the column says what it is showing. */
.loot-reaper-head {
    white-space: nowrap;
}

.loot-reaper-head select {
    margin-left: 6px;
    background: #111;
    color: #d6d8d8;
    border: 1px solid #444;
    border-radius: 3px;
    padding: 1px 3px;
    font-size: 0.8rem;
    font-weight: normal;
    vertical-align: middle;
}

.loot-skulls select {
    margin-left: 6px;
    background: #111;
    color: #d6d8d8;
    border: 1px solid #444;
    border-radius: 3px;
    padding: 2px 4px;
}

.loot-track {
    margin: 10px 0 4px;
    font-size: 0.85rem;
    color: #c8a84b;
}

.loot-wrap { overflow-x: auto; }

/* Heroic and Legendary are separate tables stacked on one another, and left to size themselves each
   would take its widths from its own longest item name — so the two sets of columns landed in
   different places and the eye had to re-find them halfway down. Fixed layout with stated widths
   makes every track's columns line up with every other's. */
.loot-table {
    border-collapse: collapse;
    font-size: 0.88rem;
    font-variant-numeric: tabular-nums;
    table-layout: fixed;
    width: 100%;
    min-width: 420px;
    max-width: 1000px;
}

.loot-table th,
.loot-table td {
    padding: 4px 12px;
    border-bottom: 1px solid #2a2a2a;
    text-align: center;
    white-space: nowrap;
}

/* The header row is what fixed layout takes its widths from, so the columns are stated here once
   and every track inherits the same geometry. Reaper carries a skull picker and needs the extra. */
.loot-table thead th {
    color: #c8a84b;
    font-weight: 600;
    text-align: center;
    width: 11%;
}

/* A rate is five characters at its longest, so the width these columns need is set by their own
   headings, not their contents — everything spare belongs to the item name, which is the column
   that actually runs out of room. Reaper keeps more because it carries the skull picker. */
.loot-table thead th.loot-name { width: 51%; }
.loot-table thead th.loot-reaper-head { width: 16%; }

.loot-table .loot-name {
    text-align: left;
    white-space: normal;
}

.loot-qty { color: #8ab4d0; }

/* 36px is what the game ships and what every other icon on the site renders at, so it is stated
   rather than left to the image: a missing icon still has to hold its 36px, or the names beside the
   ones that did load go ragged. */
.loot-icon {
    width: 36px;
    height: 36px;
    margin-right: 6px;
    vertical-align: middle;
}

.loot-icon.missing { visibility: hidden; }

/* The icon is a link too, but it must not pick up the underline the name link gets — a rule under
   a 36px picture just looks like a stray line. Nothing else is set here on purpose: the anchor
   inherits the cell's font, so the icon's vertical-align resolves exactly as it did unwrapped. */
.loot-icon-link { text-decoration: none; }

/* A member row is dimmed as a whole, and its link has to come down with it rather than sit at full
   strength against the greyed-out numbers beside it. */
.loot-table tr.loot-member .loot-link { color: #b09a52; }

/* The pooled filigree row is a summary of many items, not one of them. */
.loot-table tr.loot-pool td { color: #999; font-style: italic; }

.loot-note {
    margin-top: 10px;
    font-size: 0.78rem;
    color: #777;
    font-style: italic;
}

.loot-expand {
    width: 17px;
    height: 17px;
    margin-right: 6px;
    padding: 0;
    border: 1px solid #555;
    border-radius: 3px;
    background: #1e1e1e;
    color: #ddd;
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
    vertical-align: middle;
}

.loot-expand:hover { background: #333; }

/* A pooled filigree row summarises its members, so they read as subordinate to it. */
.loot-table tr.loot-member td { color: #8b8b8b; font-size: 0.84rem; }
.loot-table tr.loot-member .loot-name { padding-left: 34px; }

/* What a drop can come with, as a badge rather than as rows. Written out per item these cost three
   lines each for numbers identical on every row; the rates are in the badge title. */
.loot-table .bonus-badge {
  display: inline-block; margin-left: 4px; padding: 0 5px;
  border-radius: 3px; font-size: 0.7rem; font-weight: 600;
  cursor: help; vertical-align: middle;
}
.loot-table .bonus-mythic { background: #3a2f16; color: #d8b45c; border: 1px solid #5b4a22; }
.loot-table .bonus-badge.bt-has-tip { position: relative; }

/* The same hover tip the browse tables use, and the same quarter-second wait — long enough not to
   fire while the pointer crosses a badge on its way somewhere, short enough to feel immediate. The
   browser's own title tooltip waits about a second, which reads as nothing happening. */
.loot-table .bonus-badge .bt-tip {
  visibility: hidden;
  position: absolute;
  left: 0;
  top: 100%;
  z-index: 200;
  background: #1a1a1a;
  border: 1px solid #555;
  border-radius: 4px;
  padding: 6px 9px;
  font-size: 0.74rem;
  font-weight: 400;
  color: #ccc;
  min-width: 240px;
  white-space: nowrap;
  line-height: 1.45;
  transition: visibility 0s linear 0.25s;
  pointer-events: none;
}

.loot-table .bonus-badge.bt-has-tip:hover > .bt-tip {
  visibility: visible;
  transition-delay: 0.25s;
}

.loot-table .bonus-badge .bt-tip-tier { display: block; padding: 1px 0; }

/* The last rows would push their tip below the table; flip those upward. */
.loot-table tbody tr:nth-last-child(-n+3) .bonus-badge .bt-tip { top: auto; bottom: 100%; }
.loot-table .bonus-reaper { background: #3a1d1d; color: #d98080; border: 1px solid #5b2c2c; }
.loot-legend { margin: 4px 0 0; font-size: 0.78rem; color: #8b8b8b; }


/* A chest marker leads somewhere, so it should look like it does. */
.map-marker[data-link]:not([data-link=""]) { cursor: pointer; }

.loot-flash {
    animation: loot-flash 1.6s ease-out;
}

@keyframes loot-flash {
    from { background: rgba(200, 168, 75, 0.35); }
    to { background: transparent; }
}

@media (prefers-reduced-motion: reduce) {
    .loot-flash { animation: none; }
}

/* ── Map debug pane ─────────────────────────────────── */
.map-stage-row {
    display: flex;
    align-items: flex-start;
    gap: 16px;
}

.map-debug {
    flex-shrink: 0;
    min-width: 210px;
    padding: 8px 12px;
    border: 1px dashed #6a5a2a;
    border-radius: 4px;
    background: #14120c;
    font-size: 0.78rem;
    line-height: 1.5;
    color: #bbb;
}

.map-debug h4 {
    margin: 0 0 6px;
    font-size: 0.82rem;
    color: #c8a84b;
}

.map-debug dl {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 1px 10px;
    margin: 0;
}

.map-debug dt { color: #777; }
.map-debug dd { margin: 0; font-family: ui-monospace, Consolas, monospace; }

/* Renaming a chest in place, development builds only. */
.chest-edit {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: 10px;
    font-weight: normal;
}

.chest-edit-open {
    border: 1px solid #444;
    border-radius: 3px;
    background: #1e1e1e;
    color: #999;
    font-size: 0.75rem;
    line-height: 1;
    padding: 2px 6px;
    cursor: pointer;
}

.chest-edit-open:hover { background: #333; color: #ddd; }

.chest-edit-input {
    width: 260px;
    background: #111;
    color: #d6d8d8;
    border: 1px solid #555;
    border-radius: 3px;
    padding: 2px 6px;
    font-size: 0.85rem;
}

.chest-edit-save {
    border: 1px solid #555;
    border-radius: 3px;
    background: #2a2a2a;
    color: #ddd;
    font-size: 0.78rem;
    padding: 2px 8px;
    cursor: pointer;
}

.chest-edit-status {
    font-size: 0.75rem;
    color: #8ab4d0;
}

/* Binding sits beside the name as the shorthand a party would say, quiet enough that it does not
   compete with the item it qualifies. */
/* ── Wilderness area page ──────────────────────────────── */

/* Quest_AdventureImage is a painted emblem for the place, not a scene: they ship at 100×100 or so,
   which is why this is sized near its native resolution instead of using .quest-hero-art. That rule
   is built for the loading screens, which are full-width paintings, and stretching a 100px crest to
   a 320px band would only make it soft. */
.wilderness-plate {
    flex-shrink: 0;
    width: clamp(72px, 9vw, 108px);
    height: auto;
    display: block;
}

/* Slayer is a ladder of counts. One rung per line, numbered, because the ranks are reached in order
   and a reader wants to find "which rank is 750" rather than scan a paragraph of chips. The counts
   are right-aligned in a fixed column so 10 and 3,000 line up on their last digit. */
.slayer-ladder {
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: slayer-rank;
}

.slayer-ladder li {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 4px 0;
    font-size: 0.9rem;
    color: #888;
    border-bottom: 1px solid #262626;
    max-width: 320px;
}

.slayer-ladder li:last-child {
    border-bottom: 0;
}

/* The rank number, so "Slayer IV" on the character sheet can be found on this list. */
.slayer-ladder li::before {
    counter-increment: slayer-rank;
    content: counter(slayer-rank) ".";
    width: 2em;
    color: #666;
    font-variant-numeric: tabular-nums;
}

.slayer-count {
    min-width: 4.5em;
    text-align: right;
    color: #e8e8e8;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.slayer-unit {
    color: #777;
}

/* The award for reaching the rung, pushed to the far edge so the counts and the XP read as two
   columns rather than one run-on line. */
.slayer-xp {
    margin-left: auto;
    color: #c9b47a;
    font-variant-numeric: tabular-nums;
}

/* A rung the fitted coefficients do not cover. Dimmed rather than omitted, so the ladder still shows
   that the rung exists and only its award is unknown. */
.slayer-xp-unknown {
    color: #555;
}

/* One objective quest's award, above its list. Set apart from the objectives themselves because it
   describes the errand rather than being part of it. */
.objective-xp {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0 0 10px;
    font-size: 0.85rem;
}

.objective-xp-value {
    color: #c9b47a;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.objective-xp-label {
    color: #777;
}

.objective-xp-sep {
    color: #444;
}

/* Where the numbers come from, once per panel. They are computed rather than read out of the data,
   and a reader comparing them against a wiki table deserves to know that. */
.objective-xp-note {
    margin: 16px 0 0;
    font-size: 0.78rem;
    line-height: 1.5;
    color: #6f6f6f;
    max-width: 60ch;
}

/* The quest a group of objectives belongs to, shown only when an area offers more than one of a
   kind. Stronger than the Points of interest / Dungeon entrances split nested beneath it, because it
   is a different quest rather than a different sort of errand within one. */
.objective-quest-heading {
    margin: 22px 0 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid #2a2a2a;
    font-size: 0.9rem;
    font-weight: 600;
    color: #d8d8d8;
}

.objective-quest-heading:first-child {
    margin-top: 0;
}

/* Explorer objectives come in two kinds — a place to stand and a door to find — and the split is
   worth a heading each when both are present. */
.objective-group-heading {
    margin: 14px 0 6px;
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #8a8a8a;
}

.objective-group-heading:first-child {
    margin-top: 0;
}

/* One row per door, with everything behind it stacked in the second cell — most doors open a single
   quest, and the few that open more should still read as one door. */
.entrance-name {
    color: #e8e8e8;
    white-space: nowrap;
    vertical-align: top;
}

.entrance-quests {
    margin: 0;
    padding: 0;
    list-style: none;
}

.entrance-quests li + li {
    margin-top: 4px;
}

/* The level a saga is offered at, or the NPC fronting an arc: a qualifier on the name beside it,
   not a second fact competing with it. */
.quest-saga-level {
    margin-left: 5px;
    font-size: 0.78rem;
    color: var(--text-faint);
}

/* One saga or arc a line, so two tiers of the same saga read as two entries. */
.quest-saga-entry + .quest-saga-entry { margin-top: 2px; }

/* ── Saga roster ─────────────────────────────────────── */
/* The saga's quests with the NPC who hands each one out and where that NPC stands. A plain ordered
   list of titles said nothing a player could act on; the giver and the district are what turn it
   into a route. */
.saga-roster {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.saga-roster th {
    text-align: left;
    padding: 4px 12px 6px 0;
    border-bottom: 1px solid var(--rule);
    font-size: 0.72rem;
    font-weight: normal;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-faint);
}

.saga-roster td {
    padding: 5px 12px 5px 0;
    border-bottom: 1px solid #1E1A1D;
    vertical-align: top;
}
.saga-roster tr:last-child td { border-bottom: none; }
.saga-roster tbody tr:hover td { background: #171416; }

/* The vendor's own slot number, not a play order — right-aligned and quiet so it reads as an index
   rather than a step to follow. */
.saga-slot {
    width: 34px;
    text-align: right;
    padding-right: 14px;
    color: var(--text-faint);
    font-variant-numeric: tabular-nums;
}

.saga-quest { width: 34%; }
.saga-npc { width: 26%; color: var(--text); }
.saga-where { color: var(--text-dim); }

/* Where the giver was actually seen, which the DATs cannot say — it comes from the collector, and
   only for NPCs somebody has stood next to. Brighter than the zone beneath it because it is the
   answer; the zone is the context. */
.saga-seen-in {
    display: block;
    color: var(--text);
}

.saga-unknown { color: var(--text-faint); }

/* "Also at" ahead of the tier links. Without it a bare "Heroic" sitting under the title reads as a
   property of this saga rather than as a way to reach the other one. */
.saga-tier-label {
    color: var(--text-faint);
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.08em;
    margin-right: 8px;
}

/* ── Saga rewards ────────────────────────────────────── */
/* What each difficulty pays out, difficulties across the top. The label stays still down the side
   while the amount moves across, which is the only way the scaling is visible at a glance — the
   amounts are inside the entity names in the DATs, so nothing else in the data shows it. */
/* Capped rather than full-bleed. Four of the five columns hold a short number, so stretching to the
   panel width left a wide gap between a row's label and its figures and made them hard to pair up
   by eye. At this width the whole row is one glance. */
.saga-rewards {
    width: 100%;
    max-width: 760px;
    border-collapse: collapse;
    font-size: 0.9rem;
    margin-bottom: 14px;
}

.saga-rewards th {
    text-align: left;
    padding: 4px 12px 6px 0;
    border-bottom: 1px solid var(--rule);
    font-size: 0.72rem;
    font-weight: normal;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-faint);
}

.saga-rewards td {
    padding: 5px 12px 5px 0;
    border-bottom: 1px solid #1E1A1D;
}
.saga-rewards tr:last-child td { border-bottom: none; }

.saga-reward-name { color: var(--text); }

/* Tabular figures so the columns line up digit for digit — 5,000 above 15,000 reads as a jump
   only if the thousands sit under the thousands. */
.saga-reward-amount {
    text-align: right;
    width: 108px;
    font-variant-numeric: tabular-nums;
    color: var(--gold);
}

/* Qualified with the table, because `.saga-rewards th` sets text-align: left and out-specifies a
   bare class — which left every difficulty heading sitting at the left edge of a column whose
   figures were right-aligned at the other end of it. */
.saga-rewards th.saga-reward-amount {
    text-align: right;
    color: var(--text-faint);
}

/* The chance pool: one roll across twenty tomes, the same twenty on every difficulty. Closed by
   default so it does not outweigh the three rows that actually differ. */
.saga-reward-pool {
    font-size: 0.85rem;
    color: var(--text-dim);
    margin-top: 2px;
}

/* fit-content, because a <summary> is a block and its hit area is the whole container whether or
   not there is any text out there. At panel width that was 1320px of clickable nothing for 230px
   of label, so a click anywhere to the right of the sentence toggled a list the reader never
   aimed at. Sized to the words instead. list-item is kept rather than swapping to inline-block,
   which would drop the disclosure triangle. */
.saga-reward-pool summary {
    cursor: pointer;
    padding: 3px 12px 3px 0;
    width: fit-content;
    list-style-position: outside;
}

.saga-reward-pool-diff {
    display: inline-block;
    /* Wide enough for "TRUE ELITE", the longest of the four. At 76px that one overflowed its own
       box and pushed its text out of line with the three above it. */
    min-width: 92px;
    color: var(--text-faint);
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.08em;
}

/* A grid rather than two CSS columns. Twenty tome names in two columns at this indent ran to ten
   tight rows with nowhere for the eye to rest; auto-fill takes as many columns as the width allows
   and the row gap gives each name its own line rather than a block of text. */
.saga-reward-pool-list {
    margin: 4px 0 12px 0;
    padding-left: 106px;
    max-width: 1000px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(215px, 1fr));
    gap: 4px 24px;
    list-style: none;
}

.saga-reward-pool-list li {
    color: var(--text-dim);
    line-height: 1.5;
}

.saga-reward-pool-list a { color: var(--gold); }
.saga-reward-pool-list a:hover { color: var(--gold-lit); }
