/* =========================================================
   d20Craft — Main Stylesheet
   ========================================================= */

@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600;700&family=Cinzel+Decorative:wght@400;700&family=Crimson+Pro:ital,wght@0,300;0,400;0,600;1,300;1,400&display=swap');

/* ----- Variables ---------------------------------------- */
:root {
    --campaign-accent:        var(--gold);
    --campaign-accent-faint:  var(--gold-faint);
    --campaign-accent-border: var(--gold-border);
    --campaign-accent-dim:    var(--gold-dim);
}

:root {
    --bg:          #0d0b09;
    --bg-raised:   #121008;
    --bg-card:     #1a1712;
    --bg-card-alt: #1e1c16;
    --bg-input:    #141210;
    --bg-overlay:  rgba(0,0,0,0.7);

    --gold:        #c9a227;
    --gold-bright: #e8c547;
    --gold-dim:    #876e18;
    --gold-faint:  rgba(201,162,39,0.12);
    --gold-border: rgba(201,162,39,0.28);

    --parchment:     #f0e6cc;
    --parchment-dim: #c8b896;

    --text:       #ddd5c4;
    --text-dim:   #9a907e;
    --text-muted: #6b5e4e;

    --border:     #231f18;
    --border-mid: #2e2a20;

    --red:        #7a1f2e;
    --red-text:   #e57373;
    --green:      #1e4a35;
    --green-text: #6dbf8c;
    --blue:       #1a2e4a;
    --blue-text:  #7ab4e8;
    --amber:      #4a3410;
    --amber-text: #e8c547;

    --font-heading:  'Cinzel', 'Palatino Linotype', 'Book Antiqua', Palatino, serif;
    --font-display:  'Cinzel Decorative', 'Cinzel', serif;
    --font-body:     'Crimson Pro', 'Palatino Linotype', Georgia, serif;
    --font-ui:       system-ui, -apple-system, 'Segoe UI', sans-serif;
    /* The display voice a campaign theme speaks in. Used once per page, on the
       page title, so a characterful face stays an event rather than a texture.
       Defaults to the heading face, so the base look is unchanged. */
    --font-title:    var(--font-heading);

    /* The site's own gold. Campaign themes repaint everything else, but never
       this — the logo is the one fixed thing across every campaign. */
    --logo:      #c9a227;
    --header-bg: rgba(13,11,9,0.96);
    /* The material the page is printed on; each theme swaps its own in. */
    --wash:
        radial-gradient(ellipse at 20% 10%, rgba(201,162,39,0.04) 0%, transparent 50%),
        radial-gradient(ellipse at 80% 90%, rgba(201,162,39,0.03) 0%, transparent 50%);

    --space-xs:  0.25rem;
    --space-sm:  0.5rem;
    --space-md:  1rem;
    --space-lg:  1.5rem;
    --space-xl:  2rem;
    --space-2xl: 3rem;
    --space-3xl: 5rem;

    --radius:    3px;
    --radius-lg: 6px;
    --shadow:    0 2px 12px rgba(0,0,0,0.5);
    --shadow-lg: 0 6px 32px rgba(0,0,0,0.7);
    --transition: 0.18s ease;

    --header-h: 64px;
    --campaign-bar-h: 74px;
    --container-w: 1100px;
}

/* ----- Reset -------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-size: 16px; scroll-behavior: smooth; }
body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 1.0625rem;
    line-height: 1.65;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}
body::before {
    content: '';
    position: fixed;
    inset: 0;
    background-image: var(--wash);
    pointer-events: none;
    z-index: 0;
}
img { max-width: 100%; display: block; }
a { color: var(--gold); text-decoration: none; transition: color var(--transition); }
a:hover { color: var(--gold-bright); }
ul, ol { padding-left: 1.25em; }

/* ----- Layout ------------------------------------------- */
.container {
    width: 100%;
    max-width: var(--container-w);
    margin: 0 auto;
    padding: 0 var(--space-lg);
}

.site-main {
    flex: 1;
    padding-top: var(--space-2xl);
    padding-bottom: var(--space-3xl);
    position: relative;
    z-index: 1;
}

body.has-campaign .site-main {
    padding-top: var(--space-xl);
}

/* ----- Site Header -------------------------------------- */
.site-header {
    position: sticky;
    top: 0;
    z-index: 100;
    background: var(--header-bg);
    border-bottom: 1px solid var(--gold-border);
    backdrop-filter: blur(8px);
    height: var(--header-h);
}

.header-inner {
    max-width: var(--container-w);
    margin: 0 auto;
    padding: 0 var(--space-lg);
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-lg);
}

.site-logo {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    color: var(--logo);
    font-family: var(--font-display);
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    white-space: nowrap;
}
.site-logo:hover { color: #e8c547; }
.logo-icon { font-size: 1.1em; }
/* The product tag beside the d20Craft wordmark ("Campaigns"): the parent
   brand stays the gold anchor, the subsite reads as a quieter label. */
.logo-product {
    align-self: center;
    padding-left: var(--space-sm);
    border-left: 1px solid var(--border);
    color: var(--text-dim);
    font-family: var(--font-ui);
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
}
.site-logo:hover .logo-product { color: var(--text); }

.site-nav {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
}

.nav-link {
    color: var(--text-dim);
    font-family: var(--font-ui);
    font-size: 0.85rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 0.35rem 0.75rem;
    border-radius: var(--radius);
    transition: color var(--transition), background var(--transition);
}
.nav-link:hover { color: var(--gold); background: var(--gold-faint); }

.nav-link-cta {
    background: var(--gold-faint);
    border: 1px solid var(--gold-border);
    color: var(--gold);
}
.nav-link-cta:hover { background: var(--gold); color: var(--bg); }

.nav-link-admin { color: var(--amber-text); }
.nav-link-logout { color: var(--text-muted); }

.nav-user {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding-left: var(--space-md);
    border-left: 1px solid var(--border-mid);
}

.nav-username {
    font-family: var(--font-ui);
    font-size: 0.82rem;
    color: var(--text-dim);
    text-decoration: none;
}
.nav-username:hover { color: var(--gold); }

.nav-toggle {
    display: none;
    flex-direction: column;
    gap: 5px;
    background: none;
    border: none;
    cursor: pointer;
    padding: 4px;
}
.nav-toggle span {
    display: block;
    width: 22px;
    height: 2px;
    background: var(--text-dim);
    border-radius: 2px;
    transition: var(--transition);
}

/* ----- Campaign Bar ------------------------------------- */
.campaign-bar {
    background: var(--bg-raised);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: var(--header-h);
    z-index: 90;
}
.campaign-bar-inner {
    max-width: var(--container-w);
    margin: 0 auto;
    padding: 0 var(--space-lg);
    height: var(--campaign-bar-h);
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 3px;
}

.campaign-bar-meta {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex: 0 0 auto;
}

/* Stays on the heading face, not --font-title: at 0.9rem a display face like
   Rye or Pirata One is decoration the reader has to fight. The bar still
   changes voice per theme, because --font-heading is themed too. */
.campaign-title {
    font-family: var(--font-heading);
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--gold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 60vw;
}
.campaign-sep { color: var(--text-muted); }

.campaign-nav {
    display: flex;
    align-items: center;
    gap: 4px;
    overflow-x: auto;
    scrollbar-width: none;
}
.campaign-nav::-webkit-scrollbar { display: none; }
/* If the bar ever outruns its width (phones), fade the edge so it reads as
   "there's more" rather than as a clipped word. This is a sticky overlay, not
   a mask — a mask on this element would clip the plates nested inside it. */
.campaign-nav.is-scrollable::after {
    content: '';
    position: sticky;
    right: 0;
    flex: 0 0 2.5rem;
    align-self: stretch;
    margin-left: -2.5rem;
    pointer-events: none;
    background: linear-gradient(to right, transparent, var(--bg-raised));
    transition: opacity var(--transition);
}
.campaign-nav.is-scrollable.is-scrolled-end::after { opacity: 0; }
.cnav {
    font-family: var(--font-ui);
    font-size: 0.78rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--text-muted);
    padding: 0.3rem 0.85rem;
    border-radius: var(--radius);
    white-space: nowrap;
    transition: color var(--transition), background var(--transition);
}
.cnav:hover { color: var(--text); background: var(--bg-card); }
.cnav.active { color: var(--gold); background: var(--gold-faint); }

/* The group triggers open a plate rather than navigating, so they're buttons. */
button.cnav {
    border: 0;
    background: none;
    line-height: inherit;
    cursor: pointer;
}
.cnav-caret { margin-left: 3px; font-size: 0.6em; opacity: 0.6; vertical-align: middle; }
.cnav-group[data-open] > .cnav-trigger { color: var(--text); background: var(--bg-card); }
.cnav-group[data-open] > .cnav-trigger .cnav-caret { opacity: 1; }

/* ----- Campaign nav plates ------------------------------
   A group opens a "plate": a rail of sections (label + what it's for) beside
   live entity columns, divided by hinge rules. Positioned by main.js, which
   clamps it inside the viewport — nothing may run off the right edge. */
.cnav-group { position: relative; }

.cnav-panel {
    display: none;
    position: fixed;
    z-index: 300;
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-top: 1px solid var(--gold-border);
    border-radius: var(--radius);
    box-shadow: 0 14px 40px rgba(0,0,0,0.6);
}
.cnav-panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    padding: 0.5rem 0.9rem 0.45rem;
    border-bottom: 1px solid var(--border);
}
.cnav-eyebrow {
    font-family: var(--font-ui);
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.cnav-panel-body { display: flex; align-items: stretch; }

.cnav-rail {
    flex: 0 0 auto;
    width: 15rem;
    padding: 0.35rem;
    display: flex;
    flex-direction: column;
}
.cnav-panel-slim .cnav-rail { width: 14rem; }

.cnav-sec {
    display: block;
    padding: 0.4rem 0.55rem 0.45rem;
    border-radius: var(--radius);
    border-left: 2px solid transparent;
    transition: background var(--transition), border-color var(--transition);
}
.cnav-sec-label {
    display: block;
    font-family: var(--font-ui);
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--text);
}
.cnav-sec-blurb {
    display: block;
    font-family: var(--font-body);
    font-size: 0.82rem;
    line-height: 1.35;
    color: var(--text-muted);
}
.cnav-sec:hover { background: var(--bg-raised); border-left-color: var(--border-mid); }
.cnav-sec:hover .cnav-sec-label { color: var(--gold); }
.cnav-sec.active { background: var(--gold-faint); border-left-color: var(--gold); }
.cnav-sec.active .cnav-sec-label { color: var(--gold); }

.cnav-col {
    flex: 0 0 auto;
    width: 14rem;
    min-width: 0;
    border-left: 1px solid var(--border);
    padding: 0.35rem 0;
    display: flex;
    flex-direction: column;
}
.cnav-col-head {
    font-family: var(--font-ui);
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: 0.2rem 0.9rem 0.4rem;
}
.cnav-col-body { overflow-y: auto; max-height: 17rem; }

.cnav-dropdown-item {
    display: block;
    padding: 0.28rem 0.9rem;
    font-family: var(--font-ui);
    font-size: 0.8rem;
    color: var(--text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: color var(--transition), background var(--transition);
}
.cnav-dropdown-item:hover { background: var(--gold-faint); color: var(--gold); }
.cnav-dropdown-sub { color: var(--text-muted); font-size: 0.76rem; }

/* The GM's private tools read as their own plate — warm parchment wash and the
   same lock chip the site uses on secret records. */
.cnav-group-private .cnav-panel {
    background: linear-gradient(rgba(201,162,39,0.05), rgba(201,162,39,0.02)), var(--bg-card);
    border-color: rgba(201,162,39,0.28);
}
.cnav-group-private .cnav-panel-head { border-bottom-color: rgba(201,162,39,0.2); }
.cnav-group-private .cnav-sec:hover { background: rgba(201,162,39,0.08); }

/* Narrow viewports: the plate stacks into one column and scrolls as a sheet. */
@media (max-width: 700px) {
    .cnav-panel { overflow-y: auto; }
    .cnav-panel-body { flex-wrap: wrap; }
    .cnav-rail, .cnav-panel-slim .cnav-rail, .cnav-col { width: 100%; }
    .cnav-col {
        border-left: 0;
        border-top: 1px solid var(--border);
    }
    .cnav-col-body { max-height: none; }
}

/* ----- Expanding location tree in the nav dropdown ------ */
.cnav-tree-row { display: flex; align-items: stretch; }
.cnav-tree-row .cnav-dropdown-item { flex: 1 1 auto; }
.cnav-tree-toggle {
    flex: 0 0 auto;
    width: 1.5rem;
    border: 0;
    background: none;
    color: var(--text-muted);
    font-size: 0.7rem;
    line-height: 1;
    cursor: pointer;
    transition: transform var(--transition), color var(--transition);
}
.cnav-tree-toggle:hover { color: var(--gold); }
.cnav-tree-spacer { flex: 0 0 auto; width: 1.5rem; }
/* Sub-locations expand on hover (or when pinned open via the toggle on touch). */
.cnav-tree-children {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--transition);
}
.cnav-tree-children-inner { overflow: hidden; }
.cnav-tree-node:hover > .cnav-tree-children,
.cnav-tree-node.open > .cnav-tree-children { grid-template-rows: 1fr; }
.cnav-tree-node:hover > .cnav-tree-row > .cnav-tree-toggle,
.cnav-tree-node.open > .cnav-tree-row > .cnav-tree-toggle { transform: rotate(90deg); }

/* ----- Typography --------------------------------------- */
h1, h2, h3, h4, h5 {
    font-family: var(--font-heading);
    font-weight: 600;
    color: var(--parchment);
    line-height: 1.25;
}
h1 { font-size: 2rem; margin-bottom: var(--space-md); }
h2 { font-size: 1.5rem; margin-bottom: var(--space-md); }
h3 { font-size: 1.2rem; margin-bottom: var(--space-sm); }
h4 { font-size: 1rem; margin-bottom: var(--space-xs); }

.page-header {
    margin-bottom: var(--space-2xl);
    padding-bottom: var(--space-lg);
    border-bottom: 1px solid var(--gold-border);
}
.page-header h1 { margin-bottom: var(--space-xs); font-family: var(--font-title); }
.page-subtitle {
    color: var(--text-dim);
    font-size: 1.05rem;
}

.section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--space-lg);
    flex-wrap: wrap;
    gap: var(--space-sm) var(--space-md);
}

.ornament {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    color: var(--gold-dim);
    margin: var(--space-lg) 0;
}
.ornament::before, .ornament::after {
    content: '';
    flex: 1;
    height: 1px;
    background: linear-gradient(to right, transparent, var(--gold-border));
}
.ornament::after {
    background: linear-gradient(to left, transparent, var(--gold-border));
}

/* ----- Cards -------------------------------------------- */
.card {
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    position: relative;
}
.card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--gold-border), transparent);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.card-title {
    font-family: var(--font-heading);
    font-size: 1.1rem;
    color: var(--parchment);
    margin-bottom: var(--space-sm);
}
.card-body { color: var(--text-dim); }

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-lg);
}

/* A shelf of covers: the campaign's own plate on the left (see
   .campaign-spine), everything else stacked beside it. */
.campaign-card {
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    display: grid;
    grid-template-columns: 54px minmax(0, 1fr);
    column-gap: var(--space-md);
    row-gap: var(--space-sm);
    align-content: start;
    transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
    position: relative;
    overflow: hidden;
}
.campaign-card > *:not(.campaign-spine) { grid-column: 2; }
.campaign-card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--gold-border), transparent);
}
.campaign-card:hover {
    border-color: var(--gold-border);
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

.campaign-card-title {
    font-family: var(--font-heading);
    font-size: 1.15rem;
    color: var(--parchment);
    font-weight: 600;
}

.campaign-card-desc {
    color: var(--text-dim);
    font-size: 0.95rem;
    flex: 1;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Stacked, not inline: the cover slot narrows this column, and an inline row
   wrapped mid-value and left the "·" dangling at the end of a line. */
.campaign-card-meta {
    display: flex;
    flex-direction: column;
    gap: 1px;
    margin-top: var(--space-sm);
    font-size: 0.82rem;
    color: var(--text-muted);
    font-family: var(--font-ui);
}
.campaign-card-meta > span { white-space: nowrap; }
.campaign-card-meta > .meta-sep { display: none; }

.section-card {
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    display: flex;
    align-items: flex-start;
    gap: var(--space-lg);
    text-decoration: none;
    color: inherit;
    transition: border-color var(--transition), background var(--transition), transform var(--transition);
}
.section-card:hover {
    border-color: var(--gold-border);
    background: var(--bg-card-alt);
    transform: translateY(-1px);
    color: inherit;
}
.section-card-icon {
    font-size: 1.8rem;
    width: 2.5rem;
    text-align: center;
    flex-shrink: 0;
    margin-top: 2px;
}
.section-card-content {}
.section-card-title {
    font-family: var(--font-heading);
    font-size: 1rem;
    color: var(--parchment);
    margin-bottom: var(--space-xs);
}
.section-card-desc {
    font-size: 0.9rem;
    color: var(--text-dim);
}

/* ----- Badges ------------------------------------------- */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.2em 0.6em;
    border-radius: 2px;
    font-family: var(--font-ui);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.badge-role-gm      { background: var(--gold-faint); color: var(--gold); border: 1px solid var(--gold-border); }
.badge-role-player  { background: var(--blue); color: var(--blue-text); border: 1px solid rgba(122,180,232,0.2); }
.badge-role-superadmin { background: var(--amber); color: var(--amber-text); border: 1px solid rgba(232,197,71,0.3); }

/* Theme chip — colours come from campaign_themes() as inline --chip vars, so a
   newly registered theme needs no CSS rule of its own. */
.badge-theme { background: var(--chip-faint); color: var(--chip); border: 1px solid var(--chip-border); }

/* ----- Forms -------------------------------------------- */
.form-card {
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
    padding: var(--space-2xl);
    max-width: 480px;
    margin: 0 auto;
    position: relative;
}
.form-card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--gold-border), transparent);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.form-card-wide { max-width: 640px; }

.form-group {
    margin-bottom: var(--space-lg);
}
.form-group:last-of-type { margin-bottom: 0; }

label {
    display: block;
    font-family: var(--font-ui);
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-dim);
    margin-bottom: var(--space-xs);
}
label .required { color: var(--red-text); margin-left: 2px; }

input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
input[type="number"],
input[type="search"],
select,
textarea {
    width: 100%;
    background: var(--bg-input);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius);
    padding: 0.6rem 0.85rem;
    color: var(--text);
    font-family: var(--font-body);
    font-size: 1rem;
    transition: border-color var(--transition), box-shadow var(--transition);
    appearance: none;
}
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--gold-dim);
    box-shadow: 0 0 0 3px var(--gold-faint);
}
input::placeholder, textarea::placeholder { color: var(--text-muted); }

select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23876e18' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.85rem center;
    padding-right: 2.5rem;
    cursor: pointer;
}

textarea { resize: vertical; min-height: 100px; }

.form-hint {
    margin-top: var(--space-xs);
    font-size: 0.82rem;
    color: var(--text-muted);
    font-family: var(--font-ui);
}

.form-actions {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin-top: var(--space-xl);
    flex-wrap: wrap;
}

.form-footer {
    text-align: center;
    margin-top: var(--space-lg);
    color: var(--text-muted);
    font-family: var(--font-ui);
    font-size: 0.88rem;
}

/* ----- Buttons ------------------------------------------ */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    padding: 0.6rem 1.4rem;
    border: 1px solid transparent;
    border-radius: var(--radius);
    font-family: var(--font-ui);
    font-size: 0.85rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    cursor: pointer;
    text-decoration: none;
    transition: all var(--transition);
    white-space: nowrap;
}
.btn:hover { text-decoration: none; }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }

.btn-primary {
    background: var(--gold);
    color: #0d0b09;
    border-color: var(--gold);
}
.btn-primary:hover {
    background: var(--gold-bright);
    border-color: var(--gold-bright);
    color: #0d0b09;
    box-shadow: 0 0 16px rgba(201,162,39,0.25);
}

.btn-secondary {
    background: transparent;
    color: var(--text-dim);
    border-color: var(--border-mid);
}
.btn-secondary:hover {
    border-color: var(--text-muted);
    color: var(--text);
    background: var(--bg-card);
}

.btn-ghost {
    background: transparent;
    color: var(--gold-dim);
    border-color: var(--gold-border);
}
.btn-ghost:hover {
    background: var(--gold-faint);
    color: var(--gold);
    border-color: var(--gold-dim);
}

.btn-danger {
    background: transparent;
    color: var(--red-text);
    border-color: rgba(229,115,115,0.3);
}
.btn-danger:hover {
    background: rgba(122,31,46,0.2);
    border-color: var(--red-text);
}

.btn-sm {
    padding: 0.35rem 0.85rem;
    font-size: 0.75rem;
}

.btn-lg {
    padding: 0.8rem 2rem;
    font-size: 0.9rem;
}

/* ----- Alerts ------------------------------------------- */
.alert {
    padding: var(--space-md) var(--space-lg);
    border-radius: var(--radius);
    border-left: 3px solid;
    margin-bottom: var(--space-lg);
    font-family: var(--font-ui);
    font-size: 0.92rem;
}
.alert-success { background: var(--green); border-color: var(--green-text); color: var(--green-text); }
.alert-error   { background: var(--red);   border-color: var(--red-text);   color: var(--red-text); }
.alert-warning { background: var(--amber); border-color: var(--amber-text); color: var(--amber-text); }
.alert-info    { background: var(--blue);  border-color: var(--blue-text);  color: var(--blue-text); }

/* ----- Tables ------------------------------------------- */
.table-wrapper { overflow-x: auto; border-radius: var(--radius-lg); }
table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.95rem;
}
thead tr {
    background: var(--bg-raised);
    border-bottom: 1px solid var(--gold-border);
}
th {
    font-family: var(--font-ui);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    padding: 0.75rem 1rem;
    text-align: left;
}
td {
    padding: 0.8rem 1rem;
    border-bottom: 1px solid var(--border);
    color: var(--text);
    vertical-align: middle;
}
tbody tr:hover { background: var(--bg-card); }
tbody tr:last-child td { border-bottom: none; }

/* ----- Hero --------------------------------------------- */
.hero {
    text-align: center;
    padding: var(--space-3xl) 0 var(--space-2xl);
}
.hero-eyebrow {
    font-family: var(--font-ui);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--gold-dim);
    margin-bottom: var(--space-md);
}
.hero-title {
    font-family: var(--font-display);
    font-size: clamp(2.2rem, 6vw, 3.5rem);
    color: var(--parchment);
    margin-bottom: var(--space-lg);
    line-height: 1.15;
    text-shadow: 0 2px 20px rgba(201,162,39,0.15);
}
.hero-title .accent { color: var(--gold); }
.hero-body {
    max-width: 580px;
    margin: 0 auto var(--space-xl);
    font-size: 1.1rem;
    color: var(--text-dim);
}
.hero-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-md);
    flex-wrap: wrap;
}
.hero-divider {
    margin: var(--space-2xl) 0;
    border: none;
    border-top: 1px solid var(--gold-border);
    opacity: 0.5;
}

/* ----- Feature Grid ------------------------------------- */
.features {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--space-lg);
    margin-top: var(--space-2xl);
}
.feature {
    padding: var(--space-xl);
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
}
.feature-icon {
    font-size: 1.8rem;
    margin-bottom: var(--space-md);
}
.feature-title {
    font-family: var(--font-heading);
    font-size: 1rem;
    color: var(--parchment);
    margin-bottom: var(--space-xs);
}
.feature-desc {
    font-size: 0.92rem;
    color: var(--text-dim);
}

/* ----- Stats Bar ---------------------------------------- */
.stats-row {
    display: flex;
    gap: var(--space-lg);
    flex-wrap: wrap;
    margin-bottom: var(--space-2xl);
}
.stat-box {
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
    padding: var(--space-lg) var(--space-xl);
    text-align: center;
    flex: 1;
    min-width: 120px;
}
.stat-number {
    font-family: var(--font-heading);
    font-size: 1.8rem;
    color: var(--gold);
    display: block;
    line-height: 1;
    margin-bottom: var(--space-xs);
}
.stat-label {
    font-family: var(--font-ui);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-muted);
}

/* ----- Invite Code Display ------------------------------ */
.invite-code-box {
    background: var(--bg-raised);
    border: 1px dashed var(--gold-border);
    border-radius: var(--radius);
    padding: var(--space-md) var(--space-lg);
    display: inline-flex;
    align-items: center;
    gap: var(--space-md);
}
.invite-code {
    font-family: var(--font-ui);
    font-size: 1.3rem;
    font-weight: 700;
    letter-spacing: 0.15em;
    color: var(--gold);
}
.copy-btn {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    padding: 0;
    font-size: 1rem;
    transition: color var(--transition);
}
.copy-btn:hover { color: var(--gold); }

/* ----- Empty States ------------------------------------- */
.empty-state {
    text-align: center;
    padding: var(--space-3xl) var(--space-lg);
    color: var(--text-muted);
}
.empty-icon { font-size: 3rem; margin-bottom: var(--space-lg); opacity: 0.4; }
.empty-title {
    font-family: var(--font-heading);
    font-size: 1.1rem;
    color: var(--text-dim);
    margin-bottom: var(--space-sm);
}
.empty-desc { font-size: 0.92rem; margin-bottom: var(--space-lg); }

/* ----- Site Footer -------------------------------------- */
.site-footer {
    border-top: 1px solid var(--border);
    padding: var(--space-xl) 0;
    position: relative;
    z-index: 1;
}
.footer-inner {
    max-width: var(--container-w);
    margin: 0 auto;
    padding: 0 var(--space-lg);
    text-align: center;
}
.footer-brand {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    font-family: var(--font-display);
    font-size: 1rem;
    color: var(--gold-dim);
    margin-bottom: var(--space-sm);
}
.footer-tagline {
    font-style: italic;
    color: var(--text-muted);
    font-size: 0.92rem;
    margin-bottom: var(--space-xs);
}
.footer-copy {
    font-family: var(--font-ui);
    font-size: 0.78rem;
    color: var(--text-muted);
}

/* ----- Auth Page Layout --------------------------------- */
.auth-page {
    max-width: 480px;
    margin: 0 auto;
}
.auth-title {
    font-family: var(--font-display);
    text-align: center;
    margin-bottom: var(--space-2xl);
}

/* ----- Utility ------------------------------------------ */
.text-gold   { color: var(--gold); }
.text-dim    { color: var(--text-dim); }
.text-muted  { color: var(--text-muted); }
.text-center { text-align: center; }
.text-right  { text-align: right; }
.text-sm     { font-size: 0.88rem; }
.text-ui     { font-family: var(--font-ui); }
.mt-sm  { margin-top: var(--space-sm); }
.mt-md  { margin-top: var(--space-md); }
.mt-lg  { margin-top: var(--space-lg); }
.mt-xl  { margin-top: var(--space-xl); }
.mb-sm  { margin-bottom: var(--space-sm); }
.mb-md  { margin-bottom: var(--space-md); }
.mb-lg  { margin-bottom: var(--space-lg); }
.mb-xl  { margin-bottom: var(--space-xl); }
.flex   { display: flex; }
.gap-sm { gap: var(--space-sm); }
.gap-md { gap: var(--space-md); }
.items-center { align-items: center; }
.items-end { align-items: flex-end; }
.justify-between { justify-content: space-between; }
.hidden { display: none; }

/* ----- Icons -------------------------------------------- */
.icon {
    width: 1em;
    height: 1em;
    flex-shrink: 0;
    vertical-align: -0.125em;
}
.site-logo .icon,
.footer-brand .icon { color: var(--gold); }
.feature-icon,
.section-card-icon { color: var(--gold-dim); transition: color var(--transition); }
.section-card:hover .section-card-icon { color: var(--gold); }
.empty-icon { color: var(--gold-dim); }
.ornament { font-size: 1.4rem; }
.copy-btn .icon { width: 1.1em; height: 1.1em; }

/* ----- Media thumbnails --------------------------------- */
.media-card { padding-top: 0; }
.media-card .thumb {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 16 / 10;
    margin: 0 calc(-1 * var(--space-xl)) var(--space-sm);
    background: var(--bg-raised);
    border-bottom: 1px solid var(--border-mid);
    overflow: hidden;
}
.media-card .thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--transition);
}
.media-card:hover .thumb img { transform: scale(1.04); }
.thumb-placeholder { color: var(--text-muted); font-size: 2.75rem; }
.thumb-placeholder .icon { opacity: 0.5; }

/* File thumbnail used inside table rows */
.file-cell { display: flex; align-items: center; gap: var(--space-md); }
.file-thumb {
    width: 42px;
    height: 42px;
    flex-shrink: 0;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--bg-raised);
    border: 1px solid var(--border-mid);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
    font-size: 1.2rem;
}
.file-thumb img { width: 100%; height: 100%; object-fit: cover; }

/* ----- Location detail ---------------------------------- */
.loc-breadcrumb {
    font-family: var(--font-ui);
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-bottom: var(--space-md);
}
.loc-breadcrumb a { color: var(--text-muted); }
.loc-breadcrumb a:hover { color: var(--gold); }
.loc-breadcrumb .sep { opacity: 0.5; margin: 0 0.4rem; }

.loc-section { margin-top: var(--space-2xl); }
.loc-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    margin-bottom: var(--space-md);
    flex-wrap: wrap;
}
.loc-section-head h2 { margin: 0; }

.attach-list { display: flex; flex-direction: column; gap: var(--space-sm); }
.attach-item {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-raised);
}
.attach-item .file-thumb { width: 48px; height: 48px; }
.attach-meta { min-width: 0; flex: 1; }
.attach-name { font-weight: 600; word-break: break-word; }
.attach-sub {
    font-family: var(--font-ui);
    font-size: 0.75rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.attach-actions { display: flex; gap: var(--space-sm); flex-shrink: 0; align-items: center; }

.attach-add-row {
    display: grid;
    grid-template-columns: 1fr 1fr auto;
    gap: var(--space-md);
    align-items: end;
}
@media (max-width: 640px) {
    .attach-add-row { grid-template-columns: 1fr; }
    .attach-item { flex-wrap: wrap; }
}

/* ----- Rich Text Editor (Quill dark overrides) ---------- */
.rich-editor-wrap {
    border: 1px solid var(--border-mid);
    border-radius: var(--radius);
    overflow: hidden;
    transition: border-color var(--transition), box-shadow var(--transition);
}
.rich-editor-wrap:focus-within {
    border-color: var(--gold-dim);
    box-shadow: 0 0 0 3px var(--gold-faint);
}
.rich-editor-value { display: none !important; }

.ql-toolbar.ql-snow {
    background: var(--bg-raised);
    border: none;
    border-bottom: 1px solid var(--border-mid);
    padding: 6px 8px;
}
.ql-container.ql-snow {
    background: var(--bg-input);
    border: none;
    font-family: var(--font-body);
    font-size: 1rem;
    color: var(--text);
    min-height: 140px;
}
.ql-editor { min-height: 140px; padding: 0.6rem 0.85rem; }
.ql-editor.ql-blank::before {
    color: var(--text-muted);
    font-style: italic;
    left: 0.85rem;
}
.ql-snow .ql-stroke { stroke: var(--text-dim); }
.ql-snow .ql-fill, .ql-snow .ql-stroke.ql-fill { fill: var(--text-dim); }
.ql-snow.ql-toolbar button:hover .ql-stroke,
.ql-snow.ql-toolbar button.ql-active .ql-stroke { stroke: var(--gold); }
.ql-snow.ql-toolbar button:hover .ql-fill,
.ql-snow.ql-toolbar button.ql-active .ql-fill { fill: var(--gold); }
.ql-snow.ql-toolbar button:hover,
.ql-snow.ql-toolbar button.ql-active { color: var(--gold); }
.ql-snow .ql-picker { color: var(--text-dim); }
.ql-snow .ql-picker-label { border-color: var(--border-mid) !important; }
.ql-snow .ql-picker-options {
    background: var(--bg-card);
    border-color: var(--border-mid);
}
.ql-snow .ql-picker-item:hover { color: var(--gold); }
.ql-snow a { color: var(--gold); }
.ql-tooltip {
    background: var(--bg-card) !important;
    border-color: var(--border-mid) !important;
    color: var(--text) !important;
    box-shadow: var(--shadow) !important;
}
.ql-tooltip input[type=text] {
    background: var(--bg-input);
    border-color: var(--border-mid);
    color: var(--text);
}
.ql-tooltip a.ql-action, .ql-tooltip a.ql-remove { color: var(--gold) !important; }

/* ----- Rich Content Display (stored HTML output) -------- */
.rich-content {
    color: var(--text);
    line-height: 1.7;
    font-size: 1.0625rem;
}
.rich-content p { margin-bottom: 0.75em; }
.rich-content p:last-child { margin-bottom: 0; }
.rich-content h2 { font-size: 1.3rem; margin: 1.2em 0 0.5em; color: var(--parchment); }
.rich-content h3 { font-size: 1.1rem; margin: 1em 0 0.4em; color: var(--parchment); }
.rich-content ul, .rich-content ol { padding-left: 1.4em; margin-bottom: 0.75em; }
.rich-content li { margin-bottom: 0.25em; }
.rich-content blockquote {
    border-left: 3px solid var(--gold-border);
    margin: 0.8em 0;
    padding: 0.4em 1em;
    color: var(--text-dim);
    font-style: italic;
}
.rich-content a { color: var(--gold); }
.rich-content a:hover { color: var(--gold-bright); }
.rich-content strong, .rich-content b { color: var(--parchment); }

/* ----- Character Cards ---------------------------------- */
.char-card { display: flex; flex-direction: column; gap: var(--space-sm); }

.char-portrait {
    width: 100%;
    aspect-ratio: 3 / 4;
    overflow: hidden;
    border-radius: var(--radius);
    background: var(--bg-raised);
    border: 1px solid var(--border-mid);
    margin-bottom: var(--space-sm);
}
.char-portrait img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.char-portrait-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    color: var(--text-muted);
    font-size: 0.8rem;
    font-family: var(--font-ui);
}
.char-portrait-placeholder .icon { font-size: 3rem; opacity: 0.3; }

/* ----- Cards that lead with a thumbnail ----------------- */
/* Same idea as .char-card: opt out of .campaign-card's spine grid (there is no
   spine here) and stack the thumbnail above the text. Landscape, not 3/4 —
   the entity types using this (locations, shops) are generated landscape_4_3
   in image_owner_types(), so a portrait frame would crop the place out of the
   picture. It reads the pool's primary via the legacy image_path column. */
.entity-thumb-card { display: flex; flex-direction: column; gap: var(--space-sm); }
/* The head row brings its own bottom margin for the 48px .catalog-thumb layout
   it was built for; under a banner the flex gap already provides it. */
.entity-thumb-card .catalog-card-head { margin-bottom: 0; }
/* Not every one of these grids has a description — the location page's shop
   list doesn't — so there is nothing whose flex:1 absorbs the slack, and the
   meta lines end up ragged across a row. Where a .campaign-card-desc IS
   present it has already eaten the free space and this resolves to zero. */
.entity-thumb-card .campaign-card-meta { margin-top: auto; }

.entity-thumb {
    width: 100%;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-radius: var(--radius);
    background: var(--bg-raised);
    border: 1px solid var(--border-mid);
    margin-bottom: var(--space-sm);
}
.entity-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.entity-thumb-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
}
.entity-thumb-empty .icon { font-size: 2.5rem; opacity: 0.3; }

/* ----- NPC Status Badges -------------------------------- */
.status-badge {
    display: inline-block;
    flex-shrink: 0;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    font-family: var(--font-ui);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
    border: 1px solid transparent;
}
.status-alive    { background: rgba(45,106,79,0.18);  color: #6dbf8c; border-color: rgba(45,106,79,0.4); }
.status-friendly { background: rgba(58,125,90,0.20);  color: #7fd6a0; border-color: rgba(58,125,90,0.45); }
.status-neutral  { background: rgba(26,46,74,0.30);   color: #7ab4e8; border-color: rgba(26,46,74,0.6); }
.status-hostile  { background: rgba(122,31,46,0.22);  color: #e57373; border-color: rgba(122,31,46,0.45); }
.status-unknown  { background: var(--bg-card-alt);    color: var(--text-dim); border-color: var(--border-mid); }
.status-missing  { background: rgba(122,90,16,0.25);  color: #d4aa6d; border-color: rgba(122,90,16,0.5); }
.status-deceased { background: rgba(40,40,44,0.55);   color: #9a9a9a; border-color: rgba(90,90,90,0.5); }

/* ----- Party Roster (campaign home) --------------------- */
.party-roster {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-lg);
    padding: var(--space-lg);
}
.party-member {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-sm);
    text-decoration: none;
    color: var(--text);
    width: 72px;
    transition: transform var(--transition);
}
.party-member:hover { transform: translateY(-2px); color: var(--gold); }
.party-avatar {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    overflow: hidden;
    border: 2px solid var(--border-mid);
    background: var(--bg-raised);
    transition: border-color var(--transition);
}
.party-member:hover .party-avatar { border-color: var(--gold-dim); }
.party-avatar img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.party-avatar-placeholder {
    display: flex;
    width: 100%;
    height: 100%;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
}
.party-avatar-placeholder .icon { font-size: 1.6rem; opacity: 0.5; }
.party-member-name {
    font-size: 0.72rem;
    font-family: var(--font-ui);
    text-align: center;
    line-height: 1.2;
    max-width: 72px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ----- Character Profile (view) ------------------------- */
.char-profile {
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: var(--space-2xl);
    align-items: start;
}
.char-profile-portrait {
    border-radius: var(--radius-lg);
    overflow: hidden;
    border: 1px solid var(--border-mid);
    background: var(--bg-raised);
    position: sticky;
    top: calc(var(--header-h) + var(--campaign-bar-h) + var(--space-lg));
}
.char-profile-portrait img { width: 100%; display: block; }
.char-profile-body { min-width: 0; }
/* No portrait → body is the first (and only) child; span the full width
   instead of being squeezed into the narrow 220px portrait column. */
.char-profile-body:first-child { grid-column: 1 / -1; }

.card-private {
    border-color: rgba(201,162,39,0.2);
    background: rgba(201,162,39,0.04);
}
.card-private-label {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    font-family: var(--font-ui);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--gold-dim);
    margin-bottom: var(--space-md);
}

/* ----- GM Secret notes (polymorphic private info) ------- */
/* View-mode block: a muted, warded card that stands apart from public content. */
.secret-note {
    margin-top: var(--space-xl);
    border-color: rgba(201,162,39,0.32);
    background:
        linear-gradient(180deg, rgba(201,162,39,0.07), rgba(201,162,39,0.02)),
        repeating-linear-gradient(135deg, transparent 0 9px, rgba(201,162,39,0.035) 9px 10px);
}
.secret-note-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-bottom: var(--space-md);
}
.secret-note-label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    font-family: var(--font-ui);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--gold-dim);
}
.secret-note-label .icon { color: var(--gold); }
.secret-note-tag {
    font-family: var(--font-ui);
    font-size: 0.66rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bg);
    background: var(--gold);
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    white-space: nowrap;
}
.secret-note-foot {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-top: var(--space-md);
    padding-top: var(--space-md);
    border-top: 1px dashed rgba(201,162,39,0.25);
}
.secret-note-foot .icon { flex: none; }

/* Edit-form editor: the private rich text + per-player reveal checklist. */
.secret-editor {
    border: 1px solid rgba(201,162,39,0.25);
    border-radius: var(--radius);
    background: rgba(201,162,39,0.04);
    padding: var(--space-md) var(--space-md) var(--space-sm);
}
.secret-editor > label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    color: var(--gold-dim);
}
.secret-editor > label .icon { color: var(--gold); }
.secret-share { margin-top: var(--space-md); }
.secret-share-head {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-sm);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

/* ----- NPC core traits (the GM's roleplay card) --------- */
/* Read at the table mid-scene, so it is set as a reference card: label column,
   text column, nothing decorative competing with the five lines that matter.
   Warded like a secret note, but cooler — this one is never shared with anyone. */
.core-traits {
    margin-top: var(--space-xl);
    border-color: rgba(201,162,39,0.32);
    background: linear-gradient(180deg, rgba(201,162,39,0.06), rgba(201,162,39,0.015));
}
.core-traits-tag {
    font-family: var(--font-ui);
    font-size: 0.66rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--gold-dim);
    border: 1px solid rgba(201,162,39,0.32);
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    white-space: nowrap;
}
.core-traits-list { margin: 0; }
.core-trait {
    display: grid;
    grid-template-columns: 11rem 1fr;
    gap: var(--space-md);
    padding: var(--space-sm) 0;
    border-top: 1px dashed rgba(201,162,39,0.18);
}
.core-trait:first-child { border-top: 0; }
.core-trait dt {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    flex-wrap: wrap;
    font-family: var(--font-ui);
    font-size: 0.74rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--gold-dim);
    padding-top: 0.15rem;
}
.core-trait dd { margin: 0; color: var(--text); }
.core-trait-ai {
    font-size: 0.58rem;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0 0.35rem;
}
.core-traits-panel { margin-top: var(--space-lg); }
@media (max-width: 640px) {
    .core-trait { grid-template-columns: 1fr; gap: 0.2rem; }
}

/* Edit-form fields: one stacked textarea per registered trait. */
.core-traits-editor {
    border: 1px solid rgba(201,162,39,0.25);
    border-radius: var(--radius);
    background: rgba(201,162,39,0.04);
    padding: var(--space-md) var(--space-md) var(--space-sm);
}
.core-traits-editor > label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    color: var(--gold-dim);
}
.core-traits-editor > label .icon { color: var(--gold); }
.core-trait-field { margin-top: var(--space-md); }
.core-trait-field > label {
    font-family: var(--font-ui);
    font-size: 0.74rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}
.core-trait-field textarea { width: 100%; }

/* ----- Secret ENTITIES (whole-record visibility gate) --- */
/* Inline pill on list cards/rows the viewer can see but that are secret. */
.secret-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-family: var(--font-ui);
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--gold-dim);
    background: rgba(201,162,39,0.10);
    border: 1px solid rgba(201,162,39,0.32);
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    white-space: nowrap;
    vertical-align: middle;
}
.secret-chip .icon { width: 0.7em; height: 0.7em; color: var(--gold); }

/* View-page banner telling an allowed viewer this record is secret/special. */
.restrict-banner {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-lg);
    padding: 0.55rem 0.85rem;
    border: 1px solid rgba(201,162,39,0.32);
    border-left-width: 3px;
    border-radius: var(--radius);
    background: linear-gradient(180deg, rgba(201,162,39,0.08), rgba(201,162,39,0.02));
    font-family: var(--font-ui);
    font-size: 0.8rem;
    color: var(--gold-dim);
}
.restrict-banner .icon { flex: none; color: var(--gold); }

/* Edit-form toggle: the per-player allow-list collapses until "Secret" is on. */
.restrict-toggle-label {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    cursor: pointer;
    color: var(--gold-dim);
}
.restrict-toggle-label .icon { color: var(--gold); }
.restrict-body { margin-top: var(--space-sm); }
.restrict-body[hidden] { display: none; }
.restrict-details > summary {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    cursor: pointer;
    font-family: var(--font-ui);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--gold-dim);
    list-style: none;
}
.restrict-details > summary::-webkit-details-marker { display: none; }
.restrict-details > summary .icon { color: var(--gold); }

/* ----- Character Edit Layout ---------------------------- */
.char-edit-layout {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: var(--space-2xl);
    align-items: start;
}
.char-edit-portrait-col { display: flex; flex-direction: column; align-items: center; }

.portrait-upload-area {
    width: 100%;
    aspect-ratio: 3 / 4;
    border: 2px dashed var(--border-mid);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--bg-raised);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: border-color var(--transition);
}
.portrait-upload-area:hover { border-color: var(--gold-border); }
.portrait-upload-area img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.portrait-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-sm);
    color: var(--text-muted);
    font-size: 0.8rem;
    font-family: var(--font-ui);
    padding: var(--space-md);
    text-align: center;
}
.portrait-placeholder .icon { font-size: 2.5rem; opacity: 0.3; }

/* ----- Responsive --------------------------------------- */
@media (max-width: 640px) {
    .char-profile {
        grid-template-columns: 1fr;
    }
    .char-profile-portrait {
        position: static;
        max-width: 200px;
        margin: 0 auto;
    }
    .char-edit-layout {
        grid-template-columns: 1fr;
    }
    .char-edit-portrait-col {
        max-width: 220px;
        margin: 0 auto;
    }
}

/* ----- Campaign Cover Art ------------------------------- */
/* A campaign's image is a *cover*, not a masthead. It gets to be big exactly
   once — on the overview, the campaign's title page — and everywhere else it
   appears only as information (the dashboard shelf) or as material (a wash
   inside chrome that already exists). It never occupies a band of its own,
   which is what made the old strip impossible to place. */

/* 1. The wash. The bar is ~78px tall, so any picture put behind it lands as an
   unreadable horizontal slice. Blurring past recognition is the point: what
   survives is the artwork's colour and weight, which is the part that says
   "this is your campaign". Costs zero layout height. */
/* The campaign bar is deliberately NOT the surface for this. It carries small
   muted type edge to edge, so art behind it has to be crushed until it is
   invisible to stay legible — the original strip's problem, only quieter.
   The page margins are the empty surface: on any monitor wider than the
   1100px container there is dead space either side of every page, and cards
   are opaque, so the artwork shows through where nothing else lives. It rides
   on body::after, a fixed layer above the theme's own --wash and below
   .site-main (z-index 1). */
body.has-cover-wash::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: var(--cover-img);
    background-size: auto 125%;
    background-position: right -4% top -8%;
    background-repeat: no-repeat;
    opacity: 0.09;
    /* Fades to nothing before it reaches the column of text. No filter on this
       element, so the mask behaves predictably. */
    -webkit-mask-image: radial-gradient(120% 95% at 100% 0%, #000 0%, rgba(0,0,0,0.55) 42%, transparent 78%);
            mask-image: radial-gradient(120% 95% at 100% 0%, #000 0%, rgba(0,0,0,0.55) 42%, transparent 78%);
}

/* 2. The plate — the cover on the campaign overview, tipped in like a colour
   plate glued into a printed book: its own paper margin, its own shadow, set
   a degree off square. Straightens under the cursor. */
.page-header-cover {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-xl);
}
.campaign-plate {
    display: block;
    width: 176px;
    /* Weighted mount — deeper at the foot, the way a print is matted. The empty
       margin is the affordance; a "view full size" caption sat inside the
       artwork's own frame and read as UI litter. */
    padding: 8px 8px 22px;
    background: var(--parchment-dim);
    border-radius: 1px;
    box-shadow: 0 12px 28px rgba(0,0,0,0.6), 0 1px 0 rgba(255,255,255,0.12) inset;
    transform: rotate(-1deg);
    transition: transform 0.35s ease, box-shadow 0.35s ease;
    cursor: zoom-in;
}
.campaign-plate img {
    display: block;
    width: 100%;
    max-height: 226px;
    object-fit: cover;
    background: var(--bg);
}
.campaign-plate:hover,
.campaign-plate:focus-visible {
    transform: rotate(0deg) translateY(-3px);
    box-shadow: 0 18px 34px rgba(0,0,0,0.68), 0 1px 0 rgba(255,255,255,0.12) inset;
}
/* 3. The shelf. On the dashboard the cover is the fastest way to tell one
   campaign from another — the one place the image is information rather than
   atmosphere, so here it stays a picture. The slot is always rendered (blank
   campaigns get a stamped plate) because a thumbnail that came and went left
   the titles down the shelf ragged. */
.campaign-spine {
    position: relative;
    display: block;
    grid-row: 1 / -1;
    align-self: start;
    width: 100%;
    aspect-ratio: 3 / 4;
    border-radius: 2px;
    overflow: hidden;
    border: 1px solid var(--border-mid);
    box-shadow: 0 4px 14px rgba(0,0,0,0.55);
    transition: border-color var(--transition);
}
.campaign-spine img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.campaign-spine-blank {
    display: grid;
    place-items: center;
    background: var(--bg-card-alt);
}
/* The colour band an unillustrated module gets on its cover. */
.campaign-spine-blank::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--spine-accent);
    opacity: 0.85;
}
.campaign-spine-initials {
    font-family: var(--font-heading);
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    color: var(--spine-accent);
}
.campaign-card:hover .campaign-spine { border-color: var(--gold-border); }

@media (max-width: 640px) {
    .page-header-cover {
        grid-template-columns: auto minmax(0, 1fr);
    }
    .campaign-plate { width: 108px; padding: 5px 5px 14px; }
    .campaign-plate img { max-height: 148px; }
}
@media (prefers-reduced-motion: reduce) {
    .campaign-plate { transform: none; transition: none; }
    .campaign-plate:hover, .campaign-plate:focus-visible { transform: none; }
}

/* ----- Campaign Accent Overrides ------------------------ */
body.has-campaign .campaign-title {
    color: var(--campaign-accent);
}
body.has-campaign .cnav.active {
    color: var(--campaign-accent);
    background: var(--campaign-accent-faint);
}
body.has-campaign .page-header {
    border-bottom-color: var(--campaign-accent-border);
}

/* ----- Color Swatch Picker (campaign edit) -------------- */
.color-swatches {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
    margin-top: var(--space-sm);
}
.swatch-btn {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    padding: 0;
    position: relative;
    transition: transform var(--transition), box-shadow var(--transition);
    outline-offset: 3px;
}
.swatch-btn:hover { transform: scale(1.12); }
.swatch-btn.selected {
    box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--parchment);
}
.swatch-btn-auto {
    background: var(--bg-card-alt);
    border-color: var(--border-mid);
    font-family: var(--font-ui);
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    width: auto;
    border-radius: var(--radius);
    padding: 0 0.5rem;
    line-height: 26px;
    height: 30px;
}
.swatch-btn-auto.selected {
    color: var(--parchment);
    border-color: var(--parchment);
}
.swatch-custom-wrap {
    position: relative;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    overflow: hidden;
    cursor: pointer;
    border: 2px solid var(--border-mid);
    transition: border-color var(--transition), box-shadow var(--transition);
    flex-shrink: 0;
}
.swatch-custom-wrap.selected {
    box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--parchment);
}
.swatch-custom-wrap input[type="color"] {
    position: absolute;
    inset: -4px;
    width: calc(100% + 8px);
    height: calc(100% + 8px);
    border: none;
    padding: 0;
    cursor: pointer;
    opacity: 1;
    background: none;
}
.swatch-custom-wrap input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.swatch-custom-wrap input[type="color"]::-webkit-color-swatch { border: none; }
.swatch-hint {
    font-family: var(--font-ui);
    font-size: 0.72rem;
    color: var(--text-muted);
    margin-top: var(--space-xs);
}
.accent-preview {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    margin-top: var(--space-sm);
    font-family: var(--font-ui);
    font-size: 0.8rem;
    color: var(--text-dim);
}
.accent-preview-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* ----- Cover Art setting (campaign edit) ---------------- */
/* The cover preview is the shared entity-image carousel now — the campaign is a
   registered image owner, so it gets the same pool, set-primary and generate
   controls as an NPC portrait rather than a bespoke single-file preview.
   Constrained because the cover reads as a plate, not a hero: at the card's full
   width the one image dwarfs every control under it. Only the carousel is
   narrowed, so the generate panel below it keeps the full width. */
.cover-images .carousel { max-width: 280px; }
.cover-blank {
    width: 160px;
    aspect-ratio: 3 / 4;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    margin: 0 0 var(--space-md);
    border: 1px dashed var(--border-mid);
    border-radius: var(--radius);
    background: var(--bg-input);
    color: var(--text-muted);
    font-family: var(--font-ui);
    font-size: 0.72rem;
    text-align: center;
}

.cover-pick { margin-top: var(--space-lg); }
.cover-pick > summary {
    cursor: pointer;
    font-family: var(--font-ui);
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--gold-dim);
}
.cover-pick > summary:hover { color: var(--gold); }
.cover-pick-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
    gap: var(--space-sm);
    margin-top: var(--space-md);
    /* Long pools scroll rather than pushing the upload form off the screen. */
    max-height: 340px;
    overflow-y: auto;
}
.cover-pick-item {
    display: block;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-input);
    overflow: hidden;
    cursor: pointer;
    text-align: left;
    transition: border-color 0.15s, transform 0.15s;
}
.cover-pick-item:hover {
    border-color: var(--gold);
    transform: translateY(-2px);
}
.cover-pick-item img {
    display: block;
    width: 100%;
    aspect-ratio: 3 / 4;
    object-fit: cover;
}
.cover-pick-cap {
    display: block;
    padding: 4px 6px 5px;
    font-family: var(--font-ui);
    line-height: 1.25;
}
.cover-pick-title {
    display: block;
    font-size: 0.72rem;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cover-pick-kind {
    display: block;
    font-size: 0.62rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.cover-where-head {
    margin: var(--space-lg) 0 var(--space-xs);
    font-family: var(--font-ui);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.cover-where {
    margin: 0;
    padding-left: 1.1rem;
    font-size: 0.86rem;
    color: var(--text-dim);
}
.cover-where li { margin-bottom: 2px; }

/* An ordinary opt-in. Settings used to borrow the old red "remove banner"
   label, so every toggle on the page shouted in alert red uppercase — a switch
   that turns a feature *on* was styled like a delete. */
.check-row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    padding: var(--space-md);
    background: var(--bg-raised);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius);
    font-family: var(--font-ui);
    font-size: 0.85rem;
    font-weight: 600;
    text-transform: none;
    letter-spacing: 0;
    color: var(--text);
    cursor: pointer;
}
.check-row input[type="checkbox"] {
    width: auto;
    margin-top: 3px;
    accent-color: var(--campaign-accent);
}
.check-row .form-hint {
    text-transform: none;
    letter-spacing: 0;
    font-weight: 400;
}

@media (max-width: 768px) {
    .site-nav {
        display: none;
        position: absolute;
        top: var(--header-h);
        left: 0; right: 0;
        background: rgba(13,11,9,0.98);
        flex-direction: column;
        align-items: stretch;
        padding: var(--space-md);
        border-bottom: 1px solid var(--border-mid);
        gap: 4px;
    }
    .site-nav.open { display: flex; }
    .nav-toggle { display: flex; }
    .nav-user {
        flex-direction: column;
        align-items: flex-start;
        border-left: none;
        border-top: 1px solid var(--border-mid);
        padding-left: 0;
        padding-top: var(--space-sm);
        margin-top: var(--space-sm);
    }
    .campaign-nav .cnav { font-size: 0.72rem; padding: 0.25rem 0.5rem; }
    .features { grid-template-columns: 1fr; }
    .card-grid { grid-template-columns: 1fr; }
    h1 { font-size: 1.6rem; }
    .form-card { padding: var(--space-lg); }
    .stats-row { gap: var(--space-sm); }
}

/* =========================================================
   Comments, Discussion forum & roll-up
   ========================================================= */

/* ----- Monogram avatar (initials, deterministic hue) ---- */
.monogram {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.4rem;
    height: 2.4rem;
    flex: none;
    border-radius: 50%;
    font-family: var(--font-ui);
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: #fff;
    background: hsl(var(--mono-hue, 40) 38% 32%);
    border: 1px solid hsl(var(--mono-hue, 40) 40% 48% / 0.5);
    user-select: none;
}

/* ----- Section subheadings (discussion page) ------------ */
.section-subhead {
    font-family: var(--font-heading);
    color: var(--parchment);
    font-size: 1.15rem;
    margin: var(--space-2xl) 0 var(--space-md);
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}
.section-subhead .icon { color: var(--campaign-accent); }

/* ----- Comment thread ----------------------------------- */
.comment-thread { margin-top: var(--space-2xl); }
.comment-thread-head {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    margin-bottom: var(--space-lg);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--border-mid);
}
.comment-thread-head h2 { font-size: 1.3rem; color: var(--parchment); }
.comment-count { font-family: var(--font-ui); font-size: 0.8rem; color: var(--text-muted); }

.comment-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    margin-bottom: var(--space-xl);
}
.comment { display: flex; gap: var(--space-md); }
.comment-avatar { flex: none; }
.comment-main {
    flex: 1;
    min-width: 0;
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
    padding: var(--space-md) var(--space-lg);
}
.comment-head {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-bottom: var(--space-xs);
}
.comment-author { font-family: var(--font-ui); font-weight: 600; color: var(--parchment); font-size: 0.92rem; }
.comment-time { font-family: var(--font-ui); font-size: 0.75rem; color: var(--text-muted); }
.comment-body { font-size: 1rem; }
.comment-actions { display: flex; gap: var(--space-md); margin-top: var(--space-sm); }
.comment-action {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    font-family: var(--font-ui);
    font-size: 0.75rem;
    color: var(--text-muted);
    text-decoration: none;
    transition: color var(--transition);
}
.comment-action:hover { color: var(--gold); }
.comment-action-danger:hover { color: var(--red-text); }
.inline-form { display: inline; }
.comment-editing .comment-main { border-color: var(--gold-border); }
.comment-empty { color: var(--text-muted); font-style: italic; margin-bottom: var(--space-lg); }
.comment-locked {
    font-family: var(--font-ui);
    font-size: 0.85rem;
    color: var(--text-dim);
    padding: var(--space-md);
    background: var(--bg-card);
    border: 1px dashed var(--border-mid);
    border-radius: var(--radius);
}

/* ----- Comment post form (sits above the newest-first list) -- */
.comment-form { margin-bottom: var(--space-xl); padding-bottom: var(--space-lg); border-bottom: 1px solid var(--border-mid); }
.comment-form-row { display: flex; gap: var(--space-md); }
.comment-form-editor { flex: 1; min-width: 0; }

/* ----- Discussion thread (opening post) ----------------- */
.thread-op { display: flex; gap: var(--space-md); margin-bottom: var(--space-2xl); }
.thread-op-main { flex: 1; min-width: 0; }
.thread-op-body { margin-top: var(--space-sm); }

/* ----- Announcements ------------------------------------ */
.announcement-list { display: flex; flex-direction: column; gap: var(--space-md); }
.announcement {
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-left: 3px solid var(--campaign-accent);
    border-radius: var(--radius-lg);
    padding: var(--space-lg) var(--space-xl);
}
.announcement-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-md);
    margin-bottom: var(--space-sm);
}
.announcement-title {
    font-family: var(--font-heading);
    font-size: 1.15rem;
    color: var(--parchment);
    margin: 0 0 2px;
}
.announcement-meta { font-family: var(--font-ui); font-size: 0.75rem; color: var(--text-muted); }
.announcement-body { font-size: 1rem; }

/* ----- Activity feed ------------------------------------ */
.activity-list { padding: var(--space-sm) 0; }
.activity-item {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-sm) var(--space-lg);
    border-bottom: 1px solid var(--border-faint, var(--border-mid));
}
.activity-item:last-child { border-bottom: none; }
.activity-avatar { flex-shrink: 0; }
.activity-avatar .monogram { width: 1.9rem; height: 1.9rem; font-size: 0.72rem; }
.activity-text { flex: 1; min-width: 0; font-size: 0.95rem; line-height: 1.5; }
.activity-actor { font-weight: 600; color: var(--parchment); }
.activity-link {
    color: var(--gold-bright, var(--gold));
    text-decoration: none;
    white-space: nowrap;
}
.activity-link:hover { text-decoration: underline; }
.activity-link .icon { width: 0.85em; height: 0.85em; vertical-align: -1px; opacity: 0.8; }
.activity-time { flex-shrink: 0; white-space: nowrap; font-family: var(--font-ui); }

/* "Since you were last here" — the overview's catch-up card */
.since-visit { border-left: 3px solid var(--campaign-accent); }
.since-visit-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-md);
    flex-wrap: wrap;
}
.since-visit-chips {
    margin: var(--space-sm) 0 var(--space-md);
    font-family: var(--font-ui);
    font-size: 0.9rem;
    color: var(--parchment);
}
.since-visit-list { list-style: none; margin: 0; padding: 0; }
.since-visit-item {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 2px var(--space-sm);
    padding: var(--space-xs) 0;
    border-top: 1px solid var(--border-faint, var(--border-mid));
}
.since-visit-item .activity-link { white-space: normal; overflow-wrap: anywhere; }
.since-visit-item .activity-time { margin-left: auto; }
.since-visit-reply {
    font-family: var(--font-ui);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--campaign-accent);
    border: 1px solid currentColor;
    border-radius: 999px;
    padding: 0 6px;
}
.since-visit-more, .since-visit-foot { margin: var(--space-sm) 0 0; }

/* "N new" badge on dashboard campaign cards */
.new-badge {
    display: inline-flex;
    align-items: center;
    font-family: var(--font-ui);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: #1a1206;
    background: var(--gold, #c8a24a);
    border-radius: 999px;
    padding: 2px 8px;
    line-height: 1.4;
}

/* ----- Forum topic list --------------------------------- */
.thread-list { display: flex; flex-direction: column; gap: var(--space-sm); }
.thread-row {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-md) var(--space-lg);
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
    text-decoration: none;
    transition: border-color var(--transition), transform var(--transition);
}
.thread-row:hover { border-color: var(--campaign-accent-border); transform: translateX(2px); }
.thread-row-main { flex: 1; min-width: 0; }
.thread-row-title { font-family: var(--font-heading); font-size: 1.05rem; color: var(--parchment); }
.thread-row-meta { font-family: var(--font-ui); font-size: 0.78rem; color: var(--text-muted); margin-top: 2px; }
.thread-row-replies { flex: none; text-align: center; font-family: var(--font-ui); font-size: 0.72rem; color: var(--text-muted); }
.thread-row-replies b { display: block; font-size: 1.1rem; color: var(--parchment); }
.badge-pinned { background: var(--gold-faint); color: var(--gold); border: 1px solid var(--gold-border); }
.badge-locked { background: var(--bg-card-alt); color: var(--text-dim); border: 1px solid var(--border-mid); }

/* ----- Recent activity roll-up -------------------------- */
.activity-feed { display: flex; flex-direction: column; gap: var(--space-sm); }
.activity-item {
    display: flex;
    gap: var(--space-md);
    padding: var(--space-md);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    text-decoration: none;
    color: var(--text);
    transition: border-color var(--transition), background var(--transition);
}
.activity-item:hover { border-color: var(--campaign-accent-border); background: var(--bg-card); }
.activity-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.activity-head {
    font-family: var(--font-ui);
    font-size: 0.82rem;
    color: var(--text-dim);
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    flex-wrap: wrap;
}
.activity-author { color: var(--parchment); font-weight: 600; }
.activity-on { color: var(--text-muted); }
.activity-chip { display: inline-flex; align-items: center; gap: 4px; color: var(--gold); }
.activity-chip .icon { font-size: 0.95rem; }
.activity-type { color: var(--text-muted); }
.activity-snippet {
    color: var(--text-dim);
    font-size: 0.95rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.activity-time { font-family: var(--font-ui); font-size: 0.72rem; color: var(--text-muted); }

/* ----- Emoji picker ------------------------------------- */
.ql-emoji { color: var(--text-dim) !important; }
.ql-emoji:hover { color: var(--gold) !important; }
.emoji-picker {
    position: absolute;
    z-index: 1000;
    display: none;
    width: 280px;
    max-height: 220px;
    overflow-y: auto;
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: var(--space-sm);
}
.emoji-picker.open { display: block; }
.emoji-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; }
.emoji-btn {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1.25rem;
    line-height: 1;
    padding: 4px;
    border-radius: var(--radius);
    transition: background var(--transition);
}
.emoji-btn:hover { background: var(--gold-faint); }

/* =========================================================
   Sessions
   ========================================================= */

/* List page — session card */
.sess-card { transition: border-color var(--transition); }
.sess-card:hover { border-color: var(--campaign-accent, var(--gold-dim)); }
.sess-summary-preview {
    color: var(--text-dim);
    font-size: 0.95rem;
    line-height: 1.55;
    margin-bottom: var(--space-sm);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.sess-card-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    margin-top: var(--space-sm);
    padding-top: var(--space-sm);
    border-top: 1px solid var(--border);
}
.sess-meta-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-family: var(--font-ui);
    font-size: 0.8rem;
    color: var(--text-muted);
}
.sess-meta-pill .icon { font-size: 0.9rem; }

/* Detail form — top meta row */
.sess-meta-row {
    display: grid;
    grid-template-columns: 6rem 1fr 9rem;
    gap: var(--space-lg);
    margin-bottom: var(--space-lg);
}
@media (max-width: 640px) {
    .sess-meta-row { grid-template-columns: 1fr; }
}

/* Detail page — participants */
.session-participants {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
}
.session-char-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: 0.35rem 0.75rem 0.35rem 0.4rem;
    background: var(--bg-raised);
    border: 1px solid var(--border);
    border-radius: 999px;
    text-decoration: none;
    color: inherit;
    transition: border-color var(--transition), background var(--transition);
}
.session-char-chip:hover { border-color: var(--campaign-accent, var(--gold-dim)); background: var(--bg-card); }
.session-char-avatar {
    width: 1.8rem;
    height: 1.8rem;
    border-radius: 50%;
    object-fit: cover;
    object-position: top;
    flex: none;
}
.session-char-mono { flex: none; }
.session-char-mono .monogram { width: 1.8rem; height: 1.8rem; font-size: 0.7rem; }
.session-char-name { font-weight: 600; color: var(--parchment); }
.session-char-player { color: var(--text-muted); font-size: 0.8rem; font-family: var(--font-ui); }

/* Detail form — character checklist */
.sess-char-checklist {
    display: flex;
    flex-direction: column;
    gap: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
}
.sess-char-check {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 0.6rem var(--space-md);
    cursor: pointer;
    border-bottom: 1px solid var(--border);
    transition: background var(--transition);
}
.sess-char-check:last-child { border-bottom: none; }
.sess-char-check:hover { background: var(--bg-raised); }
.sess-char-check input[type="checkbox"] { width: 1rem; height: 1rem; flex: none; accent-color: var(--campaign-accent); }
.sess-char-check-name { font-weight: 600; color: var(--parchment); flex: 1; }
.sess-char-check-player { color: var(--text-muted); }

/* Link rows (NPC <-> Location) — checkbox + per-row relationship select */
.link-row {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 0.45rem var(--space-md);
    border-bottom: 1px solid var(--border);
    transition: background var(--transition);
}
.link-row:last-child { border-bottom: none; }
.link-row:hover { background: var(--bg-raised); }
.link-row-main { display: flex; align-items: center; gap: var(--space-sm); flex: 1; min-width: 0; cursor: pointer; }
.link-row-main input[type="checkbox"] { width: 1rem; height: 1rem; flex: none; accent-color: var(--campaign-accent); }
.link-row-role { flex: none; width: auto; min-width: 9rem; padding: 0.3rem 0.5rem; font-size: 0.85rem; }
.link-row-role:disabled { opacity: 0.4; }

/* Type-to-filter box injected above long checklists (main.js) */
.link-search { margin-bottom: var(--space-sm); }
.sess-char-checklist.is-searchable { max-height: 20rem; overflow-y: auto; }
.link-search-empty { padding: 0.6rem var(--space-md); color: var(--text-muted); font-style: italic; }

.rel-badge {
    display: inline-block;
    font-family: var(--font-ui);
    font-size: 0.66rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 2px 8px;
    border-radius: 20px;
    background: var(--campaign-accent-faint, var(--gold-faint));
    color: var(--campaign-accent);
    border: 1px solid var(--campaign-accent-border, var(--gold-border));
}

/* ── Admin: game-systems list ─────────────────────────────────────────────── */
.rule-system-list { display: flex; flex-direction: column; gap: var(--space-sm); }
.rule-system-row {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: var(--space-md);
    padding: var(--space-sm) var(--space-md);
    background: var(--bg-card-alt);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
}
.rule-system-row.is-hidden { opacity: 0.6; }
.rule-system-edit {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: var(--space-sm); flex: 1 1 420px; margin: 0;
}
.rule-system-edit input { margin: 0; }
.rule-system-edit .rs-sort { width: 64px; }
.rule-system-edit .rs-name { flex: 1 1 160px; min-width: 140px; }
.rule-system-edit .rs-link { flex: 2 1 220px; min-width: 160px; }
.rule-system-meta {
    display: flex; align-items: center; gap: var(--space-sm);
    flex-wrap: wrap; margin-left: auto;
}
.rule-system-meta form { margin: 0; }

/* ── Campaign meta chips (system / currency on overview) ──────────────────── */
.campaign-meta-chips { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.meta-chip {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.25rem 0.6rem;
    background: var(--bg-card-alt);
    border: 1px solid var(--border-mid);
    border-radius: 999px;
    font-family: var(--font-ui);
    font-size: 0.82rem;
    color: var(--text-dim);
}
.meta-chip .icon { color: var(--campaign-accent); }
.meta-chip strong { color: var(--parchment); font-weight: 600; }
.meta-chip a { color: var(--parchment); text-decoration: none; }
.meta-chip a:hover { text-decoration: underline; }

/* ===== Shops & Item Catalog ============================== */

/* Item-kind badge (Good / Service) — sibling of .status-badge */
.kind-badge {
    display: inline-block;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    font-family: var(--font-ui);
    font-size: 0.65rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
    border: 1px solid transparent;
    vertical-align: middle;
}
.kind-good    { background: var(--gold-faint);        color: var(--gold-bright); border-color: var(--gold-border); }
.kind-service { background: rgba(26,46,74,0.30);      color: #7ab4e8;            border-color: rgba(26,46,74,0.6); }

/* Price tag */
.price-tag {
    flex-shrink: 0;
    font-family: var(--font-ui);
    font-weight: 700;
    color: var(--gold-bright);
    white-space: nowrap;
}
.price-tag-lg { font-size: 1.25rem; }

/* Price-modifier chip on shop cards */
.price-mod-chip {
    flex-shrink: 0;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    font-family: var(--font-ui);
    font-size: 0.68rem;
    font-weight: 700;
    white-space: nowrap;
    border: 1px solid transparent;
}
.price-mod-chip.up   { background: rgba(122,31,46,0.22); color: var(--red-text);   border-color: rgba(122,31,46,0.45); }
.price-mod-chip.down { background: rgba(30,74,53,0.25);  color: var(--green-text); border-color: rgba(30,74,53,0.5); }

/* Catalog / shop cards with a leading thumbnail */
.catalog-card-head {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-sm);
}
.catalog-card-head > div { flex: 1; }
.catalog-thumb {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: var(--radius);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-input);
    border: 1px solid var(--border-mid);
}
.catalog-thumb.sm { width: 40px; height: 40px; }
.catalog-thumb img { width: 100%; height: 100%; object-fit: cover; }
.catalog-thumb-empty .icon { font-size: 1.4rem; color: var(--gold-dim); }

/* Storefront list */
.shop-table {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
}
.shop-cat-row {
    padding: var(--space-sm) var(--space-md);
    background: var(--bg-card-alt);
    border-top: 1px solid var(--border);
    font-family: var(--font-ui);
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-dim);
}
.shop-cat-row:first-child { border-top: none; }
.shop-item-row {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    flex-wrap: wrap;
    padding: var(--space-md);
    border-top: 1px solid var(--border);
    background: var(--bg-card);
}
.shop-item-row.is-out { opacity: 0.55; }
.shop-item-main {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex: 1;
    min-width: 220px;
    color: inherit;
    text-decoration: none;
}
.shop-item-main:hover .shop-item-name { color: var(--gold-bright); }
.shop-item-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.shop-item-name {
    font-weight: 600;
    color: var(--parchment, var(--text));
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
}
.shop-item-desc { font-size: 0.82rem; color: var(--text-dim); }
.shop-item-side {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    flex-shrink: 0;
}
.price-override-note .icon { font-size: 0.9rem; color: var(--gold-dim); }

/* Stock chip */
.stock-chip {
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-family: var(--font-ui);
    font-size: 0.7rem;
    font-weight: 600;
    white-space: nowrap;
    border: 1px solid transparent;
}
.stock-chip.in  { background: rgba(30,74,53,0.22);  color: var(--green-text); border-color: rgba(30,74,53,0.45); }
.stock-chip.out { background: var(--bg-card-alt);   color: var(--text-muted); border-color: var(--border-mid); }

/* GM inventory controls on each row */
.shop-item-gm {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
    width: 100%;
    padding-top: var(--space-sm);
    border-top: 1px dashed var(--border-mid);
}
.rotate-flag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-family: var(--font-ui);
    font-size: 0.72rem;
    color: var(--text-dim);
    margin-right: auto;
}
.rotate-flag.fixed { color: var(--text-muted); }
.rotate-flag .icon { font-size: 0.9rem; color: var(--gold-dim); }

/* "from <pool>" tag on pool-generated inventory rows */
.pool-tag {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-family: var(--font-ui);
    font-size: 0.68rem;
    color: var(--campaign-accent, var(--gold-dim));
    border: 1px solid var(--border-mid);
    border-radius: 999px;
    padding: 1px 7px;
    margin-left: 6px;
    white-space: nowrap;
}

/* Inline checkbox + label row (e.g. the auto-restock toggle on the shop form) */
.check-inline {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    cursor: pointer;
    font-weight: 400;
    text-transform: none;
}
.check-inline input { margin-top: 3px; flex: none; }

/* Auto-stocking pools manager */
.pool-list { display: flex; flex-direction: column; gap: var(--space-sm); margin-bottom: var(--space-lg); }
.pool-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    flex-wrap: wrap;
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
}
.pool-row.is-inactive { opacity: 0.55; }
.pool-row-summary { font-family: var(--font-ui); font-size: 0.8rem; color: var(--text-dim); }
.pool-row-summary strong { color: var(--text); font-weight: 600; }
.pool-edit-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-md);
}

/* Inline inventory edit form */
.shop-inv-edit { width: 100%; margin-top: var(--space-sm); }
.shop-inv-edit-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-md);
}
.shop-inv-edit-grid .form-group { margin: 0; }

/* ----- List toolbar: category browser + layout toggle --- */
.list-toolbar {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-md);
    flex-wrap: wrap;
    margin-bottom: var(--space-lg);
}
.cat-filter {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs, 0.4rem);
    flex: 1;
    min-width: 0;
}
.cat-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.7rem;
    border-radius: 999px;
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    color: var(--text-dim);
    font-family: var(--font-ui);
    font-size: 0.82rem;
    text-decoration: none;
    white-space: nowrap;
    transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.cat-pill:hover { color: var(--parchment); border-color: var(--gold-border); }
.cat-pill.active {
    background: var(--gold-faint);
    border-color: var(--gold-border);
    color: var(--gold-bright);
    font-weight: 600;
}
.cat-count {
    font-size: 0.7rem;
    color: var(--text-muted);
    background: var(--bg-input);
    border-radius: 999px;
    padding: 0.05rem 0.4rem;
}
.cat-pill.active .cat-count { color: var(--gold-bright); background: var(--gold-faint); }

/* ----- Tab bar (AI studio & friends) --------------------- */
.tab-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.15rem;
    border-bottom: 1px solid var(--border-mid);
    margin-bottom: var(--space-lg);
}
.tab-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.55rem 1rem;
    margin-bottom: -1px;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--text-dim);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.tab-btn:hover { color: var(--text); }
.tab-btn.active { color: var(--gold-bright); border-bottom-color: var(--gold); }
.tab-count {
    font-size: 0.78rem;
    color: var(--text-dim);
    background: var(--bg-input);
    border-radius: 999px;
    padding: 0.05rem 0.5rem;
}
.tab-btn.active .tab-count { color: var(--gold-bright); background: var(--gold-faint); }
.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* Segmented layout toggle (table / grid) */
.view-toggle {
    display: inline-flex;
    flex-shrink: 0;
    border: 1px solid var(--border-mid);
    border-radius: var(--radius);
    overflow: hidden;
}
.view-toggle-right { margin-left: auto; margin-bottom: var(--space-md); }
.view-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.35rem 0.6rem;
    color: var(--text-dim);
    background: var(--bg-card);
    text-decoration: none;
    border: none;
}
.view-btn + .view-btn { border-left: 1px solid var(--border-mid); }
.view-btn:hover { color: var(--parchment); }
.view-btn.active { background: var(--gold-faint); color: var(--gold-bright); }
.view-btn .icon { font-size: 1.05rem; }

/* ----- Tight data tables (catalog + storefront) --------- */
.data-table td, .data-table th { padding: 0.55rem 0.85rem; }
.data-table .num { text-align: right; white-space: nowrap; }
.data-table th.num { text-align: right; }
.data-table tr.row-link { cursor: pointer; }
.data-table .cell-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    color: inherit;
    text-decoration: none;
    min-width: 0;
}
.data-table tr.row-link:hover .cell-item-name { color: var(--gold-bright); }
.data-table .cell-item-name { font-weight: 600; }
.data-table tr.is-out { opacity: 0.55; }
.data-table .actions {
    display: flex;
    gap: var(--space-xs, 0.4rem);
    align-items: center;
    justify-content: flex-end;
    white-space: nowrap;
}
.data-table .actions .inline-form { display: inline; }
/* Category group header row inside a data table */
.data-table tr.cat-row td {
    background: var(--bg-card-alt);
    font-family: var(--font-ui);
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-dim);
    padding: 0.4rem 0.85rem;
}
.data-table tr.cat-row:hover td { background: var(--bg-card-alt); }
.data-table tr.inv-edit-row:hover td { background: transparent; }
.data-table tr.inv-edit-row td { padding: 0; background: transparent; }
.data-table tr.inv-edit-row .shop-inv-edit { margin: 0; border-radius: 0; }

/* Extra-small thumbnail for dense table rows */
.catalog-thumb.xs { width: 28px; height: 28px; border-radius: var(--radius-sm, 4px); }
.catalog-thumb.xs .icon { font-size: 0.95rem; }

/* ----- Rumors ------------------------------------------------ */
/* Rarity badges — siblings of .status-badge */
.rarity-common    { background: var(--bg-card-alt);    color: var(--text-dim); border-color: var(--border-mid); }
.rarity-uncommon  { background: rgba(45,106,79,0.18);  color: #6dbf8c; border-color: rgba(45,106,79,0.4); }
.rarity-rare      { background: rgba(26,46,74,0.30);   color: #7ab4e8; border-color: rgba(26,46,74,0.6); }
.rarity-legendary { background: rgba(122,90,16,0.25);  color: #d4aa6d; border-color: rgba(122,90,16,0.5); }
.rarity-mythic    { background: rgba(99,46,122,0.28);  color: #c79be0; border-color: rgba(99,46,122,0.55); }

/* Quest kind chips — siblings of .status-badge */
.qkind-main     { background: rgba(122,90,16,0.25);  color: #d4aa6d; border-color: rgba(122,90,16,0.5); }
.qkind-side     { background: rgba(26,46,74,0.30);   color: #7ab4e8; border-color: rgba(26,46,74,0.6); }
.qkind-personal { background: rgba(58,125,90,0.20);  color: #7fd6a0; border-color: rgba(58,125,90,0.45); }
.qkind-faction  { background: rgba(99,46,122,0.28);  color: #c79be0; border-color: rgba(99,46,122,0.55); }
.qkind-mystery  { background: rgba(72,52,102,0.30);  color: #b7a6e6; border-color: rgba(72,52,102,0.6); }

/* Quest status badges — siblings of .status-badge */
.qstatus-active    { background: rgba(45,106,79,0.20);  color: #7fd6a0; border-color: rgba(45,106,79,0.45); }
.qstatus-rumored   { background: rgba(26,46,74,0.30);   color: #7ab4e8; border-color: rgba(26,46,74,0.6); }
.qstatus-stalled   { background: rgba(122,90,16,0.25);  color: #d4aa6d; border-color: rgba(122,90,16,0.5); }
.qstatus-completed { background: rgba(45,106,79,0.30);  color: #8fe0ac; border-color: rgba(45,106,79,0.6); }
.qstatus-failed    { background: rgba(122,31,46,0.22);  color: #e57373; border-color: rgba(122,31,46,0.45); }
.qstatus-abandoned { background: rgba(40,40,44,0.55);   color: #9a9a9a; border-color: rgba(90,90,90,0.5); }

/* Quest meta definition list (giver / location / sessions / reward) */
.quest-meta { display: grid; gap: var(--space-sm); margin: 0; }
.quest-meta > div { display: flex; gap: var(--space-md); align-items: baseline; }
.quest-meta dt {
    flex: 0 0 8rem;
    color: var(--text-dim);
    font-family: var(--font-ui, inherit);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.quest-meta dd { margin: 0; }

/* Quest beats timeline — a vertical thread of dated developments */
.quest-beats { list-style: none; margin: 0; padding: 0; position: relative; }
.quest-beats::before {
    content: "";
    position: absolute;
    left: 0.4rem;
    top: 0.3rem;
    bottom: 0.3rem;
    width: 2px;
    background: var(--border);
}
.quest-beats .beat {
    position: relative;
    padding: 0 0 var(--space-lg) 1.6rem;
}
.quest-beats .beat::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.35rem;
    width: 0.85rem;
    height: 0.85rem;
    border-radius: 50%;
    background: var(--bg-card);
    border: 2px solid var(--gold, var(--campaign-accent, #d4aa6d));
}
.quest-beats .beat-head { margin-bottom: 0.35rem; }
.quest-beats .beat-body { margin: 0; }

/* Full-viewport overlay host — never blocks interaction */
#rumor-stage {
    position: fixed;
    inset: 0;
    z-index: 80;
    pointer-events: none;
    overflow: hidden;
}

.rumor-blurb {
    /* Per-blurb knobs, randomised in rumors.js (safe fallbacks here). */
    --glow: rgba(201,162,39,0.45);
    --blur: 0px;
    --peak: 1;
    --rot-start: 0deg;
    --rot-end: 0deg;
    --dx: 0vw;
    --dy: -60px;

    position: absolute;
    max-width: min(360px, 70vw);
    padding: 0.6rem 0.9rem;
    font-family: var(--font-display, Georgia, serif);
    font-size: 1.05rem;
    font-style: italic;
    line-height: 1.45;
    color: var(--gold-bright);
    text-shadow: 0 0 8px var(--glow), 0 2px 10px rgba(0,0,0,0.8);
    opacity: 0;
    will-change: transform, opacity, filter;
    filter: blur(var(--blur)) drop-shadow(0 0 7px var(--glow));
}

/* Gradient-filled variant: paint the text with the shimmering background. */
.rumor-blurb.rumor-grad {
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    text-shadow: none;
}

/* Drift variants — all fade in, travel slowly, then fade out. The transform
   endpoints come from the --dx/--dy/--rot-* custom properties set per blurb. */
@keyframes drift-up {
    0%   { opacity: 0; transform: translate(0, 18px) rotate(var(--rot-start)); }
    12%  { opacity: var(--peak); }
    85%  { opacity: var(--peak); }
    100% { opacity: 0; transform: translate(var(--dx), var(--dy)) rotate(var(--rot-end)); }
}
@keyframes drift-rise-left {
    0%   { opacity: 0; transform: translate(24px, 16px) rotate(var(--rot-start)); }
    14%  { opacity: var(--peak); }
    82%  { opacity: var(--peak); }
    100% { opacity: 0; transform: translate(calc(var(--dx) - 8vw), var(--dy)) rotate(var(--rot-end)); }
}
@keyframes drift-rise-right {
    0%   { opacity: 0; transform: translate(-24px, 16px) rotate(var(--rot-start)); }
    14%  { opacity: var(--peak); }
    82%  { opacity: var(--peak); }
    100% { opacity: 0; transform: translate(calc(var(--dx) + 8vw), var(--dy)) rotate(var(--rot-end)); }
}
@keyframes drift-sway {
    0%   { opacity: 0; transform: translate(0, 14px) rotate(var(--rot-start)); }
    15%  { opacity: var(--peak); }
    45%  { transform: translate(calc(var(--dx) * 0.6 + 3vw), calc(var(--dy) * 0.45)) rotate(var(--rot-end)); }
    80%  { opacity: var(--peak); transform: translate(calc(var(--dx) - 3vw), calc(var(--dy) * 0.8)) rotate(var(--rot-start)); }
    100% { opacity: 0; transform: translate(var(--dx), var(--dy)) rotate(var(--rot-end)); }
}

/* Slow breathing pulse layered on top of the drift — modulates glow + softness
   without fighting the drift's opacity envelope (this rides on filter only). */
@keyframes rumor-pulse {
    0%, 100% { filter: blur(var(--blur)) drop-shadow(0 0 6px var(--glow)) brightness(0.92); }
    50%      { filter: blur(calc(var(--blur) + 1.6px)) drop-shadow(0 0 16px var(--glow)) brightness(1.3); }
}

@media (prefers-reduced-motion: reduce) {
    .rumor-blurb { animation: none !important; opacity: var(--peak); filter: drop-shadow(0 0 7px var(--glow)); }
}

/* ----- Theme picker (campaign create / settings) ---------
   Every card is painted and set in the theme it offers, so the choice is made
   by looking at the thing rather than reading its name. Colours and the title
   face arrive as inline --t-* vars straight from campaign_themes(). */
.theme-picker {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
    gap: var(--space-sm);
    margin-top: var(--space-sm);
}
.theme-option {
    position: relative;
    display: block;
    cursor: pointer;
    /* The card is a <label>, so the uppercase form-label styling would other-
       wise shout through every theme name and blurb. */
    text-transform: none;
    letter-spacing: normal;
    font-weight: 400;
    margin-bottom: 0;
    background: var(--bg-input);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
    overflow: hidden;
    transition: transform var(--transition), border-color var(--transition), box-shadow var(--transition);
}
.theme-option:hover { transform: translateY(-2px); border-color: var(--t-accent); }
.theme-option input { position: absolute; opacity: 0; pointer-events: none; }
.theme-option:focus-within { outline: 2px solid var(--parchment); outline-offset: 2px; }

/* A campaign page in miniature: title rule over a content panel. */
.theme-preview {
    display: block;
    height: 62px;
    padding: 11px 12px;
    background: var(--t-paper);
    border-bottom: 1px solid var(--border);
}
.tp-bar  { display: block; width: 46%; height: 6px; border-radius: 1px; background: var(--t-accent); }
.tp-body { display: block; margin-top: 9px; padding: 6px 7px; border-radius: 2px; background: var(--t-panel); }
.tp-line { display: block; height: 3px; border-radius: 1px; background: var(--t-accent); opacity: 0.42; }
.tp-line + .tp-line { margin-top: 4px; width: 62%; opacity: 0.2; }

.theme-name {
    display: block;
    padding: 9px 12px 0;
    font-family: var(--t-font);
    font-size: 1rem;
    line-height: 1.2;
    color: var(--parchment);
}
.theme-blurb {
    display: block;
    padding: 3px 12px 11px;
    font-family: var(--font-ui);
    font-size: 0.7rem;
    line-height: 1.45;
    color: var(--text-muted);
}
.theme-option input:checked ~ .theme-name { color: var(--t-accent); }
.theme-option:has(input:checked) {
    border-color: var(--t-accent);
    box-shadow: 0 0 0 1px var(--t-accent), var(--shadow);
}
@media (prefers-reduced-motion: reduce) {
    .theme-option, .theme-option:hover { transform: none; transition: none; }
}

/* ===== Per-location palettes (scoped to content area only) ===== */
.site-main[class*="loc-pal-"] { background: var(--bg); color: var(--text); }

.site-main.loc-pal-haven {
    --bg:#1a120b; --bg-raised:#1f1610; --bg-card:#2a1f15; --bg-card-alt:#31261a; --bg-input:#241a12;
    --text:#f1e4cd; --text-dim:#c4ad8a; --text-muted:#937c5e; --border:#3a2c1c; --border-mid:#48381f;
    --campaign-accent:#e8964a; --campaign-accent-faint:rgba(232,150,74,.14);
    --campaign-accent-border:rgba(232,150,74,.34); --campaign-accent-dim:#a5612b;
    --gold:#e8964a; --gold-bright:#f3ad68; --gold-dim:#a5612b;
    --gold-faint:rgba(232,150,74,.14); --gold-border:rgba(232,150,74,.34);
}
.site-main.loc-pal-voidship {
    --bg:#090d13; --bg-raised:#0c1119; --bg-card:#121a24; --bg-card-alt:#16202c; --bg-input:#0f161e;
    --text:#cfdae6; --text-dim:#8ba0b4; --text-muted:#5d7186; --border:#1d2c3a; --border-mid:#274055;
    --campaign-accent:#46c8d6; --campaign-accent-faint:rgba(70,200,214,.12);
    --campaign-accent-border:rgba(70,200,214,.32); --campaign-accent-dim:#2c8f9a;
    --gold:#46c8d6; --gold-bright:#6fdce8; --gold-dim:#2c8f9a;
    --gold-faint:rgba(70,200,214,.12); --gold-border:rgba(70,200,214,.32);
}
.site-main.loc-pal-wilds {
    --bg:#0a0f0a; --bg-raised:#0d130d; --bg-card:#141d14; --bg-card-alt:#19241a; --bg-input:#101810;
    --text:#d6e0c9; --text-dim:#9bab86; --text-muted:#6c7c58; --border:#22301f; --border-mid:#2f4129;
    --campaign-accent:#73ab4c; --campaign-accent-faint:rgba(115,171,76,.12);
    --campaign-accent-border:rgba(115,171,76,.30); --campaign-accent-dim:#4f7a32;
    --gold:#73ab4c; --gold-bright:#8fc766; --gold-dim:#4f7a32;
    --gold-faint:rgba(115,171,76,.12); --gold-border:rgba(115,171,76,.30);
}
.site-main.loc-pal-arcane {
    --bg:#0e0a14; --bg-raised:#120d1a; --bg-card:#1a1327; --bg-card-alt:#1f1730; --bg-input:#150f1f;
    --text:#ded2ee; --text-dim:#a896c4; --text-muted:#766289; --border:#2a1f3c; --border-mid:#392a52;
    --campaign-accent:#a97ce8; --campaign-accent-faint:rgba(169,124,232,.14);
    --campaign-accent-border:rgba(169,124,232,.34); --campaign-accent-dim:#7d54b8;
    --gold:#a97ce8; --gold-bright:#c29ff2; --gold-dim:#7d54b8;
    --gold-faint:rgba(169,124,232,.14); --gold-border:rgba(169,124,232,.34);
}

/* ============================================================================
   Interactive maps
   ========================================================================== */
.map-card-thumb {
    width: 100%;
    aspect-ratio: 16 / 9;
    background-size: cover;
    background-position: center;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    margin-bottom: 0.6rem;
}

.map-stage {
    position: relative;
    border: 1px solid var(--gold-border);
    border-radius: var(--radius-lg);
    background: var(--bg-card);
}
/* The viewport clips the zoomed/panned canvas. */
.map-viewport {
    position: relative;
    overflow: hidden;
    border-radius: var(--radius-lg);
    cursor: grab;
    touch-action: none;          /* pan/zoom are handled in JS */
}
.map-viewport.panning { cursor: grabbing; }
.map-stage.is-editing .map-viewport { cursor: crosshair; }
.map-stage.is-editing .map-viewport.panning { cursor: grabbing; }
.map-canvas {
    position: relative;
    display: block;
    width: 100%;
    line-height: 0;
    transform-origin: 0 0;
    will-change: transform;
}
.map-image {
    display: block;
    width: 100%;
    height: auto;
    user-select: none;
    -webkit-user-drag: none;
}
.map-markers { position: absolute; inset: 0; }
.map-edit-hint { margin-bottom: 0.75rem; }

/* Zoom controls (top-right overlay). */
.map-zoom-controls {
    position: absolute;
    top: 8px;
    right: 8px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    z-index: 20;
}
.map-zoom-btn {
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.15rem;
    line-height: 1;
    background: rgba(20, 17, 11, 0.85);
    color: var(--gold);
    border: 1px solid var(--gold-border);
    border-radius: var(--radius);
    cursor: pointer;
}
.map-zoom-btn:hover { background: var(--gold-faint); color: var(--gold-bright); }

/* A marker is anchored by its bottom-centre tip at (x%, y%). */
.map-marker {
    position: absolute;
    transform: translate(-50%, -100%);
    width: 30px;
    height: 30px;
    color: var(--mk-color, var(--gold));
    cursor: pointer;
    z-index: 1;
}
/* Pin sizes (medium is the 30px baseline above). */
.map-marker.mk-sz-small { width: 20px; height: 20px; }
.map-marker.mk-sz-large { width: 44px; height: 44px; }
.map-marker:hover,
.map-marker:focus-visible { z-index: 5; outline: none; }
.map-stage.is-editing .map-marker { cursor: grab; }
.map-stage.is-editing .map-marker:active { cursor: grabbing; }

/* Party token: a pulsing ring marks it as the movable party piece, and it
   shows a grab cursor for everyone (players can drag it, not just the GM). */
.map-marker.mk-token { cursor: grab; z-index: 6; }
.map-marker.mk-token:active { cursor: grabbing; }
.map-marker.mk-token .map-pin { position: relative; z-index: 1; }
.map-marker.mk-token::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 168%;
    aspect-ratio: 1;
    transform: translate(-50%, -52%);
    border-radius: 50%;
    border: 2px solid var(--mk-color, var(--gold));
    box-shadow: 0 0 8px var(--mk-color, var(--gold));
    opacity: 0.55;
    pointer-events: none;
    animation: mk-token-ring 2.4s ease-in-out infinite;
}
@keyframes mk-token-ring {
    0%, 100% { transform: translate(-50%, -52%) scale(1);    opacity: 0.45; }
    50%      { transform: translate(-50%, -52%) scale(1.12); opacity: 0.75; }
}

.map-pin { display: block; width: 100%; height: 100%; }
.map-pin-svg {
    width: 100%;
    height: 100%;
    filter: drop-shadow(0 1px 2px rgba(0,0,0,0.7));
    transition: transform var(--transition);
}
.map-marker:hover .map-pin-svg { transform: scale(1.18); }

/* GM-only secret markers: dashed ring so the GM can tell them apart. */
.mk-secret .map-pin-svg {
    outline: 1px dashed rgba(255,255,255,0.55);
    outline-offset: 2px;
    border-radius: 50%;
    opacity: 0.92;
}

/* Hover tooltip. */
.map-marker-tip {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    min-width: 90px;
    max-width: 240px;
    padding: 0.5rem 0.65rem;
    background: #14110b;
    border: 1px solid var(--gold-border);
    border-radius: var(--radius);
    box-shadow: 0 6px 18px rgba(0,0,0,0.55);
    color: var(--text);
    font-size: 0.82rem;
    line-height: 1.35;
    text-align: left;
    white-space: normal;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--transition);
    z-index: 10;
}
/* Markers near the top edge flip their tooltip to below the pin. */
.map-marker.tip-below .map-marker-tip {
    bottom: auto;
    top: calc(100% + 6px);
}
.map-marker:hover .map-marker-tip,
.map-marker:focus-visible .map-marker-tip { opacity: 1; visibility: visible; }
.mk-tip-title { display: block; font-weight: 600; color: var(--gold-bright); }
.mk-tip-body  { display: block; margin-top: 0.2rem; color: var(--text); }
.mk-tip-link  { display: block; margin-top: 0.3rem; font-size: 0.76rem; color: var(--gold); }

/* Marker editor panel. */
.marker-panel {
    margin-top: 1rem;
    max-width: 560px;
    padding: 1rem 1.25rem;
    background: var(--bg-card);
    border: 1px solid var(--gold-border);
    border-radius: var(--radius-lg);
}
.marker-panel .checkbox-row { display: flex; gap: 0.5rem; align-items: flex-start; margin-top: 0.5rem; }

/* --- Marker effects -------------------------------------------------------- */
/* Glowing: soft pulsing halo. */
.mk-fx-glow .map-pin-svg {
    filter: drop-shadow(0 0 4px var(--mk-color, var(--gold))) drop-shadow(0 0 9px var(--mk-color, var(--gold)));
    animation: mk-glow 2.4s ease-in-out infinite;
}
@keyframes mk-glow {
    0%, 100% { filter: drop-shadow(0 0 3px var(--mk-color, var(--gold))) drop-shadow(0 0 6px var(--mk-color, var(--gold))); }
    50%      { filter: drop-shadow(0 0 6px var(--mk-color, var(--gold))) drop-shadow(0 0 14px var(--mk-color, var(--gold))); }
}

/* Pulsing: scale heartbeat. */
.mk-fx-pulse .map-pin-svg { animation: mk-pulse 1.6s ease-in-out infinite; transform-origin: bottom center; }
@keyframes mk-pulse {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.22); }
}

/* On fire: warm flicker glow + a flame glyph licking up from the pin. */
.mk-fx-fire .map-pin-svg {
    filter: drop-shadow(0 0 5px #ff8a2a) drop-shadow(0 -2px 8px #ff5a1e);
    animation: mk-fire 0.45s ease-in-out infinite alternate;
}
.mk-fx-fire::before {
    content: "";
    position: absolute;
    left: 50%; top: -8px;
    width: 14px; height: 18px;
    transform: translateX(-50%);
    background: radial-gradient(ellipse at 50% 80%, rgba(255,180,60,0.9), rgba(255,90,20,0.55) 55%, transparent 75%);
    border-radius: 50% 50% 50% 50% / 70% 70% 40% 40%;
    filter: blur(1px);
    animation: mk-flame 0.5s ease-in-out infinite alternate;
    pointer-events: none;
}
@keyframes mk-fire  { from { filter: drop-shadow(0 0 4px #ff8a2a) drop-shadow(0 -2px 6px #ff5a1e); }
                      to   { filter: drop-shadow(0 0 7px #ffb43c) drop-shadow(0 -3px 11px #ff5a1e); } }
@keyframes mk-flame { from { transform: translateX(-50%) scaleY(0.9) translateY(1px); opacity: 0.8; }
                      to   { transform: translateX(-50%) scaleY(1.15) translateY(-2px); opacity: 1; } }

/* Frosted: cool steady glow with a frozen blue cast. */
.mk-fx-frost .map-pin-svg {
    filter: drop-shadow(0 0 4px #9fd9ff) drop-shadow(0 0 8px #6fb8e8);
    animation: mk-frost 3s ease-in-out infinite;
}
@keyframes mk-frost {
    0%, 100% { filter: drop-shadow(0 0 3px #9fd9ff) drop-shadow(0 0 6px #6fb8e8); }
    50%      { filter: drop-shadow(0 0 6px #cfeeff) drop-shadow(0 0 12px #6fb8e8); }
}

/* Hallowed: gentle golden-white radiance. */
.mk-fx-holy .map-pin-svg {
    filter: drop-shadow(0 0 5px #fff4c2) drop-shadow(0 0 11px #f5d97a);
    animation: mk-holy 3.4s ease-in-out infinite;
}
@keyframes mk-holy {
    0%, 100% { filter: drop-shadow(0 0 4px #fff4c2) drop-shadow(0 0 8px #f5d97a); }
    50%      { filter: drop-shadow(0 0 8px #fffbe8) drop-shadow(0 0 16px #f5d97a); }
}

@media (prefers-reduced-motion: reduce) {
    .mk-fx-glow .map-pin-svg, .mk-fx-pulse .map-pin-svg, .mk-fx-fire .map-pin-svg,
    .mk-fx-frost .map-pin-svg, .mk-fx-holy .map-pin-svg { animation: none; }
    .mk-fx-fire::before { animation: none; }
    .map-marker.mk-token::after { animation: none; }
}

/* ─── Shop Stock Log ────────────────────────────────────────────────────────── */

/* Shop filter chips */
.filter-chip {
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: 12px;
    border: 1px solid var(--border-mid);
    background: var(--bg-card);
    color: var(--text-dim);
    font-size: 0.82rem;
    text-decoration: none;
    white-space: nowrap;
    transition: border-color 0.15s, color 0.15s;
}
.filter-chip:hover { border-color: var(--gold-dim); color: var(--text); }
.filter-chip.active { border-color: var(--gold); color: var(--gold); background: rgba(212,163,70,0.10); }

/* Date-group label */
.log-date-group { margin-bottom: var(--space-lg); }
.log-date-label {
    padding: var(--space-xs) 0 var(--space-xs);
    border-bottom: 1px solid var(--border-mid);
    margin-bottom: var(--space-sm);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-size: 0.78rem;
}

/* Individual run card (uses <details> for native expand/collapse) */
.restock-run-card {
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
    margin-bottom: var(--space-xs);
    overflow: hidden;
}
.restock-run-card[open] { border-color: var(--gold-dim); }
.restock-run-summary {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    cursor: pointer;
    list-style: none;
    flex-wrap: wrap;
    user-select: none;
}
.restock-run-summary::-webkit-details-marker { display: none; }
.restock-run-summary::before {
    content: '▸';
    color: var(--text-dim);
    font-size: 0.75rem;
    flex-shrink: 0;
    transition: transform 0.15s;
}
.restock-run-card[open] .restock-run-summary::before { transform: rotate(90deg); }
.restock-run-shop { font-weight: 600; color: var(--text); }
.restock-run-meta { display: flex; align-items: center; gap: 4px; }
.restock-run-counts { display: flex; align-items: center; gap: var(--space-xs); flex-wrap: wrap; margin-left: auto; }

/* Summary count chips */
.stock-count-chip {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 0.78rem;
    border: 1px solid transparent;
    white-space: nowrap;
}
.stock-count-chip.restocked { background: rgba(30,74,53,0.22);  color: var(--green-text); border-color: rgba(30,74,53,0.45); }
.stock-count-chip.sold      { background: rgba(122,31,46,0.22); color: var(--red-text);   border-color: rgba(122,31,46,0.40); }
.stock-count-chip.added     { background: rgba(212,163,70,0.15); color: var(--gold);  border-color: rgba(212,163,70,0.35); }
.stock-count-chip.retired   { background: var(--bg-card-alt);   color: var(--text-muted); border-color: var(--border-mid); }

/* Per-item list inside an expanded run */
.restock-item-list {
    list-style: none;
    margin: 0;
    padding: 0 var(--space-md) var(--space-sm);
    border-top: 1px solid var(--border-mid);
}
.restock-item {
    display: flex;
    align-items: baseline;
    gap: var(--space-xs);
    padding: 5px 0;
    border-bottom: 1px solid var(--border-mid);
    font-size: 0.88rem;
    flex-wrap: wrap;
}
.restock-item:last-child { border-bottom: none; }
.restock-item-name { font-weight: 500; color: var(--text); flex: 0 0 auto; }
.restock-item-qty  { color: var(--text-dim); font-size: 0.82rem; }
.restock-item-type { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; margin-left: 2px; }
.restock-item-pool { font-size: 0.78rem; }

/* Colour the change-type label by category */
.stock-change-restocked .restock-item-type { color: var(--green-text); }
.stock-change-sold      .restock-item-type { color: var(--red-text); }
.stock-change-added     .restock-item-type { color: var(--gold); }
.stock-change-retired   .restock-item-type { color: var(--text-muted); }

.restock-no-items { padding: var(--space-sm) var(--space-md); }

/* AI Studio result cards — collapsed by default, expand to the merge form.
   Mirrors the .restock-run-card <details> pattern above. */
.ai-result {
    margin-bottom: var(--space-sm);
    padding: 0;
    overflow: hidden;
}
.ai-result[open] { border-color: var(--gold-dim); }
.ai-result-summary {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    cursor: pointer;
    list-style: none;
    flex-wrap: wrap;
    user-select: none;
}
.ai-result-summary::-webkit-details-marker { display: none; }
.ai-result-summary::before {
    content: '▸';
    color: var(--text-dim);
    font-size: 0.75rem;
    flex-shrink: 0;
    transition: transform 0.15s;
}
.ai-result[open] .ai-result-summary::before { transform: rotate(90deg); }
.ai-result-summary strong { color: var(--text); font-weight: 600; }
.ai-result-meta { color: var(--text-dim); font-size: 0.82rem; }
.ai-result-counts {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    flex-wrap: wrap;
    margin-left: auto;
}
.ai-result-body {
    padding: 0 var(--space-md) var(--space-md);
    border-top: 1px solid var(--border-mid);
}

/* Summary count chips (sibling of .stock-count-chip) */
.ai-count-chip {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 0.78rem;
    border: 1px solid transparent;
    white-space: nowrap;
}
.ai-count-chip.pending   { background: rgba(212,163,70,0.18); color: var(--gold-bright); border-color: rgba(212,163,70,0.45); }
.ai-count-chip.added     { background: rgba(58,125,90,0.20);  color: #7fd6a0; border-color: rgba(58,125,90,0.45); }
.ai-count-chip.dismissed { background: var(--bg-card-alt);    color: var(--text-muted); border-color: var(--border-mid); }
.ai-count-chip.cleared   { background: rgba(26,46,74,0.30);   color: #7ab4e8; border-color: rgba(26,46,74,0.6); }

/* Model tag — which LLM produced a job's result (for comparing runs) */
.ai-model-chip {
    display: inline-flex;
    align-items: center;
    padding: 1px 7px;
    border-radius: 10px;
    font-size: 0.76rem;
    font-family: var(--font-mono, ui-monospace, monospace);
    background: rgba(150,120,200,0.14);
    color: #c3aee6;
    border: 1px solid rgba(150,120,200,0.4);
    white-space: nowrap;
}

/* ── Session scheduling ─────────────────────────────────────────────────── */

/* "Next session" banner on the campaign overview */
.next-session-banner {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-md) var(--space-lg);
    margin-bottom: var(--space-xl);
    background: linear-gradient(90deg, var(--campaign-accent-faint), transparent);
    border: 1px solid var(--campaign-accent-border);
    border-left: 3px solid var(--campaign-accent);
    border-radius: var(--radius-lg);
    text-decoration: none;
    color: inherit;
    transition: background 0.15s;
}
.next-session-banner:hover { background: linear-gradient(90deg, var(--campaign-accent-faint), var(--campaign-accent-faint)); }
.next-session-icon { color: var(--campaign-accent); display: flex; }
.next-session-icon .icon { width: 22px; height: 22px; }
.next-session-text { display: flex; flex-direction: column; line-height: 1.25; }
.next-session-label {
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--campaign-accent); font-weight: 700;
}
.next-session-when { font-size: 1.05rem; font-weight: 600; color: var(--text); }
.next-session-tally {
    margin-left: auto; font-size: 0.85rem; color: var(--text-dim);
    white-space: nowrap; font-variant-numeric: tabular-nums;
}

/* Compact chip on dashboard campaign cards */
.next-session-chip {
    display: flex; align-items: center; gap: var(--space-xs);
    margin: var(--space-sm) 0;
    padding: 4px 8px;
    background: var(--gold-faint);
    border: 1px solid var(--gold-border);
    border-radius: 10px;
    font-size: 0.78rem; color: var(--text-dim);
}
.next-session-chip .icon { width: 14px; height: 14px; color: var(--gold); flex-shrink: 0; }
.next-session-chip strong { color: var(--gold-bright); font-weight: 600; }

/* Create-poll candidate-time grid */
.poll-time-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: var(--space-sm);
}

/* Tally grid: players × candidate times */
.poll-grid { width: 100%; border-collapse: collapse; }
.poll-grid th, .poll-grid td {
    border: 1px solid var(--border-mid);
    padding: var(--space-sm);
    text-align: center;
    vertical-align: middle;
}
.poll-grid-corner, .poll-player {
    text-align: left; font-weight: 600;
    background: var(--bg-card-alt); white-space: nowrap;
}
.poll-player { color: var(--text); font-weight: 500; }
.poll-opt { min-width: 130px; background: var(--bg-card-alt); }
.poll-opt-when { font-size: 0.85rem; font-weight: 600; color: var(--text); margin-bottom: 4px; }
.poll-opt-won { background: var(--gold-faint); border-color: var(--gold-border) !important; }
.poll-opt-badge {
    margin-top: 4px; font-size: 0.72rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.05em; color: var(--gold-bright);
}
.poll-lock-btn { margin-top: 6px; }

.poll-you > .poll-player { background: var(--gold-faint); color: var(--gold-bright); }
.poll-you-tag {
    display: inline-block; margin-left: 6px; padding: 1px 6px;
    font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.05em;
    background: var(--gold); color: #1a1408; border-radius: 8px; font-weight: 700;
    vertical-align: middle;
}

/* Live tally chip under an option header */
.opt-tally {
    display: inline-flex; gap: 6px; justify-content: center;
    font-size: 0.72rem; font-variant-numeric: tabular-nums;
}
.opt-tally span { display: inline-flex; align-items: center; gap: 2px; }
.opt-tally b { font-weight: 700; }
.tally-yes   { color: var(--green-text); }
.tally-maybe { color: var(--gold-bright); }
.tally-no    { color: var(--red-text); }

/* Read-only vote marks (other players) */
.poll-mark { font-size: 1rem; font-weight: 700; }
.poll-mark-yes   { color: var(--green-text); background: rgba(30,74,53,0.25); }
.poll-mark-maybe { color: var(--gold-bright); background: var(--gold-faint); }
.poll-mark-no    { color: var(--red-text); background: rgba(122,31,46,0.20); }
.poll-mark-none  { color: var(--text-muted); }

/* Interactive vote buttons (current player's row) */
.poll-vote-cell { padding: 4px !important; }
.vote-group { display: inline-flex; gap: 3px; }
.vote-btn {
    width: 30px; height: 30px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--border-mid); background: var(--bg-input);
    color: var(--text-muted); border-radius: var(--radius);
    font-size: 0.9rem; font-weight: 700; cursor: pointer;
    transition: all 0.12s;
}
.vote-btn:hover:not(:disabled) { color: var(--text); border-color: var(--text-dim); }
.vote-btn:disabled { opacity: 0.5; cursor: default; }
.vote-yes.active   { background: var(--green); color: #eafaf0; border-color: var(--green-text); }
.vote-maybe.active { background: var(--gold-dim); color: #1a1408; border-color: var(--gold-bright); }
.vote-no.active    { background: var(--red); color: #fbeaec; border-color: var(--red-text); }

/* ============================================================================
   Search + @-mentions
   ========================================================================== */

/* Campaign sub-nav search box */
.cnav-search {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-left: auto;
    background: var(--bg-input);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius);
    padding: 2px 8px;
    max-width: 220px;
    transition: border-color 0.15s;
}
.cnav-search:focus-within { border-color: var(--campaign-accent-border); }
.cnav-search-icon { display: inline-flex; color: var(--text-muted); }
.cnav-search-icon .icon { width: 14px; height: 14px; }
.cnav-search input {
    border: none; background: none; outline: none;
    color: var(--text); font-family: var(--font-ui);
    font-size: 0.78rem; width: 100%; padding: 3px 0;
}
.cnav-search input::placeholder { color: var(--text-muted); }
@media (max-width: 640px) { .cnav-search { max-width: 150px; } }

/* Search results page */
.search-page-form {
    display: flex; align-items: center; gap: var(--space-sm);
    background: var(--bg-card); border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg); padding: 6px 8px 6px 12px;
    margin-bottom: var(--space-xl);
}
.search-page-icon { display: inline-flex; color: var(--text-dim); }
.search-page-form input[type="search"] {
    flex: 1; border: none; background: none; outline: none;
    color: var(--text); font-family: var(--font-body); font-size: 1rem; padding: 6px 0;
}
.search-page-form input[type="search"]::placeholder { color: var(--text-muted); }

.search-summary { margin-bottom: var(--space-lg); font-size: 0.9rem; }
.search-group { margin-bottom: var(--space-xl); }
.search-group-count {
    font-size: 0.72rem; font-weight: 600; color: var(--text-muted);
    background: var(--bg-card-alt); border-radius: 999px; padding: 1px 8px; margin-left: 4px;
}
.search-results { display: flex; flex-direction: column; gap: 6px; }
.search-result {
    display: block; text-decoration: none;
    background: var(--bg-card); border: 1px solid var(--border);
    border-left: 3px solid var(--campaign-accent-border);
    border-radius: var(--radius); padding: 10px 14px;
    transition: border-color 0.12s, background 0.12s;
}
.search-result:hover { background: var(--bg-card-alt); border-left-color: var(--campaign-accent); }
.search-result-title { font-family: var(--font-heading); font-size: 0.95rem; color: var(--gold); margin-bottom: 3px; }
.search-result-snippet { font-size: 0.86rem; color: var(--text-dim); line-height: 1.5; }
.search-result-meta { font-size: 0.75rem; color: var(--text-muted); margin-top: 4px; }
.search-result mark, .search-result-snippet mark {
    background: var(--gold-faint); color: var(--gold-bright);
    border-radius: 2px; padding: 0 2px;
}
.search-page-form kbd, .empty-desc kbd {
    font-family: var(--font-ui); font-size: 0.78em;
    background: var(--bg-input); border: 1px solid var(--border-mid);
    border-radius: 3px; padding: 1px 5px; color: var(--text-dim);
}

/* Rendered @-mention links inside rich content */
.mention {
    color: var(--gold-bright); text-decoration: none;
    font-weight: 600; border-radius: 2px; padding: 0 1px;
    background: var(--gold-faint);
}
.mention:hover { text-decoration: underline; }

/* @-mention autocomplete menu (Quill editor) */
.mention-menu {
    position: absolute; z-index: 300; display: none;
    min-width: 200px; max-width: 300px; max-height: 260px; overflow-y: auto;
    background: var(--bg-card); border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg); box-shadow: 0 8px 24px rgba(0,0,0,0.45);
    padding: 4px;
}
.mention-menu.open { display: block; }
.mention-opt {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 8px; border-radius: var(--radius); cursor: pointer;
    font-size: 0.88rem; color: var(--text);
}
.mention-opt.active, .mention-opt:hover { background: var(--gold-faint); }
.mention-opt-type {
    display: inline-flex; align-items: center; justify-content: center;
    width: 18px; height: 18px; flex: 0 0 auto;
    font-size: 0.7rem; font-weight: 700; border-radius: 50%;
    background: var(--bg-input); color: var(--text-dim);
}
.mention-opt-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Journal panel (render_journal() in journal.php): session-anchored entries */
.journal-session { margin-bottom: var(--space-lg); }
.journal-session-head {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-sm);
    font-size: 1rem; margin: 0 0 var(--space-sm);
    padding-bottom: 4px; border-bottom: 1px solid var(--border-mid);
}
.journal-entry {
    background: var(--bg-card); border: 1px solid var(--border-mid);
    border-left: 3px solid var(--gold-border);
    border-radius: var(--radius-lg); padding: var(--space-md) var(--space-lg);
    margin-bottom: var(--space-sm); min-width: 0; overflow-wrap: anywhere;
}
.journal-entry-head {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px var(--space-sm);
    margin-bottom: var(--space-sm);
}
.journal-entry-title { font-family: var(--font-heading); color: var(--parchment); }
.journal-chip {
    display: inline-block;
    font-family: var(--font-ui); font-size: 0.68rem; font-weight: 600;
    letter-spacing: 0.03em; text-transform: uppercase;
    color: var(--gold); border: 1px solid var(--gold-border); border-radius: 999px;
    padding: 0 7px; white-space: nowrap;
}
.journal-chip-muted { color: var(--text-dim); border-color: var(--border-mid); }
.journal-muted { opacity: 0.7; border-left-style: dashed; }
.journal-others {
    display: grid; gap: var(--space-md);
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.journal-other {
    background: var(--bg-card); border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg); padding: var(--space-md) var(--space-lg); min-width: 0;
    overflow-wrap: anywhere;
}
.journal-other-head {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-sm);
    font-size: 0.95rem; margin: 0 0 var(--space-sm);
}
.journal-other-entry + .journal-other-entry { border-top: 1px solid var(--border); padding-top: var(--space-sm); margin-top: var(--space-sm); }
.journal-add > summary { list-style: none; display: inline-flex; }
.journal-add > summary::-webkit-details-marker { display: none; }
.journal-fields {
    display: grid; gap: 0 var(--space-md);
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}

/* "Mentioned In" backlinks panel (render_backlinks() in backlinks.php) */
.backlinks-count {
    font-family: var(--font-ui); font-size: 0.72rem; font-weight: 600;
    color: var(--text-dim); background: var(--bg-input);
    border: 1px solid var(--border-mid); border-radius: 999px;
    padding: 1px 8px; vertical-align: middle; margin-left: 4px;
}
.backlinks-groups {
    display: grid; gap: var(--space-md);
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.backlinks-group {
    background: var(--bg-card); border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg); padding: var(--space-md) var(--space-lg);
    min-width: 0;
}
.backlinks-group-head {
    display: flex; align-items: center; gap: 6px;
    font-size: 0.95rem; margin: 0 0 var(--space-sm);
}
.backlinks-group-head svg { width: 16px; height: 16px; color: var(--gold); }
.backlinks-group-head .backlinks-count { margin-left: auto; }
.backlinks-list { list-style: none; margin: 0; padding: 0; }
.backlink { padding: 6px 0; border-top: 1px solid var(--border); }
.backlinks-list > .backlink:first-child { border-top: 0; }
.backlink-title { font-weight: 600; overflow-wrap: anywhere; }
.backlink-meta { display: block; }
.backlink-snippet {
    margin: 4px 0 0; padding-left: var(--space-sm);
    border-left: 2px solid var(--gold-border);
    font-size: 0.85rem; line-height: 1.45; color: var(--text-dim);
    overflow-wrap: anywhere;
}
.backlink-snippet mark {
    background: var(--gold-faint); color: var(--text); padding: 0 1px; border-radius: 2px;
}
.backlinks-more summary {
    cursor: pointer; font-family: var(--font-ui); font-size: 0.82rem;
    color: var(--text-dim); padding: 6px 0 2px;
}
.backlinks-more summary:hover { color: var(--gold); }
.backlinks-more .backlinks-list > .backlink:first-child { border-top: 1px solid var(--border); }
/* What the AI found the session did with this record (Appeared, Visited, …) */
.backlink-kind {
    display: inline-block; margin-left: 6px; vertical-align: 1px;
    font-family: var(--font-ui); font-size: 0.68rem; font-weight: 600;
    letter-spacing: 0.03em; text-transform: uppercase;
    color: var(--gold); border: 1px solid var(--gold-border); border-radius: 999px;
    padding: 0 7px; white-space: nowrap;
}
/* The studio's read-only Results card for a cross_references job */
.xref-results {
    display: grid; gap: var(--space-sm) var(--space-lg);
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.xref-result-group { min-width: 0; }
.xref-result-group h4 { margin: var(--space-sm) 0 4px; font-size: 0.9rem; }
.xref-result-group ul { margin: 0; padding-left: 1.1rem; font-size: 0.88rem; }
.xref-result-group li { margin: 2px 0; overflow-wrap: anywhere; }

/* ══════════════════════════════════════════════════════════════════════
   Entity images — carousel, GM controls, lightbox
   Ported from the dicelords carousel/lightbox and re-tokenised. The
   carousel lives in the portrait column on entity pages, so it must never
   exceed its container's width.
   ══════════════════════════════════════════════════════════════════════ */
.entity-images { margin: 0; }
/* Standalone block (sessions have no portrait column) — keep it from spanning
   the whole content width on a wide screen. */
.entity-images-block { max-width: 640px; margin: 0 0 var(--space-lg); }

.carousel { position: relative; max-width: 100%; margin: 0 auto var(--space-md); }
.carousel-viewport {
    overflow: hidden;
    border: 1px solid var(--border-mid);
    border-radius: var(--radius);
    background: var(--bg-input);
}
.carousel-track { display: flex; transition: transform 320ms ease; }
.carousel-slide {
    flex: 0 0 100%;
    min-width: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
}
.carousel-slide a { display: block; max-width: 100%; line-height: 0; }
.carousel-slide img {
    display: block;
    max-width: 100%;
    max-height: 68vh;
    width: auto;             /* keep aspect ratio; never upscale past intrinsic size */
    height: auto;
    cursor: zoom-in;
}

/* Prev/next arrows + counter overlay the viewport (rendered only when >1 image). */
.carousel-btn {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 36px; height: 36px;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.5rem; line-height: 1;
    color: var(--text);
    background: rgba(8, 6, 4, 0.62);
    border: 1px solid var(--gold-border);
    border-radius: 50%;
    cursor: pointer;
    transition: background var(--transition), color var(--transition);
}
.carousel-btn:hover { background: rgba(8, 6, 4, 0.9); color: var(--gold-bright); }
.carousel-btn.prev { left: 8px; }
.carousel-btn.next { right: 8px; }
.carousel-counter {
    position: absolute;
    bottom: 8px; right: 10px;
    font-family: var(--font-ui);
    font-size: 0.66rem; font-weight: 600; letter-spacing: 0.1em;
    color: var(--text);
    background: rgba(8, 6, 4, 0.7);
    padding: 3px 8px;
    border-radius: var(--radius);
}

/* GM-only per-image controls, in the slide's figcaption. */
.ei-controls {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    flex-wrap: wrap;
    width: 100%;
    padding: var(--space-xs) 2px var(--space-sm);
    font-family: var(--font-ui);
    font-size: 0.75rem;
}
.ei-controls .inline-form { display: inline; margin: 0; }
.ei-controls .ei-del { margin-left: auto; }
.ei-btn {
    background: none;
    border: 1px solid var(--border-mid);
    color: var(--text-dim);
    border-radius: var(--radius);
    font-family: var(--font-ui);
    font-size: 0.72rem;
    line-height: 1;
    padding: 3px 7px;
    cursor: pointer;
    transition: color var(--transition), border-color var(--transition);
}
.ei-btn:hover { color: var(--gold-bright); border-color: var(--gold-border); }
.ei-btn-danger:hover { color: var(--red-text); border-color: var(--red); }
.ei-tag {
    display: inline-flex; align-items: center;
    padding: 2px 7px;
    border-radius: var(--radius);
    font-size: 0.68rem; font-weight: 600;
    letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--gold); background: var(--gold-faint);
    border: 1px solid var(--gold-border);
}
.ei-tag-ai { color: var(--blue-text); background: var(--blue); border-color: transparent; cursor: help; }

/* Generation panel below the carousel (GM only, AI images enabled). */
.ei-panel { font-family: var(--font-ui); font-size: 0.82rem; }
.ei-chip {
    display: flex; align-items: center; gap: var(--space-xs);
    margin: 0 0 var(--space-sm);
    padding: var(--space-sm);
    border: 1px solid var(--gold-border);
    border-radius: var(--radius);
    background: var(--gold-faint);
    color: var(--text-dim);
}
.ei-error {
    display: flex; align-items: flex-start; gap: var(--space-sm);
    flex-wrap: wrap;
    margin-bottom: var(--space-sm);
    padding: var(--space-sm);
    border: 1px solid var(--red);
    border-radius: var(--radius);
    background: rgba(122, 31, 46, 0.15);
    color: var(--red-text);
}
.ei-gen { margin-bottom: var(--space-sm); }
.ei-gen > summary {
    cursor: pointer;
    display: flex; align-items: center; gap: var(--space-xs);
    padding: var(--space-xs) 0;
    color: var(--text-dim);
}
.ei-gen > summary:hover { color: var(--gold-bright); }
.ei-gen textarea { width: 100%; font-size: 0.82rem; }
.ei-label {
    display: block;
    margin-top: var(--space-xs);
    font-size: 0.72rem; font-weight: 600;
    letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--text-dim);
}
.ei-note { margin: var(--space-xs) 0; color: var(--text-muted); font-size: 0.76rem; }
.ei-actions {
    display: flex; align-items: center; gap: var(--space-sm);
    flex-wrap: wrap;
    margin-top: var(--space-sm);
}
.ei-cap { color: var(--text-muted); font-size: 0.75rem; }

/* Lightbox popout — clicking a carousel image opens it here instead of leaving. */
body.lb-lock { overflow: hidden; }
.lightbox {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: none;
    align-items: center;
    justify-content: center;
    background: rgba(6, 5, 3, 0.93);
}
.lightbox.open { display: flex; }
.lb-figure {
    margin: 0;
    max-width: 92vw; max-height: 92vh;
    display: flex; flex-direction: column; align-items: center;
}
.lb-figure img {
    max-width: 92vw; max-height: 90vh;
    width: auto; height: auto;
    border: 1px solid var(--gold-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
}
.lb-close, .lb-nav {
    position: absolute;
    background: rgba(10, 8, 4, 0.55);
    border: 1px solid var(--gold-border);
    color: var(--gold);
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    transition: background var(--transition), color var(--transition);
}
.lb-close:hover, .lb-nav:hover { background: rgba(10, 8, 4, 0.9); color: var(--gold-bright); }
.lb-close { top: 16px; right: 20px; width: 42px; height: 42px; font-size: 1rem; border-radius: 50%; }
.lb-nav {
    top: 50%; transform: translateY(-50%);
    width: 52px; height: 52px;
    font-size: 2rem; line-height: 1;
    border-radius: 50%;
}
.lb-prev { left: 16px; }
.lb-next { right: 16px; }

@media (max-width: 720px) {
    .lb-close { top: 10px; right: 10px; width: 38px; height: 38px; }
    .lb-nav { width: 42px; height: 42px; font-size: 1.6rem; }
    .lb-prev { left: 6px; }
    .lb-next { right: 6px; }
}

/* ----- Session Feedback ------------------------------------ */
/* /campaign/feedback.php — private critiques from the AI Studio. Charts follow
   the site's single-hue rule: data ink in the campaign accent, the player
   average as a dashed neutral reference, identity in the legend and line style. */
.cnav-badge {
    display: inline-block;
    margin-left: 0.35rem;
    padding: 0 0.4rem;
    border-radius: 999px;
    background: var(--campaign-accent-faint);
    border: 1px solid var(--campaign-accent-border);
    color: var(--text);
    font-family: var(--font-ui);
    font-size: 0.65rem;
    font-weight: 600;
    vertical-align: middle;
}
.cnav-dot {
    display: inline-block;
    width: 6px; height: 6px;
    margin-left: 4px;
    border-radius: 50%;
    background: var(--campaign-accent);
    vertical-align: middle;
}

.fb-optout { margin-bottom: var(--space-lg); padding: var(--space-md) var(--space-lg); }
.fb-card   { margin-bottom: var(--space-xl); }
.fb-card-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--space-md);
    flex-wrap: wrap;
}
.fb-card-title { margin: 0; font-size: 1.15rem; }
.fb-new {
    font-family: var(--font-ui);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    background: var(--campaign-accent-faint);
    border: 1px solid var(--campaign-accent-border);
    color: var(--text);
}
.fb-headline {
    margin: var(--space-md) 0;
    padding-left: var(--space-md);
    border-left: 3px solid var(--campaign-accent);
    font-size: 1.05rem;
    font-style: italic;
    color: var(--text);
}
.fb-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(135px, 1fr));
    gap: var(--space-sm);
    margin: var(--space-md) 0;
}
.fb-tile {
    background: var(--bg-raised);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
    padding: var(--space-sm) var(--space-md);
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.fb-tile-label {
    font-family: var(--font-ui);
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--text-dim);
}
.fb-tile-value { font-family: var(--font-ui); font-size: 1.35rem; font-weight: 600; color: var(--text); }
.fb-tile-sub   { font-family: var(--font-ui); font-size: 0.72rem; color: var(--text-muted); }
.fb-subhead {
    font-family: var(--font-ui);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-dim);
    margin: var(--space-lg) 0 var(--space-xs);
}
.fb-legend {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-family: var(--font-ui);
    font-size: 0.75rem;
    color: var(--text-dim);
    margin-bottom: 2px;
}
.fb-key { display: inline-block; width: 18px; height: 0; margin-left: 0.6rem; }
.fb-key:first-child { margin-left: 0; }
.fb-key-me  { border-top: 2px solid var(--campaign-accent); }
.fb-key-avg { border-top: 2px dashed var(--text-muted); }
.fb-chart { width: 100%; height: auto; display: block; }
.fb-grid  { stroke: var(--border-mid); stroke-width: 1; }
.fb-tick  { fill: var(--text-muted); font-family: var(--font-ui); font-size: 10px; }
/* The SVG scales with its column, so strokes are pinned to screen pixels and
   the tick text is enlarged on narrow screens — at phone width the 720-unit
   viewBox renders at ~0.4x and 10-unit labels would be unreadable. */
.fb-grid, .fb-line-me, .fb-line-avg { vector-effect: non-scaling-stroke; }
.fb-line-me  { fill: none; stroke: var(--campaign-accent); stroke-width: 2; stroke-linejoin: round; }
.fb-line-avg { fill: none; stroke: var(--text-muted); stroke-width: 2; stroke-dasharray: 5 4; }
.fb-pt { fill: var(--campaign-accent); stroke: var(--bg-card); stroke-width: 2; opacity: 0; }
.fb-hit:hover .fb-pt { opacity: 1; }
.fb-meter {
    display: grid;
    grid-template-columns: minmax(80px, 140px) 1fr minmax(90px, auto);
    align-items: center;
    gap: var(--space-sm);
    padding: 0.2rem 0;
}
.fb-meter-label { font-family: var(--font-ui); font-size: 0.82rem; color: var(--text);
                  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-meter-track { display: block; height: 8px; background: var(--bg-raised);
                  border: 1px solid var(--border); border-radius: 4px; overflow: hidden; }
.fb-meter-fill  { display: block; height: 100%; background: var(--campaign-accent); border-radius: 4px; }
.fb-meter-val   { font-family: var(--font-ui); font-size: 0.8rem; color: var(--text-dim);
                  text-align: right; white-space: nowrap; }
.fb-meter-sub   { color: var(--text-muted); font-size: 0.72rem; }
.fb-body { margin-top: var(--space-lg); }
.fb-details > summary { cursor: pointer; margin-top: var(--space-sm); color: var(--text-dim); }
.fb-trend { margin-bottom: var(--space-xl); }
.fb-trend-table { width: 100%; border-collapse: collapse; font-family: var(--font-ui); font-size: 0.85rem; margin-top: var(--space-sm); }
.fb-trend-table th, .fb-trend-table td { text-align: left; padding: 0.35rem 0.6rem; border-bottom: 1px solid var(--border); }
.fb-trend-table th { color: var(--text-dim); font-weight: 600; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; }
@media (max-width: 560px) {
    .fb-tick  { font-size: 22px; }
    .fb-meter { grid-template-columns: 1fr; gap: 2px; }
    .fb-meter-val { text-align: left; }
}

/* ----- Footer guide link (the guide itself: help.css) --- */
.footer-links { margin-top: var(--space-xs); font-size: 0.85rem; }
.footer-links a { color: var(--text-muted); text-decoration: none; border-bottom: 1px solid transparent; }
.footer-links a:hover { color: var(--gold); border-bottom-color: var(--gold-border); }

/* ─── Codex (campaign/codex.php) ──────────────────────────────────────────── */
.codex-viewas {
    display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-sm);
    margin-bottom: var(--space-md);
}
.codex-viewas select { width: auto; max-width: 100%; }
.codex-as-banner a { margin-left: var(--space-xs); }
.codex-filters { display: grid; gap: var(--space-sm); margin-bottom: var(--space-sm); }
.codex-chips { display: flex; flex-wrap: wrap; gap: var(--space-xs); }
.codex-chips .filter-chip { cursor: pointer; gap: 6px; position: relative; }
.codex-chips .filter-chip input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.codex-chips .filter-chip:focus-within { outline: 2px solid var(--gold-dim); outline-offset: 2px; }
.codex-controls { display: flex; flex-wrap: wrap; gap: var(--space-sm); align-items: center; }
.codex-controls .codex-search { flex: 1 1 220px; min-width: 0; }
.codex-controls select { width: auto; flex: 0 1 auto; max-width: 100%; }
.codex-count { margin: 0 0 var(--space-sm); }
.codex-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
    gap: var(--space-md);
}
.codex-entry {
    display: grid;
    grid-template-columns: 64px minmax(0, 1fr);
    gap: var(--space-md);
    align-items: start;
    padding: var(--space-md);
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
}
.codex-entry[hidden] { display: none; }
.codex-entry:hover { border-color: var(--campaign-accent-border); }
.codex-portrait {
    width: 64px; height: 64px;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--bg-raised);
    border: 1px solid var(--border);
    display: flex; align-items: center; justify-content: center;
    color: var(--text-muted);
}
.codex-portrait img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.codex-portrait .icon { width: 26px; height: 26px; opacity: .6; }
.codex-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.codex-name {
    font-family: var(--font-heading);
    font-weight: 600;
    color: var(--parchment);
    overflow-wrap: anywhere;
}
.codex-name:hover { color: var(--campaign-accent); }
.codex-sub { margin-top: 2px; }
.codex-excerpt {
    margin: var(--space-xs) 0 0;
    color: var(--text-dim);
    font-size: .95rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.codex-first { margin-top: var(--space-xs); color: var(--text-dim); }
.codex-first a { color: var(--campaign-accent); }
.codex-none { margin-top: var(--space-lg); text-align: center; }
.js-codex-submit[hidden], .js-autosubmit-btn[hidden] { display: none; }

/* ─── Timeline (campaign/timeline.php) ─────────────────────────────────────
   Sessions hang off one vertical rule, each on a numbered marker. Colours
   come from the campaign tokens, so every theme skins it without its own rule. */
.tl-filters {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-sm);
    margin-bottom: var(--space-lg);
}
.tl-filters select { width: auto; flex: 0 1 auto; max-width: 100%; min-width: 0; }
.tl {
    --tl-marker: 2.25rem;
    list-style: none; margin: 0; padding: 0;
    position: relative;
}
.tl::before {
    content: "";
    position: absolute;
    left: calc(var(--tl-marker) / 2 - 1px);
    top: .5rem; bottom: .5rem;
    width: 2px;
    background: linear-gradient(var(--campaign-accent-border), var(--border) 85%, transparent);
}
.tl-session {
    position: relative;
    display: grid;
    grid-template-columns: var(--tl-marker) minmax(0, 1fr);
    gap: var(--space-md);
    padding-bottom: var(--space-lg);
    scroll-margin-top: 7rem;
}
.tl-marker {
    position: relative;
    width: var(--tl-marker); height: var(--tl-marker);
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--bg-card);
    border: 2px solid var(--campaign-accent);
    color: var(--campaign-accent);
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: .9rem;
    font-variant-numeric: tabular-nums;
}
.tl-session.is-upcoming .tl-marker { border-style: dashed; color: var(--text-dim); border-color: var(--border-mid); }
.tl-card {
    min-width: 0;
    padding: var(--space-md);
    background: var(--bg-card);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-lg);
}
.tl-session:target .tl-card { border-color: var(--campaign-accent-border); box-shadow: 0 0 0 1px var(--campaign-accent-border); }
.tl-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 2px var(--space-sm); }
.tl-title { margin: 0; font-size: 1.1rem; font-family: var(--font-heading); overflow-wrap: anywhere; }
.tl-title a { color: var(--parchment); }
.tl-title a:hover { color: var(--campaign-accent); }
.tl-date { white-space: nowrap; }
.tl-chip {
    display: inline-block;
    margin-left: 4px;
    padding: 0 7px;
    border-radius: 10px;
    border: 1px solid var(--campaign-accent-border);
    background: var(--campaign-accent-faint);
    color: var(--campaign-accent);
    font-family: var(--font-ui);
    font-size: .7rem;
    line-height: 1.5;
    white-space: nowrap;
}
.tl-why { margin: var(--space-xs) 0 0; color: var(--campaign-accent); }
.tl-summary { margin: var(--space-sm) 0 0; color: var(--text-dim); }
.tl-poll, .tl-attended { margin: var(--space-sm) 0 0; }
.tl-poll .icon, .tl-attended .icon { width: 14px; height: 14px; vertical-align: -2px; }
.tl-attended a.is-hit { color: var(--campaign-accent); font-weight: 600; }
.tl-group { margin-top: var(--space-md); padding-top: var(--space-sm); border-top: 1px solid var(--border); }
.tl-label {
    display: flex; align-items: center; gap: 6px;
    margin: 0 0 var(--space-xs);
    font-family: var(--font-ui);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.tl-label .icon { width: 14px; height: 14px; }
.tl-quest + .tl-quest { margin-top: var(--space-sm); }
.tl-quest-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; font-weight: 600; }
.tl-quest-head .tl-chip { margin-left: 0; }
.tl-beat {
    margin: var(--space-xs) 0 0;
    padding-left: var(--space-sm);
    border-left: 2px solid var(--campaign-accent-border);
    font-size: .95rem;
}
.tl-beat > :last-child { margin-bottom: 0; }
.tl-quest.is-hit .tl-quest-head a { color: var(--campaign-accent); }
.tl-quest.is-hit .tl-beat { border-left-color: var(--campaign-accent); }
.tl-chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.tl-first {
    display: inline-flex; align-items: center; gap: 5px;
    max-width: 100%;
    padding: 2px 10px 2px 8px;
    border-radius: 12px;
    border: 1px solid var(--border-mid);
    background: var(--bg-raised);
    font-size: .9rem;
}
.tl-first a { overflow-wrap: anywhere; }
.tl-first .icon { width: 14px; height: 14px; flex: none; color: var(--text-muted); }
.tl-first.is-hit { border-color: var(--campaign-accent); background: var(--campaign-accent-faint); }
.tl-list { margin: 0; padding-left: 1.2rem; }
@media (max-width: 600px) {
    .tl { --tl-marker: 1.75rem; }
    .tl-session { gap: var(--space-sm); }
    .tl-marker { font-size: .75rem; }
    .tl-card { padding: var(--space-sm) var(--space-md); }
}
