/* ACE.Market stylesheet. One file, no framework, no build step.
   Dark warm ground, Cormorant headings, Lora body: the game's own inventory panel, on the web. */

:root {
    --ground: #191714;
    --panel: #1f1c18;
    --input: #262219;
    --modal: #1c1915;

    --appraisal-fill: #141210;
    --appraisal-border: #6b5a2e;

    --text: #efe9df;
    --text-2: #d9cdb8;
    --muted: #a89f92;
    --faint: #7d7569;

    --gold: #e1ad66;
    --gold-border: #b68235;
    --gold-tint: rgba(182, 130, 53, 0.07);
    --gold-tint-2: rgba(182, 130, 53, 0.1);
    --gold-tint-3: rgba(182, 130, 53, 0.16);

    --frame-light: #907854;
    /* The client's exact middle-band colour. Kept for reference; not used directly in the band
       rules below, because on real screens it sits too close in brightness to --frame-light and
       the two light lines merge into one at 1x/1.25x scaling. */
    --frame-dark: #67553b;
    /* A darkened ground colour, deliberately darker than --frame-dark, used as the band's actual
       middle line so the two light lines stay visually separate. */
    --frame-gap: #2b241c;
    --frame-corner: #96794e;
    --frame-corner-hi: #b2956a;
    --frame-corner-lo: #74634a;

    --spell: #b9dbe6;
    --spell-border: rgba(143, 199, 214, 0.35);

    /* Appraisal Rating and Set chips: the spell chip's siblings (red and purple). Text colours are
       >= 4.5:1 against --appraisal-fill (#141210). */
    --rating: #f2a7a0;
    --rating-border: rgba(217, 122, 106, 0.55);
    --set: #d4b8f2;
    --set-border: rgba(167, 128, 214, 0.55);

    /* Mods: the spell chip's sibling with its own accent, so the two never read as one list. */
    --mod: #d7c9a3;
    --mod-border: rgba(196, 170, 110, 0.35);
    --mod-high: #f3d27a;
    --mod-mid: #cdb98a;
    --mod-low: #8f877b;

    --ok: #8fbf8a;
    --err: #d97a6a;
    --warn: #e1ad66;

    --hairline: rgba(239, 233, 223, 0.12);
    --rule: rgba(239, 233, 223, 0.08);
    --input-border: rgba(239, 233, 223, 0.14);

    --head: "Cormorant Garamond", Georgia, serif;
    --body: "Lora", Georgia, serif;

    /* The sticky header's height, for anything that parks below it (toasts, the planner columns).
       61px is the one-row header; the collapsed two-row header (see the 1200px block below) overrides it. */
    --site-header-h: 61px;
}

/* One keyframe in the whole sheet. */
@keyframes rise {
    from { opacity: 0; transform: translateY(-4px); }
    to { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------- base ---- */

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
    margin: 0;
    background: var(--ground);
    color: var(--text);
    font-family: var(--body);
    font-size: 14px;
    line-height: 1.5;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

a {
    color: var(--gold);
    text-underline-offset: 3px;
    text-decoration-color: rgba(225, 173, 102, 0.45);
}

a:hover { color: #f0c98c; text-decoration-color: #f0c98c; }

h1, h2, h3 { font-family: var(--head); font-weight: 600; margin: 0; }

input, select, button, textarea { font: inherit; color: inherit; }

input::placeholder { color: rgba(239, 233, 223, 0.38); }

select option { background: var(--input); color: var(--text); }

::selection { background: rgba(182, 130, 53, 0.35); }

:focus { outline: none; }

:focus-visible { outline: 2px solid var(--gold-border); outline-offset: 2px; }

input[type=number]::-webkit-inner-spin-button { opacity: 0.4; }

[hidden] { display: none !important; }

/* ------------------------------------------------------------- icon slot ---- */

/* Layered icons. The four layers stack in document order: plate, underlay, base, overlay, exactly as
   the game client composites them. These rules are structural and must survive any restyling. */
.icon {
    position: relative;
    display: inline-block;
    width: 40px;
    height: 40px;
    vertical-align: middle;
    border-radius: 3px;
    background: linear-gradient(158deg, #514a3f 0%, #3d382f 55%, #2f2b24 100%);
    border: 1px solid #211f1a;
    box-shadow: inset 1px 1px 0 rgba(255, 255, 255, 0.13), inset -1px -1px 0 rgba(0, 0, 0, 0.5);
}

.icon .icon-layer {
    position: absolute;
    inset: 3px;
    width: 32px;
    height: 32px;
    /* The pack exports 32x32 art. Without this, any scaling blurs it into mush. */
    image-rendering: pixelated;
}

/* The enchantment halo the client draws behind an enchanted item's icon. There is no halo texture
   in the pack, so this is a glow on the icon box rather than a fifth layer. It restates the two
   inset bevel shadows from .icon because box-shadow does not merge across rules; it must therefore
   stay AFTER .icon in this file, since both are single-class selectors and document order decides.
   The colour comes from UiEffectGlows.cs, one class per effect suffix. */
.icon-glow {
    box-shadow:
        inset 1px 1px 0 rgba(255, 255, 255, 0.13),
        inset -1px -1px 0 rgba(0, 0, 0, 0.5),
        0 0 6px 1px var(--icon-glow);
}

/* PLACEHOLDER COLOUR, matching UiEffectGlows.MagicalGlow. Awaiting an in-game sample. */
.icon-glow--magical { --icon-glow: rgba(127, 182, 255, 0.75); }

/* The detail header draws the same 32px art at a whole multiple, never a resized pack file.
   The modifier lives on a WRAPPER so _Icon.cshtml itself stays untouched. */
.icon-frame-lg .icon { width: 72px; height: 72px; border-radius: 4px; }
.icon-frame-lg .icon .icon-layer { inset: 3px; width: 64px; height: 64px; }

/* The class plate the client draws under every inventory icon. It is the BOTTOM-most layer
   (first in document order, so it stacks under underlay/base/overlay with no z-index needed).
   When the loaded pack has the plate texture it renders as art; otherwise these flat colours
   stand in. One variant per ItemTypePlates.cs fallback group. */
.icon-plate--weapon { background-color: #865548; }
.icon-plate--armor { background-color: #1F3554; }
.icon-plate--clothing { background-color: #196670; }
.icon-plate--jewelry { background-color: #542348; }
.icon-plate--food { background-color: #1D381D; }
.icon-plate--gem { background-color: #142941; }
.icon-plate--spell { background-color: #2D2D2D; }
.icon-plate--misc { background-color: #694631; }

/* A key with no file. Reads as an empty slot rather than guessing at art. */
.icon-missing, .icon-placeholder {
    display: inline-block;
    background: rgba(0, 0, 0, 0.28);
    border: 1px dashed rgba(255, 255, 255, 0.22);
}

.icon-missing { position: relative; inset: auto; width: 40px; height: 40px; }

.icon-frame-lg .icon-missing { width: 72px; height: 72px; }

/* --------------------------------------------------------- gold panel frame ---- */
/* The client's interface frame: a thin light/dark/light gold band around a panel,
   with a bevelled square sitting on the band at each corner. Square corners only -
   border-radius is forced to 0 on every framed element.

   The inner line is a real border (paints under any opaque child background, e.g.
   thead tr); the middle and outer lines are box-shadow rings, which sit outside the
   border box and so are never painted over by a child. An inset shadow was tried
   first and rejected: it paints INSIDE the box, so an opaque child like `thead tr`
   covers it and the top edge loses its band and corners.

   Corner geometry: the band is 3px wide (border 1px, gap 1px, outer line 1px) and
   runs from 2px outside the border box to 1px inside it. The corner strips are
   absolutely positioned, so their offsets are measured from the PADDING box, one
   pixel further in than the border edge: -4px there is -3px from the outer edge, and
   a 5px square lands on [-3px, +2px], one pixel past the band on each side. The first
   cut used 7px squares, which overhung 1px outward and 3px inward and read as
   off-centre. */

.filters,
.framed,
.detail-card,
.card,
.modal-panel {
    position: relative;
    border: 1px solid var(--frame-light);
    border-radius: 0;
    box-shadow: 0 0 0 1px var(--frame-gap), 0 0 0 2px var(--frame-light);
}

.modal-panel {
    box-shadow: 0 0 0 1px var(--frame-gap), 0 0 0 2px var(--frame-light), 0 24px 64px rgba(0, 0, 0, 0.6);
}

.filters::before, .filters::after,
.framed::before, .framed::after,
.detail-card::before, .detail-card::after,
.card::before, .card::after,
.modal-panel::before, .modal-panel::after {
    content: "";
    position: absolute;
    left: -4px;
    right: -4px;
    height: 5px;
    pointer-events: none;
    z-index: 1;
    background-repeat: no-repeat;
    background-size: 5px 5px;
    background-position:
        left top, left top, left top, left top, left top,
        right top, right top, right top, right top, right top;
    background-image:
        linear-gradient(to bottom, var(--frame-corner-hi) 0 1px, transparent 1px 5px),
        linear-gradient(to right, var(--frame-corner-hi) 0 1px, transparent 1px 5px),
        linear-gradient(to top, var(--frame-corner-lo) 0 1px, transparent 1px 5px),
        linear-gradient(to left, var(--frame-corner-lo) 0 1px, transparent 1px 5px),
        linear-gradient(var(--frame-corner), var(--frame-corner)),
        linear-gradient(to bottom, var(--frame-corner-hi) 0 1px, transparent 1px 5px),
        linear-gradient(to right, var(--frame-corner-hi) 0 1px, transparent 1px 5px),
        linear-gradient(to top, var(--frame-corner-lo) 0 1px, transparent 1px 5px),
        linear-gradient(to left, var(--frame-corner-lo) 0 1px, transparent 1px 5px),
        linear-gradient(var(--frame-corner), var(--frame-corner));
}

.filters::before, .framed::before, .detail-card::before, .card::before, .modal-panel::before { top: -4px; }
.filters::after, .framed::after, .detail-card::after, .card::after, .modal-panel::after { bottom: -4px; }

/* ----------------------------------------------------------------- frame ---- */

.site-header {
    position: sticky;
    top: 0;
    z-index: 20;
    background: rgba(25, 23, 20, 0.92);
    backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--frame-gap);
    box-shadow: 0 1px 0 var(--frame-light), inset 0 -1px 0 var(--frame-light);
}

.site-header-inner {
    max-width: 1180px;
    margin: 0 auto;
    padding: 0 28px;
    height: 60px;
    display: flex;
    align-items: center;
    gap: 28px;
}

.site-brand {
    display: flex;
    align-items: center;
    gap: 12px;
    text-decoration: none;
    color: var(--text);
    margin-right: 8px;
}

.site-brand img { width: 30px; height: 30px; border-radius: 6px; display: block; }

.site-brand span { font-family: var(--head); font-weight: 600; font-size: 22px; letter-spacing: 0.01em; }

.site-nav { display: flex; align-items: center; gap: 22px; font-size: 14px; }

.site-nav a {
    white-space: nowrap;
    text-decoration: none;
    color: var(--text-2);
    padding: 6px 0;
    border-bottom: 1px solid transparent;
}

.site-nav a:hover { color: var(--gold); }

.site-nav a.is-active { color: var(--gold); border-bottom-color: var(--gold); }

/* Dropdowns: pure CSS, no script. The menu hangs directly under the top link (top: 100% of the
   item, no gap), so the pointer does not cross a dead zone on the way in. It opens on :hover and on
   :focus-within, so tabbing from the top link into the menu keeps it open. The top link stays a real link, so touch users navigate through it. */
.site-nav .nav-item {
    position: relative;
    display: flex;
    align-items: center;
}

.site-nav .nav-top::after {
    content: "";
    display: inline-block;
    margin-left: 6px;
    vertical-align: 2px;
    border: 4px solid transparent;
    border-top-color: currentColor;
    border-bottom-width: 0;
}

.site-nav .nav-menu {
    display: none;
    position: absolute;
    top: 100%;
    left: -12px;
    min-width: 168px;
    flex-direction: column;
    gap: 2px;
    padding: 6px;
    background: var(--panel);
    border: 1px solid var(--hairline);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
    z-index: 30;
}

/* Opens on hover and on keyboard/tap focus at every width. The top link stays a real link. */
/* .is-open is set by nav.js for a touch tap (a tap would navigate before :hover could show the menu). */
.site-nav .nav-item:hover .nav-menu,
.site-nav .nav-item:focus-within .nav-menu,
.site-nav .nav-item.is-open .nav-menu { display: flex; }


.site-nav .nav-menu a {
    padding: 7px 12px;
    border-bottom: 0;
    border-radius: 6px;
    white-space: nowrap;
}

.site-nav .nav-menu a:hover { background: var(--gold-tint-2); }

.site-nav .nav-menu a.is-active { background: var(--gold-tint-3); }

/* Defined BEFORE the collapsed-header blocks below so their gap overrides win. */
.site-account { margin-left: auto; display: flex; align-items: center; gap: 16px; }

/* Collapsed header, for every width where brand + menu + account do not fit on one 60px row (the
   five-item menu plus a signed-in account pill needs about 1120px with an admin session, a six-figure balance and the share icons, so the cut is 1200px). Nothing is flattened: row one is
   the brand on the left and the account on the right, row two is the menu with its dropdowns working
   exactly as on desktop. The header stays sticky. At very narrow widths the menu row itself may wrap
   to more lines. */
@media (max-width: 1200px) {
    :root { --site-header-h: 94px; }

    .site-header:not(.sheet-header) .site-header-inner {
        height: auto;
        min-height: 60px;
        flex-wrap: wrap;
        align-items: center;
        gap: 4px 14px;
        padding: 8px 16px;
    }

    .site-header:not(.sheet-header) .site-brand { order: 1; margin-right: 0; }

    .site-account { order: 2; margin-left: auto; flex-wrap: wrap; justify-content: flex-end; gap: 8px 12px; }

    .site-header:not(.sheet-header) .site-nav {
        order: 3;
        flex-basis: 100%;
        flex-wrap: wrap;
        gap: 0 20px;
        padding-top: 2px;
    }
}

/* The character-sheet host's header has no account block (brand + menu only), so it stays one 60px row
   until the menu itself no longer fits beside the brand icon, and only then wraps the menu onto a second row.
   Measured: the one-row sheet header (icon + five-item menu) fits down to about 400px and overflows at 360px
   (needs ~388px), so the cut is 420px. */
@media (max-width: 420px) {
    .sheet-header .site-header-inner {
        height: auto;
        min-height: 60px;
        flex-wrap: wrap;
        align-items: center;
        gap: 4px 14px;
        padding: 8px 16px;
    }

    .sheet-header .site-nav {
        flex-basis: 100%;
        flex-wrap: wrap;
        gap: 0 20px;
        padding-top: 2px;
    }
}

/* Phone widths: a dropdown hung from its own item can run off the right edge (the item may sit
   anywhere in a wrapped row), so here the menu hangs from the whole menu row instead, left-aligned
   and never wider than it, which keeps it fully on screen. */
@media (max-width: 560px) {
    .site-nav { position: relative; }

    .site-nav .nav-item { position: static; }

    .site-nav .nav-menu { left: 0; max-width: 100%; }

    /* Make room for the account beside the brand: the balance is on the Characters page, and a long
       name is cut rather than pushing the account onto its own line. */
    .site-header-inner { gap: 4px 10px; }
    .site-brand { gap: 8px; }
    .site-brand span { font-size: 19px; }
    .site-account { gap: 6px 8px; }
    .account-balance { display: none; }
    .account-name { max-width: 9ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* --site-header-h per breakpoint, from measurement (tallest signed-in header at each width): 94px down to
   about 434px; 125px from there to about 379px, where the menu wraps to two lines; 155px below that, where
   the market layout's account also drops onto its own line. */
@media (max-width: 434px) {
    :root { --site-header-h: 125px; }
}

@media (max-width: 378px) {
    :root { --site-header-h: 155px; }
}

@media (max-width: 400px) {
    .site-brand img { width: 26px; height: 26px; }
    .site-brand span { font-size: 17px; }
    .site-header-inner { padding-left: 12px; padding-right: 12px; }
    .account-name { max-width: 7ch; }
}
.account-pill {
    display: flex;
    align-items: baseline;
    gap: 10px;
    text-decoration: none;
    color: var(--text);
    padding: 6px 12px;
    border: 1px solid var(--input-border);
    border-radius: 4px;
}

.account-pill:hover { border-color: var(--gold-border); color: var(--text); }

.account-pill .account-name { font-size: 13px; }

.account-pill .account-balance { font-size: 13px; color: var(--gold); font-variant-numeric: tabular-nums; }

.signout-form { margin: 0; }

main {
    flex: 1;
    width: 100%;
    max-width: 1180px;
    margin: 0 auto;
    padding: 36px 28px 80px;
}

.site-footer {
    border-top: 1px solid var(--frame-gap);
    box-shadow: 0 -1px 0 var(--frame-light), inset 0 1px 0 var(--frame-light);
    width: 100%;
}

.site-footer-inner {
    padding: 18px 28px;
    font-size: 12px;
    color: var(--faint);
    display: flex;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    max-width: 1180px;
    margin: 0 auto;
    width: 100%;
    box-sizing: border-box;
}

.site-footer-inner a { color: var(--gold); text-decoration: none; }

.site-footer-inner a:hover { text-decoration: underline; }

/* ------------------------------------------------------------------ page ---- */

.page { display: flex; flex-direction: column; gap: 22px; }

/* A titled block inside a page: its heading, its control panel and its table travel together with a
   tighter gap than the 22px .page puts between whole sections. */
.page-section { display: flex; flex-direction: column; gap: 12px; }

.section-title { font-size: 22px; }

.page-title {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
}

.page-title h1 { font-size: 40px; line-height: 1.05; }

.page-title .title-note { margin: 0; font-size: 13px; color: var(--muted); }

.page-title .title-note.tabular { font-variant-numeric: tabular-nums; }

.title-stack { display: flex; flex-direction: column; gap: 4px; }

.title-counts { display: flex; gap: 20px; font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }

.title-counts .count-total { color: var(--text); }

.title-counts .count-listed { color: var(--gold); }

.narrow-page { max-width: 420px; margin: 40px auto 0; display: flex; flex-direction: column; gap: 20px; }

.narrow-page-wide { max-width: 520px; }

/* --------------------------------------------------------------- buttons ---- */

.btn, .btn-primary, .btn-secondary, .btn-ghost {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 36px;
    padding: 6px 14px;
    border-radius: 4px;
    background: transparent;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
}

.btn-primary {
    border: 1px solid var(--gold-border);
    color: var(--gold);
    font-family: var(--head);
    font-weight: 600;
    font-size: 15px;
}

.btn-primary:hover { background: var(--gold-tint-3); color: var(--gold); }

.btn-primary.is-armed { background: var(--gold-tint-3); }

.btn-lg { min-height: 40px; padding: 8px 16px; font-size: 17px; }

.btn-block { width: 100%; min-height: 42px; font-size: 17px; }

.btn-secondary {
    border: 1px solid var(--input-border);
    color: var(--text);
    font-size: 13px;
}

.btn-secondary:hover { border-color: rgba(239, 233, 223, 0.4); color: var(--text); }

.btn-ghost {
    border: 1px solid transparent;
    color: var(--gold);
    font-size: 13px;
}

.btn-ghost:hover { background: var(--gold-tint-2); color: var(--gold); }

.btn-destructive { border-color: rgba(239, 233, 223, 0.2); color: var(--text-2); }

.btn-destructive:hover { border-color: var(--err); color: var(--err); }

.btn-small { min-height: 30px; padding: 5px 12px; font-size: 13px; }

/* 33px, half again over the 22px it was: the barrel is a whole action of its own and had to be
   hunted for at the old size. Kept in step with .btn-bulk-barrel img further down, which is the
   same art in the toolbar. */
.btn-barrel { background: none; border: 1px solid transparent; padding: 0.15rem 0.3rem; line-height: 1; cursor: pointer; }
.btn-barrel img { width: 33px; height: 33px; display: block; }
.btn-barrel:hover { border-color: var(--err); }

/* --------------------------------------------------------- confirm step ---- */

/* Bordered in the error colour without being an error: it is the one panel that must not be
   skimmed past, because the click after it cannot be taken back by the player. */
.confirm-action { border: 1px solid var(--err); border-radius: 3px; padding: 1rem; margin: 1rem 0; }

.confirm-title { margin: 0 0 0.5rem; font-size: 1.1rem; }

.confirm-body { margin: 0 0 0.75rem; color: var(--text-2); }

.confirm-items { margin: 0 0 0.75rem 1.25rem; }

.confirm-actions { display: flex; gap: 0.5rem; align-items: center; }

/* ---------------------------------------------------------------- fields ---- */

.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }

.field-label-row { display: flex; align-items: center; gap: 6px; }

.field > label, .field > .field-label, fieldset.range > legend {
    font-size: 12px;
    color: var(--muted);
    padding: 0;
}

.field-hint { color: var(--faint); }

.text-input, .number-input, select.select-input {
    width: 100%;
    min-height: 36px;
    padding: 6px 10px;
    background: var(--input);
    border: 1px solid var(--input-border);
    border-radius: 4px;
    color: var(--text);
    caret-color: var(--gold-border);
}

.number-input { font-variant-numeric: tabular-nums; }

.text-input:hover, .number-input:hover, select.select-input:hover { border-color: rgba(239, 233, 223, 0.4); }

.text-input:focus, .number-input:focus, select.select-input:focus { border-color: var(--gold-border); }

.input-tall { min-height: 40px; padding: 8px 12px; }

fieldset.range {
    border: 0;
    padding: 0;
    margin: 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 5px;
}

fieldset.range > legend { margin-bottom: 5px; }

.range-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }

/* ---------------------------------------------------------- filter panel ---- */

.filters {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    background: var(--panel);
    margin: 0;
}

.filter-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: end;
}

/* The flex BASIS is what decides where the row wraps; the grow factors are what decide how it
   looks once it has not. Keeping the grow factors and pulling the bases in therefore changes
   nothing at desktop width - the fields still expand to fill the row in the same proportions -
   and only moves the point at which the actions group drops to a second line. Measured by
   rendering both filter rows at 1440/1280/1024/960/900/820: the vault row now holds one line down
   to roughly 840px, where it held to about 940px before. Below that the segmented Show control and
   the actions group are fixed-width floors and the row has to wrap. */
.filter-row .grow-text { flex: 1.6 1 180px; position: relative; }
.filter-row .grow-type { flex: 1 1 120px; }
.filter-row .grow-price { flex: 1.3 1 170px; }
.filter-row .grow-vault-text { flex: 2 1 180px; }

.filter-actions { display: flex; gap: 6px; align-items: center; min-height: 36px; flex: 0 0 auto; margin-left: auto; }

.filter-more {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
    padding-top: 12px;
    border-top: 1px solid rgba(239, 233, 223, 0.1);
    animation: rise 140ms ease-out;
}

/* The segmented Show control: three real submit buttons in one bordered group. */
.segmented {
    display: inline-flex;
    border: 1px solid var(--input-border);
    border-radius: 4px;
    overflow: hidden;
    min-height: 36px;
}

.segmented button {
    padding: 6px 14px;
    background: transparent;
    border: 0;
    color: var(--text-2);
    cursor: pointer;
    font-size: 13px;
}

.segmented button + button { border-left: 1px solid var(--input-border); }

.segmented button:hover { background: rgba(239, 233, 223, 0.06); }

.segmented button[aria-pressed="true"] { color: var(--gold); box-shadow: inset 0 0 0 1px var(--gold-border); }

/* ------------------------------------------------------------- type-ahead ---- */

.listbox {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin: 4px 0 0;
    padding: 4px;
    list-style: none;
    background: var(--input);
    border: 1px solid rgba(239, 233, 223, 0.16);
    border-radius: 4px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
    z-index: 10;
    max-height: 280px;
    overflow-y: auto;
    animation: rise 120ms ease-out;
}

.listbox li {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 7px 10px;
    border-radius: 3px;
    cursor: pointer;
    font-size: 13px;
}

.listbox li:hover, .listbox li.is-active { background: rgba(182, 130, 53, 0.14); }

.listbox .option-kind { color: var(--muted); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; }

.listbox .option-count { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------ search help ---- */

.info-icon {
    flex: none;
    width: 16px;
    height: 16px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: 1px solid var(--muted);
    background: transparent;
    color: var(--muted);
    font-size: 10px;
    font-style: italic;
    cursor: pointer;
}

.info-icon:hover { border-color: var(--gold-border); color: var(--gold); }

/* Same round icon-button treatment as .info-icon, just sized for a page title rather than a
   filter-field label, and holding an SVG glyph instead of a lone letter. */
.share-icon {
    flex: none;
    width: 28px;
    height: 28px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: 1px solid var(--muted);
    background: transparent;
    color: var(--muted);
    cursor: pointer;
}
.share-icon:hover { border-color: var(--gold-border); color: var(--gold); }
.share-icon.is-copied { border-color: var(--gold-border); color: var(--gold); }

/* Positioned wrapper the share icon now lives in (in the header, left of the account pill), so the
   copied-link chip below can sit at position: absolute without disturbing the row it's in. */
.share-icon-wrap { position: relative; display: flex; align-items: center; flex: none; }

/* The visible "copied" confirmation - out of flow so it never pushes the account pill or Sign out
   button sideways when it appears or fades. Anchored under the icon; .site-header/-inner carry no
   overflow rule, so it is never clipped by the header even though the icon sits close to its edge. */
.share-copied-chip {
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    margin-top: 8px;
    padding: 4px 8px;
    border-radius: 4px;
    background: var(--gold);
    color: var(--ground);
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 160ms ease;
    z-index: 5;
}

.share-copied-chip.is-visible { opacity: 1; }

/* The manual-copy fallback input market.js inserts next to .share-icon. Same out-of-flow treatment
   as .share-copied-chip and for the same reason: an in-flow fixed-width input dropped into this
   nowrap header row would push the account pill and Sign out button sideways instead of just
   overlaying. right: 0 (rather than the chip's centered left: 50%) keeps it from running past the
   header's right edge, since the icon sits close to the end of the row. Free to be wider than the
   old in-flow 170px now that it overlays instead of widening the row. */
.share-fallback {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 8px;
    width: 260px;
    z-index: 5;
}

/* The character sheet link page's action row: copy, New link and Hide my sheet side by side under
   the link itself. */
.sheet-link-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
}

/* Room under the row for the "Link copied" chip, which overlays below the copy button (8px gap +
   ~26px chip). The note's own default paragraph margin (~14px) left the chip over its first line;
   24px on top of the section's 12px gap clears it. */
.sheet-link-actions + .title-note {
    margin-top: 24px;
}

/* A share button at the START of its row (the sheet link page) rather than near the header's right
   edge: its chip and manual-copy fallback open left-aligned under the icon, so they neither run
   past the page's left edge (centered) nor off it to the left (right-anchored). */
.share-icon-wrap-start .share-copied-chip {
    left: 0;
    transform: none;
}

.share-icon-wrap-start .share-fallback {
    left: 0;
    right: auto;
}

.info-popover {
    max-width: 320px;
    padding: 10px 12px;
    background: var(--input);
    border: 1px solid rgba(239, 233, 223, 0.16);
    border-radius: 4px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
    color: var(--text-2);
    font-size: 12px;
    line-height: 1.5;
}

.info-popover p + p { margin-top: 6px; }

.info-popover code {
    color: var(--gold);
    font-size: 11px;
}

/* ------------------------------------------------------------ count line ---- */

.result-line {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
    font-size: 13px;
    color: var(--muted);
    margin: 0;
}

.result-count { font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- tables ---- */

.table-scroll {
    overflow-x: auto;
}

table.listings, table.vault, table.history {
    width: 100%;
    border-collapse: collapse;
    font-size: 13.5px;
}

table.listings { min-width: 820px; }
table.vault { min-width: 930px; }
table.history { min-width: 820px; }

table.my-listings { min-width: 640px; }

thead tr { background: var(--panel); }

th {
    text-align: left;
    padding: 10px 12px;
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
    font-weight: 500;
    border-bottom: 1px solid rgba(239, 233, 223, 0.14);
}

th.col-icon { width: 56px; }
th.col-num { width: 32px; text-align: right; }
/* Wide enough for the List button and the 33px barrel to sit side by side without wrapping. */
th.col-action { width: 150px; text-align: right; }
th.num { text-align: right; }

/* A sortable header is a real link, so it works with JavaScript off. It fills the cell. */
th.sortable { padding: 0; }

th.sortable a {
    display: block;
    width: 100%;
    padding: 10px 12px;
    text-decoration: none;
    color: var(--muted);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    font-weight: 500;
}

th.sortable.num a { text-align: right; }

th.sortable a:hover { color: var(--gold); }

th.sortable[aria-sort] a { color: var(--gold); }

tbody tr { border-bottom: 1px solid var(--rule); }

td { padding: 6px 12px; }

td.num { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-2); }

/* The Dmg column is a composite string ("+163% +5 (Fire)"), not a number, so it reads left-aligned
   and must not wrap mid-value. Its header keeps th.num's right alignment off for the same reason. */
td.dmg { text-align: left; white-space: nowrap; color: var(--text-2); }

th.dmg { text-align: left; }

th.sortable.dmg a { text-align: left; }

td.text { color: var(--text-2); }

td.entry-number { text-align: right; font-variant-numeric: tabular-nums; color: var(--faint); font-size: 12px; }

td.price { text-align: right; font-variant-numeric: tabular-nums; color: var(--gold); font-weight: 500; }

tr.row-link { cursor: pointer; }

tr.row-link:hover, tbody tr:hover { background: var(--gold-tint); }

.row-name { text-decoration: none; color: var(--text); font-weight: 500; }

.row-name:hover { color: var(--gold); }

.row-sub { font-size: 12px; color: var(--muted); }
/* Salvage Hammer uses badge beside the item name; a partly used (or unknown-count) Hammer takes the warning gold. */
.row-uses { margin-left: 0.5em; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.row-uses-partial { color: var(--warn); font-weight: 600; }
/* A counted class row (pooled items, managed in game) is read-only on the web: dimmed slightly so
   it reads as "not actionable here" without hiding its name or count. */
.vault-row-class .row-name, .vault-row-class .row-sub { opacity: 0.7; }

td.listed-yes { font-variant-numeric: tabular-nums; color: var(--gold); }

td.listed-no { color: var(--faint); }

/* --------------------------------------------------------- empty states ---- */

.empty-state {
    padding: 48px 24px;
    text-align: center;
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: center;
}

.empty-state .empty-title { font-family: var(--head); font-size: 24px; font-weight: 500; }

.empty-state p { margin: 0; color: var(--muted); max-width: 46ch; }

.empty-state .btn-primary, .empty-state a.btn-primary { margin-top: 8px; }

/* -------------------------------------------------------------- messages ---- */

.error, .success, .warning {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    padding: 12px 14px;
    border: 1px solid var(--hairline);
    border-left: 3px solid var(--muted);
    border-radius: 4px;
    font-size: 13px;
    color: var(--text-2);
    background: var(--panel);
    margin: 0;
    animation: rise 160ms ease-out;
}

.error { border-left-color: var(--err); }
.success { border-left-color: var(--ok); }
.warning { border-left-color: var(--warn); }

.msg-glyph {
    flex: none;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 1px solid var(--muted);
    font-size: 11px;
    display: grid;
    place-items: center;
    font-weight: 600;
}

.error .msg-glyph { border-color: var(--err); color: var(--err); }
.success .msg-glyph { border-color: var(--ok); color: var(--ok); }
.warning .msg-glyph { border-color: var(--warn); color: var(--warn); }

.msg-text { flex: 1; }

.msg-dismiss {
    background: transparent;
    border: 0;
    color: var(--muted);
    cursor: pointer;
    font-size: 14px;
    line-height: 1;
    padding: 0 2px;
}

.msg-dismiss:hover { color: var(--text); }

/* The ambient warning: a dashed gold strip under the title, no fill. */
.warning-ambient {
    background: transparent;
    border: 1px dashed rgba(225, 173, 102, 0.5);
    border-left: 1px dashed rgba(225, 173, 102, 0.5);
    padding: 10px 14px;
}

/* ----------------------------------------------------------- item detail ---- */

.detail-page { display: flex; flex-direction: column; gap: 20px; }

.detail-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
}

.detail-kicker { font-size: 12px; color: var(--muted); letter-spacing: 0.08em; text-transform: uppercase; }

.detail-back { font-size: 13px; text-decoration: none; }

.detail-close {
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    background: transparent;
    border: 1px solid rgba(239, 233, 223, 0.16);
    border-radius: 4px;
    color: var(--muted);
    cursor: pointer;
    font-size: 18px;
    line-height: 1;
}

.detail-close:hover { border-color: var(--gold-border); color: var(--text); }

.item-detail { display: flex; flex-wrap: wrap; gap: 32px; align-items: start; }

.detail-main { display: flex; flex-direction: column; gap: 24px; min-width: 0; flex: 1 1 460px; }

.detail-main > header { display: flex; align-items: center; gap: 20px; }

.detail-heading { display: flex; flex-direction: column; gap: 4px; min-width: 0; }

.detail-heading h1 { font-size: 36px; line-height: 1.05; }

.detail-sub { font-size: 13px; color: var(--muted); }

.item-desc { margin: 0; font-style: italic; color: var(--text-2); max-width: 60ch; }

/* The one deliberately game-native element: the client's own appraisal panel. */
.appraisal {
    border: 1px solid var(--appraisal-border);
    border-radius: 4px;
    background: var(--appraisal-fill);
    box-shadow: inset 0 0 0 1px rgba(182, 130, 53, 0.18), 0 8px 24px rgba(0, 0, 0, 0.4);
    overflow: hidden;
}

.appraisal-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 14px;
    background: linear-gradient(180deg, #2a2419, #1d1913);
    border-bottom: 1px solid var(--appraisal-border);
}

/* The popover titles the bar with the item name, which can be long: it truncates rather than
   wrapping or squeezing the as-of label off the bar. */
.appraisal-bar .appraisal-title { font-family: var(--head); font-weight: 600; font-size: 16px; color: var(--gold); letter-spacing: 0.02em; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.appraisal-bar .appraisal-asof { font-size: 11px; color: var(--muted); letter-spacing: 0.06em; text-transform: uppercase; flex-shrink: 0; }

ul.panel-lines {
    margin: 0;
    padding: 14px 16px;
    list-style: none;
    columns: 2;
    column-gap: 28px;
    font-size: 13px;
    line-height: 1.7;
    color: var(--text-2);
    font-variant-numeric: tabular-nums;
}

ul.panel-lines li { break-inside: avoid; }

/* Per-kind panel layout: two explicit columns instead of the single list's CSS columns:2. Same
   gap and padding as the single-list case; the nested ul.panel-lines must not double up on either. */
.panel-cols { display: grid; grid-template-columns: 1fr 1fr; column-gap: 28px; padding: 14px 16px; }

.panel-cols ul.panel-lines { padding: 0; columns: unset; }

.appraisal-spells { padding: 12px 16px 16px; border-top: 1px dashed rgba(107, 90, 46, 0.6); }

.spells-heading { margin: 0 0 8px; font-family: var(--head); font-weight: 600; font-size: 16px; color: var(--gold); }

ul.spells { margin: 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 6px 8px; }

ul.spells li {
    font-size: 12.5px;
    padding: 3px 9px;
    border: 1px solid var(--spell-border);
    border-radius: 3px;
    color: var(--spell);
}

/* Rating and Set rows sit above Spells. The chip matches the spell chip's shape and size; the
   modifiers only recolour it. Shared with the suit builder. */
.appraisal-rating-row,
.appraisal-set-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    padding: 10px 16px;
    border-top: 1px dashed rgba(107, 90, 46, 0.6);
}

.appraisal-row-label { margin: 0; min-width: 52px; font-family: var(--head); font-weight: 600; font-size: 16px; color: var(--gold); }

ul.appraisal-chips { margin: 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 6px 8px; }

.appraisal-chip {
    font-size: 12.5px;
    padding: 3px 9px;
    border: 1px solid var(--spell-border);
    border-radius: 3px;
    color: var(--spell);
}

.appraisal-chip--rating { color: var(--rating); border-color: var(--rating-border); background: rgba(217, 122, 106, 0.12); }

.appraisal-chip--set { color: var(--set); border-color: var(--set-border); background: rgba(167, 128, 214, 0.14); }

/* Cantrips render on their own green-accented row above the standard spells. */
ul.spells.cantrips + ul.spells { margin-top: 8px; }
ul.spells.cantrips li { color: #a6d9a0; border-color: rgba(106, 170, 98, 0.6); background: rgba(70, 125, 62, 0.14); }

.appraisal-mods { padding: 12px 16px 16px; border-top: 1px dashed rgba(107, 90, 46, 0.6); }

.mods-heading { margin: 0 0 8px; font-family: var(--head); font-weight: 600; font-size: 16px; color: var(--gold); }

ul.mods { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }

ul.mods li {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 8px;
    font-size: 13px;
    padding: 3px 9px;
    border: 1px solid var(--mod-border);
    border-radius: 3px;
    color: var(--mod);
}

.mod-name { font-weight: 600; }

.mod-badge { font-size: 12px; padding: 0 5px; border: 1px solid currentColor; border-radius: 3px; font-variant-numeric: tabular-nums; }

.mod-badge-high { color: var(--mod-high); }

.mod-badge-mid { color: var(--mod-mid); }

.mod-badge-low { color: var(--mod-low); }

.mod-effect { color: var(--text-2); }

ul.mod-footer { margin: 8px 0 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 4px 20px; font-size: 13px; color: var(--text-2); font-variant-numeric: tabular-nums; }

ul.mod-footer.mod-footer-plain { margin: 0; padding: 0 16px 14px; }

.detail-aside { display: flex; flex-direction: column; gap: 16px; flex: 0 1 320px; min-width: 280px; }

.detail-card {
    background: var(--panel);
    padding: 18px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

dl.item-facts {
    margin: 0;
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 8px 18px;
    font-size: 13.5px;
}

dl.item-facts dt { color: var(--muted); }

dl.item-facts dd { margin: 0; color: var(--text-2); font-variant-numeric: tabular-nums; }

dl.item-facts dd.fact-gold { color: var(--gold); font-weight: 500; }

dl.item-facts dd.fact-muted { color: var(--muted); }

.detail-action {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding-top: 14px;
    border-top: 1px solid rgba(239, 233, 223, 0.1);
    margin: 0;
}

.detail-note {
    margin: 0;
    padding-top: 14px;
    border-top: 1px solid rgba(239, 233, 223, 0.1);
    font-size: 13px;
    color: var(--muted);
}

.buy-line {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 13px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.buy-line .buy-value { color: var(--text); }

.buy-line .buy-value.is-negative { color: var(--err); }

.field-row { display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: center; }

.field-row label { font-size: 13px; color: var(--muted); }

.signin-note { margin: 0; font-size: 12px; color: var(--muted); text-align: center; }

.recent-sales { margin: 0; font-size: 12.5px; color: var(--muted); line-height: 1.5; max-width: 46ch; }

.recent-sales .recent-label { color: var(--gold); }

.recent-sales.is-none { color: var(--faint); }

.gone-state {
    padding: 56px 24px;
    text-align: center;
    border: 1px solid var(--hairline);
    border-radius: 6px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: center;
}

.gone-state .gone-title { font-family: var(--head); font-size: 28px; font-weight: 500; }

.gone-state p { margin: 0; color: var(--muted); max-width: 44ch; }

.gone-state a { margin-top: 8px; }

/* ----------------------------------------------------------------- modal ---- */

.modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 40;
    background: rgba(12, 10, 8, 0.72);
    backdrop-filter: blur(3px);
    display: grid;
    place-items: start center;
    padding: 56px 20px 40px;
    overflow-y: auto;
    animation: rise 140ms ease-out;
}

.modal-panel {
    width: min(1040px, 100%);
    background: var(--modal);
    padding: 28px 28px 32px;
}

body.modal-open { overflow: hidden; }

/* ------------------------------------------------------------- login card ---- */

.card {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 22px;
    background: var(--panel);
    margin: 0;
}

.card .btn-block { margin-top: 6px; }

.form-note { margin: 0; font-size: 13px; color: var(--muted); }

/* ------------------------------------------------------------- character ---- */

.character-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; }

.character-list button {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    padding: 14px 18px;
    background: var(--panel);
    border: 1px solid var(--hairline);
    border-radius: 6px;
    color: var(--text);
    cursor: pointer;
    text-align: left;
}

.character-list button:hover { border-color: var(--gold-border); background: rgba(182, 130, 53, 0.08); }

.character-name { font-family: var(--head); font-weight: 600; font-size: 20px; }

.character-balance { font-variant-numeric: tabular-nums; color: var(--gold); font-size: 15px; }

/* ------------------------------------------------------------ vault rows ---- */

.vault-list-form {
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: stretch;
    margin: 0;
}

/* Once JS moves the form into its own full-width row it lays out horizontally. */
tr.vault-list-row { background: var(--gold-tint); }

tr.vault-list-row > td { padding: 12px 12px 14px 80px; }

tr.vault-list-row .vault-list-form {
    flex-direction: row;
    align-items: end;
    flex-wrap: wrap;
    gap: 14px;
    animation: rise 140ms ease-out;
}

tr.vault-list-row .vault-list-form .field { flex: 0 0 auto; }

tr.vault-list-form-qty { width: 110px; }

tr.vault-list-row .recent-sales { margin: 0 0 8px auto; }

.vault-list-form .number-input { max-width: 130px; }

.vault-delist-form { margin: 0; display: flex; justify-content: flex-end; }

td.vault-action { text-align: right; white-space: nowrap; }

/* A form is a block element, so the barrel used to start its own line under the List button and
   made the row taller than every one beside it. Inline-block puts the two controls on the one
   line that the cell's text-align already right-justifies. The list form deliberately stays a
   block: with JavaScript it is lifted into its own full-width row, and without it, it belongs
   under the buttons rather than beside them. */
.vault-barrel-form { display: inline-block; margin: 0; vertical-align: middle; }
td.vault-action .list-toggle { vertical-align: middle; }

.list-toggle.is-open { background: var(--gold-tint-3); }

/* ----------------------------------------------------------- history tags ---- */

table.history td { padding: 9px 12px; }

td.history-when { font-variant-numeric: tabular-nums; color: var(--muted); white-space: nowrap; }

td.history-item { color: var(--text); }

td.history-side-bought { color: var(--text-2); }

td.history-side-sold { color: var(--gold); }

td.history-total { text-align: right; font-variant-numeric: tabular-nums; font-weight: 500; }

td.history-total.is-buy { color: var(--text-2); }

td.history-total.is-sell { color: var(--ok); }

.status-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    padding: 2px 9px;
    border: 1px solid rgba(239, 233, 223, 0.2);
    border-radius: 3px;
    color: var(--text-2);
    text-transform: capitalize;
}

.status-tag.status-pending { border-color: var(--gold); color: var(--gold); }
.status-tag.status-refunded { border-color: rgba(143, 199, 214, 0.4); color: var(--spell); }
.status-tag.status-failed { border-color: var(--err); color: var(--err); }

.status-note { font-size: 11.5px; color: var(--muted); margin-top: 3px; }

/* --------------------------------------------------------------- toasts ---- */

/* Bottom right, out of the way of the header pill and the table. The container itself never
   catches a click, so an empty stack cannot swallow the page underneath it. */
/* Top centre, clear of the sticky header (--site-header-h), stacking downward. The header is where the balance
   this news is about already lives, so the eye has one place to look. */
#toasts {
    position: fixed;
    top: calc(var(--site-header-h) + 11px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 60;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    pointer-events: none;
}

.toast {
    pointer-events: auto;
    display: flex;
    gap: 12px;
    align-items: flex-start;
    max-width: 340px;
    padding: 11px 13px;
    background: var(--panel);
    border: 1px solid var(--hairline);
    border-left: 3px solid var(--muted);
    border-radius: 4px;
    font-family: var(--body);
    font-size: 13px;
    color: var(--text-2);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
    animation: rise 160ms ease-out;
}

/* Cyan for money coming in, gold for money going out: the same two colours the History
   table already spends and earns in. */
.toast-sold { border-left-color: var(--spell); }
.toast-bought { border-left-color: var(--gold); }

.toast-text { flex: 1; }

.toast-dismiss {
    background: transparent;
    border: 0;
    color: var(--muted);
    cursor: pointer;
    font-size: 14px;
    line-height: 1;
    padding: 0 2px;
}

.toast-dismiss:hover { color: var(--text); }

/* -------------------------------------------------------- vault loading ---- */

.vault-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 48px 24px;
    text-align: center;
}

.vault-spinner {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 2px solid rgba(182, 130, 53, 0.25);
    border-top-color: var(--gold);
    animation: spin 900ms linear infinite;
}

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

/* A ring that does not turn still reads as "not finished yet", which is the whole message. */
@media (prefers-reduced-motion: reduce) {
    .vault-spinner { animation: none; }
}

.vault-loading-text { color: var(--muted); margin: 0; }

/* The same waiting state, but inline where a write's answer would have gone: a panel rather than a
   full-height block, because the page around it is still the page the player was using. */
.write-retry {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 16px 14px;
    background: var(--panel);
    border: 1px solid var(--hairline);
    border-left: 3px solid var(--gold);
    border-radius: 4px;
    text-align: center;
    animation: rise 160ms ease-out;
}

.write-retry .vault-spinner { width: 22px; height: 22px; }

.write-retry .retry-form { margin: 0; }

/* -------------------------------------------------- progressive enhancement ---- */

/* Anything marked js-only stays hidden until market.js claims the page. */
html:not(.js) .js-only { display: none !important; }

/* The no-JS submit button: live filtering makes it redundant, so JS hides it. */
html.js .no-js-only { display: none !important; }

/* -------------------------------------------------- bulk vault actions -------- */

.bulk-actions { margin: 0 0 0.5rem; }

.bulk-fieldset {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: flex-end;
    border: 1px solid var(--input-border);
    border-radius: 4px;
    padding: 0.5rem 0.75rem 0.6rem;
    margin: 0;
}

.bulk-fieldset legend {
    padding: 0 0.35rem;
    color: var(--text-2);
    font-size: 12px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* Progressive enhancement, and it has to be keyed on html.js rather than on the panel alone:
   .js is added by market.js itself, so with JavaScript off - or if the script fails to load -
   the bulk fields are simply visible from the start and the whole flow still works. With
   JavaScript they appear as soon as a row is ticked. */
html.js .bulk-actions .bulk-fieldset { display: none; }
html.js .bulk-actions.is-armed .bulk-fieldset { display: flex; }

/* The select-all lives in the table's own header cell, so the column stays narrow and the
   count sits right beside the box. */
.col-select { width: 2.6rem; text-align: center; }
.bulk-all { display: inline-flex; align-items: center; gap: 0.25rem; cursor: pointer; }
.bulk-all-count { color: var(--text-2); font-size: 11px; font-weight: 400; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* Same look as the per-row .btn-barrel, kept as its own selector: see the doc comment on the
   toolbar button in Vault.cshtml for why it cannot share the class name. */
.btn-bulk-barrel { background: none; border: 1px solid transparent; padding: 0.15rem 0.3rem; line-height: 1; cursor: pointer; }
.btn-bulk-barrel img { width: 33px; height: 33px; display: block; }
.btn-bulk-barrel:hover { border-color: var(--err); }

/* -------------------------------------------------- wanted board -------------- */

.wanted .inline-form { display: flex; gap: 0.5rem; align-items: center; }
.wanted .number-input { width: 4.5rem; }

/* -------------------------------------------------------- item popover ---- */

/* A hover/focus preview of an item's Appraisal box, anchored beside the trigger by market.js
   (position: fixed, left/top set from JS). It is never interactive - pointer-events: none - so
   it can never block the click that opens the real modal underneath it. The box itself carries
   the same look as .appraisal so it reads as the same thing at a glance; the .appraisal element
   swapped in resets its own border/background so the two do not double up. */
.item-popover {
    position: fixed;
    z-index: 30;
    width: min(640px, calc(100vw - 32px));
    max-height: calc(100vh - 16px);
    pointer-events: none;
    border: 1px solid var(--appraisal-border);
    border-radius: 4px;
    background: var(--appraisal-fill);
    box-shadow: inset 0 0 0 1px rgba(182, 130, 53, 0.18), 0 8px 24px rgba(0, 0, 0, 0.4);
    overflow: hidden;
}

.item-popover .appraisal {
    margin: 0;
    border: none;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
}

.item-popover-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 160px;
}

/* ------------------------------------------------------------- admin panel ---- */

.admin-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    border-bottom: 1px solid var(--hairline);
    padding-bottom: 2px;
}

.admin-tabs a {
    padding: 8px 12px;
    text-decoration: none;
    color: var(--muted);
    font-size: 13px;
    border-bottom: 2px solid transparent;
}

.admin-tabs a:hover { color: var(--gold); }

.admin-tabs a.is-active { color: var(--gold); border-bottom-color: var(--gold); }

.admin-group {
    border: 1px solid var(--hairline);
    border-radius: 4px;
    background: var(--panel);
}

.admin-group summary {
    cursor: pointer;
    padding: 10px 14px;
    font-family: var(--head);
    font-size: 16px;
    color: var(--text-2);
    list-style: none;
}

.admin-group summary::-webkit-details-marker { display: none; }

.admin-group summary::before {
    content: "\25B8";
    display: inline-block;
    width: 1em;
    color: var(--muted);
}

.admin-group[open] summary::before { content: "\25BE"; }

table.admin-settings {
    width: 100%;
    border-collapse: collapse;
    font-size: 13.5px;
    min-width: 640px;
}

table.admin-settings tbody tr.is-modified { background: var(--gold-tint); }

.setting-key {
    font-family: ui-monospace, "Consolas", monospace;
    font-size: 12.5px;
    cursor: help;
    border-bottom: 1px dotted var(--muted);
}

.setting-hidden { color: var(--faint); font-style: italic; }

.origin-badge {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 3px;
    font-size: 10.5px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: 1px solid var(--input-border);
    color: var(--muted);
}

.origin-badge.origin-fork { color: var(--gold); border-color: var(--gold-border); }

.admin-sections {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    border-bottom: 1px solid var(--hairline);
    padding-bottom: 2px;
    margin-bottom: 14px;
}

.admin-sections a {
    padding: 8px 12px;
    text-decoration: none;
    color: var(--muted);
    font-size: 13px;
    border-bottom: 2px solid transparent;
}

.admin-sections a:hover { color: var(--gold); }

.admin-sections a.is-active { color: var(--gold); border-bottom-color: var(--gold); }

.admin-chat {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 60vh;
    overflow-y: auto;
    border: 1px solid var(--hairline);
    border-radius: 4px;
    background: var(--panel);
}

.admin-chat-line {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem .5rem;
    padding: 6px 10px;
    border-bottom: 1px solid var(--hairline);
    font-size: 13px;
}

.admin-chat-line:last-child { border-bottom: none; }

.chat-time { color: var(--faint); font-variant-numeric: tabular-nums; }

.chat-channel {
    display: inline-block;
    padding: 0 6px;
    border-radius: 3px;
    font-size: 10.5px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: 1px solid var(--input-border);
    color: var(--muted);
}

.chat-channel-general { color: var(--text-2); border-color: var(--hairline); }
.chat-channel-trade { color: var(--gold); border-color: var(--gold-border); }
.chat-channel-lfg { color: #6fb3d2; border-color: #6fb3d2; }
.chat-channel-roleplay { color: #b98fd6; border-color: #b98fd6; }

.chat-sender { font-weight: 600; }

.chat-text { flex: 1 1 100%; overflow-wrap: anywhere; white-space: pre-wrap; }

.chat-truncated { color: var(--faint); font-style: italic; }

.admin-chat-gap {
    padding: 6px 10px;
    color: var(--faint);
    font-style: italic;
    text-align: center;
}

.admin-chat-notice {
    padding: 8px 10px;
    color: var(--muted);
    font-size: 13px;
}

.admin-chat-notice[hidden] { display: none; }

.announce-form { display: flex; flex-direction: column; gap: 8px; margin: 0 0 14px; max-width: 100%; }

.announce-form textarea {
    width: 100%;
    box-sizing: border-box;
    font: inherit;
    resize: vertical;
}

.setting-edit .setting-meta {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 4px 12px;
    margin: 0 0 18px;
}

.setting-meta div { display: contents; }

.setting-meta dt {
    color: var(--muted);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.setting-meta dd { margin: 0; }

.setting-bool {
    display: flex;
    gap: 18px;
    border: none;
    padding: 0;
    margin: 0 0 14px;
}

.admin-command-character {
    margin: 0 0 14px;
    font-size: 13px;
    color: var(--text-2);
}

.admin-command-character-offline { color: var(--muted); }

.command-search-form {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 14px;
}

.command-search-form input[type="search"] {
    flex: 1 1 220px;
    min-width: 0;
    box-sizing: border-box;
    font: inherit;
}

table.admin-commands {
    width: 100%;
    border-collapse: collapse;
    font-size: 13.5px;
    min-width: 640px;
}

table.admin-commands tbody tr.is-disabled { color: var(--faint); }

.command-name {
    font-family: ui-monospace, "Consolas", monospace;
    font-size: 12.5px;
    cursor: help;
    border-bottom: 1px dotted var(--muted);
}

.command-usage {
    display: block;
    color: var(--muted);
    font-size: 11.5px;
    margin-top: 2px;
}

.bucket-badge {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 3px;
    font-size: 10.5px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: 1px solid var(--input-border);
    color: var(--muted);
}

.bucket-badge.bucket-web { color: var(--gold); border-color: var(--gold-border); }
.bucket-badge.bucket-in_game_character { color: #6fb3d2; border-color: #6fb3d2; }
.bucket-badge.bucket-in_game_only { color: var(--faint); }

.long-running-badge,
.capture-badge {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 7px;
    border-radius: 3px;
    font-size: 10.5px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: 1px solid var(--input-border);
    color: var(--muted);
}

.command-fill {
    font: inherit;
    font-family: ui-monospace, "Consolas", monospace;
    font-size: 12.5px;
    background: none;
    border: none;
    border-bottom: 1px dotted var(--muted);
    color: inherit;
    padding: 0;
    cursor: pointer;
}

.command-fill:hover { color: var(--gold); border-color: var(--gold-border); }

.command-console-form {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 14px;
}

.command-console-input {
    flex: 1 1 320px;
    min-width: 0;
    box-sizing: border-box;
    font-family: ui-monospace, "Consolas", monospace;
    font-size: 13px;
}

.command-run-result {
    margin: 0 0 14px;
    border: 1px solid var(--input-border);
    border-radius: 3px;
    padding: 10px 12px;
}

.command-run-outcome {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 0 0 6px;
    font-size: 12.5px;
}

.command-run-result-badge {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 3px;
    font-size: 10.5px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: 1px solid var(--input-border);
    color: var(--muted);
}

.command-run-result-badge.result-ok { color: var(--ok); border-color: var(--ok); }
.command-run-result-badge.result-exception,
.command-run-result-badge.result-usage,
.command-run-result-badge.result-not_in_world { color: var(--err); border-color: var(--err); }
.command-run-result-badge.result-timeout { color: var(--gold); border-color: var(--gold-border); }

.command-run-name {
    font-family: ui-monospace, "Consolas", monospace;
}

.command-run-elapsed { color: var(--muted); }

.command-output {
    margin: 0;
    padding: 8px 10px;
    background: var(--input);
    border-radius: 3px;
    font-family: ui-monospace, "Consolas", monospace;
    font-size: 12px;
    max-height: 320px;
    overflow-y: auto;
    list-style: none;
}

.command-output li { white-space: pre-wrap; word-break: break-word; padding: 1px 0; }
.command-output li.out-error { color: var(--err); }
.command-output li.out-debug { color: var(--muted); }
.command-output li.out-chat { color: var(--gold); }

.command-history {
    margin: 0 0 14px;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.command-history:empty { display: none; }

/* ------------------------------------------------------ admin world events ---- */

.we-heading { font-family: var(--head); font-size: 1.25rem; margin: 1.25rem 0 0.5rem; color: var(--gold); }

.we-status, .we-preview { border: 1px solid var(--hairline); border-radius: 3px; padding: 0.75rem 1rem; margin: 1rem 0; background: var(--panel); }

.we-facts { display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px; margin: 0.5rem 0; }
.we-facts dt { color: var(--muted); font-size: 13px; }
.we-facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

.we-state { text-transform: capitalize; }
.we-state-idle { color: var(--warn); }
.we-state-active { color: var(--ok); }

.we-status-text { color: var(--faint); font-size: 13px; margin: 0.5rem 0; overflow-wrap: anywhere; }

.we-stop-controls { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }
.we-stop-form { margin: 0; }

.we-reason { display: block; margin-top: 4px; color: var(--muted); }

.we-start-form { margin: 1rem 0; }
.we-random { margin-bottom: 0.75rem; }
.we-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px 16px; }
.we-grid select, .we-grid input[type="number"] { width: 100%; }
.we-guard { color: var(--warn); margin: 0.75rem 0 0; }
.we-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
.we-repost-form { margin-top: 0.75rem; }

.we-start-form .btn-primary:disabled, .we-start-form .btn-secondary:disabled { opacity: 0.45; cursor: not-allowed; }
