/* ======================================
   MODAL
   ====================================== */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(13, 11, 14, 0.85);
  z-index: 500;
  display: none;
  align-items: center;
  justify-content: center;
}
.modal-overlay.open { display: flex; }

.modal-box {
  background: var(--bg-panel);
  border: 1px solid var(--border-dim);
  border-radius: var(--radius);
  padding: 1.5rem;
  max-width: 480px;
  width: 90%;
  max-height: 85vh;
  overflow-y: auto;
  position: relative;
}

/* -- CENTERED SECTION TABS (2026-08-11) ------------------------------------
   The letterspaced underline tab bar the NPC profile introduced (Relations /
   Service / Chronicle), promoted to a shared control so any page can use it -
   the Market's four sections were the first to follow. Container centers the
   row over a hairline; the active tab is parchment-bright with a gold
   underline. */
/* The Ravens' .raven-tab and the Plots tab's .sub-tab dress the same way and
   keep their own names only because JS toggles them (.active / .selected);
   they share these rules rather than carrying three copies (2026-09-23). */
.sec-tabs, .raven-tabs, .sub-tabs {
  display: flex;
  justify-content: center;
  gap: 2.2rem;
  border-bottom: 1px solid var(--border-dim);
}
.sec-tabs, .sub-tabs { flex-wrap: wrap; }
.sec-tab, .raven-tab, .sub-tab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 0.45rem 0.2rem 0.55rem;
  font-family: var(--font-serif);
  font-size: 0.78rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-muted);
  cursor: pointer;
}
.sec-tab:hover, .raven-tab:hover, .sub-tab:hover { color: var(--text-secondary); }
.sec-tab.active, .raven-tab.active, .sub-tab.selected {
  color: var(--text-primary);
  border-bottom-color: var(--accent-gold);
}
@media (max-width: 640px) {
  .sec-tabs, .raven-tabs, .sub-tabs { gap: 1.1rem; }
  .sec-tab, .raven-tab, .sub-tab { letter-spacing: 0.14em; }
}
/* The panes a .sec-tabs bar switches between: static wrappers marked with
   data-cs, one .active at a time. (The NPC profile keeps its own .cp-sec
   twin because its panes double as the player's untabbed layout.) */
.sec-pane { display: none; }
.sec-pane.active { display: block; }
/* A second, denser row nested inside a pane - the Retinue's region courts. */
.sec-tabs.sub { gap: 1.3rem; }
.sec-tabs.sub .sec-tab { font-size: 0.72rem; letter-spacing: 0.12em; padding: 0.3rem 0.15rem 0.4rem; }

.modal-title {
  font-family: var(--font-display);
  font-variant: small-caps;
  font-size: 1.1rem;
  color: var(--accent-gold);
  margin-bottom: 0.75rem;
}

.modal-close {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: 1.1rem;
  cursor: pointer;
  line-height: 1;
  transition: color 0.15s;
}
.modal-close:hover { color: var(--text-primary); }

/* ======================================
   BUTTONS
   ====================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.55rem 1.2rem;
  /* SQUARE, AND SET IN THE DISPLAY FACE (maggie, 2026-08-20, from her
     screenshot: "I want the orange buttons to look like this. Not rounded").
     A rounded sans-serif button is a web control; this game is set in EB
     Garamond small-caps throughout - the house banners, the section heads, the
     names in every list - and the buttons were the one thing that had never
     joined in. `font-variant: small-caps` rather than `text-transform:
     uppercase` is what gives "Set Routine" its taller S and R, which is the
     whole look. Wide tracking, because small-caps needs air. */
  border-radius: 0;
  font-family: var(--font-display);
  font-variant: small-caps;
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: none;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
  cursor: pointer;
  border: 1px solid transparent;
  /* TRANSPARENT BY DEFAULT, AND THIS FIXES A WHITE SLAB (found 2026-08-20 while
     re-cutting the buttons). `button` in base.css sets no background, so the
     thirty-odd buttons that name their own colour inline - the red Release, the
     gold Buy, the violet whisper ones - fell through to the browser's own
     ButtonFace and rendered as WHITE boxes with coloured text on them. The
     comment below assumed they were transparent; they never were. The fill rule
     under this one is more specific, so an ordinary button still fills. */
  background: transparent;
}

/* AIR INSIDE THE SMALL BUTTONS (maggie, 2026-09-18: "some padding here and
   around all the buttons like that", from a rumour row whose two buttons had
   their words against the frame).
   ==========================================================================
   Roughly two hundred buttons in this codebase are sized at their call site -
   `class="btn" style="font-size:0.62rem;padding:0.1rem 0.45rem"` and thirty
   other combinations of the same two - and most of them were cut tight enough
   that a two-line label touches the border. An inline style beats a stylesheet,
   so a floor cannot be expressed any other way than this: !important, over the
   selector that matches exactly those call sites and nothing else. A full-size
   button never writes its own font-size, so it is untouched.

   This is the same trick as `:not([style*="color"])` below - reading the inline
   style attribute rather than bulk-editing two hundred template literals, which
   is a class of edit this repo has been burnt by twice. If the small buttons
   ever get a real `.btn-sm` class, this rule is what it replaces. */
.btn[style*="font-size:0.5"],
.btn[style*="font-size:0.6"],
.btn[style*="font-size:0.7"] {
  padding: 0.3rem 0.7rem !important;
}

/* THE PLAIN BUTTON IS THE EMBER BUTTON (maggie, 2026-08-10).
   ==========================================================================
   `.btn` on its own set no colours at all, so a bare button took whatever the
   surface gave it - a pale parchment slab in light mode, a pale grey one in
   dark. Beside it, anything that mattered was `.btn-primary` in ember. The
   result was two looks for the same control, scattered: Save Note pale, Send
   ember, Buy pale, Publish pale, the interaction tiles pale. Her call, after
   half a dozen screenshots of the same complaint: the pale ones ARE the ember
   ones. So the DEFAULT is now the ember fill, and `.btn-primary` is what a bare
   `.btn` already gives you (kept, because 99 call sites say it and saying
   "primary" out loud is not wrong).

   WHY `:not([style*="color"])`, WHICH LOOKS LIKE A TRICK AND IS ONE.
   About thirty buttons in this codebase are written as
   `class="btn" style="border-color:#f44336;color:#f44336"` - a red outline for
   something destructive, gold for something rare, violet for a whisper. That
   is the house convention for "this button is its own colour". An inline
   `color` beats any stylesheet, but an inline `background` was never written,
   so filling `.btn` unconditionally would have painted red text onto an orange
   slab in thirty places at once.

   The alternative was a bulk edit adding `background:transparent` to all
   thirty, across a dozen files - exactly the kind of sweep AGENTS.md forbids,
   and for a purely cosmetic gain. This selector says the same thing in one
   line: a button that names its own colour keeps its own look. It matches
   `border-color` too, which is what those declarations all carry.

   Not touched, on purpose: `.stance-pill` (Normal/Flirty/Secretive/Hostile),
   where ember IS the selected state and filling all four would erase the only
   thing the control says; `.btn-secondary`, which is a real second rank and
   sets its own transparent background; and `.cp-action.danger`, which sets
   its own so the irons tile stays red. */
/* THE LIGHTER RULE AROUND THE BRICK is half of what makes it look struck
   rather than printed - the fill alone reads flat on this page. */
.btn:not([style*="color"]) {
  background: var(--btn-fill);
  color: var(--btn-ink);
  border-color: var(--btn-edge);
}
.btn:not([style*="color"]):hover:not(:disabled) {
  background: var(--btn-fill-hover);
  border-color: var(--btn-edge);
}

.btn-primary {
  background: var(--btn-fill);
  color: var(--btn-ink);
  border-color: var(--btn-edge);
}
.btn-primary:hover { background: var(--btn-fill-hover); border-color: var(--btn-edge); }

/* THE UNSELECTED HALF OF A PAIR (2026-08-10). Nine controls in the game said
   "this tab is the one you are on" purely by being ember while its neighbour
   was pale - Buy/Sell in the market, Awaiting/History in the Tidings, the house
   picker, the seat's order buttons, the diary and notification filters. The
   moment the pale default became ember, both halves looked chosen and the
   control said nothing at all. They now name this class for the unselected
   half: SELECTED is `btn-primary`, UNSELECTED is `btn-secondary`, and neither
   is the bare default. Write a new pair that way. */
/* WRITTEN `.btn.btn-secondary`, NOT `.btn-secondary`, AND THAT MATTERS.
   The default rule above is `.btn:not([style*="color"])`, and a `:not()` with an
   attribute selector inside it weighs as much as a second class - so a plain
   `.btn-secondary` LOST to it, and the first run of this change came back with
   Awaiting You and History both filled, saying nothing. Doubling the class
   matches its weight, and these rules sit after it, so they win. Same for the
   two below. */
.btn.btn-secondary {
  background: transparent;
  color: var(--text-primary);
  border-color: var(--border-dim);
}
/* `:not(:disabled)` too, or the default hover above (four parts) outweighs this
   one (three) and an outline button fills brick under the mouse. */
.btn.btn-secondary:hover:not(:disabled) { border-color: var(--text-muted); background: transparent; }

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

/* The routine panel lives in layout.css (one copy since 2026-09-23). */

/* ======================================
   BIOGRAPHY BLOCK
   ====================================== */
.biography-text {
  font-family: var(--font-prose);
  font-size: 0.92rem;
  line-height: 1.7;
  color: var(--text-primary);
  /* Upright since 2026-08-11 - maggie retired the italic reading voice. */
}

/* == THE DISCORD ROW IN THE MENU (maggie, 2026-09-06) =======================
   Its heading is a full-width button like every other row in the Menu, so the
   block itself carries no border - the box belongs to what the heading folds
   open, which is where the fields actually are. `.fold-body` is put on by
   ui/fold.js, which builds that wrapper and is the only thing that can name
   it. Scoped to #discord-opts so no other folded block is restyled. */
#discord-opts > .fold-body {
  border: 1px solid var(--border-dim);
  border-radius: 6px;
  padding: 0.5rem 0.6rem;
  margin-bottom: 0.4rem;
}

/* ======================================
   THE CONFIRM THAT SHOWS ITS WORKING
   ====================================== */

/* hofConfirm() in js/ui/helpers.js. It borrows .modal-box / .modal-title
   above, so it is the game's own box and not the browser's - the
   only thing it adds is the shape of what goes inside: a breakdown to read,
   then the two buttons, with the affirmative on the right where every other
   pair in this game puts it.

   The body scrolls rather than the box growing: a plot's breakdown is six or
   seven lines and a long one must not push Begin off a phone screen, which is
   how somebody ends up agreeing to a thing they could not read. */
/* The box is a native <dialog>: stripped of the browser's own skin, it fills
   the screen and centres .modal-box, and its ::backdrop is the dim that
   .modal-overlay paints for the other modals. */
dialog.hof-confirm {
  margin: 0; padding: 0; border: 0;
  width: 100%; height: 100%; max-width: none; max-height: none;
  background: transparent; color: inherit;
}
dialog.hof-confirm[open] { display: flex; align-items: center; justify-content: center; }
dialog.hof-confirm::backdrop { background: rgba(13, 11, 14, 0.85); }
.hof-confirm-box { max-width: 420px; }
.hof-confirm-body {
  max-height: 50vh;
  overflow-y: auto;
  margin-bottom: 1rem;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--text-secondary);
}
.hof-confirm-body > div { margin-bottom: 0.3rem; }
/* CENTRED (maggie, 2026-09-18: "this should be centered"). The pair sat against
   the right-hand edge of a box whose title and body are read from the left, so
   the two buttons hung off one corner of it. */
.hof-confirm-actions {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  flex-wrap: wrap;
}

/* A SINK OFFERED INSIDE THE CONFIRM BOX - "pay with your name?" - rather than as
   a second button on the page. See sinkChoice in ui/helpers.js. Shut, it keeps
   its place and wears the route's own reason in its title. */
.sink-choice {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin-top: 0.15rem;
  font-size: 0.8rem;
  color: var(--accent-gold);
  cursor: pointer;
}
.sink-choice input { accent-color: var(--accent-gold); margin: 0; }
.sink-choice.is-shut { color: var(--text-muted); opacity: 0.6; cursor: not-allowed; }
@media (pointer: coarse) {
  /* Thumb-sized and side by side, each taking half the row, so neither is the
     one you hit by accident. */
  .hof-confirm-actions .btn { flex: 1 1 8rem; min-height: 44px; }
}

/* THE SEARCH BOX OVER A LONG LIST (listSearchBox in ui/helpers.js).
   ==========================================================================
   It is written as the first child of the very container it filters, so that
   one expression owns both - and three of those containers are GRIDS. A grid
   item takes one column and stretches to its row's height, so on the Relations
   page the box came out as a tall empty slab the size of a person card beside
   it (maggie, 2026-09-18: "this search bar is hideous"). A box that spans its
   row and keeps its own height is right wherever it is put, and both
   properties are simply ignored outside a grid. */
.list-search {
  grid-column: 1 / -1;
  align-self: start;
  justify-self: stretch;
  box-sizing: border-box;
  width: 100%;
  height: auto;
  min-height: 0;
  padding: 0.35rem 0.5rem;
  font-family: inherit;
}
.list-search::placeholder { font-style: italic; color: var(--text-muted); }

/* One rule of rules.json: the creation page's gate and the in-game ? box. */
.rule-item { padding: 0.7rem 0; border-top: 1px solid var(--border-dim); }
.rule-item:first-child { border-top: none; padding-top: 0.2rem; }
.rule-title {
  font-family: var(--font-display);
  font-variant: small-caps;
  letter-spacing: 0.05em;
  font-size: 1rem;
  color: var(--accent-gold);
  margin-bottom: 0.2rem;
}
.rule-text {
  font-family: var(--font-prose);
  font-size: 0.82rem;
  line-height: 1.6;
  color: var(--text-secondary);
}

/* -- A FILTER CHIP (the QoL pass, 2026-09-18, item 4.12) --------------- */
/* The Tidings category filters were hand-rolled buttons carrying six inline
   declarations each. One look, named once. (The diary's filter is a checkbox
   list inside a fold, not chips - there was no second copy to fold in, which is
   worth saying because the plan expected one.) */
.chip {
  font-size: 0.72rem; padding: 0.2rem 0.6rem; margin: 0.1rem 0.3rem 0.1rem 0;
  border-radius: 999px; min-height: var(--tap-min); line-height: 1.1;
}
@media (pointer: fine) { .chip { min-height: 0; } }
.chip.chip-off { opacity: 0.5; }

/* -- THE READABLE FLOOR REACHES THE INLINE SIZES (item 4.10) ----------- */
/* The 09-17 audit put a 0.72rem floor on the stylesheets, and generated markup
   carries its own inline font-size - about ten pixels in places - which no
   stylesheet rule can outrank without this. Scoped to the four screens the
   audit actually named rather than swept across the game: a global !important
   would resize screens nobody complained about, and 453 hand edits is not the
   'targeted edits' the plan asked for. Phones only, where it matters. */
@media (pointer: coarse) {
  #tab-relations [style*="font-size:0.6"],
  #tab-market [style*="font-size:0.6"],
  #tab-intrigue [style*="font-size:0.6"],
  #notifications-body [style*="font-size:0.6"] { font-size: 0.72rem !important; }
}
