/* ── Modal shell ── */
.modal-overlay {
    position: fixed; inset: 0;
    background: var(--scrim);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 200;
    backdrop-filter: blur(2px);
}
.modal-overlay.open { display: flex; }
/* .settings-corner sits at z-index: 300 (above the base modal-overlay z-index: 200)
   so the gear stays reachable over the (non-fullpage) config modal. The story
   editor is full-viewport though, so at the base z-index the gear floated visibly
   above it — bump it above .settings-corner here so the editor fully covers it. */
#storyEditorOverlay { z-index: 350; }

.modal {
    position: relative;
    background: var(--modal-bg);
    border: 1px solid var(--seam);
    border-radius: 10px;
    width: min(92vw, 900px);
    height: 84vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: 0 24px 60px var(--shadow-lg);
    animation: fadeUp 0.22s ease;
}

/* Full-page variant — used by the story editor */
.modal-loading-overlay {
    position: absolute;
    inset: 0;
    background: var(--surface-veil);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    z-index: 50;
}
.modal-loading-spinner {
    width: 42px; height: 42px;
    border: 3px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: modal-spin 0.8s linear infinite;
}
@keyframes modal-spin { to { transform: rotate(360deg); } }

/* Until /api/state lands, appState is all zeroes — showing the page would assert
   an empty account rather than an unfinished load. Below the auth overlay, which
   is up at the same time on a cold visit. */
.boot-overlay {
    position: fixed; inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
    background: var(--bg);
    z-index: 9000;
}
body.booting .boot-overlay { display: flex; }
.modal-loading-text {
    font-family: 'Cormorant Garamond', serif;
    font-size: 1.05rem;
    color: var(--cream);
    letter-spacing: 0.04em;
}
.modal-loading-bar-track {
    width: 220px;
    height: 6px;
    background: var(--panel2);
    border: 1px solid var(--border);
    border-radius: 4px;
    overflow: hidden;
}
.modal-loading-bar-fill {
    height: 100%;
    width: 0%;
    background: linear-gradient(90deg, var(--accent), var(--gold));
    transition: width 0.25s linear;
}
.modal-loading-pct {
    font-size: 0.78rem;
    color: var(--muted);
    letter-spacing: 0.04em;
}

.modal-fullpage {
    width: 100vw;
    max-width: 100vw;
    height: 100dvh;
    border-radius: 0;
    border: none;
    /* The story editor reads brighter than the rest of the (very dark) app because
       .modal / inputs lean on --panel/--panel2, a step up from the page's --bg.
       Shift the whole editor's palette one step darker so it matches the main page.
       --panel is nudged ~2% lighter than --bg so the prompt textarea (darker still)
       has something to contrast against instead of blending flat. */
    --panel:  #080f1c;
    --panel2: #0a1220;
    /* The editor is the full viewport — it *is* the page while it's open, so it
       keeps its own panel tone rather than the raised dialog surface. */
    --modal-bg: var(--panel);
}
/* Same intent on cream: one step toward the page rather than away from it. */
body.theme-cream .modal-fullpage {
    --panel:  #f4ead9;
    --panel2: #e9dac0;
}
body.theme-espresso .modal-fullpage {
    --panel:  #17130e;
    --panel2: #221b14;
}

/* Compact variant — a dialog sized to what it holds, rather than to the tall
   tabbed shell the config modal and the editor need. */
.modal.modal-compact {
    width: min(92vw, 560px);
    height: auto;
    max-height: 84vh;
}

/* ── Campaign picker ── */
.campaign-body {
    gap: 1rem;
    padding: 1.25rem 1.5rem;
    overflow-y: auto;
}
.campaign-list { display: flex; flex-direction: column; gap: 0.6rem; }
/* The banner is the card. The name rides on top of it, held back until the
   pointer is on the card so the art gets the first look. */
.campaign-card {
    position: relative;
    display: block;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--wash);
    cursor: pointer;
    overflow: hidden;
    transition: border-color 0.15s;
}
.campaign-card:hover,
.campaign-card:focus-visible { border-color: var(--gold); outline: none; }
.campaign-card-banner {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    transition: transform 0.4s ease, filter 0.25s;
}
.campaign-card:hover .campaign-card-banner,
.campaign-card:focus-visible .campaign-card-banner {
    transform: scale(1.03);
    filter: brightness(0.55);
}
.campaign-card-name {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    padding: 0 1rem;
    font-family: 'Cormorant Garamond', serif;
    font-size: 1.9rem; letter-spacing: 0.14em; text-align: center;
    /* This label always sits over darkened artwork, even in the light theme. */
    color: #f7efe3;
    text-shadow: 0 2px 18px rgba(0, 0, 0, 0.85);
    opacity: 0;
    transition: opacity 0.25s;
}
.campaign-card:hover .campaign-card-name,
.campaign-card:focus-visible .campaign-card-name {
    color: #f7efe3;
    opacity: 1;
}
/* Nothing hovers on a touch screen, so there the name is simply always up. */
@media (hover: none) {
    .campaign-card-name { opacity: 1; }
    .campaign-card-banner { filter: brightness(0.55); }
}

.modal-header {
    padding: 1rem 1.5rem;
    border-bottom: 1px solid var(--seam);
    display: flex; align-items: center; justify-content: space-between;
    flex-shrink: 0;
}
.modal-header h2 {
    font-family: 'Cormorant Garamond', serif;
    font-size: 1.15rem; font-weight: 300;
    letter-spacing: 0.2em; color: var(--accent);
}
#editorTitle {
    height: 48px;
    width: auto;
    display: block;
}
.modal-close {
    background: none; border: none;
    color: var(--muted); cursor: pointer;
    font-size: 0.9rem; padding: 4px 8px; border-radius: 4px;
    transition: color 0.15s;
}
.modal-close:hover { color: var(--cream); }

/* The editor's title strip carries the Story Bible banner the way the app
   header carries the brand one, so on cream it takes the same dark note —
   the lettering is cream-to-gold and washes out on a light panel. */
body.theme-cream .modal-fullpage .modal-header {
    background: var(--header-bg);
    border-bottom-color: var(--header-bg);
}
body.theme-cream .modal-fullpage .modal-close { color: var(--header-ink); }
body.theme-cream .modal-fullpage .modal-close:hover { color: #fffdf8; }

.modal-tabs {
    display: flex;
    border-bottom: 1px solid var(--seam);
    padding: 0 1.5rem;
    flex-shrink: 0;
    overflow-x: auto;
}
.modal-tabs::-webkit-scrollbar { display: none; }

.modal-tab {
    background: none; border: none;
    border-bottom: 2px solid transparent;
    color: var(--muted); cursor: pointer;
    padding: 0.6rem 1rem;
    font-family: 'Nunito', sans-serif;
    font-size: 0.73rem; letter-spacing: 0.12em; text-transform: uppercase;
    transition: all 0.15s; margin-bottom: -1px; white-space: nowrap;
}
.modal-tab:hover { color: var(--text); }
.modal-tab.active { color: var(--accent); border-bottom-color: var(--accent); }

.modal-body {
    flex: 1; overflow: hidden;
    display: flex; flex-direction: column;
}

.modal-footer {
    padding: 0.85rem 1.5rem;
    border-top: 1px solid var(--seam);
    display: flex; align-items: center; justify-content: space-between;
    flex-shrink: 0; gap: 1rem;
}
.modal-footer-note { font-size: 0.7rem; color: var(--muted); }
.modal-footer-btns { display: flex; gap: 0.6rem; }

.btn-secondary {
    background: none; border: 1px solid var(--border-strong); border-radius: 6px;
    color: var(--muted); cursor: pointer;
    padding: 0.45rem 0.9rem;
    font-family: 'Nunito', sans-serif; font-size: 0.8rem;
    transition: all 0.15s;
}
.btn-secondary:hover { border-color: var(--text); color: var(--text); }

.btn-primary {
    background: var(--btn-grad);
    border: 1px solid var(--btn-border); border-radius: 6px;
    color: var(--btn-ink); cursor: pointer;
    padding: 0.45rem 1.1rem;
    font-family: 'Cormorant Garamond', serif;
    font-size: 0.95rem; letter-spacing: 0.08em;
    transition: all 0.18s;
}
.btn-primary:hover:not(:disabled) {
    background: var(--btn-grad-hi);
    box-shadow: 0 0 12px rgba(100,170,230,0.25);
}
.btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }

/* ── Doc section ── */
.doc-section {
    flex: 1; overflow: hidden;
    padding: 1.1rem 1.5rem 1rem;
    display: flex; flex-direction: column; gap: 0.55rem;
}
/* The rebuild overlay covers this section alone, so it anchors to it. */
#storySection { position: relative; }

.story-summary-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}
.story-summary-head .doc-hint { flex: 1 1 16rem; }

.doc-hint { font-size: 0.7rem; color: var(--muted); letter-spacing: 0.06em; flex-shrink: 0; }
.doc-hint em { color: var(--accent); font-style: normal; }

.doc-textarea {
    flex: 1; width: 100%;
    background: var(--input-dark);
    border: none; border-radius: 6px;
    padding: 1rem 1.1rem;
    color: var(--cream);
    font-family: 'Courier New', Courier, monospace;
    font-size: 0.84rem; line-height: 1.65;
    resize: none; outline: none;
    transition: border-color 0.18s; overflow-y: auto;
}
.doc-textarea:focus { border: none; }
.doc-textarea::-webkit-scrollbar { width: 3px; }
.doc-textarea::-webkit-scrollbar-thumb { background: var(--scrollbar); border-radius: 2px; }

/* ── Characters section ── */
.chars-section { flex: 1; overflow: hidden; display: flex; }

.chars-sidebar {
    width: 195px; flex-shrink: 0;
    border-right: 1px solid var(--seam);
    display: flex; flex-direction: column; overflow: hidden;
}

.chars-list {
    flex: 1; overflow-y: auto;
    padding: 0.6rem 0.5rem;
    display: flex; flex-direction: column; gap: 0.2rem;
}
.chars-list::-webkit-scrollbar { width: 3px; }
.chars-list::-webkit-scrollbar-thumb { background: var(--scrollbar); border-radius: 2px; }

.char-item {
    display: flex; align-items: center; gap: 0.4rem;
    padding: 0.45rem 0.6rem;
    border-radius: 5px; cursor: pointer;
    font-size: 0.85rem; color: var(--text);
    border: 1px solid transparent; transition: all 0.15s; min-width: 0;
}
.char-item:hover { background: var(--wash); border-color: var(--border-strong); }
.char-item.active { background: var(--accent-wash); border-color: var(--accent); color: var(--accent); }
.char-item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.char-item-del {
    opacity: 0; background: none; border: none;
    color: var(--danger); cursor: pointer;
    font-size: 0.65rem; padding: 1px 3px; border-radius: 3px; flex-shrink: 0;
    transition: opacity 0.15s;
}
.char-item:hover .char-item-del { opacity: 0.55; }
.char-item-del:hover { opacity: 1 !important; }

/* The same control as the task sidebar's add button (.add-task button): bare
   until hovered, when the circle and its highlight come in. What it adds is
   named by the list it sits under, and by its tooltip. */
.chars-add-btn {
    align-self: flex-end; margin: 0.35rem 0.5rem; flex-shrink: 0;
    width: 32px; height: 32px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    background: transparent; border: 1px solid transparent; border-radius: 50%;
    color: var(--accent); cursor: pointer;
    transition: background 0.18s, border-color 0.18s;
}
.chars-add-btn svg { width: 15px; height: 15px; }
.chars-add-btn:hover { background: var(--accent-wash); border-color: var(--accent); }

/* Empty-list note, in place of the rows. */
.chars-list-empty {
    padding: 0.6rem 0.75rem;
    font-size: 0.78rem; color: var(--muted); font-style: italic;
}

/* ── Mobile picker ──
   Stands in for the list on a phone, where the sidebar collapses to a short
   scrolling strip above the editor and reads as an accident rather than a
   choice. Desktop keeps the list; only one of the two is ever visible. */
.chars-picker { display: none; }
.chars-select {
    flex: 1; min-width: 0;
    background: var(--input-dark); border: 1px solid var(--border-strong); border-radius: 6px;
    padding: 0.45rem 0.5rem; color: var(--cream);
    font-family: 'Nunito', sans-serif; font-size: 0.85rem;
    outline: none; color-scheme: dark;
}
.chars-select:disabled { color: var(--muted); font-style: italic; }
.chars-picker-del {
    flex-shrink: 0; width: 32px; height: 32px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    background: transparent; border: 1px solid transparent; border-radius: 50%;
    color: var(--danger); cursor: pointer; font-size: 0.8rem;
    transition: background 0.18s, border-color 0.18s;
}
.chars-picker-del:hover { background: rgba(224,92,110,0.1); border-color: var(--danger); }

.chars-editor {
    flex: 1; overflow: hidden;
    display: flex; flex-direction: column; padding: 1rem 1.25rem; gap: 0.6rem;
}
/* The Characters tab's pane holds a character panel, which brings its own
   padding — the topic tabs' panes keep theirs. */
.chars-editor-panel { padding: 0; gap: 0; }
.chars-empty-state {
    flex: 1; display: flex; align-items: center; justify-content: center;
    color: var(--muted);
    font-family: 'Cormorant Garamond', serif; font-style: italic; font-size: 1rem; text-align: center;
}
.char-name-row {
    display: flex; align-items: center; gap: 0.6rem; flex-shrink: 0;
}
.story-time-section { flex-shrink: 0; margin-bottom: 0.6rem; display: flex; flex-direction: column; }
.story-time-heading {
    font-size: 0.62rem; letter-spacing: 0.15em; text-transform: uppercase;
    color: var(--muted); margin-bottom: 0.5rem;
}
.story-time-fields { display: flex; gap: 0.6rem; }
.story-time-input {
    background: var(--input-dark); border: none; border-radius: 5px;
    padding: 0.5rem 0.75rem; color: var(--cream);
    font-family: 'Nunito', sans-serif; font-size: 0.9rem; outline: none;
    width: 180px;
}
/* One placeholder treatment for every field in the story editor, popups
   included — they used to drift apart (Courier here, no italic there, and
   Story Memory falling through to the browser default).
   The grey is deliberately neutral, not var(--muted): that one is blue-tinted
   and reads as a different colour next to the rest. */
.story-time-input::placeholder,
.char-name-input::placeholder,
.apikey-input::placeholder,
.doc-textarea::placeholder,
.prompt-input::placeholder {
    color: #808080;
    font-family: 'Nunito', sans-serif;
    font-size: 0.85rem;
    font-style: normal;
    letter-spacing: normal;
}
.char-name-label {
    font-size: 0.62rem; letter-spacing: 0.15em; text-transform: uppercase;
    color: var(--muted); white-space: nowrap; flex-shrink: 0;
}
.char-name-input {
    flex: 1;
    background: var(--input-dark); border: none; border-radius: 5px;
    padding: 0.5rem 0.75rem; color: var(--cream);
    font-family: 'Nunito', sans-serif; font-size: 0.9rem; outline: none;
    transition: border-color 0.18s;
}
.char-name-input:focus { border: none; }
.char-birth-date-input { color-scheme: dark; }
/* The label is the checkbox's, so clicking the words toggles it. */
.char-birth-enable {
    display: flex; align-items: center; gap: 0.4rem;
    flex-shrink: 0; cursor: pointer;
}
.char-birth-enable input { accent-color: var(--gold); cursor: pointer; margin: 0; }

